feat(codex): support native Anthropic Messages protocol as upstream#5071
Conversation
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
3785d5e to
2b3a4e2
Compare
|
Our company has been eagerly awaiting the launch of this feature. As you may know, we're one of those companies that can't use Claude Code (😭). Though this feature might be niche, I can assure you it's our most anticipated one—it genuinely solves a real problem for us. We'd be incredibly grateful to see it rolled out soon. Thank you so much! 🙏 |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2b3a4e2c33
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…ncated 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.
I understand. However, format conversion involves things like tool call parameters, as well as critical cache hit issues, so it requires a substantial amount of work. That said, we’ll do our best to get this feature completed as soon as possible. |
farion1231
left a comment
There was a problem hiding this comment.
我直接用中文回复啦,review 了一下,目前还有这些问题:
阻塞问题
[1m] 长上下文标记会在 catalog 匹配前被剥掉,导致 context-1m-2025-08-07 beta 不发,甚至被默认模型覆盖。见 forwarder.rs (line 1146)、forwarder.rs (line 1406)。
第一次工具调用后,整个 Codex agentic 会话会永久失去 Anthropic thinking。当前门控扫全量历史,Codex 又每轮重发历史,所以过宽。见 transform_codex_anthropic.rs (line 135)。
Anthropic prompt cache 没有启用。转换层没有注入 cache_control,导致 system/tools/history 每轮全价重发,成本和首字延迟都会偏高。已有 cache_injector.rs 可复用。
base URL 粘贴完整 /v1/messages 时会拼成 /v1/messages/v1/messages。Chat 路径已有类似保护,Anthropic 路径缺失。见 codex.rs (line 614)。
路由和 catalog 用不同谓词判断 Anthropic,配置分歧时请求会走 Anthropic 转换,但 catalog 仍按 ProxyChat 生成,apply_patch 这类 freeform 工具会被静默过滤。见 codex_config.rs (line 117)。
web_search 对 Anthropic profile 没有稳定禁用或映射。Codex 会以为可用,转换层实际过滤掉,表现为静默无效。见 codex_config.rs (line 947)。
tools 被过滤空时仍写 tool_choice,上游很可能 400,且 400 不 failover。见 transform_codex_anthropic.rs (line 257)。
缺省 max_tokens=32000 对低输出上限模型/网关有硬 400 风险,且当前错误分类不会重试。见 forwarder.rs (line 1395)。
次要但建议修
Claude Code impersonation 是本 PR 新增的完整链路,但目前不够收敛:UA、anthropic-beta、x-app、system identity 有处理,其他 Codex 专属头仍可能透传。
流式 Anthropic 工具调用只累积 delta,忽略 content_block_start.input,遇到 start 带完整 input 的网关会把工具参数变空。
新流式 emitter 和既有 chat emitter 有复制漂移风险,后续事件格式修复容易漏一条路径。
|
另外我看到代码里面有伪装 Claude Code 请求头的相关功能,贵公司提供的是 Claude API 还是 Claude 订阅?如果是订阅的话,如何进行反向代理之后不被封禁是一个非常非常复杂的问题,而且试错的成本很高。 |
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.
非常感谢作者review 并提出很有价值的问题,以上问题均已修复,详情如下:
次要但建议修: |
…hropic 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
239915e to
0e8bd21
Compare
|
I heard that your company has already banned the use of CC Switch. Is this PR still needed? |
Thanks for checking in! Actually, that rumor isn't accurate for our case—our company has not banned cc-switch. However, we are officially deprecating the Claude Code client very soon. |
OK, I will finish this asap. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7e476f4e2c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 897e29e80e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c7d66e13fb
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a42b1720a2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Merges upstream farion1231/cc-switch up to 99e11e0 (40 commits) to bring in farion1231#5071 (Codex native Anthropic Messages protocol) and the proxy-layer commits it depends on. Manual port was infeasible: the proxy files (forwarder/handlers/codex.rs) diverged by 300-665 lines from upstream's base, and farion1231#5071's new modules reference upstream-only APIs. Conflict resolution: - Files already manually ported (11c/94f/farion1231#5128/profiles): kept ours (crates-adapted, tested); took upstream for the 3 new farion1231#5071 modules (transform_codex_anthropic / streaming_codex_anthropic / codex_responses_sse) and let auto-merge handle the rest of the proxy changes. - i18n: took upstream (has farion1231#5071 keys) + re-added profiles.clearFailed. - Deduplicated auto-merge artifacts: `mod profile` / `mod profiles` declared twice in commands/mod.rs, dao/mod.rs, services/mod.rs. - Brought missing codex_state_db module (rename-detection miss) and declared it in cc-switch-core lib.rs. - Adapted src-tauri-style `crate::services` ref in config.rs to `cc_switch_core::services`; wrapped query_codex_quota call in Ok to match the merged signature. - UsageDashboard: merged budget features (ours) with farion1231#5057 refresh- interval persistence (upstream). - Removed spurious src-tauri/src/commands/{coding_plan,mcp}.rs rename duplicates (real files live in crates/). cargo check -p cc-switch-app passes.
* feat(codex): support native Anthropic Messages protocol as upstream (farion1231#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 <[email protected]> * fix: exclude Fable model env from Claude common config (farion1231#4272) (farion1231#5206) * Add test for Fable model env key exclusion Add regression test to ensure Fable model env keys are excluded from common config. * Add Fable model to CLAUDE_MODEL_OVERRIDE_ENV_KEYS * Add files via upload * Delete .github/workflows/build-windows-unsigned.yml * Fix/opencode known field editors (farion1231#2907) * fix: add opencode model limit editor * fix: add opencode headers editor * style: refine opencode advanced field layout * fix: preserve valid opencode headers * fix: preserve opencode extra options and sync translations --------- Co-authored-by: wzk <[email protected]> Co-authored-by: Jason Young <[email protected]> Co-authored-by: Jason <[email protected]> * fix: handle missing provider keys and tool schema types (farion1231#5069) * fix: handle missing api keys and tool schema types * fix: preserve nested tool schemas --------- Co-authored-by: Jason <[email protected]> * fix(usage): 修复 Codex 子代理使用量未计入统计 (farion1231#5187) * fix(usage): count Codex subagent session tokens * fix(usage): address Codex subagent review feedback * fix(usage): preserve Codex migration history * fix(usage): harden Codex subagent migration * fix(usage): reimport late Codex subagents * fix(usage): guard late Codex rollup reimport * refactor(usage): simplify Codex subagent accounting fix * fix(proxy): inject a single auth placeholder on managed Claude takeover (farion1231#5095) Switching the Claude provider from a third-party (DeepSeek/MiMo/...) to a managed Codex provider wrote both ANTHROPIC_API_KEY and ANTHROPIC_AUTH_TOKEN as PROXY_MANAGED into ~/.claude/settings.json, making Claude Code warn "Both ANTHROPIC_AUTH_TOKEN and ANTHROPIC_API_KEY set - auth may not work as expected" on every run. The double key is an accretion artifact: the ManagedAccount takeover policy originally injected only ANTHROPIC_API_KEY (Copilot, farion1231#1049), and the Codex fix that preserved ANTHROPIC_AUTH_TOKEN to avoid the login prompt (farion1231#3784 / PR farion1231#3789) added the token on top without removing the API key insert. Inject exactly one placeholder instead: AUTH_TOKEN for Codex-managed providers (keeps the farion1231#3784 fix), API_KEY for Copilot (keeps the farion1231#1049 behavior). Local-proxy auth is unaffected - the forwarder resolves the PROXY_MANAGED placeholder from either header. Updates the three Codex takeover tests to assert API_KEY is absent and adds a regression test for the exact third-party -> Codex switch from the report. Fixes farion1231#4919 * feat(pricing): seed GPT-5.6 Sol/Terra/Luna pricing Add the three GPT-5.6 tiers to seed_model_pricing, cross-checked against OpenAI's official pricing page and OpenRouter: gpt-5.6-sol 5 / 30 / 0.50 (cache read) gpt-5.6-terra 2.50 / 15 / 0.25 gpt-5.6-luna 1 / 6 / 0.10 cache_write is "0": OpenAI publishes only a cached-input (read) rate and no separate cache-write price, matching the gpt-5.x family convention. Base ids only for now — effort-suffix variants are deferred until the upstream logging suffix set for 5.6 is confirmed. New model, so seed only (no repair branch, no SCHEMA_VERSION bump). * feat(pricing): seed Tencent Hunyuan Hy3 pricing Add Hunyuan Hy3 (released 2026-07-06, 256K context) to seed_model_pricing under both the hunyuan-hy3 and hy3 ids, since the upstream billing id isn't yet confirmed and one of the two should match logged usage. Prices come from Tencent's launch-day list price (CNY 1 / 4 / 0.25 per 1M input / output / cache-hit), converted at 1 USD ~= 7.14: 0.14 / 0.56 / 0.035. cache_write is "0" (no published write rate). Hy3 actually uses input-length tiered billing (<16K / 16-32K / >=32K); the single-price table holds the lowest tier, so long-context requests are under-billed until this is revisited against the official billing page. New model, so seed only. * feat(codex): add default model field to provider form Expose the top-level `model` key of config.toml as an editable field in the Codex provider form, so users can switch to newly released models (e.g. gpt-5.6) without waiting for a preset update — preset updates only affect newly added providers, existing ones keep their saved TOML. The field syncs bidirectionally with the TOML editor (mirroring the base-URL pattern), suggests models from the mapping catalog plus the provider's /models endpoint, and offers a one-click "add to mapping" action when the value is outside a non-empty catalog. Hidden for official providers. Details: - Save-time catalog sync now only backfills the first mapping row into the top-level model when the field was left empty, so the explicit field wins over the implicit row-0 sync - Escape model names (and base_url) with TOML basic-string escaping and strip control characters from field input: /models ids are remote data and unescaped interpolation could inject config.toml lines (e.g. a forged [mcp_servers.*] command) - The strict model-line matcher now recognizes escaped output, empty strings and single-quoted literals, keeping extract/set round-trips stable; deliberately no key-only loose matching (it would misfire on assignment-looking text inside multiline strings) - Invalidate the fetched model list whenever the request identity changes (base URL, full-URL toggle, API key, custom UA) and discard in-flight responses via a sequence guard, so the dropdown never shows a previous provider's models - i18n for zh/en/ja/zh-TW * feat(profiles): add setting to toggle project switcher on main page Add a show/hide toggle for the header project profile switcher under the Homepage Display section in settings. Defaults to visible so existing users keep the current behavior. * refactor(health-check): remove per-provider test config * fix(usage): account for cache-write tokens across schema versions Parse cache_write_tokens from OpenAI usage details and preserve cache creation data across Chat, Responses, and Anthropic conversion paths. Add explicit input-token semantics to request logs and rollups so legacy rows subtract cache reads only while new total-inclusive rows subtract both cache reads and writes. Migrate v12 databases, normalize rollups to fresh input, and cover historical backfill behavior with regression tests. * fix(proxy): harden Responses reasoning and tool-call conversion Round-trip encrypted Responses reasoning items through bridge-owned Anthropic thinking blocks, discard orphaned reasoning-only history, and consume the official reasoning text event vocabulary. Track concurrent streaming items by stable IDs and output indexes, reuse a dedicated fallback block for keyless legacy reasoning, recover tool arguments from done events, and close blocks in protocol order. Normalize empty or incomplete non-streaming tool arguments, reject malformed completed calls, and persist upstream usage before returning terminal conversion errors. * fix(cache): surface unsupported breakpoint counts Warn when caller-provided cache breakpoints already exceed the supported total of four while preserving the original markers and upgrading their TTLs. Clarify that automatic injection is governed by the remaining breakpoint budget, and add regression coverage proving excess caller markers are never deleted or reordered. * feat(proxy): session-based prompt_cache_key routing for Codex Chat bridge Codex always sends prompt_cache_key in its Responses requests, but the Responses -> Chat Completions conversion dropped it, breaking session cache affinity on upstreams that route by key (e.g. Kimi Coding). - Re-inject prompt_cache_key after conversion in the forwarder: an explicit client key wins, otherwise a client-provided session ID; generated per-request UUIDs are never sent upstream. - Provider-aware gating: "auto" enables only known-compatible upstreams (api.openai.com, api.kimi.com/coding) because strict gateways reject unknown fields with HTTP 400 (e.g. Fireworks); an advanced Auto/Enabled/Disabled override is available on the Codex form in all four locales. - Kimi For Coding preset opts in explicitly. * fix(proxy): harden Responses and Anthropic protocol bridges Fail closed on HTTP 2xx failure envelopes and pre-output SSE failures so semantic upstream errors can trigger failover instead of becoming empty successful replies. Finalize incomplete and truncated streams explicitly, handle clean EOF and whole JSON responses, and keep tool-call stop reasons and terminal event ordering consistent. Preserve structured tool results, URL images, documents, system roles, and signed thinking across both conversion directions. Drop incomplete historical tool calls safely and classify malformed completed arguments as non-retryable client requests. Keep Codex-to-Anthropic prompt caching enabled by default while honoring the dedicated cache-injection switch. * fix(cache): strengthen prompt cache breakpoint injection Honor both the optimizer master switch and the cache-injection sub-switch before mutating native optimizer requests. Use the available four-breakpoint budget across tools, system content, the latest cacheable message, and an older user anchor for long tool-heavy conversations. Preserve caller-owned breakpoint limits, avoid thinking blocks as cache targets, normalize configured TTLs, and add regression coverage for disabled optimization and long histories. * fix(usage): account for Anthropic cache write TTLs Parse and retain Anthropic's ephemeral 5-minute and 1-hour cache-creation token buckets while preserving the existing aggregate cache-write metric for compatibility. Price 1-hour writes at the documented premium relative to the configured 5-minute write rate, clamp inconsistent provider details safely, and include TTL buckets in usage diagnostics. Persist 1-hour cache-write tokens with schema version 14 so zero-cost backfills and later pricing updates retain the original TTL semantics. Keep session import paths compatible through zero-valued detail fields. * feat(codex): route native ChatGPT sessions through proxy takeover Allow the built-in Codex official provider to participate in takeover mode while preserving Codex's native OAuth or API-key credentials instead of persisting them into provider records. Project official routing into a dedicated TOML provider, normalize inline tables, clean stale managed placeholders, and fail closed when the live configuration cannot be transformed safely. Validate forwarded authorization, make official 401/403 responses non-retryable, avoid circuit-breaker pollution, and share the first-party ChatGPT endpoint across the Codex and Claude adapters. * fix(providers): skip reachability probes for official OAuth entries Do not derive unauthenticated health-check targets from runtime adapter defaults for official providers. Batch checks now skip official entries, and direct base-URL resolution fails explicitly instead of probing first-party endpoints without credentials. Cover the Codex official provider in the stream-check regression tests so future adapter changes cannot silently reintroduce these probes. * feat(codex): expose official routing and restore the built-in provider Let users switch between the built-in OpenAI provider and third-party Codex providers directly from the provider panel while takeover mode remains active. Centralize the frontend capability predicate so only the fixed codex-official seed receives native-login routing support, and keep copied UUID-based official entries clearly marked as unsupported. Add an idempotent backend command that recreates the deleted official seed, wire it into the add-provider flow, refresh localized guidance, and add mutation and provider-action regression coverage. * feat(codex): declare gpt-5.6 context window for Claude Code takeover - Update Codex OAuth presets to the gpt-5.6 family (haiku -> gpt-5.6-luna) and bump the custom Codex template default model - Inject CLAUDE_CODE_MAX_CONTEXT_TOKENS / CLAUDE_CODE_AUTO_COMPACT_WINDOW (372000, the ChatGPT Codex catalog window with a ~353K effective budget, openai/codex#31860) into effective live settings so Claude Code stops assuming a 200K window and compacts before the upstream rejects the prompt - Gate the injected defaults on every configured model being gpt-5.6*: gpt-5.5's upstream catalog oscillates between 272K and 372K and must not inherit them; explicit user values always win - Strip the injected values on switch-away backfill (mirror-inverse of the injection conditions) so program defaults never harden into per-provider explicit values, and keep both keys out of the shared common-config snippet * feat(pricing): seed gpt-5.6 alias rows and 1.25x cache-write rates - Add the bare gpt-5.6 row (official Sol alias) plus effort-suffix variants mirroring the gpt-5.5 accounting shape, priced at Sol rates - The GPT-5.6 family charges cache writes at 1.25x the uncached input rate (new for OpenAI; earlier GPT models keep their correct zero): set 6.25 / 3.125 / 1.25 for Sol / Terra / Luna across seed rows - Repair earlier zero-value gpt-5.6 tier seeds in existing databases, matching only untouched rows so user-customized prices survive * feat(kimi): declare the 256K context window for Kimi For Coding Claude Code caps unknown model ids at 200K, so the preset's standalone CLAUDE_CODE_AUTO_COMPACT_WINDOW=262144 was clamped by min(window, value) and never took effect. Pair it with CLAUDE_CODE_MAX_CONTEXT_TOKENS and route the endpoint's kimi-for-coding alias on every tier, since both context envs are ignored for claude-* prefixed model ids. Saved providers get the same context defaults injected into effective live settings at switch time, with a mirror-inverse strip on backfill so injected values never harden into provider config. Explicit user values always win over the injected defaults. * refactor(presets): pin context window values instead of form fields Drop the Max Context Tokens / Auto Compact Window template inputs from the Codex and Kimi For Coding presets and hardcode the values in the preset env (372000 / 262144). The rare user who wants different numbers can edit them directly in the JSON editor. Both keys stay on purpose: the compact window resolves as min(model window, value), so matching the window is behavior-neutral today, but the explicit env pins compaction locally against remote-config experiments dialing it down. * fix(proxy): align Codex OAuth client identity ChatGPT's Codex backend routes model availability by the originator and version header pair. Requests identifying as cc-switch without a version were assigned to a cohort where gpt-5.6-luna resolved to an unavailable internal engine, resulting in a misleading 404 Model not found response. Identify takeover requests as codex_cli_rs and send version 0.144.1, satisfying luna's minimal_client_version requirement of 0.144.0. A direct HTTP A/B test confirmed the existing headers returned 404 while the aligned identity completed successfully, so no WebSocket transport workaround is required. * feat(presets): promote SudoCode to paid sponsor across six clients Replace the legacy sudocode.us provider (a name collision) with the new paid sponsor SudoCode on sudocode.chat, updated in place across six clients: Claude Code, Codex, Claude Desktop, OpenCode, OpenClaw, Hermes. - Switch endpoints to api.sudocode.chat, add isPartner + partnerPromotionKey, and add four-locale partnerPromotion copy - Claude Code / Desktop use direct passthrough (no model mapping) - Codex / OpenCode / OpenClaw / Hermes use gpt-5.6-sol - Remove the Gemini entry (outside sponsor scope) - Replace the provider icon with the new brand PNG * fix(codex): infer image capability for generated catalogs and resync takeover live on save Mapped GPT models were rejected by Codex clients with "model does not support image inputs". Two root causes: - Catalog entries for native-Responses/Anthropic providers cloned a template whose input_modalities defaulted to ["text"], so every mapped model was advertised text-only. model_catalog_json replaces Codex's built-in model table wholesale, and both the TUI and the IDE extension block images pre-send when the current model is found without "image". - Editing the current Codex provider during proxy takeover only refreshed the DB backup, so removing the mapping left a stale model_catalog_json pointer (and its text-only catalog file) active in live config. Changes: - New shared model_capabilities module: explicit row declaration first, then a confirmed text-only registry (exact tail match only — prefix matching removed, variants enumerated so future -vl/-vision models fail open), everything else unknown. - Catalog generation writes input_modalities from that inference for all tool profiles: unknown models fail open to ["text","image"]; only confirmed text-only models are advertised as ["text"], giving users a clear client-side prompt instead of silent image stripping. - Live catalog reverse-import collapses modalities that match current inference, so registry corrections are not frozen into hidden row overrides and the rectifier's heuristic opt-out keeps working. - Saving the current Codex provider while takeover owns live now re-projects the live config (mirrors the hot-switch path), so mapping edits and removals take effect immediately. - Media rectifier delegates to the shared module; its preflight toggle is documented (4 locales) as proxy-request-only, never affecting catalog capability declarations. * revert(proxy): drop the 1-hour cache TTL option and TTL-bucketed write accounting The forced 1-hour cache_control TTL (schema v14) was a mistake. Injected breakpoints return to Anthropic's standard 5-minute TTL, caller-owned markers are preserved verbatim instead of having their TTLs rewritten, and the 5m/1h cache-write buckets are removed from usage parsing and pricing (back to the single aggregate cache-creation rate). The cache TTL selector is removed from the rectifier settings panel along with its i18n keys in all four locales. SCHEMA_VERSION returns to 13: the unreleased cache_creation_1h_tokens column and the v13->v14 migration are removed. The feature never shipped in a release and the introducing commit was never pushed, so no databases were stamped v14 outside this machine (local DB verified at user_version 13). * chore(release): v3.17.0 * docs(release): add v3.17.0 release notes * fix(i18n): add missing proxyReasonAnthropicMessages key across locales The routing-required toast for Anthropic-format Codex providers only had a Chinese defaultValue in code; non-Chinese locales showed a mixed-language message. Add the reason string to zh/en/ja/zh-TW following the phrasing of the sibling proxyReason* keys. * docs(guides): add Codex + Claude local routing guide in three languages Step-by-step guide for the v3.17.0 native Anthropic Messages upstream: add a custom Codex provider pointed at a Claude-family /v1/messages gateway, pick the anthropic upstream format, enable local routing, and verify the chain. Covers the auth-field choice (Bearer vs x-api-key), the Claude Code impersonation toggle, the 8192 max-output fallback, and a FAQ entry for gateways that restrict keys to Claude Code only. Includes four UI screenshots captured from the real 3.17.0 app with sample data, and links the guide from the v3.17.0 release notes in all three languages. * feat(copilot): support GPT-5.6 1M max effort --------- Co-authored-by: Yeeyzy <[email protected]> Co-authored-by: Jason <[email protected]> Co-authored-by: Dawn <[email protected]> Co-authored-by: v2v <[email protected]> Co-authored-by: wzk <[email protected]> Co-authored-by: Jason Young <[email protected]> Co-authored-by: Komi <[email protected]> Co-authored-by: 白喵喵喵喵 <[email protected]> Co-authored-by: 风少1227 <[email protected]>
…arion1231#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 <[email protected]>


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:
Frontend:
Robustness:
Summary / 概述
让只提供原生 Anthropic Messages 协议(/v1/messages)的网关可以作为 Codex 的上游使用。本地代理在 OpenAI Responses 协议与 Anthropic Messages 协议之间做双向转换(请求 / 响应 / 流式),因此 Codex 无需任何客户端改动即可对接仅支持 Anthropic 的端点。
Related Issue / 关联 Issue
实际的使用需求
Screenshots / 截图
Checklist / 检查清单