Skip to content

fix(server): Claude subagents keep their model after a usage-limit notice - #17097

Open
jieyuexing wants to merge 1 commit into
pingdotgg:mainfrom
jieyuexing:fix/claude-synthetic-subagent-model
Open

jieyuexing wants to merge 1 commit into
pingdotgg:mainfrom
jieyuexing:fix/claude-synthetic-subagent-model

Conversation

@jieyuexing

Copy link
Copy Markdown

Problem

When Claude hits a usage limit or an API error while a background subagent is running, the CLI emits an assistant frame under that subagent's parent_tool_use_id with model: "<synthetic>". ClaudeAdapterV2 treats every non-empty message.model under a subagent as that subagent's model snapshot. So it replaced the real model (for example haiku or claude-opus-5-5) with <synthetic>, and the subagent card showed <synthetic> as its model.

Seen on 0.0.46-nightly.20261007. A thread started 14 background subagents and 12 of them failed on a usage limit. 13 of the 14 subagent rows ended up with model = "<synthetic>". The one that kept its real model had completed before the limit.

Fix

Treat "<synthetic>" like an empty model when taking the subagent model snapshot. The same variable feeds both the update of a registered subagent and the pending-launch record (rememberPendingClaudeSubagentLaunch), so one check covers both paths. The adapter already treats "<synthetic>" as Claude's own notice for goal frames (nextClaudeGoal, and the goal check in the root-frame handler).

This is a very small, focused fix for an obvious bug, so it is submitted without a prior issue under CONTRIBUTING. <synthetic> is a sentinel, not a model, and the change does not affect any real model value.

Verification

  • Added a synthetic-after case to the existing parameterized test records the subagent model from %s without inheriting the parent override. The subagent is launched with model: "haiku", then a <synthetic> frame arrives under it, and the test asserts the model stays haiku.
    • Without the fix it fails: expected '<synthetic>' to equal 'haiku'.
    • With the fix, vp test run apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.test.ts passes (158 tests).
  • vp lint and vp fmt --check on the two changed files are clean. tsc --noEmit in apps/server reports no errors.

Not covered: no live run against a rate-limited Claude account. #14670 / #14672 fix the same sentinel showing up in the Usage model list; this PR is the subagent card.


Model: Claude Opus 5.5 (1M context), harness: Claude Code running inside T3 Code.

🤖 Generated with Claude Code

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XS 0-9 changed lines (additions + deletions). labels Oct 8, 2026
macroscopeapp[bot]
macroscopeapp Bot previously approved these changes Oct 8, 2026
@macroscopeapp

macroscopeapp Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 92aab78

Macroscope's review found this PR approvable — This is a narrowly scoped Claude adapter bug fix that prevents synthetic usage-limit/API notice frames from replacing a subagent’s real model, with targeted regression coverage. It introduces no schema, security, deployment, product-default, or static-analysis changes.

You can add or adjust custom eligibility rules. Learn more.

@coderabbitai

coderabbitai Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Path: .coderabbit.config.ts
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 3ab1baa9-b086-4bf9-86f7-2e52174e44a4

📥 Commits

Reviewing files that changed from the base of the PR and between af954a9 and 92aab78.


📒 Files selected for processing (2)
  • apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.test.ts
  • apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.



📝 Walkthrough

Walkthrough

Claude subagent model tracking now ignores snapshots with an empty model name or "<synthetic>". A test covers a synthetic assistant frame received after task registration.

Changes

Subagent model handling

Layer / File(s) Summary
Ignore synthetic model values
apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts, apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.test.ts
Model tracking ignores "<synthetic>" snapshots. The test verifies that a later synthetic assistant frame does not replace the subagent model.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~8 minutes

Change: Bug fix

Suggested reviewers: juliusmarminge


Merge Risk: ⚪ Minimal · up to 92aab

Subagent cards should retain the inferred model when a synthetic notice arrives; no actionable merge risk is evident in the supplied changes.

Architecture Summary

Architecture risk: 🔵 Low · up to 92aab

The change affects 1 system.

Changed systems: apps/server

Architecture concerns
No architecture-level concerns identified.

Review details

Systems and components

  • observed — apps/server (service) was modified; 2 changed files map to changed impact.

Before / after behavior

  • observed — Modified behavior in apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.test.ts: Added synthetic-after to the subagent-model test cases; the existing cases remain.
  • observed — Modified behavior in apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.test.ts: For synthetic-after, the observed assistant frame now uses "<synthetic>"; other cases continue to use the Haiku model string.
  • observed — Modified behavior in apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.test.ts: The observed frame is now queued after task_started for both observed-after and synthetic-after; previously this applied only to observed-after.
  • observed — Modified behavior in apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts: Subagent model tracking now ignores "<synthetic>" snapshots as well as empty model names; previously only empty names were ignored, so synthetic notices could be canonicalized and applied as the subagent model.

Pre-merge checks | Passed 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description check Passed The description includes the required Problem, Change, Scope and approval, and Verification sections. It explains the bug, the sentinel handling change, the focused test coverage, validation results, …
Title check Passed The title clearly and concisely describes the primary server fix: preserving Claude subagent models after usage-limit notices.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR

  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@juliusmarminge juliusmarminge added the macroscope-review Opt PRs made by unvouched contributors in for Macroscope review. Vouched contributors auto-reviews label Oct 11, 2026 — with ChatGPT Codex Connector
@macroscopeapp
macroscopeapp Bot dismissed their stale review October 11, 2026 05:54

Dismissing prior approval to re-evaluate af954a9

macroscopeapp[bot]
macroscopeapp Bot previously approved these changes Oct 11, 2026
…tice

Claude stamps its own notices, such as a usage-limit or API error message,
with the model "<synthetic>". When such a frame arrived under a running
background subagent, the adapter took it as the subagent's model snapshot
and overwrote the real model, so the subagent card showed "<synthetic>".

Ignore "<synthetic>" like an empty model, matching how the adapter already
treats it for goal frames.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@jieyuexing
jieyuexing force-pushed the fix/claude-synthetic-subagent-model branch from af954a9 to 92aab78 Compare October 11, 2026 06:14
@jieyuexing

Copy link
Copy Markdown
Author

Note

Drafted by Claude Opus 5.5 in Claude Code (running inside T3 Code); reviewed and posted by @jieyuexing

Rebased onto current main (5047ee7) to clear the conflict with #17496.

The subagent model is now passed through canonicalClaudeSubagentModel, which still turns "<synthetic>" into the subagent's model, so the bug is still on main. The fix now skips "<synthetic>" before that call, and the test case is unchanged.

  • On main without the fix, the synthetic-after case fails: expected '<synthetic>' to equal 'claude-haiku-5-5'.
  • With the fix, vp test run apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.test.ts passes (227 tests). vp fmt --check and tsc --noEmit in apps/server are clean. vp lint reports only the existing unused layer warning in ClaudeAdapterV2.ts, which this PR does not touch.

@macroscopeapp
macroscopeapp Bot dismissed their stale review October 11, 2026 06:14

Dismissing prior approval to re-evaluate 92aab78

This branch has not been deployed

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

Labels

macroscope-review Opt PRs made by unvouched contributors in for Macroscope review. Vouched contributors auto-reviews size:XS 0-9 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants