@ynhcj/xiaoyi-channel 0.0.44-beta → 0.0.44-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.
Files changed (73) hide show
  1. package/dist/index.d.ts +0 -2
  2. package/dist/index.js +42 -2
  3. package/dist/src/bot.d.ts +1 -0
  4. package/dist/src/bot.js +59 -61
  5. package/dist/src/channel.js +30 -4
  6. package/dist/src/client.js +0 -9
  7. package/dist/src/cspl/call-api.d.ts +3 -0
  8. package/dist/src/cspl/call-api.js +86 -0
  9. package/dist/src/cspl/config.d.ts +19 -0
  10. package/dist/src/cspl/config.js +50 -0
  11. package/dist/src/cspl/constants.d.ts +43 -0
  12. package/dist/src/cspl/constants.js +22 -0
  13. package/dist/src/cspl/utils.d.ts +10 -0
  14. package/dist/src/cspl/utils.js +57 -0
  15. package/dist/src/file-upload.d.ts +5 -0
  16. package/dist/src/file-upload.js +88 -6
  17. package/dist/src/formatter.d.ts +2 -0
  18. package/dist/src/formatter.js +13 -30
  19. package/dist/src/heartbeat.js +0 -4
  20. package/dist/src/monitor.js +8 -10
  21. package/dist/src/onboarding.d.ts +3 -4
  22. package/dist/src/onboarding.js +2 -2
  23. package/dist/src/outbound.d.ts +2 -1
  24. package/dist/src/outbound.js +1 -19
  25. package/dist/src/parser.d.ts +6 -0
  26. package/dist/src/parser.js +16 -0
  27. package/dist/src/push.js +0 -21
  28. package/dist/src/reply-dispatcher.d.ts +4 -0
  29. package/dist/src/reply-dispatcher.js +46 -8
  30. package/dist/src/steer-injector.d.ts +16 -0
  31. package/dist/src/steer-injector.js +74 -0
  32. package/dist/src/thread-bindings.d.ts +54 -0
  33. package/dist/src/thread-bindings.js +214 -0
  34. package/dist/src/tools/calendar-tool.js +2 -37
  35. package/dist/src/tools/call-phone-tool.js +3 -60
  36. package/dist/src/tools/create-alarm-tool.js +8 -109
  37. package/dist/src/tools/delete-alarm-tool.js +5 -69
  38. package/dist/src/tools/device-tool-map.d.ts +4 -0
  39. package/dist/src/tools/device-tool-map.js +24 -0
  40. package/dist/src/tools/image-reading-tool.d.ts +5 -0
  41. package/dist/src/tools/image-reading-tool.js +328 -0
  42. package/dist/src/tools/location-tool.js +6 -40
  43. package/dist/src/tools/modify-alarm-tool.js +8 -114
  44. package/dist/src/tools/modify-note-tool.js +3 -41
  45. package/dist/src/tools/note-tool.js +4 -16
  46. package/dist/src/tools/search-alarm-tool.js +12 -118
  47. package/dist/src/tools/search-calendar-tool.js +4 -81
  48. package/dist/src/tools/search-contact-tool.js +2 -55
  49. package/dist/src/tools/search-file-tool.js +4 -61
  50. package/dist/src/tools/search-message-tool.js +2 -59
  51. package/dist/src/tools/search-note-tool.js +4 -22
  52. package/dist/src/tools/search-photo-gallery-tool.js +8 -57
  53. package/dist/src/tools/send-command-to-car-tool.d.ts +5 -0
  54. package/dist/src/tools/send-command-to-car-tool.js +85 -0
  55. package/dist/src/tools/send-file-to-user-tool.js +1 -39
  56. package/dist/src/tools/send-message-tool.js +5 -56
  57. package/dist/src/tools/session-manager.d.ts +1 -0
  58. package/dist/src/tools/session-manager.js +0 -45
  59. package/dist/src/tools/timestamp-to-utc8-tool.d.ts +12 -0
  60. package/dist/src/tools/timestamp-to-utc8-tool.js +104 -0
  61. package/dist/src/tools/upload-file-tool.js +0 -49
  62. package/dist/src/tools/upload-photo-tool.js +0 -42
  63. package/dist/src/tools/view-push-result-tool.js +0 -11
  64. package/dist/src/tools/xiaoyi-collection-tool.js +4 -82
  65. package/dist/src/tools/xiaoyi-gui-tool.js +0 -34
  66. package/dist/src/utils/runtime-manager.d.ts +7 -0
  67. package/dist/src/utils/runtime-manager.js +42 -0
  68. package/dist/src/websocket.js +33 -13
  69. package/package.json +3 -4
  70. package/dist/src/tools/search-photo-tool.d.ts +0 -9
  71. package/dist/src/tools/search-photo-tool.js +0 -270
  72. package/dist/src/utils/session.d.ts +0 -34
  73. package/dist/src/utils/session.js +0 -50
@@ -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
  // Enum definitions for alarm search parameters
6
5
  const RANGE_TYPE_VALUES = ["all", "next", "current"];
7
6
  const ALARM_STATE_VALUES = [0, 1];
@@ -33,7 +32,9 @@ export const searchAlarmTool = {
33
32
 
34
33
  注意:
35
34
  a. 操作超时时间为60秒,请勿重复调用此工具,如果超时或失败,最多重试一次。
36
- b. 使用该工具之前需获取当前真实时间`,
35
+ b. 使用该工具之前需获取当前真实时间
36
+
37
+ 回复约束:如果工具返回没有授权或者其他报错,只需要完整描述没有授权或者其他报错内容即可,不需要主动给用户提供解决方案,例如告诉用户如何授权,如何解决报错等都是不需要的,请严格遵守。`,
37
38
  parameters: {
38
39
  type: "object",
39
40
  properties: {
@@ -63,10 +64,6 @@ b. 使用该工具之前需获取当前真实时间`,
63
64
  },
64
65
  },
65
66
  async execute(toolCallId, params) {
66
- logger.log(`[SEARCH_ALARM_TOOL] 🚀 Starting execution`);
67
- logger.log(`[SEARCH_ALARM_TOOL] - toolCallId: ${toolCallId}`);
68
- logger.log(`[SEARCH_ALARM_TOOL] - params:`, JSON.stringify(params));
69
- logger.log(`[SEARCH_ALARM_TOOL] - timestamp: ${new Date().toISOString()}`);
70
67
  // ===== Validate at least one search criterion is provided =====
71
68
  const hasRangeType = params.rangeType !== undefined && params.rangeType !== null;
72
69
  const hasAlarmState = params.alarmState !== undefined && params.alarmState !== null;
@@ -74,92 +71,64 @@ b. 使用该工具之前需获取当前真实时间`,
74
71
  const hasStartTime = params.startTime !== undefined && params.startTime !== null;
75
72
  const hasEndTime = params.endTime !== undefined && params.endTime !== null;
76
73
  if (!hasRangeType && !hasAlarmState && !hasDaysOfWakeType && !hasStartTime && !hasEndTime) {
77
- logger.error(`[SEARCH_ALARM_TOOL] ❌ No search criteria provided`);
78
74
  throw new Error("至少需要提供一个检索条件:rangeType、alarmState、daysOfWakeType 或时间范围(startTime + endTime)");
79
75
  }
80
76
  // ===== Validate rangeType =====
81
77
  if (hasRangeType) {
82
78
  if (typeof params.rangeType !== "string") {
83
- logger.error(`[SEARCH_ALARM_TOOL] ❌ Invalid rangeType type`);
84
79
  throw new Error("rangeType must be a string");
85
80
  }
86
81
  if (!RANGE_TYPE_VALUES.includes(params.rangeType)) {
87
- logger.error(`[SEARCH_ALARM_TOOL] ❌ Invalid rangeType value: ${params.rangeType}`);
88
82
  throw new Error(`rangeType must be one of: ${RANGE_TYPE_VALUES.join(", ")}`);
89
83
  }
90
- logger.log(`[SEARCH_ALARM_TOOL] - rangeType: ${params.rangeType}`);
91
84
  }
92
85
  // ===== Validate alarmState =====
93
86
  if (hasAlarmState) {
94
87
  if (typeof params.alarmState !== "number") {
95
- logger.error(`[SEARCH_ALARM_TOOL] ❌ Invalid alarmState type`);
96
88
  throw new Error("alarmState must be a number");
97
89
  }
98
90
  if (!ALARM_STATE_VALUES.includes(params.alarmState)) {
99
- logger.error(`[SEARCH_ALARM_TOOL] ❌ Invalid alarmState value: ${params.alarmState}`);
100
91
  throw new Error(`alarmState must be one of: ${ALARM_STATE_VALUES.join(", ")}`);
101
92
  }
102
- logger.log(`[SEARCH_ALARM_TOOL] - alarmState: ${params.alarmState}`);
103
93
  }
104
94
  // ===== Validate daysOfWakeType =====
105
95
  if (hasDaysOfWakeType) {
106
96
  if (typeof params.daysOfWakeType !== "number") {
107
- logger.error(`[SEARCH_ALARM_TOOL] ❌ Invalid daysOfWakeType type`);
108
97
  throw new Error("daysOfWakeType must be a number");
109
98
  }
110
99
  if (!DAYS_OF_WAKE_TYPE_VALUES.includes(params.daysOfWakeType)) {
111
- logger.error(`[SEARCH_ALARM_TOOL] ❌ Invalid daysOfWakeType value: ${params.daysOfWakeType}`);
112
100
  throw new Error(`daysOfWakeType must be one of: ${DAYS_OF_WAKE_TYPE_VALUES.join(", ")}`);
113
101
  }
114
- logger.log(`[SEARCH_ALARM_TOOL] - daysOfWakeType: ${params.daysOfWakeType}`);
115
102
  }
116
103
  // ===== Validate time interval (startTime and endTime must be provided together) =====
117
104
  if (hasStartTime !== hasEndTime) {
118
- logger.error(`[SEARCH_ALARM_TOOL] ❌ startTime and endTime must be provided together`);
119
105
  throw new Error("startTime 和 endTime 必须一起提供");
120
106
  }
121
107
  let timeInterval = null;
122
108
  if (hasStartTime && hasEndTime) {
123
109
  // Parse and convert startTime and endTime to timestamps
124
- logger.log(`[SEARCH_ALARM_TOOL] 🕒 Parsing time interval...`);
125
- logger.log(`[SEARCH_ALARM_TOOL] - startTime input: ${params.startTime}`);
126
- logger.log(`[SEARCH_ALARM_TOOL] - endTime input: ${params.endTime}`);
127
110
  const startTimeMs = parseAlarmTimeToTimestamp(params.startTime);
128
111
  const endTimeMs = parseAlarmTimeToTimestamp(params.endTime);
129
112
  if (startTimeMs === null) {
130
- logger.error(`[SEARCH_ALARM_TOOL] ❌ Invalid startTime format`);
131
113
  throw new Error("Invalid startTime format. Required format: YYYYMMDD hhmmss (e.g., 20240315 000000)");
132
114
  }
133
115
  if (endTimeMs === null) {
134
- logger.error(`[SEARCH_ALARM_TOOL] ❌ Invalid endTime format`);
135
116
  throw new Error("Invalid endTime format. Required format: YYYYMMDD hhmmss (e.g., 20240315 235959)");
136
117
  }
137
118
  if (startTimeMs >= endTimeMs) {
138
- logger.error(`[SEARCH_ALARM_TOOL] ❌ startTime must be before endTime`);
139
119
  throw new Error("startTime 必须早于 endTime");
140
120
  }
141
121
  timeInterval = [startTimeMs, endTimeMs];
142
- logger.log(`[SEARCH_ALARM_TOOL] ✅ Time interval parsed: [${startTimeMs}, ${endTimeMs}]`);
143
122
  }
144
123
  // Get session context
145
- logger.log(`[SEARCH_ALARM_TOOL] 🔍 Attempting to get session context...`);
146
124
  const sessionContext = getCurrentSessionContext();
147
125
  if (!sessionContext) {
148
- logger.error(`[SEARCH_ALARM_TOOL] ❌ FAILED: No active session found!`);
149
- logger.error(`[SEARCH_ALARM_TOOL] - toolCallId: ${toolCallId}`);
150
126
  throw new Error("No active XY session found. Search alarm tool can only be used during an active conversation.");
151
127
  }
152
- logger.log(`[SEARCH_ALARM_TOOL] ✅ Session context found`);
153
- logger.log(`[SEARCH_ALARM_TOOL] - sessionId: ${sessionContext.sessionId}`);
154
- logger.log(`[SEARCH_ALARM_TOOL] - taskId: ${sessionContext.taskId}`);
155
- logger.log(`[SEARCH_ALARM_TOOL] - messageId: ${sessionContext.messageId}`);
156
128
  const { config, sessionId, taskId, messageId } = sessionContext;
157
129
  // Get WebSocket manager
158
- logger.log(`[SEARCH_ALARM_TOOL] 🔌 Getting WebSocket manager...`);
159
130
  const wsManager = getXYWebSocketManager(config);
160
- logger.log(`[SEARCH_ALARM_TOOL] ✅ WebSocket manager obtained`);
161
131
  // Build SearchAlarm command
162
- logger.log(`[SEARCH_ALARM_TOOL] 📦 Building SearchAlarm command...`);
163
132
  // Build intentParam with provided search criteria
164
133
  const intentParam = {};
165
134
  if (hasRangeType) {
@@ -206,96 +175,35 @@ b. 使用该工具之前需获取当前真实时间`,
206
175
  },
207
176
  };
208
177
  // Send command and wait for response (60 second timeout)
209
- logger.log(`[SEARCH_ALARM_TOOL] ⏳ Setting up promise to wait for alarm search response...`);
210
- logger.log(`[SEARCH_ALARM_TOOL] - Timeout: 60 seconds`);
211
178
  return new Promise((resolve, reject) => {
212
179
  const timeout = setTimeout(() => {
213
- logger.error(`[SEARCH_ALARM_TOOL] ⏰ Timeout: No response received within 60 seconds`);
214
180
  wsManager.off("data-event", handler);
215
181
  reject(new Error("检索闹钟超时(60秒)"));
216
182
  }, 60000);
217
183
  // Listen for data events from WebSocket
218
184
  const handler = (event) => {
219
- logger.log(`[SEARCH_ALARM_TOOL] 📨 Received data event:`, JSON.stringify(event));
220
185
  if (event.intentName === "SearchAlarm") {
221
- logger.log(`[SEARCH_ALARM_TOOL] 🎯 SearchAlarm event received`);
222
- logger.log(`[SEARCH_ALARM_TOOL] - status: ${event.status}`);
223
186
  clearTimeout(timeout);
224
187
  wsManager.off("data-event", handler);
225
188
  if (event.status === "success" && event.outputs) {
226
- logger.log(`[SEARCH_ALARM_TOOL] Alarm search completed successfully`);
227
- logger.log(`[SEARCH_ALARM_TOOL] - outputs:`, JSON.stringify(event.outputs));
228
- // Check for error code in outputs
229
- const code = event.outputs.code !== undefined ? event.outputs.code : null;
230
- if (code !== null && code !== 0) {
231
- logger.error(`[SEARCH_ALARM_TOOL] ❌ Device returned error`);
232
- logger.error(`[SEARCH_ALARM_TOOL] - code: ${code}`);
233
- const errorMsg = event.outputs.errorMsg || event.outputs.errMsg || "未知错误";
234
- logger.error(`[SEARCH_ALARM_TOOL] - errorMsg: ${errorMsg}`);
235
- reject(new Error(`检索闹钟失败: ${errorMsg} (错误代码: ${code})`));
236
- return;
237
- }
238
- // Extract result.items with safe checks
239
- const result = event.outputs.result;
240
- let items = [];
241
- if (result && typeof result === "object" && Array.isArray(result.items)) {
242
- items = result.items;
243
- logger.log(`[SEARCH_ALARM_TOOL] 📋 Found ${items.length} alarm(s)`);
244
- // Parse JSON strings in items array
245
- // Items are returned as JSON strings that need to be parsed
246
- const parsedItems = items.map((itemStr, index) => {
247
- if (typeof itemStr !== "string") {
248
- logger.warn(`[SEARCH_ALARM_TOOL] ⚠️ Item at index ${index} is not a string:`, typeof itemStr);
249
- return null;
250
- }
251
- try {
252
- const parsed = JSON.parse(itemStr);
253
- logger.log(`[SEARCH_ALARM_TOOL] 📋 Parsed alarm [${index}]:`, JSON.stringify(parsed));
254
- return parsed;
255
- }
256
- catch (parseError) {
257
- logger.error(`[SEARCH_ALARM_TOOL] ❌ Failed to parse item at index ${index}:`, parseError);
258
- logger.error(`[SEARCH_ALARM_TOOL] - itemStr: ${itemStr}`);
259
- return null;
260
- }
261
- }).filter((item) => item !== null);
262
- logger.log(`[SEARCH_ALARM_TOOL] 🎉 Successfully parsed ${parsedItems.length} alarm(s)`);
263
- resolve({
264
- content: [
265
- {
266
- type: "text",
267
- text: JSON.stringify(parsedItems),
268
- },
269
- ],
270
- });
271
- }
272
- else {
273
- logger.warn(`[SEARCH_ALARM_TOOL] ⚠️ No items found in result or result is invalid`);
274
- logger.warn(`[SEARCH_ALARM_TOOL] - result:`, JSON.stringify(result || {}));
275
- // Return empty array
276
- resolve({
277
- content: [
278
- {
279
- type: "text",
280
- text: "[]",
281
- },
282
- ],
283
- });
284
- }
189
+ // 成功,直接返回完整的 event.outputs JSON 字符串
190
+ resolve({
191
+ content: [
192
+ {
193
+ type: "text",
194
+ text: JSON.stringify(event.outputs),
195
+ },
196
+ ],
197
+ });
285
198
  }
286
199
  else {
287
- logger.error(`[SEARCH_ALARM_TOOL] ❌ Alarm search failed`);
288
- logger.error(`[SEARCH_ALARM_TOOL] - status: ${event.status}`);
289
- logger.error(`[SEARCH_ALARM_TOOL] - outputs:`, JSON.stringify(event.outputs || {}));
290
200
  reject(new Error(`检索闹钟失败: ${event.status}`));
291
201
  }
292
202
  }
293
203
  };
294
204
  // Register event handler
295
- logger.log(`[SEARCH_ALARM_TOOL] 📡 Registering data-event handler on WebSocket manager`);
296
205
  wsManager.on("data-event", handler);
297
206
  // Send the command
298
- logger.log(`[SEARCH_ALARM_TOOL] 📤 Sending SearchAlarm command...`);
299
207
  sendCommand({
300
208
  config,
301
209
  sessionId,
@@ -304,10 +212,8 @@ b. 使用该工具之前需获取当前真实时间`,
304
212
  command,
305
213
  })
306
214
  .then(() => {
307
- logger.log(`[SEARCH_ALARM_TOOL] ✅ Command sent successfully, waiting for response...`);
308
215
  })
309
216
  .catch((error) => {
310
- logger.error(`[SEARCH_ALARM_TOOL] ❌ Failed to send command:`, error);
311
217
  clearTimeout(timeout);
312
218
  wsManager.off("data-event", handler);
313
219
  reject(error);
@@ -327,17 +233,14 @@ function parseAlarmTimeToTimestamp(alarmTime) {
327
233
  const trimmed = alarmTime.trim();
328
234
  // Check basic format (should have at least 13 characters: YYYYMMDD hhmmss)
329
235
  if (trimmed.length < 13) {
330
- logger.error(`[SEARCH_ALARM_TOOL] ❌ alarmTime too short: ${trimmed}`);
331
236
  return null;
332
237
  }
333
238
  // Extract date and time parts
334
239
  // Format: YYYYMMDD hhmmss
335
240
  const datePart = trimmed.substring(0, 8); // YYYYMMDD
336
241
  const timePart = trimmed.substring(8).trim(); // hhmmss (may have leading space)
337
- logger.log(`[SEARCH_ALARM_TOOL] - datePart: ${datePart}, timePart: ${timePart}`);
338
242
  // Validate lengths
339
243
  if (datePart.length !== 8 || timePart.length !== 6) {
340
- logger.error(`[SEARCH_ALARM_TOOL] ❌ Invalid part lengths: datePart=${datePart.length}, timePart=${timePart.length}`);
341
244
  return null;
342
245
  }
343
246
  // Parse components
@@ -347,45 +250,36 @@ function parseAlarmTimeToTimestamp(alarmTime) {
347
250
  const hour = parseInt(timePart.substring(0, 2), 10);
348
251
  const minute = parseInt(timePart.substring(2, 4), 10);
349
252
  const second = parseInt(timePart.substring(4, 6), 10);
350
- logger.log(`[SEARCH_ALARM_TOOL] - Parsed: ${year}-${month}-${day} ${hour}:${minute}:${second}`);
351
253
  // Validate values
352
254
  if (isNaN(year) || isNaN(month) || isNaN(day) ||
353
255
  isNaN(hour) || isNaN(minute) || isNaN(second)) {
354
- logger.error(`[SEARCH_ALARM_TOOL] ❌ NaN detected in parsed values`);
355
256
  return null;
356
257
  }
357
258
  // Validate ranges
358
259
  if (month < 1 || month > 12) {
359
- logger.error(`[SEARCH_ALARM_TOOL] ❌ Invalid month: ${month}`);
360
260
  return null;
361
261
  }
362
262
  if (day < 1 || day > 31) {
363
- logger.error(`[SEARCH_ALARM_TOOL] ❌ Invalid day: ${day}`);
364
263
  return null;
365
264
  }
366
265
  if (hour < 0 || hour > 23) {
367
- logger.error(`[SEARCH_ALARM_TOOL] ❌ Invalid hour: ${hour}`);
368
266
  return null;
369
267
  }
370
268
  if (minute < 0 || minute > 59) {
371
- logger.error(`[SEARCH_ALARM_TOOL] ❌ Invalid minute: ${minute}`);
372
269
  return null;
373
270
  }
374
271
  if (second < 0 || second > 59) {
375
- logger.error(`[SEARCH_ALARM_TOOL] ❌ Invalid second: ${second}`);
376
272
  return null;
377
273
  }
378
274
  // Create Date object and get timestamp
379
275
  const date = new Date(year, month - 1, day, hour, minute, second);
380
276
  const timestamp = date.getTime();
381
277
  if (isNaN(timestamp)) {
382
- logger.error(`[SEARCH_ALARM_TOOL] ❌ Generated timestamp is NaN`);
383
278
  return null;
384
279
  }
385
280
  return timestamp;
386
281
  }
387
282
  catch (error) {
388
- logger.error(`[SEARCH_ALARM_TOOL] ❌ Exception in parseAlarmTimeToTimestamp:`, error);
389
283
  return null;
390
284
  }
391
285
  }
@@ -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 search calendar event tool - searches calendar events on user's device.
7
6
  * Returns matching events based on time range and optional title filter.
@@ -28,6 +27,8 @@ export const searchCalendarTool = {
28
27
  注意:
29
28
  a. 该工具执行时间较长(最多60秒),请勿重复调用,超时或失败时最多重试一次。
30
29
  b. 使用该工具之前需获取当前真实时间
30
+
31
+ 回复约束:如果工具返回没有授权或者其他报错,只需要完整描述没有授权或者其他报错内容即可,不需要主动给用户提供解决方案,例如告诉用户如何授权,如何解决报错等都是不需要的,请严格遵守。
31
32
  `,
32
33
  parameters: {
33
34
  type: "object",
@@ -48,19 +49,11 @@ b. 使用该工具之前需获取当前真实时间
48
49
  required: ["startTime", "endTime"],
49
50
  },
50
51
  async execute(toolCallId, params) {
51
- logger.log(`[SEARCH_CALENDAR_TOOL] 🚀 Starting execution`);
52
- logger.log(`[SEARCH_CALENDAR_TOOL] - toolCallId: ${toolCallId}`);
53
- logger.log(`[SEARCH_CALENDAR_TOOL] - params:`, JSON.stringify(params));
54
- logger.log(`[SEARCH_CALENDAR_TOOL] - timestamp: ${new Date().toISOString()}`);
55
52
  // Validate parameters
56
53
  if (!params.startTime || !params.endTime) {
57
- logger.error(`[SEARCH_CALENDAR_TOOL] ❌ Missing required parameters`);
58
54
  throw new Error("Missing required parameters: startTime and endTime are required");
59
55
  }
60
56
  // Convert time strings to millisecond timestamps
61
- logger.log(`[SEARCH_CALENDAR_TOOL] 🕒 Converting time strings to timestamps...`);
62
- logger.log(`[SEARCH_CALENDAR_TOOL] - startTime input: ${params.startTime}`);
63
- logger.log(`[SEARCH_CALENDAR_TOOL] - endTime input: ${params.endTime}`);
64
57
  // Parse YYYYMMDD hhmmss format
65
58
  const parseTimeString = (timeStr) => {
66
59
  // Remove any extra spaces and split
@@ -83,17 +76,6 @@ b. 使用该工具之前需获取当前真实时间
83
76
  const date = new Date(year, month, day, hours, minutes, seconds);
84
77
  return date.getTime();
85
78
  };
86
- // Helper function to convert timestamp to YYYYMMDD hhmmss format
87
- const formatTimestamp = (timestamp) => {
88
- const date = new Date(timestamp);
89
- const year = date.getFullYear();
90
- const month = String(date.getMonth() + 1).padStart(2, '0');
91
- const day = String(date.getDate()).padStart(2, '0');
92
- const hours = String(date.getHours()).padStart(2, '0');
93
- const minutes = String(date.getMinutes()).padStart(2, '0');
94
- const seconds = String(date.getSeconds()).padStart(2, '0');
95
- return `${year}${month}${day} ${hours}${minutes}${seconds}`;
96
- };
97
79
  let startTimeMs;
98
80
  let endTimeMs;
99
81
  try {
@@ -101,42 +83,26 @@ b. 使用该工具之前需获取当前真实时间
101
83
  endTimeMs = parseTimeString(params.endTime);
102
84
  }
103
85
  catch (error) {
104
- logger.error(`[SEARCH_CALENDAR_TOOL] ❌ Time parsing error:`, error);
105
86
  throw new Error(`Invalid time format. Required format: YYYYMMDD hhmmss (e.g., 20240115 143000). Error: ${error instanceof Error ? error.message : String(error)}`);
106
87
  }
107
88
  if (isNaN(startTimeMs) || isNaN(endTimeMs)) {
108
- logger.error(`[SEARCH_CALENDAR_TOOL] ❌ Invalid time format`);
109
89
  throw new Error("Invalid time format. Required format: YYYYMMDD hhmmss (e.g., 20240115 143000)");
110
90
  }
111
- logger.log(`[SEARCH_CALENDAR_TOOL] ✅ Time conversion successful`);
112
- logger.log(`[SEARCH_CALENDAR_TOOL] - startTime timestamp: ${startTimeMs}`);
113
- logger.log(`[SEARCH_CALENDAR_TOOL] - endTime timestamp: ${endTimeMs}`);
114
91
  // Get session context
115
- logger.log(`[SEARCH_CALENDAR_TOOL] 🔍 Attempting to get session context...`);
116
92
  const sessionContext = getCurrentSessionContext();
117
93
  if (!sessionContext) {
118
- logger.error(`[SEARCH_CALENDAR_TOOL] ❌ FAILED: No active session found!`);
119
- logger.error(`[SEARCH_CALENDAR_TOOL] - toolCallId: ${toolCallId}`);
120
94
  throw new Error("No active XY session found. Search calendar tool can only be used during an active conversation.");
121
95
  }
122
- logger.log(`[SEARCH_CALENDAR_TOOL] ✅ Session context found`);
123
- logger.log(`[SEARCH_CALENDAR_TOOL] - sessionId: ${sessionContext.sessionId}`);
124
- logger.log(`[SEARCH_CALENDAR_TOOL] - taskId: ${sessionContext.taskId}`);
125
- logger.log(`[SEARCH_CALENDAR_TOOL] - messageId: ${sessionContext.messageId}`);
126
96
  const { config, sessionId, taskId, messageId } = sessionContext;
127
97
  // Get WebSocket manager
128
- logger.log(`[SEARCH_CALENDAR_TOOL] 🔌 Getting WebSocket manager...`);
129
98
  const wsManager = getXYWebSocketManager(config);
130
- logger.log(`[SEARCH_CALENDAR_TOOL] ✅ WebSocket manager obtained`);
131
99
  // Build SearchCalendarEvent command
132
- logger.log(`[SEARCH_CALENDAR_TOOL] 📦 Building SearchCalendarEvent command...`);
133
100
  // Build intentParam with timeInterval and optional title
134
101
  const intentParam = {
135
102
  timeInterval: [startTimeMs, endTimeMs],
136
103
  };
137
104
  if (params.title) {
138
105
  intentParam.title = params.title;
139
- logger.log(`[SEARCH_CALENDAR_TOOL] - Including title filter: ${params.title}`);
140
106
  }
141
107
  const command = {
142
108
  header: {
@@ -171,76 +137,35 @@ b. 使用该工具之前需获取当前真实时间
171
137
  },
172
138
  };
173
139
  // Send command and wait for response (60 second timeout)
174
- logger.log(`[SEARCH_CALENDAR_TOOL] ⏳ Setting up promise to wait for calendar search response...`);
175
- logger.log(`[SEARCH_CALENDAR_TOOL] - Timeout: 60 seconds`);
176
140
  return new Promise((resolve, reject) => {
177
141
  const timeout = setTimeout(() => {
178
- logger.error(`[SEARCH_CALENDAR_TOOL] ⏰ Timeout: No response received within 60 seconds`);
179
142
  wsManager.off("data-event", handler);
180
143
  reject(new Error("检索日程超时(60秒)"));
181
144
  }, 60000);
182
145
  // Listen for data events from WebSocket
183
146
  const handler = (event) => {
184
- logger.log(`[SEARCH_CALENDAR_TOOL] 📨 Received data event:`, JSON.stringify(event));
185
147
  if (event.intentName === "SearchCalendarEvent") {
186
- logger.log(`[SEARCH_CALENDAR_TOOL] 🎯 SearchCalendarEvent event received`);
187
- logger.log(`[SEARCH_CALENDAR_TOOL] - status: ${event.status}`);
188
148
  clearTimeout(timeout);
189
149
  wsManager.off("data-event", handler);
190
150
  if (event.status === "success" && event.outputs) {
191
- logger.log(`[SEARCH_CALENDAR_TOOL] Calendar events response received`);
192
- logger.log(`[SEARCH_CALENDAR_TOOL] - outputs:`, JSON.stringify(event.outputs));
193
- // Check for error code in outputs
194
- if (event.outputs.retErrCode && event.outputs.retErrCode !== "0") {
195
- logger.error(`[SEARCH_CALENDAR_TOOL] ❌ Device returned error`);
196
- logger.error(`[SEARCH_CALENDAR_TOOL] - retErrCode: ${event.outputs.retErrCode}`);
197
- logger.error(`[SEARCH_CALENDAR_TOOL] - errMsg: ${event.outputs.errMsg || "Unknown error"}`);
198
- reject(new Error(`检索日程失败: ${event.outputs.errMsg || "未知错误"} (错误代码: ${event.outputs.retErrCode})`));
199
- return;
200
- }
201
- // Return the result directly as requested
202
- const result = event.outputs.result;
203
- // Ensure result is not undefined
204
- if (result === undefined) {
205
- logger.warn(`[SEARCH_CALENDAR_TOOL] ⚠️ Result is undefined, returning empty result`);
206
- }
207
- // Convert dtStart and dtEnd from timestamps to YYYYMMDD hhmmss format
208
- if (result && result.items && Array.isArray(result.items)) {
209
- logger.log(`[SEARCH_CALENDAR_TOOL] 🔄 Converting timestamps to formatted dates...`);
210
- result.items = result.items.map((item) => {
211
- const formattedItem = { ...item };
212
- if (item.dtStart) {
213
- formattedItem.dtStart = formatTimestamp(item.dtStart);
214
- logger.log(`[SEARCH_CALENDAR_TOOL] - dtStart: ${item.dtStart} -> ${formattedItem.dtStart}`);
215
- }
216
- if (item.dtEnd) {
217
- formattedItem.dtEnd = formatTimestamp(item.dtEnd);
218
- logger.log(`[SEARCH_CALENDAR_TOOL] - dtEnd: ${item.dtEnd} -> ${formattedItem.dtEnd}`);
219
- }
220
- return formattedItem;
221
- });
222
- }
151
+ // 成功,直接返回完整的 event.outputs JSON 字符串
223
152
  resolve({
224
153
  content: [
225
154
  {
226
155
  type: "text",
227
- text: result !== undefined ? JSON.stringify(result) : "[]",
156
+ text: JSON.stringify(event.outputs),
228
157
  },
229
158
  ],
230
159
  });
231
160
  }
232
161
  else {
233
- logger.error(`[SEARCH_CALENDAR_TOOL] ❌ Calendar event search failed`);
234
- logger.error(`[SEARCH_CALENDAR_TOOL] - status: ${event.status}`);
235
162
  reject(new Error(`检索日程失败: ${event.status}`));
236
163
  }
237
164
  }
238
165
  };
239
166
  // Register event handler
240
- logger.log(`[SEARCH_CALENDAR_TOOL] 📡 Registering data-event handler on WebSocket manager`);
241
167
  wsManager.on("data-event", handler);
242
168
  // Send the command
243
- logger.log(`[SEARCH_CALENDAR_TOOL] 📤 Sending SearchCalendarEvent command...`);
244
169
  sendCommand({
245
170
  config,
246
171
  sessionId,
@@ -249,10 +174,8 @@ b. 使用该工具之前需获取当前真实时间
249
174
  command,
250
175
  })
251
176
  .then(() => {
252
- logger.log(`[SEARCH_CALENDAR_TOOL] ✅ Command sent successfully, waiting for response...`);
253
177
  })
254
178
  .catch((error) => {
255
- logger.error(`[SEARCH_CALENDAR_TOOL] ❌ Failed to send command:`, error);
256
179
  clearTimeout(timeout);
257
180
  wsManager.off("data-event", handler);
258
181
  reject(error);
@@ -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 search contact tool - searches contacts on user's device.
7
6
  * Returns matching contact information based on name.
@@ -21,34 +20,19 @@ export const searchContactTool = {
21
20
  required: ["name"],
22
21
  },
23
22
  async execute(toolCallId, params) {
24
- logger.log(`[SEARCH_CONTACT_TOOL] 🚀 Starting execution`);
25
- logger.log(`[SEARCH_CONTACT_TOOL] - toolCallId: ${toolCallId}`);
26
- logger.log(`[SEARCH_CONTACT_TOOL] - params:`, JSON.stringify(params));
27
- logger.log(`[SEARCH_CONTACT_TOOL] - timestamp: ${new Date().toISOString()}`);
28
23
  // Validate parameters
29
24
  if (!params.name) {
30
- logger.error(`[SEARCH_CONTACT_TOOL] ❌ Missing required parameter: name`);
31
25
  throw new Error("Missing required parameter: name is required");
32
26
  }
33
27
  // Get session context
34
- logger.log(`[SEARCH_CONTACT_TOOL] 🔍 Attempting to get session context...`);
35
28
  const sessionContext = getCurrentSessionContext();
36
29
  if (!sessionContext) {
37
- logger.error(`[SEARCH_CONTACT_TOOL] ❌ FAILED: No active session found!`);
38
- logger.error(`[SEARCH_CONTACT_TOOL] - toolCallId: ${toolCallId}`);
39
30
  throw new Error("No active XY session found. Search contact tool can only be used during an active conversation.");
40
31
  }
41
- logger.log(`[SEARCH_CONTACT_TOOL] ✅ Session context found`);
42
- logger.log(`[SEARCH_CONTACT_TOOL] - sessionId: ${sessionContext.sessionId}`);
43
- logger.log(`[SEARCH_CONTACT_TOOL] - taskId: ${sessionContext.taskId}`);
44
- logger.log(`[SEARCH_CONTACT_TOOL] - messageId: ${sessionContext.messageId}`);
45
32
  const { config, sessionId, taskId, messageId } = sessionContext;
46
33
  // Get WebSocket manager
47
- logger.log(`[SEARCH_CONTACT_TOOL] 🔌 Getting WebSocket manager...`);
48
34
  const wsManager = getXYWebSocketManager(config);
49
- logger.log(`[SEARCH_CONTACT_TOOL] ✅ WebSocket manager obtained`);
50
35
  // Build SearchContactLocal command
51
- logger.log(`[SEARCH_CONTACT_TOOL] 📦 Building SearchContactLocal command...`);
52
36
  const command = {
53
37
  header: {
54
38
  namespace: "Common",
@@ -83,70 +67,35 @@ export const searchContactTool = {
83
67
  },
84
68
  };
85
69
  // Send command and wait for response (60 second timeout)
86
- logger.log(`[SEARCH_CONTACT_TOOL] ⏳ Setting up promise to wait for contact search response...`);
87
- logger.log(`[SEARCH_CONTACT_TOOL] - Timeout: 60 seconds`);
88
70
  return new Promise((resolve, reject) => {
89
71
  const timeout = setTimeout(() => {
90
- logger.error(`[SEARCH_CONTACT_TOOL] ⏰ Timeout: No response received within 60 seconds`);
91
72
  wsManager.off("data-event", handler);
92
73
  reject(new Error("搜索联系人超时(60秒)"));
93
74
  }, 60000);
94
75
  // Listen for data events from WebSocket
95
76
  const handler = (event) => {
96
- logger.log(`[SEARCH_CONTACT_TOOL] 📨 Received data event:`, JSON.stringify(event));
97
77
  if (event.intentName === "SearchContactLocal") {
98
- logger.log(`[SEARCH_CONTACT_TOOL] 🎯 SearchContactLocal event received`);
99
- logger.log(`[SEARCH_CONTACT_TOOL] - status: ${event.status}`);
100
78
  clearTimeout(timeout);
101
79
  wsManager.off("data-event", handler);
102
80
  if (event.status === "success" && event.outputs) {
103
- logger.log(`[SEARCH_CONTACT_TOOL] Contact search completed successfully`);
104
- logger.log(`[SEARCH_CONTACT_TOOL] - outputs:`, JSON.stringify(event.outputs));
105
- // Check for error code first
106
- if (event.outputs.retErrCode && event.outputs.retErrCode !== "0") {
107
- logger.error(`[SEARCH_CONTACT_TOOL] ❌ Search failed with error code: ${event.outputs.retErrCode}`);
108
- logger.error(`[SEARCH_CONTACT_TOOL] - errMsg: ${event.outputs.errMsg}`);
109
- reject(new Error(`搜索联系人失败: ${event.outputs.errMsg || '未知错误'} (错误码: ${event.outputs.retErrCode})`));
110
- return;
111
- }
112
- // Get the result
113
- const result = event.outputs.result;
114
- // Check if result exists
115
- if (!result) {
116
- logger.warn(`[SEARCH_CONTACT_TOOL] ⚠️ No result found for name "${params.name}"`);
117
- resolve({
118
- content: [
119
- {
120
- type: "text",
121
- text: JSON.stringify({ items: [], message: "未找到匹配的联系人" }),
122
- },
123
- ],
124
- });
125
- return;
126
- }
127
- logger.log(`[SEARCH_CONTACT_TOOL] 📊 Contacts found: ${result?.items?.length || 0} results for name "${params.name}"`);
128
- // Return the result with valid string content
81
+ // 成功,直接返回完整的 event.outputs JSON 字符串
129
82
  resolve({
130
83
  content: [
131
84
  {
132
85
  type: "text",
133
- text: JSON.stringify(result),
86
+ text: JSON.stringify(event.outputs),
134
87
  },
135
88
  ],
136
89
  });
137
90
  }
138
91
  else {
139
- logger.error(`[SEARCH_CONTACT_TOOL] ❌ Contact search failed`);
140
- logger.error(`[SEARCH_CONTACT_TOOL] - status: ${event.status}`);
141
92
  reject(new Error(`搜索联系人失败: ${event.status}`));
142
93
  }
143
94
  }
144
95
  };
145
96
  // Register event handler
146
- logger.log(`[SEARCH_CONTACT_TOOL] 📡 Registering data-event handler on WebSocket manager`);
147
97
  wsManager.on("data-event", handler);
148
98
  // Send the command
149
- logger.log(`[SEARCH_CONTACT_TOOL] 📤 Sending SearchContactLocal command...`);
150
99
  sendCommand({
151
100
  config,
152
101
  sessionId,
@@ -155,10 +104,8 @@ export const searchContactTool = {
155
104
  command,
156
105
  })
157
106
  .then(() => {
158
- logger.log(`[SEARCH_CONTACT_TOOL] ✅ Command sent successfully, waiting for response...`);
159
107
  })
160
108
  .catch((error) => {
161
- logger.error(`[SEARCH_CONTACT_TOOL] ❌ Failed to send command:`, error);
162
109
  clearTimeout(timeout);
163
110
  wsManager.off("data-event", handler);
164
111
  reject(error);