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
package/CLAUDE.md ADDED
@@ -0,0 +1,112 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Build & Test Commands
6
+
7
+ ```bash
8
+ npm run build # TypeScript compilation (tsc → dist/)
9
+ npm test # Run all tests (vitest)
10
+ npm test -- AgentBase # Run tests matching a filename
11
+ npm test -- -t "renders basic SWML" # Run tests matching a description
12
+ npm run test:watch # Continuous test mode
13
+ npm run dev # TypeScript watch + rebuild
14
+ ```
15
+
16
+ CLI tool for testing agents without a running server:
17
+ ```bash
18
+ npx tsx src/cli/swaig-test.ts examples/simple-agent.ts --dump-swml
19
+ npx tsx src/cli/swaig-test.ts examples/simple-agent.ts --list-tools
20
+ npx tsx src/cli/swaig-test.ts examples/simple-agent.ts --exec get_time
21
+ ```
22
+
23
+ ## Architecture
24
+
25
+ This SDK builds AI voice agents as HTTP microservices. Agents serve [SWML](https://developer.signalwire.com/sdks/reference/swml/methods/) documents (JSON call-flow instructions) and handle [SWAIG](https://developer.signalwire.com/sdks/reference/swml/methods/ai/swaig/) function callbacks from the SignalWire platform.
26
+
27
+ ### Core Flow
28
+
29
+ ```
30
+ SignalWire ──GET /──> AgentBase (returns SWML JSON)
31
+ SignalWire ──POST /swaig──> AgentBase (dispatches to tool handlers)
32
+ SignalWire ──POST /post_prompt──> AgentBase (receives call summary)
33
+ ```
34
+
35
+ ### Composition Architecture
36
+
37
+ `AgentBase` is the central class (~1100 lines). It uses **composition** (not inheritance) to assemble functionality from internal managers:
38
+
39
+ - **PromptManager** / **PomBuilder** — raw text or structured prompt rendering
40
+ - **SwmlBuilder** — assembles the 5-phase SWML document
41
+ - **SessionManager** — HMAC token generation/validation for secure tools
42
+ - **ContextBuilder** — multi-step conversation workflows (state machine)
43
+ - **SkillManager** — loads/unloads skill plugins that inject tools, prompts, and hints
44
+ - **Hono App** — HTTP server with basicAuth, CORS, security headers, rate limiting
45
+
46
+ This differs from the Python SDK which uses 8 mixins. The TS SDK composes everything inside AgentBase.
47
+
48
+ ### SWML 5-Phase Rendering
49
+
50
+ `renderSwml()` builds the call-flow document in phases:
51
+ 1. **Pre-answer** — verbs before picking up (e.g., play ringing)
52
+ 2. **Answer** — auto-answer verb (if enabled)
53
+ 3. **Post-answer** — verbs after answer, before AI (e.g., welcome message)
54
+ 4. **AI** — the AI block with prompt, tools, languages, params
55
+ 5. **Post-AI** — verbs after AI ends (e.g., hangup)
56
+
57
+ ### Key Classes
58
+
59
+ | Class | Purpose | Size |
60
+ |-------|---------|------|
61
+ | `AgentBase` | HTTP server, SWML rendering, tool dispatch, dynamic config | ~1100 lines |
62
+ | `SwaigFunctionResult` | Fluent response builder with 40+ call-control actions | ~900 lines |
63
+ | `ContextBuilder` | Multi-step workflows: Context → Step → GatherInfo | ~800 lines |
64
+ | `DataMap` | Server-side tools (webhooks + expressions, no server roundtrip) | ~400 lines |
65
+ | `SwaigFunction` | Wraps a tool handler with metadata for SWAIG serialization | ~100 lines |
66
+
67
+ ### Subclassing Pattern
68
+
69
+ Prefab agents and user agents extend `AgentBase` using three key hooks:
70
+
71
+ ```typescript
72
+ class MyAgent extends AgentBase {
73
+ static override PROMPT_SECTIONS = [/* declarative prompt sections */];
74
+ protected override defineTools(): void { /* register tools */ }
75
+ async onSummary(summary, rawData) { /* process call summary */ }
76
+ }
77
+ ```
78
+
79
+ `defineTools()` is called at the end of the `AgentBase` constructor. Subclasses override it to register their tools after all fields are initialized.
80
+
81
+ ### Builder Pattern
82
+
83
+ `SwaigFunctionResult`, `DataMap`, `ContextBuilder`, and `PomBuilder` all use fluent chaining (methods return `this`).
84
+
85
+ ## Code Conventions
86
+
87
+ - **ES Modules** throughout (`"type": "module"` in package.json, `.js` extensions in imports)
88
+ - **SWML output keys** use `snake_case` to match the Python SDK and platform expectations
89
+ - **TypeScript strict mode** enabled — no implicit any, strict null checks
90
+ - All public API surfaces have JSDoc comments
91
+ - Tests use vitest with globals enabled (no explicit imports of `describe`/`it`/`expect`)
92
+ - Test setup (`tests/setup.ts`) polyfills `globalThis.crypto` for Hono's basicAuth in Node
93
+
94
+ ## Key Environment Variables
95
+
96
+ | Variable | Purpose |
97
+ |----------|---------|
98
+ | `PORT` | HTTP server port (default 3000) |
99
+ | `SWML_BASIC_AUTH_USER` / `SWML_BASIC_AUTH_PASSWORD` | Auth credentials |
100
+ | `SWML_PROXY_URL_BASE` | Proxy/tunnel base URL for webhook URLs |
101
+ | `SIGNALWIRE_LOG_LEVEL` | debug, info, warn, error |
102
+ | `SIGNALWIRE_LOG_MODE` | Set to "off" to suppress all logging |
103
+
104
+ ## Project Layout
105
+
106
+ - `src/` — TypeScript source (compiled to `dist/`)
107
+ - `src/cli/` — CLI tool for offline agent testing (swaig-test)
108
+ - `src/skills/` — Skills framework + 18 built-in skills in `builtin/`
109
+ - `src/prefabs/` — 5 pre-built agent types (InfoGatherer, Survey, FAQ, Concierge, Receptionist)
110
+ - `tests/` — Vitest test files mirroring src/ structure
111
+ - `examples/` — Runnable example agents (`npx tsx examples/simple-agent.ts`)
112
+ - `docs/` — Comprehensive markdown documentation (12 guides + API reference)
package/README.md ADDED
@@ -0,0 +1,417 @@
1
+ # SignalWire AI Agents SDK for TypeScript
2
+
3
+ Build AI voice agents as HTTP microservices that serve [SWML](https://developer.signalwire.com/sdks/reference/swml/methods/) documents and handle [SWAIG](https://developer.signalwire.com/sdks/reference/swml/methods/ai/swaig/) function callbacks.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ npm install
9
+ npm run build
10
+ ```
11
+
12
+ ```typescript
13
+ import { AgentBase, SwaigFunctionResult } from 'signalwire-agents';
14
+
15
+ const agent = new AgentBase({
16
+ name: 'my-agent',
17
+ route: '/',
18
+ basicAuth: ['user', 'pass'],
19
+ });
20
+
21
+ agent.setPromptText('You are a helpful assistant.');
22
+
23
+ agent.defineTool({
24
+ name: 'get_time',
25
+ description: 'Get the current time',
26
+ parameters: {},
27
+ handler: () => new SwaigFunctionResult(`It is ${new Date().toLocaleTimeString()}`),
28
+ });
29
+
30
+ agent.run(); // Starts HTTP server on port 3000
31
+ ```
32
+
33
+ Point your SignalWire phone number's SWML webhook at `http://user:pass@your-host:3000/` and the agent will answer calls.
34
+
35
+ ## How It Works
36
+
37
+ When a call comes in, SignalWire requests a SWML document from your agent's HTTP endpoint. The SDK builds this document with your configured prompt, tools, languages, and call flow verbs. During the call, the AI can invoke your tools via SWAIG callbacks to the same server.
38
+
39
+ ```
40
+ SignalWire ──GET /──> Agent (returns SWML JSON)
41
+ SignalWire ──POST /swaig──> Agent (calls your tool handlers)
42
+ SignalWire ──POST /post_prompt──> Agent (sends call summary)
43
+ ```
44
+
45
+ ## Installation
46
+
47
+ ```bash
48
+ npm install signalwire-agents
49
+ ```
50
+
51
+ Requires Node.js >= 18.
52
+
53
+ ## Core Concepts
54
+
55
+ ### AgentBase
56
+
57
+ The main class. Each agent is an HTTP server that serves SWML and handles tool callbacks.
58
+
59
+ ```typescript
60
+ const agent = new AgentBase({
61
+ name: 'my-agent', // Agent name (required)
62
+ route: '/', // HTTP route path
63
+ port: 3000, // Server port
64
+ basicAuth: ['u', 'p'], // HTTP basic auth credentials
65
+ autoAnswer: true, // Auto-answer incoming calls
66
+ recordCall: false, // Record calls
67
+ recordFormat: 'mp4', // Recording format
68
+ nativeFunctions: [], // Platform-native functions (e.g., 'check_time')
69
+ });
70
+ ```
71
+
72
+ Auth credentials can also be set via environment variables `SWML_BASIC_AUTH_USER` and `SWML_BASIC_AUTH_PASSWORD`. If neither is provided, credentials are auto-generated and logged at startup.
73
+
74
+ ### Tools (SWAIG Functions)
75
+
76
+ Tools let the AI perform actions during a call. Define them with `defineTool()`:
77
+
78
+ ```typescript
79
+ agent.defineTool({
80
+ name: 'lookup_order',
81
+ description: 'Look up an order by ID',
82
+ parameters: {
83
+ order_id: { type: 'string', description: 'The order ID' },
84
+ },
85
+ handler: async (args, fullBody) => {
86
+ const order = await db.findOrder(args.order_id);
87
+ return new SwaigFunctionResult(`Order ${order.id}: status is ${order.status}`);
88
+ },
89
+ });
90
+ ```
91
+
92
+ Handlers receive the parsed arguments and the full request body. They can be async. The return value must be a `SwaigFunctionResult`.
93
+
94
+ #### Secure Tools
95
+
96
+ Mark a tool as `secure: true` to require per-call HMAC tokens:
97
+
98
+ ```typescript
99
+ agent.defineTool({
100
+ name: 'charge_card',
101
+ description: 'Charge the customer credit card',
102
+ parameters: { amount: { type: 'string', description: 'Amount to charge' } },
103
+ secure: true,
104
+ handler: (args) => new SwaigFunctionResult(`Charged $${args.amount}`),
105
+ });
106
+ ```
107
+
108
+ ### SwaigFunctionResult
109
+
110
+ The response builder for tool handlers. Carries response text plus structured platform actions. All methods return `this` for chaining.
111
+
112
+ ```typescript
113
+ // Simple response
114
+ return new SwaigFunctionResult('Done.');
115
+
116
+ // Transfer the call
117
+ return new SwaigFunctionResult('Transferring you now.')
118
+ .connect('+15551234567');
119
+
120
+ // Multiple actions
121
+ return new SwaigFunctionResult('Noted.')
122
+ .updateGlobalData({ last_action: 'sms' })
123
+ .sendSms({
124
+ toNumber: '+15551234567',
125
+ fromNumber: '+15559876543',
126
+ body: 'Your order has shipped!',
127
+ });
128
+
129
+ // Hang up
130
+ return new SwaigFunctionResult('Goodbye!').hangup();
131
+ ```
132
+
133
+ **Available actions:** `connect`, `hangup`, `hold`, `stop`, `waitForUser`, `say`, `playBackgroundFile`, `stopBackgroundFile`, `sendSms`, `recordCall`, `stopRecordCall`, `tap`, `stopTap`, `joinRoom`, `joinConference`, `sipRefer`, `pay`, `executeSwml`, `switchContext`, `swmlChangeStep`, `swmlChangeContext`, `updateGlobalData`, `removeGlobalData`, `setMetadata`, `removeMetadata`, `toggleFunctions`, `simulateUserInput`, `replaceInHistory`, `addDynamicHints`, `clearDynamicHints`, `setEndOfSpeechTimeout`, `executeRpc`, and more.
134
+
135
+ ### Prompts
136
+
137
+ #### Raw Text
138
+
139
+ ```typescript
140
+ agent.setPromptText('You are a helpful assistant.');
141
+ ```
142
+
143
+ #### Prompt Object Model (POM)
144
+
145
+ Build structured prompts with sections, bullets, and subsections:
146
+
147
+ ```typescript
148
+ agent.promptAddSection('Role', {
149
+ body: 'You are a customer support agent.',
150
+ });
151
+
152
+ agent.promptAddSection('Rules', {
153
+ bullets: [
154
+ 'Always be polite',
155
+ 'Never share internal data',
156
+ 'Escalate if unsure',
157
+ ],
158
+ });
159
+
160
+ agent.promptAddSection('Guidelines', {
161
+ body: 'Follow these interaction patterns:',
162
+ subsections: [
163
+ { title: 'Greeting', body: 'Always start with a warm greeting.' },
164
+ { title: 'Closing', body: 'Ask if there is anything else before ending.' },
165
+ ],
166
+ });
167
+ ```
168
+
169
+ You can also append to existing sections:
170
+
171
+ ```typescript
172
+ agent.promptAddToSection('Rules', { bullet: 'Keep responses under 2 sentences' });
173
+ agent.promptAddSubsection('Guidelines', 'Tone', { body: 'Use a conversational tone.' });
174
+ ```
175
+
176
+ ### DataMap (Server-Side Tools)
177
+
178
+ DataMap tools execute on the SignalWire platform without hitting your server. They map API responses to AI-consumable text using templates:
179
+
180
+ ```typescript
181
+ import { DataMap, SwaigFunctionResult } from 'signalwire-agents';
182
+
183
+ const weather = new DataMap('get_weather')
184
+ .purpose('Get weather for a city')
185
+ .parameter('city', 'string', 'City name', { required: true })
186
+ .webhook('GET', 'https://wttr.in/${lc:args.city}?format=j1')
187
+ .output(new SwaigFunctionResult('Weather: ${response.current_condition[0].temp_F}°F'))
188
+ .fallbackOutput(new SwaigFunctionResult('Could not fetch weather.'));
189
+
190
+ agent.registerSwaigFunction(weather.toSwaigFunction());
191
+ ```
192
+
193
+ Or use the helper for simple cases:
194
+
195
+ ```typescript
196
+ import { createSimpleApiTool } from 'signalwire-agents';
197
+
198
+ const joke = createSimpleApiTool({
199
+ name: 'get_joke',
200
+ url: 'https://official-joke-api.appspot.com/random_joke',
201
+ responseTemplate: '${response.setup} ... ${response.punchline}',
202
+ });
203
+
204
+ agent.registerSwaigFunction(joke.toSwaigFunction());
205
+ ```
206
+
207
+ ### Contexts & Steps
208
+
209
+ Define multi-step conversation workflows where the AI follows a structured sequence:
210
+
211
+ ```typescript
212
+ const ctx = agent.defineContexts();
213
+ const flow = ctx.addContext('default');
214
+
215
+ flow.addStep('greeting', { task: 'Greet the user and ask how you can help.' })
216
+ .setStepCriteria('User has stated their request')
217
+ .setFunctions('none')
218
+ .setValidSteps(['help', 'goodbye']);
219
+
220
+ flow.addStep('help', { task: 'Help the user with their request.' })
221
+ .setFunctions(['lookup_order', 'check_status'])
222
+ .setValidSteps(['goodbye']);
223
+
224
+ flow.addStep('goodbye', { task: 'Thank the user and end the call.' })
225
+ .setEnd(true);
226
+ ```
227
+
228
+ Steps support gather_info for structured data collection:
229
+
230
+ ```typescript
231
+ flow.addStep('collect_info')
232
+ .setText('Collect the caller information.')
233
+ .setGatherInfo({ outputKey: 'caller_info' })
234
+ .addGatherQuestion({ key: 'name', question: 'What is your name?' })
235
+ .addGatherQuestion({ key: 'email', question: 'What is your email?', type: 'string', confirm: true })
236
+ .setValidSteps(['process']);
237
+ ```
238
+
239
+ ### Call Flow (5-Phase Rendering)
240
+
241
+ Control what happens at each stage of the call:
242
+
243
+ ```typescript
244
+ // Phase 1: Before answering (e.g., play ringing)
245
+ agent.addPreAnswerVerb('play', { urls: ['ring:us'], auto_answer: false });
246
+
247
+ // Phase 2: Answer (automatic if autoAnswer: true)
248
+
249
+ // Phase 3: After answer, before AI (e.g., welcome message, recording)
250
+ agent.addPostAnswerVerb('play', { url: 'say:Welcome!' });
251
+
252
+ // Phase 4: AI conversation (automatic - built from your prompt, tools, etc.)
253
+
254
+ // Phase 5: After AI ends (e.g., cleanup)
255
+ agent.addPostAiVerb('hangup', {});
256
+ ```
257
+
258
+ ### AI Configuration
259
+
260
+ ```typescript
261
+ // Speech hints for better recognition
262
+ agent.addHints(['SignalWire', 'SWML', 'SWAIG']);
263
+
264
+ // Languages and voices
265
+ agent.addLanguage({ name: 'English', code: 'en-US', voice: 'rachel' });
266
+
267
+ // Pronunciation corrections
268
+ agent.addPronunciation({ replace: 'API', with: 'A P I' });
269
+
270
+ // LLM parameters
271
+ agent.setParam('temperature', 0.7);
272
+ agent.setParams({ top_p: 0.9, frequency_penalty: 0.3 });
273
+ agent.setPromptLlmParams({ temperature: 0.5 }); // per-prompt params
274
+
275
+ // Global data accessible to all tools
276
+ agent.setGlobalData({ company: 'Acme Corp', plan: 'enterprise' });
277
+
278
+ // Native platform functions
279
+ agent.setNativeFunctions(['check_time']);
280
+ ```
281
+
282
+ ### Dynamic Configuration
283
+
284
+ Customize agent behavior per-request based on caller info, query params, or headers:
285
+
286
+ ```typescript
287
+ agent.setDynamicConfigCallback(async (queryParams, bodyParams, headers, agentCopy) => {
288
+ const copy = agentCopy as AgentBase;
289
+
290
+ // Different prompt based on query param
291
+ if (queryParams['lang'] === 'es') {
292
+ copy.setPromptText('Responde en español.');
293
+ copy.setLanguages([{ name: 'Spanish', code: 'es-ES', voice: 'polly.Lucia' }]);
294
+ }
295
+
296
+ // Add caller-specific data
297
+ const callerId = bodyParams['caller_id_number'] as string;
298
+ if (callerId) {
299
+ copy.setGlobalData({ caller_phone: callerId });
300
+ }
301
+ });
302
+ ```
303
+
304
+ Each request gets an ephemeral copy of the agent, so modifications don't affect other callers.
305
+
306
+ ### Post-Prompt (Call Summaries)
307
+
308
+ Get a summary after each call:
309
+
310
+ ```typescript
311
+ agent.setPostPrompt('Summarize this call as JSON with: topic, resolution, follow_up_needed');
312
+ ```
313
+
314
+ Override `onSummary()` in a subclass to process summaries:
315
+
316
+ ```typescript
317
+ class MyAgent extends AgentBase {
318
+ async onSummary(summary: Record<string, unknown> | null, rawData: Record<string, unknown>) {
319
+ console.log('Call summary:', summary);
320
+ // Save to database, send notification, etc.
321
+ }
322
+ }
323
+ ```
324
+
325
+ ### Multi-Agent Server
326
+
327
+ Host multiple agents under a single HTTP server:
328
+
329
+ ```typescript
330
+ import { AgentServer, AgentBase } from 'signalwire-agents';
331
+
332
+ const support = new AgentBase({ name: 'support', route: '/support', basicAuth: ['u', 'p'] });
333
+ support.setPromptText('You are a support agent.');
334
+
335
+ const sales = new AgentBase({ name: 'sales', route: '/sales', basicAuth: ['u', 'p'] });
336
+ sales.setPromptText('You are a sales agent.');
337
+
338
+ const server = new AgentServer({ port: 3000 });
339
+ server.register(support);
340
+ server.register(sales);
341
+ server.run();
342
+ ```
343
+
344
+ The root `/` returns a JSON listing of all registered agents. Health checks are at `/health` and `/ready`.
345
+
346
+ ## HTTP Endpoints
347
+
348
+ Each agent exposes these endpoints:
349
+
350
+ | Endpoint | Method | Description |
351
+ |----------|--------|-------------|
352
+ | `/` | GET/POST | Returns SWML document |
353
+ | `/swaig` | GET/POST | SWAIG function dispatcher |
354
+ | `/post_prompt` | GET/POST | Post-prompt summary handler |
355
+ | `/health` | GET | Health check |
356
+ | `/ready` | GET | Readiness check |
357
+
358
+ All endpoints (except health/ready) require basic auth.
359
+
360
+ ## Environment Variables
361
+
362
+ | Variable | Description |
363
+ |----------|-------------|
364
+ | `PORT` | Server port (default: 3000) |
365
+ | `SWML_BASIC_AUTH_USER` | Basic auth username |
366
+ | `SWML_BASIC_AUTH_PASSWORD` | Basic auth password |
367
+ | `SWML_PROXY_URL_BASE` | Proxy/tunnel base URL for webhook URLs |
368
+
369
+ ## Documentation
370
+
371
+ Comprehensive guides and API reference are in the [`docs/`](docs/) directory:
372
+
373
+ | Guide | Description |
374
+ |-------|-------------|
375
+ | [Agent Guide](docs/agent-guide.md) | Getting started — creating agents, prompts, tools, call flow, dynamic config |
376
+ | [Architecture](docs/architecture.md) | System design, component relationships, SWML rendering pipeline |
377
+ | [SWAIG Reference](docs/swaig-reference.md) | Complete SwaigFunctionResult API — all call control, audio, data, and action methods |
378
+ | [DataMap Guide](docs/datamap-guide.md) | Server-side tools — webhooks, expressions, templates, environment variables |
379
+ | [Contexts & Steps](docs/contexts-guide.md) | Multi-step conversation workflows, navigation, gather_info |
380
+ | [Skills Guide](docs/skills-guide.md) | Skills framework — 18 built-in skills, custom skill development |
381
+ | [Prefabs Guide](docs/prefabs-guide.md) | Pre-built agents — InfoGatherer, Survey, FAQ, Concierge, Receptionist |
382
+ | [CLI Guide](docs/cli-guide.md) | Testing tool — dump SWML, execute tools, simulate serverless |
383
+ | [Configuration](docs/configuration.md) | Constructor options, environment variables, ConfigLoader, AuthHandler |
384
+ | [Security](docs/security.md) | Authentication, SSL/TLS, CORS, rate limiting, production checklist |
385
+ | [Serverless Guide](docs/serverless-guide.md) | Deploy to AWS Lambda, Google Cloud Functions, Azure Functions, CGI |
386
+ | [API Reference](docs/api-reference.md) | Complete reference for every exported class, method, and interface |
387
+
388
+ ## Examples
389
+
390
+ See the [`examples/`](examples/) directory:
391
+
392
+ - [`simple-agent.ts`](examples/simple-agent.ts) - Minimal agent with a tool
393
+ - [`pom-prompt.ts`](examples/pom-prompt.ts) - Structured prompts with POM
394
+ - [`datamap-tools.ts`](examples/datamap-tools.ts) - Server-side API tools with DataMap
395
+ - [`contexts-steps.ts`](examples/contexts-steps.ts) - Multi-step conversation workflows
396
+ - [`multi-agent.ts`](examples/multi-agent.ts) - Multiple agents on one server
397
+ - [`dynamic-config.ts`](examples/dynamic-config.ts) - Per-request agent customization
398
+ - [`call-flow.ts`](examples/call-flow.ts) - Call flow verbs and recording
399
+
400
+ Run any example:
401
+
402
+ ```bash
403
+ npx tsx examples/simple-agent.ts
404
+ ```
405
+
406
+ ## Development
407
+
408
+ ```bash
409
+ npm run build # Compile TypeScript
410
+ npm test # Run tests
411
+ npm run test:watch # Watch mode
412
+ npm run dev # Watch + rebuild
413
+ ```
414
+
415
+ ## License
416
+
417
+ MIT