opencode-auto-resume 1.0.18 → 1.0.20
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 +95 -30
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -12583,9 +12583,9 @@ var AutoResumePlugin = async (ctx, options) => {
|
|
|
12583
12583
|
return;
|
|
12584
12584
|
}
|
|
12585
12585
|
w.continuing = true;
|
|
12586
|
+
let agent;
|
|
12587
|
+
let model;
|
|
12586
12588
|
try {
|
|
12587
|
-
let agent2;
|
|
12588
|
-
let model2;
|
|
12589
12589
|
const msgResp = await ctx.client.session.messages({ path: { id: sid } });
|
|
12590
12590
|
const msgs = extractMessages(msgResp);
|
|
12591
12591
|
for (let i = msgs.length - 1;i >= 0; i--) {
|
|
@@ -12594,11 +12594,11 @@ var AutoResumePlugin = async (ctx, options) => {
|
|
|
12594
12594
|
if (role === "user") {
|
|
12595
12595
|
const rawAgent = msg.agent;
|
|
12596
12596
|
if (typeof rawAgent === "string") {
|
|
12597
|
-
|
|
12597
|
+
agent = rawAgent;
|
|
12598
12598
|
} else {
|
|
12599
12599
|
const fallbackAgent = msg.info?.agent;
|
|
12600
12600
|
if (typeof fallbackAgent === "string") {
|
|
12601
|
-
|
|
12601
|
+
agent = fallbackAgent;
|
|
12602
12602
|
}
|
|
12603
12603
|
}
|
|
12604
12604
|
let rawModel = msg.model;
|
|
@@ -12606,7 +12606,7 @@ var AutoResumePlugin = async (ctx, options) => {
|
|
|
12606
12606
|
rawModel = msg.info?.model;
|
|
12607
12607
|
}
|
|
12608
12608
|
if (rawModel && typeof rawModel.providerID === "string" && typeof rawModel.modelID === "string") {
|
|
12609
|
-
|
|
12609
|
+
model = {
|
|
12610
12610
|
providerID: rawModel.providerID,
|
|
12611
12611
|
modelID: rawModel.modelID
|
|
12612
12612
|
};
|
|
@@ -12618,11 +12618,11 @@ var AutoResumePlugin = async (ctx, options) => {
|
|
|
12618
12618
|
path: { id: sid },
|
|
12619
12619
|
body: {
|
|
12620
12620
|
parts: [{ type: "text", text }],
|
|
12621
|
-
agent
|
|
12622
|
-
model
|
|
12621
|
+
agent,
|
|
12622
|
+
model
|
|
12623
12623
|
}
|
|
12624
12624
|
});
|
|
12625
|
-
await log("debug", `${short(sid)} - prompt sent with agent: ${
|
|
12625
|
+
await log("debug", `${short(sid)} - prompt sent with agent: ${agent ?? "(default)"}, model: ${model ? `${model.providerID}/${model.modelID}` : "(default)"}`);
|
|
12626
12626
|
recordContinue(sid);
|
|
12627
12627
|
w.lastRetryAt = Date.now();
|
|
12628
12628
|
} catch (err) {
|
|
@@ -12679,6 +12679,46 @@ var AutoResumePlugin = async (ctx, options) => {
|
|
|
12679
12679
|
return false;
|
|
12680
12680
|
}
|
|
12681
12681
|
}
|
|
12682
|
+
async function hasBusySubagents(parentSid) {
|
|
12683
|
+
try {
|
|
12684
|
+
const response = await ctx.client.session.list();
|
|
12685
|
+
const allSessions = extractMessages(response);
|
|
12686
|
+
for (const s of allSessions) {
|
|
12687
|
+
const sId = s.id;
|
|
12688
|
+
if (!sId || sId === parentSid)
|
|
12689
|
+
continue;
|
|
12690
|
+
const status = s.status;
|
|
12691
|
+
if (status === "busy")
|
|
12692
|
+
return true;
|
|
12693
|
+
}
|
|
12694
|
+
return false;
|
|
12695
|
+
} catch (err) {
|
|
12696
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
12697
|
+
await log("debug", `hasBusySubagents failed for ${short(parentSid)}: ${errMsg}`);
|
|
12698
|
+
return false;
|
|
12699
|
+
}
|
|
12700
|
+
}
|
|
12701
|
+
async function checkSessionHasActiveTool(sid) {
|
|
12702
|
+
try {
|
|
12703
|
+
const response = await ctx.client.session.messages({ path: { id: sid } });
|
|
12704
|
+
const messages = extractMessages(response);
|
|
12705
|
+
const lastMsg = messages[messages.length - 1];
|
|
12706
|
+
if (!lastMsg)
|
|
12707
|
+
return false;
|
|
12708
|
+
const rawRole = lastMsg?.role ?? lastMsg?.info?.role;
|
|
12709
|
+
if (rawRole !== "assistant")
|
|
12710
|
+
return false;
|
|
12711
|
+
const toolCall = lastMsg.toolCall;
|
|
12712
|
+
const toolCalls = lastMsg.tool_calls;
|
|
12713
|
+
const parts = lastMsg.parts;
|
|
12714
|
+
const hasToolCall = toolCall !== undefined || (toolCalls?.length ?? 0) > 0 || (parts?.some((p) => p.type === "tool-call" || p.type === "tool_use") ?? false);
|
|
12715
|
+
return hasToolCall;
|
|
12716
|
+
} catch (err) {
|
|
12717
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
12718
|
+
await log("debug", `checkSessionHasActiveTool failed for ${short(sid)}: ${errMsg}`);
|
|
12719
|
+
return false;
|
|
12720
|
+
}
|
|
12721
|
+
}
|
|
12682
12722
|
async function checkSubagentStatus(parentSid) {
|
|
12683
12723
|
try {
|
|
12684
12724
|
const response = await ctx.client.session.list();
|
|
@@ -12698,10 +12738,15 @@ var AutoResumePlugin = async (ctx, options) => {
|
|
|
12698
12738
|
const rawRole = lastMsg?.role ?? lastMsg?.info?.role;
|
|
12699
12739
|
if (lastMsg && rawRole === "assistant" && (("error" in lastMsg) || lastMsg.info && ("error" in lastMsg.info))) {
|
|
12700
12740
|
await log("debug", `Subagent ${short(sId)} appears crashed`);
|
|
12701
|
-
return "crashed";
|
|
12741
|
+
return { status: "crashed" };
|
|
12702
12742
|
}
|
|
12703
12743
|
const msgTime = lastMsg?.time?.created ?? lastMsg?.time;
|
|
12704
|
-
|
|
12744
|
+
if (!msgTime)
|
|
12745
|
+
continue;
|
|
12746
|
+
const toolCall = lastMsg.toolCall;
|
|
12747
|
+
const toolCalls = lastMsg.tool_calls;
|
|
12748
|
+
const parts = lastMsg.parts;
|
|
12749
|
+
const hasToolCall = toolCall !== undefined || (toolCalls?.length ?? 0) > 0 || (parts?.some((p) => p.type === "tool-call") ?? false);
|
|
12705
12750
|
const isStuck = hasToolCall ? now - msgTime > SUBAGENT_STUCK_MS * 3 : now - msgTime > SUBAGENT_STUCK_MS;
|
|
12706
12751
|
if (isStuck) {
|
|
12707
12752
|
await log("debug", `Subagent ${short(sId)} stuck - no new text in >${hasToolCall ? 3 : 1}min`);
|
|
@@ -12770,10 +12815,10 @@ var AutoResumePlugin = async (ctx, options) => {
|
|
|
12770
12815
|
}
|
|
12771
12816
|
return false;
|
|
12772
12817
|
}
|
|
12773
|
-
function trackToolCall(w,
|
|
12818
|
+
function trackToolCall(w, toolName) {
|
|
12774
12819
|
const now = Date.now();
|
|
12775
12820
|
w.recentToolCalls = w.recentToolCalls.filter((call) => now - call.at < 120000);
|
|
12776
|
-
w.recentToolCalls.push({ toolName
|
|
12821
|
+
w.recentToolCalls.push({ toolName, at: now });
|
|
12777
12822
|
const recentTools = w.recentToolCalls.slice(-15).map((call) => call.toolName);
|
|
12778
12823
|
if (recentTools.length < 6)
|
|
12779
12824
|
return false;
|
|
@@ -12816,18 +12861,18 @@ var AutoResumePlugin = async (ctx, options) => {
|
|
|
12816
12861
|
continue;
|
|
12817
12862
|
const toolCall = msg.toolCall;
|
|
12818
12863
|
if (toolCall && typeof toolCall === "object" && "name" in toolCall) {
|
|
12819
|
-
const
|
|
12820
|
-
if (
|
|
12821
|
-
trackToolCall(w,
|
|
12864
|
+
const toolName = toolCall.name;
|
|
12865
|
+
if (toolName) {
|
|
12866
|
+
trackToolCall(w, toolName);
|
|
12822
12867
|
}
|
|
12823
12868
|
}
|
|
12824
12869
|
const toolCalls = msg.tool_calls;
|
|
12825
12870
|
if (toolCalls) {
|
|
12826
12871
|
for (const tc of toolCalls) {
|
|
12827
12872
|
if (typeof tc === "object" && "name" in tc) {
|
|
12828
|
-
const
|
|
12829
|
-
if (
|
|
12830
|
-
trackToolCall(w,
|
|
12873
|
+
const toolName = tc.name;
|
|
12874
|
+
if (toolName) {
|
|
12875
|
+
trackToolCall(w, toolName);
|
|
12831
12876
|
}
|
|
12832
12877
|
}
|
|
12833
12878
|
}
|
|
@@ -12847,14 +12892,15 @@ var AutoResumePlugin = async (ctx, options) => {
|
|
|
12847
12892
|
isReasoning = true;
|
|
12848
12893
|
} else if (partType === "tool_use") {
|
|
12849
12894
|
isToolUse = true;
|
|
12850
|
-
const
|
|
12851
|
-
text = `tool_use: ${
|
|
12895
|
+
const toolName = part.name ?? "unknown";
|
|
12896
|
+
text = `tool_use: ${toolName}`;
|
|
12852
12897
|
} else {
|
|
12853
12898
|
continue;
|
|
12854
12899
|
}
|
|
12855
12900
|
allAssistantText += text + `
|
|
12856
12901
|
`;
|
|
12857
12902
|
if (isToolUse) {
|
|
12903
|
+
const toolName = part.name ?? "unknown";
|
|
12858
12904
|
const isLoop = trackToolCall(w, toolName);
|
|
12859
12905
|
if (isLoop && w.toolLoopAttempts < 2) {
|
|
12860
12906
|
w.toolLoopAttempts++;
|
|
@@ -12878,6 +12924,22 @@ var AutoResumePlugin = async (ctx, options) => {
|
|
|
12878
12924
|
}
|
|
12879
12925
|
}
|
|
12880
12926
|
if (containsToolCallAsText(text)) {
|
|
12927
|
+
const toolMatch = text.match(/<function=([a-zA-Z_]+)/) || text.match(/<invoke\s+name=([a-zA-Z_]+)/) || text.match(/"name":\s*"([a-zA-Z_]+)/);
|
|
12928
|
+
if (toolMatch) {
|
|
12929
|
+
const toolName = toolMatch[1] || "unknown";
|
|
12930
|
+
const isLoop = trackToolCall(w, toolName);
|
|
12931
|
+
if (isLoop && w.toolLoopAttempts < 2) {
|
|
12932
|
+
w.toolLoopAttempts++;
|
|
12933
|
+
const loopCandidate = {
|
|
12934
|
+
prompt: TOOL_LOOP_RECOVERY_PROMPT,
|
|
12935
|
+
source: "tool-text-loop",
|
|
12936
|
+
priority: 0
|
|
12937
|
+
};
|
|
12938
|
+
if (!bestCandidate || loopCandidate.priority < bestCandidate.priority) {
|
|
12939
|
+
bestCandidate = loopCandidate;
|
|
12940
|
+
}
|
|
12941
|
+
}
|
|
12942
|
+
}
|
|
12881
12943
|
const candidate = {
|
|
12882
12944
|
prompt: isReasoning ? THINKING_TOOL_RECOVERY_PROMPT : TOOL_TEXT_RECOVERY_PROMPT,
|
|
12883
12945
|
source: isReasoning ? "reasoning" : "text",
|
|
@@ -13101,8 +13163,13 @@ var AutoResumePlugin = async (ctx, options) => {
|
|
|
13101
13163
|
tryAbortAndResume(sid, w);
|
|
13102
13164
|
}
|
|
13103
13165
|
} else if (subStatus.status === "idle") {
|
|
13104
|
-
|
|
13105
|
-
|
|
13166
|
+
const hasBusySub = await hasBusySubagents(sid);
|
|
13167
|
+
if (hasBusySub) {
|
|
13168
|
+
await log("debug", `Subagents exist but not busy yet, waiting for startup...`);
|
|
13169
|
+
} else {
|
|
13170
|
+
await log("info", `Parent ${short(sid)} stuck with no active subagents. Triggering abort+resume.`);
|
|
13171
|
+
tryAbortAndResume(sid, w);
|
|
13172
|
+
}
|
|
13106
13173
|
} else {
|
|
13107
13174
|
await log("debug", `Subagent still running, waiting...`);
|
|
13108
13175
|
}
|
|
@@ -13121,6 +13188,12 @@ var AutoResumePlugin = async (ctx, options) => {
|
|
|
13121
13188
|
continue;
|
|
13122
13189
|
w.lastSubagentCheckAt = now;
|
|
13123
13190
|
if (w.lastActivityAt > 0 && now - w.lastActivityAt > subagentWaitMs) {
|
|
13191
|
+
const hasActiveTool = await checkSessionHasActiveTool(sid);
|
|
13192
|
+
if (hasActiveTool) {
|
|
13193
|
+
await log("debug", `Parent ${short(sid)} has active tool call, skipping abort check`);
|
|
13194
|
+
w.lastSubagentCheckAt = now;
|
|
13195
|
+
continue;
|
|
13196
|
+
}
|
|
13124
13197
|
const subStatus = await checkSubagentStatus(sid);
|
|
13125
13198
|
if (subStatus.status === "idle" || subStatus.status === "unknown") {
|
|
13126
13199
|
await log("info", `Parent ${short(sid)} stuck with no active subagents. Triggering abort+resume.`);
|
|
@@ -13349,14 +13422,6 @@ var AutoResumePlugin = async (ctx, options) => {
|
|
|
13349
13422
|
},
|
|
13350
13423
|
config: async () => {
|
|
13351
13424
|
log("info", `opencode-auto-resume config OK`);
|
|
13352
|
-
if (ctx.ui && typeof ctx.ui.toast === "function") {
|
|
13353
|
-
ctx.ui.toast({
|
|
13354
|
-
title: "Auto-Resume Plugin",
|
|
13355
|
-
message: `Loaded with ${chunkTimeoutMs}ms timeout, ${loopMaxContinues} loop attempts`,
|
|
13356
|
-
variant: "success",
|
|
13357
|
-
duration: 5000
|
|
13358
|
-
});
|
|
13359
|
-
}
|
|
13360
13425
|
},
|
|
13361
13426
|
tool: {
|
|
13362
13427
|
task_complete: taskCompleteTool
|
package/package.json
CHANGED