8.8 KiB
8.8 KiB
| id | name | status | progress |
|---|---|---|---|
| codex-model-switch | Codex 模型切换 | planned | 0 |
概述
在 DeepSeek 与官方模型之间安全切换 Codex 的模型提供方,并管理 DeepSeek API Key。
炼境侧只读:展示当前档位、Key 提示、冲突告警,所有写入动作转发给独立二进制 codex-switch 执行。
决策记录
- 写入职责不放炼境:
claude-autonomy-config已立下规则「炼境只读,不写第三方工具配置,避免意外覆盖用户的 settings.json」。模型切换必须写~/.codex/config.toml,若放进炼境核心就与该规则直接冲突。故写入交给独立 CLI,炼境只做展示与转发。 - 不引入插件系统:炼境「工具」页(
ToolsPage.tsx)本就是「低频独立页合并为 tabs」的容器,v2rayn-import、devtools-scan已确立「感知宿主开发工具状态」这一模块族。新需求是该族成员,加一个 tab 即可,无需先造扩展机制。 - Key 归 CLI 管理,落炼境 SQLite:写配置的是 CLI,密钥就该在写入方一侧,否则 CLI 独立使用时没有密钥来源。炼境因此不新增数据表,也不接触 DeepSeek 明文密钥。
- 只物化一处:Key 只写
[model_providers.deepseek].experimental_bearer_token,并停止向[shell_environment_policy.set]写DEEPSEEK_API_KEY。现状两处值不一致(sk-599a66…vssk-c12beb…)正源于此。
设计决策:Codex 模型切换工具
背景
- 关联现有模块:
devtools-scan(宿主开发工具扫描)、wsl-proxy(第三方工具配置同步)、claude-autonomy-config(外部 AI CLI 配置只读展示先例)、api-keys(密钥保管,职责不同不复用存储) - 现状事实:
~/.codex/config.toml已被 DeepSeek 官方脚本改写(model = "deepseek-flash"、model_provider = "deepseek");[model_providers.code-switch]由 cc-studio 托管且处于disabled_alias;DeepSeek Key 同时存在于 provider 段与shell_environment_policy.set两处且值不同 - 用户痛点:官方脚本是一次性安装器(只有「装 flash / 装 v4-pro / 恢复到安装前」),无状态查询、无 Key 体检、无失败回滚
方案选择
| 方案 | 说明 | 结论 |
|---|---|---|
| A 纯炼境内置模块 | Rust 直接写 config.toml |
否决:违反 claude-autonomy-config 既有规则,且炼境承担第三方配置写坏的责任 |
| B 独立 CLI + 炼境只读面板 | CLI 拥有写入与密钥;炼境只读探测 + 转发 | 选定 |
| C 完整插件系统 | 先定义 manifest / 发现 / 生命周期 | 否决:当前仅一个候选插件,属过度设计 |
受影响文件
新增:
src-tauri/src/commands/codex_switch.rs— 只读探测 Codex 配置状态 + 定位并调用codex-switchCLIsrc/components/tools/CodexSwitchPanel.tsx— 工具页面板
修改:
src-tauri/src/commands/mod.rs— 声明pub mod codex_switchsrc-tauri/src/lib.rs— 注册 command(静态 invoke_handler)src/lib/commands.ts— 前端封装(AGENTS.md 硬约定:新增 command 必须同步)src/components/tools/ToolsPage.tsx— 新增codextab
同仓库内(独立子项目,自带 Cargo workspace,不纳入 src-tauri 构建):
codex-switch/crates/core— 纯逻辑:detect / config_edit / catalog / secret / verify / backupcodex-switch/crates/cli— 命令入口:status / preview / switch / undo / set-key / doctor
系统边界变更
- 不新增数据表(Key 归 CLI,炼境不落密钥)
- 新增 Tauri command:
get_codex_switch_status() -> CodexSwitchStatus— 只读;含当前档位、provider、Key hint(脱敏)、CLI 是否已安装、cc-studio 冲突、残留旧条目run_codex_switch_action(action, target?) -> ActionResult— 转发给 CLI,回传 stdout/stderr 与退出码
- CLI 契约(炼境与 CLI 之间的稳定接口):
codex-switch status --jsoncodex-switch preview --to <target> --jsoncodex-switch switch --to <target>codex-switch undocodex-switch set-key --stdincodex-switch doctor --json
风险点
- cc-studio 同时托管
model_provider/preferred_auth_method/model_providers.code-switch:写入会互相覆盖 → CLI preflight 检测托管文件,拒绝静默覆盖并告警 - CLI 未安装:面板降级为「未安装 + 获取引导」,不报错
- 配置被 CLI 改写后面板缓存陈旧 → 每次进入面板重新探测,不做前端缓存
- 二进制分发:CLI 需随炼境打包(Tauri xternalBin)或落 PATH。P0 阶段先按「PATH 查找 + 可配置路径」实现,打包留到发布前处理
toml_edit对含大量手写内容的config.toml格式保真:非拥有字段在写入前后做哈希断言,并补 fixture 回归测试- 切换 provider 后历史会话按登录方式分组隐藏(官方文档已说明):必须由面板显式提示,否则新手误判为数据丢失
拆解建议
建议拆为 5 张任务卡,依赖顺序:
- core 骨架(M)—
codex-switch/crates/core:detect + config_edit(toml_edit)+ backup - CLI 切换(M)— 依赖 1:status / preview / switch / undo
- CLI 密钥与体检(M)— 依赖 2:set-key(凭据管理器)+ doctor 连通性验证
- 炼境只读探测与转发(M)— 依赖 2 的 CLI 契约:
codex_switch.rs+commands.ts - 炼境工具页面板(M)— 依赖 4:
ToolsPage新增 tab + 面板 UI + 新手护栏文案
任务卡
codex-switch/指炼境仓库内的独立子目录,自带 Cargo workspace,不并入src-tauri的构建(对炼境现有编译零影响)。
📋 core:配置探测与精细改写骨架
- status: todo
- complexity: M
- files: codex-switch/crates/core/Cargo.toml, codex-switch/crates/core/src/lib.rs, codex-switch/crates/core/src/detect.rs, codex-switch/crates/core/src/config_edit.rs, codex-switch/crates/core/src/backup.rs, codex-switch/crates/core/tests/fixtures/config.toml
- acceptance: 对 fixture 执行档位切换后,非拥有字段(mcp_servers / plugins / projects / notify / shell_environment_policy)逐字节不变;config.toml 解析失败时中止且零文件修改;备份可原样还原
核心 crate 不得依赖 Tauri。config_edit 用 toml_edit 保留注释与字段顺序,写入走临时文件 + 同目录原子 rename。
📋 CLI:status / preview / switch / undo
- status: todo
- complexity: M
- files: codex-switch/crates/cli/Cargo.toml, codex-switch/crates/cli/src/main.rs, codex-switch/crates/cli/src/commands/status.rs, codex-switch/crates/cli/src/commands/preview.rs, codex-switch/crates/cli/src/commands/switch.rs, codex-switch/crates/cli/src/commands/undo.rs
- depends: core:配置探测与精细改写骨架
- acceptance:
status --json报出当前档位与 provider;switch --to official与switch --to deepseek-flash可往返切换;undo回到上一状态;preview --to X --json输出字段级 diff 且不含明文密钥
📋 CLI:密钥托管与连通性体检
- status: todo
- complexity: M
- files: codex-switch/crates/core/src/secret.rs, codex-switch/crates/cli/src/commands/set_key.rs, codex-switch/crates/cli/src/commands/doctor.rs
- depends: CLI:status / preview / switch / undo
- acceptance:
set-key --stdin后密钥只物化到[model_providers.deepseek].experimental_bearer_token一处,且不再写入环境变量段;任何输出与日志中只出现sk-+ 前 6 + … + 后 4;doctor --json能区分 Key 无效 / 限流 / 网络不通 / 模型名不存在
密钥存系统凭据管理器;set-key 接受 stdout 管道输入,不接受命令行明文参数。
🔵 炼境:只读探测与 CLI 转发
- status: in_progress
- complexity: M
- files: src-tauri/src/commands/codex_switch.rs, src-tauri/src/commands/mod.rs, src-tauri/src/lib.rs, src/lib/commands.ts
- depends: CLI:status / preview / switch / undo
- acceptance:
get_codex_switch_status返回当前档位 / provider / 脱敏 Key hint / CLI 是否已安装 / cc-studio 托管冲突 / 旧条目残留;run_codex_switch_action转发 CLI 并回传 stdout、stderr 与退出码;全流程炼境不写入任何 Codex 配置文件
CLI 调用统一走 crate::silent_cmd(Windows 隐藏窗口)。新增 command 必须同步 src/lib/commands.ts。
📋 炼境:工具页面板与新手护栏
- status: todo
- complexity: M
- files: src/components/tools/CodexSwitchPanel.tsx, src/components/tools/ToolsPage.tsx
- depends: 炼境:只读探测与 CLI 转发
- acceptance: 「工具」页新增 Codex 模型切换 tab;CLI 未安装时显示获取引导而非报错;切换成功后提示「历史会话按登录方式分组、未删除」与「桌面端需重启」;检测到 cc-studio 托管时给出告警
面板所有写入动作经确认弹窗后转发 CLI;每次进入面板重新探测,不做前端缓存。