Skip to content

Add Responses-to-Anthropic Moon Bridge port#285

Open
Uchiha007 wants to merge 2 commits into
qxcnm:mainfrom
Uchiha007:main
Open

Add Responses-to-Anthropic Moon Bridge port#285
Uchiha007 wants to merge 2 commits into
qxcnm:mainfrom
Uchiha007:main

Conversation

@Uchiha007
Copy link
Copy Markdown

Summary

This PR ports the Responses-to-Anthropic bridge from the fork into the current upstream main.

The goal is to provide a Moon Bridge-style compatibility path for clients that send OpenAI Responses API requests while the selected aggregate upstream is configured as an Anthropic/Claude-compatible provider, especially DeepSeek's official Anthropic API endpoint:

  • ANTHROPIC_BASE_URL=https://api.deepseek.com/anthropic
  • upstream request path rewritten from /v1/responses to /v1/messages
  • request body adapted from OpenAI Responses shape to Anthropic Messages shape
  • upstream Anthropic Messages responses adapted back to OpenAI Responses shape

What Changed

  • Adds a new ResponsesFromAnthropicMessages response adapter.
  • Detects Claude/Anthropic aggregate API candidates receiving /v1/responses traffic and bridges them to /v1/messages.
  • Converts Responses request fields into Anthropic Messages fields:
    • model
    • stream
    • max_output_tokens / max_tokens -> max_tokens
    • instructions / system or developer input -> system
    • text message input -> Anthropic messages[].content[].text
    • function_call -> Anthropic tool_use
    • function_call_output -> Anthropic tool_result
    • Responses function tools -> Anthropic tools[].input_schema
    • Responses tool_choice -> Anthropic tool_choice
    • Responses reasoning.effort -> Anthropic thinking
  • Converts non-streaming Anthropic Messages responses back into OpenAI Responses responses.
  • Converts streaming Anthropic SSE events into Responses SSE events, including:
    • response lifecycle events
    • text deltas
    • function-call output items
    • token usage collection
  • Preserves completed streamed tool_use blocks in the final response.completed.response.output, so downstream Responses clients can derive tool execution from the terminal response object.
  • Avoids forwarding Responses image input as Anthropic image blocks because DeepSeek's Anthropic API compatibility documentation marks image content as unsupported.

Moon Bridge Port Scope

This is a port of the Moon Bridge-style bridge pattern for Codex Manager's gateway architecture:

  1. Keep the client-facing interface as /v1/responses.
  2. Use an Anthropic-compatible upstream when the aggregate API provider is Claude/Anthropic.
  3. Translate the request into Anthropic Messages.
  4. Translate the response back into OpenAI Responses.

The implementation is intentionally integrated with Codex Manager's existing gateway layers:

  • aggregate API rotation and model override handling
  • response adapter logging
  • request log response adapter names
  • HTTP bridge stream readers
  • existing timeout and keepalive behavior

Current Compatibility

Covered:

  • text input and output
  • system/developer instructions
  • function tools
  • function tool calls
  • function tool results
  • basic reasoning/thinking request translation
  • streaming and non-streaming response conversion
  • usage accounting for Anthropic token fields
  • DeepSeek Anthropic base-path style URLs such as https://api.deepseek.com/anthropic/v1/messages

Known follow-up gaps before claiming complete Moon Bridge parity:

  • Anthropic thinking response blocks are not fully mapped into Responses reasoning output.
  • Anthropic server_tool_use and web_search_tool_result response blocks are not fully mapped into Responses output items yet.
  • Responses web-search request tools are translated to Anthropic web search tools, but the response-side web-search/server-tool round trip still needs dedicated mapping and tests.

Validation

Ran:

rustfmt --edition 2021 --check crates/service/src/gateway/observability/http_bridge/delivery.rs crates/service/src/gateway/observability/http_bridge/mod.rs crates/service/src/gateway/observability/http_bridge/stream_readers.rs crates/service/src/gateway/observability/http_bridge/stream_readers/responses_from_anthropic.rs crates/service/src/gateway/observability/request_log.rs crates/service/src/gateway/protocol_adapter/mod.rs crates/service/src/gateway/protocol_adapter/request_router.rs crates/service/src/gateway/protocol_adapter/types.rs crates/service/src/gateway/upstream/protocol/aggregate_api.rs
cargo check -p codexmanager-service
cargo test -p codexmanager-service responses_request -- --nocapture
cargo test -p codexmanager-service anthropic_tool_use_sse_is_in_completed_responses_output -- --nocapture
pnpm run build:desktop

Notes:

  • pnpm run build:desktop was run from apps/ after installing missing frontend dependencies with pnpm install.
  • Full-repository cargo fmt --check currently reports formatting differences in unrelated upstream files from qxcnm/main; this PR only checks the bridge-related Rust files to avoid mixing unrelated formatting churn into the Moon Bridge port.

Copy link
Copy Markdown
Collaborator

@KilimiaoSix KilimiaoSix left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

本次不通过,建议先修复以下问题后再合并:

  1. crates/service/src/gateway/upstream/protocol/aggregate_api.rs L818-L823:Claude 聚合 API bridge 硬编码 /v1/messages,但默认 Claude provider URL 是 https://api.anthropic.com/v1build_upstream_url 会把路径追加到 base path 上,实际变成 /v1/v1/messages。这里同时绕过了用户配置的 candidate.action,默认 Claude 聚合 API 会直接打错地址。

  2. crates/service/src/gateway/upstream/protocol/aggregate_api.rs L575-L606:新 bridge 走通用 build_aggregate_api_request,只转发 OpenAI 请求头并默认加 Authorization: Bearer,没有补 anthropic-version,默认 auth 也没有 x-api-key。Anthropic Messages API 运行时请求会因为缺少必需 header/auth 失败;probe 路径已有 Claude 专用 header,但运行时路径没有同步。

  3. crates/service/src/gateway/observability/http_bridge/delivery.rs L2280-L2290:ResponsesFromAnthropicMessages 的流式分支没有使用旁边适配器都用的 respond_streaming_chunked,而是直接 request.respond(Response::new(...))。这绕过了现有按 read chunk flush 的 SSE 发送路径,可能导致客户端收不到低延迟流式输出。

  4. crates/service/src/gateway/protocol_adapter/request_router.rs L57-L65、L657-L675:reasoning.effort=high 会生成 budget_tokens=8192,但 max_tokens 默认只有 4096;用户显式传更小 max_output_tokens 时也会触发。Anthropic extended thinking 要求 thinking budget 与 max_tokens 合法匹配,这类请求会被上游校验拒绝。

我在独立 worktree 上验证过:

  • cargo check -p codexmanager-service --lib
  • cargo test -p codexmanager-service responses_from_anthropic --lib
  • cargo test -p codexmanager-service responses_request_rewrites --lib
  • cargo test -p codexmanager-service bridge_tests --lib

这些现有/新增测试通过,但未覆盖上述生产路径问题。

@Uchiha007 Uchiha007 force-pushed the main branch 2 times, most recently from 1ae57c8 to 28c3662 Compare May 28, 2026 09:24
@Uchiha007
Copy link
Copy Markdown
Author

@KilimiaoSix 已按 review 的 4 个点补了独立修复提交 28c36620 fix: harden responses anthropic bridge,麻烦再 review 一次。

修复内容:

  1. Claude aggregate API 的 Responses-to-Anthropic bridge 不再硬编码 /v1/messages。默认 Anthropic base https://api.anthropic.com/v1 会请求 /v1/messages,DeepSeek 这类 https://api.deepseek.com/anthropic base 仍会请求 /anthropic/v1/messages,同时保留 candidate.action 覆盖能力。

  2. 运行时 Anthropic bridge 请求新增 Anthropic Messages API 必需 header/auth:anthropic-version: 2023-06-01,默认 apikey 模式下补 x-api-key,并保留原有 Authorization: Bearer ...

  3. ResponsesFromAnthropicMessages 流式响应 delivery 改为使用现有 respond_streaming_chunked,保持按 read chunk flush 的 SSE 输出路径。

  4. Responses reasoning.effort 转 Anthropic thinking.budget_tokens 时会按 max_tokens 截断,确保 budget_tokens < max_tokens;当 max_tokens <= 1024 时不发送 invalid thinking 配置。

验证:

rustfmt --edition 2021 --check crates/service/src/gateway/observability/http_bridge/delivery.rs crates/service/src/gateway/protocol_adapter/request_router.rs crates/service/src/gateway/upstream/protocol/aggregate_api.rs crates/service/tests/gateway_logs/anthropic.rs
cargo check -p codexmanager-service
cargo test -p codexmanager-service --lib responses_bridge_
cargo test -p codexmanager-service --lib anthropic_bridge_request_adds_required_messages_headers_with_default_auth
cargo test -p codexmanager-service --lib responses_reasoning_budget_stays_below_max_tokens
cargo test -p codexmanager-service --lib responses_request
cargo test -p codexmanager-service --lib responses_from_anthropic
cargo test -p codexmanager-service --test gateway_logs gateway_aggregate_responses_bridge_adds_anthropic_headers_and_messages_path -- --nocapture

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