signalwire-agents 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (245) hide show
  1. package/CLAUDE.md +112 -0
  2. package/README.md +417 -0
  3. package/dist/AgentBase.d.ts +481 -0
  4. package/dist/AgentBase.js +1155 -0
  5. package/dist/AgentBase.js.map +1 -0
  6. package/dist/AgentServer.d.ts +60 -0
  7. package/dist/AgentServer.js +128 -0
  8. package/dist/AgentServer.js.map +1 -0
  9. package/dist/AuthHandler.d.ts +56 -0
  10. package/dist/AuthHandler.js +119 -0
  11. package/dist/AuthHandler.js.map +1 -0
  12. package/dist/ConfigLoader.d.ts +68 -0
  13. package/dist/ConfigLoader.js +150 -0
  14. package/dist/ConfigLoader.js.map +1 -0
  15. package/dist/ContextBuilder.d.ts +431 -0
  16. package/dist/ContextBuilder.js +751 -0
  17. package/dist/ContextBuilder.js.map +1 -0
  18. package/dist/DataMap.d.ts +179 -0
  19. package/dist/DataMap.js +321 -0
  20. package/dist/DataMap.js.map +1 -0
  21. package/dist/Logger.d.ts +91 -0
  22. package/dist/Logger.js +191 -0
  23. package/dist/Logger.js.map +1 -0
  24. package/dist/PomBuilder.d.ts +144 -0
  25. package/dist/PomBuilder.js +249 -0
  26. package/dist/PomBuilder.js.map +1 -0
  27. package/dist/PromptManager.d.ts +85 -0
  28. package/dist/PromptManager.js +108 -0
  29. package/dist/PromptManager.js.map +1 -0
  30. package/dist/SchemaUtils.d.ts +42 -0
  31. package/dist/SchemaUtils.js +148 -0
  32. package/dist/SchemaUtils.js.map +1 -0
  33. package/dist/ServerlessAdapter.d.ts +100 -0
  34. package/dist/ServerlessAdapter.js +166 -0
  35. package/dist/ServerlessAdapter.js.map +1 -0
  36. package/dist/SessionManager.d.ts +86 -0
  37. package/dist/SessionManager.js +155 -0
  38. package/dist/SessionManager.js.map +1 -0
  39. package/dist/SslConfig.d.ts +77 -0
  40. package/dist/SslConfig.js +100 -0
  41. package/dist/SslConfig.js.map +1 -0
  42. package/dist/SwaigFunction.d.ts +88 -0
  43. package/dist/SwaigFunction.js +125 -0
  44. package/dist/SwaigFunction.js.map +1 -0
  45. package/dist/SwaigFunctionResult.d.ts +442 -0
  46. package/dist/SwaigFunctionResult.js +735 -0
  47. package/dist/SwaigFunctionResult.js.map +1 -0
  48. package/dist/SwmlBuilder.d.ts +37 -0
  49. package/dist/SwmlBuilder.js +55 -0
  50. package/dist/SwmlBuilder.js.map +1 -0
  51. package/dist/cli/agent-loader.d.ts +22 -0
  52. package/dist/cli/agent-loader.js +106 -0
  53. package/dist/cli/agent-loader.js.map +1 -0
  54. package/dist/cli/mock-data.d.ts +37 -0
  55. package/dist/cli/mock-data.js +79 -0
  56. package/dist/cli/mock-data.js.map +1 -0
  57. package/dist/cli/swaig-test.d.ts +32 -0
  58. package/dist/cli/swaig-test.js +405 -0
  59. package/dist/cli/swaig-test.js.map +1 -0
  60. package/dist/index.d.ts +36 -0
  61. package/dist/index.js +44 -0
  62. package/dist/index.js.map +1 -0
  63. package/dist/prefabs/ConciergeAgent.d.ts +64 -0
  64. package/dist/prefabs/ConciergeAgent.js +188 -0
  65. package/dist/prefabs/ConciergeAgent.js.map +1 -0
  66. package/dist/prefabs/FAQBotAgent.d.ts +68 -0
  67. package/dist/prefabs/FAQBotAgent.js +206 -0
  68. package/dist/prefabs/FAQBotAgent.js.map +1 -0
  69. package/dist/prefabs/InfoGathererAgent.d.ts +73 -0
  70. package/dist/prefabs/InfoGathererAgent.js +202 -0
  71. package/dist/prefabs/InfoGathererAgent.js.map +1 -0
  72. package/dist/prefabs/ReceptionistAgent.d.ts +65 -0
  73. package/dist/prefabs/ReceptionistAgent.js +205 -0
  74. package/dist/prefabs/ReceptionistAgent.js.map +1 -0
  75. package/dist/prefabs/SurveyAgent.d.ts +84 -0
  76. package/dist/prefabs/SurveyAgent.js +324 -0
  77. package/dist/prefabs/SurveyAgent.js.map +1 -0
  78. package/dist/prefabs/index.d.ts +13 -0
  79. package/dist/prefabs/index.js +14 -0
  80. package/dist/prefabs/index.js.map +1 -0
  81. package/dist/skills/SkillBase.d.ts +134 -0
  82. package/dist/skills/SkillBase.js +105 -0
  83. package/dist/skills/SkillBase.js.map +1 -0
  84. package/dist/skills/SkillManager.d.ts +83 -0
  85. package/dist/skills/SkillManager.js +159 -0
  86. package/dist/skills/SkillManager.js.map +1 -0
  87. package/dist/skills/SkillRegistry.d.ts +105 -0
  88. package/dist/skills/SkillRegistry.js +195 -0
  89. package/dist/skills/SkillRegistry.js.map +1 -0
  90. package/dist/skills/builtin/api_ninjas_trivia.d.ts +35 -0
  91. package/dist/skills/builtin/api_ninjas_trivia.js +161 -0
  92. package/dist/skills/builtin/api_ninjas_trivia.js.map +1 -0
  93. package/dist/skills/builtin/claude_skills.d.ts +34 -0
  94. package/dist/skills/builtin/claude_skills.js +156 -0
  95. package/dist/skills/builtin/claude_skills.js.map +1 -0
  96. package/dist/skills/builtin/custom_skills.d.ts +59 -0
  97. package/dist/skills/builtin/custom_skills.js +231 -0
  98. package/dist/skills/builtin/custom_skills.js.map +1 -0
  99. package/dist/skills/builtin/datasphere.d.ts +34 -0
  100. package/dist/skills/builtin/datasphere.js +163 -0
  101. package/dist/skills/builtin/datasphere.js.map +1 -0
  102. package/dist/skills/builtin/datasphere_serverless.d.ts +54 -0
  103. package/dist/skills/builtin/datasphere_serverless.js +155 -0
  104. package/dist/skills/builtin/datasphere_serverless.js.map +1 -0
  105. package/dist/skills/builtin/datetime.d.ts +31 -0
  106. package/dist/skills/builtin/datetime.js +95 -0
  107. package/dist/skills/builtin/datetime.js.map +1 -0
  108. package/dist/skills/builtin/google_maps.d.ts +33 -0
  109. package/dist/skills/builtin/google_maps.js +233 -0
  110. package/dist/skills/builtin/google_maps.js.map +1 -0
  111. package/dist/skills/builtin/index.d.ts +28 -0
  112. package/dist/skills/builtin/index.js +75 -0
  113. package/dist/skills/builtin/index.js.map +1 -0
  114. package/dist/skills/builtin/info_gatherer.d.ts +52 -0
  115. package/dist/skills/builtin/info_gatherer.js +237 -0
  116. package/dist/skills/builtin/info_gatherer.js.map +1 -0
  117. package/dist/skills/builtin/joke.d.ts +32 -0
  118. package/dist/skills/builtin/joke.js +142 -0
  119. package/dist/skills/builtin/joke.js.map +1 -0
  120. package/dist/skills/builtin/math.d.ts +33 -0
  121. package/dist/skills/builtin/math.js +120 -0
  122. package/dist/skills/builtin/math.js.map +1 -0
  123. package/dist/skills/builtin/mcp_gateway.d.ts +35 -0
  124. package/dist/skills/builtin/mcp_gateway.js +85 -0
  125. package/dist/skills/builtin/mcp_gateway.js.map +1 -0
  126. package/dist/skills/builtin/native_vector_search.d.ts +44 -0
  127. package/dist/skills/builtin/native_vector_search.js +248 -0
  128. package/dist/skills/builtin/native_vector_search.js.map +1 -0
  129. package/dist/skills/builtin/play_background_file.d.ts +34 -0
  130. package/dist/skills/builtin/play_background_file.js +135 -0
  131. package/dist/skills/builtin/play_background_file.js.map +1 -0
  132. package/dist/skills/builtin/spider.d.ts +34 -0
  133. package/dist/skills/builtin/spider.js +164 -0
  134. package/dist/skills/builtin/spider.js.map +1 -0
  135. package/dist/skills/builtin/swml_transfer.d.ts +44 -0
  136. package/dist/skills/builtin/swml_transfer.js +204 -0
  137. package/dist/skills/builtin/swml_transfer.js.map +1 -0
  138. package/dist/skills/builtin/weather_api.d.ts +34 -0
  139. package/dist/skills/builtin/weather_api.js +136 -0
  140. package/dist/skills/builtin/weather_api.js.map +1 -0
  141. package/dist/skills/builtin/web_search.d.ts +34 -0
  142. package/dist/skills/builtin/web_search.js +141 -0
  143. package/dist/skills/builtin/web_search.js.map +1 -0
  144. package/dist/skills/builtin/wikipedia_search.d.ts +34 -0
  145. package/dist/skills/builtin/wikipedia_search.js +166 -0
  146. package/dist/skills/builtin/wikipedia_search.js.map +1 -0
  147. package/dist/skills/index.d.ts +11 -0
  148. package/dist/skills/index.js +10 -0
  149. package/dist/skills/index.js.map +1 -0
  150. package/dist/types.d.ts +85 -0
  151. package/dist/types.js +5 -0
  152. package/dist/types.js.map +1 -0
  153. package/docs/agent-guide.md +869 -0
  154. package/docs/api-reference.md +2419 -0
  155. package/docs/architecture.md +843 -0
  156. package/docs/cli-guide.md +579 -0
  157. package/docs/configuration.md +422 -0
  158. package/docs/contexts-guide.md +787 -0
  159. package/docs/datamap-guide.md +1141 -0
  160. package/docs/prefabs-guide.md +830 -0
  161. package/docs/security.md +436 -0
  162. package/docs/serverless-guide.md +513 -0
  163. package/docs/skills-guide.md +845 -0
  164. package/docs/swaig-reference.md +1627 -0
  165. package/examples/call-flow.ts +60 -0
  166. package/examples/contexts-steps.ts +62 -0
  167. package/examples/datamap-tools.ts +52 -0
  168. package/examples/dynamic-config.ts +51 -0
  169. package/examples/multi-agent.ts +67 -0
  170. package/examples/pom-prompt.ts +68 -0
  171. package/examples/simple-agent.ts +33 -0
  172. package/package.json +35 -0
  173. package/src/AgentBase.ts +1279 -0
  174. package/src/AgentServer.ts +149 -0
  175. package/src/AuthHandler.ts +141 -0
  176. package/src/ConfigLoader.ts +165 -0
  177. package/src/ContextBuilder.ts +796 -0
  178. package/src/DataMap.ts +365 -0
  179. package/src/Logger.ts +197 -0
  180. package/src/PomBuilder.ts +298 -0
  181. package/src/PromptManager.ts +133 -0
  182. package/src/SchemaUtils.ts +170 -0
  183. package/src/ServerlessAdapter.ts +218 -0
  184. package/src/SessionManager.ts +161 -0
  185. package/src/SslConfig.ts +118 -0
  186. package/src/SwaigFunction.ts +168 -0
  187. package/src/SwaigFunctionResult.ts +864 -0
  188. package/src/SwmlBuilder.ts +62 -0
  189. package/src/cli/agent-loader.ts +122 -0
  190. package/src/cli/mock-data.ts +110 -0
  191. package/src/cli/swaig-test.ts +440 -0
  192. package/src/index.ts +99 -0
  193. package/src/prefabs/ConciergeAgent.ts +251 -0
  194. package/src/prefabs/FAQBotAgent.ts +263 -0
  195. package/src/prefabs/InfoGathererAgent.ts +276 -0
  196. package/src/prefabs/ReceptionistAgent.ts +277 -0
  197. package/src/prefabs/SurveyAgent.ts +413 -0
  198. package/src/prefabs/index.ts +23 -0
  199. package/src/skills/SkillBase.ts +184 -0
  200. package/src/skills/SkillManager.ts +177 -0
  201. package/src/skills/SkillRegistry.ts +231 -0
  202. package/src/skills/builtin/api_ninjas_trivia.ts +230 -0
  203. package/src/skills/builtin/claude_skills.ts +239 -0
  204. package/src/skills/builtin/custom_skills.ts +326 -0
  205. package/src/skills/builtin/datasphere.ts +225 -0
  206. package/src/skills/builtin/datasphere_serverless.ts +194 -0
  207. package/src/skills/builtin/datetime.ts +115 -0
  208. package/src/skills/builtin/google_maps.ts +347 -0
  209. package/src/skills/builtin/index.ts +79 -0
  210. package/src/skills/builtin/info_gatherer.ts +331 -0
  211. package/src/skills/builtin/joke.ts +180 -0
  212. package/src/skills/builtin/math.ts +150 -0
  213. package/src/skills/builtin/mcp_gateway.ts +99 -0
  214. package/src/skills/builtin/native_vector_search.ts +327 -0
  215. package/src/skills/builtin/play_background_file.ts +189 -0
  216. package/src/skills/builtin/spider.ts +232 -0
  217. package/src/skills/builtin/swml_transfer.ts +285 -0
  218. package/src/skills/builtin/weather_api.ts +193 -0
  219. package/src/skills/builtin/web_search.ts +212 -0
  220. package/src/skills/builtin/wikipedia_search.ts +248 -0
  221. package/src/skills/index.ts +12 -0
  222. package/src/types.ts +99 -0
  223. package/tests/AgentBase.test.ts +693 -0
  224. package/tests/AgentServer.test.ts +102 -0
  225. package/tests/AuthHandler.test.ts +121 -0
  226. package/tests/ConfigLoader.test.ts +121 -0
  227. package/tests/DataMap.test.ts +286 -0
  228. package/tests/Logger.test.ts +218 -0
  229. package/tests/PomBuilder.test.ts +164 -0
  230. package/tests/ProxyDetection.test.ts +185 -0
  231. package/tests/SchemaUtils.test.ts +106 -0
  232. package/tests/ServerlessAdapter.test.ts +200 -0
  233. package/tests/SessionManager.test.ts +139 -0
  234. package/tests/SslConfig.test.ts +97 -0
  235. package/tests/SwaigFunctionResult.test.ts +298 -0
  236. package/tests/cli/mock-data.test.ts +94 -0
  237. package/tests/cli/swaig-test.test.ts +96 -0
  238. package/tests/prefabs/prefabs.test.ts +854 -0
  239. package/tests/setup.ts +6 -0
  240. package/tests/skills/SkillBase.test.ts +118 -0
  241. package/tests/skills/SkillManager.test.ts +164 -0
  242. package/tests/skills/SkillRegistry.test.ts +124 -0
  243. package/tests/skills/builtin.test.ts +924 -0
  244. package/tsconfig.json +18 -0
  245. package/vitest.config.ts +9 -0
@@ -0,0 +1,869 @@
1
+ # SignalWire AI Agents TypeScript SDK -- Agent Guide
2
+
3
+ ## Table of Contents
4
+
5
+ - [Introduction](#introduction)
6
+ - [Creating an Agent](#creating-an-agent)
7
+ - [Prompts](#prompts)
8
+ - [Raw Text Prompts](#raw-text-prompts)
9
+ - [Prompt Object Model (POM)](#prompt-object-model-pom)
10
+ - [Declarative PROMPT_SECTIONS](#declarative-prompt_sections)
11
+ - [Tools (SWAIG Functions)](#tools-swaig-functions)
12
+ - [Defining Tools](#defining-tools)
13
+ - [Tool Parameters](#tool-parameters)
14
+ - [Secure Tools](#secure-tools)
15
+ - [SwaigFunctionResult](#swaigfunctionresult)
16
+ - [DataMap (Server-Side Tools)](#datamap-server-side-tools)
17
+ - [Speech and Languages](#speech-and-languages)
18
+ - [Hints](#hints)
19
+ - [Languages](#languages)
20
+ - [Pronunciation](#pronunciation)
21
+ - [AI Parameters](#ai-parameters)
22
+ - [Global Data](#global-data)
23
+ - [Call Flow (5 Phases)](#call-flow-5-phases)
24
+ - [Dynamic Configuration](#dynamic-configuration)
25
+ - [Post-Prompt and Summaries](#post-prompt-and-summaries)
26
+ - [Multi-Agent Server](#multi-agent-server)
27
+ - [Subclassing AgentBase](#subclassing-agentbase)
28
+ - [HTTP Endpoints](#http-endpoints)
29
+ - [Environment Variables](#environment-variables)
30
+
31
+ ---
32
+
33
+ ## Introduction
34
+
35
+ The SignalWire AI Agents TypeScript SDK lets you build AI-powered voice agents as HTTP microservices. Each agent is a lightweight HTTP server built on the [Hono](https://hono.dev/) framework that serves **SWML** (SignalWire Markup Language) documents and handles **SWAIG** (SignalWire AI Gateway) function callbacks.
36
+
37
+ When SignalWire receives an inbound call (or an outbound call is placed), it requests a SWML document from your agent's HTTP endpoint. The SWML document describes the entire call flow: answering, playing audio, launching the AI engine with a prompt, registering tools the AI can invoke, and handling post-call summaries. The agent SDK automates all of this -- you configure the prompt, define tools, and the SDK handles SWML rendering, webhook routing, authentication, and session management.
38
+
39
+ ```
40
+ Caller --> SignalWire Platform --> GET/POST your-agent/ --> SWML document
41
+ POST your-agent/swaig --> tool execution
42
+ POST your-agent/post_prompt --> call summary
43
+ ```
44
+
45
+ ### Installation
46
+
47
+ ```bash
48
+ npm install signalwire-ai-agents
49
+ ```
50
+
51
+ ### Quick Start
52
+
53
+ ```typescript
54
+ import { AgentBase, SwaigFunctionResult } from 'signalwire-ai-agents';
55
+
56
+ const agent = new AgentBase({ name: 'my-agent' });
57
+
58
+ agent.setPromptText('You are a helpful customer service agent for Acme Corp.');
59
+
60
+ agent.defineTool({
61
+ name: 'check_order_status',
62
+ description: 'Look up the status of a customer order by order number.',
63
+ parameters: {
64
+ order_id: { type: 'string', description: 'The order number to look up' },
65
+ },
66
+ handler: async (args) => {
67
+ const status = await lookupOrder(args.order_id as string);
68
+ return new SwaigFunctionResult(`Order ${args.order_id} is ${status}.`);
69
+ },
70
+ });
71
+
72
+ agent.serve();
73
+ ```
74
+
75
+ ---
76
+
77
+ ## Creating an Agent
78
+
79
+ The `AgentBase` constructor accepts an `AgentOptions` object:
80
+
81
+ ```typescript
82
+ const agent = new AgentBase({
83
+ name: 'support-bot',
84
+ route: '/',
85
+ host: '0.0.0.0',
86
+ port: 3000,
87
+ basicAuth: ['admin', 's3cretP@ss'],
88
+ usePom: true,
89
+ tokenExpirySecs: 3600,
90
+ autoAnswer: true,
91
+ recordCall: false,
92
+ recordFormat: 'mp4',
93
+ recordStereo: true,
94
+ nativeFunctions: [],
95
+ suppressLogs: false,
96
+ });
97
+ ```
98
+
99
+ ### AgentOptions Reference
100
+
101
+ | Option | Type | Default | Description |
102
+ |--------|------|---------|-------------|
103
+ | `name` | `string` | **(required)** | Display name; also used as the default basic-auth username when credentials are auto-generated. |
104
+ | `route` | `string` | `"/"` | HTTP route path this agent listens on. |
105
+ | `host` | `string` | `"0.0.0.0"` | Hostname the server binds to. |
106
+ | `port` | `number` | `PORT` env or `3000` | Port number for the HTTP server. |
107
+ | `basicAuth` | `[string, string]` | auto-generated | Explicit `[username, password]` pair; if omitted, reads from env vars or generates random credentials. |
108
+ | `usePom` | `boolean` | `true` | Use Prompt Object Model for structured prompts. |
109
+ | `tokenExpirySecs` | `number` | `3600` | Session token validity in seconds for secure tools. |
110
+ | `autoAnswer` | `boolean` | `true` | Automatically insert an `answer` verb in the SWML call flow. |
111
+ | `recordCall` | `boolean` | `false` | Whether to record the call. |
112
+ | `recordFormat` | `string` | `"mp4"` | Recording format (e.g., `"mp4"`, `"wav"`). |
113
+ | `recordStereo` | `boolean` | `true` | Whether to record in stereo. |
114
+ | `defaultWebhookUrl` | `string` | `null` | Override the default SWAIG function webhook URL. |
115
+ | `nativeFunctions` | `string[]` | `[]` | List of built-in platform function names to include. |
116
+ | `agentId` | `string` | random hex | Unique identifier for this agent instance. |
117
+ | `suppressLogs` | `boolean` | `false` | Suppress all log output. |
118
+
119
+ ### Basic Auth
120
+
121
+ Authentication credentials are resolved in this order:
122
+
123
+ 1. **Provided** -- `basicAuth` option in the constructor.
124
+ 2. **Environment** -- `SWML_BASIC_AUTH_USER` and `SWML_BASIC_AUTH_PASSWORD` environment variables.
125
+ 3. **Generated** -- A random password is generated, using the agent name as the username. Credentials are logged at startup so you can retrieve them.
126
+
127
+ ### Starting the Server
128
+
129
+ ```typescript
130
+ // Start listening
131
+ await agent.serve();
132
+ // or equivalently:
133
+ await agent.run();
134
+ ```
135
+
136
+ The server logs its address and auth credentials at startup:
137
+
138
+ ```
139
+ Agent 'support-bot' running at http://0.0.0.0:3000/
140
+ Auth: support-bot:**** (source: generated)
141
+ ```
142
+
143
+ ---
144
+
145
+ ## Prompts
146
+
147
+ The SDK provides two ways to define the system prompt sent to the AI: **raw text** and the **Prompt Object Model (POM)**.
148
+
149
+ ### Raw Text Prompts
150
+
151
+ The simplest approach -- pass a complete prompt string:
152
+
153
+ ```typescript
154
+ agent.setPromptText(`
155
+ You are a friendly receptionist for Dr. Smith's office.
156
+ You help patients schedule appointments and answer basic questions.
157
+ Always be polite and professional.
158
+ `);
159
+ ```
160
+
161
+ When raw text is set, it is used verbatim as the AI's system prompt. This bypasses POM rendering.
162
+
163
+ ### Prompt Object Model (POM)
164
+
165
+ POM allows you to build structured prompts from titled sections, body text, bullet points, and nested subsections. The SDK renders them as Markdown headings and lists. POM is enabled by default (`usePom: true`).
166
+
167
+ #### Adding Sections
168
+
169
+ ```typescript
170
+ agent.promptAddSection('Personality', {
171
+ body: 'You are a cheerful and knowledgeable tech support agent.',
172
+ bullets: [
173
+ 'Always greet the customer warmly',
174
+ 'Ask clarifying questions before troubleshooting',
175
+ 'Offer to escalate if you cannot resolve the issue',
176
+ ],
177
+ });
178
+ ```
179
+
180
+ #### Appending to Existing Sections
181
+
182
+ ```typescript
183
+ agent.promptAddToSection('Personality', {
184
+ bullet: 'Never make promises about timelines',
185
+ });
186
+
187
+ agent.promptAddToSection('Personality', {
188
+ bullets: ['Speak in simple, non-technical language', 'Confirm understanding before proceeding'],
189
+ });
190
+
191
+ agent.promptAddToSection('Personality', {
192
+ body: 'Remember to always thank the customer at the end of the call.',
193
+ });
194
+ ```
195
+
196
+ #### Subsections
197
+
198
+ ```typescript
199
+ agent.promptAddSubsection('Personality', 'Tone', {
200
+ body: 'Maintain a warm but professional tone throughout the conversation.',
201
+ bullets: ['Avoid slang', 'Do not use jargon'],
202
+ });
203
+ ```
204
+
205
+ #### Checking for Sections
206
+
207
+ ```typescript
208
+ if (!agent.promptHasSection('Escalation')) {
209
+ agent.promptAddSection('Escalation', {
210
+ body: 'If the issue cannot be resolved, transfer to a human agent.',
211
+ });
212
+ }
213
+ ```
214
+
215
+ #### Numbered Sections and Bullets
216
+
217
+ ```typescript
218
+ agent.promptAddSection('Troubleshooting Steps', {
219
+ numbered: true,
220
+ numberedBullets: true,
221
+ bullets: [
222
+ 'Ask the customer to restart the device',
223
+ 'Check if the firmware is up to date',
224
+ 'Try a factory reset',
225
+ ],
226
+ });
227
+ ```
228
+
229
+ #### Retrieving the Rendered Prompt
230
+
231
+ ```typescript
232
+ const renderedPrompt: string = agent.getPrompt();
233
+ ```
234
+
235
+ ### Declarative PROMPT_SECTIONS
236
+
237
+ When subclassing `AgentBase`, you can define prompt sections declaratively as a static property. They are automatically applied in the constructor:
238
+
239
+ ```typescript
240
+ class SupportAgent extends AgentBase {
241
+ static PROMPT_SECTIONS = [
242
+ {
243
+ title: 'Role',
244
+ body: 'You are a technical support agent for CloudCo.',
245
+ },
246
+ {
247
+ title: 'Guidelines',
248
+ bullets: [
249
+ 'Be concise and helpful',
250
+ 'Verify the customer identity before sharing account details',
251
+ ],
252
+ },
253
+ ];
254
+
255
+ constructor() {
256
+ super({ name: 'support-agent' });
257
+ this.defineTools();
258
+ }
259
+ }
260
+ ```
261
+
262
+ ---
263
+
264
+ ## Tools (SWAIG Functions)
265
+
266
+ Tools (also called SWAIG functions) are actions the AI can invoke during a conversation. When the AI decides to call a tool, SignalWire sends a POST request to your agent's `/swaig` endpoint with the function name and arguments.
267
+
268
+ ### Defining Tools
269
+
270
+ Use `defineTool()` to register a tool:
271
+
272
+ ```typescript
273
+ agent.defineTool({
274
+ name: 'get_weather',
275
+ description: 'Get the current weather for a city.',
276
+ parameters: {
277
+ city: { type: 'string', description: 'City name' },
278
+ units: { type: 'string', description: 'Temperature units', enum: ['celsius', 'fahrenheit'] },
279
+ },
280
+ required: ['city'],
281
+ handler: async (args, rawData) => {
282
+ const weather = await fetchWeather(args.city as string, args.units as string);
283
+ return new SwaigFunctionResult(`The weather in ${args.city} is ${weather.temp} degrees and ${weather.condition}.`);
284
+ },
285
+ });
286
+ ```
287
+
288
+ The `handler` function receives two arguments:
289
+
290
+ | Argument | Type | Description |
291
+ |----------|------|-------------|
292
+ | `args` | `Record<string, unknown>` | Parsed arguments extracted by the AI from the user's speech. |
293
+ | `rawData` | `Record<string, unknown>` | The full raw SWAIG request payload from SignalWire. |
294
+
295
+ The handler can return:
296
+
297
+ - A `SwaigFunctionResult` instance (recommended)
298
+ - A plain object with a `response` key
299
+ - A plain string (wrapped automatically)
300
+
301
+ ### Tool Parameters
302
+
303
+ Parameters follow JSON Schema conventions. You can provide them in shorthand (just the properties) or full schema format:
304
+
305
+ ```typescript
306
+ // Shorthand -- properties only, SDK wraps in { type: 'object', properties: ... }
307
+ parameters: {
308
+ name: { type: 'string', description: 'Customer name' },
309
+ email: { type: 'string', description: 'Email address' },
310
+ }
311
+
312
+ // Full schema
313
+ parameters: {
314
+ type: 'object',
315
+ properties: {
316
+ name: { type: 'string', description: 'Customer name' },
317
+ email: { type: 'string', description: 'Email address' },
318
+ },
319
+ required: ['name'],
320
+ }
321
+ ```
322
+
323
+ ### Secure Tools
324
+
325
+ Secure tools require a valid HMAC session token for each invocation. The token is bound to the call ID and function name, preventing replay attacks:
326
+
327
+ ```typescript
328
+ agent.defineTool({
329
+ name: 'transfer_funds',
330
+ description: 'Transfer money between accounts.',
331
+ secure: true,
332
+ parameters: {
333
+ amount: { type: 'number', description: 'Amount to transfer' },
334
+ to_account: { type: 'string', description: 'Destination account ID' },
335
+ },
336
+ handler: async (args) => {
337
+ // This handler only executes if the token is valid
338
+ await doTransfer(args.amount as number, args.to_account as string);
339
+ return new SwaigFunctionResult('Transfer completed successfully.');
340
+ },
341
+ });
342
+ ```
343
+
344
+ When `secure: true` is set, the SWML document includes a `__token` query parameter in the tool's webhook URL. On each `/swaig` request, the SDK validates the token's HMAC signature, call ID binding, and expiry before executing the handler.
345
+
346
+ ### SwaigFunctionResult
347
+
348
+ `SwaigFunctionResult` is a fluent builder for tool responses. It carries response text and an ordered list of actions:
349
+
350
+ ```typescript
351
+ import { SwaigFunctionResult } from 'signalwire-ai-agents';
352
+
353
+ // Simple text response
354
+ const result = new SwaigFunctionResult('The order has been placed.');
355
+
356
+ // Response with actions
357
+ const result = new SwaigFunctionResult('Transferring you now.')
358
+ .connect('+15551234567') // Transfer the call
359
+ .hangup(); // Then hang up
360
+
361
+ // Update global data from within a tool
362
+ const result = new SwaigFunctionResult('Account verified.')
363
+ .updateGlobalData({ verified: true, customer_id: '12345' });
364
+
365
+ // Context switch
366
+ const result = new SwaigFunctionResult('Let me transfer you to billing.')
367
+ .switchContext({ systemPrompt: 'You are now a billing specialist.' });
368
+ ```
369
+
370
+ Key `SwaigFunctionResult` methods:
371
+
372
+ | Method | Description |
373
+ |--------|-------------|
374
+ | `setResponse(text)` | Set the response text. |
375
+ | `connect(destination, final?, from?)` | Transfer the call to a destination. |
376
+ | `hangup()` | Hang up the call. |
377
+ | `hold(timeout?)` | Place the call on hold (0-900 seconds). |
378
+ | `say(text)` | Speak text via TTS. |
379
+ | `stop()` | Stop the AI session. |
380
+ | `updateGlobalData(data)` | Merge data into the shared global store. |
381
+ | `setMetadata(data)` | Set call metadata. |
382
+ | `switchContext(opts)` | Switch the AI context with optional prompt changes. |
383
+ | `toggleFunctions(toggles)` | Enable/disable specific SWAIG functions. |
384
+ | `sendSms(opts)` | Send an SMS or MMS. |
385
+ | `playBackgroundFile(url, wait?)` | Play background audio. |
386
+ | `waitForUser(opts?)` | Wait for user input before continuing. |
387
+ | `addDynamicHints(hints)` | Add speech recognition hints at runtime. |
388
+ | `executeSwml(swml, transfer?)` | Execute arbitrary SWML content. |
389
+ | `pay(opts)` | Initiate a payment collection flow. |
390
+
391
+ Serialization fallback: if both `response` and `action` are empty, `toDict()` returns `{ response: "Action completed." }`.
392
+
393
+ ### DataMap (Server-Side Tools)
394
+
395
+ DataMap tools execute entirely on the SignalWire platform without requiring a webhook. They are useful for simple API calls and pattern-matching:
396
+
397
+ ```typescript
398
+ import { DataMap, SwaigFunctionResult } from 'signalwire-ai-agents';
399
+
400
+ const weatherTool = new DataMap('get_weather')
401
+ .purpose('Look up weather for a city')
402
+ .parameter('city', 'string', 'City name', { required: true })
403
+ .webhook('GET', 'https://api.weather.com/v1/current?q=${args.city}', {
404
+ headers: { 'Authorization': 'Bearer ${ENV.WEATHER_API_KEY}' },
405
+ })
406
+ .output(new SwaigFunctionResult('The weather is ${temp}F and ${condition}.'))
407
+ .enableEnvExpansion();
408
+
409
+ weatherTool.registerWithAgent(agent);
410
+ ```
411
+
412
+ Convenience helpers:
413
+
414
+ ```typescript
415
+ import { createSimpleApiTool, createExpressionTool } from 'signalwire-ai-agents';
416
+
417
+ const tool = createSimpleApiTool({
418
+ name: 'joke',
419
+ url: 'https://api.example.com/joke',
420
+ responseTemplate: 'Here is a joke: ${joke}',
421
+ });
422
+ tool.registerWithAgent(agent);
423
+ ```
424
+
425
+ ---
426
+
427
+ ## Speech and Languages
428
+
429
+ ### Hints
430
+
431
+ Speech recognition hints improve transcription accuracy for domain-specific vocabulary:
432
+
433
+ ```typescript
434
+ // Single hint
435
+ agent.addHint('SignalWire');
436
+
437
+ // Multiple hints
438
+ agent.addHints(['HIPAA', 'deductible', 'copay', 'pre-authorization']);
439
+
440
+ // Pattern hint (find and replace in transcription)
441
+ agent.addPatternHint({
442
+ pattern: 'signal wire',
443
+ replace: 'SignalWire',
444
+ ignoreCase: true,
445
+ });
446
+ ```
447
+
448
+ ### Languages
449
+
450
+ Configure supported languages with voice and filler phrases:
451
+
452
+ ```typescript
453
+ agent.addLanguage({
454
+ name: 'English',
455
+ code: 'en-US',
456
+ voice: 'en-US-Neural2-F',
457
+ engine: 'google',
458
+ speechModel: 'enhanced',
459
+ fillers: { thinking: ['Let me check on that...', 'One moment please...'] },
460
+ functionFillers: { get_weather: { 'en-US': ['Checking the forecast...'] } },
461
+ });
462
+
463
+ agent.addLanguage({
464
+ name: 'Spanish',
465
+ code: 'es-MX',
466
+ voice: 'es-MX-Neural2-A',
467
+ });
468
+ ```
469
+
470
+ Replace all languages at once:
471
+
472
+ ```typescript
473
+ agent.setLanguages([
474
+ { name: 'English', code: 'en-US', voice: 'en-US-Neural2-F' },
475
+ { name: 'French', code: 'fr-FR', voice: 'fr-FR-Neural2-A' },
476
+ ]);
477
+ ```
478
+
479
+ ### Pronunciation
480
+
481
+ Override how the TTS engine pronounces specific words:
482
+
483
+ ```typescript
484
+ agent.addPronunciation({
485
+ replace: 'SQL',
486
+ with: 'sequel',
487
+ ignoreCase: true,
488
+ });
489
+
490
+ agent.addPronunciation({
491
+ replace: 'API',
492
+ with: 'A P I',
493
+ });
494
+ ```
495
+
496
+ ---
497
+
498
+ ## AI Parameters
499
+
500
+ Control the AI model's behavior with parameters like temperature and top_p:
501
+
502
+ ```typescript
503
+ // Set a single parameter
504
+ agent.setParam('temperature', 0.7);
505
+ agent.setParam('top_p', 0.9);
506
+
507
+ // Set multiple parameters at once
508
+ agent.setParams({
509
+ temperature: 0.3,
510
+ top_p: 0.85,
511
+ confidence: 0.5,
512
+ barge_confidence: 0.3,
513
+ presence_penalty: 0.2,
514
+ frequency_penalty: 0.5,
515
+ });
516
+ ```
517
+
518
+ ### Prompt-Specific LLM Parameters
519
+
520
+ Set LLM parameters that apply specifically to the main prompt or post-prompt:
521
+
522
+ ```typescript
523
+ // Main prompt LLM params (e.g., model selection, temperature override)
524
+ agent.setPromptLlmParams({
525
+ model: 'gpt-4',
526
+ temperature: 0.2,
527
+ });
528
+
529
+ // Post-prompt LLM params
530
+ agent.setPostPromptLlmParams({
531
+ model: 'gpt-3.5-turbo',
532
+ temperature: 0.1,
533
+ });
534
+ ```
535
+
536
+ ---
537
+
538
+ ## Global Data
539
+
540
+ Global data is a key-value store shared across all tool invocations within a call. Tools can read from it and update it:
541
+
542
+ ```typescript
543
+ // Replace the entire global data object
544
+ agent.setGlobalData({
545
+ company: 'Acme Corp',
546
+ support_hours: '9am-5pm EST',
547
+ max_refund: 500,
548
+ });
549
+
550
+ // Merge additional entries into existing global data
551
+ agent.updateGlobalData({
552
+ promo_code: 'SUMMER2025',
553
+ });
554
+ ```
555
+
556
+ Within a tool handler, you can update global data dynamically:
557
+
558
+ ```typescript
559
+ handler: async (args) => {
560
+ return new SwaigFunctionResult('Customer verified.')
561
+ .updateGlobalData({ customer_verified: true, customer_name: args.name });
562
+ }
563
+ ```
564
+
565
+ ---
566
+
567
+ ## Call Flow (5 Phases)
568
+
569
+ The SWML document is assembled from five sequential phases. Each phase adds verbs to the document's `main` section:
570
+
571
+ | Phase | Method | Description |
572
+ |-------|--------|-------------|
573
+ | **1. Pre-Answer** | `addPreAnswerVerb(verb, config)` | Verbs executed before answering the call (e.g., playing a ring tone). |
574
+ | **2. Answer** | `addAnswerVerb(config?)` | The `answer` verb that picks up the call. Automatic when `autoAnswer: true`. |
575
+ | **3. Post-Answer** | `addPostAnswerVerb(verb, config)` | Verbs after answering but before the AI starts (e.g., `record_call`, `play`). |
576
+ | **4. AI** | *(automatic)* | The `ai` verb containing the prompt, tools, hints, languages, and all AI configuration. |
577
+ | **5. Post-AI** | `addPostAiVerb(verb, config)` | Verbs executed after the AI session ends (e.g., `hangup`, `connect`). |
578
+
579
+ ### Example
580
+
581
+ ```typescript
582
+ const agent = new AgentBase({ name: 'ivr-bot', autoAnswer: true, recordCall: true });
583
+
584
+ // Phase 1: Play hold music before answering
585
+ agent.addPreAnswerVerb('play', {
586
+ url: 'https://cdn.example.com/hold-music.mp3',
587
+ });
588
+
589
+ // Phase 3: Play a greeting after answering, before AI starts
590
+ agent.addPostAnswerVerb('play', {
591
+ url: 'https://cdn.example.com/greeting.wav',
592
+ });
593
+
594
+ // Phase 5: Hang up after the AI session ends
595
+ agent.addPostAiVerb('hangup', {});
596
+ ```
597
+
598
+ Note: When `recordCall: true`, a `record_call` verb is automatically inserted at the start of Phase 3.
599
+
600
+ ### Clearing Verbs
601
+
602
+ ```typescript
603
+ agent.clearPreAnswerVerbs();
604
+ agent.clearPostAnswerVerbs();
605
+ agent.clearPostAiVerbs();
606
+ ```
607
+
608
+ ---
609
+
610
+ ## Dynamic Configuration
611
+
612
+ Dynamic configuration lets you modify the agent's settings per-request. On each SWML request, the SDK creates an **ephemeral copy** of the agent, passes it to your callback, and renders SWML from the modified copy. The original agent is never mutated.
613
+
614
+ ```typescript
615
+ agent.setDynamicConfigCallback(async (queryParams, bodyParams, headers, ephemeralAgent) => {
616
+ const agent = ephemeralAgent as AgentBase;
617
+
618
+ // Customize based on query parameters
619
+ const lang = queryParams['lang'];
620
+ if (lang === 'es') {
621
+ agent.setPromptText('Eres un asistente de servicio al cliente amable.');
622
+ agent.addLanguage({ name: 'Spanish', code: 'es-MX', voice: 'es-MX-Neural2-A' });
623
+ }
624
+
625
+ // Customize based on request headers
626
+ const tier = headers['x-customer-tier'];
627
+ if (tier === 'premium') {
628
+ agent.updateGlobalData({ premium: true, max_refund: 1000 });
629
+ }
630
+
631
+ // Customize based on body data
632
+ const callerId = bodyParams['caller_id_number'] as string;
633
+ if (callerId) {
634
+ const customer = await lookupCustomer(callerId);
635
+ agent.updateGlobalData({ customer_name: customer.name });
636
+ }
637
+ });
638
+ ```
639
+
640
+ The callback signature:
641
+
642
+ ```typescript
643
+ type DynamicConfigCallback = (
644
+ queryParams: Record<string, string>, // URL query parameters
645
+ bodyParams: Record<string, unknown>, // Parsed request body
646
+ headers: Record<string, string>, // HTTP headers
647
+ agent: unknown, // Ephemeral AgentBase copy (cast as needed)
648
+ ) => void | Promise<void>;
649
+ ```
650
+
651
+ ### SWAIG Query Parameters
652
+
653
+ Append custom query parameters to all SWAIG webhook URLs:
654
+
655
+ ```typescript
656
+ agent.addSwaigQueryParams({ tenant: 'acme', region: 'us-east' });
657
+ ```
658
+
659
+ ---
660
+
661
+ ## Post-Prompt and Summaries
662
+
663
+ The **post-prompt** is a separate prompt evaluated after the call ends. It is typically used to generate a structured summary of the conversation.
664
+
665
+ ### Setting the Post-Prompt
666
+
667
+ ```typescript
668
+ agent.setPostPrompt(`
669
+ Summarize this conversation as JSON with the following fields:
670
+ - "resolution": whether the issue was resolved (true/false)
671
+ - "category": the type of issue (billing, technical, general)
672
+ - "summary": a one-sentence summary of the call
673
+ `);
674
+ ```
675
+
676
+ ### Handling Summaries
677
+
678
+ Override the `onSummary` lifecycle hook to process the summary when it arrives:
679
+
680
+ ```typescript
681
+ class MyAgent extends AgentBase {
682
+ constructor() {
683
+ super({ name: 'my-agent' });
684
+ }
685
+
686
+ async onSummary(summary: Record<string, unknown> | null, rawData: Record<string, unknown>): Promise<void> {
687
+ if (summary) {
688
+ console.log('Call summary:', summary);
689
+ await saveToDatabase(summary);
690
+ }
691
+ }
692
+ }
693
+ ```
694
+
695
+ The SDK extracts the summary from the post-prompt payload by checking `body.summary`, then `body.post_prompt_data.parsed[0]`, then parsing `body.post_prompt_data.raw` as JSON.
696
+
697
+ ### Post-Prompt LLM Parameters
698
+
699
+ You can use a different (often cheaper/faster) model for the post-prompt evaluation:
700
+
701
+ ```typescript
702
+ agent.setPostPromptLlmParams({
703
+ model: 'gpt-3.5-turbo',
704
+ temperature: 0.0,
705
+ });
706
+ ```
707
+
708
+ ---
709
+
710
+ ## Multi-Agent Server
711
+
712
+ `AgentServer` hosts multiple `AgentBase` instances on a single HTTP server, each mounted at its own route prefix:
713
+
714
+ ```typescript
715
+ import { AgentBase, AgentServer } from 'signalwire-ai-agents';
716
+
717
+ const salesAgent = new AgentBase({ name: 'sales', route: '/sales' });
718
+ salesAgent.setPromptText('You are a sales representative.');
719
+
720
+ const supportAgent = new AgentBase({ name: 'support', route: '/support' });
721
+ supportAgent.setPromptText('You are a technical support agent.');
722
+
723
+ const server = new AgentServer({ host: '0.0.0.0', port: 4000 });
724
+ server.register(salesAgent);
725
+ server.register(supportAgent);
726
+
727
+ await server.run();
728
+ ```
729
+
730
+ ### AgentServer Features
731
+
732
+ - **Agent listing**: If no agent is mounted at `/`, a GET to `/` returns a JSON listing of all registered agents and their routes.
733
+ - **Health endpoints**: `/health` and `/ready` return `{ "status": "ok" }` and `{ "status": "ready" }` respectively.
734
+ - **Security headers**: `X-Content-Type-Options`, `X-Frame-Options`, `X-XSS-Protection`, and `Referrer-Policy` are set on all responses.
735
+ - **CORS**: Enabled globally with `origin: *`.
736
+
737
+ ### API
738
+
739
+ | Method | Description |
740
+ |--------|-------------|
741
+ | `register(agent, route?)` | Mount an agent at a route prefix. Throws if the route is already in use. |
742
+ | `unregister(route)` | Remove an agent registration. |
743
+ | `getAgents()` | Returns a `Map<string, AgentBase>` of all registered agents. |
744
+ | `getAgent(route)` | Look up an agent by route. |
745
+ | `getApp()` | Returns the underlying Hono application. |
746
+ | `run(host?, port?)` | Start the HTTP server. |
747
+
748
+ ---
749
+
750
+ ## Subclassing AgentBase
751
+
752
+ For reusable, self-contained agents, extend `AgentBase`:
753
+
754
+ ```typescript
755
+ import { AgentBase, SwaigFunctionResult } from 'signalwire-ai-agents';
756
+
757
+ class RestaurantBot extends AgentBase {
758
+ // Declarative prompt sections
759
+ static PROMPT_SECTIONS = [
760
+ {
761
+ title: 'Role',
762
+ body: 'You are a helpful restaurant reservation assistant for Bella Italia.',
763
+ },
764
+ {
765
+ title: 'Guidelines',
766
+ bullets: [
767
+ 'Be warm and inviting',
768
+ 'Always confirm the reservation details before finalizing',
769
+ 'Mention daily specials when relevant',
770
+ ],
771
+ },
772
+ ];
773
+
774
+ constructor() {
775
+ super({ name: 'restaurant-bot', route: '/restaurant' });
776
+
777
+ this.addHints(['Bella Italia', 'risotto', 'tiramisu']);
778
+ this.setParams({ temperature: 0.6 });
779
+
780
+ // Must be called explicitly at the end of the constructor
781
+ this.defineTools();
782
+ }
783
+
784
+ // Override to register tools
785
+ protected defineTools(): void {
786
+ this.defineTool({
787
+ name: 'make_reservation',
788
+ description: 'Create a restaurant reservation.',
789
+ parameters: {
790
+ date: { type: 'string', description: 'Reservation date (YYYY-MM-DD)' },
791
+ time: { type: 'string', description: 'Reservation time (HH:MM)' },
792
+ party_size: { type: 'number', description: 'Number of guests' },
793
+ name: { type: 'string', description: 'Name for the reservation' },
794
+ },
795
+ required: ['date', 'time', 'party_size', 'name'],
796
+ handler: async (args) => {
797
+ const id = await createReservation(args);
798
+ return new SwaigFunctionResult(
799
+ `Reservation confirmed for ${args.party_size} on ${args.date} at ${args.time}. ` +
800
+ `Confirmation number: ${id}.`
801
+ );
802
+ },
803
+ });
804
+ }
805
+
806
+ // Override the post-prompt summary hook
807
+ async onSummary(summary: Record<string, unknown> | null): Promise<void> {
808
+ if (summary) {
809
+ await logReservationSummary(summary);
810
+ }
811
+ }
812
+
813
+ // Override pre-execution hook for all tools
814
+ async onFunctionCall(name: string, args: Record<string, unknown>): Promise<void> {
815
+ console.log(`Tool invoked: ${name}`, args);
816
+ }
817
+
818
+ // Override basic auth validation
819
+ validateBasicAuth(username: string, password: string): boolean {
820
+ return username === 'admin' && password === process.env.ADMIN_PASSWORD!;
821
+ }
822
+ }
823
+ ```
824
+
825
+ ### Extension Points
826
+
827
+ | Method / Property | Purpose |
828
+ |-------------------|---------|
829
+ | `static PROMPT_SECTIONS` | Declarative prompt sections applied in the constructor. |
830
+ | `defineTools()` | Override to register tools. Call explicitly at the end of your constructor. |
831
+ | `onSummary(summary, rawData)` | Called when a post-prompt summary is received. |
832
+ | `onFunctionCall(name, args, rawData)` | Called before each tool handler executes. |
833
+ | `onSwmlRequest(rawData)` | Called on every SWML request before rendering. |
834
+ | `onDebugEvent(event)` | Called when a debug event webhook is received. |
835
+ | `validateBasicAuth(username, password)` | Override to add custom auth validation logic. |
836
+
837
+ ---
838
+
839
+ ## HTTP Endpoints
840
+
841
+ Each agent exposes the following HTTP endpoints (all relative to the agent's `route`):
842
+
843
+ | Method | Path | Auth | Description |
844
+ |--------|------|------|-------------|
845
+ | GET / POST | `/` | Basic Auth | Returns the rendered SWML document. Triggers proxy detection and dynamic config callback. |
846
+ | GET / POST | `/swaig` | Basic Auth | SWAIG function dispatcher. Receives `{ "function": "name", "argument": {...} }`, validates tokens for secure tools, calls `onFunctionCall`, executes the handler. |
847
+ | GET / POST | `/post_prompt` | Basic Auth | Receives post-prompt summary data. Extracts the summary and calls `onSummary`. |
848
+ | POST | `/debug_events` | Basic Auth | Receives debug event webhooks (when `enableDebugEvents()` is active). |
849
+ | GET | `/health` | None | Returns `{ "status": "ok" }`. |
850
+ | GET | `/ready` | None | Returns `{ "status": "ready" }`. |
851
+
852
+ ---
853
+
854
+ ## Environment Variables
855
+
856
+ | Variable | Default | Description |
857
+ |----------|---------|-------------|
858
+ | `PORT` | `3000` | HTTP server port (used when `port` is not specified in `AgentOptions`). |
859
+ | `SWML_BASIC_AUTH_USER` | *(none)* | Basic auth username. Used when `basicAuth` is not provided in options. |
860
+ | `SWML_BASIC_AUTH_PASSWORD` | *(none)* | Basic auth password. Used when `basicAuth` is not provided in options. |
861
+ | `SWML_PROXY_URL_BASE` | *(none)* | External-facing base URL for webhook URLs (e.g., `https://agents.example.com`). Takes highest priority for proxy detection. |
862
+ | `SWML_PROXY_DEBUG` | `"false"` | Set to `"true"` to enable verbose logging of proxy/header detection. |
863
+ | `SWML_CORS_ORIGINS` | `"*"` | Comma-separated list of allowed CORS origins. Defaults to allow all. |
864
+ | `SWML_ALLOWED_HOSTS` | *(none)* | Comma-separated list of allowed `Host` header values. Requests from other hosts receive 403. |
865
+ | `SWML_MAX_REQUEST_SIZE` | `1048576` | Maximum request body size in bytes (default 1 MB). Requests exceeding this receive 413. |
866
+ | `SWML_RATE_LIMIT` | *(none)* | Maximum requests per minute per IP address. When exceeded, requests receive 429. |
867
+ | `SWML_REQUEST_TIMEOUT` | `30000` | Request timeout in milliseconds. |
868
+ | `SIGNALWIRE_LOG_LEVEL` | `"info"` | Logging level: `"debug"`, `"info"`, `"warn"`, `"error"`. |
869
+ | `SIGNALWIRE_LOG_MODE` | `"pretty"` | Log output format: `"pretty"` for human-readable, `"json"` for structured JSON. |