Skip to content

Commit 654efad

Browse files
committed
sidecar docs and schema additions
1 parent fdf7da8 commit 654efad

32 files changed

Lines changed: 3532 additions & 95 deletions

File tree

fern/apis/signalwire-rest/openapi.yaml

Lines changed: 681 additions & 13 deletions
Large diffs are not rendered by default.

fern/fern.config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
22
"organization": "signalwire",
3-
"version": "5.23.3"
3+
"version": "5.44.4"
44
}

fern/products/platform/pages/messaging/sms/overview.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ You can see this list in full detail [here](/docs/platform/messaging/sms-best-pr
294294

295295
<Accordion title="How do I redact the body of a sent message?">
296296

297-
For compliance, privacy, or moderation use cases, you can redact the body of a previously sent message by sending a `PATCH` request to `/api/messaging/messages/:message_id` with a `body` of `""`. Only messages in terminal states (`delivered`, `undelivered`, `failed`) are eligible; messages still in progress (`queued` or `initiated`) cannot be redacted. Once redacted, the original body is overwritten and cannot be recovered. See the [Redact a message](/docs/apis/rest/signalwire-rest/messages/update-message) API reference for full details.
297+
For compliance, privacy, or moderation use cases, you can redact the body of a previously sent message by sending a `PATCH` request to `/api/messaging/messages/:message_id` with a `body` of `""`. Only messages in terminal states (`delivered`, `undelivered`, `failed`) are eligible; messages still in progress (`queued` or `initiated`) cannot be redacted. Once redacted, the original body is overwritten and cannot be recovered. See the [Redact a message](/docs/apis/rest/messages/update-message) API reference for full details.
298298

299299
</Accordion>
300300

fern/products/platform/pages/messaging/sms/platform-free-trial.mdx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ description: Test SignalWire's messaging APIs before registering with The Campai
66
---
77

88
Platform Free Trial (PFT) provides a way to test SignalWire's messaging APIs before registering Brands or Campaigns with
9-
[The Campaign Registry](/messaging/campaign-registry/campaign-service-providers).
9+
[The Campaign Registry](/docs/platform/messaging/campaign-registry/campaign-service-providers).
1010
There is no set length of your trial, so you can take your time experimenting with Messaging.
1111
The only cost to you is [standard message rates](https://signalwire.com/pricing/messaging) and carrier fees.
1212

@@ -39,15 +39,15 @@ It is simple to set up, but, as a trial, it does have restrictions. Let's go ove
3939

4040
When you have a verified mobile number and an active SignalWire number in your account, you will see a notice in your [Messaging Campaigns Space](https://my.signalwire.com?page=registry/brands) that you can now send test messages.
4141

42-
For a quick start on sending your first message, see the **Try it out** examples on the [Messaging overview](/messaging).
42+
For a quick start on sending your first message, see the **Try it out** examples on the [Messaging overview](/docs/platform/messaging).
4343

4444
</Step>
4545

4646
</Steps>
4747

4848
## Trial Restrictions
4949

50-
Test messages with Platform Free Trial may only be sent from the assigned SignalWire phone number to the assigned verified mobile number. No other messaging traffic will be possible without registering a Campaign with [The Campaign Registry](/messaging/campaign-registry/campaign-service-providers).
50+
Test messages with Platform Free Trial may only be sent from the assigned SignalWire phone number to the assigned verified mobile number. No other messaging traffic will be possible without registering a Campaign with [The Campaign Registry](/docs/platform/messaging/campaign-registry/campaign-service-providers).
5151

5252
There is a limit of 200 messages per day.
5353

@@ -56,5 +56,5 @@ SMS integrations with LaML, SWML and Call Flow Builder will not work with Platfo
5656
Each message is prepended with `[SignalWire Free Trial]`.
5757

5858
<Warning title="PFT is a single-use trial">
59-
Releasing or removing either your PFT-enabled SignalWire phone number or verified caller ID number will end the free trial. You will not be able to re-enable the trial by adding a new phone number. You would be unable to send any further messages until registering a Campaign with [The Campaign Registry](/messaging/campaign-registry).
59+
Releasing or removing either your PFT-enabled SignalWire phone number or verified caller ID number will end the free trial. You will not be able to re-enable the trial by adding a new phone number. You would be unable to send any further messages until registering a Campaign with [The Campaign Registry](/docs/platform/messaging/campaign-registry).
6060
</Warning>

fern/products/server-sdks/pages/reference/python/agents/agent-base/add-mcp-server.mdx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,15 @@ max-toc-depth: 3
77

88
[enable-mcp-server]: /docs/server-sdks/reference/python/agents/agent-base/enable-mcp-server
99
[ref-agentbase]: /docs/server-sdks/reference/python/agents/agent-base
10+
[swml-mcp-servers]: /docs/swml/reference/calling/ai/swaig#swaigmcp_servers
1011

1112
Connect the agent to an external [Model Context Protocol](https://modelcontextprotocol.io/) (MCP) server. Tools are
1213
discovered via the MCP protocol at session start and automatically registered as
1314
SWAIG functions. Optionally, the server's resources can be fetched into the agent's
1415
global data.
1516

17+
Each server you add appears in the SWML [`SWAIG.mcp_servers`][swml-mcp-servers] field of the document the agent generates.
18+
1619
<Note>
1720
This method connects your agent **to** an MCP server as a client. To expose your
1821
agent's own tools **as** an MCP server, use
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
---
2+
title: "define_tool"
3+
slug: /reference/python/agents/swml-service/define-tool
4+
description: Host a SWAIG tool directly on a SWMLService so any SWML document — including ai_sidecar — can invoke it.
5+
max-toc-depth: 3
6+
---
7+
8+
[functionresult]: /docs/server-sdks/reference/python/agents/function-result
9+
[ref-swmlservice]: /docs/server-sdks/reference/python/agents/swml-service
10+
[register-routing-callback]: /docs/server-sdks/reference/python/agents/swml-service/register-routing-callback
11+
[ai_sidecar]: /docs/swml/reference/calling/ai_sidecar
12+
[ai_sidecar-swaig]: /docs/swml/reference/calling/ai_sidecar/swaig
13+
14+
Define a SWAIG function (tool) hosted directly on the `SWMLService`, without subclassing
15+
`AgentBase`. The service exposes a `POST /<route>/swaig` endpoint that dispatches tool calls
16+
to your handler, so any SWML document the service emits — including the
17+
[`ai_sidecar`][ai_sidecar] verb — can reference and invoke the tool.
18+
19+
<Info>
20+
SWAIG hosting is available on `SWMLService` itself, so you can build an AI Sidecar (or any
21+
non-agent SWML service) with plain `SWMLService` — no `AgentBase` required. Tool definitions
22+
map to SWML [`ai_sidecar.SWAIG.functions`][ai_sidecar-swaig] entries (and to the `ai` verb's
23+
SWAIG functions when used with an agent).
24+
</Info>
25+
26+
## **Parameters**
27+
28+
<ParamField path="name" type="str" required={true} toc={true}>
29+
Function name. Must be unique within the service. The model uses this name to invoke the
30+
function.
31+
</ParamField>
32+
33+
<ParamField path="description" type="str" required={true} toc={true}>
34+
Human-readable description of what the function does. The model reads this to decide when
35+
to call the function.
36+
</ParamField>
37+
38+
<ParamField path="parameters" type="dict[str, Any]" required={true} toc={true}>
39+
JSON Schema describing the function's parameters. The model generates arguments conforming
40+
to this schema.
41+
</ParamField>
42+
43+
<ParamField path="handler" type="Callable" required={true} toc={true}>
44+
Python function to call when the model invokes this tool. Receives `(args: dict, raw_data: dict)`
45+
and should return a [`FunctionResult`][functionresult].
46+
</ParamField>
47+
48+
<ParamField path="secure" type="bool" default="True" toc={true}>
49+
Whether to require token validation on tool calls. Recommended for production.
50+
</ParamField>
51+
52+
<ParamField path="fillers" type="Optional[dict[str, list[str]]]" toc={true}>
53+
Language-specific filler phrases spoken while the function executes.
54+
Format: `{"en-US": ["Looking that up...", "One moment..."]}`.
55+
</ParamField>
56+
57+
<ParamField path="webhook_url" type="Optional[str]" toc={true}>
58+
External URL to forward the tool call to instead of executing locally.
59+
</ParamField>
60+
61+
<ParamField path="required" type="Optional[list[str]]" toc={true}>
62+
List of required parameter names from the JSON Schema.
63+
</ParamField>
64+
65+
<ParamField path="is_typed_handler" type="bool" default="False" toc={true}>
66+
Set to `True` if the handler uses type-hinted parameters instead of the standard
67+
`(args, raw_data)` signature.
68+
</ParamField>
69+
70+
<ParamField path="**swaig_fields" type="Any" toc={true}>
71+
Additional SWAIG fields to include in the function definition.
72+
</ParamField>
73+
74+
## **Returns**
75+
76+
[`SWMLService`][ref-swmlservice] -- Returns self for method chaining.
77+
78+
## **Example**
79+
80+
Host a tool on a sidecar service. The `ai_sidecar` verb references the tool through
81+
`SWAIG.defaults.web_hook_url`, and the model calls it during the live call. Sidecar events
82+
are delivered to the `/events` endpoint registered with
83+
[`register_routing_callback`][register-routing-callback].
84+
85+
```python {21}
86+
from signalwire.core.swml_service import SWMLService
87+
from signalwire.core.function_result import FunctionResult
88+
89+
90+
class SalesSidecar(SWMLService):
91+
def __init__(self):
92+
super().__init__(name="sales-sidecar", route="/sales-sidecar")
93+
94+
public_url = "https://your-app.example.com/sales-sidecar"
95+
96+
self.add_verb_to_section("main", "ai_sidecar", {
97+
"prompt": "You are a real-time sales copilot. Give the agent one concise piece of advice per customer turn, or call sidecar_skip.",
98+
"lang": "en-US",
99+
"url": f"{public_url}/events",
100+
"SWAIG": {"defaults": {"web_hook_url": f"{public_url}/swaig"}},
101+
})
102+
103+
def lookup_competitor(args, raw_data=None):
104+
name = args.get("competitor", "unknown")
105+
return FunctionResult(f"{name} charges $99/seat. We're $79.")
106+
107+
self.define_tool(
108+
name="lookup_competitor",
109+
description="Look up a competitor by name.",
110+
parameters={
111+
"type": "object",
112+
"properties": {"competitor": {"type": "string", "description": "Competitor name."}},
113+
},
114+
handler=lookup_competitor,
115+
required=["competitor"],
116+
)
117+
118+
self.register_routing_callback(self.on_event, path="/events")
119+
120+
def on_event(self, request, body):
121+
event = body.get("sidecar_event", body)
122+
if event.get("type") == "insight":
123+
print(f"[insight] {event.get('raw')}")
124+
return None
125+
126+
127+
if __name__ == "__main__":
128+
SalesSidecar().serve()
129+
```

fern/products/server-sdks/pages/reference/python/agents/swml-service/register-routing-callback.mdx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ max-toc-depth: 3
66
---
77

88
[serve]: /docs/server-sdks/reference/python/agents/swml-service/serve
9+
[ai-sidecar-callbacks]: /docs/swml/reference/calling/ai_sidecar#webhook-callbacks
910

1011
Register a callback function for dynamic request routing. When a request arrives at
1112
the specified path, the callback inspects the POST body and decides whether to route
@@ -16,6 +17,13 @@ An HTTP endpoint is automatically created at the specified path when the service
1617
The callback receives the raw FastAPI `Request` object and the parsed request body as
1718
a dictionary.
1819

20+
<Tip>
21+
This is also how you receive an [`ai_sidecar`](/docs/swml/reference/calling/ai_sidecar) verb's webhook
22+
callbacks. Register a callback at the path your `ai_sidecar.url` points to (for example, `/events`) and
23+
return `None` to acknowledge each one. The callback's body wraps the event under `sidecar_event` — see the
24+
[callback catalog][ai-sidecar-callbacks] for the payload shapes.
25+
</Tip>
26+
1927
<Note>
2028
The callback path is registered at the time of calling this method but the actual
2129
FastAPI route is created when [`serve()`][serve]

fern/products/server-sdks/pages/reference/typescript/agents/agent-base/add-mcp-server.mdx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,15 @@ max-toc-depth: 3
77

88
[enable-mcp-server]: /docs/server-sdks/reference/typescript/agents/agent-base/enable-mcp-server
99
[ref-agentbase]: /docs/server-sdks/reference/typescript/agents/agent-base
10+
[swml-mcp-servers]: /docs/swml/reference/calling/ai/swaig#swaigmcp_servers
1011

1112
Connect the agent to an external [Model Context Protocol](https://modelcontextprotocol.io/) (MCP) server. Tools are
1213
discovered via the MCP protocol at session start and automatically registered as
1314
SWAIG functions. Optionally, the server's resources can be fetched into the agent's
1415
global data.
1516

17+
Each server you add appears in the SWML [`SWAIG.mcp_servers`][swml-mcp-servers] field of the document the agent generates.
18+
1619
<Note>
1720
This method connects your agent **to** an MCP server as a client. To expose your
1821
agent's own tools **as** an MCP server, use
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
---
2+
title: "defineTool"
3+
slug: /reference/typescript/agents/swml-service/define-tool
4+
description: Host a SWAIG tool directly on a SWMLService so any SWML document — including ai_sidecar — can invoke it.
5+
max-toc-depth: 3
6+
---
7+
8+
[functionresult]: /docs/server-sdks/reference/typescript/agents/function-result
9+
[ref-swmlservice]: /docs/server-sdks/reference/typescript/agents/swml-service
10+
[register-routing-callback]: /docs/server-sdks/reference/typescript/agents/swml-service/register-routing-callback
11+
[ai_sidecar]: /docs/swml/reference/calling/ai_sidecar
12+
[ai_sidecar-swaig]: /docs/swml/reference/calling/ai_sidecar/swaig
13+
14+
Define a SWAIG function (tool) hosted directly on the `SWMLService`, without subclassing
15+
`AgentBase`. The service exposes a `POST /<route>/swaig` endpoint that dispatches tool calls
16+
to your handler, so any SWML document the service emits — including the
17+
[`ai_sidecar`][ai_sidecar] verb — can reference and invoke the tool.
18+
19+
<Info>
20+
SWAIG hosting is available on `SWMLService` itself, so you can build an AI Sidecar (or any
21+
non-agent SWML service) with plain `SWMLService` — no `AgentBase` required. Tool definitions
22+
map to SWML [`ai_sidecar.SWAIG.functions`][ai_sidecar-swaig] entries (and to the `ai` verb's
23+
SWAIG functions when used with an agent).
24+
</Info>
25+
26+
## **Parameters**
27+
28+
<ParamField path="opts" type="object" required={true} toc={true}>
29+
Tool definition object.
30+
</ParamField>
31+
32+
<Indent>
33+
<ParamField path="opts.name" type="string" required={true} toc={true}>
34+
Tool name. Must be unique within the service. The model uses this name to invoke the
35+
function.
36+
</ParamField>
37+
38+
<ParamField path="opts.description" type="string" required={true} toc={true}>
39+
Human-readable description of what the tool does. The model reads this to decide when to
40+
call the tool.
41+
</ParamField>
42+
43+
<ParamField path="opts.parameters" type={"Record<string, unknown>"} toc={true}>
44+
JSON Schema describing the tool's parameters. The model generates arguments conforming to
45+
this schema.
46+
</ParamField>
47+
48+
<ParamField path="opts.handler" type="SwaigHandler" required={true} toc={true}>
49+
Callback invoked when the model calls this tool. Receives
50+
`(args: Record<string, unknown>, rawData: Record<string, unknown>)` and should return a
51+
[`FunctionResult`][functionresult].
52+
</ParamField>
53+
54+
<ParamField path="opts.secure" type="boolean" default="false" toc={true}>
55+
Whether to require token validation on tool calls. Recommended for production.
56+
</ParamField>
57+
58+
<ParamField path="opts.fillers" type={"Record<string, string[]>"} toc={true}>
59+
Language-specific filler phrases spoken while the tool executes.
60+
Format: `{ "en-US": ["Looking that up...", "One moment..."] }`.
61+
</ParamField>
62+
63+
<ParamField path="opts.webhookUrl" type="string" toc={true}>
64+
External URL to forward the tool call to instead of executing locally.
65+
</ParamField>
66+
67+
<ParamField path="opts.required" type={"string[]"} toc={true}>
68+
List of required parameter names from the JSON Schema.
69+
</ParamField>
70+
71+
<ParamField path="opts.isTypedHandler" type="boolean" default="false" toc={true}>
72+
Set to `true` if the handler uses named, typed parameters instead of the standard
73+
`(args, rawData)` signature.
74+
</ParamField>
75+
76+
<ParamField path="opts.extraFields" type={"Record<string, unknown>"} toc={true}>
77+
Additional SWAIG fields to include in the function definition.
78+
</ParamField>
79+
</Indent>
80+
81+
## **Returns**
82+
83+
[`SWMLService`][ref-swmlservice] -- Returns `this` for method chaining.
84+
85+
## **Example**
86+
87+
Host a tool on a sidecar service. The `ai_sidecar` verb references the tool through
88+
`SWAIG.defaults.web_hook_url`, and the model calls it during the live call. Sidecar events
89+
are delivered to the `/events` endpoint registered with
90+
[`registerRoutingCallback`][register-routing-callback].
91+
92+
```typescript {20}
93+
import { SWMLService } from '@signalwire/agents';
94+
95+
class SalesSidecar extends SWMLService {
96+
constructor() {
97+
super({ name: 'sales-sidecar', route: '/sales-sidecar' });
98+
99+
const publicUrl = 'https://your-app.example.com/sales-sidecar';
100+
101+
this.addVerbToSection('main', 'ai_sidecar', {
102+
prompt:
103+
'You are a real-time sales copilot. Give the agent one concise piece of advice per customer turn, or call sidecar_skip.',
104+
lang: 'en-US',
105+
url: `${publicUrl}/events`,
106+
SWAIG: { defaults: { web_hook_url: `${publicUrl}/swaig` } },
107+
});
108+
109+
this.defineTool({
110+
name: 'lookup_competitor',
111+
description: 'Look up a competitor by name.',
112+
parameters: {
113+
type: 'object',
114+
properties: { competitor: { type: 'string', description: 'Competitor name.' } },
115+
},
116+
required: ['competitor'],
117+
handler: (args) => ({ response: `${args.competitor} charges $99/seat. We're $79.` }),
118+
});
119+
120+
this.registerRoutingCallback((body) => {
121+
const event = (body['sidecar_event'] as Record<string, unknown>) ?? body;
122+
if (event['type'] === 'insight') {
123+
this.log.info(`[insight] ${event['raw']}`);
124+
}
125+
return null;
126+
}, '/events');
127+
}
128+
}
129+
130+
const agent = new SalesSidecar();
131+
agent.run();
132+
```

fern/products/server-sdks/pages/reference/typescript/agents/swml-service/register-routing-callback.mdx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ max-toc-depth: 3
88
[ref-serve]: /docs/server-sdks/reference/typescript/agents/swml-service/serve
99
[ref-asrouter]: /docs/server-sdks/reference/typescript/agents/swml-service/as-router
1010
[ref-extractsipusername]: /docs/server-sdks/reference/typescript/agents/swml-service/extract-sip-username
11+
[ai-sidecar-callbacks]: /docs/swml/reference/calling/ai_sidecar#webhook-callbacks
1112

1213
Register a callback for dynamic request routing. When a request arrives at the
1314
specified path, the callback inspects the POST body and decides whether to
@@ -18,6 +19,13 @@ destination depends on the incoming SIP URI.
1819
A Hono endpoint is registered immediately for the specified path, serving both
1920
GET and POST.
2021

22+
<Tip>
23+
This is also how you receive an [`ai_sidecar`](/docs/swml/reference/calling/ai_sidecar) verb's webhook
24+
callbacks. Register a callback at the path your `ai_sidecar.url` points to (for example, `/events`) and
25+
return `null` to acknowledge each one. The callback's body wraps the event under `sidecar_event` — see the
26+
[callback catalog][ai-sidecar-callbacks] for the payload shapes.
27+
</Tip>
28+
2129
<Note>
2230
Unlike the Python SDK, the TypeScript `RoutingCallback` receives only the
2331
parsed request body -- not the underlying `Request` object. If you need access

0 commit comments

Comments
 (0)