@ynhcj/xiaoyi-channel 0.0.51-beta → 0.0.52-beta

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.
Files changed (31) hide show
  1. package/dist/src/bot.js +0 -16
  2. package/dist/src/client.js +0 -2
  3. package/dist/src/formatter.js +3 -23
  4. package/dist/src/heartbeat.js +0 -1
  5. package/dist/src/reply-dispatcher.js +32 -0
  6. package/dist/src/tools/calendar-tool.js +2 -37
  7. package/dist/src/tools/call-phone-tool.js +1 -42
  8. package/dist/src/tools/create-alarm-tool.js +3 -74
  9. package/dist/src/tools/delete-alarm-tool.js +3 -45
  10. package/dist/src/tools/image-reading-tool.js +0 -47
  11. package/dist/src/tools/location-tool.js +1 -32
  12. package/dist/src/tools/modify-alarm-tool.js +3 -77
  13. package/dist/src/tools/modify-note-tool.js +1 -34
  14. package/dist/src/tools/note-tool.js +2 -4
  15. package/dist/src/tools/search-alarm-tool.js +3 -61
  16. package/dist/src/tools/search-calendar-tool.js +2 -39
  17. package/dist/src/tools/search-contact-tool.js +0 -30
  18. package/dist/src/tools/search-file-tool.js +0 -33
  19. package/dist/src/tools/search-message-tool.js +0 -33
  20. package/dist/src/tools/search-note-tool.js +1 -26
  21. package/dist/src/tools/search-photo-gallery-tool.js +2 -31
  22. package/dist/src/tools/send-file-to-user-tool.js +0 -39
  23. package/dist/src/tools/send-message-tool.js +1 -39
  24. package/dist/src/tools/session-manager.js +0 -45
  25. package/dist/src/tools/upload-file-tool.js +0 -49
  26. package/dist/src/tools/upload-photo-tool.js +0 -42
  27. package/dist/src/tools/view-push-result-tool.js +0 -11
  28. package/dist/src/tools/xiaoyi-collection-tool.js +4 -82
  29. package/dist/src/tools/xiaoyi-gui-tool.js +0 -34
  30. package/dist/src/websocket.js +24 -8
  31. package/package.json +1 -1
@@ -1,7 +1,6 @@
1
1
  import { getXYWebSocketManager } from "../client.js";
2
2
  import { sendCommand } from "../formatter.js";
3
3
  import { getCurrentSessionContext } from "./session-manager.js";
4
- import { logger } from "../utils/logger.js";
5
4
  /**
6
5
  * XY collection tool - retrieves user's collection data from XiaoYi.
7
6
  * Returns personalized knowledge data saved in user's collection.
@@ -22,29 +21,15 @@ export const xiaoyiCollectionTool = {
22
21
  required: [],
23
22
  },
24
23
  async execute(toolCallId, params) {
25
- logger.log(`[XIAOYI_COLLECTION_TOOL] 🚀 Starting execution`);
26
- logger.log(`[XIAOYI_COLLECTION_TOOL] - toolCallId: ${toolCallId}`);
27
- logger.log(`[XIAOYI_COLLECTION_TOOL] - params:`, JSON.stringify(params));
28
- logger.log(`[XIAOYI_COLLECTION_TOOL] - timestamp: ${new Date().toISOString()}`);
29
24
  // Get session context
30
- logger.log(`[XIAOYI_COLLECTION_TOOL] 🔍 Attempting to get session context...`);
31
25
  const sessionContext = getCurrentSessionContext();
32
26
  if (!sessionContext) {
33
- logger.error(`[XIAOYI_COLLECTION_TOOL] ❌ FAILED: No active session found!`);
34
- logger.error(`[XIAOYI_COLLECTION_TOOL] - toolCallId: ${toolCallId}`);
35
27
  throw new Error("No active XY session found. XiaoYi collection tool can only be used during an active conversation.");
36
28
  }
37
- logger.log(`[XIAOYI_COLLECTION_TOOL] ✅ Session context found`);
38
- logger.log(`[XIAOYI_COLLECTION_TOOL] - sessionId: ${sessionContext.sessionId}`);
39
- logger.log(`[XIAOYI_COLLECTION_TOOL] - taskId: ${sessionContext.taskId}`);
40
- logger.log(`[XIAOYI_COLLECTION_TOOL] - messageId: ${sessionContext.messageId}`);
41
29
  const { config, sessionId, taskId, messageId } = sessionContext;
42
30
  // Get WebSocket manager
43
- logger.log(`[XIAOYI_COLLECTION_TOOL] 🔌 Getting WebSocket manager...`);
44
31
  const wsManager = getXYWebSocketManager(config);
45
- logger.log(`[XIAOYI_COLLECTION_TOOL] ✅ WebSocket manager obtained`);
46
32
  // Build QueryCollection command
47
- logger.log(`[XIAOYI_COLLECTION_TOOL] 📦 Building QueryCollection command...`);
48
33
  const command = {
49
34
  header: {
50
35
  namespace: "Common",
@@ -79,96 +64,35 @@ export const xiaoyiCollectionTool = {
79
64
  },
80
65
  };
81
66
  // Send command and wait for response (60 second timeout)
82
- logger.log(`[XIAOYI_COLLECTION_TOOL] ⏳ Setting up promise to wait for collection query response...`);
83
- logger.log(`[XIAOYI_COLLECTION_TOOL] - Timeout: 60 seconds`);
84
67
  return new Promise((resolve, reject) => {
85
68
  const timeout = setTimeout(() => {
86
- logger.error(`[XIAOYI_COLLECTION_TOOL] ⏰ Timeout: No response received within 60 seconds`);
87
69
  wsManager.off("data-event", handler);
88
70
  reject(new Error("查询小艺收藏超时(60秒)"));
89
71
  }, 60000);
90
72
  // Listen for data events from WebSocket
91
73
  const handler = (event) => {
92
- logger.log(`[XIAOYI_COLLECTION_TOOL] 📨 Received data event:`, JSON.stringify(event));
93
74
  if (event.intentName === "QueryCollection") {
94
- logger.log(`[XIAOYI_COLLECTION_TOOL] 🎯 QueryCollection event received`);
95
- logger.log(`[XIAOYI_COLLECTION_TOOL] - status: ${event.status}`);
96
75
  clearTimeout(timeout);
97
76
  wsManager.off("data-event", handler);
98
77
  if (event.status === "success" && event.outputs) {
99
- logger.log(`[XIAOYI_COLLECTION_TOOL] ✅ Collection query completed successfully`);
100
- logger.log(`[XIAOYI_COLLECTION_TOOL] - outputs:`, JSON.stringify(event.outputs));
101
- // Check for error code first
102
- if (event.outputs.code && event.outputs.code !== 0) {
103
- logger.error(`[XIAOYI_COLLECTION_TOOL] ❌ Query failed with error code: ${event.outputs.code}`);
104
- reject(new Error(`查询小艺收藏失败 (错误码: ${event.outputs.code})`));
105
- return;
106
- }
107
- // Get the result from outputs
108
- const result = event.outputs.result;
109
- // Check if result exists
110
- if (!result) {
111
- logger.warn(`[XIAOYI_COLLECTION_TOOL] ⚠️ No collection data found`);
112
- resolve({
113
- content: [
114
- {
115
- type: "text",
116
- text: JSON.stringify({
117
- success: true,
118
- memoryInfo: [],
119
- message: "未找到收藏数据"
120
- }),
121
- },
122
- ],
123
- });
124
- return;
125
- }
126
- // Extract memoryInfo from the nested result structure
127
- const memoryInfo = result.result?.memoryInfo || [];
128
- logger.log(`[XIAOYI_COLLECTION_TOOL] 📊 Collections found: ${memoryInfo.length} items`);
129
- // Process and simplify the collection data
130
- const simplifiedCollections = memoryInfo.map((item) => ({
131
- uuid: item.uuid,
132
- type: item.type,
133
- status: item.status,
134
- collectionTime: item.collectionTime,
135
- editTime: item.editTime,
136
- title: item.linkTitle || item.aiTitle || item.textTitle || item.imageTitle || item.podcastTitle || "",
137
- description: item.description || item.abstract || "",
138
- content: item.textContent || "",
139
- linkUrl: item.linkUrl,
140
- linkType: item.linkType,
141
- appName: item.appNameFromPab || item.appName || "",
142
- labels: item.label || [],
143
- collectionMethod: item.collectionMethod,
144
- }));
145
- // Return the result with valid string content
78
+ // 成功,直接返回完整的 event.outputs JSON 字符串
146
79
  resolve({
147
80
  content: [
148
81
  {
149
82
  type: "text",
150
- text: JSON.stringify({
151
- success: true,
152
- totalResults: simplifiedCollections.length,
153
- collections: simplifiedCollections,
154
- message: result.message,
155
- }),
156
- },
157
- ],
83
+ text: JSON.stringify(event.outputs),
84
+ }
85
+ ]
158
86
  });
159
87
  }
160
88
  else {
161
- logger.error(`[XIAOYI_COLLECTION_TOOL] ❌ Collection query failed`);
162
- logger.error(`[XIAOYI_COLLECTION_TOOL] - status: ${event.status}`);
163
89
  reject(new Error(`查询小艺收藏失败: ${event.status}`));
164
90
  }
165
91
  }
166
92
  };
167
93
  // Register event handler
168
- logger.log(`[XIAOYI_COLLECTION_TOOL] 📡 Registering data-event handler on WebSocket manager`);
169
94
  wsManager.on("data-event", handler);
170
95
  // Send the command
171
- logger.log(`[XIAOYI_COLLECTION_TOOL] 📤 Sending QueryCollection command...`);
172
96
  sendCommand({
173
97
  config,
174
98
  sessionId,
@@ -177,10 +101,8 @@ export const xiaoyiCollectionTool = {
177
101
  command,
178
102
  })
179
103
  .then(() => {
180
- logger.log(`[XIAOYI_COLLECTION_TOOL] ✅ Command sent successfully, waiting for response...`);
181
104
  })
182
105
  .catch((error) => {
183
- logger.error(`[XIAOYI_COLLECTION_TOOL] ❌ Failed to send command:`, error);
184
106
  clearTimeout(timeout);
185
107
  wsManager.off("data-event", handler);
186
108
  reject(error);
@@ -2,7 +2,6 @@
2
2
  import { getXYWebSocketManager } from "../client.js";
3
3
  import { sendCommand } from "../formatter.js";
4
4
  import { getCurrentSessionContext } from "./session-manager.js";
5
- import { logger } from "../utils/logger.js";
6
5
  /**
7
6
  * XiaoYi GUI tool - executes phone app interactions through GUI agent.
8
7
  * Simulates user interactions on phone screen (click, swipe, input, navigation, etc.)
@@ -38,35 +37,19 @@ export const xiaoyiGuiTool = {
38
37
  required: ["query"],
39
38
  },
40
39
  async execute(toolCallId, params) {
41
- logger.log(`[XIAOYI_GUI_TOOL] 🚀 Starting execution`);
42
- logger.log(`[XIAOYI_GUI_TOOL] - toolCallId: ${toolCallId}`);
43
- logger.log(`[XIAOYI_GUI_TOOL] - query: ${params.query}`);
44
- logger.log(`[XIAOYI_GUI_TOOL] - timestamp: ${new Date().toISOString()}`);
45
40
  // Validate parameters
46
41
  if (!params.query || typeof params.query !== "string") {
47
- logger.error(`[XIAOYI_GUI_TOOL] ❌ FAILED: Invalid query parameter`);
48
42
  throw new Error("Missing or invalid required parameter: query must be a non-empty string");
49
43
  }
50
44
  // Get session context
51
- logger.log(`[XIAOYI_GUI_TOOL] 🔍 Attempting to get session context...`);
52
45
  const sessionContext = getCurrentSessionContext();
53
46
  if (!sessionContext) {
54
- logger.error(`[XIAOYI_GUI_TOOL] ❌ FAILED: No active session found!`);
55
- logger.error(`[XIAOYI_GUI_TOOL] - toolCallId: ${toolCallId}`);
56
47
  throw new Error("No active XY session found. XiaoYi GUI tool can only be used during an active conversation.");
57
48
  }
58
- logger.log(`[XIAOYI_GUI_TOOL] ✅ Session context found`);
59
- logger.log(`[XIAOYI_GUI_TOOL] - sessionId: ${sessionContext.sessionId}`);
60
- logger.log(`[XIAOYI_GUI_TOOL] - taskId (interactionId): ${sessionContext.taskId}`);
61
- logger.log(`[XIAOYI_GUI_TOOL] - messageId: ${sessionContext.messageId}`);
62
- logger.log(`[XIAOYI_GUI_TOOL] - agentId: ${sessionContext.agentId}`);
63
49
  const { config, sessionId, taskId, messageId } = sessionContext;
64
50
  // Get WebSocket manager
65
- logger.log(`[XIAOYI_GUI_TOOL] 🔌 Getting WebSocket manager...`);
66
51
  const wsManager = getXYWebSocketManager(config);
67
- logger.log(`[XIAOYI_GUI_TOOL] ✅ WebSocket manager obtained`);
68
52
  // Build InvokeJarvisGUIAgentRequest command
69
- logger.log(`[XIAOYI_GUI_TOOL] 📦 Building InvokeJarvisGUIAgentRequest command...`);
70
53
  const command = {
71
54
  header: {
72
55
  namespace: "ClawAgent",
@@ -78,32 +61,23 @@ export const xiaoyiGuiTool = {
78
61
  interactionId: taskId, // taskId corresponds to interactionId
79
62
  },
80
63
  };
81
- logger.log(`[XIAOYI_GUI_TOOL] 📋 Command details:`, JSON.stringify(command, null, 2));
82
64
  // Send command and wait for response (5 minute timeout)
83
- logger.log(`[XIAOYI_GUI_TOOL] ⏳ Setting up promise to wait for GUI agent response...`);
84
- logger.log(`[XIAOYI_GUI_TOOL] - Timeout: 300 seconds (5 minutes)`);
85
65
  return new Promise((resolve, reject) => {
86
66
  const timeout = setTimeout(() => {
87
- logger.error(`[XIAOYI_GUI_TOOL] ⏰ Timeout: No response received within 300 seconds (5 minutes)`);
88
67
  wsManager.off("gui-agent-response", handler);
89
68
  reject(new Error("XiaoYi GUI Agent 操作超时(5分钟)"));
90
69
  }, 180000); // 5 minutes timeout
91
70
  // Listen for GUI agent response events
92
71
  const handler = (event) => {
93
- logger.log(`[XIAOYI_GUI_TOOL] 📨 Received event:`, JSON.stringify(event));
94
72
  // Check if this is the InvokeJarvisGUIAgentResponse we're waiting for
95
73
  if (event.header?.namespace === "ClawAgent" &&
96
74
  event.header?.name === "InvokeJarvisGUIAgentResponse") {
97
- logger.log(`[XIAOYI_GUI_TOOL] 🎯 InvokeJarvisGUIAgentResponse event received`);
98
- logger.log(`[XIAOYI_GUI_TOOL] - isFinal: ${event.payload?.isFinal}`);
99
75
  // According to the spec, we only get one response (isFinal: true)
100
76
  if (event.payload?.isFinal === true) {
101
77
  clearTimeout(timeout);
102
78
  wsManager.off("gui-agent-response", handler);
103
79
  const streamContent = event.payload?.streamInfo?.streamContent;
104
80
  if (streamContent) {
105
- logger.log(`[XIAOYI_GUI_TOOL] ✅ GUI Agent operation completed successfully`);
106
- logger.log(`[XIAOYI_GUI_TOOL] - streamContent: ${streamContent}`);
107
81
  resolve({
108
82
  content: [
109
83
  {
@@ -114,23 +88,18 @@ export const xiaoyiGuiTool = {
114
88
  });
115
89
  }
116
90
  else {
117
- logger.error(`[XIAOYI_GUI_TOOL] ❌ Response missing streamContent`);
118
- logger.error(`[XIAOYI_GUI_TOOL] - payload:`, JSON.stringify(event.payload));
119
91
  reject(new Error("XiaoYi GUI Agent 响应格式错误:缺少 streamContent"));
120
92
  }
121
93
  }
122
94
  else if (event.payload?.isFinal === false) {
123
95
  // According to spec, we shouldn't get intermediate responses, but log if we do
124
- logger.log(`[XIAOYI_GUI_TOOL] 📝 Intermediate response received (isFinal: false), waiting for final...`);
125
96
  }
126
97
  }
127
98
  };
128
99
  // Register event handler
129
100
  // Note: The WebSocket manager needs to emit 'gui-agent-response' when receiving this type of response
130
- logger.log(`[XIAOYI_GUI_TOOL] 📡 Registering gui-agent-response handler on WebSocket manager`);
131
101
  wsManager.on("gui-agent-response", handler);
132
102
  // Send the command
133
- logger.log(`[XIAOYI_GUI_TOOL] 📤 Sending InvokeJarvisGUIAgentRequest command...`);
134
103
  sendCommand({
135
104
  config,
136
105
  sessionId,
@@ -138,10 +107,7 @@ export const xiaoyiGuiTool = {
138
107
  messageId,
139
108
  command,
140
109
  }).then(() => {
141
- logger.log(`[XIAOYI_GUI_TOOL] ✅ Command sent successfully, waiting for response...`);
142
- logger.log(`[XIAOYI_GUI_TOOL] - This may take up to 5 minutes depending on the task complexity`);
143
110
  }).catch((error) => {
144
- logger.error(`[XIAOYI_GUI_TOOL] ❌ Failed to send command:`, error);
145
111
  clearTimeout(timeout);
146
112
  wsManager.off("gui-agent-response", handler);
147
113
  reject(error);
@@ -323,24 +323,40 @@ export class XYWebSocketManager extends EventEmitter {
323
323
  const messageStr = data.toString();
324
324
  console.log(`[WS-RECV] Raw message frame, size: ${messageStr.length} bytes`);
325
325
  const parsed = JSON.parse(messageStr);
326
- console.log("[WS-RECV] Parsed message:", JSON.stringify(parsed, null, 2));
326
+ // 提取并打印消息内容(只显示 text,data 只打印提示)
327
+ const parts = parsed.params?.message?.parts;
328
+ if (parts && Array.isArray(parts) && parts.length > 0) {
329
+ const textParts = parts.filter((p) => p?.kind === "text");
330
+ const dataParts = parts.filter((p) => p?.kind === "data");
331
+ // 打印 text 内容
332
+ if (textParts.length > 0) {
333
+ const textContents = textParts
334
+ .map((p) => p?.text || "")
335
+ .filter((text) => text.length > 0)
336
+ .join(" ");
337
+ if (textContents.length > 0) {
338
+ console.log("[WS-RECV] Text:", textContents);
339
+ }
340
+ }
341
+ // 打印 data 提示
342
+ if (dataParts.length > 0) {
343
+ console.log("[WS-RECV] Data: received data message(s)");
344
+ }
345
+ }
327
346
  // Check if message is in direct A2A JSON-RPC format (server push)
328
347
  if (parsed.jsonrpc === "2.0") {
329
348
  const a2aRequest = parsed;
330
- console.log(`[XY] Message type: Direct A2A JSON-RPC, method: ${a2aRequest.method}`);
331
349
  // Extract sessionId from params
332
350
  const sessionId = a2aRequest.params?.sessionId;
333
351
  if (!sessionId) {
334
352
  console.error("[XY] Message missing sessionId");
335
353
  return;
336
354
  }
337
- console.log(`[XY] Session ID: ${sessionId}`);
338
355
  // Check if message contains only data parts (tool results)
339
356
  const dataParts = a2aRequest.params?.message?.parts?.filter((p) => p.kind === "data");
340
357
  const hasOnlyDataParts = dataParts && dataParts.length > 0 &&
341
358
  dataParts.length === a2aRequest.params?.message?.parts?.length;
342
359
  if (hasOnlyDataParts) {
343
- console.log("[XY] Message contains only data parts, processing as tool result");
344
360
  for (const dataPart of dataParts) {
345
361
  const events = dataPart.data?.events;
346
362
  if (!Array.isArray(events)) {
@@ -355,11 +371,11 @@ export class XYWebSocketManager extends EventEmitter {
355
371
  outputs: item.payload.outputs || {},
356
372
  status: "success",
357
373
  };
358
- console.log("[XY] Emitting data-event:", dataEvent);
374
+ console.log(`[XY] Emitting data-event, intentName: ${item.payload.intentName}, size: ${JSON.stringify(dataEvent).length} bytes`);
359
375
  this.emit("data-event", dataEvent);
360
376
  }
361
377
  else if (item.header?.namespace === "ClawAgent" && item.header?.name === "InvokeJarvisGUIAgentResponse") {
362
- console.log("[XY] Emitting gui-agent-response:", item);
378
+ console.log(`[XY] Emitting gui-agent-response, size: ${JSON.stringify(item).length} bytes`);
363
379
  this.emit("gui-agent-response", item);
364
380
  }
365
381
  else if (item.header?.namespace === "Common" && item.header?.name === "Trigger") {
@@ -410,11 +426,11 @@ export class XYWebSocketManager extends EventEmitter {
410
426
  outputs: item.payload.outputs || {},
411
427
  status: "success",
412
428
  };
413
- console.log("[XY] Emitting data-event:", dataEvent);
429
+ console.log(`[XY] Emitting data-event, intentName: ${item.payload.intentName}, size: ${JSON.stringify(dataEvent).length} bytes`);
414
430
  this.emit("data-event", dataEvent);
415
431
  }
416
432
  else if (item.header?.namespace === "ClawAgent" && item.header?.name === "InvokeJarvisGUIAgentResponse") {
417
- console.log("[XY] Emitting gui-agent-response:", item);
433
+ console.log(`[XY] Emitting gui-agent-response, size: ${JSON.stringify(item).length} bytes`);
418
434
  this.emit("gui-agent-response", item);
419
435
  }
420
436
  else if (item.header?.namespace === "Common" && item.header?.name === "Trigger") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ynhcj/xiaoyi-channel",
3
- "version": "0.0.51-beta",
3
+ "version": "0.0.52-beta",
4
4
  "description": "OpenClaw Xiaoyi Channel plugin - Xiaoyi A2A protocol integration",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",