# Context

当前桌面端实际上有两条**不能混用**的配置链路：

1. **项目 zip / 项目侧链路**：客户端会用员工密钥请求 `openclaw-employee-config`。这条链路服务的是项目包 / 项目运行时相关配置，不是客户端 model 设置来源。
2. **客户端设置链路**：客户端自己的 model 配置必须在设置页里单独绑定与保存。

但 `workspace` 下的小红书 / 抖音项目仍有多处模型写死：文案、生图、生视频分别在各自脚本里使用默认模型或启发式回退；同时客户端设置页虽然已经有部分 expert 配置能力，但没有完整的“客户端模型配置 UI / 消费链路”。因此现在的问题不是简单复用 employee config，而是要把**客户端设置**与**项目模型消费方**真正打通。

目标是把客户端设置页作为唯一入口：

- 客户端 model 配置在设置页绑定、保存、回读
- 主进程负责把这份客户端设置下发到项目执行链路
- `workspace` 只消费客户端下发的解析结果，不再各自维护散落的硬编码默认模型

# Recommended approach

## 1. 以现有 `expertModelConfig` 为中心扩展，不新建第二套模型配置对象

优先复用现有设置保存链路，而不是再加一个独立的 `clientModelConfig`：

- 现有结构已经覆盖三类能力：`copywriting` / `image` / `video`
- UI、IPC、配置持久化已经能保存这三类 expert 配置
- 只需在每一项上补充 `modelId`（必要时补 `modelDisplayName` 仅用于展示）

建议目标结构：

- `expertModelConfig.copywriting = { baseUrl, apiKey, modelId }`
- `expertModelConfig.image = { baseUrl, apiKey, modelId }`
- `expertModelConfig.video = { baseUrl, apiKey, modelId }`

员工密钥仍保留在顶层 `apiKey`，但它只用于项目 zip / 项目侧链路，不作为客户端 model 配置来源。

## 2. 主进程统一做“客户端设置 -> 项目执行”的模型归一化

由桌面端主进程统一决定最终生效配置，优先级建议统一为：

1. 用户在设置页显式填写的 `modelId`
2. 对应 capability 的本地 `baseUrl` / `apiKey`
3. 现有脚本里的历史回退值（过渡期保留）

这里**不再把 `openclaw-employee-config` 当成客户端 model 默认值来源**。它继续服务项目 zip / 项目侧配置，但客户端模型选择完全来自设置页。

主进程需要输出一份**归一化后的运行时模型配置**，再注入到项目执行链路。不要让 `workspace` 内各脚本继续各自解析一套默认值。

## 3. `workspace` 只消费归一化结果，先兼容旧环境变量，再逐步去硬编码

XHS 和 Douyin 都先改成“优先读主进程传入配置，其次兼容现有 env，最后才走历史默认值”。这样可以分阶段上线，不需要一次性把所有旧分支删掉。

## 4. 首期范围只统一“模型选择”，不扩大到所有生成参数

首期重点打通：

- 客户端聊天 / 文案模型
- 生图模型
- 生视频模型

像 `IMAGE_SIZE`、`IMAGE_COUNT`、风格 prompt、Seedance 分辨率/比例、OmniHuman TTS voice 这类“生成参数默认值”暂不并入设置页，避免范围膨胀。它们可以先维持原样，等模型配置链路稳定后再考虑二期治理。

# Files to modify

## Desktop shared types / UI / main process

### `D:\qjclaw\packages\shared-types\src\index.ts`
- 扩展 `AppConfig` / `SaveConfigInput` 中 `expertModelConfig` 的类型定义，给 image / video / copywriting 增加 `modelId`
- 确认 `WorkspaceSummary` / 其他摘要结构是否需要暴露 capability 级别模型信息给 UI

### `D:\qjclaw\apps\ui\src\App.tsx`
- 设置页已有保存 `expertModelConfig` 的状态与 `saveConfig()` 链路，需补三类 `modelId` 的 UI 输入与本地 state
- 现有 `saveConfig()` 已会提交 `expertModelConfig`，应在此基础上把 `modelId` 一并提交
- 当前没有“客户端模型配置 UI”，这里是主要补齐点

### `D:\qjclaw\apps\desktop\src\main\ipc.ts`
- 确认 `config.save`、`workspace.getSummary`、项目执行请求构建处是否需要增加 capability 级模型透传
- 将主进程解析后的模型配置送入项目执行链路，而不是只用于聊天模型

### `D:\qjclaw\apps\desktop\src\main\services\cloud-api.ts`
- 继续保留 `openclaw-employee-config` 的现有职责，但不要把它作为客户端 model 默认值来源
- 仅检查是否有现有逻辑误把 employee config 的 `model_id` 当成客户端聊天模型默认值；如果有，需要与新的本地设置优先级重新梳理

## Workspace — XHS

### `D:\qjclaw\workspace\xhs\scripts\qwen.py`
当前热点：
- `ARK_TEXT_MODEL` 最终回退到 `qwen-plus`
- `ARK_VISION_MODEL` 与 provider 选择依赖启发式逻辑

需要改为：
- 先读归一化后的 copywriting / vision 配置
- 再兼容现有 `ARK_*` / `QWEN_*`
- 最后才回退历史默认值

### `D:\qjclaw\workspace\xhs\scripts\run.py`
当前热点：
- `XHS_IMAGE_MODEL` / provider 选择启发式
- `_candidate_image_provider_names()` / `_pick_image_model_id()` / `IMAGE_MODEL`

需要改为：
- 生图优先读主进程解析后的 image `modelId`
- 减少按 provider 名称、模型名猜测能力的逻辑作为主路径

### `D:\qjclaw\workspace\xhs\index.ts`
- 如果工具描述里仍写死固定模型品牌，需要同步去掉，以免 UI/文案与真实配置不一致

## Workspace — Douyin

### `D:\qjclaw\workspace\douyin\skills\douyin-master\scripts\coordinator.py`
当前热点：
- `writer_model: "qwen3-plus"`
- CLI 默认又是 `qwen3.5-plus`
- 统一编排入口却仍注入写死默认值

需要改为：
- coordinator 统一从客户端下发的归一化配置读取 copywriting / image / video 默认模型
- CLI 参数保留最高优先级覆盖

### `D:\qjclaw\workspace\douyin\skills\douyin-writer\scripts\generator.py`
当前热点：
- `llm_model="qwen3.5-plus"`
- `--llm-model` 默认值仍是硬编码

需要改为：
- 优先消费主进程注入配置
- 保留 CLI / env 兼容
- 最后才落到历史默认值

### `D:\qjclaw\workspace\douyin\skills\douyin-seedance-split\scripts\run_pipeline.py`
当前热点：
- `--llm-model default="qwen3-plus"`
- 与 coordinator / writer 存在重复默认值

需要改为：
- 统一走与 coordinator 相同的配置优先级
- 不再维护第二套 copywriting / image / video 默认模型

### `D:\qjclaw\workspace\douyin\skills\seedream-image-generator\scripts\run_seedream.py`
当前热点：
- `doubao-seedream-4-0-250828` 写死回退

需要改为：
- 优先读客户端设置中的 image `modelId`
- 再兼容 `SEEDREAM_MODEL`
- 最后才保留历史默认值兜底

### `D:\qjclaw\workspace\douyin\skills\seedance-2-0-video-generator\scripts\run_seedance.py`
当前热点：
- `doubao-seedance-2-0-260128` 写死回退

需要改为：
- 优先读客户端设置中的 video `modelId`
- 再兼容 `SEEDANCE_MODEL`
- 最后才保留历史默认值兜底

# Scope and impact

## 明确会动到的范围

1. **桌面端设置模型**
   - shared types
   - settings UI
   - config save/load
   - 主进程模型归一化逻辑

2. **客户端到项目的配置传递链路**
   - config save -> main process -> project execution handoff
   - env 注入 / runtime handoff
   - 项目执行入口

3. **项目侧消费方**
   - XHS 文案 / 视觉 / 生图
   - Douyin 文案 / 生图 / 生视频

## 暂不建议纳入首期的范围

- employee config 接口协议扩展
- 生图尺寸、张数、风格词等生成参数
- Seedance ratio / resolution / audio / watermark 等非模型参数
- Omnihuman TTS voice 等与模型配置不同层级的运行参数
- 全量重构为新的统一 Python 配置库

# Risks

## 1. 现有保存配置缺少 `modelId`，需要平滑兼容
老配置里只有 `baseUrl` / `apiKey`。新增字段后，读取逻辑必须允许 `modelId` 为空；空值应解释为“继续走旧逻辑 / 历史默认值”，不能当成清空。

## 2. 需要把“客户端设置”和“employee config”职责彻底分开
当前部分链路已经会把 employee config 的 `modelId` 暴露到 `WorkspaceSummary` / 运行时配置里。如果后续又把它当客户端 model 默认值，就会重新混淆两条链路。首期要明确：
- employee config：项目 zip / 项目侧
- settings model config：客户端与项目模型选择

## 3. XHS / Douyin 各脚本仍依赖旧 env 名称
现有项目脚本散落读取：
- `ARK_*`
- `QWEN_*`
- `XHS_IMAGE_*`
- `SEEDREAM_*`
- `SEEDANCE_*`

如果主进程不继续注入这些兼容 env，首轮改动容易断链。建议首期保留旧 env 兼容层。

## 4. Douyin 内部默认值不一致，统一后可能改变历史行为
Douyin 当前同一能力存在 `qwen3-plus` / `qwen3.5-plus` 两套默认值。统一后会暴露出行为变化，需要明确“谁是最终默认值来源”。建议以后统一以：
- 用户设置
- 单一保底默认值

两层为准。

## 5. XHS 当前部分逻辑依赖模型能力猜测
例如按 provider 名称或 model id token 推测是不是视觉/生图模型。切到显式 `modelId` 后，这些猜测逻辑可能与新配置冲突。首期应改成“显式配置优先，启发式仅兜底”。

## 6. 调试复杂度会上升，必须增加可观测性
链路变成“设置页 -> 主进程归一化 -> runtime 注入 -> workspace 消费”后，如果没有清晰日志，很难判断最终生效的是哪一层。建议在主进程和项目入口增加脱敏后的 resolved-config 调试输出。

# Verification

## 1. 设置保存与回读
- 在设置页填写：copywriting/image/video 的 `baseUrl`、`apiKey`、`modelId`
- 保存后确认：
  - UI 能正确回显保存值
  - 老配置文件可正常升级加载
  - 未填写 `modelId` 的旧配置不报错

## 2. 主进程归一化
- 不依赖 `openclaw-employee-config`，直接验证本地 settings 保存后的 resolved model config
- 验证优先级：
  - settings 中显式 `modelId`
  - 对应 capability 的 `baseUrl` / `apiKey`
  - 历史回退值

## 3. 主进程到项目执行链路
- 在项目启动/执行前检查归一化后的 resolved model config
- 验证 XHS / Douyin 拿到的是同一套解析后的 capability 配置
- 验证旧 env 兼容字段仍被正确注入

## 4. XHS 端到端
- 文案/分析链路：确认 `xhs/scripts/qwen.py` 不再优先落到 `qwen-plus`
- 视觉分析链路：确认 `ARK_VISION_MODEL` 来源于客户端设置下发配置
- 生图链路：确认 `xhs/scripts/run.py` 使用 settings 中的 image `modelId`，而不是 provider heuristics

## 5. Douyin 端到端
- 文案生成：确认 `douyin-writer/scripts/generator.py` 使用统一后的 copywriting `modelId`
- Seedream 生图：确认 `run_seedream.py` 使用 settings 中的 image `modelId`
- Seedance 生视频：确认 `run_seedance.py` 使用 settings 中的 video `modelId`
- split pipeline：确认 `run_pipeline.py` 与 coordinator 使用同一套默认模型来源，不再各自写死

## 6. 回归测试
- 未填写任何 capability `modelId` 时，旧项目仍可执行
- 仅配置 copywriting 时，不影响 image/video
- 仅配置 image/video 时，不影响其他能力
- 保存空白 apiKey 字段时，不会误清除已有 capability 密钥

# Recommended execution order

1. 扩展 shared types 与 settings UI，补齐 `modelId` 保存能力
2. 在主进程建立统一的 resolved model config
3. 先接 Douyin：因为硬编码更多、收益最明显
4. 再接 XHS：收敛 `qwen.py` 与 `run.py`
5. 最后清理工具描述、日志与 smoke 测试

