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.
Files changed (37) hide show
  1. signalwire_agents/__init__.py +1 -1
  2. signalwire_agents/agent_server.py +50 -11
  3. signalwire_agents/core/__init__.py +2 -2
  4. signalwire_agents/core/agent/__init__.py +14 -0
  5. signalwire_agents/core/agent/config/__init__.py +14 -0
  6. signalwire_agents/core/agent/config/ephemeral.py +176 -0
  7. signalwire_agents/core/agent/deployment/__init__.py +0 -0
  8. signalwire_agents/core/agent/deployment/handlers/__init__.py +0 -0
  9. signalwire_agents/core/agent/prompt/__init__.py +14 -0
  10. signalwire_agents/core/agent/prompt/manager.py +288 -0
  11. signalwire_agents/core/agent/routing/__init__.py +0 -0
  12. signalwire_agents/core/agent/security/__init__.py +0 -0
  13. signalwire_agents/core/agent/swml/__init__.py +0 -0
  14. signalwire_agents/core/agent/tools/__init__.py +15 -0
  15. signalwire_agents/core/agent/tools/decorator.py +95 -0
  16. signalwire_agents/core/agent/tools/registry.py +192 -0
  17. signalwire_agents/core/agent_base.py +131 -413
  18. signalwire_agents/core/data_map.py +3 -15
  19. signalwire_agents/core/skill_manager.py +0 -17
  20. signalwire_agents/core/swaig_function.py +0 -2
  21. signalwire_agents/core/swml_builder.py +207 -11
  22. signalwire_agents/core/swml_renderer.py +123 -312
  23. signalwire_agents/core/swml_service.py +25 -94
  24. signalwire_agents/search/index_builder.py +1 -1
  25. signalwire_agents/skills/api_ninjas_trivia/__init__.py +3 -0
  26. signalwire_agents/skills/api_ninjas_trivia/skill.py +192 -0
  27. signalwire_agents/skills/play_background_file/__init__.py +3 -0
  28. signalwire_agents/skills/play_background_file/skill.py +197 -0
  29. signalwire_agents/skills/weather_api/__init__.py +3 -0
  30. signalwire_agents/skills/weather_api/skill.py +154 -0
  31. {signalwire_agents-0.1.20.dist-info → signalwire_agents-0.1.23.dist-info}/METADATA +5 -8
  32. {signalwire_agents-0.1.20.dist-info → signalwire_agents-0.1.23.dist-info}/RECORD +37 -18
  33. {signalwire_agents-0.1.20.data → signalwire_agents-0.1.23.data}/data/schema.json +0 -0
  34. {signalwire_agents-0.1.20.dist-info → signalwire_agents-0.1.23.dist-info}/WHEEL +0 -0
  35. {signalwire_agents-0.1.20.dist-info → signalwire_agents-0.1.23.dist-info}/entry_points.txt +0 -0
  36. {signalwire_agents-0.1.20.dist-info → signalwire_agents-0.1.23.dist-info}/licenses/LICENSE +0 -0
  37. {signalwire_agents-0.1.20.dist-info → signalwire_agents-0.1.23.dist-info}/top_level.txt +0 -0
@@ -18,7 +18,7 @@ A package for building AI agents using SignalWire's AI and SWML capabilities.
18
18
  from .core.logging_config import configure_logging
19
19
  configure_logging()
20
20
 
21
- __version__ = "0.1.20"
21
+ __version__ = "0.1.23"
22
22
 
23
23
  # Import core classes for easier access
24
24
  from .core.agent_base import AgentBase
@@ -11,6 +11,7 @@ See LICENSE file in the project root for full license information.
11
11
  AgentServer - Class for hosting multiple SignalWire AI Agents in a single server
12
12
  """
13
13
 
14
+ import os
14
15
  import re
15
16
  from typing import Dict, Any, Optional, List, Tuple, Callable
16
17
 
@@ -575,24 +576,62 @@ class AgentServer:
575
576
  # No matching agent found
576
577
  return {"error": "Not Found"}
577
578
 
578
- # Print server info
579
+ # Set host and port
579
580
  host = host or self.host
580
581
  port = port or self.port
581
582
 
582
- self.logger.info(f"Starting server on {host}:{port}")
583
+ # Check for SSL configuration from environment variables
584
+ ssl_enabled_env = os.environ.get('SWML_SSL_ENABLED', '').lower()
585
+ ssl_enabled = ssl_enabled_env in ('true', '1', 'yes')
586
+ ssl_cert_path = os.environ.get('SWML_SSL_CERT_PATH')
587
+ ssl_key_path = os.environ.get('SWML_SSL_KEY_PATH')
588
+ domain = os.environ.get('SWML_DOMAIN')
589
+
590
+ # Validate SSL configuration if enabled
591
+ if ssl_enabled:
592
+ if not ssl_cert_path or not os.path.exists(ssl_cert_path):
593
+ self.logger.warning(f"SSL cert not found: {ssl_cert_path}")
594
+ ssl_enabled = False
595
+ elif not ssl_key_path or not os.path.exists(ssl_key_path):
596
+ self.logger.warning(f"SSL key not found: {ssl_key_path}")
597
+ ssl_enabled = False
598
+
599
+ # Update server info display with correct protocol
600
+ protocol = "https" if ssl_enabled else "http"
601
+
602
+ # Determine display host - include port unless it's the standard port for the protocol
603
+ if ssl_enabled and domain:
604
+ # Use domain, but include port if it's not the standard HTTPS port (443)
605
+ display_host = f"{domain}:{port}" if port != 443 else domain
606
+ else:
607
+ # Use host:port for HTTP or when no domain is specified
608
+ display_host = f"{host}:{port}"
609
+
610
+ self.logger.info(f"Starting server on {protocol}://{display_host}")
583
611
  for route, agent in self.agents.items():
584
612
  username, password = agent.get_basic_auth_credentials()
585
613
  self.logger.info(f"Agent '{agent.get_name()}' available at:")
586
- self.logger.info(f"URL: http://{host}:{port}{route}")
614
+ self.logger.info(f"URL: {protocol}://{display_host}{route}")
587
615
  self.logger.info(f"Basic Auth: {username}:{password}")
588
-
589
- # Start the server
590
- uvicorn.run(
591
- self.app,
592
- host=host,
593
- port=port,
594
- log_level=self.log_level
595
- )
616
+
617
+ # Start the server with or without SSL
618
+ if ssl_enabled and ssl_cert_path and ssl_key_path:
619
+ self.logger.info(f"Starting with SSL - cert: {ssl_cert_path}, key: {ssl_key_path}")
620
+ uvicorn.run(
621
+ self.app,
622
+ host=host,
623
+ port=port,
624
+ log_level=self.log_level,
625
+ ssl_certfile=ssl_cert_path,
626
+ ssl_keyfile=ssl_key_path
627
+ )
628
+ else:
629
+ uvicorn.run(
630
+ self.app,
631
+ host=host,
632
+ port=port,
633
+ log_level=self.log_level
634
+ )
596
635
 
597
636
  def register_global_routing_callback(self, callback_fn: Callable[[Request, Dict[str, Any]], Optional[str]],
598
637
  path: str) -> None:
@@ -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 SwaigFunction
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
- 'SwaigFunction',
24
+ 'SWAIGFunction',
25
25
  'SWMLService',
26
26
  'SWMLVerbHandler',
27
27
  'VerbHandlerRegistry',
@@ -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
+ """Agent refactored components."""
11
+
12
+ from .config.ephemeral import EphemeralAgentConfig
13
+
14
+ __all__ = ['EphemeralAgentConfig']
@@ -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
+ """Configuration management modules."""
11
+
12
+ from .ephemeral import EphemeralAgentConfig
13
+
14
+ __all__ = ['EphemeralAgentConfig']
@@ -0,0 +1,176 @@
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
+ """Ephemeral agent configuration for dynamic per-request settings."""
11
+
12
+ from typing import Dict, Any, Optional, List
13
+
14
+
15
+ class EphemeralAgentConfig:
16
+ """
17
+ An ephemeral configurator object that mimics AgentBase's configuration interface.
18
+
19
+ This allows dynamic configuration callbacks to use the same familiar methods
20
+ they would use during agent initialization, but for per-request configuration.
21
+ """
22
+
23
+ def __init__(self):
24
+ # Initialize all configuration containers
25
+ self._hints = []
26
+ self._languages = []
27
+ self._pronounce = []
28
+ self._params = {}
29
+ self._global_data = {}
30
+ self._prompt_sections = []
31
+ self._raw_prompt = None
32
+ self._post_prompt = None
33
+ self._function_includes = []
34
+ self._native_functions = []
35
+
36
+ # Mirror all the AgentBase configuration methods
37
+
38
+ def add_hint(self, hint: str) -> 'EphemeralAgentConfig':
39
+ """Add a simple string hint"""
40
+ if isinstance(hint, str) and hint:
41
+ self._hints.append(hint)
42
+ return self
43
+
44
+ def add_hints(self, hints: List[str]) -> 'EphemeralAgentConfig':
45
+ """Add multiple string hints"""
46
+ if hints and isinstance(hints, list):
47
+ for hint in hints:
48
+ if isinstance(hint, str) and hint:
49
+ self._hints.append(hint)
50
+ return self
51
+
52
+ def add_language(self, name: str, code: str, voice: str, **kwargs) -> 'EphemeralAgentConfig':
53
+ """Add a language configuration"""
54
+ language = {
55
+ "name": name,
56
+ "code": code,
57
+ "voice": voice
58
+ }
59
+
60
+ # Handle additional parameters
61
+ for key, value in kwargs.items():
62
+ if key in ["engine", "model", "speech_fillers", "function_fillers", "fillers"]:
63
+ language[key] = value
64
+
65
+ self._languages.append(language)
66
+ return self
67
+
68
+ def add_pronunciation(self, replace: str, with_text: str, ignore_case: bool = False) -> 'EphemeralAgentConfig':
69
+ """Add a pronunciation rule"""
70
+ if replace and with_text:
71
+ rule = {"replace": replace, "with": with_text}
72
+ if ignore_case:
73
+ rule["ignore_case"] = True
74
+ self._pronounce.append(rule)
75
+ return self
76
+
77
+ def set_param(self, key: str, value: Any) -> 'EphemeralAgentConfig':
78
+ """Set a single AI parameter"""
79
+ if key:
80
+ self._params[key] = value
81
+ return self
82
+
83
+ def set_params(self, params: Dict[str, Any]) -> 'EphemeralAgentConfig':
84
+ """Set multiple AI parameters"""
85
+ if params and isinstance(params, dict):
86
+ self._params.update(params)
87
+ return self
88
+
89
+ def set_global_data(self, data: Dict[str, Any]) -> 'EphemeralAgentConfig':
90
+ """Set global data"""
91
+ if data and isinstance(data, dict):
92
+ self._global_data = data
93
+ return self
94
+
95
+ def update_global_data(self, data: Dict[str, Any]) -> 'EphemeralAgentConfig':
96
+ """Update global data"""
97
+ if data and isinstance(data, dict):
98
+ self._global_data.update(data)
99
+ return self
100
+
101
+ def set_prompt_text(self, text: str) -> 'EphemeralAgentConfig':
102
+ """Set raw prompt text"""
103
+ self._raw_prompt = text
104
+ return self
105
+
106
+ def set_post_prompt(self, text: str) -> 'EphemeralAgentConfig':
107
+ """Set post-prompt text"""
108
+ self._post_prompt = text
109
+ return self
110
+
111
+ def prompt_add_section(self, title: str, body: str = "", bullets: Optional[List[str]] = None, **kwargs) -> 'EphemeralAgentConfig':
112
+ """Add a prompt section"""
113
+ section = {
114
+ "title": title,
115
+ "body": body
116
+ }
117
+ if bullets:
118
+ section["bullets"] = bullets
119
+
120
+ # Handle additional parameters
121
+ for key, value in kwargs.items():
122
+ if key in ["numbered", "numbered_bullets", "subsections"]:
123
+ section[key] = value
124
+
125
+ self._prompt_sections.append(section)
126
+ return self
127
+
128
+ def set_native_functions(self, function_names: List[str]) -> 'EphemeralAgentConfig':
129
+ """Set native functions"""
130
+ if function_names and isinstance(function_names, list):
131
+ self._native_functions = [name for name in function_names if isinstance(name, str)]
132
+ return self
133
+
134
+ def add_function_include(self, url: str, functions: List[str], meta_data: Optional[Dict[str, Any]] = None) -> 'EphemeralAgentConfig':
135
+ """Add a function include"""
136
+ if url and functions and isinstance(functions, list):
137
+ include = {"url": url, "functions": functions}
138
+ if meta_data and isinstance(meta_data, dict):
139
+ include["meta_data"] = meta_data
140
+ self._function_includes.append(include)
141
+ return self
142
+
143
+ def extract_config(self) -> Dict[str, Any]:
144
+ """
145
+ Extract the configuration as a dictionary for applying to the real agent.
146
+
147
+ Returns:
148
+ Dictionary containing all the configuration changes
149
+ """
150
+ config = {}
151
+
152
+ if self._hints:
153
+ config["hints"] = self._hints
154
+ if self._languages:
155
+ config["languages"] = self._languages
156
+ if self._pronounce:
157
+ config["pronounce"] = self._pronounce
158
+ if self._params:
159
+ config["params"] = self._params
160
+ if self._global_data:
161
+ config["global_data"] = self._global_data
162
+ if self._function_includes:
163
+ config["function_includes"] = self._function_includes
164
+ if self._native_functions:
165
+ config["native_functions"] = self._native_functions
166
+
167
+ # Handle prompt sections - these should be applied to the agent's POM, not as raw config
168
+ # The calling code should use these to build the prompt properly
169
+ if self._prompt_sections:
170
+ config["_ephemeral_prompt_sections"] = self._prompt_sections
171
+ if self._raw_prompt:
172
+ config["_ephemeral_raw_prompt"] = self._raw_prompt
173
+ if self._post_prompt:
174
+ config["_ephemeral_post_prompt"] = self._post_prompt
175
+
176
+ return config
File without changes
@@ -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,288 @@
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
+ self.agent.pom.add_to_section(
196
+ title=title,
197
+ body=body,
198
+ bullet=bullet,
199
+ bullets=bullets
200
+ )
201
+
202
+ def prompt_add_subsection(
203
+ self,
204
+ parent_title: str,
205
+ title: str,
206
+ body: str = "",
207
+ bullets: Optional[List[str]] = None
208
+ ) -> None:
209
+ """
210
+ Add a subsection to an existing section (creating parent if needed).
211
+
212
+ Args:
213
+ parent_title: Parent section title
214
+ title: Subsection title
215
+ body: Optional subsection body text
216
+ bullets: Optional list of bullet points
217
+ """
218
+ if self.agent._use_pom and self.agent.pom:
219
+ # First find or create the parent section
220
+ parent_section = None
221
+
222
+ # Try to find the parent section by title
223
+ if hasattr(self.agent.pom, 'sections'):
224
+ for section in self.agent.pom.sections:
225
+ if hasattr(section, 'title') and section.title == parent_title:
226
+ parent_section = section
227
+ break
228
+
229
+ # If parent section not found, create it
230
+ if not parent_section:
231
+ parent_section = self.agent.pom.add_section(title=parent_title)
232
+
233
+ # Now call add_subsection on the parent section object, not on POM
234
+ parent_section.add_subsection(
235
+ title=title,
236
+ body=body,
237
+ bullets=bullets or []
238
+ )
239
+
240
+ def prompt_has_section(self, title: str) -> bool:
241
+ """
242
+ Check if a section exists in the prompt.
243
+
244
+ Args:
245
+ title: Section title to check
246
+
247
+ Returns:
248
+ True if section exists, False otherwise
249
+ """
250
+ if self.agent._use_pom and self.agent.pom:
251
+ return self.agent.pom.has_section(title)
252
+ return False
253
+
254
+ def get_prompt(self) -> Optional[Union[str, List[Dict[str, Any]]]]:
255
+ """
256
+ Get the prompt configuration.
257
+
258
+ Returns:
259
+ Prompt text or sections or None
260
+ """
261
+ return self._process_prompt_sections()
262
+
263
+ def get_raw_prompt(self) -> Optional[str]:
264
+ """
265
+ Get the raw prompt text if set.
266
+
267
+ Returns:
268
+ Raw prompt text or None
269
+ """
270
+ return self._prompt_text
271
+
272
+ def get_post_prompt(self) -> Optional[str]:
273
+ """
274
+ Get the post-prompt text.
275
+
276
+ Returns:
277
+ Post-prompt text or None
278
+ """
279
+ return self._post_prompt_text
280
+
281
+ def get_contexts(self) -> Optional[Dict[str, Any]]:
282
+ """
283
+ Get the contexts configuration.
284
+
285
+ Returns:
286
+ Contexts dict or None
287
+ """
288
+ return self._contexts
File without changes
File without changes
File without changes
@@ -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']