SIGN IN SIGN UP

fix(byoa): record the real model for Grok ACP turns (#43)

`GrokSession` reported `opts.model` for both the ledger hop and the turn
result, falling back to the literal string `'grok'`. But `opts.model` is only
the pin Cumora asked for, and it is null whenever the operator left the model
unpinned — which is the default, and is also what CUMORA_ENGINE_MODEL=local
produces for a custom provider.

So on the ACP path — the default path on macOS and Linux — every turn wrote
`model: 'grok'` into llm_calls (a model id that does not exist) or none at all,
while the one-shot `grok -p` path on the same machine correctly reported
`grok-4.6` off its stream. Two paths, two answers, and `cost.priceFor` resolves
neither, so the spend lands on FALLBACK_PRICE.

Grok announces the live model over ACP and re-announces it when it changes:

  {"jsonrpc":"2.0","method":"_x.ai/models/update",
   "params":{"currentModelId":"grok-4.6","availableModels":[...]}}

Sniff it, exactly as ClaudeSession sniffs `message.model` off its own stream,
and prefer it over the pin. Verified against a real grok 1.0.4 install:

  before   turn model: null        hop model: grok
  after    turn model: grok-4.6    hop model: grok-4.6

which also makes the ACP path agree with the one-shot path on the same machine.

Also teach the observability brain-tier split about Grok's cerebellum. `isSmall`
matched only /haiku|mini/, so `grok-4.5` — the small model the daemon's own
triageModel() picks for Grok — rendered as "big brain" in the cost view.

Not included: cost.ts has no `grok-*` price seed, so Grok spend still prices on
FALLBACK_PRICE. I only have two sampled costs from the CLI and three unknowns
(input / cached-input / output rates), so any seed I derived would be a guess
dressed up as a rate. That needs xAI's published prices.
X
Xialie Zhuang committed
8aaf54a7e89f103d05f9c57d6299d575bb4d9cc7
Parent: c4eecea
Committed by GitHub <noreply@github.com> on 8/20/2026, 10:59:37 AM