Skip to content

fix(claude): report subagent model and effort - #7287

Open
lnieuwenhuis wants to merge 6 commits into
pingdotgg:mainfrom
lnieuwenhuis:dev/fix/subagent-model-attribution
Open

fix(claude): report subagent model and effort#7287
lnieuwenhuis wants to merge 6 commits into
pingdotgg:mainfrom
lnieuwenhuis:dev/fix/subagent-model-attribution

Conversation

@lnieuwenhuis

@lnieuwenhuis lnieuwenhuis commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Problem

Claude file-defined subagents were seeded with the parent session's model and effort. The Agents panel therefore showed the parent settings for every subagent, and authoritative model snapshots that arrived late never reached the client.

Fix

  • leave subagent model and effort unknown unless the Agent launch explicitly overrides them
  • reconcile authoritative model snapshots before or after task.started
  • capture each subagent's effort through the SDK's typed SubagentStart and SubagentStop hooks
  • emit late identity corrections and bound pending refinements to avoid unbounded session growth
  • cover parent non-inheritance, event ordering, terminal-task correction, explicit overrides, and cache eviction

Verification

  • pnpm exec vp test run apps/server/src/provider/Layers/ClaudeAdapter.test.ts (74 passed)
  • pnpm exec vp test run packages/client-runtime/src/state/subagentRuntime.test.ts (48 passed)
  • pnpm exec vp run --filter t3 typecheck
  • targeted format, lint, diff, and changed-file secret checks

Fixes #7281

Model: GPT-5.6 Sol
Harness: Codex in T3 Code


Note

Medium Risk
Changes runtime event payloads and task identity logic in the Claude provider path; incorrect linkage could affect UI/analytics for subagents, but scope is localized to adapter event emission with heavy test coverage.

Overview
Fixes misattributed subagent model/effort in the Claude adapter: file-defined agents no longer inherit the parent session’s selection when the Agent tool omits overrides. Identity is seeded only from explicit launch input, then refined from subagent assistant snapshots and SDK SubagentStart / SubagentStop hooks (effort).

Late or early identity is handled via a bounded pending-refinement map (model + effort, cap 256): snapshots that beat task_started apply on start; snapshots or hooks that arrive after terminal rows emit task.updated corrections. Error frames with model <synthetic> are ignored. Repeated task_started on resume keeps the original Agent tool_use_id so snapshots still link correctly.

Tests add invokeSubagentEffortHook and broaden scenarios (non-inheritance, ordering, post-completion correction, resume, synthetic models, explicit overrides, eviction).

Reviewed by Cursor Bugbot for commit 1f67bd5. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix subagent model and effort attribution in ClaudeAdapter

  • Subagent task.started events no longer infer model or effort from the parent session; they use explicit Agent-tool overrides, buffered runtime refinements, or existing task metadata.
  • Adds SubagentStart/SubagentStop hook callbacks to capture effort metadata, either buffering it for unregistered tasks or emitting task.updated corrections for registered tasks.
  • Replaces the model-only pending buffer with a model-and-effort refinement buffer capped at 256 entries with FIFO eviction, keyed by a generic identity string.
  • Filters the synthetic error-frame model sentinel out of subagent attribution so progress retains the real model.
  • Risk: task.started now reports unknown model/effort when no explicit override or runtime refinement is available — check makeClaudeAdapter in ClaudeAdapter.ts for the fallback removal.

Macroscope summarized 1f67bd5.

@coderabbitai

coderabbitai Bot commented Aug 17, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 85bd484b-088d-4ed0-9fd2-ac17437dce64

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Aug 17, 2026
@macroscopeapp

macroscopeapp Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This production change alters Claude task lifecycle events and adds SDK hook-driven reconciliation for subagent model, effort, and resume identity. The scope is localized and well tested, but the new asynchronous state and event-ordering logic is complex enough to merit human review.

Not approved because:

  • Monthly spending limit reached (workspace setting). Approvability relies on correctness review in order to determine eligibility

Review your spending limits in Billing settings. You can add or adjust custom eligibility rules. Learn more.

@t3dotgg t3dotgg added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. and removed vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Aug 24, 2026
…del-attribution

# Conflicts:
#	apps/server/src/provider/Layers/ClaudeAdapter.ts
@lnieuwenhuis

Copy link
Copy Markdown
Contributor Author

Merged current main and resolved the conflicts with #7583, which landed a narrower version of the snapshot/task_started race fix (model only, keyed by parent_tool_use_id). This branch's pending-refinement buffer subsumes that behavior, so I kept the refinement implementation and removed the now-redundant pendingTaskModels map.

Two notes for reviewers:

  • fix(server): keep the authoritative subagent model when snapshots race task_started #7583's new test ("a subagent snapshot that beats task_started still wins over the seed") asserted that a subagent with no explicit effort override inherits the parent session's effort. That inheritance is exactly the misattribution this PR removes, so the assertion now expects undefined; the model assertions (including propagation into task.progress) are unchanged, and effort attribution is covered by the SubagentStart-hook tests here.
  • Everything else merged cleanly. All 82 ClaudeAdapter tests pass locally.

@SamGu-NRX

Copy link
Copy Markdown

Independent reproduction, plus one data point on AgentInfo.model that may be useful here.

Prevalence. I compared the label on every local_agent task in my local event store against the model: each agent file declares, normalizing effort and [1m] suffixes. Over 241 tasks: 192 wrong at task_started (79%), and 35 still wrong at rest (14%) after snapshot refinement had its chance. One task recorded "model": "claude-opus-5" on task.started and "model": "gpt-5.6-luna" on task.progress seconds later, for the same task id, which matches your reading that routing was correct and only the label was wrong.

The 79%→14% gap is the part I found interesting: refinement does most of the work, so the residual is concentrated in children that never stream an assistant snapshot the parent sees.

One possible addition. query.supportedAgents() returns AgentInfo[], and AgentInfo.model is documented as "Model alias this agent uses. If omitted, inherits the parent's model" (sdk.d.ts:97-109). It resolves off the cached initialization result rather than a per-task control request. Probing my installed CLI 2.1.245:

claude               (inherits)
Explore              (inherits)
general-purpose      (inherits)
Plan                 (inherits)
statusline-setup     sonnet
theo-composer        cursor/composer-2.5

That would give a launch-time value between an explicit Agent override and the parent fallback, so a definition-pinned agent starts with its own alias rather than blank, while genuinely inheriting agents still fall through. It is an alias, not the resolved API id, so your snapshot path would still be the authority that corrects it.

Worth noting the built-in defaults are version-sensitive: on the SDK-bundled 2.1.170 Explore reports haiku, but on 2.1.245 it inherits. So this helps custom agents much more than stock ones, and it does not reach effort at all, since AgentInfo has no effort field. It may well not be worth the extra surface here.

Composition. I have a separate fix for a different bug in this file, the parent context meter counting subagent tokens (#5942, PR #8453). I applied your branch and mine together on today's main: they typecheck, and the suite passes at 85 tests once three shared tests are reconciled. Only the test file collides; the source changes are independent. Happy to rebase mine whenever yours lands.

…l-attribution

# Conflicts:
#	apps/server/src/provider/Layers/ClaudeAdapter.test.ts
@VendettaGhub

Copy link
Copy Markdown

Independent Windows test report for 1f67bd5. I checked this PR because we use a local Claude SDK / hybrid-router setup and had patched the same parent-model/effort attribution problem locally.

Results

  • Unmodified PR checkout: pnpm exec vp test run apps/server/src/provider/Layers/ClaudeAdapter.test.ts packages/client-runtime/src/state/subagentRuntime.test.ts133 passed, 2 files.
  • Additional local, synthetic matrix: parameterized the existing “uses a subagent snapshot that arrives before task.started” test across five snapshot model identifiers (gpt-6-astra, gpt-5.6-sol, gpt-5.6-luna, claude-opus-5, claude-fable-5-1) and five hook effort strings (low, medium, high, xhigh, max). All 25 combinations passed. With that one test expanded to 25, the same two-file run passes 157 tests.
  • pnpm exec vp run --filter t3 typecheck — passed with the matrix in place.
  • git diff --check — passed.

The matrix emits an assistant snapshot with parent_tool_use_id, invokes the existing invokeSubagentEffortHook(harness, "SubagentStart", "task-model", effort) helper, then emits the matching task_started. It asserts that task.started preserves the exact snapshot model and hook effort instead of the parent session's claude-opus-4-6 / max selection. The original suite also exercises unknown metadata, explicit overrides, late corrections and resumed-task identity.

Boundaries

These are adapter/client-runtime tests with synthetic SDK input, not real provider calls or a rendered sidebar check. The matrix treats model names and effort values as metadata: it does not establish that every model supports every effort, that a hybrid router applies them, or that the live CLI emits each tested hook payload. No production T3 instance was replaced or restarted, and this is not a latest-main integration/rebase test.

Environment: Windows x64, Node 25.8.0, pnpm 11.10.0, lockfile-installed SDK 0.3.170. Node is outside the repository's declared ^24.13.1 range, so this is supplementary Windows evidence, not a replacement for supported-runtime CI.

For our use case, preserving runtime-reported model IDs and effort is preferable to upstreaming our local frontmatter/alias display workaround. I did not find an additional issue in the tested metadata path that warrants a competing PR.

Test report prepared with Codex Desktop (local configuration: GPT-6 Astra, medium).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Agents panel shows the parent session's model/effort for every subagent instead of the subagent's own

4 participants