Skip to content

fix(ai): repair evidenced prefill output-budget rejections - #1616

Open
rlaope wants to merge 4 commits into
code-yeongyu:mainfrom
rlaope:fix/fallback-context-budget-rlaope
Open

rlaope wants to merge 4 commits into
code-yeongyu:mainfrom
rlaope:fix/fallback-context-budget-rlaope

Conversation

@rlaope

@rlaope rlaope commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Summary

Propose one evidence-based output-reservation repair at the OpenAI-compatible prefill boundary, including requests reached through model fallback. The full conversation and request options are preserved; only the completion cap changes.

Diagnosis

The incident switched from openai-codex/gpt-6-astra after a usage-limit error to a custom og/moonshotai/kimi-k3-ultrafast model. Prefill reported:

  • Context limit: 294,912
  • Input: 210,744
  • Completion: 131,072
  • Total: 341,816

The custom target declared 1,048,576 context tokens. Installed OmO 5.0.0-0.beta.53 / Senpi 2026.9.10-2 already contained the target-context completion clamp; its declared window therefore allowed this request. The arithmetic alone did not establish a missing admission check. The catalog default was already corrected to 262,144 in #1255, but this separate custom provider retained its own metadata. Existing overflow classification did start compaction.

This is distinct from candidate-admission work in #1338 and Cursor-specific server-window tracking in #1614. Neither a repeated check against the stale custom window nor a catalog-only change fixes this request.

Proposed behavior

  • Before first-chunk prefetch completes, recognize only the observed prefill-400 report containing all four counts.
  • Require positive safe integers, consistent arithmetic, actual overflow, and a reported completion count matching the final post-hook wire cap.
  • Reserve the existing 4,096 safety tokens and existing answer/reasoning minimum; do not reduce reasoning to create room.
  • Repair the completion cap once to 294912 - 210744 - 4096 = 80072 in the incident fixture. Reuse the built payload without re-running onPayload.
  • Preserve explicit fitting output caps, both output-field variants, message history and reasoning settings. Do not repair after cancellation or any received chunk. Ambiguous/unrepairable and subsequent failures retain existing error handling and configured transient retry policy.

No model metadata, fallback-chain policy, installed runtime, live settings, transcripts, or credentials are changed. No logging expansion or persistent learned-window cache is added.

Verification

  • Failing-first real-SDK/SSE regression: stale 1M metadata returned the incident prefill error; the accurate-window control already succeeded. The patched stale-window case succeeds with exactly two sends (131,072 then 80,072).
  • bun run --cwd packages/ai test --maxWorkers=4: 285 files / 2,766 tests passed; existing opt-in live gates skipped 26 suites / 884 tests.
  • bun run --cwd packages/coding-agent test test/suite/retry-fallback-billing-swap.test.ts test/suite/rpc-worker-routing.test.ts --maxWorkers=2: 21 passed.
  • bun run check and bun run build: passed. Language-server diagnostics unavailable because typescript-language-server is not installed; repository TypeScript/Biome checks ran instead.
  • Real isolated source CLI, through senpi-qa sandbox helpers and a local HTTP/SSE provider: primary usage-limit failure -> custom Kimi fallback -> prefill rejection -> corrected completion -> final marker. Exactly three total requests; hashes of both Kimi payloads match after excluding the completion cap. No paid provider calls.
  • Package Unreleased changelogs and nearest changes.md updated.

Local reproducible receipts: local-ignore/qa-evidence/20260912-fallback-budget/ (not committed; synthetic request metadata only).

CI baseline blocker correction

The first CI run passed every job except coding-agent shard 2, which expected catalog ID opencode-go/deepseek-flash. Release commit 0a22329af had already changed the catalog to opencode-go/deepseek-v4.1-flash; both affected files were unchanged from this PR's base. The same failure reproduced locally.

A separate one-line test-only commit updates the inventory assertion to the released ID. The legacy alias routing case and the assertion that every matching catalog model resolves to the V4.1 preset are retained. No production catalog or preset behavior was changed. bun run --cwd packages/coding-agent test test/suite/prompt-presets-deepseek-v4-1-flash.test.ts: 37 passed; root check passed again.

Limitations and review focus

This proposal cannot prevent the first rejection caused by an unknown server limit. It handles the observed report dialect only and does not claim exact cross-model token estimation. Correcting custom metadata remains the preventive remedy. Please scrutinize whether this narrowly evidenced repair is preferable to a different admission/reservation policy; a separate discussion comment compares those alternatives and diagnostic logging.

Not merged or installed by this PR.

@rlaope

rlaope commented Sep 12, 2026

Copy link
Copy Markdown
Contributor Author

Maintainers/reviewers: please treat the implemented bounded prefill repair as a proposal, not the sole solution.

The observed mismatch is custom target metadata (1,048,576) versus the server's reported limit (294,912); Senpi's existing clamp and the catalog correction in #1255 were already present. The server also reported input 210,744 and completion 131,072. That establishes an output-reservation overflow, but does not by itself establish an estimator bug or a missing target-admission check.

Please consider alternatives:

  • Correct or reconcile custom model metadata: the direct preventive remedy here. Re-admitting against the target budget only helps if the target limit is accurate; repeating admission against the stale 1M declaration would not help.
  • Provider-aware output reservation / target-model re-admission: potentially prevent the rejected request when trustworthy target limits or token counts are available, rather than repairing after the first rejection.
  • Pre-switch compaction or candidate handling, where appropriate: useful when the input plus required output genuinely cannot fit. In this incident fixture, the reported input leaves 80,072 completion tokens after the existing safety reserve, so preserving context is the tradeoff motivating this patch. I have deliberately not folded the broader candidate policy from fix(coding-agent): skip context-incompatible fallbacks #1338 into this PR.
  • Improved structured diagnostics, instead of or alongside behavioral changes: source/target selectors, declared and server-reported context caps, input estimate versus reported input, requested completion, total, and decision/reason would make metadata faults distinguishable from estimation or admission faults. Such logging must contain no prompt content, reasoning payloads, credentials, or auth headers. Logging alone would improve diagnosis but would not prevent the 400.

The current proposal handles only the observed, internally consistent prefill report before any chunk; changes the completion cap once; preserves the built request, reasoning settings, and explicit fitting caps; and leaves ambiguous/unrepairable failures on existing error handling. It does not prevent the first rejection from an unknown limit or persist a learned window. Please suggest a different seam or policy if it is more appropriate for Senpi's contracts.

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.

1 participant