Add six Desktop and CLI presets, global defaults and per-key overrides, custom identity parameters, and official release tracking. Keep the resolved identity stable throughout each request and its retries.
21 KiB
上游客户端身份配置实施计划
状态:实现与本地验收完成,真实上游账号验收尚未覆盖。当前实现位于 feat/upstream-client-profiles 独立工作区。
代码核对基线:3328a435。
1. 目标与已确定的规则
为 OpenAI 上游请求提供 macOS、Linux、Windows 与 Desktop、CLI 组合的六套客户端身份预设, 支持自定义,并允许管理员在 Client Key 中单独选择,覆盖通用设置。
配置只保留两层:
Key 有独立配置 → 使用 Key 配置
Key 跟随通用设置 → 使用通用设置
- 新安装的通用设置默认使用 macOS · Desktop · 自动最新,管理员可以修改。
- 新建及升级前已有的 Key 默认「跟随通用设置」。
- 内置默认值只用于初始化通用设置,不参与运行时配置优先级。
- 修改通用设置后,跟随它的 Key 在新请求中自动生效;独立配置的 Key 保持自己的选择。
- Key 切回「跟随通用设置」时清除独立覆盖,不保留参与运行时合并的隐藏字段。
- 独立覆盖以完整配置为单位,不逐字段混合 Key 与通用设置,避免组合出不一致的身份。
本文中的客户端身份指网关发给上游的 User-Agent、originator、平台和版本等信息。 该功能不改变接入客户端的最低版本门禁、客户端安装方式或网关宿主操作系统。
2. 当前实现与可复用入口
| 现有能力 | 代码入口 | 本次需要补齐的部分 |
|---|---|---|
| 启动时的 Desktop 身份配置,默认 macOS | OpenAI 配置 | 将用户选择纳入持久化通用设置,支持客户端类型与平台选择 |
| 共享请求画像、Desktop 发布检查及版本元组更新 | 请求画像 | 按类型与平台解析版本,支持固定版本以及每请求独立身份 |
| 模型、账号及 Desktop 专属请求的头部组装 | 请求头 | 按调用场景消费解析后的身份,保留不同接口的协议边界 |
| 通用设置管理 | 管理模型、持久化 | 保存全局选择,复用事务、审计及配置发布 |
| Key 管理 | 管理模型、管理用例 | 保存可空的独立覆盖,并提供实际生效配置的投影 |
| 请求策略冻结与发布 | 运行快照、快照发布 | 携带配置选择,保持同一请求及重试的一致性 |
| 上游连接池已有身份区分与精确续写;模型目录已有缓存隔离 | WebSocket、账号目录 | 复用现有机制,核对新增身份字段是否完整进入隔离维度 |
| 设置页及首页身份展示 | 设置页、身份卡片 | 增加配置入口,明确全局展示与 Key 实际生效值的区别 |
目前画像类型包含 Desktop 专属字段,自动更新通过同一 Desktop 制品取得应用版本、Core 版本及构建号。 因此,六套配置需要按官方身份语义扩展,不能仅替换现有 UA 的操作系统名称。
3. 预设、自定义与版本策略
3.1 六套预设
| 平台 | Desktop | CLI |
|---|---|---|
| macOS | macOS Desktop | macOS CLI |
| Linux | Linux Desktop | Linux CLI |
| Windows | Windows Desktop | Windows CLI |
平台与客户端类型决定预设;系统版本、CPU 架构及终端信息是预设参数,不再展开成额外的顶级选项。 预设值由后端统一提供,前端不维护另一份默认值和 UA 拼接规则。
实施前逐项核对官方源码或官方制品,记录版本、提交或制品标识、请求格式和更新来源。 尤其需要核实 Linux Desktop 的可用制品及身份依据,不能因为有六个组合就宣称六套均已获得官方验证。 没有可靠官方依据的组合保留自定义配置入口,标明核验状态;不伪造官方发布版本或自动更新来源。
3.2 自定义
通用设置和 Key 独立配置共用一套编辑模型:选择预设后,可以调整客户端标识、系统版本、 架构、终端及适用的版本字段,并预览最终请求身份。
- 首期将自定义内容保存在对应通用设置或 Key 中;命名模板库、共享模板引用及模板管理不属于本次范围。
- 后端按客户端类型生成 UA 与相关身份头;不增加任意请求头透传或任意发布源 URL 配置。
- 校验必填项、字段长度、HTTP 头合法性、控制字符及客户端类型对应的版本格式。
- Desktop 与 CLI 使用各自适用的字段;CLI 不携带由 Desktop 默认值遗留的应用版本后缀。
- 自定义值与「官方核验」状态分别展示,用户填写的值不能自行获得官方核验标记。
- 认证信息、账号 ID、Cookie、请求位置及数据驻留仍由现有职责管理,不纳入身份自定义。
3.3 自动最新与固定版本
| 模式 | 行为 |
|---|---|
| 自动最新(默认) | 跟随该客户端、平台及适用架构对应的最新已核验稳定发布;后台更新,不在业务请求中访问发布源 |
| 固定版本 | 使用保存的版本;后台发布检查不能覆盖固定值 |
自动最新只更新版本资料,不覆盖用户的平台、架构、终端等选择。手动修改版本时转为固定版本, 避免保存后又被后台任务覆盖。恢复自动最新后,重新采用对应发布源的有效版本。
- Desktop 应用版本、内嵌 Core 版本和构建号作为同一制品的完整元组更新;不拼接独立 CLI 的最新版本。
- CLI 使用对应官方 CLI 发布信息,不借用 Desktop 发布号。
- 不假设不同平台的 Desktop 同步发布或共享构建号。
- 更新失败保留同一预设上次成功的版本,并展示检查失败及检查时间;不得切到其他平台或客户端。
- 首次离线启动可使用同一预设随版本附带的已核验版本资料,并标明未完成最新检查。 这些资料属于版本解析器的种子数据,不是第三层用户配置。
- 没有有效发布源或启动资料的组合不能进入可用的「自动最新」状态;提供原因与固定自定义入口。
- Redis 中的发布缓存至少区分客户端类型、平台和影响制品选择的架构,不再仅凭 Provider 区分。 缓存失效和重启后的恢复也不得覆盖用户的固定配置。
4. 配置合同与职责
4.1 持久化与管理 API
拟增加的概念字段如下,最终名称在实施时与现有 API 风格统一:
| 位置 | 字段 | 语义 |
|---|---|---|
| 通用设置 | openaiClientProfile |
必须存在的完整配置选择,包含预设或自定义参数、版本模式 |
| Client Key | openaiClientProfileOverride |
null 表示跟随通用设置;对象表示完整独立配置 |
| 只读投影 | effectiveOpenaiClientProfile |
返回当前解析结果、配置来源、版本来源及检查状态,不作为另一份可写配置 |
新建 Key 省略覆盖字段等同于 null;更新 Key 省略字段保留已有覆盖,显式 null 才清除。
旧调用方更新通用设置时省略新增字段,应保留现值,不能重置管理员已保存的选择。
通用设置不接受以 null 制造第三层回退的语义。
配置由 PostgreSQL 保存。管理写入沿用现有事务、脱敏审计、revision 和快照发布流程。 官方发布结果继续作为 Provider 的派生缓存,不将每次版本检查写成用户配置或推进全局配置 revision。
职责依照 系统架构:
- Admin 负责全局与 Key 的管理规则和继承选择,复用同一解析入口生成生效投影。
- Core 负责请求策略的携带与冻结,不依赖具体 Provider,也不解释 UA、官方制品或请求头。
- OpenAI Provider 负责预设、官方版本解析、字段语义校验及上游头部生成,通过现有端口风格提供能力。
- Store 实现配置、迁移与缓存存取,不解释客户端身份的业务规则。
- API 负责 wire 校验及投影,前端负责编辑与展示,不重复推导最终身份。
4.2 生效范围
本次配置作用于 OpenAI Provider。Key 同时授权其他 Provider 时,不把 OpenAI 身份套用到 xAI。
由 Client Key 发起的 OpenAI 模型请求及其相关目录读取,消费该 Key 的有效身份; HTTP/SSE、WebSocket 以及 Images、Search 等入口按实际调用链逐一核对覆盖。 OAuth 与 API Key 上游认证模式继续共用适用的身份规则,认证字段仍按各自协议生成。
后台令牌刷新、额度查询、账号管理及 Desktop 专属接口没有 Client Key 上下文,不能被某个 Key 的选择污染。 实施时按官方接口要求划分共用身份与 Desktop 专属身份,保留必要的独立请求格式; 全局选为 CLI 时也不能让 Desktop 专属接口意外携带缺失或错误的应用版本。
4.3 请求一致性与资源隔离
本节以接入现有机制为主。当前鉴权已持有 RuntimeSnapshot,重试通过原路由计划传递冻结策略;
WebSocket 连接池已将 originator、user-agent 等纳入连接身份,且已有
画像更新后保留精确续写所属连接的测试。
实施沿用这些快照、重试和续写机制,补齐新增配置的数据传递与必要隔离维度。
- 将通用与 Key 的身份选择接入已有配置快照,沿现有请求上下文传入 Provider, 同一逻辑请求的重试与换号继续使用冻结的选择。
- 自动发布版本目前属于 Provider 的共享运行时画像,
response_headers在组装头部时读取self.profile.snapshot(),尚未由RuntimeSnapshot冻结。 为满足跨重试也使用同一解析版本的目标,在已有请求生命周期内保存首次解析结果并复用; 这部分与用户配置的快照继承分别验证,不改动重试决策和状态机。 - 禁止通过临时修改共享
CodexWireProfileState实现 Key 覆盖;并发 Key 使用独立的不可变请求身份。 - 同一入站 WebSocket 的每个
response.create按现有规则获取新策略。 普通连接获取复用现有身份匹配规则;精确续写继续使用持有响应状态的原连接, 保留已有的画像更新例外,不能因版本刷新强制断开或重建这类连接。 - 检查新增字段是否已被现有连接身份和模型目录缓存键覆盖,仅补齐影响协议结果的缺失维度。 Key 授权边界沿用现有机制;身份切换继续遵循原有续写和重放限制,避免上下文丢失或越界重放。
- 「当前生效」投影显示解析结果;请求观测使用本次冻结的摘要,不能事后用最新全局值替代。
5. 管理端交互
通用设置
新增「上游客户端身份」配置区,包含平台、客户端类型、预设/自定义、版本策略以及相应字段。 默认展示 macOS Desktop 自动最新;提供最终 UA、相关版本、发布检查状态及字段错误提示。 保存后通过现有设置发布机制对新请求生效,无需重启。
Key 创建与编辑
默认选择「跟随通用设置」,同时展示当前通用配置摘要。 选择「独立配置」后使用与通用设置相同的编辑组件;首次切换可用当前通用值填充表单草稿, 只有保存后才形成独立配置。摘要明确标出「通用设置」或「Key 独立配置」。
现有展示
首页身份卡片标明展示的是通用配置,不将其描述成所有 Key 的唯一身份。 Key 详情展示该 Key 当前有效身份;复用后端投影,不在浏览器拼装 UA 或解析版本。 复用现有基础组件及 管理端主题,提供保存失败、版本检查失败、无可用发布源等状态。
6. 升级与迁移
- 按 迁移规则 新增编号迁移,更新冻结清单,不修改历史迁移。
- 新安装在初始化阶段写入通用默认配置;存量 Key 的覆盖初始化为
null。 - 升级需识别既有
openai.wire_profile自定义值,首次导入通用配置时保留有效的环境与身份选择。 标准配置映射到 macOS Desktop 自动最新;显式自定义版本映射到固定自定义,并在升级说明交代。 - SQL 迁移不负责读取部署文件;必要的一次性导入由启动组装流程经正式管理/存储端口完成, 在设置尚未初始化时原子写入。初始化标记避免重启或更新重新覆盖数据库中的设置。
- 实施前核实配置加载器能否区分显式自定义与默认填充值,必要时在加载阶段保留该来源信息。
- 初始化完成后,相关用户选择以数据库为唯一权威;清理旧配置的运行时覆盖路径并同步配置样例。 其他仍有效的 Provider 配置字段继续归原 owner 管理。
- 备份与恢复包含通用配置和 Key 覆盖;发布缓存仍可重建,不成为配置恢复的前置依赖。
7. 实施顺序
- 核对官方依据与接口范围。 完成六个组合的来源矩阵,明确可自动更新的组合、 Desktop 专属接口、CLI 格式及旧配置来源识别方式,记录无法核验的项目。
- 定义合同并打通持久化。 确定完整配置对象、继承语义及只读投影;实现新增迁移、 一次性初始化、设置与 Key 管理 API,复用审计和快照发布。
- 扩展 Provider 解析。 复用现有 Desktop 版本核验,补充 CLI 及平台来源、固定版本、 自定义校验和分维度缓存;确保官方资料与用户配置分别存储。
- 接入实际请求链路。 复用现有快照与请求上下文携带有效选择,补齐解析版本的请求级复用, 覆盖相关传输与目录入口;复用连接池身份匹配与精确续写规则,仅补齐必要的隔离维度。
- 实现设置与 Key 界面。 复用一套编辑组件和服务端投影,调整首页身份卡片含义, 完成浏览器交互验收。
- 验证并同步正式文档。 完成下列矩阵;在行为可用后就地更新 API、架构、部署和用户入口的必要说明, 不提前将本计划中的拟定合同写成已发布能力。
8. 验收条件
| 范围 | 必须覆盖的场景与结果 |
|---|---|
| 默认与继承 | 新安装采用约定默认;新旧 Key 跟随;通用修改只影响跟随者;独立配置不受影响;显式清除后恢复继承 |
| API 更新语义 | 省略覆盖字段保留原值,显式 null 清除;旧设置调用不重置新配置;非法配置不留下部分提交 |
| 预设与自定义 | 六个组合均有明确支持状态;已核验预设与对应官方证据一致;自定义可保存、重启恢复并生成合法头部 |
| 版本解析 | 自动最新按来源更新;固定值不被刷新;Desktop 元组一致;检查失败保留同组合旧版本;无来源状态如实显示 |
| 并发与冻结 | 两个不同配置的 Key 并发请求不串用身份;配置或发布刷新期间,已开始请求及其重试保持一致 |
| 上游传输 | 在可用的真实测试环境检查 HTTP/SSE、WebSocket 及受影响接口发出的身份与结果;API Key 认证不混入 OAuth 字段 |
| 缓存与续写 | 不同有效身份不误用目录结果或连接;配置切换后的新请求应用新身份;旧 continuation 无上下文丢失或越界重放 |
| 管理与后台 | Key 覆盖不影响其他 Key、后台任务及 Desktop 专属操作;全局 CLI 与混合 Provider 授权场景可用 |
| 升级与恢复 | 标准配置、自定义配置、重复启动、数据库备份恢复和发布缓存缺失均按约定处理;历史迁移校验不变 |
| 界面 | 创建/编辑/清除覆盖、保存与加载失败、自动与固定切换、来源及核验状态正确;检查窄屏、深浅色和键盘操作 |
后端补充能验证上述真实行为的用例,按 贡献与审查 和 架构验收入口 执行适用的 Rustfmt、Clippy、测试、架构边界与迁移检查。 数据库与 Redis 使用专用测试实例,因环境缺失跳过的测试明确记录为缺口。
前端执行 pnpm --dir frontend format:check、pnpm --dir frontend build,并提供实际浏览器运行证据;
不为本功能引入项目当前不维护的独立前端测试体系。所有变更执行 git diff --check。
构建、单元测试或模拟上游通过不能替代真实协议验收;测试账号和上游环境不足时列明未覆盖组合。
9. 已核对的官方依据与实现边界
- CLI UA 与 originator:官方
openai/codex提交4d205c7a4dc36b719679a0356a45b23133732265,codex-rs/login/src/auth/default_client.rs。CLI 不添加 Desktop 应用后缀。 - CLI 版本:
https://registry.npmjs.org/@openai%2Fcodex/latest,2026-09-18 返回0.155.0, darwin/linux/win32 × arm64/x64 的依赖版本均配套。实现验证包名、稳定 SemVer 和六个依赖,逐制品缓存。 - macOS Desktop:沿用官方 appcast 与同一 ZIP 的内嵌 Core 核验路径,支持 arm64。
- Windows Desktop:分别读取官方
ChatGPT-x64.msix、ChatGPT-arm64.msix,从app.asar/package.json获取应用版本和构建号,从同包codex.exe核验架构和 Core 版本;MSIX 清单版本不作为应用版本。 - Linux Desktop:依据官方安装说明,分别读取 amd64/arm64 DEB,
按 XZ 索引跳读 tar,核验同包
app.asar/package.json与 ELF Core。Windows/Linux 的 Range 请求锁定 ETag, 未变更时只检查一个字节,变更后完整核验版本元组;独立缓存、检查失败保留已核验版本。
身份预览采用独立只读接口,由后端解析全局或所提交的完整覆盖;Key 列表保存并返回覆盖配置, 编辑器按预览结果显示当前生效身份,不在前端生成 UA。
10. 本地验收记录
2026-09-18,独立 PostgreSQL 18、Redis 8 与 127.0.0.1:28080 测试实例,使用合成账号与 Key。
RUST_MIN_STACK=16777216 cargo +1.97.0 test --manifest-path backend/Cargo.toml --test main --locked全部 9 个测试套件通过,合计 2420 项,PostgreSQL/Redis 使用上述专用实例。 覆盖配置继承、首次导入、旧调用保留字段、清除覆盖、跨重试版本冻结、并发请求身份隔离、制品缓存隔离, 以及 Windows/Linux 归档解析、架构不符、损坏/截断、ETag 变化、XZ 跨块跳读和发布回退。cargo +1.97.0 fmt --all --manifest-path backend/Cargo.toml -- --check、严格 Clippy(所有 target/feature)通过。pnpm --dir frontend format:check、pnpm --dir frontend build、git diff --check通过。backend/migrations/.frozen-sha256全部校验通过,历史迁移未修改。- Chrome 实测通用设置切换并保存 Linux CLI、创建默认继承的 Key、保存 Windows CLI 固定版本覆盖、 重载回显与清除覆盖后恢复继承;检查 1920 px 与 390 px、深浅色、Key 弹窗和键盘关闭下拉框。 新增表单宽度与相邻设置对齐,文案仅保留短标签与必要状态,浏览器无错误或警告。
- Chrome 实测 Windows/Linux Desktop 自动模式与各自 UA,Windows 保存后重载回显;验收后恢复原 MacOS Desktop 通用配置。
下拉显示
MacOS,内部枚举仍为macos,UA 的系统类型仍为Mac OS。 - 官方发布检查实际成功:macOS Desktop
26.915.31029/ Core0.155.0-alpha.9,CLI0.155.0。 Windows 两种架构为 Desktop26.908.70816/ Core0.154.0-alpha.6.2/ Build9275; Linux 两种架构为 Desktop26.915.31029/ Core0.155.0-alpha.9/ Build9771。 四个官方包首次核验耗时约 17~30 秒,重复检查约 67~74 毫秒,未重新扫描制品。 cargo audit --file backend/Cargo.lock未通过:已有固定依赖rustls 0.23.36命中RUSTSEC-2026-0285,另有原有chacha20、wnaf撤回警告;新增归档依赖未报告漏洞。 本次未改变受官方 TLS 指纹约束的依赖版本。
验证边界:没有真实上游账号,真实认证下的 HTTP/SSE、WebSocket、Images/Search 未进行端到端验收; 本地传输测试不能替代该验收。Windows/Linux Desktop 的 x86_64、arm64 官方制品解析和未变化复用均已实测,真实账号请求仍未覆盖。 完整备份恢复、生产部署环境及发布源故障下的界面交互尚未实测。