feat(badge): reflect the model the session is actually using, not the stale config default#1020
feat(badge): reflect the model the session is actually using, not the stale config default#1020SmolSmolStar wants to merge 4 commits into
Conversation
…nfig default The terminal model badge read the model only from the Claude settings cascade (settings files + env). But a user can switch models mid-session with /model, which never touches those files — so the badge could show "Fable" while the session was actually running Opus, with no indication anything had changed. (Hit in the wild: badge said Fable the whole time; /model showed Opus.) Read the live model from the running session's transcript instead. Claude Code records the model on every assistant turn in ~/.claude/projects/<encoded-cwd>/<session>.jsonl, so the newest entry reflects the true current model even after a /model switch. resolveClaudeConfig now prefers that live model and falls back to the config-derived model when no transcript can be resolved. Effort still comes from config (it isn't in the transcript, and it hot-reloads from the settings file anyway). Implementation reads only the tail (64 KB) of the transcript so multi-MB files stay cheap, and skips synthetic placeholder models. Verified end-to-end against a real running session (returned claude-opus-4-8, matching /model, where the config default was claude-fable-5). Adds unit tests for the path encoding, tail model read (incl. skipping synthetic), live-over-config preference, and the no-transcript fallback. Full service suite green (23/23). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ing regex Review findings addressed: - The regex tail-scan matched any "model":"..." substring, including model params inside message content (sub-agent spawns, quoted JSON) — verified against a real transcript where it would report a sub-agent's model. Now whole JSONL lines are parsed newest-first and only an assistant turn's top-level message.model counts. - Live-model lookups are now cached per directory with the same TTL as the file cache, so per-session badge polling doesn't re-scan the project dir and stat every historical transcript each time. - The cwd->project-folder encoder is hoisted to utils/pathUtils and shared with sessionRecoveryService instead of being a fourth private copy. - The model badge tooltip no longer claims session-only /model picks can't be shown — transcript detection is exactly what surfaces them. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Reviewed as part of an open-PR sweep. The transcript-based live-model concept and the config fallback are sound and kept as-is. Pushed fixes for four findings: (1) the substring regex could match "model" keys inside message content (e.g. sub-agent spawn params — reproduced against a real transcript), so extraction now JSON-parses lines and only accepts an assistant turn's top-level message.model; (2) added per-directory TTL caching so the per-session poll doesn't readdir+stat every historical transcript; (3) the cwd encoder now reuses the shared claudeProjectFolderName from pathUtils (was a 4th independent copy of scar-tissue logic); (4) updated the now-contradictory badge tooltip. Tests extended (content false-positive + cache behavior), 25/25 passing. Verdict after fix: good to merge. |
… running User feedback: terminals with no open chat still showed model/effort from the worktree's most recent transcript, presented as live state. A finished or closed session leaves its transcript behind, so transcript detection is now gated on session recovery reporting an active Claude agent for that terminal; otherwise the badge shows the configured launch default. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
User feedback: with xhigh as the daily default the warning-orange chip lit up every terminal header — now expensive efforts keep only a faintly tinted border. Badge text order flips to model · EFFORT: the model is the fact you scan for, effort is the qualifier. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Two follow-ups from live testing: (1) transcript-based detection is now gated on an actually-running Claude agent (session recovery's lastAgent/lastAgentActive) — a closed chat's leftover transcript no longer masquerades as live state; terminals with no agent show the configured launch default. (2) Badge presentation: model name now comes first (model · EFFORT), and the high-effort orange is muted to a faint tinted border — with xhigh as a daily default it lit up every header. Tests: 26/26 passing. |
Problem
The terminal model badge (#1005) reads the model only from the Claude settings cascade (settings files + env). But
/modelcan switch a running session's model without touching those files — so the badge can show one model while the session is actually running another, with no sign anything changed.Hit in the wild: the badge said Fable the whole time, but
/modelshowed Opus — the user had been on Opus for most of the session and never knew, because the badge only ever reflected the saved default.Fix
Read the live model from the running session's transcript. Claude Code records the model on every assistant turn in
~/.claude/projects/<encoded-cwd>/<session>.jsonl, so the newest entry is the true current model even after a mid-session/modelswitch.resolveClaudeConfignow prefers the live transcript model and falls back to the config-derived model when no transcript can be resolved (safe degradation to today's behaviour).<cwd>→ dashes for every non-alphanumeric char) matches Claude Code's naming.Caveats (intentional)
/modelis opened. Still accurate to what's actually running, versus today's stale guess.[1m]context suffix the config model can carry (the transcript stores the plain model id). The model identity — the thing that was confusing — is correct.Test plan
claude-opus-4-8(matching/model) where the config default wasclaude-fable-5.<synthetic>), live-over-config preference, and no-transcript fallback.agentModelConfigServicesuite green (23/23), no regressions.🤖 Generated with Claude Code