agentgui 1.0.383 → 1.0.384
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/package.json +1 -1
- package/server.js +4 -569
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -340,6 +340,8 @@ function discoverAgents() {
|
|
|
340
340
|
|
|
341
341
|
const discoveredAgents = discoverAgents();
|
|
342
342
|
initializeDescriptors(discoveredAgents);
|
|
343
|
+
const acpQueries = createACPQueries(db, prepare);
|
|
344
|
+
acpQueries.getAgentDescriptor = getAgentDescriptor;
|
|
343
345
|
|
|
344
346
|
const modelCache = new Map();
|
|
345
347
|
|
|
@@ -1512,7 +1514,7 @@ const server = http.createServer(async (req, res) => {
|
|
|
1512
1514
|
}
|
|
1513
1515
|
|
|
1514
1516
|
const oldRunCancelMatch = pathOnly.match(/^\/api\/runs\/([^/]+)\/cancel$/);
|
|
1515
|
-
if (
|
|
1517
|
+
if (oldRunCancelMatch && req.method === 'POST') {
|
|
1516
1518
|
const runId = oldRunCancelMatch[1];
|
|
1517
1519
|
const session = queries.getSession(runId);
|
|
1518
1520
|
|
|
@@ -2073,7 +2075,7 @@ const server = http.createServer(async (req, res) => {
|
|
|
2073
2075
|
}
|
|
2074
2076
|
|
|
2075
2077
|
const oldRunCancelMatch1 = pathOnly.match(/^\/api\/runs\/([^/]+)\/cancel$/);
|
|
2076
|
-
if (
|
|
2078
|
+
if (oldRunCancelMatch1 && req.method === 'POST') {
|
|
2077
2079
|
const runId = oldRunCancelMatch1[1];
|
|
2078
2080
|
try {
|
|
2079
2081
|
const run = acpQueries.cancelRun(runId);
|
|
@@ -2323,573 +2325,6 @@ const server = http.createServer(async (req, res) => {
|
|
|
2323
2325
|
return;
|
|
2324
2326
|
}
|
|
2325
2327
|
|
|
2326
|
-
const threadsMatch = pathOnly.match(/^\/api\/threads$/);
|
|
2327
|
-
if (threadsMatch && req.method === 'POST') {
|
|
2328
|
-
let body = '';
|
|
2329
|
-
for await (const chunk of req) { body += chunk; }
|
|
2330
|
-
let parsed = {};
|
|
2331
|
-
try { parsed = body ? JSON.parse(body) : {}; } catch {}
|
|
2332
|
-
|
|
2333
|
-
const thread = queries.createConversation(parsed.agentId || 'claude-code', parsed.title || 'New Thread', parsed.workingDirectory || STARTUP_CWD);
|
|
2334
|
-
sendJSON(req, res, 200, {
|
|
2335
|
-
id: thread.id,
|
|
2336
|
-
agentId: thread.agentId,
|
|
2337
|
-
title: thread.title,
|
|
2338
|
-
created_at: thread.created_at,
|
|
2339
|
-
status: thread.status,
|
|
2340
|
-
state: null
|
|
2341
|
-
});
|
|
2342
|
-
return;
|
|
2343
|
-
}
|
|
2344
|
-
|
|
2345
|
-
const threadsSearchMatch = pathOnly.match(/^\/api\/threads\/search$/);
|
|
2346
|
-
if (threadsSearchMatch && req.method === 'POST') {
|
|
2347
|
-
const conversations = queries.getConversations();
|
|
2348
|
-
const threads = conversations.map(c => ({
|
|
2349
|
-
id: c.id,
|
|
2350
|
-
agentId: c.agentId,
|
|
2351
|
-
title: c.title,
|
|
2352
|
-
created_at: c.created_at,
|
|
2353
|
-
updated_at: c.updated_at,
|
|
2354
|
-
status: c.status,
|
|
2355
|
-
state: null
|
|
2356
|
-
}));
|
|
2357
|
-
sendJSON(req, res, 200, threads);
|
|
2358
|
-
return;
|
|
2359
|
-
}
|
|
2360
|
-
|
|
2361
|
-
const oldThreadByIdMatch = pathOnly.match(/^\/api\/threads\/([^/]+)$/);
|
|
2362
|
-
if (oldThreadByIdMatch) {
|
|
2363
|
-
const threadId = oldThreadByIdMatch[1];
|
|
2364
|
-
const conv = queries.getConversation(threadId);
|
|
2365
|
-
|
|
2366
|
-
if (!conv) {
|
|
2367
|
-
sendJSON(req, res, 404, { error: 'Thread not found' });
|
|
2368
|
-
return;
|
|
2369
|
-
}
|
|
2370
|
-
|
|
2371
|
-
if (req.method === 'GET') {
|
|
2372
|
-
sendJSON(req, res, 200, {
|
|
2373
|
-
id: conv.id,
|
|
2374
|
-
agentId: conv.agentId,
|
|
2375
|
-
title: conv.title,
|
|
2376
|
-
created_at: conv.created_at,
|
|
2377
|
-
updated_at: conv.updated_at,
|
|
2378
|
-
status: conv.status,
|
|
2379
|
-
state: null
|
|
2380
|
-
});
|
|
2381
|
-
return;
|
|
2382
|
-
}
|
|
2383
|
-
|
|
2384
|
-
if (req.method === 'DELETE') {
|
|
2385
|
-
const activeEntry = activeExecutions.get(threadId);
|
|
2386
|
-
if (activeEntry) {
|
|
2387
|
-
sendJSON(req, res, 409, { error: 'Thread has an active run, cannot delete' });
|
|
2388
|
-
return;
|
|
2389
|
-
}
|
|
2390
|
-
queries.deleteConversation(threadId);
|
|
2391
|
-
sendJSON(req, res, 204, {});
|
|
2392
|
-
return;
|
|
2393
|
-
}
|
|
2394
|
-
|
|
2395
|
-
if (req.method === 'PATCH') {
|
|
2396
|
-
let body = '';
|
|
2397
|
-
for await (const chunk of req) { body += chunk; }
|
|
2398
|
-
let parsed = {};
|
|
2399
|
-
try { parsed = body ? JSON.parse(body) : {}; } catch {}
|
|
2400
|
-
|
|
2401
|
-
const updates = {};
|
|
2402
|
-
if (parsed.title !== undefined) updates.title = parsed.title;
|
|
2403
|
-
if (parsed.state !== undefined) updates.state = parsed.state;
|
|
2404
|
-
|
|
2405
|
-
if (Object.keys(updates).length > 0) {
|
|
2406
|
-
queries.updateConversation(threadId, updates);
|
|
2407
|
-
}
|
|
2408
|
-
|
|
2409
|
-
const updated = queries.getConversation(threadId);
|
|
2410
|
-
sendJSON(req, res, 200, {
|
|
2411
|
-
id: updated.id,
|
|
2412
|
-
agentId: updated.agentId,
|
|
2413
|
-
title: updated.title,
|
|
2414
|
-
created_at: updated.created_at,
|
|
2415
|
-
updated_at: updated.updated_at,
|
|
2416
|
-
status: updated.status,
|
|
2417
|
-
state: updated.state
|
|
2418
|
-
});
|
|
2419
|
-
return;
|
|
2420
|
-
}
|
|
2421
|
-
}
|
|
2422
|
-
|
|
2423
|
-
const oldThreadHistoryMatch = pathOnly.match(/^\/api\/threads\/([^/]+)\/history$/);
|
|
2424
|
-
if (threadHistoryMatch && req.method === 'GET') {
|
|
2425
|
-
const threadId = oldThreadHistoryMatch[1];
|
|
2426
|
-
const conv = queries.getConversation(threadId);
|
|
2427
|
-
|
|
2428
|
-
if (!conv) {
|
|
2429
|
-
sendJSON(req, res, 404, { error: 'Thread not found' });
|
|
2430
|
-
return;
|
|
2431
|
-
}
|
|
2432
|
-
|
|
2433
|
-
const limit = parseInt(new URL(req.url, 'http://localhost').searchParams.get('limit') || '10', 10);
|
|
2434
|
-
const sessions = queries.getSessionsByConversation(threadId, limit);
|
|
2435
|
-
|
|
2436
|
-
const history = sessions.map(s => ({
|
|
2437
|
-
checkpoint: s.id,
|
|
2438
|
-
state: null,
|
|
2439
|
-
created_at: s.started_at,
|
|
2440
|
-
runId: s.id,
|
|
2441
|
-
status: s.status
|
|
2442
|
-
})).reverse();
|
|
2443
|
-
|
|
2444
|
-
sendJSON(req, res, 200, history);
|
|
2445
|
-
return;
|
|
2446
|
-
}
|
|
2447
|
-
|
|
2448
|
-
const oldThreadCopyMatch = pathOnly.match(/^\/api\/threads\/([^/]+)\/copy$/);
|
|
2449
|
-
if (threadCopyMatch && req.method === 'POST') {
|
|
2450
|
-
const threadId = threadCopyMatch[1];
|
|
2451
|
-
const original = queries.getConversation(threadId);
|
|
2452
|
-
|
|
2453
|
-
if (!original) {
|
|
2454
|
-
sendJSON(req, res, 404, { error: 'Thread not found' });
|
|
2455
|
-
return;
|
|
2456
|
-
}
|
|
2457
|
-
|
|
2458
|
-
const newThread = queries.createConversation(original.agentId, original.title + ' (copy)', original.workingDirectory);
|
|
2459
|
-
|
|
2460
|
-
const messages = queries.getMessages(threadId, 1000, 0);
|
|
2461
|
-
for (const msg of messages) {
|
|
2462
|
-
queries.createMessage(newThread.id, msg.role, msg.content);
|
|
2463
|
-
}
|
|
2464
|
-
|
|
2465
|
-
sendJSON(req, res, 200, {
|
|
2466
|
-
id: newThread.id,
|
|
2467
|
-
agentId: newThread.agentId,
|
|
2468
|
-
title: newThread.title,
|
|
2469
|
-
created_at: newThread.created_at,
|
|
2470
|
-
status: newThread.status,
|
|
2471
|
-
state: null
|
|
2472
|
-
});
|
|
2473
|
-
return;
|
|
2474
|
-
}
|
|
2475
|
-
|
|
2476
|
-
const threadRunsMatch = pathOnly.match(/^\/api\/threads\/([^/]+)\/runs$/);
|
|
2477
|
-
if (threadRunsMatch) {
|
|
2478
|
-
const threadId = threadRunsMatch[1];
|
|
2479
|
-
const conv = queries.getConversation(threadId);
|
|
2480
|
-
|
|
2481
|
-
if (!conv) {
|
|
2482
|
-
sendJSON(req, res, 404, { error: 'Thread not found' });
|
|
2483
|
-
return;
|
|
2484
|
-
}
|
|
2485
|
-
|
|
2486
|
-
if (req.method === 'GET') {
|
|
2487
|
-
const limit = parseInt(new URL(req.url, 'http://localhost').searchParams.get('limit') || '10', 10);
|
|
2488
|
-
const offset = parseInt(new URL(req.url, 'http://localhost').searchParams.get('offset') || '0', 10);
|
|
2489
|
-
const sessions = queries.getSessionsByConversation(threadId, limit, offset);
|
|
2490
|
-
|
|
2491
|
-
const runs = sessions.map(s => ({
|
|
2492
|
-
id: s.id,
|
|
2493
|
-
threadId: s.conversationId,
|
|
2494
|
-
status: s.status,
|
|
2495
|
-
started_at: s.started_at,
|
|
2496
|
-
completed_at: s.completed_at,
|
|
2497
|
-
agentId: s.agentId,
|
|
2498
|
-
input: null,
|
|
2499
|
-
output: null
|
|
2500
|
-
}));
|
|
2501
|
-
|
|
2502
|
-
sendJSON(req, res, 200, runs);
|
|
2503
|
-
return;
|
|
2504
|
-
}
|
|
2505
|
-
|
|
2506
|
-
if (req.method === 'POST') {
|
|
2507
|
-
const activeEntry = activeExecutions.get(threadId);
|
|
2508
|
-
if (activeEntry) {
|
|
2509
|
-
sendJSON(req, res, 409, { error: 'Thread already has an active run' });
|
|
2510
|
-
return;
|
|
2511
|
-
}
|
|
2512
|
-
|
|
2513
|
-
let body = '';
|
|
2514
|
-
for await (const chunk of req) { body += chunk; }
|
|
2515
|
-
let parsed = {};
|
|
2516
|
-
try { parsed = body ? JSON.parse(body) : {}; } catch {}
|
|
2517
|
-
|
|
2518
|
-
const { input, agentId, webhook } = parsed;
|
|
2519
|
-
if (!input) {
|
|
2520
|
-
sendJSON(req, res, 400, { error: 'Missing input in request body' });
|
|
2521
|
-
return;
|
|
2522
|
-
}
|
|
2523
|
-
|
|
2524
|
-
const resolvedAgentId = agentId || conv.agentId || 'claude-code';
|
|
2525
|
-
const resolvedModel = parsed.model || conv.model || null;
|
|
2526
|
-
const cwd = conv.workingDirectory || STARTUP_CWD;
|
|
2527
|
-
|
|
2528
|
-
const session = queries.createSession(threadId, resolvedAgentId, 'pending');
|
|
2529
|
-
const message = queries.createMessage(threadId, 'user', typeof input === 'string' ? input : JSON.stringify(input));
|
|
2530
|
-
|
|
2531
|
-
processMessageWithStreaming(threadId, message.id, session.id, typeof input === 'string' ? input : JSON.stringify(input), resolvedAgentId, resolvedModel);
|
|
2532
|
-
|
|
2533
|
-
sendJSON(req, res, 200, {
|
|
2534
|
-
id: session.id,
|
|
2535
|
-
threadId: threadId,
|
|
2536
|
-
status: 'pending',
|
|
2537
|
-
started_at: session.started_at,
|
|
2538
|
-
agentId: resolvedAgentId
|
|
2539
|
-
});
|
|
2540
|
-
return;
|
|
2541
|
-
}
|
|
2542
|
-
}
|
|
2543
|
-
|
|
2544
|
-
const threadRunsStreamMatch = pathOnly.match(/^\/api\/threads\/([^\/]+)\/runs\/stream$/);
|
|
2545
|
-
if (threadRunsStreamMatch && req.method === 'POST') {
|
|
2546
|
-
const threadId = threadRunsStreamMatch[1];
|
|
2547
|
-
const conv = queries.getConversation(threadId);
|
|
2548
|
-
|
|
2549
|
-
if (!conv) {
|
|
2550
|
-
sendJSON(req, res, 404, { error: 'Thread not found' });
|
|
2551
|
-
return;
|
|
2552
|
-
}
|
|
2553
|
-
|
|
2554
|
-
const activeEntry = activeExecutions.get(threadId);
|
|
2555
|
-
if (activeEntry) {
|
|
2556
|
-
sendJSON(req, res, 409, { error: 'Thread already has an active run' });
|
|
2557
|
-
return;
|
|
2558
|
-
}
|
|
2559
|
-
|
|
2560
|
-
let body = '';
|
|
2561
|
-
for await (const chunk of req) { body += chunk; }
|
|
2562
|
-
let parsed = {};
|
|
2563
|
-
try { parsed = body ? JSON.parse(body) : {}; } catch {}
|
|
2564
|
-
|
|
2565
|
-
const { input, agentId } = parsed;
|
|
2566
|
-
if (!input) {
|
|
2567
|
-
sendJSON(req, res, 400, { error: 'Missing input in request body' });
|
|
2568
|
-
return;
|
|
2569
|
-
}
|
|
2570
|
-
|
|
2571
|
-
const resolvedAgentId = agentId || conv.agentId || 'claude-code';
|
|
2572
|
-
const resolvedModel = parsed.model || conv.model || null;
|
|
2573
|
-
|
|
2574
|
-
const session = queries.createSession(threadId, resolvedAgentId, 'pending');
|
|
2575
|
-
const message = queries.createMessage(threadId, 'user', typeof input === 'string' ? input : JSON.stringify(input));
|
|
2576
|
-
|
|
2577
|
-
res.writeHead(200, {
|
|
2578
|
-
'Content-Type': 'text/event-stream',
|
|
2579
|
-
'Cache-Control': 'no-cache',
|
|
2580
|
-
'Connection': 'keep-alive'
|
|
2581
|
-
});
|
|
2582
|
-
|
|
2583
|
-
const eventListeners = [];
|
|
2584
|
-
const broadcastListener = (event) => {
|
|
2585
|
-
if (event.sessionId === session.id) {
|
|
2586
|
-
if (event.type === 'streaming_progress') {
|
|
2587
|
-
res.write(`event: message\ndata: ${JSON.stringify(event)}\n\n`);
|
|
2588
|
-
} else if (event.type === 'streaming_complete') {
|
|
2589
|
-
res.write(`event: done\ndata: ${JSON.stringify({ status: 'completed' })}\n\n`);
|
|
2590
|
-
res.end();
|
|
2591
|
-
} else if (event.type === 'streaming_error') {
|
|
2592
|
-
res.write(`event: error\ndata: ${JSON.stringify({ error: event.error })}\n\n`);
|
|
2593
|
-
res.end();
|
|
2594
|
-
}
|
|
2595
|
-
}
|
|
2596
|
-
};
|
|
2597
|
-
eventListeners.push(broadcastListener);
|
|
2598
|
-
|
|
2599
|
-
req.on('close', () => {
|
|
2600
|
-
eventListeners.length = 0;
|
|
2601
|
-
});
|
|
2602
|
-
|
|
2603
|
-
processMessageWithStreaming(threadId, message.id, session.id, typeof input === 'string' ? input : JSON.stringify(input), resolvedAgentId, resolvedModel);
|
|
2604
|
-
return;
|
|
2605
|
-
}
|
|
2606
|
-
|
|
2607
|
-
const threadRunsWaitMatch = pathOnly.match(/^\/api\/threads\/([^\/]+)\/runs\/wait$/);
|
|
2608
|
-
if (threadRunsWaitMatch && req.method === 'POST') {
|
|
2609
|
-
const threadId = threadRunsWaitMatch[1];
|
|
2610
|
-
const conv = queries.getConversation(threadId);
|
|
2611
|
-
|
|
2612
|
-
if (!conv) {
|
|
2613
|
-
sendJSON(req, res, 404, { error: 'Thread not found' });
|
|
2614
|
-
return;
|
|
2615
|
-
}
|
|
2616
|
-
|
|
2617
|
-
const activeEntry = activeExecutions.get(threadId);
|
|
2618
|
-
if (activeEntry) {
|
|
2619
|
-
sendJSON(req, res, 409, { error: 'Thread already has an active run' });
|
|
2620
|
-
return;
|
|
2621
|
-
}
|
|
2622
|
-
|
|
2623
|
-
let body = '';
|
|
2624
|
-
for await (const chunk of req) { body += chunk; }
|
|
2625
|
-
let parsed = {};
|
|
2626
|
-
try { parsed = body ? JSON.parse(body) : {}; } catch {}
|
|
2627
|
-
|
|
2628
|
-
const { input, agentId } = parsed;
|
|
2629
|
-
if (!input) {
|
|
2630
|
-
sendJSON(req, res, 400, { error: 'Missing input in request body' });
|
|
2631
|
-
return;
|
|
2632
|
-
}
|
|
2633
|
-
|
|
2634
|
-
const resolvedAgentId = agentId || conv.agentId || 'claude-code';
|
|
2635
|
-
const resolvedModel = parsed.model || conv.model || null;
|
|
2636
|
-
|
|
2637
|
-
const session = queries.createSession(threadId, resolvedAgentId, 'pending');
|
|
2638
|
-
const message = queries.createMessage(threadId, 'user', typeof input === 'string' ? input : JSON.stringify(input));
|
|
2639
|
-
|
|
2640
|
-
const waitPromise = new Promise((resolve, reject) => {
|
|
2641
|
-
const checkInterval = setInterval(() => {
|
|
2642
|
-
const updatedSession = queries.getSession(session.id);
|
|
2643
|
-
if (!updatedSession) {
|
|
2644
|
-
clearInterval(checkInterval);
|
|
2645
|
-
reject(new Error('Session not found'));
|
|
2646
|
-
return;
|
|
2647
|
-
}
|
|
2648
|
-
if (['success', 'error', 'interrupted', 'cancelled'].includes(updatedSession.status)) {
|
|
2649
|
-
clearInterval(checkInterval);
|
|
2650
|
-
resolve(updatedSession);
|
|
2651
|
-
}
|
|
2652
|
-
}, 500);
|
|
2653
|
-
|
|
2654
|
-
setTimeout(() => {
|
|
2655
|
-
clearInterval(checkInterval);
|
|
2656
|
-
const updatedSession = queries.getSession(session.id);
|
|
2657
|
-
resolve(updatedSession || session);
|
|
2658
|
-
}, 300000);
|
|
2659
|
-
});
|
|
2660
|
-
|
|
2661
|
-
processMessageWithStreaming(threadId, message.id, session.id, typeof input === 'string' ? input : JSON.stringify(input), resolvedAgentId, resolvedModel);
|
|
2662
|
-
|
|
2663
|
-
try {
|
|
2664
|
-
const completedSession = await waitPromise;
|
|
2665
|
-
sendJSON(req, res, 200, {
|
|
2666
|
-
id: completedSession.id,
|
|
2667
|
-
threadId: threadId,
|
|
2668
|
-
status: completedSession.status,
|
|
2669
|
-
started_at: completedSession.started_at,
|
|
2670
|
-
completed_at: completedSession.completed_at,
|
|
2671
|
-
agentId: resolvedAgentId,
|
|
2672
|
-
output: completedSession.response || null
|
|
2673
|
-
});
|
|
2674
|
-
} catch (err) {
|
|
2675
|
-
sendJSON(req, res, 500, { error: err.message });
|
|
2676
|
-
}
|
|
2677
|
-
return;
|
|
2678
|
-
}
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
const threadRunByIdMatch = pathOnly.match(/^\/api\/threads\/([^/]+)\/runs\/([^/]+)$/);
|
|
2682
|
-
if (threadRunByIdMatch) {
|
|
2683
|
-
const threadId = threadRunByIdMatch[1];
|
|
2684
|
-
const runId = threadRunByIdMatch[2];
|
|
2685
|
-
const session = queries.getSession(runId);
|
|
2686
|
-
|
|
2687
|
-
if (!session || session.conversationId !== threadId) {
|
|
2688
|
-
sendJSON(req, res, 404, { error: 'Run not found' });
|
|
2689
|
-
return;
|
|
2690
|
-
}
|
|
2691
|
-
|
|
2692
|
-
if (req.method === 'GET') {
|
|
2693
|
-
sendJSON(req, res, 200, {
|
|
2694
|
-
id: session.id,
|
|
2695
|
-
threadId: session.conversationId,
|
|
2696
|
-
status: session.status,
|
|
2697
|
-
started_at: session.started_at,
|
|
2698
|
-
completed_at: session.completed_at,
|
|
2699
|
-
agentId: session.agentId,
|
|
2700
|
-
input: null,
|
|
2701
|
-
output: null
|
|
2702
|
-
});
|
|
2703
|
-
return;
|
|
2704
|
-
}
|
|
2705
|
-
|
|
2706
|
-
if (req.method === 'DELETE') {
|
|
2707
|
-
queries.deleteSession(runId);
|
|
2708
|
-
sendJSON(req, res, 204, {});
|
|
2709
|
-
return;
|
|
2710
|
-
}
|
|
2711
|
-
|
|
2712
|
-
if (req.method === 'POST') {
|
|
2713
|
-
if (session.status !== 'interrupted') {
|
|
2714
|
-
sendJSON(req, res, 409, { error: 'Can only resume interrupted runs' });
|
|
2715
|
-
return;
|
|
2716
|
-
}
|
|
2717
|
-
|
|
2718
|
-
let body = '';
|
|
2719
|
-
for await (const chunk of req) { body += chunk; }
|
|
2720
|
-
let parsed = {};
|
|
2721
|
-
try { parsed = body ? JSON.parse(body) : {}; } catch {}
|
|
2722
|
-
|
|
2723
|
-
const { input } = parsed;
|
|
2724
|
-
if (!input) {
|
|
2725
|
-
sendJSON(req, res, 400, { error: 'Missing input in request body' });
|
|
2726
|
-
return;
|
|
2727
|
-
}
|
|
2728
|
-
|
|
2729
|
-
const conv = queries.getConversation(threadId);
|
|
2730
|
-
const resolvedAgentId = session.agentId || conv.agentId || 'claude-code';
|
|
2731
|
-
const resolvedModel = conv?.model || null;
|
|
2732
|
-
const cwd = conv?.workingDirectory || STARTUP_CWD;
|
|
2733
|
-
|
|
2734
|
-
queries.updateSession(runId, { status: 'pending' });
|
|
2735
|
-
|
|
2736
|
-
const message = queries.createMessage(threadId, 'user', typeof input === 'string' ? input : JSON.stringify(input));
|
|
2737
|
-
|
|
2738
|
-
processMessageWithStreaming(threadId, message.id, runId, typeof input === 'string' ? input : JSON.stringify(input), resolvedAgentId, resolvedModel);
|
|
2739
|
-
|
|
2740
|
-
sendJSON(req, res, 200, {
|
|
2741
|
-
id: session.id,
|
|
2742
|
-
threadId: threadId,
|
|
2743
|
-
status: 'pending',
|
|
2744
|
-
started_at: session.started_at,
|
|
2745
|
-
agentId: resolvedAgentId
|
|
2746
|
-
});
|
|
2747
|
-
return;
|
|
2748
|
-
}
|
|
2749
|
-
}
|
|
2750
|
-
|
|
2751
|
-
const threadRunWaitMatch = pathOnly.match(/^\/api\/threads\/([^\/]+)\/runs\/([^\/]+)\/wait$/);
|
|
2752
|
-
if (threadRunWaitMatch && req.method === 'GET') {
|
|
2753
|
-
const threadId = threadRunWaitMatch[1];
|
|
2754
|
-
const runId = threadRunWaitMatch[2];
|
|
2755
|
-
const session = queries.getSession(runId);
|
|
2756
|
-
|
|
2757
|
-
if (!session || session.conversationId !== threadId) {
|
|
2758
|
-
sendJSON(req, res, 404, { error: 'Run not found' });
|
|
2759
|
-
return;
|
|
2760
|
-
}
|
|
2761
|
-
|
|
2762
|
-
const waitPromise = new Promise((resolve) => {
|
|
2763
|
-
const checkInterval = setInterval(() => {
|
|
2764
|
-
const updatedSession = queries.getSession(runId);
|
|
2765
|
-
if (!updatedSession) {
|
|
2766
|
-
clearInterval(checkInterval);
|
|
2767
|
-
resolve(session);
|
|
2768
|
-
return;
|
|
2769
|
-
}
|
|
2770
|
-
if (['success', 'error', 'interrupted', 'cancelled'].includes(updatedSession.status)) {
|
|
2771
|
-
clearInterval(checkInterval);
|
|
2772
|
-
resolve(updatedSession);
|
|
2773
|
-
}
|
|
2774
|
-
}, 500);
|
|
2775
|
-
|
|
2776
|
-
setTimeout(() => {
|
|
2777
|
-
clearInterval(checkInterval);
|
|
2778
|
-
const updatedSession = queries.getSession(runId) || session;
|
|
2779
|
-
resolve(updatedSession);
|
|
2780
|
-
}, 30000);
|
|
2781
|
-
});
|
|
2782
|
-
|
|
2783
|
-
try {
|
|
2784
|
-
const completedSession = await waitPromise;
|
|
2785
|
-
sendJSON(req, res, 200, {
|
|
2786
|
-
id: completedSession.id,
|
|
2787
|
-
threadId: threadId,
|
|
2788
|
-
status: completedSession.status,
|
|
2789
|
-
started_at: completedSession.started_at,
|
|
2790
|
-
completed_at: completedSession.completed_at,
|
|
2791
|
-
agentId: completedSession.agentId,
|
|
2792
|
-
output: completedSession.response || null
|
|
2793
|
-
});
|
|
2794
|
-
} catch (err) {
|
|
2795
|
-
sendJSON(req, res, 500, { error: err.message });
|
|
2796
|
-
}
|
|
2797
|
-
return;
|
|
2798
|
-
}
|
|
2799
|
-
|
|
2800
|
-
const threadRunStreamMatch = pathOnly.match(/^\/api\/threads\/([^\/]+)\/runs\/([^\/]+)\/stream$/);
|
|
2801
|
-
if (threadRunStreamMatch && req.method === 'GET') {
|
|
2802
|
-
const threadId = threadRunStreamMatch[1];
|
|
2803
|
-
const runId = threadRunStreamMatch[2];
|
|
2804
|
-
const session = queries.getSession(runId);
|
|
2805
|
-
|
|
2806
|
-
if (!session || session.conversationId !== threadId) {
|
|
2807
|
-
sendJSON(req, res, 404, { error: 'Run not found' });
|
|
2808
|
-
return;
|
|
2809
|
-
}
|
|
2810
|
-
|
|
2811
|
-
res.writeHead(200, {
|
|
2812
|
-
'Content-Type': 'text/event-stream',
|
|
2813
|
-
'Cache-Control': 'no-cache',
|
|
2814
|
-
'Connection': 'keep-alive'
|
|
2815
|
-
});
|
|
2816
|
-
|
|
2817
|
-
const chunks = queries.getSessionChunks(runId, 0);
|
|
2818
|
-
for (const chunk of chunks) {
|
|
2819
|
-
res.write(`event: message\ndata: ${JSON.stringify(chunk)}\n\n`);
|
|
2820
|
-
}
|
|
2821
|
-
|
|
2822
|
-
const eventListeners = [];
|
|
2823
|
-
const broadcastListener = (event) => {
|
|
2824
|
-
if (event.sessionId === runId) {
|
|
2825
|
-
if (event.type === 'streaming_progress') {
|
|
2826
|
-
res.write(`event: message\ndata: ${JSON.stringify(event)}\n\n`);
|
|
2827
|
-
} else if (event.type === 'streaming_complete') {
|
|
2828
|
-
res.write(`event: done\ndata: ${JSON.stringify({ status: 'completed' })}\n\n`);
|
|
2829
|
-
res.end();
|
|
2830
|
-
} else if (event.type === 'streaming_error') {
|
|
2831
|
-
res.write(`event: error\ndata: ${JSON.stringify({ error: event.error })}\n\n`);
|
|
2832
|
-
res.end();
|
|
2833
|
-
}
|
|
2834
|
-
}
|
|
2835
|
-
};
|
|
2836
|
-
eventListeners.push(broadcastListener);
|
|
2837
|
-
|
|
2838
|
-
req.on('close', () => {
|
|
2839
|
-
eventListeners.length = 0;
|
|
2840
|
-
});
|
|
2841
|
-
|
|
2842
|
-
if (['success', 'error', 'interrupted', 'cancelled'].includes(session.status)) {
|
|
2843
|
-
res.write(`event: done\ndata: ${JSON.stringify({ status: session.status })}\n\n`);
|
|
2844
|
-
res.end();
|
|
2845
|
-
}
|
|
2846
|
-
|
|
2847
|
-
return;
|
|
2848
|
-
}
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
const threadRunCancelMatch = pathOnly.match(/^\/api\/threads\/([^/]+)\/runs\/([^/]+)\/cancel$/);
|
|
2852
|
-
if (threadRunCancelMatch && req.method === 'POST') {
|
|
2853
|
-
const threadId = threadRunCancelMatch[1];
|
|
2854
|
-
const runId = threadRunCancelMatch[2];
|
|
2855
|
-
const session = queries.getSession(runId);
|
|
2856
|
-
|
|
2857
|
-
if (!session || session.conversationId !== threadId) {
|
|
2858
|
-
sendJSON(req, res, 404, { error: 'Run not found' });
|
|
2859
|
-
return;
|
|
2860
|
-
}
|
|
2861
|
-
|
|
2862
|
-
const entry = activeExecutions.get(threadId);
|
|
2863
|
-
|
|
2864
|
-
if (entry && entry.sessionId === runId) {
|
|
2865
|
-
const { pid } = entry;
|
|
2866
|
-
if (pid) {
|
|
2867
|
-
try {
|
|
2868
|
-
process.kill(-pid, 'SIGKILL');
|
|
2869
|
-
} catch {
|
|
2870
|
-
try {
|
|
2871
|
-
process.kill(pid, 'SIGKILL');
|
|
2872
|
-
} catch (e) {}
|
|
2873
|
-
}
|
|
2874
|
-
}
|
|
2875
|
-
}
|
|
2876
|
-
|
|
2877
|
-
queries.updateSession(runId, { status: 'interrupted', completed_at: Date.now() });
|
|
2878
|
-
queries.setIsStreaming(threadId, false);
|
|
2879
|
-
activeExecutions.delete(threadId);
|
|
2880
|
-
|
|
2881
|
-
broadcastSync({
|
|
2882
|
-
type: 'streaming_complete',
|
|
2883
|
-
sessionId: runId,
|
|
2884
|
-
conversationId: threadId,
|
|
2885
|
-
interrupted: true,
|
|
2886
|
-
timestamp: Date.now()
|
|
2887
|
-
});
|
|
2888
|
-
|
|
2889
|
-
sendJSON(req, res, 204, {});
|
|
2890
|
-
return;
|
|
2891
|
-
}
|
|
2892
|
-
|
|
2893
2328
|
if (pathOnly === '/api/stt' && req.method === 'POST') {
|
|
2894
2329
|
try {
|
|
2895
2330
|
const chunks = [];
|