Files
zcode-tooling/zcode-thinking-mode/README.md
T

114 lines
6.0 KiB
Markdown

# zcode-thinking-mode
思考模式切换插件:查看/切换 ZCode 模型配置里的思考强度档位(`reasoning.defaultVariant`:low / max / high)。
## 命令
| 命令 | 作用 |
|---|---|
| `/thinking` | 不带参数=看现状;带 `low\|max\|high`=直接切换 |
| `/thinking:status` | 看各模型的当前默认档位与可选档位 |
| `/thinking:set <档位> [--model 模型名] [--hot-only\|--persist-only]` | 切换档位;不加 `--model` 则改全部带 reasoning 的模型 |
| `/thinking:history` | 看切换历史(时间/旧值→新值/分写标记/备份) |
| `/thinking:rollback [--steps N]` | 回滚到上次切换之前(热档位与持久默认都写回去) |
| `/thinking:defaults [set\|clear]` | 默认档位/默认模型(不带参数时 `set` 用哪档、`status` 看哪个模型) |
| `/thinking:doctor` | 自检:为什么切不了(只读,不改任何东西) |
示例:
```
/thinking:status
/thinking:set high
/thinking:set low --model GLM-5.3-Flash
/thinking:set high --hot-only --model GLM-5.3-Flash # 只写热档位,不碰模型配置
/thinking:set low --persist-only # 只写模型配置,不碰热档位
/thinking:history
/thinking:rollback
/thinking:defaults set --variant high --model GLM-5.3
/thinking:doctor
```
## 原理(双写:热 + 持久)
1. session 库 `~/.zcode/cli/db/db.sqlite` → `local_setting(user/default/model/reasoningLevel)`—— 全局**热档位**,新会话/新 turn 直接按它解析,内置 `/effort` 切的也是这一格。
2. `~/.zcode/v2/config.json` 各模型 `reasoning.defaultVariant` —— 模型配置里的**持久默认**。
3. v2/config 写前自动备份(`config.json.bak-<时间戳>`,同秒撞名补 `.1`/`.2`);sqlite 单格 upsert,旧值会打印。
4. 切换历史 `~/.zcode/zcode-thinking-mode-state.json`(`ZCODE_THINKING_STATE` 可改路径)—— 每次 `set` 成功追加一条(旧热值/持久旧值/分写标记/备份路径,保留最近 50 条);`rollback` 按最新一条把两边写回去,不删历史。
生效:新会话直接按新档位;**当前这轮会话要立刻生效,再敲一行内置命令 `/effort <档位>`**(热切,不重启)。
## 默认值(为什么需要落地文件)
`plugin.json` 的 `userConfig`(设置 → 插件详情 → Advanced)在界面上能填,但宿主只把
`${user_config.*}` 插值进 **MCP server 字段与 hook**,**命令正文拿不到** —— 所以填在那里的
`default_variant` / `target_model` 不会自动生效。脚本改为自己读一份落地文件:
```bash
node scripts/thinking.mjs defaults set --variant high --model GLM-5.3
node scripts/thinking.mjs defaults # 看当前默认与来源
node scripts/thinking.mjs defaults clear # 回到内置兜底
```
文件:`~/.zcode/zcode-thinking-mode.json`(`ZCODE_THINKING_CONFIG` 可改路径)。
优先级:
```
命令行参数 > 环境变量(ZCODE_THINKING_VARIANT / ZCODE_THINKING_MODEL) > 默认值文件 > 内置兜底
```
设了之后:`set` 不带档位就用默认档位(`set` 两处都没有会**明确报错**,不会瞎猜一个档位就改配置);
`status` / `variants` 不带 `--model` 就用默认模型。
## 安全性
- **整批校验**:目标里只要有一个模型不支持该档位,整批中止,不做部分切换
- **校验收紧**:档位不在全部目标的 variants 并集里(如 `ultra`)直接拒绝,两边都不写
- **分写开关**:`--hot-only` 只写热档位,`--persist-only` 只写模型配置;两者不能同时用
- **先热后持久**:热档位写失败时模型配置原样不动,报错里明说"模型配置未动"
- **改写前备份**:每次真改模型配置都留一份 `config.json.bak-*`,同秒连续切换也不互相覆盖
- **只读自检**:`/thinking:doctor` 不改任何东西(连备份探测文件都当场删掉)
## 配置项(设置 → 插件详情 → Advanced)
- `default_variant`:文档默认引用的档位(默认 max)。**实际生效请用 `/thinking:defaults set`**
- `target_model`:默认作用的模型名(空=全部),命令参数优先。同上
## 测试
```bash
npm test # 34 项:档位读取/切换/备份/默认值/自检/分写/历史/回滚/收紧校验,含失败路径
npm run doctor # 真机自检
```
测试用 `ZCODE_V2_CONFIG` + `ZCODE_SESSION_DB` + `ZCODE_THINKING_CONFIG` + `ZCODE_THINKING_STATE`
把四个读写目标全部重定向到临时目录,不碰真实模型配置、真实 session 库、真实默认值文件与真实历史。
覆盖:热档位与持久默认的双写、大小写归一、`--model` 只动目标、默认值优先级、
整批校验中止不留半截改动、非法档位收紧拒绝、`--hot-only`/`--persist-only` 分写、
`history`/`rollback` 写回两边、无历史回滚报错、无效 session 库、配置缺失、备份撞名不覆盖、doctor 的各种 fail 分支。
## 环境变量
| 变量 | 默认 | 说明 |
|---|---|---|
| `ZCODE_V2_CONFIG` | `~/.zcode/v2/config.json` | 模型配置路径 |
| `ZCODE_SESSION_DB` | `~/.zcode/cli/db/db.sqlite` | 热档位库路径 |
| `ZCODE_THINKING_CONFIG` | `~/.zcode/zcode-thinking-mode.json` | 默认值文件路径 |
| `ZCODE_THINKING_STATE` | 与默认值文件同目录 `zcode-thinking-mode-state.json` | 切换历史文件路径 |
| `ZCODE_THINKING_VARIANT` | — | 覆盖默认档位(优先于文件) |
| `ZCODE_THINKING_MODEL` | — | 覆盖默认模型(优先于文件) |
| `ZCODE_THINKING_SCRIPT` | 自动定位 | 命令文档里指定脚本路径用 |
## 故障排查
先跑 `/thinking:doctor`。它直接指出问题并给修复命令,常见的有:
| 现象 | 处理 |
|---|---|
| `切不了,提示 node:sqlite 导入失败` | Node 需 ≥22.5;升 Node,否则只能改模型配置这一半 |
| `热档位库结构:缺 local_setting 表` | `ZCODE_SESSION_DB` 指错了,或该文件不是 ZCode 的 session 库 |
| `模型配置:读不到 / JSON 解析失败` | 检查路径;坏了就从同目录 `config.json.bak-*` 拷回 |
| `可切换模型:0 个带 reasoning` | 模型没声明 `reasoning.variants`,档位切不了,先在模型配置里加上 |
| `切完当前会话没变化` | 新会话才自动生效;当前轮再敲一行 `/effort <档位>` 热切 |