@ynhcj/xiaoyi-channel 0.0.50-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.
- package/dist/index.js +42 -0
- package/dist/src/bot.js +3 -16
- package/dist/src/client.js +0 -3
- package/dist/src/cspl/call-api.d.ts +3 -0
- package/dist/src/cspl/call-api.js +79 -0
- package/dist/src/cspl/config.d.ts +19 -0
- package/dist/src/cspl/config.js +50 -0
- package/dist/src/cspl/constants.d.ts +43 -0
- package/dist/src/cspl/constants.js +22 -0
- package/dist/src/cspl/utils.d.ts +10 -0
- package/dist/src/cspl/utils.js +57 -0
- package/dist/src/formatter.js +3 -23
- package/dist/src/heartbeat.js +0 -4
- package/dist/src/reply-dispatcher.js +32 -0
- package/dist/src/steer-injector.d.ts +16 -0
- package/dist/src/steer-injector.js +74 -0
- package/dist/src/tools/calendar-tool.js +2 -37
- package/dist/src/tools/call-phone-tool.js +1 -42
- package/dist/src/tools/create-alarm-tool.js +3 -74
- package/dist/src/tools/delete-alarm-tool.js +3 -45
- package/dist/src/tools/image-reading-tool.js +0 -47
- package/dist/src/tools/location-tool.js +1 -32
- package/dist/src/tools/modify-alarm-tool.js +3 -77
- package/dist/src/tools/modify-note-tool.js +1 -34
- package/dist/src/tools/note-tool.js +2 -4
- package/dist/src/tools/search-alarm-tool.js +3 -61
- package/dist/src/tools/search-calendar-tool.js +2 -39
- package/dist/src/tools/search-contact-tool.js +0 -30
- package/dist/src/tools/search-file-tool.js +0 -33
- package/dist/src/tools/search-message-tool.js +0 -33
- package/dist/src/tools/search-note-tool.js +1 -26
- package/dist/src/tools/search-photo-gallery-tool.js +2 -31
- package/dist/src/tools/send-file-to-user-tool.js +0 -39
- package/dist/src/tools/send-message-tool.js +1 -39
- package/dist/src/tools/session-manager.js +0 -45
- package/dist/src/tools/upload-file-tool.js +0 -49
- package/dist/src/tools/upload-photo-tool.js +0 -42
- package/dist/src/tools/view-push-result-tool.js +0 -11
- package/dist/src/tools/xiaoyi-collection-tool.js +4 -82
- package/dist/src/tools/xiaoyi-gui-tool.js +0 -34
- package/dist/src/websocket.js +24 -10
- 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
|
// 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);
|
|
@@ -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 file tool - searches files on user's device file system.
|
|
7
6
|
* Returns matching files based on keyword search in file name or content.
|
|
@@ -33,35 +32,19 @@ export const searchFileTool = {
|
|
|
33
32
|
required: ["query"],
|
|
34
33
|
},
|
|
35
34
|
async execute(toolCallId, params) {
|
|
36
|
-
logger.log(`[SEARCH_FILE_TOOL] 🚀 Starting execution`);
|
|
37
|
-
logger.log(`[SEARCH_FILE_TOOL] - toolCallId: ${toolCallId}`);
|
|
38
|
-
logger.log(`[SEARCH_FILE_TOOL] - params:`, JSON.stringify(params));
|
|
39
|
-
logger.log(`[SEARCH_FILE_TOOL] - timestamp: ${new Date().toISOString()}`);
|
|
40
35
|
// Validate query parameter
|
|
41
36
|
if (!params.query || typeof params.query !== "string" || params.query.trim() === "") {
|
|
42
|
-
logger.error(`[SEARCH_FILE_TOOL] ❌ Missing or invalid query parameter`);
|
|
43
37
|
throw new Error("Missing required parameter: query must be a non-empty string");
|
|
44
38
|
}
|
|
45
|
-
logger.log(`[SEARCH_FILE_TOOL] 🔍 Searching for files with keyword: ${params.query}`);
|
|
46
39
|
// Get session context
|
|
47
|
-
logger.log(`[SEARCH_FILE_TOOL] 🔍 Attempting to get session context...`);
|
|
48
40
|
const sessionContext = getCurrentSessionContext();
|
|
49
41
|
if (!sessionContext) {
|
|
50
|
-
logger.error(`[SEARCH_FILE_TOOL] ❌ FAILED: No active session found!`);
|
|
51
|
-
logger.error(`[SEARCH_FILE_TOOL] - toolCallId: ${toolCallId}`);
|
|
52
42
|
throw new Error("No active XY session found. Search file tool can only be used during an active conversation.");
|
|
53
43
|
}
|
|
54
|
-
logger.log(`[SEARCH_FILE_TOOL] ✅ Session context found`);
|
|
55
|
-
logger.log(`[SEARCH_FILE_TOOL] - sessionId: ${sessionContext.sessionId}`);
|
|
56
|
-
logger.log(`[SEARCH_FILE_TOOL] - taskId: ${sessionContext.taskId}`);
|
|
57
|
-
logger.log(`[SEARCH_FILE_TOOL] - messageId: ${sessionContext.messageId}`);
|
|
58
44
|
const { config, sessionId, taskId, messageId } = sessionContext;
|
|
59
45
|
// Get WebSocket manager
|
|
60
|
-
logger.log(`[SEARCH_FILE_TOOL] 🔌 Getting WebSocket manager...`);
|
|
61
46
|
const wsManager = getXYWebSocketManager(config);
|
|
62
|
-
logger.log(`[SEARCH_FILE_TOOL] ✅ WebSocket manager obtained`);
|
|
63
47
|
// Build SearchFile command
|
|
64
|
-
logger.log(`[SEARCH_FILE_TOOL] 📦 Building SearchFile command...`);
|
|
65
48
|
const command = {
|
|
66
49
|
header: {
|
|
67
50
|
namespace: "Common",
|
|
@@ -95,27 +78,18 @@ export const searchFileTool = {
|
|
|
95
78
|
pageControlRelated: false,
|
|
96
79
|
},
|
|
97
80
|
};
|
|
98
|
-
logger.log(`[SEARCH_FILE_TOOL] 📋 Command details:`, JSON.stringify(command, null, 2));
|
|
99
81
|
// Send command and wait for response (60 second timeout)
|
|
100
|
-
logger.log(`[SEARCH_FILE_TOOL] ⏳ Setting up promise to wait for file search response...`);
|
|
101
|
-
logger.log(`[SEARCH_FILE_TOOL] - Timeout: 60 seconds`);
|
|
102
82
|
return new Promise((resolve, reject) => {
|
|
103
83
|
const timeout = setTimeout(() => {
|
|
104
|
-
logger.error(`[SEARCH_FILE_TOOL] ⏰ Timeout: No response received within 60 seconds`);
|
|
105
84
|
wsManager.off("data-event", handler);
|
|
106
85
|
reject(new Error("搜索文件超时(60秒)"));
|
|
107
86
|
}, 60000);
|
|
108
87
|
// Listen for data events from WebSocket
|
|
109
88
|
const handler = (event) => {
|
|
110
|
-
logger.log(`[SEARCH_FILE_TOOL] 📨 Received data event:`, JSON.stringify(event));
|
|
111
89
|
if (event.intentName === "SearchFile") {
|
|
112
|
-
logger.log(`[SEARCH_FILE_TOOL] 🎯 SearchFile event received`);
|
|
113
|
-
logger.log(`[SEARCH_FILE_TOOL] - status: ${event.status}`);
|
|
114
90
|
clearTimeout(timeout);
|
|
115
91
|
wsManager.off("data-event", handler);
|
|
116
92
|
if (event.status === "success" && event.outputs) {
|
|
117
|
-
logger.log(`[SEARCH_FILE_TOOL] ✅ File search completed successfully`);
|
|
118
|
-
logger.log(`[SEARCH_FILE_TOOL] - outputs:`, JSON.stringify(event.outputs));
|
|
119
93
|
// 成功,直接返回完整的 event.outputs JSON 字符串
|
|
120
94
|
resolve({
|
|
121
95
|
content: [
|
|
@@ -127,19 +101,14 @@ export const searchFileTool = {
|
|
|
127
101
|
});
|
|
128
102
|
}
|
|
129
103
|
else {
|
|
130
|
-
logger.error(`[SEARCH_FILE_TOOL] ❌ File search failed`);
|
|
131
|
-
logger.error(`[SEARCH_FILE_TOOL] - status: ${event.status}`);
|
|
132
|
-
logger.error(`[SEARCH_FILE_TOOL] - outputs:`, JSON.stringify(event.outputs || {}));
|
|
133
104
|
const errorDetail = event.outputs ? JSON.stringify(event.outputs) : event.status;
|
|
134
105
|
reject(new Error(`搜索文件失败: ${errorDetail}`));
|
|
135
106
|
}
|
|
136
107
|
}
|
|
137
108
|
};
|
|
138
109
|
// Register event handler
|
|
139
|
-
logger.log(`[SEARCH_FILE_TOOL] 📡 Registering data-event handler on WebSocket manager`);
|
|
140
110
|
wsManager.on("data-event", handler);
|
|
141
111
|
// Send the command
|
|
142
|
-
logger.log(`[SEARCH_FILE_TOOL] 📤 Sending SearchFile command...`);
|
|
143
112
|
sendCommand({
|
|
144
113
|
config,
|
|
145
114
|
sessionId,
|
|
@@ -148,10 +117,8 @@ export const searchFileTool = {
|
|
|
148
117
|
command,
|
|
149
118
|
})
|
|
150
119
|
.then(() => {
|
|
151
|
-
logger.log(`[SEARCH_FILE_TOOL] ✅ Command sent successfully, waiting for response...`);
|
|
152
120
|
})
|
|
153
121
|
.catch((error) => {
|
|
154
|
-
logger.error(`[SEARCH_FILE_TOOL] ❌ Failed to send command:`, error);
|
|
155
122
|
clearTimeout(timeout);
|
|
156
123
|
wsManager.off("data-event", handler);
|
|
157
124
|
reject(error);
|