Bug
estimateSystemPromptTokens (introduced in PR #241) gives wildly different results depending on which call site invokes it:
- Nudge breakdown (
inject.ts): reported 162.3K system tokens (53% of context)
- acp_status (
status.ts): reported 32.6K system tokens (19% of context)
Same function, same session, 5× difference. The real system prompt is ~30-40K (AGENTS.md + tool definitions + ACP rules), so acp_status is closer to correct.
Root Cause
estimateSystemPromptTokens scans the messages array for the first assistant message with token data, reads its tokens.input + cache.read + cache.write, and subtracts the first user message's token count:
systemTokens = firstAssistantMsg.totalInput - firstUserMsgTokens
After compression replaces older messages, the "first visible assistant message" may be from turn 100+, where totalInput includes system + 100 turns of context — not just system + firstUser. So systemTokens is grossly inflated.
The two call sites see different message array states (nudge runs early in message-transform, acp_status is a later tool call), so they find different "first assistant messages" with different token data.
Impact
- Nudge shows
system 53% → model thinks system prompt dominates context → misleads compression strategy
compressibleTokens = total - systemTokens is miscalculated → affects nudge gating
- Model sees inconsistent numbers between nudge and
acp_status → confusion
Reproduction
- Start a long session with many compressions
- Observe nudge breakdown system tokens vs
acp_status system tokens
- They diverge significantly
Environment
Fix Direction
Cache system prompt size once from the earliest API call (when context = system + first user message only). Store in state.systemPromptTokens and reuse. The system prompt doesn't change between turns unless the user edits AGENTS.md.
Bug
estimateSystemPromptTokens(introduced in PR #241) gives wildly different results depending on which call site invokes it:inject.ts): reported 162.3K system tokens (53% of context)status.ts): reported 32.6K system tokens (19% of context)Same function, same session, 5× difference. The real system prompt is ~30-40K (AGENTS.md + tool definitions + ACP rules), so acp_status is closer to correct.
Root Cause
estimateSystemPromptTokensscans the messages array for the first assistant message with token data, reads itstokens.input + cache.read + cache.write, and subtracts the first user message's token count:After compression replaces older messages, the "first visible assistant message" may be from turn 100+, where
totalInputincludes system + 100 turns of context — not just system + firstUser. SosystemTokensis grossly inflated.The two call sites see different message array states (nudge runs early in message-transform, acp_status is a later tool call), so they find different "first assistant messages" with different token data.
Impact
system 53%→ model thinks system prompt dominates context → misleads compression strategycompressibleTokens = total - systemTokensis miscalculated → affects nudge gatingacp_status→ confusionReproduction
acp_statussystem tokensEnvironment
d087522)Fix Direction
Cache system prompt size once from the earliest API call (when context = system + first user message only). Store in
state.systemPromptTokensand reuse. The system prompt doesn't change between turns unless the user edits AGENTS.md.