signalwire-agents 0.1.13__py3-none-any.whl → 1.0.17.dev4__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 +99 -15
- signalwire_agents/agent_server.py +248 -60
- signalwire_agents/agents/bedrock.py +296 -0
- signalwire_agents/cli/__init__.py +9 -0
- signalwire_agents/cli/build_search.py +951 -41
- 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/dokku.py +2320 -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 +2636 -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 +566 -2366
- 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 +845 -2916
- signalwire_agents/core/auth_handler.py +233 -0
- signalwire_agents/core/config_loader.py +259 -0
- signalwire_agents/core/contexts.py +418 -0
- signalwire_agents/core/data_map.py +3 -15
- signalwire_agents/core/function_result.py +116 -44
- signalwire_agents/core/logging_config.py +162 -18
- 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 +280 -0
- signalwire_agents/core/mixins/prompt_mixin.py +358 -0
- signalwire_agents/core/mixins/serverless_mixin.py +460 -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 +1142 -0
- signalwire_agents/core/security_config.py +333 -0
- signalwire_agents/core/skill_base.py +84 -1
- signalwire_agents/core/skill_manager.py +62 -20
- signalwire_agents/core/swaig_function.py +18 -5
- signalwire_agents/core/swml_builder.py +207 -11
- signalwire_agents/core/swml_handler.py +27 -21
- signalwire_agents/core/swml_renderer.py +123 -312
- signalwire_agents/core/swml_service.py +171 -203
- signalwire_agents/mcp_gateway/__init__.py +29 -0
- signalwire_agents/mcp_gateway/gateway_service.py +564 -0
- signalwire_agents/mcp_gateway/mcp_manager.py +513 -0
- signalwire_agents/mcp_gateway/session_manager.py +218 -0
- signalwire_agents/prefabs/concierge.py +0 -3
- signalwire_agents/prefabs/faq_bot.py +0 -3
- signalwire_agents/prefabs/info_gatherer.py +0 -3
- signalwire_agents/prefabs/receptionist.py +0 -3
- signalwire_agents/prefabs/survey.py +0 -3
- signalwire_agents/schema.json +9218 -5489
- signalwire_agents/search/__init__.py +7 -1
- signalwire_agents/search/document_processor.py +490 -31
- signalwire_agents/search/index_builder.py +307 -37
- signalwire_agents/search/migration.py +418 -0
- signalwire_agents/search/models.py +30 -0
- signalwire_agents/search/pgvector_backend.py +748 -0
- signalwire_agents/search/query_processor.py +162 -31
- signalwire_agents/search/search_engine.py +916 -35
- signalwire_agents/search/search_service.py +376 -53
- signalwire_agents/skills/README.md +452 -0
- signalwire_agents/skills/__init__.py +14 -2
- 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/skill.py +84 -3
- signalwire_agents/skills/datasphere_serverless/README.md +258 -0
- signalwire_agents/skills/datasphere_serverless/__init__.py +9 -0
- signalwire_agents/skills/datasphere_serverless/skill.py +82 -1
- signalwire_agents/skills/datetime/README.md +132 -0
- signalwire_agents/skills/datetime/__init__.py +9 -0
- signalwire_agents/skills/datetime/skill.py +20 -7
- signalwire_agents/skills/joke/README.md +149 -0
- signalwire_agents/skills/joke/__init__.py +9 -0
- signalwire_agents/skills/joke/skill.py +21 -0
- signalwire_agents/skills/math/README.md +161 -0
- signalwire_agents/skills/math/__init__.py +9 -0
- signalwire_agents/skills/math/skill.py +18 -4
- 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 +9 -0
- signalwire_agents/skills/native_vector_search/skill.py +569 -101
- 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 +395 -40
- 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 +9 -0
- signalwire_agents/skills/web_search/skill.py +586 -112
- signalwire_agents/skills/wikipedia_search/README.md +228 -0
- signalwire_agents/{core/state → skills/wikipedia_search}/__init__.py +5 -4
- signalwire_agents/skills/{wikipedia → wikipedia_search}/skill.py +33 -3
- signalwire_agents/web/__init__.py +17 -0
- signalwire_agents/web/web_service.py +559 -0
- signalwire_agents-1.0.17.dev4.data/data/share/man/man1/sw-agent-init.1 +400 -0
- signalwire_agents-1.0.17.dev4.data/data/share/man/man1/sw-search.1 +483 -0
- signalwire_agents-1.0.17.dev4.data/data/share/man/man1/swaig-test.1 +308 -0
- {signalwire_agents-0.1.13.dist-info → signalwire_agents-1.0.17.dev4.dist-info}/METADATA +347 -215
- signalwire_agents-1.0.17.dev4.dist-info/RECORD +147 -0
- signalwire_agents-1.0.17.dev4.dist-info/entry_points.txt +6 -0
- signalwire_agents/core/state/file_state_manager.py +0 -219
- signalwire_agents/core/state/state_manager.py +0 -101
- signalwire_agents/skills/wikipedia/__init__.py +0 -9
- signalwire_agents-0.1.13.data/data/schema.json +0 -5611
- signalwire_agents-0.1.13.dist-info/RECORD +0 -67
- signalwire_agents-0.1.13.dist-info/entry_points.txt +0 -3
- {signalwire_agents-0.1.13.dist-info → signalwire_agents-1.0.17.dev4.dist-info}/WHEEL +0 -0
- {signalwire_agents-0.1.13.dist-info → signalwire_agents-1.0.17.dev4.dist-info}/licenses/LICENSE +0 -0
- {signalwire_agents-0.1.13.dist-info → signalwire_agents-1.0.17.dev4.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Copyright (c) 2025 SignalWire
|
|
4
|
+
|
|
5
|
+
This file is part of the SignalWire AI Agents SDK.
|
|
6
|
+
|
|
7
|
+
Licensed under the MIT License.
|
|
8
|
+
See LICENSE file in the project root for full license information.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
"""
|
|
12
|
+
Type definitions for the CLI tools
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from typing import TypedDict, Dict, Any, Optional, List, Union
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class CallData(TypedDict, total=False):
|
|
19
|
+
"""Call data structure for SWML post_data"""
|
|
20
|
+
id: str
|
|
21
|
+
node_id: str
|
|
22
|
+
state: str
|
|
23
|
+
type: str
|
|
24
|
+
direction: str
|
|
25
|
+
project_id: str
|
|
26
|
+
space_id: str
|
|
27
|
+
from_number: str
|
|
28
|
+
to_number: str
|
|
29
|
+
from_: str
|
|
30
|
+
to: str
|
|
31
|
+
from_name: str
|
|
32
|
+
headers: Dict[str, str]
|
|
33
|
+
timeout: int
|
|
34
|
+
tag: str
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class VarsData(TypedDict, total=False):
|
|
38
|
+
"""Variables data structure for SWML post_data"""
|
|
39
|
+
userVariables: Dict[str, Any]
|
|
40
|
+
environment: str
|
|
41
|
+
call_data: Dict[str, Any]
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class PostData(TypedDict, total=False):
|
|
45
|
+
"""Complete post_data structure for SWML requests"""
|
|
46
|
+
call_id: str
|
|
47
|
+
call: CallData
|
|
48
|
+
vars: VarsData
|
|
49
|
+
params: Dict[str, Any]
|
|
50
|
+
project_id: str
|
|
51
|
+
space_id: str
|
|
52
|
+
meta_data: Dict[str, Any]
|
|
53
|
+
post_prompt_data: Dict[str, Any]
|
|
54
|
+
error: Optional[str]
|
|
55
|
+
protocol_error: Optional[bool]
|
|
56
|
+
parse_error: Optional[bool]
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class DataMapConfig(TypedDict, total=False):
|
|
60
|
+
"""DataMap function configuration"""
|
|
61
|
+
function: str
|
|
62
|
+
data_map: Dict[str, Any]
|
|
63
|
+
description: str
|
|
64
|
+
parameters: Dict[str, Any]
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class AgentInfo(TypedDict):
|
|
68
|
+
"""Information about a discovered agent"""
|
|
69
|
+
class_name: str
|
|
70
|
+
file_path: str
|
|
71
|
+
is_instance: bool
|
|
72
|
+
instance_name: Optional[str]
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class FunctionInfo(TypedDict):
|
|
76
|
+
"""Information about a SWAIG function"""
|
|
77
|
+
name: str
|
|
78
|
+
description: str
|
|
79
|
+
parameters: Dict[str, Any]
|
|
80
|
+
type: str # 'local', 'external', 'datamap'
|
|
81
|
+
webhook_url: Optional[str]
|
|
@@ -13,7 +13,7 @@ Core components for SignalWire AI Agents
|
|
|
13
13
|
|
|
14
14
|
from signalwire_agents.core.agent_base import AgentBase
|
|
15
15
|
from signalwire_agents.core.function_result import SwaigFunctionResult
|
|
16
|
-
from signalwire_agents.core.swaig_function import
|
|
16
|
+
from signalwire_agents.core.swaig_function import SWAIGFunction
|
|
17
17
|
from signalwire_agents.core.swml_service import SWMLService
|
|
18
18
|
from signalwire_agents.core.swml_handler import SWMLVerbHandler, VerbHandlerRegistry
|
|
19
19
|
from signalwire_agents.core.swml_builder import SWMLBuilder
|
|
@@ -21,7 +21,7 @@ from signalwire_agents.core.swml_builder import SWMLBuilder
|
|
|
21
21
|
__all__ = [
|
|
22
22
|
'AgentBase',
|
|
23
23
|
'SwaigFunctionResult',
|
|
24
|
-
'
|
|
24
|
+
'SWAIGFunction',
|
|
25
25
|
'SWMLService',
|
|
26
26
|
'SWMLVerbHandler',
|
|
27
27
|
'VerbHandlerRegistry',
|
|
@@ -0,0 +1,12 @@
|
|
|
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
|
+
"""Agent refactored components."""
|
|
11
|
+
|
|
12
|
+
__all__ = []
|
|
@@ -0,0 +1,12 @@
|
|
|
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
|
+
"""Configuration management modules."""
|
|
11
|
+
|
|
12
|
+
__all__ = []
|
|
@@ -0,0 +1,14 @@
|
|
|
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
|
+
"""Prompt management modules."""
|
|
11
|
+
|
|
12
|
+
from .manager import PromptManager
|
|
13
|
+
|
|
14
|
+
__all__ = ['PromptManager']
|
|
@@ -0,0 +1,306 @@
|
|
|
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
|
+
"""Prompt management functionality for AgentBase."""
|
|
11
|
+
|
|
12
|
+
from typing import Dict, Any, Optional, List, Union
|
|
13
|
+
import inspect
|
|
14
|
+
import logging
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class PromptManager:
|
|
20
|
+
"""Manages prompt building and configuration."""
|
|
21
|
+
|
|
22
|
+
def __init__(self, agent):
|
|
23
|
+
"""
|
|
24
|
+
Initialize PromptManager with reference to parent agent.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
agent: Parent AgentBase instance
|
|
28
|
+
"""
|
|
29
|
+
self.agent = agent
|
|
30
|
+
self._prompt_text = None
|
|
31
|
+
self._post_prompt_text = None
|
|
32
|
+
self._contexts = None
|
|
33
|
+
|
|
34
|
+
def _validate_prompt_mode_exclusivity(self):
|
|
35
|
+
"""
|
|
36
|
+
Check that only one prompt mode is in use.
|
|
37
|
+
|
|
38
|
+
Raises:
|
|
39
|
+
ValueError: If both prompt modes are in use
|
|
40
|
+
"""
|
|
41
|
+
if self._prompt_text and self.agent._use_pom and self.agent.pom:
|
|
42
|
+
pom_sections = self.agent.pom.to_dict() if hasattr(self.agent.pom, 'to_dict') else []
|
|
43
|
+
if pom_sections:
|
|
44
|
+
raise ValueError(
|
|
45
|
+
"Cannot use both prompt_text and POM sections. "
|
|
46
|
+
"Please use either set_prompt_text() OR the prompt_add_* methods, not both."
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
def _process_prompt_sections(self) -> Optional[Union[str, List[Dict[str, Any]]]]:
|
|
50
|
+
"""
|
|
51
|
+
Process prompt sections from POM or raw prompt text.
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
String, List of section dictionaries, or None
|
|
55
|
+
"""
|
|
56
|
+
# First check if we have contexts - they take precedence
|
|
57
|
+
if self._contexts:
|
|
58
|
+
return None # Contexts handle their own prompt sections
|
|
59
|
+
|
|
60
|
+
# Check if we have a raw prompt text - return it directly
|
|
61
|
+
if self._prompt_text:
|
|
62
|
+
return self._prompt_text
|
|
63
|
+
|
|
64
|
+
# Otherwise use POM sections if available
|
|
65
|
+
if self.agent._use_pom and self.agent.pom:
|
|
66
|
+
sections = self.agent.pom.to_dict()
|
|
67
|
+
if sections:
|
|
68
|
+
return sections
|
|
69
|
+
|
|
70
|
+
return None
|
|
71
|
+
|
|
72
|
+
def define_contexts(self, contexts: Union[Dict[str, Any], Any]) -> None:
|
|
73
|
+
"""
|
|
74
|
+
Define contexts for the agent.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
contexts: Context configuration (dict or ContextBuilder)
|
|
78
|
+
"""
|
|
79
|
+
if hasattr(contexts, 'to_dict'):
|
|
80
|
+
# It's a ContextBuilder
|
|
81
|
+
self._contexts = contexts.to_dict()
|
|
82
|
+
elif isinstance(contexts, dict):
|
|
83
|
+
# It's already a dictionary
|
|
84
|
+
self._contexts = contexts
|
|
85
|
+
else:
|
|
86
|
+
raise ValueError("contexts must be a dictionary or a ContextBuilder object")
|
|
87
|
+
|
|
88
|
+
logger.debug(f"Defined contexts: {self._contexts}")
|
|
89
|
+
|
|
90
|
+
def set_prompt_text(self, text: str) -> None:
|
|
91
|
+
"""
|
|
92
|
+
Set the agent's prompt as raw text.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
text: Prompt text
|
|
96
|
+
"""
|
|
97
|
+
self._validate_prompt_mode_exclusivity()
|
|
98
|
+
self._prompt_text = text
|
|
99
|
+
logger.debug(f"Set prompt text: {text[:100]}...")
|
|
100
|
+
|
|
101
|
+
def set_post_prompt(self, text: str) -> None:
|
|
102
|
+
"""
|
|
103
|
+
Set the post-prompt text.
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
text: Post-prompt text
|
|
107
|
+
"""
|
|
108
|
+
self._post_prompt_text = text
|
|
109
|
+
logger.debug(f"Set post-prompt text: {text[:100]}...")
|
|
110
|
+
|
|
111
|
+
def set_prompt_pom(self, pom: List[Dict[str, Any]]) -> None:
|
|
112
|
+
"""
|
|
113
|
+
Set the prompt as a POM dictionary.
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
pom: POM dictionary structure
|
|
117
|
+
|
|
118
|
+
Raises:
|
|
119
|
+
ValueError: If use_pom is False
|
|
120
|
+
"""
|
|
121
|
+
if self.agent._use_pom:
|
|
122
|
+
self.agent.pom = pom
|
|
123
|
+
else:
|
|
124
|
+
raise ValueError("use_pom must be True to use set_prompt_pom")
|
|
125
|
+
|
|
126
|
+
def prompt_add_section(
|
|
127
|
+
self,
|
|
128
|
+
title: str,
|
|
129
|
+
body: str = "",
|
|
130
|
+
bullets: Optional[List[str]] = None,
|
|
131
|
+
numbered: bool = False,
|
|
132
|
+
numbered_bullets: bool = False,
|
|
133
|
+
subsections: Optional[List[Dict[str, Any]]] = None
|
|
134
|
+
) -> None:
|
|
135
|
+
"""
|
|
136
|
+
Add a section to the prompt.
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
title: Section title
|
|
140
|
+
body: Optional section body text
|
|
141
|
+
bullets: Optional list of bullet points
|
|
142
|
+
numbered: Whether this section should be numbered
|
|
143
|
+
numbered_bullets: Whether bullets should be numbered
|
|
144
|
+
subsections: Optional list of subsection objects
|
|
145
|
+
"""
|
|
146
|
+
self._validate_prompt_mode_exclusivity()
|
|
147
|
+
if self.agent._use_pom and self.agent.pom:
|
|
148
|
+
# Create parameters for add_section based on what's supported
|
|
149
|
+
kwargs = {}
|
|
150
|
+
|
|
151
|
+
# Start with basic parameters
|
|
152
|
+
kwargs['title'] = title
|
|
153
|
+
kwargs['body'] = body
|
|
154
|
+
if bullets:
|
|
155
|
+
kwargs['bullets'] = bullets
|
|
156
|
+
|
|
157
|
+
# Add optional parameters if they look supported
|
|
158
|
+
if hasattr(self.agent.pom, 'add_section'):
|
|
159
|
+
sig = inspect.signature(self.agent.pom.add_section)
|
|
160
|
+
if 'numbered' in sig.parameters:
|
|
161
|
+
kwargs['numbered'] = numbered
|
|
162
|
+
if 'numberedBullets' in sig.parameters:
|
|
163
|
+
kwargs['numberedBullets'] = numbered_bullets
|
|
164
|
+
|
|
165
|
+
# Create the section
|
|
166
|
+
section = self.agent.pom.add_section(**kwargs)
|
|
167
|
+
|
|
168
|
+
# Now add subsections if provided, by calling add_subsection on the section
|
|
169
|
+
if subsections:
|
|
170
|
+
for subsection in subsections:
|
|
171
|
+
if 'title' in subsection:
|
|
172
|
+
section.add_subsection(
|
|
173
|
+
title=subsection.get('title'),
|
|
174
|
+
body=subsection.get('body', ''),
|
|
175
|
+
bullets=subsection.get('bullets', [])
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
def prompt_add_to_section(
|
|
179
|
+
self,
|
|
180
|
+
title: str,
|
|
181
|
+
body: Optional[str] = None,
|
|
182
|
+
bullet: Optional[str] = None,
|
|
183
|
+
bullets: Optional[List[str]] = None
|
|
184
|
+
) -> None:
|
|
185
|
+
"""
|
|
186
|
+
Add content to an existing section (creating it if needed).
|
|
187
|
+
|
|
188
|
+
Args:
|
|
189
|
+
title: Section title
|
|
190
|
+
body: Optional text to append to section body
|
|
191
|
+
bullet: Optional single bullet point to add
|
|
192
|
+
bullets: Optional list of bullet points to add
|
|
193
|
+
"""
|
|
194
|
+
if self.agent._use_pom and self.agent.pom:
|
|
195
|
+
# Find the section first
|
|
196
|
+
section = self.agent.pom.find_section(title)
|
|
197
|
+
|
|
198
|
+
if section is None:
|
|
199
|
+
# Section doesn't exist, create it
|
|
200
|
+
section = self.agent.pom.add_section(title=title)
|
|
201
|
+
|
|
202
|
+
# Add content to the section
|
|
203
|
+
if body:
|
|
204
|
+
if section.body:
|
|
205
|
+
section.body = f"{section.body}\n\n{body}"
|
|
206
|
+
else:
|
|
207
|
+
section.body = body
|
|
208
|
+
|
|
209
|
+
# Process bullets
|
|
210
|
+
bullets_to_add = []
|
|
211
|
+
if bullet:
|
|
212
|
+
bullets_to_add.append(bullet)
|
|
213
|
+
if bullets:
|
|
214
|
+
bullets_to_add.extend(bullets)
|
|
215
|
+
|
|
216
|
+
if bullets_to_add:
|
|
217
|
+
section.add_bullets(bullets_to_add)
|
|
218
|
+
|
|
219
|
+
def prompt_add_subsection(
|
|
220
|
+
self,
|
|
221
|
+
parent_title: str,
|
|
222
|
+
title: str,
|
|
223
|
+
body: str = "",
|
|
224
|
+
bullets: Optional[List[str]] = None
|
|
225
|
+
) -> None:
|
|
226
|
+
"""
|
|
227
|
+
Add a subsection to an existing section (creating parent if needed).
|
|
228
|
+
|
|
229
|
+
Args:
|
|
230
|
+
parent_title: Parent section title
|
|
231
|
+
title: Subsection title
|
|
232
|
+
body: Optional subsection body text
|
|
233
|
+
bullets: Optional list of bullet points
|
|
234
|
+
"""
|
|
235
|
+
if self.agent._use_pom and self.agent.pom:
|
|
236
|
+
# First find or create the parent section
|
|
237
|
+
parent_section = None
|
|
238
|
+
|
|
239
|
+
# Try to find the parent section by title
|
|
240
|
+
if hasattr(self.agent.pom, 'sections'):
|
|
241
|
+
for section in self.agent.pom.sections:
|
|
242
|
+
if hasattr(section, 'title') and section.title == parent_title:
|
|
243
|
+
parent_section = section
|
|
244
|
+
break
|
|
245
|
+
|
|
246
|
+
# If parent section not found, create it
|
|
247
|
+
if not parent_section:
|
|
248
|
+
parent_section = self.agent.pom.add_section(title=parent_title)
|
|
249
|
+
|
|
250
|
+
# Now call add_subsection on the parent section object, not on POM
|
|
251
|
+
parent_section.add_subsection(
|
|
252
|
+
title=title,
|
|
253
|
+
body=body,
|
|
254
|
+
bullets=bullets or []
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
def prompt_has_section(self, title: str) -> bool:
|
|
258
|
+
"""
|
|
259
|
+
Check if a section exists in the prompt.
|
|
260
|
+
|
|
261
|
+
Args:
|
|
262
|
+
title: Section title to check
|
|
263
|
+
|
|
264
|
+
Returns:
|
|
265
|
+
True if section exists, False otherwise
|
|
266
|
+
"""
|
|
267
|
+
if self.agent._use_pom and self.agent.pom:
|
|
268
|
+
# Use find_section method from POM
|
|
269
|
+
return self.agent.pom.find_section(title) is not None
|
|
270
|
+
return False
|
|
271
|
+
|
|
272
|
+
def get_prompt(self) -> Optional[Union[str, List[Dict[str, Any]]]]:
|
|
273
|
+
"""
|
|
274
|
+
Get the prompt configuration.
|
|
275
|
+
|
|
276
|
+
Returns:
|
|
277
|
+
Prompt text or sections or None
|
|
278
|
+
"""
|
|
279
|
+
return self._process_prompt_sections()
|
|
280
|
+
|
|
281
|
+
def get_raw_prompt(self) -> Optional[str]:
|
|
282
|
+
"""
|
|
283
|
+
Get the raw prompt text if set.
|
|
284
|
+
|
|
285
|
+
Returns:
|
|
286
|
+
Raw prompt text or None
|
|
287
|
+
"""
|
|
288
|
+
return self._prompt_text
|
|
289
|
+
|
|
290
|
+
def get_post_prompt(self) -> Optional[str]:
|
|
291
|
+
"""
|
|
292
|
+
Get the post-prompt text.
|
|
293
|
+
|
|
294
|
+
Returns:
|
|
295
|
+
Post-prompt text or None
|
|
296
|
+
"""
|
|
297
|
+
return self._post_prompt_text
|
|
298
|
+
|
|
299
|
+
def get_contexts(self) -> Optional[Dict[str, Any]]:
|
|
300
|
+
"""
|
|
301
|
+
Get the contexts configuration.
|
|
302
|
+
|
|
303
|
+
Returns:
|
|
304
|
+
Contexts dict or None
|
|
305
|
+
"""
|
|
306
|
+
return self._contexts
|
|
@@ -0,0 +1,15 @@
|
|
|
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 management modules."""
|
|
11
|
+
|
|
12
|
+
from .registry import ToolRegistry
|
|
13
|
+
from .decorator import ToolDecorator
|
|
14
|
+
|
|
15
|
+
__all__ = ['ToolRegistry', 'ToolDecorator']
|
|
@@ -0,0 +1,97 @@
|
|
|
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
|
+
required = kwargs.pop("required", None)
|
|
54
|
+
|
|
55
|
+
registry.define_tool(
|
|
56
|
+
name=name,
|
|
57
|
+
description=description,
|
|
58
|
+
parameters=parameters,
|
|
59
|
+
handler=func,
|
|
60
|
+
secure=secure,
|
|
61
|
+
fillers=fillers,
|
|
62
|
+
webhook_url=webhook_url,
|
|
63
|
+
required=required,
|
|
64
|
+
**kwargs # Pass through any additional swaig_fields
|
|
65
|
+
)
|
|
66
|
+
return func
|
|
67
|
+
return inner_decorator
|
|
68
|
+
return decorator
|
|
69
|
+
|
|
70
|
+
@classmethod
|
|
71
|
+
def create_class_decorator(cls):
|
|
72
|
+
"""
|
|
73
|
+
Create class tool decorator.
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
Decorator function
|
|
77
|
+
"""
|
|
78
|
+
def tool(name=None, **kwargs):
|
|
79
|
+
"""
|
|
80
|
+
Class method decorator for defining SWAIG tools.
|
|
81
|
+
|
|
82
|
+
Used as:
|
|
83
|
+
|
|
84
|
+
@AgentBase.tool(name="example_function", parameters={...})
|
|
85
|
+
def example_function(self, param1):
|
|
86
|
+
# ...
|
|
87
|
+
"""
|
|
88
|
+
def decorator(func):
|
|
89
|
+
# Mark the function as a tool
|
|
90
|
+
func._is_tool = True
|
|
91
|
+
func._tool_name = name if name else func.__name__
|
|
92
|
+
func._tool_params = kwargs
|
|
93
|
+
|
|
94
|
+
# Return the original function
|
|
95
|
+
return func
|
|
96
|
+
return decorator
|
|
97
|
+
return tool
|