Skip to content

fix(settings): 刷新模型列表带上用户配置的自定义请求头 - #707

Merged
su-fen merged 1 commit into
Stack-Cairn:mainfrom
xiaozhou26:fix/provider-models-custom-headers
Sep 1, 2026
Merged

fix(settings): 刷新模型列表带上用户配置的自定义请求头#707
su-fen merged 1 commit into
Stack-Cairn:mainfrom
xiaozhou26:fix/provider-models-custom-headers

Conversation

@xiaozhou26

@xiaozhou26 xiaozhou26 commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

问题

Closes #668

User-Agent 鉴权的第三方中转,在「刷新模型列表」上永久返回 401
UNAUTHENTICATED,聊天却正常。

根因不是漏了一处赋值,而是两条路各有一套实现:聊天走 prepareProviderRequest,
里面调了 mergeCustomHeaders;取模型列表是完全独立的另一条链路,从装配请求头到
发请求都是自己的代码,从来没并过自定义头。

桌面端(Rust fetch_provider_models)与 WebUI(TS buildModelsHeaders)又是两份
互不复用的平行实现,由一个契约测试钉住。所以同一个修复要落两次。

改了什么

proto — 新增 ProviderCustomHeaders 包装 message,ProviderModelsRequest
custom_headers = 8

包一层是为了拿到字段存在性。proto3 的 repeated 分不清「草稿没带这个字段」和
「草稿把头清空了」,而这两种情况在已保存的供应商上处理是相反的:前者要沿用
落库的头,后者要按空集发。和现有 optional bool is_full_url 是同一套三态语义。

两条链路各自并头 — Rust 侧新增 merge_custom_headers,TS 侧复用既有
mergeCustomHeaders。两边同一套约束:

  • authorization / x-api-key / x-goog-api-key / anthropic-beta / host /
    content-length 属保留头,自定义头顶不掉;
  • x-liveagent- 前缀保留 —— 这是本地反代的内部通道,放行等于让用户注入代理令牌;
  • 键名不合 HTTP token、取值含 CR/LF(header 注入)的直接丢弃。

身份伪装收敛为显式开启 — 顺手修掉一个相关的既有行为:provider_models.rs
providerUtils.ts 原本会无条件给每个请求塞一个伪造的 CLI User-Agent。现在
删掉,改成自定义请求头那一行新增的「模拟 CLI」按钮一键写入(Claude Code / Codex /
Grok)。不点就照实发,不冒充任何官方 CLI。

Anthropic 指纹头的 SDK/运行时版本同时对齐到 0.94.0 / v26.3.0,和 UA 里的 CLI
版本成套 —— 之前 UA 写 claude-cli/2.1.186、SDK 却停在 0.74.0,这两个对不上
本身就是破绽。

⚠️ 行为变更

原先所有人的模型列表请求都带着那个伪造 UA,合并后不带了。如果有中转恰好是靠这个
默认 UA 放行的,升级后会开始 401 —— 去供应商设置里点一下「模拟 CLI」即可恢复,
且此后是用户显式选择的结果。

Screenshots / preview

改动前 —— 供应商弹窗「请求配置」页,自定义请求头一行只有「导入」「+ 添加」;
身份 UA 是代码里无条件下发的,用户看不见也关不掉:

请求配置页与新按钮

改动后 · 入口 —— 同一行新增「模拟 CLI」,菜单列出三个官方 CLI 及其 UA 前缀:

模拟 CLI 下拉菜单

改动后 · 结果 —— 选 Claude Code 后写入 12 条头,走与「导入」同一条合并路径
(同名覆盖、其余保留),用户可逐条查看和编辑:

写入后的自定义请求头列表

写入的取值(实机读取):

User-Agent                                 claude-cli/2.1.186 (external, cli)
x-app                                      cli
X-Stainless-OS                             MacOS
X-Stainless-Arch                           arm64
X-Stainless-Lang                           js
anthropic-version                          2023-06-01
X-Stainless-Runtime                        node
X-Stainless-Timeout                        600
x-stainless-retry-count                    0
X-Stainless-Package-Version                0.94.0
X-Stainless-Runtime-Version                v26.3.0
anthropic-dangerous-direct-browser-access  true

不在本 PR 范围

  • 用量查询子系统(含「测试用量查询」按钮)、Cherry Studio 导入时的模型拉取 ——
    这三条路同样没并自定义头,但各自有独立的配置面,单独处理更清楚。
  • 任何 body 层改写(替换 system prompt、伪造 metadata.user_id、请求签名等)。
    本 PR 只碰传输层请求头。

测试

  • cargo check --all-targets 0 error;provider_models 9/9、gateway_bridge 13/13
  • 桌面端 provider-models-fetch 23/23、request-options 46/46
  • WebUI 680/680
  • Go go build ./... + go test ./... 19 包通过
  • 三个 tsc --noEmit(agent-gui / agent-ui / gateway-webui)均 exit 0
  • 上方截图为 rebase 后实机运行所截,不是 mockup

新增覆盖:自定义头到达模型列表请求、保留头不被顶掉、非法键值被丢弃、三态回退
(草稿未带则沿用落库、草稿显式清空则为空、草稿有值则覆盖),以及「不点按钮就不
产出任何 UA 或 SDK 指纹头」。

@StackCairn
StackCairn marked this pull request as draft August 31, 2026 18:00
@github-actions

github-actions Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

PR governance checks passed. Awaiting human review.

@xiaozhou26
xiaozhou26 marked this pull request as ready for review August 31, 2026 18:04
@StackCairn
StackCairn marked this pull request as draft August 31, 2026 18:04
@xiaozhou26
xiaozhou26 force-pushed the fix/provider-models-custom-headers branch from cec5554 to d965198 Compare August 31, 2026 18:07
按 UA 鉴权的第三方中转在「刷新模型列表」上永久 401:聊天走
prepareProviderRequest 会并入自定义头,取模型列表这条路却是另一套独立实现,
从来没并过。桌面端与 WebUI 是两份平行实现,因此要各修一次。

- proto 新增 ProviderCustomHeaders 包装 message。repeated 无法区分「草稿没带」
  与「草稿清空了头」,而这两种在已保存供应商上的处理相反(前者沿用落库配置、
  后者按空集发),沿用 is_full_url 的 optional 三态语义。
- Rust fetch_provider_models 与前端 buildModelsHeaders 各自并入自定义头,
  鉴权头与 host/content-length/x-liveagent-* 仍走保留头名单兜底,
  非法键名与含 CR/LF 的取值直接丢弃。

同时把客户端身份伪装收敛成显式开启:删掉 provider_models.rs 与
providerUtils.ts 里无条件下发的内置 CLI UA,改由自定义请求头行新增的
「模拟 CLI」按钮一键写入。不点就照实发,不冒充任何官方 CLI。
Anthropic 指纹头的 SDK/运行时版本对齐 CLIProxyAPI 的 claudeDeviceProfile
(0.94.0 / v26.3.0),与 UA 里的 CLI 版本成套。

Refs Stack-Cairn#668
@xiaozhou26
xiaozhou26 force-pushed the fix/provider-models-custom-headers branch from d965198 to 7bec815 Compare August 31, 2026 18:24
@xiaozhou26
xiaozhou26 marked this pull request as ready for review August 31, 2026 18:27
@su-fen
su-fen merged commit a43166a into Stack-Cairn:main Sep 1, 2026
11 checks passed
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.

[Bug] 自定义请求头不作用于「刷新模型列表」,UA 鉴权的中转端点永久 401

2 participants