Skip to content

Commit f91bf02

Browse files
magiclaude
authored andcommitted
fix: resolve task resumption stalling and improve error handling
- Add timeout handling for resume state to prevent indefinite waiting - Fix resumeTask function to properly handle new content without duplication - Improve server-side resume logic with fallback to new task on timeout - Add better validation and logging for resume operations 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent abc7ade commit f91bf02

3 files changed

Lines changed: 30 additions & 9 deletions

File tree

demo/package-lock.json

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

demo/server.js

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,18 +69,28 @@ wss.on('connection', (ws, req) => {
6969

7070
// If resuming, wait for the state before starting the task
7171
if (isResume) {
72-
pendingState = new Promise((resolve) => {
72+
pendingState = new Promise((resolve, reject) => {
73+
let timeout;
7374
const stateHandler = (message) => {
7475
try {
7576
const data = JSON.parse(message.toString());
7677
if (data.type === 'resume_state') {
78+
clearTimeout(timeout);
7779
resolve(data.finalState);
7880
ws.removeListener('message', stateHandler);
7981
}
8082
} catch (error) {
8183
console.error('State parse error:', error);
8284
}
8385
};
86+
87+
// Set timeout for resume state
88+
timeout = setTimeout(() => {
89+
console.warn(`⏰ Resume state timeout for session ${sessionId}, falling back to new task`);
90+
ws.removeListener('message', stateHandler);
91+
resolve(null); // Resolve with null to fallback to regular task
92+
}, 5000);
93+
8494
ws.on('message', stateHandler);
8595
});
8696
}
@@ -94,11 +104,17 @@ wss.on('connection', (ws, req) => {
94104

95105
if (isResume && pendingState) {
96106
const finalState = await pendingState;
97-
console.log(`📋 Resuming task with ${finalState.messages.length} messages`);
98-
99-
taskController = startDemoTask(prompt, (data) => {
100-
ws.send(JSON.stringify(data));
101-
}, { ...options, finalState, isResume: true });
107+
if (finalState && finalState.messages && finalState.messages.length > 0) {
108+
console.log(`📋 Resuming task with ${finalState.messages.length} messages`);
109+
taskController = startDemoTask(prompt, (data) => {
110+
ws.send(JSON.stringify(data));
111+
}, { ...options, finalState, isResume: true });
112+
} else {
113+
console.log(`⚠️ Resume failed or no state, starting new task`);
114+
taskController = startDemoTask(prompt, (data) => {
115+
ws.send(JSON.stringify(data));
116+
}, options);
117+
}
102118
} else {
103119
taskController = startDemoTask(prompt, (data) => {
104120
ws.send(JSON.stringify(data));

src/core/engine.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,16 @@ export function resumeTask(
111111
content: newContent,
112112
id: uuidv4()
113113
});
114+
115+
// Update the finalState with the new messages
116+
finalState.messages = messages;
117+
118+
// Resume with the full state, using a placeholder content since we already added the message
119+
return runTask(agent, 'Resume task', finalState);
114120
}
115121

116-
// Resume with the full state
117-
return runTask(agent, newContent || 'Continue with the task', finalState);
122+
// Resume with the full state without adding new content
123+
return runTask(agent, 'Continue with the task', finalState);
118124
}
119125

120126
/**

0 commit comments

Comments
 (0)