Part of #1. Depends on #3, #4, #5.
Goal
Let a Claude Code / Anthropic SDK client hit POST /v1/messages and have copilot-api dispatch to upstream /responses (instead of /chat/completions) when the resolved model is in the codex / o-pro family. This is the path that lets Claude Code use Copilot's gpt-5.3-codex / gpt-5.1-codex-max.
Current state
src/routes/messages/ only translates Anthropic Messages to Chat Completions, never to Responses. Once #4 lands and a codex model is resolved, this code path errors out because chat/completions can't reach codex on the upstream.
Tasks
Acceptance criteria
POST /v1/messages with model=gpt-5.3-codex works end-to-end against Copilot upstream
- Streaming returns Anthropic-shaped SSE that Claude Code understands
- Two-turn agent loop preserves reasoning context (no "encrypted content could not be verified" errors)
- Existing Anthropic→Chat Completions tests still pass for non-codex models
File pointers
src/routes/messages/route.ts:10–18
src/routes/messages/non-stream-translation.ts — reference for Anthropic→OpenAI translation
src/routes/messages/stream-translation.ts — reference for streaming state machine
- litellm reference:
litellm/llms/anthropic/experimental_pass_through/responses_adapters/transformation.py (LiteLLMAnthropicToResponsesAPIAdapter)
- litellm PR #22448 — thinking_blocks ↔ reasoning round-trip
Part of #1. Depends on #3, #4, #5.
Goal
Let a Claude Code / Anthropic SDK client hit
POST /v1/messagesand have copilot-api dispatch to upstream/responses(instead of/chat/completions) when the resolved model is in the codex / o-pro family. This is the path that lets Claude Code use Copilot'sgpt-5.3-codex/gpt-5.1-codex-max.Current state
src/routes/messages/only translates Anthropic Messages to Chat Completions, never to Responses. Once #4 lands and a codex model is resolved, this code path errors out because chat/completions can't reach codex on the upstream.Tasks
src/routes/messages/route.ts:endpoint === 'responses'only → call newmessagesToResponses(...)src/routes/messages/responses-translation.ts:messages→ Responsesinputitemssystem→ Responsesinstructionstools→ Responsestools(function-call shape)tool_choice→ Responsestool_choicethinking { type: 'enabled', budget_tokens: N }→ Responsesreasoning: { effort: tier(N), summary: 'auto' }≥10000 → 'high',≥5000 → 'medium',≥2000 → 'low', else'minimal'tool_useblock in history → Responsesfunction_callinput itemtool_resultblock in history → Responsesfunction_call_outputinput itemsrc/routes/messages/responses-stream-translation.ts:message_start,content_block_start/delta/stop,message_delta,message_stop,ping)response.reasoning.delta/response.reasoning_summary_text.delta→ Anthropicthinking_delta(cross-reference Anthropic /v1/messages → Responses API adapter #8 and Emit Anthropic thinking blocks from reasoning channel #9)response.output_text.delta→text_deltaresponse.function_call_arguments.delta→input_json_deltathinkingblocks containingsignature(encrypted_content holder), forward them as Responses reasoning items ininput(cross-link Model-to-endpoint routing (chat vs responses) #5)Acceptance criteria
POST /v1/messageswithmodel=gpt-5.3-codexworks end-to-end against Copilot upstreamFile pointers
src/routes/messages/route.ts:10–18src/routes/messages/non-stream-translation.ts— reference for Anthropic→OpenAI translationsrc/routes/messages/stream-translation.ts— reference for streaming state machinelitellm/llms/anthropic/experimental_pass_through/responses_adapters/transformation.py(LiteLLMAnthropicToResponsesAPIAdapter)