Skip to content

Commit d6e8475

Browse files
committed
Merge branch 'main' into hey-august-patch-1
2 parents b0fd8f1 + 91942f6 commit d6e8475

File tree

333 files changed

+30999
-29525
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

333 files changed

+30999
-29525
lines changed

docker-compose.yml

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
version: '3.9'
2+
3+
services:
4+
# TypeSense search server (ephemeral - no data persistence)
5+
typesense:
6+
image: typesense/typesense:29.0
7+
container_name: typesense-local
8+
ports:
9+
- "8108:8108"
10+
volumes:
11+
- typesense-data:/data # Named volume for ephemeral storage
12+
command: '--data-dir /data --api-key=local-dev-api-key-12345 --enable-cors'
13+
healthcheck:
14+
test: ["CMD", "bash", "-c", "exec 3<>/dev/tcp/localhost/8108 && printf 'GET /health HTTP/1.1\r\nConnection: close\r\n\r\n' >&3 && head -n1 <&3 | grep '200' && exec 3>&-"]
15+
interval: 10s
16+
timeout: 1s
17+
retries: 5
18+
start_period: 10s
19+
networks:
20+
- docs-network
21+
22+
# TypeSense documentation scraper
23+
# NOTE: Requires local dev server running at localhost:3000 (run 'yarn start --host 0.0.0.0' first)
24+
docs-scraper:
25+
image: typesense/docsearch-scraper:0.9.1
26+
container_name: docs-scraper
27+
entrypoint: [] # Override default entrypoint to run custom setup
28+
volumes:
29+
- ./website:/tmp/search:ro
30+
environment:
31+
- TYPESENSE_API_KEY=local-dev-api-key-12345
32+
- TYPESENSE_HOST=typesense
33+
- TYPESENSE_PORT=8108
34+
- TYPESENSE_PROTOCOL=http
35+
- CONFIG=/tmp/typesense.local.json
36+
depends_on:
37+
typesense:
38+
condition: service_healthy
39+
# Auto-generate local config and scrape from host dev server
40+
command: >
41+
sh -c "
42+
echo 'Generating typesense.local.json from typesense.json...' &&
43+
sed -e 's|https\?://developer.signalwire.com|http://host.docker.internal:3000|g' /tmp/search/typesense.json > /tmp/typesense.local.json &&
44+
echo 'Config generated. Waiting for local dev server at http://host.docker.internal:3000...' &&
45+
until wget --spider --quiet http://host.docker.internal:3000 2>/dev/null; do
46+
echo 'Dev server not ready yet, waiting 5s... (Make sure you run: yarn start)' &&
47+
sleep 5;
48+
done &&
49+
echo 'Dev server is ready! Starting documentation scraper...' &&
50+
pipenv run python -m src.index &&
51+
echo 'Scraping complete! Search is now available at http://localhost:3000'
52+
"
53+
networks:
54+
- docs-network
55+
extra_hosts:
56+
- "host.docker.internal:host-gateway"
57+
58+
networks:
59+
docs-network:
60+
name: docs-local-network
61+
driver: bridge
62+
63+
volumes:
64+
typesense-data:

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
"serve": "yarn --cwd website serve",
1313
"start": "yarn --cwd website start",
1414
"start-fresh": "yarn --cwd website start-fresh",
15+
"start:search": "TYPESENSE_HOST=localhost TYPESENSE_EXPORTS=8108 TYPESENSE_PROTOCOL=http TYPESENSE_API_SEARCH_KEY=local-dev-api-key-12345 TYPESENSE_COLLECTION_NAME=signalwire-docs yarn --cwd website start",
16+
"search:up": "docker compose up -d",
17+
"search:down": "docker compose down -v",
18+
"search:logs": "docker compose logs -f",
1519
"build:website": "yarn --cwd website build",
1620
"build:specs": "yarn --cwd specs build",
1721
"build:tools": "yarn --cwd tools build",

specs/signalwire-rest/calling-api/calls/main.tsp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ namespace CallingAPI.Calls {
1616
interface Calls {
1717
@summary("Send Call Commands")
1818
@doc("""
19-
Unified OpenRPC-style endpoint for executing call methods through command-based dispatch.
19+
Unified JSON-RPC style endpoint for executing call methods through command-based dispatch.
2020
Send a request with the appropriate `command` field to invoke the desired call operation.
2121
This endpoint provides a single interface for all call-related methods including creation, updates, termination, and AI conversation control.
2222
""")

specs/signalwire-rest/calling-api/calls/models/requests.tsp

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,19 @@ model CallHoldRequest {
5050
command: "calling.ai_hold";
5151

5252
@doc(paramsDescription)
53-
params: {};
53+
params: {
54+
@doc("The duration to hold the caller in seconds.")
55+
@example(300)
56+
@maxValue(300)
57+
timeout?: int32 = 300;
58+
59+
@doc("""
60+
A system message added to the AI conversation before placing the caller on hold.
61+
The AI will speak this message to the caller before hold music begins.
62+
""")
63+
@example("Please hold while I transfer you to a specialist.")
64+
prompt?: string = "Tell the user you are putting them on hold.";
65+
};
5466
}
5567

5668
@summary("Unhold call")
@@ -64,7 +76,14 @@ model CallUnholdRequest {
6476
command: "calling.ai_unhold";
6577

6678
@doc(paramsDescription)
67-
params: {};
79+
params: {
80+
@doc("""
81+
A system message added to the AI conversation when taking the caller off hold.
82+
The AI will use this context when resuming the conversation.
83+
""")
84+
@example("The user has been connected to a specialist.")
85+
prompt?: string = "The user has been taken off hold.";
86+
};
6887
}
6988

7089
@summary("Inject AI message")
@@ -202,7 +221,7 @@ model CallUpdateCurrentCallRequest {
202221

203222
@discriminated(#{discriminatorPropertyName: "command", envelope: "none"})
204223
@doc("""
205-
Call request union for OpenRPC-style method dispatch. Use the `command` field to specify which call method to invoke:
224+
Call request union for JSON-RPC style method dispatch. Use the `command` field to specify which call method to invoke:
206225
207226
- **`dial`** - Create and initiate a new outbound call to a destination. Returns immediately with call details while the call is being established in the background.
208227

specs/signalwire-rest/calling-api/tsp-output/@typespec/openapi3/openapi.yaml

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ paths:
2626
operationId: call-commands
2727
summary: Send Call Commands
2828
description: |-
29-
Unified OpenRPC-style endpoint for executing call methods through command-based dispatch.
29+
Unified JSON-RPC style endpoint for executing call methods through command-based dispatch.
3030
Send a request with the appropriate `command` field to invoke the desired call operation.
3131
This endpoint provides a single interface for all call-related methods including creation, updates, termination, and AI conversation control.
3232
parameters: []
@@ -352,6 +352,21 @@ components:
352352
example: calling.ai_hold
353353
params:
354354
type: object
355+
properties:
356+
timeout:
357+
type: integer
358+
format: int32
359+
maximum: 300
360+
description: The duration to hold the caller in seconds.
361+
example: 300
362+
default: 300
363+
prompt:
364+
type: string
365+
description: |-
366+
A system message added to the AI conversation before placing the caller on hold.
367+
The AI will speak this message to the caller before hold music begins.
368+
example: Please hold while I transfer you to a specialist.
369+
default: Tell the user you are putting them on hold.
355370
description: An object of parameters that will be utilized by the active command.
356371
title: Hold call
357372
CallRequest:
@@ -373,7 +388,7 @@ components:
373388
calling.ai_unhold: '#/components/schemas/CallUnholdRequest'
374389
calling.ai_message: '#/components/schemas/CallAIMessageRequest'
375390
description: |-
376-
Call request union for OpenRPC-style method dispatch. Use the `command` field to specify which call method to invoke:
391+
Call request union for JSON-RPC style method dispatch. Use the `command` field to specify which call method to invoke:
377392
378393
- **`dial`** - Create and initiate a new outbound call to a destination. Returns immediately with call details while the call is being established in the background.
379394
@@ -508,6 +523,14 @@ components:
508523
example: calling.ai_unhold
509524
params:
510525
type: object
526+
properties:
527+
prompt:
528+
type: string
529+
description: |-
530+
A system message added to the AI conversation when taking the caller off hold.
531+
The AI will use this context when resuming the conversation.
532+
example: The user has been connected to a specialist.
533+
default: The user has been taken off hold.
511534
description: An object of parameters that will be utilized by the active command.
512535
title: Unhold call
513536
CallUpdateCurrentCallRequest:

specs/signalwire-rest/fabric-api/ai-agent/models/ai/ai_params.tsp

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,47 @@ enum Direction {
1111
outbound,
1212
}
1313

14+
@summary("Conversation message role")
15+
enum ConversationRole {
16+
@doc("A message from the user.")
17+
user,
18+
19+
@doc("A message from the AI assistant.")
20+
assistant,
21+
22+
@doc("A system message providing instructions or context.")
23+
system,
24+
}
25+
26+
@summary("Conversation message object")
27+
@doc("A message object representing a single turn in the conversation history.")
28+
model ConversationMessage {
29+
@doc("The role of the message sender.")
30+
role: ConversationRole;
31+
32+
@doc("The text content of the message.")
33+
content: string;
34+
35+
@doc("Optional language code for the message (e.g., 'en', 'es', 'fr').")
36+
lang?: string;
37+
}
38+
1439
@summary("params object")
1540
model AIParams {
1641
@doc("Instructs the agent to acknowledge crosstalk and confirm user input when the user speaks over the agent.")
1742
acknowledge_interruptions?: boolean;
1843

44+
@doc("Sets the name the AI agent responds to for wake/activation purposes. When using `enable_pause`, `start_paused`, or `speak_when_spoken_to`, the user must say this name to get the agent's attention.")
45+
ai_name?: string = "computer";
46+
1947
@doc("Adjust the volume of the AI. Allowed values from `-50` - `50`.")
2048
@minValue(-50)
2149
@maxValue(50)
2250
ai_volume?: integer;
2351

52+
@doc("A custom identifier for the AI application instance. This name is included in webhook payloads.")
53+
app_name?: string = "swml app";
54+
2455
@doc("Amount of time, in ms, to wait before prompting the user to respond. Allowed values from `10,000` - `600,000`. Set to `0` to disable.")
2556
attention_timeout?: IntegerOrZero | 0;
2657

@@ -57,6 +88,9 @@ model AIParams {
5788
@example("Place an order")
5889
conscience?: string;
5990

91+
@doc("Injects pre-existing conversation history into the AI session at startup. This allows you to seed the AI agent with context from a previous conversation or provide example interactions.")
92+
convo?: ConversationMessage[];
93+
6094
@doc("Used by `check_for_input` and `save_conversation` to identify an individual conversation.")
6195
@example("Conversation ID")
6296
conversation_id?: string;
@@ -70,6 +104,9 @@ model AIParams {
70104
@example("https://example.com")
71105
debug_webhook_url?: url;
72106

107+
@doc("Enables debug mode for the AI session.")
108+
debug?: boolean | integer;
109+
73110
@doc("Forces the direction of the call to the assistant. Valid values are `inbound` and `outbound`.")
74111
direction?: Direction[];
75112

@@ -87,6 +124,15 @@ model AIParams {
87124
@maxValue(10000)
88125
end_of_speech_timeout?: integer;
89126

127+
@doc("Enables the inner dialog feature for background conversation analysis.")
128+
enable_inner_dialog?: boolean = false;
129+
130+
@doc("Enables the pause/resume functionality for the AI agent.")
131+
enable_pause?: boolean = false;
132+
133+
@doc("Enables intelligent turn detection that monitors partial speech transcripts.")
134+
enable_turn_detection?: boolean = true;
135+
90136
@doc("The stability slider determines how stable the voice is and the randomness between each generation. Lowering this slider introduces a broader emotional range for the voice.")
91137
eleven_labs_stability?: float;
92138

@@ -110,6 +156,15 @@ model AIParams {
110156
@maxValue(3600000)
111157
inactivity_timeout?: integer;
112158

159+
@doc("Specifies the AI model to use for the inner dialog feature.")
160+
inner_dialog_model?: string;
161+
162+
@doc("The system prompt that guides the inner dialog AI's behavior.")
163+
inner_dialog_prompt?: string = "The assistant is intelligent and straightforward, does its job well and is not excessively polite.";
164+
165+
@doc("When enabled, synchronizes the inner dialog with the main conversation flow.")
166+
inner_dialog_synced?: boolean = false;
167+
113168
@doc("""
114169
Check for input function with check_for_input.
115170
Example use case: Feeding an inbound SMS to AI on a voice call, eg., for collecting an email address or other complex information.
@@ -130,18 +185,35 @@ model AIParams {
130185
@example("America/Ensenada")
131186
local_tz?: string;
132187

188+
@doc("Sets the maximum number of tokens the AI model can generate in a single response.")
189+
@minValue(1)
190+
@maxValue(16384)
191+
max_response_tokens?: integer;
192+
133193
@doc("Sets a time duration for the outbound call recipient to respond to the AI agent before timeout, in a range from `10000` to `600000`.")
134194
@minValue(10000)
135195
@maxValue(600000)
136196
outbound_attention_timeout?: integer;
137197

198+
@doc("When enabled, global_data persists across multiple AI agent invocations within the same call.")
199+
persist_global_data?: boolean = true;
200+
201+
@doc("Specifies the output format for structured prompts. Valid values are `markdown` or `xml`.")
202+
pom_format?: "markdown" | "xml" = "markdown";
203+
138204
@doc("""
139205
Send a summary of the conversation after the call ends.
140206
This requires a `post_url` to be set in the ai parameters and the `conversation_id` defined below.
141207
This eliminates the need for a `post_prompt` in the ai parameters.
142208
""")
143209
save_conversation?: boolean;
144210

211+
@doc("When enabled, the AI agent remains silent until directly addressed by name.")
212+
speak_when_spoken_to?: boolean = false;
213+
214+
@doc("When enabled, the AI agent starts in a paused state.")
215+
start_paused?: boolean = false;
216+
145217
@doc("Allows tweaking any of the indicated settings, such as `barge_match_string`, using the returned SWML from the SWAIG function.")
146218
swaig_allow_settings?: boolean;
147219

@@ -151,12 +223,26 @@ model AIParams {
151223
@doc("Post entire conversation to any SWAIG call.")
152224
swaig_post_conversation?: boolean;
153225

226+
@doc("Controls whether SWML variables are included in SWAIG function webhook payloads.")
227+
swaig_post_swml_vars?: boolean | string[];
228+
154229
@doc("Pass a summary of a conversation from one AI agent to another. For example, transfer a call summary between support agents in two departments.")
155230
transfer_summary?: boolean;
156231

232+
@doc("Time in milliseconds to wait after detecting a potential end-of-turn before finalizing speech recognition.")
233+
@minValue(0)
234+
@maxValue(10000)
235+
turn_detection_timeout?: integer = 250;
236+
237+
@doc("Configures Silero Voice Activity Detection (VAD) settings. Format: `threshold` or `threshold:frame_ms`. The threshold (0-100) sets sensitivity for detecting voice activity. The optional frame_ms (16-40) sets frame duration in milliseconds.")
238+
vad_config?: string;
239+
157240
@doc("Enable verbose logging.")
158241
verbose_logs?: boolean;
159242

160243
@doc("When false, AI agent will initialize dialogue after call is setup. When true, agent will wait for the user to speak first.")
161244
wait_for_user?: boolean;
245+
246+
@doc("Specifies an additional prefix that must be spoken along with the agent's name to wake the agent.")
247+
wake_prefix?: string;
162248
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
@summary("HangupAction object")
2+
model HangupAction {
3+
@doc("Whether to hang up the call. When set to `true`, the call will be terminated after the AI agent finishes speaking.")
4+
@summary("hangup")
5+
hangup: boolean;
6+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
@summary("HoldAction object")
2+
model HoldAction {
3+
@doc("""
4+
Places the caller on hold while playing hold music (configured via params.hold_music).
5+
During hold, speech detection is paused and the AI agent will not respond to the caller.
6+
The value specifies the hold timeout in seconds.
7+
Can be a number or an object with timeout property.
8+
""")
9+
@summary("hold")
10+
@maxValue(900)
11+
hold: int32 | {
12+
@doc("The duration to hold the caller in seconds. Can be a number or an object with timeout property.")
13+
@maxValue(900)
14+
timeout?: int32 = 300;
15+
};
16+
}

specs/signalwire-rest/fabric-api/ai-agent/models/ai/swaig/functions/data_map/actions/main.tsp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import "./change_context.tsp";
22
import "./change_step.tsp";
33
import "./context_switch.tsp";
4+
import "./hangup.tsp";
5+
import "./hold.tsp";
46
import "./playback_bg.tsp";
57
import "./say.tsp";
68
import "./set_global_data.tsp";
@@ -17,6 +19,8 @@ union Action {
1719
ChangeContextAction,
1820
ChangeStepAction,
1921
ContextSwitchAction,
22+
HangupAction,
23+
HoldAction,
2024
PlaybackBGAction,
2125
SayAction,
2226
SetGlobalDataAction,

0 commit comments

Comments
 (0)