Files
CC-Switch/tests/hooks
Yeeyzy 99e11e0851 feat(codex): support native Anthropic Messages protocol as upstream (#5071)
* feat(codex): support native Anthropic Messages protocol as upstream

Allow gateways that only expose the native Anthropic Messages protocol
(/v1/messages) to be used by Codex: the local proxy performs bidirectional
request/response/streaming conversion between Responses and Anthropic.

Backend:
- Add two conversion modules: transform_codex_anthropic / streaming_codex_anthropic
- codex.rs: add routing detection and auth: ANTHROPIC_AUTH_TOKEN→Bearer (default),
  ANTHROPIC_API_KEY→x-api-key, mutually exclusive
- handlers.rs: add handle_codex_anthropic_to_responses_transform
- forwarder.rs: support optional Claude Code client fingerprint impersonation
  (User-Agent / anthropic-beta / x-app / system prompt first-line injection)
  and /responses→/v1/messages rewriting
- codex_config: the anthropic format reuses the NativeResponses profile to strip
  custom tools
- ProviderMeta: add impersonateClaudeCode

Frontend:
- CodexApiFormat: add "anthropic"; the form adds auth field selection and an
  impersonation toggle
- Add en/ja/zh/zh-TW copy

Robustness:
- Downgrade when tool history / forced tool_choice conflicts with extended
  thinking, avoiding upstream 400s
- Emit cache_creation_input_tokens in usage and use saturating_add to guard
  against overflow
- Append a unique suffix to non-streaming/streaming output-item ids to avoid
  multi-segment text/thinking overwriting each other

* fix(codex): harden Anthropic bridge against empty text blocks and truncated streams

- Drop empty/whitespace-only text content blocks when rebuilding Anthropic
  messages from Responses history; Anthropic 400s on empty text blocks (e.g. an
  empty assistant text emitted alongside a tool_use), which broke follow-up and
  tool-result requests. Also drop messages left without content.
- Do not report a truncated Anthropic stream as completed: when the SSE
  connection ends before message_stop with no stop_reason, emit an incomplete
  response if partial output exists, or a failed (stream_truncated) response
  otherwise, mirroring the chat converter's EOF handling.

* fix(codex): resolve Anthropic-bridge review findings

Blocking:
1. Defer stripping the [1m] long-context marker until after catalog matching and model write-back, re-stripping it on the final Codex→Anthropic body and setting a flag to emit the context-1m-2025-08-07 beta header, so the marker is no longer lost or overridden by the default model.
2. Gate Anthropic thinking on the trailing turn only (via trailing_turn_allows_thinking) instead of scanning full history, so a Codex session that resends history each round no longer permanently loses thinking after the first tool call.
3. Inject 5m ephemeral cache_control on the Codex→Anthropic body by reusing cache_injector (handling the system string→array conversion), so system/tools/history are cached instead of re-sent at full price every round.
4. Add a shared base_url_is_full_endpoint helper (normalizing whitespace/query/fragment/trailing slash) used by both the Anthropic and Chat paths, so a base URL already ending in /v1/messages is treated as a full endpoint instead of double-appending to /v1/messages/v1/messages.
5. Align the catalog tool-profile predicate with the routing predicate so resolve_codex_catalog_tool_profile returns the Anthropic profile whenever the request converts to Anthropic, preventing freeform tools like apply_patch from being silently filtered by a ProxyChat catalog.
6. Explicitly disable native web_search for the Anthropic profile (including the no-catalog branch) via set_codex_native_web_search_field, so Codex no longer treats it as available while the transform silently drops it.
7. Only forward tool_choice when tools survive filtering, dropping it otherwise, to avoid a non-retryable 400 from upstream when tool_choice is sent with no tools.
8. Lower the fallback default to max_tokens=8192 (only when max_output_tokens is omitted) and clamp the thinking budget to max_tokens/2, disabling thinking below the 1024 floor, to avoid hard 400s on low-output-ceiling models/gateways.

Minor:
9. Centralize the Codex/OpenAI fingerprint-header denylist in is_codex_client_fingerprint_header so impersonating Claude Code uniformly drops originator/session_id/conversation_id/chatgpt-account-id/x-client-request-id/openai-* and the x-stainless-*/x-codex-* prefixes.
10. Retain content_block_start.input as start_input and fall back to it at block close when no input_json_delta arrived, so a gateway that carries the full tool input on the start event no longer yields empty tool arguments.
11. Extract a shared codex_responses_sse module as the single Responses SSE envelope builder that both the chat and anthropic streaming emitters delegate to, with byte-for-byte-unchanged wire output, so future event-format fixes touch one place instead of two.

* fix(codex): add per-provider max_output_tokens override for Codex→Anthropic path

Codex does not forward model_max_output_tokens in the request body,
causing the proxy to fall back to a conservative 8192 default. This
truncates long or thinking-heavy responses (stop_reason=max_tokens).

- Add maxOutputTokens field to ProviderMeta (Rust + TypeScript)
- Inject the value into the Anthropic request body before transform,
  taking precedence over request-supplied and default values
- Add numeric input in Codex form fields (Anthropic format only)
- Add i18n entries for label, placeholder, and hint (en/zh/zh-TW/ja)
- Include roundtrip and omission unit tests for the new field

* fix(codex): harden Anthropic protocol bridge

* fix(codex): address Anthropic bridge review

* fix(codex): preserve flattened Anthropic inputs

* fix(codex): harden Anthropic recovery paths

* fix(ci): satisfy Rust clippy

---------

Co-authored-by: Jason <farion1231@gmail.com>
2026-07-10 23:06:30 +08:00
..
2025-11-22 19:18:35 +08:00
2025-11-22 19:18:35 +08:00