@ynhcj/xiaoyi-channel 0.0.224-next → 0.0.225-next
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/dist/index.js +73 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -306,6 +306,53 @@ function registerCronRecoveryHook(api) {
|
|
|
306
306
|
logger.log(`${logTag} ═══════════════════════════════════════════`);
|
|
307
307
|
});
|
|
308
308
|
}
|
|
309
|
+
/**
|
|
310
|
+
* 从 sessions_spawn 工具结果中提取 ACP child sessionKey。
|
|
311
|
+
* 兼容三种 result 形态:{status, childSessionKey} 直返、JSON 字符串、
|
|
312
|
+
* {content:[{text: "<json>"}], details:{...}} 工具信封。
|
|
313
|
+
* 仅接受 status="accepted" 且 key 形如 agent:<id>:acp:<uuid> 的结果。
|
|
314
|
+
*/
|
|
315
|
+
function extractAcceptedAcpChildSessionKey(result) {
|
|
316
|
+
const pick = (obj) => {
|
|
317
|
+
if (!obj || typeof obj !== "object")
|
|
318
|
+
return null;
|
|
319
|
+
const record = obj;
|
|
320
|
+
if (record.status !== "accepted")
|
|
321
|
+
return null;
|
|
322
|
+
const key = record.childSessionKey;
|
|
323
|
+
return typeof key === "string" && key.includes(":acp:") ? key : null;
|
|
324
|
+
};
|
|
325
|
+
const direct = pick(result);
|
|
326
|
+
if (direct)
|
|
327
|
+
return direct;
|
|
328
|
+
const envelope = result;
|
|
329
|
+
const fromDetails = pick(envelope?.details);
|
|
330
|
+
if (fromDetails)
|
|
331
|
+
return fromDetails;
|
|
332
|
+
if (Array.isArray(envelope?.content)) {
|
|
333
|
+
for (const item of envelope.content) {
|
|
334
|
+
if (typeof item?.text !== "string")
|
|
335
|
+
continue;
|
|
336
|
+
try {
|
|
337
|
+
const fromText = pick(JSON.parse(item.text));
|
|
338
|
+
if (fromText)
|
|
339
|
+
return fromText;
|
|
340
|
+
}
|
|
341
|
+
catch {
|
|
342
|
+
// 非 JSON 文本,忽略
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
if (typeof result === "string") {
|
|
347
|
+
try {
|
|
348
|
+
return pick(JSON.parse(result));
|
|
349
|
+
}
|
|
350
|
+
catch {
|
|
351
|
+
return null;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
309
356
|
function registerSubagentHooks(api) {
|
|
310
357
|
// subagent_spawned: fires after a subagent run is successfully registered.
|
|
311
358
|
// We increment the expected completion count so that onIdle knows to wait.
|
|
@@ -318,6 +365,32 @@ function registerSubagentHooks(api) {
|
|
|
318
365
|
logger.log(`[XY-SUBAGENT] spawned, requesterSessionKey=${requesterSessionKey.slice(0, 30)}, expected=${count}`);
|
|
319
366
|
}
|
|
320
367
|
});
|
|
368
|
+
// ACP SPAWN TRACKING: openclaw 的 subagent_spawned hook 仅由内嵌 subagent
|
|
369
|
+
// 路径(subagent-spawn.ts)发射;acp-spawn.ts(runtime="acp",如 Claude Code)
|
|
370
|
+
// 不发射 —— 实测 ACP run 仅在结束时经 run registry 触发 subagent_ended,
|
|
371
|
+
// 导致等待态从未建立、父 turn onIdle 直接发 final 结束对话。
|
|
372
|
+
// 因此在 after_tool_call 补记:sessions_spawn 成功且 childSessionKey 为 ACP
|
|
373
|
+
// 形态时递增等待计数。内嵌 subagent 的 childKey 形如 agent:<id>:subagent:<id>,
|
|
374
|
+
// 不命中此分支,仍由 subagent_spawned hook 负责,不会重复计数。
|
|
375
|
+
api.on("after_tool_call", async (event, ctx) => {
|
|
376
|
+
try {
|
|
377
|
+
if (event?.toolName !== "sessions_spawn" || event?.error)
|
|
378
|
+
return;
|
|
379
|
+
const childKey = extractAcceptedAcpChildSessionKey(event?.result);
|
|
380
|
+
if (!childKey)
|
|
381
|
+
return;
|
|
382
|
+
const sessionKey = ctx?.sessionKey;
|
|
383
|
+
if (!sessionKey)
|
|
384
|
+
return;
|
|
385
|
+
const count = markSubagentSpawned(sessionKey);
|
|
386
|
+
if (count > 0) {
|
|
387
|
+
logger.log(`[XY-SUBAGENT] ACP spawned, childSessionKey=${childKey.slice(0, 40)}, expected=${count}`);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
catch (err) {
|
|
391
|
+
logger.error(`[XY-SUBAGENT] Error tracking ACP spawn:`, err);
|
|
392
|
+
}
|
|
393
|
+
});
|
|
321
394
|
// subagent_ended: fires when a subagent run terminates (complete/error/killed).
|
|
322
395
|
// This is the PRIMARY delivery tracking mechanism. When all expected
|
|
323
396
|
// subagents have ended and parent has settled, we finalize the A2A session.
|