@ynhcj/xiaoyi 2.0.6 → 2.0.8

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
@@ -211,39 +211,49 @@ exports.xiaoyiPlugin = {
211
211
  const { getXiaoYiRuntime } = require("./runtime");
212
212
  const runtime = getXiaoYiRuntime();
213
213
  console.log(`XiaoYi: [Message Handler] Using runtime instance: ${runtime.getInstanceId()}`);
214
- // Store sessionId -> taskId mapping in runtime
215
- runtime.setTaskIdForSession(message.sessionId, message.id);
214
+ // Store sessionId -> taskId mapping in runtime (use params.id as taskId)
215
+ runtime.setTaskIdForSession(message.sessionId, message.params.id);
216
216
  // Get PluginRuntime from our runtime wrapper
217
217
  const pluginRuntime = runtime.getPluginRuntime();
218
218
  if (!pluginRuntime) {
219
219
  console.error("PluginRuntime not available");
220
220
  return;
221
221
  }
222
+ // Extract text content from parts array (ignore kind: "data" as per user request)
223
+ let bodyText = "";
224
+ for (const part of message.params.message.parts) {
225
+ if (part.kind === "text" && part.text) {
226
+ bodyText += part.text;
227
+ }
228
+ // TODO: Handle file parts if needed in the future
229
+ }
230
+ // Determine sender ID from role
231
+ const senderId = message.params.message.role === "user" ? "user" : message.agentId;
222
232
  // Build MsgContext for OpenClaw's message pipeline
223
233
  const msgContext = {
224
- Body: message.content.text || "",
225
- From: message.sender.id,
234
+ Body: bodyText,
235
+ From: senderId,
226
236
  To: message.sessionId,
227
237
  SessionKey: `xiaoyi:${resolvedAccount.accountId}:${message.sessionId}`,
228
238
  AccountId: resolvedAccount.accountId,
229
- MessageSid: message.messageId,
230
- Timestamp: message.timestamp,
239
+ MessageSid: message.id, // Use top-level id as message sequence number
240
+ Timestamp: Date.now(), // Generate timestamp since new format doesn't include it
231
241
  Provider: "xiaoyi",
232
242
  Surface: "xiaoyi",
233
243
  ChatType: "direct",
234
- SenderName: message.sender.name,
235
- SenderId: message.sender.id,
244
+ SenderName: message.params.message.role, // Use role as sender name
245
+ SenderId: senderId,
236
246
  OriginatingChannel: "xiaoyi",
237
247
  };
238
- // Use the correct API to dispatch the message
248
+ // Use the correct API to dispatch the message (non-streaming mode)
239
249
  try {
240
250
  await pluginRuntime.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
241
251
  ctx: msgContext,
242
252
  cfg: config,
243
253
  dispatcherOptions: {
244
254
  deliver: async (payload) => {
245
- console.log("XiaoYi: Delivering final response:", payload);
246
- // Send final response back through WebSocket
255
+ console.log("XiaoYi: Delivering final response:", payload.text?.substring(0, 100) + "...");
256
+ // Send final response back through WebSocket (non-streaming, complete message)
247
257
  const taskId = runtime.getTaskIdForSession(message.sessionId) || `task_${Date.now()}`;
248
258
  const response = {
249
259
  sessionId: message.sessionId,
@@ -264,37 +274,13 @@ exports.xiaoyiPlugin = {
264
274
  const conn = runtime.getConnection();
265
275
  if (conn) {
266
276
  await conn.sendResponse(response, taskId, message.sessionId);
267
- console.log("XiaoYi: Final response sent successfully");
277
+ console.log("XiaoYi: Final response sent successfully (non-streaming mode)");
268
278
  }
269
279
  },
270
280
  },
271
281
  replyOptions: {
272
- // Enable streaming responses through onPartialReply callback
273
- onPartialReply: async (payload) => {
274
- console.log("XiaoYi: Streaming partial response:", payload.text?.substring(0, 50));
275
- // Send partial response back through WebSocket
276
- const taskId = runtime.getTaskIdForSession(message.sessionId) || `task_${Date.now()}`;
277
- const partialResponse = {
278
- sessionId: message.sessionId,
279
- messageId: `partial_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
280
- timestamp: Date.now(),
281
- agentId: resolvedAccount.config.agentId,
282
- sender: {
283
- id: resolvedAccount.config.agentId,
284
- name: "OpenClaw Agent",
285
- type: "agent",
286
- },
287
- content: {
288
- type: "text",
289
- text: payload.text || "",
290
- },
291
- status: "processing",
292
- };
293
- const conn = runtime.getConnection();
294
- if (conn) {
295
- await conn.sendResponse(partialResponse, taskId, message.sessionId);
296
- }
297
- },
282
+ // Disable streaming by removing onPartialReply callback
283
+ // This ensures all responses are buffered and delivered only once at the end
298
284
  },
299
285
  });
300
286
  }
package/dist/types.d.ts CHANGED
@@ -1,26 +1,27 @@
1
1
  export interface A2ARequestMessage {
2
2
  agentId: string;
3
3
  sessionId: string;
4
+ jsonrpc: "2.0";
4
5
  id: string;
5
- messageId: string;
6
- timestamp: number;
7
- sender: {
6
+ method: "message/stream";
7
+ params: {
8
8
  id: string;
9
- name?: string;
10
- type: "user" | "agent";
11
- };
12
- content: {
13
- type: "text" | "image" | "audio" | "video" | "file";
14
- text?: string;
15
- mediaUrl?: string;
16
- fileName?: string;
17
- fileSize?: number;
18
- mimeType?: string;
19
- };
20
- context?: {
21
- conversationId?: string;
22
- threadId?: string;
23
- replyToMessageId?: string;
9
+ sessionId: string;
10
+ agentLoginSessionId?: string;
11
+ message: {
12
+ role: "user" | "agent";
13
+ parts: Array<{
14
+ kind: "text" | "file" | "data";
15
+ text?: string;
16
+ file?: {
17
+ name: string;
18
+ mimeType: string;
19
+ bytes?: string;
20
+ uri?: string;
21
+ };
22
+ data?: any;
23
+ }>;
24
+ };
24
25
  };
25
26
  }
26
27
  export interface A2AResponseMessage {
@@ -76,7 +76,7 @@ export declare class XiaoYiWebSocketManager extends EventEmitter {
76
76
  */
77
77
  sendCancelSuccessResponse(sessionId: string, taskId: string, requestId: string): Promise<void>;
78
78
  /**
79
- * Type guard for A2A request messages
79
+ * Type guard for A2A request messages (JSON-RPC 2.0 format)
80
80
  */
81
81
  private isA2ARequestMessage;
82
82
  /**
package/dist/websocket.js CHANGED
@@ -355,17 +355,21 @@ class XiaoYiWebSocketManager extends events_1.EventEmitter {
355
355
  this.activeTasks.delete(taskId);
356
356
  }
357
357
  /**
358
- * Type guard for A2A request messages
358
+ * Type guard for A2A request messages (JSON-RPC 2.0 format)
359
359
  */
360
360
  isA2ARequestMessage(data) {
361
361
  return data &&
362
362
  typeof data.agentId === "string" &&
363
363
  typeof data.sessionId === "string" &&
364
+ data.jsonrpc === "2.0" &&
364
365
  typeof data.id === "string" &&
365
- typeof data.messageId === "string" &&
366
- typeof data.timestamp === "number" &&
367
- data.sender &&
368
- data.content;
366
+ data.method === "message/stream" &&
367
+ data.params &&
368
+ typeof data.params.id === "string" &&
369
+ typeof data.params.sessionId === "string" &&
370
+ data.params.message &&
371
+ typeof data.params.message.role === "string" &&
372
+ Array.isArray(data.params.message.parts);
369
373
  }
370
374
  /**
371
375
  * Start protocol-level heartbeat (ping/pong)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ynhcj/xiaoyi",
3
- "version": "2.0.6",
3
+ "version": "2.0.8",
4
4
  "description": "XiaoYi channel plugin for OpenClaw",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",