From d3c2b83f884021f67b7e0531f828933d1a3004f0 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Tue, 20 Jan 2026 10:06:47 +0000 Subject: [PATCH] fix: avoid context-window-too-small misclassification (#1266, thanks @humanwritten) Co-authored-by: humanwritten --- CHANGELOG.md | 1 + ...lpers.islikelycontextoverflowerror.test.ts | 34 +++++++++++++++++++ src/agents/pi-embedded-helpers.ts | 1 + src/agents/pi-embedded-helpers/errors.ts | 11 ++++++ .../reply/agent-runner-execution.ts | 6 ++-- 5 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 src/agents/pi-embedded-helpers.islikelycontextoverflowerror.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d9c44414..83959f86f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ Docs: https://docs.clawd.bot - TUI: keep thinking blocks ordered before content during streaming and isolate per-run assembly. (#1202) — thanks @aaronveklabs. - CLI: avoid duplicating --profile/--dev flags when formatting commands. - Auth: dedupe codex-cli profiles when tokens match custom openai-codex entries. (#1264) — thanks @odrobnik. +- Agents: avoid misclassifying context-window-too-small errors as context overflow. (#1266) — thanks @humanwritten. ## 2026.1.19-3 diff --git a/src/agents/pi-embedded-helpers.islikelycontextoverflowerror.test.ts b/src/agents/pi-embedded-helpers.islikelycontextoverflowerror.test.ts new file mode 100644 index 000000000..64f65cc54 --- /dev/null +++ b/src/agents/pi-embedded-helpers.islikelycontextoverflowerror.test.ts @@ -0,0 +1,34 @@ +import { describe, expect, it } from "vitest"; +import { isLikelyContextOverflowError } from "./pi-embedded-helpers.js"; +import { DEFAULT_AGENTS_FILENAME } from "./workspace.js"; + +const _makeFile = (overrides: Partial): WorkspaceBootstrapFile => ({ + name: DEFAULT_AGENTS_FILENAME, + path: "/tmp/AGENTS.md", + content: "", + missing: false, + ...overrides, +}); + +describe("isLikelyContextOverflowError", () => { + it("matches context overflow hints", () => { + const samples = [ + "Model context window is 128k tokens, you requested 256k tokens", + "Context window exceeded: requested 12000 tokens", + "Prompt too large for this model", + ]; + for (const sample of samples) { + expect(isLikelyContextOverflowError(sample)).toBe(true); + } + }); + + it("excludes context window too small errors", () => { + const samples = [ + "Model context window too small (minimum is 128k tokens)", + "Context window too small: minimum is 1000 tokens", + ]; + for (const sample of samples) { + expect(isLikelyContextOverflowError(sample)).toBe(false); + } + }); +}); diff --git a/src/agents/pi-embedded-helpers.ts b/src/agents/pi-embedded-helpers.ts index 47a19183b..64e14ebcc 100644 --- a/src/agents/pi-embedded-helpers.ts +++ b/src/agents/pi-embedded-helpers.ts @@ -19,6 +19,7 @@ export { isCloudCodeAssistFormatError, isCompactionFailureError, isContextOverflowError, + isLikelyContextOverflowError, isFailoverAssistantError, isFailoverErrorMessage, isImageDimensionErrorMessage, diff --git a/src/agents/pi-embedded-helpers/errors.ts b/src/agents/pi-embedded-helpers/errors.ts index ad287fa02..d29842958 100644 --- a/src/agents/pi-embedded-helpers/errors.ts +++ b/src/agents/pi-embedded-helpers/errors.ts @@ -18,6 +18,17 @@ export function isContextOverflowError(errorMessage?: string): boolean { ); } +const CONTEXT_WINDOW_TOO_SMALL_RE = /context window.*(too small|minimum is)/i; +const CONTEXT_OVERFLOW_HINT_RE = + /context.*overflow|context window.*(too (?:large|long)|exceed|over|limit|max(?:imum)?|requested|sent|tokens)|(?:prompt|request|input).*(too (?:large|long)|exceed|over|limit|max(?:imum)?)/i; + +export function isLikelyContextOverflowError(errorMessage?: string): boolean { + if (!errorMessage) return false; + if (CONTEXT_WINDOW_TOO_SMALL_RE.test(errorMessage)) return false; + if (isContextOverflowError(errorMessage)) return true; + return CONTEXT_OVERFLOW_HINT_RE.test(errorMessage); +} + export function isCompactionFailureError(errorMessage?: string): boolean { if (!errorMessage) return false; if (!isContextOverflowError(errorMessage)) return false; diff --git a/src/auto-reply/reply/agent-runner-execution.ts b/src/auto-reply/reply/agent-runner-execution.ts index 9bfbd4aa1..c423d3356 100644 --- a/src/auto-reply/reply/agent-runner-execution.ts +++ b/src/auto-reply/reply/agent-runner-execution.ts @@ -9,6 +9,7 @@ import { runEmbeddedPiAgent } from "../../agents/pi-embedded.js"; import { isCompactionFailureError, isContextOverflowError, + isLikelyContextOverflowError, sanitizeUserFacingText, } from "../../agents/pi-embedded-helpers.js"; import { @@ -419,10 +420,7 @@ export async function runAgentTurnWithFallback(params: { break; } catch (err) { const message = err instanceof Error ? err.message : String(err); - const isContextOverflow = - isContextOverflowError(message) || - (/context.*overflow|too large|context window/i.test(message) && - !/too small|minimum is/i.test(message)); + const isContextOverflow = isLikelyContextOverflowError(message); const isCompactionFailure = isCompactionFailureError(message); const isSessionCorruption = /function call turn comes immediately after/i.test(message); const isRoleOrderingError = /incorrect role information|roles must alternate/i.test(message);