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.
- signalwire_agents/__init__.py +1 -1
- signalwire_agents/agent_server.py +50 -11
- signalwire_agents/core/__init__.py +2 -2
- signalwire_agents/core/agent/__init__.py +14 -0
- signalwire_agents/core/agent/config/__init__.py +14 -0
- signalwire_agents/core/agent/config/ephemeral.py +176 -0
- signalwire_agents/core/agent/deployment/__init__.py +0 -0
- signalwire_agents/core/agent/deployment/handlers/__init__.py +0 -0
- signalwire_agents/core/agent/prompt/__init__.py +14 -0
- signalwire_agents/core/agent/prompt/manager.py +288 -0
- signalwire_agents/core/agent/routing/__init__.py +0 -0
- signalwire_agents/core/agent/security/__init__.py +0 -0
- signalwire_agents/core/agent/swml/__init__.py +0 -0
- signalwire_agents/core/agent/tools/__init__.py +15 -0
- signalwire_agents/core/agent/tools/decorator.py +95 -0
- signalwire_agents/core/agent/tools/registry.py +192 -0
- signalwire_agents/core/agent_base.py +131 -413
- signalwire_agents/core/data_map.py +3 -15
- signalwire_agents/core/skill_manager.py +0 -17
- signalwire_agents/core/swaig_function.py +0 -2
- signalwire_agents/core/swml_builder.py +207 -11
- signalwire_agents/core/swml_renderer.py +123 -312
- signalwire_agents/core/swml_service.py +25 -94
- signalwire_agents/search/index_builder.py +1 -1
- signalwire_agents/skills/api_ninjas_trivia/__init__.py +3 -0
- signalwire_agents/skills/api_ninjas_trivia/skill.py +192 -0
- signalwire_agents/skills/play_background_file/__init__.py +3 -0
- signalwire_agents/skills/play_background_file/skill.py +197 -0
- signalwire_agents/skills/weather_api/__init__.py +3 -0
- signalwire_agents/skills/weather_api/skill.py +154 -0
- {signalwire_agents-0.1.20.dist-info → signalwire_agents-0.1.23.dist-info}/METADATA +5 -8
- {signalwire_agents-0.1.20.dist-info → signalwire_agents-0.1.23.dist-info}/RECORD +37 -18
- {signalwire_agents-0.1.20.data → signalwire_agents-0.1.23.data}/data/schema.json +0 -0
- {signalwire_agents-0.1.20.dist-info → signalwire_agents-0.1.23.dist-info}/WHEEL +0 -0
- {signalwire_agents-0.1.20.dist-info → signalwire_agents-0.1.23.dist-info}/entry_points.txt +0 -0
- {signalwire_agents-0.1.20.dist-info → signalwire_agents-0.1.23.dist-info}/licenses/LICENSE +0 -0
- {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
|