Repository navigation
fix(server): resumed Claude subagents keep their own model and effort label - #14272
spiky02plateau wants to merge 1 commit into
Conversation
Reviving a finished subagent with SendMessage re-registers the same task under the SendMessage call, which names no model or effort, so the row fell back to the session's model and effort. Re-registration now keeps what is already known for the task. Subagent effort also defaulted to the session's effort, which is wrong whenever an agent definition sets its own. The SDK reports no per-agent effort, so effort is shown only when the launch input sets it.
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — This is a small, well-tested Claude adapter bug fix that corrects resumed subagent metadata without changing the underlying model or effort used by the runtime. The production impact is limited to task labeling and state retention, with no new capability, schema change, or deployment impact. Notes:
You can add or adjust custom eligibility rules. Learn more. |
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository: pingdotgg/t3code/.coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (2)
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review. 📝 WalkthroughWalkthroughClaude task registration now selects the model from launch input, recorded task state, or session state. It uses explicit or previously recorded task effort, not session effort. Tests cover omitted launch values and resumed-agent model and effort retention. ChangesClaude agent registration
Priority: ⬇️ Low Estimated code review effort: 2 (Simple) | ~12 minutes Change: Bug fix Suggested reviewers: Merge Risk: ⚪ Minimal · up to No actionable merge-blocking issue was identified in Claude subagent metadata registration or resume behavior. The change is mergeable after normal checks. Security Architecture ReviewSecurity architecture risk: 🔵 Low · up to Resumed tasks now retain their own displayed settings instead of inheriting session settings. No new privilege path was found, but behavior during overlapping lifecycle events is not fully established. Retained concerns Security review detailsSecurity Blast Radius
Trust Boundaries and Controls
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Description checkExplanation The description explains the problem, intended behavior, implementation scope, and linked issue. It does not follow the required template headings and does not provide focused verification steps or observed test results. It also does not clearly document maintainer approval or why the change qualifies as an obvious bug fix. Resolution Add the required Problem, Change, Scope and approval, and Verification sections. Include the specific tests run, their observed results, and anything not checked. Link the triaged issue with approval evidence, or explain why this focused fix does not require prior approval.
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
…ard (#539) > [!NOTE] > A Claude subagent's own background shells and nested agents leaked into the parent timeline as "Received N updates" rows and one-agent "Kicked off 1 subagent" cards. The server now attributes those tasks to the subagent that started them, and web and mobile keep them inside that subagent's single spawn card. ## Problem When a Claude subagent started its own background shells or its own agents, the parent thread's timeline filled with stray rows. Each finished shell became a "Received N updates" row. Each nested agent became a separate "Kicked off 1 subagent" card, placed wherever it happened to start, often between unrelated messages. The clients already hide a subagent's internal work, but only when the task carries `agentId` (its owner). The Claude adapter never set it. It looked for the launching tool call among streamed tool calls, but Claude streams tool-call deltas only for the parent conversation. A subagent's tool calls arrive only as whole `assistant` snapshots tagged with `parent_tool_use_id`, and the adapter used those snapshots only to refine the model name. In practice no task row ever got `agentId`. Upstream has the same gap. The open related PRs don't cover this path: pingdotgg#10575 still depends on child stream events, and pingdotgg#14272 and pingdotgg#14031 address resumed-subagent labels and reactivation. ## Fix - **Server (Claude adapter):** records which subagent made each tool call from its assistant snapshots, bounded to 512 entries per session. `task_started` uses that record when no streamed call matches. A subagent's shells therefore carry the subagent's `agentId`, and so do its nested agents. A resumed subagent keeps its owner. Its later messages also still resolve to it, because they keep the original Agent call as their parent even though the SDK re-registers the task under the `SendMessage` call. - **Web and mobile:** a nested agent joins its owner's spawn card instead of opening its own. Its owner's first row has already decided that card. The existing quiet-timeline rule already hides a subagent's own shells once they carry `agentId`. Existing threads are not repaired, because their persisted task rows have no owner to group by. ## Validation - **Live run** against an isolated dev server with a real Claude Sonnet 5.5 thread. The parent launched one background subagent and ended its turn. After that, the subagent started a background `sleep` shell and a nested background agent, and the nested agent started its own shell. The persisted task rows had the expected owners: - The subagent's shell and the nested agent were attributed to the subagent. - The nested agent's shell was attributed to the nested agent. - When the CLI resumed the subagent on its own, it stayed unowned. - **Timeline:** one "Ran 2 subagents ✓ completed" card at the spawn point, with no "Received N updates" rows and no extra cards. The Agents panel listed both agents. - **Focused tests:** one each for the adapter, web and mobile. Each fails without the fix and passes with it. The adapter test covers shells, nested agents, completions, and a shell started after a resume. Full `ClaudeAdapter.test.ts`, `session-logic.test.ts` and `threadActivity.test.ts` pass, and server, web and mobile typecheck. - **Not verified:** the mobile client was not run. Mobile is covered by its unit test only. | Before | After | | --- | --- | |  |  | --- Written by an agent (Claude Code, claude-opus-5-5). Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Dismissing prior approval to re-evaluate eb08085
|
Thanks for working on this. We merged the orchestrator V2 rewrite in #2829, and we are closing this PR as part of that transition. This change touches ClaudeAdapter.ts, which the V2 merge removed. Claude execution now runs through ClaudeAdapterV2. Sorry for the extra work this creates. If the change is still needed on V2, please rebuild it on current main, verify it there, and open a new PR linking back here. We're closing the current implementation without assuming the underlying request is resolved. |
What Changed
When a finished Claude subagent is revived with SendMessage, its row in the agents list now keeps the subagent's model instead of switching to the parent session's model. Subagent rows also stop showing the session's effort level; effort appears only when the Agent call sets it explicitly.
Why
Reviving a finished subagent makes the SDK register the same task again, with the SendMessage call as its launching tool. That call names no model or effort, so the adapter fell back to the session's selection and the row showed the parent's model while the subagent kept running on its own. Subagents that received a message while still running were unaffected, because no new task_started arrives for them.
Effort had a second problem: when the Agent call set no effort, the row showed the session's effort. An agent definition can set its own effort, and the SDK reports no per-subagent effort on any stream message, so the row could show
mediumfor a subagent running onhigh. The contract describes the field as "effort when known", so the adapter now reports effort only when the launch input sets it, and keeps the known value across a resume.Scope is the Claude adapter's task_started handling. Model refinement from subagent snapshots and the client reducers are unchanged.
Closes #14842
Checklist
Summary by CodeRabbit