opencode-immune 1.0.2 → 1.0.4
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 +49 -3
- package/package.json +1 -1
package/dist/plugin.js
CHANGED
|
@@ -197,9 +197,7 @@ function isRateLimitApiError(error) {
|
|
|
197
197
|
const maybeError = error;
|
|
198
198
|
const message = `${maybeError.message ?? ""} ${maybeError.data?.message ?? ""}`.toLowerCase();
|
|
199
199
|
const type = `${maybeError.data?.type ?? ""}`.toLowerCase();
|
|
200
|
-
return (
|
|
201
|
-
maybeError.data?.isRetryable === true &&
|
|
202
|
-
(type.includes("rate_limit") || message.includes("too many requests") || message.includes("rate limit")));
|
|
200
|
+
return ((type.includes("rate_limit") || message.includes("too many requests") || message.includes("rate limit")));
|
|
203
201
|
}
|
|
204
202
|
async function setSessionFallbackModel(state, sessionID, model) {
|
|
205
203
|
const existing = state.managedUltraworkSessions.get(sessionID);
|
|
@@ -212,6 +210,33 @@ async function setSessionFallbackModel(state, sessionID, model) {
|
|
|
212
210
|
});
|
|
213
211
|
await writeManagedSessionsCache(state);
|
|
214
212
|
}
|
|
213
|
+
async function forceRetryManagedSession(state, sessionID, reason) {
|
|
214
|
+
const managedSession = state.managedUltraworkSessions.get(sessionID);
|
|
215
|
+
if (!managedSession)
|
|
216
|
+
return;
|
|
217
|
+
const retryAgent = managedSession.agent || ULTRAWORK_AGENT;
|
|
218
|
+
const fallbackModel = managedSession.fallbackModel;
|
|
219
|
+
const retryText = retryAgent === ULTRAWORK_AGENT
|
|
220
|
+
? "[SYSTEM: Previous API call failed with a transient error. Re-read memory-bank/tasks.md, check the Phase Status block, and continue the pipeline. Use the exact neutral prompt from your Step 5 table for the next router call. Do NOT analyze or evaluate file contents.]"
|
|
221
|
+
: `[SYSTEM: Previous API call failed with a transient error. Resume the current task in your current role as ${retryAgent}. Continue from the existing session state. Do not restart from scratch unless the current session state is missing.]`;
|
|
222
|
+
await state.input.client.session.promptAsync({
|
|
223
|
+
body: {
|
|
224
|
+
...(fallbackModel ? { model: fallbackModel } : {}),
|
|
225
|
+
agent: retryAgent,
|
|
226
|
+
parts: [
|
|
227
|
+
{
|
|
228
|
+
type: "text",
|
|
229
|
+
text: retryText,
|
|
230
|
+
},
|
|
231
|
+
],
|
|
232
|
+
},
|
|
233
|
+
path: { id: sessionID },
|
|
234
|
+
});
|
|
235
|
+
console.log(`[opencode-immune] Forced retry sent to session ${sessionID} (${reason})` +
|
|
236
|
+
(fallbackModel
|
|
237
|
+
? ` using fallback model ${fallbackModel.providerID}/${fallbackModel.modelID}`
|
|
238
|
+
: ""));
|
|
239
|
+
}
|
|
215
240
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
216
241
|
// UTILITY: ERROR BOUNDARY
|
|
217
242
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
@@ -749,6 +774,7 @@ const MAX_CYCLES = 10;
|
|
|
749
774
|
const PRE_COMMIT_MARKER = "0-ULTRAWORK: PRE_COMMIT";
|
|
750
775
|
const CYCLE_COMPLETE_MARKER = "0-ULTRAWORK: CYCLE_COMPLETE";
|
|
751
776
|
const NEXT_TASK_PATTERN = /Next task:\s*(.+)/;
|
|
777
|
+
const RATE_LIMIT_MESSAGE_PATTERN = /too many requests|rate_limit|rate limit/i;
|
|
752
778
|
/**
|
|
753
779
|
* chat.message part: scans assistant messages for PRE_COMMIT and CYCLE_COMPLETE markers.
|
|
754
780
|
*
|
|
@@ -771,6 +797,26 @@ function createMultiCycleHandler(state) {
|
|
|
771
797
|
messageContent = messageContent.trim();
|
|
772
798
|
if (!messageContent)
|
|
773
799
|
return;
|
|
800
|
+
if (sessionID && RATE_LIMIT_MESSAGE_PATTERN.test(messageContent)) {
|
|
801
|
+
const managedSession = getManagedSession(state, sessionID);
|
|
802
|
+
if (managedSession && !managedSession.fallbackModel) {
|
|
803
|
+
await setSessionFallbackModel(state, sessionID, RATE_LIMIT_FALLBACK_MODEL);
|
|
804
|
+
console.log(`[opencode-immune] Rate limit message detected in chat output for session ${sessionID}. ` +
|
|
805
|
+
`Fallback model pinned to ${RATE_LIMIT_FALLBACK_MODEL.providerID}/${RATE_LIMIT_FALLBACK_MODEL.modelID}.`);
|
|
806
|
+
}
|
|
807
|
+
if (managedSession && !state.retryTimers.has(sessionID)) {
|
|
808
|
+
const timer = setTimeout(async () => {
|
|
809
|
+
state.retryTimers.delete(sessionID);
|
|
810
|
+
try {
|
|
811
|
+
await forceRetryManagedSession(state, sessionID, "rate-limit message fallback");
|
|
812
|
+
}
|
|
813
|
+
catch (err) {
|
|
814
|
+
console.error(`[opencode-immune] Forced retry after rate-limit message failed for session ${sessionID}:`, err);
|
|
815
|
+
}
|
|
816
|
+
}, 1_000);
|
|
817
|
+
state.retryTimers.set(sessionID, timer);
|
|
818
|
+
}
|
|
819
|
+
}
|
|
774
820
|
// ── PRE_COMMIT: execute /commit ──
|
|
775
821
|
if (messageContent.includes(PRE_COMMIT_MARKER) && !state.commitPending) {
|
|
776
822
|
state.commitPending = true;
|