fix(agents): preserve original prompt on model fallback retry (#65760) (#66029)

Merged via squash.

Prepared head SHA: ba919d1934
Co-authored-by: WuKongAI-CMU <210765158+WuKongAI-CMU@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
This commit is contained in:
Peter
2026-04-14 16:47:01 -04:00
committed by GitHub
parent f958e311d2
commit 70b67b0c68
3 changed files with 10 additions and 3 deletions

View File

@@ -29,6 +29,7 @@ Docs: https://docs.openclaw.ai
- Agents/workspace files: route `agents.files.get`, `agents.files.set`, and workspace listing through the shared `fs-safe` helpers (`openFileWithinRoot`/`readFileWithinRoot`/`writeFileWithinRoot`), reject symlink aliases for allowlisted agent files, and have `fs-safe` resolve opened-file real paths from the file descriptor before falling back to path-based `realpath` so a symlink swap between `open` and `realpath` can no longer redirect the validated path off the intended inode. (#66636) Thanks @eleqtrizit.
- Gateway/MCP loopback: switch the `/mcp` bearer comparison from plain `!==` to constant-time `safeEqualSecret` (matching the convention every other auth surface in the codebase uses), and reject non-loopback browser-origin requests via `checkBrowserOrigin` before the auth gate runs. Loopback origins (`127.0.0.1:*`, `localhost:*`, same-origin) still go through, including the `localhost``127.0.0.1` host mismatch that browsers flag as `Sec-Fetch-Site: cross-site`. (#66665) Thanks @eleqtrizit.
- Auto-reply/billing: classify pure billing cooldown fallback summaries from structured fallback reasons so users see billing guidance instead of the generic failure reply. (#66363) Thanks @Rohan5commit.
- Agents/fallback: preserve the original prompt body on model fallback retries with session history so the retrying model keeps the active task instead of only seeing a generic continue message. (#66029) Thanks @WuKongAI-CMU.
## 2026.4.14

View File

@@ -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() {

View File

@@ -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)", () => {