Skip to content

port(upstream): #2608 - Route Claude models through GitHub Copilot native /v1/messages - #291

Merged
bloodf merged 7 commits into
devfrom
port/upstream-2608
Jul 16, 2026
Merged

bloodf merged 7 commits into
devfrom
port/upstream-2608

Conversation

@bloodf

@bloodf bloodf commented Jul 16, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • What changed: Claude models on GitHub Copilot are routed to Copilot's Anthropic-native /v1/messages shim; message_stop usage fallback folds cache_read/cache_creation into prompt_tokens. Hardened the route per Codex review: strips params upstream rejects, maps max_completion_tokens/stop/tool_choice:"none" to Anthropic shapes, bounds the fetch with the provider connect timeout, retries transient 502/503/504 + network failures, drops the Claude Code persona for non-Claude-Code Copilot clients, and strips unsigned thinking history.
  • Why it changed: Port of upstream decolua/9router #2608. /v1/messages is the only Copilot endpoint that surfaces prompt-cache token counts (cached_tokens); /chat/completions never gets cache_control. Non-Claude models (gpt/gemini/grok) keep existing /chat/completions (or /responses) routes untouched.

Type

  • feat: — new feature (port)

Breaking changes

  • No

Testing

  • What was tested: claude→/v1/messages routing + forced upstream SSE + cache-usage surfacing; failure (never [DONE]) on truncated/malformed stream; connect-timeout aborts with no in-place retry; 503 transient retries exhausted (initial+3) and 503→200 recovery; persona injected for claude-cli but absent for a generic Copilot client; unsigned thinking stripped; tool_choice:"none"→{type:"none"} contract (promoted from known-bug it.fails).
  • Commands run: npm run test:ci (full fail-closed gate); targeted vitest unit/github-claude-messages.test.js + unit/openai-to-claude.test.js.
  • Evidence: targeted suite 31/31 PASS (25 prior + 6 new); full npm run test:ci Raw failures: 0 under pinned Node 20.20.2; CI 3/3 GREEN on head e3892be0 — ✨ Lint & Build, 🧪 Vitest + No-regression gate, commitlint. git diff --check origin/dev...HEAD clean.

Checklist

  • Tests added or updated for behavioral changes (tests/unit/github-claude-messages.test.js +6 tests; tests/translator/bugs-toClaude-context.test.js known-bug promoted)
  • No new dependencies without explicit justification (none added)
  • Conventional commit used (port(upstream): / fix(port): / test(port):)
  • CHANGELOG updated if this change is user-facing (Unreleased → Features + Fixes bullets)
  • No secrets, keys, credentials, or tokens committed

Upstream: decolua/9router#2608

Agent disclosure

  • Model: durindoor/kimi/kimi-k2.7
  • Harness: Oh My Pi (omp) coding harness — Claude-Code-style agent
  • Harness version: unknown (not surfaced to agent)
  • Plugins installed: none visible to this agent beyond the shared skill library

This contribution is agent-generated as part of the orchestrated upstream-port cycle and was produced without interactive human review of the diff in this session.

@bloodf
bloodf force-pushed the port/upstream-2608 branch from 7d1dc8b to 5ccf065 Compare July 16, 2026 03:35

@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: 7d1dc8bf40

ℹ️ 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 thread open-sse/executors/github.js Outdated
Comment thread open-sse/executors/github.js Outdated
Comment thread open-sse/executors/github.js Outdated
Comment thread open-sse/executors/github.js Outdated
@bloodf
bloodf force-pushed the port/upstream-2608 branch from 5ccf065 to 25d7517 Compare July 16, 2026 04:33

@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: 25d7517de4

ℹ️ 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 thread open-sse/executors/github.js Outdated
Comment thread open-sse/executors/github.js Outdated
Comment thread open-sse/executors/github.js Outdated
Comment thread open-sse/executors/github.js Outdated
bloodf pushed a commit that referenced this pull request Jul 16, 2026
…tion_tokens/stop/tool_choice on Claude /v1/messages

Codex review on PR #291 (1 P1 + 3 P2): the new native /v1/messages path
translated the OpenAI body without the stripUnsupportedParams pass the
/chat/completions path applies, and the generic OpenAI->Claude translator
dropped max_completion_tokens, stop, and tool_choice "none".

- github executor: stripUnsupportedParams("github", model, {...body}) before
  translateRequest so temperature/thinking/reasoning_effort no longer 400.
- openai-to-claude: honor max_completion_tokens when max_tokens absent
  (prefer explicit max_tokens); map stop string|string[] to stop_sequences
  (guard stop:null); map tool_choice "none" to Anthropic {type:"none"}.

Tests: route assertions in github-claude-messages.test.js; shared translator
cases in openai-to-claude.test.js (30 passed across claude suites).
@bloodf
bloodf force-pushed the port/upstream-2608 branch from 25d7517 to 3624109 Compare July 16, 2026 05:17
bloodf pushed a commit that referenced this pull request Jul 16, 2026
…p/tool_choice on /v1/messages

Codex review on PR #291 (1 P1 + 3 P2): the new native /v1/messages path
translated the OpenAI body without the stripUnsupportedParams pass the
/chat/completions path applies, and the generic OpenAI->Claude translator
dropped max_completion_tokens, stop, and tool_choice "none".

- github executor: stripUnsupportedParams("github", model, {...body}) before
  translateRequest so temperature/thinking/reasoning_effort no longer 400.
- openai-to-claude: honor max_completion_tokens when max_tokens absent
  (prefer explicit max_tokens); map stop string|string[] to stop_sequences
  (guard stop:null); map tool_choice "none" to Anthropic {type:"none"}.

Tests: route assertions in github-claude-messages.test.js; shared translator
cases in openai-to-claude.test.js (30 passed across claude suites).
@bloodf
bloodf force-pushed the port/upstream-2608 branch from 3624109 to e6a4ff6 Compare July 16, 2026 05:18
bloodf pushed a commit that referenced this pull request Jul 16, 2026
…p/tool_choice on /v1/messages

Codex review on PR #291 (1 P1 + 3 P2): the new native /v1/messages path
translated the OpenAI body without the stripUnsupportedParams pass the
/chat/completions path applies, and the generic OpenAI->Claude translator
dropped max_completion_tokens, stop, and tool_choice "none".

- github executor: stripUnsupportedParams("github", model, {...body}) before
  translateRequest so temperature/thinking/reasoning_effort no longer 400.
- openai-to-claude: honor max_completion_tokens when max_tokens absent
  (prefer explicit max_tokens); map stop string|string[] to stop_sequences
  (guard stop:null); map tool_choice "none" to Anthropic {type:"none"}.

Tests: route assertions in github-claude-messages.test.js; shared translator
cases in openai-to-claude.test.js (30 passed across claude suites).
@bloodf
bloodf force-pushed the port/upstream-2608 branch from e6a4ff6 to 1c59908 Compare July 16, 2026 05:23
@bloodf

bloodf commented Jul 16, 2026

Copy link
Copy Markdown
Owner Author

All 8 Codex findings addressed on e3892be0:

Original 4 (already in code, this push confirms):

  1. stripUnsupportedParams("github", body) — github.js:221 → drops temperature/thinking/reasoning_effort upstream 400s
  2. max_completion_tokens → max_tokens fallback — openai-to-claude.js:23-33
  3. stop (string|array) → stop_sequences, stop:null guarded — openai-to-claude.js:35
  4. tool_choice:"none" → {type:"none"} — openai-to-claude.js:332 (promoted it.fails known-bug in bugs-toClaude-context.test.js:38 to a passing contract)

New 4 (added this push):
5. Connect-timeout bound — per-attempt AbortController + FETCH_CONNECT_TIMEOUT_MS around proxyAwareFetch (github.js:235)
6. Persona guard — detectClientTool(requestContext.clientHeaders) !== "claude" drops the CLAUDE_SYSTEM_PROMPT block for non-Claude-Code Copilot clients (github.js:269)
7. Unsigned-thinking strip — normalizeClaudePassthrough(..., "claude") validating path (github.js:300)
8. Transient retry loop — 502/503/504 + network-as-502 with per-status counters and waitForRetryDelay (github.js:315)

Defended by 6 new tests in tests/unit/github-claude-messages.test.js (timeout aborts with 1 dispatch; 503 exhausted after initial+3 retries; 503→200 transient recovery; persona absent for non-Claude-Code client; persona kept for claude-cli; unsigned thinking stripped). Targeted suite 31/31 green; full npm run test:ci gate Raw failures 0; CI 3/3 green.

@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: e3892be073

ℹ️ 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 thread open-sse/executors/github.js Outdated
Comment thread open-sse/executors/github.js
Comment thread open-sse/executors/github.js
Comment thread open-sse/executors/github.js
bloodf pushed a commit that referenced this pull request Jul 16, 2026
…p/tool_choice on /v1/messages

Codex review on PR #291 (1 P1 + 3 P2): the new native /v1/messages path
translated the OpenAI body without the stripUnsupportedParams pass the
/chat/completions path applies, and the generic OpenAI->Claude translator
dropped max_completion_tokens, stop, and tool_choice "none".

- github executor: stripUnsupportedParams("github", model, {...body}) before
  translateRequest so temperature/thinking/reasoning_effort no longer 400.
- openai-to-claude: honor max_completion_tokens when max_tokens absent
  (prefer explicit max_tokens); map stop string|string[] to stop_sequences
  (guard stop:null); map tool_choice "none" to Anthropic {type:"none"}.

Tests: route assertions in github-claude-messages.test.js; shared translator
cases in openai-to-claude.test.js (30 passed across claude suites).
bloodf pushed a commit that referenced this pull request Jul 16, 2026
bloodf pushed a commit that referenced this pull request Jul 16, 2026
@bloodf
bloodf force-pushed the port/upstream-2608 branch from e3892be to 362d896 Compare July 16, 2026 19:20
CortexOS and others added 7 commits July 16, 2026 22:02
…p/tool_choice on /v1/messages

Codex review on PR #291 (1 P1 + 3 P2): the new native /v1/messages path
translated the OpenAI body without the stripUnsupportedParams pass the
/chat/completions path applies, and the generic OpenAI->Claude translator
dropped max_completion_tokens, stop, and tool_choice "none".

- github executor: stripUnsupportedParams("github", model, {...body}) before
  translateRequest so temperature/thinking/reasoning_effort no longer 400.
- openai-to-claude: honor max_completion_tokens when max_tokens absent
  (prefer explicit max_tokens); map stop string|string[] to stop_sequences
  (guard stop:null); map tool_choice "none" to Anthropic {type:"none"}.

Tests: route assertions in github-claude-messages.test.js; shared translator
cases in openai-to-claude.test.js (30 passed across claude suites).
@bloodf
bloodf force-pushed the port/upstream-2608 branch from 362d896 to 938336e Compare July 16, 2026 22:02
@bloodf
bloodf merged commit cb1939c into dev Jul 16, 2026
3 checks passed
@bloodf
bloodf deleted the port/upstream-2608 branch July 17, 2026 02:46
@bloodf bloodf mentioned this pull request Jul 20, 2026
7 of 8 tasks
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