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