Skip to content

estimateSystemPromptTokens inconsistent between nudge and acp_status after compression #255

Description

@ranxianglei

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

  1. Start a long session with many compressions
  2. Observe nudge breakdown system tokens vs acp_status system tokens
  3. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions