@ynhcj/xiaoyi-channel 0.0.46-beta → 0.0.46-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 +44 -2
- package/dist/src/bot.d.ts +1 -0
- package/dist/src/bot.js +47 -51
- package/dist/src/channel.js +29 -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 -28
- 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/provider.d.ts +2 -0
- package/dist/src/provider.js +80 -0
- package/dist/src/push.js +0 -21
- package/dist/src/reply-dispatcher.d.ts +4 -0
- package/dist/src/reply-dispatcher.js +46 -6
- 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 +6 -91
- package/dist/src/tools/delete-alarm-tool.js +3 -56
- package/dist/src/tools/device-tool-map.d.ts +4 -0
- package/dist/src/tools/device-tool-map.js +31 -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 +1 -32
- package/dist/src/tools/modify-alarm-tool.js +6 -94
- 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 +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 +7 -56
- 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/openclaw.plugin.json +1 -0
- 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,35 +235,17 @@ 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
|
-
logger.log(`[CREATE_ALARM_TOOL] ✅ Alarm creation completed successfully`);
|
|
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
249
|
// 成功,直接返回完整的 event.outputs JSON 字符串
|
|
316
250
|
resolve({
|
|
317
251
|
content: [
|
|
@@ -323,18 +257,13 @@ b. 使用该工具之前需获取当前真实时间`,
|
|
|
323
257
|
});
|
|
324
258
|
}
|
|
325
259
|
else {
|
|
326
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Alarm creation failed`);
|
|
327
|
-
logger.error(`[CREATE_ALARM_TOOL] - status: ${event.status}`);
|
|
328
|
-
logger.error(`[CREATE_ALARM_TOOL] - outputs:`, JSON.stringify(event.outputs || {}));
|
|
329
260
|
reject(new Error(`创建闹钟失败: ${event.status}`));
|
|
330
261
|
}
|
|
331
262
|
}
|
|
332
263
|
};
|
|
333
264
|
// Register event handler
|
|
334
|
-
logger.log(`[CREATE_ALARM_TOOL] 📡 Registering data-event handler on WebSocket manager`);
|
|
335
265
|
wsManager.on("data-event", handler);
|
|
336
266
|
// Send the command
|
|
337
|
-
logger.log(`[CREATE_ALARM_TOOL] 📤 Sending CreateAlarm command...`);
|
|
338
267
|
sendCommand({
|
|
339
268
|
config,
|
|
340
269
|
sessionId,
|
|
@@ -343,10 +272,8 @@ b. 使用该工具之前需获取当前真实时间`,
|
|
|
343
272
|
command,
|
|
344
273
|
})
|
|
345
274
|
.then(() => {
|
|
346
|
-
logger.log(`[CREATE_ALARM_TOOL] ✅ Command sent successfully, waiting for response...`);
|
|
347
275
|
})
|
|
348
276
|
.catch((error) => {
|
|
349
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Failed to send command:`, error);
|
|
350
277
|
clearTimeout(timeout);
|
|
351
278
|
wsManager.off("data-event", handler);
|
|
352
279
|
reject(error);
|
|
@@ -366,17 +293,14 @@ function parseAlarmTimeToTimestamp(alarmTime) {
|
|
|
366
293
|
const trimmed = alarmTime.trim();
|
|
367
294
|
// Check basic format (should have at least 13 characters: YYYYMMDD hhmmss)
|
|
368
295
|
if (trimmed.length < 13) {
|
|
369
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ alarmTime too short: ${trimmed}`);
|
|
370
296
|
return null;
|
|
371
297
|
}
|
|
372
298
|
// Extract date and time parts
|
|
373
299
|
// Format: YYYYMMDD hhmmss
|
|
374
300
|
const datePart = trimmed.substring(0, 8); // YYYYMMDD
|
|
375
301
|
const timePart = trimmed.substring(8).trim(); // hhmmss (may have leading space)
|
|
376
|
-
logger.log(`[CREATE_ALARM_TOOL] - datePart: ${datePart}, timePart: ${timePart}`);
|
|
377
302
|
// Validate lengths
|
|
378
303
|
if (datePart.length !== 8 || timePart.length !== 6) {
|
|
379
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Invalid part lengths: datePart=${datePart.length}, timePart=${timePart.length}`);
|
|
380
304
|
return null;
|
|
381
305
|
}
|
|
382
306
|
// Parse components
|
|
@@ -386,45 +310,36 @@ function parseAlarmTimeToTimestamp(alarmTime) {
|
|
|
386
310
|
const hour = parseInt(timePart.substring(0, 2), 10);
|
|
387
311
|
const minute = parseInt(timePart.substring(2, 4), 10);
|
|
388
312
|
const second = parseInt(timePart.substring(4, 6), 10);
|
|
389
|
-
logger.log(`[CREATE_ALARM_TOOL] - Parsed: ${year}-${month}-${day} ${hour}:${minute}:${second}`);
|
|
390
313
|
// Validate values
|
|
391
314
|
if (isNaN(year) || isNaN(month) || isNaN(day) ||
|
|
392
315
|
isNaN(hour) || isNaN(minute) || isNaN(second)) {
|
|
393
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ NaN detected in parsed values`);
|
|
394
316
|
return null;
|
|
395
317
|
}
|
|
396
318
|
// Validate ranges
|
|
397
319
|
if (month < 1 || month > 12) {
|
|
398
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Invalid month: ${month}`);
|
|
399
320
|
return null;
|
|
400
321
|
}
|
|
401
322
|
if (day < 1 || day > 31) {
|
|
402
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Invalid day: ${day}`);
|
|
403
323
|
return null;
|
|
404
324
|
}
|
|
405
325
|
if (hour < 0 || hour > 23) {
|
|
406
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Invalid hour: ${hour}`);
|
|
407
326
|
return null;
|
|
408
327
|
}
|
|
409
328
|
if (minute < 0 || minute > 59) {
|
|
410
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Invalid minute: ${minute}`);
|
|
411
329
|
return null;
|
|
412
330
|
}
|
|
413
331
|
if (second < 0 || second > 59) {
|
|
414
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Invalid second: ${second}`);
|
|
415
332
|
return null;
|
|
416
333
|
}
|
|
417
334
|
// Create Date object and get timestamp
|
|
418
335
|
const date = new Date(year, month - 1, day, hour, minute, second);
|
|
419
336
|
const timestamp = date.getTime();
|
|
420
337
|
if (isNaN(timestamp)) {
|
|
421
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Generated timestamp is NaN`);
|
|
422
338
|
return null;
|
|
423
339
|
}
|
|
424
340
|
return timestamp;
|
|
425
341
|
}
|
|
426
342
|
catch (error) {
|
|
427
|
-
logger.error(`[CREATE_ALARM_TOOL] ❌ Exception in parseAlarmTimeToTimestamp:`, error);
|
|
428
343
|
return null;
|
|
429
344
|
}
|
|
430
345
|
}
|