From dda84d572afd0a1cb0ecf79f7de29341c814b567 Mon Sep 17 00:00:00 2001 From: Intern Dev Date: Mon, 13 Apr 2026 11:48:06 -0400 Subject: [PATCH] fix(agents): preserve original prompt on model fallback retry (#65760) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a model call fails and OpenClaw triggers a fallback retry, resolveFallbackRetryPrompt() replaced the entire original user body with the fixed string "Continue where you left off. The previous model attempt failed or timed out." This discarded the original task instruction entirely, forcing the fallback model to reconstruct the task from history alone — sometimes impossible, sometimes just wrong. Prepend the retry context to the original body instead so the fallback model has both the recovery signal and the task instruction: [Retry after the previous model attempt failed or timed out] The existing subagent-spawn branch (no persisted session history) is unaffected — that path still returns params.body verbatim. Update the matching test to assert the new prefixed form. Closes #65760 --- src/agents/command/attempt-execution.helpers.ts | 8 +++++++- src/agents/command/attempt-execution.test.ts | 4 ++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/agents/command/attempt-execution.helpers.ts b/src/agents/command/attempt-execution.helpers.ts index f9abc3401c1..2315346ecf5 100644 --- a/src/agents/command/attempt-execution.helpers.ts +++ b/src/agents/command/attempt-execution.helpers.ts @@ -73,7 +73,13 @@ export function resolveFallbackRetryPrompt(params: { if (!params.sessionHasHistory) { return params.body; } - return "Continue where you left off. The previous model attempt failed or timed out."; + // Even with persisted session history, fully replacing the body with a + // generic "continue where you left off" message strips the original task + // from the fallback model's view. Agents then have to reconstruct the + // instruction from history alone, which is fragile and sometimes + // impossible. Prepend the retry context to the original body instead so + // the fallback model has both the recovery signal AND the task. (#65760) + return `[Retry after the previous model attempt failed or timed out]\n\n${params.body}`; } export function createAcpVisibleTextAccumulator() { diff --git a/src/agents/command/attempt-execution.test.ts b/src/agents/command/attempt-execution.test.ts index b1b5ab72700..6ab929778bd 100644 --- a/src/agents/command/attempt-execution.test.ts +++ b/src/agents/command/attempt-execution.test.ts @@ -20,14 +20,14 @@ describe("resolveFallbackRetryPrompt", () => { ).toBe(originalBody); }); - it("returns recovery prompt for fallback retry with existing session history", () => { + it("prepends recovery prefix to original body on fallback retry with existing session history", () => { expect( resolveFallbackRetryPrompt({ body: originalBody, isFallbackRetry: true, sessionHasHistory: true, }), - ).toBe("Continue where you left off. The previous model attempt failed or timed out."); + ).toBe(`[Retry after the previous model attempt failed or timed out]\n\n${originalBody}`); }); it("preserves original body for fallback retry when session has no history (subagent spawn)", () => {