Skip to content

Let OpenAI Responses and Chat clients use any provider - #23

Merged
playgrndlabs-bot merged 12 commits into
mainfrom
claude/project-thread-y9ekd4
Oct 28, 2026
Merged

playgrndlabs-bot merged 12 commits into
mainfrom
claude/project-thread-y9ekd4

Conversation

@playgrndlabs-bot

Copy link
Copy Markdown
Contributor

What

OpenAI Responses clients (/v1/responses) could only reach Codex keys and ChatGPT logins. Now they reach every provider, and so do OpenAI Chat clients, by pivoting through Anthropic Messages:

  • free/src/responses-claude.ts (new), ported from CPA's translator/claude/openai/responses:
    • Request: instructions and system/developer items become the system prompt; input_text/output_text/refusal/input_image/input_file parts; reasoning items replay as thinking only when they carry a Claude signature (OpenAI's gAAAA… tokens are dropped); function_call and custom_tool_call become tool_use (custom tools take a one-string {input} schema); tool outputs keep the last result per call id; missing results are filled in as an "interrupted" error and orphaned ones become text, so Claude always gets valid pairing; a trailing thought is stripped; reasoning.effort, max_output_tokens, text.format, tool_choice (incl. allowed_tools, custom), parallel_tool_calls. Built-in tools (web search etc.) are dropped.
    • Response: ResponsesStream turns Anthropic events into Responses SSE (response.created … output_item.added/done, text and reasoning-summary deltas, function-call argument deltas, custom tool input, response.completed/incomplete/failed, sequence numbers, usage with cached tokens). responsesResponse does the same for non-streaming clients.
  • free/src/app.ts: viaClaudeKey becomes viaClaudeMessages, used for Chat and Responses clients. It translates to Claude, then sends to a Claude key directly or through the existing Claude→Chat/Gemini/Responses translators (viaTranslation split so its core takes a parsed body), and converts back. Upstream errors come back in the client's error shape. servable() now lets Chat and Responses clients use every provider; Chat clients asking for a ChatGPT model also get the ChatGPT login. Gemini clients are unchanged (next PR).
  • free/src/openai-claude.ts: helpers exported for reuse, no behaviour change.

Security and safety

  • No new upstream hosts: requests still go only to the configured credentials' base URLs or the ChatGPT endpoint. The client's own headers are never forwarded on translated requests (a bare request is used, as before).
  • Image and file URLs in the input are passed to Anthropic as URL sources; the Worker never fetches them, so there's no SSRF.
  • Claude logins are still not offered to non-Claude-Code clients (no cloaking), with a clear error.
  • Body size cap (32 MB) and the one-parse rule are unchanged. A 600 KB Responses conversation translates in about 2–3 ms warm, in line with the Chat translator. Chained routes (for example Responses → Claude → Chat) re-parse the stream's events once more, which costs a little extra CPU per event.
  • Upstream error messages are passed through as before; nothing new is logged or stored.

Tests

npm run verify: typecheck, lint and 170 tests pass. New free/test/responses-claude.test.ts covers request translation, streaming order and sequence numbers, custom tools, incomplete/failed streams and whole responses. app.test.ts adds Responses → Claude key (streamed and whole), Responses → OpenAI-compatible key, errors in the Responses shape, and Chat → ChatGPT login.


Generated by Claude Code

Port CPA's gemini/claude translator: Anthropic Messages become Gemini
generateContent (system instruction, turns, function calls and
responses, images, tools, tool choice, thinking), and Gemini answers,
streamed or whole, become Anthropic events and messages. Google's
default safety settings stay in place instead of being switched off.
Port CPA's claude/openai/chat-completions translator: Chat Completions
requests become Anthropic Messages (system and developer prompts, turns,
tool calls and results, images, files, cache_control, reasoning effort,
tool choice, structured output as a system instruction), and Claude's
answers, streamed or whole, become Chat Completions chunks and
completions. Claude logins stay Claude Code only.
Move each install's button out of the narrow table column into its own
section, shown at 320 px wide, and bring the Workers-only description up
to date.
Record each API request in the Durable Object, batched a few seconds
apart: success and failure counts per login file and API key (totals and
CPA's twenty 10-minute buckets) and, while logging to file is on, a CPA
style request line (time, status, latency, client IP, path, provider,
model; never bodies, keys or the query). The dashboard's credential list,
API-key usage and Logs pages read them back. API keys are stored only as
hashes.
Responses requests are translated to Anthropic Messages (ported from CPA's
Responses-to-Claude translator) and sent to a Claude key, or on through the
existing Claude translators to Gemini, OpenAI-compatible and Codex keys and
the ChatGPT login. Answers come back as Responses events or a whole response.
Chat clients take the same route to the providers they couldn't reach before.
@playgrndlabs-bot
playgrndlabs-bot merged commit 542c025 into main Oct 28, 2026
4 checks passed
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.

2 participants