# dsh-advisor

[English](README.md) | **中文**

[![npm](https://img.shields.io/npm/v/@slhssb/dsh-advisor)](https://www.npmjs.com/package/@slhssb/dsh-advisor)
[![license](https://img.shields.io/npm/l/@slhssb/dsh-advisor)](LICENSE)

为 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 提供独立模型 advisory 审查。

每个工具执行步之后，由独立的审查模型审计 agent 最近的操作。发现真实问题时（破坏性/不可逆操作、契约/模式违规、偏离用户明确要求、正确性 bug），向下一轮模型调用注入一条简短的 `[advisor]` 指导消息，让 agent 自我纠正。操作健全时什么都不注入，审查只消耗一次（廉价的）审查调用。

dsh 本身没有内置 advisor；本插件基于标准的 `agent/pre-step` waterfall 实现（与 `dsh-agent-instructions`、`dsh-compaction-basic` 相同的注入通道）。

## 安装

```sh
dsh plugin add @slhssb/dsh-advisor
```

或加入 profile 的 `package.json`：

```json
"dependencies": { "@slhssb/dsh-advisor": "^0.1.0" },
"dsh": { "profile": { "bundles": ["@slhssb/dsh-advisor"] } }
```

然后在 profile 目录执行 `npm install`（或 `pnpm install`）并重启 dsh。

## 配置

默认目标为 DeepSeek 官方 API（`deepseek-official` provider）与廉价的 `deepseek-v4-flash` 模型。API key **不由本插件管理**：`deepseek-official` adapter 按请求从 `DEEPSEEK_API_KEY` 环境变量或凭据存储解析。

默认值无需覆盖——即 DeepSeek 官方 API（`deepseek-official`/`deepseek-v4-flash`）。要换审查 provider，在 profile 的 `cordis.patch.yml` 中覆盖（后写覆盖先写）。以下示例把审查路由到第三方中转：API key 由该 provider 的 adapter 解析（此处按 `settings.yaml` 的 `apiKeyEnv` 取 `TOKENRHYTHM_API_KEY` 环境变量）——本文件从不存放 key：

```yaml
- id: advisor
  config:
    provider: tokenrhythm
    model: deepseek-v4-pro
    maxTokens: 512
    maxHistoryMessages: 40
    interval: 1
    timeoutMs: 30000
```

| 键 | 默认 | 含义 |
| --- | --- | --- |
| `provider` | `deepseek-official` | 审查 provider 路由（任意 OpenAI 兼容 adapter 可用）。 |
| `model` | `deepseek-v4-flash` | 审查模型。 |
| `maxTokens` | `512` | 审查输出上限。 |
| `maxHistoryMessages` | `40` | 发送给审查模型的最新派生消息数。 |
| `interval` | `1` | 每隔 N 个含工具结果的步审查一次（1 = 每步）。 |
| `timeoutMs` | `30000` | 单次审查超时；超时静默降级。 |

行上加 `disabled: true` 可整体关闭；留空 `provider`/`model` 则回退到当前请求路由（`agent/session` 请求头，再退 agent options）。

## 规则（确定性检查）

除 LLM 审查外，`rules` 提供零成本、确定性的检查：用正则匹配最近一次工具调用（工具名 + 参数 JSON）。规则不会失败、不消耗 token；`warn` 规则向下一步注入 `[advisor] Rule check:` 消息，`block` 规则直接拒绝该步（显式开启，默认 `warn`）。

```yaml
- id: advisor
  config:
    provider: deepseek-official
    rules:
      - id: no-recursive-delete
        pattern: 'Remove-Item|rm\s+(-rf|-r\s*-f)|del\s+/[sq]'
        message: '检测到破坏性删除命令，请确认目标路径与用户授权。'
        action: warn            # 或 block
        tools: ['pwsh', 'bash'] # 可选：只对这些工具名生效
        enabled: true           # 可选，默认 true
```

| 键 | 默认 | 含义 |
| --- | --- | --- |
| `id` | — | 规则标识（触发时记录日志）。 |
| `pattern` | — | 大小写不敏感的 JS 正则，匹配 `工具名 + 参数`。 |
| `message` | — | 注入文本 `[advisor] Rule check: …`。 |
| `action` | `warn` | `warn` 注入提示；`block` 拒绝该步。 |
| `tools` | 全部 | 可选：规则生效的工具名子串列表。 |
| `enabled` | `true` | 禁用但不删除规则。 |

非法规则（缺字段、坏正则）会被跳过并记录警告；错误配置的规则永远不会阻塞 agent。多条 `warn` 命中合并为一条消息。`block` 在 LLM 审查之前触发——被阻断的步不跑审查。

## 工作原理

1. 每次模型调用前触发 `agent/pre-step`（waterfall）。
2. 插件扫描会话日志找最新的 `tool/result` 事件。没有，或其 seq 已审过，则放行本步。
3. 否则审查模型接收最近的派生历史 + 审查指令，流式返回。
4. 非空响应包装为 `user` 消息（`source: { kind: 'plugin', plugin: 'dsh-advisor' }`，文本带 `[advisor]` 前缀），插入本步 messages 的 claimed 消息之后、system context 之前——与 `dsh-agent-instructions` 相同的插入点，保证下一轮模型调用一定能看到。
5. 审查失败（LLM 错误、超时、空输出）记录 warning，不注入，并推进已审 seq 标记，同一批不会在下一步重试。agent 主流程永不被阻塞。

注入的 `[advisor]` 消息是普通 `user/message` 日志条目；它们永不产生 `tool/result` 事件，因此审查不会递归自触发。

## 开发

```sh
npm install
npx tsc -p tsconfig.json
node test/smoke.mjs   # 手写 fake，无网络
```

`lib/` 已提交进 git（git 安装的消费者无需构建即可使用）；gitignore 只排除 `node_modules/`、`test/smoke.mjs`、`package-lock.json`。npm 发布经 `files` 白名单打 `lib`。

## 发布

已发布到 npm：`@slhssb/dsh-advisor`；仓库带 GitHub `dsh-plugin` topic 便于发现。发新版：改 `package.json` 的 `version` → 发布 → 打 tag：

```sh
npm publish --access public
git tag v0.1.0 && git push --tags
```
