@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.
Files changed (73) hide show
  1. package/dist/index.d.ts +0 -2
  2. package/dist/index.js +42 -2
  3. package/dist/src/bot.d.ts +1 -0
  4. package/dist/src/bot.js +59 -61
  5. package/dist/src/channel.js +30 -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 -30
  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/push.js +0 -21
  28. package/dist/src/reply-dispatcher.d.ts +4 -0
  29. package/dist/src/reply-dispatcher.js +46 -8
  30. package/dist/src/steer-injector.d.ts +16 -0
  31. package/dist/src/steer-injector.js +74 -0
  32. package/dist/src/thread-bindings.d.ts +54 -0
  33. package/dist/src/thread-bindings.js +214 -0
  34. package/dist/src/tools/calendar-tool.js +2 -37
  35. package/dist/src/tools/call-phone-tool.js +3 -60
  36. package/dist/src/tools/create-alarm-tool.js +8 -109
  37. package/dist/src/tools/delete-alarm-tool.js +5 -69
  38. package/dist/src/tools/device-tool-map.d.ts +4 -0
  39. package/dist/src/tools/device-tool-map.js +24 -0
  40. package/dist/src/tools/image-reading-tool.d.ts +5 -0
  41. package/dist/src/tools/image-reading-tool.js +328 -0
  42. package/dist/src/tools/location-tool.js +6 -40
  43. package/dist/src/tools/modify-alarm-tool.js +8 -114
  44. package/dist/src/tools/modify-note-tool.js +3 -41
  45. package/dist/src/tools/note-tool.js +4 -16
  46. package/dist/src/tools/search-alarm-tool.js +12 -118
  47. package/dist/src/tools/search-calendar-tool.js +4 -81
  48. package/dist/src/tools/search-contact-tool.js +2 -55
  49. package/dist/src/tools/search-file-tool.js +4 -61
  50. package/dist/src/tools/search-message-tool.js +2 -59
  51. package/dist/src/tools/search-note-tool.js +4 -22
  52. package/dist/src/tools/search-photo-gallery-tool.js +8 -57
  53. package/dist/src/tools/send-command-to-car-tool.d.ts +5 -0
  54. package/dist/src/tools/send-command-to-car-tool.js +85 -0
  55. package/dist/src/tools/send-file-to-user-tool.js +1 -39
  56. package/dist/src/tools/send-message-tool.js +5 -56
  57. package/dist/src/tools/session-manager.d.ts +1 -0
  58. package/dist/src/tools/session-manager.js +0 -45
  59. package/dist/src/tools/timestamp-to-utc8-tool.d.ts +12 -0
  60. package/dist/src/tools/timestamp-to-utc8-tool.js +104 -0
  61. package/dist/src/tools/upload-file-tool.js +0 -49
  62. package/dist/src/tools/upload-photo-tool.js +0 -42
  63. package/dist/src/tools/view-push-result-tool.js +0 -11
  64. package/dist/src/tools/xiaoyi-collection-tool.js +4 -82
  65. package/dist/src/tools/xiaoyi-gui-tool.js +0 -34
  66. package/dist/src/utils/runtime-manager.d.ts +7 -0
  67. package/dist/src/utils/runtime-manager.js +42 -0
  68. package/dist/src/websocket.js +33 -13
  69. package/package.json +3 -4
  70. package/dist/src/tools/search-photo-tool.d.ts +0 -9
  71. package/dist/src/tools/search-photo-tool.js +0 -270
  72. package/dist/src/utils/session.d.ts +0 -34
  73. 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,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
- 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
- // 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
  }