signalwire-agents 0.1.10__py3-none-any.whl → 0.1.12__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 (46) hide show
  1. signalwire_agents/__init__.py +43 -4
  2. signalwire_agents/agent_server.py +268 -15
  3. signalwire_agents/cli/__init__.py +9 -0
  4. signalwire_agents/cli/build_search.py +457 -0
  5. signalwire_agents/cli/test_swaig.py +2609 -0
  6. signalwire_agents/core/agent_base.py +691 -82
  7. signalwire_agents/core/contexts.py +289 -0
  8. signalwire_agents/core/data_map.py +499 -0
  9. signalwire_agents/core/function_result.py +57 -10
  10. signalwire_agents/core/logging_config.py +232 -0
  11. signalwire_agents/core/skill_base.py +27 -37
  12. signalwire_agents/core/skill_manager.py +89 -23
  13. signalwire_agents/core/swaig_function.py +13 -1
  14. signalwire_agents/core/swml_handler.py +37 -13
  15. signalwire_agents/core/swml_service.py +37 -28
  16. signalwire_agents/search/__init__.py +131 -0
  17. signalwire_agents/search/document_processor.py +764 -0
  18. signalwire_agents/search/index_builder.py +534 -0
  19. signalwire_agents/search/query_processor.py +371 -0
  20. signalwire_agents/search/search_engine.py +383 -0
  21. signalwire_agents/search/search_service.py +251 -0
  22. signalwire_agents/skills/datasphere/__init__.py +12 -0
  23. signalwire_agents/skills/datasphere/skill.py +229 -0
  24. signalwire_agents/skills/datasphere_serverless/__init__.py +1 -0
  25. signalwire_agents/skills/datasphere_serverless/skill.py +156 -0
  26. signalwire_agents/skills/datetime/skill.py +9 -5
  27. signalwire_agents/skills/joke/__init__.py +1 -0
  28. signalwire_agents/skills/joke/skill.py +88 -0
  29. signalwire_agents/skills/math/skill.py +9 -6
  30. signalwire_agents/skills/native_vector_search/__init__.py +1 -0
  31. signalwire_agents/skills/native_vector_search/skill.py +352 -0
  32. signalwire_agents/skills/registry.py +10 -4
  33. signalwire_agents/skills/web_search/skill.py +57 -21
  34. signalwire_agents/skills/wikipedia/__init__.py +9 -0
  35. signalwire_agents/skills/wikipedia/skill.py +180 -0
  36. signalwire_agents/utils/__init__.py +14 -0
  37. signalwire_agents/utils/schema_utils.py +111 -44
  38. signalwire_agents-0.1.12.dist-info/METADATA +863 -0
  39. signalwire_agents-0.1.12.dist-info/RECORD +67 -0
  40. {signalwire_agents-0.1.10.dist-info → signalwire_agents-0.1.12.dist-info}/WHEEL +1 -1
  41. signalwire_agents-0.1.12.dist-info/entry_points.txt +3 -0
  42. signalwire_agents-0.1.10.dist-info/METADATA +0 -319
  43. signalwire_agents-0.1.10.dist-info/RECORD +0 -44
  44. {signalwire_agents-0.1.10.data → signalwire_agents-0.1.12.data}/data/schema.json +0 -0
  45. {signalwire_agents-0.1.10.dist-info → signalwire_agents-0.1.12.dist-info}/licenses/LICENSE +0 -0
  46. {signalwire_agents-0.1.10.dist-info → signalwire_agents-0.1.12.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,229 @@
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
+ import requests
11
+ import json
12
+ from typing import Optional, List, Dict, Any
13
+
14
+ from signalwire_agents.core.skill_base import SkillBase
15
+ from signalwire_agents.core.function_result import SwaigFunctionResult
16
+
17
+ class DataSphereSkill(SkillBase):
18
+ """SignalWire DataSphere knowledge search capability"""
19
+
20
+ SKILL_NAME = "datasphere"
21
+ SKILL_DESCRIPTION = "Search knowledge using SignalWire DataSphere RAG stack"
22
+ SKILL_VERSION = "1.0.0"
23
+ REQUIRED_PACKAGES = ["requests"]
24
+ REQUIRED_ENV_VARS = [] # No required env vars since all config comes from params
25
+
26
+ # Enable multiple instances support
27
+ SUPPORTS_MULTIPLE_INSTANCES = True
28
+
29
+ def get_instance_key(self) -> str:
30
+ """
31
+ Get the key used to track this skill instance
32
+
33
+ For DataSphere, we use 'search_knowledge' as the default tool name instead of 'datasphere'
34
+ """
35
+ tool_name = self.params.get('tool_name', 'search_knowledge')
36
+ return f"{self.SKILL_NAME}_{tool_name}"
37
+
38
+ def setup(self) -> bool:
39
+ """Setup the datasphere skill"""
40
+ # Validate required parameters
41
+ required_params = ['space_name', 'project_id', 'token', 'document_id']
42
+ missing_params = [param for param in required_params if not self.params.get(param)]
43
+ if missing_params:
44
+ self.logger.error(f"Missing required parameters: {missing_params}")
45
+ return False
46
+
47
+ # Set required parameters
48
+ self.space_name = self.params['space_name']
49
+ self.project_id = self.params['project_id']
50
+ self.token = self.params['token']
51
+ self.document_id = self.params['document_id']
52
+
53
+ # Set optional parameters with defaults
54
+ self.count = self.params.get('count', 1)
55
+ self.distance = self.params.get('distance', 3.0)
56
+ self.tags = self.params.get('tags', None) # None means don't include in request
57
+ self.language = self.params.get('language', None) # None means don't include in request
58
+ self.pos_to_expand = self.params.get('pos_to_expand', None) # None means don't include in request
59
+ self.max_synonyms = self.params.get('max_synonyms', None) # None means don't include in request
60
+
61
+ # Tool name (for multiple instances)
62
+ self.tool_name = self.params.get('tool_name', 'search_knowledge')
63
+
64
+ # No results message
65
+ self.no_results_message = self.params.get('no_results_message',
66
+ "I couldn't find any relevant information for '{query}' in the knowledge base. "
67
+ "Try rephrasing your question or asking about a different topic."
68
+ )
69
+
70
+ # Build API URL
71
+ self.api_url = f"https://{self.space_name}.signalwire.com/api/datasphere/documents/search"
72
+
73
+ # Setup session for requests
74
+ self.session = requests.Session()
75
+
76
+ return True
77
+
78
+ def register_tools(self) -> None:
79
+ """Register knowledge search tool with the agent"""
80
+ self.agent.define_tool(
81
+ name=self.tool_name,
82
+ description="Search the knowledge base for information on any topic and return relevant results",
83
+ parameters={
84
+ "query": {
85
+ "type": "string",
86
+ "description": "The search query - what information you're looking for in the knowledge base"
87
+ }
88
+ },
89
+ handler=self._search_knowledge_handler,
90
+ **self.swaig_fields
91
+ )
92
+
93
+ def _search_knowledge_handler(self, args, raw_data):
94
+ """Handler for knowledge search tool"""
95
+ query = args.get("query", "").strip()
96
+
97
+ if not query:
98
+ return SwaigFunctionResult(
99
+ "Please provide a search query. What would you like me to search for in the knowledge base?"
100
+ )
101
+
102
+ self.logger.info(f"DataSphere search requested: '{query}' (document: {self.document_id})")
103
+
104
+ # Build request payload
105
+ payload = {
106
+ "document_id": self.document_id,
107
+ "query_string": query,
108
+ "distance": self.distance,
109
+ "count": self.count
110
+ }
111
+
112
+ # Add optional parameters only if they were provided
113
+ if self.tags is not None:
114
+ payload["tags"] = self.tags
115
+ if self.language is not None:
116
+ payload["language"] = self.language
117
+ if self.pos_to_expand is not None:
118
+ payload["pos_to_expand"] = self.pos_to_expand
119
+ if self.max_synonyms is not None:
120
+ payload["max_synonyms"] = self.max_synonyms
121
+
122
+ try:
123
+ # Make API request
124
+ response = self.session.post(
125
+ self.api_url,
126
+ auth=(self.project_id, self.token),
127
+ headers={
128
+ 'Content-Type': 'application/json',
129
+ 'Accept': 'application/json'
130
+ },
131
+ json=payload,
132
+ timeout=30
133
+ )
134
+
135
+ response.raise_for_status()
136
+ data = response.json()
137
+
138
+ # Check if we have valid response data
139
+ if not data or not isinstance(data, dict):
140
+ self.logger.warning(f"DataSphere API returned invalid data: {data}")
141
+ formatted_message = self.no_results_message.format(query=query) if '{query}' in self.no_results_message else self.no_results_message
142
+ return SwaigFunctionResult(formatted_message)
143
+
144
+ # Extract results - DataSphere API returns 'chunks', not 'results'
145
+ chunks = data.get('chunks', [])
146
+
147
+ if not chunks:
148
+ formatted_message = self.no_results_message.format(query=query) if '{query}' in self.no_results_message else self.no_results_message
149
+ return SwaigFunctionResult(formatted_message)
150
+
151
+ # Format the results
152
+ formatted_results = self._format_search_results(query, chunks)
153
+ return SwaigFunctionResult(formatted_results)
154
+
155
+ except requests.exceptions.Timeout:
156
+ self.logger.error("DataSphere API request timed out")
157
+ return SwaigFunctionResult(
158
+ "Sorry, the knowledge search timed out. Please try again."
159
+ )
160
+ except requests.exceptions.HTTPError as e:
161
+ self.logger.error(f"DataSphere API HTTP error: {e}")
162
+ return SwaigFunctionResult(
163
+ "Sorry, there was an error accessing the knowledge base. Please try again later."
164
+ )
165
+ except Exception as e:
166
+ self.logger.error(f"Error performing DataSphere search: {e}")
167
+ return SwaigFunctionResult(
168
+ "Sorry, I encountered an error while searching the knowledge base. Please try again later."
169
+ )
170
+
171
+ def _format_search_results(self, query: str, chunks: List[Dict[str, Any]]) -> str:
172
+ """Format search results for display"""
173
+ if len(chunks) == 1:
174
+ result_text = f"I found 1 result for '{query}':\n\n"
175
+ else:
176
+ result_text = f"I found {len(chunks)} results for '{query}':\n\n"
177
+
178
+ formatted_results = []
179
+
180
+ for i, chunk in enumerate(chunks, 1):
181
+ result_content = f"=== RESULT {i} ===\n"
182
+
183
+ # DataSphere API returns chunks with 'text' field
184
+ if 'text' in chunk:
185
+ result_content += chunk['text']
186
+ elif 'content' in chunk:
187
+ result_content += chunk['content']
188
+ elif 'chunk' in chunk:
189
+ result_content += chunk['chunk']
190
+ else:
191
+ # Fallback to the entire result as JSON if we don't recognize the format
192
+ result_content += json.dumps(chunk, indent=2)
193
+
194
+ result_content += f"\n{'='*50}\n\n"
195
+ formatted_results.append(result_content)
196
+
197
+ return result_text + '\n'.join(formatted_results)
198
+
199
+ def get_hints(self) -> List[str]:
200
+ """Return speech recognition hints"""
201
+ # Currently no hints provided, but you could add them like:
202
+ # return [
203
+ # "knowledge", "search", "information", "database", "find",
204
+ # "look up", "research", "query", "datasphere", "document"
205
+ # ]
206
+ return []
207
+
208
+ def get_global_data(self) -> Dict[str, Any]:
209
+ """Return global data for agent context"""
210
+ return {
211
+ "datasphere_enabled": True,
212
+ "document_id": self.document_id,
213
+ "knowledge_provider": "SignalWire DataSphere"
214
+ }
215
+
216
+ def get_prompt_sections(self) -> List[Dict[str, Any]]:
217
+ """Return prompt sections to add to agent"""
218
+ return [
219
+ {
220
+ "title": "Knowledge Search Capability",
221
+ "body": f"You can search a knowledge base for information using the {self.tool_name} tool.",
222
+ "bullets": [
223
+ f"Use the {self.tool_name} tool when users ask for information that might be in the knowledge base",
224
+ "Search for relevant information using clear, specific queries",
225
+ "Summarize search results in a clear, helpful way",
226
+ "If no results are found, suggest the user try rephrasing their question"
227
+ ]
228
+ }
229
+ ]
@@ -0,0 +1 @@
1
+ """DataSphere Serverless Skill for SignalWire Agents using DataMap"""
@@ -0,0 +1,156 @@
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
+ import base64
11
+ from typing import Optional, List, Dict, Any
12
+
13
+ from signalwire_agents.core.skill_base import SkillBase
14
+ from signalwire_agents.core.data_map import DataMap
15
+ from signalwire_agents.core.function_result import SwaigFunctionResult
16
+
17
+ class DataSphereServerlessSkill(SkillBase):
18
+ """SignalWire DataSphere knowledge search using DataMap (serverless execution)"""
19
+
20
+ SKILL_NAME = "datasphere_serverless"
21
+ SKILL_DESCRIPTION = "Search knowledge using SignalWire DataSphere with serverless DataMap execution"
22
+ SKILL_VERSION = "1.0.0"
23
+ REQUIRED_PACKAGES = [] # DataMap handles API calls serverlessly
24
+ REQUIRED_ENV_VARS = [] # No required env vars since all config comes from params
25
+
26
+ # Enable multiple instances support
27
+ SUPPORTS_MULTIPLE_INSTANCES = True
28
+
29
+ def get_instance_key(self) -> str:
30
+ """
31
+ Get the key used to track this skill instance
32
+
33
+ For DataSphere Serverless, we use 'search_knowledge' as the default tool name
34
+ """
35
+ tool_name = self.params.get('tool_name', 'search_knowledge')
36
+ return f"{self.SKILL_NAME}_{tool_name}"
37
+
38
+ def setup(self) -> bool:
39
+ """Setup the datasphere serverless skill"""
40
+ # Validate required parameters
41
+ required_params = ['space_name', 'project_id', 'token', 'document_id']
42
+ missing_params = [param for param in required_params if not self.params.get(param)]
43
+ if missing_params:
44
+ self.logger.error(f"Missing required parameters: {missing_params}")
45
+ return False
46
+
47
+ # Set required parameters
48
+ self.space_name = self.params['space_name']
49
+ self.project_id = self.params['project_id']
50
+ self.token = self.params['token']
51
+ self.document_id = self.params['document_id']
52
+
53
+ # Set optional parameters with defaults
54
+ self.count = self.params.get('count', 1)
55
+ self.distance = self.params.get('distance', 3.0)
56
+ self.tags = self.params.get('tags', None)
57
+ self.language = self.params.get('language', None)
58
+ self.pos_to_expand = self.params.get('pos_to_expand', None)
59
+ self.max_synonyms = self.params.get('max_synonyms', None)
60
+
61
+ # Tool name (for multiple instances)
62
+ self.tool_name = self.params.get('tool_name', 'search_knowledge')
63
+
64
+ # No results message
65
+ self.no_results_message = self.params.get('no_results_message',
66
+ "I couldn't find any relevant information for '{query}' in the knowledge base. "
67
+ "Try rephrasing your question or asking about a different topic."
68
+ )
69
+
70
+ # Build API URL
71
+ self.api_url = f"https://{self.space_name}.signalwire.com/api/datasphere/documents/search"
72
+
73
+ # Build auth header for DataMap
74
+ auth_string = f"{self.project_id}:{self.token}"
75
+ self.auth_header = base64.b64encode(auth_string.encode()).decode()
76
+
77
+ return True
78
+
79
+ def register_tools(self) -> None:
80
+ """Register knowledge search tool using DataMap"""
81
+
82
+ # Build webhook params with configuration values
83
+ webhook_params = {
84
+ "document_id": self.document_id,
85
+ "query_string": "${args.query}", # Only this is dynamic from user input
86
+ "distance": self.distance,
87
+ "count": self.count
88
+ }
89
+
90
+ # Add optional parameters only if they were provided
91
+ if self.tags is not None:
92
+ webhook_params["tags"] = self.tags
93
+ if self.language is not None:
94
+ webhook_params["language"] = self.language
95
+ if self.pos_to_expand is not None:
96
+ webhook_params["pos_to_expand"] = self.pos_to_expand
97
+ if self.max_synonyms is not None:
98
+ webhook_params["max_synonyms"] = self.max_synonyms
99
+
100
+ # Create DataMap tool for DataSphere search
101
+ datasphere_tool = (DataMap(self.tool_name)
102
+ .description("Search the knowledge base for information on any topic and return relevant results")
103
+ .parameter('query', 'string', 'The search query - what information you\'re looking for in the knowledge base', required=True)
104
+ .webhook('POST', self.api_url,
105
+ headers={
106
+ 'Content-Type': 'application/json',
107
+ 'Authorization': f'Basic {self.auth_header}'
108
+ })
109
+ .params(webhook_params)
110
+ .foreach({
111
+ "input_key": "chunks",
112
+ "output_key": "formatted_results",
113
+ "max": self.count,
114
+ "append": "=== RESULT ===\n${this.text}\n" + "="*50 + "\n\n"
115
+ })
116
+ .output(SwaigFunctionResult('I found results for "${args.query}":\n\n${formatted_results}'))
117
+ .error_keys(['error'])
118
+ .fallback_output(SwaigFunctionResult(self.no_results_message.replace('{query}', '${args.query}')))
119
+ )
120
+
121
+ # Convert DataMap to SWAIG function and apply swaig_fields
122
+ swaig_function = datasphere_tool.to_swaig_function()
123
+
124
+ # Merge swaig_fields from skill params into the function definition
125
+ swaig_function.update(self.swaig_fields)
126
+
127
+ # Register the enhanced DataMap tool with the agent
128
+ self.agent.register_swaig_function(swaig_function)
129
+
130
+ def get_hints(self) -> List[str]:
131
+ """Return speech recognition hints"""
132
+ return []
133
+
134
+ def get_global_data(self) -> Dict[str, Any]:
135
+ """Return global data for agent context"""
136
+ return {
137
+ "datasphere_serverless_enabled": True,
138
+ "document_id": self.document_id,
139
+ "knowledge_provider": "SignalWire DataSphere (Serverless)"
140
+ }
141
+
142
+ def get_prompt_sections(self) -> List[Dict[str, Any]]:
143
+ """Return prompt sections to add to agent"""
144
+ return [
145
+ {
146
+ "title": "Knowledge Search Capability (Serverless)",
147
+ "body": f"You can search a knowledge base for information using the {self.tool_name} tool.",
148
+ "bullets": [
149
+ f"Use the {self.tool_name} tool when users ask for information that might be in the knowledge base",
150
+ "Search for relevant information using clear, specific queries",
151
+ "Summarize search results in a clear, helpful way",
152
+ "If no results are found, suggest the user try rephrasing their question",
153
+ "This tool executes on SignalWire servers for optimal performance"
154
+ ]
155
+ }
156
+ ]
@@ -30,7 +30,7 @@ class DateTimeSkill(SkillBase):
30
30
  def register_tools(self) -> None:
31
31
  """Register datetime tools with the agent"""
32
32
 
33
- self.define_tool_with_swaig_fields(
33
+ self.agent.define_tool(
34
34
  name="get_current_time",
35
35
  description="Get the current time, optionally in a specific timezone",
36
36
  parameters={
@@ -39,10 +39,11 @@ class DateTimeSkill(SkillBase):
39
39
  "description": "Timezone name (e.g., 'America/New_York', 'Europe/London'). Defaults to UTC."
40
40
  }
41
41
  },
42
- handler=self._get_time_handler
42
+ handler=self._get_time_handler,
43
+ **self.swaig_fields
43
44
  )
44
45
 
45
- self.define_tool_with_swaig_fields(
46
+ self.agent.define_tool(
46
47
  name="get_current_date",
47
48
  description="Get the current date",
48
49
  parameters={
@@ -51,7 +52,8 @@ class DateTimeSkill(SkillBase):
51
52
  "description": "Timezone name for the date. Defaults to UTC."
52
53
  }
53
54
  },
54
- handler=self._get_date_handler
55
+ handler=self._get_date_handler,
56
+ **self.swaig_fields
55
57
  )
56
58
 
57
59
  def _get_time_handler(self, args, raw_data):
@@ -92,7 +94,9 @@ class DateTimeSkill(SkillBase):
92
94
 
93
95
  def get_hints(self) -> List[str]:
94
96
  """Return speech recognition hints"""
95
- return ["time", "date", "today", "now", "current", "timezone"]
97
+ # Currently no hints provided, but you could add them like:
98
+ # return ["time", "date", "today", "now", "current", "timezone"]
99
+ return []
96
100
 
97
101
  def get_prompt_sections(self) -> List[Dict[str, Any]]:
98
102
  """Return prompt sections to add to agent"""
@@ -0,0 +1 @@
1
+ """Joke Skill for SignalWire Agents using DataMap"""
@@ -0,0 +1,88 @@
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
+ from typing import List, Dict, Any
11
+
12
+ from signalwire_agents.core.skill_base import SkillBase
13
+ from signalwire_agents.core.data_map import DataMap
14
+ from signalwire_agents.core.function_result import SwaigFunctionResult
15
+
16
+
17
+ class JokeSkill(SkillBase):
18
+ """Joke telling capability using API Ninjas with DataMap"""
19
+
20
+ SKILL_NAME = "joke"
21
+ SKILL_DESCRIPTION = "Tell jokes using the API Ninjas joke API"
22
+ SKILL_VERSION = "1.0.0"
23
+ REQUIRED_PACKAGES = [] # DataMap doesn't require local packages
24
+ REQUIRED_ENV_VARS = [] # API key comes from parameters
25
+
26
+ def setup(self) -> bool:
27
+ """Setup the joke skill"""
28
+ # Validate required parameters
29
+ required_params = ['api_key']
30
+ missing_params = [param for param in required_params if not self.params.get(param)]
31
+ if missing_params:
32
+ self.logger.error(f"Missing required parameters: {missing_params}")
33
+ return False
34
+
35
+ # Set parameters from config
36
+ self.api_key = self.params['api_key']
37
+
38
+ # Optional parameters with defaults
39
+ self.tool_name = self.params.get('tool_name', 'get_joke')
40
+
41
+ return True
42
+
43
+ def register_tools(self) -> None:
44
+ """Register joke tool using DataMap"""
45
+
46
+ # Create DataMap tool for jokes - uses required enum parameter
47
+ joke_tool = (DataMap(self.tool_name)
48
+ .description('Get a random joke from API Ninjas')
49
+ .parameter('type', 'string', 'Type of joke to get',
50
+ required=True, enum=['jokes', 'dadjokes'])
51
+ .webhook('GET', "https://api.api-ninjas.com/v1/${args.type}",
52
+ headers={'X-Api-Key': self.api_key})
53
+ .output(SwaigFunctionResult('Here\'s a joke: ${array[0].joke}'))
54
+ .error_keys(['error'])
55
+ .fallback_output(SwaigFunctionResult('Sorry, there is a problem with the joke service right now. Please try again later.'))
56
+ )
57
+
58
+ # Register the DataMap tool with the agent
59
+ self.agent.register_swaig_function(joke_tool.to_swaig_function())
60
+
61
+ def get_hints(self) -> List[str]:
62
+ """Return speech recognition hints"""
63
+ # Currently no hints are provided, but you could add them like:
64
+ # return [
65
+ # "joke", "tell me a joke", "funny", "humor", "dad joke",
66
+ # "regular joke", "make me laugh", "comedy"
67
+ # ]
68
+ return []
69
+
70
+ def get_global_data(self) -> Dict[str, Any]:
71
+ """Return global data to be available in DataMap variables"""
72
+ return {
73
+ "joke_skill_enabled": True
74
+ }
75
+
76
+ def get_prompt_sections(self) -> List[Dict[str, Any]]:
77
+ """Return prompt sections to add to agent"""
78
+ return [
79
+ {
80
+ "title": "Joke Telling",
81
+ "body": "You can tell jokes to entertain users.",
82
+ "bullets": [
83
+ f"Use {self.tool_name} to tell jokes when users ask for humor",
84
+ "You can tell regular jokes or dad jokes",
85
+ "Be enthusiastic and fun when sharing jokes"
86
+ ]
87
+ }
88
+ ]
@@ -29,7 +29,7 @@ class MathSkill(SkillBase):
29
29
  def register_tools(self) -> None:
30
30
  """Register math tools with the agent"""
31
31
 
32
- self.define_tool_with_swaig_fields(
32
+ self.agent.define_tool(
33
33
  name="calculate",
34
34
  description="Perform a mathematical calculation with basic operations (+, -, *, /, %, **)",
35
35
  parameters={
@@ -38,7 +38,8 @@ class MathSkill(SkillBase):
38
38
  "description": "Mathematical expression to evaluate (e.g., '2 + 3 * 4', '(10 + 5) / 3')"
39
39
  }
40
40
  },
41
- handler=self._calculate_handler
41
+ handler=self._calculate_handler,
42
+ **self.swaig_fields
42
43
  )
43
44
 
44
45
  def _calculate_handler(self, args, raw_data):
@@ -68,10 +69,12 @@ class MathSkill(SkillBase):
68
69
 
69
70
  def get_hints(self) -> List[str]:
70
71
  """Return speech recognition hints"""
71
- return [
72
- "calculate", "math", "plus", "minus", "times", "multiply",
73
- "divide", "equals", "percent", "power", "squared"
74
- ]
72
+ # Currently no hints provided, but you could add them like:
73
+ # return [
74
+ # "calculate", "math", "plus", "minus", "times", "multiply",
75
+ # "divide", "equals", "percent", "power", "squared"
76
+ # ]
77
+ return []
75
78
 
76
79
  def get_prompt_sections(self) -> List[Dict[str, Any]]:
77
80
  """Return prompt sections to add to agent"""
@@ -0,0 +1 @@
1
+ # Native Vector Search Skill