Skip to content

refactor: 去除 Codex CLI 伪装并简化 Codex 兼容逻辑#1166

Merged
looplj merged 5 commits intolooplj:release/v0.9.xfrom
llc1123:feat/remove-codex-simulation
Mar 26, 2026
Merged

refactor: 去除 Codex CLI 伪装并简化 Codex 兼容逻辑#1166
looplj merged 5 commits intolooplj:release/v0.9.xfrom
llc1123:feat/remove-codex-simulation

Conversation

@llc1123
Copy link
Copy Markdown
Contributor

@llc1123 llc1123 commented Mar 26, 2026

摘要

  • 去除 Codex 通道对 Codex CLI 身份与指令的伪装逻辑,收敛为更小的最小兼容面。
  • 不再主动注入 Codex CLI 专用请求头、版本号和系统提示词,改为优先透传调用方已提供的信息,并使用 AxonHub 自身默认身份。
  • 同步调整 quota 检查、trace 相关测试和 Codex 出站测试,明确新的行为契约是“最小转换”,而不是模拟官方私有客户端。

变更说明

  • 删除默认 Codex CLI User-AgentOriginatorVersion、指令注入及相关判定逻辑。
  • 保留必要的 Responses/Codex 请求适配,例如 SSE、store=false、鉴权和 Session_id 回退。
  • 将测试从“必须保持 Codex CLI 兼容伪装”改为“允许透传调用方头部并验证 AxonHub 最小默认行为”。

影响范围

  • 这是一次有意的兼容边界收缩:AxonHub 不再承诺伪装成 Codex CLI。
  • 依赖私有 Codex CLI 请求头或行为细节的调用方,需要自行提供对应 header 或自行保证兼容性。

Copilot AI review requested due to automatic review settings March 26, 2026 07:14
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

本次拉取请求旨在简化 AxonHub 与 Codex 服务的集成方式。通过移除对 Codex CLI 的特定伪装行为,AxonHub 现在采取“最小转换”策略,减少了不必要的复杂性,并允许调用方对请求头有更大的控制权。这一变更使得系统更加清晰和可维护,同时确保了核心功能的兼容性。

Highlights

  • 移除伪装逻辑: 移除了对 Codex CLI 身份和指令的伪装逻辑,将兼容面收敛到最小。
  • 简化请求头处理: 不再主动注入 Codex CLI 专用的请求头、版本号和系统提示词,而是优先透传调用方提供的信息,并使用 AxonHub 自身的默认身份。
  • 调整测试: 同步调整了配额检查、追踪相关测试和 Codex 出站测试,以明确新的行为契约是“最小转换”,而非模拟官方私有客户端。
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request refactors the Codex outbound transformer and related components to improve flexibility and maintainability. Key changes include decoupling the transformer from hardcoded Codex CLI user agents, versions, and system instructions, instead using a more generic 'axonhub' identity by default while allowing specific inbound headers to be preserved. The CodexQuotaChecker now utilizes a standardized httpclient.NewRequestBuilder for streamlined HTTP request handling. The LLM request parameter handling has been refined, making the transformer more selective about modifications and ensuring compatibility with the Codex Responses API. Additionally, session ID management has been improved, prioritizing inbound headers, then context, and generating a UUID if neither is present. The changes are supported by enhanced testing for header handling, session ID precedence, and the customized executor's behavior for both streaming and non-streaming requests.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

该 PR 将 Codex 通道从“伪装 Codex CLI”调整为“最小转换/最小兼容面”,减少默认注入的 CLI 专用身份、指令与请求头,改为尽量透传调用方信息并使用 AxonHub 默认身份;同时同步更新 quota、trace 与 Codex 出站相关测试以匹配新契约。

Changes:

  • 移除 Codex CLI 伪装逻辑(默认 UA/Originator/Version/系统指令注入与相关判定),收敛 Codex 出站转换规则。
  • Codex quota 检查改用统一 httpclient 发起请求(减少 CLI 专用 header 依赖),并新增相应单测。
  • 更新/新增 Codex、trace、OAuth 相关测试,明确“透传 + AxonHub 默认身份 + 最小必要转换”的新行为。

Reviewed changes

Copilot reviewed 11 out of 12 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
llm/transformer/openai/codex/token_provider_test.go 断言 OAuth 刷新请求默认使用 AxonHub UA。
llm/transformer/openai/codex/token.go TokenProvider 不再显式注入 Codex CLI UA。
llm/transformer/openai/codex/outbound_test.go 删除与 CLI 指令注入/判定相关的旧测试。
llm/transformer/openai/codex/outbound_executor_test.go 新增/重写 Codex 出站行为测试(SSE、身份透传覆盖、聚合非流式请求、最小转换契约)。
llm/transformer/openai/codex/outbound.go 移除 CLI 伪装/指令注入逻辑,保留必要的 Codex Responses 适配与会话/鉴权处理。
llm/transformer/openai/codex/constants.go 移除 Codex CLI 常量与指令文本,新增 AxonHub 默认 Originator 常量。
llm/transformer/openai/codex/codex_simulator_test.go 调整模拟器测试以验证“最小身份/透传”与 Session_id 优先级。
llm/httpclient/utils.go header blocklist 格式化调整(无语义变化)。
internal/server/middleware/trace_test.go Codex trace 行为测试增强:同时验证 Session_id 写入 context;新增缺失 Session 不设置 trace 的用例。
internal/server/biz/provider_quota/codex_checker_test.go 新增 Codex quota checker 的最小 header 行为测试。
internal/server/biz/provider_quota/codex_checker.go quota checker 改为使用 httpclient 请求构建/执行,移除 CLI 专用 header 注入与 account_id header 依赖。
internal/server/api/codex_test.go 新增 StartOAuth 返回的 AuthURL 不包含 originator 参数的测试。

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +83 to +88
resp, err := hc.Do(ctx, httpRequest)
if err != nil {
return QuotaData{}, fmt.Errorf("quota request failed: %w", err)
}

defer func() { _ = resp.Body.Close() }()

// Read body
body, err := io.ReadAll(resp.Body)
if err != nil {
return QuotaData{}, fmt.Errorf("failed to read response body: %w", err)
}

if resp.StatusCode != http.StatusOK {
return QuotaData{}, fmt.Errorf("quota request failed with status %d: %s", resp.StatusCode, string(body))
}

return c.parseResponse(body)
return c.parseResponse(resp.Body)
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

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

After switching to hc.Do(ctx, httpRequest), non-2xx responses now return an *httpclient.Error whose Error() string does not include the response body. Previously this code read the body and included it in the returned error, which is helpful for diagnosing quota failures. Consider detecting *httpclient.Error here and wrapping the error to include err.Body (similar to oauth.wrapHttpError), so callers still get actionable error details.

Copilot uses AI. Check for mistakes.
Comment on lines +64 to +66
assert.Equal(t, codexAPIURL, finalReq.URL.String())
assert.Equal(t, "text/plain", finalReq.Header.Get("Accept"))
assert.Equal(t, "application/json", finalReq.Header.Get("Content-Type"))
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

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

Simulator.Simulate() ends by calling httpclient.BuildHttpRequest, but real Codex traffic goes through HttpClient.DoStream, which always overwrites Accept to text/event-stream (and adds other stream headers). As a result, asserting finalReq.Header.Get("Accept") == "text/plain" here is misleading vs the actual executed request. Consider either removing the Accept assertion, or updating the simulator/test to mimic the DoStream header injection when validating outbound headers.

Copilot uses AI. Check for mistakes.
reqCopy.TransformerMetadata["include"] = []string{"reasoning.encrypted_content"}
}

if reqCopy.ReasoningSummary == nil || *reqCopy.ReasoningSummary == "" {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

这些不用删吧

reqCopy.Store = lo.ToPtr(false)

// Codex recommends parallel tool calls.
reqCopy.ParallelToolCalls = lo.ToPtr(true)
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

这些不用删吧

reqCopy.MaxTokens = nil

// Strip sampling params and tier.
reqCopy.ServiceTier = nil
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

这些不用删吧

@looplj
Copy link
Copy Markdown
Owner

looplj commented Mar 26, 2026

我确认下,这个改动较大。
本地测试验证过没有,比如从 claude code 使用 codex。

有些字段的设置都是有原因的,需要比较完善的真实测试覆盖。

@llc1123
Copy link
Copy Markdown
Contributor Author

llc1123 commented Mar 26, 2026

本地测试验证过没有,比如从 claude code 使用 codex

我用codex cli和opencode都测试过了没问题。

上面提到的几个删除的内容,我是考虑希望能够尽量透传客户端的参数,尤其是 service_tier 确实是用得上的,codex cli 的 fast mode 就是配置了 service_tier = "priority"

@looplj
Copy link
Copy Markdown
Owner

looplj commented Mar 26, 2026

codex 应该是不支持 metadata 的

@llc1123
Copy link
Copy Markdown
Contributor Author

llc1123 commented Mar 26, 2026

这次修改的目标是明确收敛 AxonHub 在 Codex 通道里的职责:去掉客户端伪装,只保留必要的协议转换,不再替调用方模拟 Codex CLI 的请求行为。

具体来说:

  • 凡是属于 Codex CLI 伪装的部分,这次都是有意删除的,包括主动补默认值、主动模拟客户端身份、主动注入 CLI 特有行为等。
  • metadata 没有放开,这里我保留了原来的过滤逻辑,因为从现有注释和上下文看,Codex 后端并不支持这个字段。
  • service_tier、parallel_tool_calls、reasoning.summary、include 等这类 Responses 请求语义参数,我倾向于保持透传,不再由 AxonHub 在 Codex outbound 层做额外裁剪或合成。它们更像是调用方的真实请求意图,而不是“伪装 Codex CLI”所必需的内容。

这点我也额外对了下 opencode 和 @ai-sdk/openai 的实现:

  • 在 opencode 里,这些参数本身就会由上游调用链显式设置,例如 store=false、reasoningSummary="auto"、include=["reasoning.encrypted_content"] 等;
  • 在 @ai-sdk/openai 的 Responses 请求构造里,service_tier、parallel_tool_calls、reasoning.summary、include 这类字段本来就是会透传/校验后下发给下游的;
  • 也就是说,这些字段本身属于 Responses API 的请求语义,不是 CLI 伪装逻辑。

所以从这个角度看,当前这版实现已经符合预期设计:

  • 去掉 Codex CLI 伪装相关逻辑;
  • 对明确不支持的字段(如 metadata)继续保守过滤;
  • 其余 Responses 语义参数按下游行为透传,不再由 AxonHub 代替调用方做额外“补齐”或“回滚”。

@looplj
Copy link
Copy Markdown
Owner

looplj commented Mar 26, 2026

reasoningSummary="auto"、include=["reasoning.encrypted_content"]

这两个建议加上默认值。

如果没有默认值,那么在 cc 里面使用,就不会传这些值,就会导致返回里面没有 encrypted_content,interleave thinking 失效。
在 codex 和 open code 没问题,是因为客户端主动传了这些值。
在 cc 或者 opencode 的 anthropic provider 应该会有问题。

@llc1123
Copy link
Copy Markdown
Contributor Author

llc1123 commented Mar 26, 2026

已按要求修复

@looplj
Copy link
Copy Markdown
Owner

looplj commented Mar 26, 2026

感谢 PR

@looplj looplj merged commit 89fe53f into looplj:release/v0.9.x Mar 26, 2026
2 checks passed
NekoNuo pushed a commit to NekoNuo/axonhub that referenced this pull request Mar 28, 2026
* refactor: 去除 Codex CLI 伪装逻辑

* fix: filter metadata from codex outbound

* fix: restore codex reasoning defaults

* refactor: align codex defaults with previous structure

* test: align codex simulator header assertions
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.

3 participants