Skip to content

feat: route each model through an API it advertises - #269

Open
graehl wants to merge 2 commits into
ericc-ch:masterfrom
graehl:feat/copilot-endpoint-routing
Open

feat: route each model through an API it advertises#269
graehl wants to merge 2 commits into
ericc-ch:masterfrom
graehl:feat/copilot-endpoint-routing

Conversation

@graehl

@graehl graehl commented Aug 5, 2026

Copy link
Copy Markdown

Copilot's model catalog declares per-model supported_endpoints, but copilot-api currently translates everything through Chat Completions. This routes each model through an API it actually advertises:

  • Claude models → native /v1/messages passthrough. Anthropic-API clients (e.g. Claude Code) get full fidelity — thinking blocks, signed reasoning, exact tool_use semantics — instead of a lossy Anthropic→OpenAI→Anthropic round-trip.
  • Responses-only models become usable. Models like gpt-5.6-terra don't support Chat Completions at all, so they previously couldn't be served to Anthropic-API clients. A new Anthropic↔Responses adapter covers tools, streaming, signed reasoning, and explicit reasoning-effort mapping.
  • No false capabilities. Endpoint metadata is preserved through /v1/models; a model whose advertised endpoint set isn't supported is rejected up front rather than failing confusingly at request time. Catalogs without endpoint metadata keep the existing Chat Completions fallback.
  • Production HTTP dependencies bumped to patched releases.

bun test passes. This has been in daily production use since late July as the gateway behind yepanywhere's Claude Gateway provider, serving real Claude Code sessions — claude-opus-5 via the native passthrough and gpt-5.6-terra via the Responses adapter, with tools, streaming, and effort selection exercised end to end.

Independent of #268 (no overlapping files).

🤖 Generated by Fable

graehl added 2 commits July 27, 2026 21:49
Preserve Copilot model endpoint and reasoning metadata, then route each
model only through an API it advertises. Pass native Anthropic
Messages requests through unchanged and translate Responses-only models
so Claude Code can use Terra with tools, signed reasoning, streaming,
and explicit effort.

Keep Chat Completions as the legacy fallback when older catalogs omit
endpoint metadata. Reject known unsupported endpoint sets instead of
advertising a false capability.

Update production HTTP dependencies to patched releases after rejecting
wholesale adoption of the much larger third-party fork.
The ya claude gateway saw degraded structure from both translated
paths: deltas aimed at already-stopped content blocks, zeroed usage,
invisible web searches, and prior-turn thinking replayed as visible
assistant text (which teaches models to emit pseudo-thinking prose).

Chat Completions -> Anthropic stream:
- Keep tool_use blocks open until the stream ends so interleaved
  parallel tool-call deltas can never target a stopped block; text
  after a tool call opens a fresh block. Anthropic consumers address
  deltas by block index, so multiple open blocks are safe.
- Capture usage from any chunk, including the trailing usage-only
  chunk (empty choices) that was previously dropped, and defer
  message_delta/message_stop to a new finalizeAnthropicStream() the
  handler calls once the upstream stream is exhausted.

Responses -> Anthropic stream:
- Text-block identity now includes content_index; a second content
  part in one message item gets its own block instead of feeding a
  block that output_text.done already stopped.
- Blocks carry a closed flag; late deltas to a closed block are
  dropped rather than emitted as protocol violations.
- Reasoning summary parts are separated with a blank line, matching
  the non-stream join.

Web search (both Responses paths): web_search_call output items now
translate to server_tool_use + web_search_tool_result blocks, with
usage.server_tool_use.web_search_requests, instead of vanishing.
Requests with a web_search tool add the
web_search_call.action.sources include so result URLs come back
(verified live against Copilot: sources arrive as {type:"url",url}
entries, no titles, hence the title-falls-back-to-url mapping).
These blocks intentionally do not round-trip: request translation
already drops them since Copilot rejects them as input.

Chat Completions request: assistant thinking blocks are dropped
instead of flattened into visible text, mirroring how Anthropic
ignores prior-turn thinking.

Verified live on port 4779: gemini-3.6-flash parallel tool calls
(two tool_use blocks, correct args, non-zero usage), gpt-5.6-luna
web search (structured blocks, sources populated, protocol-clean
SSE), claude-haiku-4.5 passthrough unaffected.
@graehl

graehl commented Aug 6, 2026

Copy link
Copy Markdown
Author

Pushed 7e92143 fixing several stream-translation defects found while exercising this branch against a live gateway:

  • Chat Completions: interleaved parallel tool-call deltas could target already-closed content blocks; tool blocks now stay open until stream end. Trailing usage-only chunks (empty choices) were dropped, zeroing output_tokens; usage is now captured from any chunk and the closing message_delta/message_stop are emitted when the upstream stream is exhausted.
  • Responses: text-block identity now includes content_index (a second content part previously fed a stopped block); web_search_call items now surface as server_tool_use + web_search_tool_result blocks (with web_search_call.action.sources requested so result URLs come back) instead of being dropped.
  • Chat request translation: prior-turn thinking blocks are dropped rather than flattened into visible assistant text, matching Anthropic semantics.

Verified live against Copilot (parallel tool calls, web search, Claude passthrough) plus new regression tests for each defect.

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