@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 modify note tool - appends content to an existing note on user's device.
7
6
  * Requires entityId from search_notes tool as prerequisite.
@@ -13,7 +12,7 @@ import { logger } from "../utils/logger.js";
13
12
  export const modifyNoteTool = {
14
13
  name: "modify_note",
15
14
  label: "Modify Note",
16
- description: "在指定备忘录中追加新内容。使用前必须先调用 search_notes 工具获取备忘录的 entityId。参数说明:entityId 是备忘录的唯一标识符(从 search_notes 工具获取),text 是要追加的文本内容。注意:操作超时时间为60秒,请勿重复调用此工具,如果超时或失败,最多重试一次。",
15
+ description: "在指定备忘录中追加新内容。使用前必须先调用 search_notes 工具获取备忘录的 entityId。参数说明:entityId 是备忘录的唯一标识符(从 search_notes 工具获取),text 是要追加的文本内容。注意:操作超时时间为60秒,请勿重复调用此工具,如果超时或失败,最多重试一次。回复约束:如果工具返回没有授权或者其他报错,只需要完整描述没有授权或者其他报错内容即可,不需要主动给用户提供解决方案,例如告诉用户如何授权,如何解决报错等都是不需要的,请严格遵守。",
17
16
  parameters: {
18
17
  type: "object",
19
18
  properties: {
@@ -29,34 +28,19 @@ export const modifyNoteTool = {
29
28
  required: ["entityId", "text"],
30
29
  },
31
30
  async execute(toolCallId, params) {
32
- logger.log(`[MODIFY_NOTE_TOOL] 🚀 Starting execution`);
33
- logger.log(`[MODIFY_NOTE_TOOL] - toolCallId: ${toolCallId}`);
34
- logger.log(`[MODIFY_NOTE_TOOL] - params:`, JSON.stringify(params));
35
- logger.log(`[MODIFY_NOTE_TOOL] - timestamp: ${new Date().toISOString()}`);
36
31
  // Validate parameters
37
32
  if (!params.entityId || !params.text) {
38
- logger.error(`[MODIFY_NOTE_TOOL] ❌ Missing required parameters`);
39
33
  throw new Error("Missing required parameters: entityId and text are required");
40
34
  }
41
35
  // Get session context
42
- logger.log(`[MODIFY_NOTE_TOOL] 🔍 Attempting to get session context...`);
43
36
  const sessionContext = getCurrentSessionContext();
44
37
  if (!sessionContext) {
45
- logger.error(`[MODIFY_NOTE_TOOL] ❌ FAILED: No active session found!`);
46
- logger.error(`[MODIFY_NOTE_TOOL] - toolCallId: ${toolCallId}`);
47
38
  throw new Error("No active XY session found. Modify note tool can only be used during an active conversation.");
48
39
  }
49
- logger.log(`[MODIFY_NOTE_TOOL] ✅ Session context found`);
50
- logger.log(`[MODIFY_NOTE_TOOL] - sessionId: ${sessionContext.sessionId}`);
51
- logger.log(`[MODIFY_NOTE_TOOL] - taskId: ${sessionContext.taskId}`);
52
- logger.log(`[MODIFY_NOTE_TOOL] - messageId: ${sessionContext.messageId}`);
53
40
  const { config, sessionId, taskId, messageId } = sessionContext;
54
41
  // Get WebSocket manager
55
- logger.log(`[MODIFY_NOTE_TOOL] 🔌 Getting WebSocket manager...`);
56
42
  const wsManager = getXYWebSocketManager(config);
57
- logger.log(`[MODIFY_NOTE_TOOL] ✅ WebSocket manager obtained`);
58
43
  // Build ModifyNote command
59
- logger.log(`[MODIFY_NOTE_TOOL] 📦 Building ModifyNote command...`);
60
44
  const command = {
61
45
  header: {
62
46
  namespace: "Common",
@@ -92,29 +76,18 @@ export const modifyNoteTool = {
92
76
  pageControlRelated: false,
93
77
  },
94
78
  };
95
- logger.log(`[MODIFY_NOTE_TOOL] - entityId: ${params.entityId}`);
96
- logger.log(`[MODIFY_NOTE_TOOL] - contentType: 1 (append mode)`);
97
- logger.log(`[MODIFY_NOTE_TOOL] - text length: ${params.text.length} characters`);
98
79
  // Send command and wait for response (60 second timeout)
99
- logger.log(`[MODIFY_NOTE_TOOL] ⏳ Setting up promise to wait for note modification response...`);
100
- logger.log(`[MODIFY_NOTE_TOOL] - Timeout: 60 seconds`);
101
80
  return new Promise((resolve, reject) => {
102
81
  const timeout = setTimeout(() => {
103
- logger.error(`[MODIFY_NOTE_TOOL] ⏰ Timeout: No response received within 60 seconds`);
104
82
  wsManager.off("data-event", handler);
105
83
  reject(new Error("修改备忘录超时(60秒)"));
106
84
  }, 60000);
107
85
  // Listen for data events from WebSocket
108
86
  const handler = (event) => {
109
- logger.log(`[MODIFY_NOTE_TOOL] 📨 Received data event:`, JSON.stringify(event));
110
87
  if (event.intentName === "ModifyNote") {
111
- logger.log(`[MODIFY_NOTE_TOOL] 🎯 ModifyNote event received`);
112
- logger.log(`[MODIFY_NOTE_TOOL] - status: ${event.status}`);
113
88
  clearTimeout(timeout);
114
89
  wsManager.off("data-event", handler);
115
90
  if (event.status === "success" && event.outputs) {
116
- logger.log(`[MODIFY_NOTE_TOOL] ✅ Note modified successfully`);
117
- logger.log(`[MODIFY_NOTE_TOOL] - outputs:`, JSON.stringify(event.outputs));
118
91
  // 成功,直接返回完整的 event.outputs JSON 字符串
119
92
  resolve({
120
93
  content: [
@@ -126,17 +99,13 @@ export const modifyNoteTool = {
126
99
  });
127
100
  }
128
101
  else {
129
- logger.error(`[MODIFY_NOTE_TOOL] ❌ Note modification failed`);
130
- logger.error(`[MODIFY_NOTE_TOOL] - status: ${event.status}`);
131
102
  reject(new Error(`修改备忘录失败: ${event.status}`));
132
103
  }
133
104
  }
134
105
  };
135
106
  // Register event handler
136
- logger.log(`[MODIFY_NOTE_TOOL] 📡 Registering data-event handler on WebSocket manager`);
137
107
  wsManager.on("data-event", handler);
138
108
  // Send the command
139
- logger.log(`[MODIFY_NOTE_TOOL] 📤 Sending ModifyNote command...`);
140
109
  sendCommand({
141
110
  config,
142
111
  sessionId,
@@ -145,10 +114,8 @@ export const modifyNoteTool = {
145
114
  command,
146
115
  })
147
116
  .then(() => {
148
- logger.log(`[MODIFY_NOTE_TOOL] ✅ Command sent successfully, waiting for response...`);
149
117
  })
150
118
  .catch((error) => {
151
- logger.error(`[MODIFY_NOTE_TOOL] ❌ Failed to send command:`, error);
152
119
  clearTimeout(timeout);
153
120
  wsManager.off("data-event", handler);
154
121
  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
  * Duck-typed ToolInputError: openclaw 按 .name 字段匹配,不用 instanceof。
7
6
  * 抛出此错误会让 openclaw 返回 HTTP 400 而非 500,
@@ -26,6 +25,8 @@ export const noteTool = {
26
25
  a. 操作超时时间为60秒,请勿重复调用此工具
27
26
  b. 如果遇到各类调用失败场景,最多只能重试一次,不可以重复调用多次。
28
27
  c. 调用工具前需认真检查调用参数是否满足工具要求
28
+
29
+ 回复约束:如果工具返回没有授权或者其他报错,只需要完整描述没有授权或者其他报错内容即可,不需要主动给用户提供解决方案,例如告诉用户如何授权,如何解决报错等都是不需要的,请严格遵守。
29
30
  `,
30
31
  parameters: {
31
32
  type: "object",
@@ -42,7 +43,6 @@ export const noteTool = {
42
43
  required: ["title", "content"],
43
44
  },
44
45
  async execute(toolCallId, params) {
45
- logger.debug("Executing note tool, toolCallId:", toolCallId);
46
46
  // Validate parameters — 抛 ToolInputError 而非普通 Error,
47
47
  // 让 openclaw 返回 400 而非 500,明确告知 LLM 这是参数错误,不应重试。
48
48
  if (typeof params.title !== "string" || !params.title) {
@@ -101,12 +101,10 @@ export const noteTool = {
101
101
  }, 60000);
102
102
  // Listen for data events from WebSocket
103
103
  const handler = (event) => {
104
- logger.debug("Received data event:", event);
105
104
  if (event.intentName === "CreateNote") {
106
105
  clearTimeout(timeout);
107
106
  wsManager.off("data-event", handler);
108
107
  if (event.status === "success" && event.outputs) {
109
- logger.log(`Note created successfully, outputs:`, JSON.stringify(event.outputs));
110
108
  // 成功,直接返回完整的 event.outputs JSON 字符串
111
109
  resolve({
112
110
  content: [
@@ -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,25 +175,17 @@ 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
189
  // 成功,直接返回完整的 event.outputs JSON 字符串
229
190
  resolve({
230
191
  content: [
@@ -236,18 +197,13 @@ b. 使用该工具之前需获取当前真实时间`,
236
197
  });
237
198
  }
238
199
  else {
239
- logger.error(`[SEARCH_ALARM_TOOL] ❌ Alarm search failed`);
240
- logger.error(`[SEARCH_ALARM_TOOL] - status: ${event.status}`);
241
- logger.error(`[SEARCH_ALARM_TOOL] - outputs:`, JSON.stringify(event.outputs || {}));
242
200
  reject(new Error(`检索闹钟失败: ${event.status}`));
243
201
  }
244
202
  }
245
203
  };
246
204
  // Register event handler
247
- logger.log(`[SEARCH_ALARM_TOOL] 📡 Registering data-event handler on WebSocket manager`);
248
205
  wsManager.on("data-event", handler);
249
206
  // Send the command
250
- logger.log(`[SEARCH_ALARM_TOOL] 📤 Sending SearchAlarm command...`);
251
207
  sendCommand({
252
208
  config,
253
209
  sessionId,
@@ -256,10 +212,8 @@ b. 使用该工具之前需获取当前真实时间`,
256
212
  command,
257
213
  })
258
214
  .then(() => {
259
- logger.log(`[SEARCH_ALARM_TOOL] ✅ Command sent successfully, waiting for response...`);
260
215
  })
261
216
  .catch((error) => {
262
- logger.error(`[SEARCH_ALARM_TOOL] ❌ Failed to send command:`, error);
263
217
  clearTimeout(timeout);
264
218
  wsManager.off("data-event", handler);
265
219
  reject(error);
@@ -279,17 +233,14 @@ function parseAlarmTimeToTimestamp(alarmTime) {
279
233
  const trimmed = alarmTime.trim();
280
234
  // Check basic format (should have at least 13 characters: YYYYMMDD hhmmss)
281
235
  if (trimmed.length < 13) {
282
- logger.error(`[SEARCH_ALARM_TOOL] ❌ alarmTime too short: ${trimmed}`);
283
236
  return null;
284
237
  }
285
238
  // Extract date and time parts
286
239
  // Format: YYYYMMDD hhmmss
287
240
  const datePart = trimmed.substring(0, 8); // YYYYMMDD
288
241
  const timePart = trimmed.substring(8).trim(); // hhmmss (may have leading space)
289
- logger.log(`[SEARCH_ALARM_TOOL] - datePart: ${datePart}, timePart: ${timePart}`);
290
242
  // Validate lengths
291
243
  if (datePart.length !== 8 || timePart.length !== 6) {
292
- logger.error(`[SEARCH_ALARM_TOOL] ❌ Invalid part lengths: datePart=${datePart.length}, timePart=${timePart.length}`);
293
244
  return null;
294
245
  }
295
246
  // Parse components
@@ -299,45 +250,36 @@ function parseAlarmTimeToTimestamp(alarmTime) {
299
250
  const hour = parseInt(timePart.substring(0, 2), 10);
300
251
  const minute = parseInt(timePart.substring(2, 4), 10);
301
252
  const second = parseInt(timePart.substring(4, 6), 10);
302
- logger.log(`[SEARCH_ALARM_TOOL] - Parsed: ${year}-${month}-${day} ${hour}:${minute}:${second}`);
303
253
  // Validate values
304
254
  if (isNaN(year) || isNaN(month) || isNaN(day) ||
305
255
  isNaN(hour) || isNaN(minute) || isNaN(second)) {
306
- logger.error(`[SEARCH_ALARM_TOOL] ❌ NaN detected in parsed values`);
307
256
  return null;
308
257
  }
309
258
  // Validate ranges
310
259
  if (month < 1 || month > 12) {
311
- logger.error(`[SEARCH_ALARM_TOOL] ❌ Invalid month: ${month}`);
312
260
  return null;
313
261
  }
314
262
  if (day < 1 || day > 31) {
315
- logger.error(`[SEARCH_ALARM_TOOL] ❌ Invalid day: ${day}`);
316
263
  return null;
317
264
  }
318
265
  if (hour < 0 || hour > 23) {
319
- logger.error(`[SEARCH_ALARM_TOOL] ❌ Invalid hour: ${hour}`);
320
266
  return null;
321
267
  }
322
268
  if (minute < 0 || minute > 59) {
323
- logger.error(`[SEARCH_ALARM_TOOL] ❌ Invalid minute: ${minute}`);
324
269
  return null;
325
270
  }
326
271
  if (second < 0 || second > 59) {
327
- logger.error(`[SEARCH_ALARM_TOOL] ❌ Invalid second: ${second}`);
328
272
  return null;
329
273
  }
330
274
  // Create Date object and get timestamp
331
275
  const date = new Date(year, month - 1, day, hour, minute, second);
332
276
  const timestamp = date.getTime();
333
277
  if (isNaN(timestamp)) {
334
- logger.error(`[SEARCH_ALARM_TOOL] ❌ Generated timestamp is NaN`);
335
278
  return null;
336
279
  }
337
280
  return timestamp;
338
281
  }
339
282
  catch (error) {
340
- logger.error(`[SEARCH_ALARM_TOOL] ❌ Exception in parseAlarmTimeToTimestamp:`, error);
341
283
  return null;
342
284
  }
343
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
@@ -90,42 +83,26 @@ b. 使用该工具之前需获取当前真实时间
90
83
  endTimeMs = parseTimeString(params.endTime);
91
84
  }
92
85
  catch (error) {
93
- logger.error(`[SEARCH_CALENDAR_TOOL] ❌ Time parsing error:`, error);
94
86
  throw new Error(`Invalid time format. Required format: YYYYMMDD hhmmss (e.g., 20240115 143000). Error: ${error instanceof Error ? error.message : String(error)}`);
95
87
  }
96
88
  if (isNaN(startTimeMs) || isNaN(endTimeMs)) {
97
- logger.error(`[SEARCH_CALENDAR_TOOL] ❌ Invalid time format`);
98
89
  throw new Error("Invalid time format. Required format: YYYYMMDD hhmmss (e.g., 20240115 143000)");
99
90
  }
100
- logger.log(`[SEARCH_CALENDAR_TOOL] ✅ Time conversion successful`);
101
- logger.log(`[SEARCH_CALENDAR_TOOL] - startTime timestamp: ${startTimeMs}`);
102
- logger.log(`[SEARCH_CALENDAR_TOOL] - endTime timestamp: ${endTimeMs}`);
103
91
  // Get session context
104
- logger.log(`[SEARCH_CALENDAR_TOOL] 🔍 Attempting to get session context...`);
105
92
  const sessionContext = getCurrentSessionContext();
106
93
  if (!sessionContext) {
107
- logger.error(`[SEARCH_CALENDAR_TOOL] ❌ FAILED: No active session found!`);
108
- logger.error(`[SEARCH_CALENDAR_TOOL] - toolCallId: ${toolCallId}`);
109
94
  throw new Error("No active XY session found. Search calendar tool can only be used during an active conversation.");
110
95
  }
111
- logger.log(`[SEARCH_CALENDAR_TOOL] ✅ Session context found`);
112
- logger.log(`[SEARCH_CALENDAR_TOOL] - sessionId: ${sessionContext.sessionId}`);
113
- logger.log(`[SEARCH_CALENDAR_TOOL] - taskId: ${sessionContext.taskId}`);
114
- logger.log(`[SEARCH_CALENDAR_TOOL] - messageId: ${sessionContext.messageId}`);
115
96
  const { config, sessionId, taskId, messageId } = sessionContext;
116
97
  // Get WebSocket manager
117
- logger.log(`[SEARCH_CALENDAR_TOOL] 🔌 Getting WebSocket manager...`);
118
98
  const wsManager = getXYWebSocketManager(config);
119
- logger.log(`[SEARCH_CALENDAR_TOOL] ✅ WebSocket manager obtained`);
120
99
  // Build SearchCalendarEvent command
121
- logger.log(`[SEARCH_CALENDAR_TOOL] 📦 Building SearchCalendarEvent command...`);
122
100
  // Build intentParam with timeInterval and optional title
123
101
  const intentParam = {
124
102
  timeInterval: [startTimeMs, endTimeMs],
125
103
  };
126
104
  if (params.title) {
127
105
  intentParam.title = params.title;
128
- logger.log(`[SEARCH_CALENDAR_TOOL] - Including title filter: ${params.title}`);
129
106
  }
130
107
  const command = {
131
108
  header: {
@@ -160,25 +137,17 @@ b. 使用该工具之前需获取当前真实时间
160
137
  },
161
138
  };
162
139
  // Send command and wait for response (60 second timeout)
163
- logger.log(`[SEARCH_CALENDAR_TOOL] ⏳ Setting up promise to wait for calendar search response...`);
164
- logger.log(`[SEARCH_CALENDAR_TOOL] - Timeout: 60 seconds`);
165
140
  return new Promise((resolve, reject) => {
166
141
  const timeout = setTimeout(() => {
167
- logger.error(`[SEARCH_CALENDAR_TOOL] ⏰ Timeout: No response received within 60 seconds`);
168
142
  wsManager.off("data-event", handler);
169
143
  reject(new Error("检索日程超时(60秒)"));
170
144
  }, 60000);
171
145
  // Listen for data events from WebSocket
172
146
  const handler = (event) => {
173
- logger.log(`[SEARCH_CALENDAR_TOOL] 📨 Received data event:`, JSON.stringify(event));
174
147
  if (event.intentName === "SearchCalendarEvent") {
175
- logger.log(`[SEARCH_CALENDAR_TOOL] 🎯 SearchCalendarEvent event received`);
176
- logger.log(`[SEARCH_CALENDAR_TOOL] - status: ${event.status}`);
177
148
  clearTimeout(timeout);
178
149
  wsManager.off("data-event", handler);
179
150
  if (event.status === "success" && event.outputs) {
180
- logger.log(`[SEARCH_CALENDAR_TOOL] ✅ Calendar events retrieved successfully`);
181
- logger.log(`[SEARCH_CALENDAR_TOOL] - outputs:`, JSON.stringify(event.outputs));
182
151
  // 成功,直接返回完整的 event.outputs JSON 字符串
183
152
  resolve({
184
153
  content: [
@@ -190,17 +159,13 @@ b. 使用该工具之前需获取当前真实时间
190
159
  });
191
160
  }
192
161
  else {
193
- logger.error(`[SEARCH_CALENDAR_TOOL] ❌ Calendar event search failed`);
194
- logger.error(`[SEARCH_CALENDAR_TOOL] - status: ${event.status}`);
195
162
  reject(new Error(`检索日程失败: ${event.status}`));
196
163
  }
197
164
  }
198
165
  };
199
166
  // Register event handler
200
- logger.log(`[SEARCH_CALENDAR_TOOL] 📡 Registering data-event handler on WebSocket manager`);
201
167
  wsManager.on("data-event", handler);
202
168
  // Send the command
203
- logger.log(`[SEARCH_CALENDAR_TOOL] 📤 Sending SearchCalendarEvent command...`);
204
169
  sendCommand({
205
170
  config,
206
171
  sessionId,
@@ -209,10 +174,8 @@ b. 使用该工具之前需获取当前真实时间
209
174
  command,
210
175
  })
211
176
  .then(() => {
212
- logger.log(`[SEARCH_CALENDAR_TOOL] ✅ Command sent successfully, waiting for response...`);
213
177
  })
214
178
  .catch((error) => {
215
- logger.error(`[SEARCH_CALENDAR_TOOL] ❌ Failed to send command:`, error);
216
179
  clearTimeout(timeout);
217
180
  wsManager.off("data-event", handler);
218
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,25 +67,17 @@ 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
81
  // 成功,直接返回完整的 event.outputs JSON 字符串
106
82
  resolve({
107
83
  content: [
@@ -113,17 +89,13 @@ export const searchContactTool = {
113
89
  });
114
90
  }
115
91
  else {
116
- logger.error(`[SEARCH_CONTACT_TOOL] ❌ Contact search failed`);
117
- logger.error(`[SEARCH_CONTACT_TOOL] - status: ${event.status}`);
118
92
  reject(new Error(`搜索联系人失败: ${event.status}`));
119
93
  }
120
94
  }
121
95
  };
122
96
  // Register event handler
123
- logger.log(`[SEARCH_CONTACT_TOOL] 📡 Registering data-event handler on WebSocket manager`);
124
97
  wsManager.on("data-event", handler);
125
98
  // Send the command
126
- logger.log(`[SEARCH_CONTACT_TOOL] 📤 Sending SearchContactLocal command...`);
127
99
  sendCommand({
128
100
  config,
129
101
  sessionId,
@@ -132,10 +104,8 @@ export const searchContactTool = {
132
104
  command,
133
105
  })
134
106
  .then(() => {
135
- logger.log(`[SEARCH_CONTACT_TOOL] ✅ Command sent successfully, waiting for response...`);
136
107
  })
137
108
  .catch((error) => {
138
- logger.error(`[SEARCH_CONTACT_TOOL] ❌ Failed to send command:`, error);
139
109
  clearTimeout(timeout);
140
110
  wsManager.off("data-event", handler);
141
111
  reject(error);