@feng0531/dsh-execution-bus 0.8.0 → 0.10.0
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/README.md +9 -3
- package/dist/bus.d.ts +2 -0
- package/dist/bus.js +2 -0
- package/dist/plugin.js +28 -3
- package/dist/product.d.ts +311 -2
- package/dist/product.js +118 -7
- package/docs/FLOW-TEST.md +2 -0
- package/docs/PRODUCT.md +4 -0
- package/docs/host-compatibility.md +3 -0
- package/docs/protocol.md +9 -1
- package/docs/releases/0.10.0.md +19 -0
- package/docs/releases/0.9.0.md +19 -0
- package/docs/validation.md +4 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
“萧何”是产品与模式显示名,执行总线是其技术功能;不新增人物 Agent,不进行角色扮演。仓库 dsh-execution-bus、npm 包名、execution_bus 工具名及 execution-bus-test 预设 ID 保持不变。历史版本发布说明保留当时名称。
|
|
6
6
|
|
|
7
|
-
DSH 独立插件:`@feng0531/dsh-execution-bus` · 当前版本 **0.
|
|
7
|
+
DSH 独立插件:`@feng0531/dsh-execution-bus` · 当前版本 **0.10.0**
|
|
8
8
|
|
|
9
9
|
> 萧何模式从宿主已声明的 PTC 组合派生,保留日常工具,再叠加可选执行总线。已验证隔离的真实 Node PTC → 原 read + 总线调用,以及脚本模型内存会话;真实模型、桌面界面与实际沙箱仍未验收。**不支持重启后恢复任务。**
|
|
10
10
|
|
|
@@ -19,6 +19,7 @@ DSH 独立插件:`@feng0531/dsh-execution-bus` · 当前版本 **0.8.0**
|
|
|
19
19
|
| 同一次请求重复提交 | 在同一会话、同一存活实例和保存期内,共用一次执行 |
|
|
20
20
|
| 重复或迟到的进度到达 | 按序号处理,忽略旧进度和终态后的进度 |
|
|
21
21
|
| 取消时不确定任务是否真的停了 | 区分“已请求取消”和“已确认取消” |
|
|
22
|
+
| 长任务超出 `run_code` 的时间预算 | PTC 程序结束时只停止等待,已受理执行继续;用同一 requestId 的 `status`/`result` 取回,或用 `cancel` 取消 |
|
|
22
23
|
|
|
23
24
|
它只是**执行协调层**,不是新的模型或 Agent,不是工作流引擎,也不是对所有工具的全局拦截器。它不能解决模型理解错误、反复改变方案等推理问题。
|
|
24
25
|
|
|
@@ -129,7 +130,7 @@ flowchart TD
|
|
|
129
130
|
2. 在你选定的隔离 DSH 配置依赖目录安装固定版本,不要在 DSH 程序安装目录执行:
|
|
130
131
|
|
|
131
132
|
```powershell
|
|
132
|
-
npm install --ignore-scripts @feng0531/dsh-execution-bus@0.
|
|
133
|
+
npm install --ignore-scripts @feng0531/dsh-execution-bus@0.10.0
|
|
133
134
|
```
|
|
134
135
|
|
|
135
136
|
这是 npm 目录示例。若目标配置使用 pnpm,应沿用其包管理器,不混用锁文件。遇到宿主 peer 版本冲突就停止,不用强制安装绕过。
|
|
@@ -200,6 +201,10 @@ flowchart TD
|
|
|
200
201
|
|
|
201
202
|
PTC 是 DSH 的程序化工具调用入口。在 `run_code` 内使用 `await tools.execution_bus(请求对象)`,而不是直接调用折叠后的工具名。执行总线不会解除 `run_code` 自身的时间预算。已有真实 Node PTC 隔离进程读文件和调用总线的验证,但尚未进行实际模型/桌面沙箱全链路验收。
|
|
202
203
|
|
|
204
|
+
**0.10.0 起,模式说明与工具声明给出明确触发条件。** 仅当预计单次宿主操作超过约 30 秒、同一逻辑操作可能重复提交(沿用 requestId)、任务需要在 `run_code` 预算结束后继续、或多个步骤需要等待同一执行时,才使用 `execution_bus`;其余任务继续用原工具,避免为简单调用增加包装。工具声明改为按 Handler 的判别联合(`host.read`/`host.glob`/`host.grep`/`host.edit`/`host.write`/`host.pwsh`/`test`),PTC SDK 与原生声明里可直接看到每个 Handler 的必填字段,而不是泛型 `payload`。
|
|
205
|
+
|
|
206
|
+
**0.9.0 起,预算到期不再连带取消已受理执行。** `run_code` 因时间预算到期或程序结束时,宿主会中断其中的工具子调用;总线把这种中断视为**只停止等待**:已受理执行与宿主 Job 继续,程序返回预算错误后,可在后续 `run_code` 中用同一 `requestId` 的 `status`/`result` 取回结果,或用 `cancel` 取消。用户主动中断、会话取消、沙箱模式变化等其他原因仍会请求取消整个执行。该识别依赖 DSH 0.2.1-rc.2 的中断原因字符串(见[宿主兼容性](<docs/host-compatibility.md>)),不是宿主公开稳定契约;进程退出仍会丢失全部内存状态,保留期一小时。
|
|
207
|
+
|
|
203
208
|
## 如何理解任务状态?
|
|
204
209
|
|
|
205
210
|
```mermaid
|
|
@@ -241,6 +246,7 @@ core 开发者可用 `new ExecutionBus(options, {sessionQueueLimit:16,maxQueueWa
|
|
|
241
246
|
宿主插件默认并发 **2**,全局排队上限 **32**,每会话排队上限 **16**;排队超过 **120 秒**且尚未开始执行时结算为 `failed / QUEUE_WAIT_TIMEOUT`,不调用 Handler。运行后不会被该排队期限中止,PTC 外层仍有独立时间预算。最多保存 **256** 条任务记录,单结果最多 **64 KiB**,完成结果保留期 **1 小时**,在新请求和查询时惰性清理;不是一小时一到即定时删除。队列或记录满时拒绝新任务;宿主 Job 自身也有容量限制。
|
|
242
247
|
|
|
243
248
|
- **全部状态在内存中。** 受理没有落盘,插件关闭或进程崩溃后,不能依靠它恢复原调用或保证请求不丢失。
|
|
249
|
+
- **预算分离等待不是持久化。** PTC 程序结束后继续执行的任务只在当前插件实例存活期间有效;进程关闭即丢失,结果最多保留一小时,不保证模型一定取回。
|
|
244
250
|
- **不自动重跑任务。** 通信超时不等于执行失败,取消不等于回滚。Job 等待服务异常会在原执行排空后返回服务错误,执行可能已成功;应核对原 requestId 的状态,不要换编号盲目重跑。
|
|
245
251
|
- **不承诺端到端 exactly-once。** 当前实例的请求复用不能代替外部副作用对账。
|
|
246
252
|
- 当前没有远端执行端、跨插件 Handler 注册服务或非幂等操作对账能力。
|
|
@@ -272,7 +278,7 @@ npm run test:install # 临时目录安装,不操作日常 DSH
|
|
|
272
278
|
|
|
273
279
|
- [协议和投递语义](<docs/protocol.md>):字段、状态、重复处理与取消规则。
|
|
274
280
|
- [宿主兼容性与源码调用链](<docs/host-compatibility.md>):为什么可以等待,为什么不能跨重启恢复。
|
|
275
|
-
- [验证记录](<docs/validation.md>)、[0.
|
|
281
|
+
- [验证记录](<docs/validation.md>)、[0.10.0 发布说明](<docs/releases/0.10.0.md>):已验证与未验证范围。
|
|
276
282
|
- [同类项目源码整合](<docs/INTEGRATION.md>):固定来源、采用范围、许可与验证边界。
|
|
277
283
|
- [维护者发布流程](<docs/RELEASING.md>):标签 CI、安装包校验与正式发布门禁。
|
|
278
284
|
|
package/dist/bus.d.ts
CHANGED
|
@@ -65,6 +65,8 @@ export declare class ExecutionBus {
|
|
|
65
65
|
submit(owner: Owner, raw: unknown, onEvent?: (e: Event) => void, invoke?: Capability): {
|
|
66
66
|
accepted: Event;
|
|
67
67
|
done: Promise<RecordView>;
|
|
68
|
+
/** 当前快照:供仅在停止等待时使用,不改变交付标记。 */
|
|
69
|
+
snapshot: () => RecordView;
|
|
68
70
|
cancel: () => void;
|
|
69
71
|
detach: () => void;
|
|
70
72
|
returned: () => void;
|
package/dist/bus.js
CHANGED
package/dist/plugin.js
CHANGED
|
@@ -4,6 +4,12 @@ import { ExecutionOwner } from "./execution.js";
|
|
|
4
4
|
import { ExecutionBus, parse } from "./bus.js";
|
|
5
5
|
import { ERRORS } from "./error-codes.js";
|
|
6
6
|
import { testHandler, readHandler, globHandler, grepHandler, editHandler, writeHandler, pwshHandler, } from "./handlers.js";
|
|
7
|
+
/** DSH 0.2.1-rc.2 的 PTC 在程序结束(含时间预算到期)时用它作为子调用中断原因;
|
|
8
|
+
* 用户/会话取消使用调用方提供的原因,不匹配该固定字符串。 */
|
|
9
|
+
const PTC_PROGRAM_SETTLED = "run_code settled";
|
|
10
|
+
function isPtcProgramEnd(signal) {
|
|
11
|
+
return signal.aborted && signal.reason === PTC_PROGRAM_SETTLED;
|
|
12
|
+
}
|
|
7
13
|
export const name = "execution-bus";
|
|
8
14
|
export const inject = ["tools", "jobs"];
|
|
9
15
|
export function apply(ctx) {
|
|
@@ -148,14 +154,33 @@ export function apply(ctx) {
|
|
|
148
154
|
throw Error(ERRORS.HOST_JOB_UNAVAILABLE);
|
|
149
155
|
}
|
|
150
156
|
}
|
|
151
|
-
/**
|
|
157
|
+
/** 外层取消映射:PTC 程序结束(含预算到期)只停止本次等待,已受理执行与
|
|
158
|
+
* 宿主 Job 保留,同会话可用同 requestId 的 status/result 取回;其他取消原因
|
|
159
|
+
* (用户/会话中断)仍请求取消整个执行。 */
|
|
152
160
|
async function awaitProjection(exec, attached, execution) {
|
|
153
|
-
|
|
161
|
+
let release;
|
|
162
|
+
const detachedView = new Promise((resolve) => (release = resolve));
|
|
163
|
+
const abort = () => {
|
|
164
|
+
if (!isPtcProgramEnd(exec.signal)) {
|
|
165
|
+
attached.cancel();
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
attached.detach();
|
|
169
|
+
release(attached.snapshot());
|
|
170
|
+
};
|
|
154
171
|
exec.signal.addEventListener("abort", abort, { once: true });
|
|
155
172
|
if (exec.signal.aborted)
|
|
156
173
|
abort();
|
|
174
|
+
const settled = execution.settled.then(() => ({ kind: "settled" }), (error) => ({ kind: "error", error }));
|
|
157
175
|
try {
|
|
158
|
-
await
|
|
176
|
+
const outcome = await Promise.race([
|
|
177
|
+
settled,
|
|
178
|
+
detachedView.then((view) => ({ kind: "detached", view })),
|
|
179
|
+
]);
|
|
180
|
+
if (outcome.kind === "detached")
|
|
181
|
+
return outcome.view;
|
|
182
|
+
if (outcome.kind === "error")
|
|
183
|
+
throw outcome.error;
|
|
159
184
|
const value = await attached.done;
|
|
160
185
|
attached.returned();
|
|
161
186
|
return value;
|
package/dist/product.d.ts
CHANGED
|
@@ -23,6 +23,161 @@ export declare const HANDLER_LIMITS: Readonly<{
|
|
|
23
23
|
readPathChars: 2048;
|
|
24
24
|
diagnosticDelayMs: 30000;
|
|
25
25
|
}>;
|
|
26
|
+
/** request 的 {handler,input} 判别联合;控制消息为空对象。 */
|
|
27
|
+
export declare const PAYLOAD_SCHEMA: {
|
|
28
|
+
readonly description: "request 必须匹配某个 Handler 的 {handler,input};status/result/cancel 的 payload 必须为空对象 {}。";
|
|
29
|
+
readonly oneOf: readonly [...{
|
|
30
|
+
type: "object";
|
|
31
|
+
additionalProperties: false;
|
|
32
|
+
required: string[];
|
|
33
|
+
properties: {
|
|
34
|
+
handler: {
|
|
35
|
+
type: "string";
|
|
36
|
+
const: "host.read" | "host.glob" | "host.grep" | "host.edit" | "host.write" | "host.pwsh" | "test";
|
|
37
|
+
};
|
|
38
|
+
input: {
|
|
39
|
+
readonly type: "object";
|
|
40
|
+
readonly additionalProperties: false;
|
|
41
|
+
readonly required: readonly ["delayMs", "fail"];
|
|
42
|
+
readonly properties: {
|
|
43
|
+
readonly delayMs: {
|
|
44
|
+
readonly type: "integer";
|
|
45
|
+
readonly description: "Diagnostic delay in milliseconds (0-30000).";
|
|
46
|
+
};
|
|
47
|
+
readonly fail: {
|
|
48
|
+
readonly type: "boolean";
|
|
49
|
+
readonly description: "Settle as a controlled failure when true.";
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
} | {
|
|
53
|
+
readonly type: "object";
|
|
54
|
+
readonly additionalProperties: false;
|
|
55
|
+
readonly required: readonly ["file_path"];
|
|
56
|
+
readonly properties: {
|
|
57
|
+
readonly file_path: {
|
|
58
|
+
readonly type: "string";
|
|
59
|
+
readonly description: "Path resolved against the session working directory.";
|
|
60
|
+
};
|
|
61
|
+
readonly offset: {
|
|
62
|
+
readonly type: "integer";
|
|
63
|
+
readonly description: "1-based first line to read.";
|
|
64
|
+
};
|
|
65
|
+
readonly limit: {
|
|
66
|
+
readonly type: "integer";
|
|
67
|
+
readonly description: "Maximum lines to read (<=100).";
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
} | {
|
|
71
|
+
readonly type: "object";
|
|
72
|
+
readonly additionalProperties: false;
|
|
73
|
+
readonly required: readonly ["pattern"];
|
|
74
|
+
readonly properties: {
|
|
75
|
+
readonly pattern: {
|
|
76
|
+
readonly type: "string";
|
|
77
|
+
readonly description: "Glob pattern; a bare pattern matches basenames at any depth.";
|
|
78
|
+
};
|
|
79
|
+
readonly path: {
|
|
80
|
+
readonly type: "string";
|
|
81
|
+
readonly description: "Directory to search; defaults to the session working directory.";
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
} | {
|
|
85
|
+
readonly type: "object";
|
|
86
|
+
readonly additionalProperties: false;
|
|
87
|
+
readonly required: readonly ["pattern"];
|
|
88
|
+
readonly properties: {
|
|
89
|
+
readonly pattern: {
|
|
90
|
+
readonly type: "string";
|
|
91
|
+
readonly description: "Ripgrep regular expression.";
|
|
92
|
+
};
|
|
93
|
+
readonly path: {
|
|
94
|
+
readonly type: "string";
|
|
95
|
+
readonly description: "File or directory to search; defaults to the session working directory.";
|
|
96
|
+
};
|
|
97
|
+
readonly include: {
|
|
98
|
+
readonly type: "string";
|
|
99
|
+
readonly description: "One positive glob filter; negation and comma lists are rejected.";
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
} | {
|
|
103
|
+
readonly type: "object";
|
|
104
|
+
readonly additionalProperties: false;
|
|
105
|
+
readonly required: readonly ["file_path", "old_string", "new_string"];
|
|
106
|
+
readonly properties: {
|
|
107
|
+
readonly file_path: {
|
|
108
|
+
readonly type: "string";
|
|
109
|
+
readonly description: "File to edit.";
|
|
110
|
+
};
|
|
111
|
+
readonly old_string: {
|
|
112
|
+
readonly type: "string";
|
|
113
|
+
readonly description: "Literal text to replace.";
|
|
114
|
+
};
|
|
115
|
+
readonly new_string: {
|
|
116
|
+
readonly type: "string";
|
|
117
|
+
readonly description: "Replacement text.";
|
|
118
|
+
};
|
|
119
|
+
readonly replace_all: {
|
|
120
|
+
readonly type: "boolean";
|
|
121
|
+
readonly description: "Replace every occurrence.";
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
} | {
|
|
125
|
+
readonly type: "object";
|
|
126
|
+
readonly additionalProperties: false;
|
|
127
|
+
readonly required: readonly ["file_path", "content"];
|
|
128
|
+
readonly properties: {
|
|
129
|
+
readonly file_path: {
|
|
130
|
+
readonly type: "string";
|
|
131
|
+
readonly description: "File to write.";
|
|
132
|
+
};
|
|
133
|
+
readonly content: {
|
|
134
|
+
readonly type: "string";
|
|
135
|
+
readonly description: "Full file content.";
|
|
136
|
+
};
|
|
137
|
+
};
|
|
138
|
+
} | {
|
|
139
|
+
readonly type: "object";
|
|
140
|
+
readonly additionalProperties: false;
|
|
141
|
+
readonly required: readonly ["description", "command"];
|
|
142
|
+
readonly properties: {
|
|
143
|
+
readonly description: {
|
|
144
|
+
readonly type: "string";
|
|
145
|
+
readonly description: "Clear, concise description of what the command does (shown in the UI).";
|
|
146
|
+
};
|
|
147
|
+
readonly command: {
|
|
148
|
+
readonly type: "string";
|
|
149
|
+
readonly description: "PowerShell command to execute.";
|
|
150
|
+
};
|
|
151
|
+
readonly timeoutMs: {
|
|
152
|
+
readonly type: "number";
|
|
153
|
+
readonly description: "Positive timeout in milliseconds.";
|
|
154
|
+
};
|
|
155
|
+
readonly workdir: {
|
|
156
|
+
readonly type: "string";
|
|
157
|
+
readonly description: "Working directory; defaults to the session working directory.";
|
|
158
|
+
};
|
|
159
|
+
readonly run_in_background: {
|
|
160
|
+
readonly type: "boolean";
|
|
161
|
+
readonly description: "Return a host Job id immediately instead of waiting.";
|
|
162
|
+
};
|
|
163
|
+
readonly sandbox_permissions: {
|
|
164
|
+
readonly type: "string";
|
|
165
|
+
readonly enum: readonly ["workspace-write", "danger-full-access"];
|
|
166
|
+
readonly description: "Narrowest wider sandbox mode; must be paired with justification.";
|
|
167
|
+
};
|
|
168
|
+
readonly justification: {
|
|
169
|
+
readonly type: "string";
|
|
170
|
+
readonly description: "Required with sandbox_permissions; one sentence of reason.";
|
|
171
|
+
};
|
|
172
|
+
};
|
|
173
|
+
};
|
|
174
|
+
};
|
|
175
|
+
}[], {
|
|
176
|
+
readonly type: "object";
|
|
177
|
+
readonly additionalProperties: false;
|
|
178
|
+
readonly properties: {};
|
|
179
|
+
}];
|
|
180
|
+
};
|
|
26
181
|
export declare const REQUEST_PARAMETERS: {
|
|
27
182
|
readonly type: "object";
|
|
28
183
|
readonly additionalProperties: false;
|
|
@@ -34,16 +189,170 @@ export declare const REQUEST_PARAMETERS: {
|
|
|
34
189
|
};
|
|
35
190
|
readonly messageId: {
|
|
36
191
|
readonly type: "string";
|
|
192
|
+
readonly description: "Unique id of this message; reuse only when redelivering the same message.";
|
|
37
193
|
};
|
|
38
194
|
readonly requestId: {
|
|
39
195
|
readonly type: "string";
|
|
196
|
+
readonly description: "Stable id of one logical operation; reuse it when the same operation is submitted again.";
|
|
40
197
|
};
|
|
41
198
|
readonly type: {
|
|
42
199
|
readonly type: "string";
|
|
43
200
|
readonly enum: readonly ["request", "status", "result", "cancel"];
|
|
201
|
+
readonly description: "request submits work; status/result read the saved snapshot; cancel requests cancellation.";
|
|
44
202
|
};
|
|
45
203
|
readonly payload: {
|
|
46
|
-
readonly
|
|
204
|
+
readonly description: "request 必须匹配某个 Handler 的 {handler,input};status/result/cancel 的 payload 必须为空对象 {}。";
|
|
205
|
+
readonly oneOf: readonly [...{
|
|
206
|
+
type: "object";
|
|
207
|
+
additionalProperties: false;
|
|
208
|
+
required: string[];
|
|
209
|
+
properties: {
|
|
210
|
+
handler: {
|
|
211
|
+
type: "string";
|
|
212
|
+
const: "host.read" | "host.glob" | "host.grep" | "host.edit" | "host.write" | "host.pwsh" | "test";
|
|
213
|
+
};
|
|
214
|
+
input: {
|
|
215
|
+
readonly type: "object";
|
|
216
|
+
readonly additionalProperties: false;
|
|
217
|
+
readonly required: readonly ["delayMs", "fail"];
|
|
218
|
+
readonly properties: {
|
|
219
|
+
readonly delayMs: {
|
|
220
|
+
readonly type: "integer";
|
|
221
|
+
readonly description: "Diagnostic delay in milliseconds (0-30000).";
|
|
222
|
+
};
|
|
223
|
+
readonly fail: {
|
|
224
|
+
readonly type: "boolean";
|
|
225
|
+
readonly description: "Settle as a controlled failure when true.";
|
|
226
|
+
};
|
|
227
|
+
};
|
|
228
|
+
} | {
|
|
229
|
+
readonly type: "object";
|
|
230
|
+
readonly additionalProperties: false;
|
|
231
|
+
readonly required: readonly ["file_path"];
|
|
232
|
+
readonly properties: {
|
|
233
|
+
readonly file_path: {
|
|
234
|
+
readonly type: "string";
|
|
235
|
+
readonly description: "Path resolved against the session working directory.";
|
|
236
|
+
};
|
|
237
|
+
readonly offset: {
|
|
238
|
+
readonly type: "integer";
|
|
239
|
+
readonly description: "1-based first line to read.";
|
|
240
|
+
};
|
|
241
|
+
readonly limit: {
|
|
242
|
+
readonly type: "integer";
|
|
243
|
+
readonly description: "Maximum lines to read (<=100).";
|
|
244
|
+
};
|
|
245
|
+
};
|
|
246
|
+
} | {
|
|
247
|
+
readonly type: "object";
|
|
248
|
+
readonly additionalProperties: false;
|
|
249
|
+
readonly required: readonly ["pattern"];
|
|
250
|
+
readonly properties: {
|
|
251
|
+
readonly pattern: {
|
|
252
|
+
readonly type: "string";
|
|
253
|
+
readonly description: "Glob pattern; a bare pattern matches basenames at any depth.";
|
|
254
|
+
};
|
|
255
|
+
readonly path: {
|
|
256
|
+
readonly type: "string";
|
|
257
|
+
readonly description: "Directory to search; defaults to the session working directory.";
|
|
258
|
+
};
|
|
259
|
+
};
|
|
260
|
+
} | {
|
|
261
|
+
readonly type: "object";
|
|
262
|
+
readonly additionalProperties: false;
|
|
263
|
+
readonly required: readonly ["pattern"];
|
|
264
|
+
readonly properties: {
|
|
265
|
+
readonly pattern: {
|
|
266
|
+
readonly type: "string";
|
|
267
|
+
readonly description: "Ripgrep regular expression.";
|
|
268
|
+
};
|
|
269
|
+
readonly path: {
|
|
270
|
+
readonly type: "string";
|
|
271
|
+
readonly description: "File or directory to search; defaults to the session working directory.";
|
|
272
|
+
};
|
|
273
|
+
readonly include: {
|
|
274
|
+
readonly type: "string";
|
|
275
|
+
readonly description: "One positive glob filter; negation and comma lists are rejected.";
|
|
276
|
+
};
|
|
277
|
+
};
|
|
278
|
+
} | {
|
|
279
|
+
readonly type: "object";
|
|
280
|
+
readonly additionalProperties: false;
|
|
281
|
+
readonly required: readonly ["file_path", "old_string", "new_string"];
|
|
282
|
+
readonly properties: {
|
|
283
|
+
readonly file_path: {
|
|
284
|
+
readonly type: "string";
|
|
285
|
+
readonly description: "File to edit.";
|
|
286
|
+
};
|
|
287
|
+
readonly old_string: {
|
|
288
|
+
readonly type: "string";
|
|
289
|
+
readonly description: "Literal text to replace.";
|
|
290
|
+
};
|
|
291
|
+
readonly new_string: {
|
|
292
|
+
readonly type: "string";
|
|
293
|
+
readonly description: "Replacement text.";
|
|
294
|
+
};
|
|
295
|
+
readonly replace_all: {
|
|
296
|
+
readonly type: "boolean";
|
|
297
|
+
readonly description: "Replace every occurrence.";
|
|
298
|
+
};
|
|
299
|
+
};
|
|
300
|
+
} | {
|
|
301
|
+
readonly type: "object";
|
|
302
|
+
readonly additionalProperties: false;
|
|
303
|
+
readonly required: readonly ["file_path", "content"];
|
|
304
|
+
readonly properties: {
|
|
305
|
+
readonly file_path: {
|
|
306
|
+
readonly type: "string";
|
|
307
|
+
readonly description: "File to write.";
|
|
308
|
+
};
|
|
309
|
+
readonly content: {
|
|
310
|
+
readonly type: "string";
|
|
311
|
+
readonly description: "Full file content.";
|
|
312
|
+
};
|
|
313
|
+
};
|
|
314
|
+
} | {
|
|
315
|
+
readonly type: "object";
|
|
316
|
+
readonly additionalProperties: false;
|
|
317
|
+
readonly required: readonly ["description", "command"];
|
|
318
|
+
readonly properties: {
|
|
319
|
+
readonly description: {
|
|
320
|
+
readonly type: "string";
|
|
321
|
+
readonly description: "Clear, concise description of what the command does (shown in the UI).";
|
|
322
|
+
};
|
|
323
|
+
readonly command: {
|
|
324
|
+
readonly type: "string";
|
|
325
|
+
readonly description: "PowerShell command to execute.";
|
|
326
|
+
};
|
|
327
|
+
readonly timeoutMs: {
|
|
328
|
+
readonly type: "number";
|
|
329
|
+
readonly description: "Positive timeout in milliseconds.";
|
|
330
|
+
};
|
|
331
|
+
readonly workdir: {
|
|
332
|
+
readonly type: "string";
|
|
333
|
+
readonly description: "Working directory; defaults to the session working directory.";
|
|
334
|
+
};
|
|
335
|
+
readonly run_in_background: {
|
|
336
|
+
readonly type: "boolean";
|
|
337
|
+
readonly description: "Return a host Job id immediately instead of waiting.";
|
|
338
|
+
};
|
|
339
|
+
readonly sandbox_permissions: {
|
|
340
|
+
readonly type: "string";
|
|
341
|
+
readonly enum: readonly ["workspace-write", "danger-full-access"];
|
|
342
|
+
readonly description: "Narrowest wider sandbox mode; must be paired with justification.";
|
|
343
|
+
};
|
|
344
|
+
readonly justification: {
|
|
345
|
+
readonly type: "string";
|
|
346
|
+
readonly description: "Required with sandbox_permissions; one sentence of reason.";
|
|
347
|
+
};
|
|
348
|
+
};
|
|
349
|
+
};
|
|
350
|
+
};
|
|
351
|
+
}[], {
|
|
352
|
+
readonly type: "object";
|
|
353
|
+
readonly additionalProperties: false;
|
|
354
|
+
readonly properties: {};
|
|
355
|
+
}];
|
|
47
356
|
};
|
|
48
357
|
};
|
|
49
358
|
};
|
|
@@ -52,5 +361,5 @@ export declare const STATE_PARAMETERS: {
|
|
|
52
361
|
readonly properties: {};
|
|
53
362
|
readonly additionalProperties: false;
|
|
54
363
|
};
|
|
55
|
-
export declare const REQUEST_DESCRIPTION = "\u8427\u4F55 / Xiao He. Submit a version 1 request and WAIT for its terminal result in this tool call.
|
|
364
|
+
export declare const REQUEST_DESCRIPTION = "\u8427\u4F55 / Xiao He. Submit a version 1 request and WAIT for its terminal result in this tool call. Use only when a host operation is expected to exceed ~30s, may be retried as the same logical operation (reuse requestId), must outlive a run_code budget end, or several steps must await one execution; otherwise call the original tool directly. messageId is per message; requestId is per logical operation. Control status/result/cancel use an empty payload; their snapshot is read-only. A PTC program end (including run_code budget expiry) only stops waiting: accepted work continues and the same requestId can be retrieved with status/result or cancelled. Diagnostic handler only: test {delayMs:0..30000,fail:boolean}; never use it to perform real work. Acceptance is volatile, not success. No polling or restart resume.";
|
|
56
365
|
export declare const MODE_INSTRUCTIONS: string;
|
package/dist/product.js
CHANGED
|
@@ -23,16 +23,127 @@ export const HANDLER_LIMITS = Object.freeze({
|
|
|
23
23
|
readPathChars: 2048,
|
|
24
24
|
diagnosticDelayMs: 30000,
|
|
25
25
|
});
|
|
26
|
+
/** 每个 Handler 的模型可见输入声明。只用于工具 schema/SDK 生成;运行时仍由 Handler.validate 严格校验。 */
|
|
27
|
+
const INPUT_SCHEMAS = {
|
|
28
|
+
test: {
|
|
29
|
+
type: "object",
|
|
30
|
+
additionalProperties: false,
|
|
31
|
+
required: ["delayMs", "fail"],
|
|
32
|
+
properties: {
|
|
33
|
+
delayMs: { type: "integer", description: "Diagnostic delay in milliseconds (0-30000)." },
|
|
34
|
+
fail: { type: "boolean", description: "Settle as a controlled failure when true." },
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
"host.read": {
|
|
38
|
+
type: "object",
|
|
39
|
+
additionalProperties: false,
|
|
40
|
+
required: ["file_path"],
|
|
41
|
+
properties: {
|
|
42
|
+
file_path: { type: "string", description: "Path resolved against the session working directory." },
|
|
43
|
+
offset: { type: "integer", description: "1-based first line to read." },
|
|
44
|
+
limit: { type: "integer", description: "Maximum lines to read (<=100)." },
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
"host.glob": {
|
|
48
|
+
type: "object",
|
|
49
|
+
additionalProperties: false,
|
|
50
|
+
required: ["pattern"],
|
|
51
|
+
properties: {
|
|
52
|
+
pattern: { type: "string", description: "Glob pattern; a bare pattern matches basenames at any depth." },
|
|
53
|
+
path: { type: "string", description: "Directory to search; defaults to the session working directory." },
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
"host.grep": {
|
|
57
|
+
type: "object",
|
|
58
|
+
additionalProperties: false,
|
|
59
|
+
required: ["pattern"],
|
|
60
|
+
properties: {
|
|
61
|
+
pattern: { type: "string", description: "Ripgrep regular expression." },
|
|
62
|
+
path: { type: "string", description: "File or directory to search; defaults to the session working directory." },
|
|
63
|
+
include: { type: "string", description: "One positive glob filter; negation and comma lists are rejected." },
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
"host.edit": {
|
|
67
|
+
type: "object",
|
|
68
|
+
additionalProperties: false,
|
|
69
|
+
required: ["file_path", "old_string", "new_string"],
|
|
70
|
+
properties: {
|
|
71
|
+
file_path: { type: "string", description: "File to edit." },
|
|
72
|
+
old_string: { type: "string", description: "Literal text to replace." },
|
|
73
|
+
new_string: { type: "string", description: "Replacement text." },
|
|
74
|
+
replace_all: { type: "boolean", description: "Replace every occurrence." },
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
"host.write": {
|
|
78
|
+
type: "object",
|
|
79
|
+
additionalProperties: false,
|
|
80
|
+
required: ["file_path", "content"],
|
|
81
|
+
properties: {
|
|
82
|
+
file_path: { type: "string", description: "File to write." },
|
|
83
|
+
content: { type: "string", description: "Full file content." },
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
"host.pwsh": {
|
|
87
|
+
type: "object",
|
|
88
|
+
additionalProperties: false,
|
|
89
|
+
required: ["description", "command"],
|
|
90
|
+
properties: {
|
|
91
|
+
description: { type: "string", description: "Clear, concise description of what the command does (shown in the UI)." },
|
|
92
|
+
command: { type: "string", description: "PowerShell command to execute." },
|
|
93
|
+
timeoutMs: { type: "number", description: "Positive timeout in milliseconds." },
|
|
94
|
+
workdir: { type: "string", description: "Working directory; defaults to the session working directory." },
|
|
95
|
+
run_in_background: { type: "boolean", description: "Return a host Job id immediately instead of waiting." },
|
|
96
|
+
sandbox_permissions: { type: "string", enum: ["workspace-write", "danger-full-access"], description: "Narrowest wider sandbox mode; must be paired with justification." },
|
|
97
|
+
justification: { type: "string", description: "Required with sandbox_permissions; one sentence of reason." },
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
/** Handler 名列表同时决定 request payload 的联合分支顺序。 */
|
|
102
|
+
const HANDLER_NAMES = [
|
|
103
|
+
"host.read",
|
|
104
|
+
"host.glob",
|
|
105
|
+
"host.grep",
|
|
106
|
+
"host.edit",
|
|
107
|
+
"host.write",
|
|
108
|
+
"host.pwsh",
|
|
109
|
+
"test",
|
|
110
|
+
];
|
|
111
|
+
/** request 的 {handler,input} 判别联合;控制消息为空对象。 */
|
|
112
|
+
export const PAYLOAD_SCHEMA = {
|
|
113
|
+
description: "request 必须匹配某个 Handler 的 {handler,input};status/result/cancel 的 payload 必须为空对象 {}。",
|
|
114
|
+
oneOf: [
|
|
115
|
+
...HANDLER_NAMES.map((handler) => ({
|
|
116
|
+
type: "object",
|
|
117
|
+
additionalProperties: false,
|
|
118
|
+
required: ["handler", "input"],
|
|
119
|
+
properties: {
|
|
120
|
+
handler: { type: "string", const: handler },
|
|
121
|
+
input: INPUT_SCHEMAS[handler],
|
|
122
|
+
},
|
|
123
|
+
})),
|
|
124
|
+
{ type: "object", additionalProperties: false, properties: {} },
|
|
125
|
+
],
|
|
126
|
+
};
|
|
26
127
|
export const REQUEST_PARAMETERS = {
|
|
27
128
|
type: "object",
|
|
28
129
|
additionalProperties: false,
|
|
29
130
|
required: ["protocolVersion", "messageId", "requestId", "type", "payload"],
|
|
30
131
|
properties: {
|
|
31
132
|
protocolVersion: { type: "integer", const: 1 },
|
|
32
|
-
messageId: {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
133
|
+
messageId: {
|
|
134
|
+
type: "string",
|
|
135
|
+
description: "Unique id of this message; reuse only when redelivering the same message.",
|
|
136
|
+
},
|
|
137
|
+
requestId: {
|
|
138
|
+
type: "string",
|
|
139
|
+
description: "Stable id of one logical operation; reuse it when the same operation is submitted again.",
|
|
140
|
+
},
|
|
141
|
+
type: {
|
|
142
|
+
type: "string",
|
|
143
|
+
enum: ["request", "status", "result", "cancel"],
|
|
144
|
+
description: "request submits work; status/result read the saved snapshot; cancel requests cancellation.",
|
|
145
|
+
},
|
|
146
|
+
payload: PAYLOAD_SCHEMA,
|
|
36
147
|
},
|
|
37
148
|
};
|
|
38
149
|
export const STATE_PARAMETERS = {
|
|
@@ -40,9 +151,9 @@ export const STATE_PARAMETERS = {
|
|
|
40
151
|
properties: {},
|
|
41
152
|
additionalProperties: false,
|
|
42
153
|
};
|
|
43
|
-
export const REQUEST_DESCRIPTION = "萧何 / Xiao He. Submit a version 1 request and WAIT for its terminal result in this tool call.
|
|
44
|
-
export const MODE_INSTRUCTIONS = "你正在萧何模式中。这不是角色扮演。保留宿主 PTC 的日常工具能力与权限规则。普通编辑、搜索、命令、安装和其他工作使用原工具,不要声称此模式只读。execution_bus
|
|
154
|
+
export const REQUEST_DESCRIPTION = "萧何 / Xiao He. Submit a version 1 request and WAIT for its terminal result in this tool call. Use only when a host operation is expected to exceed ~30s, may be retried as the same logical operation (reuse requestId), must outlive a run_code budget end, or several steps must await one execution; otherwise call the original tool directly. messageId is per message; requestId is per logical operation. Control status/result/cancel use an empty payload; their snapshot is read-only. A PTC program end (including run_code budget expiry) only stops waiting: accepted work continues and the same requestId can be retrieved with status/result or cancelled. Diagnostic handler only: test {delayMs:0..30000,fail:boolean}; never use it to perform real work. Acceptance is volatile, not success. No polling or restart resume.";
|
|
155
|
+
export const MODE_INSTRUCTIONS = "你正在萧何模式中。这不是角色扮演。保留宿主 PTC 的日常工具能力与权限规则。普通编辑、搜索、命令、安装和其他工作使用原工具,不要声称此模式只读。execution_bus 是可选协调入口,只在以下情况使用:预计单次宿主操作超过约 30 秒;同一逻辑操作可能重复提交或需要重试核对(沿用 requestId);任务需要在 run_code 时间预算结束后继续或取回结果;多个步骤需要等待同一执行。其余情况直接用原工具,不要为简单调用增加总线包装。实际业务 Handler 为 host.read、host.glob、host.grep(只读,可复用终态结果)与 host.edit、host.write、host.pwsh(有副作用,终态结果不可复用);test 仅用于用户明确要求的诊断,不做真实工作。示例:await tools.execution_bus({protocolVersion:1,messageId:\"<消息编号>\",requestId:\"<逻辑操作编号>\",type:\"request\",payload:{handler:\"host.read\",input:{file_path:\"README.md\"}}});messageId 每条消息唯一,同一逻辑操作重发沿用 requestId。通过 run_code 调用 await tools.execution_bus(...),受原有时间预算约束。每会话排队上限 " +
|
|
45
156
|
ADMISSION_DEFAULTS.sessionQueueLimit +
|
|
46
157
|
",排队超过 " +
|
|
47
158
|
ADMISSION_DEFAULTS.maxQueueWaitMs / 1000 +
|
|
48
|
-
" 秒且未执行会返回 QUEUE_WAIT_TIMEOUT,不自动重试。execution_bus_state 只用于用户明确诊断本会话元数据,不循环查询。请求只提交一次并等待结果,同一逻辑操作重发沿用 requestId。cancelRequested 不等于已取消,unknown 不代表执行失败,不承诺跨重启恢复。后台命令返回 Job ID 不代表已经完成。";
|
|
159
|
+
" 秒且未执行会返回 QUEUE_WAIT_TIMEOUT,不自动重试。execution_bus_state 只用于用户明确诊断本会话元数据,不循环查询。请求只提交一次并等待结果,同一逻辑操作重发沿用 requestId。PTC 程序结束或 run_code 时间预算到期时,已受理请求只停止等待、继续执行;用同一 requestId 的 status/result 取回,或用 cancel 取消;用户/会话中断仍会请求取消执行。cancelRequested 不等于已取消,unknown 不代表执行失败,不承诺跨重启恢复。后台命令返回 Job ID 不代表已经完成。";
|
package/docs/FLOW-TEST.md
CHANGED
|
@@ -37,6 +37,7 @@ npm run test:install
|
|
|
37
37
|
- Job 先行移除、等待/清理异常与卸载交错。
|
|
38
38
|
- 派生预设成功激活、原 ptc 声明不变、普通 Agent 不可见总线、write/edit 保留且宿主策略可拒绝。
|
|
39
39
|
- 真实 Node PTC 进程调用原 read 与总线;测试使用显式非约束策略,不代表桌面沙箱通过。
|
|
40
|
+
- 真实 Node PTC 预算到期后,已受理总线执行继续并可同 requestId 取回;外部中断仍请求取消执行。
|
|
40
41
|
|
|
41
42
|
以上是场景摘要,不表示真实模型/宿主 GUI 已通过。
|
|
42
43
|
|
|
@@ -45,6 +46,7 @@ npm run test:install
|
|
|
45
46
|
- 宿主工具调用失败在转发层使用固定码(host.read 为 `HOST_READ_FAILED`,其余为 `HOST_TOOL_FAILED`),进入总线后统一结算为 `failed` / `HANDLER_FAILED`,错误原文不保存;取消后可能保守记为 `unknown`,不能把它当作取消已确认。
|
|
46
47
|
- 相同逻辑请求的取消是请求级取消,不能简单用 Promise.race 放弃执行来改成等待者级取消。
|
|
47
48
|
- 当前没有远端 Handler 传输或持久化恢复;测试没有提供这些能力。
|
|
49
|
+
- 预算分离等待依据 DSH 0.2.1-rc.2 的内部中断原因字符串;换宿主版本需重新验证,未知原因保守按取消处理。
|
|
48
50
|
|
|
49
51
|
## 要直接在聊天会话中试用
|
|
50
52
|
|
package/docs/PRODUCT.md
CHANGED
|
@@ -6,6 +6,10 @@
|
|
|
6
6
|
|
|
7
7
|
0.8.0 在 DSH 0.2.1-rc.2 基线上补入只读搜索 Handler host.glob / host.grep 与有副作用命令 Handler host.pwsh,沿用 0.7.0 的幂等声明与宿主工具工厂,不以更名宣称完成生产环境认证。当前真实模型、桌面 UI 和实际沙箱尚未完整验收;同进程内存状态不支持跨重启恢复。
|
|
8
8
|
|
|
9
|
+
0.9.0 增加 PTC 预算到期后的分离等待:宿主中断 PTC 子调用时,已受理执行只解除等待、继续运行,可用同 requestId 的 status/result 取回或用 cancel 取消;其他中断原因仍按取消处理。该区分依据 DSH 0.2.1-rc.2 的中断原因字符串,不是公开稳定契约,宿主升级需复核。
|
|
10
|
+
|
|
11
|
+
0.10.0 改善模型侧的采用条件:模式说明写明仅在预计 >30 秒、可能重复提交、预算结束后继续或跨步骤等待同一执行时使用总线,并给出调用示例;工具声明把 payload 改为按 Handler 的判别联合,PTC SDK 与原生声明直接显示每个 Handler 的必填/可选字段。wire 协议、字段、错误码与 Handler 行为不变,只改变模型可见的提示与 schema。
|
|
12
|
+
|
|
9
13
|
## 入口及配置层次
|
|
10
14
|
|
|
11
15
|
| 入口 | 谁使用 | 责任 |
|
|
@@ -35,6 +35,7 @@ PTC 是可选入口:外层 `run_code` 可以调用同一个工具。它不是
|
|
|
35
35
|
| 注册与卸载 | `@deepseek-ai/dsh-tools`:2878–2886,工具注册;3294–3331,`dispatchToolBody` | 注册为作用域副作用,工具体可异步等待 |
|
|
36
36
|
| 身份与策略 | `@deepseek-ai/dsh-tools`:3131–3175、3225、3504、3417 | 生成可信 token、保留 agent/callId/rootCallId,执行前后策略及结果通知 |
|
|
37
37
|
| PTC 子调用 | `@deepseek-ai/dsh-tools`:1294–1307 | 子调用携带 agent、rootCallId 和 parent token;不是任意身份注入 |
|
|
38
|
+
| PTC 子调用中断 | `@deepseek-ai/dsh-tools`:1282–1285 外层中断转发;1376、1508 子调用信号取自 `runController`;1514 程序结束/预算到期后以固定字符串中断残留子调用 | 外层中断原因与程序结束原因可区分;固定字符串是 rc.2 构建细节,不是公开稳定契约 |
|
|
38
39
|
| 文件读取 | `@deepseek-ai/dsh-tool-fs`:174、348,read 注册/执行路径 | 工作目录来自会话;输出和文件边界由宿主组合决定 |
|
|
39
40
|
| 任务与等待 | `@deepseek-ai/dsh-jobs-local`:412–491 `start`、510 `wait`、717–729 `updateProgress` | 所属访问、容量、进度、取消、首终态与程序等待可复用 |
|
|
40
41
|
| 完成通知 | `@deepseek-ai/dsh-tool-jobs`:268–270 | 正常已等待的完成通知不再额外报告;异常等待通道不承诺这一抑制仍完整生效 |
|
|
@@ -52,6 +53,7 @@ PTC 是可选入口:外层 `run_code` 可以调用同一个工具。它不是
|
|
|
52
53
|
- 复用宿主工具管线和 Job 服务,不自行启动进程或实现独立 HTTP 执行服务。
|
|
53
54
|
- bundle patch 加载派生注册器,从已声明 ptc 读取组合快照并注册可选预设,由宿主既有 Agent 预设界面消费元数据,不需要自定义前端。readDocument 在宿主注释中用于查看声明,本插件只读取其序列化数据再注册独立预设,并不认领源预设的运行实例或私有基准地址。
|
|
54
55
|
- 同预设范围内共享有界总线,但查询/取消按宿主 Agent 的会话身份分隔。
|
|
56
|
+
- PTC 预算到期后的分离等待(0.9.0):程序结束只停止等待,已受理执行与宿主 Job 继续,同会话可用同一 requestId 取回结果;其他中断原因仍取消。该识别依赖 rc.2 固定中断原因,未知原因保守按取消处理。
|
|
55
57
|
|
|
56
58
|
旧版只读 guard 在 0.3.0 移除,预设保留源 ptc 的工具与权限,不再削减普通写入/命令能力,也不自动启用源组合禁用行。它不是进程或权限沙箱,不隔离进程资源消耗。宿主 cwd 只是路径解析基准,不是文件访问围栏。
|
|
57
59
|
|
|
@@ -63,6 +65,7 @@ PTC 是可选入口:外层 `run_code` 可以调用同一个工具。它不是
|
|
|
63
65
|
- 持久化受理、跨重启恢复或重新认领原工具调用。
|
|
64
66
|
- 工具结果已写入会话磁盘日志的持久化回执。
|
|
65
67
|
- 远端执行端、通用工作流或有副作用操作的对账能力。
|
|
68
|
+
- 跨宿主版本稳定的 PTC 中断原因契约;0.9.0 的预算分离等待只按 rc.2 实际使用的固定字符串识别,宿主升级后需复核。
|
|
66
69
|
|
|
67
70
|
若未来要跨重启接续,需要宿主公开稳定的认领/提交契约;本项目不虚构这样的 API,也不通过聊天消息绕过。
|
|
68
71
|
|
package/docs/protocol.md
CHANGED
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
|
|
41
41
|
快照字段:`requestId`、`state`、`sequence`、`cancelRequested`、`delivery`,以及可选 `result`、`error`、`progress`。`status`、`result`、`cancel` 均返回当前快照;`result` 在运行中也只返回当前状态,不额外等待。
|
|
42
42
|
|
|
43
|
-
core 的 `submit()` 返回 `accepted`、`done` Promise
|
|
43
|
+
core 的 `submit()` 返回 `accepted`、`done` Promise、只读 `snapshot()` 及取消/解除通知/返回标记句柄。accepted 只是内存受理或已有记录的快照,`durable:false`,不代表执行成功;终态重取也不代表重新执行。0.9.0 的 `snapshot()` 只供停止等待时读取当前视图,不改变交付标记。
|
|
44
44
|
|
|
45
45
|
通知包含版本、消息 ID、请求 ID、关联 ID(correlationId)、请求内序号、类型与 payload。accepted 的 correlationId 对应本次提交消息,序号是当前快照;后续事件关联首次请求 messageId,新增序号。类型包括 started、progress、cancel_requested 和 succeeded、failed、cancelled、unknown 四种终态事件。
|
|
46
46
|
|
|
@@ -68,6 +68,12 @@ queued → running → succeeded / failed / cancelled / unknown
|
|
|
68
68
|
|
|
69
69
|
执行完成与结果交付分开。`pending`/`returned` 只是插件返回路径的标记;done 快照保留当时值,后续查询可看到更新。**returned 不证明宿主磁盘提交或模型已消费**。外层取消/后置策略仍可能改变返回值。
|
|
70
70
|
|
|
71
|
+
### 外层调用结束与时间预算(0.9.0)
|
|
72
|
+
|
|
73
|
+
PTC 程序结束(含 `run_code` 时间预算到期)时,宿主以固定原因中断其中的工具子调用。总线对**已受理**请求只解除本次等待,不请求取消:执行与宿主 Job 继续,同一会话可用同一 requestId 的 `status`/`result` 取回(受记录保留期限制),或发送 `cancel`。用户/会话主动中断、沙箱模式变化等其他原因仍请求取消整个执行。
|
|
74
|
+
|
|
75
|
+
这条区分依据 DSH 0.2.1-rc.2 的内部中断原因字符串(`run_code settled`),不是宿主公开稳定契约;未知原因按取消处理。分离等待不改变内存与保留期边界:进程退出仍丢失全部状态,`returned` 仍不证明模型已取回结果。
|
|
76
|
+
|
|
71
77
|
错误也须分层:Handler 异常原文不进入保存结果,使用 HANDLER_FAILED 等固定码;不合法、过大或快照不可保存结果为 unknown / RESULT_NOT_RETAINED。宿主 wait/remove 等服务错误可能作为外层工具错误传出,不能笼统声称所有错误都已脱敏或都是固定码。不要把宿主服务错误文本当成业务执行失败凭据。
|
|
72
78
|
|
|
73
79
|
## 4. 容量、保存与关闭
|
|
@@ -116,4 +122,6 @@ core 实例的 `diagnostics()` 返回只读用途的独立快照:阶段计数
|
|
|
116
122
|
|
|
117
123
|
包的 `./core` 导出 ExecutionBus、Handler、Capability 类型。Handler 只接收输入、requestId、signal、progress 和可选最小 capability,不接收聊天历史。register 返回绑定唯一注册令牌的幂等注销函数,不会误删后来同名注册;已受理请求继续持有原 Handler。
|
|
118
124
|
|
|
125
|
+
0.10.0 起,模型可见的工具体声明把 `payload` 改为按 Handler 的判别联合(每个 `host.*`/test 的 `input` 字段与必填项);这是提示与 SDK 类型层的变化,wire 结构、校验、错误码与保存语义不变。
|
|
126
|
+
|
|
119
127
|
内置 test、host.read、host.glob 与 host.grep 没有副作用;host.edit、host.write 与 host.pwsh 是非幂等写/命令 Handler,通过 `Handler.idempotent=false` 显式声明,其终态结果复用被 `MUTATING_REUSE_DENIED` 拒绝,运行中的重复附着仍只等待同一执行。0.8.0 新增宿主工具输入错误码 INVALID_GLOB_INPUT、INVALID_GREP_INPUT 与 INVALID_PWSH_INPUT;协议既有错误码不改名。host.pwsh 的后台结果只是宿主 Job ID,不是完成回执。当前没有 ctx.executionBus 服务、远端传输、跨插件动态注册或外部副作用对账契约。扩展有副作用 Handler 前必须显式声明幂等并另行设计授权与崩溃对账,不能仅依赖本版请求键。
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# 萧何 / Xiao He 0.10.0
|
|
2
|
+
|
|
3
|
+
## 让总线可被采用:触发条件与类型化声明
|
|
4
|
+
|
|
5
|
+
本版不改变执行机制,专门改善“模式被选中但总线从未被调用”的采用问题。
|
|
6
|
+
|
|
7
|
+
- 模式说明新增明确触发条件:仅在预计单次宿主操作超过约 30 秒、同一逻辑操作可能重复提交(沿用 requestId)、任务需要在 `run_code` 时间预算结束后继续、或多个步骤需要等待同一执行时才使用总线;其余任务继续直接用原工具,并给出一条调用示例与 messageId/requestId 语义。
|
|
8
|
+
- `execution_bus` 的模型可见参数从泛型 `payload: Record<string, JsonValue>` 改为按 Handler 的判别联合(`host.read` / `host.glob` / `host.grep` / `host.edit` / `host.write` / `host.pwsh` / `test` + 空控制 payload)。PTC SDK 与原生工具声明现在直接显示每个 Handler 的必填/可选字段;wire 结构、校验、错误码、状态机与 Handler 行为不变。
|
|
9
|
+
- 工具描述同步写明触发条件与编号语义;诊断 Handler 仍标注仅用于明确诊断。
|
|
10
|
+
- 代价:模型可见声明变大。模式说明 916 字符(+319),`execution_bus` 的 SDK 参数声明约 4.1KB(原泛型声明约 1.3KB);是否换来更高的真实采用率与更好的结果,需要 pilot 与同任务 A/B 对照验证。
|
|
11
|
+
- 新增 4 项回归(判别联合结构、合法/未知 Handler 校验、SDK 渲染、提示触发条件),并扩展真实 Node PTC 用例断言装配后的 SDK 含类型化声明。
|
|
12
|
+
|
|
13
|
+
## 升级说明
|
|
14
|
+
|
|
15
|
+
需要 DSH 0.2.1-rc.2。本版只有模型可见提示与工具 schema 变化;请求结构、字段、预设、工具名、错误码与 Handler 行为均不变。不自动安装、重写日常配置或重启 DSH。
|
|
16
|
+
|
|
17
|
+
## 验证与限制
|
|
18
|
+
|
|
19
|
+
本地全量 105 项测试通过。真实模型采用率、轮次/耗时收益未验证,需 pilot 与 A/B 对照;真实模型、桌面 UI 与实际沙箱仍未完整验收。若 pilot 显示声明开销不值得,可回退为较短的泛型声明。
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# 萧何 / Xiao He 0.9.0
|
|
2
|
+
|
|
3
|
+
## PTC 预算到期后的分离等待
|
|
4
|
+
|
|
5
|
+
本版解决“长任务超出 `run_code` 时间预算就被连带取消”的问题:程序结束只停止等待,已受理执行继续。
|
|
6
|
+
|
|
7
|
+
- PTC 程序结束或 `run_code` 时间预算到期时,宿主会以固定原因中断其中的工具子调用。总线对已受理请求只解除本次等待:执行与宿主 Job 继续,同一会话可用同一 requestId 的 `status`/`result` 取回结果(受 1 小时保留期与 256 条记录上限约束),或发送 `cancel` 取消。
|
|
8
|
+
- 用户/会话主动中断、沙箱模式变化等其他中断原因仍请求取消整个执行;未知原因保守按取消处理。
|
|
9
|
+
- 该区分依赖 DSH 0.2.1-rc.2 实际使用的内部中断原因字符串(`@deepseek-ai/dsh-tools` 构建中的 `run_code settled`),不是宿主公开稳定契约;宿主升级后需复核。
|
|
10
|
+
- core 的 `submit()` 附着新增只读 `snapshot()`,供停止等待时返回当前快照;不改变既有状态机、幂等与结果保留语义。
|
|
11
|
+
- 模式提示与工具体描述同步说明取回与取消方式。
|
|
12
|
+
|
|
13
|
+
## 升级说明
|
|
14
|
+
|
|
15
|
+
需要 DSH 0.2.1-rc.2。行为变化:**PTC 程序结束不再连带取消已受理执行**。若需要旧行为(程序结束即取消),应在程序结束前显式发送 `cancel` 控制消息。不自动安装、重写日常配置或重启 DSH。历史预设、配置行、工具名、协议字段与既有错误码均不变;状态仍为进程内存,不支持跨重启恢复。
|
|
16
|
+
|
|
17
|
+
## 验证与限制
|
|
18
|
+
|
|
19
|
+
本地全量 101 项测试通过(新增 6 项分离等待回归、2 项真实 Node PTC 预算/中断回归,覆盖宿主 Job 生命周期、重附着与分离后的宿主工具续调用)。真实模型、桌面 UI 与实际沙箱仍未完整验收;分离等待只在同一插件实例存活期间有效,进程退出即丢失状态;跨宿主版本的中断原因识别未验证。
|
package/docs/validation.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 验证范围与使用限制
|
|
2
2
|
|
|
3
|
-
本文说明当前版本的证据边界,不是生产环境认证。当前能力基线为 **v0.
|
|
3
|
+
本文说明当前版本的证据边界,不是生产环境认证。当前能力基线为 **v0.10.0**,在 0.5.0 的会话准入/排队、0.7.0 的宿主工具转发、0.8.0 的搜索/命令 Handler 与 0.9.0 的预算分离等待上,改善模型侧采用条件(触发说明、类型化工具声明);预设沿用 v0.3.0 的宿主 PTC 声明派生方式。验证环境为 Windows、Node.js 24.21.0,宿主组件锁定 DSH 0.2.1-rc.2、Cordis 4.0.4。
|
|
4
4
|
|
|
5
5
|
## 已验证什么?
|
|
6
6
|
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
| 总线核心 | 参数、队列、并发、重复请求、冲突、取消竞争、结果保存、TTL、监听与注销 | 程序内部约束及已覆盖异常路径可重复检查 |
|
|
10
10
|
| 真实宿主组件 | Cordis、ToolRuntime、LocalJobs、LocalFS、文件工具;host.glob/host.grep/host.pwsh 的转发测试使用宿主工具桩 | 请求经过真实工具管线;权限拒绝、Job 进度、共享任务、参数校验、幂等分流与清理逻辑有效;Agent 身份与工具实现为夹具,桩不证明真实搜索/命令工具实现 |
|
|
11
11
|
| 真实会话循环 | AgentLoop、AgentRegistry、SessionStore;脚本模型适配器 | 内存会话中原工具结果只提交一次,完成后再进入下一次适配器调用 |
|
|
12
|
+
| PTC 预算分离等待 | 真实 Node PTC `run_code` 以 2 秒预算等待 5 秒总线执行:预算到期后执行继续、宿主 Job 保留、同 requestId 取回结果;外部中断仍取消执行 | 在 DSH 0.2.1-rc.2 实际中断原因下成立;固定字符串不是跨版本契约 |
|
|
12
13
|
| 预设隔离 | AgentPresetRegistry 与 Loader | 派生预设可激活;源 ptc 声明不变、普通 Agent 不可见总线;原 write/edit/Job 工具保留,宿主前置策略拒绝仍有效 |
|
|
13
14
|
| 故障注入 | 克隆失败、观察者拒绝、Job 等待/清理异常、先行移除与卸载交错 | 指定故障下的回归约束;不证明所有故障组合都已覆盖 |
|
|
14
15
|
| 候选包 | 严格文件白名单、临时目录生产依赖安装、入口注册 | 包可安装和加载;安装验证使用简化宿主夹具,不是桌面插件管理器验收 |
|
|
@@ -43,6 +44,8 @@ eb95b4e51675f5f1821275e0812ef4dd4984b1aba45a52fbc6bab3518bbf6f38
|
|
|
43
44
|
| 实际模型/桌面 PTC 与时间预算、沙箱行为 | 真实 Node PTC 隔离子进程已调用原 read 和总线;使用显式 danger-full-access 测试策略与测试 Agent,不是桌面沙箱/真实模型验收 |
|
|
44
45
|
| 从真实 tgz 经宿主插件管理器加载预设、卸载与回滚 | 未完成完整桌面流程;源码工作区的 Loader 测试不能替代 |
|
|
45
46
|
| 真实 glob/grep/pwsh 工具实现 | 未在测试环境启用:真实搜索工具依赖打包 ripgrep 与 subprocess 服务,真实 pwsh 依赖 shell/sandbox/审批组合;本版只验证按 handler 名转发、输入校验、幂等分流与失败固定码 |
|
|
47
|
+
| 跨版本 PTC 中断原因 | 分离等待只识别 DSH 0.2.1-rc.2 实际使用的固定中断原因字符串;宿主升级后未知原因保守按取消处理,需复核 |
|
|
48
|
+
| 模式采用率与效果 | 未验证。0.10.0 只改善触发说明与工具声明可读性;真实模型是否更常使用总线、是否带来更少轮次/更短耗时,需要 pilot 与同任务 A/B 对照,不能由 schema 或测试推断 |
|
|
46
49
|
| 磁盘会话结果提交及重启恢复原调用 | 未验收磁盘提交;本插件不支持跨重启恢复 |
|
|
47
50
|
| 减少真实模型轮次、状态查询或总耗时的对照 | 未验证,不给提升比例 |
|
|
48
51
|
| 长期运行、所有卸载/服务故障组合 | 未穷尽;持续故障仍有清理限制 |
|