feat(responses): loopback OpenAI Responses shim for Codex

Draft
SH
1mo ago
+2831-1345

Summary

Adds a loopback OpenAI Responses API shim so Codex CLI can run against RunAnywhere models. Codex 0.145.0 removed wire_api = "chat", so a /v1/responses front door is now the only way it can reach our chat-completions gateway.

Rather than duplicate the Anthropic bridge's transport, this extracts the provider-agnostic loopback transport into a shared crate::shim module parameterized by a small Dialect trait (+ a StreamConverter). Both bridges are now thin dialects over one transport:

  • Anthropic (Claude Code) — /v1/messages, unchanged behaviour.
  • Responses (Codex) — /v1/responses, new.

Each keeps its own CURRENT singleton, so starting one never tears the other down. No transport is duplicated.

What's included

  • src/shim.rs — shared transport (pooled + watched upstream, the streaming worker with keepalives + pre-stream status decision + incomplete-stream guard, disconnect handling, start/stop), the Dialect/StreamConverter traits, and the shared Shim/Runtime.
  • src/anthropic/messages.rs — reduced from ~1,460 lines to ~340: just the Anthropic dialect (x-api-key/Bearer auth, its translation, its error envelope, its Claude-Desktop discovery shape, /api/hello).
  • src/responses/translate.rs — Responses ↔ chat translation (all serde_json::Value, matching the Anthropic path): request mapping (input items, tools, call_id round-trip, max_output_tokens → max_tokens, developer → system, mirrors the stream flag), non-streaming response, and the streaming state machine (created/in_progress → text/function_call lifecycles → completed; monotonic sequence_number; no [DONE]).
  • src/responses/messages.rs — the Responses dialect (Bearer auth, OpenAI error envelope + /v1/models).
  • src/commands/cmd_responses.rs — hidden dev entrypoint wally __responses-serve (kept out of --help) for validation.

Validation

  • cargo test --lib: 393/393; cargo fmt --check + cargo clippy --lib clean.
  • In-process e2e test drives the Anthropic dialect through the shared transport (auth → translate → upstream → Anthropic envelope), guarding the Claude path against the refactor.
  • Real Codex 0.145.0 → shim → real glm-5.3-flash: a text turn, and a tool round-trip where the model called exec_command, Codex executed it, and the model reported the output.

Follow-ups (not blockers)

  • Emit response.reasoning_summary_text.* events (currently reasoning_content is dropped; Codex works without it).
  • A proper wally codex launcher (writes ~/.codex/config.toml, sets CODEX_HOME).
  • A real DeclaredHarness::KCodex — a human-gated server contract change (OpenAPI + sync_from_inferenceinfra.py regen); today it attributes as KRcli.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Hm9aUP3Fvg83pJZo2mixgv

Summary by CodeRabbit

  • New Features
    • Added wally codex to launch Codex with a selected local or hosted model. Additional command-line arguments are passed through, and model settings such as context window are applied when available.
    • Added support for the OpenAI Responses API through a local compatibility service, including request and response conversion, streaming, model discovery, and authentication.