signalwire-agents 0.1.6__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 (140) hide show
  1. signalwire_agents/__init__.py +130 -4
  2. signalwire_agents/agent_server.py +438 -32
  3. signalwire_agents/agents/bedrock.py +296 -0
  4. signalwire_agents/cli/__init__.py +18 -0
  5. signalwire_agents/cli/build_search.py +1367 -0
  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 +809 -0
  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 +959 -2166
  40. signalwire_agents/core/auth_handler.py +233 -0
  41. signalwire_agents/core/config_loader.py +259 -0
  42. signalwire_agents/core/contexts.py +707 -0
  43. signalwire_agents/core/data_map.py +487 -0
  44. signalwire_agents/core/function_result.py +1150 -1
  45. signalwire_agents/core/logging_config.py +376 -0
  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/session_manager.py +174 -86
  56. signalwire_agents/core/security_config.py +333 -0
  57. signalwire_agents/core/skill_base.py +200 -0
  58. signalwire_agents/core/skill_manager.py +244 -0
  59. signalwire_agents/core/swaig_function.py +33 -9
  60. signalwire_agents/core/swml_builder.py +212 -12
  61. signalwire_agents/core/swml_handler.py +43 -13
  62. signalwire_agents/core/swml_renderer.py +123 -297
  63. signalwire_agents/core/swml_service.py +277 -260
  64. signalwire_agents/prefabs/concierge.py +6 -2
  65. signalwire_agents/prefabs/info_gatherer.py +149 -33
  66. signalwire_agents/prefabs/receptionist.py +14 -22
  67. signalwire_agents/prefabs/survey.py +6 -2
  68. signalwire_agents/schema.json +9218 -5489
  69. signalwire_agents/search/__init__.py +137 -0
  70. signalwire_agents/search/document_processor.py +1223 -0
  71. signalwire_agents/search/index_builder.py +804 -0
  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 +502 -0
  76. signalwire_agents/search/search_engine.py +1264 -0
  77. signalwire_agents/search/search_service.py +574 -0
  78. signalwire_agents/skills/README.md +452 -0
  79. signalwire_agents/skills/__init__.py +23 -0
  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/__init__.py +12 -0
  85. signalwire_agents/skills/datasphere/skill.py +310 -0
  86. signalwire_agents/skills/datasphere_serverless/README.md +258 -0
  87. signalwire_agents/skills/datasphere_serverless/__init__.py +10 -0
  88. signalwire_agents/skills/datasphere_serverless/skill.py +237 -0
  89. signalwire_agents/skills/datetime/README.md +132 -0
  90. signalwire_agents/skills/datetime/__init__.py +10 -0
  91. signalwire_agents/skills/datetime/skill.py +126 -0
  92. signalwire_agents/skills/joke/README.md +149 -0
  93. signalwire_agents/skills/joke/__init__.py +10 -0
  94. signalwire_agents/skills/joke/skill.py +109 -0
  95. signalwire_agents/skills/math/README.md +161 -0
  96. signalwire_agents/skills/math/__init__.py +10 -0
  97. signalwire_agents/skills/math/skill.py +105 -0
  98. signalwire_agents/skills/mcp_gateway/README.md +230 -0
  99. signalwire_agents/skills/mcp_gateway/__init__.py +10 -0
  100. signalwire_agents/skills/mcp_gateway/skill.py +421 -0
  101. signalwire_agents/skills/native_vector_search/README.md +210 -0
  102. signalwire_agents/skills/native_vector_search/__init__.py +10 -0
  103. signalwire_agents/skills/native_vector_search/skill.py +820 -0
  104. signalwire_agents/skills/play_background_file/README.md +218 -0
  105. signalwire_agents/skills/play_background_file/__init__.py +12 -0
  106. signalwire_agents/skills/play_background_file/skill.py +242 -0
  107. signalwire_agents/skills/registry.py +459 -0
  108. signalwire_agents/skills/spider/README.md +236 -0
  109. signalwire_agents/skills/spider/__init__.py +13 -0
  110. signalwire_agents/skills/spider/skill.py +598 -0
  111. signalwire_agents/skills/swml_transfer/README.md +395 -0
  112. signalwire_agents/skills/swml_transfer/__init__.py +10 -0
  113. signalwire_agents/skills/swml_transfer/skill.py +359 -0
  114. signalwire_agents/skills/weather_api/README.md +178 -0
  115. signalwire_agents/skills/weather_api/__init__.py +12 -0
  116. signalwire_agents/skills/weather_api/skill.py +191 -0
  117. signalwire_agents/skills/web_search/README.md +163 -0
  118. signalwire_agents/skills/web_search/__init__.py +10 -0
  119. signalwire_agents/skills/web_search/skill.py +739 -0
  120. signalwire_agents/skills/wikipedia_search/README.md +228 -0
  121. signalwire_agents/{core/state → skills/wikipedia_search}/__init__.py +5 -4
  122. signalwire_agents/skills/wikipedia_search/skill.py +210 -0
  123. signalwire_agents/utils/__init__.py +14 -0
  124. signalwire_agents/utils/schema_utils.py +111 -44
  125. signalwire_agents/web/__init__.py +17 -0
  126. signalwire_agents/web/web_service.py +559 -0
  127. signalwire_agents-1.0.7.data/data/share/man/man1/sw-agent-init.1 +307 -0
  128. signalwire_agents-1.0.7.data/data/share/man/man1/sw-search.1 +483 -0
  129. signalwire_agents-1.0.7.data/data/share/man/man1/swaig-test.1 +308 -0
  130. signalwire_agents-1.0.7.dist-info/METADATA +992 -0
  131. signalwire_agents-1.0.7.dist-info/RECORD +142 -0
  132. {signalwire_agents-0.1.6.dist-info → signalwire_agents-1.0.7.dist-info}/WHEEL +1 -1
  133. signalwire_agents-1.0.7.dist-info/entry_points.txt +4 -0
  134. signalwire_agents/core/state/file_state_manager.py +0 -219
  135. signalwire_agents/core/state/state_manager.py +0 -101
  136. signalwire_agents-0.1.6.data/data/schema.json +0 -5611
  137. signalwire_agents-0.1.6.dist-info/METADATA +0 -199
  138. signalwire_agents-0.1.6.dist-info/RECORD +0 -34
  139. {signalwire_agents-0.1.6.dist-info → signalwire_agents-1.0.7.dist-info}/licenses/LICENSE +0 -0
  140. {signalwire_agents-0.1.6.dist-info → signalwire_agents-1.0.7.dist-info}/top_level.txt +0 -0
@@ -8,12 +8,11 @@ See LICENSE file in the project root for full license information.
8
8
  """
9
9
 
10
10
  """
11
- SwmlRenderer for generating complete SWML documents for SignalWire AI Agents
11
+ SWML document rendering utilities for SignalWire AI Agents.
12
12
  """
13
13
 
14
- from typing import Dict, List, Any, Optional, Union
15
14
  import json
16
- import yaml
15
+ from typing import Dict, List, Any, Optional, Union
17
16
 
18
17
  from signalwire_agents.core.swml_service import SWMLService
19
18
  from signalwire_agents.core.swml_builder import SWMLBuilder
@@ -23,14 +22,13 @@ class SwmlRenderer:
23
22
  """
24
23
  Renders SWML documents for SignalWire AI Agents with AI and SWAIG components
25
24
 
26
- This class provides backward-compatible methods for rendering SWML documents
27
- while also supporting the new SWMLService architecture. It can work either
28
- standalone (legacy mode) or with a SWMLService instance.
25
+ This class provides methods for rendering SWML documents using the SWMLService architecture.
29
26
  """
30
27
 
31
28
  @staticmethod
32
29
  def render_swml(
33
30
  prompt: Union[str, List[Dict[str, Any]]],
31
+ service: SWMLService,
34
32
  post_prompt: Optional[str] = None,
35
33
  post_prompt_url: Optional[str] = None,
36
34
  swaig_functions: Optional[List[Dict[str, Any]]] = None,
@@ -43,326 +41,154 @@ class SwmlRenderer:
43
41
  record_format: str = "mp4",
44
42
  record_stereo: bool = True,
45
43
  format: str = "json",
46
- default_webhook_url: Optional[str] = None,
47
- service: Optional[SWMLService] = None
44
+ default_webhook_url: Optional[str] = None
48
45
  ) -> str:
49
46
  """
50
47
  Generate a complete SWML document with AI configuration
51
48
 
52
49
  Args:
53
- prompt: Either a string prompt or a POM in list-of-dict format
54
- post_prompt: Optional post-prompt text (for summary)
55
- post_prompt_url: URL to receive the post-prompt result
50
+ prompt: AI prompt text or POM structure
51
+ service: SWMLService instance to use for document building
52
+ post_prompt: Optional post-prompt text
53
+ post_prompt_url: Optional post-prompt URL
56
54
  swaig_functions: List of SWAIG function definitions
57
- startup_hook_url: URL for startup hook
58
- hangup_hook_url: URL for hangup hook
59
- prompt_is_pom: Whether prompt is a POM object or raw text
60
- params: Additional AI params (temperature, etc)
61
- add_answer: Whether to auto-add the answer block after AI
62
- record_call: Whether to add a record_call block
63
- record_format: Format for recording the call
55
+ startup_hook_url: Optional startup hook URL
56
+ hangup_hook_url: Optional hangup hook URL
57
+ prompt_is_pom: Whether prompt is POM format
58
+ params: Additional AI verb parameters
59
+ add_answer: Whether to add answer verb
60
+ record_call: Whether to add record_call verb
61
+ record_format: Recording format
64
62
  record_stereo: Whether to record in stereo
65
- format: Output format, 'json' or 'yaml'
66
- default_webhook_url: Optional default webhook URL for all SWAIG functions
67
- service: Optional SWMLService instance to use
63
+ format: Output format (json or yaml)
64
+ default_webhook_url: Default webhook URL for SWAIG functions
68
65
 
69
66
  Returns:
70
67
  SWML document as a string
71
68
  """
72
- # If we have a service, use it to build the document
73
- if service:
74
- # Create a builder for the service
75
- builder = SWMLBuilder(service)
76
-
77
- # Reset the document to start fresh
78
- builder.reset()
79
-
80
- # Add answer block if requested
81
- if add_answer:
82
- builder.answer()
83
-
84
- # Add record_call if requested
85
- if record_call:
86
- # TODO: Add record_call to builder API
87
- service.add_verb("record_call", {
88
- "format": record_format,
89
- "stereo": record_stereo
90
- })
91
-
92
- # Configure SWAIG object for AI verb
93
- swaig_config = {}
94
- functions = []
95
-
96
- # Add startup hook if provided
97
- if startup_hook_url:
98
- functions.append({
99
- "function": "startup_hook",
100
- "description": "Called when the call starts",
101
- "parameters": {
102
- "type": "object",
103
- "properties": {}
104
- },
105
- "web_hook_url": startup_hook_url
106
- })
107
-
108
- # Add hangup hook if provided
109
- if hangup_hook_url:
110
- functions.append({
111
- "function": "hangup_hook",
112
- "description": "Called when the call ends",
113
- "parameters": {
114
- "type": "object",
115
- "properties": {}
116
- },
117
- "web_hook_url": hangup_hook_url
118
- })
119
-
120
- # Add regular functions if provided
121
- if swaig_functions:
122
- for func in swaig_functions:
123
- # Skip special hooks as we've already added them
124
- if func.get("function") not in ["startup_hook", "hangup_hook"]:
125
- functions.append(func)
126
-
127
- # Only add SWAIG if we have functions or a default URL
128
- if functions or default_webhook_url:
129
- swaig_config = {}
130
-
131
- # Add defaults if we have a default webhook URL
132
- if default_webhook_url:
133
- swaig_config["defaults"] = {
134
- "web_hook_url": default_webhook_url
135
- }
136
-
137
- # Add functions if we have any
138
- if functions:
139
- swaig_config["functions"] = functions
140
-
141
- # Add AI verb with appropriate configuration
142
- builder.ai(
143
- prompt_text=None if prompt_is_pom else prompt,
144
- prompt_pom=prompt if prompt_is_pom else None,
145
- post_prompt=post_prompt,
146
- post_prompt_url=post_prompt_url,
147
- swaig=swaig_config if swaig_config else None,
148
- **(params or {})
149
- )
150
-
151
- # Get the document as a dictionary or string based on format
152
- if format.lower() == "yaml":
153
- import yaml
154
- return yaml.dump(builder.build(), sort_keys=False)
155
- else:
156
- return builder.render()
157
- else:
158
- # Legacy implementation (unchanged for backward compatibility)
159
- # Start building the SWML document
160
- swml = {
161
- "version": "1.0.0",
162
- "sections": {
163
- "main": []
164
- }
165
- }
166
-
167
- # Build the AI block
168
- ai_block = {
169
- "ai": {
170
- "prompt": {}
171
- }
172
- }
173
-
174
- # Set prompt based on type
175
- if prompt_is_pom:
176
- ai_block["ai"]["prompt"]["pom"] = prompt
177
- else:
178
- ai_block["ai"]["prompt"]["text"] = prompt
179
-
180
- # Add post_prompt if provided
181
- if post_prompt:
182
- ai_block["ai"]["post_prompt"] = {
183
- "text": post_prompt
184
- }
185
-
186
- # Add post_prompt_url if provided
187
- if post_prompt_url:
188
- ai_block["ai"]["post_prompt_url"] = post_prompt_url
189
-
190
- # SWAIG is a dictionary not an array (fix from old implementation)
191
- ai_block["ai"]["SWAIG"] = {}
192
-
69
+ # Use the service to build the document
70
+ builder = SWMLBuilder(service)
71
+
72
+ # Reset the document to start fresh
73
+ builder.reset()
74
+
75
+ # Add answer block if requested
76
+ if add_answer:
77
+ builder.answer()
78
+
79
+ # Add record_call if requested
80
+ if record_call:
81
+ service.add_verb("record_call", {
82
+ "format": record_format,
83
+ "stereo": record_stereo
84
+ })
85
+
86
+ # Configure SWAIG object for AI verb
87
+ swaig_config = {}
88
+ functions = []
89
+
90
+ # Add startup hook if provided
91
+ if startup_hook_url:
92
+ functions.append({
93
+ "function": "startup_hook",
94
+ "description": "Called when the call starts",
95
+ "parameters": {
96
+ "type": "object",
97
+ "properties": {}
98
+ },
99
+ "web_hook_url": startup_hook_url
100
+ })
101
+
102
+ # Add hangup hook if provided
103
+ if hangup_hook_url:
104
+ functions.append({
105
+ "function": "hangup_hook",
106
+ "description": "Called when the call ends",
107
+ "parameters": {
108
+ "type": "object",
109
+ "properties": {}
110
+ },
111
+ "web_hook_url": hangup_hook_url
112
+ })
113
+
114
+ # Add regular functions if provided
115
+ if swaig_functions:
116
+ for func in swaig_functions:
117
+ # Skip special hooks as we've already added them
118
+ if func.get("function") not in ["startup_hook", "hangup_hook"]:
119
+ functions.append(func)
120
+
121
+ # Only add SWAIG if we have functions or a default URL
122
+ if functions or default_webhook_url:
193
123
  # Add defaults if we have a default webhook URL
194
124
  if default_webhook_url:
195
- ai_block["ai"]["SWAIG"]["defaults"] = {
125
+ swaig_config["defaults"] = {
196
126
  "web_hook_url": default_webhook_url
197
127
  }
198
128
 
199
- # Collect all functions
200
- functions = []
201
-
202
- # Add SWAIG hooks if provided
203
- if startup_hook_url:
204
- startup_hook = {
205
- "function": "startup_hook",
206
- "description": "Called when the call starts",
207
- "parameters": {
208
- "type": "object",
209
- "properties": {}
210
- },
211
- "web_hook_url": startup_hook_url
212
- }
213
- functions.append(startup_hook)
214
-
215
- if hangup_hook_url:
216
- hangup_hook = {
217
- "function": "hangup_hook",
218
- "description": "Called when the call ends",
219
- "parameters": {
220
- "type": "object",
221
- "properties": {}
222
- },
223
- "web_hook_url": hangup_hook_url
224
- }
225
- functions.append(hangup_hook)
226
-
227
- # Add regular functions from the provided list
228
- if swaig_functions:
229
- for func in swaig_functions:
230
- # Skip special hooks as we've already added them
231
- if func.get("function") not in ["startup_hook", "hangup_hook"]:
232
- functions.append(func)
233
-
234
- # Add functions to SWAIG if we have any
129
+ # Add functions if we have any
235
130
  if functions:
236
- ai_block["ai"]["SWAIG"]["functions"] = functions
237
-
238
- # Add AI params if provided (but not rendering settings)
239
- if params:
240
- # Filter out non-AI parameters that should be separate SWML methods
241
- ai_params = {k: v for k, v in params.items()
242
- if k not in ["auto_answer", "record_call", "record_format", "record_stereo"]}
243
-
244
- # Only update if we have valid AI parameters
245
- if ai_params:
246
- ai_block["ai"]["params"] = ai_params
247
-
248
- # Start building the SWML blocks
249
- main_blocks = []
250
-
251
- # Add answer block first if requested (to answer the call)
252
- if add_answer:
253
- main_blocks.append({"answer": {}})
254
-
255
- # Add record_call block next if requested
256
- if record_call:
257
- main_blocks.append({
258
- "record_call": {
259
- "format": record_format,
260
- "stereo": record_stereo # SWML expects a boolean not a string
261
- }
262
- })
263
-
264
- # Add the AI block
265
- main_blocks.append(ai_block)
266
-
267
- # Set the main section to our ordered blocks
268
- swml["sections"]["main"] = main_blocks
269
-
270
- # Return in requested format
271
- if format.lower() == "yaml":
272
- return yaml.dump(swml, sort_keys=False)
273
- else:
274
- return json.dumps(swml, indent=2)
131
+ swaig_config["functions"] = functions
132
+
133
+ # Add AI verb with appropriate configuration
134
+ builder.ai(
135
+ prompt_text=None if prompt_is_pom else prompt,
136
+ prompt_pom=prompt if prompt_is_pom else None,
137
+ post_prompt=post_prompt,
138
+ post_prompt_url=post_prompt_url,
139
+ swaig=swaig_config if swaig_config else None,
140
+ **(params or {})
141
+ )
142
+
143
+ # Get the document as a dictionary or string based on format
144
+ if format.lower() == "yaml":
145
+ import yaml
146
+ return yaml.dump(builder.build(), sort_keys=False)
147
+ else:
148
+ return builder.render()
275
149
 
276
150
  @staticmethod
277
151
  def render_function_response_swml(
278
152
  response_text: str,
153
+ service: SWMLService,
279
154
  actions: Optional[List[Dict[str, Any]]] = None,
280
- format: str = "json",
281
- service: Optional[SWMLService] = None
155
+ format: str = "json"
282
156
  ) -> str:
283
157
  """
284
158
  Generate a SWML document for a function response
285
159
 
286
160
  Args:
287
- response_text: Text to say/display
288
- actions: List of SWML actions to execute
289
- format: Output format, 'json' or 'yaml'
290
- service: Optional SWMLService instance to use
161
+ response_text: Text response to include in the document
162
+ service: SWMLService instance to use
163
+ actions: Optional list of actions to perform
164
+ format: Output format (json or yaml)
291
165
 
292
166
  Returns:
293
167
  SWML document as a string
294
168
  """
295
- if service:
296
- # Use the service to build the document
297
- service.reset_document()
298
-
299
- # Add a play block for the response if provided
300
- if response_text:
301
- service.add_verb("play", {
302
- "url": f"say:{response_text}"
303
- })
304
-
305
- # Add any actions
306
- if actions:
307
- for action in actions:
308
- if action["type"] == "play":
309
- service.add_verb("play", {
310
- "url": action["url"]
311
- })
312
- elif action["type"] == "transfer":
313
- service.add_verb("connect", [
314
- {"to": action["dest"]}
315
- ])
316
- elif action["type"] == "hang_up":
317
- service.add_verb("hangup", {})
318
- # Additional action types could be added here
319
-
320
- # Return in requested format
321
- if format.lower() == "yaml":
322
- import yaml
323
- return yaml.dump(service.get_document(), sort_keys=False)
324
- else:
325
- return service.render_document()
169
+ # Use the service to build the document
170
+ service.reset_document()
171
+
172
+ # Add a play block for the response if provided
173
+ if response_text:
174
+ service.add_verb("play", {"text": response_text})
175
+
176
+ # Add any actions that were provided
177
+ if actions:
178
+ for action in actions:
179
+ if "play" in action:
180
+ service.add_verb("play", action["play"])
181
+ elif "hangup" in action:
182
+ service.add_verb("hangup", action["hangup"])
183
+ elif "transfer" in action:
184
+ service.add_verb("transfer", action["transfer"])
185
+ elif "ai" in action:
186
+ service.add_verb("ai", action["ai"])
187
+ # Add more action types as needed
188
+
189
+ # Get the document as a dictionary or string based on format
190
+ if format.lower() == "yaml":
191
+ import yaml
192
+ return yaml.dump(service.get_document(), sort_keys=False)
326
193
  else:
327
- # Legacy implementation (unchanged for backward compatibility)
328
- swml = {
329
- "version": "1.0.0",
330
- "sections": {
331
- "main": []
332
- }
333
- }
334
-
335
- # Add a play block for the response if provided
336
- if response_text:
337
- swml["sections"]["main"].append({
338
- "play": {
339
- "url": f"say:{response_text}"
340
- }
341
- })
342
-
343
- # Add any actions
344
- if actions:
345
- for action in actions:
346
- if action["type"] == "play":
347
- swml["sections"]["main"].append({
348
- "play": {
349
- "url": action["url"]
350
- }
351
- })
352
- elif action["type"] == "transfer":
353
- swml["sections"]["main"].append({
354
- "connect": [
355
- {"to": action["dest"]}
356
- ]
357
- })
358
- elif action["type"] == "hang_up":
359
- swml["sections"]["main"].append({
360
- "hangup": {}
361
- })
362
- # Additional action types could be added here
363
-
364
- # Return in requested format
365
- if format.lower() == "yaml":
366
- return yaml.dump(swml, sort_keys=False)
367
- else:
368
- return json.dumps(swml)
194
+ return service.render_document()