@ynhcj/xiaoyi-channel 0.0.226-next → 0.0.227-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 CHANGED
@@ -406,9 +406,10 @@ function registerSubagentHooks(api) {
406
406
  if (transition?.shouldFinalize) {
407
407
  logger.log(`[XY-SUBAGENT-END] Starting finalization...`);
408
408
  // Grace: announce 投递的 sendText 与 subagent_ended hook 并发到达
409
- // (实测 sendText 可能先于 hook 约 1s,也可能略晚于 hook),
410
- // 短等让最后一条完成文本先落入 completionTexts 再合并发 final 帧。
411
- await new Promise((r) => setTimeout(r, 1500));
409
+ // (实测 sendText 可能先于 hook 约 1s,也可能晚于 hook;长文本还会
410
+ // 被 textChunkLimit 分片成多次 sendText)。捕获窗口直到
411
+ // finalDeliveryStarted 才关闭,此处的等待直接扩大迟到来片的入窗机会。
412
+ await new Promise((r) => setTimeout(r, 3000));
412
413
  // 最终交付由对话管理层统一负责(含 config 解析、final 帧、清理)
413
414
  await deliverSubagentFinalResult({
414
415
  state: transition.state,
@@ -261,6 +261,7 @@ export function markSubagentSpawned(sessionKey) {
261
261
  completionTexts: [],
262
262
  parentSettled: false,
263
263
  finalizationClaimed: false,
264
+ finalDeliveryStarted: false,
264
265
  };
265
266
  states.push(state);
266
267
  }
@@ -367,6 +368,9 @@ export async function deliverSubagentFinalResult(params) {
367
368
  log.error(`[SUBAGENT-FINAL] No cached XY config, cannot deliver final result`);
368
369
  return;
369
370
  }
371
+ // 关闭捕获窗口:此后到达的 sendText 不再并入 final 文本。
372
+ // 等待态在发送后立即清除,迟到的 announce 文本回退 push 通道兜底(不丢消息)。
373
+ state.finalDeliveryStarted = true;
370
374
  const finalText = state.completionTexts.length > 0
371
375
  ? state.completionTexts.join("\n\n")
372
376
  : (params.text || undefined) ?? "子任务已完成";
@@ -16,6 +16,12 @@ export interface SubagentWaitState {
16
16
  completionTexts: string[];
17
17
  parentSettled: boolean;
18
18
  finalizationClaimed: boolean;
19
+ /**
20
+ * final 帧开始交付(deliverSubagentFinalResult 入口)后置位。
21
+ * 捕获窗口以此为准:grace 期间迟到的 announce 文本仍可并入 final;
22
+ * 置位后到达的 sendText 不再捕获(等待态随即清除,回退 push 兜底)。
23
+ */
24
+ finalDeliveryStarted: boolean;
19
25
  }
20
26
  export interface SubagentWaitTransition {
21
27
  state: SubagentWaitState;
@@ -136,19 +136,28 @@ export const xyOutbound = {
136
136
  // 改用 parentSettled 区分:父 run 存活期间的 sendText 是父自己的 message
137
137
  // 工具调用(不捕获、push 照常);父 settle 后命中 waitState 的 sendText
138
138
  // 即为 subagent 完成结果的 announce 投递(捕获 + 吞掉 push)。
139
+ // 捕获窗口以 finalDeliveryStarted 为准(而非 finalizationClaimed):
140
+ // finalizationClaimed 在 markSubagentEnded 时就置位,若 announce 的
141
+ // sendText 晚于 subagent_ended hook 到达(如长文本被 textChunkLimit
142
+ // 分片、投递时序竞争),claim 会提前关闭捕获导致内容丢失——配合
143
+ // push 抑制,丢失是永久的。finalDeliveryStarted 在 grace 结束后、
144
+ // final 帧发送前才置位,grace 期间迟到的文本仍能并入 final。
139
145
  const isFromWaitState = waitState && waitState.parentSettled;
140
146
  if (isFromWaitState) {
141
147
  const log = logger.withContext(waitState.sessionId, waitState.taskId);
142
- if (!waitState.finalizationClaimed) {
148
+ if (!waitState.finalDeliveryStarted) {
143
149
  log.log(`[xyOutbound.sendText] Subagent completion text captured, len=${text?.length ?? 0}`);
144
150
  addCompletionText(targetSessionId, targetTaskId, text);
151
+ log.log(`[xyOutbound.sendText] Subagent announce — swallowing push (result delivered via A2A final frame)`);
152
+ return {
153
+ channel: "xiaoyi-channel",
154
+ messageId: `subagent-swallowed-${Date.now()}`,
155
+ chatId: typeof to === "string" ? to : "",
156
+ };
145
157
  }
146
- log.log(`[xyOutbound.sendText] Subagent announce — swallowing push (result delivered via A2A final frame)`);
147
- return {
148
- channel: "xiaoyi-channel",
149
- messageId: `subagent-swallowed-${Date.now()}`,
150
- chatId: typeof to === "string" ? to : "",
151
- };
158
+ // final 帧已开始交付:不再捕获也不再吞没,fall through 走 push 兜底,
159
+ // 避免迟到的 announce 文本被静默丢弃。
160
+ log.log(`[xyOutbound.sendText] Subagent announce arrived after final delivery started — falling back to push`);
152
161
  }
153
162
  }
154
163
  // ── End subagent text capture ───────────────────────────────
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ynhcj/xiaoyi-channel",
3
- "version": "0.0.226-next",
3
+ "version": "0.0.227-next",
4
4
  "description": "OpenClaw Xiaoyi Channel plugin - Xiaoyi A2A protocol integration",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",