@ynhcj/xiaoyi-channel 0.0.132-next → 0.0.133-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/src/bot.d.ts CHANGED
@@ -24,3 +24,8 @@ export interface HandleXYMessageParams {
24
24
  * Runtime is expected to be validated before calling this function.
25
25
  */
26
26
  export declare function handleXYMessage(params: HandleXYMessageParams): Promise<void>;
27
+ /**
28
+ * 由 provider.ts 在 wrapStreamFn 调用时触发。
29
+ * 这是模型 API 被调用的精确时刻,此时 isStreaming 一定为 true。
30
+ */
31
+ export declare function notifyModelStreaming(sessionId: string): void;
package/dist/src/bot.js CHANGED
@@ -254,9 +254,10 @@ export async function handleXYMessage(params) {
254
254
  // so the dispatcher skips all user-facing callbacks (deliver, onIdle, etc.)
255
255
  // and onSettled skips cleanup.
256
256
  const steerState = { steered: isUpdate };
257
- // 🔑 第一条消息的 streaming 信号:deliver 首次触发时 resolve
258
- // steer 消息通过串行队列等待此信号后再 dispatch
259
- const streamingSignal = !isUpdate ? createStreamingSignal(parsed.sessionId) : undefined;
257
+ // 🔑 第一条消息创建 streaming 信号(provider.ts wrapStreamFn 触发)
258
+ if (!isUpdate) {
259
+ createStreamingSignal(parsed.sessionId);
260
+ }
260
261
  // 🔑 创建dispatcher
261
262
  logger.log(`[BOT-DISPATCHER] 🎯 Creating reply dispatcher`);
262
263
  logger.log(`[BOT-DISPATCHER] - taskId: ${parsed.taskId}`);
@@ -268,7 +269,6 @@ export async function handleXYMessage(params) {
268
269
  messageId: parsed.messageId,
269
270
  accountId: route.accountId,
270
271
  steerState,
271
- onFirstStream: streamingSignal?.notify,
272
272
  });
273
273
  // Steer injections don't need status intervals
274
274
  if (!skipReg) {
@@ -404,6 +404,18 @@ function buildXYMediaPayload(mediaList) {
404
404
  };
405
405
  }
406
406
  const streamingSignals = new Map();
407
+ /**
408
+ * 由 provider.ts 在 wrapStreamFn 调用时触发。
409
+ * 这是模型 API 被调用的精确时刻,此时 isStreaming 一定为 true。
410
+ */
411
+ export function notifyModelStreaming(sessionId) {
412
+ const signal = streamingSignals.get(sessionId);
413
+ if (signal) {
414
+ streamingSignals.delete(sessionId);
415
+ signal.notify();
416
+ logger.log(`[STEER-QUEUE] 📡 Model streaming signal fired for session=${sessionId}`);
417
+ }
418
+ }
407
419
  function createStreamingSignal(sessionId) {
408
420
  let resolve;
409
421
  const promise = new Promise(r => { resolve = r; });
@@ -11,6 +11,7 @@ import { createHash } from "crypto";
11
11
  import { logger } from "./utils/logger.js";
12
12
  import { getCurrentSessionContext } from "./tools/session-manager.js";
13
13
  import { selfEvolutionManager } from "./utils/self-evolution-manager.js";
14
+ import { notifyModelStreaming } from "./bot.js";
14
15
  // ── Retry config ──────────────────────────────────────────────
15
16
  const RETRY_DELAYS_MS = [10_000, 20_000, 40_000, 60_000, 60_000];
16
17
  const MAX_RETRY_ATTEMPTS = 5;
@@ -536,6 +537,11 @@ export const xiaoyiProvider = {
536
537
  }
537
538
  // 记录输入
538
539
  logger.log(`[xiaoyiprovider] input messages count: ${context.messages?.length ?? 0}`);
540
+ // 🔑 通知 steer 队列:模型 API 已被调用,此时 isStreaming 一定为 true
541
+ const sessionCtx = getCurrentSessionContext();
542
+ if (sessionCtx?.sessionId) {
543
+ notifyModelStreaming(sessionCtx.sessionId);
544
+ }
539
545
  if (context.systemPrompt) {
540
546
  logger.log(`[xiaoyiprovider] system prompt length: ${context.systemPrompt.length}`);
541
547
  }
@@ -9,8 +9,6 @@ export interface CreateXYReplyDispatcherParams {
9
9
  steerState: {
10
10
  steered: boolean;
11
11
  };
12
- /** Called the first time deliver fires for a non-steered dispatch — signals the model is streaming. */
13
- onFirstStream?: () => void;
14
12
  }
15
13
  /**
16
14
  * 清理 /tmp/xy_channel 目录中超过 24 小时的旧文件
@@ -45,7 +45,7 @@ export async function cleanupStaleTempFiles(tempDir = "/tmp/xy_channel") {
45
45
  * Runtime is expected to be validated before calling this function.
46
46
  */
47
47
  export function createXYReplyDispatcher(params) {
48
- const { cfg, runtime, sessionId, taskId, messageId, accountId, steerState, onFirstStream } = params;
48
+ const { cfg, runtime, sessionId, taskId, messageId, accountId, steerState } = params;
49
49
  logger.log(`[DISPATCHER-CREATE] ******* Creating dispatcher *******`);
50
50
  logger.log(`[DISPATCHER-CREATE] - taskId: ${taskId}`);
51
51
  // 初始taskId和messageId(作为fallback)
@@ -73,7 +73,6 @@ export function createXYReplyDispatcher(params) {
73
73
  let hasSentResponse = false;
74
74
  let finalSent = false;
75
75
  let accumulatedText = "";
76
- let streamingSignaled = false;
77
76
  /**
78
77
  * Start the status update interval
79
78
  */
@@ -119,11 +118,6 @@ export function createXYReplyDispatcher(params) {
119
118
  logger.log(`[DELIVER] Steered dispatch - skipping deliver, info.kind=${info?.kind}`);
120
119
  return;
121
120
  }
122
- // 🔑 第一次 deliver = 模型开始 streaming,通知等待中的 steer
123
- if (onFirstStream && !streamingSignaled) {
124
- streamingSignaled = true;
125
- onFirstStream();
126
- }
127
121
  const text = payload.text ?? "";
128
122
  const currentTaskId = getActiveTaskId();
129
123
  const currentMessageId = getActiveMessageId();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ynhcj/xiaoyi-channel",
3
- "version": "0.0.132-next",
3
+ "version": "0.0.133-next",
4
4
  "description": "OpenClaw Xiaoyi Channel plugin - Xiaoyi A2A protocol integration",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",