@miriad-systems/backend 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/dist/agent-manager.d.ts +69 -0
- package/dist/agent-manager.d.ts.map +1 -0
- package/dist/agent-manager.js +424 -0
- package/dist/agent-manager.js.map +1 -0
- package/dist/cli.d.ts +14 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +203 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +60 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +221 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/runtime-client.d.ts +80 -0
- package/dist/runtime-client.d.ts.map +1 -0
- package/dist/runtime-client.js +347 -0
- package/dist/runtime-client.js.map +1 -0
- package/dist/tymbal-bridge.d.ts +47 -0
- package/dist/tymbal-bridge.d.ts.map +1 -0
- package/dist/tymbal-bridge.js +283 -0
- package/dist/tymbal-bridge.js.map +1 -0
- package/dist/types.d.ts +181 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime Client
|
|
3
|
+
*
|
|
4
|
+
* Manages the WebSocket connection to the CAST backend.
|
|
5
|
+
* Handles the LocalRuntime protocol: authentication, message routing,
|
|
6
|
+
* and agent lifecycle coordination.
|
|
7
|
+
*/
|
|
8
|
+
import WebSocket from 'ws';
|
|
9
|
+
import { AgentManager } from './agent-manager.js';
|
|
10
|
+
import { getMachineInfo } from './config.js';
|
|
11
|
+
// =============================================================================
|
|
12
|
+
// Runtime Client
|
|
13
|
+
// =============================================================================
|
|
14
|
+
export class RuntimeClient {
|
|
15
|
+
runtimeConfig;
|
|
16
|
+
agentManager;
|
|
17
|
+
ws = null;
|
|
18
|
+
status = 'disconnected';
|
|
19
|
+
reconnectAttempts = 0;
|
|
20
|
+
reconnectTimeout = null;
|
|
21
|
+
heartbeatInterval = null;
|
|
22
|
+
/** Heartbeat interval in milliseconds (30 seconds) */
|
|
23
|
+
static HEARTBEAT_INTERVAL_MS = 30000;
|
|
24
|
+
onConnected;
|
|
25
|
+
onDisconnected;
|
|
26
|
+
onError;
|
|
27
|
+
constructor(config) {
|
|
28
|
+
this.runtimeConfig = config.config;
|
|
29
|
+
this.onConnected = config.onConnected;
|
|
30
|
+
this.onDisconnected = config.onDisconnected;
|
|
31
|
+
this.onError = config.onError;
|
|
32
|
+
// Create agent manager
|
|
33
|
+
this.agentManager = new AgentManager({
|
|
34
|
+
workspaceBasePath: this.runtimeConfig.workspace.basePath,
|
|
35
|
+
onFrame: (message) => this.sendFrame(message),
|
|
36
|
+
onCheckin: (agentId) => this.sendCheckin(agentId),
|
|
37
|
+
onError: (agentId, error) => {
|
|
38
|
+
console.error(`[RuntimeClient] Agent ${agentId} error:`, error);
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Get current runtime status.
|
|
44
|
+
*/
|
|
45
|
+
getStatus() {
|
|
46
|
+
return this.status;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Get agent manager for status queries.
|
|
50
|
+
*/
|
|
51
|
+
getAgentManager() {
|
|
52
|
+
return this.agentManager;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Connect to the backend.
|
|
56
|
+
*/
|
|
57
|
+
async connect() {
|
|
58
|
+
if (this.ws) {
|
|
59
|
+
console.log('[RuntimeClient] Already connected');
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
this.status = 'connecting';
|
|
63
|
+
const { credentials } = this.runtimeConfig;
|
|
64
|
+
// Use query param for protocol - works with both local dev and AWS Lambda
|
|
65
|
+
// (API Gateway doesn't have /runtimes/connect route, uses $connect with query param)
|
|
66
|
+
const url = `${credentials.wsUrl}?protocol=runtime`;
|
|
67
|
+
console.log(`[RuntimeClient] Connecting to ${url}`);
|
|
68
|
+
return new Promise((resolve, reject) => {
|
|
69
|
+
this.ws = new WebSocket(url, {
|
|
70
|
+
headers: {
|
|
71
|
+
Authorization: `Server ${credentials.secret}`,
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
this.ws.on('open', () => {
|
|
75
|
+
console.log('[RuntimeClient] Connected');
|
|
76
|
+
this.status = 'connected';
|
|
77
|
+
this.reconnectAttempts = 0;
|
|
78
|
+
this.sendRuntimeReady();
|
|
79
|
+
resolve();
|
|
80
|
+
});
|
|
81
|
+
this.ws.on('message', (data) => {
|
|
82
|
+
this.handleMessage(data.toString());
|
|
83
|
+
});
|
|
84
|
+
this.ws.on('close', (code, reason) => {
|
|
85
|
+
console.log(`[RuntimeClient] Disconnected: ${code} ${reason.toString()}`);
|
|
86
|
+
this.status = 'disconnected';
|
|
87
|
+
this.ws = null;
|
|
88
|
+
this.stopHeartbeatInterval();
|
|
89
|
+
this.onDisconnected?.(code, reason.toString());
|
|
90
|
+
this.scheduleReconnect();
|
|
91
|
+
});
|
|
92
|
+
this.ws.on('error', (error) => {
|
|
93
|
+
// Log connection errors cleanly without full stack traces
|
|
94
|
+
const errorMsg = this.formatConnectionError(error);
|
|
95
|
+
if (errorMsg) {
|
|
96
|
+
console.error(`[RuntimeClient] ${errorMsg}`);
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
console.error('[RuntimeClient] WebSocket error:', error);
|
|
100
|
+
}
|
|
101
|
+
this.onError?.(error);
|
|
102
|
+
if (this.status === 'connecting') {
|
|
103
|
+
reject(error);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Disconnect from the backend.
|
|
110
|
+
*/
|
|
111
|
+
async disconnect() {
|
|
112
|
+
if (this.reconnectTimeout) {
|
|
113
|
+
clearTimeout(this.reconnectTimeout);
|
|
114
|
+
this.reconnectTimeout = null;
|
|
115
|
+
}
|
|
116
|
+
// Stop heartbeat interval
|
|
117
|
+
this.stopHeartbeatInterval();
|
|
118
|
+
// Suspend all agents
|
|
119
|
+
await this.agentManager.suspendAll();
|
|
120
|
+
if (this.ws) {
|
|
121
|
+
this.ws.close(1000, 'Client disconnect');
|
|
122
|
+
this.ws = null;
|
|
123
|
+
}
|
|
124
|
+
this.status = 'disconnected';
|
|
125
|
+
}
|
|
126
|
+
// ===========================================================================
|
|
127
|
+
// Message Handling
|
|
128
|
+
// ===========================================================================
|
|
129
|
+
handleMessage(data) {
|
|
130
|
+
let message;
|
|
131
|
+
try {
|
|
132
|
+
message = JSON.parse(data);
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
console.error('[RuntimeClient] Invalid JSON:', data);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
switch (message.type) {
|
|
139
|
+
case 'runtime_connected':
|
|
140
|
+
console.log(`[RuntimeClient] Runtime connected: ${message.runtimeId} (protocol ${message.protocolVersion})`);
|
|
141
|
+
this.status = 'ready';
|
|
142
|
+
this.onConnected?.();
|
|
143
|
+
// Re-checkin all active agents on reconnect
|
|
144
|
+
// This ensures backend knows about agents that survived the disconnect
|
|
145
|
+
this.reCheckinActiveAgents();
|
|
146
|
+
// Start heartbeat interval for agent liveness
|
|
147
|
+
this.startHeartbeatInterval();
|
|
148
|
+
break;
|
|
149
|
+
case 'activate':
|
|
150
|
+
this.handleActivate(message);
|
|
151
|
+
break;
|
|
152
|
+
case 'message':
|
|
153
|
+
this.handleDeliverMessage(message);
|
|
154
|
+
break;
|
|
155
|
+
case 'suspend':
|
|
156
|
+
this.handleSuspend(message);
|
|
157
|
+
break;
|
|
158
|
+
case 'ping':
|
|
159
|
+
this.sendPong(message.timestamp);
|
|
160
|
+
break;
|
|
161
|
+
case 'error':
|
|
162
|
+
console.error(`[RuntimeClient] Backend error: ${message.code} - ${message.message}`);
|
|
163
|
+
break;
|
|
164
|
+
default:
|
|
165
|
+
console.log(`[RuntimeClient] Unknown message type: ${message.type}`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
async handleActivate(message) {
|
|
169
|
+
console.log(`[RuntimeClient] Activate agent: ${message.agentId}`);
|
|
170
|
+
await this.agentManager.activate(message);
|
|
171
|
+
}
|
|
172
|
+
async handleDeliverMessage(message) {
|
|
173
|
+
console.log(`[RuntimeClient] Message for agent: ${message.agentId}`);
|
|
174
|
+
await this.agentManager.deliverMessage(message);
|
|
175
|
+
}
|
|
176
|
+
async handleSuspend(message) {
|
|
177
|
+
console.log(`[RuntimeClient] Suspend agent: ${message.agentId}`);
|
|
178
|
+
await this.agentManager.suspend(message);
|
|
179
|
+
}
|
|
180
|
+
// ===========================================================================
|
|
181
|
+
// Outgoing Messages
|
|
182
|
+
// ===========================================================================
|
|
183
|
+
send(message) {
|
|
184
|
+
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
185
|
+
this.ws.send(JSON.stringify(message));
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
console.error('[RuntimeClient] Cannot send: WebSocket not open');
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
sendRuntimeReady() {
|
|
192
|
+
const { credentials, spaceId, name } = this.runtimeConfig;
|
|
193
|
+
const machineInfo = getMachineInfo();
|
|
194
|
+
const message = {
|
|
195
|
+
type: 'runtime_ready',
|
|
196
|
+
runtimeId: credentials.runtimeId,
|
|
197
|
+
spaceId,
|
|
198
|
+
name,
|
|
199
|
+
machineInfo,
|
|
200
|
+
};
|
|
201
|
+
console.log(`[RuntimeClient] Sending runtime_ready: ${name} (${credentials.runtimeId})`);
|
|
202
|
+
this.send(message);
|
|
203
|
+
}
|
|
204
|
+
sendCheckin(agentId) {
|
|
205
|
+
const message = {
|
|
206
|
+
type: 'agent_checkin',
|
|
207
|
+
agentId,
|
|
208
|
+
};
|
|
209
|
+
console.log(`[RuntimeClient] Agent checkin: ${agentId}`);
|
|
210
|
+
this.send(message);
|
|
211
|
+
}
|
|
212
|
+
sendFrame(frameMessage) {
|
|
213
|
+
this.send(frameMessage);
|
|
214
|
+
}
|
|
215
|
+
sendPong(timestamp) {
|
|
216
|
+
const message = {
|
|
217
|
+
type: 'pong',
|
|
218
|
+
timestamp,
|
|
219
|
+
};
|
|
220
|
+
this.send(message);
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Re-checkin all active agents after reconnection.
|
|
224
|
+
* This notifies the backend about agents that survived the disconnect.
|
|
225
|
+
*/
|
|
226
|
+
reCheckinActiveAgents() {
|
|
227
|
+
const agents = this.agentManager.getAgents();
|
|
228
|
+
const activeAgents = agents.filter((a) => a.status !== 'offline');
|
|
229
|
+
if (activeAgents.length === 0) {
|
|
230
|
+
console.log('[RuntimeClient] No active agents to re-checkin');
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
console.log(`[RuntimeClient] Re-checking in ${activeAgents.length} active agent(s)`);
|
|
234
|
+
for (const agent of activeAgents) {
|
|
235
|
+
this.sendCheckin(agent.agentId);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
// ===========================================================================
|
|
239
|
+
// Heartbeat
|
|
240
|
+
// ===========================================================================
|
|
241
|
+
/**
|
|
242
|
+
* Start periodic heartbeat for all online agents.
|
|
243
|
+
*/
|
|
244
|
+
startHeartbeatInterval() {
|
|
245
|
+
if (this.heartbeatInterval) {
|
|
246
|
+
return; // Already running
|
|
247
|
+
}
|
|
248
|
+
console.log(`[RuntimeClient] Starting heartbeat interval (${RuntimeClient.HEARTBEAT_INTERVAL_MS / 1000}s)`);
|
|
249
|
+
this.heartbeatInterval = setInterval(() => {
|
|
250
|
+
this.sendHeartbeats();
|
|
251
|
+
}, RuntimeClient.HEARTBEAT_INTERVAL_MS);
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Stop the heartbeat interval.
|
|
255
|
+
*/
|
|
256
|
+
stopHeartbeatInterval() {
|
|
257
|
+
if (this.heartbeatInterval) {
|
|
258
|
+
clearInterval(this.heartbeatInterval);
|
|
259
|
+
this.heartbeatInterval = null;
|
|
260
|
+
console.log('[RuntimeClient] Stopped heartbeat interval');
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Send heartbeats for all online agents.
|
|
265
|
+
*/
|
|
266
|
+
sendHeartbeats() {
|
|
267
|
+
const agents = this.agentManager.getAgents();
|
|
268
|
+
const onlineAgents = agents.filter((a) => a.status === 'online' || a.status === 'busy');
|
|
269
|
+
if (onlineAgents.length === 0) {
|
|
270
|
+
return; // No agents to heartbeat
|
|
271
|
+
}
|
|
272
|
+
for (const agent of onlineAgents) {
|
|
273
|
+
const message = {
|
|
274
|
+
type: 'agent_heartbeat',
|
|
275
|
+
agentId: agent.agentId,
|
|
276
|
+
};
|
|
277
|
+
this.send(message);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
// ===========================================================================
|
|
281
|
+
// Error Formatting
|
|
282
|
+
// ===========================================================================
|
|
283
|
+
/**
|
|
284
|
+
* Format common connection errors into clean single-line messages.
|
|
285
|
+
* Returns null for unexpected errors that should show full stack trace.
|
|
286
|
+
*/
|
|
287
|
+
formatConnectionError(error) {
|
|
288
|
+
const message = error.message || '';
|
|
289
|
+
const code = error.code;
|
|
290
|
+
// Handle AggregateError (multiple connection attempts failed)
|
|
291
|
+
if (error.name === 'AggregateError' && 'errors' in error) {
|
|
292
|
+
const aggError = error;
|
|
293
|
+
if (aggError.errors.length > 0) {
|
|
294
|
+
const firstError = aggError.errors[0];
|
|
295
|
+
if (firstError.code === 'ECONNREFUSED') {
|
|
296
|
+
return 'Connection refused - server unavailable';
|
|
297
|
+
}
|
|
298
|
+
if (firstError.code === 'ETIMEDOUT') {
|
|
299
|
+
return 'Connection timed out';
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
// Handle direct error codes
|
|
304
|
+
if (code === 'ECONNREFUSED') {
|
|
305
|
+
return 'Connection refused - server unavailable';
|
|
306
|
+
}
|
|
307
|
+
if (code === 'ETIMEDOUT') {
|
|
308
|
+
return 'Connection timed out';
|
|
309
|
+
}
|
|
310
|
+
if (code === 'ENOTFOUND') {
|
|
311
|
+
return 'Server not found - check URL';
|
|
312
|
+
}
|
|
313
|
+
if (code === 'ECONNRESET') {
|
|
314
|
+
return 'Connection reset by server';
|
|
315
|
+
}
|
|
316
|
+
// Check message patterns
|
|
317
|
+
if (message.includes('ECONNREFUSED')) {
|
|
318
|
+
return 'Connection refused - server unavailable';
|
|
319
|
+
}
|
|
320
|
+
if (message.includes('ETIMEDOUT')) {
|
|
321
|
+
return 'Connection timed out';
|
|
322
|
+
}
|
|
323
|
+
return null;
|
|
324
|
+
}
|
|
325
|
+
// ===========================================================================
|
|
326
|
+
// Reconnection
|
|
327
|
+
// ===========================================================================
|
|
328
|
+
scheduleReconnect() {
|
|
329
|
+
if (this.reconnectTimeout)
|
|
330
|
+
return;
|
|
331
|
+
// Exponential backoff: 1s, 2s, 4s, 8s, 16s, max 30s
|
|
332
|
+
const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000);
|
|
333
|
+
this.reconnectAttempts++;
|
|
334
|
+
console.log(`[RuntimeClient] Reconnecting in ${delay / 1000}s (attempt ${this.reconnectAttempts})`);
|
|
335
|
+
this.reconnectTimeout = setTimeout(async () => {
|
|
336
|
+
this.reconnectTimeout = null;
|
|
337
|
+
try {
|
|
338
|
+
await this.connect();
|
|
339
|
+
}
|
|
340
|
+
catch {
|
|
341
|
+
// Error already logged by WebSocket error handler
|
|
342
|
+
// Will be scheduled again by close handler
|
|
343
|
+
}
|
|
344
|
+
}, delay);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
//# sourceMappingURL=runtime-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-client.js","sourceRoot":"","sources":["../src/runtime-client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,SAAS,MAAM,IAAI,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AA4B7C,gFAAgF;AAChF,iBAAiB;AACjB,gFAAgF;AAEhF,MAAM,OAAO,aAAa;IACP,aAAa,CAAgB;IAC7B,YAAY,CAAe;IAEpC,EAAE,GAAqB,IAAI,CAAC;IAC5B,MAAM,GAAkB,cAAc,CAAC;IACvC,iBAAiB,GAAG,CAAC,CAAC;IACtB,gBAAgB,GAAyC,IAAI,CAAC;IAC9D,iBAAiB,GAA0C,IAAI,CAAC;IAExE,sDAAsD;IAC9C,MAAM,CAAU,qBAAqB,GAAG,KAAK,CAAC;IAErC,WAAW,CAAc;IACzB,cAAc,CAA0C;IACxD,OAAO,CAA0B;IAElD,YAAY,MAA2B;QACrC,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC;QACnC,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;QACtC,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC,cAAc,CAAC;QAC5C,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;QAE9B,uBAAuB;QACvB,IAAI,CAAC,YAAY,GAAG,IAAI,YAAY,CAAC;YACnC,iBAAiB,EAAE,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,QAAQ;YACxD,OAAO,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;YAC7C,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;YACjD,OAAO,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE;gBAC1B,OAAO,CAAC,KAAK,CAAC,yBAAyB,OAAO,SAAS,EAAE,KAAK,CAAC,CAAC;YAClE,CAAC;SACF,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,SAAS;QACP,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED;;OAEG;IACH,eAAe;QACb,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,OAAO;QACX,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;YACZ,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;YACjD,OAAO;QACT,CAAC;QAED,IAAI,CAAC,MAAM,GAAG,YAAY,CAAC;QAC3B,MAAM,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC,aAAa,CAAC;QAC3C,0EAA0E;QAC1E,qFAAqF;QACrF,MAAM,GAAG,GAAG,GAAG,WAAW,CAAC,KAAK,mBAAmB,CAAC;QAEpD,OAAO,CAAC,GAAG,CAAC,iCAAiC,GAAG,EAAE,CAAC,CAAC;QAEpD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,IAAI,CAAC,EAAE,GAAG,IAAI,SAAS,CAAC,GAAG,EAAE;gBAC3B,OAAO,EAAE;oBACP,aAAa,EAAE,UAAU,WAAW,CAAC,MAAM,EAAE;iBAC9C;aACF,CAAC,CAAC;YAEH,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE;gBACtB,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;gBACzC,IAAI,CAAC,MAAM,GAAG,WAAW,CAAC;gBAC1B,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAC;gBAC3B,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBACxB,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE;gBAC7B,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;YACtC,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE;gBACnC,OAAO,CAAC,GAAG,CAAC,iCAAiC,IAAI,IAAI,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;gBAC1E,IAAI,CAAC,MAAM,GAAG,cAAc,CAAC;gBAC7B,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC;gBACf,IAAI,CAAC,qBAAqB,EAAE,CAAC;gBAC7B,IAAI,CAAC,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;gBAC/C,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC3B,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;gBAC5B,0DAA0D;gBAC1D,MAAM,QAAQ,GAAG,IAAI,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC;gBACnD,IAAI,QAAQ,EAAE,CAAC;oBACb,OAAO,CAAC,KAAK,CAAC,mBAAmB,QAAQ,EAAE,CAAC,CAAC;gBAC/C,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,KAAK,CAAC,kCAAkC,EAAE,KAAK,CAAC,CAAC;gBAC3D,CAAC;gBACD,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC;gBACtB,IAAI,IAAI,CAAC,MAAM,KAAK,YAAY,EAAE,CAAC;oBACjC,MAAM,CAAC,KAAK,CAAC,CAAC;gBAChB,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,UAAU;QACd,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC1B,YAAY,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;YACpC,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAC/B,CAAC;QAED,0BAA0B;QAC1B,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAE7B,qBAAqB;QACrB,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC;QAErC,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;YACZ,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,mBAAmB,CAAC,CAAC;YACzC,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC;QACjB,CAAC;QAED,IAAI,CAAC,MAAM,GAAG,cAAc,CAAC;IAC/B,CAAC;IAED,8EAA8E;IAC9E,mBAAmB;IACnB,8EAA8E;IAEtE,aAAa,CAAC,IAAY;QAChC,IAAI,OAAgC,CAAC;QACrC,IAAI,CAAC;YACH,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,IAAI,CAAC,CAAC;YACrD,OAAO;QACT,CAAC;QAED,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;YACrB,KAAK,mBAAmB;gBACtB,OAAO,CAAC,GAAG,CAAC,sCAAsC,OAAO,CAAC,SAAS,cAAc,OAAO,CAAC,eAAe,GAAG,CAAC,CAAC;gBAC7G,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC;gBACtB,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;gBACrB,4CAA4C;gBAC5C,uEAAuE;gBACvE,IAAI,CAAC,qBAAqB,EAAE,CAAC;gBAC7B,8CAA8C;gBAC9C,IAAI,CAAC,sBAAsB,EAAE,CAAC;gBAC9B,MAAM;YAER,KAAK,UAAU;gBACb,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;gBAC7B,MAAM;YAER,KAAK,SAAS;gBACZ,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC;gBACnC,MAAM;YAER,KAAK,SAAS;gBACZ,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;gBAC5B,MAAM;YAER,KAAK,MAAM;gBACT,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;gBACjC,MAAM;YAER,KAAK,OAAO;gBACV,OAAO,CAAC,KAAK,CAAC,kCAAkC,OAAO,CAAC,IAAI,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;gBACrF,MAAM;YAER;gBACE,OAAO,CAAC,GAAG,CAAC,yCAA0C,OAA4B,CAAC,IAAI,EAAE,CAAC,CAAC;QAC/F,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,cAAc,CAAC,OAA6B;QACxD,OAAO,CAAC,GAAG,CAAC,mCAAmC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;QAClE,MAAM,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC5C,CAAC;IAEO,KAAK,CAAC,oBAAoB,CAAC,OAA8B;QAC/D,OAAO,CAAC,GAAG,CAAC,sCAAsC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;QACrE,MAAM,IAAI,CAAC,YAAY,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;IAClD,CAAC;IAEO,KAAK,CAAC,aAAa,CAAC,OAA4B;QACtD,OAAO,CAAC,GAAG,CAAC,kCAAkC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;QACjE,MAAM,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3C,CAAC;IAED,8EAA8E;IAC9E,oBAAoB;IACpB,8EAA8E;IAEtE,IAAI,CAAC,OAAgC;QAC3C,IAAI,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC;YACrD,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;QACxC,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,KAAK,CAAC,iDAAiD,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;IAEO,gBAAgB;QACtB,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,aAAa,CAAC;QAC1D,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;QAErC,MAAM,OAAO,GAAwB;YACnC,IAAI,EAAE,eAAe;YACrB,SAAS,EAAE,WAAW,CAAC,SAAS;YAChC,OAAO;YACP,IAAI;YACJ,WAAW;SACZ,CAAC;QAEF,OAAO,CAAC,GAAG,CAAC,0CAA0C,IAAI,KAAK,WAAW,CAAC,SAAS,GAAG,CAAC,CAAC;QACzF,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACrB,CAAC;IAEO,WAAW,CAAC,OAAe;QACjC,MAAM,OAAO,GAAwB;YACnC,IAAI,EAAE,eAAe;YACrB,OAAO;SACR,CAAC;QACF,OAAO,CAAC,GAAG,CAAC,kCAAkC,OAAO,EAAE,CAAC,CAAC;QACzD,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACrB,CAAC;IAEO,SAAS,CAAC,YAA+B;QAC/C,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC1B,CAAC;IAEO,QAAQ,CAAC,SAAiB;QAChC,MAAM,OAAO,GAAgB;YAC3B,IAAI,EAAE,MAAM;YACZ,SAAS;SACV,CAAC;QACF,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACrB,CAAC;IAED;;;OAGG;IACK,qBAAqB;QAC3B,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE,CAAC;QAC7C,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;QAElE,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9B,OAAO,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC;YAC9D,OAAO;QACT,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,kCAAkC,YAAY,CAAC,MAAM,kBAAkB,CAAC,CAAC;QACrF,KAAK,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;YACjC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAClC,CAAC;IACH,CAAC;IAED,8EAA8E;IAC9E,YAAY;IACZ,8EAA8E;IAE9E;;OAEG;IACK,sBAAsB;QAC5B,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC3B,OAAO,CAAC,kBAAkB;QAC5B,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,gDAAgD,aAAa,CAAC,qBAAqB,GAAG,IAAI,IAAI,CAAC,CAAC;QAC5G,IAAI,CAAC,iBAAiB,GAAG,WAAW,CAAC,GAAG,EAAE;YACxC,IAAI,CAAC,cAAc,EAAE,CAAC;QACxB,CAAC,EAAE,aAAa,CAAC,qBAAqB,CAAC,CAAC;IAC1C,CAAC;IAED;;OAEG;IACK,qBAAqB;QAC3B,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC3B,aAAa,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;YACtC,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC;YAC9B,OAAO,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;IAED;;OAEG;IACK,cAAc;QACpB,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE,CAAC;QAC7C,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;QAExF,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9B,OAAO,CAAC,yBAAyB;QACnC,CAAC;QAED,KAAK,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;YACjC,MAAM,OAAO,GAA0B;gBACrC,IAAI,EAAE,iBAAiB;gBACvB,OAAO,EAAE,KAAK,CAAC,OAAO;aACvB,CAAC;YACF,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IAED,8EAA8E;IAC9E,mBAAmB;IACnB,8EAA8E;IAE9E;;;OAGG;IACK,qBAAqB,CAAC,KAAY;QACxC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC;QACpC,MAAM,IAAI,GAAI,KAA+B,CAAC,IAAI,CAAC;QAEnD,8DAA8D;QAC9D,IAAI,KAAK,CAAC,IAAI,KAAK,gBAAgB,IAAI,QAAQ,IAAI,KAAK,EAAE,CAAC;YACzD,MAAM,QAAQ,GAAG,KAAuB,CAAC;YACzC,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC/B,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAA0B,CAAC;gBAC/D,IAAI,UAAU,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;oBACvC,OAAO,yCAAyC,CAAC;gBACnD,CAAC;gBACD,IAAI,UAAU,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;oBACpC,OAAO,sBAAsB,CAAC;gBAChC,CAAC;YACH,CAAC;QACH,CAAC;QAED,4BAA4B;QAC5B,IAAI,IAAI,KAAK,cAAc,EAAE,CAAC;YAC5B,OAAO,yCAAyC,CAAC;QACnD,CAAC;QACD,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;YACzB,OAAO,sBAAsB,CAAC;QAChC,CAAC;QACD,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;YACzB,OAAO,8BAA8B,CAAC;QACxC,CAAC;QACD,IAAI,IAAI,KAAK,YAAY,EAAE,CAAC;YAC1B,OAAO,4BAA4B,CAAC;QACtC,CAAC;QAED,yBAAyB;QACzB,IAAI,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;YACrC,OAAO,yCAAyC,CAAC;QACnD,CAAC;QACD,IAAI,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;YAClC,OAAO,sBAAsB,CAAC;QAChC,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED,8EAA8E;IAC9E,eAAe;IACf,8EAA8E;IAEtE,iBAAiB;QACvB,IAAI,IAAI,CAAC,gBAAgB;YAAE,OAAO;QAElC,oDAAoD;QACpD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,iBAAiB,CAAC,EAAE,KAAK,CAAC,CAAC;QAC1E,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAEzB,OAAO,CAAC,GAAG,CAAC,mCAAmC,KAAK,GAAG,IAAI,cAAc,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAC;QAEpG,IAAI,CAAC,gBAAgB,GAAG,UAAU,CAAC,KAAK,IAAI,EAAE;YAC5C,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;YAC7B,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;YACvB,CAAC;YAAC,MAAM,CAAC;gBACP,kDAAkD;gBAClD,2CAA2C;YAC7C,CAAC;QACH,CAAC,EAAE,KAAK,CAAC,CAAC;IACZ,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tymbal Bridge for Local Runtime
|
|
3
|
+
*
|
|
4
|
+
* Translates Claude Agent SDK messages to Tymbal protocol frames
|
|
5
|
+
* and sends them to the backend via the runtime's WS connection.
|
|
6
|
+
*
|
|
7
|
+
* Adapted from local-agent-engine for multi-agent support:
|
|
8
|
+
* - Frames are wrapped with agentId for routing
|
|
9
|
+
* - Uses callback instead of direct WS send (runtime manages connection)
|
|
10
|
+
*/
|
|
11
|
+
import type { SDKMessage } from '@anthropic-ai/claude-agent-sdk';
|
|
12
|
+
import type { AgentFrameMessage } from './types.js';
|
|
13
|
+
export interface TymbalBridgeConfig {
|
|
14
|
+
/** Agent ID ({spaceId}:{channelId}:{callsign}) */
|
|
15
|
+
agentId: string;
|
|
16
|
+
/** Agent callsign for frame sender attribution */
|
|
17
|
+
callsign: string;
|
|
18
|
+
/** Callback to send frames to runtime */
|
|
19
|
+
onFrame: (message: AgentFrameMessage) => void;
|
|
20
|
+
}
|
|
21
|
+
export declare class TymbalBridge {
|
|
22
|
+
private readonly agentId;
|
|
23
|
+
private readonly callsign;
|
|
24
|
+
private readonly onFrame;
|
|
25
|
+
private sessionId;
|
|
26
|
+
private currentAssistantMsgId;
|
|
27
|
+
private assistantContent;
|
|
28
|
+
private startFrameEmitted;
|
|
29
|
+
constructor(config: TymbalBridgeConfig);
|
|
30
|
+
getSessionId(): string | null;
|
|
31
|
+
getCallsign(): string;
|
|
32
|
+
/**
|
|
33
|
+
* Process an SDK message and emit appropriate Tymbal frames.
|
|
34
|
+
*/
|
|
35
|
+
processSDKMessage(message: SDKMessage): Promise<void>;
|
|
36
|
+
private handleSystem;
|
|
37
|
+
private handlePartialAssistant;
|
|
38
|
+
private handleAssistant;
|
|
39
|
+
private handleUser;
|
|
40
|
+
private handleResult;
|
|
41
|
+
finalize(): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Emit a frame wrapped with agentId for routing.
|
|
44
|
+
*/
|
|
45
|
+
private emitFrame;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=tymbal-bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tymbal-bridge.d.ts","sourceRoot":"","sources":["../src/tymbal-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EACV,UAAU,EAMX,MAAM,gCAAgC,CAAC;AAExC,OAAO,KAAK,EAA0C,iBAAiB,EAAE,MAAM,YAAY,CAAC;AA6B5F,MAAM,WAAW,kBAAkB;IACjC,kDAAkD;IAClD,OAAO,EAAE,MAAM,CAAC;IAChB,kDAAkD;IAClD,QAAQ,EAAE,MAAM,CAAC;IACjB,yCAAyC;IACzC,OAAO,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAC/C;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuC;IAG/D,OAAO,CAAC,SAAS,CAAuB;IAGxC,OAAO,CAAC,qBAAqB,CAAuB;IACpD,OAAO,CAAC,gBAAgB,CAAc;IACtC,OAAO,CAAC,iBAAiB,CAAkB;gBAE/B,MAAM,EAAE,kBAAkB;IAMtC,YAAY,IAAI,MAAM,GAAG,IAAI;IAI7B,WAAW,IAAI,MAAM;IAIrB;;OAEG;IACG,iBAAiB,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;YA+B7C,YAAY;YAOZ,sBAAsB;YA2BtB,eAAe;YA0Df,UAAU;YA2CV,YAAY;IAwFpB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB/B;;OAEG;YACW,SAAS;CASxB"}
|