Repository navigation
Agents panel shows the parent session's model/effort for every subagent instead of the subagent's own #7281
Description
Activity
On 0.0.38 I hit a second trigger for the same false value: a background subagent pinned to
model: opusand served throughout byclaude-opus-5rendered asfable-5-1 · high— the parent session's model — after I resumed it withSendMessagefollowing an API error, and an unresumed failure rendered<synthetic> · high.The launch-time seed in
ClaudeAdapter.tsfalls back to the session model when the launching tool input carries no model, as you describe. ASendMessageresume re-emitstask_startedwith no model and a newtool_use_id, so the record is overwritten with the parent's value and rebound to an id thatagentIdForParentToolUsenever matches on later assistant snapshots.<synthetic>, the model field on Claude Code's synthetic error message, is accepted like any other model.04:55:29 task.started model=opus 04:59:25 task.updated model=<synthetic> status=failed 13:15:48 task.started model=claude-fable-5-1 (resume) 13:19:37 task.updated model=claude-fable-5-1 status=completedThat rebinding is one confirmed instance of the matching failure you suspected: refinement cannot land because the lookup has nothing to match. Workaround is to read
message.modelfrom the subagent jsonl.Drafted with Claude Code (Claude Opus 5) from source and transcripts on my machine; I reviewed and posted it.
Still observing incorrect parent-model attribution on macOS with installed nightly 0.0.41-nightly.20260913.1646, including completed stages displayed after resuming a Workflow with
resumeFromRunId.The parent runs
gpt-6-astra(medium). Five build, deployment and repair stages explicitly select an Opus agent. Their original child JSONL transcripts all recordmessage.model: "claude-opus-5", with actual tool calls and completed results. Yet earlier completed stages in the resumed Workflow displaygpt-6-astra(medium)and no token count. The newly executed stage displays Opus with its tokens and tools. The same repair stage appears as Opus in one run and Astra in a later resumed view.This is a display attribution problem in these samples, not evidence that the work ran on Astra or was skipped after a quota error. A missing token count alone cannot establish either.
This appears to be another instance of this issue's symptom. I have not tested whether #7287 covers the resumed-Workflow case. Reused stages should retain their original verified model, or display unknown when identity cannot be recovered, rather than present the parent's model as fact.
Investigated with Codex using local child transcripts and Workflow journals.
Also seeing this on 0.0.40 (macOS). Custom agents in
~/.claude/agents/witheffort: lowandeffort: mediumin frontmatter all show the parent session'shighin the Agents panel, while each subagent's own transcript JSONL records"effort":"low"/"effort":"medium"on every request. So the agents run at the right effort and only the label is wrong. That makes the panel misleading for anyone using per-agent effort to control cost. Happy to re-test once V2 lands.Closed #13333 because of the V2 freeze. Note for V2: the SDK only reports a subagent's real effort on hooks fired inside it.
PreToolUseandSubagentStopinputs carryagent_id(equal totask_id) andeffort.level;SubagentStarthas no effort (SDK 0.3.276).I'm still seeing this on
0.0.43-nightly.20260929.2416on Linux. My custom agent in~/.claude/agents/setsmodel: claude-sonnet-5-5andeffort: low. Its card shows whatever effort the thread is on, somediumin one thread andhighin another. The agent's transcript records"effort":"low","perTurnEffort":"low"on every turn, so it really runs at low.The model label is right for me.
handleAssistantMessageswaps in the subagent's model as soon as its first message arrives. That leaves effort as the only field stuck on the start-time fallback.#14272 would leave effort blank, which beats showing a wrong value. There's another option, though.
task_startedalready carriessubagent_type, and a file-defined agent keeps its effort in frontmatter, in~/.claude/agents/<type>.md, the project's.claude/agents/, or a plugin's agents folder. If the adapter read that file at start, custom agents would show their real effort. Agents without aneffort:line,general-purposeincluded, would keep following the session or show nothing.
Summary
Every row in the Agents panel displays the parent session's model and effort rather than what the subagent actually ran on. With a session on
opus-5 · xhigh, eight subagents spanning four different models all rendered asopus-5 · xhigh.The token counts and titles on those rows are correct — only model/effort are wrong — so it reads as authoritative rather than as a placeholder. That's what makes it costly: it silently misreports model routing, and anyone reasoning from the panel will draw wrong conclusions about which model handled what.
Reproduction
Requires custom subagents that declare
model:/effort:in frontmatter (~/.claude/agents/*.md).opus-5atxhigh.model: haiku/effort: low,model: sonnet/effort: medium,model: fable/effort: high.Expected — each row shows that agent's own model/effort.
Actual — every row shows
opus-5 · xhigh.Evidence
Eight probes, each
Reply with the single word ACK. "Panel" is what the sidebar rendered; "actual" is from the SDK's own run records at~/.claude/projects/<project>/<session>/subagents/agent-*.jsonl, wheremessage.modelon each assistant record is the API's report of which model served the request:lookup-fastopus-5 · xhighclaude-haiku-4-5-20251001, no effortimplement-fastopus-5 · xhighclaude-opus-5/lowgeneralopus-5 · xhighclaude-sonnet-5/mediumreview-standardopus-5 · xhighclaude-sonnet-5/highdeep-reasoningopus-5 · xhighclaude-opus-5/highcritical-reviewopus-5 · xhighclaude-opus-5/xhigh✅long-horizonopus-5 · xhighclaude-fable-5/highinheritopus-5 · xhighclaude-opus-5/xhigh✅The two correct rows are the two that coincidentally match the session —
critical-reviewhappens to share it, andinheritis supposed to.Same eight agents in both columns: panel token counts match the records exactly (8.8k↔8895, 16.7k↔16684, 22.2k↔22151, 12.0k↔11960, 16.5k↔16537, 7.7k↔7707, 16.7k↔16729, 16.4k↔16421). Two independent signals confirm different models really ran: the haiku probe emitted
out=73tokens where every Opus/Sonnet probe emittedout=5, and it carries noeffortfield at all — Haiku 4.5 doesn't take reasoning effort, yet the panel labels itxhigh.Cause
apps/server/src/provider/Layers/ClaudeAdapter.ts:3194-3202seeds both fields at launch:The comment above it — "absent ones inherit the session's selection (SDK behavior)" — holds only for agent types that genuinely inherit (
general-purpose,claude,inherit). For a file-defined agent, the SDK resolves model and effort from the agent's own frontmatter and pushes an effort layer for that subagent; theAgenttool input carries no override, so this fallback attributes the session's values to an agent that never used them. The adapter can't see the agent definition, so the launch-time seed is unavoidably a guess — the issue is that the guess is presented as fact.Effort is never corrected. The model has a refinement path at
ClaudeAdapter.ts:2876-2883, which overwritesowningAgent.modelfrom the authoritativemessage.modelon subagent assistant snapshots, andtaskLinkageFor(:1034-1035) propagates both onward. There is no equivalent for effort anywhere —context.currentEffortis the only source it ever has.For model, the refinement path exists but did not land for these direct spawns (all eight kept the seeded value). I haven't diagnosed why; the
agentIdForParentToolUse(…, assistantParentToolUseId)lookup at:2878seems the place to look, and these probes were short-lived (1–2s), so a snapshot ordering or matching issue is plausible. Flagging it as observed rather than asserting the mechanism.Suggested direction
lookup-fastrecord has noeffortfield, andxhighon Haiku 4.5 is not a value that can exist.Environment
t3code on macOS 26 (Darwin 27.0.0) · Claude Code 2.1.233 · session
claude-opus-5atxhigh