Skip to content

fix(core): compact once after payload size rejections - #61306

Open
ekeane wants to merge 1 commit into
anomalyco:devfrom
ekeane:payload-recovery
Open

ekeane wants to merge 1 commit into
anomalyco:devfrom
ekeane:payload-recovery

Conversation

@ekeane

@ekeane ekeane commented Nov 2, 2026 •

Copy link
Copy Markdown

Issue for this PR

Closes #53107. Related: #53108 (earlier PR for the same issue).

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

HTTP 413 payload rejections currently leave long sessions resending the same oversized history. Route these failures through the existing one-shot compaction recovery before assistant output starts. Recovery summaries omit inline media without unnecessarily reducing the token budget; original messages and images remain stored. Automatic-compaction opt-out and the existing recovery limit still apply.

This is an independent implementation against current dev.

How did you verify your code works?

  • Root bun run check and core bun run typecheck:tsc pass.
  • Core runner, step, compaction and native-compaction suites: 294 tests pass. Provider-error suite: 46 tests pass.
  • Six new cases cover raw/streamed rejections, stored images, disabled compaction, repeated rejection, failed summaries and partial output. All pass across 10 repetitions; the two recovery cases fail on unchanged dev.
  • Full core suite: 7,192 pass, 35 skip, 3 fail. The three shell cases also fail on unchanged dev with macOS /bin/bash 3.2.

To reproduce the focused coverage: from packages/core, run bun run script/test.ts test/session-runner.test.ts test/session-step.test.ts test/session-compaction.test.ts test/session-native-compaction.test.ts.

Visual

<svg xmlns="http://www.w3.org/2000/svg" width="240" height="72" viewBox="0 0 240 72" role="img" aria-label="A rejected request compacts once and resumes">
  <style>
    @keyframes pulse { 0%,100% { opacity:.45 } 50% { opacity:1 } }
    .compact { animation:pulse 3s infinite }
    .resume { animation:pulse 3s 1s infinite }
    @media (prefers-reduced-motion:reduce) { .compact,.resume { animation:none } }
  </style>
  <g fill="none" stroke="currentColor" opacity=".7">
    <rect x="3" y="16" width="62" height="40" rx="8"/>
    <path d="M69 36h15m-5-5 5 5-5 5M154 36h15m-5-5 5 5-5 5"/>
  </g>
  <g fill="currentColor" font-family="system-ui,sans-serif" font-size="11" text-anchor="middle">
    <text x="34" y="40">413</text>
    <g class="compact"><rect x="89" y="16" width="62" height="40" rx="8" fill="none" stroke="currentColor"/><text x="120" y="40">Compact</text></g>
    <g class="resume"><rect x="175" y="16" width="62" height="40" rx="8" fill="none" stroke="currentColor"/><text x="206" y="40">Resume</text></g>
  </g>
</svg>

Screenshots / recordings

No UI changes; verified with deterministic runner fixtures.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

Added by the opencode bot (AI-generated).

Related: #48095, #52042

@opencodejr opencodejr Bot 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.

This looks right to me. I ran the #53107 reproduction from source against a mock gateway that returns 413 for request bodies over 200 KB. On the base, the turn with the image and every --continue after it fail, and the gateway only ever sees requests that still contain the image. With this PR, the 413 leads to one summary request without the image, then a rebuilt request without the image, and both that turn and the next one succeed. In the context-overflow control case, the request rebuilt after compaction also no longer resends the image. The runner, step and compaction tests (289) and typecheck:tsc pass.

Public API: unchanged. The recoverOverflow signature and the new payload value for the Trigger reason are internal to packages/core.

One behaviour to be aware of, not blocking: when the image that triggers the rejection is attached to the current turn, the model then answers that turn with the image left out (the summary says [image/png omitted]) and the user isn't told. That's probably the right trade-off compared with a session that stays stuck, but a visible notice may be worth a follow-up.

This overlaps closely with #53108, which takes the same approach for the same issue and now has merge conflicts with dev.

Related: #48095, #52042

This branch has not been deployed

No deployments
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.

fix(core): recover sessions after HTTP 413 payload rejections

1 participant