agentgui 1.0.148 → 1.0.149
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/database.js +4 -4
- package/package.json +1 -1
- package/server.js +78 -39
package/database.js
CHANGED
|
@@ -335,14 +335,14 @@ export const queries = {
|
|
|
335
335
|
|
|
336
336
|
getSessionsProcessingLongerThan(minutes) {
|
|
337
337
|
const cutoff = Date.now() - (minutes * 60 * 1000);
|
|
338
|
-
const stmt = db.prepare(
|
|
339
|
-
return stmt.all(
|
|
338
|
+
const stmt = db.prepare("SELECT * FROM sessions WHERE status IN ('active', 'pending') AND started_at < ?");
|
|
339
|
+
return stmt.all(cutoff);
|
|
340
340
|
},
|
|
341
341
|
|
|
342
342
|
cleanupOrphanedSessions(days) {
|
|
343
343
|
const cutoff = Date.now() - (days * 24 * 60 * 60 * 1000);
|
|
344
|
-
const stmt = db.prepare(
|
|
345
|
-
const result = stmt.run(
|
|
344
|
+
const stmt = db.prepare("DELETE FROM sessions WHERE status IN ('active', 'pending') AND started_at < ?");
|
|
345
|
+
const result = stmt.run(cutoff);
|
|
346
346
|
return result.changes || 0;
|
|
347
347
|
},
|
|
348
348
|
|
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -23,6 +23,9 @@ const SYSTEM_PROMPT = `Write all responses as clean semantic HTML. Use tags like
|
|
|
23
23
|
|
|
24
24
|
const activeExecutions = new Map();
|
|
25
25
|
const messageQueues = new Map();
|
|
26
|
+
const STUCK_AGENT_THRESHOLD_MS = 600000;
|
|
27
|
+
const NO_PID_GRACE_PERIOD_MS = 60000;
|
|
28
|
+
const STALE_SESSION_MIN_AGE_MS = 30000;
|
|
26
29
|
|
|
27
30
|
const debugLog = (msg) => {
|
|
28
31
|
const timestamp = new Date().toISOString();
|
|
@@ -648,7 +651,7 @@ function persistChunkWithRetry(sessionId, conversationId, sequence, blockType, b
|
|
|
648
651
|
|
|
649
652
|
async function processMessageWithStreaming(conversationId, messageId, sessionId, content, agentId) {
|
|
650
653
|
const startTime = Date.now();
|
|
651
|
-
activeExecutions.set(conversationId, { pid: null, startTime, sessionId });
|
|
654
|
+
activeExecutions.set(conversationId, { pid: null, startTime, sessionId, lastActivity: startTime });
|
|
652
655
|
queries.setIsStreaming(conversationId, true);
|
|
653
656
|
queries.updateSession(sessionId, { status: 'active' });
|
|
654
657
|
|
|
@@ -665,6 +668,8 @@ async function processMessageWithStreaming(conversationId, messageId, sessionId,
|
|
|
665
668
|
|
|
666
669
|
const onEvent = (parsed) => {
|
|
667
670
|
eventCount++;
|
|
671
|
+
const entry = activeExecutions.get(conversationId);
|
|
672
|
+
if (entry) entry.lastActivity = Date.now();
|
|
668
673
|
debugLog(`[stream] Event ${eventCount}: type=${parsed.type}`);
|
|
669
674
|
|
|
670
675
|
if (parsed.type === 'system') {
|
|
@@ -1045,25 +1050,27 @@ server.on('error', (err) => {
|
|
|
1045
1050
|
function recoverStaleSessions() {
|
|
1046
1051
|
try {
|
|
1047
1052
|
const staleSessions = queries.getActiveSessions ? queries.getActiveSessions() : [];
|
|
1053
|
+
const now = Date.now();
|
|
1048
1054
|
let recoveredCount = 0;
|
|
1049
1055
|
for (const session of staleSessions) {
|
|
1050
|
-
if (
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
}
|
|
1056
|
+
if (activeExecutions.has(session.conversationId)) continue;
|
|
1057
|
+
const sessionAge = now - session.started_at;
|
|
1058
|
+
if (sessionAge < STALE_SESSION_MIN_AGE_MS) continue;
|
|
1059
|
+
queries.updateSession(session.id, {
|
|
1060
|
+
status: 'error',
|
|
1061
|
+
error: 'Agent died unexpectedly (server restart)',
|
|
1062
|
+
completed_at: now
|
|
1063
|
+
});
|
|
1064
|
+
queries.setIsStreaming(session.conversationId, false);
|
|
1065
|
+
broadcastSync({
|
|
1066
|
+
type: 'streaming_error',
|
|
1067
|
+
sessionId: session.id,
|
|
1068
|
+
conversationId: session.conversationId,
|
|
1069
|
+
error: 'Agent died unexpectedly (server restart)',
|
|
1070
|
+
recoverable: false,
|
|
1071
|
+
timestamp: now
|
|
1072
|
+
});
|
|
1073
|
+
recoveredCount++;
|
|
1067
1074
|
}
|
|
1068
1075
|
if (recoveredCount > 0) {
|
|
1069
1076
|
console.log(`[RECOVERY] Recovered ${recoveredCount} stale active session(s)`);
|
|
@@ -1073,31 +1080,63 @@ function recoverStaleSessions() {
|
|
|
1073
1080
|
}
|
|
1074
1081
|
}
|
|
1075
1082
|
|
|
1083
|
+
function isProcessAlive(pid) {
|
|
1084
|
+
try {
|
|
1085
|
+
process.kill(pid, 0);
|
|
1086
|
+
return true;
|
|
1087
|
+
} catch (err) {
|
|
1088
|
+
if (err.code === 'EPERM') return true;
|
|
1089
|
+
return false;
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
function markAgentDead(conversationId, entry, reason) {
|
|
1094
|
+
if (!activeExecutions.has(conversationId)) return;
|
|
1095
|
+
activeExecutions.delete(conversationId);
|
|
1096
|
+
queries.setIsStreaming(conversationId, false);
|
|
1097
|
+
if (entry.sessionId) {
|
|
1098
|
+
queries.updateSession(entry.sessionId, {
|
|
1099
|
+
status: 'error',
|
|
1100
|
+
error: reason,
|
|
1101
|
+
completed_at: Date.now()
|
|
1102
|
+
});
|
|
1103
|
+
}
|
|
1104
|
+
broadcastSync({
|
|
1105
|
+
type: 'streaming_error',
|
|
1106
|
+
sessionId: entry.sessionId,
|
|
1107
|
+
conversationId,
|
|
1108
|
+
error: reason,
|
|
1109
|
+
recoverable: false,
|
|
1110
|
+
timestamp: Date.now()
|
|
1111
|
+
});
|
|
1112
|
+
drainMessageQueue(conversationId);
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1076
1115
|
function performAgentHealthCheck() {
|
|
1116
|
+
const now = Date.now();
|
|
1077
1117
|
for (const [conversationId, entry] of activeExecutions) {
|
|
1078
|
-
if (!entry
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1118
|
+
if (!entry) continue;
|
|
1119
|
+
|
|
1120
|
+
if (entry.pid) {
|
|
1121
|
+
if (!isProcessAlive(entry.pid)) {
|
|
1122
|
+
debugLog(`[HEALTH] Agent PID ${entry.pid} for conv ${conversationId} is dead`);
|
|
1123
|
+
markAgentDead(conversationId, entry, 'Agent process died unexpectedly');
|
|
1124
|
+
} else if (now - entry.lastActivity > STUCK_AGENT_THRESHOLD_MS) {
|
|
1125
|
+
debugLog(`[HEALTH] Agent PID ${entry.pid} for conv ${conversationId} has no activity for ${Math.round((now - entry.lastActivity) / 1000)}s`);
|
|
1126
|
+
broadcastSync({
|
|
1127
|
+
type: 'streaming_error',
|
|
1128
|
+
sessionId: entry.sessionId,
|
|
1129
|
+
conversationId,
|
|
1130
|
+
error: 'Agent may be stuck (no activity for 10 minutes)',
|
|
1131
|
+
recoverable: true,
|
|
1132
|
+
timestamp: now
|
|
1090
1133
|
});
|
|
1091
1134
|
}
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
conversationId,
|
|
1096
|
-
|
|
1097
|
-
recoverable: false,
|
|
1098
|
-
timestamp: Date.now()
|
|
1099
|
-
});
|
|
1100
|
-
drainMessageQueue(conversationId);
|
|
1135
|
+
} else {
|
|
1136
|
+
if (now - entry.startTime > NO_PID_GRACE_PERIOD_MS) {
|
|
1137
|
+
debugLog(`[HEALTH] Agent for conv ${conversationId} never reported PID after ${Math.round((now - entry.startTime) / 1000)}s`);
|
|
1138
|
+
markAgentDead(conversationId, entry, 'Agent failed to start (no PID reported)');
|
|
1139
|
+
}
|
|
1101
1140
|
}
|
|
1102
1141
|
}
|
|
1103
1142
|
}
|