opencode-immune 1.0.3 → 1.0.5
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
|
@@ -210,6 +210,33 @@ async function setSessionFallbackModel(state, sessionID, model) {
|
|
|
210
210
|
});
|
|
211
211
|
await writeManagedSessionsCache(state);
|
|
212
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
|
+
}
|
|
213
240
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
214
241
|
// UTILITY: ERROR BOUNDARY
|
|
215
242
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
@@ -747,6 +774,7 @@ const MAX_CYCLES = 10;
|
|
|
747
774
|
const PRE_COMMIT_MARKER = "0-ULTRAWORK: PRE_COMMIT";
|
|
748
775
|
const CYCLE_COMPLETE_MARKER = "0-ULTRAWORK: CYCLE_COMPLETE";
|
|
749
776
|
const NEXT_TASK_PATTERN = /Next task:\s*(.+)/;
|
|
777
|
+
const RATE_LIMIT_MESSAGE_PATTERN = /too many requests|rate_limit|rate limit/i;
|
|
750
778
|
/**
|
|
751
779
|
* chat.message part: scans assistant messages for PRE_COMMIT and CYCLE_COMPLETE markers.
|
|
752
780
|
*
|
|
@@ -756,8 +784,6 @@ const NEXT_TASK_PATTERN = /Next task:\s*(.+)/;
|
|
|
756
784
|
function createMultiCycleHandler(state) {
|
|
757
785
|
return async (input, output) => {
|
|
758
786
|
const sessionID = input.sessionID;
|
|
759
|
-
if (!isManagedRootUltraworkSession(state, sessionID))
|
|
760
|
-
return;
|
|
761
787
|
// Extract text content from parts
|
|
762
788
|
const parts = output.parts ?? [];
|
|
763
789
|
let messageContent = "";
|
|
@@ -769,6 +795,28 @@ function createMultiCycleHandler(state) {
|
|
|
769
795
|
messageContent = messageContent.trim();
|
|
770
796
|
if (!messageContent)
|
|
771
797
|
return;
|
|
798
|
+
if (sessionID && RATE_LIMIT_MESSAGE_PATTERN.test(messageContent)) {
|
|
799
|
+
const managedSession = getManagedSession(state, sessionID);
|
|
800
|
+
if (managedSession && !managedSession.fallbackModel) {
|
|
801
|
+
await setSessionFallbackModel(state, sessionID, RATE_LIMIT_FALLBACK_MODEL);
|
|
802
|
+
console.log(`[opencode-immune] Rate limit message detected in chat output for session ${sessionID}. ` +
|
|
803
|
+
`Fallback model pinned to ${RATE_LIMIT_FALLBACK_MODEL.providerID}/${RATE_LIMIT_FALLBACK_MODEL.modelID}.`);
|
|
804
|
+
}
|
|
805
|
+
if (managedSession && !state.retryTimers.has(sessionID)) {
|
|
806
|
+
const timer = setTimeout(async () => {
|
|
807
|
+
state.retryTimers.delete(sessionID);
|
|
808
|
+
try {
|
|
809
|
+
await forceRetryManagedSession(state, sessionID, "rate-limit message fallback");
|
|
810
|
+
}
|
|
811
|
+
catch (err) {
|
|
812
|
+
console.error(`[opencode-immune] Forced retry after rate-limit message failed for session ${sessionID}:`, err);
|
|
813
|
+
}
|
|
814
|
+
}, 1_000);
|
|
815
|
+
state.retryTimers.set(sessionID, timer);
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
if (!isManagedRootUltraworkSession(state, sessionID))
|
|
819
|
+
return;
|
|
772
820
|
// ── PRE_COMMIT: execute /commit ──
|
|
773
821
|
if (messageContent.includes(PRE_COMMIT_MARKER) && !state.commitPending) {
|
|
774
822
|
state.commitPending = true;
|