signalwire-agents 0.1.20__py3-none-any.whl → 0.1.23__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 (37) hide show
  1. signalwire_agents/__init__.py +1 -1
  2. signalwire_agents/agent_server.py +50 -11
  3. signalwire_agents/core/__init__.py +2 -2
  4. signalwire_agents/core/agent/__init__.py +14 -0
  5. signalwire_agents/core/agent/config/__init__.py +14 -0
  6. signalwire_agents/core/agent/config/ephemeral.py +176 -0
  7. signalwire_agents/core/agent/deployment/__init__.py +0 -0
  8. signalwire_agents/core/agent/deployment/handlers/__init__.py +0 -0
  9. signalwire_agents/core/agent/prompt/__init__.py +14 -0
  10. signalwire_agents/core/agent/prompt/manager.py +288 -0
  11. signalwire_agents/core/agent/routing/__init__.py +0 -0
  12. signalwire_agents/core/agent/security/__init__.py +0 -0
  13. signalwire_agents/core/agent/swml/__init__.py +0 -0
  14. signalwire_agents/core/agent/tools/__init__.py +15 -0
  15. signalwire_agents/core/agent/tools/decorator.py +95 -0
  16. signalwire_agents/core/agent/tools/registry.py +192 -0
  17. signalwire_agents/core/agent_base.py +131 -413
  18. signalwire_agents/core/data_map.py +3 -15
  19. signalwire_agents/core/skill_manager.py +0 -17
  20. signalwire_agents/core/swaig_function.py +0 -2
  21. signalwire_agents/core/swml_builder.py +207 -11
  22. signalwire_agents/core/swml_renderer.py +123 -312
  23. signalwire_agents/core/swml_service.py +25 -94
  24. signalwire_agents/search/index_builder.py +1 -1
  25. signalwire_agents/skills/api_ninjas_trivia/__init__.py +3 -0
  26. signalwire_agents/skills/api_ninjas_trivia/skill.py +192 -0
  27. signalwire_agents/skills/play_background_file/__init__.py +3 -0
  28. signalwire_agents/skills/play_background_file/skill.py +197 -0
  29. signalwire_agents/skills/weather_api/__init__.py +3 -0
  30. signalwire_agents/skills/weather_api/skill.py +154 -0
  31. {signalwire_agents-0.1.20.dist-info → signalwire_agents-0.1.23.dist-info}/METADATA +5 -8
  32. {signalwire_agents-0.1.20.dist-info → signalwire_agents-0.1.23.dist-info}/RECORD +37 -18
  33. {signalwire_agents-0.1.20.data → signalwire_agents-0.1.23.data}/data/schema.json +0 -0
  34. {signalwire_agents-0.1.20.dist-info → signalwire_agents-0.1.23.dist-info}/WHEEL +0 -0
  35. {signalwire_agents-0.1.20.dist-info → signalwire_agents-0.1.23.dist-info}/entry_points.txt +0 -0
  36. {signalwire_agents-0.1.20.dist-info → signalwire_agents-0.1.23.dist-info}/licenses/LICENSE +0 -0
  37. {signalwire_agents-0.1.20.dist-info → signalwire_agents-0.1.23.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,95 @@
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
+ """Tool decorator functionality."""
11
+
12
+ from functools import wraps
13
+ from typing import Callable, Optional, Dict, Any
14
+ import logging
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+
19
+ class ToolDecorator:
20
+ """Handles tool decoration logic."""
21
+
22
+ @staticmethod
23
+ def create_instance_decorator(registry):
24
+ """
25
+ Create instance tool decorator.
26
+
27
+ Args:
28
+ registry: ToolRegistry instance to register with
29
+
30
+ Returns:
31
+ Decorator function
32
+ """
33
+ def decorator(name=None, **kwargs):
34
+ """
35
+ Decorator for defining SWAIG tools in a class.
36
+
37
+ Used as:
38
+
39
+ @agent.tool(name="example_function", parameters={...})
40
+ def example_function(self, param1):
41
+ # ...
42
+ """
43
+ def inner_decorator(func):
44
+ nonlocal name
45
+ if name is None:
46
+ name = func.__name__
47
+
48
+ parameters = kwargs.pop("parameters", {})
49
+ description = kwargs.pop("description", func.__doc__ or f"Function {name}")
50
+ secure = kwargs.pop("secure", True)
51
+ fillers = kwargs.pop("fillers", None)
52
+ webhook_url = kwargs.pop("webhook_url", None)
53
+
54
+ registry.define_tool(
55
+ name=name,
56
+ description=description,
57
+ parameters=parameters,
58
+ handler=func,
59
+ secure=secure,
60
+ fillers=fillers,
61
+ webhook_url=webhook_url,
62
+ **kwargs # Pass through any additional swaig_fields
63
+ )
64
+ return func
65
+ return inner_decorator
66
+ return decorator
67
+
68
+ @classmethod
69
+ def create_class_decorator(cls):
70
+ """
71
+ Create class tool decorator.
72
+
73
+ Returns:
74
+ Decorator function
75
+ """
76
+ def tool(name=None, **kwargs):
77
+ """
78
+ Class method decorator for defining SWAIG tools.
79
+
80
+ Used as:
81
+
82
+ @AgentBase.tool(name="example_function", parameters={...})
83
+ def example_function(self, param1):
84
+ # ...
85
+ """
86
+ def decorator(func):
87
+ # Mark the function as a tool
88
+ func._is_tool = True
89
+ func._tool_name = name if name else func.__name__
90
+ func._tool_params = kwargs
91
+
92
+ # Return the original function
93
+ return func
94
+ return decorator
95
+ return tool
@@ -0,0 +1,192 @@
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
+ """Tool registration and management."""
11
+
12
+ from typing import Dict, Any, Optional, List, Callable, Union
13
+ import inspect
14
+ import logging
15
+
16
+ from signalwire_agents.core.swaig_function import SWAIGFunction
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+ class ToolRegistry:
22
+ """Manages SWAIG function registration."""
23
+
24
+ def __init__(self, agent):
25
+ """
26
+ Initialize ToolRegistry with reference to parent agent.
27
+
28
+ Args:
29
+ agent: Parent AgentBase instance
30
+ """
31
+ self.agent = agent
32
+ self._swaig_functions = {}
33
+ self._class_decorated_tools = []
34
+
35
+ def define_tool(
36
+ self,
37
+ name: str,
38
+ description: str,
39
+ parameters: Dict[str, Any],
40
+ handler: Callable,
41
+ secure: bool = True,
42
+ fillers: Optional[Dict[str, List[str]]] = None,
43
+ webhook_url: Optional[str] = None,
44
+ **swaig_fields
45
+ ) -> None:
46
+ """
47
+ Define a SWAIG function that the AI can call.
48
+
49
+ Args:
50
+ name: Function name (must be unique)
51
+ description: Function description for the AI
52
+ parameters: JSON Schema of parameters
53
+ handler: Function to call when invoked
54
+ secure: Whether to require token validation
55
+ fillers: Optional dict mapping language codes to arrays of filler phrases
56
+ webhook_url: Optional external webhook URL to use instead of local handling
57
+ **swaig_fields: Additional SWAIG fields to include in function definition
58
+
59
+ Raises:
60
+ ValueError: If tool name already exists
61
+ """
62
+ if name in self._swaig_functions:
63
+ raise ValueError(f"Tool with name '{name}' already exists")
64
+
65
+ self._swaig_functions[name] = SWAIGFunction(
66
+ name=name,
67
+ description=description,
68
+ parameters=parameters,
69
+ handler=handler,
70
+ secure=secure,
71
+ fillers=fillers,
72
+ webhook_url=webhook_url,
73
+ **swaig_fields
74
+ )
75
+
76
+ logger.debug(f"Defined tool: {name}")
77
+
78
+ def register_swaig_function(self, function_dict: Dict[str, Any]) -> None:
79
+ """
80
+ Register a raw SWAIG function dictionary (e.g., from DataMap.to_swaig_function()).
81
+
82
+ Args:
83
+ function_dict: Complete SWAIG function definition dictionary
84
+
85
+ Raises:
86
+ ValueError: If function name missing or already exists
87
+ """
88
+ function_name = function_dict.get('function')
89
+ if not function_name:
90
+ raise ValueError("Function dictionary must contain 'function' field with the function name")
91
+
92
+ if function_name in self._swaig_functions:
93
+ raise ValueError(f"Tool with name '{function_name}' already exists")
94
+
95
+ # Store the raw function dictionary for data_map tools
96
+ # These don't have handlers since they execute on SignalWire's server
97
+ self._swaig_functions[function_name] = function_dict
98
+
99
+ logger.debug(f"Registered SWAIG function: {function_name}")
100
+
101
+ def register_class_decorated_tools(self) -> None:
102
+ """
103
+ Register tools defined with @AgentBase.tool class decorator.
104
+
105
+ This method scans the class for methods decorated with @AgentBase.tool
106
+ and registers them automatically.
107
+ """
108
+ # Get the class of this instance
109
+ cls = self.agent.__class__
110
+
111
+ # Loop through all attributes in the class
112
+ for name in dir(cls):
113
+ # Get the attribute
114
+ attr = getattr(cls, name)
115
+
116
+ # Check if it's a method decorated with @AgentBase.tool
117
+ if inspect.ismethod(attr) or inspect.isfunction(attr):
118
+ if hasattr(attr, "_is_tool") and getattr(attr, "_is_tool", False):
119
+ # Extract tool information
120
+ tool_name = getattr(attr, "_tool_name", name)
121
+ tool_params = getattr(attr, "_tool_params", {})
122
+
123
+ # Extract known parameters and pass through the rest as swaig_fields
124
+ tool_params_copy = tool_params.copy()
125
+ description = tool_params_copy.pop("description", attr.__doc__ or f"Function {tool_name}")
126
+ parameters = tool_params_copy.pop("parameters", {})
127
+ secure = tool_params_copy.pop("secure", True)
128
+ fillers = tool_params_copy.pop("fillers", None)
129
+ webhook_url = tool_params_copy.pop("webhook_url", None)
130
+
131
+ # Register the tool with any remaining params as swaig_fields
132
+ self.define_tool(
133
+ name=tool_name,
134
+ description=description,
135
+ parameters=parameters,
136
+ handler=attr.__get__(self.agent, cls), # Bind the method to this instance
137
+ secure=secure,
138
+ fillers=fillers,
139
+ webhook_url=webhook_url,
140
+ **tool_params_copy # Pass through any additional swaig_fields
141
+ )
142
+
143
+ logger.debug(f"Registered class-decorated tool: {tool_name}")
144
+
145
+ def get_function(self, name: str) -> Optional[Union[SWAIGFunction, Dict[str, Any]]]:
146
+ """
147
+ Get a registered function by name.
148
+
149
+ Args:
150
+ name: Function name
151
+
152
+ Returns:
153
+ SWAIGFunction instance or raw function dict, or None if not found
154
+ """
155
+ return self._swaig_functions.get(name)
156
+
157
+ def get_all_functions(self) -> Dict[str, Union[SWAIGFunction, Dict[str, Any]]]:
158
+ """
159
+ Get all registered functions.
160
+
161
+ Returns:
162
+ Dictionary of function name to function object/dict
163
+ """
164
+ return self._swaig_functions.copy()
165
+
166
+ def has_function(self, name: str) -> bool:
167
+ """
168
+ Check if a function is registered.
169
+
170
+ Args:
171
+ name: Function name
172
+
173
+ Returns:
174
+ True if function exists, False otherwise
175
+ """
176
+ return name in self._swaig_functions
177
+
178
+ def remove_function(self, name: str) -> bool:
179
+ """
180
+ Remove a registered function.
181
+
182
+ Args:
183
+ name: Function name
184
+
185
+ Returns:
186
+ True if removed, False if not found
187
+ """
188
+ if name in self._swaig_functions:
189
+ del self._swaig_functions[name]
190
+ logger.debug(f"Removed function: {name}")
191
+ return True
192
+ return False