Skip to content

fix(anthropic): preserve the provider-qualified response model (#1117) - #1138

Open
lidge-jun wants to merge 1 commit into
codex/260806-stack05-structured-outputfrom
codex/260806-stack07-anthropic-identity
Open

fix(anthropic): preserve the provider-qualified response model (#1117)#1138
lidge-jun wants to merge 1 commit into
codex/260806-stack05-structured-outputfrom
codex/260806-stack07-anthropic-identity

Conversation

@lidge-jun

Copy link
Copy Markdown
Owner

Summary

A request for anthropic/claude-sonnet-5 came back as claude-sonnet-5. applyFinalRouteRequestNormalization overwrites parsed.modelId with the bare upstream id so the Anthropic request goes out correctly, but every downstream consumer then built response.model from that mutated value — the Responses bridge, the image loop, and the web-search loop. A client that round-trips response.model loses the provider routing.

The final Codex-facing selector is now retained on _responseModelId and used for client-facing output on all three paths, while the upstream request body keeps the bare model. Request logs keep the physical routed model, so observability still shows what was actually called.

Scope guard. This is deliberately Anthropic-only: _responseModelId is set only when the routed provider is Anthropic, so every other provider leaves it undefined and ?? parsed.modelId yields byte-identical behavior. A regression test pins that — a non-Anthropic routed provider whose public and wire model differ still emits exactly what it emitted before. Response identity for every provider is a contract change, not a bug fix, and this PR does not make it.

Closes #1117.

Attribution

The mechanism is @giulioleone097's (Giulio Leone) from #1122 — the _responseModelId field, the 29-line responses-model-rewrite.ts helper, the bridge/loop wiring, and the request-log preservation are all their design, credited via Co-authored-by. They also reported the issue.

@Ingwannu independently diagnosed the same defect correctly in #1121; credit for the diagnosis is theirs too.

What I intentionally did not carry over from #1122: the catalog changes (sync.ts, parsing.ts, provider-fetch.ts, effort.ts, convergence.ts), the hidden bare-selector compatibility rows, and the adapter-resolve.ts captured-default change. Generated catalog rows with restore/removal semantics carry their own failure modes (user-owned row collisions, restore deleting a generated row) and deserve their own PR rather than riding along with a response-identity fix. That brought this down from 25 files to 10.

Both #1122 and #1121 are left open for their authors. Planning unit: devlog/_plan/260806_stacked_bug_campaign/050_phase6_anthropic_response_identity.md.

Stack 6 of the 260806 attribution campaign, stacked on #1137.

Verification

  • bun test tests/response-model-identity.test.ts tests/images/loop.test.ts tests/web-search.test.ts tests/request-log.test.ts — 132 pass, 0 fail (re-run after rebase onto stack 5)
  • Red-then-green confirmed: before the fix the four qualified Anthropic JSON/SSE cases failed while the non-Anthropic guard already passed
  • bun run typecheck — exit 0
  • bun run privacy:scan — passed
  • Full suite passed the repository prepush gate on push

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed.
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults.

Adapt the response-model rewrite mechanism from PR #1122 for issue #1117, narrowed to Anthropic message routes so all other providers retain their existing response.model contract.

Co-authored-by: Giulio Leone <giulioleone097@gmail.com>
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

🗂️ Base branches to auto review (2)
  • ^dev$
  • ^preview$

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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 65cf23b0-ae50-4858-9ad5-a771564625f2

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 commented Aug 6, 2026

Copy link
Copy Markdown

Deterministic PR hygiene checks passed.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1879bd0df6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +871 to +872
const preserveAnthropicResponseModel = route.providerName === "anthropic"
|| route.provider.adapter === "anthropic";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Include finalized Anthropic wire routes in preservation

When a client requests opencode-go/minimax-m3 (similarly minimax-m2.5 or minimax-m2.7), the provider initially has the openai-chat adapter, so this predicate is false; line 891 then applies the repository's hard pin and switches the finalized adapter to anthropic. Consequently, parsed.modelId is stripped to minimax-m3 without setting _responseModelId, and JSON/SSE responses still return the bare selector, so round-tripping it loses the opencode-go route—the same failure this change is intended to fix. Include the finalized adapter or pinned-wire result in the preservation predicate and add coverage for a pinned Anthropic route.

Useful? React with 👍 / 👎.

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

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant