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
@@ -8,12 +8,11 @@ See LICENSE file in the project root for full license information.
|
|
8
8
|
"""
|
9
9
|
|
10
10
|
"""
|
11
|
-
|
11
|
+
SWML document rendering utilities for SignalWire AI Agents.
|
12
12
|
"""
|
13
13
|
|
14
|
-
from typing import Dict, List, Any, Optional, Union
|
15
14
|
import json
|
16
|
-
import
|
15
|
+
from typing import Dict, List, Any, Optional, Union
|
17
16
|
|
18
17
|
from signalwire_agents.core.swml_service import SWMLService
|
19
18
|
from signalwire_agents.core.swml_builder import SWMLBuilder
|
@@ -23,14 +22,13 @@ class SwmlRenderer:
|
|
23
22
|
"""
|
24
23
|
Renders SWML documents for SignalWire AI Agents with AI and SWAIG components
|
25
24
|
|
26
|
-
This class provides
|
27
|
-
while also supporting the new SWMLService architecture. It can work either
|
28
|
-
standalone (legacy mode) or with a SWMLService instance.
|
25
|
+
This class provides methods for rendering SWML documents using the SWMLService architecture.
|
29
26
|
"""
|
30
27
|
|
31
28
|
@staticmethod
|
32
29
|
def render_swml(
|
33
30
|
prompt: Union[str, List[Dict[str, Any]]],
|
31
|
+
service: SWMLService,
|
34
32
|
post_prompt: Optional[str] = None,
|
35
33
|
post_prompt_url: Optional[str] = None,
|
36
34
|
swaig_functions: Optional[List[Dict[str, Any]]] = None,
|
@@ -43,341 +41,154 @@ class SwmlRenderer:
|
|
43
41
|
record_format: str = "mp4",
|
44
42
|
record_stereo: bool = True,
|
45
43
|
format: str = "json",
|
46
|
-
default_webhook_url: Optional[str] = None
|
47
|
-
service: Optional[SWMLService] = None
|
44
|
+
default_webhook_url: Optional[str] = None
|
48
45
|
) -> str:
|
49
46
|
"""
|
50
47
|
Generate a complete SWML document with AI configuration
|
51
48
|
|
52
49
|
Args:
|
53
|
-
prompt:
|
54
|
-
|
55
|
-
|
50
|
+
prompt: AI prompt text or POM structure
|
51
|
+
service: SWMLService instance to use for document building
|
52
|
+
post_prompt: Optional post-prompt text
|
53
|
+
post_prompt_url: Optional post-prompt URL
|
56
54
|
swaig_functions: List of SWAIG function definitions
|
57
|
-
startup_hook_url:
|
58
|
-
hangup_hook_url:
|
59
|
-
prompt_is_pom: Whether prompt is
|
60
|
-
params: Additional AI
|
61
|
-
add_answer: Whether to
|
62
|
-
record_call: Whether to add
|
63
|
-
record_format:
|
55
|
+
startup_hook_url: Optional startup hook URL
|
56
|
+
hangup_hook_url: Optional hangup hook URL
|
57
|
+
prompt_is_pom: Whether prompt is POM format
|
58
|
+
params: Additional AI verb parameters
|
59
|
+
add_answer: Whether to add answer verb
|
60
|
+
record_call: Whether to add record_call verb
|
61
|
+
record_format: Recording format
|
64
62
|
record_stereo: Whether to record in stereo
|
65
|
-
format: Output format
|
66
|
-
default_webhook_url:
|
67
|
-
service: Optional SWMLService instance to use
|
63
|
+
format: Output format (json or yaml)
|
64
|
+
default_webhook_url: Default webhook URL for SWAIG functions
|
68
65
|
|
69
66
|
Returns:
|
70
67
|
SWML document as a string
|
71
68
|
"""
|
72
|
-
#
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
"
|
100
|
-
"
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
"
|
112
|
-
"
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
# Only add SWAIG if we have functions or a default URL
|
128
|
-
if functions or default_webhook_url:
|
129
|
-
swaig_config = {}
|
130
|
-
|
131
|
-
# Add defaults if we have a default webhook URL
|
132
|
-
if default_webhook_url:
|
133
|
-
swaig_config["defaults"] = {
|
134
|
-
"web_hook_url": default_webhook_url
|
135
|
-
}
|
136
|
-
|
137
|
-
# Add functions if we have any
|
138
|
-
if functions:
|
139
|
-
swaig_config["functions"] = functions
|
140
|
-
|
141
|
-
# Add AI verb with appropriate configuration
|
142
|
-
builder.ai(
|
143
|
-
prompt_text=None if prompt_is_pom else prompt,
|
144
|
-
prompt_pom=prompt if prompt_is_pom else None,
|
145
|
-
post_prompt=post_prompt,
|
146
|
-
post_prompt_url=post_prompt_url,
|
147
|
-
swaig=swaig_config if swaig_config else None,
|
148
|
-
**(params or {})
|
149
|
-
)
|
150
|
-
|
151
|
-
# Get the document as a dictionary or string based on format
|
152
|
-
if format.lower() == "yaml":
|
153
|
-
import yaml
|
154
|
-
return yaml.dump(builder.build(), sort_keys=False)
|
155
|
-
else:
|
156
|
-
return builder.render()
|
157
|
-
else:
|
158
|
-
# Legacy implementation (unchanged for backward compatibility)
|
159
|
-
# Start building the SWML document
|
160
|
-
swml = {
|
161
|
-
"version": "1.0.0",
|
162
|
-
"sections": {
|
163
|
-
"main": []
|
164
|
-
}
|
165
|
-
}
|
166
|
-
|
167
|
-
# Build the AI block
|
168
|
-
ai_block = {
|
169
|
-
"ai": {
|
170
|
-
"prompt": {}
|
171
|
-
}
|
172
|
-
}
|
173
|
-
|
174
|
-
# Set prompt based on type
|
175
|
-
if prompt_is_pom:
|
176
|
-
ai_block["ai"]["prompt"]["pom"] = prompt
|
177
|
-
else:
|
178
|
-
ai_block["ai"]["prompt"]["text"] = prompt
|
179
|
-
|
180
|
-
# Add post_prompt if provided
|
181
|
-
if post_prompt:
|
182
|
-
ai_block["ai"]["post_prompt"] = {
|
183
|
-
"text": post_prompt
|
184
|
-
}
|
185
|
-
|
186
|
-
# Add post_prompt_url if provided
|
187
|
-
if post_prompt_url:
|
188
|
-
ai_block["ai"]["post_prompt_url"] = post_prompt_url
|
189
|
-
|
190
|
-
# SWAIG is a dictionary not an array (fix from old implementation)
|
191
|
-
ai_block["ai"]["SWAIG"] = {}
|
192
|
-
|
69
|
+
# Use the service to build the document
|
70
|
+
builder = SWMLBuilder(service)
|
71
|
+
|
72
|
+
# Reset the document to start fresh
|
73
|
+
builder.reset()
|
74
|
+
|
75
|
+
# Add answer block if requested
|
76
|
+
if add_answer:
|
77
|
+
builder.answer()
|
78
|
+
|
79
|
+
# Add record_call if requested
|
80
|
+
if record_call:
|
81
|
+
service.add_verb("record_call", {
|
82
|
+
"format": record_format,
|
83
|
+
"stereo": record_stereo
|
84
|
+
})
|
85
|
+
|
86
|
+
# Configure SWAIG object for AI verb
|
87
|
+
swaig_config = {}
|
88
|
+
functions = []
|
89
|
+
|
90
|
+
# Add startup hook if provided
|
91
|
+
if startup_hook_url:
|
92
|
+
functions.append({
|
93
|
+
"function": "startup_hook",
|
94
|
+
"description": "Called when the call starts",
|
95
|
+
"parameters": {
|
96
|
+
"type": "object",
|
97
|
+
"properties": {}
|
98
|
+
},
|
99
|
+
"web_hook_url": startup_hook_url
|
100
|
+
})
|
101
|
+
|
102
|
+
# Add hangup hook if provided
|
103
|
+
if hangup_hook_url:
|
104
|
+
functions.append({
|
105
|
+
"function": "hangup_hook",
|
106
|
+
"description": "Called when the call ends",
|
107
|
+
"parameters": {
|
108
|
+
"type": "object",
|
109
|
+
"properties": {}
|
110
|
+
},
|
111
|
+
"web_hook_url": hangup_hook_url
|
112
|
+
})
|
113
|
+
|
114
|
+
# Add regular functions if provided
|
115
|
+
if swaig_functions:
|
116
|
+
for func in swaig_functions:
|
117
|
+
# Skip special hooks as we've already added them
|
118
|
+
if func.get("function") not in ["startup_hook", "hangup_hook"]:
|
119
|
+
functions.append(func)
|
120
|
+
|
121
|
+
# Only add SWAIG if we have functions or a default URL
|
122
|
+
if functions or default_webhook_url:
|
193
123
|
# Add defaults if we have a default webhook URL
|
194
124
|
if default_webhook_url:
|
195
|
-
|
125
|
+
swaig_config["defaults"] = {
|
196
126
|
"web_hook_url": default_webhook_url
|
197
127
|
}
|
198
128
|
|
199
|
-
#
|
200
|
-
functions = []
|
201
|
-
|
202
|
-
# Add SWAIG hooks if provided
|
203
|
-
if startup_hook_url:
|
204
|
-
startup_hook = {
|
205
|
-
"function": "startup_hook",
|
206
|
-
"description": "Called when the call starts",
|
207
|
-
"parameters": {
|
208
|
-
"type": "object",
|
209
|
-
"properties": {}
|
210
|
-
},
|
211
|
-
"web_hook_url": startup_hook_url
|
212
|
-
}
|
213
|
-
functions.append(startup_hook)
|
214
|
-
|
215
|
-
if hangup_hook_url:
|
216
|
-
hangup_hook = {
|
217
|
-
"function": "hangup_hook",
|
218
|
-
"description": "Called when the call ends",
|
219
|
-
"parameters": {
|
220
|
-
"type": "object",
|
221
|
-
"properties": {}
|
222
|
-
},
|
223
|
-
"web_hook_url": hangup_hook_url
|
224
|
-
}
|
225
|
-
functions.append(hangup_hook)
|
226
|
-
|
227
|
-
# Add regular functions from the provided list
|
228
|
-
if swaig_functions:
|
229
|
-
for func in swaig_functions:
|
230
|
-
# Skip special hooks as we've already added them
|
231
|
-
if func.get("function") not in ["startup_hook", "hangup_hook"]:
|
232
|
-
functions.append(func)
|
233
|
-
|
234
|
-
# Add functions to SWAIG if we have any
|
129
|
+
# Add functions if we have any
|
235
130
|
if functions:
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
# Add record_call block next if requested
|
256
|
-
if record_call:
|
257
|
-
main_blocks.append({
|
258
|
-
"record_call": {
|
259
|
-
"format": record_format,
|
260
|
-
"stereo": record_stereo # SWML expects a boolean not a string
|
261
|
-
}
|
262
|
-
})
|
263
|
-
|
264
|
-
# Add the AI block
|
265
|
-
main_blocks.append(ai_block)
|
266
|
-
|
267
|
-
# Set the main section to our ordered blocks
|
268
|
-
swml["sections"]["main"] = main_blocks
|
269
|
-
|
270
|
-
# Return in requested format
|
271
|
-
if format.lower() == "yaml":
|
272
|
-
import yaml
|
273
|
-
return yaml.dump(swml, sort_keys=False)
|
274
|
-
else:
|
275
|
-
return json.dumps(swml, indent=2)
|
131
|
+
swaig_config["functions"] = functions
|
132
|
+
|
133
|
+
# Add AI verb with appropriate configuration
|
134
|
+
builder.ai(
|
135
|
+
prompt_text=None if prompt_is_pom else prompt,
|
136
|
+
prompt_pom=prompt if prompt_is_pom else None,
|
137
|
+
post_prompt=post_prompt,
|
138
|
+
post_prompt_url=post_prompt_url,
|
139
|
+
swaig=swaig_config if swaig_config else None,
|
140
|
+
**(params or {})
|
141
|
+
)
|
142
|
+
|
143
|
+
# Get the document as a dictionary or string based on format
|
144
|
+
if format.lower() == "yaml":
|
145
|
+
import yaml
|
146
|
+
return yaml.dump(builder.build(), sort_keys=False)
|
147
|
+
else:
|
148
|
+
return builder.render()
|
276
149
|
|
277
150
|
@staticmethod
|
278
151
|
def render_function_response_swml(
|
279
152
|
response_text: str,
|
153
|
+
service: SWMLService,
|
280
154
|
actions: Optional[List[Dict[str, Any]]] = None,
|
281
|
-
format: str = "json"
|
282
|
-
service: Optional[SWMLService] = None
|
155
|
+
format: str = "json"
|
283
156
|
) -> str:
|
284
157
|
"""
|
285
158
|
Generate a SWML document for a function response
|
286
159
|
|
287
160
|
Args:
|
288
|
-
response_text: Text to
|
289
|
-
|
290
|
-
|
291
|
-
|
161
|
+
response_text: Text response to include in the document
|
162
|
+
service: SWMLService instance to use
|
163
|
+
actions: Optional list of actions to perform
|
164
|
+
format: Output format (json or yaml)
|
292
165
|
|
293
166
|
Returns:
|
294
167
|
SWML document as a string
|
295
168
|
"""
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
elif action["type"] == "hang_up":
|
321
|
-
service.add_verb("hangup", {})
|
322
|
-
# Additional action types could be added here
|
323
|
-
else:
|
324
|
-
# Direct SWML verb format
|
325
|
-
for verb_name, verb_config in action.items():
|
326
|
-
service.add_verb(verb_name, verb_config)
|
327
|
-
|
328
|
-
# Return in requested format
|
329
|
-
if format.lower() == "yaml":
|
330
|
-
import yaml
|
331
|
-
return yaml.dump(service.get_document(), sort_keys=False)
|
332
|
-
else:
|
333
|
-
return service.render_document()
|
169
|
+
# Use the service to build the document
|
170
|
+
service.reset_document()
|
171
|
+
|
172
|
+
# Add a play block for the response if provided
|
173
|
+
if response_text:
|
174
|
+
service.add_verb("play", {"text": response_text})
|
175
|
+
|
176
|
+
# Add any actions that were provided
|
177
|
+
if actions:
|
178
|
+
for action in actions:
|
179
|
+
if "play" in action:
|
180
|
+
service.add_verb("play", action["play"])
|
181
|
+
elif "hangup" in action:
|
182
|
+
service.add_verb("hangup", action["hangup"])
|
183
|
+
elif "transfer" in action:
|
184
|
+
service.add_verb("transfer", action["transfer"])
|
185
|
+
elif "ai" in action:
|
186
|
+
service.add_verb("ai", action["ai"])
|
187
|
+
# Add more action types as needed
|
188
|
+
|
189
|
+
# Get the document as a dictionary or string based on format
|
190
|
+
if format.lower() == "yaml":
|
191
|
+
import yaml
|
192
|
+
return yaml.dump(service.get_document(), sort_keys=False)
|
334
193
|
else:
|
335
|
-
|
336
|
-
swml = {
|
337
|
-
"version": "1.0.0",
|
338
|
-
"sections": {
|
339
|
-
"main": []
|
340
|
-
}
|
341
|
-
}
|
342
|
-
|
343
|
-
# Add a play block for the response if provided
|
344
|
-
if response_text:
|
345
|
-
swml["sections"]["main"].append({
|
346
|
-
"play": {
|
347
|
-
"url": f"say:{response_text}"
|
348
|
-
}
|
349
|
-
})
|
350
|
-
|
351
|
-
# Add any actions
|
352
|
-
if actions:
|
353
|
-
for action in actions:
|
354
|
-
# Support both type-based actions and direct SWML verbs
|
355
|
-
if "type" in action:
|
356
|
-
# Type-based action format
|
357
|
-
if action["type"] == "play":
|
358
|
-
swml["sections"]["main"].append({
|
359
|
-
"play": {
|
360
|
-
"url": action["url"]
|
361
|
-
}
|
362
|
-
})
|
363
|
-
elif action["type"] == "transfer":
|
364
|
-
swml["sections"]["main"].append({
|
365
|
-
"connect": [
|
366
|
-
{"to": action["dest"]}
|
367
|
-
]
|
368
|
-
})
|
369
|
-
elif action["type"] == "hang_up":
|
370
|
-
swml["sections"]["main"].append({
|
371
|
-
"hangup": {}
|
372
|
-
})
|
373
|
-
# Additional action types could be added here
|
374
|
-
else:
|
375
|
-
# Direct SWML verb format - add the action as-is
|
376
|
-
swml["sections"]["main"].append(action)
|
377
|
-
|
378
|
-
# Return in requested format
|
379
|
-
if format.lower() == "yaml":
|
380
|
-
import yaml
|
381
|
-
return yaml.dump(swml, sort_keys=False)
|
382
|
-
else:
|
383
|
-
return json.dumps(swml)
|
194
|
+
return service.render_document()
|
@@ -82,8 +82,13 @@ class SWMLService:
|
|
82
82
|
self.route = route.rstrip("/") # Ensure no trailing slash
|
83
83
|
self.host = host
|
84
84
|
self.port = port
|
85
|
-
|
86
|
-
|
85
|
+
|
86
|
+
# Initialize SSL configuration from environment variables
|
87
|
+
ssl_enabled_env = os.environ.get('SWML_SSL_ENABLED', '').lower()
|
88
|
+
self.ssl_enabled = ssl_enabled_env in ('true', '1', 'yes')
|
89
|
+
self.domain = os.environ.get('SWML_DOMAIN')
|
90
|
+
self.ssl_cert_path = os.environ.get('SWML_SSL_CERT_PATH')
|
91
|
+
self.ssl_key_path = os.environ.get('SWML_SSL_KEY_PATH')
|
87
92
|
|
88
93
|
# Initialize proxy detection attributes
|
89
94
|
self._proxy_url_base = os.environ.get('SWML_PROXY_URL_BASE')
|
@@ -749,13 +754,15 @@ class SWMLService:
|
|
749
754
|
"""
|
750
755
|
import uvicorn
|
751
756
|
|
752
|
-
# Store SSL configuration
|
753
|
-
|
754
|
-
|
757
|
+
# Store SSL configuration (override environment if explicitly provided)
|
758
|
+
if ssl_enabled is not None:
|
759
|
+
self.ssl_enabled = ssl_enabled
|
760
|
+
if domain is not None:
|
761
|
+
self.domain = domain
|
755
762
|
|
756
|
-
# Set SSL paths
|
757
|
-
ssl_cert_path = ssl_cert
|
758
|
-
ssl_key_path = ssl_key
|
763
|
+
# Set SSL paths (use provided paths or fall back to environment)
|
764
|
+
ssl_cert_path = ssl_cert or getattr(self, 'ssl_cert_path', None)
|
765
|
+
ssl_key_path = ssl_key or getattr(self, 'ssl_key_path', None)
|
759
766
|
|
760
767
|
# Validate SSL configuration if enabled
|
761
768
|
if self.ssl_enabled:
|
@@ -838,7 +845,14 @@ class SWMLService:
|
|
838
845
|
|
839
846
|
# Use correct protocol and host in displayed URL
|
840
847
|
protocol = "https" if self.ssl_enabled else "http"
|
841
|
-
|
848
|
+
|
849
|
+
# Determine display host - include port unless it's the standard port for the protocol
|
850
|
+
if self.ssl_enabled and self.domain:
|
851
|
+
# Use domain, but include port if it's not the standard HTTPS port (443)
|
852
|
+
display_host = f"{self.domain}:{port}" if port != 443 else self.domain
|
853
|
+
else:
|
854
|
+
# Use host:port for HTTP or when no domain is specified
|
855
|
+
display_host = f"{host}:{port}"
|
842
856
|
|
843
857
|
self.log.info("starting_server",
|
844
858
|
url=f"{protocol}://{display_host}{self.route}",
|
@@ -932,90 +946,6 @@ class SWMLService:
|
|
932
946
|
|
933
947
|
return username, password
|
934
948
|
|
935
|
-
# Keep the existing methods for backward compatibility
|
936
|
-
|
937
|
-
def add_answer_verb(self, max_duration: Optional[int] = None, codecs: Optional[str] = None) -> bool:
|
938
|
-
"""
|
939
|
-
Add an answer verb to the current document
|
940
|
-
|
941
|
-
Args:
|
942
|
-
max_duration: Maximum duration in seconds
|
943
|
-
codecs: Comma-separated list of codecs
|
944
|
-
|
945
|
-
Returns:
|
946
|
-
True if added successfully, False otherwise
|
947
|
-
"""
|
948
|
-
config = {}
|
949
|
-
if max_duration is not None:
|
950
|
-
config["max_duration"] = max_duration
|
951
|
-
if codecs is not None:
|
952
|
-
config["codecs"] = codecs
|
953
|
-
|
954
|
-
return self.add_verb("answer", config)
|
955
|
-
|
956
|
-
def add_hangup_verb(self, reason: Optional[str] = None) -> bool:
|
957
|
-
"""
|
958
|
-
Add a hangup verb to the current document
|
959
|
-
|
960
|
-
Args:
|
961
|
-
reason: Hangup reason (hangup, busy, decline)
|
962
|
-
|
963
|
-
Returns:
|
964
|
-
True if added successfully, False otherwise
|
965
|
-
"""
|
966
|
-
config = {}
|
967
|
-
if reason is not None:
|
968
|
-
config["reason"] = reason
|
969
|
-
|
970
|
-
return self.add_verb("hangup", config)
|
971
|
-
|
972
|
-
def add_ai_verb(self,
|
973
|
-
prompt_text: Optional[str] = None,
|
974
|
-
prompt_pom: Optional[List[Dict[str, Any]]] = None,
|
975
|
-
post_prompt: Optional[str] = None,
|
976
|
-
post_prompt_url: Optional[str] = None,
|
977
|
-
swaig: Optional[Dict[str, Any]] = None,
|
978
|
-
**kwargs) -> bool:
|
979
|
-
"""
|
980
|
-
Add an AI verb to the current document
|
981
|
-
|
982
|
-
Args:
|
983
|
-
prompt_text: Simple prompt text
|
984
|
-
prompt_pom: Prompt object model
|
985
|
-
post_prompt: Post-prompt text
|
986
|
-
post_prompt_url: Post-prompt URL
|
987
|
-
swaig: SWAIG configuration
|
988
|
-
**kwargs: Additional parameters
|
989
|
-
|
990
|
-
Returns:
|
991
|
-
True if added successfully, False otherwise
|
992
|
-
"""
|
993
|
-
config = {}
|
994
|
-
|
995
|
-
# Handle prompt
|
996
|
-
if prompt_text is not None:
|
997
|
-
config["prompt"] = prompt_text
|
998
|
-
elif prompt_pom is not None:
|
999
|
-
config["prompt"] = prompt_pom
|
1000
|
-
|
1001
|
-
# Handle post prompt
|
1002
|
-
if post_prompt is not None:
|
1003
|
-
config["post_prompt"] = post_prompt
|
1004
|
-
|
1005
|
-
# Handle post prompt URL
|
1006
|
-
if post_prompt_url is not None:
|
1007
|
-
config["post_prompt_url"] = post_prompt_url
|
1008
|
-
|
1009
|
-
# Handle SWAIG
|
1010
|
-
if swaig is not None:
|
1011
|
-
config["SWAIG"] = swaig
|
1012
|
-
|
1013
|
-
# Handle additional parameters
|
1014
|
-
for key, value in kwargs.items():
|
1015
|
-
if value is not None:
|
1016
|
-
config[key] = value
|
1017
|
-
|
1018
|
-
return self.add_verb("ai", config)
|
1019
949
|
|
1020
950
|
def _build_webhook_url(self, endpoint: str, query_params: Optional[Dict[str, str]] = None) -> str:
|
1021
951
|
"""
|
@@ -1043,7 +973,8 @@ class SWMLService:
|
|
1043
973
|
|
1044
974
|
# Use domain if available and SSL is enabled
|
1045
975
|
if getattr(self, 'ssl_enabled', False) and getattr(self, 'domain', None):
|
1046
|
-
|
976
|
+
# Use domain, but include port if it's not the standard HTTPS port (443)
|
977
|
+
host_part = f"{self.domain}:{self.port}" if self.port != 443 else self.domain
|
1047
978
|
else:
|
1048
979
|
# For local URLs
|
1049
980
|
if self.host in ("0.0.0.0", "127.0.0.1", "localhost"):
|
@@ -203,7 +203,7 @@ class IndexBuilder:
|
|
203
203
|
file_types: List[str], exclude_patterns: Optional[List[str]] = None,
|
204
204
|
languages: List[str] = None, tags: Optional[List[str]] = None):
|
205
205
|
"""
|
206
|
-
Build complete search index from a single directory
|
206
|
+
Build complete search index from a single directory
|
207
207
|
|
208
208
|
Args:
|
209
209
|
source_dir: Directory to scan for documents
|