signalwire-agents 0.1.13__py3-none-any.whl → 1.0.17.dev4__py3-none-any.whl

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 (143) hide show
  1. signalwire_agents/__init__.py +99 -15
  2. signalwire_agents/agent_server.py +248 -60
  3. signalwire_agents/agents/bedrock.py +296 -0
  4. signalwire_agents/cli/__init__.py +9 -0
  5. signalwire_agents/cli/build_search.py +951 -41
  6. signalwire_agents/cli/config.py +80 -0
  7. signalwire_agents/cli/core/__init__.py +10 -0
  8. signalwire_agents/cli/core/agent_loader.py +470 -0
  9. signalwire_agents/cli/core/argparse_helpers.py +179 -0
  10. signalwire_agents/cli/core/dynamic_config.py +71 -0
  11. signalwire_agents/cli/core/service_loader.py +303 -0
  12. signalwire_agents/cli/dokku.py +2320 -0
  13. signalwire_agents/cli/execution/__init__.py +10 -0
  14. signalwire_agents/cli/execution/datamap_exec.py +446 -0
  15. signalwire_agents/cli/execution/webhook_exec.py +134 -0
  16. signalwire_agents/cli/init_project.py +2636 -0
  17. signalwire_agents/cli/output/__init__.py +10 -0
  18. signalwire_agents/cli/output/output_formatter.py +255 -0
  19. signalwire_agents/cli/output/swml_dump.py +186 -0
  20. signalwire_agents/cli/simulation/__init__.py +10 -0
  21. signalwire_agents/cli/simulation/data_generation.py +374 -0
  22. signalwire_agents/cli/simulation/data_overrides.py +200 -0
  23. signalwire_agents/cli/simulation/mock_env.py +282 -0
  24. signalwire_agents/cli/swaig_test_wrapper.py +52 -0
  25. signalwire_agents/cli/test_swaig.py +566 -2366
  26. signalwire_agents/cli/types.py +81 -0
  27. signalwire_agents/core/__init__.py +2 -2
  28. signalwire_agents/core/agent/__init__.py +12 -0
  29. signalwire_agents/core/agent/config/__init__.py +12 -0
  30. signalwire_agents/core/agent/deployment/__init__.py +9 -0
  31. signalwire_agents/core/agent/deployment/handlers/__init__.py +9 -0
  32. signalwire_agents/core/agent/prompt/__init__.py +14 -0
  33. signalwire_agents/core/agent/prompt/manager.py +306 -0
  34. signalwire_agents/core/agent/routing/__init__.py +9 -0
  35. signalwire_agents/core/agent/security/__init__.py +9 -0
  36. signalwire_agents/core/agent/swml/__init__.py +9 -0
  37. signalwire_agents/core/agent/tools/__init__.py +15 -0
  38. signalwire_agents/core/agent/tools/decorator.py +97 -0
  39. signalwire_agents/core/agent/tools/registry.py +210 -0
  40. signalwire_agents/core/agent_base.py +845 -2916
  41. signalwire_agents/core/auth_handler.py +233 -0
  42. signalwire_agents/core/config_loader.py +259 -0
  43. signalwire_agents/core/contexts.py +418 -0
  44. signalwire_agents/core/data_map.py +3 -15
  45. signalwire_agents/core/function_result.py +116 -44
  46. signalwire_agents/core/logging_config.py +162 -18
  47. signalwire_agents/core/mixins/__init__.py +28 -0
  48. signalwire_agents/core/mixins/ai_config_mixin.py +442 -0
  49. signalwire_agents/core/mixins/auth_mixin.py +280 -0
  50. signalwire_agents/core/mixins/prompt_mixin.py +358 -0
  51. signalwire_agents/core/mixins/serverless_mixin.py +460 -0
  52. signalwire_agents/core/mixins/skill_mixin.py +55 -0
  53. signalwire_agents/core/mixins/state_mixin.py +153 -0
  54. signalwire_agents/core/mixins/tool_mixin.py +230 -0
  55. signalwire_agents/core/mixins/web_mixin.py +1142 -0
  56. signalwire_agents/core/security_config.py +333 -0
  57. signalwire_agents/core/skill_base.py +84 -1
  58. signalwire_agents/core/skill_manager.py +62 -20
  59. signalwire_agents/core/swaig_function.py +18 -5
  60. signalwire_agents/core/swml_builder.py +207 -11
  61. signalwire_agents/core/swml_handler.py +27 -21
  62. signalwire_agents/core/swml_renderer.py +123 -312
  63. signalwire_agents/core/swml_service.py +171 -203
  64. signalwire_agents/mcp_gateway/__init__.py +29 -0
  65. signalwire_agents/mcp_gateway/gateway_service.py +564 -0
  66. signalwire_agents/mcp_gateway/mcp_manager.py +513 -0
  67. signalwire_agents/mcp_gateway/session_manager.py +218 -0
  68. signalwire_agents/prefabs/concierge.py +0 -3
  69. signalwire_agents/prefabs/faq_bot.py +0 -3
  70. signalwire_agents/prefabs/info_gatherer.py +0 -3
  71. signalwire_agents/prefabs/receptionist.py +0 -3
  72. signalwire_agents/prefabs/survey.py +0 -3
  73. signalwire_agents/schema.json +9218 -5489
  74. signalwire_agents/search/__init__.py +7 -1
  75. signalwire_agents/search/document_processor.py +490 -31
  76. signalwire_agents/search/index_builder.py +307 -37
  77. signalwire_agents/search/migration.py +418 -0
  78. signalwire_agents/search/models.py +30 -0
  79. signalwire_agents/search/pgvector_backend.py +748 -0
  80. signalwire_agents/search/query_processor.py +162 -31
  81. signalwire_agents/search/search_engine.py +916 -35
  82. signalwire_agents/search/search_service.py +376 -53
  83. signalwire_agents/skills/README.md +452 -0
  84. signalwire_agents/skills/__init__.py +14 -2
  85. signalwire_agents/skills/api_ninjas_trivia/README.md +215 -0
  86. signalwire_agents/skills/api_ninjas_trivia/__init__.py +12 -0
  87. signalwire_agents/skills/api_ninjas_trivia/skill.py +237 -0
  88. signalwire_agents/skills/datasphere/README.md +210 -0
  89. signalwire_agents/skills/datasphere/skill.py +84 -3
  90. signalwire_agents/skills/datasphere_serverless/README.md +258 -0
  91. signalwire_agents/skills/datasphere_serverless/__init__.py +9 -0
  92. signalwire_agents/skills/datasphere_serverless/skill.py +82 -1
  93. signalwire_agents/skills/datetime/README.md +132 -0
  94. signalwire_agents/skills/datetime/__init__.py +9 -0
  95. signalwire_agents/skills/datetime/skill.py +20 -7
  96. signalwire_agents/skills/joke/README.md +149 -0
  97. signalwire_agents/skills/joke/__init__.py +9 -0
  98. signalwire_agents/skills/joke/skill.py +21 -0
  99. signalwire_agents/skills/math/README.md +161 -0
  100. signalwire_agents/skills/math/__init__.py +9 -0
  101. signalwire_agents/skills/math/skill.py +18 -4
  102. signalwire_agents/skills/mcp_gateway/README.md +230 -0
  103. signalwire_agents/skills/mcp_gateway/__init__.py +10 -0
  104. signalwire_agents/skills/mcp_gateway/skill.py +421 -0
  105. signalwire_agents/skills/native_vector_search/README.md +210 -0
  106. signalwire_agents/skills/native_vector_search/__init__.py +9 -0
  107. signalwire_agents/skills/native_vector_search/skill.py +569 -101
  108. signalwire_agents/skills/play_background_file/README.md +218 -0
  109. signalwire_agents/skills/play_background_file/__init__.py +12 -0
  110. signalwire_agents/skills/play_background_file/skill.py +242 -0
  111. signalwire_agents/skills/registry.py +395 -40
  112. signalwire_agents/skills/spider/README.md +236 -0
  113. signalwire_agents/skills/spider/__init__.py +13 -0
  114. signalwire_agents/skills/spider/skill.py +598 -0
  115. signalwire_agents/skills/swml_transfer/README.md +395 -0
  116. signalwire_agents/skills/swml_transfer/__init__.py +10 -0
  117. signalwire_agents/skills/swml_transfer/skill.py +359 -0
  118. signalwire_agents/skills/weather_api/README.md +178 -0
  119. signalwire_agents/skills/weather_api/__init__.py +12 -0
  120. signalwire_agents/skills/weather_api/skill.py +191 -0
  121. signalwire_agents/skills/web_search/README.md +163 -0
  122. signalwire_agents/skills/web_search/__init__.py +9 -0
  123. signalwire_agents/skills/web_search/skill.py +586 -112
  124. signalwire_agents/skills/wikipedia_search/README.md +228 -0
  125. signalwire_agents/{core/state → skills/wikipedia_search}/__init__.py +5 -4
  126. signalwire_agents/skills/{wikipedia → wikipedia_search}/skill.py +33 -3
  127. signalwire_agents/web/__init__.py +17 -0
  128. signalwire_agents/web/web_service.py +559 -0
  129. signalwire_agents-1.0.17.dev4.data/data/share/man/man1/sw-agent-init.1 +400 -0
  130. signalwire_agents-1.0.17.dev4.data/data/share/man/man1/sw-search.1 +483 -0
  131. signalwire_agents-1.0.17.dev4.data/data/share/man/man1/swaig-test.1 +308 -0
  132. {signalwire_agents-0.1.13.dist-info → signalwire_agents-1.0.17.dev4.dist-info}/METADATA +347 -215
  133. signalwire_agents-1.0.17.dev4.dist-info/RECORD +147 -0
  134. signalwire_agents-1.0.17.dev4.dist-info/entry_points.txt +6 -0
  135. signalwire_agents/core/state/file_state_manager.py +0 -219
  136. signalwire_agents/core/state/state_manager.py +0 -101
  137. signalwire_agents/skills/wikipedia/__init__.py +0 -9
  138. signalwire_agents-0.1.13.data/data/schema.json +0 -5611
  139. signalwire_agents-0.1.13.dist-info/RECORD +0 -67
  140. signalwire_agents-0.1.13.dist-info/entry_points.txt +0 -3
  141. {signalwire_agents-0.1.13.dist-info → signalwire_agents-1.0.17.dev4.dist-info}/WHEEL +0 -0
  142. {signalwire_agents-0.1.13.dist-info → signalwire_agents-1.0.17.dev4.dist-info}/licenses/LICENSE +0 -0
  143. {signalwire_agents-0.1.13.dist-info → signalwire_agents-1.0.17.dev4.dist-info}/top_level.txt +0 -0
@@ -1,10 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: signalwire_agents
3
- Version: 0.1.13
3
+ Version: 1.0.17.dev4
4
4
  Summary: SignalWire AI Agents SDK
5
5
  Author-email: SignalWire Team <info@signalwire.com>
6
- Project-URL: Homepage, https://github.com/signalwire/signalwire-ai-agents
7
- Classifier: Development Status :: 3 - Alpha
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/signalwire/signalwire-agents
8
+ Keywords: signalwire,ai,agents,voice,telephony,swaig,swml
9
+ Classifier: Development Status :: 4 - Beta
8
10
  Classifier: Intended Audience :: Developers
9
11
  Classifier: License :: OSI Approved :: MIT License
10
12
  Classifier: Programming Language :: Python :: 3
@@ -16,16 +18,22 @@ Classifier: Programming Language :: Python :: 3.11
16
18
  Requires-Python: >=3.7
17
19
  Description-Content-Type: text/markdown
18
20
  License-File: LICENSE
19
- Requires-Dist: fastapi==0.115.12
20
- Requires-Dist: pydantic==2.11.4
21
- Requires-Dist: PyYAML==6.0.2
22
- Requires-Dist: Requests==2.32.3
23
- Requires-Dist: setuptools==66.1.1
24
- Requires-Dist: signalwire_pom==2.7.1
25
- Requires-Dist: structlog==25.3.0
26
- Requires-Dist: uvicorn==0.34.2
27
- Requires-Dist: beautifulsoup4==4.12.3
28
- Requires-Dist: pytz==2023.3
21
+ Requires-Dist: fastapi>=0.115.12
22
+ Requires-Dist: pydantic>=2.11.4
23
+ Requires-Dist: PyYAML>=6.0.2
24
+ Requires-Dist: Requests>=2.32.3
25
+ Requires-Dist: setuptools<81,>=66.1.1
26
+ Requires-Dist: signalwire_pom>=2.7.1
27
+ Requires-Dist: structlog>=25.3.0
28
+ Requires-Dist: uvicorn>=0.34.2
29
+ Requires-Dist: beautifulsoup4>=4.12.3
30
+ Requires-Dist: pytz>=2023.3
31
+ Requires-Dist: lxml>=4.9.0
32
+ Provides-Extra: search-queryonly
33
+ Requires-Dist: numpy>=1.24.0; extra == "search-queryonly"
34
+ Requires-Dist: scikit-learn>=1.3.0; extra == "search-queryonly"
35
+ Requires-Dist: sentence-transformers>=2.2.0; extra == "search-queryonly"
36
+ Requires-Dist: nltk>=3.8; extra == "search-queryonly"
29
37
  Provides-Extra: search
30
38
  Requires-Dist: sentence-transformers>=2.2.0; extra == "search"
31
39
  Requires-Dist: scikit-learn>=1.3.0; extra == "search"
@@ -62,28 +70,165 @@ Requires-Dist: striprtf>=0.0.26; extra == "search-all"
62
70
  Requires-Dist: openpyxl>=3.1.0; extra == "search-all"
63
71
  Requires-Dist: python-pptx>=0.6.21; extra == "search-all"
64
72
  Requires-Dist: python-magic>=0.4.27; extra == "search-all"
73
+ Requires-Dist: psycopg2-binary>=2.9.0; extra == "search-all"
74
+ Requires-Dist: pgvector>=0.2.0; extra == "search-all"
75
+ Provides-Extra: pgvector
76
+ Requires-Dist: psycopg2-binary>=2.9.0; extra == "pgvector"
77
+ Requires-Dist: pgvector>=0.2.0; extra == "pgvector"
78
+ Provides-Extra: mcp-gateway
79
+ Requires-Dist: flask>=2.0.0; extra == "mcp-gateway"
80
+ Requires-Dist: flask-limiter>=3.5.0; extra == "mcp-gateway"
81
+ Provides-Extra: all
82
+ Requires-Dist: sentence-transformers>=2.2.0; extra == "all"
83
+ Requires-Dist: scikit-learn>=1.3.0; extra == "all"
84
+ Requires-Dist: nltk>=3.8; extra == "all"
85
+ Requires-Dist: numpy>=1.24.0; extra == "all"
86
+ Requires-Dist: spacy>=3.6.0; extra == "all"
87
+ Requires-Dist: pdfplumber>=0.9.0; extra == "all"
88
+ Requires-Dist: python-docx>=0.8.11; extra == "all"
89
+ Requires-Dist: markdown>=3.4.0; extra == "all"
90
+ Requires-Dist: striprtf>=0.0.26; extra == "all"
91
+ Requires-Dist: openpyxl>=3.1.0; extra == "all"
92
+ Requires-Dist: python-pptx>=0.6.21; extra == "all"
93
+ Requires-Dist: python-magic>=0.4.27; extra == "all"
65
94
  Dynamic: license-file
66
95
 
67
- # SignalWire AI Agent SDK
96
+ <!-- Header -->
97
+ <div align="center">
98
+ <a href="https://signalwire.com" target="_blank">
99
+ <img src="https://github.com/user-attachments/assets/0c8ed3b9-8c50-4dc6-9cc4-cc6cd137fd50" width="500" />
100
+ </a>
68
101
 
69
- A Python SDK for creating, hosting, and securing SignalWire AI agents as microservices with minimal boilerplate.
102
+ # Agents SDK
103
+
104
+ #### _A Python SDK for creating, hosting, and securing SignalWire AI agents as microservices with minimal boilerplate._
105
+
106
+ <br/>
107
+
108
+ <p align="center">
109
+ <a href="https://developer.signalwire.com/sdks/agents-sdk" target="_blank">📖 Documentation</a> &nbsp; &nbsp; <code>#</code> &nbsp; &nbsp;
110
+ <a href="https://github.com/signalwire/signalwire-docs/issues/new/choose" target="_blank">🐛 Report an issue</a> &nbsp; &nbsp; <code>#</code> &nbsp; &nbsp;
111
+ <a href="https://pypi.org/project/signalwire-agents/" target="_blank">🐍 PyPI</a>
112
+ </p>
113
+
114
+ <br/>
115
+
116
+ <!-- Badges -->
117
+ <div align="center">
118
+ <a href="https://discord.com/invite/F2WNYTNjuF" target="_blank"><img src="https://img.shields.io/badge/Discord%20Community-5865F2" alt="Discord" /></a>
119
+ <a href="LICENSE"><img src="https://img.shields.io/badge/MIT-License-blue" alt="MIT License" /></a>
120
+ <a href="https://github.com/signalwire" target="_blank"><img src="https://img.shields.io/badge/GitHub-%23121011.svg?logo=github&logoColor=white&" alt="GitHub" /></a>
121
+ <a href="https://github.com/signalwire/docs" target="_blank"><img src="https://img.shields.io/github/stars/signalwire/signalwire-agents" alt="GitHub Stars" /></a>
122
+ </div>
123
+
124
+ <br/>
125
+
126
+ <a href="https://signalwire.com/signup" target="_blank">
127
+ <img src="https://github.com/user-attachments/assets/c2510c86-ae03-42a9-be06-ab9bcea948e1" alt="Sign Up" height="65"/>
128
+ </a>
129
+
130
+ </div>
70
131
 
71
132
  ## Features
72
133
 
73
- - **Self-Contained Agents**: Each agent is both a web app and an AI persona
74
- - **Prompt Object Model**: Structured prompt composition using POM
75
- - **SWAIG Integration**: Easily define and handle AI tools/functions
76
- - **Dynamic Configuration**: Configure agents per-request for multi-tenant apps and personalization
77
- - **Custom Routing**: Dynamic request handling for different paths and content
78
- - **SIP Integration**: Route SIP calls to agents based on SIP usernames
79
- - **Security Built-In**: Session management, function-specific security tokens, and basic auth
80
- - **State Management**: Persistent conversation state with automatic tracking
81
- - **Prefab Archetypes**: Ready-to-use agent types for common scenarios
82
- - **Multi-Agent Support**: Host multiple agents on a single server
83
- - **Modular Skills System**: Add capabilities to agents with simple one-liner calls
84
- - **Local Search System**: Offline document search with vector similarity and keyword search
85
-
86
- ## Skills System
134
+ | | |
135
+ |-------------------------------|:-----------------------------------------------------------------------------:|
136
+ | 🤖 **Self-Contained Agents** | Each agent is both a web app and an AI persona |
137
+ | 📝 **Prompt Object Model** | Structured prompt composition using POM |
138
+ | ⚙️ **SWAIG Integration** | Easily define and handle AI tools/functions |
139
+ | 🔧 **Dynamic Configuration** | Configure agents per-request for multi-tenant apps and personalization |
140
+ | 🗺️ **Custom Routing** | Dynamic request handling for different paths and content |
141
+ | 📞 **SIP Integration** | Route SIP calls to agents based on SIP usernames |
142
+ | 🔒 **Security Built-In** | Session management, function-specific security tokens, and basic auth |
143
+ | 💾 **State Management** | Persistent conversation state with automatic tracking |
144
+ | 🏗️ **Prefab Archetypes** | Ready-to-use agent types for common scenarios |
145
+ | 🏢 **Multi-Agent Support** | Host multiple agents on a single server |
146
+ | � **Modular Skills System** | Add capabilities to agents with simple one-liner calls |
147
+ | 🔍 **Local Search System** | Offline document search with vector similarity and keyword search |
148
+
149
+ ## Installation
150
+
151
+ ### Basic Installation
152
+
153
+ ```bash
154
+ pip install signalwire-agents
155
+ ```
156
+
157
+ ### Optional Search Functionality
158
+
159
+ The SDK includes optional local search capabilities that can be installed separately to avoid adding large dependencies to the base installation:
160
+
161
+ #### Search Installation Options
162
+
163
+ ```bash
164
+ # Query existing .swsearch files only (smallest footprint)
165
+ pip install signalwire-agents[search-queryonly]
166
+
167
+ # Basic search (vector search + keyword search + building indexes)
168
+ pip install signalwire-agents[search]
169
+
170
+ # Full search with document processing (PDF, DOCX, etc.)
171
+ pip install signalwire-agents[search-full]
172
+
173
+ # Advanced NLP features (includes spaCy)
174
+ pip install signalwire-agents[search-nlp]
175
+
176
+ # All search features
177
+ pip install signalwire-agents[search-all]
178
+ ```
179
+
180
+ #### What Each Option Includes
181
+
182
+ | Option | Size | Features |
183
+ |--------|------|----------|
184
+ | `search-queryonly` | ~400MB | Query existing .swsearch files only (no building/processing) |
185
+ | `search` | ~500MB | Vector embeddings, keyword search, basic text processing |
186
+ | `search-full` | ~600MB | + PDF, DOCX, Excel, PowerPoint, HTML, Markdown processing |
187
+ | `search-nlp` | ~600MB | + Advanced spaCy NLP features |
188
+ | `search-all` | ~700MB | All search features combined |
189
+
190
+ **When to use `search-queryonly`:**
191
+ - Production containers with pre-built `.swsearch` files
192
+ - Lambda/serverless deployments
193
+ - Agents that only need to query knowledge bases (not build them)
194
+ - Smaller deployment footprint requirements
195
+
196
+ #### Search Features
197
+
198
+ - **Local/Offline Search**: No external API dependencies
199
+ - **Hybrid Search**: Vector similarity + keyword search
200
+ - **Smart Document Processing**: Markdown, Python, PDF, DOCX, etc.
201
+ - **Multiple Languages**: English, Spanish, with extensible framework
202
+ - **CLI Tools**: Build search indexes from document directories
203
+ - **HTTP API**: Standalone or embedded search service
204
+
205
+ #### Usage Example
206
+
207
+ ```python
208
+ # Only available with search extras installed
209
+ from signalwire_agents.search import IndexBuilder, SearchEngine
210
+
211
+ # Build search index
212
+ builder = IndexBuilder()
213
+ builder.build_index(
214
+ source_dir="./docs",
215
+ output_file="knowledge.swsearch",
216
+ file_types=['md', 'txt', 'pdf']
217
+ )
218
+
219
+ # Search documents
220
+ engine = SearchEngine("knowledge.swsearch")
221
+ results = engine.search(
222
+ query_vector=embeddings,
223
+ enhanced_text="search query",
224
+ count=5
225
+ )
226
+ ```
227
+
228
+ <details>
229
+ <summary><h2>Documentation</h2></summary>
230
+
231
+ ### Skills System
87
232
 
88
233
  The SignalWire Agents SDK includes a powerful modular skills system that allows you to add complex capabilities to your agents with simple one-liner calls:
89
234
 
@@ -155,7 +300,7 @@ agent.add_skill("datasphere", {
155
300
  agent.serve()
156
301
  ```
157
302
 
158
- ### Available Built-in Skills
303
+ #### Available Built-in Skills
159
304
 
160
305
  - **web_search**: Google Custom Search API integration with web scraping (supports multiple instances)
161
306
  - **datetime**: Current date and time with timezone support
@@ -163,7 +308,7 @@ agent.serve()
163
308
  - **datasphere**: SignalWire DataSphere knowledge search (supports multiple instances)
164
309
  - **native_vector_search**: Offline document search with vector similarity and keyword search
165
310
 
166
- ### Benefits
311
+ #### Benefits
167
312
 
168
313
  - **One-liner integration**: `agent.add_skill("skill_name")`
169
314
  - **Configurable parameters**: `agent.add_skill("skill_name", {"param": "value"})`
@@ -171,13 +316,13 @@ agent.serve()
171
316
  - **Dependency validation**: Clear error messages for missing requirements
172
317
  - **Modular architecture**: Skills are self-contained and reusable
173
318
 
174
- For detailed documentation, see [Skills System README](docs/SKILLS_SYSTEM_README.md).
319
+ For detailed documentation, see [Skills System README](docs/skills_system.md).
175
320
 
176
- ## DataMap Tools
321
+ ### DataMap Tools
177
322
 
178
323
  The SDK provides a DataMap system for creating SWAIG tools that integrate directly with REST APIs without requiring custom webhook endpoints. DataMap tools execute on the SignalWire server, making them simpler to deploy than traditional webhook-based tools.
179
324
 
180
- ### Basic DataMap Usage
325
+ #### Basic DataMap Usage
181
326
 
182
327
  ```python
183
328
  from signalwire_agents import AgentBase
@@ -203,7 +348,7 @@ agent = APIAgent()
203
348
  agent.serve()
204
349
  ```
205
350
 
206
- ### Advanced DataMap Examples
351
+ #### Advanced DataMap Examples
207
352
 
208
353
  ```python
209
354
  # POST API with authentication
@@ -234,7 +379,7 @@ docs_tool = (DataMap('get_latest_docs')
234
379
  )
235
380
  ```
236
381
 
237
- ### Helper Functions
382
+ #### Helper Functions
238
383
 
239
384
  For simpler use cases, use the convenience functions:
240
385
 
@@ -264,7 +409,7 @@ self.register_swaig_function(weather.to_swaig_function())
264
409
  self.register_swaig_function(file_control.to_swaig_function())
265
410
  ```
266
411
 
267
- ### Variable Expansion
412
+ #### Variable Expansion
268
413
 
269
414
  DataMap tools support powerful variable expansion using `${variable}` syntax:
270
415
 
@@ -274,7 +419,7 @@ DataMap tools support powerful variable expansion using `${variable}` syntax:
274
419
  - **Global data**: `${global_data.key}`
275
420
  - **Metadata**: `${meta_data.call_id}`
276
421
 
277
- ### Benefits of DataMap Tools
422
+ #### Benefits of DataMap Tools
278
423
 
279
424
  - **No webhook infrastructure**: Tools run on SignalWire servers
280
425
  - **Simplified deployment**: No need to expose endpoints
@@ -285,20 +430,20 @@ DataMap tools support powerful variable expansion using `${variable}` syntax:
285
430
 
286
431
  For detailed documentation, see [DataMap Guide](docs/datamap_guide.md).
287
432
 
288
- ## Contexts and Steps
433
+ ### Contexts and Steps
289
434
 
290
- The SignalWire Agents SDK provides a powerful alternative to traditional Prompt Object Model (POM) prompts through the **Contexts and Steps** system. This feature allows you to create structured, workflow-driven AI interactions with explicit navigation control and step-by-step guidance.
435
+ The SignalWire Agents SDK provides a powerful enhancement to traditional prompts through the **Contexts and Steps** system. This feature allows you to add structured, workflow-driven AI interactions on top of your base prompt, with explicit navigation control and step-by-step guidance.
291
436
 
292
- ### Why Use Contexts and Steps?
437
+ #### Why Use Contexts and Steps?
293
438
 
294
439
  - **Structured Workflows**: Define clear, step-by-step processes for complex interactions
295
440
  - **Navigation Control**: Explicitly control which steps or contexts users can access
296
441
  - **Completion Criteria**: Set specific criteria for step completion and progression
297
442
  - **Function Restrictions**: Limit which AI tools are available in each step
298
443
  - **Workflow Isolation**: Create separate contexts for different conversation flows
299
- - **Backward Compatibility**: Works alongside traditional prompts and all existing AgentBase features
444
+ - **Enhanced Base Prompts**: Adds structured workflows on top of your existing prompt foundation
300
445
 
301
- ### Basic Usage
446
+ #### Basic Usage
302
447
 
303
448
  ```python
304
449
  from signalwire_agents import AgentBase
@@ -307,30 +452,34 @@ class WorkflowAgent(AgentBase):
307
452
  def __init__(self):
308
453
  super().__init__(name="Workflow Assistant", route="/workflow")
309
454
 
310
- # Define contexts and steps (alternative to traditional prompts)
455
+ # Set base prompt (required even when using contexts)
456
+ self.prompt_add_section("Role", "You are a helpful workflow assistant.")
457
+ self.prompt_add_section("Instructions", "Guide users through structured processes step by step.")
458
+
459
+ # Define contexts and steps (adds structured workflow to base prompt)
311
460
  contexts = self.define_contexts()
312
461
 
313
462
  # Create a single context named "default" (required for single context)
314
- context = contexts.create_context("default")
463
+ context = contexts.add_context("default")
315
464
 
316
465
  # Add step-by-step workflow
317
- context.create_step("greeting") \
466
+ context.add_step("greeting") \
318
467
  .set_text("Welcome! I'm here to help you complete your application. Let's start with your personal information.") \
319
468
  .set_step_criteria("User has provided their name and confirmed they want to continue") \
320
469
  .set_valid_steps(["personal_info"]) # Can only go to personal_info step
321
470
 
322
- context.create_step("personal_info") \
471
+ context.add_step("personal_info") \
323
472
  .add_section("Instructions", "Collect the user's personal information") \
324
473
  .add_bullets(["Ask for full name", "Ask for email address", "Ask for phone number"]) \
325
474
  .set_step_criteria("All personal information has been collected and confirmed") \
326
475
  .set_valid_steps(["review", "personal_info"]) # Can stay or move to review
327
476
 
328
- context.create_step("review") \
477
+ context.add_step("review") \
329
478
  .set_text("Let me review the information you've provided. Please confirm if everything is correct.") \
330
479
  .set_step_criteria("User has confirmed or requested changes") \
331
480
  .set_valid_steps(["personal_info", "complete"]) # Can go back or complete
332
481
 
333
- context.create_step("complete") \
482
+ context.add_step("complete") \
334
483
  .set_text("Thank you! Your application has been submitted successfully.") \
335
484
  .set_step_criteria("Application processing is complete")
336
485
  # No valid_steps = end of workflow
@@ -339,29 +488,34 @@ agent = WorkflowAgent()
339
488
  agent.serve()
340
489
  ```
341
490
 
342
- ### Advanced Features
491
+ #### Advanced Features
343
492
 
344
493
  ```python
345
494
  class MultiContextAgent(AgentBase):
346
495
  def __init__(self):
347
496
  super().__init__(name="Multi-Context Agent", route="/multi-context")
348
497
 
349
- # Add skills first
498
+ # Set base prompt (required)
499
+ self.prompt_add_section("Role", "You are a versatile AI assistant.")
500
+ self.prompt_add_section("Capabilities", "You can help with calculations and provide time information.")
501
+
502
+ # Add skills
350
503
  self.add_skill("datetime")
351
504
  self.add_skill("math")
352
505
 
506
+ # Define contexts for different service modes
353
507
  contexts = self.define_contexts()
354
508
 
355
509
  # Main conversation context
356
- main_context = contexts.create_context("main")
357
- main_context.create_step("welcome") \
510
+ main_context = contexts.add_context("main")
511
+ main_context.add_step("welcome") \
358
512
  .set_text("Welcome! I can help with calculations or provide date/time info. What would you like to do?") \
359
513
  .set_step_criteria("User has chosen a service type") \
360
514
  .set_valid_contexts(["calculator", "datetime_info"]) # Can switch contexts
361
515
 
362
516
  # Calculator context with function restrictions
363
- calc_context = contexts.create_context("calculator")
364
- calc_context.create_step("math_mode") \
517
+ calc_context = contexts.add_context("calculator")
518
+ calc_context.add_step("math_mode") \
365
519
  .add_section("Role", "You are a mathematical assistant") \
366
520
  .add_section("Instructions", "Help users with calculations") \
367
521
  .set_functions(["math"]) # Only math function available \
@@ -369,21 +523,21 @@ class MultiContextAgent(AgentBase):
369
523
  .set_valid_contexts(["main"]) # Can return to main
370
524
 
371
525
  # DateTime context
372
- datetime_context = contexts.create_context("datetime_info")
373
- datetime_context.create_step("time_mode") \
526
+ datetime_context = contexts.add_context("datetime_info")
527
+ datetime_context.add_step("time_mode") \
374
528
  .set_text("I can provide current date and time information. What would you like to know?") \
375
529
  .set_functions(["datetime"]) # Only datetime function available \
376
530
  .set_step_criteria("Date/time information has been provided") \
377
531
  .set_valid_contexts(["main"]) # Can return to main
378
532
  ```
379
533
 
380
- ### Context and Step Methods
534
+ #### Context and Step Methods
381
535
 
382
- #### Context Methods
383
- - `create_step(name)`: Create a new step in this context
536
+ ##### Context Methods
537
+ - `add_step(name)`: Create a new step in this context
384
538
  - `set_valid_contexts(contexts)`: Control which contexts can be accessed from this context
385
539
 
386
- #### Step Methods
540
+ ##### Step Methods
387
541
  - `set_text(text)`: Set direct text prompt for the step
388
542
  - `add_section(title, body)`: Add POM-style section (alternative to set_text)
389
543
  - `add_bullets(bullets)`: Add bullet points to the current or last section
@@ -392,55 +546,59 @@ class MultiContextAgent(AgentBase):
392
546
  - `set_valid_steps(steps)`: Control navigation to other steps in same context
393
547
  - `set_valid_contexts(contexts)`: Control navigation to other contexts
394
548
 
395
- ### Navigation Rules
549
+ #### Navigation Rules
396
550
 
397
551
  - **Valid Steps**: If omitted, only "next" step is implied. If specified, only those steps are allowed.
398
552
  - **Valid Contexts**: If omitted, user is trapped in current context. If specified, can navigate to those contexts.
399
553
  - **Single Context**: Must be named "default" for single-context workflows.
400
554
  - **Function Restrictions**: Use `set_functions(["function_name"])` or `set_functions("none")` to control AI tool access.
401
555
 
402
- ### Complete Example: Customer Support Workflow
556
+ #### Complete Example: Customer Support Workflow
403
557
 
404
558
  ```python
405
559
  class SupportAgent(AgentBase):
406
560
  def __init__(self):
407
561
  super().__init__(name="Customer Support", route="/support")
408
562
 
563
+ # Set base prompt (required)
564
+ self.prompt_add_section("Role", "You are a professional customer support representative.")
565
+ self.prompt_add_section("Goal", "Provide excellent customer service using structured workflows.")
566
+
409
567
  # Add skills for enhanced capabilities
410
568
  self.add_skill("datetime")
411
569
  self.add_skill("web_search", {"api_key": "your-key", "search_engine_id": "your-id"})
412
570
 
571
+ # Define support workflow contexts
413
572
  contexts = self.define_contexts()
414
573
 
415
574
  # Triage context
416
- triage = contexts.create_context("triage")
417
- triage.create_step("initial_greeting") \
418
- .add_section("Role", "You are a helpful customer support agent") \
419
- .add_section("Goal", "Understand the customer's issue and route them appropriately") \
420
- .add_bullets(["Be empathetic and professional", "Ask clarifying questions", "Categorize the issue"]) \
575
+ triage = contexts.add_context("triage")
576
+ triage.add_step("initial_greeting") \
577
+ .add_section("Current Task", "Understand the customer's issue and route them appropriately") \
578
+ .add_bullets("Questions to Ask", ["What problem are you experiencing?", "How urgent is this issue?", "Have you tried any troubleshooting steps?"]) \
421
579
  .set_step_criteria("Issue type has been identified") \
422
580
  .set_valid_contexts(["technical_support", "billing_support", "general_inquiry"])
423
581
 
424
582
  # Technical support context
425
- tech = contexts.create_context("technical_support")
426
- tech.create_step("technical_diagnosis") \
427
- .add_section("Role", "You are a technical support specialist") \
428
- .add_section("Instructions", "Help diagnose and resolve technical issues") \
583
+ tech = contexts.add_context("technical_support")
584
+ tech.add_step("technical_diagnosis") \
585
+ .add_section("Current Task", "Help diagnose and resolve technical issues") \
586
+ .add_section("Available Tools", "Use web search to find solutions and datetime to check service windows") \
429
587
  .set_functions(["web_search", "datetime"]) # Can search for solutions and check times \
430
588
  .set_step_criteria("Technical issue is resolved or escalated") \
431
589
  .set_valid_contexts(["triage"]) # Can return to triage
432
590
 
433
591
  # Billing support context
434
- billing = contexts.create_context("billing_support")
435
- billing.create_step("billing_assistance") \
592
+ billing = contexts.add_context("billing_support")
593
+ billing.add_step("billing_assistance") \
436
594
  .set_text("I'll help you with your billing inquiry. Please provide your account details.") \
437
595
  .set_functions("none") # No external tools for sensitive billing info \
438
596
  .set_step_criteria("Billing issue is addressed") \
439
597
  .set_valid_contexts(["triage"])
440
598
 
441
599
  # General inquiry context
442
- general = contexts.create_context("general_inquiry")
443
- general.create_step("general_help") \
600
+ general = contexts.add_context("general_inquiry")
601
+ general.add_step("general_help") \
444
602
  .set_text("I'm here to help with general questions. What can I assist you with?") \
445
603
  .set_functions(["web_search", "datetime"]) # Full access to search and time \
446
604
  .set_step_criteria("Inquiry has been answered") \
@@ -450,7 +608,7 @@ agent = SupportAgent()
450
608
  agent.serve()
451
609
  ```
452
610
 
453
- ### Benefits
611
+ #### Benefits
454
612
 
455
613
  - **Clear Structure**: Explicit workflow definition makes agent behavior predictable
456
614
  - **Enhanced Control**: Fine-grained control over function access and navigation
@@ -460,76 +618,7 @@ agent.serve()
460
618
 
461
619
  For detailed documentation and advanced examples, see [Contexts and Steps Guide](docs/contexts_guide.md).
462
620
 
463
- ## Installation
464
-
465
- ### Basic Installation
466
-
467
- ```bash
468
- pip install signalwire-agents
469
- ```
470
-
471
- ### Optional Search Functionality
472
-
473
- The SDK includes optional local search capabilities that can be installed separately to avoid adding large dependencies to the base installation:
474
-
475
- #### Search Installation Options
476
-
477
- ```bash
478
- # Basic search (vector search + keyword search)
479
- pip install signalwire-agents[search]
480
-
481
- # Full search with document processing (PDF, DOCX, etc.)
482
- pip install signalwire-agents[search-full]
483
-
484
- # Advanced NLP features (includes spaCy)
485
- pip install signalwire-agents[search-nlp]
486
-
487
- # All search features
488
- pip install signalwire-agents[search-all]
489
- ```
490
-
491
- #### What Each Option Includes
492
-
493
- | Option | Size | Features |
494
- |--------|------|----------|
495
- | `search` | ~500MB | Vector embeddings, keyword search, basic text processing |
496
- | `search-full` | ~600MB | + PDF, DOCX, Excel, PowerPoint, HTML, Markdown processing |
497
- | `search-nlp` | ~600MB | + Advanced spaCy NLP features |
498
- | `search-all` | ~700MB | All search features combined |
499
-
500
- #### Search Features
501
-
502
- - **Local/Offline Search**: No external API dependencies
503
- - **Hybrid Search**: Vector similarity + keyword search
504
- - **Smart Document Processing**: Markdown, Python, PDF, DOCX, etc.
505
- - **Multiple Languages**: English, Spanish, with extensible framework
506
- - **CLI Tools**: Build search indexes from document directories
507
- - **HTTP API**: Standalone or embedded search service
508
-
509
- #### Usage Example
510
-
511
- ```python
512
- # Only available with search extras installed
513
- from signalwire_agents.search import IndexBuilder, SearchEngine
514
-
515
- # Build search index
516
- builder = IndexBuilder()
517
- builder.build_index(
518
- source_dir="./docs",
519
- output_file="knowledge.swsearch",
520
- file_types=['md', 'txt', 'pdf']
521
- )
522
-
523
- # Search documents
524
- engine = SearchEngine("knowledge.swsearch")
525
- results = engine.search(
526
- query_vector=embeddings,
527
- enhanced_text="search query",
528
- count=5
529
- )
530
- ```
531
-
532
- ## Quick Start
621
+ ### Quick Start
533
622
 
534
623
  ```python
535
624
  from signalwire_agents import AgentBase
@@ -544,10 +633,7 @@ class SimpleAgent(AgentBase):
544
633
  self.prompt_add_section("Goal", body="Help users with basic questions.")
545
634
  self.prompt_add_section("Instructions", bullets=["Be concise and clear."])
546
635
 
547
- # Alternative using convenience methods:
548
- # self.setPersonality("You are a helpful assistant.")
549
- # self.setGoal("Help users with basic questions.")
550
- # self.setInstructions(["Be concise and clear."])
636
+ # Note: Use prompt_add_section() for all prompt configuration
551
637
 
552
638
  @AgentBase.tool(
553
639
  name="get_time",
@@ -565,65 +651,59 @@ if __name__ == "__main__":
565
651
  agent.serve(host="0.0.0.0", port=8000)
566
652
  ```
567
653
 
568
- ## Using State Management
654
+ ### Customizing LLM Parameters
655
+
656
+ The SDK allows you to customize LLM parameters for both the main prompt and post-prompt, giving you fine control over the AI's behavior:
569
657
 
570
658
  ```python
571
659
  from signalwire_agents import AgentBase
572
- from signalwire_agents.core.function_result import SwaigFunctionResult
573
- from signalwire_agents.core.state import FileStateManager
574
660
 
575
- class StatefulAgent(AgentBase):
661
+ class PreciseAgent(AgentBase):
576
662
  def __init__(self):
577
- # Configure state management
578
- state_manager = FileStateManager(storage_dir="./state_data")
579
-
580
- super().__init__(
581
- name="stateful",
582
- route="/stateful",
583
- enable_state_tracking=True, # Enable state tracking
584
- state_manager=state_manager # Use custom state manager
663
+ super().__init__(name="precise", route="/precise")
664
+
665
+ # Configure the agent's personality
666
+ self.prompt_add_section("Role", "You are a precise technical assistant.")
667
+ self.prompt_add_section("Instructions", "Provide accurate, detailed information.")
668
+
669
+ # Set custom LLM parameters for the main prompt
670
+ # These parameters are passed to the server which validates them based on the model
671
+ self.set_prompt_llm_params(
672
+ temperature=0.3, # Low temperature for more consistent responses
673
+ top_p=0.9, # Slightly reduced for focused responses
674
+ barge_confidence=0.7, # Moderate interruption threshold
675
+ presence_penalty=0.1, # Slight penalty for repetition
676
+ frequency_penalty=0.2 # Encourage varied vocabulary
585
677
  )
586
678
 
587
- # When enable_state_tracking=True, startup_hook and hangup_hook
588
- # are automatically registered to track session lifecycle
589
-
590
- # Custom tool for accessing and updating state
591
- @AgentBase.tool(
592
- name="save_preference",
593
- description="Save a user preference",
594
- parameters={
595
- "preference_name": {
596
- "type": "string",
597
- "description": "Name of the preference to save"
598
- },
599
- "preference_value": {
600
- "type": "string",
601
- "description": "Value of the preference"
602
- }
603
- }
604
- )
605
- def save_preference(self, args, raw_data):
606
- # Get the call ID from the raw data
607
- call_id = raw_data.get("call_id")
679
+ # Set post-prompt for summaries
680
+ self.set_post_prompt("Provide a concise summary of the key points discussed.")
608
681
 
609
- if call_id:
610
- # Get current state or empty dict if none exists
611
- state = self.get_state(call_id) or {}
612
-
613
- # Update the state
614
- preferences = state.get("preferences", {})
615
- preferences[args.get("preference_name")] = args.get("preference_value")
616
- state["preferences"] = preferences
617
-
618
- # Save the updated state
619
- self.update_state(call_id, state)
620
-
621
- return SwaigFunctionResult("Preference saved successfully")
622
- else:
623
- return SwaigFunctionResult("Could not save preference: No call ID")
682
+ # Different parameters for post-prompt (summaries should be even more focused)
683
+ self.set_post_prompt_llm_params(
684
+ temperature=0.2, # Very low for consistent summaries
685
+ top_p=0.85 # More focused token selection
686
+ )
687
+
688
+ agent = PreciseAgent()
689
+ agent.serve()
624
690
  ```
625
691
 
626
- ## Using Prefab Agents
692
+ #### Common LLM Parameters
693
+
694
+ The SDK accepts any parameters which are passed to the server for validation based on the model. Common parameters include:
695
+
696
+ - **temperature**: Controls randomness. Lower = more focused, higher = more creative
697
+ - **top_p**: Nucleus sampling. Lower = more focused on likely tokens
698
+ - **barge_confidence**: ASR confidence to interrupt. Higher = harder to interrupt (main prompt only)
699
+ - **presence_penalty**: Topic diversity. Positive = new topics
700
+ - **frequency_penalty**: Repetition control. Positive = varied vocabulary
701
+
702
+ Note: No defaults are sent unless explicitly set. The server handles validation and applies appropriate defaults based on the model.
703
+
704
+ For more details on LLM parameter tuning, see [LLM Parameters Guide](docs/llm_parameters.md).
705
+
706
+ ### Using Prefab Agents
627
707
 
628
708
  ```python
629
709
  from signalwire_agents.prefabs import InfoGathererAgent
@@ -648,16 +728,16 @@ Available prefabs include:
648
728
  - `SurveyAgent`: Conducts structured surveys with questions and rating scales
649
729
  - `ReceptionistAgent`: Greets callers and transfers them to appropriate departments
650
730
 
651
- ## Dynamic Agent Configuration
731
+ ### Dynamic Agent Configuration
652
732
 
653
733
  Configure agents dynamically based on request parameters for multi-tenant applications, A/B testing, and personalization.
654
734
 
655
- ### Static vs Dynamic Configuration
735
+ #### Static vs Dynamic Configuration
656
736
 
657
737
  - **Static**: Agent configured once at startup (traditional approach)
658
738
  - **Dynamic**: Agent configured fresh for each request based on parameters
659
739
 
660
- ### Basic Example
740
+ #### Basic Example
661
741
 
662
742
  ```python
663
743
  from signalwire_agents import AgentBase
@@ -702,7 +782,7 @@ class DynamicAgent(AgentBase):
702
782
  # curl "http://localhost:3000/dynamic?tier=standard&language=en"
703
783
  ```
704
784
 
705
- ### Use Cases
785
+ #### Use Cases
706
786
 
707
787
  - **Multi-tenant SaaS**: Different configurations per customer/organization
708
788
  - **A/B Testing**: Test different agent behaviors with different user groups
@@ -710,13 +790,55 @@ class DynamicAgent(AgentBase):
710
790
  - **Localization**: Language and cultural adaptation based on user location
711
791
  - **Dynamic Pricing**: Adjust features and capabilities based on subscription tiers
712
792
 
713
- The `EphemeralAgentConfig` object provides all the same familiar methods as `AgentBase` (like `add_language()`, `prompt_add_section()`, `set_global_data()`) but applies them per-request instead of at startup.
793
+ #### Preserving Dynamic State in SWAIG Callbacks
794
+
795
+ When using dynamic configuration to add skills or tools based on request parameters, there's a challenge: SWAIG webhook callbacks are separate HTTP requests that won't have the original query parameters. The SDK provides `add_swaig_query_params()` to solve this:
796
+
797
+ ```python
798
+ class DynamicAgent(AgentBase):
799
+ def __init__(self):
800
+ super().__init__(name="dynamic-agent", route="/agent")
801
+ self.set_dynamic_config_callback(self.configure_per_request)
802
+
803
+ def configure_per_request(self, query_params, body_params, headers, agent):
804
+ tier = query_params.get('tier', 'basic')
805
+ region = query_params.get('region', 'us-east')
806
+
807
+ if tier == 'premium':
808
+ # Add premium skills dynamically
809
+ agent.add_skill('advanced_search', {
810
+ 'api_key': 'your-api-key',
811
+ 'num_results': 5
812
+ })
813
+
814
+ # IMPORTANT: Preserve parameters for SWAIG callbacks
815
+ agent.add_swaig_query_params({
816
+ 'tier': tier,
817
+ 'region': region
818
+ })
819
+
820
+ # Now when SignalWire calls the SWAIG webhook, these params
821
+ # will be included, triggering the same dynamic configuration
822
+
823
+ # Initial request: GET /agent?tier=premium&region=eu-west
824
+ # SWAIG callback: POST /swaig/?tier=premium&region=eu-west
825
+ # Result: Premium skills are available in both requests!
826
+ ```
827
+
828
+ **Key Points:**
829
+
830
+ - **Problem**: Dynamically added skills/tools won't exist during SWAIG callbacks without the original request parameters
831
+ - **Solution**: Use `add_swaig_query_params()` to include critical parameters in all SWAIG webhook URLs
832
+ - **Clear State**: Use `clear_swaig_query_params()` if needed to reset parameters between requests
833
+ - **Token Safety**: The SDK automatically renames security tokens from `token` to `__token` to avoid parameter collisions
834
+
835
+ This ensures that any dynamic configuration based on request parameters is consistently applied across the initial SWML request and all subsequent SWAIG function callbacks.
714
836
 
715
837
  For detailed documentation and advanced examples, see the [Agent Guide](docs/agent_guide.md#dynamic-agent-configuration).
716
838
 
717
- ## Configuration
839
+ ### Configuration
718
840
 
719
- ### Environment Variables
841
+ #### Environment Variables
720
842
 
721
843
  The SDK supports the following environment variables:
722
844
 
@@ -733,14 +855,14 @@ When the auth environment variables are set, they will be used for all agents in
733
855
 
734
856
  To enable HTTPS directly (without a reverse proxy), set `SWML_SSL_ENABLED` to "true", provide valid paths to your certificate and key files, and specify your domain name.
735
857
 
736
- ## Testing
858
+ ### Testing
737
859
 
738
860
  The SDK includes powerful CLI tools for development and testing:
739
861
 
740
862
  - **`swaig-test`**: Comprehensive local testing and serverless environment simulation
741
863
  - **`sw-search`**: Build local search indexes from document directories and search within them
742
864
 
743
- ### Local Testing with swaig-test
865
+ #### Local Testing with swaig-test
744
866
 
745
867
  Test your agents locally without deployment:
746
868
 
@@ -757,12 +879,16 @@ swaig-test examples/my_agent.py --list-tools
757
879
  # Test SWAIG functions with CLI syntax
758
880
  swaig-test examples/my_agent.py --exec get_weather --location "New York"
759
881
 
882
+ # Multi-agent support
883
+ swaig-test examples/multi_agent.py --route /agent-path --list-tools
884
+ swaig-test examples/multi_agent.py --agent-class AgentName --exec function_name
885
+
760
886
  # Generate and inspect SWML documents
761
887
  swaig-test examples/my_agent.py --dump-swml
762
- swaig-test examples/my_agent.py --dump-swml --format-json | jq '.'
888
+ swaig-test examples/my_agent.py --dump-swml --raw | jq '.'
763
889
  ```
764
890
 
765
- ### Serverless Environment Simulation
891
+ #### Serverless Environment Simulation
766
892
 
767
893
  Test your agents in simulated serverless environments without deployment:
768
894
 
@@ -795,7 +921,7 @@ swaig-test examples/my_agent.py --simulate-serverless azure_function \
795
921
  --exec my_function
796
922
  ```
797
923
 
798
- ### Environment Management
924
+ #### Environment Management
799
925
 
800
926
  Use environment files for consistent testing across platforms:
801
927
 
@@ -817,7 +943,7 @@ swaig-test examples/my_agent.py --simulate-serverless lambda \
817
943
  --env-file production.env --env DEBUG=true --dump-swml
818
944
  ```
819
945
 
820
- ### Cross-Platform Testing
946
+ #### Cross-Platform Testing
821
947
 
822
948
  Test the same agent across multiple serverless platforms:
823
949
 
@@ -834,7 +960,7 @@ swaig-test examples/my_agent.py --simulate-serverless lambda --dump-swml | grep
834
960
  swaig-test examples/my_agent.py --simulate-serverless cgi --cgi-host example.com --dump-swml | grep web_hook_url
835
961
  ```
836
962
 
837
- ### Key Benefits
963
+ #### Key Benefits
838
964
 
839
965
  - **No Deployment Required**: Test serverless behavior locally
840
966
  - **Environment Simulation**: Complete platform-specific environment variable setup
@@ -845,7 +971,7 @@ swaig-test examples/my_agent.py --simulate-serverless cgi --cgi-host example.com
845
971
 
846
972
  For detailed testing documentation, see the [CLI Testing Guide](docs/cli_testing_guide.md).
847
973
 
848
- ## Documentation
974
+ ### Documentation
849
975
 
850
976
  The package includes comprehensive documentation in the `docs/` directory:
851
977
 
@@ -858,6 +984,12 @@ The package includes comprehensive documentation in the `docs/` directory:
858
984
 
859
985
  These documents provide in-depth explanations of the features, APIs, and usage patterns.
860
986
 
987
+ </details
988
+
989
+ ### ***[Read the official docs.](https://developer.signalwire.com/sdks/agents-sdk)***
990
+
991
+ ---
992
+
861
993
  ## License
862
994
 
863
995
  MIT