opencode-immune 1.0.42 → 1.0.43
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/plugin.js +50 -2
- package/package.json +1 -1
package/dist/plugin.js
CHANGED
|
@@ -11,7 +11,7 @@ const child_process_1 = require("child_process");
|
|
|
11
11
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
12
12
|
// PLUGIN VERSION CHECK
|
|
13
13
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
14
|
-
const PLUGIN_VERSION = "1.0.
|
|
14
|
+
const PLUGIN_VERSION = "1.0.43";
|
|
15
15
|
const PLUGIN_PACKAGE_NAME = "opencode-immune";
|
|
16
16
|
/**
|
|
17
17
|
* Read plugin version from package.json at runtime.
|
|
@@ -76,6 +76,7 @@ function createState(input) {
|
|
|
76
76
|
managedUltraworkSessions: new Map(),
|
|
77
77
|
sessionRetryTimers: new Map(),
|
|
78
78
|
providerRetryWatchdogs: new Map(),
|
|
79
|
+
childFallbackRequests: new Map(),
|
|
79
80
|
sessionErrorRetryCount: new Map(),
|
|
80
81
|
ultraworkMarkerPath: (0, path_1.join)(input.directory, ".opencode", "state", "ultrawork-active.json"),
|
|
81
82
|
diagnosticsLogPath: (0, path_1.join)(input.directory, ".opencode", "state", "opencode-immune-debug.log"),
|
|
@@ -93,6 +94,7 @@ function createState(input) {
|
|
|
93
94
|
const ULTRAWORK_AGENT = "0-ultrawork";
|
|
94
95
|
const MANAGED_SESSION_TTL_MS = 7 * 24 * 60 * 60 * 1000;
|
|
95
96
|
const PROVIDER_RETRY_WATCHDOG_MS = 30_000;
|
|
97
|
+
const CHILD_FALLBACK_REQUEST_TTL_MS = 10 * 60 * 1000;
|
|
96
98
|
const RATE_LIMIT_FALLBACK_MODEL = {
|
|
97
99
|
providerID: "externcash",
|
|
98
100
|
modelID: "gpt-5.5",
|
|
@@ -364,6 +366,36 @@ function isCertificateApiError(error) {
|
|
|
364
366
|
function isProviderRetryBanner(text) {
|
|
365
367
|
return /(?:<none>\s*)?retrying in \d+s\s*-\s*attempt #\d+/i.test(text);
|
|
366
368
|
}
|
|
369
|
+
function getRetryableErrorType(error) {
|
|
370
|
+
if (isModelAccessError(error))
|
|
371
|
+
return "model access error";
|
|
372
|
+
if (isRateLimitApiError(error))
|
|
373
|
+
return "rate limit";
|
|
374
|
+
if (isCertificateApiError(error))
|
|
375
|
+
return "certificate error";
|
|
376
|
+
return "retryable provider error";
|
|
377
|
+
}
|
|
378
|
+
function recordChildFallbackRequest(state, managedSession, childSessionID, error) {
|
|
379
|
+
const request = {
|
|
380
|
+
childSessionID,
|
|
381
|
+
rootSessionID: managedSession.rootSessionID,
|
|
382
|
+
agent: managedSession.agent || "unknown",
|
|
383
|
+
errorType: getRetryableErrorType(error),
|
|
384
|
+
fallbackModel: CHILD_SESSION_FALLBACK_MODEL,
|
|
385
|
+
createdAt: Date.now(),
|
|
386
|
+
};
|
|
387
|
+
state.childFallbackRequests.set(managedSession.rootSessionID, request);
|
|
388
|
+
}
|
|
389
|
+
function getChildFallbackRequest(state, rootSessionID, now = Date.now()) {
|
|
390
|
+
const request = state.childFallbackRequests.get(rootSessionID);
|
|
391
|
+
if (!request)
|
|
392
|
+
return undefined;
|
|
393
|
+
if (now - request.createdAt > CHILD_FALLBACK_REQUEST_TTL_MS) {
|
|
394
|
+
state.childFallbackRequests.delete(rootSessionID);
|
|
395
|
+
return undefined;
|
|
396
|
+
}
|
|
397
|
+
return request;
|
|
398
|
+
}
|
|
367
399
|
function scheduleProviderRetryWatchdog(state, sessionID, model) {
|
|
368
400
|
if (!isManagedRootUltraworkSession(state, sessionID))
|
|
369
401
|
return;
|
|
@@ -1041,6 +1073,21 @@ function createSystemTransform(state) {
|
|
|
1041
1073
|
`Read memory-bank/tasks.md and memory-bank/activeContext.md to resume work.`);
|
|
1042
1074
|
}
|
|
1043
1075
|
}
|
|
1076
|
+
const rootSessionID = input.sessionID;
|
|
1077
|
+
if (rootSessionID && isManagedRootUltraworkSession(state, rootSessionID)) {
|
|
1078
|
+
const childFallbackRequest = getChildFallbackRequest(state, rootSessionID);
|
|
1079
|
+
if (childFallbackRequest) {
|
|
1080
|
+
output.system.push(`[Router-Owned Child Retry Required]\n` +
|
|
1081
|
+
`A child/subagent session failed with a retryable provider/model error. ` +
|
|
1082
|
+
`Do not advance to the next sequential pipeline slot until this failed slot is explicitly resolved.\n` +
|
|
1083
|
+
`- Failed child session: ${childFallbackRequest.childSessionID}\n` +
|
|
1084
|
+
`- Agent: ${childFallbackRequest.agent}\n` +
|
|
1085
|
+
`- Error type: ${childFallbackRequest.errorType}\n` +
|
|
1086
|
+
`- Required fallback model: ${childFallbackRequest.fallbackModel.providerID}/${childFallbackRequest.fallbackModel.modelID}\n` +
|
|
1087
|
+
`Router action: retry the SAME agent/slot once using the fallback model if available; if it still fails or cannot be retried, record DECLINE/failed-provider-retry for that slot before continuing. ` +
|
|
1088
|
+
`Never resume the failed child session directly; create a router-owned replacement attempt instead.`);
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1044
1091
|
// Ralph Loop injection
|
|
1045
1092
|
if (state.lastEditAttempt) {
|
|
1046
1093
|
const edit = state.lastEditAttempt;
|
|
@@ -1334,8 +1381,9 @@ function createEventHandler(state) {
|
|
|
1334
1381
|
// Child/subagent failures are owned by the router. Auto-resuming a failed
|
|
1335
1382
|
// child after the router advances can create two writers in one pipeline.
|
|
1336
1383
|
if (isChild) {
|
|
1384
|
+
recordChildFallbackRequest(state, managedSession, sessionID, error);
|
|
1337
1385
|
console.log(`[opencode-immune] Child session ${sessionID}: retryable error detected. ` +
|
|
1338
|
-
`
|
|
1386
|
+
`Recorded router-owned fallback request and skipped plugin auto-retry.`);
|
|
1339
1387
|
state.sessionErrorRetryCount.set(sessionID, count);
|
|
1340
1388
|
return;
|
|
1341
1389
|
}
|