opencode-auto-resume 1.0.14 → 1.0.16
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/dist/index.js +92 -7
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -12364,12 +12364,18 @@ var TOOL_TEXT_PATTERNS = [
|
|
|
12364
12364
|
/<invoke\s+/i,
|
|
12365
12365
|
/<func(?:t|ti|tio|tion)?$/im,
|
|
12366
12366
|
/<par(?:a|am|ame|amet|amete|ameter)?$/im,
|
|
12367
|
-
/<(?:edit|write|read|bash|grep|glob|search|replace|execute|run)\s*(?:\s[^>]*)?\s*(?:\/>|>)/i
|
|
12367
|
+
/<(?:edit|write|read|bash|grep|glob|search|replace|execute|run)\s*(?:\s[^>]*)?\s*(?:\/>|>)/i,
|
|
12368
|
+
/{"type":\s*"function"/i,
|
|
12369
|
+
/{"name":\s*"[a-zA-Z_]/i,
|
|
12370
|
+
/\{\s*"type"\s*:?$/im,
|
|
12371
|
+
/\{\s*"name"\s*:?$/im
|
|
12368
12372
|
];
|
|
12369
12373
|
var TRUNCATED_XML_PATTERNS = [
|
|
12370
12374
|
{ open: /<function[^>]*>/i, close: /<\/function>/i },
|
|
12371
12375
|
{ open: /<parameter[^>]*>/i, close: /<\/parameter>/i },
|
|
12372
|
-
{ open: /<tool_call[^>]*>/i, close: /<\/tool_call>/i }
|
|
12376
|
+
{ open: /<tool_call[^>]*>/i, close: /<\/tool_call>/i },
|
|
12377
|
+
{ open: /\{\s*"type"\s*:/i, close: /}/ },
|
|
12378
|
+
{ open: /\{\s*"name"\s*:/i, close: /}/ }
|
|
12373
12379
|
];
|
|
12374
12380
|
var READY_TO_CONTINUE_PATTERNS = [
|
|
12375
12381
|
/ready to continue with task/i,
|
|
@@ -12408,7 +12414,9 @@ var DONE_CLAIM_PATTERNS = [
|
|
|
12408
12414
|
/^finished[.!]*$/im,
|
|
12409
12415
|
/^complete[.!]*$/im,
|
|
12410
12416
|
/^task\s+complete[.!]*$/im,
|
|
12417
|
+
/^task\s+completed[.!]*$/im,
|
|
12411
12418
|
/^all\s+tasks?\s+complete[.!]*$/im,
|
|
12419
|
+
/^all\s+tasks?\s+completed[.!]*$/im,
|
|
12412
12420
|
/^(?:i['']?m\s+)?done\s+with\s+task/im
|
|
12413
12421
|
];
|
|
12414
12422
|
var DONE_WITHOUT_WORK_PROMPT = "I need you to verify more carefully that you have actually completed all the required tasks. " + "Your response indicated you're done, but no work was detected. Please check your todo list " + "and complete any remaining work.";
|
|
@@ -12479,7 +12487,8 @@ var AutoResumePlugin = async (ctx, options) => {
|
|
|
12479
12487
|
todoCheckAttempts: 0,
|
|
12480
12488
|
toolTextTimer: null,
|
|
12481
12489
|
checkingToolText: false,
|
|
12482
|
-
lastSubagentCheckAt: 0
|
|
12490
|
+
lastSubagentCheckAt: 0,
|
|
12491
|
+
interruptedContinueCount: 0
|
|
12483
12492
|
};
|
|
12484
12493
|
sessions.set(sid, w);
|
|
12485
12494
|
}
|
|
@@ -12721,6 +12730,7 @@ var AutoResumePlugin = async (ctx, options) => {
|
|
|
12721
12730
|
w.continuing = false;
|
|
12722
12731
|
w.todoCheckAttempts = 0;
|
|
12723
12732
|
w.checkingToolText = false;
|
|
12733
|
+
w.interruptedContinueCount = 0;
|
|
12724
12734
|
if (w.toolTextTimer) {
|
|
12725
12735
|
clearTimeout(w.toolTextTimer);
|
|
12726
12736
|
w.toolTextTimer = null;
|
|
@@ -12770,16 +12780,31 @@ var AutoResumePlugin = async (ctx, options) => {
|
|
|
12770
12780
|
const partType = part.type;
|
|
12771
12781
|
let text = "";
|
|
12772
12782
|
let isReasoning = false;
|
|
12783
|
+
let isToolUse = false;
|
|
12773
12784
|
if (partType === "text") {
|
|
12774
12785
|
text = part.text ?? "";
|
|
12775
12786
|
} else if (partType === "reasoning") {
|
|
12776
12787
|
text = part.text ?? "";
|
|
12777
12788
|
isReasoning = true;
|
|
12789
|
+
} else if (partType === "tool_use") {
|
|
12790
|
+
isToolUse = true;
|
|
12791
|
+
const toolName = part.name ?? "unknown";
|
|
12792
|
+
text = `tool_use: ${toolName}`;
|
|
12778
12793
|
} else {
|
|
12779
12794
|
continue;
|
|
12780
12795
|
}
|
|
12781
12796
|
allAssistantText += text + `
|
|
12782
12797
|
`;
|
|
12798
|
+
if (isToolUse) {
|
|
12799
|
+
const candidate = {
|
|
12800
|
+
prompt: "continue",
|
|
12801
|
+
source: "tool-use",
|
|
12802
|
+
priority: 1
|
|
12803
|
+
};
|
|
12804
|
+
if (!bestCandidate || candidate.priority < bestCandidate.priority) {
|
|
12805
|
+
bestCandidate = candidate;
|
|
12806
|
+
}
|
|
12807
|
+
}
|
|
12783
12808
|
if (containsToolCallAsText(text)) {
|
|
12784
12809
|
const candidate = {
|
|
12785
12810
|
prompt: isReasoning ? THINKING_TOOL_RECOVERY_PROMPT : TOOL_TEXT_RECOVERY_PROMPT,
|
|
@@ -12819,6 +12844,18 @@ var AutoResumePlugin = async (ctx, options) => {
|
|
|
12819
12844
|
bestCandidate = candidate;
|
|
12820
12845
|
}
|
|
12821
12846
|
}
|
|
12847
|
+
if (!bestCandidate && containsDoneClaimPattern(text)) {
|
|
12848
|
+
const todos = w.todos || [];
|
|
12849
|
+
const hasOpenTodos = todos.some((t) => t.status === "pending" || t.status === "in_progress");
|
|
12850
|
+
if (hasOpenTodos) {
|
|
12851
|
+
await log("info", `${short(sid)} - model claims done but todos remain open. Sending recovery prompt...`);
|
|
12852
|
+
bestCandidate = {
|
|
12853
|
+
prompt: DONE_WITHOUT_WORK_PROMPT,
|
|
12854
|
+
source: "done-claim-no-emoji",
|
|
12855
|
+
priority: 1
|
|
12856
|
+
};
|
|
12857
|
+
}
|
|
12858
|
+
}
|
|
12822
12859
|
}
|
|
12823
12860
|
}
|
|
12824
12861
|
const trimmedText = allAssistantText.trim();
|
|
@@ -12832,6 +12869,18 @@ var AutoResumePlugin = async (ctx, options) => {
|
|
|
12832
12869
|
}
|
|
12833
12870
|
return;
|
|
12834
12871
|
}
|
|
12872
|
+
if (!bestCandidate) {
|
|
12873
|
+
const todos = w.todos || [];
|
|
12874
|
+
const hasOpenTodos = todos.some((t) => t.status === "pending" || t.status === "in_progress");
|
|
12875
|
+
if (hasOpenTodos) {
|
|
12876
|
+
await log("info", `${short(sid)} - no activity detected but todos remain open (${todos.filter((t) => t.status === "pending" || t.status === "in_progress").length} tasks). Sending continue...`);
|
|
12877
|
+
bestCandidate = {
|
|
12878
|
+
prompt: "continue",
|
|
12879
|
+
source: "idle-with-open-todos",
|
|
12880
|
+
priority: 2
|
|
12881
|
+
};
|
|
12882
|
+
}
|
|
12883
|
+
}
|
|
12835
12884
|
if (!bestCandidate)
|
|
12836
12885
|
return;
|
|
12837
12886
|
w.toolTextRecovered = true;
|
|
@@ -13036,7 +13085,7 @@ var AutoResumePlugin = async (ctx, options) => {
|
|
|
13036
13085
|
setTimeout(discoverSessions, 5000);
|
|
13037
13086
|
}
|
|
13038
13087
|
startTimer();
|
|
13039
|
-
function handleEvent(ev) {
|
|
13088
|
+
async function handleEvent(ev) {
|
|
13040
13089
|
const type = ev.type;
|
|
13041
13090
|
const sid = getSid(ev);
|
|
13042
13091
|
if (sid) {
|
|
@@ -13054,7 +13103,7 @@ var AutoResumePlugin = async (ctx, options) => {
|
|
|
13054
13103
|
w.lastActivityAt = Date.now();
|
|
13055
13104
|
resetSessionFlags(w);
|
|
13056
13105
|
log("debug", `${short(sid)} -> busy (${busyCount()})`);
|
|
13057
|
-
} else if (statusType === "idle") {
|
|
13106
|
+
} else if (statusType === "idle" || statusType === "interrupted") {
|
|
13058
13107
|
w.status = "idle";
|
|
13059
13108
|
resetIdleFlags(w);
|
|
13060
13109
|
const currentBusy = busyCount();
|
|
@@ -13066,13 +13115,14 @@ var AutoResumePlugin = async (ctx, options) => {
|
|
|
13066
13115
|
}
|
|
13067
13116
|
}
|
|
13068
13117
|
prevBusyCount = currentBusy;
|
|
13069
|
-
log("debug", `${short(sid)} -> idle (${currentBusy})`);
|
|
13118
|
+
log("debug", `${short(sid)} -> idle (${currentBusy})${statusType === "interrupted" ? " (interrupted)" : ""}`);
|
|
13070
13119
|
if (!w.toolTextRecovered && w.toolTextAttempts < maxRetries) {
|
|
13071
13120
|
if (w.toolTextTimer)
|
|
13072
13121
|
clearTimeout(w.toolTextTimer);
|
|
13122
|
+
const checkDelay = statusType === "interrupted" ? 500 : TOOL_TEXT_CHECK_DELAY_MS;
|
|
13073
13123
|
w.toolTextTimer = setTimeout(() => {
|
|
13074
13124
|
checkForToolCallAsText(sid, w);
|
|
13075
|
-
},
|
|
13125
|
+
}, checkDelay);
|
|
13076
13126
|
}
|
|
13077
13127
|
} else if (statusType === "retry") {
|
|
13078
13128
|
touchSession(sid);
|
|
@@ -13109,6 +13159,41 @@ var AutoResumePlugin = async (ctx, options) => {
|
|
|
13109
13159
|
}
|
|
13110
13160
|
break;
|
|
13111
13161
|
}
|
|
13162
|
+
case "session.interrupted": {
|
|
13163
|
+
if (!sid)
|
|
13164
|
+
break;
|
|
13165
|
+
const w = sessions.get(sid);
|
|
13166
|
+
if (w) {
|
|
13167
|
+
const wasJustContinued = w.continuing || Date.now() - w.lastRetryAt < 2000;
|
|
13168
|
+
w.status = "idle";
|
|
13169
|
+
resetIdleFlags(w);
|
|
13170
|
+
log("debug", `${short(sid)} -> interrupted${wasJustContinued ? " (after continue)" : ""}`);
|
|
13171
|
+
if (wasJustContinued && w.interruptedContinueCount < 3 && !w.toolTextRecovered && w.toolTextAttempts < maxRetries) {
|
|
13172
|
+
w.interruptedContinueCount++;
|
|
13173
|
+
await log("info", `${short(sid)} - continue was interrupted (${w.interruptedContinueCount}/3), retrying...`);
|
|
13174
|
+
w.continuing = false;
|
|
13175
|
+
try {
|
|
13176
|
+
await sendContinuePrompt(sid, "continue", w);
|
|
13177
|
+
await log("info", `${short(sid)} - interrupted continue retried`);
|
|
13178
|
+
} catch (err) {
|
|
13179
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
13180
|
+
await log("warn", `${short(sid)} - interrupted continue retry failed: ${errMsg}`);
|
|
13181
|
+
}
|
|
13182
|
+
return;
|
|
13183
|
+
} else if (wasJustContinued && w.interruptedContinueCount >= 3) {
|
|
13184
|
+
await log("warn", `${short(sid)} - too many interrupted continues (${w.interruptedContinueCount}), stopping retries`);
|
|
13185
|
+
w.interruptedContinueCount = 0;
|
|
13186
|
+
}
|
|
13187
|
+
if (!w.toolTextRecovered && w.toolTextAttempts < maxRetries) {
|
|
13188
|
+
if (w.toolTextTimer)
|
|
13189
|
+
clearTimeout(w.toolTextTimer);
|
|
13190
|
+
w.toolTextTimer = setTimeout(() => {
|
|
13191
|
+
checkForToolCallAsText(sid, w);
|
|
13192
|
+
}, 500);
|
|
13193
|
+
}
|
|
13194
|
+
}
|
|
13195
|
+
break;
|
|
13196
|
+
}
|
|
13112
13197
|
case "todo.updated": {
|
|
13113
13198
|
if (!sid)
|
|
13114
13199
|
break;
|
package/package.json
CHANGED