dsh-harness-supervisor 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +48 -48
- package/cordis.patch.yml +7 -7
- package/dist/bridge.js +157 -157
- package/dist/client.js +163 -163
- package/dist/index.js +86 -86
- package/dist/node-runtime.js +17 -17
- package/node_modules/harness-supervisor/LICENSE +21 -21
- package/node_modules/harness-supervisor/README.md +461 -461
- package/node_modules/harness-supervisor/dist/src/cli.js +88 -88
- package/node_modules/harness-supervisor/dist/src/version.d.ts +1 -1
- package/node_modules/harness-supervisor/dist/src/version.js +1 -1
- package/node_modules/harness-supervisor/dist/src/worker-protocol.js +2 -2
- package/node_modules/harness-supervisor/dist/web/assets/{index-CGX0pkMi.css → index-BqbkyngR.css} +1 -1
- package/node_modules/harness-supervisor/dist/web/assets/{qoder-JStW91Ty.svg → qoder-DMyhGYme.svg} +27 -27
- package/node_modules/harness-supervisor/dist/web/index.html +14 -14
- package/node_modules/harness-supervisor/node_modules/which/bin/node-which +0 -0
- package/node_modules/harness-supervisor/package.json +1 -1
- package/node_modules/harness-supervisor/production-lock.json +173 -173
- package/package.json +3 -3
- /package/node_modules/harness-supervisor/dist/web/assets/{index-CBACx3zJ.js → index-C22kUlUp.js} +0 -0
|
@@ -1,461 +1,461 @@
|
|
|
1
|
-
<div align="center">
|
|
2
|
-
|
|
3
|
-
# Harness Supervisor
|
|
4
|
-
|
|
5
|
-
通过 **CLI** 或 **MCP** 启动、观察、指导、取消和恢复其他厂商的原生 Harness;每个被启动的 Harness 进程称为 **Worker**。HS 只管理进程、会话与事件;规划、工具调用和上下文管理由各 Harness 自己完成。
|
|
12
|
-
|
|
13
|
-
</div>
|
|
14
|
-
|
|
15
|
-
## 核心理念
|
|
16
|
-
|
|
17
|
-
HS 的目标:以尽可能低的开销,让独立的原生 Harness Worker 被可靠地调用、观察、控制和协作。
|
|
18
|
-
|
|
19
|
-
**不做**
|
|
20
|
-
|
|
21
|
-
- 新的 Agent 框架或 Agent Loop;
|
|
22
|
-
- Planner / Reviewer / Challenger 等角色拆分;
|
|
23
|
-
- 任务 DAG、投票、模型路由或固定工作流;
|
|
24
|
-
- Harness 内部的规划、工具调用与上下文管理;
|
|
25
|
-
- 额外 LLM 做调度或生命周期管理;
|
|
26
|
-
- 多用户、远程调度、配额管理或安全沙箱。
|
|
27
|
-
|
|
28
|
-
**设计原则**
|
|
29
|
-
|
|
30
|
-
- **原生优先**:优先使用运行时原生协议、Session 与控制能力;不为统一接口伪造底层不支持的行为。
|
|
31
|
-
- **提供能力,不规定工作流**:任务如何拆分、是否多轮协作,由 Master 自行决定。
|
|
32
|
-
- **状态来自证据**:`completed` 只在 Harness 报告 settle、或进程退出被确认后出现。
|
|
33
|
-
- **先落盘再交付**:重要事件与通知先写入本地追加日志,消费者离线不丢。
|
|
34
|
-
|
|
35
|
-
## 当前接入
|
|
36
|
-
|
|
37
|
-
| Runtime | 传输 | 状态 |
|
|
38
|
-
| --- | --- | --- |
|
|
39
|
-
| Pi Agent | Pi 原生 RPC(Pi v1.3+) | 完整支持 |
|
|
40
|
-
| Qoder CLI | 官方 ACP 默认,stream-json 可回退 | 实验性 |
|
|
41
|
-
| MiniMax Code | ACP over ndJSON | 实验性 |
|
|
42
|
-
| DeepSeek Harness / DSH | 官方 ACP(`dsh --profile acp`) | PoC |
|
|
43
|
-
|
|
44
|
-
## 功能
|
|
45
|
-
|
|
46
|
-
- **独立 Worker**:每个 Worker 是一个原生 Harness 子进程,有自己的 cwd、session 与进程树。Worker 属于 daemon,客户端断开后继续运行。
|
|
47
|
-
- **完整生命周期**:spawn / status / events / wait / send / answer / cancel / resume,含并发准入、取消与关停屏障、重启对账。
|
|
48
|
-
- **增量事件**:每 Worker 一条追加式事件流,`seq` 单调递增,支持 `sinceSeq` 游标;状态变化与普通进度分开返回。
|
|
49
|
-
- **持久化通知收件箱**:完成 / 失败 / 取消 / 需要输入 / 崩溃 / 失联等事件生成稳定 ID 的通知,可查询、可确认、跨重启不重复;默认不产生任何外部调用。
|
|
50
|
-
- **可选队列投递**:登记 Codex thread 后,可用官方 `codex queue` 把简短通知写入该 thread;是否真正唤醒 Master 取决于宿主是否加载该 thread。
|
|
51
|
-
- **可选请求幂等**:`spawn` / `resume` / `send` 支持 `requestId`;重复请求不会重复执行,结果不确定时报 `UNCERTAIN`。
|
|
52
|
-
- **任务度量**:每次 `spawn` 自动创建或关联一个委托任务;记录 Worker 终态、耗时、可得的运行时 Token 用量,并生成带覆盖率、来源和未知字段的单任务/汇总报告。费用不采集,验收、返工与干预尚未采集。
|
|
53
|
-
- **Qoder 双传输**:默认使用官方 ACP,可回退 stream-json;两种传输的会话句柄不互换,能力差异如实报告。
|
|
54
|
-
- **DSH ACP 接入**:支持 spawn / 事件 / 取消 / `session/resume` / 模型与推理强度配置 / 权限提权应答;桌面端安装可自动发现,也可用 `HARNESS_SUPERVISOR_DSH_ENTRY` 指定入口。
|
|
55
|
-
- **统一入口**:CLI、MCP、IPC 共享同一个 daemon 与同一份状态。
|
|
56
|
-
|
|
57
|
-
## 架构
|
|
58
|
-
|
|
59
|
-
```mermaid
|
|
60
|
-
flowchart TB
|
|
61
|
-
Client["Master / 外部客户端"]
|
|
62
|
-
|
|
63
|
-
subgraph interfaces["接口"]
|
|
64
|
-
CLI["CLI"]
|
|
65
|
-
MCP["MCP (stdio)"]
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
IPC["SupervisorClient<br/>本地 IPC(named pipe / Unix socket + token)"]
|
|
69
|
-
|
|
70
|
-
subgraph daemon["Supervisor daemon"]
|
|
71
|
-
direction TB
|
|
72
|
-
Lifecycle["生命周期<br/>状态机 / 并发准入 / wait / 输入 / 取消 / 恢复"]
|
|
73
|
-
Events["事件<br/>追加式日志 + seq 游标"]
|
|
74
|
-
Inbox["通知<br/>持久化收件箱"]
|
|
75
|
-
Metrics["度量<br/>任务 / 用量追加日志"]
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
subgraph adapters["Runtime Adapters"]
|
|
79
|
-
Pi["Pi 原生 RPC<br/>Pi 子进程"]
|
|
80
|
-
Qoder["Qoder ACP 默认 / stream-json 回退<br/>qodercli 子进程"]
|
|
81
|
-
Mcode["MiniMax Code ACP(ndJSON)<br/>mcode acp 子进程"]
|
|
82
|
-
Dsh["DeepSeek Harness ACP(ndJSON)<br/>dsh --profile acp 子进程"]
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
Client --> CLI
|
|
86
|
-
Client --> MCP
|
|
87
|
-
CLI --> IPC
|
|
88
|
-
MCP --> IPC
|
|
89
|
-
IPC --> Lifecycle
|
|
90
|
-
Lifecycle --> Events
|
|
91
|
-
Lifecycle --> Inbox
|
|
92
|
-
Lifecycle --> Metrics
|
|
93
|
-
Lifecycle --> Pi
|
|
94
|
-
Lifecycle --> Qoder
|
|
95
|
-
Lifecycle --> Mcode
|
|
96
|
-
Lifecycle --> Dsh
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
| 模块 | 职责 |
|
|
100
|
-
| --- | --- |
|
|
101
|
-
| `src/adapters/` | Pi / Qoder / MiniMax Code / DSH 的运行时适配,以及通用 ACP ndJSON 传输 |
|
|
102
|
-
| `src/supervisor.ts` | 状态机、wait、send/answer、cancel、resume、重启对账 |
|
|
103
|
-
| `src/store.ts` | Worker 记录、追加式事件日志、游标、持久化 |
|
|
104
|
-
| `src/metrics.ts` | 任务/用量记录、独立追加日志、覆盖率与报告计算 |
|
|
105
|
-
| `src/notify.ts` | 通知收件箱、确认、可选投递与重试 |
|
|
106
|
-
| `src/ipc/` | 本地 IPC、token 认证、server/client |
|
|
107
|
-
| `src/cli.ts` / `src/mcp.ts` | 两个入口,共用同一套核心行为 |
|
|
108
|
-
| `src/types.ts` | 公开类型、状态与事件 schema |
|
|
109
|
-
|
|
110
|
-
## 工作原理
|
|
111
|
-
|
|
112
|
-
1. **进程归属**:daemon 启动 Harness 子进程并持有其 stdio;CLI/MCP 只是客户端,断开不影响 Worker。
|
|
113
|
-
2. **Adapter 只做翻译**:把 Harness 原生事件映射为统一事件,把统一指令映射为原生命令,保留运行时自己的语义。
|
|
114
|
-
3. **状态来自证据**:`spawn` 返回只表示 prompt 被接受;`completed` 只在 Harness 报告 settle、或进程退出被确认后出现。
|
|
115
|
-
4. **恢复显式且受限**:daemon 重启不会接管原进程;`resume` 使用“新进程 + 加载持久化 session + 新 prompt”,并校验 session,不重放旧操作。
|
|
116
|
-
5. **先落盘再交付**:重要事件与通知写入本地追加日志;投递语义为 at-least-once。
|
|
117
|
-
|
|
118
|
-
## 快速开始
|
|
119
|
-
|
|
120
|
-
要求:Node.js >= 22.19;Pi >= 1.3 并已配置 provider/凭据。
|
|
121
|
-
|
|
122
|
-
```bash
|
|
123
|
-
npm install
|
|
124
|
-
npm run build
|
|
125
|
-
node dist/src/cli.js up # 启动本地 daemon(已在运行则直接返回)
|
|
126
|
-
|
|
127
|
-
# 启动 Worker:只表示 prompt 被接受,任务可能仍在运行
|
|
128
|
-
node dist/src/cli.js spawn \
|
|
129
|
-
--cwd D:/work/demo \
|
|
130
|
-
--prompt "Create hello.txt containing hello. Then reply exactly DONE." \
|
|
131
|
-
--name demo-worker --json
|
|
132
|
-
|
|
133
|
-
node dist/src/cli.js status <workerId> # 状态、最近事件与结果
|
|
134
|
-
node dist/src/cli.js wait <workerId> --timeout-ms 60000
|
|
135
|
-
node dist/src/cli.js send <workerId> --message "也写一个时间戳" --mode steer
|
|
136
|
-
node dist/src/cli.js cancel <workerId>
|
|
137
|
-
node dist/src/cli.js resume <workerId> --prompt "继续并总结改动"
|
|
138
|
-
node dist/src/cli.js metrics show <taskId> # 任务状态、Worker 耗时与用量
|
|
139
|
-
node dist/src/cli.js metrics report # 汇总、覆盖率与未知字段
|
|
140
|
-
node dist/src/cli.js down # 优雅关闭(会取消活动 Worker)
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
默认状态目录为 `~/.harness-supervisor`,可用 `--state-dir <dir>` 或 `HARNESS_SUPERVISOR_HOME` 隔离实例。完整命令见 `node dist/src/cli.js help`,示例见 [`examples/cli-walkthrough.sh`](examples/cli-walkthrough.sh)。
|
|
144
|
-
|
|
145
|
-
### DSH 插件
|
|
146
|
-
|
|
147
|
-
让 DSH 委派和管理 Pi、Qoder、MiniMax Code 等原生 Worker,并在会话中查看任务、结果和审批。插件已包含 HS 核心与 WebUI,无需额外安装或编译。
|
|
148
|
-
|
|
149
|
-
[项目仓库](https://gitcode.com/chenpi_1/harness-supervisor) · [插件安装与配置](packages/dsh-plugin/README.md)
|
|
150
|
-
|
|
151
|
-
### 在浏览器中使用 WebUI
|
|
152
|
-
|
|
153
|
-
WebUI 是可选功能,默认不开端口。已安装独立 HS 时,运行:
|
|
154
|
-
|
|
155
|
-
```bash
|
|
156
|
-
harness-sup ui # 启用并在系统浏览器中打开
|
|
157
|
-
harness-sup ui --stop # 关闭 WebUI,Worker 继续运行
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
源码运行方式为 `node dist/src/cli.js ui`。浏览器和 DSH 使用同一套界面:可按工作目录分组查看 Worker,读取结果、事件和用量,回答请求或取消任务;创建与续接任务仍交给 Master。
|
|
161
|
-
|
|
162
|
-
界面仅供本机使用,监听 `127.0.0.1`。CLI 和 DSH 的人工界面均可查看当前 HS 实例的全部 Worker;DSH 默认展开当前对话分组,模型工具仍保持会话隔离。daemon 或 WebUI 重启后,需从对应入口重新打开。
|
|
163
|
-
|
|
164
|
-
### 更新 HS
|
|
165
|
-
|
|
166
|
-
**更新不需要拉取源码。** 可以选择下面任一方式:
|
|
167
|
-
|
|
168
|
-
| 使用方式 | 更新步骤 |
|
|
169
|
-
| --- | --- |
|
|
170
|
-
| DSH 插件 | 安装新版插件 `.tgz`,再到设置中点击 **Harness Supervisor → 应用配套 HS 核心**。 |
|
|
171
|
-
| 独立 HS | 安装预构建核心 `.tgz`,再将运行中的核心切换到该版本;受控切换命令见下面的高级说明。 |
|
|
172
|
-
|
|
173
|
-
更新插件只准备新核心,**不会立即替换运行实例**。点击应用后,HS 暂停接收新任务,等待已有任务与队列结束再切换;等待期间仍可回答请求、取消任务,也可取消此次更新。切换完成后,使用同一状态目录、支持托管更新的 CLI、MCP 和插件共用新核心,源码目录与全局安装文件不会被覆盖。
|
|
174
|
-
|
|
175
|
-
目前按 `.tgz` 安装包分发,尚未提供在线检查新版功能。从旧 `0.9.2` 首次迁入时,需要先安排维护窗口、处理活动 Worker 并停止旧 daemon;之后兼容版本可使用上述受控更新。
|
|
176
|
-
|
|
177
|
-
<details>
|
|
178
|
-
<summary>独立 HS 的核心切换命令</summary>
|
|
179
|
-
|
|
180
|
-
独立核心包可用 `npm install -g <核心包.tgz>` 安装。**安装客户端不等于切换正在运行的核心**;对支持受控更新的 daemon,使用新核心的安装目录准备候选版本,再应用返回的 runtime ID:
|
|
181
|
-
|
|
182
|
-
```bash
|
|
183
|
-
harness-sup runtime prepare --source <新核心的安装目录>
|
|
184
|
-
harness-sup runtime apply --runtime-id <返回的id> --intent-id <本次更新的唯一标识>
|
|
185
|
-
harness-sup runtime status
|
|
186
|
-
harness-sup runtime cancel --intent-id <同一标识> # 仅等待任务结束期间可取消
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
这些命令应使用与现有实例相同的 `--state-dir`。首次升级旧 `0.9.2` 须走前述维护窗口,不能使用这些命令热切换。无法确认进程退出时,自动更新会停止;不要删除锁或并行启动旧核心强行恢复。状态目录中的 `runtime-update.json`、`runtime-update.log` 和 `runtime-backups/` 保留恢复线索。
|
|
190
|
-
|
|
191
|
-
</details>
|
|
192
|
-
|
|
193
|
-
### 全新 clone / 另一台机器
|
|
194
|
-
|
|
195
|
-
仓库只包含源码、测试与文档;`dist/` 被 `.gitignore` 忽略,必须在本机构建。
|
|
196
|
-
|
|
197
|
-
```bash
|
|
198
|
-
git clone --branch main https://gitcode.com/chenpi_1/harness-supervisor.git Harness-Supervisor
|
|
199
|
-
cd Harness-Supervisor
|
|
200
|
-
npm ci # 按 package-lock.json 安装,可复现
|
|
201
|
-
npm run build # 生成 dist/(核心 + 共用 WebUI)
|
|
202
|
-
npm run typecheck # 可选:类型检查
|
|
203
|
-
node dist/src/cli.js up
|
|
204
|
-
node dist/src/cli.js info # 核对 version=0.10.
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
若 `npm ci` 因网络镜像失败,改用 `npm install`,再用 `git status` 确认 `package-lock.json` 未被意外改写。
|
|
208
|
-
|
|
209
|
-
本机状态与凭据不会随 Git 迁移:状态目录(Worker 记录、事件日志、session、收件箱)、daemon 进程与 IPC 端点、MCP 客户端注册、各 Harness 自己的登录态都必须在本机建立。复制源码不会复制运行状态;缺少凭据时 `spawn` 会失败,这属于运行时的环境问题。
|
|
210
|
-
|
|
211
|
-
### MCP 接入
|
|
212
|
-
|
|
213
|
-
MCP server 是 daemon 的客户端;daemon 需要独立启动并保持运行。若宿主会随会话清理 MCP server 的子进程树,不要在宿主内自动拉起 daemon:
|
|
214
|
-
|
|
215
|
-
```bash
|
|
216
|
-
node <clone>/dist/src/cli.js up
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
在宿主支持的任何 stdio MCP 配置中注册以下 server,`command` 与 `args` 指向本机 clone 的绝对路径:
|
|
220
|
-
|
|
221
|
-
```json
|
|
222
|
-
{
|
|
223
|
-
"mcpServers": {
|
|
224
|
-
"harness-supervisor": {
|
|
225
|
-
"command": "node",
|
|
226
|
-
"args": ["<clone>/dist/src/mcp.js"]
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
MCP 协议本身不规定客户端配置字段。常见的 `mcpServers` 写法通常只有 `command`、`args`、`env`,工具超时与审批由各客户端自行定义:Codex 使用 `tool_timeout_sec` / `default_tools_approval_mode`,Claude Code 使用每服务器 `timeout` / `MCP_TOOL_TIMEOUT`,Qoder 使用 `timeout` / `trust`,Cursor 主要通过 UI 与 Run Modes 控制审批。请以所用客户端文档为准,JSON 形式可参考 [`examples/mcp.json`](examples/mcp.json)。
|
|
233
|
-
|
|
234
|
-
这些宿主侧设置只影响宿主如何审批、超时调用 **HS 的 MCP 工具**(`worker_spawn`、`worker_wait` 等),不会改变 Worker 内部的权限;Pi、Qoder、MiniMax Code、DSH 的权限由各自的运行时配置或 HS 环境变量决定。无论使用哪个客户端,工具调用超时都应大于 `worker_wait` 的等待时间。若 daemon 使用 `--state-dir`,MCP 的 args 也要指向同一目录。
|
|
235
|
-
|
|
236
|
-
需要将多个 Master 会话分开时,为各 MCP 进程固定不同的会话标识:
|
|
237
|
-
|
|
238
|
-
```bash
|
|
239
|
-
node dist/src/mcp.js --owner-ref <stable-session-reference> --notify-none
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
该连接只能操作本会话的 Worker 和通知 ACK,不继承共享 daemon 的 Codex 通知目标。旧 Worker 不自动归入新会话,仍可通过全局 CLI 查询。归属检查是路由护栏,不是操作系统安全沙箱。DSH 插件会自动配置这些参数。
|
|
243
|
-
|
|
244
|
-
### 推荐权限
|
|
245
|
-
|
|
246
|
-
HS 的推荐默认是让原生 Harness 直接执行完整任务,不为普通文件/命令操作增加人工审批:
|
|
247
|
-
|
|
248
|
-
| 运行时 | 推荐设置 | 说明 |
|
|
249
|
-
| --- | --- | --- |
|
|
250
|
-
| Qoder CLI | `HARNESS_SUPERVISOR_QODER_PERMISSION_MODE=bypass_permissions` | ACP 下映射为 `yolo`(Auto-approves all tools);不设置时也是该默认 |
|
|
251
|
-
| MiniMax Code | `HARNESS_SUPERVISOR_MCODE_PERMISSION_MODE=bypassPermissions` | 宿主原生默认;不设置时也是该默认 |
|
|
252
|
-
| DSH | `HARNESS_SUPERVISOR_DSH_PERMISSION_MODE=danger-full-access` | 原生默认 `workspace-write` + 审批 `ask`:工作区内写入免审批,工作区外写入会被拒绝并可触发一次性提权。设为 `danger-full-access` 才移除文件沙箱且不再询问;`read-only` 只读。桌面端 UI 的三种模式属于 desktop profile,不会自动传给 ACP |
|
|
253
|
-
| Pi | 由 Pi 自身配置决定 | HS 不管理 Pi 的权限模式 |
|
|
254
|
-
|
|
255
|
-
建议在**启动 daemon 的环境**中显式写出上述值,修改后重启 daemon。只有确实需要逐工具人工审批时,才改为 `default`(Qoder 在 ACP 下会通过 `session/request_permission` 暴露原生选项)。桌面端权限选择器只影响桌面会话。
|
|
256
|
-
|
|
257
|
-
**边界**:这些模式只表示跳过审批,不提供沙箱隔离。Worker 与 daemon 使用同一 OS 用户,仍可访问该用户可访问的文件、进程和网络;高风险任务应使用真正的隔离环境。
|
|
258
|
-
|
|
259
|
-
### MCP 输出模式
|
|
260
|
-
|
|
261
|
-
MCP server 有两种呈现模式,只影响当前 MCP 进程如何返回结果,不改变 daemon、Worker 状态、持久化事件、通知路由或权限边界:
|
|
262
|
-
|
|
263
|
-
- `production`(默认):只返回 Master 执行任务所需字段。`status` 是有界状态快照,不返回事件、时间线或完整结果;`wait` 在完成时返回完整最终结果,需要输入时返回 `pendingInput`,超时只返回状态与游标;`until=event` 未指定 `types` 时只等待 lifecycle 事件,progress 不会结束等待;`events` 只返回 lifecycle 摘要,`run.progress` 不会进入 Production;`list` 使用 Keyset 分页。适合日常使用。
|
|
264
|
-
- `development`:扩展诊断字段白名单(完整 result/pendingInput、`recentEvents`、`lastProgress`、`timeline`、`stderrTail`、PID/session 引用等),但不是原始内部记录直出。用于排查问题,不进入 Master 的默认调用链。
|
|
265
|
-
|
|
266
|
-
配置优先级:命令行 `--mode` > 环境变量 `HARNESS_SUPERVISOR_MCP_MODE` > 默认 `production`。非法值会在 MCP 启动时明确报错退出,不会静默降级,也不使用 `NODE_ENV`。
|
|
267
|
-
|
|
268
|
-
```powershell
|
|
269
|
-
$env:HARNESS_SUPERVISOR_MCP_MODE = 'development' # 或 production
|
|
270
|
-
node D:/Projects/Harness-Supervisor/dist/src/mcp.js
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
`production` 的字段精简只服务于上下文预算,不提供安全隔离;完整诊断可在 `development` 或 CLI/IPC 中获取。完整最终结果不会被展示层截断;`result.truncated` 只表示 Supervisor 存储层已按 `maxResultBytes` 截断。
|
|
274
|
-
|
|
275
|
-
`worker_spawn` 返回样例(接受任务,任务可能仍在运行;`notifyTarget` 是实际持久化目标):
|
|
276
|
-
|
|
277
|
-
```json
|
|
278
|
-
{"id":"w-xxx","accepted":true,"runtime":"pi","status":"running","lastSeq":5,"notifyTarget":{"channel":"none"}}
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
`worker_wait` 完成时返回样例(完整结果只出现一次;默认不带事件):
|
|
282
|
-
|
|
283
|
-
```json
|
|
284
|
-
{"worker":{"id":"w-xxx","runtime":"pi","status":"completed","lastSeq":11,"result":{"text":"最终报告全文","truncated":false},"resumeAvailable":true,"session":{"available":true,"restorable":true}},"terminal":true,"timedOut":false,"nextSeq":11,"hasMore":false}
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
`worker_status` 默认是有界快照:只带 `resultPreview`/`errorPreview` 和必要的 `pendingInput`,不带 `recentEvents`、`lastProgress`、`timeline` 或 `inputState`。需要完整待处理输入时显式传 `includeInput=true`;需要完整结果时用 `worker_wait`。完整结果可从 `worker_wait` 获取,事件历史从 `worker_events` 获取。
|
|
288
|
-
|
|
289
|
-
`worker_list` 返回 `{workers,nextCursor,hasMore}`;把 `nextCursor` 原样传回并保持相同的 `statuses`/`includeArchived` 过滤条件即可遍历完整历史。旧于 0.9.1 的 Daemon 仍可返回第一页;cursor 页会返回带升级指引的 `UNSUPPORTED`,不会把旧严格 Schema 错误直接暴露。
|
|
290
|
-
|
|
291
|
-
## 接口
|
|
292
|
-
|
|
293
|
-
### MCP 工具
|
|
294
|
-
|
|
295
|
-
| 工具 | 用途 |
|
|
296
|
-
| --- | --- |
|
|
297
|
-
| `worker_spawn` | 启动 Worker;prompt 被接受即返回,不等待完成 |
|
|
298
|
-
| `worker_status` | 有界状态快照、pending input 预览、结果/错误预览;完整结果用 `worker_wait` |
|
|
299
|
-
| `worker_list` | 列出 Worker(持久化、跨重启);`{workers,nextCursor,hasMore}` Keyset 分页 |
|
|
300
|
-
| `worker_events` | 增量读取 lifecycle 事件;Production 不返回 `run.progress` 或原始 `data` |
|
|
301
|
-
| `worker_wait` | 有界等待(默认 30s,最大 120s);完成时返回完整结果,超时只返回状态与游标 |
|
|
302
|
-
| `worker_send` | 运行中追加 steer / follow-up |
|
|
303
|
-
| `worker_answer` | 回答输入请求或权限询问 |
|
|
304
|
-
| `worker_cancel` | 取消并确认终态;不影响其他 Worker |
|
|
305
|
-
| `worker_resume` | 用新指令恢复已有 session |
|
|
306
|
-
| `worker_continue` | 在 idle 的 persistent Worker 上提交下一轮;沿用同一 native session |
|
|
307
|
-
| `worker_admin` | pin / unpin、archive / unarchive、retire / unretire |
|
|
308
|
-
| `worker_forget` | 删除终态 Worker 的 HS 记录与事件;保留 native session 文件 |
|
|
309
|
-
| `supervisor_info` | Production 为版本、模式、runtime 与 Worker 计数快照;完整诊断在 Development |
|
|
310
|
-
| `supervisor_notifications` | 读取通知收件箱(production 默认全部未确认;development 默认 pending) |
|
|
311
|
-
| `supervisor_notifications_ack` | 确认通知(幂等) |
|
|
312
|
-
| `supervisor_wake_target` | 可选:登记 Codex thread 以启用队列投递 |
|
|
313
|
-
| `metrics_task_create` | 创建一个可关联多个 Worker 的委托任务 |
|
|
314
|
-
| `metrics_task_show` | 单任务状态、耗时、用量摘要、覆盖率与警告;原始 usage 记录仅在 Development 返回 |
|
|
315
|
-
| `metrics_report` | 区间汇总(按任务创建时间)、覆盖率、未知字段;`includeTasks` 在 Production 返回任务摘要,Development 返回完整详情 |
|
|
316
|
-
| `metrics_record_usage` | 人工补录 Master 或 Worker 用量;支持 `usageId` 幂等 |
|
|
317
|
-
|
|
318
|
-
### CLI 命令
|
|
319
|
-
|
|
320
|
-
| 分类 | 命令 | 用途 |
|
|
321
|
-
| --- | --- | --- |
|
|
322
|
-
| 守护进程 | `up` `down` `daemon` `info` | 启动、关闭、前台运行 daemon,查看版本与状态目录 |
|
|
323
|
-
| Worker 管理 | `spawn` `list` `status` `events` | 创建 Worker,列出、查询状态,增量读取事件 |
|
|
324
|
-
| Worker 通信 | `wait` `send` `answer` `cancel` `resume` `continue` | 有界等待、追加指令、回答输入、取消、恢复、继续同一 Worker 的下一轮 |
|
|
325
|
-
| Worker 管理 | `admin` `forget` | 固定、归档、退役、取消退役;删除 HS 记录但保留 native session |
|
|
326
|
-
| 通知 | `inbox` `ack` `notify-target` `retry-notifications` | 读取与确认收件箱,登记投递目标,重试投递 |
|
|
327
|
-
| 度量 | `metrics create\|show\|report\|export\|record-usage` | 创建任务,查看单任务/汇总报告,导出,补录用量 |
|
|
328
|
-
| 维护 | `prune` `compact` | 清理终态且没有未确认通知的 Worker;压缩终态 Worker 的旧进度事件 |
|
|
329
|
-
|
|
330
|
-
### 状态与事件
|
|
331
|
-
|
|
332
|
-
| 类别 | 值 |
|
|
333
|
-
| --- | --- |
|
|
334
|
-
| 非终态 | `starting` `running` `awaiting_input` |
|
|
335
|
-
| 终态 | `completed` `failed` `cancelled` `crashed` `orphaned` `interrupted` |
|
|
336
|
-
| Worker 事件 | `worker.starting` `worker.started` `worker.session` |
|
|
337
|
-
| 运行事件 | `run.accepted` `run.started` `run.progress` `run.usage` `run.needs_input` `run.input_answered` `run.message_sent` `run.error` `run.completed` `run.failed` `run.cancelled` |
|
|
338
|
-
| 生命周期事件 | `worker.cancel_requested` `worker.exited` `worker.crashed` `worker.orphaned` `worker.interrupted` `worker.resumed` `worker.continued` `worker.resume_failed` |
|
|
339
|
-
|
|
340
|
-
`run.usage` 是结构化、低频的运行时用量报告;`run.progress` 中旧的 `kind=usage` 仍保留以兼容既有事件消费者,但任务度量只消费 `run.usage`。`run.usage` 只描述 Token,不包含费用。
|
|
341
|
-
|
|
342
|
-
`orphaned` 表示 daemon 重启后进程可能仍存活但已失去控制;`interrupted` 表示进程已不在或 PID 已被复用。两者都不代表任务成功,也不会被自动重跑。
|
|
343
|
-
|
|
344
|
-
### 关键语义
|
|
345
|
-
|
|
346
|
-
| 主题 | 语义 |
|
|
347
|
-
| --- | --- |
|
|
348
|
-
| `spawn` | 返回时任务尚未完成;终态以 `wait` / `status` 为准 |
|
|
349
|
-
| `worker_wait` | 有界等待;超时只表示等待窗口结束,不带游标时应先检查当前状态 |
|
|
350
|
-
| `run.message_sent` | 只表示消息被 Harness 接受;模型是否看到或采纳需以事件与结果为准 |
|
|
351
|
-
| `resume` | 使用新进程加载持久化 session;不会续接原进程内存,也不会自动重跑中断任务 |
|
|
352
|
-
| `continue` | 仅用于 `persistent` Worker;要求同一 session 仍可恢复,拒绝时不会创建替代 Worker |
|
|
353
|
-
| `pin` | 保护 Worker 不被 `prune` 或 `forget` 删除 |
|
|
354
|
-
| `archive` | 仅从默认 `list` 隐藏;记录、事件与 session 引用保留 |
|
|
355
|
-
| `retire` | 停止接受新的 `continue` / `resume`;`unretire` 可恢复 |
|
|
356
|
-
| `forget` | 显式删除 HS 记录与事件;native session 文件保留,需无未确认通知 |
|
|
357
|
-
| `prune` | 显式维护操作;只清理终态、未 pin 且没有未确认通知的 Worker |
|
|
358
|
-
| `compact` | 只处理终态、未 pin、无运行中进程且非 orphaned 的 Worker;保留全部生命周期事件与最新进度,seq 游标不变 |
|
|
359
|
-
| `requestId` | 不带 `requestId` 时不具备幂等性;带 `requestId` 时也不提供跨组件的 exactly-once |
|
|
360
|
-
|
|
361
|
-
### Persistent Worker(开发分支能力)
|
|
362
|
-
|
|
363
|
-
> 状态:0.9.2。审批、事件交接与通知修复见 [CHANGELOG](CHANGELOG.md);MCP 返回契约变更与真实 Qoder / MiniMax Code 验收见 [0.9.1 交付报告](docs/2026-11-10-hs-0.9.1-report.md)。
|
|
364
|
-
|
|
365
|
-
`worker_spawn` 传入 `persistence="persistent"`(CLI 为 `spawn --persistence persistent`)后,Worker 的身份和 native session 会跨 Turn 保留。每轮结束后 Activation 进程退出,`status` 仍记录本轮终态(通常为 `completed`),派生字段 `lifecycle` 变为 `idle`;下一轮通过 `worker_continue` 在同一个 `workerId` 和同一个 session 上启动新的 Activation。
|
|
366
|
-
|
|
367
|
-
| 字段 | 含义 |
|
|
368
|
-
| --- | --- |
|
|
369
|
-
| `persistence` | `oneshot`(默认,兼容旧行为)或 `persistent` |
|
|
370
|
-
| `lifecycle` | `active` `awaiting_input` `activating` `idle` `orphaned` `unavailable` `unknown`;由状态、进程与 session 可用性派生,不额外持久化 |
|
|
371
|
-
| `session.available` | 记录的 session locator 存在 |
|
|
372
|
-
| `session.restorable` | 当前可以安全启动新的 Activation;进程可能仍在运行、Worker orphaned 或文件缺失时为 `false` |
|
|
373
|
-
| `session.reason` | `restorable=false` 的原因,例如 `session_file_missing`、`process_may_be_running` |
|
|
374
|
-
|
|
375
|
-
`continue` 与 `resume` 分工:`continue` 用于正常交付下一轮工作;`resume` 保留原有恢复语义。Worker 为 `persistent` 但 session 不可恢复时,`continue` 返回真实错误,不会静默新建 Worker 或伪造上下文连续性。旧记录没有该字段时按 `oneshot` 读取。
|
|
376
|
-
|
|
377
|
-
进程退出只释放运行资源;HS 不会因 Turn 结束删除 native session,也不会自动把 Worker 标记为退役。`pin` 保护记录,`archive` 只影响默认列表,`retire` 阻止新的 Turn,`forget` 删除 HS 记录与事件但保留 native session 文件,`compact` 只裁剪旧进度事件、不改动 session。原生 Session 删除尚未提供。
|
|
378
|
-
|
|
379
|
-
### 存储诊断
|
|
380
|
-
|
|
381
|
-
`supervisor_info`(CLI 为 `info`)的 `storage` 字段提供状态目录的事件字节总量、最大事件文件、active / idle / other Worker 数量以及上次启动各阶段耗时。数值来自已加载的事件文件长度,不做额外全盘扫描;`startup.store.eventBytes` 是启动时快照,不是当前值。
|
|
382
|
-
|
|
383
|
-
`compact [workerId] [--keep-progress 200] [--dry-run] [--json]` 用于压缩终态 Worker 的事件日志:保留全部非 `run.progress` 事件、最新 N 条进度以及最后一条事件,原子重写 `events.jsonl` 并在记录中写入 `compacted` 标记。序列号保持不变,因此已有游标仍可继续读取;`worker.compacted.retainedFromSeq` 标明仍保留的最小序号,失去的中间序号属于显式压缩,重启时不会被误报为历史损坏。压缩后的记录仍可 `continue`(persistent Worker),`forget` 与原生 session 行为不变。`--dry-run` 只报告可回收的事件与字节数;活跃、orphaned、pinned 或仍有运行中进程的 Worker 会被拒绝或跳过。
|
|
384
|
-
|
|
385
|
-
### 持久化与幂等
|
|
386
|
-
|
|
387
|
-
每个 Worker 的事件缓存最多保存最近 500 条,完整历史仍在追加日志中。启动流式扫描日志,历史查询按需异步分页,稀疏字节索引支持深页读取;通知重建使用单次流式扫描。已知的事件缺口或追加失败会明确报错,不将残缺历史伪装为完整结果;单个损坏日志不会阻止其他 Worker 继续受管。
|
|
388
|
-
|
|
389
|
-
直接使用 TypeScript/JavaScript 库的调用方需注意:`Supervisor.events()` 返回 Promise,应使用 `await`;`Store.getEvents()` 只访问缓存,`truncated:true` 表示需调用 `await Store.readEvents()` 获取完整历史,`Store.scanEvents()` 用于全历史流式处理。
|
|
390
|
-
|
|
391
|
-
带 `requestId` 的副作用操作会先等待准入记录写入,再启动进程或发送消息;持久化失败会明确返回错误。通知也在收件箱记录写入确认后才调用宿主。上述承诺针对进程崩溃和写入失败,不提供断电 fsync、磁盘损坏或跨组件 exactly-once 保证。
|
|
392
|
-
|
|
393
|
-
### Worker 报告协议与命令守卫
|
|
394
|
-
|
|
395
|
-
HS 是唯一受支持的 Worker 通知生产路径。`spawn` / `resume` 发送的任务提示会前置固定协议块:Worker 以最终答复结束本次运行,不得调用 `codex queue` 或其他宿主接口向 Master 会话注入报告,也不得为此另起 Codex 会话;需要决策时使用自带 harness 的 permission/input。
|
|
396
|
-
|
|
397
|
-
运行时再加一层最小护栏:Daemon 启动时若在 PATH 中找到 Codex CLI,就在 `<stateDir>/worker-guard/bin` 生成 `codex` shim,并只把该目录前置到 **Worker 进程**的 PATH。`codex queue` 返回退出码 2、向工具 stderr 写一行说明,并在 `<stateDir>/worker-guard/worker-guard.jsonl` 追加 `{ts, workerId, argv, cwd}`;其他子命令转发给真实 CLI。Daemon 自身的 PATH 与通知投递不受影响。若 Codex 是后来才安装的,重启 Daemon 后护栏才会生成。
|
|
398
|
-
|
|
399
|
-
```powershell
|
|
400
|
-
# 暂时关闭护栏(仅诊断/兼容)
|
|
401
|
-
$env:HARNESS_SUPERVISOR_WORKER_GUARD = '0'
|
|
402
|
-
# 关闭任务提示中的协议块(仅诊断/兼容)
|
|
403
|
-
$env:HARNESS_SUPERVISOR_WORKER_PROTOCOL = '0'
|
|
404
|
-
```
|
|
405
|
-
|
|
406
|
-
**边界**:这是一层护栏与审计,不构成安全边界。Worker 使用绝对路径、其他宿主接口、修改 PATH 或覆盖 shim 都能绕过;同一 OS 用户下 HS 无法仅凭 PATH 阻止。Pi 已用真实进程和 shell 验证拦截与放行;Qoder、MiniMax Code 与 DSH 复用同一环境注入,但其工具 shell 的 PATH 解析未单独验证。护栏失败(找不到 Codex、目录不可写)只记 `daemon.log`,不阻断 Worker 启动。
|
|
407
|
-
|
|
408
|
-
## 运行时支持
|
|
409
|
-
|
|
410
|
-
| Runtime | 状态 | 已验证范围 |
|
|
411
|
-
| --- | --- | --- |
|
|
412
|
-
| Pi | 完整 | 原生 RPC;spawn / steer / follow-up / cancel / resume;Persistent 3 轮连续协作(同 Worker / 同 Session);dialog 尚未单独真实覆盖 |
|
|
413
|
-
| Qoder CLI | 实验性 | ACP 默认:spawn / resume / 审批 / 提问 / 取消 / Persistent 3 轮连续协作。stream-json 回退:spawn / cancel / resume;steer、follow-up 被接受但未生效 |
|
|
414
|
-
| MiniMax Code | 实验性 | ACP:spawn / 完成 / 取消 / resume / Persistent 3 轮连续协作;活跃回合内 steer;queue 入队;Ask 模式尚未触发 |
|
|
415
|
-
| DSH | PoC | ACP v1:spawn / resume / 模型与推理配置 / 工作区写入 / 工作区外提权 / 完全权限 / 取消 / Persistent 3 轮连续协作 |
|
|
416
|
-
|
|
417
|
-
### 操作能力对比
|
|
418
|
-
|
|
419
|
-
`是` 表示适配器实现了该能力;`有条件` 表示依赖特定传输、扩展或版本,或只有协议/单元测试;`否` 表示明确不支持。真实运行覆盖范围见上表。
|
|
420
|
-
|
|
421
|
-
| 操作 | Pi | Qoder ACP(默认) | Qoder stream-json 回退 | MiniMax Code | DSH |
|
|
422
|
-
| --- | --- | --- | --- | --- | --- |
|
|
423
|
-
| 协议 | Pi RPC | ACP v1 | stream-json | ACP | ACP v1 |
|
|
424
|
-
| spawn / 单轮 prompt | 是 | 是 | 是 | 是 | 是 |
|
|
425
|
-
| 流式文本 / 思考 / 工具事件 | 是 | 是 | 是 | 是 | 是(无 plan) |
|
|
426
|
-
| 取消 | 是 | 是 | 是 | 是 | 是 |
|
|
427
|
-
| resume | 是(Pi session 文件) | 是(`session/load`) | 是(`--resume`,校验 session id) | 是(`session/load`) | 是(`session/resume`,要求相同绝对 cwd) |
|
|
428
|
-
| Idle continue(同一 Worker / Session 下一轮) | L3(真实 3 轮) | L3(真实 3 轮) | L2(未跑 3 轮;resume 已真实验证) | L3(真实 3 轮) | L3(真实 3 轮) |
|
|
429
|
-
| 运行中 steer | 是 | 否 | 有条件(被接受,未验证生效) | 有条件(需 steer 扩展;活跃回合内已验证) | 否 |
|
|
430
|
-
| follow-up 队列 | 是 | 否 | 有条件(被接受,未验证生效) | 有条件(需 queue 扩展;已验证入队) | 否 |
|
|
431
|
-
| 交互输入(审批 / 提问 / 对话框) | 是(extension dialog) | 是(permission + elicitation) | 1.1.79 及以前支持;1.1.82 不支持提问/审批 | 是(Ask 模式触发时) | 仅审批;请求不含工具名/输入,无 elicitation |
|
|
432
|
-
| 权限模式控制 | 由 Pi 自身配置,HS 不管理 | 5 种 ACP 模式映射(plan 无对应) | 支持(默认 `bypass_permissions`) | `bypassPermissions` 默认 / `default` 为 Ask | 3 种(默认 `workspace-write` + `ask`) |
|
|
433
|
-
| 模型 / 思考配置 | 是 | 是 | 是 | 否(忽略,走运行时配置) | 是(model 对 + `reasoning_effort`) |
|
|
434
|
-
| provider 参数 | 是 | 否(写进 model 名) | 否(写进 model 名) | 否(写进 model 名) | 是(model 重名时必须) |
|
|
435
|
-
| 工具白名单 | 是 | 否 | 是 | 否(忽略) | 否 |
|
|
436
|
-
| extraArgs | 是(禁改保留参数) | 是(禁改保留参数) | 是(禁改保留参数) | 仅校验,不转发 | 否(明确 `UNSUPPORTED`) |
|
|
437
|
-
| Token 用量 | 是(原生 usage) | 未知(1.1.82 计数全零) | 有条件(`result.usage` 存在时) | 否(仅上下文占用) | 否(仅上下文占用) |
|
|
438
|
-
| pause | 否 | 否 | 否 | 否 | 否 |
|
|
439
|
-
|
|
440
|
-
说明:
|
|
441
|
-
|
|
442
|
-
- MiniMax Code 的 `model`、`thinking` 和 `tools` 不会传给其 ACP 会话;`extraArgs` 只做保留参数校验,不会转发。需要这些设置时应在 MiniMax Code 自身配置中完成。
|
|
443
|
-
- Qoder ACP 的 `tools` 会被明确拒绝,需要工具白名单时请使用 stream-json 回退;Qoder 的 `provider` 需要写进 model 名。
|
|
444
|
-
- DSH 的 `tools` 与 `extraArgs` 会被明确拒绝;其 `usage_update` 只表示上下文占用。DSH 仍为 PoC,未合并进生产默认。
|
|
445
|
-
|
|
446
|
-
用量采集边界:Pi 只在 assistant message 原生提供 `usage` 时记录;Qoder 只在 `result.usage` 存在时记录;MiniMax Code 0.6.13 的 ACP 只提供上下文 `used`/`size` 与 `cost=0 USD`,prompt result 不含 usage;DSH 的 `usage_update` 同样只表示上下文占用,不写 `run.usage`。Master 用量不会从宿主会话自动读取,必须显式补录。
|
|
447
|
-
|
|
448
|
-
## 边界
|
|
449
|
-
|
|
450
|
-
- **无沙箱**:`cwd` 只表示默认工作目录;Worker 与 daemon 同用户、继承环境变量,可访问该用户可访问的文件与网络。
|
|
451
|
-
- **单用户本地**:没有多用户、远程 MCP 认证或配额管理;生命周期控制不提供资源限制。
|
|
452
|
-
- **投递语义为 at-least-once**:通知与队列投递可能重复;`delivered` 只表示已写入目标,Master 是否读到取决于宿主。
|
|
453
|
-
- **唤醒受宿主约束**:只有宿主加载了目标 thread,队列消息才会触发新回合。
|
|
454
|
-
- **度量为参考值**:Token 来自运行时事件或人工补录,未与 provider 账单核对;本系统不采集费用,验收、返工、干预和对照基线也未采集。Master 用量缺失即未知,不会按零计算。
|
|
455
|
-
- **统计故障不阻断执行**:度量存储不可用时 Worker 仍可运行,但该 Worker 可能没有任务关联或用量记录,报告会明确说明。
|
|
456
|
-
- **崩溃后不接管**:daemon 重启只做状态对账,不会重新接上原管道,也不会自动重跑。
|
|
457
|
-
- **平台**:Windows 原生已验证;WSL / 其他 POSIX 需自行验证。
|
|
458
|
-
|
|
459
|
-
## License
|
|
460
|
-
|
|
461
|
-
MIT
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# Harness Supervisor
|
|
4
|
+
|
|
5
|
+
     
|
|
6
|
+
|
|
7
|
+
<hr />
|
|
8
|
+
|
|
9
|
+
**本地、轻量、运行时无关的 Agent Worker 生命周期与通信层**
|
|
10
|
+
|
|
11
|
+
主 Agent(下称 **Master**)通过 **CLI** 或 **MCP** 启动、观察、指导、取消和恢复其他厂商的原生 Harness;每个被启动的 Harness 进程称为 **Worker**。HS 只管理进程、会话与事件;规划、工具调用和上下文管理由各 Harness 自己完成。
|
|
12
|
+
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
## 核心理念
|
|
16
|
+
|
|
17
|
+
HS 的目标:以尽可能低的开销,让独立的原生 Harness Worker 被可靠地调用、观察、控制和协作。
|
|
18
|
+
|
|
19
|
+
**不做**
|
|
20
|
+
|
|
21
|
+
- 新的 Agent 框架或 Agent Loop;
|
|
22
|
+
- Planner / Reviewer / Challenger 等角色拆分;
|
|
23
|
+
- 任务 DAG、投票、模型路由或固定工作流;
|
|
24
|
+
- Harness 内部的规划、工具调用与上下文管理;
|
|
25
|
+
- 额外 LLM 做调度或生命周期管理;
|
|
26
|
+
- 多用户、远程调度、配额管理或安全沙箱。
|
|
27
|
+
|
|
28
|
+
**设计原则**
|
|
29
|
+
|
|
30
|
+
- **原生优先**:优先使用运行时原生协议、Session 与控制能力;不为统一接口伪造底层不支持的行为。
|
|
31
|
+
- **提供能力,不规定工作流**:任务如何拆分、是否多轮协作,由 Master 自行决定。
|
|
32
|
+
- **状态来自证据**:`completed` 只在 Harness 报告 settle、或进程退出被确认后出现。
|
|
33
|
+
- **先落盘再交付**:重要事件与通知先写入本地追加日志,消费者离线不丢。
|
|
34
|
+
|
|
35
|
+
## 当前接入
|
|
36
|
+
|
|
37
|
+
| Runtime | 传输 | 状态 |
|
|
38
|
+
| --- | --- | --- |
|
|
39
|
+
| Pi Agent | Pi 原生 RPC(Pi v1.3+) | 完整支持 |
|
|
40
|
+
| Qoder CLI | 官方 ACP 默认,stream-json 可回退 | 实验性 |
|
|
41
|
+
| MiniMax Code | ACP over ndJSON | 实验性 |
|
|
42
|
+
| DeepSeek Harness / DSH | 官方 ACP(`dsh --profile acp`) | PoC |
|
|
43
|
+
|
|
44
|
+
## 功能
|
|
45
|
+
|
|
46
|
+
- **独立 Worker**:每个 Worker 是一个原生 Harness 子进程,有自己的 cwd、session 与进程树。Worker 属于 daemon,客户端断开后继续运行。
|
|
47
|
+
- **完整生命周期**:spawn / status / events / wait / send / answer / cancel / resume,含并发准入、取消与关停屏障、重启对账。
|
|
48
|
+
- **增量事件**:每 Worker 一条追加式事件流,`seq` 单调递增,支持 `sinceSeq` 游标;状态变化与普通进度分开返回。
|
|
49
|
+
- **持久化通知收件箱**:完成 / 失败 / 取消 / 需要输入 / 崩溃 / 失联等事件生成稳定 ID 的通知,可查询、可确认、跨重启不重复;默认不产生任何外部调用。
|
|
50
|
+
- **可选队列投递**:登记 Codex thread 后,可用官方 `codex queue` 把简短通知写入该 thread;是否真正唤醒 Master 取决于宿主是否加载该 thread。
|
|
51
|
+
- **可选请求幂等**:`spawn` / `resume` / `send` 支持 `requestId`;重复请求不会重复执行,结果不确定时报 `UNCERTAIN`。
|
|
52
|
+
- **任务度量**:每次 `spawn` 自动创建或关联一个委托任务;记录 Worker 终态、耗时、可得的运行时 Token 用量,并生成带覆盖率、来源和未知字段的单任务/汇总报告。费用不采集,验收、返工与干预尚未采集。
|
|
53
|
+
- **Qoder 双传输**:默认使用官方 ACP,可回退 stream-json;两种传输的会话句柄不互换,能力差异如实报告。
|
|
54
|
+
- **DSH ACP 接入**:支持 spawn / 事件 / 取消 / `session/resume` / 模型与推理强度配置 / 权限提权应答;桌面端安装可自动发现,也可用 `HARNESS_SUPERVISOR_DSH_ENTRY` 指定入口。
|
|
55
|
+
- **统一入口**:CLI、MCP、IPC 共享同一个 daemon 与同一份状态。
|
|
56
|
+
|
|
57
|
+
## 架构
|
|
58
|
+
|
|
59
|
+
```mermaid
|
|
60
|
+
flowchart TB
|
|
61
|
+
Client["Master / 外部客户端"]
|
|
62
|
+
|
|
63
|
+
subgraph interfaces["接口"]
|
|
64
|
+
CLI["CLI"]
|
|
65
|
+
MCP["MCP (stdio)"]
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
IPC["SupervisorClient<br/>本地 IPC(named pipe / Unix socket + token)"]
|
|
69
|
+
|
|
70
|
+
subgraph daemon["Supervisor daemon"]
|
|
71
|
+
direction TB
|
|
72
|
+
Lifecycle["生命周期<br/>状态机 / 并发准入 / wait / 输入 / 取消 / 恢复"]
|
|
73
|
+
Events["事件<br/>追加式日志 + seq 游标"]
|
|
74
|
+
Inbox["通知<br/>持久化收件箱"]
|
|
75
|
+
Metrics["度量<br/>任务 / 用量追加日志"]
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
subgraph adapters["Runtime Adapters"]
|
|
79
|
+
Pi["Pi 原生 RPC<br/>Pi 子进程"]
|
|
80
|
+
Qoder["Qoder ACP 默认 / stream-json 回退<br/>qodercli 子进程"]
|
|
81
|
+
Mcode["MiniMax Code ACP(ndJSON)<br/>mcode acp 子进程"]
|
|
82
|
+
Dsh["DeepSeek Harness ACP(ndJSON)<br/>dsh --profile acp 子进程"]
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
Client --> CLI
|
|
86
|
+
Client --> MCP
|
|
87
|
+
CLI --> IPC
|
|
88
|
+
MCP --> IPC
|
|
89
|
+
IPC --> Lifecycle
|
|
90
|
+
Lifecycle --> Events
|
|
91
|
+
Lifecycle --> Inbox
|
|
92
|
+
Lifecycle --> Metrics
|
|
93
|
+
Lifecycle --> Pi
|
|
94
|
+
Lifecycle --> Qoder
|
|
95
|
+
Lifecycle --> Mcode
|
|
96
|
+
Lifecycle --> Dsh
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
| 模块 | 职责 |
|
|
100
|
+
| --- | --- |
|
|
101
|
+
| `src/adapters/` | Pi / Qoder / MiniMax Code / DSH 的运行时适配,以及通用 ACP ndJSON 传输 |
|
|
102
|
+
| `src/supervisor.ts` | 状态机、wait、send/answer、cancel、resume、重启对账 |
|
|
103
|
+
| `src/store.ts` | Worker 记录、追加式事件日志、游标、持久化 |
|
|
104
|
+
| `src/metrics.ts` | 任务/用量记录、独立追加日志、覆盖率与报告计算 |
|
|
105
|
+
| `src/notify.ts` | 通知收件箱、确认、可选投递与重试 |
|
|
106
|
+
| `src/ipc/` | 本地 IPC、token 认证、server/client |
|
|
107
|
+
| `src/cli.ts` / `src/mcp.ts` | 两个入口,共用同一套核心行为 |
|
|
108
|
+
| `src/types.ts` | 公开类型、状态与事件 schema |
|
|
109
|
+
|
|
110
|
+
## 工作原理
|
|
111
|
+
|
|
112
|
+
1. **进程归属**:daemon 启动 Harness 子进程并持有其 stdio;CLI/MCP 只是客户端,断开不影响 Worker。
|
|
113
|
+
2. **Adapter 只做翻译**:把 Harness 原生事件映射为统一事件,把统一指令映射为原生命令,保留运行时自己的语义。
|
|
114
|
+
3. **状态来自证据**:`spawn` 返回只表示 prompt 被接受;`completed` 只在 Harness 报告 settle、或进程退出被确认后出现。
|
|
115
|
+
4. **恢复显式且受限**:daemon 重启不会接管原进程;`resume` 使用“新进程 + 加载持久化 session + 新 prompt”,并校验 session,不重放旧操作。
|
|
116
|
+
5. **先落盘再交付**:重要事件与通知写入本地追加日志;投递语义为 at-least-once。
|
|
117
|
+
|
|
118
|
+
## 快速开始
|
|
119
|
+
|
|
120
|
+
要求:Node.js >= 22.19;Pi >= 1.3 并已配置 provider/凭据。
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
npm install
|
|
124
|
+
npm run build
|
|
125
|
+
node dist/src/cli.js up # 启动本地 daemon(已在运行则直接返回)
|
|
126
|
+
|
|
127
|
+
# 启动 Worker:只表示 prompt 被接受,任务可能仍在运行
|
|
128
|
+
node dist/src/cli.js spawn \
|
|
129
|
+
--cwd D:/work/demo \
|
|
130
|
+
--prompt "Create hello.txt containing hello. Then reply exactly DONE." \
|
|
131
|
+
--name demo-worker --json
|
|
132
|
+
|
|
133
|
+
node dist/src/cli.js status <workerId> # 状态、最近事件与结果
|
|
134
|
+
node dist/src/cli.js wait <workerId> --timeout-ms 60000
|
|
135
|
+
node dist/src/cli.js send <workerId> --message "也写一个时间戳" --mode steer
|
|
136
|
+
node dist/src/cli.js cancel <workerId>
|
|
137
|
+
node dist/src/cli.js resume <workerId> --prompt "继续并总结改动"
|
|
138
|
+
node dist/src/cli.js metrics show <taskId> # 任务状态、Worker 耗时与用量
|
|
139
|
+
node dist/src/cli.js metrics report # 汇总、覆盖率与未知字段
|
|
140
|
+
node dist/src/cli.js down # 优雅关闭(会取消活动 Worker)
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
默认状态目录为 `~/.harness-supervisor`,可用 `--state-dir <dir>` 或 `HARNESS_SUPERVISOR_HOME` 隔离实例。完整命令见 `node dist/src/cli.js help`,示例见 [`examples/cli-walkthrough.sh`](examples/cli-walkthrough.sh)。
|
|
144
|
+
|
|
145
|
+
### DSH 插件
|
|
146
|
+
|
|
147
|
+
让 DSH 委派和管理 Pi、Qoder、MiniMax Code 等原生 Worker,并在会话中查看任务、结果和审批。插件已包含 HS 核心与 WebUI,无需额外安装或编译。
|
|
148
|
+
|
|
149
|
+
[项目仓库](https://gitcode.com/chenpi_1/harness-supervisor) · [插件安装与配置](packages/dsh-plugin/README.md)
|
|
150
|
+
|
|
151
|
+
### 在浏览器中使用 WebUI
|
|
152
|
+
|
|
153
|
+
WebUI 是可选功能,默认不开端口。已安装独立 HS 时,运行:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
harness-sup ui # 启用并在系统浏览器中打开
|
|
157
|
+
harness-sup ui --stop # 关闭 WebUI,Worker 继续运行
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
源码运行方式为 `node dist/src/cli.js ui`。浏览器和 DSH 使用同一套界面:可按工作目录分组查看 Worker,读取结果、事件和用量,回答请求或取消任务;创建与续接任务仍交给 Master。
|
|
161
|
+
|
|
162
|
+
界面仅供本机使用,监听 `127.0.0.1`。CLI 和 DSH 的人工界面均可查看当前 HS 实例的全部 Worker;DSH 默认展开当前对话分组,模型工具仍保持会话隔离。daemon 或 WebUI 重启后,需从对应入口重新打开。
|
|
163
|
+
|
|
164
|
+
### 更新 HS
|
|
165
|
+
|
|
166
|
+
**更新不需要拉取源码。** 可以选择下面任一方式:
|
|
167
|
+
|
|
168
|
+
| 使用方式 | 更新步骤 |
|
|
169
|
+
| --- | --- |
|
|
170
|
+
| DSH 插件 | 安装新版插件 `.tgz`,再到设置中点击 **Harness Supervisor → 应用配套 HS 核心**。 |
|
|
171
|
+
| 独立 HS | 安装预构建核心 `.tgz`,再将运行中的核心切换到该版本;受控切换命令见下面的高级说明。 |
|
|
172
|
+
|
|
173
|
+
更新插件只准备新核心,**不会立即替换运行实例**。点击应用后,HS 暂停接收新任务,等待已有任务与队列结束再切换;等待期间仍可回答请求、取消任务,也可取消此次更新。切换完成后,使用同一状态目录、支持托管更新的 CLI、MCP 和插件共用新核心,源码目录与全局安装文件不会被覆盖。
|
|
174
|
+
|
|
175
|
+
目前按 `.tgz` 安装包分发,尚未提供在线检查新版功能。从旧 `0.9.2` 首次迁入时,需要先安排维护窗口、处理活动 Worker 并停止旧 daemon;之后兼容版本可使用上述受控更新。
|
|
176
|
+
|
|
177
|
+
<details>
|
|
178
|
+
<summary>独立 HS 的核心切换命令</summary>
|
|
179
|
+
|
|
180
|
+
独立核心包可用 `npm install -g <核心包.tgz>` 安装。**安装客户端不等于切换正在运行的核心**;对支持受控更新的 daemon,使用新核心的安装目录准备候选版本,再应用返回的 runtime ID:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
harness-sup runtime prepare --source <新核心的安装目录>
|
|
184
|
+
harness-sup runtime apply --runtime-id <返回的id> --intent-id <本次更新的唯一标识>
|
|
185
|
+
harness-sup runtime status
|
|
186
|
+
harness-sup runtime cancel --intent-id <同一标识> # 仅等待任务结束期间可取消
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
这些命令应使用与现有实例相同的 `--state-dir`。首次升级旧 `0.9.2` 须走前述维护窗口,不能使用这些命令热切换。无法确认进程退出时,自动更新会停止;不要删除锁或并行启动旧核心强行恢复。状态目录中的 `runtime-update.json`、`runtime-update.log` 和 `runtime-backups/` 保留恢复线索。
|
|
190
|
+
|
|
191
|
+
</details>
|
|
192
|
+
|
|
193
|
+
### 全新 clone / 另一台机器
|
|
194
|
+
|
|
195
|
+
仓库只包含源码、测试与文档;`dist/` 被 `.gitignore` 忽略,必须在本机构建。
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
git clone --branch main https://gitcode.com/chenpi_1/harness-supervisor.git Harness-Supervisor
|
|
199
|
+
cd Harness-Supervisor
|
|
200
|
+
npm ci # 按 package-lock.json 安装,可复现
|
|
201
|
+
npm run build # 生成 dist/(核心 + 共用 WebUI)
|
|
202
|
+
npm run typecheck # 可选:类型检查
|
|
203
|
+
node dist/src/cli.js up
|
|
204
|
+
node dist/src/cli.js info # 核对 version=0.10.2 与 stateDir
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
若 `npm ci` 因网络镜像失败,改用 `npm install`,再用 `git status` 确认 `package-lock.json` 未被意外改写。
|
|
208
|
+
|
|
209
|
+
本机状态与凭据不会随 Git 迁移:状态目录(Worker 记录、事件日志、session、收件箱)、daemon 进程与 IPC 端点、MCP 客户端注册、各 Harness 自己的登录态都必须在本机建立。复制源码不会复制运行状态;缺少凭据时 `spawn` 会失败,这属于运行时的环境问题。
|
|
210
|
+
|
|
211
|
+
### MCP 接入
|
|
212
|
+
|
|
213
|
+
MCP server 是 daemon 的客户端;daemon 需要独立启动并保持运行。若宿主会随会话清理 MCP server 的子进程树,不要在宿主内自动拉起 daemon:
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
node <clone>/dist/src/cli.js up
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
在宿主支持的任何 stdio MCP 配置中注册以下 server,`command` 与 `args` 指向本机 clone 的绝对路径:
|
|
220
|
+
|
|
221
|
+
```json
|
|
222
|
+
{
|
|
223
|
+
"mcpServers": {
|
|
224
|
+
"harness-supervisor": {
|
|
225
|
+
"command": "node",
|
|
226
|
+
"args": ["<clone>/dist/src/mcp.js"]
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
MCP 协议本身不规定客户端配置字段。常见的 `mcpServers` 写法通常只有 `command`、`args`、`env`,工具超时与审批由各客户端自行定义:Codex 使用 `tool_timeout_sec` / `default_tools_approval_mode`,Claude Code 使用每服务器 `timeout` / `MCP_TOOL_TIMEOUT`,Qoder 使用 `timeout` / `trust`,Cursor 主要通过 UI 与 Run Modes 控制审批。请以所用客户端文档为准,JSON 形式可参考 [`examples/mcp.json`](examples/mcp.json)。
|
|
233
|
+
|
|
234
|
+
这些宿主侧设置只影响宿主如何审批、超时调用 **HS 的 MCP 工具**(`worker_spawn`、`worker_wait` 等),不会改变 Worker 内部的权限;Pi、Qoder、MiniMax Code、DSH 的权限由各自的运行时配置或 HS 环境变量决定。无论使用哪个客户端,工具调用超时都应大于 `worker_wait` 的等待时间。若 daemon 使用 `--state-dir`,MCP 的 args 也要指向同一目录。
|
|
235
|
+
|
|
236
|
+
需要将多个 Master 会话分开时,为各 MCP 进程固定不同的会话标识:
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
node dist/src/mcp.js --owner-ref <stable-session-reference> --notify-none
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
该连接只能操作本会话的 Worker 和通知 ACK,不继承共享 daemon 的 Codex 通知目标。旧 Worker 不自动归入新会话,仍可通过全局 CLI 查询。归属检查是路由护栏,不是操作系统安全沙箱。DSH 插件会自动配置这些参数。
|
|
243
|
+
|
|
244
|
+
### 推荐权限
|
|
245
|
+
|
|
246
|
+
HS 的推荐默认是让原生 Harness 直接执行完整任务,不为普通文件/命令操作增加人工审批:
|
|
247
|
+
|
|
248
|
+
| 运行时 | 推荐设置 | 说明 |
|
|
249
|
+
| --- | --- | --- |
|
|
250
|
+
| Qoder CLI | `HARNESS_SUPERVISOR_QODER_PERMISSION_MODE=bypass_permissions` | ACP 下映射为 `yolo`(Auto-approves all tools);不设置时也是该默认 |
|
|
251
|
+
| MiniMax Code | `HARNESS_SUPERVISOR_MCODE_PERMISSION_MODE=bypassPermissions` | 宿主原生默认;不设置时也是该默认 |
|
|
252
|
+
| DSH | `HARNESS_SUPERVISOR_DSH_PERMISSION_MODE=danger-full-access` | 原生默认 `workspace-write` + 审批 `ask`:工作区内写入免审批,工作区外写入会被拒绝并可触发一次性提权。设为 `danger-full-access` 才移除文件沙箱且不再询问;`read-only` 只读。桌面端 UI 的三种模式属于 desktop profile,不会自动传给 ACP |
|
|
253
|
+
| Pi | 由 Pi 自身配置决定 | HS 不管理 Pi 的权限模式 |
|
|
254
|
+
|
|
255
|
+
建议在**启动 daemon 的环境**中显式写出上述值,修改后重启 daemon。只有确实需要逐工具人工审批时,才改为 `default`(Qoder 在 ACP 下会通过 `session/request_permission` 暴露原生选项)。桌面端权限选择器只影响桌面会话。
|
|
256
|
+
|
|
257
|
+
**边界**:这些模式只表示跳过审批,不提供沙箱隔离。Worker 与 daemon 使用同一 OS 用户,仍可访问该用户可访问的文件、进程和网络;高风险任务应使用真正的隔离环境。
|
|
258
|
+
|
|
259
|
+
### MCP 输出模式
|
|
260
|
+
|
|
261
|
+
MCP server 有两种呈现模式,只影响当前 MCP 进程如何返回结果,不改变 daemon、Worker 状态、持久化事件、通知路由或权限边界:
|
|
262
|
+
|
|
263
|
+
- `production`(默认):只返回 Master 执行任务所需字段。`status` 是有界状态快照,不返回事件、时间线或完整结果;`wait` 在完成时返回完整最终结果,需要输入时返回 `pendingInput`,超时只返回状态与游标;`until=event` 未指定 `types` 时只等待 lifecycle 事件,progress 不会结束等待;`events` 只返回 lifecycle 摘要,`run.progress` 不会进入 Production;`list` 使用 Keyset 分页。适合日常使用。
|
|
264
|
+
- `development`:扩展诊断字段白名单(完整 result/pendingInput、`recentEvents`、`lastProgress`、`timeline`、`stderrTail`、PID/session 引用等),但不是原始内部记录直出。用于排查问题,不进入 Master 的默认调用链。
|
|
265
|
+
|
|
266
|
+
配置优先级:命令行 `--mode` > 环境变量 `HARNESS_SUPERVISOR_MCP_MODE` > 默认 `production`。非法值会在 MCP 启动时明确报错退出,不会静默降级,也不使用 `NODE_ENV`。
|
|
267
|
+
|
|
268
|
+
```powershell
|
|
269
|
+
$env:HARNESS_SUPERVISOR_MCP_MODE = 'development' # 或 production
|
|
270
|
+
node D:/Projects/Harness-Supervisor/dist/src/mcp.js
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
`production` 的字段精简只服务于上下文预算,不提供安全隔离;完整诊断可在 `development` 或 CLI/IPC 中获取。完整最终结果不会被展示层截断;`result.truncated` 只表示 Supervisor 存储层已按 `maxResultBytes` 截断。
|
|
274
|
+
|
|
275
|
+
`worker_spawn` 返回样例(接受任务,任务可能仍在运行;`notifyTarget` 是实际持久化目标):
|
|
276
|
+
|
|
277
|
+
```json
|
|
278
|
+
{"id":"w-xxx","accepted":true,"runtime":"pi","status":"running","lastSeq":5,"notifyTarget":{"channel":"none"}}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
`worker_wait` 完成时返回样例(完整结果只出现一次;默认不带事件):
|
|
282
|
+
|
|
283
|
+
```json
|
|
284
|
+
{"worker":{"id":"w-xxx","runtime":"pi","status":"completed","lastSeq":11,"result":{"text":"最终报告全文","truncated":false},"resumeAvailable":true,"session":{"available":true,"restorable":true}},"terminal":true,"timedOut":false,"nextSeq":11,"hasMore":false}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
`worker_status` 默认是有界快照:只带 `resultPreview`/`errorPreview` 和必要的 `pendingInput`,不带 `recentEvents`、`lastProgress`、`timeline` 或 `inputState`。需要完整待处理输入时显式传 `includeInput=true`;需要完整结果时用 `worker_wait`。完整结果可从 `worker_wait` 获取,事件历史从 `worker_events` 获取。
|
|
288
|
+
|
|
289
|
+
`worker_list` 返回 `{workers,nextCursor,hasMore}`;把 `nextCursor` 原样传回并保持相同的 `statuses`/`includeArchived` 过滤条件即可遍历完整历史。旧于 0.9.1 的 Daemon 仍可返回第一页;cursor 页会返回带升级指引的 `UNSUPPORTED`,不会把旧严格 Schema 错误直接暴露。
|
|
290
|
+
|
|
291
|
+
## 接口
|
|
292
|
+
|
|
293
|
+
### MCP 工具
|
|
294
|
+
|
|
295
|
+
| 工具 | 用途 |
|
|
296
|
+
| --- | --- |
|
|
297
|
+
| `worker_spawn` | 启动 Worker;prompt 被接受即返回,不等待完成 |
|
|
298
|
+
| `worker_status` | 有界状态快照、pending input 预览、结果/错误预览;完整结果用 `worker_wait` |
|
|
299
|
+
| `worker_list` | 列出 Worker(持久化、跨重启);`{workers,nextCursor,hasMore}` Keyset 分页 |
|
|
300
|
+
| `worker_events` | 增量读取 lifecycle 事件;Production 不返回 `run.progress` 或原始 `data` |
|
|
301
|
+
| `worker_wait` | 有界等待(默认 30s,最大 120s);完成时返回完整结果,超时只返回状态与游标 |
|
|
302
|
+
| `worker_send` | 运行中追加 steer / follow-up |
|
|
303
|
+
| `worker_answer` | 回答输入请求或权限询问 |
|
|
304
|
+
| `worker_cancel` | 取消并确认终态;不影响其他 Worker |
|
|
305
|
+
| `worker_resume` | 用新指令恢复已有 session |
|
|
306
|
+
| `worker_continue` | 在 idle 的 persistent Worker 上提交下一轮;沿用同一 native session |
|
|
307
|
+
| `worker_admin` | pin / unpin、archive / unarchive、retire / unretire |
|
|
308
|
+
| `worker_forget` | 删除终态 Worker 的 HS 记录与事件;保留 native session 文件 |
|
|
309
|
+
| `supervisor_info` | Production 为版本、模式、runtime 与 Worker 计数快照;完整诊断在 Development |
|
|
310
|
+
| `supervisor_notifications` | 读取通知收件箱(production 默认全部未确认;development 默认 pending) |
|
|
311
|
+
| `supervisor_notifications_ack` | 确认通知(幂等) |
|
|
312
|
+
| `supervisor_wake_target` | 可选:登记 Codex thread 以启用队列投递 |
|
|
313
|
+
| `metrics_task_create` | 创建一个可关联多个 Worker 的委托任务 |
|
|
314
|
+
| `metrics_task_show` | 单任务状态、耗时、用量摘要、覆盖率与警告;原始 usage 记录仅在 Development 返回 |
|
|
315
|
+
| `metrics_report` | 区间汇总(按任务创建时间)、覆盖率、未知字段;`includeTasks` 在 Production 返回任务摘要,Development 返回完整详情 |
|
|
316
|
+
| `metrics_record_usage` | 人工补录 Master 或 Worker 用量;支持 `usageId` 幂等 |
|
|
317
|
+
|
|
318
|
+
### CLI 命令
|
|
319
|
+
|
|
320
|
+
| 分类 | 命令 | 用途 |
|
|
321
|
+
| --- | --- | --- |
|
|
322
|
+
| 守护进程 | `up` `down` `daemon` `info` | 启动、关闭、前台运行 daemon,查看版本与状态目录 |
|
|
323
|
+
| Worker 管理 | `spawn` `list` `status` `events` | 创建 Worker,列出、查询状态,增量读取事件 |
|
|
324
|
+
| Worker 通信 | `wait` `send` `answer` `cancel` `resume` `continue` | 有界等待、追加指令、回答输入、取消、恢复、继续同一 Worker 的下一轮 |
|
|
325
|
+
| Worker 管理 | `admin` `forget` | 固定、归档、退役、取消退役;删除 HS 记录但保留 native session |
|
|
326
|
+
| 通知 | `inbox` `ack` `notify-target` `retry-notifications` | 读取与确认收件箱,登记投递目标,重试投递 |
|
|
327
|
+
| 度量 | `metrics create\|show\|report\|export\|record-usage` | 创建任务,查看单任务/汇总报告,导出,补录用量 |
|
|
328
|
+
| 维护 | `prune` `compact` | 清理终态且没有未确认通知的 Worker;压缩终态 Worker 的旧进度事件 |
|
|
329
|
+
|
|
330
|
+
### 状态与事件
|
|
331
|
+
|
|
332
|
+
| 类别 | 值 |
|
|
333
|
+
| --- | --- |
|
|
334
|
+
| 非终态 | `starting` `running` `awaiting_input` |
|
|
335
|
+
| 终态 | `completed` `failed` `cancelled` `crashed` `orphaned` `interrupted` |
|
|
336
|
+
| Worker 事件 | `worker.starting` `worker.started` `worker.session` |
|
|
337
|
+
| 运行事件 | `run.accepted` `run.started` `run.progress` `run.usage` `run.needs_input` `run.input_answered` `run.message_sent` `run.error` `run.completed` `run.failed` `run.cancelled` |
|
|
338
|
+
| 生命周期事件 | `worker.cancel_requested` `worker.exited` `worker.crashed` `worker.orphaned` `worker.interrupted` `worker.resumed` `worker.continued` `worker.resume_failed` |
|
|
339
|
+
|
|
340
|
+
`run.usage` 是结构化、低频的运行时用量报告;`run.progress` 中旧的 `kind=usage` 仍保留以兼容既有事件消费者,但任务度量只消费 `run.usage`。`run.usage` 只描述 Token,不包含费用。
|
|
341
|
+
|
|
342
|
+
`orphaned` 表示 daemon 重启后进程可能仍存活但已失去控制;`interrupted` 表示进程已不在或 PID 已被复用。两者都不代表任务成功,也不会被自动重跑。
|
|
343
|
+
|
|
344
|
+
### 关键语义
|
|
345
|
+
|
|
346
|
+
| 主题 | 语义 |
|
|
347
|
+
| --- | --- |
|
|
348
|
+
| `spawn` | 返回时任务尚未完成;终态以 `wait` / `status` 为准 |
|
|
349
|
+
| `worker_wait` | 有界等待;超时只表示等待窗口结束,不带游标时应先检查当前状态 |
|
|
350
|
+
| `run.message_sent` | 只表示消息被 Harness 接受;模型是否看到或采纳需以事件与结果为准 |
|
|
351
|
+
| `resume` | 使用新进程加载持久化 session;不会续接原进程内存,也不会自动重跑中断任务 |
|
|
352
|
+
| `continue` | 仅用于 `persistent` Worker;要求同一 session 仍可恢复,拒绝时不会创建替代 Worker |
|
|
353
|
+
| `pin` | 保护 Worker 不被 `prune` 或 `forget` 删除 |
|
|
354
|
+
| `archive` | 仅从默认 `list` 隐藏;记录、事件与 session 引用保留 |
|
|
355
|
+
| `retire` | 停止接受新的 `continue` / `resume`;`unretire` 可恢复 |
|
|
356
|
+
| `forget` | 显式删除 HS 记录与事件;native session 文件保留,需无未确认通知 |
|
|
357
|
+
| `prune` | 显式维护操作;只清理终态、未 pin 且没有未确认通知的 Worker |
|
|
358
|
+
| `compact` | 只处理终态、未 pin、无运行中进程且非 orphaned 的 Worker;保留全部生命周期事件与最新进度,seq 游标不变 |
|
|
359
|
+
| `requestId` | 不带 `requestId` 时不具备幂等性;带 `requestId` 时也不提供跨组件的 exactly-once |
|
|
360
|
+
|
|
361
|
+
### Persistent Worker(开发分支能力)
|
|
362
|
+
|
|
363
|
+
> 状态:0.9.2。审批、事件交接与通知修复见 [CHANGELOG](CHANGELOG.md);MCP 返回契约变更与真实 Qoder / MiniMax Code 验收见 [0.9.1 交付报告](docs/2026-11-10-hs-0.9.1-report.md)。
|
|
364
|
+
|
|
365
|
+
`worker_spawn` 传入 `persistence="persistent"`(CLI 为 `spawn --persistence persistent`)后,Worker 的身份和 native session 会跨 Turn 保留。每轮结束后 Activation 进程退出,`status` 仍记录本轮终态(通常为 `completed`),派生字段 `lifecycle` 变为 `idle`;下一轮通过 `worker_continue` 在同一个 `workerId` 和同一个 session 上启动新的 Activation。
|
|
366
|
+
|
|
367
|
+
| 字段 | 含义 |
|
|
368
|
+
| --- | --- |
|
|
369
|
+
| `persistence` | `oneshot`(默认,兼容旧行为)或 `persistent` |
|
|
370
|
+
| `lifecycle` | `active` `awaiting_input` `activating` `idle` `orphaned` `unavailable` `unknown`;由状态、进程与 session 可用性派生,不额外持久化 |
|
|
371
|
+
| `session.available` | 记录的 session locator 存在 |
|
|
372
|
+
| `session.restorable` | 当前可以安全启动新的 Activation;进程可能仍在运行、Worker orphaned 或文件缺失时为 `false` |
|
|
373
|
+
| `session.reason` | `restorable=false` 的原因,例如 `session_file_missing`、`process_may_be_running` |
|
|
374
|
+
|
|
375
|
+
`continue` 与 `resume` 分工:`continue` 用于正常交付下一轮工作;`resume` 保留原有恢复语义。Worker 为 `persistent` 但 session 不可恢复时,`continue` 返回真实错误,不会静默新建 Worker 或伪造上下文连续性。旧记录没有该字段时按 `oneshot` 读取。
|
|
376
|
+
|
|
377
|
+
进程退出只释放运行资源;HS 不会因 Turn 结束删除 native session,也不会自动把 Worker 标记为退役。`pin` 保护记录,`archive` 只影响默认列表,`retire` 阻止新的 Turn,`forget` 删除 HS 记录与事件但保留 native session 文件,`compact` 只裁剪旧进度事件、不改动 session。原生 Session 删除尚未提供。
|
|
378
|
+
|
|
379
|
+
### 存储诊断
|
|
380
|
+
|
|
381
|
+
`supervisor_info`(CLI 为 `info`)的 `storage` 字段提供状态目录的事件字节总量、最大事件文件、active / idle / other Worker 数量以及上次启动各阶段耗时。数值来自已加载的事件文件长度,不做额外全盘扫描;`startup.store.eventBytes` 是启动时快照,不是当前值。
|
|
382
|
+
|
|
383
|
+
`compact [workerId] [--keep-progress 200] [--dry-run] [--json]` 用于压缩终态 Worker 的事件日志:保留全部非 `run.progress` 事件、最新 N 条进度以及最后一条事件,原子重写 `events.jsonl` 并在记录中写入 `compacted` 标记。序列号保持不变,因此已有游标仍可继续读取;`worker.compacted.retainedFromSeq` 标明仍保留的最小序号,失去的中间序号属于显式压缩,重启时不会被误报为历史损坏。压缩后的记录仍可 `continue`(persistent Worker),`forget` 与原生 session 行为不变。`--dry-run` 只报告可回收的事件与字节数;活跃、orphaned、pinned 或仍有运行中进程的 Worker 会被拒绝或跳过。
|
|
384
|
+
|
|
385
|
+
### 持久化与幂等
|
|
386
|
+
|
|
387
|
+
每个 Worker 的事件缓存最多保存最近 500 条,完整历史仍在追加日志中。启动流式扫描日志,历史查询按需异步分页,稀疏字节索引支持深页读取;通知重建使用单次流式扫描。已知的事件缺口或追加失败会明确报错,不将残缺历史伪装为完整结果;单个损坏日志不会阻止其他 Worker 继续受管。
|
|
388
|
+
|
|
389
|
+
直接使用 TypeScript/JavaScript 库的调用方需注意:`Supervisor.events()` 返回 Promise,应使用 `await`;`Store.getEvents()` 只访问缓存,`truncated:true` 表示需调用 `await Store.readEvents()` 获取完整历史,`Store.scanEvents()` 用于全历史流式处理。
|
|
390
|
+
|
|
391
|
+
带 `requestId` 的副作用操作会先等待准入记录写入,再启动进程或发送消息;持久化失败会明确返回错误。通知也在收件箱记录写入确认后才调用宿主。上述承诺针对进程崩溃和写入失败,不提供断电 fsync、磁盘损坏或跨组件 exactly-once 保证。
|
|
392
|
+
|
|
393
|
+
### Worker 报告协议与命令守卫
|
|
394
|
+
|
|
395
|
+
HS 是唯一受支持的 Worker 通知生产路径。`spawn` / `resume` 发送的任务提示会前置固定协议块:Worker 以最终答复结束本次运行,不得调用 `codex queue` 或其他宿主接口向 Master 会话注入报告,也不得为此另起 Codex 会话;需要决策时使用自带 harness 的 permission/input。
|
|
396
|
+
|
|
397
|
+
运行时再加一层最小护栏:Daemon 启动时若在 PATH 中找到 Codex CLI,就在 `<stateDir>/worker-guard/bin` 生成 `codex` shim,并只把该目录前置到 **Worker 进程**的 PATH。`codex queue` 返回退出码 2、向工具 stderr 写一行说明,并在 `<stateDir>/worker-guard/worker-guard.jsonl` 追加 `{ts, workerId, argv, cwd}`;其他子命令转发给真实 CLI。Daemon 自身的 PATH 与通知投递不受影响。若 Codex 是后来才安装的,重启 Daemon 后护栏才会生成。
|
|
398
|
+
|
|
399
|
+
```powershell
|
|
400
|
+
# 暂时关闭护栏(仅诊断/兼容)
|
|
401
|
+
$env:HARNESS_SUPERVISOR_WORKER_GUARD = '0'
|
|
402
|
+
# 关闭任务提示中的协议块(仅诊断/兼容)
|
|
403
|
+
$env:HARNESS_SUPERVISOR_WORKER_PROTOCOL = '0'
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
**边界**:这是一层护栏与审计,不构成安全边界。Worker 使用绝对路径、其他宿主接口、修改 PATH 或覆盖 shim 都能绕过;同一 OS 用户下 HS 无法仅凭 PATH 阻止。Pi 已用真实进程和 shell 验证拦截与放行;Qoder、MiniMax Code 与 DSH 复用同一环境注入,但其工具 shell 的 PATH 解析未单独验证。护栏失败(找不到 Codex、目录不可写)只记 `daemon.log`,不阻断 Worker 启动。
|
|
407
|
+
|
|
408
|
+
## 运行时支持
|
|
409
|
+
|
|
410
|
+
| Runtime | 状态 | 已验证范围 |
|
|
411
|
+
| --- | --- | --- |
|
|
412
|
+
| Pi | 完整 | 原生 RPC;spawn / steer / follow-up / cancel / resume;Persistent 3 轮连续协作(同 Worker / 同 Session);dialog 尚未单独真实覆盖 |
|
|
413
|
+
| Qoder CLI | 实验性 | ACP 默认:spawn / resume / 审批 / 提问 / 取消 / Persistent 3 轮连续协作。stream-json 回退:spawn / cancel / resume;steer、follow-up 被接受但未生效 |
|
|
414
|
+
| MiniMax Code | 实验性 | ACP:spawn / 完成 / 取消 / resume / Persistent 3 轮连续协作;活跃回合内 steer;queue 入队;Ask 模式尚未触发 |
|
|
415
|
+
| DSH | PoC | ACP v1:spawn / resume / 模型与推理配置 / 工作区写入 / 工作区外提权 / 完全权限 / 取消 / Persistent 3 轮连续协作 |
|
|
416
|
+
|
|
417
|
+
### 操作能力对比
|
|
418
|
+
|
|
419
|
+
`是` 表示适配器实现了该能力;`有条件` 表示依赖特定传输、扩展或版本,或只有协议/单元测试;`否` 表示明确不支持。真实运行覆盖范围见上表。
|
|
420
|
+
|
|
421
|
+
| 操作 | Pi | Qoder ACP(默认) | Qoder stream-json 回退 | MiniMax Code | DSH |
|
|
422
|
+
| --- | --- | --- | --- | --- | --- |
|
|
423
|
+
| 协议 | Pi RPC | ACP v1 | stream-json | ACP | ACP v1 |
|
|
424
|
+
| spawn / 单轮 prompt | 是 | 是 | 是 | 是 | 是 |
|
|
425
|
+
| 流式文本 / 思考 / 工具事件 | 是 | 是 | 是 | 是 | 是(无 plan) |
|
|
426
|
+
| 取消 | 是 | 是 | 是 | 是 | 是 |
|
|
427
|
+
| resume | 是(Pi session 文件) | 是(`session/load`) | 是(`--resume`,校验 session id) | 是(`session/load`) | 是(`session/resume`,要求相同绝对 cwd) |
|
|
428
|
+
| Idle continue(同一 Worker / Session 下一轮) | L3(真实 3 轮) | L3(真实 3 轮) | L2(未跑 3 轮;resume 已真实验证) | L3(真实 3 轮) | L3(真实 3 轮) |
|
|
429
|
+
| 运行中 steer | 是 | 否 | 有条件(被接受,未验证生效) | 有条件(需 steer 扩展;活跃回合内已验证) | 否 |
|
|
430
|
+
| follow-up 队列 | 是 | 否 | 有条件(被接受,未验证生效) | 有条件(需 queue 扩展;已验证入队) | 否 |
|
|
431
|
+
| 交互输入(审批 / 提问 / 对话框) | 是(extension dialog) | 是(permission + elicitation) | 1.1.79 及以前支持;1.1.82 不支持提问/审批 | 是(Ask 模式触发时) | 仅审批;请求不含工具名/输入,无 elicitation |
|
|
432
|
+
| 权限模式控制 | 由 Pi 自身配置,HS 不管理 | 5 种 ACP 模式映射(plan 无对应) | 支持(默认 `bypass_permissions`) | `bypassPermissions` 默认 / `default` 为 Ask | 3 种(默认 `workspace-write` + `ask`) |
|
|
433
|
+
| 模型 / 思考配置 | 是 | 是 | 是 | 否(忽略,走运行时配置) | 是(model 对 + `reasoning_effort`) |
|
|
434
|
+
| provider 参数 | 是 | 否(写进 model 名) | 否(写进 model 名) | 否(写进 model 名) | 是(model 重名时必须) |
|
|
435
|
+
| 工具白名单 | 是 | 否 | 是 | 否(忽略) | 否 |
|
|
436
|
+
| extraArgs | 是(禁改保留参数) | 是(禁改保留参数) | 是(禁改保留参数) | 仅校验,不转发 | 否(明确 `UNSUPPORTED`) |
|
|
437
|
+
| Token 用量 | 是(原生 usage) | 未知(1.1.82 计数全零) | 有条件(`result.usage` 存在时) | 否(仅上下文占用) | 否(仅上下文占用) |
|
|
438
|
+
| pause | 否 | 否 | 否 | 否 | 否 |
|
|
439
|
+
|
|
440
|
+
说明:
|
|
441
|
+
|
|
442
|
+
- MiniMax Code 的 `model`、`thinking` 和 `tools` 不会传给其 ACP 会话;`extraArgs` 只做保留参数校验,不会转发。需要这些设置时应在 MiniMax Code 自身配置中完成。
|
|
443
|
+
- Qoder ACP 的 `tools` 会被明确拒绝,需要工具白名单时请使用 stream-json 回退;Qoder 的 `provider` 需要写进 model 名。
|
|
444
|
+
- DSH 的 `tools` 与 `extraArgs` 会被明确拒绝;其 `usage_update` 只表示上下文占用。DSH 仍为 PoC,未合并进生产默认。
|
|
445
|
+
|
|
446
|
+
用量采集边界:Pi 只在 assistant message 原生提供 `usage` 时记录;Qoder 只在 `result.usage` 存在时记录;MiniMax Code 0.6.13 的 ACP 只提供上下文 `used`/`size` 与 `cost=0 USD`,prompt result 不含 usage;DSH 的 `usage_update` 同样只表示上下文占用,不写 `run.usage`。Master 用量不会从宿主会话自动读取,必须显式补录。
|
|
447
|
+
|
|
448
|
+
## 边界
|
|
449
|
+
|
|
450
|
+
- **无沙箱**:`cwd` 只表示默认工作目录;Worker 与 daemon 同用户、继承环境变量,可访问该用户可访问的文件与网络。
|
|
451
|
+
- **单用户本地**:没有多用户、远程 MCP 认证或配额管理;生命周期控制不提供资源限制。
|
|
452
|
+
- **投递语义为 at-least-once**:通知与队列投递可能重复;`delivered` 只表示已写入目标,Master 是否读到取决于宿主。
|
|
453
|
+
- **唤醒受宿主约束**:只有宿主加载了目标 thread,队列消息才会触发新回合。
|
|
454
|
+
- **度量为参考值**:Token 来自运行时事件或人工补录,未与 provider 账单核对;本系统不采集费用,验收、返工、干预和对照基线也未采集。Master 用量缺失即未知,不会按零计算。
|
|
455
|
+
- **统计故障不阻断执行**:度量存储不可用时 Worker 仍可运行,但该 Worker 可能没有任务关联或用量记录,报告会明确说明。
|
|
456
|
+
- **崩溃后不接管**:daemon 重启只做状态对账,不会重新接上原管道,也不会自动重跑。
|
|
457
|
+
- **平台**:Windows 原生已验证;WSL / 其他 POSIX 需自行验证。
|
|
458
|
+
|
|
459
|
+
## License
|
|
460
|
+
|
|
461
|
+
MIT
|