Skip to content

feat(server): add /compact context compaction on every agent - #252

Merged
TheDarkPhantom merged 4 commits into
mainfrom
feat/context-compaction-server
Sep 30, 2026
Merged

TheDarkPhantom merged 4 commits into
mainfrom
feat/context-compaction-server

Conversation

@TheDarkPhantom

Copy link
Copy Markdown
Owner

The fork only observed compaction. Nothing could trigger it, so a long thread kept growing until the provider compacted it on its own terms. This ports upstream's /compact command (server, contracts, shared only; the web UI comes later).

How it works

  • A user message of exactly /compact with no attachments is intercepted by ProviderCommandReactor and routed to the new ProviderService.compactThread instead of being sent as a prompt. It is rejected when the thread has no conversation yet, or while a turn is running.
  • Every adapter now has to declare compaction (a required field on ProviderAdapterShape, following refactor(server): let adapters declare context compaction pingdotgg/t3code#10112):
    • Codex runs its native thread/compact/start, and a finished contextCompaction item now emits thread.state.changed: compacted.
    • OpenCode runs its native session.summarize({ auto: false }) and maps session.compacted.
    • Claude and Grok send /compact as a turn, and Cursor sends /compress.
    • The test adapter declares unsupported, which fails with a validation error.
  • The bookkeeping lives in a new ProviderCompaction.ts, so ProviderService.ts only gains a few call sites. It allows one compaction per thread and uses a 10-minute timeout. A native run that times out blocks retries until it reports back or the session restarts. A slash-command run waits for its own turn to settle, and if that turn completes without reporting a compaction, one is synthesized. The compacted event carries the /compact message id as requestId.
  • Messages sent during compaction queue and replay in order, each with the interaction mode and model it was sent with (fix(server): queue messages during context compaction pingdotgg/t3code#11107). If compaction fails, is interrupted, or the session stops, they are reported as "Queued message was not sent".
  • The projection keeps the /compact pending row while messages queue behind it. It clears that row on a context-compaction or provider.turn.start.failed activity whose requestId matches, or when the reactor sets the session back to ready.
  • Ingestion attaches beforeTokens/afterTokens, taken from the provider when it reports them (Claude's compact_boundary) and otherwise from the last two context-window readings. The activity summary reads "Compacted context 899K → 0 tokens".
  • Claude (feat(claude): compact old threads before they burn through usage pingdotgg/t3code#8144):
    • New autoCompactWindow setting (100000 to 1000000). A settings patch with any other value is rejected, and a bad value already stored decodes to empty.
    • ThreadTokenUsageSnapshot.autoCompactThreshold.
    • onUserDialog with supportedDialogKinds: ["resume_return"], surfaced through the existing AskUserQuestion user-input path with "Compact and continue" / "Keep full history" / "Don't ask again".
    • New packages/shared/src/claudeCompaction.ts.
    • The ultrathink prefix is no longer added to slash commands, so they still run.
  • All five providers advertise /compact as a slash command.

No DB migrations. The web-only follow-ups (pingdotgg#11103, pingdotgg#9623, pingdotgg#9430, and the web half of pingdotgg#8144) are listed in FUTURE_ENHANCEMENTS.md.

Ported from pingdotgg#9293, pingdotgg#10112, pingdotgg#11107 and pingdotgg#8144.

Tests cover reactor /compact routing, the empty-thread rejection, queue and replay order, queued-message cancellation on failure, per-adapter compaction (Codex, OpenCode, native and slash-command in ProviderService, unsupported, timeout quarantine), the projection's pending-row handling, ingestion requestId and token sizes, the Claude setting and dialog, the settings decode, and the shared copy.

Done by Claude Opus 5.5 (1M context) in Claude Code.

🤖 Generated with Claude Code

TheDarkPhantom and others added 3 commits September 30, 2026 06:01
A user message of exactly /compact now compacts the thread's provider
context instead of being sent as a prompt. Each adapter declares how it
compacts: Codex and OpenCode run their native compaction, Claude and
Grok send /compact as a turn, Cursor sends /compress, and an adapter
that declares nothing fails loudly. Messages sent while a thread
compacts queue and are replayed in order once it finishes, or are
reported as not sent if compaction fails or the session stops.

Claude also gains an Auto-compact after setting (100,000 to 1,000,000
tokens), reports its auto-compact threshold, and asks through the
existing question UI whether to compact an old session on resume.

Ported from pingdotgg#9293
Ported from pingdotgg#10112
Ported from pingdotgg#11107
Ported from pingdotgg#8144

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL labels Sep 30, 2026
@TheDarkPhantom
TheDarkPhantom merged commit e0e0462 into main Sep 30, 2026
12 checks passed
@TheDarkPhantom
TheDarkPhantom deleted the feat/context-compaction-server branch September 30, 2026 12:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant