@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.
- package/dist/index.d.ts +0 -2
- package/dist/index.js +42 -2
- package/dist/src/bot.d.ts +1 -0
- package/dist/src/bot.js +59 -61
- package/dist/src/channel.js +30 -4
- package/dist/src/client.js +0 -9
- package/dist/src/cspl/call-api.d.ts +3 -0
- package/dist/src/cspl/call-api.js +86 -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/file-upload.d.ts +5 -0
- package/dist/src/file-upload.js +88 -6
- package/dist/src/formatter.d.ts +2 -0
- package/dist/src/formatter.js +13 -30
- package/dist/src/heartbeat.js +0 -4
- package/dist/src/monitor.js +8 -10
- package/dist/src/onboarding.d.ts +3 -4
- package/dist/src/onboarding.js +2 -2
- package/dist/src/outbound.d.ts +2 -1
- package/dist/src/outbound.js +1 -19
- package/dist/src/parser.d.ts +6 -0
- package/dist/src/parser.js +16 -0
- package/dist/src/push.js +0 -21
- package/dist/src/reply-dispatcher.d.ts +4 -0
- package/dist/src/reply-dispatcher.js +46 -8
- package/dist/src/steer-injector.d.ts +16 -0
- package/dist/src/steer-injector.js +74 -0
- package/dist/src/thread-bindings.d.ts +54 -0
- package/dist/src/thread-bindings.js +214 -0
- package/dist/src/tools/calendar-tool.js +2 -37
- package/dist/src/tools/call-phone-tool.js +3 -60
- package/dist/src/tools/create-alarm-tool.js +8 -109
- package/dist/src/tools/delete-alarm-tool.js +5 -69
- package/dist/src/tools/device-tool-map.d.ts +4 -0
- package/dist/src/tools/device-tool-map.js +24 -0
- package/dist/src/tools/image-reading-tool.d.ts +5 -0
- package/dist/src/tools/image-reading-tool.js +328 -0
- package/dist/src/tools/location-tool.js +6 -40
- package/dist/src/tools/modify-alarm-tool.js +8 -114
- package/dist/src/tools/modify-note-tool.js +3 -41
- package/dist/src/tools/note-tool.js +4 -16
- package/dist/src/tools/search-alarm-tool.js +12 -118
- package/dist/src/tools/search-calendar-tool.js +4 -81
- package/dist/src/tools/search-contact-tool.js +2 -55
- package/dist/src/tools/search-file-tool.js +4 -61
- package/dist/src/tools/search-message-tool.js +2 -59
- package/dist/src/tools/search-note-tool.js +4 -22
- package/dist/src/tools/search-photo-gallery-tool.js +8 -57
- package/dist/src/tools/send-command-to-car-tool.d.ts +5 -0
- package/dist/src/tools/send-command-to-car-tool.js +85 -0
- package/dist/src/tools/send-file-to-user-tool.js +1 -39
- package/dist/src/tools/send-message-tool.js +5 -56
- package/dist/src/tools/session-manager.d.ts +1 -0
- package/dist/src/tools/session-manager.js +0 -45
- package/dist/src/tools/timestamp-to-utc8-tool.d.ts +12 -0
- package/dist/src/tools/timestamp-to-utc8-tool.js +104 -0
- 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/utils/runtime-manager.d.ts +7 -0
- package/dist/src/utils/runtime-manager.js +42 -0
- package/dist/src/websocket.js +33 -13
- package/package.json +3 -4
- package/dist/src/tools/search-photo-tool.d.ts +0 -9
- package/dist/src/tools/search-photo-tool.js +0 -270
- package/dist/src/utils/session.d.ts +0 -34
- 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
|
/**
|
|
6
5
|
* XY call phone tool - makes a phone call on user's device.
|
|
7
6
|
* Requires phoneNumber parameter and optional slotId (0 for primary SIM, 1 for secondary SIM).
|
|
@@ -9,7 +8,7 @@ import { logger } from "../utils/logger.js";
|
|
|
9
8
|
export const callPhoneTool = {
|
|
10
9
|
name: "call_phone",
|
|
11
10
|
label: "Call Phone",
|
|
12
|
-
description: "拨打电话。需要提供要拨打的电话号码。slotId参数可选,默认为0(主卡),如果用户明确要求使用副卡则设置为1。注意:操作超时时间为60
|
|
11
|
+
description: "拨打电话。需要提供要拨打的电话号码。slotId参数可选,默认为0(主卡),如果用户明确要求使用副卡则设置为1。注意:操作超时时间为60秒,请勿重复调用此工具,如果超时或失败,最多重试一次。回复约束:如果工具返回没有授权或者其他报错,只需要完整描述没有授权或者其他报错内容即可,不需要主动给用户提供解决方案,例如告诉用户如何授权,如何解决报错等都是不需要的,请严格遵守。",
|
|
13
12
|
parameters: {
|
|
14
13
|
type: "object",
|
|
15
14
|
properties: {
|
|
@@ -26,43 +25,25 @@ export const callPhoneTool = {
|
|
|
26
25
|
required: ["phoneNumber"],
|
|
27
26
|
},
|
|
28
27
|
async execute(toolCallId, params) {
|
|
29
|
-
logger.log(`[CALL_PHONE_TOOL] 🚀 Starting execution`);
|
|
30
|
-
logger.log(`[CALL_PHONE_TOOL] - toolCallId: ${toolCallId}`);
|
|
31
|
-
logger.log(`[CALL_PHONE_TOOL] - params:`, JSON.stringify(params));
|
|
32
|
-
logger.log(`[CALL_PHONE_TOOL] - timestamp: ${new Date().toISOString()}`);
|
|
33
28
|
// Validate phoneNumber parameter
|
|
34
29
|
if (!params.phoneNumber || typeof params.phoneNumber !== "string" || params.phoneNumber.trim() === "") {
|
|
35
|
-
logger.error(`[CALL_PHONE_TOOL] ❌ Missing or invalid phoneNumber parameter`);
|
|
36
30
|
throw new Error("Missing required parameter: phoneNumber must be a non-empty string");
|
|
37
31
|
}
|
|
38
32
|
// Set default slotId if not provided
|
|
39
33
|
const slotId = params.slotId !== undefined && params.slotId !== null ? params.slotId : 0;
|
|
40
34
|
// Validate slotId (must be 0 or 1)
|
|
41
35
|
if (slotId !== 0 && slotId !== 1) {
|
|
42
|
-
logger.error(`[CALL_PHONE_TOOL] ❌ Invalid slotId: ${slotId}`);
|
|
43
36
|
throw new Error("Invalid slotId: must be 0 (primary SIM) or 1 (secondary SIM)");
|
|
44
37
|
}
|
|
45
|
-
logger.log(`[CALL_PHONE_TOOL] 📞 Preparing to call phone number: ${params.phoneNumber}`);
|
|
46
|
-
logger.log(`[CALL_PHONE_TOOL] - slotId: ${slotId} (${slotId === 0 ? "主卡" : "副卡"})`);
|
|
47
38
|
// Get session context
|
|
48
|
-
logger.log(`[CALL_PHONE_TOOL] 🔍 Attempting to get session context...`);
|
|
49
39
|
const sessionContext = getCurrentSessionContext();
|
|
50
40
|
if (!sessionContext) {
|
|
51
|
-
logger.error(`[CALL_PHONE_TOOL] ❌ FAILED: No active session found!`);
|
|
52
|
-
logger.error(`[CALL_PHONE_TOOL] - toolCallId: ${toolCallId}`);
|
|
53
41
|
throw new Error("No active XY session found. Call phone tool can only be used during an active conversation.");
|
|
54
42
|
}
|
|
55
|
-
logger.log(`[CALL_PHONE_TOOL] ✅ Session context found`);
|
|
56
|
-
logger.log(`[CALL_PHONE_TOOL] - sessionId: ${sessionContext.sessionId}`);
|
|
57
|
-
logger.log(`[CALL_PHONE_TOOL] - taskId: ${sessionContext.taskId}`);
|
|
58
|
-
logger.log(`[CALL_PHONE_TOOL] - messageId: ${sessionContext.messageId}`);
|
|
59
43
|
const { config, sessionId, taskId, messageId } = sessionContext;
|
|
60
44
|
// Get WebSocket manager
|
|
61
|
-
logger.log(`[CALL_PHONE_TOOL] 🔌 Getting WebSocket manager...`);
|
|
62
45
|
const wsManager = getXYWebSocketManager(config);
|
|
63
|
-
logger.log(`[CALL_PHONE_TOOL] ✅ WebSocket manager obtained`);
|
|
64
46
|
// Build StartCall command
|
|
65
|
-
logger.log(`[CALL_PHONE_TOOL] 📦 Building StartCall command...`);
|
|
66
47
|
const command = {
|
|
67
48
|
header: {
|
|
68
49
|
namespace: "Common",
|
|
@@ -97,71 +78,35 @@ export const callPhoneTool = {
|
|
|
97
78
|
pageControlRelated: false,
|
|
98
79
|
},
|
|
99
80
|
};
|
|
100
|
-
logger.log(`[CALL_PHONE_TOOL] 📋 Command details:`, JSON.stringify(command, null, 2));
|
|
101
81
|
// Send command and wait for response (60 second timeout)
|
|
102
|
-
logger.log(`[CALL_PHONE_TOOL] ⏳ Setting up promise to wait for call response...`);
|
|
103
|
-
logger.log(`[CALL_PHONE_TOOL] - Timeout: 60 seconds`);
|
|
104
82
|
return new Promise((resolve, reject) => {
|
|
105
83
|
const timeout = setTimeout(() => {
|
|
106
|
-
logger.error(`[CALL_PHONE_TOOL] ⏰ Timeout: No response received within 60 seconds`);
|
|
107
84
|
wsManager.off("data-event", handler);
|
|
108
85
|
reject(new Error("拨打电话超时(60秒)"));
|
|
109
86
|
}, 60000);
|
|
110
87
|
// Listen for data events from WebSocket
|
|
111
88
|
const handler = (event) => {
|
|
112
|
-
logger.log(`[CALL_PHONE_TOOL] 📨 Received data event:`, JSON.stringify(event));
|
|
113
89
|
if (event.intentName === "StartCall") {
|
|
114
|
-
logger.log(`[CALL_PHONE_TOOL] 🎯 StartCall event received`);
|
|
115
|
-
logger.log(`[CALL_PHONE_TOOL] - status: ${event.status}`);
|
|
116
90
|
clearTimeout(timeout);
|
|
117
91
|
wsManager.off("data-event", handler);
|
|
118
92
|
if (event.status === "success" && event.outputs) {
|
|
119
|
-
logger.log(`[CALL_PHONE_TOOL] ✅ Call response received`);
|
|
120
|
-
logger.log(`[CALL_PHONE_TOOL] - outputs:`, JSON.stringify(event.outputs));
|
|
121
|
-
// Check for error code in outputs
|
|
122
|
-
const code = event.outputs.code !== undefined ? event.outputs.code : null;
|
|
123
|
-
if (code !== null && code !== 0) {
|
|
124
|
-
logger.error(`[CALL_PHONE_TOOL] ❌ Device returned error`);
|
|
125
|
-
logger.error(`[CALL_PHONE_TOOL] - code: ${code}`);
|
|
126
|
-
const errorMsg = event.outputs.errorMsg || event.outputs.errMsg || "未知错误";
|
|
127
|
-
logger.error(`[CALL_PHONE_TOOL] - errorMsg: ${errorMsg}`);
|
|
128
|
-
reject(new Error(`拨打电话失败: ${errorMsg} (错误代码: ${code})`));
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
// Return the outputs directly
|
|
132
|
-
const result = {
|
|
133
|
-
success: true,
|
|
134
|
-
code: code,
|
|
135
|
-
phoneNumber: params.phoneNumber,
|
|
136
|
-
slotId: slotId,
|
|
137
|
-
message: "电话拨打成功",
|
|
138
|
-
};
|
|
139
|
-
logger.log(`[CALL_PHONE_TOOL] 🎉 Call initiated successfully`);
|
|
140
|
-
logger.log(`[CALL_PHONE_TOOL] - phoneNumber: ${params.phoneNumber}`);
|
|
141
|
-
logger.log(`[CALL_PHONE_TOOL] - slotId: ${slotId}`);
|
|
142
93
|
resolve({
|
|
143
94
|
content: [
|
|
144
95
|
{
|
|
145
96
|
type: "text",
|
|
146
|
-
text: JSON.stringify(
|
|
97
|
+
text: JSON.stringify(event.outputs),
|
|
147
98
|
},
|
|
148
99
|
],
|
|
149
100
|
});
|
|
150
101
|
}
|
|
151
102
|
else {
|
|
152
|
-
|
|
153
|
-
logger.error(`[CALL_PHONE_TOOL] - status: ${event.status}`);
|
|
154
|
-
logger.error(`[CALL_PHONE_TOOL] - outputs:`, JSON.stringify(event.outputs || {}));
|
|
155
|
-
const errorDetail = event.outputs ? JSON.stringify(event.outputs) : event.status;
|
|
156
|
-
reject(new Error(`拨打电话失败: ${errorDetail}`));
|
|
103
|
+
reject(new Error(`拨打电话失败: ${event.status}`));
|
|
157
104
|
}
|
|
158
105
|
}
|
|
159
106
|
};
|
|
160
107
|
// Register event handler
|
|
161
|
-
logger.log(`[CALL_PHONE_TOOL] 📡 Registering data-event handler on WebSocket manager`);
|
|
162
108
|
wsManager.on("data-event", handler);
|
|
163
109
|
// Send the command
|
|
164
|
-
logger.log(`[CALL_PHONE_TOOL] 📤 Sending StartCall command...`);
|
|
165
110
|
sendCommand({
|
|
166
111
|
config,
|
|
167
112
|
sessionId,
|
|
@@ -170,10 +115,8 @@ export const callPhoneTool = {
|
|
|
170
115
|
command,
|
|
171
116
|
})
|
|
172
117
|
.then(() => {
|
|
173
|
-
logger.log(`[CALL_PHONE_TOOL] ✅ Command sent successfully, waiting for response...`);
|
|
174
118
|
})
|
|
175
119
|
.catch((error) => {
|
|
176
|
-
logger.error(`[CALL_PHONE_TOOL] ❌ Failed to send command:`, error);
|
|
177
120
|
clearTimeout(timeout);
|
|
178
121
|
wsManager.off("data-event", handler);
|
|
179
122
|
reject(error);
|
|
@@ -1,13 +1,12 @@
|
|
|
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 parameters
|
|
6
5
|
const ALARM_SNOOZE_DURATION_VALUES = [5, 10, 15, 20, 25, 30];
|
|
7
6
|
const ALARM_SNOOZE_TOTAL_VALUES = [0, 1, 3, 5, 10];
|
|
8
7
|
const ALARM_RING_DURATION_VALUES = [1, 5, 10, 15, 20, 30];
|
|
9
8
|
const DAYS_OF_WAKE_TYPE_VALUES = [0, 1, 2, 3, 4];
|
|
10
|
-
const DAYS_OF_WEEK_VALUES = ["Mon", "
|
|
9
|
+
const DAYS_OF_WEEK_VALUES = ["Mon", "Tues", "Wed", "Thur", "Fri", "Sat", "Sun"];
|
|
11
10
|
/**
|
|
12
11
|
* XY create alarm tool - creates an alarm on user's device.
|
|
13
12
|
* Requires alarmTime parameter. Other parameters are optional with sensible defaults.
|
|
@@ -28,11 +27,13 @@ export const createAlarmTool = {
|
|
|
28
27
|
- alarmSnoozeTotal: 再响次数,枚举值:0,1,3,5,10,默认0(表示不再响)
|
|
29
28
|
- alarmRingDuration: 响铃时长(分钟),枚举值:1,5,10,15,20,30,默认5
|
|
30
29
|
- daysOfWakeType: 闹钟响铃类型,枚举值:0=单次响铃,1=法定节假日,2=每天,3=自定义时间,4=法定工作日,默认0
|
|
31
|
-
- daysOfWeek: 自定义响铃星期,仅当daysOfWakeType=3(自定义时间)时必需且有效,其他情况不要传递此参数。数组或JSON字符串,枚举值:Mon,
|
|
30
|
+
- daysOfWeek: 自定义响铃星期,仅当daysOfWakeType=3(自定义时间)时必需且有效,其他情况不要传递此参数。数组或JSON字符串,枚举值:Mon,Tues,Wed,Thur,Fri,Sat,Sun。
|
|
32
31
|
|
|
33
32
|
注意事项:
|
|
34
33
|
a. 操作超时时间为60秒,请勿重复调用此工具,如果超时或失败,最多重试一次。
|
|
35
|
-
b.
|
|
34
|
+
b. 使用该工具之前需获取当前真实时间
|
|
35
|
+
|
|
36
|
+
回复约束:如果工具返回没有授权或者其他报错,只需要完整描述没有授权或者其他报错内容即可,不需要主动给用户提供解决方案,例如告诉用户如何授权,如何解决报错等都是不需要的,请严格遵守。`,
|
|
36
37
|
parameters: {
|
|
37
38
|
type: "object",
|
|
38
39
|
properties: {
|
|
@@ -63,176 +64,129 @@ b. 使用该工具之前需获取当前真实时间`,
|
|
|
63
64
|
daysOfWeek: {
|
|
64
65
|
// 不指定 type,允许传入数组或 JSON 字符串
|
|
65
66
|
// 具体的类型验证和转换在 execute 函数内部进行
|
|
66
|
-
description: "自定义响铃星期(仅当daysOfWakeType=3时需要,其他情况不要传递),数组或JSON字符串,枚举值:Mon,
|
|
67
|
+
description: "自定义响铃星期(仅当daysOfWakeType=3时需要,其他情况不要传递),数组或JSON字符串,枚举值:Mon,Tues,Wed,Thur,Fri,Sat,Sun。",
|
|
67
68
|
},
|
|
68
69
|
},
|
|
69
70
|
required: ["alarmTime"],
|
|
70
71
|
},
|
|
71
72
|
async execute(toolCallId, params) {
|
|
72
|
-
logger.log(`[CREATE_ALARM_TOOL] 🚀 Starting execution`);
|
|
73
|
-
logger.log(`[CREATE_ALARM_TOOL] - toolCallId: ${toolCallId}`);
|
|
74
|
-
logger.log(`[CREATE_ALARM_TOOL] - params:`, JSON.stringify(params));
|
|
75
|
-
logger.log(`[CREATE_ALARM_TOOL] - timestamp: ${new Date().toISOString()}`);
|
|
76
73
|
// ===== Validate required parameter: alarmTime =====
|
|
77
74
|
if (!params.alarmTime || typeof params.alarmTime !== "string") {
|
|
78
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Missing or invalid alarmTime`);
|
|
79
75
|
throw new Error("Missing required parameter: alarmTime must be a string in format YYYYMMDD hhmmss");
|
|
80
76
|
}
|
|
81
77
|
// Parse and convert alarmTime to timestamp
|
|
82
|
-
logger.log(`[CREATE_ALARM_TOOL] 🕒 Parsing alarmTime: ${params.alarmTime}`);
|
|
83
78
|
const alarmTimeMs = parseAlarmTimeToTimestamp(params.alarmTime);
|
|
84
79
|
if (alarmTimeMs === null) {
|
|
85
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Invalid alarmTime format`);
|
|
86
80
|
throw new Error("Invalid alarmTime format. Required format: YYYYMMDD hhmmss (e.g., 20240315 143000)");
|
|
87
81
|
}
|
|
88
|
-
logger.log(`[CREATE_ALARM_TOOL] ✅ alarmTime converted to timestamp: ${alarmTimeMs}`);
|
|
89
82
|
// ===== Validate and set optional parameters with defaults =====
|
|
90
83
|
// alarmTitle - default to "闹钟"
|
|
91
84
|
const alarmTitle = params.alarmTitle && typeof params.alarmTitle === "string"
|
|
92
85
|
? params.alarmTitle
|
|
93
86
|
: "闹钟";
|
|
94
|
-
logger.log(`[CREATE_ALARM_TOOL] - alarmTitle: ${alarmTitle}`);
|
|
95
87
|
// alarmSnoozeDuration - default 10
|
|
96
88
|
let alarmSnoozeDuration = 10;
|
|
97
89
|
if (params.alarmSnoozeDuration !== undefined && params.alarmSnoozeDuration !== null) {
|
|
98
90
|
if (typeof params.alarmSnoozeDuration !== "number") {
|
|
99
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Invalid alarmSnoozeDuration type`);
|
|
100
91
|
throw new Error("alarmSnoozeDuration must be a number");
|
|
101
92
|
}
|
|
102
93
|
if (!ALARM_SNOOZE_DURATION_VALUES.includes(params.alarmSnoozeDuration)) {
|
|
103
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Invalid alarmSnoozeDuration value: ${params.alarmSnoozeDuration}`);
|
|
104
94
|
throw new Error(`alarmSnoozeDuration must be one of: ${ALARM_SNOOZE_DURATION_VALUES.join(", ")}`);
|
|
105
95
|
}
|
|
106
96
|
alarmSnoozeDuration = params.alarmSnoozeDuration;
|
|
107
97
|
}
|
|
108
|
-
logger.log(`[CREATE_ALARM_TOOL] - alarmSnoozeDuration: ${alarmSnoozeDuration}`);
|
|
109
98
|
// alarmSnoozeTotal - default 0
|
|
110
99
|
let alarmSnoozeTotal = 0;
|
|
111
100
|
if (params.alarmSnoozeTotal !== undefined && params.alarmSnoozeTotal !== null) {
|
|
112
101
|
if (typeof params.alarmSnoozeTotal !== "number") {
|
|
113
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Invalid alarmSnoozeTotal type`);
|
|
114
102
|
throw new Error("alarmSnoozeTotal must be a number");
|
|
115
103
|
}
|
|
116
104
|
if (!ALARM_SNOOZE_TOTAL_VALUES.includes(params.alarmSnoozeTotal)) {
|
|
117
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Invalid alarmSnoozeTotal value: ${params.alarmSnoozeTotal}`);
|
|
118
105
|
throw new Error(`alarmSnoozeTotal must be one of: ${ALARM_SNOOZE_TOTAL_VALUES.join(", ")}`);
|
|
119
106
|
}
|
|
120
107
|
alarmSnoozeTotal = params.alarmSnoozeTotal;
|
|
121
108
|
}
|
|
122
|
-
logger.log(`[CREATE_ALARM_TOOL] - alarmSnoozeTotal: ${alarmSnoozeTotal}`);
|
|
123
109
|
// alarmRingDuration - default 20
|
|
124
110
|
let alarmRingDuration = 20;
|
|
125
111
|
if (params.alarmRingDuration !== undefined && params.alarmRingDuration !== null) {
|
|
126
112
|
if (typeof params.alarmRingDuration !== "number") {
|
|
127
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Invalid alarmRingDuration type`);
|
|
128
113
|
throw new Error("alarmRingDuration must be a number");
|
|
129
114
|
}
|
|
130
115
|
if (!ALARM_RING_DURATION_VALUES.includes(params.alarmRingDuration)) {
|
|
131
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Invalid alarmRingDuration value: ${params.alarmRingDuration}`);
|
|
132
116
|
throw new Error(`alarmRingDuration must be one of: ${ALARM_RING_DURATION_VALUES.join(", ")}`);
|
|
133
117
|
}
|
|
134
118
|
alarmRingDuration = params.alarmRingDuration;
|
|
135
119
|
}
|
|
136
|
-
logger.log(`[CREATE_ALARM_TOOL] - alarmRingDuration: ${alarmRingDuration}`);
|
|
137
120
|
// daysOfWakeType - default 0
|
|
138
121
|
let daysOfWakeType = 0;
|
|
139
122
|
if (params.daysOfWakeType !== undefined && params.daysOfWakeType !== null) {
|
|
140
123
|
if (typeof params.daysOfWakeType !== "number") {
|
|
141
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Invalid daysOfWakeType type`);
|
|
142
124
|
throw new Error("daysOfWakeType must be a number");
|
|
143
125
|
}
|
|
144
126
|
if (!DAYS_OF_WAKE_TYPE_VALUES.includes(params.daysOfWakeType)) {
|
|
145
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Invalid daysOfWakeType value: ${params.daysOfWakeType}`);
|
|
146
127
|
throw new Error(`daysOfWakeType must be one of: ${DAYS_OF_WAKE_TYPE_VALUES.join(", ")}`);
|
|
147
128
|
}
|
|
148
129
|
daysOfWakeType = params.daysOfWakeType;
|
|
149
130
|
}
|
|
150
|
-
logger.log(`[CREATE_ALARM_TOOL] - daysOfWakeType: ${daysOfWakeType}`);
|
|
151
131
|
// daysOfWeek - only required when daysOfWakeType is 3
|
|
152
132
|
let daysOfWeek = [];
|
|
153
133
|
if (daysOfWakeType === 3) {
|
|
154
134
|
if (!params.daysOfWeek) {
|
|
155
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Missing daysOfWeek when daysOfWakeType=3`);
|
|
156
135
|
throw new Error("daysOfWeek is required when daysOfWakeType is 3 (custom)");
|
|
157
136
|
}
|
|
158
137
|
// ===== 参数规范化:兼容数组和 JSON 字符串 =====
|
|
159
138
|
let normalizedDaysOfWeek = null;
|
|
160
139
|
// 情况1: 已经是数组
|
|
161
140
|
if (Array.isArray(params.daysOfWeek)) {
|
|
162
|
-
logger.log(`[CREATE_ALARM_TOOL] ✅ daysOfWeek is already an array`);
|
|
163
141
|
normalizedDaysOfWeek = params.daysOfWeek;
|
|
164
142
|
}
|
|
165
143
|
// 情况2: 是字符串,尝试解析为 JSON 数组
|
|
166
144
|
else if (typeof params.daysOfWeek === 'string') {
|
|
167
|
-
logger.log(`[CREATE_ALARM_TOOL] 🔄 daysOfWeek is a string, attempting to parse as JSON...`);
|
|
168
145
|
try {
|
|
169
146
|
const parsed = JSON.parse(params.daysOfWeek);
|
|
170
147
|
if (Array.isArray(parsed)) {
|
|
171
|
-
logger.log(`[CREATE_ALARM_TOOL] ✅ Successfully parsed JSON string to array`);
|
|
172
148
|
normalizedDaysOfWeek = parsed;
|
|
173
149
|
}
|
|
174
150
|
else {
|
|
175
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Parsed JSON is not an array:`, typeof parsed);
|
|
176
151
|
throw new Error("daysOfWeek must be an array or a JSON string representing an array");
|
|
177
152
|
}
|
|
178
153
|
}
|
|
179
154
|
catch (parseError) {
|
|
180
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Failed to parse daysOfWeek as JSON:`, parseError);
|
|
181
155
|
throw new Error(`daysOfWeek must be a valid JSON array string. Parse error: ${parseError instanceof Error ? parseError.message : String(parseError)}`);
|
|
182
156
|
}
|
|
183
157
|
}
|
|
184
158
|
// 情况3: 其他类型,报错
|
|
185
159
|
else {
|
|
186
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Invalid daysOfWeek type:`, typeof params.daysOfWeek);
|
|
187
160
|
throw new Error(`daysOfWeek must be an array or a JSON string, got ${typeof params.daysOfWeek}`);
|
|
188
161
|
}
|
|
189
162
|
// 验证数组非空
|
|
190
163
|
if (!normalizedDaysOfWeek || normalizedDaysOfWeek.length === 0) {
|
|
191
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ daysOfWeek array is empty`);
|
|
192
164
|
throw new Error("daysOfWeek array cannot be empty");
|
|
193
165
|
}
|
|
194
|
-
// 验证数组长度必须为1
|
|
195
|
-
if (normalizedDaysOfWeek.length !== 1) {
|
|
196
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ daysOfWeek array length must be 1, got ${normalizedDaysOfWeek.length}`);
|
|
197
|
-
throw new Error("daysOfWeek 仅支持长度为1的数组。如果需要一周中不同的几天,需要多次调用此工具");
|
|
198
|
-
}
|
|
199
166
|
// Validate each day
|
|
200
167
|
for (const day of normalizedDaysOfWeek) {
|
|
201
168
|
if (typeof day !== "string" || !DAYS_OF_WEEK_VALUES.includes(day)) {
|
|
202
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Invalid day value: ${day}`);
|
|
203
169
|
throw new Error(`daysOfWeek must contain only: ${DAYS_OF_WEEK_VALUES.join(", ")}`);
|
|
204
170
|
}
|
|
205
171
|
}
|
|
206
172
|
daysOfWeek = normalizedDaysOfWeek;
|
|
207
|
-
logger.log(`[CREATE_ALARM_TOOL] - daysOfWeek: ${daysOfWeek.join(", ")}`);
|
|
208
173
|
}
|
|
209
174
|
else {
|
|
210
175
|
// daysOfWakeType is not 3, daysOfWeek should not be provided
|
|
211
176
|
if (params.daysOfWeek) {
|
|
212
|
-
logger.warn(`[CREATE_ALARM_TOOL] ⚠️ daysOfWeek parameter is ignored when daysOfWakeType is not 3 (current: ${daysOfWakeType}). Please remove daysOfWeek parameter.`);
|
|
213
177
|
}
|
|
214
178
|
// Explicitly set to empty array
|
|
215
179
|
daysOfWeek = [];
|
|
216
180
|
}
|
|
217
181
|
// Get session context
|
|
218
|
-
logger.log(`[CREATE_ALARM_TOOL] 🔍 Attempting to get session context...`);
|
|
219
182
|
const sessionContext = getCurrentSessionContext();
|
|
220
183
|
if (!sessionContext) {
|
|
221
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ FAILED: No active session found!`);
|
|
222
|
-
logger.error(`[CREATE_ALARM_TOOL] - toolCallId: ${toolCallId}`);
|
|
223
184
|
throw new Error("No active XY session found. Create alarm tool can only be used during an active conversation.");
|
|
224
185
|
}
|
|
225
|
-
logger.log(`[CREATE_ALARM_TOOL] ✅ Session context found`);
|
|
226
|
-
logger.log(`[CREATE_ALARM_TOOL] - sessionId: ${sessionContext.sessionId}`);
|
|
227
|
-
logger.log(`[CREATE_ALARM_TOOL] - taskId: ${sessionContext.taskId}`);
|
|
228
|
-
logger.log(`[CREATE_ALARM_TOOL] - messageId: ${sessionContext.messageId}`);
|
|
229
186
|
const { config, sessionId, taskId, messageId } = sessionContext;
|
|
230
187
|
// Get WebSocket manager
|
|
231
|
-
logger.log(`[CREATE_ALARM_TOOL] 🔌 Getting WebSocket manager...`);
|
|
232
188
|
const wsManager = getXYWebSocketManager(config);
|
|
233
|
-
logger.log(`[CREATE_ALARM_TOOL] ✅ WebSocket manager obtained`);
|
|
234
189
|
// Build CreateAlarm command
|
|
235
|
-
logger.log(`[CREATE_ALARM_TOOL] 📦 Building CreateAlarm command...`);
|
|
236
190
|
// Build intentParam - only include daysOfWeek when daysOfWakeType is 3
|
|
237
191
|
const intentParam = {
|
|
238
192
|
entityName: "Alarm",
|
|
@@ -246,10 +200,8 @@ b. 使用该工具之前需获取当前真实时间`,
|
|
|
246
200
|
// Only include daysOfWeek when daysOfWakeType is 3
|
|
247
201
|
if (daysOfWakeType === 3 && daysOfWeek.length > 0) {
|
|
248
202
|
intentParam.daysOfWeek = daysOfWeek;
|
|
249
|
-
logger.log(`[CREATE_ALARM_TOOL] - Including daysOfWeek in intentParam: ${daysOfWeek.join(", ")}`);
|
|
250
203
|
}
|
|
251
204
|
else {
|
|
252
|
-
logger.log(`[CREATE_ALARM_TOOL] - Excluding daysOfWeek from intentParam (daysOfWakeType=${daysOfWakeType})`);
|
|
253
205
|
}
|
|
254
206
|
const command = {
|
|
255
207
|
header: {
|
|
@@ -283,74 +235,35 @@ b. 使用该工具之前需获取当前真实时间`,
|
|
|
283
235
|
},
|
|
284
236
|
};
|
|
285
237
|
// Send command and wait for response (60 second timeout)
|
|
286
|
-
logger.log(`[CREATE_ALARM_TOOL] ⏳ Setting up promise to wait for alarm creation response...`);
|
|
287
|
-
logger.log(`[CREATE_ALARM_TOOL] - Timeout: 60 seconds`);
|
|
288
238
|
return new Promise((resolve, reject) => {
|
|
289
239
|
const timeout = setTimeout(() => {
|
|
290
|
-
logger.error(`[CREATE_ALARM_TOOL] ⏰ Timeout: No response received within 60 seconds`);
|
|
291
240
|
wsManager.off("data-event", handler);
|
|
292
241
|
reject(new Error("创建闹钟超时(60秒)"));
|
|
293
242
|
}, 60000);
|
|
294
243
|
// Listen for data events from WebSocket
|
|
295
244
|
const handler = (event) => {
|
|
296
|
-
logger.log(`[CREATE_ALARM_TOOL] 📨 Received data event:`, JSON.stringify(event));
|
|
297
245
|
if (event.intentName === "CreateAlarm") {
|
|
298
|
-
logger.log(`[CREATE_ALARM_TOOL] 🎯 CreateAlarm event received`);
|
|
299
|
-
logger.log(`[CREATE_ALARM_TOOL] - status: ${event.status}`);
|
|
300
246
|
clearTimeout(timeout);
|
|
301
247
|
wsManager.off("data-event", handler);
|
|
302
248
|
if (event.status === "success" && event.outputs) {
|
|
303
|
-
|
|
304
|
-
logger.log(`[CREATE_ALARM_TOOL] - outputs:`, JSON.stringify(event.outputs));
|
|
305
|
-
// Check for error code in outputs
|
|
306
|
-
const code = event.outputs.code !== undefined ? event.outputs.code : null;
|
|
307
|
-
if (code !== null && code !== 0) {
|
|
308
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Device returned error`);
|
|
309
|
-
logger.error(`[CREATE_ALARM_TOOL] - code: ${code}`);
|
|
310
|
-
const errorMsg = event.outputs.errorMsg || event.outputs.errMsg || "未知错误";
|
|
311
|
-
logger.error(`[CREATE_ALARM_TOOL] - errorMsg: ${errorMsg}`);
|
|
312
|
-
reject(new Error(`创建闹钟失败: ${errorMsg} (错误代码: ${code})`));
|
|
313
|
-
return;
|
|
314
|
-
}
|
|
315
|
-
// Extract result with safe navigation
|
|
316
|
-
const result = event.outputs.result || {};
|
|
317
|
-
logger.log(`[CREATE_ALARM_TOOL] 📋 Alarm result:`, JSON.stringify(result));
|
|
249
|
+
// 成功,直接返回完整的 event.outputs JSON 字符串
|
|
318
250
|
resolve({
|
|
319
251
|
content: [
|
|
320
252
|
{
|
|
321
253
|
type: "text",
|
|
322
|
-
text: JSON.stringify(
|
|
323
|
-
success: true,
|
|
324
|
-
alarm: {
|
|
325
|
-
entityId: result.entityId,
|
|
326
|
-
entityName: result.entityName,
|
|
327
|
-
alarmTitle: result.alarmTitle,
|
|
328
|
-
alarmTime: result.alarmTime,
|
|
329
|
-
alarmState: result.alarmState,
|
|
330
|
-
alarmRingDuration: result.alarmRingDuration,
|
|
331
|
-
alarmSnoozeDuration: result.alarmSnoozeDuration,
|
|
332
|
-
alarmSnoozeTotal: result.alarmSnoozeTotal,
|
|
333
|
-
daysOfWakeType: result.daysOfWakeType,
|
|
334
|
-
},
|
|
335
|
-
code,
|
|
336
|
-
}),
|
|
254
|
+
text: JSON.stringify(event.outputs),
|
|
337
255
|
},
|
|
338
256
|
],
|
|
339
257
|
});
|
|
340
258
|
}
|
|
341
259
|
else {
|
|
342
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Alarm creation failed`);
|
|
343
|
-
logger.error(`[CREATE_ALARM_TOOL] - status: ${event.status}`);
|
|
344
|
-
logger.error(`[CREATE_ALARM_TOOL] - outputs:`, JSON.stringify(event.outputs || {}));
|
|
345
260
|
reject(new Error(`创建闹钟失败: ${event.status}`));
|
|
346
261
|
}
|
|
347
262
|
}
|
|
348
263
|
};
|
|
349
264
|
// Register event handler
|
|
350
|
-
logger.log(`[CREATE_ALARM_TOOL] 📡 Registering data-event handler on WebSocket manager`);
|
|
351
265
|
wsManager.on("data-event", handler);
|
|
352
266
|
// Send the command
|
|
353
|
-
logger.log(`[CREATE_ALARM_TOOL] 📤 Sending CreateAlarm command...`);
|
|
354
267
|
sendCommand({
|
|
355
268
|
config,
|
|
356
269
|
sessionId,
|
|
@@ -359,10 +272,8 @@ b. 使用该工具之前需获取当前真实时间`,
|
|
|
359
272
|
command,
|
|
360
273
|
})
|
|
361
274
|
.then(() => {
|
|
362
|
-
logger.log(`[CREATE_ALARM_TOOL] ✅ Command sent successfully, waiting for response...`);
|
|
363
275
|
})
|
|
364
276
|
.catch((error) => {
|
|
365
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Failed to send command:`, error);
|
|
366
277
|
clearTimeout(timeout);
|
|
367
278
|
wsManager.off("data-event", handler);
|
|
368
279
|
reject(error);
|
|
@@ -382,17 +293,14 @@ function parseAlarmTimeToTimestamp(alarmTime) {
|
|
|
382
293
|
const trimmed = alarmTime.trim();
|
|
383
294
|
// Check basic format (should have at least 13 characters: YYYYMMDD hhmmss)
|
|
384
295
|
if (trimmed.length < 13) {
|
|
385
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ alarmTime too short: ${trimmed}`);
|
|
386
296
|
return null;
|
|
387
297
|
}
|
|
388
298
|
// Extract date and time parts
|
|
389
299
|
// Format: YYYYMMDD hhmmss
|
|
390
300
|
const datePart = trimmed.substring(0, 8); // YYYYMMDD
|
|
391
301
|
const timePart = trimmed.substring(8).trim(); // hhmmss (may have leading space)
|
|
392
|
-
logger.log(`[CREATE_ALARM_TOOL] - datePart: ${datePart}, timePart: ${timePart}`);
|
|
393
302
|
// Validate lengths
|
|
394
303
|
if (datePart.length !== 8 || timePart.length !== 6) {
|
|
395
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Invalid part lengths: datePart=${datePart.length}, timePart=${timePart.length}`);
|
|
396
304
|
return null;
|
|
397
305
|
}
|
|
398
306
|
// Parse components
|
|
@@ -402,45 +310,36 @@ function parseAlarmTimeToTimestamp(alarmTime) {
|
|
|
402
310
|
const hour = parseInt(timePart.substring(0, 2), 10);
|
|
403
311
|
const minute = parseInt(timePart.substring(2, 4), 10);
|
|
404
312
|
const second = parseInt(timePart.substring(4, 6), 10);
|
|
405
|
-
logger.log(`[CREATE_ALARM_TOOL] - Parsed: ${year}-${month}-${day} ${hour}:${minute}:${second}`);
|
|
406
313
|
// Validate values
|
|
407
314
|
if (isNaN(year) || isNaN(month) || isNaN(day) ||
|
|
408
315
|
isNaN(hour) || isNaN(minute) || isNaN(second)) {
|
|
409
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ NaN detected in parsed values`);
|
|
410
316
|
return null;
|
|
411
317
|
}
|
|
412
318
|
// Validate ranges
|
|
413
319
|
if (month < 1 || month > 12) {
|
|
414
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Invalid month: ${month}`);
|
|
415
320
|
return null;
|
|
416
321
|
}
|
|
417
322
|
if (day < 1 || day > 31) {
|
|
418
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Invalid day: ${day}`);
|
|
419
323
|
return null;
|
|
420
324
|
}
|
|
421
325
|
if (hour < 0 || hour > 23) {
|
|
422
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Invalid hour: ${hour}`);
|
|
423
326
|
return null;
|
|
424
327
|
}
|
|
425
328
|
if (minute < 0 || minute > 59) {
|
|
426
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Invalid minute: ${minute}`);
|
|
427
329
|
return null;
|
|
428
330
|
}
|
|
429
331
|
if (second < 0 || second > 59) {
|
|
430
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Invalid second: ${second}`);
|
|
431
332
|
return null;
|
|
432
333
|
}
|
|
433
334
|
// Create Date object and get timestamp
|
|
434
335
|
const date = new Date(year, month - 1, day, hour, minute, second);
|
|
435
336
|
const timestamp = date.getTime();
|
|
436
337
|
if (isNaN(timestamp)) {
|
|
437
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Generated timestamp is NaN`);
|
|
438
338
|
return null;
|
|
439
339
|
}
|
|
440
340
|
return timestamp;
|
|
441
341
|
}
|
|
442
342
|
catch (error) {
|
|
443
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Exception in parseAlarmTimeToTimestamp:`, error);
|
|
444
343
|
return null;
|
|
445
344
|
}
|
|
446
345
|
}
|