@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.
Files changed (76) hide show
  1. package/dist/index.d.ts +0 -2
  2. package/dist/index.js +44 -2
  3. package/dist/src/bot.d.ts +1 -0
  4. package/dist/src/bot.js +47 -51
  5. package/dist/src/channel.js +29 -4
  6. package/dist/src/client.js +0 -9
  7. package/dist/src/cspl/call-api.d.ts +3 -0
  8. package/dist/src/cspl/call-api.js +86 -0
  9. package/dist/src/cspl/config.d.ts +19 -0
  10. package/dist/src/cspl/config.js +50 -0
  11. package/dist/src/cspl/constants.d.ts +43 -0
  12. package/dist/src/cspl/constants.js +22 -0
  13. package/dist/src/cspl/utils.d.ts +10 -0
  14. package/dist/src/cspl/utils.js +57 -0
  15. package/dist/src/file-upload.d.ts +5 -0
  16. package/dist/src/file-upload.js +88 -6
  17. package/dist/src/formatter.d.ts +2 -0
  18. package/dist/src/formatter.js +13 -28
  19. package/dist/src/heartbeat.js +0 -4
  20. package/dist/src/monitor.js +8 -10
  21. package/dist/src/onboarding.d.ts +3 -4
  22. package/dist/src/onboarding.js +2 -2
  23. package/dist/src/outbound.d.ts +2 -1
  24. package/dist/src/outbound.js +1 -19
  25. package/dist/src/parser.d.ts +6 -0
  26. package/dist/src/parser.js +16 -0
  27. package/dist/src/provider.d.ts +2 -0
  28. package/dist/src/provider.js +80 -0
  29. package/dist/src/push.js +0 -21
  30. package/dist/src/reply-dispatcher.d.ts +4 -0
  31. package/dist/src/reply-dispatcher.js +46 -6
  32. package/dist/src/steer-injector.d.ts +16 -0
  33. package/dist/src/steer-injector.js +74 -0
  34. package/dist/src/thread-bindings.d.ts +54 -0
  35. package/dist/src/thread-bindings.js +214 -0
  36. package/dist/src/tools/calendar-tool.js +2 -37
  37. package/dist/src/tools/call-phone-tool.js +3 -60
  38. package/dist/src/tools/create-alarm-tool.js +6 -91
  39. package/dist/src/tools/delete-alarm-tool.js +3 -56
  40. package/dist/src/tools/device-tool-map.d.ts +4 -0
  41. package/dist/src/tools/device-tool-map.js +31 -0
  42. package/dist/src/tools/image-reading-tool.d.ts +5 -0
  43. package/dist/src/tools/image-reading-tool.js +328 -0
  44. package/dist/src/tools/location-tool.js +1 -32
  45. package/dist/src/tools/modify-alarm-tool.js +6 -94
  46. package/dist/src/tools/modify-note-tool.js +1 -34
  47. package/dist/src/tools/note-tool.js +2 -4
  48. package/dist/src/tools/search-alarm-tool.js +12 -118
  49. package/dist/src/tools/search-calendar-tool.js +4 -81
  50. package/dist/src/tools/search-contact-tool.js +2 -55
  51. package/dist/src/tools/search-file-tool.js +4 -61
  52. package/dist/src/tools/search-message-tool.js +2 -59
  53. package/dist/src/tools/search-note-tool.js +4 -22
  54. package/dist/src/tools/search-photo-gallery-tool.js +7 -56
  55. package/dist/src/tools/send-command-to-car-tool.d.ts +5 -0
  56. package/dist/src/tools/send-command-to-car-tool.js +85 -0
  57. package/dist/src/tools/send-file-to-user-tool.js +1 -39
  58. package/dist/src/tools/send-message-tool.js +5 -56
  59. package/dist/src/tools/session-manager.d.ts +1 -0
  60. package/dist/src/tools/session-manager.js +0 -45
  61. package/dist/src/tools/timestamp-to-utc8-tool.d.ts +12 -0
  62. package/dist/src/tools/timestamp-to-utc8-tool.js +104 -0
  63. package/dist/src/tools/upload-file-tool.js +0 -49
  64. package/dist/src/tools/upload-photo-tool.js +0 -42
  65. package/dist/src/tools/view-push-result-tool.js +0 -11
  66. package/dist/src/tools/xiaoyi-collection-tool.js +4 -82
  67. package/dist/src/tools/xiaoyi-gui-tool.js +0 -34
  68. package/dist/src/utils/runtime-manager.d.ts +7 -0
  69. package/dist/src/utils/runtime-manager.js +42 -0
  70. package/dist/src/websocket.js +33 -13
  71. package/openclaw.plugin.json +1 -0
  72. package/package.json +3 -4
  73. package/dist/src/tools/search-photo-tool.d.ts +0 -9
  74. package/dist/src/tools/search-photo-tool.js +0 -270
  75. package/dist/src/utils/session.d.ts +0 -34
  76. 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(result),
97
+ text: JSON.stringify(event.outputs),
147
98
  },
148
99
  ],
149
100
  });
150
101
  }
151
102
  else {
152
- logger.error(`[CALL_PHONE_TOOL] Call failed`);
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", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
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,Tue,Wed,Thu,Fri,Sat,Sun。注意:仅支持长度为1的数组,如果需要一周中不同的几天,需要多次调用此工具
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,Tue,Wed,Thu,Fri,Sat,Sun。注意:仅支持长度为1的数组,如果需要一周中不同的几天,需要多次调用此工具",
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
  }