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