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,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
|
+
```
|
|
@@ -23,6 +23,27 @@ class JokeSkill(SkillBase):
|
|
|
23
23
|
REQUIRED_PACKAGES = [] # DataMap doesn't require local packages
|
|
24
24
|
REQUIRED_ENV_VARS = [] # API key comes from parameters
|
|
25
25
|
|
|
26
|
+
@classmethod
|
|
27
|
+
def get_parameter_schema(cls) -> Dict[str, Dict[str, Any]]:
|
|
28
|
+
"""Get parameter schema for joke skill"""
|
|
29
|
+
schema = super().get_parameter_schema()
|
|
30
|
+
schema.update({
|
|
31
|
+
"api_key": {
|
|
32
|
+
"type": "string",
|
|
33
|
+
"description": "API Ninjas API key for joke service",
|
|
34
|
+
"required": True,
|
|
35
|
+
"hidden": True,
|
|
36
|
+
"env_var": "API_NINJAS_KEY"
|
|
37
|
+
},
|
|
38
|
+
"tool_name": {
|
|
39
|
+
"type": "string",
|
|
40
|
+
"description": "Custom name for the joke tool",
|
|
41
|
+
"default": "get_joke",
|
|
42
|
+
"required": False
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
return schema
|
|
46
|
+
|
|
26
47
|
def setup(self) -> bool:
|
|
27
48
|
"""Setup the joke skill"""
|
|
28
49
|
# Validate required parameters
|
|
@@ -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.
|
|
@@ -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.
|
|
32
|
+
self.define_tool(
|
|
33
33
|
name="calculate",
|
|
34
34
|
description="Perform a mathematical calculation with basic operations (+, -, *, /, %, **)",
|
|
35
35
|
parameters={
|
|
@@ -38,8 +38,7 @@ 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
|
|
42
|
-
**self.swaig_fields
|
|
41
|
+
handler=self._calculate_handler
|
|
43
42
|
)
|
|
44
43
|
|
|
45
44
|
def _calculate_handler(self, args, raw_data):
|
|
@@ -88,4 +87,19 @@ class MathSkill(SkillBase):
|
|
|
88
87
|
"Can handle parentheses for complex expressions"
|
|
89
88
|
]
|
|
90
89
|
}
|
|
91
|
-
]
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
@classmethod
|
|
93
|
+
def get_parameter_schema(cls) -> Dict[str, Dict[str, Any]]:
|
|
94
|
+
"""
|
|
95
|
+
Get the parameter schema for the math skill
|
|
96
|
+
|
|
97
|
+
The math skill has no custom parameters - it inherits only
|
|
98
|
+
the base parameters from SkillBase.
|
|
99
|
+
"""
|
|
100
|
+
# Get base schema from parent
|
|
101
|
+
schema = super().get_parameter_schema()
|
|
102
|
+
|
|
103
|
+
# No additional parameters for math skill
|
|
104
|
+
|
|
105
|
+
return schema
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
# MCP Gateway Skill
|
|
2
|
+
|
|
3
|
+
Bridge MCP (Model Context Protocol) servers with SignalWire SWAIG functions, allowing agents to seamlessly interact with MCP-based tools.
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
The MCP Gateway skill connects SignalWire agents to MCP servers through a centralized gateway service. It dynamically discovers and registers MCP tools as SWAIG functions, maintaining session state throughout each call.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- Dynamic tool discovery from MCP servers
|
|
12
|
+
- Session management tied to SignalWire call IDs
|
|
13
|
+
- Automatic cleanup on call hangup
|
|
14
|
+
- Support for multiple MCP services
|
|
15
|
+
- Selective tool loading
|
|
16
|
+
- HTTPS support with SSL verification
|
|
17
|
+
- Retry logic for resilient connections
|
|
18
|
+
|
|
19
|
+
## Requirements
|
|
20
|
+
|
|
21
|
+
- Running MCP Gateway service
|
|
22
|
+
- Network access to gateway
|
|
23
|
+
- Gateway credentials (username/password)
|
|
24
|
+
|
|
25
|
+
## Configuration
|
|
26
|
+
|
|
27
|
+
### Required Parameters
|
|
28
|
+
|
|
29
|
+
Either Basic Auth credentials OR Bearer token:
|
|
30
|
+
- `gateway_url`: URL of the MCP gateway service (default: "http://localhost:8100")
|
|
31
|
+
- `auth_user` + `auth_password`: Basic auth credentials
|
|
32
|
+
- OR `auth_token`: Bearer token for authentication
|
|
33
|
+
|
|
34
|
+
### Optional Parameters
|
|
35
|
+
|
|
36
|
+
- `services`: Array of services to load (default: all available)
|
|
37
|
+
- `name`: Service name
|
|
38
|
+
- `tools`: Array of tool names or "*" for all (default: all)
|
|
39
|
+
- `session_timeout`: Session timeout in seconds (default: 300)
|
|
40
|
+
- `tool_prefix`: Prefix for SWAIG function names (default: "mcp_")
|
|
41
|
+
- `retry_attempts`: Number of retry attempts (default: 3)
|
|
42
|
+
- `request_timeout`: HTTP request timeout in seconds (default: 30)
|
|
43
|
+
- `verify_ssl`: Verify SSL certificates (default: true)
|
|
44
|
+
|
|
45
|
+
## Usage
|
|
46
|
+
|
|
47
|
+
### Basic Usage (All Services)
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from signalwire_agents import AgentBase
|
|
51
|
+
|
|
52
|
+
class MyAgent(AgentBase):
|
|
53
|
+
def __init__(self):
|
|
54
|
+
super().__init__(name="My Agent")
|
|
55
|
+
|
|
56
|
+
# Load all available MCP services
|
|
57
|
+
self.add_skill("mcp_gateway", {
|
|
58
|
+
"gateway_url": "http://localhost:8080",
|
|
59
|
+
"auth_user": "admin",
|
|
60
|
+
"auth_password": "changeme"
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
agent = MyAgent()
|
|
64
|
+
agent.run()
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Selective Service Loading
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
# Load specific services with specific tools
|
|
71
|
+
self.add_skill("mcp_gateway", {
|
|
72
|
+
"gateway_url": "https://gateway.example.com",
|
|
73
|
+
"auth_user": "admin",
|
|
74
|
+
"auth_password": "secret",
|
|
75
|
+
"services": [
|
|
76
|
+
{
|
|
77
|
+
"name": "todo",
|
|
78
|
+
"tools": ["add_todo", "list_todos"] # Only these tools
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"name": "calculator",
|
|
82
|
+
"tools": "*" # All calculator tools
|
|
83
|
+
}
|
|
84
|
+
],
|
|
85
|
+
"session_timeout": 600,
|
|
86
|
+
"tool_prefix": "ext_"
|
|
87
|
+
})
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### HTTPS with Self-Signed Certificate
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
self.add_skill("mcp_gateway", {
|
|
94
|
+
"gateway_url": "https://localhost:8443",
|
|
95
|
+
"auth_user": "admin",
|
|
96
|
+
"auth_password": "secret",
|
|
97
|
+
"verify_ssl": False # For self-signed certificates
|
|
98
|
+
})
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Bearer Token Authentication
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
self.add_skill("mcp_gateway", {
|
|
105
|
+
"gateway_url": "https://gateway.example.com",
|
|
106
|
+
"auth_token": "your-bearer-token-here",
|
|
107
|
+
"services": [{
|
|
108
|
+
"name": "todo"
|
|
109
|
+
}]
|
|
110
|
+
})
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Generated Functions
|
|
114
|
+
|
|
115
|
+
The skill dynamically generates SWAIG functions based on discovered MCP tools. Function names follow the pattern:
|
|
116
|
+
|
|
117
|
+
`{tool_prefix}{service_name}_{tool_name}`
|
|
118
|
+
|
|
119
|
+
For example, with default settings:
|
|
120
|
+
- `mcp_todo_add_todo` - Add a todo item
|
|
121
|
+
- `mcp_todo_list_todos` - List todo items
|
|
122
|
+
- `mcp_calculator_add` - Calculator addition
|
|
123
|
+
|
|
124
|
+
## Example Conversations
|
|
125
|
+
|
|
126
|
+
### Using Todo Service
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
User: "Add a task to buy milk"
|
|
130
|
+
Assistant: "I'll add that to your todo list."
|
|
131
|
+
[Calls mcp_todo_add_todo with text="buy milk"]
|
|
132
|
+
Assistant: "I've added 'buy milk' to your todo list."
|
|
133
|
+
|
|
134
|
+
User: "What's on my todo list?"
|
|
135
|
+
Assistant: "Let me check your todos."
|
|
136
|
+
[Calls mcp_todo_list_todos]
|
|
137
|
+
Assistant: "Here are your current todos:
|
|
138
|
+
○ #1 [medium] buy milk"
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Multiple Services
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
User: "Add 'finish report' to my todos and calculate 15% of 200"
|
|
145
|
+
Assistant: "I'll add that todo and do the calculation for you."
|
|
146
|
+
[Calls mcp_todo_add_todo with text="finish report"]
|
|
147
|
+
[Calls mcp_calculator_percent with value=200, percent=15]
|
|
148
|
+
Assistant: "I've added 'finish report' to your todos. 15% of 200 is 30."
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Session Management
|
|
152
|
+
|
|
153
|
+
- Each SignalWire call gets its own MCP session
|
|
154
|
+
- Sessions persist across multiple tool calls
|
|
155
|
+
- Automatic cleanup on call hangup
|
|
156
|
+
- Configurable timeout for inactive sessions
|
|
157
|
+
|
|
158
|
+
### Custom Session ID
|
|
159
|
+
|
|
160
|
+
You can override the session ID by setting `mcp_call_id` in global_data:
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
# In your agent code
|
|
164
|
+
self.set_global_data({
|
|
165
|
+
"mcp_call_id": "custom-session-123"
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
# Or in a SWAIG function
|
|
169
|
+
result = SwaigFunctionResult("Session changed")
|
|
170
|
+
result.add_action("set_global_data", {"mcp_call_id": "new-session-456"})
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
This is useful for:
|
|
174
|
+
- Managing multiple MCP sessions within a single call
|
|
175
|
+
- Sharing MCP sessions across different calls
|
|
176
|
+
- Custom session management strategies
|
|
177
|
+
|
|
178
|
+
## Troubleshooting
|
|
179
|
+
|
|
180
|
+
### Gateway Connection Failed
|
|
181
|
+
|
|
182
|
+
Check:
|
|
183
|
+
1. Gateway service is running
|
|
184
|
+
2. Correct URL and credentials
|
|
185
|
+
3. Network connectivity
|
|
186
|
+
4. Firewall rules
|
|
187
|
+
|
|
188
|
+
### SSL Certificate Errors
|
|
189
|
+
|
|
190
|
+
For self-signed certificates:
|
|
191
|
+
```python
|
|
192
|
+
"verify_ssl": False
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
For custom CA certificates, ensure they're in the system trust store.
|
|
196
|
+
|
|
197
|
+
### Tool Not Found
|
|
198
|
+
|
|
199
|
+
Verify:
|
|
200
|
+
1. Service name is correct
|
|
201
|
+
2. Tool name matches exactly
|
|
202
|
+
3. Tool is included in service configuration
|
|
203
|
+
4. MCP server is returning tools correctly
|
|
204
|
+
|
|
205
|
+
### Session Timeouts
|
|
206
|
+
|
|
207
|
+
Increase timeout if needed:
|
|
208
|
+
```python
|
|
209
|
+
"session_timeout": 600 # 10 minutes
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Gateway Setup
|
|
213
|
+
|
|
214
|
+
To run the MCP Gateway service:
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
cd mcp_gateway
|
|
218
|
+
python3 gateway_service.py
|
|
219
|
+
|
|
220
|
+
# Or with custom config
|
|
221
|
+
python3 gateway_service.py -c myconfig.json
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## Security Considerations
|
|
225
|
+
|
|
226
|
+
1. Always use HTTPS in production
|
|
227
|
+
2. Use strong authentication credentials
|
|
228
|
+
3. Limit service access to required tools only
|
|
229
|
+
4. Monitor gateway logs for suspicious activity
|
|
230
|
+
5. Set appropriate session timeouts
|