agentgui 1.0.649 → 1.0.650
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/lib/claude-runner.js +4 -0
- package/package.json +1 -1
- package/server.js +17 -65
- package/static/js/client.js +1 -5
package/lib/claude-runner.js
CHANGED
|
@@ -203,6 +203,10 @@ class AgentRunner {
|
|
|
203
203
|
|
|
204
204
|
proc.on('close', (code) => {
|
|
205
205
|
clearTimeout(timeoutHandle);
|
|
206
|
+
// Close stdin when process exits - it was kept open for steering during execution
|
|
207
|
+
if (proc.stdin && !proc.stdin.destroyed) {
|
|
208
|
+
try { proc.stdin.end(); } catch (e) {}
|
|
209
|
+
}
|
|
206
210
|
if (timedOut) return;
|
|
207
211
|
|
|
208
212
|
if (authError) {
|
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -4643,89 +4643,41 @@ server.on('error', (err) => {
|
|
|
4643
4643
|
}
|
|
4644
4644
|
});
|
|
4645
4645
|
|
|
4646
|
+
// On startup: mark all active/pending sessions as interrupted (server was down, they didn't complete).
|
|
4647
|
+
// Then resumeInterruptedStreams will pick up recent ones for auto-resume.
|
|
4646
4648
|
function recoverStaleSessions() {
|
|
4647
4649
|
try {
|
|
4648
|
-
const
|
|
4649
|
-
const
|
|
4650
|
-
|
|
4651
|
-
const resumable = new Set();
|
|
4652
|
-
const resumableConvs = queries.getResumableConversations ? queries.getResumableConversations(RESUME_WINDOW_MS) : [];
|
|
4653
|
-
for (const conv of resumableConvs) {
|
|
4654
|
-
resumable.add(conv.id); // All agent types are resumable
|
|
4655
|
-
}
|
|
4656
|
-
|
|
4657
|
-
const staleSessions = queries.getActiveSessions ? queries.getActiveSessions() : [];
|
|
4658
|
-
let markedCount = 0;
|
|
4650
|
+
const RESUME_WINDOW_MS = 600000;
|
|
4651
|
+
const cutoff = Date.now() - RESUME_WINDOW_MS;
|
|
4652
|
+
const staleSessions = queries.getActiveSessions();
|
|
4659
4653
|
for (const session of staleSessions) {
|
|
4660
|
-
if (activeExecutions.has(session.conversationId)) continue;
|
|
4661
|
-
if (resumable.has(session.conversationId)) continue;
|
|
4662
4654
|
queries.updateSession(session.id, {
|
|
4663
|
-
status: 'error',
|
|
4655
|
+
status: session.started_at > cutoff ? 'interrupted' : 'error',
|
|
4664
4656
|
error: 'Server restarted',
|
|
4665
|
-
completed_at: now
|
|
4657
|
+
completed_at: Date.now()
|
|
4666
4658
|
});
|
|
4667
|
-
markedCount++;
|
|
4668
4659
|
}
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
const streamingConvs = queries.getStreamingConversations ? queries.getStreamingConversations() : [];
|
|
4674
|
-
let clearedCount = 0;
|
|
4675
|
-
for (const conv of streamingConvs) {
|
|
4676
|
-
if (activeExecutions.has(conv.id)) continue;
|
|
4677
|
-
if (resumable.has(conv.id)) continue;
|
|
4678
|
-
queries.setIsStreaming(conv.id, false);
|
|
4679
|
-
clearedCount++;
|
|
4680
|
-
}
|
|
4681
|
-
if (clearedCount > 0) {
|
|
4682
|
-
console.log(`[RECOVERY] Cleared isStreaming flag on ${clearedCount} stale conversation(s)`);
|
|
4683
|
-
}
|
|
4684
|
-
if (resumable.size > 0) {
|
|
4685
|
-
console.log(`[RECOVERY] Found ${resumable.size} resumable conversation(s)`);
|
|
4660
|
+
// Clear all isStreaming flags - nothing is running yet
|
|
4661
|
+
queries.clearAllStreamingFlags();
|
|
4662
|
+
if (staleSessions.length > 0) {
|
|
4663
|
+
console.log(`[RECOVERY] Marked ${staleSessions.length} stale session(s); cleared streaming flags`);
|
|
4686
4664
|
}
|
|
4687
4665
|
} catch (err) {
|
|
4688
|
-
console.error('[RECOVERY]
|
|
4666
|
+
console.error('[RECOVERY] Error:', err.message);
|
|
4689
4667
|
}
|
|
4690
4668
|
}
|
|
4691
4669
|
|
|
4670
|
+
// Resume conversations with recently interrupted sessions (started within 10 min).
|
|
4692
4671
|
async function resumeInterruptedStreams() {
|
|
4693
4672
|
try {
|
|
4694
|
-
const
|
|
4695
|
-
const cutoff = Date.now() - RESUME_WINDOW_MS;
|
|
4696
|
-
|
|
4697
|
-
// Get conversations marked as streaming in database (isStreaming=1)
|
|
4698
|
-
// Fall back to getResumableConversations if isStreaming is not being used
|
|
4699
|
-
let toResume = [];
|
|
4700
|
-
|
|
4701
|
-
// Primary: Check database isStreaming flag for conversations still marked as active
|
|
4702
|
-
// Exclude conversations whose last session completed or started more than 10 min ago
|
|
4703
|
-
const streamingConvs = queries.getConversations().filter(c => {
|
|
4704
|
-
if (c.isStreaming !== 1) return false;
|
|
4705
|
-
const lastSession = queries.getLatestSession(c.id);
|
|
4706
|
-
if (!lastSession) return false;
|
|
4707
|
-
if (lastSession.status === 'complete') return false;
|
|
4708
|
-
// Only resume if session started within the last 10 minutes
|
|
4709
|
-
return lastSession.started_at > cutoff;
|
|
4710
|
-
});
|
|
4711
|
-
|
|
4712
|
-
if (streamingConvs.length > 0) {
|
|
4713
|
-
toResume = streamingConvs;
|
|
4714
|
-
} else {
|
|
4715
|
-
// Fallback: Use session-based resumable conversations (already filtered by 10 min)
|
|
4716
|
-
toResume = queries.getResumableConversations ? queries.getResumableConversations(RESUME_WINDOW_MS) : [];
|
|
4717
|
-
}
|
|
4718
|
-
|
|
4673
|
+
const toResume = queries.getResumableConversations(600000);
|
|
4719
4674
|
if (toResume.length === 0) return;
|
|
4720
|
-
|
|
4721
4675
|
console.log(`[RESUME] Resuming ${toResume.length} interrupted conversation(s)`);
|
|
4722
|
-
|
|
4723
4676
|
for (let i = 0; i < toResume.length; i++) {
|
|
4724
4677
|
const conv = toResume[i];
|
|
4725
4678
|
try {
|
|
4726
|
-
const
|
|
4727
|
-
|
|
4728
|
-
await resumeConversation(conv.id, previousSessionId, 'Server restarted, resuming');
|
|
4679
|
+
const lastSession = queries.getLatestSession(conv.id);
|
|
4680
|
+
await resumeConversation(conv.id, lastSession?.id || null, 'Server restarted');
|
|
4729
4681
|
if (i < toResume.length - 1) await new Promise(r => setTimeout(r, 200));
|
|
4730
4682
|
} catch (err) {
|
|
4731
4683
|
console.error(`[RESUME] Failed to resume conv ${conv.id}: ${err.message}`);
|
|
@@ -4733,7 +4685,7 @@ async function resumeInterruptedStreams() {
|
|
|
4733
4685
|
}
|
|
4734
4686
|
}
|
|
4735
4687
|
} catch (err) {
|
|
4736
|
-
console.error('[RESUME] Error
|
|
4688
|
+
console.error('[RESUME] Error:', err.message);
|
|
4737
4689
|
}
|
|
4738
4690
|
}
|
|
4739
4691
|
|
package/static/js/client.js
CHANGED
|
@@ -1453,7 +1453,7 @@ class AgentGUIClient {
|
|
|
1453
1453
|
this.enableControls();
|
|
1454
1454
|
}
|
|
1455
1455
|
|
|
1456
|
-
|
|
1456
|
+
handleAllConversationsDeleted(data) {
|
|
1457
1457
|
window.ConversationState?.clear('all_deleted');
|
|
1458
1458
|
this.state.currentConversation = null;
|
|
1459
1459
|
this.state.conversations = [];
|
|
@@ -1462,10 +1462,6 @@ class AgentGUIClient {
|
|
|
1462
1462
|
this.conversationListCache = { data: [], timestamp: 0, ttl: 30000 };
|
|
1463
1463
|
this.draftPrompts.clear();
|
|
1464
1464
|
window.dispatchEvent(new CustomEvent('conversation-deselected'));
|
|
1465
|
-
if (window.conversationManager) {
|
|
1466
|
-
this.state.currentConversation = null;
|
|
1467
|
-
await window.conversationManager.loadConversations();
|
|
1468
|
-
}
|
|
1469
1465
|
const outputEl = document.getElementById('output');
|
|
1470
1466
|
if (outputEl) outputEl.innerHTML = '';
|
|
1471
1467
|
}
|