@ynhcj/xiaoyi 2.3.7 → 2.3.9

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/channel.js CHANGED
@@ -214,8 +214,10 @@ exports.xiaoyiPlugin = {
214
214
  const { getXiaoYiRuntime } = require("./runtime");
215
215
  const runtime = getXiaoYiRuntime();
216
216
  console.log(`XiaoYi: [Message Handler] Using runtime instance: ${runtime.getInstanceId()}`);
217
+ // For message/stream, prioritize params.sessionId, fallback to top-level sessionid
218
+ const sessionId = message.params.sessionId || message.sessionid;
217
219
  // Store sessionId -> taskId mapping in runtime (use params.id as taskId)
218
- runtime.setTaskIdForSession(message.params.sessionId, message.params.id);
220
+ runtime.setTaskIdForSession(sessionId, message.params.id);
219
221
  // Get PluginRuntime from our runtime wrapper
220
222
  const pluginRuntime = runtime.getPluginRuntime();
221
223
  if (!pluginRuntime) {
@@ -291,8 +293,8 @@ exports.xiaoyiPlugin = {
291
293
  const msgContext = {
292
294
  Body: bodyText,
293
295
  From: senderId,
294
- To: message.params.sessionId,
295
- SessionKey: `xiaoyi:${resolvedAccount.accountId}:${message.params.sessionId}`,
296
+ To: sessionId,
297
+ SessionKey: `xiaoyi:${resolvedAccount.accountId}:${sessionId}`,
296
298
  AccountId: resolvedAccount.accountId,
297
299
  MessageSid: message.id, // Use top-level id as message sequence number
298
300
  Timestamp: Date.now(), // Generate timestamp since new format doesn't include it
@@ -307,34 +309,34 @@ exports.xiaoyiPlugin = {
307
309
  try {
308
310
  console.log("\n" + "=".repeat(60));
309
311
  console.log(`XiaoYi: [MESSAGE] Processing user message`);
310
- console.log(` Session: ${message.params.sessionId}`);
312
+ console.log(` Session: ${sessionId}`);
311
313
  console.log(` Task ID: ${message.params.id}`);
312
314
  console.log(` User input: ${bodyText.substring(0, 50)}${bodyText.length > 50 ? "..." : ""}`);
313
315
  console.log(` Images: ${images.length}`);
314
316
  console.log("=".repeat(60) + "\n");
315
- const taskId = runtime.getTaskIdForSession(message.params.sessionId) || `task_${Date.now()}`;
317
+ const taskId = runtime.getTaskIdForSession(sessionId) || `task_${Date.now()}`;
316
318
  const startTime = Date.now();
317
319
  let accumulatedText = "";
318
320
  // ==================== CREATE ABORT CONTROLLER ====================
319
321
  // Create AbortController for this session to allow cancelation
320
- const { controller: abortController, signal: abortSignal } = runtime.createAbortControllerForSession(message.params.sessionId);
322
+ const { controller: abortController, signal: abortSignal } = runtime.createAbortControllerForSession(sessionId);
321
323
  // ================================================================
322
324
  // ==================== START TIMEOUT PROTECTION ====================
323
325
  // Start 60-second timeout timer
324
326
  const timeoutConfig = runtime.getTimeoutConfig();
325
- console.log(`[TIMEOUT] Starting ${timeoutConfig.duration}ms timeout protection for session ${message.params.sessionId}`);
326
- runtime.setTimeoutForSession(message.params.sessionId, async () => {
327
+ console.log(`[TIMEOUT] Starting ${timeoutConfig.duration}ms timeout protection for session ${sessionId}`);
328
+ runtime.setTimeoutForSession(sessionId, async () => {
327
329
  // Timeout callback - send timeout message to user
328
330
  const elapsed = Date.now() - startTime;
329
331
  console.log("\n" + "=".repeat(60));
330
- console.log(`[TIMEOUT] Timeout triggered for session ${message.params.sessionId}`);
332
+ console.log(`[TIMEOUT] Timeout triggered for session ${sessionId}`);
331
333
  console.log(` Elapsed: ${elapsed}ms`);
332
334
  console.log(` Task ID: ${taskId}`);
333
335
  console.log("=".repeat(60) + "\n");
334
336
  const conn = runtime.getConnection();
335
337
  if (conn) {
336
338
  const timeoutResponse = {
337
- sessionId: message.params.sessionId,
339
+ sessionId: sessionId,
338
340
  messageId: `timeout_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
339
341
  timestamp: Date.now(),
340
342
  agentId: resolvedAccount.config.agentId,
@@ -350,8 +352,8 @@ exports.xiaoyiPlugin = {
350
352
  status: "success",
351
353
  };
352
354
  try {
353
- await conn.sendResponse(timeoutResponse, taskId, message.params.sessionId, true, false);
354
- console.log(`[TIMEOUT] Timeout message sent successfully to session ${message.params.sessionId}\n`);
355
+ await conn.sendResponse(timeoutResponse, taskId, sessionId, true, false);
356
+ console.log(`[TIMEOUT] Timeout message sent successfully to session ${sessionId}\n`);
355
357
  }
356
358
  catch (error) {
357
359
  console.error(`[TIMEOUT] Failed to send timeout message:`, error);
@@ -371,10 +373,10 @@ exports.xiaoyiPlugin = {
371
373
  const completeText = payload.text || "";
372
374
  accumulatedText = completeText;
373
375
  // Check if session was aborted
374
- if (runtime.isSessionAborted(message.params.sessionId)) {
376
+ if (runtime.isSessionAborted(sessionId)) {
375
377
  console.log("\n" + "=".repeat(60));
376
378
  console.log(`[ABORT] Response received AFTER abort`);
377
- console.log(` Session: ${message.params.sessionId}`);
379
+ console.log(` Session: ${sessionId}`);
378
380
  console.log(` Elapsed: ${elapsed}ms`);
379
381
  console.log(` Action: DISCARDING (session was canceled)`);
380
382
  console.log("=".repeat(60) + "\n");
@@ -382,10 +384,10 @@ exports.xiaoyiPlugin = {
382
384
  }
383
385
  // ==================== CHECK TIMEOUT ====================
384
386
  // If timeout already sent, discard this response
385
- if (runtime.isSessionTimeout(message.params.sessionId)) {
387
+ if (runtime.isSessionTimeout(sessionId)) {
386
388
  console.log("\n" + "=".repeat(60));
387
389
  console.log(`[TIMEOUT] Response received AFTER timeout`);
388
- console.log(` Session: ${message.params.sessionId}`);
390
+ console.log(` Session: ${sessionId}`);
389
391
  console.log(` Elapsed: ${elapsed}ms`);
390
392
  console.log(` Action: DISCARDING (timeout message already sent)`);
391
393
  console.log("=".repeat(60) + "\n");
@@ -396,7 +398,7 @@ exports.xiaoyiPlugin = {
396
398
  if (!completeText || completeText.length === 0) {
397
399
  console.log("\n" + "=".repeat(60));
398
400
  console.log(`[TIMEOUT] Empty response detected`);
399
- console.log(` Session: ${message.params.sessionId}`);
401
+ console.log(` Session: ${sessionId}`);
400
402
  console.log(` Elapsed: ${elapsed}ms`);
401
403
  console.log(` Action: KEEPING TIMEOUT (session conflict detected)`);
402
404
  console.log("=".repeat(60) + "\n");
@@ -411,7 +413,7 @@ exports.xiaoyiPlugin = {
411
413
  console.log("-".repeat(60) + "\n");
412
414
  // Send final response to XiaoYi
413
415
  const response = {
414
- sessionId: message.params.sessionId,
416
+ sessionId: sessionId,
415
417
  messageId: `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
416
418
  timestamp: Date.now(),
417
419
  agentId: resolvedAccount.config.agentId,
@@ -428,14 +430,14 @@ exports.xiaoyiPlugin = {
428
430
  };
429
431
  const conn = runtime.getConnection();
430
432
  if (conn) {
431
- await conn.sendResponse(response, taskId, message.params.sessionId, true, false);
433
+ await conn.sendResponse(response, taskId, sessionId, true, false);
432
434
  console.log(`✓ XiaoYi: Response sent successfully\n`);
433
435
  }
434
436
  else {
435
437
  console.error(`✗ XiaoYi: Connection not available\n`);
436
438
  }
437
439
  // Clear timeout as response was sent successfully
438
- runtime.markSessionCompleted(message.params.sessionId);
440
+ runtime.markSessionCompleted(sessionId);
439
441
  },
440
442
  onIdle: async () => {
441
443
  const elapsed = Date.now() - startTime;
@@ -446,8 +448,8 @@ exports.xiaoyiPlugin = {
446
448
  // Only clear timeout if we have a valid response
447
449
  // If empty, keep timeout running to handle session conflict
448
450
  if (accumulatedText.length > 0) {
449
- runtime.markSessionCompleted(message.params.sessionId);
450
- runtime.clearAbortControllerForSession(message.params.sessionId);
451
+ runtime.markSessionCompleted(sessionId);
452
+ runtime.clearAbortControllerForSession(sessionId);
451
453
  console.log(`[TIMEOUT] Timeout cleared (valid response)\n`);
452
454
  }
453
455
  else {
@@ -465,9 +467,9 @@ exports.xiaoyiPlugin = {
465
467
  catch (error) {
466
468
  console.error("XiaoYi: [ERROR] Error dispatching message:", error);
467
469
  // Clear timeout on error
468
- runtime.clearSessionTimeout(message.params.sessionId);
470
+ runtime.clearSessionTimeout(sessionId);
469
471
  // Clear abort controller on error
470
- runtime.clearAbortControllerForSession(message.params.sessionId);
472
+ runtime.clearAbortControllerForSession(sessionId);
471
473
  }
472
474
  });
473
475
  // Setup cancel handler
package/dist/types.d.ts CHANGED
@@ -3,11 +3,14 @@ export interface A2ARequestMessage {
3
3
  jsonrpc: "2.0";
4
4
  id: string;
5
5
  method: "message/stream";
6
+ deviceId?: string;
6
7
  params: {
7
8
  id: string;
8
9
  sessionId: string;
9
10
  agentLoginSessionId?: string;
10
11
  message: {
12
+ kind?: string;
13
+ messageId?: string;
11
14
  role: "user" | "agent";
12
15
  parts: Array<{
13
16
  kind: "text" | "file" | "data";
@@ -53,7 +53,7 @@ export declare class XiaoYiWebSocketManager extends EventEmitter {
53
53
  /**
54
54
  * Extract sessionId from message based on method type
55
55
  * Different methods have sessionId in different locations:
56
- * - message/stream: sessionId in params
56
+ * - message/stream: sessionId ONLY in params
57
57
  * - tasks/cancel: sessionId at top level
58
58
  * - clearContext: sessionId at top level
59
59
  */
@@ -136,6 +136,7 @@ export declare class XiaoYiWebSocketManager extends EventEmitter {
136
136
  private clearStableConnectionCheck;
137
137
  /**
138
138
  * Type guard for A2A request messages
139
+ * For message/stream, sessionId MUST be in params
139
140
  */
140
141
  private isA2ARequestMessage;
141
142
  /**
package/dist/websocket.js CHANGED
@@ -306,12 +306,12 @@ class XiaoYiWebSocketManager extends events_1.EventEmitter {
306
306
  /**
307
307
  * Extract sessionId from message based on method type
308
308
  * Different methods have sessionId in different locations:
309
- * - message/stream: sessionId in params
309
+ * - message/stream: sessionId ONLY in params
310
310
  * - tasks/cancel: sessionId at top level
311
311
  * - clearContext: sessionId at top level
312
312
  */
313
313
  extractSessionId(message) {
314
- // For message/stream, sessionId is in params
314
+ // For message/stream, sessionId is ONLY in params
315
315
  if (message.method === "message/stream") {
316
316
  return message.params?.sessionId;
317
317
  }
@@ -798,6 +798,7 @@ class XiaoYiWebSocketManager extends events_1.EventEmitter {
798
798
  }
799
799
  /**
800
800
  * Type guard for A2A request messages
801
+ * For message/stream, sessionId MUST be in params
801
802
  */
802
803
  isA2ARequestMessage(data) {
803
804
  return data &&
@@ -807,6 +808,7 @@ class XiaoYiWebSocketManager extends events_1.EventEmitter {
807
808
  data.method === "message/stream" &&
808
809
  data.params &&
809
810
  typeof data.params.id === "string" &&
811
+ // For message/stream, sessionId MUST be in params
810
812
  typeof data.params.sessionId === "string" &&
811
813
  data.params.message &&
812
814
  typeof data.params.message.role === "string" &&
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ynhcj/xiaoyi",
3
- "version": "2.3.7",
3
+ "version": "2.3.9",
4
4
  "description": "XiaoYi channel plugin for OpenClaw",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",