signalwire-agents 0.1.1__py3-none-any.whl → 0.1.5__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 (34) hide show
  1. signalwire_agents/__init__.py +1 -1
  2. signalwire_agents/agent_server.py +1 -1
  3. signalwire_agents/core/__init__.py +29 -0
  4. signalwire_agents/core/agent_base.py +2541 -0
  5. signalwire_agents/core/function_result.py +123 -0
  6. signalwire_agents/core/pom_builder.py +204 -0
  7. signalwire_agents/core/security/__init__.py +9 -0
  8. signalwire_agents/core/security/session_manager.py +179 -0
  9. signalwire_agents/core/state/__init__.py +17 -0
  10. signalwire_agents/core/state/file_state_manager.py +219 -0
  11. signalwire_agents/core/state/state_manager.py +101 -0
  12. signalwire_agents/core/swaig_function.py +172 -0
  13. signalwire_agents/core/swml_builder.py +214 -0
  14. signalwire_agents/core/swml_handler.py +227 -0
  15. signalwire_agents/core/swml_renderer.py +368 -0
  16. signalwire_agents/core/swml_service.py +1057 -0
  17. signalwire_agents/prefabs/__init__.py +26 -0
  18. signalwire_agents/prefabs/concierge.py +267 -0
  19. signalwire_agents/prefabs/faq_bot.py +305 -0
  20. signalwire_agents/prefabs/info_gatherer.py +263 -0
  21. signalwire_agents/prefabs/receptionist.py +295 -0
  22. signalwire_agents/prefabs/survey.py +378 -0
  23. signalwire_agents/utils/__init__.py +9 -0
  24. signalwire_agents/utils/pom_utils.py +9 -0
  25. signalwire_agents/utils/schema_utils.py +357 -0
  26. signalwire_agents/utils/token_generators.py +9 -0
  27. signalwire_agents/utils/validators.py +9 -0
  28. {signalwire_agents-0.1.1.dist-info → signalwire_agents-0.1.5.dist-info}/METADATA +1 -1
  29. signalwire_agents-0.1.5.dist-info/RECORD +34 -0
  30. signalwire_agents-0.1.1.dist-info/RECORD +0 -9
  31. {signalwire_agents-0.1.1.data → signalwire_agents-0.1.5.data}/data/schema.json +0 -0
  32. {signalwire_agents-0.1.1.dist-info → signalwire_agents-0.1.5.dist-info}/WHEEL +0 -0
  33. {signalwire_agents-0.1.1.dist-info → signalwire_agents-0.1.5.dist-info}/licenses/LICENSE +0 -0
  34. {signalwire_agents-0.1.1.dist-info → signalwire_agents-0.1.5.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,357 @@
1
+ """
2
+ Copyright (c) 2025 SignalWire
3
+
4
+ This file is part of the SignalWire AI Agents SDK.
5
+
6
+ Licensed under the MIT License.
7
+ See LICENSE file in the project root for full license information.
8
+ """
9
+
10
+ """
11
+ Utilities for working with the SWML JSON schema.
12
+
13
+ This module provides functions for loading, parsing, and validating SWML schemas.
14
+ It also provides utilities for working with SWML documents based on the schema.
15
+ """
16
+
17
+ import json
18
+ import os
19
+ import re
20
+ from typing import Dict, List, Any, Optional, Set, Tuple, Callable
21
+
22
+
23
+ class SchemaUtils:
24
+ """
25
+ Utilities for working with SWML JSON schema.
26
+
27
+ This class provides methods for:
28
+ - Loading and parsing schema files
29
+ - Extracting verb definitions
30
+ - Validating SWML objects against the schema
31
+ - Generating helpers for schema operations
32
+ """
33
+
34
+ def __init__(self, schema_path: Optional[str] = None):
35
+ """
36
+ Initialize the SchemaUtils with the provided schema
37
+
38
+ Args:
39
+ schema_path: Path to the schema file (optional)
40
+ """
41
+ self.schema_path = schema_path
42
+ if not self.schema_path:
43
+ self.schema_path = self._get_default_schema_path()
44
+ print(f"No schema_path provided, using default: {self.schema_path}")
45
+
46
+ self.schema = self.load_schema()
47
+ self.verbs = self._extract_verb_definitions()
48
+ print(f"Extracted {len(self.verbs)} verbs from schema")
49
+ if self.verbs:
50
+ print(f"First few verbs: {list(self.verbs.keys())[:5]}")
51
+
52
+ def _get_default_schema_path(self) -> str:
53
+ """
54
+ Get the default path to the schema file
55
+
56
+ Returns:
57
+ Path to the schema file
58
+ """
59
+ # Default path is the schema.json in the root directory
60
+ package_dir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
61
+ default_path = os.path.join(package_dir, "schema.json")
62
+ print(f"Default schema path: {default_path}")
63
+ print(f"Path exists: {os.path.exists(default_path)}")
64
+
65
+ return default_path
66
+
67
+ def load_schema(self) -> Dict[str, Any]:
68
+ """
69
+ Load the JSON schema from the specified path
70
+
71
+ Returns:
72
+ The schema as a dictionary
73
+ """
74
+ if not self.schema_path:
75
+ print(f"Warning: No schema path provided. Using empty schema.")
76
+ return {}
77
+
78
+ try:
79
+ print(f"Attempting to load schema from: {self.schema_path}")
80
+ print(f"File exists: {os.path.exists(self.schema_path)}")
81
+
82
+ if os.path.exists(self.schema_path):
83
+ with open(self.schema_path, "r") as f:
84
+ schema = json.load(f)
85
+ print(f"Successfully loaded schema from {self.schema_path}")
86
+ print(f"Schema has {len(schema.keys()) if schema else 0} top-level keys")
87
+ if "$defs" in schema:
88
+ print(f"Schema has {len(schema['$defs'])} definitions")
89
+ return schema
90
+ else:
91
+ print(f"Schema file not found at {self.schema_path}")
92
+ return {}
93
+ except (FileNotFoundError, json.JSONDecodeError) as e:
94
+ print(f"Error loading schema: {e}")
95
+ print(f"Using empty schema as fallback")
96
+ return {}
97
+
98
+ def _extract_verb_definitions(self) -> Dict[str, Dict[str, Any]]:
99
+ """
100
+ Extract verb definitions from the schema
101
+
102
+ Returns:
103
+ A dictionary mapping verb names to their definitions
104
+ """
105
+ verbs = {}
106
+
107
+ # Extract from SWMLMethod anyOf
108
+ if "$defs" in self.schema and "SWMLMethod" in self.schema["$defs"]:
109
+ swml_method = self.schema["$defs"]["SWMLMethod"]
110
+ print(f"Found SWMLMethod in schema with keys: {swml_method.keys()}")
111
+
112
+ if "anyOf" in swml_method:
113
+ print(f"Found anyOf in SWMLMethod with {len(swml_method['anyOf'])} items")
114
+
115
+ for ref in swml_method["anyOf"]:
116
+ if "$ref" in ref:
117
+ # Extract the verb name from the reference
118
+ verb_ref = ref["$ref"]
119
+ verb_name = verb_ref.split("/")[-1]
120
+ print(f"Processing verb reference: {verb_ref} -> {verb_name}")
121
+
122
+ # Look up the verb definition
123
+ if verb_name in self.schema["$defs"]:
124
+ verb_def = self.schema["$defs"][verb_name]
125
+
126
+ # Extract the actual verb name (lowercase)
127
+ if "properties" in verb_def:
128
+ prop_names = list(verb_def["properties"].keys())
129
+ if prop_names:
130
+ actual_verb = prop_names[0]
131
+ verbs[actual_verb] = {
132
+ "name": actual_verb,
133
+ "schema_name": verb_name,
134
+ "definition": verb_def
135
+ }
136
+ print(f"Added verb: {actual_verb}")
137
+ else:
138
+ print(f"Missing $defs or SWMLMethod in schema")
139
+ if "$defs" in self.schema:
140
+ print(f"Available definitions: {list(self.schema['$defs'].keys())}")
141
+
142
+ return verbs
143
+
144
+ def get_verb_properties(self, verb_name: str) -> Dict[str, Any]:
145
+ """
146
+ Get the properties for a specific verb
147
+
148
+ Args:
149
+ verb_name: The name of the verb (e.g., "ai", "answer", etc.)
150
+
151
+ Returns:
152
+ The properties for the verb or an empty dict if not found
153
+ """
154
+ if verb_name in self.verbs:
155
+ verb_def = self.verbs[verb_name]["definition"]
156
+ if "properties" in verb_def and verb_name in verb_def["properties"]:
157
+ return verb_def["properties"][verb_name]
158
+ return {}
159
+
160
+ def get_verb_required_properties(self, verb_name: str) -> List[str]:
161
+ """
162
+ Get the required properties for a specific verb
163
+
164
+ Args:
165
+ verb_name: The name of the verb (e.g., "ai", "answer", etc.)
166
+
167
+ Returns:
168
+ List of required property names for the verb or an empty list if not found
169
+ """
170
+ if verb_name in self.verbs:
171
+ verb_def = self.verbs[verb_name]["definition"]
172
+ if "properties" in verb_def and verb_name in verb_def["properties"]:
173
+ verb_props = verb_def["properties"][verb_name]
174
+ return verb_props.get("required", [])
175
+ return []
176
+
177
+ def validate_verb(self, verb_name: str, verb_config: Dict[str, Any]) -> Tuple[bool, List[str]]:
178
+ """
179
+ Validate a verb configuration against the schema
180
+
181
+ Args:
182
+ verb_name: The name of the verb (e.g., "ai", "answer", etc.)
183
+ verb_config: The configuration for the verb
184
+
185
+ Returns:
186
+ (is_valid, error_messages) tuple
187
+ """
188
+ # Simple validation for now - can be enhanced with more complete JSON Schema validation
189
+ errors = []
190
+
191
+ # Check if the verb exists in the schema
192
+ if verb_name not in self.verbs:
193
+ errors.append(f"Unknown verb: {verb_name}")
194
+ return False, errors
195
+
196
+ # Get the required properties for this verb
197
+ required_props = self.get_verb_required_properties(verb_name)
198
+
199
+ # Check if all required properties are present
200
+ for prop in required_props:
201
+ if prop not in verb_config:
202
+ errors.append(f"Missing required property '{prop}' for verb '{verb_name}'")
203
+
204
+ # Return validation result
205
+ return len(errors) == 0, errors
206
+
207
+ def get_all_verb_names(self) -> List[str]:
208
+ """
209
+ Get all verb names defined in the schema
210
+
211
+ Returns:
212
+ List of verb names
213
+ """
214
+ return list(self.verbs.keys())
215
+
216
+ def get_verb_parameters(self, verb_name: str) -> Dict[str, Any]:
217
+ """
218
+ Get the parameter definitions for a specific verb
219
+
220
+ Args:
221
+ verb_name: The name of the verb (e.g., "ai", "answer", etc.)
222
+
223
+ Returns:
224
+ Dictionary mapping parameter names to their definitions
225
+ """
226
+ properties = self.get_verb_properties(verb_name)
227
+ if "properties" in properties:
228
+ return properties["properties"]
229
+ return {}
230
+
231
+ def generate_method_signature(self, verb_name: str) -> str:
232
+ """
233
+ Generate a Python method signature for a verb
234
+
235
+ Args:
236
+ verb_name: The name of the verb
237
+
238
+ Returns:
239
+ A Python method signature string
240
+ """
241
+ # Get the verb properties
242
+ verb_props = self.get_verb_properties(verb_name)
243
+
244
+ # Get verb parameters
245
+ verb_params = self.get_verb_parameters(verb_name)
246
+
247
+ # Get required parameters
248
+ required_params = self.get_verb_required_properties(verb_name)
249
+
250
+ # Initialize method parameters
251
+ param_list = ["self"]
252
+
253
+ # Add the parameters
254
+ for param_name, param_def in verb_params.items():
255
+ # Check if this is a required parameter
256
+ is_required = param_name in required_params
257
+
258
+ # Determine parameter type annotation
259
+ param_type = self._get_type_annotation(param_def)
260
+
261
+ # Add default value if not required
262
+ if is_required:
263
+ param_list.append(f"{param_name}: {param_type}")
264
+ else:
265
+ param_list.append(f"{param_name}: Optional[{param_type}] = None")
266
+
267
+ # Add **kwargs at the end
268
+ param_list.append("**kwargs")
269
+
270
+ # Generate method docstring
271
+ docstring = f'"""\n Add the {verb_name} verb to the current document\n \n'
272
+
273
+ # Add parameter documentation
274
+ for param_name, param_def in verb_params.items():
275
+ description = param_def.get("description", "")
276
+ # Clean up the description for docstring
277
+ description = description.replace('\n', ' ').strip()
278
+ docstring += f" Args:\n {param_name}: {description}\n"
279
+
280
+ # Add return documentation
281
+ docstring += f' \n Returns:\n True if the verb was added successfully, False otherwise\n """\n'
282
+
283
+ # Create the full method signature with docstring
284
+ method_signature = f"def {verb_name}({', '.join(param_list)}) -> bool:\n{docstring}"
285
+
286
+ return method_signature
287
+
288
+ def generate_method_body(self, verb_name: str) -> str:
289
+ """
290
+ Generate the method body implementation for a verb
291
+
292
+ Args:
293
+ verb_name: The name of the verb
294
+
295
+ Returns:
296
+ The method body as a string
297
+ """
298
+ # Get verb parameters
299
+ verb_params = self.get_verb_parameters(verb_name)
300
+
301
+ body = []
302
+ body.append(" # Prepare the configuration")
303
+ body.append(" config = {}")
304
+
305
+ # Add handling for each parameter
306
+ for param_name in verb_params.keys():
307
+ body.append(f" if {param_name} is not None:")
308
+ body.append(f" config['{param_name}'] = {param_name}")
309
+
310
+ # Add handling for kwargs
311
+ body.append(" # Add any additional parameters from kwargs")
312
+ body.append(" for key, value in kwargs.items():")
313
+ body.append(" if value is not None:")
314
+ body.append(" config[key] = value")
315
+
316
+ # Add the call to add_verb
317
+ body.append("")
318
+ body.append(f" # Add the {verb_name} verb")
319
+ body.append(f" return self.add_verb('{verb_name}', config)")
320
+
321
+ return "\n".join(body)
322
+
323
+ def _get_type_annotation(self, param_def: Dict[str, Any]) -> str:
324
+ """
325
+ Get the Python type annotation for a parameter
326
+
327
+ Args:
328
+ param_def: Parameter definition from the schema
329
+
330
+ Returns:
331
+ Python type annotation as a string
332
+ """
333
+ schema_type = param_def.get("type")
334
+
335
+ if schema_type == "string":
336
+ return "str"
337
+ elif schema_type == "integer":
338
+ return "int"
339
+ elif schema_type == "number":
340
+ return "float"
341
+ elif schema_type == "boolean":
342
+ return "bool"
343
+ elif schema_type == "array":
344
+ item_type = "Any"
345
+ if "items" in param_def:
346
+ item_def = param_def["items"]
347
+ item_type = self._get_type_annotation(item_def)
348
+ return f"List[{item_type}]"
349
+ elif schema_type == "object":
350
+ return "Dict[str, Any]"
351
+ else:
352
+ # Handle complex types or oneOf/anyOf
353
+ if "anyOf" in param_def or "oneOf" in param_def:
354
+ return "Any"
355
+ if "$ref" in param_def:
356
+ return "Any" # Could be enhanced to resolve references
357
+ return "Any"
@@ -0,0 +1,9 @@
1
+ """
2
+ Copyright (c) 2025 SignalWire
3
+
4
+ This file is part of the SignalWire AI Agents SDK.
5
+
6
+ Licensed under the MIT License.
7
+ See LICENSE file in the project root for full license information.
8
+ """
9
+
@@ -0,0 +1,9 @@
1
+ """
2
+ Copyright (c) 2025 SignalWire
3
+
4
+ This file is part of the SignalWire AI Agents SDK.
5
+
6
+ Licensed under the MIT License.
7
+ See LICENSE file in the project root for full license information.
8
+ """
9
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: signalwire_agents
3
- Version: 0.1.1
3
+ Version: 0.1.5
4
4
  Summary: SignalWire AI Agents SDK
5
5
  Author-email: SignalWire Team <info@signalwire.com>
6
6
  Project-URL: Homepage, https://github.com/signalwire/signalwire-ai-agents
@@ -0,0 +1,34 @@
1
+ signalwire_agents/__init__.py,sha256=NLgfrj90HmtMNumq43u16xWptlD-JrtXPNQVcwZ1yIo,800
2
+ signalwire_agents/agent_server.py,sha256=se_YzOQE5UUoRUKCbTnOg9qr4G3qN7iVuQLutwXEwFU,12850
3
+ signalwire_agents/schema.json,sha256=M8Mn6pQda2P9jhbmkALrLr1wt-fRuhYRqdmEi9Rbhqk,178075
4
+ signalwire_agents/core/__init__.py,sha256=mVDLbpq1pg_WwiqsQR28NNZwJ6-VUXFIfg-vN7pk0ew,806
5
+ signalwire_agents/core/agent_base.py,sha256=KIvueG5wIxveyALELISmPLWEkyhW5abU4hxq427ao_o,98466
6
+ signalwire_agents/core/function_result.py,sha256=vD8eBDJBQNNnss1jShadfogCZw_prODB6eBkTuVgZKA,3538
7
+ signalwire_agents/core/pom_builder.py,sha256=ywuiIfP8BeLBPo_G4X1teZlG6zTCMkW71CZnmyoDTAQ,6636
8
+ signalwire_agents/core/swaig_function.py,sha256=WoHGQuCmU9L9k39pttRunmfRtIa_PnNRn9W0Xq3MfIk,6316
9
+ signalwire_agents/core/swml_builder.py,sha256=Y_eHThVVso-_Hz4f73eEuu3HJstsM9PtBl-36GvAXhI,6594
10
+ signalwire_agents/core/swml_handler.py,sha256=KvphI_YY47VWGVXaix_N3SuQSyygHEUr9We6xESQK44,7002
11
+ signalwire_agents/core/swml_renderer.py,sha256=iobMWWoBR7dkHndI3Qlwf4C0fg2p7DmAU2Rb7ZmmLhA,13891
12
+ signalwire_agents/core/swml_service.py,sha256=oZKM9pKPxtbsMp3nYnx5FXtW3igj2Sc2wZbQujNVNrg,42097
13
+ signalwire_agents/core/security/__init__.py,sha256=4Mr7baQ_xR_hfJ72YxQRAT_GFa663YjFX_PumJ35Xds,191
14
+ signalwire_agents/core/security/session_manager.py,sha256=5y0Mr3cI63cO34ctFgq-KX26mdG0Tpr7rTEsgoTS_44,5229
15
+ signalwire_agents/core/state/__init__.py,sha256=qpYIfQBApet6VQsy6diS3yu0lMxCBC6REOUk5l1McUw,379
16
+ signalwire_agents/core/state/file_state_manager.py,sha256=52I_KVlmhHCbKIaHj74Q-ksP_-AF6ewYmOXCf4n5DTQ,7307
17
+ signalwire_agents/core/state/state_manager.py,sha256=76B4mDutMb826dK4c_IJhOXH09BW1bJu6EZa6Mh_LB4,2511
18
+ signalwire_agents/prefabs/__init__.py,sha256=MW11J63XH7KxF2MWguRsMFM9iqMWexaEO9ynDPL_PDM,715
19
+ signalwire_agents/prefabs/concierge.py,sha256=--esvAV1lozQGYXHAqvSg8_TtlIoVfQK75APJ5zqX9I,9779
20
+ signalwire_agents/prefabs/faq_bot.py,sha256=cUuHhnDB8S4aVg-DiQe4jBmCAPrYQrND_Mff9iaeEa0,10572
21
+ signalwire_agents/prefabs/info_gatherer.py,sha256=y9gxjq1vF0-TrE6m734dCcAHqxt0I_DyCqxoM45QY8U,9940
22
+ signalwire_agents/prefabs/receptionist.py,sha256=Wb22igXTD8QK9lQVcJq88eIk7qQ2GSSIzSGuYyK-Dbk,10293
23
+ signalwire_agents/prefabs/survey.py,sha256=1pyUeZ5heDqFAYqkYs5fHN_jQ7TKqJInnOOUQEajSsY,14358
24
+ signalwire_agents/utils/__init__.py,sha256=4Mr7baQ_xR_hfJ72YxQRAT_GFa663YjFX_PumJ35Xds,191
25
+ signalwire_agents/utils/pom_utils.py,sha256=4Mr7baQ_xR_hfJ72YxQRAT_GFa663YjFX_PumJ35Xds,191
26
+ signalwire_agents/utils/schema_utils.py,sha256=LvFCFvJTQk_xYK0B-NXbkXKEF7Zmv-LqpV_vfpPnOb4,13473
27
+ signalwire_agents/utils/token_generators.py,sha256=4Mr7baQ_xR_hfJ72YxQRAT_GFa663YjFX_PumJ35Xds,191
28
+ signalwire_agents/utils/validators.py,sha256=4Mr7baQ_xR_hfJ72YxQRAT_GFa663YjFX_PumJ35Xds,191
29
+ signalwire_agents-0.1.5.data/data/schema.json,sha256=M8Mn6pQda2P9jhbmkALrLr1wt-fRuhYRqdmEi9Rbhqk,178075
30
+ signalwire_agents-0.1.5.dist-info/licenses/LICENSE,sha256=NYvAsB-rTcSvG9cqHt9EUHAWLiA9YzM4Qfz-mPdvDR0,1067
31
+ signalwire_agents-0.1.5.dist-info/METADATA,sha256=BotyeNOQW27tW_uqJOiFFie06Ra77RYRx9SHO1FkJ-w,7414
32
+ signalwire_agents-0.1.5.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
33
+ signalwire_agents-0.1.5.dist-info/top_level.txt,sha256=kDGS6ZYv84K9P5Kyg9_S8P_pbUXoHkso0On_DB5bbWc,18
34
+ signalwire_agents-0.1.5.dist-info/RECORD,,
@@ -1,9 +0,0 @@
1
- signalwire_agents/__init__.py,sha256=fOxVP6ME-O9x_nCGn9-VcssR7QnOD6cG6YlHP0dts4M,800
2
- signalwire_agents/agent_server.py,sha256=cyHVjsCSXHBVtJCB-eNgIPZNLKe-VT1fDFQR82TOkzY,12850
3
- signalwire_agents/schema.json,sha256=M8Mn6pQda2P9jhbmkALrLr1wt-fRuhYRqdmEi9Rbhqk,178075
4
- signalwire_agents-0.1.1.data/data/schema.json,sha256=M8Mn6pQda2P9jhbmkALrLr1wt-fRuhYRqdmEi9Rbhqk,178075
5
- signalwire_agents-0.1.1.dist-info/licenses/LICENSE,sha256=NYvAsB-rTcSvG9cqHt9EUHAWLiA9YzM4Qfz-mPdvDR0,1067
6
- signalwire_agents-0.1.1.dist-info/METADATA,sha256=yK8j3RqoCVO40A5MxR7UnGFCXCVJv7VS07-7WXQtbKw,7414
7
- signalwire_agents-0.1.1.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
8
- signalwire_agents-0.1.1.dist-info/top_level.txt,sha256=kDGS6ZYv84K9P5Kyg9_S8P_pbUXoHkso0On_DB5bbWc,18
9
- signalwire_agents-0.1.1.dist-info/RECORD,,