-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathframework-integration.ts
More file actions
82 lines (69 loc) · 2.34 KB
/
framework-integration.ts
File metadata and controls
82 lines (69 loc) · 2.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
/**
* Framework integration for Voice AI Agent.
*
* Mounts the VoiceApp WebSocket handler inside a standard Node.js HTTP server,
* allowing you to combine voice agent endpoints with REST routes.
* This pattern works with Express, Fastify, Koa, etc. — any framework that
* exposes the raw http.Server for the 'upgrade' event.
*
* Run:
* npx tsx examples/framework-integration.ts
*/
import { createServer, IncomingMessage, ServerResponse } from 'node:http';
import {
VoiceApp,
type AgentSessionStartedEvent,
type ToolCallEvent,
type AgentSessionEndedEvent,
} from '../src/index.js';
// -- VoiceApp --
const app = new VoiceApp();
app.onSetup((session, event) => {
const e = event as AgentSessionStartedEvent;
console.log(`Session started: ${e.agentSessionId}`);
});
app.onToolCall((session, event) => {
const e = event as ToolCallEvent;
console.log(`Tool call: ${e.name}(${JSON.stringify(e.arguments)})`);
if (e.name === 'check_weather') {
const city = (e.arguments as Record<string, unknown>).city ?? 'unknown';
session.sendToolResult(e.id, { city, temp_f: 72, condition: 'sunny' });
} else if (e.name === 'transfer_to_human') {
session.transfer(['+18005551234']);
session.sendToolResult(e.id, { status: 'transferring' });
} else {
session.sendToolError(e.id, `Unknown tool: ${e.name}`);
}
});
app.onSessionEnded((session, event) => {
const e = event as AgentSessionEndedEvent;
console.log(`Session ended: duration=${e.durationSeconds}s turns=${e.turnCount}`);
});
// -- HTTP server with REST + WebSocket routes --
const server = createServer((req: IncomingMessage, res: ServerResponse) => {
if (req.url === '/health' && req.method === 'GET') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ status: 'ok' }));
return;
}
// Reject non-WebSocket requests to /ws
if (req.url === '/ws') {
res.writeHead(426, { 'Content-Type': 'text/plain' });
res.end('Upgrade required');
return;
}
res.writeHead(404);
res.end('Not found');
});
// Handle WebSocket upgrades on /ws path only
server.on('upgrade', (req, socket, head) => {
if (req.url === '/ws') {
app.handleUpgrade(req, socket, head);
} else {
socket.destroy();
}
});
const PORT = 9000;
server.listen(PORT, () => {
console.log(`Server listening on :${PORT} (WS: /ws, REST: /health)`);
});