Skip to content

feat(claude): account for /advisor escalations under the advisor model#659

Open
iamtoruk wants to merge 1 commit into
mainfrom
feat/advisor-usage
Open

feat(claude): account for /advisor escalations under the advisor model#659
iamtoruk wants to merge 1 commit into
mainfrom
feat/advisor-usage

Conversation

@iamtoruk

Copy link
Copy Markdown
Member

What

Claude Code's new advisor tool (/advisor) escalates hard decisions mid-turn to a stronger model. Those tokens are recorded inside message.usage.iterations[] as advisor_message entries carrying their own model, and are excluded from the top-level message.usage totals (which cover only the main model).

CodeBurn read only the top-level totals, so for anyone using /advisor:

  • the advisor's tokens were silently dropped (undercounted spend), and
  • no cost was ever attributed to the advisor model (wrong model mix).

This is the same gap ccusage closed in their advisor support.

Change

  • Parse each advisor_message iteration into its own call, attributed to the advisor's model and priced accordingly. The main call keeps exactly the top-level totals, so there is no double counting.
  • Preserve advisor iterations through two paths that would otherwise drop them:
    • entry compaction (compactEntry), which trims usage for the session cache;
    • the large-line (>32KB) byte-scanner parsers, which never extracted iterations before. The fix JSON-parses only the small usage-object slice, not the whole line.
  • Fold advisor cost into the live guard budget (src/guard/usage.ts), which also reads these sessions.
  • Bump the claude parser cache version and GUARD_CACHE_VERSION so existing caches re-parse and pick up advisor spend.

Advisor calls use a stable dedup key (<msgId>:advisor:<ordinal>) keyed on advisor ordinal, so the report path (compacted, advisor-only iterations) and the guard path (raw iterations) agree.

Verification

  • New tests in tests/parser-advisor-usage.test.ts: main-call attribution unchanged, separate advisor call priced under the advisor model, no double counting, survives compaction, and survives the >32KB large-line path. Mutation-verified each fails on pre-fix code.
  • Adversarial review (two rounds) executed streaming/dedup, cache round-trip, guard-vs-report parity, UTF-8 in the large-line buffer path, and small/large parity; all clean.
  • Full suite: 3094 tests pass. tsc --noEmit clean.

Scope note

fallback_message iterations (written when a turn retries on another model) are a related, pre-existing under-count in the same family. They were never counted before this change either, so they are left as a documented follow-up rather than expanding this PR.

Claude Code's advisor tool (/advisor) escalates hard decisions mid-turn
to a stronger model. Those tokens are recorded inside
message.usage.iterations as advisor_message entries with their own model
and are excluded from the top-level message.usage totals. The parser read
only the top-level totals, so advisor spend was silently dropped and never
attributed to the advisor model.

Emit a separate call per advisor_message iteration priced under the
advisor model, preserve those iterations through entry compaction and the
large-line (>32KB) byte-scanner path, and fold advisor cost into the guard
budget. Bump the claude parser and guard cache versions so existing caches
re-parse and pick up the advisor spend.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant