@xgjktech/xg_cwork_im 1.16.45 → 1.17.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 +433 -433
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -1
- package/dist/src/connection.js +2 -2
- package/dist/src/connection.js.map +1 -1
- package/dist/src/deliver-text.test.js +22 -22
- package/dist/src/dispatch-mentioned-reply.d.ts.map +1 -1
- package/dist/src/dispatch-mentioned-reply.js +8 -0
- package/dist/src/dispatch-mentioned-reply.js.map +1 -1
- package/dist/src/plan-blocked-notice.d.ts +15 -0
- package/dist/src/plan-blocked-notice.d.ts.map +1 -0
- package/dist/src/plan-blocked-notice.js +28 -0
- package/dist/src/plan-blocked-notice.js.map +1 -0
- package/dist/src/plan-blocked-notice.test.d.ts +2 -0
- package/dist/src/plan-blocked-notice.test.d.ts.map +1 -0
- package/dist/src/plan-blocked-notice.test.js +80 -0
- package/dist/src/plan-blocked-notice.test.js.map +1 -0
- package/dist/src/plan-event-subscription.d.ts +26 -0
- package/dist/src/plan-event-subscription.d.ts.map +1 -0
- package/dist/src/plan-event-subscription.js +121 -0
- package/dist/src/plan-event-subscription.js.map +1 -0
- package/dist/src/plan-event-subscription.test.d.ts +2 -0
- package/dist/src/plan-event-subscription.test.d.ts.map +1 -0
- package/dist/src/plan-event-subscription.test.js +257 -0
- package/dist/src/plan-event-subscription.test.js.map +1 -0
- package/dist/src/plan-session-registry.d.ts +24 -0
- package/dist/src/plan-session-registry.d.ts.map +1 -0
- package/dist/src/plan-session-registry.js +84 -0
- package/dist/src/plan-session-registry.js.map +1 -0
- package/dist/src/plan-session-registry.test.d.ts +2 -0
- package/dist/src/plan-session-registry.test.d.ts.map +1 -0
- package/dist/src/plan-session-registry.test.js +109 -0
- package/dist/src/plan-session-registry.test.js.map +1 -0
- package/dist/src/plan-store-access.d.ts +16 -0
- package/dist/src/plan-store-access.d.ts.map +1 -0
- package/dist/src/plan-store-access.js +76 -0
- package/dist/src/plan-store-access.js.map +1 -0
- package/dist/src/plan-store-access.test.d.ts +2 -0
- package/dist/src/plan-store-access.test.d.ts.map +1 -0
- package/dist/src/plan-store-access.test.js +139 -0
- package/dist/src/plan-store-access.test.js.map +1 -0
- package/dist/src/plan-tool-middleware.d.ts +20 -0
- package/dist/src/plan-tool-middleware.d.ts.map +1 -0
- package/dist/src/plan-tool-middleware.js +99 -0
- package/dist/src/plan-tool-middleware.js.map +1 -0
- package/dist/src/plan-tool-middleware.test.d.ts +2 -0
- package/dist/src/plan-tool-middleware.test.d.ts.map +1 -0
- package/dist/src/plan-tool-middleware.test.js +329 -0
- package/dist/src/plan-tool-middleware.test.js.map +1 -0
- package/dist/src/plan-tool-result.d.ts +20 -0
- package/dist/src/plan-tool-result.d.ts.map +1 -0
- package/dist/src/plan-tool-result.js +78 -0
- package/dist/src/plan-tool-result.js.map +1 -0
- package/dist/src/plan-tool-result.test.d.ts +2 -0
- package/dist/src/plan-tool-result.test.d.ts.map +1 -0
- package/dist/src/plan-tool-result.test.js +107 -0
- package/dist/src/plan-tool-result.test.js.map +1 -0
- package/dist/src/subagent-monitor.js +11 -17
- package/dist/src/subagent-monitor.js.map +1 -1
- package/dist/src/turn-deliver-buffer.test.js +25 -25
- package/openclaw.plugin.json +27 -26
- package/package.json +76 -72
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { beforeEach, describe, it } from "node:test";
|
|
3
|
+
import { createPlanToolResultMiddleware } from "./plan-tool-middleware.js";
|
|
4
|
+
import { registerToolCallTarget, resetPlanSessionRegistryForTest, } from "./plan-session-registry.js";
|
|
5
|
+
const FAKE_CTX = { runtime: "openclaw" };
|
|
6
|
+
function makePlan(overrides = {}) {
|
|
7
|
+
return {
|
|
8
|
+
planId: "plan-1",
|
|
9
|
+
goal: "迁移配置到新版本",
|
|
10
|
+
createdAt: "2026-07-27T00:00:00.000Z",
|
|
11
|
+
updatedAt: "2026-07-27T00:00:00.000Z",
|
|
12
|
+
tasks: [],
|
|
13
|
+
...overrides,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function makeEvent(overrides) {
|
|
17
|
+
const content = overrides.text !== undefined
|
|
18
|
+
? [{ type: "text", text: overrides.text }]
|
|
19
|
+
: [];
|
|
20
|
+
return {
|
|
21
|
+
toolCallId: overrides.toolCallId ?? "call-1",
|
|
22
|
+
toolName: overrides.toolName ?? "xg_plan_write",
|
|
23
|
+
args: {},
|
|
24
|
+
result: {
|
|
25
|
+
details: overrides.details,
|
|
26
|
+
content,
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function makeSuccessPayload(plan, withEvent = false) {
|
|
31
|
+
return {
|
|
32
|
+
ok: true,
|
|
33
|
+
planId: plan.planId,
|
|
34
|
+
plan,
|
|
35
|
+
...(withEvent ? { event: { emitted: false, reason: "no runId" } } : {}),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
class RecordingDeps {
|
|
39
|
+
calls = [];
|
|
40
|
+
sendTextImpl = async (target, content) => {
|
|
41
|
+
this.calls.push({ target, content });
|
|
42
|
+
};
|
|
43
|
+
planById = new Map();
|
|
44
|
+
sendText = (target, content) => {
|
|
45
|
+
return this.sendTextImpl(target, content);
|
|
46
|
+
};
|
|
47
|
+
getPlanById = (planId) => {
|
|
48
|
+
return this.planById.get(planId);
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
beforeEach(() => {
|
|
52
|
+
resetPlanSessionRegistryForTest();
|
|
53
|
+
});
|
|
54
|
+
describe("createPlanToolResultMiddleware: 非 plan 工具直接放行", () => {
|
|
55
|
+
it("does not touch sendText or getPlanById for unrelated tools", () => {
|
|
56
|
+
const deps = new RecordingDeps();
|
|
57
|
+
const handler = createPlanToolResultMiddleware(deps);
|
|
58
|
+
const event = makeEvent({
|
|
59
|
+
toolName: "some_other_tool",
|
|
60
|
+
details: { ok: true, data: 123 },
|
|
61
|
+
});
|
|
62
|
+
const result = handler(event, FAKE_CTX);
|
|
63
|
+
assert.equal(result, undefined);
|
|
64
|
+
assert.equal(deps.calls.length, 0);
|
|
65
|
+
});
|
|
66
|
+
it("does not push even when a non-plan tool's details is a structurally valid plan payload (pins the name filter)", () => {
|
|
67
|
+
const deps = new RecordingDeps();
|
|
68
|
+
const handler = createPlanToolResultMiddleware(deps);
|
|
69
|
+
// 表中已登记该 toolCallId,若名字过滤被删掉,结构守卫会放行并触发推送
|
|
70
|
+
registerToolCallTarget("call-evil", { groupId: "g-evil", token: "t-evil" });
|
|
71
|
+
const plan = makePlan({ tasks: [{ title: "备份旧配置", status: "blocked", note: "缺少权限" }] });
|
|
72
|
+
const event = makeEvent({
|
|
73
|
+
toolCallId: "call-evil",
|
|
74
|
+
toolName: "some_evil_tool",
|
|
75
|
+
details: makeSuccessPayload(plan),
|
|
76
|
+
});
|
|
77
|
+
const result = handler(event, FAKE_CTX);
|
|
78
|
+
assert.equal(result, undefined);
|
|
79
|
+
assert.equal(deps.calls.length, 0);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
describe("createPlanToolResultMiddleware: details 路径", () => {
|
|
83
|
+
it("pushes a blocked notice when details carries a valid plan", () => {
|
|
84
|
+
const deps = new RecordingDeps();
|
|
85
|
+
const handler = createPlanToolResultMiddleware(deps);
|
|
86
|
+
registerToolCallTarget("call-1", { groupId: "g1", token: "t1" });
|
|
87
|
+
const plan = makePlan({
|
|
88
|
+
tasks: [{ title: "备份旧配置", status: "blocked", note: "缺少权限" }],
|
|
89
|
+
});
|
|
90
|
+
const event = makeEvent({
|
|
91
|
+
toolCallId: "call-1",
|
|
92
|
+
toolName: "xg_plan_write",
|
|
93
|
+
details: makeSuccessPayload(plan),
|
|
94
|
+
});
|
|
95
|
+
const result = handler(event, FAKE_CTX);
|
|
96
|
+
assert.equal(result, undefined);
|
|
97
|
+
assert.equal(deps.calls.length, 1);
|
|
98
|
+
assert.equal(deps.calls[0].target.groupId, "g1");
|
|
99
|
+
assert.ok(deps.calls[0].content.includes("备份旧配置"));
|
|
100
|
+
assert.ok(deps.calls[0].content.includes("缺少权限"));
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
describe("createPlanToolResultMiddleware: text 回退路径", () => {
|
|
104
|
+
it("falls back to content[0].text when details is undefined", () => {
|
|
105
|
+
const deps = new RecordingDeps();
|
|
106
|
+
const handler = createPlanToolResultMiddleware(deps);
|
|
107
|
+
registerToolCallTarget("call-2", { groupId: "g2", token: "t2" });
|
|
108
|
+
const plan = makePlan({
|
|
109
|
+
planId: "plan-2",
|
|
110
|
+
tasks: [{ title: "校验数据", status: "blocked", note: "依赖未就绪" }],
|
|
111
|
+
});
|
|
112
|
+
const rawBody = JSON.stringify(makeSuccessPayload(plan, true), null, 2);
|
|
113
|
+
const event = makeEvent({
|
|
114
|
+
toolCallId: "call-2",
|
|
115
|
+
toolName: "xg_plan_execute",
|
|
116
|
+
details: undefined,
|
|
117
|
+
text: rawBody,
|
|
118
|
+
});
|
|
119
|
+
const result = handler(event, FAKE_CTX);
|
|
120
|
+
assert.equal(result, undefined);
|
|
121
|
+
assert.equal(deps.calls.length, 1);
|
|
122
|
+
assert.ok(deps.calls[0].content.includes("校验数据"));
|
|
123
|
+
});
|
|
124
|
+
it("uses getPlanById authoritative state when details is missing (D5/RULING-1 §3)", () => {
|
|
125
|
+
const deps = new RecordingDeps();
|
|
126
|
+
const handler = createPlanToolResultMiddleware(deps);
|
|
127
|
+
registerToolCallTarget("call-3", { groupId: "g3", token: "t3" });
|
|
128
|
+
// text 路径拿到的 plan 里没有 blocked task,但权威反查里有
|
|
129
|
+
const textPlan = makePlan({ planId: "plan-3", tasks: [{ title: "t1", status: "pending" }] });
|
|
130
|
+
const authoritativePlan = makePlan({
|
|
131
|
+
planId: "plan-3",
|
|
132
|
+
tasks: [{ title: "t1", status: "blocked", note: "authoritative 才有的阻塞" }],
|
|
133
|
+
});
|
|
134
|
+
deps.planById.set("plan-3", authoritativePlan);
|
|
135
|
+
const rawBody = JSON.stringify(makeSuccessPayload(textPlan), null, 2);
|
|
136
|
+
const event = makeEvent({
|
|
137
|
+
toolCallId: "call-3",
|
|
138
|
+
toolName: "xg_plan_write",
|
|
139
|
+
details: undefined,
|
|
140
|
+
text: rawBody,
|
|
141
|
+
});
|
|
142
|
+
handler(event, FAKE_CTX);
|
|
143
|
+
assert.equal(deps.calls.length, 1);
|
|
144
|
+
assert.ok(deps.calls[0].content.includes("authoritative 才有的阻塞"));
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
describe("createPlanToolResultMiddleware: 守卫拒绝畸形 payload", () => {
|
|
148
|
+
it("does not push for ok:false", () => {
|
|
149
|
+
const deps = new RecordingDeps();
|
|
150
|
+
const handler = createPlanToolResultMiddleware(deps);
|
|
151
|
+
registerToolCallTarget("call-4", { groupId: "g4", token: "t4" });
|
|
152
|
+
const event = makeEvent({
|
|
153
|
+
toolCallId: "call-4",
|
|
154
|
+
toolName: "xg_plan_write",
|
|
155
|
+
details: { ok: false, error: { code: "PLAN_NOT_FOUND" } },
|
|
156
|
+
});
|
|
157
|
+
assert.equal(handler(event, FAKE_CTX), undefined);
|
|
158
|
+
assert.equal(deps.calls.length, 0);
|
|
159
|
+
});
|
|
160
|
+
it("does not push when planId is missing", () => {
|
|
161
|
+
const deps = new RecordingDeps();
|
|
162
|
+
const handler = createPlanToolResultMiddleware(deps);
|
|
163
|
+
registerToolCallTarget("call-5", { groupId: "g5", token: "t5" });
|
|
164
|
+
const event = makeEvent({
|
|
165
|
+
toolCallId: "call-5",
|
|
166
|
+
toolName: "xg_plan_write",
|
|
167
|
+
details: { ok: true, plan: makePlan() },
|
|
168
|
+
});
|
|
169
|
+
assert.equal(handler(event, FAKE_CTX), undefined);
|
|
170
|
+
assert.equal(deps.calls.length, 0);
|
|
171
|
+
});
|
|
172
|
+
it("does not push when tasks is not an array", () => {
|
|
173
|
+
const deps = new RecordingDeps();
|
|
174
|
+
const handler = createPlanToolResultMiddleware(deps);
|
|
175
|
+
registerToolCallTarget("call-6", { groupId: "g6", token: "t6" });
|
|
176
|
+
const event = makeEvent({
|
|
177
|
+
toolCallId: "call-6",
|
|
178
|
+
toolName: "xg_plan_write",
|
|
179
|
+
details: {
|
|
180
|
+
ok: true,
|
|
181
|
+
planId: "plan-6",
|
|
182
|
+
plan: { planId: "plan-6", goal: "g", createdAt: "t", updatedAt: "t", tasks: "not-an-array" },
|
|
183
|
+
},
|
|
184
|
+
});
|
|
185
|
+
assert.equal(handler(event, FAKE_CTX), undefined);
|
|
186
|
+
assert.equal(deps.calls.length, 0);
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
describe("createPlanToolResultMiddleware: handler 内部出错不外抛", () => {
|
|
190
|
+
it("resolves normally even when sendText throws synchronously", () => {
|
|
191
|
+
const deps = new RecordingDeps();
|
|
192
|
+
deps.sendTextImpl = () => {
|
|
193
|
+
throw new Error("boom");
|
|
194
|
+
};
|
|
195
|
+
const handler = createPlanToolResultMiddleware(deps);
|
|
196
|
+
registerToolCallTarget("call-7", { groupId: "g7", token: "t7" });
|
|
197
|
+
const plan = makePlan({ tasks: [{ title: "t1", status: "blocked", note: "n" }] });
|
|
198
|
+
const event = makeEvent({
|
|
199
|
+
toolCallId: "call-7",
|
|
200
|
+
toolName: "xg_plan_write",
|
|
201
|
+
details: makeSuccessPayload(plan),
|
|
202
|
+
});
|
|
203
|
+
assert.doesNotThrow(() => handler(event, FAKE_CTX));
|
|
204
|
+
});
|
|
205
|
+
it("resolves normally even when getPlanById throws", () => {
|
|
206
|
+
const deps = new RecordingDeps();
|
|
207
|
+
deps.getPlanById = () => {
|
|
208
|
+
throw new Error("boom");
|
|
209
|
+
};
|
|
210
|
+
const handler = createPlanToolResultMiddleware(deps);
|
|
211
|
+
registerToolCallTarget("call-8", { groupId: "g8", token: "t8" });
|
|
212
|
+
const plan = makePlan({ planId: "plan-8", tasks: [{ title: "t1", status: "blocked", note: "n" }] });
|
|
213
|
+
const rawBody = JSON.stringify(makeSuccessPayload(plan), null, 2);
|
|
214
|
+
const event = makeEvent({
|
|
215
|
+
toolCallId: "call-8",
|
|
216
|
+
toolName: "xg_plan_write",
|
|
217
|
+
details: undefined,
|
|
218
|
+
text: rawBody,
|
|
219
|
+
});
|
|
220
|
+
assert.doesNotThrow(() => handler(event, FAKE_CTX));
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
describe("createPlanToolResultMiddleware: 恒返回 void", () => {
|
|
224
|
+
it("handler's return value is undefined", () => {
|
|
225
|
+
const deps = new RecordingDeps();
|
|
226
|
+
const handler = createPlanToolResultMiddleware(deps);
|
|
227
|
+
registerToolCallTarget("call-9", { groupId: "g9", token: "t9" });
|
|
228
|
+
const plan = makePlan({ tasks: [{ title: "t1", status: "blocked", note: "n" }] });
|
|
229
|
+
const event = makeEvent({
|
|
230
|
+
toolCallId: "call-9",
|
|
231
|
+
toolName: "xg_plan_write",
|
|
232
|
+
details: makeSuccessPayload(plan),
|
|
233
|
+
});
|
|
234
|
+
const result = handler(event, FAKE_CTX);
|
|
235
|
+
assert.equal(result, undefined);
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
describe("createPlanToolResultMiddleware: 合成 id 未命中 → 静默降级 (RULING-2 追加约束 2)", () => {
|
|
239
|
+
it("does not push and does not throw when toolCallId is a synthetic openclaw-<uuid> not present in the table", () => {
|
|
240
|
+
const deps = new RecordingDeps();
|
|
241
|
+
const handler = createPlanToolResultMiddleware(deps);
|
|
242
|
+
// 故意不 registerToolCallTarget,模拟合成 id 未命中
|
|
243
|
+
const plan = makePlan({ tasks: [{ title: "t1", status: "blocked", note: "n" }] });
|
|
244
|
+
const event = makeEvent({
|
|
245
|
+
toolCallId: "openclaw-3f9a7c2e-1234-4a1b-9abc-000000000000",
|
|
246
|
+
toolName: "xg_plan_write",
|
|
247
|
+
details: makeSuccessPayload(plan),
|
|
248
|
+
});
|
|
249
|
+
assert.doesNotThrow(() => {
|
|
250
|
+
const result = handler(event, FAKE_CTX);
|
|
251
|
+
assert.equal(result, undefined);
|
|
252
|
+
});
|
|
253
|
+
assert.equal(deps.calls.length, 0);
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
describe("createPlanToolResultMiddleware: fire-and-forget", () => {
|
|
257
|
+
it("resolves immediately even when sendText returns a never-resolving promise", () => {
|
|
258
|
+
const deps = new RecordingDeps();
|
|
259
|
+
deps.sendTextImpl = () => new Promise(() => { });
|
|
260
|
+
const handler = createPlanToolResultMiddleware(deps);
|
|
261
|
+
registerToolCallTarget("call-10", { groupId: "g10", token: "t10" });
|
|
262
|
+
const plan = makePlan({ tasks: [{ title: "t1", status: "blocked", note: "n" }] });
|
|
263
|
+
const event = makeEvent({
|
|
264
|
+
toolCallId: "call-10",
|
|
265
|
+
toolName: "xg_plan_write",
|
|
266
|
+
details: makeSuccessPayload(plan),
|
|
267
|
+
});
|
|
268
|
+
// 若 handler 内部 await 了 sendText,这行会挂起整个测试进程(超时失败);
|
|
269
|
+
// handler 是同步函数,必须立即返回 undefined。
|
|
270
|
+
const result = handler(event, FAKE_CTX);
|
|
271
|
+
assert.equal(result, undefined);
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
describe("createPlanToolResultMiddleware: 查表未命中不得毒化去重状态 (FINDING-1)", () => {
|
|
275
|
+
it("a miss does not mark the notice as sent — a later call with a freshly-registered toolCallId for the same blocked key must still push", () => {
|
|
276
|
+
const deps = new RecordingDeps();
|
|
277
|
+
const handler = createPlanToolResultMiddleware(deps);
|
|
278
|
+
const plan = makePlan({
|
|
279
|
+
planId: "plan-finding1",
|
|
280
|
+
tasks: [{ title: "备份旧配置", status: "blocked", note: "缺少权限" }],
|
|
281
|
+
});
|
|
282
|
+
// 第一次:不登记 toolCallId,模拟未命中(合成 id / TTL 过期 / onToolStart 早退)
|
|
283
|
+
const missEvent = makeEvent({
|
|
284
|
+
toolCallId: "call-miss",
|
|
285
|
+
toolName: "xg_plan_write",
|
|
286
|
+
details: makeSuccessPayload(plan),
|
|
287
|
+
});
|
|
288
|
+
handler(missEvent, FAKE_CTX);
|
|
289
|
+
assert.equal(deps.calls.length, 0, "未命中时不应有任何推送");
|
|
290
|
+
// 第二次:同一 planId、同一 task、同一 note(key 完全相同),
|
|
291
|
+
// 但 toolCallId 换成新登记的 call-new——模拟 onToolStart 用新 toolCallId 重新登记
|
|
292
|
+
registerToolCallTarget("call-new", { groupId: "g-new", token: "t-new" });
|
|
293
|
+
const hitEvent = makeEvent({
|
|
294
|
+
toolCallId: "call-new",
|
|
295
|
+
toolName: "xg_plan_write",
|
|
296
|
+
details: makeSuccessPayload(plan),
|
|
297
|
+
});
|
|
298
|
+
handler(hitEvent, FAKE_CTX);
|
|
299
|
+
assert.equal(deps.calls.length, 1, "未命中不应污染去重状态,换新 toolCallId 后必须能重推");
|
|
300
|
+
assert.equal(deps.calls[0].target.groupId, "g-new");
|
|
301
|
+
assert.ok(deps.calls[0].content.includes("备份旧配置"));
|
|
302
|
+
assert.ok(deps.calls[0].content.includes("缺少权限"));
|
|
303
|
+
});
|
|
304
|
+
it("does not push again for the same key once it has actually been sent (dedup regression guard)", () => {
|
|
305
|
+
const deps = new RecordingDeps();
|
|
306
|
+
const handler = createPlanToolResultMiddleware(deps);
|
|
307
|
+
const plan = makePlan({
|
|
308
|
+
planId: "plan-finding1-dedup",
|
|
309
|
+
tasks: [{ title: "备份旧配置", status: "blocked", note: "缺少权限" }],
|
|
310
|
+
});
|
|
311
|
+
registerToolCallTarget("call-first", { groupId: "g-first", token: "t-first" });
|
|
312
|
+
const firstEvent = makeEvent({
|
|
313
|
+
toolCallId: "call-first",
|
|
314
|
+
toolName: "xg_plan_write",
|
|
315
|
+
details: makeSuccessPayload(plan),
|
|
316
|
+
});
|
|
317
|
+
handler(firstEvent, FAKE_CTX);
|
|
318
|
+
assert.equal(deps.calls.length, 1, "首次命中应推送一次");
|
|
319
|
+
registerToolCallTarget("call-second", { groupId: "g-second", token: "t-second" });
|
|
320
|
+
const secondEvent = makeEvent({
|
|
321
|
+
toolCallId: "call-second",
|
|
322
|
+
toolName: "xg_plan_write",
|
|
323
|
+
details: makeSuccessPayload(plan),
|
|
324
|
+
});
|
|
325
|
+
handler(secondEvent, FAKE_CTX);
|
|
326
|
+
assert.equal(deps.calls.length, 1, "同一 key 已成功推送过,不应重复推送");
|
|
327
|
+
});
|
|
328
|
+
});
|
|
329
|
+
//# sourceMappingURL=plan-tool-middleware.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan-tool-middleware.test.js","sourceRoot":"","sources":["../../src/plan-tool-middleware.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Plan } from "@xgjktech/xg-openclaw-shared";
|
|
2
|
+
export interface ParsedPlanToolResult {
|
|
3
|
+
planId: string;
|
|
4
|
+
plan: Plan;
|
|
5
|
+
/** plan_execute 的返回带 event 字段,plan_write 没有——用于日志区分,不参与正确性判定 */
|
|
6
|
+
hasEventField: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* 从已解析的值(如 JSON.parse 结果、middleware 的 `event.result.details`)中
|
|
10
|
+
* 结构校验并提取计划工具的成功返回。不是计划工具返回、ok:false 一律返回 undefined。
|
|
11
|
+
* 供 `parsePlanToolResult`(字符串输入)与 middleware(对象输入)共用同一份判定,
|
|
12
|
+
* 避免两份校验漂移。
|
|
13
|
+
*/
|
|
14
|
+
export declare function parsePlanToolResultFromValue(value: unknown): ParsedPlanToolResult | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* 从工具返回 JSON 文本中解析计划工具的成功返回。
|
|
17
|
+
* 不是计划工具返回、解析失败、ok:false 一律返回 undefined(绝不抛异常)。
|
|
18
|
+
*/
|
|
19
|
+
export declare function parsePlanToolResult(rawBody: string): ParsedPlanToolResult | undefined;
|
|
20
|
+
//# sourceMappingURL=plan-tool-result.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan-tool-result.d.ts","sourceRoot":"","sources":["../../src/plan-tool-result.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAc,MAAM,8BAA8B,CAAC;AAErE,MAAM,WAAW,oBAAoB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,IAAI,CAAC;IACX,gEAAgE;IAChE,aAAa,EAAE,OAAO,CAAC;CAC1B;AA4CD;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,OAAO,GAAG,oBAAoB,GAAG,SAAS,CAmB7F;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,oBAAoB,GAAG,SAAS,CASrF"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
const TASK_STATUSES = [
|
|
2
|
+
"pending",
|
|
3
|
+
"in_progress",
|
|
4
|
+
"completed",
|
|
5
|
+
"blocked",
|
|
6
|
+
];
|
|
7
|
+
function isTaskStatus(value) {
|
|
8
|
+
return typeof value === "string" && TASK_STATUSES.includes(value);
|
|
9
|
+
}
|
|
10
|
+
function isPlainObject(value) {
|
|
11
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
12
|
+
}
|
|
13
|
+
function isValidPlan(value) {
|
|
14
|
+
if (!isPlainObject(value)) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
if (typeof value.planId !== "string" || value.planId === "") {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
if (typeof value.goal !== "string") {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
if (!Array.isArray(value.tasks)) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
for (const task of value.tasks) {
|
|
27
|
+
if (!isPlainObject(task)) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
if (typeof task.title !== "string") {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
if (!isTaskStatus(task.status)) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 从已解析的值(如 JSON.parse 结果、middleware 的 `event.result.details`)中
|
|
41
|
+
* 结构校验并提取计划工具的成功返回。不是计划工具返回、ok:false 一律返回 undefined。
|
|
42
|
+
* 供 `parsePlanToolResult`(字符串输入)与 middleware(对象输入)共用同一份判定,
|
|
43
|
+
* 避免两份校验漂移。
|
|
44
|
+
*/
|
|
45
|
+
export function parsePlanToolResultFromValue(value) {
|
|
46
|
+
if (!isPlainObject(value)) {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
if (value.ok !== true) {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
if (typeof value.planId !== "string" || value.planId === "") {
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
if (!isValidPlan(value.plan)) {
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
planId: value.planId,
|
|
60
|
+
plan: value.plan,
|
|
61
|
+
hasEventField: "event" in value,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* 从工具返回 JSON 文本中解析计划工具的成功返回。
|
|
66
|
+
* 不是计划工具返回、解析失败、ok:false 一律返回 undefined(绝不抛异常)。
|
|
67
|
+
*/
|
|
68
|
+
export function parsePlanToolResult(rawBody) {
|
|
69
|
+
let parsed;
|
|
70
|
+
try {
|
|
71
|
+
parsed = JSON.parse(rawBody);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
return parsePlanToolResultFromValue(parsed);
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=plan-tool-result.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan-tool-result.js","sourceRoot":"","sources":["../../src/plan-tool-result.ts"],"names":[],"mappings":"AASA,MAAM,aAAa,GAA0B;IACzC,SAAS;IACT,aAAa;IACb,WAAW;IACX,SAAS;CACZ,CAAC;AAEF,SAAS,YAAY,CAAC,KAAc;IAChC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAK,aAAmC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC7F,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACjC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAChF,CAAC;AAED,SAAS,WAAW,CAAC,KAAc;IAC/B,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,KAAK,CAAC;IACjB,CAAC;IACD,IAAI,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QAC1D,OAAO,KAAK,CAAC;IACjB,CAAC;IACD,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QACjC,OAAO,KAAK,CAAC;IACjB,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACjB,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAC7B,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;YACvB,OAAO,KAAK,CAAC;QACjB,CAAC;QACD,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;YACjC,OAAO,KAAK,CAAC;QACjB,CAAC;QACD,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YAC7B,OAAO,KAAK,CAAC;QACjB,CAAC;IACL,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,4BAA4B,CAAC,KAAc;IACvD,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,SAAS,CAAC;IACrB,CAAC;IACD,IAAI,KAAK,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC;QACpB,OAAO,SAAS,CAAC;IACrB,CAAC;IACD,IAAI,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QAC1D,OAAO,SAAS,CAAC;IACrB,CAAC;IACD,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3B,OAAO,SAAS,CAAC;IACrB,CAAC;IAED,OAAO;QACH,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,aAAa,EAAE,OAAO,IAAI,KAAK;KAClC,CAAC;AACN,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAe;IAC/C,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACD,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,SAAS,CAAC;IACrB,CAAC;IAED,OAAO,4BAA4B,CAAC,MAAM,CAAC,CAAC;AAChD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan-tool-result.test.d.ts","sourceRoot":"","sources":["../../src/plan-tool-result.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { describe, it } from "node:test";
|
|
3
|
+
import { parsePlanToolResult } from "./plan-tool-result.js";
|
|
4
|
+
const PLAN_WRITE_SUCCESS = JSON.stringify({
|
|
5
|
+
ok: true,
|
|
6
|
+
planId: "db3b57e4-aaaa-bbbb-cccc-000000000001",
|
|
7
|
+
plan: {
|
|
8
|
+
planId: "db3b57e4-aaaa-bbbb-cccc-000000000001",
|
|
9
|
+
goal: "迁移配置到新版本",
|
|
10
|
+
createdAt: "2026-07-27T00:00:00.000Z",
|
|
11
|
+
updatedAt: "2026-07-27T00:00:00.000Z",
|
|
12
|
+
tasks: [
|
|
13
|
+
{
|
|
14
|
+
title: "备份旧配置",
|
|
15
|
+
status: "blocked",
|
|
16
|
+
note: "阻塞原因",
|
|
17
|
+
steps: [{ text: "导出 json", status: "pending" }],
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
},
|
|
21
|
+
}, null, 2);
|
|
22
|
+
const PLAN_EXECUTE_SUCCESS = JSON.stringify({
|
|
23
|
+
ok: true,
|
|
24
|
+
planId: "db3b57e4-aaaa-bbbb-cccc-000000000002",
|
|
25
|
+
plan: {
|
|
26
|
+
planId: "db3b57e4-aaaa-bbbb-cccc-000000000002",
|
|
27
|
+
goal: "迁移配置到新版本",
|
|
28
|
+
createdAt: "2026-07-27T00:00:00.000Z",
|
|
29
|
+
updatedAt: "2026-07-27T00:01:00.000Z",
|
|
30
|
+
tasks: [
|
|
31
|
+
{
|
|
32
|
+
title: "备份旧配置",
|
|
33
|
+
status: "completed",
|
|
34
|
+
steps: [{ text: "导出 json", status: "completed" }],
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
event: { emitted: false, reason: "no runId" },
|
|
39
|
+
}, null, 2);
|
|
40
|
+
describe("parsePlanToolResult", () => {
|
|
41
|
+
it("parses a real plan_write success body", () => {
|
|
42
|
+
const result = parsePlanToolResult(PLAN_WRITE_SUCCESS);
|
|
43
|
+
assert.ok(result);
|
|
44
|
+
assert.equal(result.planId, "db3b57e4-aaaa-bbbb-cccc-000000000001");
|
|
45
|
+
assert.equal(result.plan.goal, "迁移配置到新版本");
|
|
46
|
+
assert.equal(result.hasEventField, false);
|
|
47
|
+
});
|
|
48
|
+
it("parses a real plan_execute success body with event field", () => {
|
|
49
|
+
const result = parsePlanToolResult(PLAN_EXECUTE_SUCCESS);
|
|
50
|
+
assert.ok(result);
|
|
51
|
+
assert.equal(result.planId, "db3b57e4-aaaa-bbbb-cccc-000000000002");
|
|
52
|
+
assert.equal(result.hasEventField, true);
|
|
53
|
+
});
|
|
54
|
+
for (const code of [
|
|
55
|
+
"PLAN_NOT_FOUND",
|
|
56
|
+
"INDEX_OUT_OF_RANGE",
|
|
57
|
+
"NOTE_REQUIRED",
|
|
58
|
+
"STEP_INDEX_REQUIRED",
|
|
59
|
+
"INVARIANT_VIOLATION",
|
|
60
|
+
"STORE_ERROR",
|
|
61
|
+
]) {
|
|
62
|
+
it(`returns undefined for ok:false with code ${code}`, () => {
|
|
63
|
+
const body = JSON.stringify({ ok: false, error: { code, detail: "可选" } }, null, 2);
|
|
64
|
+
assert.equal(parsePlanToolResult(body), undefined);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
it("returns undefined for empty string / non-json / non-object json", () => {
|
|
68
|
+
assert.equal(parsePlanToolResult(""), undefined);
|
|
69
|
+
assert.equal(parsePlanToolResult("not json"), undefined);
|
|
70
|
+
assert.equal(parsePlanToolResult("[]"), undefined);
|
|
71
|
+
assert.equal(parsePlanToolResult("123"), undefined);
|
|
72
|
+
assert.equal(parsePlanToolResult("null"), undefined);
|
|
73
|
+
});
|
|
74
|
+
it("does not misfire on an unrelated tool's ok:true body", () => {
|
|
75
|
+
const body = JSON.stringify({ ok: true, data: 123 }, null, 2);
|
|
76
|
+
assert.equal(parsePlanToolResult(body), undefined);
|
|
77
|
+
});
|
|
78
|
+
it("returns undefined when plan.tasks contains an invalid status", () => {
|
|
79
|
+
const body = JSON.stringify({
|
|
80
|
+
ok: true,
|
|
81
|
+
planId: "p1",
|
|
82
|
+
plan: {
|
|
83
|
+
planId: "p1",
|
|
84
|
+
goal: "g",
|
|
85
|
+
createdAt: "t",
|
|
86
|
+
updatedAt: "t",
|
|
87
|
+
tasks: [{ title: "x", status: "unknown_status" }],
|
|
88
|
+
},
|
|
89
|
+
}, null, 2);
|
|
90
|
+
assert.equal(parsePlanToolResult(body), undefined);
|
|
91
|
+
});
|
|
92
|
+
it("returns undefined when planId is missing or empty", () => {
|
|
93
|
+
const body = JSON.stringify({
|
|
94
|
+
ok: true,
|
|
95
|
+
planId: "",
|
|
96
|
+
plan: {
|
|
97
|
+
planId: "p1",
|
|
98
|
+
goal: "g",
|
|
99
|
+
createdAt: "t",
|
|
100
|
+
updatedAt: "t",
|
|
101
|
+
tasks: [],
|
|
102
|
+
},
|
|
103
|
+
}, null, 2);
|
|
104
|
+
assert.equal(parsePlanToolResult(body), undefined);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
//# sourceMappingURL=plan-tool-result.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan-tool-result.test.js","sourceRoot":"","sources":["../../src/plan-tool-result.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -18,7 +18,7 @@ const groupMonitors = new Map();
|
|
|
18
18
|
const wsClients = new Map();
|
|
19
19
|
let tickerTimer = null;
|
|
20
20
|
let pluginApi = null;
|
|
21
|
-
const POLL_INTERVAL_MS =
|
|
21
|
+
const POLL_INTERVAL_MS = 10000;
|
|
22
22
|
console.log(`[subagent-monitor] module loaded, POLL_INTERVAL=${POLL_INTERVAL_MS}ms`);
|
|
23
23
|
// ─── 公开 API ─────────────────────────────────────────────────────────
|
|
24
24
|
export function setPluginApi(api) {
|
|
@@ -262,14 +262,12 @@ function cleanMsg(msg) {
|
|
|
262
262
|
return "";
|
|
263
263
|
}
|
|
264
264
|
const MAX_INCR_MSGS = 5;
|
|
265
|
-
function
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
: [];
|
|
272
|
-
sentCounts.set(runId, newMsgs.length);
|
|
265
|
+
function buildSubagentList(monitor) {
|
|
266
|
+
return Array.from(monitor.subagents.entries()).map(([runId, record]) => {
|
|
267
|
+
const total = record.messages.length;
|
|
268
|
+
const newMsgs = total > record.sendFrom ? record.messages.slice(record.sendFrom, record.sendFrom + MAX_INCR_MSGS) : [];
|
|
269
|
+
if (newMsgs.length > 0)
|
|
270
|
+
record.sendFrom += newMsgs.length;
|
|
273
271
|
return {
|
|
274
272
|
runId,
|
|
275
273
|
label: record.label ?? runId.slice(0, 8),
|
|
@@ -277,21 +275,17 @@ function sendWsStat(groupId, monitor, client, replyToMsgId) {
|
|
|
277
275
|
messages: newMsgs,
|
|
278
276
|
};
|
|
279
277
|
});
|
|
278
|
+
}
|
|
279
|
+
function sendWsStat(groupId, monitor, client, replyToMsgId) {
|
|
280
|
+
const subagentList = buildSubagentList(monitor);
|
|
280
281
|
client.sendEvent({
|
|
281
282
|
groupId,
|
|
282
283
|
replyToMsgId,
|
|
283
284
|
event: "SUBAGENT_STAT",
|
|
284
285
|
data: { subagentList },
|
|
285
|
-
}).then(() => {
|
|
286
|
-
// 发送成功后推进游标
|
|
287
|
-
for (const [runId, count] of sentCounts) {
|
|
288
|
-
const record = monitor.subagents.get(runId);
|
|
289
|
-
if (record)
|
|
290
|
-
record.sendFrom += count;
|
|
291
|
-
}
|
|
292
286
|
}).catch((err) => {
|
|
293
287
|
console.error(`[subagent-monitor] WS SUBAGENT_STAT failed: ${String(err)}`);
|
|
294
|
-
//
|
|
288
|
+
// 不删除 wsClients,WS 重连后 ensureSocketReady 会拿到新连接
|
|
295
289
|
});
|
|
296
290
|
}
|
|
297
291
|
function buildPayload(monitor) {
|