43cd42a563
- openclaw.json
- plugins.allow 放行 acpx(限制性白名单,缺了后端不会加载)
- 新增 acp 策略段:enabled/dispatch、backend=acpx、defaultAgent=dsh、
allowedAgents=[dsh]、stream.deliveryMode=live
- 新增 plugins.entries.acpx.config:permissionMode=approve-all、
timeoutSeconds=900、cwd、agents.dsh = dsh --profile acp(绝对路径)
- 新增 OpenClaw agent dsh(runtime.type=acp → harness dsh),否则
sessions_spawn 会报 dispatch_failed: Unknown agent id "dsh"
- workspace-dsh/:该 agent 的身份文件(AGENTS/SOUL/IDENTITY/USER/BOOTSTRAP.md)。
其中的空 .git 由 `openclaw agents add` 的标准 provisioning 生成(非任何 agent 自建),
会让父仓库把它当 gitlink,已移除后纳入版本控制
- docs/bk02-dsh-openclaw-ACP集成.md:部署/配置/验证证据/排错/回滚全文
- docs/dsh-acp-smoke.mjs:ACP 独立冒烟(initialize→session/new→prompt→close)
- docs/dsh-lang-check.mjs:全局中文指令验证(英文提问看是否回中文)
- skills/delegate-to-dsh:让「交给 dsh」稳定走 ACP 派发;缺此技能时模型会
静默 fallback 到内嵌 subagent(已复现「假成功」并写入判据)
- agents/main/agent/workshop-skills/acp-backend-triage:ACP 后端排查技能
- plugin-skills/acp-router:acpx 插件自带技能(symlink,与既有渠道一致)
- .gitignore:workspace-dsh 沿用 workspace/ 白名单(只版本化顶层 *.md);
新增忽略 acpx/ 插件运行产物
验证:ACP 三条途径均通过(独立冒烟、显式 sessions_spawn、自然语言「转给 dsh」),
DSH 侧会话留痕与产物落地见 docs 文档 §5 与 §7。
448 lines
24 KiB
Markdown
448 lines
24 KiB
Markdown
# bk02 · DSH × OpenClaw ACP 集成说明
|
||
|
||
> **用途**:本机 DeepSeek Harness(dsh)的部署与「OpenClaw → DSH」ACP 协同链路的完整说明。新会话/新人接手读本文件即可,无需历史对话。
|
||
> **配套**:`bk02-openclaw-系统说明.md`(OpenClaw 本体)、`openclaw-升级与维护.md`
|
||
> **主机**:bk02 / `xuan-asus-nj` · Debian 12 bookworm · 首次落地 2026-09-16
|
||
>
|
||
> ⚠️ 本目录**不含明文口令**,凭据位置见 §8。
|
||
|
||
---
|
||
|
||
## 0. 30 秒速览
|
||
|
||
| 项 | 值 |
|
||
|---|---|
|
||
| DSH 版本 | `@deepseek-ai/dsh` **0.1.5-rc.1**(nvm Node **v26.8.2**,全局安装) |
|
||
| DSH ACP 入口 | `dsh --profile acp` —— 官方 `@deepseek-ai/dsh-acp` 的 **ACP v1 stdio server** |
|
||
| DSH Web 服务 | `dsh-web.service`(**用户级** systemd),监听 `127.0.0.1:18787` |
|
||
| Web 访问入口 | **`https://bk02.baiji-algieba.ts.net:18787/?token=<启动时打印>`**(tailscale serve,仅 tailnet 内可达) |
|
||
| OpenClaw 侧 | `@openclaw/acpx` 插件 2026.9.4,harness 别名 **`dsh`**,已注册为 OpenClaw agent `dsh` |
|
||
| 链路 | **微信/飞书 → OpenClaw agent → `sessions_spawn(runtime:"acp", agentId:"dsh")` → `dsh --profile acp` → 干活 → 结果回传** |
|
||
| DSH 状态目录 | `~/.dsh`(profiles/ sessions/ .env / AGENTS.md) |
|
||
| 已装插件 | web profile:`skillhub-plugin` 0.2.16 + `superpowers-dsh` 0.1.1;**acp profile:仅 `superpowers-dsh`**(skillhub 的启动自检会往 stdout 打印,污染 ACP 协议流,见 §3.1) |
|
||
| 全局指令 | `~/.dsh/AGENTS.md` —— 交互与思考一律中文,所有 profile / 所有会话生效 |
|
||
|
||
**最常用的四条命令**:
|
||
|
||
```bash
|
||
export PATH=$HOME/.nvm/versions/node/v26.8.2/bin:$PATH # 每次登录先做
|
||
|
||
systemctl --user status dsh-web # DSH Web 状态
|
||
journalctl --user -u dsh-web -f # DSH Web 日志(含带 token 的访问 URL)
|
||
journalctl --user -u openclaw-gateway -f # OpenClaw 网关日志(ACP spawn 记录在这里)
|
||
node ~/.openclaw/docs/dsh-acp-smoke.mjs # DSH ACP 独立冒烟(不经过 OpenClaw)
|
||
```
|
||
|
||
---
|
||
|
||
## 1. 架构与职责边界
|
||
|
||
```
|
||
微信 / 飞书 / 其他渠道
|
||
│
|
||
▼
|
||
┌──────────────────────────────┐
|
||
│ OpenClaw Gateway (18789) │ ← 渠道接入、路由、会话、结果投递
|
||
│ @openclaw/acpx 插件 │ ← ACP 客户端侧(acpx 0.13.2 内嵌)
|
||
└──────────────────────────────┘
|
||
│ ACP v1 over stdio(JSON-RPC)
|
||
▼
|
||
┌──────────────────────────────┐
|
||
│ dsh --profile acp │ ← 每会话一个子进程;ACP server 侧
|
||
│ @deepseek-ai/dsh-acp │ 模型 deepseek-official / deepseek-v4-flash
|
||
│ dsh-base(工具/沙箱/持久化) │ 权限 preset workspace-write
|
||
└──────────────────────────────┘
|
||
│
|
||
▼
|
||
真实干活:读写文件、跑命令、再回传
|
||
```
|
||
|
||
职责分工(官方定位):
|
||
|
||
- **OpenClaw 拥有**:渠道、路由、后台任务状态、投递、绑定、策略。
|
||
- **DSH 拥有**:provider 登录、模型目录、文件系统行为、原生工具、会话持久化。
|
||
|
||
> 关键认知:**ACP 是 stdio 直连,不需要任何网络暴露**。DSH Web(18787)是给人用的浏览器界面,与 ACP 链路彼此独立。
|
||
|
||
---
|
||
|
||
## 2. 为什么不是「把 DSH 装成一个别的 ACP 工具」
|
||
|
||
DSH 自带官方 ACP 服务端,无需自研桥接:
|
||
|
||
- npm 包 `@deepseek-ai/dsh-acp`:`Automation-only Agent Client Protocol server for driving DeepSeek Harness agents over JSON-RPC stdio`。
|
||
- dsh ≥0.1.5 内置 `acp` profile 模板(bundles = `@deepseek-ai/dsh-base` + `@deepseek-ai/dsh-acp-app`),`dsh --profile acp` 开箱即用。
|
||
- 默认组合已配好 `provider: deepseek-official` / `model: deepseek-v4-flash`。
|
||
- ACP 能力:`initialize / session/new / session/list / session/resume / session/close / session/prompt / session/cancel / session/set_config_option`、`session/update` 语义流、`session/request_permission` 权限询问、stdio 与 HTTP MCP。
|
||
- 明确不支持(写代码时别指望):`session/load`、删除、fork、附加目录、SSE MCP、计划/终端/客户端文件系统操作、elicitation。
|
||
|
||
---
|
||
|
||
## 3. DSH 侧安装(可复现步骤)
|
||
|
||
```bash
|
||
# 1) 用 nvm 的 Node(系统 /usr/bin/node 是 22.x,不用)
|
||
export PATH=$HOME/.nvm/versions/node/v26.8.2/bin:$PATH
|
||
|
||
# 2) 全局安装 dsh(必须显式放行 install scripts,否则 node-pty / spawn helper 不生成)
|
||
npm i -g --allow-scripts=@deepseek-ai/dsh-subprocess-local,koffi,node-pty,@google/genai,protobufjs \
|
||
@deepseek-ai/dsh@0.1.5-rc.1
|
||
|
||
# 3) 初始化 ACP profile(首次执行自动创建 ~/.dsh/profiles/acp)
|
||
dsh --profile acp --help
|
||
|
||
# 4) 写入模型凭据(600 权限;凭据来源优先级见 §8)
|
||
printf 'DEEPSEEK_API_KEY=<见 §8>\n' > ~/.dsh/.env && chmod 600 ~/.dsh/.env
|
||
|
||
# 5) 独立冒烟:不经过 OpenClaw,直接与 dsh 的 ACP server 对话
|
||
node ~/.openclaw/docs/dsh-acp-smoke.mjs
|
||
```
|
||
|
||
`~/.dsh/profiles/acp/` 由 CLI 自动生成,**不要手改**(除非要换模型):
|
||
|
||
```json
|
||
{ "dsh": { "profile": { "bundles": ["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-acp-app"],
|
||
"patchReload": "startup" } } }
|
||
```
|
||
|
||
要改模型/provider,在 `~/.dsh/profiles/acp/cordis.patch.yml` 里按 id 覆盖 `acp` 行:
|
||
|
||
```yaml
|
||
- id: acp
|
||
config:
|
||
provider: deepseek-official
|
||
model: deepseek-v4-pro # 默认是 deepseek-v4-flash
|
||
```
|
||
|
||
### 3.1 插件与全局中文指令(2026-09-16 追加)
|
||
|
||
**前置:`dsh plugin` 是 pnpm 的转发器,先装 pnpm**(本机原先没有):
|
||
|
||
```bash
|
||
export PATH=$HOME/.nvm/versions/node/v26.8.2/bin:$PATH
|
||
npm i -g pnpm # → pnpm 12.4.2,落在 ~/.nvm/versions/node/v26.8.2/bin/pnpm
|
||
```
|
||
|
||
**装插件**(插件是否属于某个 profile,取决于 `dsh --profile <name>`,所以要分别装):
|
||
|
||
```bash
|
||
# Web 界面用的 profile:两个都装(HTTP 传输,不受 stdout 约束)
|
||
dsh plugin --profile web add skillhub-plugin superpowers-dsh
|
||
|
||
# ACP 自动化 profile:只装 superpowers-dsh —— 详见下方「stdout 纪律」
|
||
dsh plugin --profile acp add superpowers-dsh
|
||
```
|
||
|
||
装完 profile 的 `package.json` 会自动登记(`dsh plugin` 会按已装状态 reconcile 层列表):
|
||
|
||
```json
|
||
{ "dependencies": { "skillhub-plugin": "^0.2.16", "superpowers-dsh": "^0.1.1" },
|
||
"dsh": { "profile": { "bundles": ["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-web-app",
|
||
"skillhub-plugin", "superpowers-dsh"] } } }
|
||
```
|
||
|
||
校验(不需要起服务):
|
||
|
||
```bash
|
||
dsh --profile web --dump-config | grep -iE "skillhub|superpowers"
|
||
```
|
||
|
||
#### ⚠️ stdout 纪律:`skillhub-plugin` 不能装进 acp profile
|
||
|
||
`skillhub-plugin` 0.2.16 在插件加载时跑一个 fire-and-forget 启动自检,**用 `console.log` 往 stdout 打印**:
|
||
|
||
```
|
||
[skillhub] self-check ok: 插件分页两页零重复(5+5 条, total=2714)
|
||
```
|
||
|
||
而 ACP 的 stdout **只允许承载协议流量**(`dsh-acp` 文档原话:*Stdout carries only protocol traffic, so keep logging off it*)。该行会被 ACP 客户端当成非法 JSON 帧。实测:装进 acp profile 后,ACP 冒烟脚本每轮都会捕获到这条非 JSON 输出(脚本用宽容解析才没崩,acpx 的行为不作保证);从 acp profile 移除后立即干净:
|
||
|
||
```bash
|
||
dsh plugin --profile acp remove skillhub-plugin
|
||
node ~/.openclaw/docs/dsh-acp-smoke.mjs # 输出里不应再出现「非 JSON 的 stdout 输出」
|
||
```
|
||
|
||
该输出硬编码在 `lib/host.js` 的 `selfCheckPluginPaging()` 里(同函数另外两处用 `console.error` → stderr,无害),**没有配置开关**。若将来非要在 ACP 侧用技能市场,需要给该行打补丁改走 stderr,而不是直接安装。
|
||
|
||
#### 全局中文指令(交互 + 思考)
|
||
|
||
`~/.dsh/AGENTS.md`(DSH_HOME 级,**所有 profile、所有会话生效**;权限 600):
|
||
|
||
```markdown
|
||
# 用户全局指令(User-Global Instructions)
|
||
|
||
以下约定适用于所有 DSH 会话、所有项目目录,作为全局行为准则,优先于工具描述中的一般性提示:
|
||
|
||
## 语言
|
||
|
||
- 交互:与用户的所有交流(回复、提问、澄清、说明)一律使用中文。
|
||
- 思考:内部推理与思考过程也一律使用中文。
|
||
```
|
||
|
||
与 wit01 上 `~/.dsh/AGENTS.md` 内容一致。验证方式(脚本 `dsh-lang-check.mjs`,走 ACP 提问,故意用英文):
|
||
|
||
| 提问 | DSH 回复 | 判定 |
|
||
|---|---|---|
|
||
| `Answer in ONE short sentence, English only: what is 2+2?` | `2 + 2 = 4.` | 用户显式指定 English → 遵从用户(预期行为) |
|
||
| `Reply with a single short sentence: name one benefit of unit tests.` | `单元测试能在改动代码时快速发现回归缺陷。` | ✅ 未指定语言时输出中文,**指令生效** |
|
||
|
||
> 判定中文指令是否生效,要用**未指定语言**的英文提问;像第一行那样显式要求 English only 时,模型服从当次用户指令是正确行为,不算指令失效。
|
||
|
||
---
|
||
|
||
## 4. OpenClaw 侧配置(4 处,缺一不可)
|
||
|
||
配置全部落在 `~/.openclaw/openclaw.json`(用 `openclaw config patch` 写入,勿手改 JSON 后不校验)。
|
||
|
||
### 4.1 插件清单必须放行 `acpx`
|
||
|
||
`plugins.allow` 是**限制性白名单**,不在里面 = 插件被阻止加载(`/acp doctor` 会报缺失 allowlist 项):
|
||
|
||
```json5
|
||
"plugins": { "allow": ["deepseek","memory-core","ollama","searxng","openclaw-weixin",
|
||
"dingtalk-connector","openclaw-lark","feishu", "acpx"] }
|
||
```
|
||
|
||
### 4.2 acpx 插件里注册 DSH harness
|
||
|
||
```json5
|
||
"plugins": { "entries": { "acpx": { "enabled": true, "config": {
|
||
"permissionMode": "approve-all", // 非交互会话必需,否则写/执行被拒(见 §9 安全)
|
||
"timeoutSeconds": 900,
|
||
"cwd": "/home/yangxuan/.openclaw/workspace",
|
||
"agents": {
|
||
"dsh": {
|
||
"command": "/home/yangxuan/.nvm/versions/node/v26.8.2/bin/dsh",
|
||
"args": ["--profile", "acp"]
|
||
}
|
||
}
|
||
} } } }
|
||
```
|
||
|
||
> `agents.<id>` 是 acpx 插件自带的扩展点(schema:`{ command, args? }`),**用绝对路径**,因为网关服务的 PATH 未必包含 nvm 目录。
|
||
|
||
### 4.3 开启 ACP 策略
|
||
|
||
```json5
|
||
"acp": {
|
||
"enabled": true,
|
||
"dispatch": { "enabled": true },
|
||
"backend": "acpx",
|
||
"defaultAgent": "dsh",
|
||
"allowedAgents": ["dsh"],
|
||
"stream": { "deliveryMode": "live" }
|
||
}
|
||
```
|
||
|
||
### 4.4 把 `dsh` 注册成一个 OpenClaw agent(关键,易漏)
|
||
|
||
只做 4.2 + 4.3 会得到 `dispatch_failed: Unknown agent id "dsh"`:ACP spawn 会拼出子会话键 `agent:dsh:acp:<uuid>`,Gateway 用 `listAgentIds()` 校验该 agent 必须**真实存在**。
|
||
|
||
```bash
|
||
openclaw agents add dsh --workspace /home/yangxuan/.openclaw/workspace-dsh --non-interactive
|
||
# 再用 config patch 给它接上 ACP 运行时:
|
||
# agents.entries.dsh.runtime = { type: "acp", acp: { agent: "dsh", backend: "acpx" } }
|
||
```
|
||
|
||
最终 `agents.entries.dsh`:
|
||
|
||
```json5
|
||
{
|
||
"name": "DSH",
|
||
"workspace": "/home/yangxuan/.openclaw/workspace-dsh",
|
||
"agentDir": "/home/yangxuan/.openclaw/agents/dsh/agent",
|
||
"runtime": { "type": "acp", "acp": { "agent": "dsh", "backend": "acpx" } }
|
||
}
|
||
```
|
||
|
||
改完配置:`openclaw gateway restart`(插件类改动必须重启;纯 `agents.entries` 改动可热加载)。
|
||
|
||
---
|
||
|
||
## 5. 验证(2026-09-16 实测,均已通过)
|
||
|
||
| 检查 | 命令 | 结果 |
|
||
|---|---|---|
|
||
| ACP 独立冒烟 | `node ~/.openclaw/docs/dsh-acp-smoke.mjs` | `initialize` → `deepseek-harness-acp 0.0.1`;`session/new` → sessionId + 模型下拉(deepseek-v4-flash/pro…);`session/prompt` → 助手回「1+1 等于 2。」;`stopReason: end_turn` |
|
||
| 后端就绪 | 网关日志 | `embedded acpx runtime backend registered (cwd: /home/yangxuan/.openclaw/workspace)` → `backend ready` |
|
||
| 端到端派发 | `openclaw agent --agent main --session-key acp-e2e -m "请调用 sessions_spawn(runtime=acp, agentId=dsh, task=在 /tmp/dsh-e2e/ 创建 proof2.txt …)"` | 子会话 `agent:dsh:acp:ce3e4ea5…`,runId `b175b303-…`,约 5 秒完成 |
|
||
| DSH 侧留痕 | `~/.dsh/sessions/--home-yangxuan-.openclaw-workspace-dsh--/<uuid>/session.v3.jsonl.zstd` | 含 `permission/preset: workspace-write`、`sandbox/mode: workspace-write`、`approval/policy: ask` 及用户消息原文 |
|
||
| 产物落地 | `ls /tmp/dsh-e2e/` | `proof2.txt` / `proof3.txt` = `dsh-acp-e2e-ok` |
|
||
| Web 跨机访问 | `curl -L "https://bk02.baiji-algieba.ts.net:18787/?token=<token>"` | 303 → Set-Cookie → **200**(27724 字节 HTML) |
|
||
| 自然语言派发(**部署 skill 前**) | `openclaw agent --agent main -m "这个活我不想自己干,请转给 dsh 执行:…"` | ❌ **假成功**:回复称「已交给 dsh」,但 DSH 侧无新会话 —— 实际是默认 `subagent` + `exec` 干完再复述(工具轨迹 10 次调用 / 4 次失败) |
|
||
| 自然语言派发(**部署 skill 后**) | 同上措辞(用户不必知道参数) | ✅ DSH 侧新增会话 `332ef715-28e4-4dfb-812e-4152f3c33afd`(`cwd=workspace-dsh`、`permission/preset: workspace-write`),任务描述被自动补全验收标准,产物 `nl2.txt` = `skill-ok` |
|
||
|
||
> 证据判据:**别只看 OpenClaw 的回复文本**。回复正确可能来自 OpenClaw 内嵌运行时(`executionTrace.runner="embedded"`)。要确认真的走了 DSH,看两处:网关日志里的 `agent:dsh:acp:<uuid>` 子会话,以及 `~/.dsh/sessions/--home-yangxuan-.openclaw-workspace-dsh--/` 下是否新增会话目录。
|
||
|
||
---
|
||
|
||
## 6. DSH Web 界面(给人用,与 ACP 无关)
|
||
|
||
`~/.config/systemd/user/dsh-web.service`:
|
||
|
||
```ini
|
||
[Unit]
|
||
Description=DeepSeek Harness Web (dsh web on 18787, tailscale)
|
||
After=network-online.target
|
||
Wants=network-online.target
|
||
|
||
[Service]
|
||
Type=simple
|
||
Environment=PATH=/home/yangxuan/.nvm/versions/node/v26.8.2/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||
Environment=DSH_HOME=/home/yangxuan/.dsh
|
||
ExecStart=/home/yangxuan/.nvm/versions/node/v26.8.2/bin/node \
|
||
/home/yangxuan/.nvm/versions/node/v26.8.2/bin/dsh web \
|
||
--host 127.0.0.1 --port 18787 --no-open \
|
||
--trusted-host bk02.baiji-algieba.ts.net --trusted-host bk02.baiji-algieba.ts.net:18787 \
|
||
--trusted-host localhost:18787 --trusted-host 127.0.0.1:18787
|
||
Restart=on-failure
|
||
RestartSec=5
|
||
|
||
[Install]
|
||
WantedBy=default.target
|
||
```
|
||
|
||
对外暴露(仅 tailnet 可达,https,复用 tailscale 证书):
|
||
|
||
```bash
|
||
sudo -n tailscale serve --bg --https=18787 http://127.0.0.1:18787
|
||
sudo -n tailscale serve status # https://bk02.baiji-algieba.ts.net:18787 (tailnet only)
|
||
```
|
||
|
||
**访问必须带 token**(每次启动随机生成、只打印一次):
|
||
|
||
```bash
|
||
journalctl --user -u dsh-web --no-pager | grep -o 'token=[A-Za-z0-9]*' | tail -1
|
||
# → 浏览器打开 https://bk02.baiji-algieba.ts.net:18787/?token=<上面那串>
|
||
```
|
||
|
||
不带 token 访问返回 `401 dsh web authentication required; reopen the URL printed by dsh web.`;带 token 会用 303 + `Set-Cookie: dsh-auth-*` 落地,之后正常浏览。
|
||
|
||
两个已知坑:
|
||
|
||
1. `--host` **只接受 `127.0.0.1` 或 `0.0.0.0`**;写 `--host 100.115.195.192` 会在启动时报
|
||
`ValidationError: $.host expected "127.0.0.1" | "0.0.0.0" but got "100.115.195.192"`。
|
||
所以要「tailscale 上的 18787」就用 `127.0.0.1` + `tailscale serve`(本方案),不要指望直绑 tailscale IP。
|
||
2. 首次启动会初始化 `~/.dsh/profiles/web`,约 10–40 秒才监听端口;systemd 里已在等待逻辑外,需自行 `ss -ltn | grep 18787` 确认。
|
||
|
||
---
|
||
|
||
## 7. 微信 → DSH 的接法(2026-09-16 实测结论)
|
||
|
||
**结论:微信 / 飞书 / 钉钉只能走「助手按需派活」,渠道级 ACP 绑定在这三家都不存在。**
|
||
|
||
### 7.1 渠道能力实测(为什么不能直接绑定会话)
|
||
|
||
OpenClaw 判定一个渠道能否「把当前会话绑到 ACP 会话」的代码是:
|
||
`getChannelPlugin(id)?.conversationBindings?.supportsCurrentConversationBinding === true`;持久 `bindings[] type="acp"` 还需要适配器提供 `bindings.compileConfiguredBinding` / `matchInboundConversation`(Telegram 适配器就是这么实现的)。
|
||
|
||
体检本机三个渠道插件的结果:
|
||
|
||
| 渠道 | 插件 | `conversationBindings` | `supportsCurrentConversationBinding` | `threadBindings` |
|
||
|---|---|---|---|---|
|
||
| 微信 | `@tencent-weixin/openclaw-weixin` 2.4.8 | 0 处 | 0 处 | 0 处 |
|
||
| 飞书 | `~/.openclaw/extensions/openclaw-lark` | 0 处 | 0 处 | 0 处 |
|
||
| 钉钉 | `@dingtalk-real-ai/dingtalk-connector` | 0 处 | 0 处 | 0 处 |
|
||
| Telegram(对照组,官方内置) | `dist/channel-*.mjs` | 有 | `true`(`bindingStore: "adapter"`) | 有 |
|
||
|
||
因此:
|
||
|
||
- ❌ **`/acp spawn dsh --bind here`** 在微信/飞书/钉钉不可用(会得到 "Conversation bindings are unavailable …")。
|
||
- ❌ **持久 `bindings[] type="acp"`** 同样不可用(适配器没有绑定钩子)。
|
||
- ✅ **助手派活**是最短可用路径(也是本机唯一路径)。
|
||
|
||
### 7.2 唯一可用路径:助手把活派给 DSH(已部署)
|
||
|
||
链路:**微信消息 → OpenClaw `main` 助手 → `sessions_spawn(runtime:"acp", agentId:"dsh")` → `dsh --profile acp` → 干活 → 结果回传微信**。
|
||
|
||
为了让它**稳定**,已部署技能 `~/.openclaw/skills/delegate-to-dsh/SKILL.md`:触发词为「交给 dsh / 让 dsh 干 / 用 DSH 跑 / 转给 dsh」,并写明纪律(必须带 `runtime:"acp"`、禁止自己用 `exec` 或默认 subagent 兜底、派发失败要如实报错、结果原样回传)。
|
||
|
||
> ⚠️ **不加这个技能不可靠**:实测 17:19 那次用户说「转给 dsh 执行」,`main` 声情并茂地回了"已交给 dsh 并执行完成",但工具轨迹里是 `sessions_spawn`(默认 `subagent`)+ `exec`,DSH 侧**没有任何新会话** —— 即它由 OpenClaw 内嵌运行时干完,然后复述成 dsh 的口气。技能上线后同一句话(17:21)DSH 侧新增会话 `332ef715…`,`cwd=/home/yangxuan/.openclaw/workspace-dsh`,产物落地。
|
||
|
||
### 7.3 怎么确认真的交给了 DSH
|
||
|
||
```bash
|
||
# ① DSH 侧会话数是否 +1(最硬的证据)
|
||
ls -lt ~/.dsh/sessions/--home-yangxuan-.openclaw-workspace-dsh--/ | head
|
||
|
||
# ② 网关日志里的 ACP 子会话 / 后端就绪
|
||
journalctl --user -u openclaw-gateway --since "10 minutes ago" | grep -iE "agent:dsh:acp:|acpx runtime backend"
|
||
|
||
# ③ 会话内容(含 cwd 与 permission preset)
|
||
L=$(ls -t ~/.dsh/sessions/--home-yangxuan-.openclaw-workspace-dsh--/ | head -1)
|
||
zstd -dc ~/.dsh/sessions/--home-yangxuan-.openclaw-workspace-dsh--/$L/session.v3.jsonl.zstd | head -5
|
||
```
|
||
|
||
判据:回复文本**不算证据**(见 7.2 的反例),要看 ①/③。
|
||
|
||
### 7.4 其他说明
|
||
|
||
- `agents.entries.dsh.runtime.type="acp"` **不会**让发给 `dsh` 的普通消息自动走 ACP(实测 `openclaw agent --agent dsh` 仍是 `executionTrace.runner="embedded"`)。它的作用只有一个:让 `dsh` 能作为 `sessions_spawn(runtime:"acp", agentId:"dsh")` 的合法目标。
|
||
- 想换成「某个微信账号的消息全量交给 DSH」,在当前渠道能力下做不到「消息直通」;可行的近似做法是把该账号绑定的 agent 换成 `dsh`,但那只会让 OpenClaw 内嵌运行时换个身份干活,不是 ACP。
|
||
- 若将来 OpenClaw 侧或渠道插件补上 `conversationBindings`,再考虑 `/acp spawn --bind here`。
|
||
|
||
---
|
||
|
||
## 8. 凭据位置(本项目文档不含明文)
|
||
|
||
| 凭据 | 位置 | 说明 |
|
||
|---|---|---|
|
||
| DSH 模型 API Key | `~/.dsh/.env`(600)里的 `DEEPSEEK_API_KEY` | DSH 凭据解析优先级:**继承的进程环境** > `~/.dsh/.credentials.yaml` > 调用目录 `.env` > `~/.dsh/.env`。写 `.env` 最省事;Web 的 Models 页写入则会落到 `.credentials.yaml` 并覆盖 `.env` |
|
||
| DSH Web 访问 token | 运行时随机生成 | 见 §6,从 `journalctl` 取;不落盘 |
|
||
| OpenClaw 各类密钥 | `~/.openclaw/.env` / `~/.openclaw/openclaw.json` | 见 `bk02-openclaw-系统说明.md` §6 |
|
||
|
||
---
|
||
|
||
## 9. 排错清单(按遇到概率排序)
|
||
|
||
| 症状 | 原因 | 处置 |
|
||
|---|---|---|
|
||
| `dispatch_failed: Unknown agent id "dsh"` | 只注册了 acpx harness 别名,没建同名 OpenClaw agent | 做 §4.4:`openclaw agents add dsh` + `runtime.type="acp"` |
|
||
| `ACP runtime backend is not configured` | `@openclaw/acpx` 没装 / 被 `plugins.allow` 拦 / 网关没重启 | `openclaw plugins install @openclaw/acpx`;把 `acpx` 加进 `plugins.allow`;重启网关 |
|
||
| 回复看着对但 DSH 侧没有新会话 | 其实是 OpenClaw 内嵌运行时干的 | 看 `executionTrace.runner`;确认 `agent:dsh:acp:<uuid>` 子会话与 `~/.dsh/sessions/...-workspace-dsh--` |
|
||
| `PermissionPromptUnavailableError: Permission prompt unavailable in non-interactive mode` | 非交互 ACP 会话撞上写/执行门禁 | `plugins.entries.acpx.config.permissionMode = "approve-all"`(或 `nonInteractivePermissions="deny"` 降级) |
|
||
| `dsh: profile "acp" does not exist` | dsh 版本 < 0.1.5(无内置 acp 模板) | 升级 dsh,或 `dsh plugin --profile acp add @deepseek-ai/dsh-acp` 后手写 profile |
|
||
| 网关日志 `security warning: dangerous config flags … permissionMode=approve-all` | 预期告警 | `approve-all` 等于把 bk02 上的写/执行权限交给 DSH 会话,见下方安全说明 |
|
||
| Web 打开 401 | 没带 token | 从 `journalctl --user -u dsh-web` 取带 token 的 URL |
|
||
| Web 启动即崩、日志报 `$.host expected …` | `--host` 传了具体 IP | 改 `127.0.0.1`(+ tailscale serve) |
|
||
| `dsh` 命令找不到 | 该 shell 没加载 nvm 的 Node | `export PATH=$HOME/.nvm/versions/node/v26.8.2/bin:$PATH` |
|
||
| `dsh plugin …` 报 `pnpm not found on PATH` | 本机没装 pnpm(`dsh plugin` 只是 pnpm 转发器) | `npm i -g pnpm` |
|
||
| ACP 会话报 JSON 解析错 / 客户端把某行当非法帧 | acp profile 里装了会往 **stdout** 打印的插件(已知:`skillhub-plugin` 自检行) | `dsh plugin --profile acp remove skillhub-plugin`;装任何插件后都跑一遍冒烟脚本确认无「非 JSON 的 stdout 输出」 |
|
||
|
||
**安全说明**:`permissionMode=approve-all` 让 DSH 会话在 bk02 上自动获得写文件/执行命令的许可(这是「让 DSH 干活」的代价)。可收紧为 `approve-reads`,但写/执行类任务会需要交互确认,非交互会话可能直接失败。DSH 自身仍带 `workspace-write` 沙箱 preset 与 `approval/policy: ask` 记录,可在 `~/.dsh/sessions/*/session.v3.jsonl.zstd` 审计。
|
||
|
||
---
|
||
|
||
## 10. 回滚
|
||
|
||
```bash
|
||
# OpenClaw:配置回滚到接入前(备份在 ~/.openclaw/openclaw.json.bak-<ts>-pre-dsh-acp)
|
||
cp ~/.openclaw/openclaw.json.bak-20260916-170416-pre-dsh-acp ~/.openclaw/openclaw.json
|
||
openclaw gateway restart
|
||
|
||
# DSH Web:停用 + 撤掉 tailscale 暴露
|
||
systemctl --user disable --now dsh-web
|
||
sudo -n tailscale serve --https=18787 off
|
||
|
||
# DSH 本体
|
||
npm rm -g @deepseek-ai/dsh # 配置与历史留在 ~/.dsh(可整体删除)
|
||
```
|
||
|
||
---
|
||
|
||
## 11. 变更记录
|
||
|
||
| 时间 | 变更 |
|
||
|---|---|
|
||
| 2026-09-16 17:01 | bk02 安装 `@deepseek-ai/dsh@0.1.5-rc.1`(nvm v26.8.2),自动初始化 `acp` profile |
|
||
| 2026-09-16 17:02 | 写入 `~/.dsh/.env` 的 `DEEPSEEK_API_KEY`;ACP stdio 冒烟通过 |
|
||
| 2026-09-16 17:04 | 安装 `@openclaw/acpx`;`plugins.allow` 放行;写入 `acp` 段与 acpx `agents.dsh`;网关重启 |
|
||
| 2026-09-16 17:11 | 创建 OpenClaw agent `dsh`(workspace-dsh)并接 ACP runtime |
|
||
| 2026-09-16 17:12 | 端到端 ACP 派发成功(proof2/proof3 由 DSH 创建) |
|
||
| 2026-09-16 17:15 | `dsh-web.service` 落地(127.0.0.1:18787)+ `tailscale serve --https=18787`;跨机访问 200 |
|
||
| 2026-09-16 17:20 | 查明微信/飞书/钉钉渠道**均无** `conversationBindings` 能力(仅 Telegram 等内置渠道有)→ 排除 `/acp spawn --bind here` 与持久 `bindings[]` 两条路;部署技能 `~/.openclaw/skills/delegate-to-dsh/SKILL.md` 并重启网关 |
|
||
| 2026-09-16 17:21 | 自然语言派发验证通过(DSH 侧新会话 `332ef715…`),「微信 → OpenClaw → DSH → 结果回传」链路可用 |
|
||
| 2026-09-16 17:23 | 装 pnpm 12.4.2;web profile 增装 `skillhub-plugin` + `superpowers-dsh`;写 `~/.dsh/AGENTS.md` 全局中文指令(交互 + 思考) |
|
||
| 2026-09-16 17:24 | 发现 `skillhub-plugin` 自检用 `console.log` 污染 ACP stdout → 从 acp profile 移除(保留 `superpowers-dsh`),复测协议流干净;语言复测中文生效 |
|
||
| 2026-09-16 17:25 | 端到端回归:OpenClaw 派发仍正常(DSH 会话 6→7,产物 `nl3.txt`) |
|