Skip to content

feat(compaction): auto-compact and retry on context overflow errors#91

Merged
ezynda3 merged 2 commits into
masterfrom
feat/85-reactive-compaction
Jul 8, 2026
Merged

feat(compaction): auto-compact and retry on context overflow errors#91
ezynda3 merged 2 commits into
masterfrom
feat/85-reactive-compaction

Conversation

@ezynda3

@ezynda3 ezynda3 commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Description

Adds reactive compaction: when a provider call fails with a context-length/overflow error, Kit automatically compacts the conversation and replays the turn once instead of surfacing a hard failure.

Kit previously only compacted proactivelyrunTurn checks ShouldCompact() before building context. But token estimation inevitably drifts from real tokenizer counts (tool-heavy traffic, non-English text, images), and a single huge mid-turn tool result can overflow the context even when the turn started well under the limit. ErrContextOverflow existed in pkg/kit/errors.go but nothing recovered from it. The reactive path is the safety net that makes an imprecise estimator acceptable in practice (mirroring opencode's compactAfterOverflow).

Before: provider rejects the request → turn fails with a raw overflow error.
After: overflow → completed steps from the failed attempt are persisted → compaction runs (reusing compactInternal(ctx, opts, "", true)) → context is rebuilt from the session (so the replay resumes from where it overflowed rather than restarting) → media attachments are replaced with text placeholders (they can't be shrunk by summarization) → the turn replays once. If the replay also overflows, the turn fails with a clear "conversation too large to compact — still exceeds the model context window after compaction" error wrapping ErrContextOverflow.

Key properties:

  • Always on — independent of AutoCompact, which stays proactive-only. The reactive path only fires where the turn would otherwise hard-fail.
  • Single-retry guard — no compact/overflow loops.
  • Hook-transparentBeforeCompact hooks run (with IsAutomatic=true) and can still cancel; ContextPrepare hooks re-run on the rebuilt context so extensions observe every outgoing request. Compaction failure or cancellation surfaces the original provider error.
  • Clean stream capture — deltas from the failed attempt are discarded so TurnResult.Stream reflects only the replay.

Fixes #85

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Refactoring (no functional changes)

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes (go test -race ./..., golangci-lint run clean)

Additional Information

New files

  • pkg/kit/overflow.goisContextOverflow (detection via the existing ClassifyProviderError/ErrContextOverflow sentinel), prepareOverflowRetry (compact → rebuild context → strip media → re-run ContextPrepare hooks), stripMediaParts (non-mutating FilePart → text-placeholder replacement)
  • pkg/kit/overflow_test.go — 8 tests: overflow classification (raw provider text, pre-wrapped sentinel, negatives), media stripping (replacement, filename/media-type fallbacks, passthrough, input immutability), and prepareOverflowRetry end-to-end against an in-memory session (summary injection, IsAutomatic=true, hook execution, impossible/cancelled-compaction failure paths)

Modified

  • pkg/kit/kit.go — reactive retry in runTurn; extracted persistGenerationRemainder helper (deduplicates three copies of the remainder-persistence logic); expanded Options.AutoCompact godoc
  • pkg/kit/errors.goErrContextOverflow godoc now documents the automatic recovery
  • Docs: root README.md, pkg/kit/README.md, www/pages/ (sessions, cli/flags, sdk/options, sdk/overview), skills/kit-sdk/SKILL.md

Backward compatibility

  • Fully additive; no exported API surface changes (all new symbols are unexported)
  • Error contract unchanged for callers: overflow still surfaces as kit.ErrContextOverflow via errors.Is — it just fires only after recovery also failed
  • Sessions gain at most one extra CompactionEntry per recovered overflow (non-destructive, same as any compaction)

Out of scope (issue's optional follow-ons, suggested there as splittable): mid-turn ShouldCompact() checks between agentic steps, and the post-compaction synthetic continuation nudge.

Summary by CodeRabbit

  • New Features / Behavior Updates

    • Added reactive context-overflow recovery: the SDK now compacts and automatically replays a failed turn once, using text placeholders for removed attachments.
    • Media placeholders and retry output are handled so only replayed content is reflected when recovery occurs.
  • Bug Fixes

    • Improved persistence of generation-produced messages to avoid missing or duplicated conversation entries during overflow recovery.
  • Documentation

    • Clarified --auto-compact / AutoCompact: proactive compaction is optional, while reactive compact-and-retry on overflow is always enabled.
  • Tests

    • Expanded unit tests for overflow detection, replay preparation, attachment stripping, and hook behavior.

)

Add a reactive compaction path: when a provider call fails with a
context-length/overflow error, compact the conversation and replay the
turn once instead of surfacing a hard failure. Proactive ShouldCompact()
relies on token estimates that inevitably drift, and a single huge
mid-turn tool result can overflow even a turn that started under the
limit — this is the safety net that makes an imprecise estimator
acceptable.

- new pkg/kit/overflow.go: isContextOverflow detection via the
  ErrContextOverflow sentinel, prepareOverflowRetry (compact via
  existing compactInternal, rebuild context, re-run ContextPrepare
  hooks), and stripMediaParts (media attachments replaced with text
  placeholders on replay — they cannot be shrunk by summarization)
- runTurn: persist completed steps from the failed attempt first so the
  replay resumes rather than restarts; single-retry guard prevents
  compact/overflow loops; second overflow fails with a clear
  'conversation too large to compact' error wrapping the sentinel
- always on, independent of AutoCompact (which stays proactive-only);
  compaction failure or cancellation surfaces the original error
- extract persistGenerationRemainder helper (deduplicates three copies)
- tests: overflow classification, media stripping, and
  prepareOverflowRetry against an in-memory session (summary injection,
  hook execution, failure paths)
- docs: README, pkg/kit README, www (sessions, cli/flags, sdk/options,
  sdk/overview), kit-sdk skill, godoc on ErrContextOverflow/AutoCompact

Fixes #85
@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6b41508c-eee8-4a8a-9612-436ba611361f

📥 Commits

Reviewing files that changed from the base of the PR and between 9d14019 and 0f18a61.

📒 Files selected for processing (3)
  • pkg/kit/kit.go
  • pkg/kit/overflow.go
  • pkg/kit/overflow_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/kit/kit.go

📝 Walkthrough

Walkthrough

Adds reactive compact-and-replay handling for provider context-overflow errors, including replay-context rebuilding, media stripping, retry wiring in the turn loop, tests, and documentation updates that distinguish proactive from reactive compaction.

Changes

Reactive compaction feature

Layer / File(s) Summary
Overflow retry preparation
pkg/kit/overflow.go
Adds context-overflow classification, replay-context rebuilding, and media stripping for retry attempts.
Turn loop retry wiring
pkg/kit/kit.go
Adds persistence of unsaved generation output and wires reactive retry handling into turn execution.
Overflow recovery tests
pkg/kit/overflow_test.go
Adds unit coverage for overflow classification, media stripping, and replay preparation success and failure cases.
Documentation updates
README.md, pkg/kit/README.md, pkg/kit/errors.go, skills/kit-sdk/SKILL.md, www/pages/cli/flags.md, www/pages/sdk/options.md, www/pages/sdk/overview.md, www/pages/sessions.md
Updates docs and comments to describe proactive and reactive compaction and when ErrContextOverflow is surfaced.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant runTurn
  participant Provider
  participant prepareOverflowRetry
  participant ContextPrepare

  runTurn->>Provider: generate turn
  Provider-->>runTurn: context-overflow error
  runTurn->>prepareOverflowRetry: build retry context
  prepareOverflowRetry->>prepareOverflowRetry: compact and rebuild messages
  prepareOverflowRetry->>ContextPrepare: run hooks on replay context
  ContextPrepare-->>prepareOverflowRetry: prepared messages
  prepareOverflowRetry-->>runTurn: replay messages
  runTurn->>Provider: retry generate
  alt overflow again
    Provider-->>runTurn: overflow error
    runTurn-->>runTurn: surface ErrContextOverflow
  else success
    Provider-->>runTurn: result
  end
Loading

Possibly related PRs

  • mark3labs/kit#69: Introduces ErrContextOverflow and ClassifyProviderError, which this PR's overflow recovery path builds on directly.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: reactive compaction and retry on context overflow errors.
Linked Issues check ✅ Passed The PR implements the requested reactive overflow recovery, single retry, media stripping, and clear ErrContextOverflow failure behavior.
Out of Scope Changes check ✅ Passed The changes stay focused on overflow recovery and related docs/tests, with no obvious unrelated scope creep.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/85-reactive-compaction

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/kit/overflow_test.go`:
- Around line 148-159: The test setup in overflow_test is ignoring AppendMessage
failures, which can make the fixture invalid and the retry assertions
unreliable. Add a small helper in the test file around k.session.AppendMessage
that checks each append error and returns a wrapped fmt.Errorf with context,
then use it for the setup calls in the affected test cases. Focus on the
repeated message-building code in the test helpers/cases so failures are
surfaced immediately with useful context.

In `@pkg/kit/overflow.go`:
- Around line 36-41: `prepareOverflowRetry` is currently returning only a
success flag, which causes `runTurn` to pass through raw provider failures
instead of the expected `ErrContextOverflow`-wrapped error when compaction/retry
prep fails. Update `prepareOverflowRetry` to return an error (or otherwise
classify/wrap the failure) alongside the replay messages, and adjust `runTurn`
to surface `ErrContextOverflow` consistently whenever this helper cannot produce
usable retry context.
- Around line 49-55: After rerunning ContextPrepare hooks in overflow replay,
the returned messages may reintroduce media parts via fantasy.FilePart
replacements. Update the overflow flow in stripMediaParts and the
ContextPrepareHook path so any hook-returned messages are passed through
stripMediaParts again before proceeding, ensuring replayed requests stay
media-free.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 88458464-8628-46c1-97c6-c7793e60f087

📥 Commits

Reviewing files that changed from the base of the PR and between a2272f2 and 9d14019.

📒 Files selected for processing (11)
  • README.md
  • pkg/kit/README.md
  • pkg/kit/errors.go
  • pkg/kit/kit.go
  • pkg/kit/overflow.go
  • pkg/kit/overflow_test.go
  • skills/kit-sdk/SKILL.md
  • www/pages/cli/flags.md
  • www/pages/sdk/options.md
  • www/pages/sdk/overview.md
  • www/pages/sessions.md

Comment thread pkg/kit/overflow_test.go Outdated
Comment thread pkg/kit/overflow.go Outdated
Comment thread pkg/kit/overflow.go
- prepareOverflowRetry now returns an error instead of a bool so runTurn
  can wrap the original provider error with the recovery-failure reason;
  the surfaced error keeps the ErrContextOverflow classification via
  ClassifyProviderError even when the provider error was raw text
- strip media again from ContextPrepare hook results — a hook can
  replace the messages and reintroduce attachments, defeating recovery
- tests: check fixture AppendMessage errors via appendTestMessage
  helper; new TestPrepareOverflowRetry_StripsMediaFromHookResult;
  failure-path tests now assert the error message content
@ezynda3 ezynda3 merged commit 06df64b into master Jul 8, 2026
3 checks passed
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.

feat: auto-compact and retry on context overflow errors

1 participant