signalwire-agents 0.1.0
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.
- package/CLAUDE.md +112 -0
- package/README.md +417 -0
- package/dist/AgentBase.d.ts +481 -0
- package/dist/AgentBase.js +1155 -0
- package/dist/AgentBase.js.map +1 -0
- package/dist/AgentServer.d.ts +60 -0
- package/dist/AgentServer.js +128 -0
- package/dist/AgentServer.js.map +1 -0
- package/dist/AuthHandler.d.ts +56 -0
- package/dist/AuthHandler.js +119 -0
- package/dist/AuthHandler.js.map +1 -0
- package/dist/ConfigLoader.d.ts +68 -0
- package/dist/ConfigLoader.js +150 -0
- package/dist/ConfigLoader.js.map +1 -0
- package/dist/ContextBuilder.d.ts +431 -0
- package/dist/ContextBuilder.js +751 -0
- package/dist/ContextBuilder.js.map +1 -0
- package/dist/DataMap.d.ts +179 -0
- package/dist/DataMap.js +321 -0
- package/dist/DataMap.js.map +1 -0
- package/dist/Logger.d.ts +91 -0
- package/dist/Logger.js +191 -0
- package/dist/Logger.js.map +1 -0
- package/dist/PomBuilder.d.ts +144 -0
- package/dist/PomBuilder.js +249 -0
- package/dist/PomBuilder.js.map +1 -0
- package/dist/PromptManager.d.ts +85 -0
- package/dist/PromptManager.js +108 -0
- package/dist/PromptManager.js.map +1 -0
- package/dist/SchemaUtils.d.ts +42 -0
- package/dist/SchemaUtils.js +148 -0
- package/dist/SchemaUtils.js.map +1 -0
- package/dist/ServerlessAdapter.d.ts +100 -0
- package/dist/ServerlessAdapter.js +166 -0
- package/dist/ServerlessAdapter.js.map +1 -0
- package/dist/SessionManager.d.ts +86 -0
- package/dist/SessionManager.js +155 -0
- package/dist/SessionManager.js.map +1 -0
- package/dist/SslConfig.d.ts +77 -0
- package/dist/SslConfig.js +100 -0
- package/dist/SslConfig.js.map +1 -0
- package/dist/SwaigFunction.d.ts +88 -0
- package/dist/SwaigFunction.js +125 -0
- package/dist/SwaigFunction.js.map +1 -0
- package/dist/SwaigFunctionResult.d.ts +442 -0
- package/dist/SwaigFunctionResult.js +735 -0
- package/dist/SwaigFunctionResult.js.map +1 -0
- package/dist/SwmlBuilder.d.ts +37 -0
- package/dist/SwmlBuilder.js +55 -0
- package/dist/SwmlBuilder.js.map +1 -0
- package/dist/cli/agent-loader.d.ts +22 -0
- package/dist/cli/agent-loader.js +106 -0
- package/dist/cli/agent-loader.js.map +1 -0
- package/dist/cli/mock-data.d.ts +37 -0
- package/dist/cli/mock-data.js +79 -0
- package/dist/cli/mock-data.js.map +1 -0
- package/dist/cli/swaig-test.d.ts +32 -0
- package/dist/cli/swaig-test.js +405 -0
- package/dist/cli/swaig-test.js.map +1 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.js +44 -0
- package/dist/index.js.map +1 -0
- package/dist/prefabs/ConciergeAgent.d.ts +64 -0
- package/dist/prefabs/ConciergeAgent.js +188 -0
- package/dist/prefabs/ConciergeAgent.js.map +1 -0
- package/dist/prefabs/FAQBotAgent.d.ts +68 -0
- package/dist/prefabs/FAQBotAgent.js +206 -0
- package/dist/prefabs/FAQBotAgent.js.map +1 -0
- package/dist/prefabs/InfoGathererAgent.d.ts +73 -0
- package/dist/prefabs/InfoGathererAgent.js +202 -0
- package/dist/prefabs/InfoGathererAgent.js.map +1 -0
- package/dist/prefabs/ReceptionistAgent.d.ts +65 -0
- package/dist/prefabs/ReceptionistAgent.js +205 -0
- package/dist/prefabs/ReceptionistAgent.js.map +1 -0
- package/dist/prefabs/SurveyAgent.d.ts +84 -0
- package/dist/prefabs/SurveyAgent.js +324 -0
- package/dist/prefabs/SurveyAgent.js.map +1 -0
- package/dist/prefabs/index.d.ts +13 -0
- package/dist/prefabs/index.js +14 -0
- package/dist/prefabs/index.js.map +1 -0
- package/dist/skills/SkillBase.d.ts +134 -0
- package/dist/skills/SkillBase.js +105 -0
- package/dist/skills/SkillBase.js.map +1 -0
- package/dist/skills/SkillManager.d.ts +83 -0
- package/dist/skills/SkillManager.js +159 -0
- package/dist/skills/SkillManager.js.map +1 -0
- package/dist/skills/SkillRegistry.d.ts +105 -0
- package/dist/skills/SkillRegistry.js +195 -0
- package/dist/skills/SkillRegistry.js.map +1 -0
- package/dist/skills/builtin/api_ninjas_trivia.d.ts +35 -0
- package/dist/skills/builtin/api_ninjas_trivia.js +161 -0
- package/dist/skills/builtin/api_ninjas_trivia.js.map +1 -0
- package/dist/skills/builtin/claude_skills.d.ts +34 -0
- package/dist/skills/builtin/claude_skills.js +156 -0
- package/dist/skills/builtin/claude_skills.js.map +1 -0
- package/dist/skills/builtin/custom_skills.d.ts +59 -0
- package/dist/skills/builtin/custom_skills.js +231 -0
- package/dist/skills/builtin/custom_skills.js.map +1 -0
- package/dist/skills/builtin/datasphere.d.ts +34 -0
- package/dist/skills/builtin/datasphere.js +163 -0
- package/dist/skills/builtin/datasphere.js.map +1 -0
- package/dist/skills/builtin/datasphere_serverless.d.ts +54 -0
- package/dist/skills/builtin/datasphere_serverless.js +155 -0
- package/dist/skills/builtin/datasphere_serverless.js.map +1 -0
- package/dist/skills/builtin/datetime.d.ts +31 -0
- package/dist/skills/builtin/datetime.js +95 -0
- package/dist/skills/builtin/datetime.js.map +1 -0
- package/dist/skills/builtin/google_maps.d.ts +33 -0
- package/dist/skills/builtin/google_maps.js +233 -0
- package/dist/skills/builtin/google_maps.js.map +1 -0
- package/dist/skills/builtin/index.d.ts +28 -0
- package/dist/skills/builtin/index.js +75 -0
- package/dist/skills/builtin/index.js.map +1 -0
- package/dist/skills/builtin/info_gatherer.d.ts +52 -0
- package/dist/skills/builtin/info_gatherer.js +237 -0
- package/dist/skills/builtin/info_gatherer.js.map +1 -0
- package/dist/skills/builtin/joke.d.ts +32 -0
- package/dist/skills/builtin/joke.js +142 -0
- package/dist/skills/builtin/joke.js.map +1 -0
- package/dist/skills/builtin/math.d.ts +33 -0
- package/dist/skills/builtin/math.js +120 -0
- package/dist/skills/builtin/math.js.map +1 -0
- package/dist/skills/builtin/mcp_gateway.d.ts +35 -0
- package/dist/skills/builtin/mcp_gateway.js +85 -0
- package/dist/skills/builtin/mcp_gateway.js.map +1 -0
- package/dist/skills/builtin/native_vector_search.d.ts +44 -0
- package/dist/skills/builtin/native_vector_search.js +248 -0
- package/dist/skills/builtin/native_vector_search.js.map +1 -0
- package/dist/skills/builtin/play_background_file.d.ts +34 -0
- package/dist/skills/builtin/play_background_file.js +135 -0
- package/dist/skills/builtin/play_background_file.js.map +1 -0
- package/dist/skills/builtin/spider.d.ts +34 -0
- package/dist/skills/builtin/spider.js +164 -0
- package/dist/skills/builtin/spider.js.map +1 -0
- package/dist/skills/builtin/swml_transfer.d.ts +44 -0
- package/dist/skills/builtin/swml_transfer.js +204 -0
- package/dist/skills/builtin/swml_transfer.js.map +1 -0
- package/dist/skills/builtin/weather_api.d.ts +34 -0
- package/dist/skills/builtin/weather_api.js +136 -0
- package/dist/skills/builtin/weather_api.js.map +1 -0
- package/dist/skills/builtin/web_search.d.ts +34 -0
- package/dist/skills/builtin/web_search.js +141 -0
- package/dist/skills/builtin/web_search.js.map +1 -0
- package/dist/skills/builtin/wikipedia_search.d.ts +34 -0
- package/dist/skills/builtin/wikipedia_search.js +166 -0
- package/dist/skills/builtin/wikipedia_search.js.map +1 -0
- package/dist/skills/index.d.ts +11 -0
- package/dist/skills/index.js +10 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/types.d.ts +85 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/docs/agent-guide.md +869 -0
- package/docs/api-reference.md +2419 -0
- package/docs/architecture.md +843 -0
- package/docs/cli-guide.md +579 -0
- package/docs/configuration.md +422 -0
- package/docs/contexts-guide.md +787 -0
- package/docs/datamap-guide.md +1141 -0
- package/docs/prefabs-guide.md +830 -0
- package/docs/security.md +436 -0
- package/docs/serverless-guide.md +513 -0
- package/docs/skills-guide.md +845 -0
- package/docs/swaig-reference.md +1627 -0
- package/examples/call-flow.ts +60 -0
- package/examples/contexts-steps.ts +62 -0
- package/examples/datamap-tools.ts +52 -0
- package/examples/dynamic-config.ts +51 -0
- package/examples/multi-agent.ts +67 -0
- package/examples/pom-prompt.ts +68 -0
- package/examples/simple-agent.ts +33 -0
- package/package.json +35 -0
- package/src/AgentBase.ts +1279 -0
- package/src/AgentServer.ts +149 -0
- package/src/AuthHandler.ts +141 -0
- package/src/ConfigLoader.ts +165 -0
- package/src/ContextBuilder.ts +796 -0
- package/src/DataMap.ts +365 -0
- package/src/Logger.ts +197 -0
- package/src/PomBuilder.ts +298 -0
- package/src/PromptManager.ts +133 -0
- package/src/SchemaUtils.ts +170 -0
- package/src/ServerlessAdapter.ts +218 -0
- package/src/SessionManager.ts +161 -0
- package/src/SslConfig.ts +118 -0
- package/src/SwaigFunction.ts +168 -0
- package/src/SwaigFunctionResult.ts +864 -0
- package/src/SwmlBuilder.ts +62 -0
- package/src/cli/agent-loader.ts +122 -0
- package/src/cli/mock-data.ts +110 -0
- package/src/cli/swaig-test.ts +440 -0
- package/src/index.ts +99 -0
- package/src/prefabs/ConciergeAgent.ts +251 -0
- package/src/prefabs/FAQBotAgent.ts +263 -0
- package/src/prefabs/InfoGathererAgent.ts +276 -0
- package/src/prefabs/ReceptionistAgent.ts +277 -0
- package/src/prefabs/SurveyAgent.ts +413 -0
- package/src/prefabs/index.ts +23 -0
- package/src/skills/SkillBase.ts +184 -0
- package/src/skills/SkillManager.ts +177 -0
- package/src/skills/SkillRegistry.ts +231 -0
- package/src/skills/builtin/api_ninjas_trivia.ts +230 -0
- package/src/skills/builtin/claude_skills.ts +239 -0
- package/src/skills/builtin/custom_skills.ts +326 -0
- package/src/skills/builtin/datasphere.ts +225 -0
- package/src/skills/builtin/datasphere_serverless.ts +194 -0
- package/src/skills/builtin/datetime.ts +115 -0
- package/src/skills/builtin/google_maps.ts +347 -0
- package/src/skills/builtin/index.ts +79 -0
- package/src/skills/builtin/info_gatherer.ts +331 -0
- package/src/skills/builtin/joke.ts +180 -0
- package/src/skills/builtin/math.ts +150 -0
- package/src/skills/builtin/mcp_gateway.ts +99 -0
- package/src/skills/builtin/native_vector_search.ts +327 -0
- package/src/skills/builtin/play_background_file.ts +189 -0
- package/src/skills/builtin/spider.ts +232 -0
- package/src/skills/builtin/swml_transfer.ts +285 -0
- package/src/skills/builtin/weather_api.ts +193 -0
- package/src/skills/builtin/web_search.ts +212 -0
- package/src/skills/builtin/wikipedia_search.ts +248 -0
- package/src/skills/index.ts +12 -0
- package/src/types.ts +99 -0
- package/tests/AgentBase.test.ts +693 -0
- package/tests/AgentServer.test.ts +102 -0
- package/tests/AuthHandler.test.ts +121 -0
- package/tests/ConfigLoader.test.ts +121 -0
- package/tests/DataMap.test.ts +286 -0
- package/tests/Logger.test.ts +218 -0
- package/tests/PomBuilder.test.ts +164 -0
- package/tests/ProxyDetection.test.ts +185 -0
- package/tests/SchemaUtils.test.ts +106 -0
- package/tests/ServerlessAdapter.test.ts +200 -0
- package/tests/SessionManager.test.ts +139 -0
- package/tests/SslConfig.test.ts +97 -0
- package/tests/SwaigFunctionResult.test.ts +298 -0
- package/tests/cli/mock-data.test.ts +94 -0
- package/tests/cli/swaig-test.test.ts +96 -0
- package/tests/prefabs/prefabs.test.ts +854 -0
- package/tests/setup.ts +6 -0
- package/tests/skills/SkillBase.test.ts +118 -0
- package/tests/skills/SkillManager.test.ts +164 -0
- package/tests/skills/SkillRegistry.test.ts +124 -0
- package/tests/skills/builtin.test.ts +924 -0
- package/tsconfig.json +18 -0
- package/vitest.config.ts +9 -0
|
@@ -0,0 +1,845 @@
|
|
|
1
|
+
# Skills System Guide
|
|
2
|
+
|
|
3
|
+
Complete guide to the Skills system in the SignalWire AI Agents TypeScript SDK -- modular, reusable capabilities that can be added to any agent.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
1. [Overview](#overview)
|
|
10
|
+
2. [Using Skills](#using-skills)
|
|
11
|
+
3. [Built-in Skills (18)](#built-in-skills-18)
|
|
12
|
+
4. [Skill Configuration](#skill-configuration)
|
|
13
|
+
5. [Skill Registry](#skill-registry)
|
|
14
|
+
6. [Creating Custom Skills](#creating-custom-skills)
|
|
15
|
+
7. [Skill Lifecycle](#skill-lifecycle)
|
|
16
|
+
8. [Environment Validation](#environment-validation)
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Overview
|
|
21
|
+
|
|
22
|
+
Skills are **modular capabilities** that can be added to an agent at runtime. Each skill encapsulates one or more SWAIG tools, prompt sections, speech recognition hints, and global data -- everything needed to give an agent a new ability.
|
|
23
|
+
|
|
24
|
+
The skills system is built on three core classes:
|
|
25
|
+
|
|
26
|
+
| Class | Role | Location |
|
|
27
|
+
|---|---|---|
|
|
28
|
+
| `SkillBase` | Abstract base class that all skills extend | `src/skills/SkillBase.ts` |
|
|
29
|
+
| `SkillManager` | Manages the lifecycle of skills attached to an agent | `src/skills/SkillManager.ts` |
|
|
30
|
+
| `SkillRegistry` | Global singleton registry for discovering and instantiating skills by name | `src/skills/SkillRegistry.ts` |
|
|
31
|
+
|
|
32
|
+
**What a skill provides:**
|
|
33
|
+
|
|
34
|
+
- **Tools** -- SWAIG function definitions (name, description, parameters, handler) registered with the agent.
|
|
35
|
+
- **Prompt sections** -- Text injected into the agent's system prompt to instruct the AI on how to use the skill's tools.
|
|
36
|
+
- **Hints** -- Speech recognition hints to improve ASR accuracy for skill-related vocabulary.
|
|
37
|
+
- **Global data** -- Key-value pairs merged into the agent's global data store.
|
|
38
|
+
- **Manifest** -- Metadata describing the skill's name, version, required environment variables, and configuration schema.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Using Skills
|
|
43
|
+
|
|
44
|
+
### `agent.addSkill()`
|
|
45
|
+
|
|
46
|
+
The primary way to add a skill to an agent. This is an async operation because skills may perform setup work (API connections, config validation, etc.):
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
import { AgentBase } from 'signalwire-agents';
|
|
50
|
+
import { DateTimeSkill, WebSearchSkill } from 'signalwire-agents/skills/builtin';
|
|
51
|
+
|
|
52
|
+
const agent = new AgentBase({ name: 'my-agent' });
|
|
53
|
+
|
|
54
|
+
// Add skills (async)
|
|
55
|
+
await agent.addSkill(new DateTimeSkill());
|
|
56
|
+
await agent.addSkill(new WebSearchSkill({ max_results: 3 }));
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
When `addSkill()` is called, the agent:
|
|
60
|
+
|
|
61
|
+
1. Validates the skill's required environment variables (warns if missing).
|
|
62
|
+
2. Calls `skill.setup()` for initialization.
|
|
63
|
+
3. Marks the skill as initialized.
|
|
64
|
+
4. Registers all tools from `skill.getTools()` with the agent via `defineTool()`.
|
|
65
|
+
5. Injects all prompt sections from `skill.getPromptSections()` into the agent's prompt.
|
|
66
|
+
6. Adds all hints from `skill.getHints()`.
|
|
67
|
+
7. Merges all global data from `skill.getGlobalData()`.
|
|
68
|
+
|
|
69
|
+
### `agent.removeSkill()`
|
|
70
|
+
|
|
71
|
+
Remove a skill by its unique instance ID. Calls `cleanup()` on the skill before removal:
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
const removed = await agent.removeSkill('datetime-abc123-def456');
|
|
75
|
+
// returns true if found and removed, false otherwise
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### `agent.listSkills()`
|
|
79
|
+
|
|
80
|
+
List all currently loaded skills with their metadata:
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
const skills = agent.listSkills();
|
|
84
|
+
// Returns: [{ name: 'datetime', instanceId: 'datetime-abc123-def456', initialized: true }, ...]
|
|
85
|
+
|
|
86
|
+
for (const skill of skills) {
|
|
87
|
+
console.log(`${skill.name} (${skill.instanceId}) - initialized: ${skill.initialized}`);
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### `agent.hasSkill()`
|
|
92
|
+
|
|
93
|
+
Check whether a skill with a given name is currently registered:
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
if (agent.hasSkill('web_search')) {
|
|
97
|
+
console.log('Web search is available');
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Built-in Skills (18)
|
|
104
|
+
|
|
105
|
+
The SDK ships with 18 built-in skills organized into three tiers based on complexity and dependency requirements.
|
|
106
|
+
|
|
107
|
+
### Tier 1: Simple (No External Dependencies)
|
|
108
|
+
|
|
109
|
+
These skills work out of the box with no API keys or configuration.
|
|
110
|
+
|
|
111
|
+
| Skill Name | Class | Description | Tools | Required Env Vars | Config Options |
|
|
112
|
+
|---|---|---|---|---|---|
|
|
113
|
+
| `datetime` | `DateTimeSkill` | Current date/time with timezone support | `get_datetime` | None | None |
|
|
114
|
+
| `math` | `MathSkill` | Safe mathematical expression evaluation | `calculate` | None | None |
|
|
115
|
+
| `joke` | `JokeSkill` | Random jokes from built-in collection | `tell_joke` | None | None |
|
|
116
|
+
|
|
117
|
+
**datetime** -- Provides the current date and time in any IANA timezone via the `get_datetime` tool. Uses the `Intl.DateTimeFormat` API.
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
import { DateTimeSkill } from 'signalwire-agents/skills/builtin';
|
|
121
|
+
await agent.addSkill(new DateTimeSkill());
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**math** -- Evaluates mathematical expressions safely using a sandboxed parser. Supports `+`, `-`, `*`, `/`, `^`, `%`, and parentheses. Only allows digits, operators, parentheses, decimal points, and spaces.
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
import { MathSkill } from 'signalwire-agents/skills/builtin';
|
|
128
|
+
await agent.addSkill(new MathSkill());
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**joke** -- Tells random jokes from a curated built-in collection. Categories: `general`, `programming`, `dad`.
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
import { JokeSkill } from 'signalwire-agents/skills/builtin';
|
|
135
|
+
await agent.addSkill(new JokeSkill());
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
### Tier 2: Single API (Simple External Integration)
|
|
141
|
+
|
|
142
|
+
These skills integrate with a single external API or provide focused call-control features.
|
|
143
|
+
|
|
144
|
+
| Skill Name | Class | Description | Tools | Required Env Vars | Config Options |
|
|
145
|
+
|---|---|---|---|---|---|
|
|
146
|
+
| `weather_api` | `WeatherApiSkill` | Current weather from OpenWeatherMap | `get_weather` | `WEATHER_API_KEY` | `units` |
|
|
147
|
+
| `play_background_file` | `PlayBackgroundFileSkill` | Background audio playback during calls | `play_background`, `stop_background` | None | `default_file_url`, `allowed_domains` |
|
|
148
|
+
| `swml_transfer` | `SwmlTransferSkill` | Call transfer via SWML actions | `transfer_call`, `list_transfer_destinations` | None | `patterns`, `allow_arbitrary`, `default_message` |
|
|
149
|
+
| `api_ninjas_trivia` | `ApiNinjasTriviaSkill` | Trivia questions from API Ninjas | `get_trivia` | `API_NINJAS_KEY` | `default_category`, `reveal_answer` |
|
|
150
|
+
| `info_gatherer` | `InfoGathererSkill` | Structured data collection from users | `save_info`, `get_gathered_info` | None | `fields`, `purpose`, `confirmation_message`, `store_globally` |
|
|
151
|
+
| `custom_skills` | `CustomSkillsSkill` | User-defined tools from configuration | Dynamic (from config) | None | `tools`, `prompt_title`, `prompt_body` |
|
|
152
|
+
|
|
153
|
+
**weather_api** -- Fetches current weather data from OpenWeatherMap. Supports metric, imperial, and standard units.
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
import { WeatherApiSkill } from 'signalwire-agents/skills/builtin';
|
|
157
|
+
await agent.addSkill(new WeatherApiSkill({ units: 'imperial' }));
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**play_background_file** -- Controls background audio playback during calls (hold music, ambient sounds). Supports domain restrictions for audio file URLs.
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
import { PlayBackgroundFileSkill } from 'signalwire-agents/skills/builtin';
|
|
164
|
+
await agent.addSkill(new PlayBackgroundFileSkill({
|
|
165
|
+
default_file_url: 'https://example.com/hold-music.mp3',
|
|
166
|
+
allowed_domains: ['example.com', 'cdn.example.com'],
|
|
167
|
+
}));
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**swml_transfer** -- Transfers calls using SWML transfer actions. Supports named destination patterns and arbitrary transfers.
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
import { SwmlTransferSkill } from 'signalwire-agents/skills/builtin';
|
|
174
|
+
await agent.addSkill(new SwmlTransferSkill({
|
|
175
|
+
patterns: [
|
|
176
|
+
{ name: 'billing', destination: '+15551234567', description: 'Billing department' },
|
|
177
|
+
{ name: 'support', destination: 'sip:support@example.com', description: 'Technical support' },
|
|
178
|
+
],
|
|
179
|
+
allow_arbitrary: false,
|
|
180
|
+
default_message: 'Please hold while I transfer you.',
|
|
181
|
+
}));
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
**api_ninjas_trivia** -- Fetches trivia questions with optional category filtering. Categories include `general`, `sciencenature`, `entertainment`, `historyholidays`, `geography`, `music`, `mathematics`, and more.
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
import { ApiNinjasTriviaSkill } from 'signalwire-agents/skills/builtin';
|
|
188
|
+
await agent.addSkill(new ApiNinjasTriviaSkill({
|
|
189
|
+
default_category: 'sciencenature',
|
|
190
|
+
reveal_answer: false, // AI quizzes the user
|
|
191
|
+
}));
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
**info_gatherer** -- Collects structured information from users based on configurable field definitions with optional validation patterns. Data is stored per-call and can optionally be persisted to global data.
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
import { InfoGathererSkill } from 'signalwire-agents/skills/builtin';
|
|
198
|
+
await agent.addSkill(new InfoGathererSkill({
|
|
199
|
+
purpose: 'Collecting customer contact information for our records.',
|
|
200
|
+
fields: [
|
|
201
|
+
{ name: 'full_name', description: 'Customer full name', required: true },
|
|
202
|
+
{ name: 'email', description: 'Email address', required: true, validation: '^[\\w.+-]+@[\\w-]+\\.[\\w.]+$' },
|
|
203
|
+
{ name: 'phone', description: 'Phone number', required: false },
|
|
204
|
+
],
|
|
205
|
+
confirmation_message: 'Thank you! Your information has been saved.',
|
|
206
|
+
store_globally: true,
|
|
207
|
+
}));
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
**custom_skills** -- A meta-skill that registers user-defined tools from configuration without writing skill classes. Handler code is compiled via the `Function` constructor at instantiation time.
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
import { CustomSkillsSkill } from 'signalwire-agents/skills/builtin';
|
|
214
|
+
await agent.addSkill(new CustomSkillsSkill({
|
|
215
|
+
prompt_title: 'Greeting Tools',
|
|
216
|
+
tools: [
|
|
217
|
+
{
|
|
218
|
+
name: 'get_greeting',
|
|
219
|
+
description: 'Get a personalized greeting for a customer.',
|
|
220
|
+
parameters: [
|
|
221
|
+
{ name: 'name', type: 'string', description: 'Customer name', required: true },
|
|
222
|
+
],
|
|
223
|
+
handler_code: 'return new SwaigFunctionResult(`Hello, ${args.name}! Welcome back.`);',
|
|
224
|
+
required: ['name'],
|
|
225
|
+
},
|
|
226
|
+
],
|
|
227
|
+
}));
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
### Tier 3: Complex (Multi-API or Advanced)
|
|
233
|
+
|
|
234
|
+
These skills involve complex integrations, multiple API calls, or advanced processing.
|
|
235
|
+
|
|
236
|
+
| Skill Name | Class | Description | Tools | Required Env Vars | Config Options |
|
|
237
|
+
|---|---|---|---|---|---|
|
|
238
|
+
| `web_search` | `WebSearchSkill` | Google Custom Search | `web_search` | `GOOGLE_SEARCH_API_KEY`, `GOOGLE_SEARCH_CX` | `max_results`, `safe_search` |
|
|
239
|
+
| `wikipedia_search` | `WikipediaSearchSkill` | Wikipedia article summaries | `search_wikipedia` | None | None |
|
|
240
|
+
| `google_maps` | `GoogleMapsSkill` | Directions and place search | `get_directions`, `find_place` | `GOOGLE_MAPS_API_KEY` | `default_mode` |
|
|
241
|
+
| `datasphere` | `DataSphereSkill` | SignalWire DataSphere semantic search | `search_datasphere` | `SIGNALWIRE_PROJECT_ID`, `SIGNALWIRE_TOKEN`, `SIGNALWIRE_SPACE` | `max_results`, `distance_threshold` |
|
|
242
|
+
| `datasphere_serverless` | `DataSphereServerlessSkill` | DataSphere via server-side DataMap | `search_datasphere` | `SIGNALWIRE_PROJECT_ID`, `SIGNALWIRE_TOKEN`, `SIGNALWIRE_SPACE` | `max_results`, `distance_threshold`, `document_id` |
|
|
243
|
+
| `native_vector_search` | `NativeVectorSearchSkill` | In-memory TF-IDF document search | `search_documents` | None | `documents` |
|
|
244
|
+
| `spider` | `SpiderSkill` | Web page scraping via Spider API | `scrape_url` | `SPIDER_API_KEY` | `max_content_length` |
|
|
245
|
+
| `claude_skills` | `ClaudeSkill` | Anthropic Claude AI sub-queries | `ask_claude` | `ANTHROPIC_API_KEY` | `model`, `max_tokens` |
|
|
246
|
+
| `mcp_gateway` | `McpGatewaySkill` | MCP protocol gateway (placeholder) | `mcp_invoke` | None | None |
|
|
247
|
+
|
|
248
|
+
**web_search** -- Searches the web using Google Custom Search JSON API. Returns formatted results with titles, links, and snippets.
|
|
249
|
+
|
|
250
|
+
```typescript
|
|
251
|
+
import { WebSearchSkill } from 'signalwire-agents/skills/builtin';
|
|
252
|
+
await agent.addSkill(new WebSearchSkill({
|
|
253
|
+
max_results: 5,
|
|
254
|
+
safe_search: 'medium', // 'off' | 'medium' | 'high'
|
|
255
|
+
}));
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
**wikipedia_search** -- Searches Wikipedia for article summaries and extracts. Uses the Wikipedia REST API with no API key required. Falls back to the search API if direct page lookup fails.
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
import { WikipediaSearchSkill } from 'signalwire-agents/skills/builtin';
|
|
262
|
+
await agent.addSkill(new WikipediaSearchSkill());
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
**google_maps** -- Provides driving/walking/bicycling/transit directions and place search via Google Maps APIs (Directions API and Places Find Place API).
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
import { GoogleMapsSkill } from 'signalwire-agents/skills/builtin';
|
|
269
|
+
await agent.addSkill(new GoogleMapsSkill({ default_mode: 'walking' }));
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
**datasphere** -- Searches SignalWire DataSphere for knowledge base content using semantic search across uploaded documents. Results are ranked by relevance score.
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
import { DataSphereSkill } from 'signalwire-agents/skills/builtin';
|
|
276
|
+
await agent.addSkill(new DataSphereSkill({
|
|
277
|
+
max_results: 5,
|
|
278
|
+
distance_threshold: 0.7, // 0-1, lower is more similar
|
|
279
|
+
}));
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
**datasphere_serverless** -- Like `datasphere`, but uses a server-side DataMap instead of a webhook handler. The search executes entirely on the SignalWire platform, making it ideal for serverless or edge deployments where no webhook endpoint is available.
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
import { DataSphereServerlessSkill } from 'signalwire-agents/skills/builtin';
|
|
286
|
+
await agent.addSkill(new DataSphereServerlessSkill({
|
|
287
|
+
max_results: 5,
|
|
288
|
+
distance_threshold: 0.7,
|
|
289
|
+
document_id: 'specific-doc-id', // optional: restrict to one document
|
|
290
|
+
}));
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
**native_vector_search** -- In-memory document search using TF-IDF-like word overlap scoring. Documents are provided via configuration and indexed at construction time. No external dependencies or API keys required. Suitable for small to medium document collections.
|
|
294
|
+
|
|
295
|
+
```typescript
|
|
296
|
+
import { NativeVectorSearchSkill } from 'signalwire-agents/skills/builtin';
|
|
297
|
+
await agent.addSkill(new NativeVectorSearchSkill({
|
|
298
|
+
documents: [
|
|
299
|
+
{ id: 'faq-1', text: 'To reset your password, go to Settings > Security > Change Password.' },
|
|
300
|
+
{ id: 'faq-2', text: 'Our business hours are Monday-Friday 9am-5pm EST.' },
|
|
301
|
+
{ id: 'faq-3', text: 'Refunds are processed within 5-7 business days.', metadata: { category: 'billing' } },
|
|
302
|
+
],
|
|
303
|
+
}));
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
**spider** -- Scrapes webpage content using the Spider API. Extracts text, markdown, or HTML from any public URL with optional CSS selector filtering.
|
|
307
|
+
|
|
308
|
+
```typescript
|
|
309
|
+
import { SpiderSkill } from 'signalwire-agents/skills/builtin';
|
|
310
|
+
await agent.addSkill(new SpiderSkill({
|
|
311
|
+
max_content_length: 5000,
|
|
312
|
+
}));
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
**claude_skills** -- Provides access to Anthropic's Claude AI for sub-queries, complex reasoning, analysis, or summarization. The agent can delegate tasks to Claude when deeper processing is needed.
|
|
316
|
+
|
|
317
|
+
```typescript
|
|
318
|
+
import { ClaudeSkill } from 'signalwire-agents/skills/builtin';
|
|
319
|
+
await agent.addSkill(new ClaudeSkill({
|
|
320
|
+
model: 'claude-sonnet-4-5-20250929',
|
|
321
|
+
max_tokens: 1024,
|
|
322
|
+
}));
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
**mcp_gateway** -- Placeholder skill for future Model Context Protocol (MCP) server integration. Currently provides a non-functional `mcp_invoke` tool. Version 0.1.0 (stub).
|
|
326
|
+
|
|
327
|
+
```typescript
|
|
328
|
+
import { McpGatewaySkill } from 'signalwire-agents/skills/builtin';
|
|
329
|
+
await agent.addSkill(new McpGatewaySkill());
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
## Skill Configuration
|
|
335
|
+
|
|
336
|
+
Skills accept configuration via a `SkillConfig` key-value object passed to the constructor:
|
|
337
|
+
|
|
338
|
+
```typescript
|
|
339
|
+
interface SkillConfig {
|
|
340
|
+
[key: string]: unknown;
|
|
341
|
+
}
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### Accessing Config in Skills
|
|
345
|
+
|
|
346
|
+
Skills use `this.getConfig<T>(key, defaultValue)` to read configuration values with type safety and defaults:
|
|
347
|
+
|
|
348
|
+
```typescript
|
|
349
|
+
// Inside a skill class
|
|
350
|
+
const maxResults = this.getConfig<number>('max_results', 5);
|
|
351
|
+
const safeSearch = this.getConfig<string>('safe_search', 'medium');
|
|
352
|
+
const patterns = this.getConfig<TransferPattern[]>('patterns', []);
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
### Config Schema in Manifests
|
|
356
|
+
|
|
357
|
+
Skills declare their expected configuration in the manifest's `configSchema` field. This is a JSON-schema-like description used for documentation and tooling:
|
|
358
|
+
|
|
359
|
+
```typescript
|
|
360
|
+
getManifest(): SkillManifest {
|
|
361
|
+
return {
|
|
362
|
+
name: 'my_skill',
|
|
363
|
+
description: 'Does something useful.',
|
|
364
|
+
version: '1.0.0',
|
|
365
|
+
configSchema: {
|
|
366
|
+
max_results: {
|
|
367
|
+
type: 'number',
|
|
368
|
+
description: 'Maximum number of results to return.',
|
|
369
|
+
default: 5,
|
|
370
|
+
},
|
|
371
|
+
safe_search: {
|
|
372
|
+
type: 'string',
|
|
373
|
+
description: 'Safe search level: "off", "medium", or "high".',
|
|
374
|
+
default: 'medium',
|
|
375
|
+
},
|
|
376
|
+
},
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
383
|
+
## Skill Registry
|
|
384
|
+
|
|
385
|
+
The `SkillRegistry` is a global singleton that maps skill names to factory functions. It enables skill discovery and instantiation by name.
|
|
386
|
+
|
|
387
|
+
### Getting the Registry
|
|
388
|
+
|
|
389
|
+
```typescript
|
|
390
|
+
import { SkillRegistry } from 'signalwire-agents/skills';
|
|
391
|
+
|
|
392
|
+
const registry = SkillRegistry.getInstance();
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### Registering Built-in Skills
|
|
396
|
+
|
|
397
|
+
All 18 built-in skills can be registered at once:
|
|
398
|
+
|
|
399
|
+
```typescript
|
|
400
|
+
import { registerBuiltinSkills } from 'signalwire-agents/skills/builtin';
|
|
401
|
+
|
|
402
|
+
registerBuiltinSkills();
|
|
403
|
+
// Now all built-in skills are available via registry.create('datetime'), etc.
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
This function skips registration for any skill name already present, so it is safe to call multiple times.
|
|
407
|
+
|
|
408
|
+
### Manual Registration
|
|
409
|
+
|
|
410
|
+
Register a custom skill factory:
|
|
411
|
+
|
|
412
|
+
```typescript
|
|
413
|
+
registry.register('my_custom_skill', (config) => new MyCustomSkill(config));
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
Register with a manifest for introspection:
|
|
417
|
+
|
|
418
|
+
```typescript
|
|
419
|
+
registry.register('my_custom_skill', (config) => new MyCustomSkill(config), {
|
|
420
|
+
name: 'my_custom_skill',
|
|
421
|
+
description: 'Does custom things.',
|
|
422
|
+
version: '1.0.0',
|
|
423
|
+
});
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
### Creating Instances by Name
|
|
427
|
+
|
|
428
|
+
```typescript
|
|
429
|
+
const skill = registry.create('datetime');
|
|
430
|
+
if (skill) {
|
|
431
|
+
await agent.addSkill(skill);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// With config
|
|
435
|
+
const weatherSkill = registry.create('weather_api', { units: 'imperial' });
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
Returns `null` if the skill name is not registered.
|
|
439
|
+
|
|
440
|
+
### Querying the Registry
|
|
441
|
+
|
|
442
|
+
```typescript
|
|
443
|
+
// Check if a skill is registered
|
|
444
|
+
registry.has('datetime'); // true
|
|
445
|
+
|
|
446
|
+
// List all registered skill names
|
|
447
|
+
const names = registry.listRegistered();
|
|
448
|
+
// ['datetime', 'math', 'joke', ...]
|
|
449
|
+
|
|
450
|
+
// List with manifests
|
|
451
|
+
const withManifests = registry.listRegisteredWithManifests();
|
|
452
|
+
// [{ name: 'datetime', manifest: { ... } }, ...]
|
|
453
|
+
|
|
454
|
+
// Get a specific manifest
|
|
455
|
+
const manifest = registry.getManifest('web_search');
|
|
456
|
+
|
|
457
|
+
// Count of registered skills
|
|
458
|
+
const count = registry.size;
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
### Skill Discovery from Directories
|
|
462
|
+
|
|
463
|
+
The registry can auto-discover skills from filesystem directories:
|
|
464
|
+
|
|
465
|
+
```typescript
|
|
466
|
+
// Add a search path
|
|
467
|
+
registry.addSearchPath('/path/to/my/skills');
|
|
468
|
+
|
|
469
|
+
// Discover and register skills from a specific directory
|
|
470
|
+
const discovered = await registry.discoverFromDirectory('/path/to/my/skills');
|
|
471
|
+
// Returns array of newly discovered skill names
|
|
472
|
+
|
|
473
|
+
// Discover from all configured search paths
|
|
474
|
+
const allDiscovered = await registry.discoverAll();
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
Discovery looks for modules that export either:
|
|
478
|
+
- A `createSkill` factory function, or
|
|
479
|
+
- A default export that is a `SkillBase` subclass
|
|
480
|
+
|
|
481
|
+
The `SIGNALWIRE_SKILL_PATHS` environment variable can set additional search paths (colon-separated):
|
|
482
|
+
|
|
483
|
+
```bash
|
|
484
|
+
export SIGNALWIRE_SKILL_PATHS="/app/skills:/shared/skills"
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
### Cleanup
|
|
488
|
+
|
|
489
|
+
```typescript
|
|
490
|
+
// Unregister a single skill
|
|
491
|
+
registry.unregister('my_skill');
|
|
492
|
+
|
|
493
|
+
// Clear all registrations
|
|
494
|
+
registry.clear();
|
|
495
|
+
|
|
496
|
+
// Reset the singleton (for testing)
|
|
497
|
+
SkillRegistry.resetInstance();
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
---
|
|
501
|
+
|
|
502
|
+
## Creating Custom Skills
|
|
503
|
+
|
|
504
|
+
To create a custom skill, extend `SkillBase` and implement the required abstract methods.
|
|
505
|
+
|
|
506
|
+
### Minimal Custom Skill
|
|
507
|
+
|
|
508
|
+
```typescript
|
|
509
|
+
import { SkillBase, SkillManifest, SkillToolDefinition, SkillConfig } from 'signalwire-agents/skills';
|
|
510
|
+
import { SwaigFunctionResult } from 'signalwire-agents';
|
|
511
|
+
|
|
512
|
+
export class GreetingSkill extends SkillBase {
|
|
513
|
+
constructor(config?: SkillConfig) {
|
|
514
|
+
super('greeting', config);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
getManifest(): SkillManifest {
|
|
518
|
+
return {
|
|
519
|
+
name: 'greeting',
|
|
520
|
+
description: 'Provides personalized greetings.',
|
|
521
|
+
version: '1.0.0',
|
|
522
|
+
author: 'My Team',
|
|
523
|
+
tags: ['utility', 'greeting'],
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
getTools(): SkillToolDefinition[] {
|
|
528
|
+
const style = this.getConfig<string>('style', 'formal');
|
|
529
|
+
|
|
530
|
+
return [
|
|
531
|
+
{
|
|
532
|
+
name: 'greet_customer',
|
|
533
|
+
description: 'Generate a personalized greeting for a customer.',
|
|
534
|
+
parameters: {
|
|
535
|
+
name: {
|
|
536
|
+
type: 'string',
|
|
537
|
+
description: 'The customer name.',
|
|
538
|
+
},
|
|
539
|
+
},
|
|
540
|
+
required: ['name'],
|
|
541
|
+
handler: (args: Record<string, unknown>) => {
|
|
542
|
+
const name = args.name as string;
|
|
543
|
+
if (style === 'casual') {
|
|
544
|
+
return new SwaigFunctionResult(`Hey ${name}! What's up?`);
|
|
545
|
+
}
|
|
546
|
+
return new SwaigFunctionResult(`Good day, ${name}. How may I assist you?`);
|
|
547
|
+
},
|
|
548
|
+
},
|
|
549
|
+
];
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// Factory function (required for registry discovery)
|
|
554
|
+
export function createSkill(config?: SkillConfig): GreetingSkill {
|
|
555
|
+
return new GreetingSkill(config);
|
|
556
|
+
}
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
### Full-Featured Custom Skill
|
|
560
|
+
|
|
561
|
+
```typescript
|
|
562
|
+
import {
|
|
563
|
+
SkillBase,
|
|
564
|
+
SkillManifest,
|
|
565
|
+
SkillToolDefinition,
|
|
566
|
+
SkillPromptSection,
|
|
567
|
+
SkillConfig,
|
|
568
|
+
} from 'signalwire-agents/skills';
|
|
569
|
+
import { SwaigFunctionResult } from 'signalwire-agents';
|
|
570
|
+
|
|
571
|
+
export class InventorySkill extends SkillBase {
|
|
572
|
+
private db: Map<string, number> = new Map();
|
|
573
|
+
|
|
574
|
+
constructor(config?: SkillConfig) {
|
|
575
|
+
super('inventory', config);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
getManifest(): SkillManifest {
|
|
579
|
+
return {
|
|
580
|
+
name: 'inventory',
|
|
581
|
+
description: 'Checks product inventory levels.',
|
|
582
|
+
version: '1.0.0',
|
|
583
|
+
author: 'Acme Corp',
|
|
584
|
+
tags: ['inventory', 'products', 'e-commerce'],
|
|
585
|
+
requiredEnvVars: ['INVENTORY_DB_URL'],
|
|
586
|
+
configSchema: {
|
|
587
|
+
low_stock_threshold: {
|
|
588
|
+
type: 'number',
|
|
589
|
+
description: 'Quantity below which a product is considered low stock.',
|
|
590
|
+
default: 10,
|
|
591
|
+
},
|
|
592
|
+
},
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// Initialization -- called when the skill is added to an agent
|
|
597
|
+
async setup(): Promise<void> {
|
|
598
|
+
const dbUrl = process.env['INVENTORY_DB_URL'];
|
|
599
|
+
// ... connect to database, load initial data ...
|
|
600
|
+
this.db.set('widget-a', 150);
|
|
601
|
+
this.db.set('widget-b', 3);
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// Cleanup -- called when the skill is removed
|
|
605
|
+
async cleanup(): Promise<void> {
|
|
606
|
+
// ... close database connection ...
|
|
607
|
+
this.db.clear();
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
getTools(): SkillToolDefinition[] {
|
|
611
|
+
const threshold = this.getConfig<number>('low_stock_threshold', 10);
|
|
612
|
+
|
|
613
|
+
return [
|
|
614
|
+
{
|
|
615
|
+
name: 'check_inventory',
|
|
616
|
+
description: 'Check the current inventory level for a product.',
|
|
617
|
+
parameters: {
|
|
618
|
+
product_id: {
|
|
619
|
+
type: 'string',
|
|
620
|
+
description: 'The product ID to check.',
|
|
621
|
+
},
|
|
622
|
+
},
|
|
623
|
+
required: ['product_id'],
|
|
624
|
+
secure: true, // requires authenticated invocation
|
|
625
|
+
fillers: {
|
|
626
|
+
'en-US': ['Let me check our stock levels...', 'One moment...'],
|
|
627
|
+
},
|
|
628
|
+
handler: (args: Record<string, unknown>) => {
|
|
629
|
+
const productId = args.product_id as string;
|
|
630
|
+
const quantity = this.db.get(productId);
|
|
631
|
+
|
|
632
|
+
if (quantity === undefined) {
|
|
633
|
+
return new SwaigFunctionResult(`Product "${productId}" not found in inventory.`);
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
const status = quantity <= threshold ? 'LOW STOCK' : 'In Stock';
|
|
637
|
+
return new SwaigFunctionResult(
|
|
638
|
+
`Product ${productId}: ${quantity} units available (${status}).`
|
|
639
|
+
);
|
|
640
|
+
},
|
|
641
|
+
},
|
|
642
|
+
];
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
getPromptSections(): SkillPromptSection[] {
|
|
646
|
+
return [
|
|
647
|
+
{
|
|
648
|
+
title: 'Inventory Lookup',
|
|
649
|
+
body: 'You can check product inventory levels for customers.',
|
|
650
|
+
bullets: [
|
|
651
|
+
'Use the check_inventory tool when a customer asks about product availability.',
|
|
652
|
+
'If a product is low stock, proactively let the customer know.',
|
|
653
|
+
'Suggest alternatives if a product is out of stock.',
|
|
654
|
+
],
|
|
655
|
+
},
|
|
656
|
+
];
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
getHints(): string[] {
|
|
660
|
+
return ['inventory', 'stock', 'availability', 'in stock', 'out of stock'];
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
getGlobalData(): Record<string, unknown> {
|
|
664
|
+
return {
|
|
665
|
+
inventory_skill_version: '1.0.0',
|
|
666
|
+
low_stock_threshold: this.getConfig<number>('low_stock_threshold', 10),
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
export function createSkill(config?: SkillConfig): InventorySkill {
|
|
672
|
+
return new InventorySkill(config);
|
|
673
|
+
}
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
### SkillBase Methods Reference
|
|
677
|
+
|
|
678
|
+
| Method | Required | Description |
|
|
679
|
+
|---|---|---|
|
|
680
|
+
| `getManifest()` | Yes (abstract) | Returns the skill manifest with name, description, version, env vars, and config schema |
|
|
681
|
+
| `getTools()` | Yes (abstract) | Returns array of SWAIG tool definitions to register with the agent |
|
|
682
|
+
| `setup()` | No | Async initialization hook called when the skill is added to an agent |
|
|
683
|
+
| `cleanup()` | No | Async teardown hook called when the skill is removed |
|
|
684
|
+
| `getPromptSections()` | No | Returns prompt sections injected into the agent's system prompt |
|
|
685
|
+
| `getHints()` | No | Returns speech recognition hint strings |
|
|
686
|
+
| `getGlobalData()` | No | Returns key-value data merged into the agent's global data store |
|
|
687
|
+
| `validateEnvVars()` | No | Checks required env vars from manifest; returns array of missing names |
|
|
688
|
+
| `getConfig(key, default)` | No | Reads a configuration value with type-safe default |
|
|
689
|
+
| `isInitialized()` | No | Returns whether `setup()` has completed |
|
|
690
|
+
|
|
691
|
+
### SkillToolDefinition Fields
|
|
692
|
+
|
|
693
|
+
| Field | Type | Required | Description |
|
|
694
|
+
|---|---|---|---|
|
|
695
|
+
| `name` | `string` | Yes | Unique tool name for SWAIG function registration |
|
|
696
|
+
| `description` | `string` | Yes | Human-readable description shown to the AI |
|
|
697
|
+
| `parameters` | `Record<string, unknown>` | No | Parameter schema keyed by parameter name |
|
|
698
|
+
| `handler` | `SwaigHandler` | Yes | Function invoked when the tool is called |
|
|
699
|
+
| `secure` | `boolean` | No | Whether the tool requires authenticated invocation |
|
|
700
|
+
| `fillers` | `Record<string, string[]>` | No | Filler phrases spoken while the tool executes, keyed by language |
|
|
701
|
+
| `required` | `string[]` | No | List of required parameter names |
|
|
702
|
+
|
|
703
|
+
### SkillPromptSection Fields
|
|
704
|
+
|
|
705
|
+
| Field | Type | Required | Description |
|
|
706
|
+
|---|---|---|---|
|
|
707
|
+
| `title` | `string` | Yes | Section heading displayed in the prompt |
|
|
708
|
+
| `body` | `string` | No | Body text for the section |
|
|
709
|
+
| `bullets` | `string[]` | No | Bullet points appended after the body |
|
|
710
|
+
| `numbered` | `boolean` | No | If true, render bullets as a numbered list |
|
|
711
|
+
|
|
712
|
+
---
|
|
713
|
+
|
|
714
|
+
## Skill Lifecycle
|
|
715
|
+
|
|
716
|
+
The lifecycle of a skill follows these phases:
|
|
717
|
+
|
|
718
|
+
```
|
|
719
|
+
Construction -> setup() -> register tools/prompts/hints -> active use -> cleanup()
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
### 1. Construction
|
|
723
|
+
|
|
724
|
+
The skill is instantiated with a name and optional config. The `instanceId` is generated automatically (combination of skill name, timestamp, and random bytes):
|
|
725
|
+
|
|
726
|
+
```typescript
|
|
727
|
+
const skill = new DateTimeSkill({ /* config */ });
|
|
728
|
+
// skill.skillName === 'datetime'
|
|
729
|
+
// skill.instanceId === 'datetime-m2abc123-deadbeef'
|
|
730
|
+
// skill.isInitialized() === false
|
|
731
|
+
```
|
|
732
|
+
|
|
733
|
+
### 2. Setup
|
|
734
|
+
|
|
735
|
+
When `agent.addSkill(skill)` is called, the `SkillManager`:
|
|
736
|
+
|
|
737
|
+
1. Checks for duplicate instance IDs.
|
|
738
|
+
2. Calls `skill.validateEnvVars()` and logs warnings for any missing environment variables.
|
|
739
|
+
3. Calls `await skill.setup()` for async initialization.
|
|
740
|
+
4. Calls `skill.markInitialized()`.
|
|
741
|
+
|
|
742
|
+
```typescript
|
|
743
|
+
// Inside a custom skill
|
|
744
|
+
async setup(): Promise<void> {
|
|
745
|
+
// Connect to databases, validate API keys, pre-load data, etc.
|
|
746
|
+
const apiKey = process.env['MY_API_KEY'];
|
|
747
|
+
if (!apiKey) throw new Error('API key is required');
|
|
748
|
+
this.client = await connectToService(apiKey);
|
|
749
|
+
}
|
|
750
|
+
```
|
|
751
|
+
|
|
752
|
+
### 3. Registration
|
|
753
|
+
|
|
754
|
+
After setup, the agent registers the skill's contributions:
|
|
755
|
+
|
|
756
|
+
- **Tools** from `getTools()` are registered via `agent.defineTool()`.
|
|
757
|
+
- **Prompt sections** from `getPromptSections()` are injected via `agent.promptAddSection()`.
|
|
758
|
+
- **Hints** from `getHints()` are added via `agent.addHints()`.
|
|
759
|
+
- **Global data** from `getGlobalData()` is merged via `agent.updateGlobalData()`.
|
|
760
|
+
|
|
761
|
+
### 4. Active Use
|
|
762
|
+
|
|
763
|
+
The skill is now active. Its tools are called by the AI during conversations. The skill instance remains in memory for the lifetime of the agent.
|
|
764
|
+
|
|
765
|
+
### 5. Cleanup
|
|
766
|
+
|
|
767
|
+
When `agent.removeSkill(instanceId)` is called (or the SkillManager is cleared), the skill's `cleanup()` method is invoked:
|
|
768
|
+
|
|
769
|
+
```typescript
|
|
770
|
+
async cleanup(): Promise<void> {
|
|
771
|
+
// Close connections, release resources, flush caches
|
|
772
|
+
await this.client.disconnect();
|
|
773
|
+
}
|
|
774
|
+
```
|
|
775
|
+
|
|
776
|
+
The `SkillManager.clear()` method calls `cleanup()` on all loaded skills and removes them all.
|
|
777
|
+
|
|
778
|
+
---
|
|
779
|
+
|
|
780
|
+
## Environment Validation
|
|
781
|
+
|
|
782
|
+
Skills can declare required environment variables in their manifest. The `validateEnvVars()` method checks which ones are missing.
|
|
783
|
+
|
|
784
|
+
### In the Manifest
|
|
785
|
+
|
|
786
|
+
```typescript
|
|
787
|
+
getManifest(): SkillManifest {
|
|
788
|
+
return {
|
|
789
|
+
name: 'my_api_skill',
|
|
790
|
+
description: 'Integrates with My API.',
|
|
791
|
+
version: '1.0.0',
|
|
792
|
+
requiredEnvVars: ['MY_API_KEY', 'MY_API_SECRET'],
|
|
793
|
+
};
|
|
794
|
+
}
|
|
795
|
+
```
|
|
796
|
+
|
|
797
|
+
### Automatic Validation
|
|
798
|
+
|
|
799
|
+
When `addSkill()` is called, the `SkillManager` automatically validates env vars and logs warnings for any that are missing. The skill is still added even if env vars are missing -- it is up to the skill's handler to return appropriate error messages at call time.
|
|
800
|
+
|
|
801
|
+
### Manual Validation
|
|
802
|
+
|
|
803
|
+
```typescript
|
|
804
|
+
const skill = new WebSearchSkill();
|
|
805
|
+
const missing = skill.validateEnvVars();
|
|
806
|
+
|
|
807
|
+
if (missing.length > 0) {
|
|
808
|
+
console.warn(`Missing env vars: ${missing.join(', ')}`);
|
|
809
|
+
}
|
|
810
|
+
// missing might be ['GOOGLE_SEARCH_API_KEY', 'GOOGLE_SEARCH_CX']
|
|
811
|
+
```
|
|
812
|
+
|
|
813
|
+
### Runtime Handling
|
|
814
|
+
|
|
815
|
+
Built-in skills check for environment variables at call time and return user-friendly error messages:
|
|
816
|
+
|
|
817
|
+
```typescript
|
|
818
|
+
// Inside a tool handler
|
|
819
|
+
const apiKey = process.env['GOOGLE_SEARCH_API_KEY'];
|
|
820
|
+
if (!apiKey) {
|
|
821
|
+
return new SwaigFunctionResult(
|
|
822
|
+
'Web search is not configured. The GOOGLE_SEARCH_API_KEY environment variable is required.'
|
|
823
|
+
);
|
|
824
|
+
}
|
|
825
|
+
```
|
|
826
|
+
|
|
827
|
+
This two-layer approach (warn at registration, error at call time) allows agents to start up even when some skills are not fully configured, while providing clear feedback when an unconfigured tool is invoked.
|
|
828
|
+
|
|
829
|
+
---
|
|
830
|
+
|
|
831
|
+
## Complete Environment Variables Reference
|
|
832
|
+
|
|
833
|
+
| Env Var | Used By |
|
|
834
|
+
|---|---|
|
|
835
|
+
| `WEATHER_API_KEY` | `weather_api` |
|
|
836
|
+
| `API_NINJAS_KEY` | `api_ninjas_trivia` |
|
|
837
|
+
| `GOOGLE_SEARCH_API_KEY` | `web_search` |
|
|
838
|
+
| `GOOGLE_SEARCH_CX` | `web_search` |
|
|
839
|
+
| `GOOGLE_MAPS_API_KEY` | `google_maps` |
|
|
840
|
+
| `SIGNALWIRE_PROJECT_ID` | `datasphere`, `datasphere_serverless` |
|
|
841
|
+
| `SIGNALWIRE_TOKEN` | `datasphere`, `datasphere_serverless` |
|
|
842
|
+
| `SIGNALWIRE_SPACE` | `datasphere`, `datasphere_serverless` |
|
|
843
|
+
| `SPIDER_API_KEY` | `spider` |
|
|
844
|
+
| `ANTHROPIC_API_KEY` | `claude_skills` |
|
|
845
|
+
| `SIGNALWIRE_SKILL_PATHS` | `SkillRegistry` (directory discovery) |
|