signalwire-agents 0.1.23__py3-none-any.whl → 0.1.24__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- signalwire_agents/__init__.py +1 -1
- signalwire_agents/agent_server.py +2 -1
- signalwire_agents/cli/config.py +61 -0
- signalwire_agents/cli/core/__init__.py +1 -0
- signalwire_agents/cli/core/agent_loader.py +254 -0
- signalwire_agents/cli/core/argparse_helpers.py +164 -0
- signalwire_agents/cli/core/dynamic_config.py +62 -0
- signalwire_agents/cli/execution/__init__.py +1 -0
- signalwire_agents/cli/execution/datamap_exec.py +437 -0
- signalwire_agents/cli/execution/webhook_exec.py +125 -0
- signalwire_agents/cli/output/__init__.py +1 -0
- signalwire_agents/cli/output/output_formatter.py +132 -0
- signalwire_agents/cli/output/swml_dump.py +177 -0
- signalwire_agents/cli/simulation/__init__.py +1 -0
- signalwire_agents/cli/simulation/data_generation.py +365 -0
- signalwire_agents/cli/simulation/data_overrides.py +187 -0
- signalwire_agents/cli/simulation/mock_env.py +271 -0
- signalwire_agents/cli/test_swaig.py +522 -2539
- signalwire_agents/cli/types.py +72 -0
- signalwire_agents/core/agent/__init__.py +1 -3
- signalwire_agents/core/agent/config/__init__.py +1 -3
- signalwire_agents/core/agent/prompt/manager.py +25 -7
- signalwire_agents/core/agent/tools/decorator.py +2 -0
- signalwire_agents/core/agent/tools/registry.py +8 -0
- signalwire_agents/core/agent_base.py +492 -3053
- signalwire_agents/core/function_result.py +31 -42
- signalwire_agents/core/mixins/__init__.py +28 -0
- signalwire_agents/core/mixins/ai_config_mixin.py +373 -0
- signalwire_agents/core/mixins/auth_mixin.py +287 -0
- signalwire_agents/core/mixins/prompt_mixin.py +345 -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 +219 -0
- signalwire_agents/core/mixins/tool_mixin.py +295 -0
- signalwire_agents/core/mixins/web_mixin.py +1130 -0
- signalwire_agents/core/skill_manager.py +3 -1
- signalwire_agents/core/swaig_function.py +10 -1
- signalwire_agents/core/swml_service.py +140 -58
- signalwire_agents/skills/README.md +452 -0
- signalwire_agents/skills/api_ninjas_trivia/README.md +215 -0
- signalwire_agents/skills/datasphere/README.md +210 -0
- signalwire_agents/skills/datasphere_serverless/README.md +258 -0
- signalwire_agents/skills/datetime/README.md +132 -0
- signalwire_agents/skills/joke/README.md +149 -0
- signalwire_agents/skills/math/README.md +161 -0
- signalwire_agents/skills/native_vector_search/skill.py +33 -13
- signalwire_agents/skills/play_background_file/README.md +218 -0
- signalwire_agents/skills/spider/README.md +236 -0
- signalwire_agents/skills/spider/__init__.py +4 -0
- signalwire_agents/skills/spider/skill.py +479 -0
- signalwire_agents/skills/swml_transfer/README.md +395 -0
- signalwire_agents/skills/swml_transfer/__init__.py +1 -0
- signalwire_agents/skills/swml_transfer/skill.py +257 -0
- signalwire_agents/skills/weather_api/README.md +178 -0
- signalwire_agents/skills/web_search/README.md +163 -0
- signalwire_agents/skills/wikipedia_search/README.md +228 -0
- {signalwire_agents-0.1.23.dist-info → signalwire_agents-0.1.24.dist-info}/METADATA +47 -2
- {signalwire_agents-0.1.23.dist-info → signalwire_agents-0.1.24.dist-info}/RECORD +62 -22
- {signalwire_agents-0.1.23.dist-info → signalwire_agents-0.1.24.dist-info}/entry_points.txt +1 -1
- signalwire_agents/core/agent/config/ephemeral.py +0 -176
- signalwire_agents-0.1.23.data/data/schema.json +0 -5611
- {signalwire_agents-0.1.23.dist-info → signalwire_agents-0.1.24.dist-info}/WHEEL +0 -0
- {signalwire_agents-0.1.23.dist-info → signalwire_agents-0.1.24.dist-info}/licenses/LICENSE +0 -0
- {signalwire_agents-0.1.23.dist-info → signalwire_agents-0.1.24.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,149 @@
|
|
1
|
+
# Joke Skill
|
2
|
+
|
3
|
+
Tell jokes using the API Ninjas joke API with DataMap integration.
|
4
|
+
|
5
|
+
## Description
|
6
|
+
|
7
|
+
The Joke skill provides joke-telling capabilities to your SignalWire AI agents using the API Ninjas joke API. This skill demonstrates how to use DataMap for external API integration without requiring custom webhook endpoints.
|
8
|
+
|
9
|
+
## Features
|
10
|
+
|
11
|
+
- **Random Jokes**: Get random jokes from API Ninjas
|
12
|
+
- **Dad Jokes**: Specifically request dad jokes
|
13
|
+
- **DataMap Integration**: Uses DataMap for serverless API execution
|
14
|
+
- **Configurable Tool Name**: Support for custom tool names
|
15
|
+
- **Required Parameter Validation**: Ensures joke type is specified
|
16
|
+
|
17
|
+
## Requirements
|
18
|
+
|
19
|
+
- API Ninjas API key
|
20
|
+
- No additional Python packages required (DataMap handles API calls)
|
21
|
+
|
22
|
+
## Configuration
|
23
|
+
|
24
|
+
### Required Parameters
|
25
|
+
|
26
|
+
- `api_key`: Your API Ninjas API key
|
27
|
+
|
28
|
+
### Optional Parameters
|
29
|
+
|
30
|
+
- `tool_name`: Custom name for the joke function (default: "get_joke")
|
31
|
+
|
32
|
+
## Usage
|
33
|
+
|
34
|
+
### Basic Usage
|
35
|
+
|
36
|
+
```python
|
37
|
+
from signalwire_agents import AgentBase
|
38
|
+
|
39
|
+
class MyAgent(AgentBase):
|
40
|
+
def __init__(self):
|
41
|
+
super().__init__(name="Joke Agent", route="/jokes")
|
42
|
+
|
43
|
+
# Add joke skill
|
44
|
+
self.add_skill("joke", {
|
45
|
+
"api_key": "your-api-ninjas-api-key"
|
46
|
+
})
|
47
|
+
|
48
|
+
agent = MyAgent()
|
49
|
+
agent.serve()
|
50
|
+
```
|
51
|
+
|
52
|
+
### Advanced Usage
|
53
|
+
|
54
|
+
```python
|
55
|
+
# Custom tool name
|
56
|
+
self.add_skill("joke", {
|
57
|
+
"api_key": "your-api-ninjas-api-key",
|
58
|
+
"tool_name": "tell_joke"
|
59
|
+
})
|
60
|
+
```
|
61
|
+
|
62
|
+
## Function Details
|
63
|
+
|
64
|
+
### `get_joke(type: str)`
|
65
|
+
|
66
|
+
**Parameters:**
|
67
|
+
- `type` (required): Type of joke to get
|
68
|
+
- `"jokes"` - Regular jokes
|
69
|
+
- `"dadjokes"` - Dad jokes
|
70
|
+
|
71
|
+
**Returns:** A joke from the API Ninjas joke database
|
72
|
+
|
73
|
+
**Example Usage:**
|
74
|
+
- "Tell me a joke" (AI will choose the type)
|
75
|
+
- "Tell me a dad joke" (AI will use type="dadjokes")
|
76
|
+
- "Get me a regular joke" (AI will use type="jokes")
|
77
|
+
|
78
|
+
## API Integration
|
79
|
+
|
80
|
+
This skill integrates with the API Ninjas Jokes API:
|
81
|
+
- **Endpoint**: `https://api.api-ninjas.com/v1/{type}`
|
82
|
+
- **Method**: GET
|
83
|
+
- **Authentication**: X-Api-Key header
|
84
|
+
- **Response**: JSON array with joke objects
|
85
|
+
|
86
|
+
## Getting an API Key
|
87
|
+
|
88
|
+
1. Visit [API Ninjas](https://api.api-ninjas.com/)
|
89
|
+
2. Sign up for a free account
|
90
|
+
3. Get your API key from the dashboard
|
91
|
+
4. Use the key in your skill configuration
|
92
|
+
|
93
|
+
## Error Handling
|
94
|
+
|
95
|
+
- Missing API key: Skill setup will fail with clear error message
|
96
|
+
- Invalid joke type: Parameter validation ensures only valid types are accepted
|
97
|
+
- API errors: Handled gracefully with user-friendly error messages
|
98
|
+
|
99
|
+
## DataMap Implementation
|
100
|
+
|
101
|
+
This skill demonstrates DataMap usage with:
|
102
|
+
|
103
|
+
- **External API**: Calls API Ninjas joke endpoints
|
104
|
+
- **Dynamic URLs**: Uses `${args.type}` for different joke types
|
105
|
+
- **Header Authentication**: Includes API key in request headers
|
106
|
+
- **Response Processing**: Extracts joke from API response array
|
107
|
+
- **Error Handling**: Handles API errors gracefully
|
108
|
+
|
109
|
+
## Troubleshooting
|
110
|
+
|
111
|
+
### Common Issues
|
112
|
+
|
113
|
+
1. **"Missing required parameters: ['api_key']"**
|
114
|
+
- Ensure you provide a valid API Ninjas API key
|
115
|
+
|
116
|
+
2. **"No jokes returned"**
|
117
|
+
- Check your API key is valid
|
118
|
+
- Verify API Ninjas service is accessible
|
119
|
+
- Check API quota/rate limits
|
120
|
+
|
121
|
+
3. **"Tool not found"**
|
122
|
+
- Ensure skill loaded successfully
|
123
|
+
- Check for any setup errors in logs
|
124
|
+
|
125
|
+
### Debugging
|
126
|
+
|
127
|
+
Enable debug logging to see API requests:
|
128
|
+
|
129
|
+
```python
|
130
|
+
import logging
|
131
|
+
logging.basicConfig(level=logging.DEBUG)
|
132
|
+
```
|
133
|
+
|
134
|
+
## API Reference
|
135
|
+
|
136
|
+
### API Ninjas Endpoints
|
137
|
+
|
138
|
+
- `GET /v1/jokes` - Random jokes
|
139
|
+
- `GET /v1/dadjokes` - Dad jokes
|
140
|
+
|
141
|
+
### Response Format
|
142
|
+
|
143
|
+
```json
|
144
|
+
[
|
145
|
+
{
|
146
|
+
"joke": "Why don't scientists trust atoms? Because they make up everything!"
|
147
|
+
}
|
148
|
+
]
|
149
|
+
```
|
@@ -0,0 +1,161 @@
|
|
1
|
+
# Math Skill
|
2
|
+
|
3
|
+
The math skill provides safe mathematical calculation capabilities for agents. It allows users to perform basic arithmetic operations and complex mathematical expressions with security protections against code injection.
|
4
|
+
|
5
|
+
## Features
|
6
|
+
|
7
|
+
- Safe mathematical expression evaluation
|
8
|
+
- Support for basic arithmetic operations
|
9
|
+
- Parentheses support for complex expressions
|
10
|
+
- Division by zero protection
|
11
|
+
- Security filtering to prevent code injection
|
12
|
+
- No external dependencies required
|
13
|
+
|
14
|
+
## Requirements
|
15
|
+
|
16
|
+
- **Packages**: None (uses built-in Python functionality)
|
17
|
+
- **No external APIs required**
|
18
|
+
|
19
|
+
## Parameters
|
20
|
+
|
21
|
+
### Optional Parameters
|
22
|
+
|
23
|
+
- `swaig_fields` (dict): Additional SWAIG function configuration
|
24
|
+
- `secure` (boolean): Override security settings for the calculation function
|
25
|
+
- `fillers` (dict): Language-specific filler phrases while calculating
|
26
|
+
- Any other SWAIG function parameters
|
27
|
+
|
28
|
+
**Note**: This skill does not require any configuration parameters beyond the optional swaig_fields. It works out-of-the-box with no setup.
|
29
|
+
|
30
|
+
## Tools Created
|
31
|
+
|
32
|
+
- `calculate` - Perform a mathematical calculation with basic operations
|
33
|
+
|
34
|
+
## Usage Examples
|
35
|
+
|
36
|
+
### Basic Usage
|
37
|
+
|
38
|
+
```python
|
39
|
+
# No configuration needed - works immediately
|
40
|
+
agent.add_skill("math")
|
41
|
+
```
|
42
|
+
|
43
|
+
### With Custom Fillers
|
44
|
+
|
45
|
+
```python
|
46
|
+
agent.add_skill("math", {
|
47
|
+
"swaig_fields": {
|
48
|
+
"fillers": {
|
49
|
+
"en-US": [
|
50
|
+
"Let me calculate that for you...",
|
51
|
+
"Crunching the numbers...",
|
52
|
+
"Computing the result...",
|
53
|
+
"Working out the math..."
|
54
|
+
],
|
55
|
+
"es-ES": [
|
56
|
+
"Déjame calcular eso...",
|
57
|
+
"Procesando los números...",
|
58
|
+
"Calculando el resultado..."
|
59
|
+
]
|
60
|
+
}
|
61
|
+
}
|
62
|
+
})
|
63
|
+
```
|
64
|
+
|
65
|
+
### Disabling Security (if needed)
|
66
|
+
|
67
|
+
```python
|
68
|
+
agent.add_skill("math", {
|
69
|
+
"swaig_fields": {
|
70
|
+
"secure": False # Allow unauthenticated calculation requests
|
71
|
+
}
|
72
|
+
})
|
73
|
+
```
|
74
|
+
|
75
|
+
## How It Works
|
76
|
+
|
77
|
+
### Calculation Function
|
78
|
+
- **Input**: Mathematical expression as a string
|
79
|
+
- **Processing**: Validates expression for safety, then evaluates it
|
80
|
+
- **Output**: Shows the original expression and the calculated result
|
81
|
+
- **Example**: "2 + 3 * 4 = 14"
|
82
|
+
|
83
|
+
### Supported Operations
|
84
|
+
|
85
|
+
- **Addition**: `+` (e.g., "5 + 3")
|
86
|
+
- **Subtraction**: `-` (e.g., "10 - 7")
|
87
|
+
- **Multiplication**: `*` (e.g., "6 * 8")
|
88
|
+
- **Division**: `/` (e.g., "15 / 3")
|
89
|
+
- **Modulo**: `%` (e.g., "17 % 5")
|
90
|
+
- **Exponentiation**: `**` (e.g., "2 ** 3")
|
91
|
+
- **Parentheses**: `()` for grouping (e.g., "(2 + 3) * 4")
|
92
|
+
|
93
|
+
### Expression Examples
|
94
|
+
|
95
|
+
- Simple: `"2 + 3"` → "2 + 3 = 5"
|
96
|
+
- Complex: `"(10 + 5) * 2 / 3"` → "(10 + 5) * 2 / 3 = 10.0"
|
97
|
+
- With decimals: `"3.14 * 2"` → "3.14 * 2 = 6.28"
|
98
|
+
- Powers: `"2 ** 8"` → "2 ** 8 = 256"
|
99
|
+
- Modulo: `"17 % 5"` → "17 % 5 = 2"
|
100
|
+
|
101
|
+
## Function Parameters
|
102
|
+
|
103
|
+
The calculate tool accepts one parameter:
|
104
|
+
|
105
|
+
- `expression` (string, required): Mathematical expression to evaluate
|
106
|
+
- Must contain only numbers, operators, and parentheses
|
107
|
+
- Operators allowed: `+`, `-`, `*`, `/`, `%`, `**`, `(`, `)`
|
108
|
+
- Decimal numbers are supported
|
109
|
+
- Spaces are allowed and ignored
|
110
|
+
|
111
|
+
## Security Features
|
112
|
+
|
113
|
+
### Input Validation
|
114
|
+
- Only allows safe mathematical characters: numbers, operators, parentheses, spaces, decimal points
|
115
|
+
- Blocks any potentially dangerous code or function calls
|
116
|
+
- Uses regex pattern matching for character validation
|
117
|
+
|
118
|
+
### Safe Evaluation
|
119
|
+
- Uses Python's `eval()` with restricted builtins (empty `__builtins__`)
|
120
|
+
- No access to system functions or imports
|
121
|
+
- Cannot execute arbitrary code
|
122
|
+
|
123
|
+
### Error Handling
|
124
|
+
- **Division by Zero**: Returns friendly error message
|
125
|
+
- **Invalid Syntax**: Returns error for malformed expressions
|
126
|
+
- **Illegal Characters**: Rejects expressions with non-math characters
|
127
|
+
- **Empty Input**: Prompts user to provide an expression
|
128
|
+
|
129
|
+
## Error Examples
|
130
|
+
|
131
|
+
- **Division by zero**: "Error: Division by zero is not allowed."
|
132
|
+
- **Invalid characters**: "Invalid expression. Only numbers and basic math operators are allowed."
|
133
|
+
- **Syntax error**: "Error calculating '2 + + 3': Invalid expression"
|
134
|
+
- **Empty input**: "Please provide a mathematical expression to calculate."
|
135
|
+
|
136
|
+
## Common Use Cases
|
137
|
+
|
138
|
+
1. **Basic Arithmetic**: "What's 15 + 27?"
|
139
|
+
2. **Percentage Calculations**: "What's 15% of 200?" → "200 * 0.15"
|
140
|
+
3. **Complex Expressions**: "Calculate (100 + 50) * 0.08"
|
141
|
+
4. **Powers and Roots**: "What's 2 to the power of 10?"
|
142
|
+
5. **Financial Calculations**: "If I have $500 and spend $125, how much is left?"
|
143
|
+
|
144
|
+
## Best Practices
|
145
|
+
|
146
|
+
1. **Default Behavior**: The skill works immediately without configuration
|
147
|
+
2. **User Education**: Help users understand they can use parentheses for complex calculations
|
148
|
+
3. **Expression Formatting**: The skill is forgiving with spaces and formatting
|
149
|
+
4. **Error Recovery**: Provide helpful guidance when users make syntax errors
|
150
|
+
5. **Security**: The skill is designed to be safe even with malicious input
|
151
|
+
|
152
|
+
## Agent Integration
|
153
|
+
|
154
|
+
When added to an agent, this skill automatically:
|
155
|
+
|
156
|
+
- Adds speech recognition hints for math-related words
|
157
|
+
- Provides prompt guidance about calculation capabilities
|
158
|
+
- Enables the agent to respond to mathematical questions
|
159
|
+
- Shows both the original expression and result for transparency
|
160
|
+
|
161
|
+
The skill is designed to be completely self-contained and secure, making it safe for any agent to use for mathematical calculations.
|
@@ -190,6 +190,37 @@ class NativeVectorSearchSkill(SkillBase):
|
|
190
190
|
**self.swaig_fields
|
191
191
|
)
|
192
192
|
|
193
|
+
# Add our tool to the Knowledge Search section
|
194
|
+
search_mode = "remote search server" if self.use_remote else "local document indexes"
|
195
|
+
section_title = "Knowledge Search"
|
196
|
+
|
197
|
+
# Try to check if section exists, but handle if method doesn't exist
|
198
|
+
section_exists = False
|
199
|
+
try:
|
200
|
+
if hasattr(self.agent, 'prompt_has_section'):
|
201
|
+
section_exists = self.agent.prompt_has_section(section_title)
|
202
|
+
except Exception:
|
203
|
+
# Method might not work, assume section doesn't exist
|
204
|
+
pass
|
205
|
+
|
206
|
+
if section_exists:
|
207
|
+
# Add bullet to existing section
|
208
|
+
self.agent.prompt_add_to_section(
|
209
|
+
title=section_title,
|
210
|
+
bullet=f"Use {self.tool_name} to search {search_mode}: {description}"
|
211
|
+
)
|
212
|
+
else:
|
213
|
+
# Create the section with this tool
|
214
|
+
self.agent.prompt_add_section(
|
215
|
+
title=section_title,
|
216
|
+
body="You can search various knowledge sources using the following tools:",
|
217
|
+
bullets=[
|
218
|
+
f"Use {self.tool_name} to search {search_mode}: {description}",
|
219
|
+
"Search for relevant information using clear, specific queries",
|
220
|
+
"If no results are found, suggest the user try rephrasing their question or try another knowledge source"
|
221
|
+
]
|
222
|
+
)
|
223
|
+
|
193
224
|
def _search_handler(self, args, raw_data):
|
194
225
|
"""Handle search requests"""
|
195
226
|
|
@@ -365,19 +396,8 @@ class NativeVectorSearchSkill(SkillBase):
|
|
365
396
|
|
366
397
|
def get_prompt_sections(self) -> List[Dict[str, Any]]:
|
367
398
|
"""Return prompt sections to add to agent"""
|
368
|
-
|
369
|
-
return [
|
370
|
-
{
|
371
|
-
"title": "Document Search",
|
372
|
-
"body": f"You can search {search_mode} using the {self.tool_name} tool.",
|
373
|
-
"bullets": [
|
374
|
-
f"Use the {self.tool_name} tool when users ask questions about topics that might be in the indexed documents",
|
375
|
-
"Search for relevant information using clear, specific queries",
|
376
|
-
"Provide helpful summaries of the search results",
|
377
|
-
"If no results are found, suggest the user try rephrasing their question or ask about different topics"
|
378
|
-
]
|
379
|
-
}
|
380
|
-
]
|
399
|
+
# We'll handle this in register_tools after the agent is set
|
400
|
+
return []
|
381
401
|
|
382
402
|
def _add_prompt_section(self, agent):
|
383
403
|
"""Add prompt section to agent (called during skill loading)"""
|
@@ -0,0 +1,218 @@
|
|
1
|
+
# Play Background File Skill
|
2
|
+
|
3
|
+
A configurable skill for managing background file playback with custom tool names and multiple file collections. Supports both audio and video files with serverless DataMap execution.
|
4
|
+
|
5
|
+
## Features
|
6
|
+
|
7
|
+
- **Multiple Instances**: Create different tools with unique names and file sets
|
8
|
+
- **Dynamic Enum Generation**: Function parameters built from your file configuration
|
9
|
+
- **Audio & Video Support**: Works with any background file type
|
10
|
+
- **DataMap Efficiency**: Serverless execution, no agent processing load
|
11
|
+
- **Post-Processing**: AI speaks first, then executes the action
|
12
|
+
- **Configurable Wait**: Control attention-getting behavior per file
|
13
|
+
|
14
|
+
## Configuration
|
15
|
+
|
16
|
+
### Basic Structure
|
17
|
+
|
18
|
+
```python
|
19
|
+
agent.add_skill("play_background_file", {
|
20
|
+
"tool_name": "your_custom_tool_name",
|
21
|
+
"files": [
|
22
|
+
{
|
23
|
+
"key": "unique_identifier",
|
24
|
+
"description": "Human readable description",
|
25
|
+
"url": "https://example.com/file.mp4",
|
26
|
+
"wait": True # Optional, defaults to False
|
27
|
+
}
|
28
|
+
]
|
29
|
+
})
|
30
|
+
```
|
31
|
+
|
32
|
+
### Parameters
|
33
|
+
|
34
|
+
- **tool_name** (string): Custom name for the generated SWAIG function (default: "play_background_file")
|
35
|
+
- **files** (array): List of file objects to manage
|
36
|
+
|
37
|
+
### File Object Properties
|
38
|
+
|
39
|
+
- **key** (string, required): Unique identifier for the file (alphanumeric, underscores, hyphens only)
|
40
|
+
- **description** (string, required): Human-readable description used in AI responses
|
41
|
+
- **url** (string, required): URL to the audio/video file
|
42
|
+
- **wait** (boolean, optional): Whether to suppress attention-getting behavior during playback (default: false)
|
43
|
+
|
44
|
+
## Usage Examples
|
45
|
+
|
46
|
+
### Single File Testimonial
|
47
|
+
|
48
|
+
```python
|
49
|
+
agent.add_skill("play_background_file", {
|
50
|
+
"tool_name": "play_testimonial",
|
51
|
+
"files": [
|
52
|
+
{
|
53
|
+
"key": "massey_success",
|
54
|
+
"description": "Customer success story from Massey Energy",
|
55
|
+
"url": "https://tatooine.cantina.cloud/vids/massey.mp4",
|
56
|
+
"wait": True
|
57
|
+
}
|
58
|
+
]
|
59
|
+
})
|
60
|
+
```
|
61
|
+
|
62
|
+
**Generated Tool**: `play_testimonial(action)`
|
63
|
+
**Actions**: `["start_massey_success", "stop"]`
|
64
|
+
|
65
|
+
### Multiple Demo Videos
|
66
|
+
|
67
|
+
```python
|
68
|
+
agent.add_skill("play_background_file", {
|
69
|
+
"tool_name": "play_demo",
|
70
|
+
"files": [
|
71
|
+
{
|
72
|
+
"key": "product_overview",
|
73
|
+
"description": "Product overview demonstration",
|
74
|
+
"url": "https://example.com/overview.mp4",
|
75
|
+
"wait": False
|
76
|
+
},
|
77
|
+
{
|
78
|
+
"key": "advanced_features",
|
79
|
+
"description": "Advanced features walkthrough",
|
80
|
+
"url": "https://example.com/advanced.mp4",
|
81
|
+
"wait": True
|
82
|
+
}
|
83
|
+
]
|
84
|
+
})
|
85
|
+
```
|
86
|
+
|
87
|
+
**Generated Tool**: `play_demo(action)`
|
88
|
+
**Actions**: `["start_product_overview", "start_advanced_features", "stop"]`
|
89
|
+
|
90
|
+
### Music Playlist
|
91
|
+
|
92
|
+
```python
|
93
|
+
agent.add_skill("play_background_file", {
|
94
|
+
"tool_name": "play_music",
|
95
|
+
"files": [
|
96
|
+
{
|
97
|
+
"key": "jazz",
|
98
|
+
"description": "smooth jazz background music",
|
99
|
+
"url": "https://example.com/jazz.mp3"
|
100
|
+
},
|
101
|
+
{
|
102
|
+
"key": "classical",
|
103
|
+
"description": "classical piano background music",
|
104
|
+
"url": "https://example.com/classical.mp3"
|
105
|
+
}
|
106
|
+
]
|
107
|
+
})
|
108
|
+
```
|
109
|
+
|
110
|
+
## Generated SWAIG Function
|
111
|
+
|
112
|
+
For the testimonial example above, the skill generates:
|
113
|
+
|
114
|
+
```json
|
115
|
+
{
|
116
|
+
"function": "play_testimonial",
|
117
|
+
"description": "Control background file playback for play testimonial",
|
118
|
+
"parameters": {
|
119
|
+
"type": "object",
|
120
|
+
"properties": {
|
121
|
+
"action": {
|
122
|
+
"type": "string",
|
123
|
+
"description": "Action to perform. Options: start_massey_success: Customer success story from Massey Energy; stop: Stop any currently playing background file",
|
124
|
+
"enum": ["start_massey_success", "stop"]
|
125
|
+
}
|
126
|
+
},
|
127
|
+
"required": ["action"]
|
128
|
+
},
|
129
|
+
"data_map": {
|
130
|
+
"expressions": [
|
131
|
+
{
|
132
|
+
"string": "${args.action}",
|
133
|
+
"pattern": "/start_massey_success/i",
|
134
|
+
"output": {
|
135
|
+
"response": "Tell the user you are now going to play Customer success story from Massey Energy for them.",
|
136
|
+
"action": [
|
137
|
+
{
|
138
|
+
"playback_bg": {
|
139
|
+
"file": "https://tatooine.cantina.cloud/vids/massey.mp4",
|
140
|
+
"wait": true
|
141
|
+
}
|
142
|
+
}
|
143
|
+
],
|
144
|
+
"post_process": true
|
145
|
+
}
|
146
|
+
},
|
147
|
+
{
|
148
|
+
"string": "${args.action}",
|
149
|
+
"pattern": "/stop/i",
|
150
|
+
"output": {
|
151
|
+
"response": "Tell the user you have stopped the background file playback.",
|
152
|
+
"action": [
|
153
|
+
{
|
154
|
+
"stop_playback_bg": true
|
155
|
+
}
|
156
|
+
],
|
157
|
+
"post_process": true
|
158
|
+
}
|
159
|
+
}
|
160
|
+
]
|
161
|
+
}
|
162
|
+
}
|
163
|
+
```
|
164
|
+
|
165
|
+
## Execution Flow
|
166
|
+
|
167
|
+
1. **AI calls function**: `play_testimonial(action: "start_massey_success")`
|
168
|
+
2. **DataMap matches pattern**: `/start_massey_success/i`
|
169
|
+
3. **AI receives instruction**: "Tell the user you are now going to play Customer success story from Massey Energy for them."
|
170
|
+
4. **AI responds naturally**: The AI interprets this and responds in its own voice
|
171
|
+
5. **Action executes**: Background video starts playing
|
172
|
+
6. **User experience**: Natural AI announcement before action
|
173
|
+
|
174
|
+
## Multiple Instances
|
175
|
+
|
176
|
+
You can add multiple instances of this skill with different tool names:
|
177
|
+
|
178
|
+
```python
|
179
|
+
# Testimonials
|
180
|
+
agent.add_skill("play_background_file", {
|
181
|
+
"tool_name": "play_testimonial",
|
182
|
+
"files": [{"key": "massey", "description": "Massey Energy success story", "url": "..."}]
|
183
|
+
})
|
184
|
+
|
185
|
+
# Demos
|
186
|
+
agent.add_skill("play_background_file", {
|
187
|
+
"tool_name": "play_demo",
|
188
|
+
"files": [
|
189
|
+
{"key": "overview", "description": "Product overview", "url": "..."},
|
190
|
+
{"key": "features", "description": "Advanced features", "url": "..."}
|
191
|
+
]
|
192
|
+
})
|
193
|
+
|
194
|
+
# Music
|
195
|
+
agent.add_skill("play_background_file", {
|
196
|
+
"tool_name": "play_music",
|
197
|
+
"files": [{"key": "jazz", "description": "Jazz music", "url": "..."}]
|
198
|
+
})
|
199
|
+
```
|
200
|
+
|
201
|
+
This creates three separate tools: `play_testimonial`, `play_demo`, and `play_music`.
|
202
|
+
|
203
|
+
## Benefits
|
204
|
+
|
205
|
+
- **Reusable**: Same skill manages different file collections
|
206
|
+
- **Configurable**: Easy to add/remove files without code changes
|
207
|
+
- **Efficient**: DataMap serverless execution
|
208
|
+
- **Type Safe**: Enum parameters prevent invalid file references
|
209
|
+
- **Natural**: AI speaks before actions with post-processing
|
210
|
+
- **Maintainable**: Centralized file management logic
|
211
|
+
|
212
|
+
## Implementation Notes
|
213
|
+
|
214
|
+
- File keys are converted to `start_{key}` enum values
|
215
|
+
- All tools include a "stop" action to halt playback
|
216
|
+
- Post-processing is enabled by default for natural conversation flow
|
217
|
+
- The skill validates all configuration parameters at initialization
|
218
|
+
- Instance keys combine skill name and tool name for uniqueness
|