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
|
@@ -14,7 +14,12 @@ This module provides a fluent builder API for creating SWML documents.
|
|
|
14
14
|
It allows for chaining method calls to build up a document step by step.
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
import types
|
|
18
|
+
from typing import Dict, List, Any, Optional, Union, TypeVar
|
|
19
|
+
try:
|
|
20
|
+
from typing import Self # Python 3.11+
|
|
21
|
+
except ImportError:
|
|
22
|
+
from typing_extensions import Self # For Python 3.9-3.10
|
|
18
23
|
|
|
19
24
|
from signalwire_agents.core.swml_service import SWMLService
|
|
20
25
|
|
|
@@ -39,6 +44,12 @@ class SWMLBuilder:
|
|
|
39
44
|
service: The SWMLService to delegate to
|
|
40
45
|
"""
|
|
41
46
|
self.service = service
|
|
47
|
+
|
|
48
|
+
# Dictionary to cache dynamically created methods
|
|
49
|
+
self._verb_methods_cache = {}
|
|
50
|
+
|
|
51
|
+
# Create auto-vivified methods for all verbs
|
|
52
|
+
self._create_verb_methods()
|
|
42
53
|
|
|
43
54
|
def answer(self, max_duration: Optional[int] = None, codecs: Optional[str] = None) -> Self:
|
|
44
55
|
"""
|
|
@@ -51,7 +62,12 @@ class SWMLBuilder:
|
|
|
51
62
|
Returns:
|
|
52
63
|
Self for method chaining
|
|
53
64
|
"""
|
|
54
|
-
|
|
65
|
+
config = {}
|
|
66
|
+
if max_duration is not None:
|
|
67
|
+
config["max_duration"] = max_duration
|
|
68
|
+
if codecs is not None:
|
|
69
|
+
config["codecs"] = codecs
|
|
70
|
+
self.service.add_verb("answer", config)
|
|
55
71
|
return self
|
|
56
72
|
|
|
57
73
|
def hangup(self, reason: Optional[str] = None) -> Self:
|
|
@@ -64,7 +80,10 @@ class SWMLBuilder:
|
|
|
64
80
|
Returns:
|
|
65
81
|
Self for method chaining
|
|
66
82
|
"""
|
|
67
|
-
|
|
83
|
+
config = {}
|
|
84
|
+
if reason is not None:
|
|
85
|
+
config["reason"] = reason
|
|
86
|
+
self.service.add_verb("hangup", config)
|
|
68
87
|
return self
|
|
69
88
|
|
|
70
89
|
def ai(self,
|
|
@@ -88,14 +107,26 @@ class SWMLBuilder:
|
|
|
88
107
|
Returns:
|
|
89
108
|
Self for method chaining
|
|
90
109
|
"""
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
110
|
+
config = {}
|
|
111
|
+
|
|
112
|
+
# Handle prompt (either text or POM, but not both)
|
|
113
|
+
if prompt_text is not None:
|
|
114
|
+
config["prompt"] = prompt_text
|
|
115
|
+
elif prompt_pom is not None:
|
|
116
|
+
config["prompt"] = prompt_pom
|
|
117
|
+
|
|
118
|
+
# Add optional parameters
|
|
119
|
+
if post_prompt is not None:
|
|
120
|
+
config["post_prompt"] = post_prompt
|
|
121
|
+
if post_prompt_url is not None:
|
|
122
|
+
config["post_prompt_url"] = post_prompt_url
|
|
123
|
+
if swaig is not None:
|
|
124
|
+
config["SWAIG"] = swaig
|
|
125
|
+
|
|
126
|
+
# Add any additional kwargs
|
|
127
|
+
config.update(kwargs)
|
|
128
|
+
|
|
129
|
+
self.service.add_verb("ai", config)
|
|
99
130
|
return self
|
|
100
131
|
|
|
101
132
|
def play(self, url: Optional[str] = None, urls: Optional[List[str]] = None,
|
|
@@ -211,4 +242,173 @@ class SWMLBuilder:
|
|
|
211
242
|
Self for method chaining
|
|
212
243
|
"""
|
|
213
244
|
self.service.reset_document()
|
|
214
|
-
return self
|
|
245
|
+
return self
|
|
246
|
+
|
|
247
|
+
def _create_verb_methods(self) -> None:
|
|
248
|
+
"""
|
|
249
|
+
Create auto-vivified methods for all verbs at initialization time
|
|
250
|
+
|
|
251
|
+
This creates methods for all SWML verbs defined in the schema,
|
|
252
|
+
allowing for fluent chaining like builder.denoise().goto().play()
|
|
253
|
+
"""
|
|
254
|
+
# Get all verb names from the schema
|
|
255
|
+
if not hasattr(self.service, 'schema_utils') or not self.service.schema_utils:
|
|
256
|
+
return
|
|
257
|
+
|
|
258
|
+
verb_names = self.service.schema_utils.get_all_verb_names()
|
|
259
|
+
|
|
260
|
+
# Create a method for each verb
|
|
261
|
+
for verb_name in verb_names:
|
|
262
|
+
# Skip verbs that already have specific methods
|
|
263
|
+
if hasattr(self, verb_name):
|
|
264
|
+
continue
|
|
265
|
+
|
|
266
|
+
# Handle sleep verb specially since it takes an integer directly
|
|
267
|
+
if verb_name == "sleep":
|
|
268
|
+
def sleep_method(self_instance, duration=None, **kwargs):
|
|
269
|
+
"""
|
|
270
|
+
Add the sleep verb to the document.
|
|
271
|
+
|
|
272
|
+
Args:
|
|
273
|
+
duration: The amount of time to sleep in milliseconds
|
|
274
|
+
"""
|
|
275
|
+
# Sleep verb takes a direct integer parameter in SWML
|
|
276
|
+
if duration is not None:
|
|
277
|
+
self_instance.service.add_verb("sleep", duration)
|
|
278
|
+
elif kwargs:
|
|
279
|
+
# Try to get the value from kwargs
|
|
280
|
+
self_instance.service.add_verb("sleep", next(iter(kwargs.values())))
|
|
281
|
+
else:
|
|
282
|
+
raise TypeError("sleep() missing required argument: 'duration'")
|
|
283
|
+
return self_instance
|
|
284
|
+
|
|
285
|
+
# Set it as an attribute of self
|
|
286
|
+
setattr(self, verb_name, types.MethodType(sleep_method, self))
|
|
287
|
+
|
|
288
|
+
# Also cache it for later
|
|
289
|
+
self._verb_methods_cache[verb_name] = sleep_method
|
|
290
|
+
continue
|
|
291
|
+
|
|
292
|
+
# Generate the method implementation for normal verbs
|
|
293
|
+
def make_verb_method(name):
|
|
294
|
+
def verb_method(self_instance, **kwargs):
|
|
295
|
+
"""
|
|
296
|
+
Dynamically generated method for SWML verb - returns self for chaining
|
|
297
|
+
"""
|
|
298
|
+
config = {}
|
|
299
|
+
for key, value in kwargs.items():
|
|
300
|
+
if value is not None:
|
|
301
|
+
config[key] = value
|
|
302
|
+
self_instance.service.add_verb(name, config)
|
|
303
|
+
return self_instance
|
|
304
|
+
|
|
305
|
+
# Add docstring to the method
|
|
306
|
+
if hasattr(self.service.schema_utils, 'get_verb_properties'):
|
|
307
|
+
verb_properties = self.service.schema_utils.get_verb_properties(name)
|
|
308
|
+
if "description" in verb_properties:
|
|
309
|
+
verb_method.__doc__ = f"Add the {name} verb to the document.\n\n{verb_properties['description']}\n\nReturns: Self for method chaining"
|
|
310
|
+
else:
|
|
311
|
+
verb_method.__doc__ = f"Add the {name} verb to the document.\n\nReturns: Self for method chaining"
|
|
312
|
+
else:
|
|
313
|
+
verb_method.__doc__ = f"Add the {name} verb to the document.\n\nReturns: Self for method chaining"
|
|
314
|
+
|
|
315
|
+
return verb_method
|
|
316
|
+
|
|
317
|
+
# Create the method with closure over the verb name
|
|
318
|
+
method = make_verb_method(verb_name)
|
|
319
|
+
|
|
320
|
+
# Set it as an attribute of self
|
|
321
|
+
setattr(self, verb_name, types.MethodType(method, self))
|
|
322
|
+
|
|
323
|
+
# Also cache it for later
|
|
324
|
+
self._verb_methods_cache[verb_name] = method
|
|
325
|
+
|
|
326
|
+
def __getattr__(self, name: str) -> Any:
|
|
327
|
+
"""
|
|
328
|
+
Dynamically generate and return SWML verb methods when accessed
|
|
329
|
+
|
|
330
|
+
This method is called when an attribute lookup fails through the normal
|
|
331
|
+
mechanisms. It checks if the attribute name corresponds to a SWML verb
|
|
332
|
+
defined in the schema, and if so, dynamically creates a method for that verb.
|
|
333
|
+
|
|
334
|
+
Args:
|
|
335
|
+
name: The name of the attribute being accessed
|
|
336
|
+
|
|
337
|
+
Returns:
|
|
338
|
+
The dynamically created verb method if name is a valid SWML verb,
|
|
339
|
+
otherwise raises AttributeError
|
|
340
|
+
|
|
341
|
+
Raises:
|
|
342
|
+
AttributeError: If name is not a valid SWML verb
|
|
343
|
+
"""
|
|
344
|
+
# First check if this is a valid SWML verb
|
|
345
|
+
if not hasattr(self.service, 'schema_utils') or not self.service.schema_utils:
|
|
346
|
+
msg = f"'{self.__class__.__name__}' object has no attribute '{name}' (no schema available)"
|
|
347
|
+
raise AttributeError(msg)
|
|
348
|
+
|
|
349
|
+
verb_names = self.service.schema_utils.get_all_verb_names()
|
|
350
|
+
|
|
351
|
+
if name in verb_names:
|
|
352
|
+
# Check if we already have this method in the cache
|
|
353
|
+
if not hasattr(self, '_verb_methods_cache'):
|
|
354
|
+
self._verb_methods_cache = {}
|
|
355
|
+
|
|
356
|
+
if name in self._verb_methods_cache:
|
|
357
|
+
return types.MethodType(self._verb_methods_cache[name], self)
|
|
358
|
+
|
|
359
|
+
# Handle sleep verb specially since it takes an integer directly
|
|
360
|
+
if name == "sleep":
|
|
361
|
+
def sleep_method(self_instance, duration=None, **kwargs):
|
|
362
|
+
"""
|
|
363
|
+
Add the sleep verb to the document.
|
|
364
|
+
|
|
365
|
+
Args:
|
|
366
|
+
duration: The amount of time to sleep in milliseconds
|
|
367
|
+
"""
|
|
368
|
+
# Sleep verb takes a direct integer parameter in SWML
|
|
369
|
+
if duration is not None:
|
|
370
|
+
self_instance.service.add_verb("sleep", duration)
|
|
371
|
+
elif kwargs:
|
|
372
|
+
# Try to get the value from kwargs
|
|
373
|
+
self_instance.service.add_verb("sleep", next(iter(kwargs.values())))
|
|
374
|
+
else:
|
|
375
|
+
raise TypeError("sleep() missing required argument: 'duration'")
|
|
376
|
+
return self_instance
|
|
377
|
+
|
|
378
|
+
# Cache the method for future use
|
|
379
|
+
self._verb_methods_cache[name] = sleep_method
|
|
380
|
+
|
|
381
|
+
# Return the bound method
|
|
382
|
+
return types.MethodType(sleep_method, self)
|
|
383
|
+
|
|
384
|
+
# Generate the method implementation for normal verbs
|
|
385
|
+
def verb_method(self_instance, **kwargs):
|
|
386
|
+
"""
|
|
387
|
+
Dynamically generated method for SWML verb - returns self for chaining
|
|
388
|
+
"""
|
|
389
|
+
config = {}
|
|
390
|
+
for key, value in kwargs.items():
|
|
391
|
+
if value is not None:
|
|
392
|
+
config[key] = value
|
|
393
|
+
self_instance.service.add_verb(name, config)
|
|
394
|
+
return self_instance
|
|
395
|
+
|
|
396
|
+
# Add docstring to the method
|
|
397
|
+
if hasattr(self.service.schema_utils, 'get_verb_properties'):
|
|
398
|
+
verb_properties = self.service.schema_utils.get_verb_properties(name)
|
|
399
|
+
if "description" in verb_properties:
|
|
400
|
+
verb_method.__doc__ = f"Add the {name} verb to the document.\n\n{verb_properties['description']}\n\nReturns: Self for method chaining"
|
|
401
|
+
else:
|
|
402
|
+
verb_method.__doc__ = f"Add the {name} verb to the document.\n\nReturns: Self for method chaining"
|
|
403
|
+
else:
|
|
404
|
+
verb_method.__doc__ = f"Add the {name} verb to the document.\n\nReturns: Self for method chaining"
|
|
405
|
+
|
|
406
|
+
# Cache the method for future use
|
|
407
|
+
self._verb_methods_cache[name] = verb_method
|
|
408
|
+
|
|
409
|
+
# Return the bound method
|
|
410
|
+
return types.MethodType(verb_method, self)
|
|
411
|
+
|
|
412
|
+
# Not a valid verb
|
|
413
|
+
msg = f"'{self.__class__.__name__}' object has no attribute '{name}'"
|
|
414
|
+
raise AttributeError(msg)
|
|
@@ -93,17 +93,33 @@ class AIVerbHandler(SWMLVerbHandler):
|
|
|
93
93
|
"""
|
|
94
94
|
errors = []
|
|
95
95
|
|
|
96
|
-
# Check
|
|
96
|
+
# Check that prompt is present
|
|
97
97
|
if "prompt" not in config:
|
|
98
98
|
errors.append("Missing required field 'prompt'")
|
|
99
|
+
return False, errors
|
|
99
100
|
|
|
100
|
-
|
|
101
|
-
if
|
|
102
|
-
prompt
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
101
|
+
prompt = config["prompt"]
|
|
102
|
+
if not isinstance(prompt, dict):
|
|
103
|
+
errors.append("'prompt' must be an object")
|
|
104
|
+
return False, errors
|
|
105
|
+
|
|
106
|
+
# Check that prompt contains either text or pom (required)
|
|
107
|
+
has_text = "text" in prompt
|
|
108
|
+
has_pom = "pom" in prompt
|
|
109
|
+
has_contexts = "contexts" in prompt
|
|
110
|
+
|
|
111
|
+
# Require either text or pom (mutually exclusive)
|
|
112
|
+
base_prompt_count = sum([has_text, has_pom])
|
|
113
|
+
if base_prompt_count == 0:
|
|
114
|
+
errors.append("'prompt' must contain either 'text' or 'pom' as base prompt")
|
|
115
|
+
elif base_prompt_count > 1:
|
|
116
|
+
errors.append("'prompt' can only contain one of: 'text' or 'pom' (mutually exclusive)")
|
|
117
|
+
|
|
118
|
+
# Contexts are optional and can be combined with text or pom
|
|
119
|
+
if has_contexts:
|
|
120
|
+
contexts = prompt["contexts"]
|
|
121
|
+
if not isinstance(contexts, dict):
|
|
122
|
+
errors.append("'prompt.contexts' must be an object")
|
|
107
123
|
|
|
108
124
|
# Validate SWAIG structure if present
|
|
109
125
|
if "SWAIG" in config:
|
|
@@ -116,6 +132,7 @@ class AIVerbHandler(SWMLVerbHandler):
|
|
|
116
132
|
def build_config(self,
|
|
117
133
|
prompt_text: Optional[str] = None,
|
|
118
134
|
prompt_pom: Optional[List[Dict[str, Any]]] = None,
|
|
135
|
+
contexts: Optional[Dict[str, Any]] = None,
|
|
119
136
|
post_prompt: Optional[str] = None,
|
|
120
137
|
post_prompt_url: Optional[str] = None,
|
|
121
138
|
swaig: Optional[Dict[str, Any]] = None,
|
|
@@ -126,6 +143,7 @@ class AIVerbHandler(SWMLVerbHandler):
|
|
|
126
143
|
Args:
|
|
127
144
|
prompt_text: Text prompt for the AI (mutually exclusive with prompt_pom)
|
|
128
145
|
prompt_pom: POM structure for the AI prompt (mutually exclusive with prompt_text)
|
|
146
|
+
contexts: Optional contexts and steps configuration (can be combined with text or pom)
|
|
129
147
|
post_prompt: Optional post-prompt text
|
|
130
148
|
post_prompt_url: Optional URL for post-prompt processing
|
|
131
149
|
swaig: Optional SWAIG configuration
|
|
@@ -136,13 +154,25 @@ class AIVerbHandler(SWMLVerbHandler):
|
|
|
136
154
|
"""
|
|
137
155
|
config = {}
|
|
138
156
|
|
|
139
|
-
#
|
|
157
|
+
# Require either text or pom as base prompt (mutually exclusive)
|
|
158
|
+
base_prompt_count = sum(x is not None for x in [prompt_text, prompt_pom])
|
|
159
|
+
if base_prompt_count == 0:
|
|
160
|
+
raise ValueError("Either prompt_text or prompt_pom must be provided as base prompt")
|
|
161
|
+
elif base_prompt_count > 1:
|
|
162
|
+
raise ValueError("prompt_text and prompt_pom are mutually exclusive")
|
|
163
|
+
|
|
164
|
+
# Build prompt object with base prompt
|
|
165
|
+
prompt_config = {}
|
|
140
166
|
if prompt_text is not None:
|
|
141
|
-
|
|
167
|
+
prompt_config["text"] = prompt_text
|
|
142
168
|
elif prompt_pom is not None:
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
169
|
+
prompt_config["pom"] = prompt_pom
|
|
170
|
+
|
|
171
|
+
# Add contexts if provided (optional, activates steps feature)
|
|
172
|
+
if contexts is not None:
|
|
173
|
+
prompt_config["contexts"] = contexts
|
|
174
|
+
|
|
175
|
+
config["prompt"] = prompt_config
|
|
146
176
|
|
|
147
177
|
# Add post-prompt if provided
|
|
148
178
|
if post_prompt is not None:
|