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,787 @@
|
|
|
1
|
+
# Contexts & Steps Guide
|
|
2
|
+
|
|
3
|
+
Complete guide to building multi-step conversation workflows using the Contexts & Steps system in the SignalWire AI Agents TypeScript SDK.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
1. [Overview](#overview)
|
|
10
|
+
2. [Creating Contexts](#creating-contexts)
|
|
11
|
+
3. [Steps](#steps)
|
|
12
|
+
4. [Step Navigation](#step-navigation)
|
|
13
|
+
5. [Function Control](#function-control)
|
|
14
|
+
6. [End States](#end-states)
|
|
15
|
+
7. [GatherInfo](#gatherinfo)
|
|
16
|
+
8. [Context Settings](#context-settings)
|
|
17
|
+
9. [Isolation and Reset](#isolation-and-reset)
|
|
18
|
+
10. [Fillers](#fillers)
|
|
19
|
+
11. [Validation](#validation)
|
|
20
|
+
12. [Real-World Example](#real-world-example)
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Overview
|
|
25
|
+
|
|
26
|
+
The Contexts & Steps system provides a **state machine** for structuring multi-step AI conversations. Instead of a single flat prompt, you define a graph of **contexts** that each contain ordered **steps**. The AI navigates through these steps based on completion criteria, enabling complex branching workflows such as customer intake, troubleshooting trees, or multi-department routing.
|
|
27
|
+
|
|
28
|
+
**Key concepts:**
|
|
29
|
+
|
|
30
|
+
- **Context** -- A named group of ordered steps with its own prompt, system prompt, navigation rules, and isolation settings. Think of it as a "page" or "scene" in the conversation.
|
|
31
|
+
- **Step** -- A single stage within a context. Each step has prompt text (raw text or POM sections), completion criteria, function restrictions, and rules about which steps or contexts the AI can move to next.
|
|
32
|
+
- **ContextBuilder** -- The top-level builder that holds all contexts, validates cross-references, and serializes everything to SWML output.
|
|
33
|
+
|
|
34
|
+
The classes involved are:
|
|
35
|
+
|
|
36
|
+
| Class | Role |
|
|
37
|
+
|---|---|
|
|
38
|
+
| `ContextBuilder` | Top-level container; holds and validates all contexts |
|
|
39
|
+
| `Context` | A named context with steps, prompts, fillers, and navigation rules |
|
|
40
|
+
| `Step` | A single step within a context, with text, criteria, and function control |
|
|
41
|
+
| `GatherInfo` | Structured data collection attached to a step |
|
|
42
|
+
| `GatherQuestion` | A single question within a GatherInfo operation |
|
|
43
|
+
|
|
44
|
+
All classes are exported from `src/ContextBuilder.ts`.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Creating Contexts
|
|
49
|
+
|
|
50
|
+
### Using `agent.defineContexts()`
|
|
51
|
+
|
|
52
|
+
The primary entry point is the `defineContexts()` method on `AgentBase`. It returns a `ContextBuilder` that you use to add contexts.
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
import { AgentBase } from 'signalwire-agents';
|
|
56
|
+
|
|
57
|
+
const agent = new AgentBase({ name: 'my-agent' });
|
|
58
|
+
|
|
59
|
+
// Create and get the ContextBuilder
|
|
60
|
+
const cb = agent.defineContexts();
|
|
61
|
+
|
|
62
|
+
// Add contexts to the builder
|
|
63
|
+
const greeting = cb.addContext('greeting');
|
|
64
|
+
const support = cb.addContext('support');
|
|
65
|
+
const farewell = cb.addContext('farewell');
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
You can also pass an existing `ContextBuilder` instance:
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
import { ContextBuilder } from 'signalwire-agents';
|
|
72
|
+
|
|
73
|
+
const cb = new ContextBuilder();
|
|
74
|
+
cb.addContext('default');
|
|
75
|
+
// ... configure ...
|
|
76
|
+
|
|
77
|
+
agent.defineContexts(cb);
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Using `ContextBuilder.addContext()`
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
const cb = new ContextBuilder();
|
|
84
|
+
|
|
85
|
+
// Returns the new Context instance for chaining
|
|
86
|
+
const ctx = cb.addContext('intake');
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Context names must be unique within a builder. Adding a duplicate name throws an error.
|
|
90
|
+
|
|
91
|
+
### Retrieving a Context
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
const ctx = cb.getContext('intake');
|
|
95
|
+
if (ctx) {
|
|
96
|
+
// configure further
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Single-Context Rule
|
|
101
|
+
|
|
102
|
+
When using only one context, it **must** be named `'default'`. The validator enforces this:
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
// Valid: single context named "default"
|
|
106
|
+
const cb = new ContextBuilder();
|
|
107
|
+
cb.addContext('default');
|
|
108
|
+
|
|
109
|
+
// Invalid: single context with any other name
|
|
110
|
+
const bad = new ContextBuilder();
|
|
111
|
+
bad.addContext('main'); // validate() will throw
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Helper: `createSimpleContext()`
|
|
115
|
+
|
|
116
|
+
For the common single-context case, a standalone helper is available:
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
import { createSimpleContext } from 'signalwire-agents';
|
|
120
|
+
|
|
121
|
+
const ctx = createSimpleContext(); // name defaults to 'default'
|
|
122
|
+
const step = ctx.addStep('welcome');
|
|
123
|
+
step.setText('Welcome to our service!');
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Steps
|
|
129
|
+
|
|
130
|
+
Steps are the building blocks of a context. They are ordered -- the AI processes them in the order they were added.
|
|
131
|
+
|
|
132
|
+
### Adding a Step
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
const ctx = cb.addContext('intake');
|
|
136
|
+
|
|
137
|
+
// Basic: returns the Step for further configuration
|
|
138
|
+
const step1 = ctx.addStep('greet');
|
|
139
|
+
step1.setText('Greet the customer warmly.');
|
|
140
|
+
|
|
141
|
+
// Shorthand: pass options inline
|
|
142
|
+
const step2 = ctx.addStep('collect_info', {
|
|
143
|
+
task: 'Collect the customer name and account number.',
|
|
144
|
+
bullets: ['Ask for full name first', 'Then ask for account number'],
|
|
145
|
+
criteria: 'Customer has provided both name and account number.',
|
|
146
|
+
functions: ['lookup_account'],
|
|
147
|
+
validSteps: ['verify'],
|
|
148
|
+
});
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
The shorthand options map to:
|
|
152
|
+
|
|
153
|
+
| Option | Effect |
|
|
154
|
+
|---|---|
|
|
155
|
+
| `task` | Calls `step.addSection('Task', task)` |
|
|
156
|
+
| `bullets` | Calls `step.addBullets('Process', bullets)` |
|
|
157
|
+
| `criteria` | Calls `step.setStepCriteria(criteria)` |
|
|
158
|
+
| `functions` | Calls `step.setFunctions(functions)` |
|
|
159
|
+
| `validSteps` | Calls `step.setValidSteps(validSteps)` |
|
|
160
|
+
|
|
161
|
+
Step names must be unique within a context. Adding a duplicate throws an error.
|
|
162
|
+
|
|
163
|
+
### Step Content: `setText()` vs POM Sections
|
|
164
|
+
|
|
165
|
+
There are two mutually exclusive ways to define step content:
|
|
166
|
+
|
|
167
|
+
**Raw text:**
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
step.setText('You are greeting the customer. Be friendly and professional.');
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**POM (Prompt Object Model) sections:**
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
step.addSection('Task', 'Help the customer with their billing inquiry.');
|
|
177
|
+
step.addBullets('Guidelines', [
|
|
178
|
+
'Be empathetic and patient',
|
|
179
|
+
'Verify identity before sharing account details',
|
|
180
|
+
'Offer to escalate if needed',
|
|
181
|
+
]);
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
You cannot mix `setText()` with `addSection()`/`addBullets()` on the same step -- doing so throws an error.
|
|
185
|
+
|
|
186
|
+
POM sections render as markdown:
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
## Task
|
|
190
|
+
Help the customer with their billing inquiry.
|
|
191
|
+
|
|
192
|
+
## Guidelines
|
|
193
|
+
- Be empathetic and patient
|
|
194
|
+
- Verify identity before sharing account details
|
|
195
|
+
- Offer to escalate if needed
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Managing Steps
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
// Retrieve a step by name
|
|
202
|
+
const step = ctx.getStep('greet');
|
|
203
|
+
|
|
204
|
+
// Remove a step
|
|
205
|
+
ctx.removeStep('greet');
|
|
206
|
+
|
|
207
|
+
// Move a step to a new position (zero-indexed)
|
|
208
|
+
ctx.moveStep('verify', 0); // Move "verify" to the beginning
|
|
209
|
+
|
|
210
|
+
// Clear all content from a step (sections + text)
|
|
211
|
+
step.clearSections();
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## Step Navigation
|
|
217
|
+
|
|
218
|
+
Navigation rules control which steps and contexts the AI can move to from a given step.
|
|
219
|
+
|
|
220
|
+
### `setValidSteps()`
|
|
221
|
+
|
|
222
|
+
Restricts the AI to navigating only to the listed steps within the current context:
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
step.setValidSteps(['collect_info', 'verify', 'escalate']);
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### `setValidContexts()`
|
|
229
|
+
|
|
230
|
+
Allows the AI to switch to a different context entirely:
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
step.setValidContexts(['billing', 'technical_support', 'farewell']);
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### `setStepCriteria()`
|
|
237
|
+
|
|
238
|
+
Defines a natural-language description of what must happen before the AI considers this step complete:
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
step.setStepCriteria(
|
|
242
|
+
'The customer has confirmed their name, account number, and the nature of their issue.'
|
|
243
|
+
);
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
The AI uses this text to judge when it should advance to the next step.
|
|
247
|
+
|
|
248
|
+
### Context-Level Navigation
|
|
249
|
+
|
|
250
|
+
Contexts themselves can also define navigation rules:
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
const billing = cb.addContext('billing');
|
|
254
|
+
billing.setValidContexts(['technical_support', 'farewell']);
|
|
255
|
+
billing.setValidSteps(['step_a', 'step_b']);
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## Function Control
|
|
261
|
+
|
|
262
|
+
Each step can restrict which SWAIG functions (tools) are available during that step. This prevents the AI from calling tools that are irrelevant or potentially harmful at that stage.
|
|
263
|
+
|
|
264
|
+
### `setFunctions()`
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
267
|
+
// Only specific functions are available
|
|
268
|
+
step.setFunctions(['lookup_account', 'get_balance']);
|
|
269
|
+
|
|
270
|
+
// All functions are available (explicit wildcard)
|
|
271
|
+
step.setFunctions('*');
|
|
272
|
+
|
|
273
|
+
// No functions available (disable all tools for this step)
|
|
274
|
+
step.setFunctions('none');
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
When not set (null), the step inherits whatever functions are available from the agent's global configuration.
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
## End States
|
|
282
|
+
|
|
283
|
+
### `setEnd()`
|
|
284
|
+
|
|
285
|
+
Marks a step as a terminal step. When the AI reaches this step, the conversation is considered complete:
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
const goodbye = ctx.addStep('goodbye');
|
|
289
|
+
goodbye.setText('Thank the customer and end the call.');
|
|
290
|
+
goodbye.setEnd(true);
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### `setSkipUserTurn()`
|
|
294
|
+
|
|
295
|
+
When set to `true`, the AI does not wait for user input when entering this step. Useful for automatic transitions:
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
const transition = ctx.addStep('auto_transfer');
|
|
299
|
+
transition.setText('Transfer the call to the billing department.');
|
|
300
|
+
transition.setSkipUserTurn(true);
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### `setSkipToNextStep()`
|
|
304
|
+
|
|
305
|
+
When set to `true`, the AI automatically advances to the next step in order after completing the current one:
|
|
306
|
+
|
|
307
|
+
```typescript
|
|
308
|
+
const intro = ctx.addStep('intro');
|
|
309
|
+
intro.setText('Provide a brief introduction.');
|
|
310
|
+
intro.setSkipToNextStep(true);
|
|
311
|
+
|
|
312
|
+
const main = ctx.addStep('main');
|
|
313
|
+
main.setText('Now handle the main request.');
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## GatherInfo
|
|
319
|
+
|
|
320
|
+
The `GatherInfo` system provides structured data collection within a step. It defines a series of questions with typed answers, optional confirmation, and per-question function access.
|
|
321
|
+
|
|
322
|
+
### Setting Up GatherInfo
|
|
323
|
+
|
|
324
|
+
First initialize the gather operation on a step, then add questions:
|
|
325
|
+
|
|
326
|
+
```typescript
|
|
327
|
+
const step = ctx.addStep('collect_details');
|
|
328
|
+
step.setText('Collect the customer contact details.');
|
|
329
|
+
|
|
330
|
+
step.setGatherInfo({
|
|
331
|
+
outputKey: 'customer_info',
|
|
332
|
+
completionAction: 'proceed_to_verify',
|
|
333
|
+
prompt: 'Please collect the following information from the customer.',
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
step.addGatherQuestion({
|
|
337
|
+
key: 'full_name',
|
|
338
|
+
question: 'What is your full name?',
|
|
339
|
+
type: 'string',
|
|
340
|
+
confirm: true,
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
step.addGatherQuestion({
|
|
344
|
+
key: 'email',
|
|
345
|
+
question: 'What is your email address?',
|
|
346
|
+
type: 'string',
|
|
347
|
+
confirm: true,
|
|
348
|
+
prompt: 'Please spell out the email address carefully.',
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
step.addGatherQuestion({
|
|
352
|
+
key: 'phone',
|
|
353
|
+
question: 'What is your phone number?',
|
|
354
|
+
type: 'string',
|
|
355
|
+
confirm: false,
|
|
356
|
+
functions: ['validate_phone'],
|
|
357
|
+
});
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
You **must** call `setGatherInfo()` before calling `addGatherQuestion()`, or an error is thrown.
|
|
361
|
+
|
|
362
|
+
### GatherInfo Options
|
|
363
|
+
|
|
364
|
+
| Option | Type | Description |
|
|
365
|
+
|---|---|---|
|
|
366
|
+
| `outputKey` | `string` | Key under which the gathered data is stored |
|
|
367
|
+
| `completionAction` | `string` | Action name to execute after all questions are answered |
|
|
368
|
+
| `prompt` | `string` | Additional prompt context for the gather operation |
|
|
369
|
+
|
|
370
|
+
### GatherQuestion Options
|
|
371
|
+
|
|
372
|
+
| Option | Type | Default | Description |
|
|
373
|
+
|---|---|---|---|
|
|
374
|
+
| `key` | `string` | (required) | Unique key for storing the answer |
|
|
375
|
+
| `question` | `string` | (required) | The question text presented to the user |
|
|
376
|
+
| `type` | `string` | `'string'` | Expected answer type (e.g., `'string'`, `'number'`) |
|
|
377
|
+
| `confirm` | `boolean` | `false` | Whether to ask the user to confirm their answer |
|
|
378
|
+
| `prompt` | `string` | -- | Additional prompt context for this specific question |
|
|
379
|
+
| `functions` | `string[]` | -- | SWAIG function names available during this question |
|
|
380
|
+
|
|
381
|
+
### GatherInfo Serialization
|
|
382
|
+
|
|
383
|
+
The `GatherInfo.toDict()` method produces SWML output like:
|
|
384
|
+
|
|
385
|
+
```json
|
|
386
|
+
{
|
|
387
|
+
"questions": [
|
|
388
|
+
{ "key": "full_name", "question": "What is your full name?", "confirm": true },
|
|
389
|
+
{ "key": "email", "question": "What is your email address?", "confirm": true, "prompt": "Please spell out the email address carefully." },
|
|
390
|
+
{ "key": "phone", "question": "What is your phone number?", "functions": ["validate_phone"] }
|
|
391
|
+
],
|
|
392
|
+
"output_key": "customer_info",
|
|
393
|
+
"completion_action": "proceed_to_verify",
|
|
394
|
+
"prompt": "Please collect the following information from the customer."
|
|
395
|
+
}
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
Note: `type` defaults to `'string'` and is omitted from serialization when it has the default value. `confirm` is only emitted when `true`.
|
|
399
|
+
|
|
400
|
+
---
|
|
401
|
+
|
|
402
|
+
## Context Settings
|
|
403
|
+
|
|
404
|
+
### Prompt Configuration
|
|
405
|
+
|
|
406
|
+
Contexts have their own prompt layer, separate from step-level prompts. Like steps, you can use either raw text or POM sections.
|
|
407
|
+
|
|
408
|
+
**Raw prompt text:**
|
|
409
|
+
|
|
410
|
+
```typescript
|
|
411
|
+
const ctx = cb.addContext('billing');
|
|
412
|
+
ctx.setPrompt('You are handling a billing inquiry. Be precise with numbers.');
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
**POM prompt sections:**
|
|
416
|
+
|
|
417
|
+
```typescript
|
|
418
|
+
ctx.addSection('Role', 'You are a billing specialist for Acme Corp.');
|
|
419
|
+
ctx.addBullets('Guidelines', [
|
|
420
|
+
'Always verify the account before discussing charges',
|
|
421
|
+
'Be transparent about fees and credits',
|
|
422
|
+
'Offer payment plan options when appropriate',
|
|
423
|
+
]);
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
Raw text and POM sections are mutually exclusive at the context level.
|
|
427
|
+
|
|
428
|
+
### System Prompt
|
|
429
|
+
|
|
430
|
+
Override or extend the system prompt for a specific context:
|
|
431
|
+
|
|
432
|
+
**Raw system prompt:**
|
|
433
|
+
|
|
434
|
+
```typescript
|
|
435
|
+
ctx.setSystemPrompt('You are a helpful billing assistant. Be concise.');
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
**POM system prompt sections:**
|
|
439
|
+
|
|
440
|
+
```typescript
|
|
441
|
+
ctx.addSystemSection('Identity', 'You are Acme Corp billing support.');
|
|
442
|
+
ctx.addSystemBullets('Rules', [
|
|
443
|
+
'Never disclose internal pricing formulas',
|
|
444
|
+
'Always confirm before processing refunds',
|
|
445
|
+
]);
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
Raw system prompt and POM system sections are mutually exclusive.
|
|
449
|
+
|
|
450
|
+
### Post-Prompt
|
|
451
|
+
|
|
452
|
+
Set text appended after the main prompt for a context:
|
|
453
|
+
|
|
454
|
+
```typescript
|
|
455
|
+
ctx.setPostPrompt('Remember: always confirm before making account changes.');
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
### User Prompt
|
|
459
|
+
|
|
460
|
+
Set the initial user message when entering this context:
|
|
461
|
+
|
|
462
|
+
```typescript
|
|
463
|
+
ctx.setUserPrompt('I need help with my billing.');
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
---
|
|
467
|
+
|
|
468
|
+
## Isolation and Reset
|
|
469
|
+
|
|
470
|
+
These settings control how conversation history is handled when switching between contexts.
|
|
471
|
+
|
|
472
|
+
### `setIsolated()`
|
|
473
|
+
|
|
474
|
+
When `true`, this context does not share conversation history with other contexts. The AI starts fresh when entering this context:
|
|
475
|
+
|
|
476
|
+
```typescript
|
|
477
|
+
const secureCtx = cb.addContext('payment');
|
|
478
|
+
secureCtx.setIsolated(true);
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
### `setConsolidate()` (Context-Level)
|
|
482
|
+
|
|
483
|
+
When `true`, conversation history is summarized/consolidated when entering this context:
|
|
484
|
+
|
|
485
|
+
```typescript
|
|
486
|
+
ctx.setConsolidate(true);
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
### `setFullReset()` (Context-Level)
|
|
490
|
+
|
|
491
|
+
When `true`, conversation history is completely cleared when entering this context:
|
|
492
|
+
|
|
493
|
+
```typescript
|
|
494
|
+
ctx.setFullReset(true);
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
### Step-Level Reset Options
|
|
498
|
+
|
|
499
|
+
Individual steps can also trigger resets:
|
|
500
|
+
|
|
501
|
+
```typescript
|
|
502
|
+
const step = ctx.addStep('fresh_start');
|
|
503
|
+
|
|
504
|
+
// Replace the system prompt when entering this step
|
|
505
|
+
step.setResetSystemPrompt('You are now handling a refund request.');
|
|
506
|
+
|
|
507
|
+
// Replace the user prompt when entering this step
|
|
508
|
+
step.setResetUserPrompt('The customer wants a refund.');
|
|
509
|
+
|
|
510
|
+
// Consolidate conversation history at this step
|
|
511
|
+
step.setResetConsolidate(true);
|
|
512
|
+
|
|
513
|
+
// Perform a full conversation reset at this step
|
|
514
|
+
step.setResetFullReset(true);
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
The step-level reset options are serialized under a `reset` key in the SWML output:
|
|
518
|
+
|
|
519
|
+
```json
|
|
520
|
+
{
|
|
521
|
+
"name": "fresh_start",
|
|
522
|
+
"text": "...",
|
|
523
|
+
"reset": {
|
|
524
|
+
"system_prompt": "You are now handling a refund request.",
|
|
525
|
+
"user_prompt": "The customer wants a refund.",
|
|
526
|
+
"consolidate": true,
|
|
527
|
+
"full_reset": true
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
---
|
|
533
|
+
|
|
534
|
+
## Fillers
|
|
535
|
+
|
|
536
|
+
Filler phrases are spoken by the AI during context transitions to provide a natural conversational feel while the system processes the switch.
|
|
537
|
+
|
|
538
|
+
### Enter Fillers
|
|
539
|
+
|
|
540
|
+
Spoken when the AI enters this context:
|
|
541
|
+
|
|
542
|
+
```typescript
|
|
543
|
+
// Set all enter fillers at once (keyed by language code)
|
|
544
|
+
ctx.setEnterFillers({
|
|
545
|
+
'en-US': ['One moment please...', 'Let me connect you...'],
|
|
546
|
+
'es-ES': ['Un momento por favor...'],
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
// Add fillers for a single language
|
|
550
|
+
ctx.addEnterFiller('en-US', [
|
|
551
|
+
'Just a moment while I pull that up.',
|
|
552
|
+
'Let me check on that for you.',
|
|
553
|
+
]);
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
### Exit Fillers
|
|
557
|
+
|
|
558
|
+
Spoken when the AI leaves this context:
|
|
559
|
+
|
|
560
|
+
```typescript
|
|
561
|
+
ctx.setExitFillers({
|
|
562
|
+
'en-US': ['Alright, moving on...', 'Let me transfer you now.'],
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
ctx.addExitFiller('fr-FR', ['Un instant s\'il vous plait...']);
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
Fillers are serialized as `enter_fillers` and `exit_fillers` in the SWML output.
|
|
569
|
+
|
|
570
|
+
---
|
|
571
|
+
|
|
572
|
+
## Validation
|
|
573
|
+
|
|
574
|
+
The `ContextBuilder.validate()` method performs structural checks before serialization:
|
|
575
|
+
|
|
576
|
+
1. **At least one context must exist** -- throws if the builder is empty.
|
|
577
|
+
2. **Single-context naming** -- if only one context is defined, it must be named `'default'`.
|
|
578
|
+
3. **Steps required** -- every context must have at least one step.
|
|
579
|
+
4. **Cross-context references** -- any context name referenced in `setValidContexts()` must actually exist in the builder.
|
|
580
|
+
|
|
581
|
+
```typescript
|
|
582
|
+
const cb = new ContextBuilder();
|
|
583
|
+
const ctx = cb.addContext('default');
|
|
584
|
+
ctx.addStep('welcome').setText('Hello!');
|
|
585
|
+
|
|
586
|
+
// Explicit validation
|
|
587
|
+
cb.validate(); // throws if invalid
|
|
588
|
+
|
|
589
|
+
// Implicit validation on serialization
|
|
590
|
+
const swml = cb.toDict(); // calls validate() internally
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
### Common Validation Errors
|
|
594
|
+
|
|
595
|
+
| Error | Cause |
|
|
596
|
+
|---|---|
|
|
597
|
+
| `At least one context must be defined` | No contexts were added |
|
|
598
|
+
| `When using a single context, it must be named 'default'` | One context exists but is not named `'default'` |
|
|
599
|
+
| `Context 'X' must have at least one step` | A context has no steps |
|
|
600
|
+
| `Context 'X' references unknown context 'Y'` | `setValidContexts()` refers to a context name that does not exist |
|
|
601
|
+
| `Step 'X' has no text or POM sections defined` | A step has neither `setText()` nor `addSection()`/`addBullets()` |
|
|
602
|
+
|
|
603
|
+
---
|
|
604
|
+
|
|
605
|
+
## Real-World Example
|
|
606
|
+
|
|
607
|
+
A complete customer service agent with three contexts: greeting, troubleshooting, and resolution.
|
|
608
|
+
|
|
609
|
+
```typescript
|
|
610
|
+
import { AgentBase, ContextBuilder } from 'signalwire-agents';
|
|
611
|
+
|
|
612
|
+
const agent = new AgentBase({
|
|
613
|
+
name: 'customer-service',
|
|
614
|
+
prompt: { text: 'You are a helpful customer service agent for TechCo.' },
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
// Define the tools
|
|
618
|
+
agent.defineTool({
|
|
619
|
+
name: 'lookup_account',
|
|
620
|
+
description: 'Look up a customer account by account number.',
|
|
621
|
+
parameters: {
|
|
622
|
+
account_number: { type: 'string', description: 'The customer account number.' },
|
|
623
|
+
},
|
|
624
|
+
handler: async (args) => {
|
|
625
|
+
// ... account lookup logic
|
|
626
|
+
return { response: `Account found: ${args.account_number}` };
|
|
627
|
+
},
|
|
628
|
+
});
|
|
629
|
+
|
|
630
|
+
agent.defineTool({
|
|
631
|
+
name: 'create_ticket',
|
|
632
|
+
description: 'Create a support ticket for the customer.',
|
|
633
|
+
parameters: {
|
|
634
|
+
issue: { type: 'string', description: 'Description of the issue.' },
|
|
635
|
+
priority: { type: 'string', description: 'Ticket priority: low, medium, high.' },
|
|
636
|
+
},
|
|
637
|
+
handler: async (args) => {
|
|
638
|
+
return { response: `Ticket created: ${args.issue} (${args.priority})` };
|
|
639
|
+
},
|
|
640
|
+
});
|
|
641
|
+
|
|
642
|
+
agent.defineTool({
|
|
643
|
+
name: 'process_refund',
|
|
644
|
+
description: 'Process a refund for a customer.',
|
|
645
|
+
parameters: {
|
|
646
|
+
amount: { type: 'number', description: 'Refund amount in dollars.' },
|
|
647
|
+
reason: { type: 'string', description: 'Reason for the refund.' },
|
|
648
|
+
},
|
|
649
|
+
handler: async (args) => {
|
|
650
|
+
return { response: `Refund of $${args.amount} processed.` };
|
|
651
|
+
},
|
|
652
|
+
});
|
|
653
|
+
|
|
654
|
+
// Build the conversation flow
|
|
655
|
+
const cb = agent.defineContexts();
|
|
656
|
+
|
|
657
|
+
// ── Context 1: Greeting ──────────────────────────────────────────────
|
|
658
|
+
const greeting = cb.addContext('greeting');
|
|
659
|
+
greeting.addEnterFiller('en-US', [
|
|
660
|
+
'Welcome! Let me help you today.',
|
|
661
|
+
]);
|
|
662
|
+
greeting.setValidContexts(['troubleshooting', 'resolution']);
|
|
663
|
+
|
|
664
|
+
const welcome = greeting.addStep('welcome', {
|
|
665
|
+
task: 'Greet the customer warmly and ask how you can help today.',
|
|
666
|
+
criteria: 'The customer has stated the nature of their issue.',
|
|
667
|
+
functions: 'none',
|
|
668
|
+
validSteps: ['identify'],
|
|
669
|
+
});
|
|
670
|
+
|
|
671
|
+
const identify = greeting.addStep('identify', {
|
|
672
|
+
task: 'Verify the customer identity by asking for their account number.',
|
|
673
|
+
criteria: 'Account has been looked up and verified.',
|
|
674
|
+
functions: ['lookup_account'],
|
|
675
|
+
validSteps: ['route'],
|
|
676
|
+
});
|
|
677
|
+
|
|
678
|
+
const route = greeting.addStep('route');
|
|
679
|
+
route.addSection('Task', 'Determine the appropriate department for the customer issue.');
|
|
680
|
+
route.addBullets('Routing Rules', [
|
|
681
|
+
'Technical issues (connectivity, hardware, software) -> troubleshooting context',
|
|
682
|
+
'Billing, refunds, or account changes -> resolution context',
|
|
683
|
+
'If unclear, ask a clarifying question before routing',
|
|
684
|
+
]);
|
|
685
|
+
route.setStepCriteria('The issue category has been determined.');
|
|
686
|
+
route.setValidContexts(['troubleshooting', 'resolution']);
|
|
687
|
+
route.setFunctions('none');
|
|
688
|
+
|
|
689
|
+
// ── Context 2: Troubleshooting ───────────────────────────────────────
|
|
690
|
+
const troubleshooting = cb.addContext('troubleshooting');
|
|
691
|
+
troubleshooting.setConsolidate(true);
|
|
692
|
+
troubleshooting.addEnterFiller('en-US', [
|
|
693
|
+
'Let me look into that technical issue for you.',
|
|
694
|
+
'One moment while I pull up our troubleshooting guide.',
|
|
695
|
+
]);
|
|
696
|
+
troubleshooting.setExitFillers({
|
|
697
|
+
'en-US': ['Let me get you to the right place.'],
|
|
698
|
+
});
|
|
699
|
+
troubleshooting.setValidContexts(['resolution']);
|
|
700
|
+
|
|
701
|
+
troubleshooting.addSystemSection('Role', 'You are a technical support specialist.');
|
|
702
|
+
troubleshooting.addSystemBullets('Approach', [
|
|
703
|
+
'Start with the simplest solution first',
|
|
704
|
+
'Ask the customer to confirm each step',
|
|
705
|
+
'Escalate to a ticket if three attempts fail',
|
|
706
|
+
]);
|
|
707
|
+
|
|
708
|
+
const diagnose = troubleshooting.addStep('diagnose');
|
|
709
|
+
diagnose.setText('Ask the customer to describe their technical issue in detail.');
|
|
710
|
+
diagnose.setStepCriteria('The specific technical problem is understood.');
|
|
711
|
+
diagnose.setValidSteps(['guided_fix', 'escalate']);
|
|
712
|
+
|
|
713
|
+
const guidedFix = troubleshooting.addStep('guided_fix');
|
|
714
|
+
guidedFix.addSection('Task', 'Walk the customer through step-by-step troubleshooting.');
|
|
715
|
+
guidedFix.addBullets('Steps', [
|
|
716
|
+
'Have the customer restart their device',
|
|
717
|
+
'Check network connectivity',
|
|
718
|
+
'Verify software is up to date',
|
|
719
|
+
'Try clearing the cache',
|
|
720
|
+
]);
|
|
721
|
+
guidedFix.setStepCriteria('The issue is resolved OR three troubleshooting steps have been attempted.');
|
|
722
|
+
guidedFix.setFunctions('none');
|
|
723
|
+
guidedFix.setValidSteps(['escalate']);
|
|
724
|
+
guidedFix.setValidContexts(['resolution']);
|
|
725
|
+
|
|
726
|
+
const escalate = troubleshooting.addStep('escalate');
|
|
727
|
+
escalate.addSection('Task', 'Create a support ticket for the unresolved issue.');
|
|
728
|
+
escalate.setStepCriteria('A support ticket has been created.');
|
|
729
|
+
escalate.setFunctions(['create_ticket']);
|
|
730
|
+
escalate.setValidContexts(['resolution']);
|
|
731
|
+
|
|
732
|
+
// ── Context 3: Resolution ────────────────────────────────────────────
|
|
733
|
+
const resolution = cb.addContext('resolution');
|
|
734
|
+
resolution.setIsolated(true);
|
|
735
|
+
resolution.addEnterFiller('en-US', [
|
|
736
|
+
'Let me wrap things up for you.',
|
|
737
|
+
]);
|
|
738
|
+
|
|
739
|
+
const summarize = resolution.addStep('summarize');
|
|
740
|
+
summarize.setText('Summarize what was accomplished during this call.');
|
|
741
|
+
summarize.setStepCriteria('A summary has been provided to the customer.');
|
|
742
|
+
summarize.setFunctions('none');
|
|
743
|
+
summarize.setValidSteps(['refund_check', 'goodbye']);
|
|
744
|
+
|
|
745
|
+
const refundCheck = resolution.addStep('refund_check');
|
|
746
|
+
refundCheck.addSection('Task', 'Determine if a refund or credit is appropriate.');
|
|
747
|
+
refundCheck.addBullets('Policy', [
|
|
748
|
+
'Refunds up to $50 can be issued immediately',
|
|
749
|
+
'Refunds over $50 require manager approval -- create a ticket instead',
|
|
750
|
+
'Always confirm the refund amount with the customer before processing',
|
|
751
|
+
]);
|
|
752
|
+
refundCheck.setStepCriteria('Refund has been processed or determined not applicable.');
|
|
753
|
+
refundCheck.setFunctions(['process_refund', 'create_ticket']);
|
|
754
|
+
refundCheck.setValidSteps(['goodbye']);
|
|
755
|
+
|
|
756
|
+
// Gather customer satisfaction info before ending
|
|
757
|
+
const goodbye = resolution.addStep('goodbye');
|
|
758
|
+
goodbye.setText('Thank the customer and collect feedback.');
|
|
759
|
+
goodbye.setGatherInfo({
|
|
760
|
+
outputKey: 'satisfaction',
|
|
761
|
+
prompt: 'Before we end, we would appreciate your feedback.',
|
|
762
|
+
});
|
|
763
|
+
goodbye.addGatherQuestion({
|
|
764
|
+
key: 'rating',
|
|
765
|
+
question: 'On a scale of 1-5, how would you rate your experience today?',
|
|
766
|
+
type: 'number',
|
|
767
|
+
confirm: true,
|
|
768
|
+
});
|
|
769
|
+
goodbye.addGatherQuestion({
|
|
770
|
+
key: 'comments',
|
|
771
|
+
question: 'Do you have any additional comments or suggestions?',
|
|
772
|
+
type: 'string',
|
|
773
|
+
confirm: false,
|
|
774
|
+
});
|
|
775
|
+
goodbye.setEnd(true);
|
|
776
|
+
|
|
777
|
+
// Start the server
|
|
778
|
+
agent.start();
|
|
779
|
+
```
|
|
780
|
+
|
|
781
|
+
### How This Flow Works
|
|
782
|
+
|
|
783
|
+
1. The conversation begins in the **greeting** context. The AI welcomes the customer, identifies them via account lookup, and routes them to the appropriate department.
|
|
784
|
+
2. Technical issues go to the **troubleshooting** context, which consolidates prior conversation history. The AI walks through diagnostic steps and can escalate by creating a ticket.
|
|
785
|
+
3. All paths eventually lead to the **resolution** context, which is isolated (fresh conversation history). It summarizes the call, optionally processes a refund, then collects satisfaction feedback before ending.
|
|
786
|
+
|
|
787
|
+
The `setValidContexts()` and `setValidSteps()` calls create explicit navigation boundaries, ensuring the AI cannot jump to inappropriate stages. Function restrictions via `setFunctions()` prevent the AI from calling tools at the wrong time -- for example, `process_refund` is only available during the `refund_check` step.
|