Skip to content

feat(sse): route GitHub Copilot Claude models through native /v1/messages - #7223

Merged
diegosouzapw merged 4 commits into
release/v3.8.49from
feat/port-pr-2608-github-copilot-native-messages
Jul 17, 2026
Merged

diegosouzapw merged 4 commits into
release/v3.8.49from
feat/port-pr-2608-github-copilot-native-messages

Conversation

@diegosouzapw

Copy link
Copy Markdown
Owner

Summary

  • GitHub Copilot's /chat/completions and /responses endpoints never surface prompt-cache token counts (cached_tokens) for Claude models, and round-tripping Claude tool_use/tool_result/thinking content blocks through the OpenAI shape is lossy.
  • Claude models on the github (Copilot) provider now route through Copilot's Anthropic-native /v1/messages shim instead, reusing OmniRoute's existing per-model targetFormat mechanism (the same one already used by opencode/zen's Qwen entries and opencode/go) so chatCore translates the request to Claude shape before the executor ever sees it.
  • The github executor's request-transform quirks that only make sense for /chat/completions (content-part flattening, trailing-assistant-prefill drop, the response_format-as-system-prompt workaround) are now skipped on the native path — the flattening in particular would otherwise destroy native tool_use/tool_result blocks.

Attribution

Thanks to @yidecode for the original implementation.

Changes

  • open-sse/config/providers/registry/github/index.ts: add messagesUrl transport field + targetFormat: "claude" on every claude-* model entry.
  • open-sse/config/providers/shared.ts / open-sse/config/providerRegistry.ts / open-sse/executors/base.ts: thread the new messagesUrl registry field through to ProviderConfig (mirrors how responsesBaseUrl is threaded).
  • open-sse/executors/github.ts: buildUrl() routes claude-targeted models to messagesUrl; buildHeaders() adds the required anthropic-version header for those models; transformRequest() gates its /chat/completions-only transforms off the native path.
  • tests/unit/provider-models-config.test.ts: updated the pre-existing registry-lineup assertion to reflect the new targetFormat.

Test plan

  • new test tests/unit/github-copilot-claude-native-messages.test.ts — 10/10, fails before the change (asserted the old /chat/completions URL, missing header, flattened content, dropped prefill) and passes after
  • node --import tsx/esm --test on the full set of github/registry-adjacent test files (108/108 pass, including the updated provider-models-config.test.ts and unmodified github-claude-reasoning-effort-granular.test.ts)
  • npm run typecheck:core — clean
  • npx eslint (with suppressions) on all changed files — clean

…ages

GitHub Copilot's /chat/completions and /responses endpoints never surface
prompt-cache token counts (cached_tokens) for Claude models, and round-tripping
Claude tool_use/tool_result/thinking content blocks through the OpenAI shape
is lossy. Copilot also exposes an Anthropic-native /v1/messages shim that
reports cached_tokens correctly and accepts native content blocks as-is.

Tag each github registry claude-* model with targetFormat: "claude" so
chatCore.ts translates the request to Anthropic-native shape before the
executor ever sees it (the same mechanism opencode/zen's Qwen entries and
opencode/go already use), and teach the github executor's buildUrl() /
buildHeaders() to dispatch those models at the new messagesUrl
(api.githubcopilot.com/v1/messages) with the required anthropic-version
header. transformRequest() now skips its /chat/completions-only quirks
(content-part flattening, trailing-assistant-prefill drop, the
response_format-as-system-prompt workaround) for the native path — the first
would destroy native tool_use/tool_result blocks, the prefill drop is
unnecessary because the real Anthropic API supports assistant prefill, and
the response_format workaround is superseded by the generic openai-to-claude
translator's own JSON-mode handling.

Co-authored-by: luoyide <ydhome.code@gmail.com>
Inspired-by: decolua/9router#2608
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@diegosouzapw

Copy link
Copy Markdown
Owner Author

Aprovado. Revert-proof isola bem o fix: sem os 5 arquivos de produção, 5/10 testes caem exatamente nos pontos que o PR descreve (tool_use virando text, prefill perdido). Fiação do parâmetro 'model' em buildHeaders confirmada — o call site genérico em base.ts já suportava o 4º argumento, então não há regressão pros outros executors. Pronto para merge.

…tions

- Extract applyChatCompletionsOnlyQuirks() and resolveInitiatorHeader()
  out of GithubExecutor.transformRequest()/buildHeaders() so the two
  methods drop back under the complexity/cognitive-complexity ratchets
  (2058/891 -> 2056/890, matching the frozen baseline). No behavior
  change — same guards, just relocated.
- Update 4 pre-existing unit tests that hard-coded now-native claude-*
  Copilot ids (claude-sonnet-4.5/4.6) to exercise the /chat/completions
  legacy path via an unregistered id (claude-sonnet-4), matching the
  sibling test already using that pattern. These ids now intentionally
  route to the native /v1/messages shim added by this PR, which
  correctly skips the /chat/completions-only workarounds these tests
  were built to verify — the native path's own coverage lives in
  github-copilot-claude-native-messages.test.ts.
- Split the routing invariant test (copilot-gemini-claude-route-no-responses.test.ts)
  into a Claude case (expects /v1/messages) and a Gemini case (still
  expects /chat/completions), reflecting the intentional routing change.
@diegosouzapw

Copy link
Copy Markdown
Owner Author

Babysit summary — CI green ✅

Reds fixed (2 root causes, both real, both caused by this PR's intentional routing change):

  1. Unit Tests fast-path (1/4 – 4/4) → 2bd77f37c
    Four pre-existing tests hard-coded registered claude-* Copilot ids (claude-sonnet-4.5/4.6) to exercise the /chat/completions legacy path. This PR tags those ids targetFormat: "claude", so they now route to the native /v1/messages shim, which intentionally skips the /chat/completions-only workarounds those tests assert (content-part flattening, prefill drop, response_format-as-system-prompt). Fixed by re-pointing three of them at an unregistered claude-sonnet-4 id (the pattern the sibling test at executor-github.test.ts:123 already used), and splitting copilot-gemini-claude-route-no-responses.test.ts into a Claude case (now expects /v1/messages) and a Gemini case (still /chat/completions). No assertion was weakened or removed — the /chat/completions invariants are still asserted, just on a model that still takes that path. The native path's coverage lives in github-copilot-claude-native-messages.test.ts.

  2. Fast Quality Gates (complexity + cognitive ratchets) → 2bd77f37c
    Real regression from this PR: 2058 > 2056 and 891 > 890. transformRequest hit complexity 18 / cognitive 16 and buildHeaders hit 17 after the isClaudeNative branches were added. Extracted, not rebaselined — applyChatCompletionsOnlyQuirks() and resolveInitiatorHeader(). Both ratchets now measure exactly at baseline (2056 / 890). Behavior identical; verified by the 57 tests above.

Also: merged origin/release/v3.8.49 (4524bbe3e) — the branch was 45 commits behind, clean merge, no conflicts.

Policy check — no collision. #7223 gates its routing on targetFormat === "claude" for the GitHub Copilot provider; the open GPT-5.x nest (#7012/#7101/#7242 → /v1/responses, #7095/#7176 reasoning summaries) targets OpenAI/Codex model families and never reaches the claude branch. #7012/#7242 do touch providers/shared.ts, but in the GPT_5_6_* capability constants (~L285-300); #7223 only adds the messagesUrl?: string interface field (~L107/L178). Disjoint regions, disjoint semantics.

Gate: all green — Fast Quality Gates, 4/4 unit shards, Vitest, ESLint, Docs, Merge integrity, semgrep, dast-smoke.
Tests: 4 updated (re-pointed to the legacy-path model, none weakened), 57 passing across the 6 affected files.

Ready for human review & merge — not merging.

@diegosouzapw
diegosouzapw merged commit fea1d54 into release/v3.8.49 Jul 17, 2026
15 checks passed
@diegosouzapw
diegosouzapw deleted the feat/port-pr-2608-github-copilot-native-messages branch July 19, 2026 21:00
diegosouzapw added a commit to backryun/OmniRoute that referenced this pull request Jul 23, 2026
Dropped the claude-opus-4.6 reinstatement (contradicts diegosouzapw#7223/diegosouzapw#2821 with no new
evidence; risks a production 400 on /v1/messages). Kept the gpt-5.6-sol/terra/luna
additions, which already exist on the Codex provider.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
diegosouzapw added a commit that referenced this pull request Jul 23, 2026
* feat(github): refresh Copilot model catalog

* feat(github): refresh Copilot model catalog (gpt-5.6 family)

Dropped the claude-opus-4.6 reinstatement (contradicts #7223/#2821 with no new
evidence; risks a production 400 on /v1/messages). Kept the gpt-5.6-sol/terra/luna
additions, which already exist on the Codex provider.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

---------

Co-authored-by: backryun <backryun@users.noreply.github.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
HouMinXi pushed a commit to HouMinXi/OmniRoute that referenced this pull request Aug 2, 2026
…ages (diegosouzapw#7223)

* feat(sse): route GitHub Copilot Claude models through native /v1/messages

GitHub Copilot's /chat/completions and /responses endpoints never surface
prompt-cache token counts (cached_tokens) for Claude models, and round-tripping
Claude tool_use/tool_result/thinking content blocks through the OpenAI shape
is lossy. Copilot also exposes an Anthropic-native /v1/messages shim that
reports cached_tokens correctly and accepts native content blocks as-is.

Tag each github registry claude-* model with targetFormat: "claude" so
chatCore.ts translates the request to Anthropic-native shape before the
executor ever sees it (the same mechanism opencode/zen's Qwen entries and
opencode/go already use), and teach the github executor's buildUrl() /
buildHeaders() to dispatch those models at the new messagesUrl
(api.githubcopilot.com/v1/messages) with the required anthropic-version
header. transformRequest() now skips its /chat/completions-only quirks
(content-part flattening, trailing-assistant-prefill drop, the
response_format-as-system-prompt workaround) for the native path — the first
would destroy native tool_use/tool_result blocks, the prefill drop is
unnecessary because the real Anthropic API supports assistant prefill, and
the response_format workaround is superseded by the generic openai-to-claude
translator's own JSON-mode handling.

Co-authored-by: luoyide <ydhome.code@gmail.com>
Inspired-by: decolua/9router#2608

* chore(changelog): fragment for diegosouzapw#7223

* fix(sse): green PR diegosouzapw#7223 CI — complexity ratchet + stale test expectations

- Extract applyChatCompletionsOnlyQuirks() and resolveInitiatorHeader()
  out of GithubExecutor.transformRequest()/buildHeaders() so the two
  methods drop back under the complexity/cognitive-complexity ratchets
  (2058/891 -> 2056/890, matching the frozen baseline). No behavior
  change — same guards, just relocated.
- Update 4 pre-existing unit tests that hard-coded now-native claude-*
  Copilot ids (claude-sonnet-4.5/4.6) to exercise the /chat/completions
  legacy path via an unregistered id (claude-sonnet-4), matching the
  sibling test already using that pattern. These ids now intentionally
  route to the native /v1/messages shim added by this PR, which
  correctly skips the /chat/completions-only workarounds these tests
  were built to verify — the native path's own coverage lives in
  github-copilot-claude-native-messages.test.ts.
- Split the routing invariant test (copilot-gemini-claude-route-no-responses.test.ts)
  into a Claude case (expects /v1/messages) and a Gemini case (still
  expects /chat/completions), reflecting the intentional routing change.

---------

Co-authored-by: luoyide <ydhome.code@gmail.com>
HouMinXi pushed a commit to HouMinXi/OmniRoute that referenced this pull request Aug 2, 2026
* feat(github): refresh Copilot model catalog

* feat(github): refresh Copilot model catalog (gpt-5.6 family)

Dropped the claude-opus-4.6 reinstatement (contradicts diegosouzapw#7223/diegosouzapw#2821 with no new
evidence; risks a production 400 on /v1/messages). Kept the gpt-5.6-sol/terra/luna
additions, which already exist on the Codex provider.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

---------

Co-authored-by: backryun <backryun@users.noreply.github.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…ages (diegosouzapw#7223)

* feat(sse): route GitHub Copilot Claude models through native /v1/messages

GitHub Copilot's /chat/completions and /responses endpoints never surface
prompt-cache token counts (cached_tokens) for Claude models, and round-tripping
Claude tool_use/tool_result/thinking content blocks through the OpenAI shape
is lossy. Copilot also exposes an Anthropic-native /v1/messages shim that
reports cached_tokens correctly and accepts native content blocks as-is.

Tag each github registry claude-* model with targetFormat: "claude" so
chatCore.ts translates the request to Anthropic-native shape before the
executor ever sees it (the same mechanism opencode/zen's Qwen entries and
opencode/go already use), and teach the github executor's buildUrl() /
buildHeaders() to dispatch those models at the new messagesUrl
(api.githubcopilot.com/v1/messages) with the required anthropic-version
header. transformRequest() now skips its /chat/completions-only quirks
(content-part flattening, trailing-assistant-prefill drop, the
response_format-as-system-prompt workaround) for the native path — the first
would destroy native tool_use/tool_result blocks, the prefill drop is
unnecessary because the real Anthropic API supports assistant prefill, and
the response_format workaround is superseded by the generic openai-to-claude
translator's own JSON-mode handling.

Co-authored-by: luoyide <ydhome.code@gmail.com>
Inspired-by: decolua/9router#2608

* chore(changelog): fragment for diegosouzapw#7223

* fix(sse): green PR diegosouzapw#7223 CI — complexity ratchet + stale test expectations

- Extract applyChatCompletionsOnlyQuirks() and resolveInitiatorHeader()
  out of GithubExecutor.transformRequest()/buildHeaders() so the two
  methods drop back under the complexity/cognitive-complexity ratchets
  (2058/891 -> 2056/890, matching the frozen baseline). No behavior
  change — same guards, just relocated.
- Update 4 pre-existing unit tests that hard-coded now-native claude-*
  Copilot ids (claude-sonnet-4.5/4.6) to exercise the /chat/completions
  legacy path via an unregistered id (claude-sonnet-4), matching the
  sibling test already using that pattern. These ids now intentionally
  route to the native /v1/messages shim added by this PR, which
  correctly skips the /chat/completions-only workarounds these tests
  were built to verify — the native path's own coverage lives in
  github-copilot-claude-native-messages.test.ts.
- Split the routing invariant test (copilot-gemini-claude-route-no-responses.test.ts)
  into a Claude case (expects /v1/messages) and a Gemini case (still
  expects /chat/completions), reflecting the intentional routing change.

---------

Co-authored-by: luoyide <ydhome.code@gmail.com>
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
* feat(github): refresh Copilot model catalog

* feat(github): refresh Copilot model catalog (gpt-5.6 family)

Dropped the claude-opus-4.6 reinstatement (contradicts diegosouzapw#7223/diegosouzapw#2821 with no new
evidence; risks a production 400 on /v1/messages). Kept the gpt-5.6-sol/terra/luna
additions, which already exist on the Codex provider.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

---------

Co-authored-by: backryun <backryun@users.noreply.github.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant