feat(claude): compact old threads before they burn through usage - #8144
feat(claude): compact old threads before they burn through usage#8144t3dotgg wants to merge 7 commits into
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
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. Comment |
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
There was a problem hiding this comment.
One consistency finding in the changed web UI: the new resume-compaction notice is a hand-rolled banner inside the composer glass shell instead of the existing composer banner/drawer surface contract. Details inline.
Posted via Macroscope — UI Consistency
ApprovabilityVerdict: Not approved Macroscope's review found this PR not approvable — This PR introduces a substantial Claude compaction workflow spanning SDK settings, resume dialogs, context tracking, slash commands, and composer/banner UI. Unresolved findings also identify cases where compaction may silently do nothing or be sent as ordinary prompt text, so the runtime behavior warrants human review. Not approved because:
Adjust the Minimum Blocking Severity for this repo — including turning it Off — in Settings. You can add or adjust custom eligibility rules. Learn more. |
There was a problem hiding this comment.
UI consistency review of the web changes. The resume-compaction notice now uses the shared ComposerBannerStack contract, which resolves the earlier finding. Two smaller consistency/interaction points remain, both inline.
Posted via Macroscope — UI Consistency
There was a problem hiding this comment.
One finding on the new compaction affordances: the shared compactDisabled flag silently deadens both new controls, which departs from how every neighbouring composer/banner action communicates an unavailable state. Details inline.
Posted via Macroscope — UI Consistency
There was a problem hiding this comment.
One finding: the new composer draft-content gate re-implements a shared predicate instead of reusing it. The previously flagged hover-popover grace period (closeDelay) and the banner action's button treatment both look resolved.
Posted via Macroscope — UI Consistency
There was a problem hiding this comment.
Follow-up on the disabled-reason handling added in d803371: the reason is now delivered only through aria-label on a disabled Button. buttonVariants sets disabled:pointer-events-none and a disabled <button> is out of the tab order, so that name is unreachable by hover, focus, or AT — sighted users still see a dead control with no explanation — while it also overrides the visible label when the button is enabled. The repo already has a disabled-reason contract (DisabledReasonTooltip in RightPanelTabs.tsx, CloudLinkSwitch in ConnectionsSettings.tsx: Tooltip + TooltipTrigger render={<span className="inline-flex">…</span>}), and the sibling composer-banner actions encode state in visible text (Stopping..., Waking..., Restoring...). Two inline notes below.
Posted via Macroscope — UI Consistency
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit d803371. Configure here.
| !activeProject || | ||
| !isServerThread || | ||
| selectedProvider !== "claudeAgent" || | ||
| !compactionProviderAvailable || |
There was a problem hiding this comment.
🟡 Medium components/ChatView.tsx:4780
The resume-compaction banner enables Compact when the started thread's Claude instance is disabled but only a different continuation group is available, so compactContext returns without dispatching and the click appears to do nothing. compactionProviderAvailable must use the same locked-instance/continuation-group eligibility as the composer, or the banner must be disabled when the composer has noProviderAvailable.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/components/ChatView.tsx around line 4780:
The resume-compaction banner enables `Compact` when the started thread's Claude instance is disabled but only a different continuation group is available, so `compactContext` returns without dispatching and the click appears to do nothing. `compactionProviderAvailable` must use the same locked-instance/continuation-group eligibility as the composer, or the banner must be disabled when the composer has `noProviderAvailable`.
Evidence trail:
7dcf3f1: apps/web/src/components/ChatView.tsx:2782-2794, 4775-4827; apps/web/src/components/chat/ChatComposer.tsx:841-895, 919-925, 1994-2012; apps/server/src/provider/Drivers/ClaudeHome.ts:37-40
| disabled={compactDisabled} | ||
| onClick={() => { | ||
| if (compactDisabled) return; | ||
| composerRef.current?.compactContext(); |
There was a problem hiding this comment.
🟠 High components/ChatView.tsx:4827
Clicking Compact sends Ultrathink:\n/compact for Claude models using the ultrathink prompt-injected effort, so Claude Code treats it as ordinary prompt text instead of a /compact command and consumes a turn. compactContext() enters the normal onSend path, which applies formatOutgoingPrompt; bypass effort injection for this command or dispatch compaction through a dedicated path.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/components/ChatView.tsx around line 4827:
Clicking `Compact` sends `Ultrathink:\n/compact` for Claude models using the `ultrathink` prompt-injected effort, so Claude Code treats it as ordinary prompt text instead of a `/compact` command and consumes a turn. `compactContext()` enters the normal `onSend` path, which applies `formatOutgoingPrompt`; bypass effort injection for this command or dispatch compaction through a dedicated path.
Evidence trail:
Reviewed commit: 7dcf3f1. `apps/web/src/components/ChatView.tsx:4820-4828` calls `composerRef.current?.compactContext()`. `apps/web/src/components/chat/ChatComposer.tsx:1994-2012` sets `/compact` and invokes `submitComposer()`. `apps/web/src/components/ChatView.tsx:5473-5490` only handles `/plan` and `/default` as standalone commands. `apps/web/src/components/ChatView.tsx:547-556` and `apps/web/src/components/ChatView.tsx:5550-5559` apply outgoing prompt formatting. `packages/shared/src/model.ts:357-371` adds the `Ultrathink:\n` prefix. `apps/web/src/components/ChatView.tsx:5783-5799` starts a provider turn with the resulting message. Claude Code docs: https://code.claude.com/docs/en/commands (commands are recognized only at the start of a message; `/compact` is listed as a command).

Claude threads can resume with hundreds of thousands of old context tokens and burn through usage before the user realizes it. T3 also did not show Claude Code's resume summary prompt or expose an easy compaction control.
This change matches Claude Code's 70-minute and 100,000-token resume conditions, supports its native resume dialog on web and mobile, adds
/compactto provider command menus, and puts a compact action in the context meter. Claude provider settings can now set an earlier auto-compaction threshold without shrinking the 1M context window.Before
After
Verified with 142 server tests, 61 contract tests, 26 web tests, and scoped type checks for server, web, mobile, desktop, contracts, and client runtime. Screenshots use synthetic Sonnet 5 conversations and contain no personal thread data.
Built by GPT-5.6 Sol in the Codex harness.
Note
Medium Risk
Changes Claude session resume and context-shaping behavior via the adapter and composer; mistakes could drop history or misfire prompts, but flows mirror Claude Code’s native dialog and are user-gated.
Overview
Adds Claude session compaction end-to-end: when resuming an old thread, the server wires Claude’s
resume_returndialog through the existinguser-inputflow (onUserDialog→ compact / keep history / don’t ask again), and forwards optionalautoCompactWindowfrom provider settings into Claude querysettings.Settings & telemetry: New
autoCompactWindowon Claude provider config (100k–1M tokens or empty). Token/context snapshots now carryautoCompactThresholdso the context meter can show “compacts at N tokens.” Claude provider status always includes a/compactslash command.Web: A composer banner nudges compaction when a Claude thread matches ~70 minutes + 100k tokens (with dismissals synced to native “don’t ask again”).
ContextWindowMeterandChatComposer.compactContext()submit/compact, with guards when drafts, approvals, or pending inputs block it.Reviewed by Cursor Bugbot for commit 7dcf3f1. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Add auto-compaction for old Claude threads to reduce context usage
autoCompactWindowsetting toClaudeSettings(empty or 100000–1000000 tokens), forwarded to the Claude SDK viasettings.autoCompactWindowon query creationresume_returndialogs from Claude by routing them through the shared user-input UI, offering Compact / Continue / Never optionsChatViewContentgated by provider, token usage, and session age, with localStorage-backed permanent dismissalcompactContextimperative handle onChatComposerand a "Compact context" button in theContextWindowMeterpopover that submits/compact; thecompactslash command is now advertised in Claude provider capabilitiesautoCompactThresholdthroughThreadTokenUsageSnapshotand derived context-window snapshots so the UI can display exact thresholdsChatComposerPropsreplacesactiveThreadActivitieswithactiveContextWindowpluscompactDisabled/compactDisabledReason; any consumer still passing the old prop will breakMacroscope summarized 7dcf3f1.