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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. signalwire_agents/__init__.py +99 -15
  2. signalwire_agents/agent_server.py +248 -60
  3. signalwire_agents/agents/bedrock.py +296 -0
  4. signalwire_agents/cli/__init__.py +9 -0
  5. signalwire_agents/cli/build_search.py +951 -41
  6. signalwire_agents/cli/config.py +80 -0
  7. signalwire_agents/cli/core/__init__.py +10 -0
  8. signalwire_agents/cli/core/agent_loader.py +470 -0
  9. signalwire_agents/cli/core/argparse_helpers.py +179 -0
  10. signalwire_agents/cli/core/dynamic_config.py +71 -0
  11. signalwire_agents/cli/core/service_loader.py +303 -0
  12. signalwire_agents/cli/dokku.py +2320 -0
  13. signalwire_agents/cli/execution/__init__.py +10 -0
  14. signalwire_agents/cli/execution/datamap_exec.py +446 -0
  15. signalwire_agents/cli/execution/webhook_exec.py +134 -0
  16. signalwire_agents/cli/init_project.py +2636 -0
  17. signalwire_agents/cli/output/__init__.py +10 -0
  18. signalwire_agents/cli/output/output_formatter.py +255 -0
  19. signalwire_agents/cli/output/swml_dump.py +186 -0
  20. signalwire_agents/cli/simulation/__init__.py +10 -0
  21. signalwire_agents/cli/simulation/data_generation.py +374 -0
  22. signalwire_agents/cli/simulation/data_overrides.py +200 -0
  23. signalwire_agents/cli/simulation/mock_env.py +282 -0
  24. signalwire_agents/cli/swaig_test_wrapper.py +52 -0
  25. signalwire_agents/cli/test_swaig.py +566 -2366
  26. signalwire_agents/cli/types.py +81 -0
  27. signalwire_agents/core/__init__.py +2 -2
  28. signalwire_agents/core/agent/__init__.py +12 -0
  29. signalwire_agents/core/agent/config/__init__.py +12 -0
  30. signalwire_agents/core/agent/deployment/__init__.py +9 -0
  31. signalwire_agents/core/agent/deployment/handlers/__init__.py +9 -0
  32. signalwire_agents/core/agent/prompt/__init__.py +14 -0
  33. signalwire_agents/core/agent/prompt/manager.py +306 -0
  34. signalwire_agents/core/agent/routing/__init__.py +9 -0
  35. signalwire_agents/core/agent/security/__init__.py +9 -0
  36. signalwire_agents/core/agent/swml/__init__.py +9 -0
  37. signalwire_agents/core/agent/tools/__init__.py +15 -0
  38. signalwire_agents/core/agent/tools/decorator.py +97 -0
  39. signalwire_agents/core/agent/tools/registry.py +210 -0
  40. signalwire_agents/core/agent_base.py +845 -2916
  41. signalwire_agents/core/auth_handler.py +233 -0
  42. signalwire_agents/core/config_loader.py +259 -0
  43. signalwire_agents/core/contexts.py +418 -0
  44. signalwire_agents/core/data_map.py +3 -15
  45. signalwire_agents/core/function_result.py +116 -44
  46. signalwire_agents/core/logging_config.py +162 -18
  47. signalwire_agents/core/mixins/__init__.py +28 -0
  48. signalwire_agents/core/mixins/ai_config_mixin.py +442 -0
  49. signalwire_agents/core/mixins/auth_mixin.py +280 -0
  50. signalwire_agents/core/mixins/prompt_mixin.py +358 -0
  51. signalwire_agents/core/mixins/serverless_mixin.py +460 -0
  52. signalwire_agents/core/mixins/skill_mixin.py +55 -0
  53. signalwire_agents/core/mixins/state_mixin.py +153 -0
  54. signalwire_agents/core/mixins/tool_mixin.py +230 -0
  55. signalwire_agents/core/mixins/web_mixin.py +1142 -0
  56. signalwire_agents/core/security_config.py +333 -0
  57. signalwire_agents/core/skill_base.py +84 -1
  58. signalwire_agents/core/skill_manager.py +62 -20
  59. signalwire_agents/core/swaig_function.py +18 -5
  60. signalwire_agents/core/swml_builder.py +207 -11
  61. signalwire_agents/core/swml_handler.py +27 -21
  62. signalwire_agents/core/swml_renderer.py +123 -312
  63. signalwire_agents/core/swml_service.py +171 -203
  64. signalwire_agents/mcp_gateway/__init__.py +29 -0
  65. signalwire_agents/mcp_gateway/gateway_service.py +564 -0
  66. signalwire_agents/mcp_gateway/mcp_manager.py +513 -0
  67. signalwire_agents/mcp_gateway/session_manager.py +218 -0
  68. signalwire_agents/prefabs/concierge.py +0 -3
  69. signalwire_agents/prefabs/faq_bot.py +0 -3
  70. signalwire_agents/prefabs/info_gatherer.py +0 -3
  71. signalwire_agents/prefabs/receptionist.py +0 -3
  72. signalwire_agents/prefabs/survey.py +0 -3
  73. signalwire_agents/schema.json +9218 -5489
  74. signalwire_agents/search/__init__.py +7 -1
  75. signalwire_agents/search/document_processor.py +490 -31
  76. signalwire_agents/search/index_builder.py +307 -37
  77. signalwire_agents/search/migration.py +418 -0
  78. signalwire_agents/search/models.py +30 -0
  79. signalwire_agents/search/pgvector_backend.py +748 -0
  80. signalwire_agents/search/query_processor.py +162 -31
  81. signalwire_agents/search/search_engine.py +916 -35
  82. signalwire_agents/search/search_service.py +376 -53
  83. signalwire_agents/skills/README.md +452 -0
  84. signalwire_agents/skills/__init__.py +14 -2
  85. signalwire_agents/skills/api_ninjas_trivia/README.md +215 -0
  86. signalwire_agents/skills/api_ninjas_trivia/__init__.py +12 -0
  87. signalwire_agents/skills/api_ninjas_trivia/skill.py +237 -0
  88. signalwire_agents/skills/datasphere/README.md +210 -0
  89. signalwire_agents/skills/datasphere/skill.py +84 -3
  90. signalwire_agents/skills/datasphere_serverless/README.md +258 -0
  91. signalwire_agents/skills/datasphere_serverless/__init__.py +9 -0
  92. signalwire_agents/skills/datasphere_serverless/skill.py +82 -1
  93. signalwire_agents/skills/datetime/README.md +132 -0
  94. signalwire_agents/skills/datetime/__init__.py +9 -0
  95. signalwire_agents/skills/datetime/skill.py +20 -7
  96. signalwire_agents/skills/joke/README.md +149 -0
  97. signalwire_agents/skills/joke/__init__.py +9 -0
  98. signalwire_agents/skills/joke/skill.py +21 -0
  99. signalwire_agents/skills/math/README.md +161 -0
  100. signalwire_agents/skills/math/__init__.py +9 -0
  101. signalwire_agents/skills/math/skill.py +18 -4
  102. signalwire_agents/skills/mcp_gateway/README.md +230 -0
  103. signalwire_agents/skills/mcp_gateway/__init__.py +10 -0
  104. signalwire_agents/skills/mcp_gateway/skill.py +421 -0
  105. signalwire_agents/skills/native_vector_search/README.md +210 -0
  106. signalwire_agents/skills/native_vector_search/__init__.py +9 -0
  107. signalwire_agents/skills/native_vector_search/skill.py +569 -101
  108. signalwire_agents/skills/play_background_file/README.md +218 -0
  109. signalwire_agents/skills/play_background_file/__init__.py +12 -0
  110. signalwire_agents/skills/play_background_file/skill.py +242 -0
  111. signalwire_agents/skills/registry.py +395 -40
  112. signalwire_agents/skills/spider/README.md +236 -0
  113. signalwire_agents/skills/spider/__init__.py +13 -0
  114. signalwire_agents/skills/spider/skill.py +598 -0
  115. signalwire_agents/skills/swml_transfer/README.md +395 -0
  116. signalwire_agents/skills/swml_transfer/__init__.py +10 -0
  117. signalwire_agents/skills/swml_transfer/skill.py +359 -0
  118. signalwire_agents/skills/weather_api/README.md +178 -0
  119. signalwire_agents/skills/weather_api/__init__.py +12 -0
  120. signalwire_agents/skills/weather_api/skill.py +191 -0
  121. signalwire_agents/skills/web_search/README.md +163 -0
  122. signalwire_agents/skills/web_search/__init__.py +9 -0
  123. signalwire_agents/skills/web_search/skill.py +586 -112
  124. signalwire_agents/skills/wikipedia_search/README.md +228 -0
  125. signalwire_agents/{core/state → skills/wikipedia_search}/__init__.py +5 -4
  126. signalwire_agents/skills/{wikipedia → wikipedia_search}/skill.py +33 -3
  127. signalwire_agents/web/__init__.py +17 -0
  128. signalwire_agents/web/web_service.py +559 -0
  129. signalwire_agents-1.0.17.dev4.data/data/share/man/man1/sw-agent-init.1 +400 -0
  130. signalwire_agents-1.0.17.dev4.data/data/share/man/man1/sw-search.1 +483 -0
  131. signalwire_agents-1.0.17.dev4.data/data/share/man/man1/swaig-test.1 +308 -0
  132. {signalwire_agents-0.1.13.dist-info → signalwire_agents-1.0.17.dev4.dist-info}/METADATA +347 -215
  133. signalwire_agents-1.0.17.dev4.dist-info/RECORD +147 -0
  134. signalwire_agents-1.0.17.dev4.dist-info/entry_points.txt +6 -0
  135. signalwire_agents/core/state/file_state_manager.py +0 -219
  136. signalwire_agents/core/state/state_manager.py +0 -101
  137. signalwire_agents/skills/wikipedia/__init__.py +0 -9
  138. signalwire_agents-0.1.13.data/data/schema.json +0 -5611
  139. signalwire_agents-0.1.13.dist-info/RECORD +0 -67
  140. signalwire_agents-0.1.13.dist-info/entry_points.txt +0 -3
  141. {signalwire_agents-0.1.13.dist-info → signalwire_agents-1.0.17.dev4.dist-info}/WHEEL +0 -0
  142. {signalwire_agents-0.1.13.dist-info → signalwire_agents-1.0.17.dev4.dist-info}/licenses/LICENSE +0 -0
  143. {signalwire_agents-0.1.13.dist-info → signalwire_agents-1.0.17.dev4.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,230 @@
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
+ from typing import Dict, Any, List, Optional, Callable
11
+ import json
12
+
13
+ from signalwire_agents.core.swaig_function import SWAIGFunction
14
+ from signalwire_agents.core.function_result import SwaigFunctionResult
15
+ from signalwire_agents.core.agent.tools.decorator import ToolDecorator
16
+
17
+
18
+ class ToolMixin:
19
+ """
20
+ Mixin class containing all tool/function-related methods for AgentBase
21
+ """
22
+
23
+ def define_tool(
24
+ self,
25
+ name: str,
26
+ description: str,
27
+ parameters: Dict[str, Any],
28
+ handler: Callable,
29
+ secure: bool = True,
30
+ fillers: Optional[Dict[str, List[str]]] = None,
31
+ webhook_url: Optional[str] = None,
32
+ required: Optional[List[str]] = None,
33
+ **swaig_fields
34
+ ) -> 'AgentBase':
35
+ """
36
+ Define a SWAIG function that the AI can call
37
+
38
+ Args:
39
+ name: Function name (must be unique)
40
+ description: Function description for the AI
41
+ parameters: JSON Schema of parameters
42
+ handler: Function to call when invoked
43
+ secure: Whether to require token validation
44
+ fillers: Optional dict mapping language codes to arrays of filler phrases
45
+ webhook_url: Optional external webhook URL to use instead of local handling
46
+ required: Optional list of required parameter names
47
+ **swaig_fields: Additional SWAIG fields to include in function definition
48
+
49
+ Returns:
50
+ Self for method chaining
51
+ """
52
+ self._tool_registry.define_tool(
53
+ name=name,
54
+ description=description,
55
+ parameters=parameters,
56
+ handler=handler,
57
+ secure=secure,
58
+ fillers=fillers,
59
+ webhook_url=webhook_url,
60
+ required=required,
61
+ **swaig_fields
62
+ )
63
+ return self
64
+
65
+ def register_swaig_function(self, function_dict: Dict[str, Any]) -> 'AgentBase':
66
+ """
67
+ Register a raw SWAIG function dictionary (e.g., from DataMap.to_swaig_function())
68
+
69
+ Args:
70
+ function_dict: Complete SWAIG function definition dictionary
71
+
72
+ Returns:
73
+ Self for method chaining
74
+ """
75
+ self._tool_registry.register_swaig_function(function_dict)
76
+ return self
77
+
78
+ def _tool_decorator(self, name=None, **kwargs):
79
+ """
80
+ Decorator for defining SWAIG tools in a class
81
+
82
+ Used as:
83
+
84
+ @agent.tool(name="example_function", parameters={...})
85
+ def example_function(self, param1):
86
+ # ...
87
+ """
88
+ return ToolDecorator.create_instance_decorator(self._tool_registry)(name, **kwargs)
89
+
90
+ @classmethod
91
+ def tool(cls, name=None, **kwargs):
92
+ """
93
+ Class method decorator for defining SWAIG tools
94
+
95
+ Used as:
96
+
97
+ @AgentBase.tool(name="example_function", parameters={...})
98
+ def example_function(self, param1):
99
+ # ...
100
+ """
101
+ return ToolDecorator.create_class_decorator()(name, **kwargs)
102
+
103
+ def define_tools(self) -> List[SWAIGFunction]:
104
+ """
105
+ Define the tools this agent can use
106
+
107
+ Returns:
108
+ List of SWAIGFunction objects or raw dictionaries (for data_map tools)
109
+
110
+ This method can be overridden by subclasses.
111
+ """
112
+ tools = []
113
+ for func in self._tool_registry._swaig_functions.values():
114
+ if isinstance(func, dict):
115
+ # Raw dictionary from register_swaig_function (e.g., DataMap)
116
+ tools.append(func)
117
+ else:
118
+ # SWAIGFunction object from define_tool
119
+ tools.append(func)
120
+ return tools
121
+
122
+ def on_function_call(self, name: str, args: Dict[str, Any], raw_data: Optional[Dict[str, Any]] = None) -> Any:
123
+ """
124
+ Called when a SWAIG function is invoked
125
+
126
+ Args:
127
+ name: Function name
128
+ args: Function arguments
129
+ raw_data: Raw request data
130
+
131
+ Returns:
132
+ Function result
133
+ """
134
+ # Check if the function is registered
135
+ if name not in self._tool_registry._swaig_functions:
136
+ # If the function is not found, return an error
137
+ return {"response": f"Function '{name}' not found"}
138
+
139
+ # Get the function
140
+ func = self._tool_registry._swaig_functions[name]
141
+
142
+ # Check if this is a data_map function (raw dictionary)
143
+ if isinstance(func, dict):
144
+ # Data_map functions execute on SignalWire's server, not here
145
+ # This should never be called, but if it is, return an error
146
+ return {"response": f"Data map function '{name}' should be executed by SignalWire server, not locally"}
147
+
148
+ # Check if this is an external webhook function
149
+ if hasattr(func, 'webhook_url') and func.webhook_url:
150
+ # External webhook functions should be called directly by SignalWire, not locally
151
+ return {"response": f"External webhook function '{name}' should be executed by SignalWire at {func.webhook_url}, not locally"}
152
+
153
+ # Call the handler for regular SWAIG functions
154
+ try:
155
+ result = func.handler(args, raw_data)
156
+ if result is None:
157
+ # If the handler returns None, create a default response
158
+ result = SwaigFunctionResult("Function executed successfully")
159
+ return result
160
+ except Exception as e:
161
+ # If the handler raises an exception, return an error response
162
+ return {"response": f"Error executing function '{name}': {str(e)}"}
163
+
164
+
165
+ def _execute_swaig_function(self, function_name: str, args: Optional[Dict[str, Any]] = None, call_id: Optional[str] = None, raw_data: Optional[Dict[str, Any]] = None):
166
+ """
167
+ Execute a SWAIG function in serverless context
168
+
169
+ Args:
170
+ function_name: Name of the function to execute
171
+ args: Function arguments dictionary
172
+ call_id: Optional call ID
173
+ raw_data: Optional raw request data
174
+
175
+ Returns:
176
+ Function execution result
177
+ """
178
+ # Use the existing logger
179
+ req_log = self.log.bind(
180
+ endpoint="serverless_swaig",
181
+ function=function_name
182
+ )
183
+
184
+ if call_id:
185
+ req_log = req_log.bind(call_id=call_id)
186
+
187
+ req_log.debug("serverless_function_call_received")
188
+
189
+ try:
190
+ # Validate function exists
191
+ if function_name not in self._tool_registry._swaig_functions:
192
+ req_log.warning("function_not_found", available_functions=list(self._tool_registry._swaig_functions.keys()))
193
+ return {"error": f"Function '{function_name}' not found"}
194
+
195
+ # Use empty args if not provided
196
+ if args is None:
197
+ args = {}
198
+
199
+ # Use empty raw_data if not provided, but include function call structure
200
+ if raw_data is None:
201
+ raw_data = {
202
+ "function": function_name,
203
+ "argument": {
204
+ "parsed": [args] if args else [],
205
+ "raw": json.dumps(args) if args else "{}"
206
+ }
207
+ }
208
+ if call_id:
209
+ raw_data["call_id"] = call_id
210
+
211
+ req_log.debug("executing_function", args=json.dumps(args))
212
+
213
+ # Call the function using the existing on_function_call method
214
+ result = self.on_function_call(function_name, args, raw_data)
215
+
216
+ # Convert result to dict if needed (same logic as in _handle_swaig_request)
217
+ if isinstance(result, SwaigFunctionResult):
218
+ result_dict = result.to_dict()
219
+ elif isinstance(result, dict):
220
+ result_dict = result
221
+ else:
222
+ result_dict = {"response": str(result)}
223
+
224
+ req_log.info("serverless_function_executed_successfully")
225
+ req_log.debug("function_result", result=json.dumps(result_dict))
226
+ return result_dict
227
+
228
+ except Exception as e:
229
+ req_log.error("serverless_function_execution_error", error=str(e))
230
+ return {"error": str(e), "function": function_name}