@absolutejs/voice 0.0.22-beta.208 → 0.0.22-beta.209
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/README.md +194 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -55,6 +55,200 @@ These are the primitive-first paths a Vapi-style buyer usually needs. Each path
|
|
|
55
55
|
| Evals and simulation | fixtures, eval routes, simulation suite, workflow/tool/outcome contracts, baselines | Prove flows before live traffic | Opaque hosted test runner |
|
|
56
56
|
| Data and compliance controls | file/SQLite/Postgres/S3 storage paths, redaction, retention, audit exports, guarded deletion | Show customer-owned storage and export proof | Legal certification or compliance attestation |
|
|
57
57
|
|
|
58
|
+
## Use-Case Recipe: Support Triage
|
|
59
|
+
|
|
60
|
+
Use this path when you want a Vapi-style support assistant that can answer web or phone calls, look up customer context, route billing issues to a specialist, create follow-up work, and leave one debuggable call record. It is a recipe over primitives, not a support app kit.
|
|
61
|
+
|
|
62
|
+
The production shape is:
|
|
63
|
+
|
|
64
|
+
1. Persist sessions, traces, reviews, tasks, integration events, and audit events in app-owned runtime storage.
|
|
65
|
+
2. Define server-side tools with idempotency and contract proof.
|
|
66
|
+
3. Compose support and billing specialists with `createVoiceAgentSquad(...)`.
|
|
67
|
+
4. Mount a browser route with `voice(...)` and optionally a phone route with `createVoicePhoneAgent(...)`.
|
|
68
|
+
5. Add outcome, readiness, simulation, audit, and operations-record routes so every failed proof links back to the call.
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
import { Elysia } from 'elysia';
|
|
72
|
+
import {
|
|
73
|
+
createVoiceAgent,
|
|
74
|
+
createVoiceAgentSquad,
|
|
75
|
+
createVoiceAgentTool,
|
|
76
|
+
createVoiceFileRuntimeStorage,
|
|
77
|
+
createVoiceOperationsRecordRoutes,
|
|
78
|
+
createVoiceProductionReadinessRoutes,
|
|
79
|
+
createVoiceSimulationSuiteRoutes,
|
|
80
|
+
createVoiceToolContractRoutes,
|
|
81
|
+
createVoiceToolRuntimeContractDefaults,
|
|
82
|
+
resolveVoiceOutcomeRecipe,
|
|
83
|
+
voice
|
|
84
|
+
} from '@absolutejs/voice';
|
|
85
|
+
import { deepgram } from '@absolutejs/voice-deepgram';
|
|
86
|
+
|
|
87
|
+
const runtime = createVoiceFileRuntimeStorage({
|
|
88
|
+
directory: '.voice-runtime/support-triage'
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const lookupCustomer = createVoiceAgentTool({
|
|
92
|
+
name: 'lookup_customer',
|
|
93
|
+
description: 'Look up a customer and their open support state.',
|
|
94
|
+
parameters: {
|
|
95
|
+
type: 'object',
|
|
96
|
+
properties: {
|
|
97
|
+
customerId: { type: 'string' }
|
|
98
|
+
},
|
|
99
|
+
required: ['customerId']
|
|
100
|
+
},
|
|
101
|
+
execute: async ({ args }) => ({
|
|
102
|
+
customerId: args.customerId,
|
|
103
|
+
plan: 'business',
|
|
104
|
+
openTickets: 1,
|
|
105
|
+
status: 'active'
|
|
106
|
+
})
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const support = createVoiceAgent({
|
|
110
|
+
id: 'support',
|
|
111
|
+
system: 'Triage the caller, use tools for account context, and hand billing questions to billing.',
|
|
112
|
+
tools: [lookupCustomer],
|
|
113
|
+
trace: runtime.traces,
|
|
114
|
+
model: {
|
|
115
|
+
async generate({ messages, tools }) {
|
|
116
|
+
const latest = messages.at(-1)?.content.toLowerCase() ?? '';
|
|
117
|
+
if (latest.includes('billing')) {
|
|
118
|
+
return {
|
|
119
|
+
assistantText: 'I am routing you to billing with the context so far.',
|
|
120
|
+
handoff: { reason: 'billing-request', targetAgentId: 'billing' }
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
assistantText: `I can help with that. I can also use ${tools.map((tool) => tool.name).join(', ')} when I need account context.`
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
const billing = createVoiceAgent({
|
|
132
|
+
id: 'billing',
|
|
133
|
+
system: 'Handle billing questions and escalate refund or cancellation risk.',
|
|
134
|
+
trace: runtime.traces,
|
|
135
|
+
model: {
|
|
136
|
+
async generate() {
|
|
137
|
+
return {
|
|
138
|
+
assistantText: 'I can help with billing. I have the handoff context from support.'
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
const supportDesk = createVoiceAgentSquad({
|
|
145
|
+
id: 'support-desk',
|
|
146
|
+
defaultAgentId: 'support',
|
|
147
|
+
agents: [support, billing],
|
|
148
|
+
trace: runtime.traces,
|
|
149
|
+
handoffPolicy: ({ handoff }) =>
|
|
150
|
+
handoff.targetAgentId === 'billing'
|
|
151
|
+
? {
|
|
152
|
+
summary: 'Billing specialist receives the support summary and current caller intent.',
|
|
153
|
+
metadata: { queue: 'billing' }
|
|
154
|
+
}
|
|
155
|
+
: {
|
|
156
|
+
allow: false,
|
|
157
|
+
reason: 'Only billing handoffs are approved in this recipe.',
|
|
158
|
+
escalate: { reason: 'unsupported-specialist' }
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
const toolContractDefinitions = [
|
|
163
|
+
{
|
|
164
|
+
id: 'lookup-customer-contract',
|
|
165
|
+
label: 'Lookup customer returns support state',
|
|
166
|
+
tool: lookupCustomer,
|
|
167
|
+
cases: [
|
|
168
|
+
{
|
|
169
|
+
id: 'active-business-customer',
|
|
170
|
+
args: { customerId: 'cus_123' },
|
|
171
|
+
expect: {
|
|
172
|
+
expectedResult: {
|
|
173
|
+
customerId: 'cus_123',
|
|
174
|
+
openTickets: 1,
|
|
175
|
+
plan: 'business',
|
|
176
|
+
status: 'active'
|
|
177
|
+
},
|
|
178
|
+
expectStatus: 'ok'
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
],
|
|
182
|
+
defaultRuntime: createVoiceToolRuntimeContractDefaults()
|
|
183
|
+
}
|
|
184
|
+
];
|
|
185
|
+
|
|
186
|
+
const app = new Elysia()
|
|
187
|
+
.use(
|
|
188
|
+
voice({
|
|
189
|
+
path: '/voice/support',
|
|
190
|
+
preset: 'reliability',
|
|
191
|
+
session: runtime.session,
|
|
192
|
+
stt: deepgram({
|
|
193
|
+
apiKey: process.env.DEEPGRAM_API_KEY!,
|
|
194
|
+
model: 'flux-general-en'
|
|
195
|
+
}),
|
|
196
|
+
trace: runtime.traces,
|
|
197
|
+
onTurn: supportDesk.onTurn,
|
|
198
|
+
onComplete: async () => {},
|
|
199
|
+
ops: {
|
|
200
|
+
...resolveVoiceOutcomeRecipe('support-triage', {
|
|
201
|
+
assignee: 'support-oncall',
|
|
202
|
+
queue: 'support-triage'
|
|
203
|
+
}),
|
|
204
|
+
events: runtime.events,
|
|
205
|
+
reviews: runtime.reviews,
|
|
206
|
+
tasks: runtime.tasks
|
|
207
|
+
}
|
|
208
|
+
})
|
|
209
|
+
)
|
|
210
|
+
.use(
|
|
211
|
+
createVoiceToolContractRoutes({
|
|
212
|
+
contracts: toolContractDefinitions,
|
|
213
|
+
htmlPath: '/voice/support/tool-contracts',
|
|
214
|
+
path: '/api/voice/support/tool-contracts'
|
|
215
|
+
})
|
|
216
|
+
)
|
|
217
|
+
.use(
|
|
218
|
+
createVoiceSimulationSuiteRoutes({
|
|
219
|
+
htmlPath: '/voice/support/simulations',
|
|
220
|
+
path: '/api/voice/support/simulations',
|
|
221
|
+
tools: toolContractDefinitions,
|
|
222
|
+
operationsRecordHref: '/voice-operations/:sessionId'
|
|
223
|
+
})
|
|
224
|
+
)
|
|
225
|
+
.use(
|
|
226
|
+
createVoiceOperationsRecordRoutes({
|
|
227
|
+
htmlPath: '/voice-operations/:sessionId',
|
|
228
|
+
path: '/api/voice-operations/:sessionId',
|
|
229
|
+
store: runtime.traces,
|
|
230
|
+
reviews: runtime.reviews,
|
|
231
|
+
tasks: runtime.tasks,
|
|
232
|
+
integrationEvents: runtime.events
|
|
233
|
+
})
|
|
234
|
+
)
|
|
235
|
+
.use(
|
|
236
|
+
createVoiceProductionReadinessRoutes({
|
|
237
|
+
htmlPath: '/production-readiness',
|
|
238
|
+
path: '/api/production-readiness',
|
|
239
|
+
store: runtime.traces,
|
|
240
|
+
links: {
|
|
241
|
+
operationsRecords: '/voice-operations/:sessionId',
|
|
242
|
+
simulations: '/voice/support/simulations'
|
|
243
|
+
}
|
|
244
|
+
})
|
|
245
|
+
);
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
The demo UI should show a mic button, transcript, current specialist badge, readiness link, simulation link, and operations-record link. Use the framework helpers for that surface instead of embedding a dashboard: `VoiceAgentSquadStatus` in React, `useVoiceAgentSquadStatus(...)` in Vue, `createVoiceAgentSquadStatus(...)` in Svelte, `VoiceAgentSquadStatusService` in Angular, or `<absolute-voice-agent-squad-status>` for HTML/HTMX.
|
|
249
|
+
|
|
250
|
+
This recipe covers the hosted-platform expectations that matter for support triage: assistant entrypoint, business tools, specialist handoff, post-call task creation, simulation proof, tool contract proof, production readiness, audit-compatible runtime storage, and a call-log replacement at `/voice-operations/:sessionId`.
|
|
251
|
+
|
|
58
252
|
## How This Differs From Hosted Voice Platforms
|
|
59
253
|
|
|
60
254
|
Hosted voice-agent platforms are strongest when you want a managed dashboard, phone-number provisioning, hosted orchestration, and campaign tooling out of the box.
|