agentgui 1.0.387 → 1.0.388
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/.prd +0 -26
- package/package.json +1 -1
- package/verify-cancel-impl.mjs +119 -0
package/.prd
CHANGED
|
@@ -12,32 +12,6 @@ Transform AgentGUI into a fully ACP (Agent Connect Protocol) v0.2.3 compliant se
|
|
|
12
12
|
|
|
13
13
|
## Dependency Graph & Execution Waves
|
|
14
14
|
|
|
15
|
-
### WAVE 3: Streaming & Run Control (2 items - after Wave 2)
|
|
16
|
-
|
|
17
|
-
**3.1** SSE (Server-Sent Events) Streaming
|
|
18
|
-
- BLOCKS: 2.1, 2.2, 2.3
|
|
19
|
-
- BLOCKED_BY: 4.1
|
|
20
|
-
- Implement SSE endpoint format (Content-Type: text/event-stream)
|
|
21
|
-
- Stream run outputs as ACP `RunOutputStream` format
|
|
22
|
-
- Support both `ValueRunResultUpdate` and `CustomRunResultUpdate` modes
|
|
23
|
-
- Event types: data, error, done
|
|
24
|
-
- Keep-alive pings every 15 seconds
|
|
25
|
-
- Handle client disconnect gracefully
|
|
26
|
-
- Convert existing chunk/event stream to SSE format
|
|
27
|
-
- Parallel SSE + WebSocket support (both work simultaneously)
|
|
28
|
-
|
|
29
|
-
**3.2** Run Cancellation & Control
|
|
30
|
-
- BLOCKS: 1.1, 1.2
|
|
31
|
-
- BLOCKED_BY: 4.1
|
|
32
|
-
- Implement run status state machine: pending → active → completed/error/cancelled
|
|
33
|
-
- Cancel endpoint kills agent process (SIGTERM then SIGKILL)
|
|
34
|
-
- Update run status to 'cancelled' in database
|
|
35
|
-
- Broadcast cancellation via WebSocket
|
|
36
|
-
- Clean up active execution tracking
|
|
37
|
-
- Return 409 if run already completed/cancelled
|
|
38
|
-
- Wait endpoint implements long-polling (30s timeout, return current status)
|
|
39
|
-
- Handle graceful degradation if agent doesn't support cancellation
|
|
40
|
-
|
|
41
15
|
### WAVE 4: UI Fixes & Optimization (3 items - after Wave 3)
|
|
42
16
|
|
|
43
17
|
**4.1** Thread Sidebar UI Consistency
|
package/package.json
CHANGED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
// Verify run cancellation implementation without needing running server
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
|
|
4
|
+
const serverContent = fs.readFileSync('/config/workspace/agentgui/server.js', 'utf-8');
|
|
5
|
+
|
|
6
|
+
console.log('=== VERIFYING RUN CANCELLATION IMPLEMENTATION ===\n');
|
|
7
|
+
|
|
8
|
+
const checks = [
|
|
9
|
+
{
|
|
10
|
+
name: 'Enhanced /api/runs/{run_id}/cancel endpoint',
|
|
11
|
+
test: () => {
|
|
12
|
+
const hasGetRun = serverContent.includes('acpQueries.getRun(runId)') || serverContent.includes('queries.getRun(runId)');
|
|
13
|
+
const hasStatusCheck = serverContent.includes("['success', 'error', 'cancelled'].includes");
|
|
14
|
+
const has409 = serverContent.includes('sendJSON(req, res, 409');
|
|
15
|
+
return hasGetRun && hasStatusCheck && has409;
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
name: 'Process termination with SIGTERM then SIGKILL',
|
|
20
|
+
test: () => {
|
|
21
|
+
const hasSigterm = serverContent.includes("process.kill(-execution.pid, 'SIGTERM')") ||
|
|
22
|
+
serverContent.includes("process.kill(execution.pid, 'SIGTERM')");
|
|
23
|
+
const hasSigkill = serverContent.includes("'SIGKILL'");
|
|
24
|
+
const hasTimeout = serverContent.includes('setTimeout') && serverContent.includes('3000');
|
|
25
|
+
return hasSigterm && hasSigkill && hasTimeout;
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: 'WebSocket broadcast on cancellation',
|
|
30
|
+
test: () => {
|
|
31
|
+
return serverContent.includes("type: 'streaming_cancelled'") &&
|
|
32
|
+
serverContent.includes('broadcastSync');
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: 'Active executions cleanup',
|
|
37
|
+
test: () => {
|
|
38
|
+
return serverContent.includes('activeExecutions.delete(threadId)') &&
|
|
39
|
+
serverContent.includes('queries.setIsStreaming(threadId, false)');
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: 'Thread-based cancel endpoint /api/threads/{thread_id}/runs/{run_id}/cancel',
|
|
44
|
+
test: () => {
|
|
45
|
+
return serverContent.includes('threadRunCancelMatch') &&
|
|
46
|
+
serverContent.includes('/api/threads/([^/]+)/runs/([^/]+)/cancel');
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
name: 'Thread-based wait endpoint /api/threads/{thread_id}/runs/{run_id}/wait',
|
|
51
|
+
test: () => {
|
|
52
|
+
return serverContent.includes('threadRunWaitMatch') &&
|
|
53
|
+
serverContent.includes('/api/threads/([^/]+)/runs/([^/]+)/wait');
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: 'Wait endpoint long-polling (30s timeout, 500ms poll)',
|
|
58
|
+
test: () => {
|
|
59
|
+
const hasWait = serverContent.includes('/wait') && serverContent.includes('GET');
|
|
60
|
+
const hasPoll = serverContent.includes('setInterval') && serverContent.includes('500');
|
|
61
|
+
const hasTimeout = serverContent.includes('30000');
|
|
62
|
+
return hasWait && hasPoll && hasTimeout;
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: 'Thread validation in thread-based endpoints',
|
|
67
|
+
test: () => {
|
|
68
|
+
return serverContent.includes('run.thread_id !== threadId') &&
|
|
69
|
+
serverContent.includes('Run does not belong to specified thread');
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: 'Session status update on cancellation',
|
|
74
|
+
test: () => {
|
|
75
|
+
return serverContent.includes("status: 'error'") &&
|
|
76
|
+
serverContent.includes("error: 'Cancelled by user'");
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: 'Database run status update to cancelled',
|
|
81
|
+
test: () => {
|
|
82
|
+
const hasCancelRun = serverContent.includes('cancelRun(runId)') ||
|
|
83
|
+
serverContent.includes('cancelledRun');
|
|
84
|
+
const hasUpdateStatus = serverContent.includes('updateRunStatus');
|
|
85
|
+
return hasCancelRun || hasUpdateStatus;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
];
|
|
89
|
+
|
|
90
|
+
let passed = 0;
|
|
91
|
+
let failed = 0;
|
|
92
|
+
|
|
93
|
+
checks.forEach(check => {
|
|
94
|
+
try {
|
|
95
|
+
const result = check.test();
|
|
96
|
+
if (result) {
|
|
97
|
+
console.log(`✓ ${check.name}`);
|
|
98
|
+
passed++;
|
|
99
|
+
} else {
|
|
100
|
+
console.log(`✗ ${check.name}`);
|
|
101
|
+
failed++;
|
|
102
|
+
}
|
|
103
|
+
} catch (e) {
|
|
104
|
+
console.log(`✗ ${check.name} (error: ${e.message})`);
|
|
105
|
+
failed++;
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
console.log(`\n=== SUMMARY ===`);
|
|
110
|
+
console.log(`Passed: ${passed}/${checks.length}`);
|
|
111
|
+
console.log(`Failed: ${failed}/${checks.length}`);
|
|
112
|
+
|
|
113
|
+
if (passed === checks.length) {
|
|
114
|
+
console.log('\n✓ ALL IMPLEMENTATION CHECKS PASSED');
|
|
115
|
+
process.exit(0);
|
|
116
|
+
} else {
|
|
117
|
+
console.log('\n✗ SOME IMPLEMENTATION CHECKS FAILED');
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|