opencode-immune 1.0.3 → 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.
Files changed (2) hide show
  1. package/dist/plugin.js +48 -0
  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
  *
@@ -769,6 +797,26 @@ function createMultiCycleHandler(state) {
769
797
  messageContent = messageContent.trim();
770
798
  if (!messageContent)
771
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
+ }
772
820
  // ── PRE_COMMIT: execute /commit ──
773
821
  if (messageContent.includes(PRE_COMMIT_MARKER) && !state.commitPending) {
774
822
  state.commitPending = true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-immune",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "OpenCode plugin: session recovery, auto-retry, multi-cycle automation, context monitoring",
5
5
  "exports": {
6
6
  "./server": "./dist/plugin.js"