-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.js
More file actions
66 lines (59 loc) · 2.32 KB
/
Copy pathindex.js
File metadata and controls
66 lines (59 loc) · 2.32 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
// Mock Anthropic-over-WebSocket backend for examples/with-websocket.
//
// It speaks the same wire shape as a real Claude proxy would, but generates a
// canned reply so the example runs with no API key. The react-chorus WebSocket
// transport sends `{ prompt, history }` per frame and treats each inbound
// message as one SSE payload, so the `anthropic` connector parses the JSON
// frames below (`content_block_delta` / `message_stop`) unchanged.
//
// To talk to a real model, swap the canned-frame block for the streaming Claude
// backend in the root README ("Minimal Node.js `ws` + Claude backend").
import { WebSocketServer } from 'ws';
const PORT = Number(process.env.PORT) || 8787;
const wss = new WebSocketServer({ port: PORT });
function latestUserText(history) {
for (let i = history.length - 1; i >= 0; i -= 1) {
const message = history[i];
if (message && message.role === 'user' && typeof message.text === 'string') {
return message.text;
}
}
return '';
}
wss.on('connection', (ws) => {
ws.on('message', (raw) => {
let history = [];
try {
const parsed = JSON.parse(raw.toString());
// `history` already includes the new user turn; ignore `parsed.prompt`.
history = Array.isArray(parsed?.history) ? parsed.history : [];
} catch {
// Ignore malformed frames; an empty history still produces a reply.
}
const prompt = latestUserText(history);
const reply = `Streaming a reply over a WebSocket via the anthropic connector. You said: "${prompt}"`;
const words = reply.split(' ');
const send = (payload) => {
if (ws.readyState === ws.OPEN) ws.send(JSON.stringify(payload));
};
let index = 0;
const tick = () => {
if (ws.readyState !== ws.OPEN) return;
if (index < words.length) {
send({
type: 'content_block_delta',
index: 0,
delta: { type: 'text_delta', text: index === 0 ? words[index] : ` ${words[index]}` },
});
index += 1;
setTimeout(tick, 60);
} else {
// `message_stop` is the anthropic connector's done sentinel; the
// react-chorus WebSocket transport closes the per-send socket after it.
send({ type: 'message_stop' });
}
};
tick();
});
});
console.log(`Mock Anthropic WebSocket backend listening on ws://localhost:${PORT}`);