fix(providers): 「模拟 CLI」切换身份整套替换指纹头,并按官方 CLI 源码对齐头集 - #737
Merged
xiaozhou26 merged 1 commit intoSep 3, 2026
Merged
Conversation
切换 CLI 身份原本走 mergeImportedCustomHeaders 的"导入"语义:同名覆盖、其余追加、 从不删除。三家 CLI 除 User-Agent 外没有同名头,于是 Claude Code → Codex 只换掉 UA,x-app / anthropic-version / X-Stainless-* 等 11 条原样残留,拼出哪家都不像的混合 指纹。 - customHeaders.ts:新增 CLI_IDENTITY_HEADER_FAMILIES(每家静态身份头 + 每会话动态 头名)与 applyCliIdentity():先剥掉其它 CLI 家族名下的全部头,再并入所选 CLI 的整套 静态头;所选 CLI 自家的动态头保留用户手填值,非 CLI 业务头不动;结果带 removedCount。 - 按官方源码对齐一键写入的头集:Claude Code 复刻 claude-code-source 2.1.88(内联 SDK 0.74.0,X-Stainless-Retry-Count 用 SDK 的 Pascal-Case);Codex 补 originator/version (与 UA 同版本);Grok 补 x-grok-client-identifier/version/mode 与 cli-chat-proxy 标记 头。UA 版本号与随附 version 头统一取自 *_CLI_VERSION 常量。 - requestOptions.ts:Claude 链路有 sessionId 时补 X-Claude-Code-Session-Id + x-client-request-id;Codex 链路补 session-id / thread-id / x-client-request-id。 - ProviderModal(View):切换身份走 applyCliIdentity,摘要行新增"移除 N";下拉按当前 供应商排序并标"匹配当前",菜单加宽避免 UA 换行。 - provider_models.rs:模型列表链路 never-forge 用例补入新增身份头名。 - 测试:新增 Claude→Codex 整套替换、离开 Grok 剥 x-grok-*、重选同家保留自家动态 头、x-client-request-id 跨家归属 4 个用例;更新 golden 与 request-options 用例。 Closes Stack-Cairn#736
xiaozhou26
force-pushed
the
feat/mimic-cli-identity-align-official
branch
from
September 2, 2026 13:37
26ff30f to
4e1bd4a
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Linked issue
Closes #736
Summary
「模拟 CLI」切换身份原本走
mergeImportedCustomHeaders的"导入"语义——同名覆盖、其余追加、从不删除。三家 CLI 除User-Agent外没有同名头,于是 Claude Code → Codex 只换掉 UA,x-app/anthropic-version/X-Stainless-*等 11 条原样残留,最终发出的是哪家都不像的混合指纹(详见 #736)。本 PR 做两件事:
customHeaders.ts新增CLI_IDENTITY_HEADER_FAMILIES(每家 CLI 的静态身份头 + 每会话动态头名)与applyCliIdentity():先剥掉其它 CLI 家族名下的全部头,再并入所选 CLI 的整套静态头。所选 CLI 自家的动态头(如 Codex 的session-id)保留用户手填值;不属于任何 CLI 家族的业务头(Authorization、X-Api-Key……)原样不动。摘要行新增"移除 N",让用户看见被剥掉了多少。claude-code-source2.1.88(内联@anthropic-ai/sdk0.74.0);X-Stainless-Retry-Count改用 SDK 实际发出的 Pascal-Case。originator: codex_cli_rs与version(codex-rsdefault_client.rs/model-provider-info),version与 UA 同源。x-grok-client-identifier/x-grok-client-version/x-grok-client-mode及 cli-chat-proxy 标记头(xai-grok-http/xai-grok-shell)。X-Claude-Code-Session-Id/x-client-request-id、Codex 的session-id/thread-id、Grok 的x-grok-conv-id等)不写死;requestOptions.ts在有sessionId时按官方规则填 Claude / Codex 的两组。发请求那侧仍不含任何内置伪装:这些值只在用户点按钮时写进自定义请求头。
Change scope
crates/agent-ui/src/lib/providers/customHeaders.ts—CLI_IDENTITY_HEADER_FAMILIES、applyCliIdentity()、listCliIdentityProviderIds(),三家头集与版本常量crates/agent-ui/src/pages/settings/ProviderModal.tsx/ProviderModalView.tsx— 切换走applyCliIdentity,摘要"移除 N",下拉按当前供应商排序并标"匹配当前",菜单加宽避免 UA 换行crates/agent-ui/src/i18n/translations/{zhCN,enUS}Settings.ts— 2 个新文案键crates/agent-gui/src/lib/providers/runtime/requestOptions.ts— Claude / Codex 每会话头crates/agent-gui/src-tauri/src/services/provider_models.rs— 模型列表链路 never-forge 用例补入新增身份头名crates/agent-gui/test/providers/{custom-headers,request-options,transport-golden}.test.mjs、test/settings/provider-models-fetch.test.mjsScreenshots / preview
下拉按当前供应商排序并标"匹配当前"(Anthropic 供应商):
选 Claude Code:写入 12 条(
已导入 12; 覆盖 0):再切到 Codex:只剩 Codex 的 3 条,摘要
已导入 3; 覆盖 1; 移除 11(修复前这里仍是 12 条、只换了 UA):同一流程继续切到 Grok 的运行时输出(headless Chrome 驱动
npm run dev,从 React 状态直接读取):Verification
新增 / 更新的用例:
custom-headers.test.mjs(+9):Claude → Codex 整套替换且业务头保留;离开 Grok 时剥掉手填的x-grok-*动态头;重选同一家保留自家手填动态头;x-client-request-id在 Claude / Codex / Grok 之间的归属;三家buildCliIdentityHeaders的头集与 UA/version 同源;listCliIdentityProviderIds排序;全部身份头合法、不在保留集、合并无重复。request-options.test.mjs:Claude / Codex 链路带sessionId时的每会话头;Codex 自动生成 session 时session-id/thread-id/x-client-request-id与session_id同值;三家预设键名含新增头。transport-golden.test.mjs:golden 快照随新增头更新。provider_models.rs:provider_model_headers_never_forge_a_client_identity的禁止列表补入新增身份头名,锁定模型列表链路不自动注入。Pre-submit checklist