Skip to content

fix(agent-runtime): classify every overflow pi-ai recovers from as CONTEXT_TOO_LARGE - #1517

Merged
vastsa merged 1 commit into
vastsa:mainfrom
xpeng5278-web:fix/context-overflow-classification
Oct 9, 2026
Merged

vastsa merged 1 commit into
vastsa:mainfrom
xpeng5278-web:fix/context-overflow-classification

Conversation

@xpeng5278-web

Copy link
Copy Markdown
Contributor

Fixes #1516

Problem

Two different checks decide what a context overflow is:

  • runtime.ts starts provider overflow recovery with pi-ai's isContextOverflow.
  • classifyAgentError chooses the error code with its own, narrower CONTEXT_PATTERN.

pi-ai knows overflow wording that CONTEXT_PATTERN does not: DashScope/Qwen Range of input length should be, z.ai Prompt exceeds max length, xAI maximum prompt length is, Groq reduce the length of the messages, llama.cpp exceeds the available context size, and Bedrock Input is too long for requested model. For these:

  • Main session: the first overflow is recovered (compact + one retry). A second overflow is then reported as PROVIDER_ERROR instead of CONTEXT_TOO_LARGE, which contradicts 08-error-codes.md.
  • Delegates only have the classifier. The Task fails with PROVIDER_ERROR instead of SUBAGENT_CONTEXT_OVERFLOW, so the parent model gets raw provider text instead of the "narrow the task / larger window" guidance. A Bedrock overflow has no status in its message, so it was classified retriable and re-sent unchanged through the transient budget.

The reverse also happens: Bedrock's throttle Throttling error: Too many tokens, please wait before trying again. matches too many tokens and became a terminal CONTEXT_TOO_LARGE, so it was never retried. pi-ai's isContextOverflow already excludes that message.

Change

  • classifyAgentError now asks pi-ai's isContextOverflow using only the message text, then falls back to CONTEXT_PATTERN. This applies both to the 400/422 branch and to messages with no status. The terminal code now matches the recovery decision for every wording pi-ai knows, and it stays in sync when pi-ai adds providers.
  • Only the text is passed. No provider id, usage, or context window is passed, so pi-ai's silent-overflow checks and the Cerebras bodyless-400 check stay with the runtime, which has those facts. The opaque-400 output-limit repair is unchanged.
  • Rate-limit wording now includes throttl and is still checked before overflow wording. Bedrock throttling therefore becomes PROVIDER_RATE_LIMITED.
  • CONTEXT_PATTERN itself, the status table, and retry budgets are unchanged.

Specs

docs/spec/03-runtime/08-error-codes.md (provider exception mapping) and docs/spec/03-runtime/02-agent-runtime.md (provider overflow recovery), plus their zh-CN copies, now say the classifier follows isContextOverflow, that the second overflow is CONTEXT_TOO_LARGE, and that throttling stays PROVIDER_RATE_LIMITED. No ADR changes: ADR 0299's delegate remap already keys off CONTEXT_TOO_LARGE.

Verification (base origin/main ed54ce9)

  • New tests fail on unmodified main (12 failed) and pass with this change:
    • agent-errors.test.ts: the six provider overflow messages as pi-ai 1.1.0 formats them assert isContextOverflow === true and CONTEXT_TOO_LARGE, non-retriable, through both classifyAgentError and classifyProviderError. A separate test covers Bedrock throttling → PROVIDER_RATE_LIMITED.
    • subagent.test.ts: DashScope and Bedrock overflows end the delegate as SUBAGENT_CONTEXT_OVERFLOW, with no provider retry claimed and no continue(). On main: PROVIDER_ERROR.
    • runtime.test.ts: for DashScope, z.ai, and Bedrock, the first overflow is compacted and retried once, and the second is reported as CONTEXT_TOO_LARGE.
  • I also produced the messages with the real pi-ai openai-completions adapter against a mocked HTTP 400 body for each provider, so the test strings match what the runtime actually sees (local check, not part of the PR).
  • @pi-desktop/agent-runtime tests: 1320/1320 pass.
  • pnpm build:js, agent-runtime and desktop typecheck, pnpm lint, pnpm docs:check, node scripts/check-architecture.mjs, and pnpm check:pr-base all pass.
  • NOT RUN: Electron-binary E2E. There is no Electron binary in my Linux environment. The change is limited to the sidecar's error classifier, which the unit tests and runtime/subagent flow tests above exercise directly.

…NTEXT_TOO_LARGE

The runtime starts provider overflow recovery with pi-ai's
isContextOverflow, but classifyAgentError used its own, narrower
CONTEXT_PATTERN. Overflow wording that only pi-ai knew (DashScope/Qwen
"Range of input length should be", z.ai "Prompt exceeds max length",
xAI "maximum prompt length is", Groq, llama.cpp, Bedrock "Input is too
long for requested model") was recovered as an overflow but reported
as PROVIDER_ERROR. A delegate, which only has the classifier, reported
PROVIDER_ERROR instead of SUBAGENT_CONTEXT_OVERFLOW, and a status-less
Bedrock overflow was classified retriable, so the delegate re-sent the
same oversized request through the transient budget.

Ask pi-ai's isContextOverflow from the message text first and keep
CONTEXT_PATTERN for the wording already accepted. Probe throttling as
rate limiting before overflow wording, so Bedrock's "Throttling error:
Too many tokens, please wait" stays PROVIDER_RATE_LIMITED instead of a
terminal CONTEXT_TOO_LARGE.

Update the error-code and agent-runtime specs (with zh-CN copies).

@muzimu217 muzimu217 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified locally on macOS (patch applied to a detached worktree at current upstream HEAD ed54ce977): agent-runtime full suite 94 files / 1320 tests pass — the +12 over main are the new classification tests.

The design is the correct unification: the terminal classifier now defers to pi-ai's isContextOverflow — the same check that starts provider overflow recovery — instead of maintaining its own narrower CONTEXT_PATTERN. That single change fixes #1516's two failure modes at once:

  • vendor wordings pi-ai knows but CONTEXT_PATTERN missed (DashScope/Qwen, z.ai, xAI, Groq, llama.cpp, Bedrock) now get the recover-first-then-terminal path instead of being misreported as PROVIDER_ERROR;
  • delegates stop burning retries on a terminal condition — CONTEXT_TOO_LARGE is never replayed by either retry budget and surfaces as SUBAGENT_CONTEXT_OVERFLOW.

The ordering guarantee is documented, not just implemented: rate-limit wording (including Bedrock's Throttling error: Too many tokens…) is classified before the overflow check and stays PROVIDER_RATE_LIMITED, and HTTP 413 keeps its own path. Spec updates cover the error-code registry (08-error-codes) and the runtime spec in both languages.

Patch applies cleanly to current HEAD; nothing blocking. fix scope, fits the contribution window — and it pairs naturally with #1495/#1499 as part of the runtime-robustness batch.

@vastsa
vastsa merged commit 08e9baf into vastsa:main Oct 9, 2026
5 checks passed
@vastsa

vastsa commented Oct 9, 2026

Copy link
Copy Markdown
Owner

Thanks for the detailed reproduction and the aligned classifier fix. The regression tests cover main-session recovery, delegate error mapping, and Bedrock throttling; all required checks passed. Merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Context overflows that pi-ai recovers from are reported as PROVIDER_ERROR (and retried by delegates)

3 participants