| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
…er (#51) When Claude Code CLI points at ccproxy's /codex endpoint, the anthropic.messages -> openai.responses converter copies Anthropic's metadata.user_id into the Responses payload as "metadata". The Codex upstream (chatgpt.com/backend-api/codex/responses) rejects this with "Unsupported parameter: metadata", so every Claude Code -> codex request was failing with HTTP 400. - codex adapter: add "metadata" to the unsupported-key strip list in _sanitize_provider_body so it is removed before the upstream call, same as max_tokens/temperature. - simple_converters: convert_anthropic_to_openai_error now coerces non-Anthropic error shapes (e.g. Codex's FastAPI-style {"detail": "..."}) into a minimal ErrorResponse envelope instead of raising ValidationError. Without this, upstream 400s were being upgraded to 502s in the non-streaming error path. Adds regression tests for both the metadata strip and the error converter (three shapes: Anthropic-native, FastAPI detail, and arbitrary dict).
The OpenAI Responses -> Anthropic and OpenAI Chat -> Anthropic stream converters were emitting ContentBlockDeltaEvent with delta=TextBlock(type="text") instead of delta=TextDelta(type="text_delta"). The Pydantic model accepts either (TextBlock is a tolerated fallback), but the real Anthropic wire protocol and the Claude Code CLI's SDK parser require type="text_delta". The effect was that Claude Code CLI pointed at ccproxy's /codex endpoint received a 200 OK stream, parsed message_start/content_block_start/content_block_stop/message_stop correctly, but silently dropped every text delta — the user saw nothing. Adds two regression tests pinning the on-the-wire type to text_delta for both the Responses and Chat converters, including a check against model_dump(by_alias=True) so the serialized payload can't drift.
When Claude Code CLI targets /codex, conversations with history and
tool-use cycles were dropped or mangled, and tool streaming events did
not match the official specs. Rewrite the Anthropic -> Responses input
translation and align tool streaming with Anthropic/OpenAI specs.
- anthropic_to_openai/requests.py: translate the full message list
into Responses API input items (message / function_call /
function_call_output), preserving interleaved text and tool_use
ordering within assistant turns. Add a deterministic
_clamp_call_id so tool_use/tool_result pairs stay intact when ids
exceed OpenAI's 64-char limit. Accept LegacyCustomTool alongside
Tool in the custom-tool mapping.
- common/streams.py: emit tool_use content_block_start with empty
input {} and stream arguments via input_json_delta.partial_json,
per Anthropic streaming spec. Official SDKs ignore input attached
directly to the start event.
- openai_to_openai/streams.py: tool_call continuation chunks no
longer re-emit id/name. Per OpenAI Chat streaming spec, those
fields only appear on the first chunk for a given tool call.
- models/openai.py: FunctionCall.name is now Optional to support
the continuation chunks above.
- services/adapters/delta_utils.py: identity fields (index, type,
id, name, call_id) are overwritten instead of merged. Without
this, providers that re-send these per chunk (e.g. the Codex
Responses->Chat adapter) produced "shellshell..." /
"fc_abc_fc_abc..." and broke downstream validation.
Tests cover the full tool cycle, interleaved assistant ordering,
list-form tool_result content, pending user text after a tool
result, long call_id clamping, LegacyCustomTool acceptance, tool_use
streaming events, and delta_utils identity handling.
There was a problem hiding this comment.
This PR fixes multiple interoperability issues preventing Claude Code CLI from successfully using ccproxy’s /codex provider end-to-end, including request sanitization, error-shape handling, Anthropic→Responses message/tool translation, streaming spec compliance, and streaming delta accumulation correctness.
Changes:
Copilot reviewed 14 out of 14 changed files in this pull request and generated 1 comment.
Show a summary per file| File | Description |
|---|---|
| ccproxy/plugins/codex/adapter.py | Sanitizes outgoing Codex payloads by stripping unsupported keys like metadata. |
| ccproxy/services/adapters/simple_converters.py | Makes Anthropic→OpenAI error conversion resilient to non-Anthropic error payloads (e.g., FastAPI detail). |
| ccproxy/llms/formatters/anthropic_to_openai/requests.py | Reworks Anthropic→Responses request building to preserve history + tool interleaving; clamps long tool call IDs; accepts legacy tool definitions. |
| ccproxy/llms/formatters/common/streams.py | Emits Anthropic tool-use streaming events per spec (input={} then input_json_delta). |
| ccproxy/llms/formatters/openai_to_anthropic/streams.py | Ensures Anthropic wire streaming uses text_delta events (not TextBlock(type="text")). |
| ccproxy/llms/formatters/openai_to_openai/streams.py | Adjusts tool-call streaming chunk emission to better match OpenAI chat streaming expectations. |
| ccproxy/llms/models/openai.py | Makes FunctionCall.name optional to support spec-compliant continuation chunks. |
| ccproxy/services/adapters/delta_utils.py | Prevents identity/discriminator fields from being concatenated during streaming delta accumulation. |
| tests/plugins/codex/unit/test_adapter.py | Adds regression coverage for stripping metadata in Codex adapter sanitization. |
| tests/unit/services/adapters/test_simple_converters.py | Adds coverage for error-shape coercion in convert_anthropic_to_openai_error. |
| tests/unit/services/adapters/test_delta_utils.py | Adds regression coverage preventing concatenation of tool-call identity fields across chunks. |
| tests/unit/llms/formatters/test_anthropic_to_openai_helpers.py | Adds coverage for Responses request construction: tool cycles, long call IDs, legacy tools, ordering, mixed tool_result content. |
| tests/unit/llms/formatters/test_openai_to_anthropic_chat_response.py | Updates assertions for tool-use streaming input behavior (input_json_delta). |
| tests/unit/llms/formatters/test_streaming_converters_samples.py | Adds/updates sample-based streaming tests for tool-use input streaming and text_delta wire type. |
ccproxy/llms/formatters/openai_to_openai/streams.py:400
if not state.initial_emitted:
tool_call = openai_models.ToolCallChunk(
index=state.index,
id=state.call_id or state.id,
type="function",
function=openai_models.FunctionCall(
name=state.name or "",
arguments=arguments or "",
),
)
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Sorry, something went wrong.
| if state.initial_emitted: | ||
| tool_call = openai_models.ToolCallChunk( | ||
| index=state.index, | ||
| id=state.id, | ||
| type="function", | ||
| function=openai_models.FunctionCall( | ||
| name=state.name or "", | ||
| arguments=delta_segment, | ||
| ), | ||
| ) |
There was a problem hiding this comment.
Tool-call continuation chunks still set type="function". Per the OpenAI Chat streaming spec (and as noted in the PR description), id/type/function.name should only be present on the first chunk for a given tool call; subsequent chunks should generally include only function.arguments (plus index). Consider omitting type on continuation chunks here to avoid strict client parsers rejecting the stream.
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
Summary
Make the /codex provider actually usable from the Claude Code CLI. Closes #51 and addresses the feature request in #16 ("use codex credential in claude code").
When ANTHROPIC_BASE_URL points Claude Code at ccproxy's /codex endpoint, several independent bugs combined to break the flow end-to-end: the very first request failed with HTTP 400, and even after that, multi-turn conversations with tool calls were silently dropped or mangled on the way to the Codex Responses API. This PR fixes all of them.
What was broken
What this PR does
Codex adapter / error handling (#51)
Anthropic -> Responses conversion (#16)
Streaming spec alignment
Delta accumulation
Test plan
New / updated tests:
Issues