Repository navigation
fix(providers): resolve untagged claude-* ids on GitHub/GHE Copilot to native targetFormat (#14575) - #14758
Merged
Conversation
…o native targetFormat (#14575)
…14575 made native (#14575) Since #14575 every claude-* id on the gh alias resolves targetFormat "claude" (native /v1/messages, which honors assistant prefill), so the unregistered "claude-sonnet-4" this test used no longer reaches the /chat/completions path it covers. The drop still applies to every non-Claude model there, so the test now uses gpt-4.1 (targetFormat null). Same assertions; the GitHub executor + targetFormat suite is 392/392.
…copilot-tool-choice
3 of 6 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #14575
Root cause
GitHub Copilot's new
claude-opus-5.5id is absent from OmniRoute's curated GitHub Copilotcatalog.
GithubExecutor.buildUrl()already routes any claude-named model (registered ornot) to Copilot's Anthropic-native
/v1/messagesendpoint via an unconditional/claude/inamematch. But
getModelTargetFormat("gh", model)only recognized registered claude ids, so anuntagged id like
claude-opus-5.5fell through to the provider's baseopenaiformat. Therequest body stayed OpenAI-shaped (
tool_choiceas a string,toolsas{type:"function",...}) while being dispatched to the Anthropic-native endpoint, which rejectsit with
tool_choice: Input should be an objectandtools.0: Input tag 'function' found....Fix
open-sse/config/providerModels.ts::getModelTargetFormat(): after the curated-catalog lookupmisses, added a heuristic scoped to the
gh/ghe-copilotaliases — any model id containingclaude(case-insensitive) resolvestargetFormat: "claude", mirroring the routing decisionbuildUrl()already makes unconditionally. This is the same pattern already shipped for theopenai"-pro"heuristic (#5842). Curated catalog entries still return before this heuristicis reached, so no existing routing changes for registered models.
Regression test
tests/unit/github-copilot-claude-untagged-model-14575.test.ts(new):resolveChatCoreTargetFormat({provider:"github", resolvedModel:"claude-opus-5.5", sourceFormat:"openai", ...}).targetFormatresolved to"openai"whileGithubExecutor.buildUrl("claude-opus-5.5", ...)returned the Anthropic-nativemessagesUrl— assertion'openai' !== 'claude'failed.targetFormatresolves to"claude", matching the endpointbuildUrl()already routes to. Also added a control test for a curated model (no regression) and a parity test for theghe-copilotalias.Existing tests
Two pre-existing tests encoded the OLD (buggy) premise that an unregistered claude-named id on
ghwould stay on the/chat/completionspath (getModelTargetFormat("gh", ...) === null).With this fix that premise no longer holds — any claude-named id is now native, matching
buildUrl()'s own routing — so those tests were realigned to the corrected behavior (notweakened; assertions changed to match what is now the correct contract):
tests/unit/t27-github-copilot-response-format.test.ts— "T27: Claude + response_format=json_object injects system instruction..." renamed and now assertsresponse_formatpasses through untouched for an untagged claude id (native path skips the/chat/completions-only workaround), consistent with the already-existinggithub-copilot-claude-native-messages.test.tscoverage for registered ids.tests/unit/executor-github.test.ts— two tests updated similarly: (1) reasoning-field stripping still applies for claude models, but response_format is no longer injected as a system message (native path); (2) the Anthropic-shape content-part sanitization test now uses a non-claude model id (gpt-4o) to exercise the/chat/completions-only sanitization path, since that path is now unreachable for any claude-named id.All three files pass after the change. Also ran and confirmed green (no regressions):
provider-registry-github-copilot-targetformat.test.ts,ghe-copilot-targetformat-parity.test.ts,github-copilot-custom-model-target-format.test.ts,openai-responses-only-models-5842.test.ts,provider-models-target-format-scoping.test.ts,copilot-claude-always-v1-messages.test.ts,github-copilot-claude-native-messages.test.ts,chatcore-target-format.test.ts,custom-model-target-format.test.ts,provider-models-config.test.ts.Gates run
node --import tsx/esm --test tests/unit/github-copilot-claude-untagged-model-14575.test.ts— RED then GREEN (4/4 pass post-fix)npm run typecheck:core— 1 pre-existing error insrc/lib/services/cliproxyAccountHealth.ts(untouched by this PR; already fixed on the currentorigin/release/v3.8.51tip past this branch's base commitbeec76d5— inherited, not introduced by this diff)node scripts/check/check-open-sse-typecheck.mjs— 2 pre-existing errors inopen-sse/executors/auggie.ts(untouched by this PR; same situation — already fixed on the current tip past this branch's base)npx eslint --suppressions-location config/quality/eslint-suppressions.json open-sse/config/providerModels.ts tests/unit/github-copilot-claude-untagged-model-14575.test.ts— cleannode scripts/check/check-file-size.mjs— no violations on files this diff touches (10 pre-existing violations on unrelated frozen files)node scripts/check/check-complexity-ratchets.mjs --base-ref origin/release/v3.8.51— OK (0 changed source files in ratchet scope)node scripts/check/check-mutation-test-coverage.mjs --strict— pre-existing drift on 9 unrelated modules (none touched by this diff;providerModels.tsis not a stryker-mutated module)node scripts/check/check-changelog-integrity.mjs— OKnpm run check:provider-consistency— OK (276 registry entries, 0 registry-only exceptions)cliproxyAccountHealth.tsandauggie.tstypecheck errors above arepre-existing on this branch's cut point (
beec76d5) and already fixed on the currentorigin/release/v3.8.51tip by later, unrelated commits — not introduced by this diff.Plan-file:
_tasks/pipeline/bugs/2-implementing/14575-fix-github-copilot-tool-choice-error-in-claude-opus-5-5-on-git.plan.md