signalwire-agents 0.1.6__py3-none-any.whl → 1.0.7__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 +130 -4
- signalwire_agents/agent_server.py +438 -32
- signalwire_agents/agents/bedrock.py +296 -0
- signalwire_agents/cli/__init__.py +18 -0
- signalwire_agents/cli/build_search.py +1367 -0
- signalwire_agents/cli/config.py +80 -0
- signalwire_agents/cli/core/__init__.py +10 -0
- signalwire_agents/cli/core/agent_loader.py +470 -0
- signalwire_agents/cli/core/argparse_helpers.py +179 -0
- signalwire_agents/cli/core/dynamic_config.py +71 -0
- signalwire_agents/cli/core/service_loader.py +303 -0
- signalwire_agents/cli/execution/__init__.py +10 -0
- signalwire_agents/cli/execution/datamap_exec.py +446 -0
- signalwire_agents/cli/execution/webhook_exec.py +134 -0
- signalwire_agents/cli/init_project.py +1225 -0
- signalwire_agents/cli/output/__init__.py +10 -0
- signalwire_agents/cli/output/output_formatter.py +255 -0
- signalwire_agents/cli/output/swml_dump.py +186 -0
- signalwire_agents/cli/simulation/__init__.py +10 -0
- signalwire_agents/cli/simulation/data_generation.py +374 -0
- signalwire_agents/cli/simulation/data_overrides.py +200 -0
- signalwire_agents/cli/simulation/mock_env.py +282 -0
- signalwire_agents/cli/swaig_test_wrapper.py +52 -0
- signalwire_agents/cli/test_swaig.py +809 -0
- signalwire_agents/cli/types.py +81 -0
- signalwire_agents/core/__init__.py +2 -2
- signalwire_agents/core/agent/__init__.py +12 -0
- signalwire_agents/core/agent/config/__init__.py +12 -0
- signalwire_agents/core/agent/deployment/__init__.py +9 -0
- signalwire_agents/core/agent/deployment/handlers/__init__.py +9 -0
- signalwire_agents/core/agent/prompt/__init__.py +14 -0
- signalwire_agents/core/agent/prompt/manager.py +306 -0
- signalwire_agents/core/agent/routing/__init__.py +9 -0
- signalwire_agents/core/agent/security/__init__.py +9 -0
- signalwire_agents/core/agent/swml/__init__.py +9 -0
- signalwire_agents/core/agent/tools/__init__.py +15 -0
- signalwire_agents/core/agent/tools/decorator.py +97 -0
- signalwire_agents/core/agent/tools/registry.py +210 -0
- signalwire_agents/core/agent_base.py +959 -2166
- signalwire_agents/core/auth_handler.py +233 -0
- signalwire_agents/core/config_loader.py +259 -0
- signalwire_agents/core/contexts.py +707 -0
- signalwire_agents/core/data_map.py +487 -0
- signalwire_agents/core/function_result.py +1150 -1
- signalwire_agents/core/logging_config.py +376 -0
- signalwire_agents/core/mixins/__init__.py +28 -0
- signalwire_agents/core/mixins/ai_config_mixin.py +442 -0
- signalwire_agents/core/mixins/auth_mixin.py +287 -0
- signalwire_agents/core/mixins/prompt_mixin.py +358 -0
- signalwire_agents/core/mixins/serverless_mixin.py +368 -0
- signalwire_agents/core/mixins/skill_mixin.py +55 -0
- signalwire_agents/core/mixins/state_mixin.py +153 -0
- signalwire_agents/core/mixins/tool_mixin.py +230 -0
- signalwire_agents/core/mixins/web_mixin.py +1134 -0
- signalwire_agents/core/security/session_manager.py +174 -86
- signalwire_agents/core/security_config.py +333 -0
- signalwire_agents/core/skill_base.py +200 -0
- signalwire_agents/core/skill_manager.py +244 -0
- signalwire_agents/core/swaig_function.py +33 -9
- signalwire_agents/core/swml_builder.py +212 -12
- signalwire_agents/core/swml_handler.py +43 -13
- signalwire_agents/core/swml_renderer.py +123 -297
- signalwire_agents/core/swml_service.py +277 -260
- signalwire_agents/prefabs/concierge.py +6 -2
- signalwire_agents/prefabs/info_gatherer.py +149 -33
- signalwire_agents/prefabs/receptionist.py +14 -22
- signalwire_agents/prefabs/survey.py +6 -2
- signalwire_agents/schema.json +9218 -5489
- signalwire_agents/search/__init__.py +137 -0
- signalwire_agents/search/document_processor.py +1223 -0
- signalwire_agents/search/index_builder.py +804 -0
- signalwire_agents/search/migration.py +418 -0
- signalwire_agents/search/models.py +30 -0
- signalwire_agents/search/pgvector_backend.py +752 -0
- signalwire_agents/search/query_processor.py +502 -0
- signalwire_agents/search/search_engine.py +1264 -0
- signalwire_agents/search/search_service.py +574 -0
- signalwire_agents/skills/README.md +452 -0
- signalwire_agents/skills/__init__.py +23 -0
- signalwire_agents/skills/api_ninjas_trivia/README.md +215 -0
- signalwire_agents/skills/api_ninjas_trivia/__init__.py +12 -0
- signalwire_agents/skills/api_ninjas_trivia/skill.py +237 -0
- signalwire_agents/skills/datasphere/README.md +210 -0
- signalwire_agents/skills/datasphere/__init__.py +12 -0
- signalwire_agents/skills/datasphere/skill.py +310 -0
- signalwire_agents/skills/datasphere_serverless/README.md +258 -0
- signalwire_agents/skills/datasphere_serverless/__init__.py +10 -0
- signalwire_agents/skills/datasphere_serverless/skill.py +237 -0
- signalwire_agents/skills/datetime/README.md +132 -0
- signalwire_agents/skills/datetime/__init__.py +10 -0
- signalwire_agents/skills/datetime/skill.py +126 -0
- signalwire_agents/skills/joke/README.md +149 -0
- signalwire_agents/skills/joke/__init__.py +10 -0
- signalwire_agents/skills/joke/skill.py +109 -0
- signalwire_agents/skills/math/README.md +161 -0
- signalwire_agents/skills/math/__init__.py +10 -0
- signalwire_agents/skills/math/skill.py +105 -0
- signalwire_agents/skills/mcp_gateway/README.md +230 -0
- signalwire_agents/skills/mcp_gateway/__init__.py +10 -0
- signalwire_agents/skills/mcp_gateway/skill.py +421 -0
- signalwire_agents/skills/native_vector_search/README.md +210 -0
- signalwire_agents/skills/native_vector_search/__init__.py +10 -0
- signalwire_agents/skills/native_vector_search/skill.py +820 -0
- signalwire_agents/skills/play_background_file/README.md +218 -0
- signalwire_agents/skills/play_background_file/__init__.py +12 -0
- signalwire_agents/skills/play_background_file/skill.py +242 -0
- signalwire_agents/skills/registry.py +459 -0
- signalwire_agents/skills/spider/README.md +236 -0
- signalwire_agents/skills/spider/__init__.py +13 -0
- signalwire_agents/skills/spider/skill.py +598 -0
- signalwire_agents/skills/swml_transfer/README.md +395 -0
- signalwire_agents/skills/swml_transfer/__init__.py +10 -0
- signalwire_agents/skills/swml_transfer/skill.py +359 -0
- signalwire_agents/skills/weather_api/README.md +178 -0
- signalwire_agents/skills/weather_api/__init__.py +12 -0
- signalwire_agents/skills/weather_api/skill.py +191 -0
- signalwire_agents/skills/web_search/README.md +163 -0
- signalwire_agents/skills/web_search/__init__.py +10 -0
- signalwire_agents/skills/web_search/skill.py +739 -0
- signalwire_agents/skills/wikipedia_search/README.md +228 -0
- signalwire_agents/{core/state → skills/wikipedia_search}/__init__.py +5 -4
- signalwire_agents/skills/wikipedia_search/skill.py +210 -0
- signalwire_agents/utils/__init__.py +14 -0
- signalwire_agents/utils/schema_utils.py +111 -44
- signalwire_agents/web/__init__.py +17 -0
- signalwire_agents/web/web_service.py +559 -0
- signalwire_agents-1.0.7.data/data/share/man/man1/sw-agent-init.1 +307 -0
- signalwire_agents-1.0.7.data/data/share/man/man1/sw-search.1 +483 -0
- signalwire_agents-1.0.7.data/data/share/man/man1/swaig-test.1 +308 -0
- signalwire_agents-1.0.7.dist-info/METADATA +992 -0
- signalwire_agents-1.0.7.dist-info/RECORD +142 -0
- {signalwire_agents-0.1.6.dist-info → signalwire_agents-1.0.7.dist-info}/WHEEL +1 -1
- signalwire_agents-1.0.7.dist-info/entry_points.txt +4 -0
- signalwire_agents/core/state/file_state_manager.py +0 -219
- signalwire_agents/core/state/state_manager.py +0 -101
- signalwire_agents-0.1.6.data/data/schema.json +0 -5611
- signalwire_agents-0.1.6.dist-info/METADATA +0 -199
- signalwire_agents-0.1.6.dist-info/RECORD +0 -34
- {signalwire_agents-0.1.6.dist-info → signalwire_agents-1.0.7.dist-info}/licenses/LICENSE +0 -0
- {signalwire_agents-0.1.6.dist-info → signalwire_agents-1.0.7.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,487 @@
|
|
|
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
|
+
DataMap class for building SWAIG data_map configurations
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from typing import Dict, List, Any, Optional, Union, Pattern, Tuple
|
|
15
|
+
import re
|
|
16
|
+
from .function_result import SwaigFunctionResult
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class DataMap:
|
|
20
|
+
"""
|
|
21
|
+
Builder class for creating SWAIG data_map configurations.
|
|
22
|
+
|
|
23
|
+
This provides a fluent interface for building data_map tools that execute
|
|
24
|
+
on the SignalWire server without requiring webhook endpoints. Works similar
|
|
25
|
+
to SwaigFunctionResult but for building data_map structures.
|
|
26
|
+
|
|
27
|
+
Example usage:
|
|
28
|
+
# Simple API call - output goes inside webhook
|
|
29
|
+
data_map = (DataMap('get_weather')
|
|
30
|
+
.purpose('Get current weather information')
|
|
31
|
+
.parameter('location', 'string', 'City name', required=True)
|
|
32
|
+
.webhook('GET', 'https://api.weather.com/v1/current?key=API_KEY&q=${location}')
|
|
33
|
+
.output(SwaigFunctionResult('Weather in ${location}: ${response.current.condition.text}, ${response.current.temp_f}°F'))
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
# Multiple webhooks with fallback
|
|
37
|
+
data_map = (DataMap('search_multi')
|
|
38
|
+
.purpose('Search with fallback APIs')
|
|
39
|
+
.parameter('query', 'string', 'Search query', required=True)
|
|
40
|
+
.webhook('GET', 'https://api.primary.com/search?q=${query}')
|
|
41
|
+
.output(SwaigFunctionResult('Primary result: ${response.title}'))
|
|
42
|
+
.webhook('GET', 'https://api.fallback.com/search?q=${query}')
|
|
43
|
+
.output(SwaigFunctionResult('Fallback result: ${response.title}'))
|
|
44
|
+
.fallback_output(SwaigFunctionResult('Sorry, all search APIs are unavailable'))
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
# Expression-based responses (no API calls)
|
|
48
|
+
data_map = (DataMap('file_control')
|
|
49
|
+
.purpose('Control file playback')
|
|
50
|
+
.parameter('command', 'string', 'Playback command')
|
|
51
|
+
.parameter('filename', 'string', 'File to control', required=False)
|
|
52
|
+
.expression('${args.command}', r'start.*', SwaigFunctionResult().add_action('start_playbook', {'file': '${args.filename}'}))
|
|
53
|
+
.expression('${args.command}', r'stop.*', SwaigFunctionResult().add_action('stop_playback', True))
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
# API with array processing
|
|
57
|
+
data_map = (DataMap('search_docs')
|
|
58
|
+
.purpose('Search documentation')
|
|
59
|
+
.parameter('query', 'string', 'Search query', required=True)
|
|
60
|
+
.webhook('POST', 'https://api.docs.com/search', headers={'Authorization': 'Bearer TOKEN'})
|
|
61
|
+
.body({'query': '${query}', 'limit': 3})
|
|
62
|
+
.output(SwaigFunctionResult('Found: ${response.results[0].title} - ${response.results[0].summary}'))
|
|
63
|
+
.foreach('${response.results}')
|
|
64
|
+
)
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
def __init__(self, function_name: str):
|
|
68
|
+
"""
|
|
69
|
+
Initialize a new DataMap builder
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
function_name: Name of the SWAIG function this data_map will create
|
|
73
|
+
"""
|
|
74
|
+
self.function_name = function_name
|
|
75
|
+
self._purpose = ""
|
|
76
|
+
self._parameters = {}
|
|
77
|
+
self._expressions = []
|
|
78
|
+
self._webhooks = []
|
|
79
|
+
self._output = None
|
|
80
|
+
self._error_keys = []
|
|
81
|
+
|
|
82
|
+
def purpose(self, description: str) -> 'DataMap':
|
|
83
|
+
"""
|
|
84
|
+
Set the function description/purpose
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
description: Human-readable description of what this function does
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
Self for method chaining
|
|
91
|
+
"""
|
|
92
|
+
self._purpose = description
|
|
93
|
+
return self
|
|
94
|
+
|
|
95
|
+
def description(self, description: str) -> 'DataMap':
|
|
96
|
+
"""
|
|
97
|
+
Set the function description (alias for purpose)
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
description: Human-readable description of what this function does
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
Self for method chaining
|
|
104
|
+
"""
|
|
105
|
+
return self.purpose(description)
|
|
106
|
+
|
|
107
|
+
def parameter(self, name: str, param_type: str, description: str,
|
|
108
|
+
required: bool = False, enum: Optional[List[str]] = None) -> 'DataMap':
|
|
109
|
+
"""
|
|
110
|
+
Add a function parameter
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
name: Parameter name
|
|
114
|
+
param_type: JSON schema type (string, number, boolean, array, object)
|
|
115
|
+
description: Parameter description
|
|
116
|
+
required: Whether parameter is required
|
|
117
|
+
enum: Optional list of allowed values
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
Self for method chaining
|
|
121
|
+
"""
|
|
122
|
+
param_def = {
|
|
123
|
+
"type": param_type,
|
|
124
|
+
"description": description
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if enum:
|
|
128
|
+
param_def["enum"] = enum
|
|
129
|
+
|
|
130
|
+
self._parameters[name] = param_def
|
|
131
|
+
|
|
132
|
+
if required:
|
|
133
|
+
if "required" not in self._parameters:
|
|
134
|
+
self._parameters["required"] = []
|
|
135
|
+
if name not in self._parameters["required"]:
|
|
136
|
+
self._parameters["required"].append(name)
|
|
137
|
+
|
|
138
|
+
return self
|
|
139
|
+
|
|
140
|
+
def expression(self, test_value: str, pattern: Union[str, Pattern], output: SwaigFunctionResult,
|
|
141
|
+
nomatch_output: Optional[SwaigFunctionResult] = None) -> 'DataMap':
|
|
142
|
+
"""
|
|
143
|
+
Add an expression pattern for pattern-based responses
|
|
144
|
+
|
|
145
|
+
Args:
|
|
146
|
+
test_value: Template string to test (e.g., "${args.command}")
|
|
147
|
+
pattern: Regex pattern string or compiled Pattern object to match against
|
|
148
|
+
output: SwaigFunctionResult to return when pattern matches
|
|
149
|
+
nomatch_output: Optional SwaigFunctionResult to return when pattern doesn't match
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
Self for method chaining
|
|
153
|
+
"""
|
|
154
|
+
if isinstance(pattern, Pattern):
|
|
155
|
+
pattern_str = pattern.pattern
|
|
156
|
+
else:
|
|
157
|
+
pattern_str = str(pattern)
|
|
158
|
+
|
|
159
|
+
expr_def = {
|
|
160
|
+
"string": test_value,
|
|
161
|
+
"pattern": pattern_str,
|
|
162
|
+
"output": output.to_dict()
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if nomatch_output:
|
|
166
|
+
expr_def["nomatch-output"] = nomatch_output.to_dict()
|
|
167
|
+
|
|
168
|
+
self._expressions.append(expr_def)
|
|
169
|
+
return self
|
|
170
|
+
|
|
171
|
+
def webhook(self, method: str, url: str, headers: Optional[Dict[str, str]] = None,
|
|
172
|
+
form_param: Optional[str] = None,
|
|
173
|
+
input_args_as_params: bool = False,
|
|
174
|
+
require_args: Optional[List[str]] = None) -> 'DataMap':
|
|
175
|
+
"""
|
|
176
|
+
Add a webhook API call
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
method: HTTP method (GET, POST, PUT, DELETE, etc.)
|
|
180
|
+
url: API endpoint URL (can include ${variable} substitutions)
|
|
181
|
+
headers: Optional HTTP headers
|
|
182
|
+
form_param: Send JSON body as single form parameter with this name
|
|
183
|
+
input_args_as_params: Merge function arguments into params
|
|
184
|
+
require_args: Only execute if these arguments are present
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
Self for method chaining
|
|
188
|
+
"""
|
|
189
|
+
webhook_def = {
|
|
190
|
+
"url": url,
|
|
191
|
+
"method": method.upper()
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if headers:
|
|
195
|
+
webhook_def["headers"] = headers
|
|
196
|
+
if form_param:
|
|
197
|
+
webhook_def["form_param"] = form_param
|
|
198
|
+
if input_args_as_params:
|
|
199
|
+
webhook_def["input_args_as_params"] = True
|
|
200
|
+
if require_args:
|
|
201
|
+
webhook_def["require_args"] = require_args
|
|
202
|
+
|
|
203
|
+
self._webhooks.append(webhook_def)
|
|
204
|
+
return self
|
|
205
|
+
|
|
206
|
+
def webhook_expressions(self, expressions: List[Dict[str, Any]]) -> 'DataMap':
|
|
207
|
+
"""
|
|
208
|
+
Add expressions that run after the most recent webhook completes
|
|
209
|
+
|
|
210
|
+
Args:
|
|
211
|
+
expressions: List of expression definitions to check post-webhook
|
|
212
|
+
|
|
213
|
+
Returns:
|
|
214
|
+
Self for method chaining
|
|
215
|
+
"""
|
|
216
|
+
if not self._webhooks:
|
|
217
|
+
raise ValueError("Must add webhook before setting webhook expressions")
|
|
218
|
+
|
|
219
|
+
self._webhooks[-1]["expressions"] = expressions
|
|
220
|
+
return self
|
|
221
|
+
|
|
222
|
+
def body(self, data: Dict[str, Any]) -> 'DataMap':
|
|
223
|
+
"""
|
|
224
|
+
Set request body for the last added webhook (POST/PUT requests)
|
|
225
|
+
|
|
226
|
+
Args:
|
|
227
|
+
data: Request body data (can include ${variable} substitutions)
|
|
228
|
+
|
|
229
|
+
Returns:
|
|
230
|
+
Self for method chaining
|
|
231
|
+
"""
|
|
232
|
+
if not self._webhooks:
|
|
233
|
+
raise ValueError("Must add webhook before setting body")
|
|
234
|
+
|
|
235
|
+
self._webhooks[-1]["body"] = data
|
|
236
|
+
return self
|
|
237
|
+
|
|
238
|
+
def params(self, data: Dict[str, Any]) -> 'DataMap':
|
|
239
|
+
"""
|
|
240
|
+
Set request params for the last added webhook (alias for body)
|
|
241
|
+
|
|
242
|
+
Args:
|
|
243
|
+
data: Request params data (can include ${variable} substitutions)
|
|
244
|
+
|
|
245
|
+
Returns:
|
|
246
|
+
Self for method chaining
|
|
247
|
+
"""
|
|
248
|
+
if not self._webhooks:
|
|
249
|
+
raise ValueError("Must add webhook before setting params")
|
|
250
|
+
|
|
251
|
+
self._webhooks[-1]["params"] = data
|
|
252
|
+
return self
|
|
253
|
+
|
|
254
|
+
def foreach(self, foreach_config: Union[str, Dict[str, Any]]) -> 'DataMap':
|
|
255
|
+
"""
|
|
256
|
+
Process an array from the webhook response using foreach mechanism
|
|
257
|
+
|
|
258
|
+
Args:
|
|
259
|
+
foreach_config: Either:
|
|
260
|
+
- Dict: Foreach configuration with keys:
|
|
261
|
+
- input_key: Key in API response containing the array
|
|
262
|
+
- output_key: Name for the built string variable
|
|
263
|
+
- max: Maximum number of items to process (optional)
|
|
264
|
+
- append: Template string to append for each item
|
|
265
|
+
|
|
266
|
+
Returns:
|
|
267
|
+
Self for method chaining
|
|
268
|
+
|
|
269
|
+
Example:
|
|
270
|
+
.foreach({
|
|
271
|
+
"input_key": "results",
|
|
272
|
+
"output_key": "formatted_results",
|
|
273
|
+
"max": 3,
|
|
274
|
+
"append": "Result: ${this.title} - ${this.summary}\n"
|
|
275
|
+
})
|
|
276
|
+
"""
|
|
277
|
+
if not self._webhooks:
|
|
278
|
+
raise ValueError("Must add webhook before setting foreach")
|
|
279
|
+
|
|
280
|
+
if isinstance(foreach_config, dict):
|
|
281
|
+
# New format - validate required keys
|
|
282
|
+
required_keys = ["input_key", "output_key", "append"]
|
|
283
|
+
missing_keys = [key for key in required_keys if key not in foreach_config]
|
|
284
|
+
if missing_keys:
|
|
285
|
+
raise ValueError(f"foreach config missing required keys: {missing_keys}")
|
|
286
|
+
|
|
287
|
+
foreach_data = foreach_config
|
|
288
|
+
else:
|
|
289
|
+
raise ValueError("foreach_config must be a dictionary")
|
|
290
|
+
|
|
291
|
+
self._webhooks[-1]["foreach"] = foreach_data
|
|
292
|
+
return self
|
|
293
|
+
|
|
294
|
+
def output(self, result: SwaigFunctionResult) -> 'DataMap':
|
|
295
|
+
"""
|
|
296
|
+
Set the output result for the most recent webhook
|
|
297
|
+
|
|
298
|
+
Args:
|
|
299
|
+
result: SwaigFunctionResult defining the response for this webhook
|
|
300
|
+
|
|
301
|
+
Returns:
|
|
302
|
+
Self for method chaining
|
|
303
|
+
"""
|
|
304
|
+
if not self._webhooks:
|
|
305
|
+
raise ValueError("Must add webhook before setting output")
|
|
306
|
+
|
|
307
|
+
self._webhooks[-1]["output"] = result.to_dict()
|
|
308
|
+
return self
|
|
309
|
+
|
|
310
|
+
def fallback_output(self, result: SwaigFunctionResult) -> 'DataMap':
|
|
311
|
+
"""
|
|
312
|
+
Set a fallback output result at the top level (used when all webhooks fail)
|
|
313
|
+
|
|
314
|
+
Args:
|
|
315
|
+
result: SwaigFunctionResult defining the fallback response
|
|
316
|
+
|
|
317
|
+
Returns:
|
|
318
|
+
Self for method chaining
|
|
319
|
+
"""
|
|
320
|
+
self._output = result.to_dict()
|
|
321
|
+
return self
|
|
322
|
+
|
|
323
|
+
def error_keys(self, keys: List[str]) -> 'DataMap':
|
|
324
|
+
"""
|
|
325
|
+
Set error keys for the most recent webhook (if webhooks exist) or top-level
|
|
326
|
+
|
|
327
|
+
Args:
|
|
328
|
+
keys: List of JSON keys whose presence indicates an error
|
|
329
|
+
|
|
330
|
+
Returns:
|
|
331
|
+
Self for method chaining
|
|
332
|
+
"""
|
|
333
|
+
if self._webhooks:
|
|
334
|
+
# Add to most recent webhook
|
|
335
|
+
self._webhooks[-1]["error_keys"] = keys
|
|
336
|
+
else:
|
|
337
|
+
# Store as top-level error keys
|
|
338
|
+
self._error_keys = keys
|
|
339
|
+
return self
|
|
340
|
+
|
|
341
|
+
def global_error_keys(self, keys: List[str]) -> 'DataMap':
|
|
342
|
+
"""
|
|
343
|
+
Set top-level error keys (applies to all webhooks)
|
|
344
|
+
|
|
345
|
+
Args:
|
|
346
|
+
keys: List of JSON keys whose presence indicates an error
|
|
347
|
+
|
|
348
|
+
Returns:
|
|
349
|
+
Self for method chaining
|
|
350
|
+
"""
|
|
351
|
+
self._error_keys = keys
|
|
352
|
+
return self
|
|
353
|
+
|
|
354
|
+
def to_swaig_function(self) -> Dict[str, Any]:
|
|
355
|
+
"""
|
|
356
|
+
Convert this DataMap to a SWAIG function definition
|
|
357
|
+
|
|
358
|
+
Returns:
|
|
359
|
+
Dictionary with function definition and data_map instead of url
|
|
360
|
+
"""
|
|
361
|
+
# Build parameter schema
|
|
362
|
+
if self._parameters:
|
|
363
|
+
# Extract required params without mutating original dict
|
|
364
|
+
required_params = self._parameters.get("required", [])
|
|
365
|
+
param_properties = {k: v for k, v in self._parameters.items() if k != "required"}
|
|
366
|
+
|
|
367
|
+
param_schema = {
|
|
368
|
+
"type": "object",
|
|
369
|
+
"properties": param_properties
|
|
370
|
+
}
|
|
371
|
+
if required_params:
|
|
372
|
+
param_schema["required"] = required_params
|
|
373
|
+
else:
|
|
374
|
+
param_schema = {"type": "object", "properties": {}}
|
|
375
|
+
|
|
376
|
+
# Build data_map structure
|
|
377
|
+
data_map = {}
|
|
378
|
+
|
|
379
|
+
# Add expressions if present
|
|
380
|
+
if self._expressions:
|
|
381
|
+
data_map["expressions"] = self._expressions
|
|
382
|
+
|
|
383
|
+
# Add webhooks if present
|
|
384
|
+
if self._webhooks:
|
|
385
|
+
data_map["webhooks"] = self._webhooks
|
|
386
|
+
|
|
387
|
+
# Add output if present
|
|
388
|
+
if self._output:
|
|
389
|
+
data_map["output"] = self._output
|
|
390
|
+
|
|
391
|
+
# Add error_keys if present
|
|
392
|
+
if self._error_keys:
|
|
393
|
+
data_map["error_keys"] = self._error_keys
|
|
394
|
+
|
|
395
|
+
# Build final function definition with correct field names
|
|
396
|
+
function_def = {
|
|
397
|
+
"function": self.function_name,
|
|
398
|
+
"description": self._purpose or f"Execute {self.function_name}",
|
|
399
|
+
"parameters": param_schema,
|
|
400
|
+
"data_map": data_map
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
return function_def
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
def create_simple_api_tool(name: str, url: str, response_template: str,
|
|
407
|
+
parameters: Optional[Dict[str, Dict]] = None,
|
|
408
|
+
method: str = "GET", headers: Optional[Dict[str, str]] = None,
|
|
409
|
+
body: Optional[Dict[str, Any]] = None,
|
|
410
|
+
error_keys: Optional[List[str]] = None) -> DataMap:
|
|
411
|
+
"""
|
|
412
|
+
Create a simple API tool with minimal configuration
|
|
413
|
+
|
|
414
|
+
Args:
|
|
415
|
+
name: Function name
|
|
416
|
+
url: API endpoint URL
|
|
417
|
+
response_template: Template for formatting the response
|
|
418
|
+
parameters: Optional parameter definitions
|
|
419
|
+
method: HTTP method (default: GET)
|
|
420
|
+
headers: Optional HTTP headers
|
|
421
|
+
body: Optional request body (for POST/PUT)
|
|
422
|
+
error_keys: Optional list of error indicator keys
|
|
423
|
+
|
|
424
|
+
Returns:
|
|
425
|
+
Configured DataMap object
|
|
426
|
+
"""
|
|
427
|
+
data_map = DataMap(name)
|
|
428
|
+
|
|
429
|
+
# Add parameters if provided
|
|
430
|
+
if parameters:
|
|
431
|
+
for param_name, param_def in parameters.items():
|
|
432
|
+
required = param_def.get("required", False)
|
|
433
|
+
data_map.parameter(
|
|
434
|
+
param_name,
|
|
435
|
+
param_def.get("type", "string"),
|
|
436
|
+
param_def.get("description", f"{param_name} parameter"),
|
|
437
|
+
required=required
|
|
438
|
+
)
|
|
439
|
+
|
|
440
|
+
# Add webhook
|
|
441
|
+
data_map.webhook(method, url, headers)
|
|
442
|
+
|
|
443
|
+
# Add body if provided
|
|
444
|
+
if body:
|
|
445
|
+
data_map.body(body)
|
|
446
|
+
|
|
447
|
+
# Add error keys if provided
|
|
448
|
+
if error_keys:
|
|
449
|
+
data_map.error_keys(error_keys)
|
|
450
|
+
|
|
451
|
+
# Set output
|
|
452
|
+
data_map.output(SwaigFunctionResult(response_template))
|
|
453
|
+
|
|
454
|
+
return data_map
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
def create_expression_tool(name: str, patterns: Dict[str, Tuple[str, SwaigFunctionResult]],
|
|
458
|
+
parameters: Optional[Dict[str, Dict]] = None) -> DataMap:
|
|
459
|
+
"""
|
|
460
|
+
Create an expression-based tool for pattern matching responses
|
|
461
|
+
|
|
462
|
+
Args:
|
|
463
|
+
name: Function name
|
|
464
|
+
patterns: Dictionary mapping test_values to (pattern, SwaigFunctionResult) tuples
|
|
465
|
+
parameters: Optional parameter definitions
|
|
466
|
+
|
|
467
|
+
Returns:
|
|
468
|
+
Configured DataMap object
|
|
469
|
+
"""
|
|
470
|
+
data_map = DataMap(name)
|
|
471
|
+
|
|
472
|
+
# Add parameters if provided
|
|
473
|
+
if parameters:
|
|
474
|
+
for param_name, param_def in parameters.items():
|
|
475
|
+
required = param_def.get("required", False)
|
|
476
|
+
data_map.parameter(
|
|
477
|
+
param_name,
|
|
478
|
+
param_def.get("type", "string"),
|
|
479
|
+
param_def.get("description", f"{param_name} parameter"),
|
|
480
|
+
required=required
|
|
481
|
+
)
|
|
482
|
+
|
|
483
|
+
# Add expressions with corrected signature
|
|
484
|
+
for test_value, (pattern, result) in patterns.items():
|
|
485
|
+
data_map.expression(test_value, pattern, result)
|
|
486
|
+
|
|
487
|
+
return data_map
|