Repository navigation
[Bug]: Claude auto-compaction still shows "Thinking" — status:"compacting" is flattened into the generic running state #10959
Description
Activity
Triage
Confirmed on
main@6c58362. Automatic Claude compaction still has no in-progressCompacting…state. This is the gap#7652originally named;#9293only covered the explicit/compactcommand.What the code does today
- Claude's
SDKStatusMessagestatus:"compacting"is mapped to runtime"waiting"inClaudeAdapter.ts(session.state.changed). - Ingestion then collapses
"waiting"to orchestration"running"(orchestrationSessionStatusFromRuntimeState). By the time the session reaches the client, compacting and a normal turn are the same value. OrchestrationSessionhas nostatusDetail/compactingSince.RuntimeSessionStatehas no"compacting".- Web (
ChatView.tsx) and mobile (use-thread-composer-state.ts) setisCompactingonly when a user message is exactly/compactwith no attachments. Auto-compaction never produces that message, so the timeline stays onThinking/Working for N. compact_boundarystill becomes the completedcontext-compactiondivider after the fact. The silent interval while compaction runs is unmarked.
Codex
contextCompactionitem start events and OpenCodesession.time.compactingare also unused for in-progress UI. Completion-only signals (thread.state.changed/session.compacted) already feed the divider.Related
- [Feature]: Show compaction state and result instead of a generic "Working" #7652 — closed as fixed by feat(providers): add context compaction command #9293. The close covered the
/compactchrome and the result row, not auto-compaction while it is running. - feat(providers): add context compaction command #9293 — merged. Manual
/compact→Compacting…→ completed divider. - feat: show compaction state and result instead of a generic Working #7714 — closed unmerged as superseded by feat(providers): add context compaction command #9293. That supersession was incomplete for the automatic path.
- [Bug]: Claude thread stays on Working forever after /compact — session stuck at running with no active turn #7589 and Messages sent while /compact runs are rejected and cannot be queued #10724 are different bugs (stuck session after
/compact; queue rejected during/compact).
No open PR implements automatic compaction status.
Decision
Accept as a remaining gap left by #9293. Do not reopen #7714 as-is.
#7714 is an XL stacked PR (DB migrations, decider settle changes, per-adapter wiring, composition with still-open #7591). Current
mainalready has the #9293Compacting…UI and completion row. Reopening that branch would fight the tree we have now.Reuse #7714's overlay idea in a new, smaller change:
- Optional
statusDetail: "compacting"(plus acompactingSinceclock) onOrchestrationSession. Keepstatusasrunningso lifecycle / settling stay unchanged and older clients keep decoding. - Stop flattening Claude
status:"compacting"; raise and clear the overlay from that signal. Later: CodexcontextCompactionstarted and OpenCodesession.time.compacting. - Web + mobile:
isCompacting= existing/compactheuristic orsession.statusDetail === "compacting".
Cursor and Grok have no ACP compaction start signal — treat as not supported, same as #7652.
Leaving this issue open as the home for that work. Not reopening #7652 or #7714.
- Claude's
- addedbugSomething is broken or behaving incorrectly.Something is broken or behaving incorrectly.acceptedfeature request acceptedfeature request acceptedvia-triageFiled through npx t3 triageFiled through npx t3 triage
on Sep 9, 2026
Before submitting
Area
apps/server
Steps to reproduce
/compact).Expected behavior
Automatic compaction surfaces the same
Compacting…state that #9293 added for the manual command, so it is obvious the agent is compacting rather than stalled.Actual behavior
The thread just says
Thinking(andWorking for N) for the entire compaction, which can run for minutes with no output. It is indistinguishable from a stuck or looping turn.The
Compacting…state added by #9293 is gated entirely on an explicit/compactuser message:apps/web/src/components/ChatView.tsx:661—isCompactCommandMessagematches a user message whose text is exactly/compactwith no attachmentsapps/web/src/components/ChatView.tsx:2945—isCompactingis derived from that message plus turn timestampsAutomatic compaction produces no such message, and Claude's own start signal is discarded before any client can see it:
apps/server/src/provider/Layers/ClaudeAdapter.ts:3411—SDKStatusMessagestatus:"compacting"is flattened into the genericwaitingsession stateapps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts:261-279—orchestrationSessionStatusFromRuntimeStatecollapseswaitingintorunningSo by the time the orchestration session reaches the client, "compacting" and "running a normal turn" are the same value.
compact_boundaryonly arrives after compaction, so the completed divider and token counts do render — but nothing marks the interval while it is running.This is the case #7652 originally described (it names
ClaudeAdapter'sstatus:"compacting"→waitingflattening as the root cause). #7652 was closed as fixed by #9293, and #7714 — which did implement the automatic path via an optionalstatusDetail: "compacting"/compactingSinceonOrchestrationSession, fed by Claude'sstatus:"compacting", Codex'scontextCompactionitem, and OpenCode'ssession.time.compacting— was closed as superseded at the same time. #9293 only shipped the manual/compactcommand path, so the automatic case is still unhandled onmain.Impact
Minor bug or occasional failure
(Cosmetic in mechanism, but it reliably reads as a hung agent: users cancel turns and waste tokens because a multi-minute silent
Thinkinglooks broken.)Version or commit
main @ 6c58362 (line numbers above verified against that commit; originally observed on a fork tracking upstream 299404a)
Environment
Linux, web client served from source (
apps/server+apps/web), Node 24.15, Claude provider.Logs or stack traces
n/a — no error is produced; the status label is simply generic.Workaround
None for automatic compaction. Typing
/compactmanually does showCompacting…, but that only covers the case that already works.