@ynhcj/xiaoyi-channel 0.0.26-beta → 0.0.26-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 (86) hide show
  1. package/dist/index.d.ts +0 -2
  2. package/dist/index.js +48 -2
  3. package/dist/src/bot.js +81 -28
  4. package/dist/src/channel.js +33 -7
  5. package/dist/src/client.js +11 -27
  6. package/dist/src/config.js +2 -2
  7. package/dist/src/cspl/call-api.d.ts +3 -0
  8. package/dist/src/cspl/call-api.js +107 -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 +92 -0
  17. package/dist/src/formatter.d.ts +14 -0
  18. package/dist/src/formatter.js +49 -25
  19. package/dist/src/heartbeat.js +0 -4
  20. package/dist/src/monitor.js +12 -0
  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 +52 -6
  25. package/dist/src/parser.d.ts +7 -0
  26. package/dist/src/parser.js +22 -0
  27. package/dist/src/push.d.ts +8 -1
  28. package/dist/src/push.js +30 -22
  29. package/dist/src/reply-dispatcher.js +39 -5
  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 +7 -40
  35. package/dist/src/tools/call-phone-tool.d.ts +5 -0
  36. package/dist/src/tools/call-phone-tool.js +142 -0
  37. package/dist/src/tools/create-alarm-tool.d.ts +7 -0
  38. package/dist/src/tools/create-alarm-tool.js +349 -0
  39. package/dist/src/tools/delete-alarm-tool.d.ts +11 -0
  40. package/dist/src/tools/delete-alarm-tool.js +174 -0
  41. package/dist/src/tools/image-reading-tool.d.ts +5 -0
  42. package/dist/src/tools/image-reading-tool.js +328 -0
  43. package/dist/src/tools/location-tool.js +8 -42
  44. package/dist/src/tools/modify-alarm-tool.d.ts +9 -0
  45. package/dist/src/tools/modify-alarm-tool.js +365 -0
  46. package/dist/src/tools/modify-note-tool.js +5 -43
  47. package/dist/src/tools/note-tool.js +33 -24
  48. package/dist/src/tools/search-alarm-tool.d.ts +8 -0
  49. package/dist/src/tools/search-alarm-tool.js +285 -0
  50. package/dist/src/tools/search-calendar-tool.js +10 -84
  51. package/dist/src/tools/search-contact-tool.js +4 -57
  52. package/dist/src/tools/search-file-tool.d.ts +5 -0
  53. package/dist/src/tools/search-file-tool.js +128 -0
  54. package/dist/src/tools/search-message-tool.d.ts +5 -0
  55. package/dist/src/tools/search-message-tool.js +116 -0
  56. package/dist/src/tools/search-note-tool.js +6 -24
  57. package/dist/src/tools/search-photo-gallery-tool.js +40 -61
  58. package/dist/src/tools/send-file-to-user-tool.d.ts +5 -0
  59. package/dist/src/tools/send-file-to-user-tool.js +279 -0
  60. package/dist/src/tools/send-message-tool.d.ts +5 -0
  61. package/dist/src/tools/send-message-tool.js +138 -0
  62. package/dist/src/tools/session-manager.d.ts +15 -0
  63. package/dist/src/tools/session-manager.js +43 -31
  64. package/dist/src/tools/upload-file-tool.d.ts +13 -0
  65. package/dist/src/tools/upload-file-tool.js +216 -0
  66. package/dist/src/tools/upload-photo-tool.js +2 -44
  67. package/dist/src/tools/view-push-result-tool.d.ts +5 -0
  68. package/dist/src/tools/view-push-result-tool.js +107 -0
  69. package/dist/src/tools/xiaoyi-collection-tool.d.ts +5 -0
  70. package/dist/src/tools/xiaoyi-collection-tool.js +112 -0
  71. package/dist/src/tools/xiaoyi-gui-tool.js +2 -36
  72. package/dist/src/trigger-handler.d.ts +22 -0
  73. package/dist/src/trigger-handler.js +59 -0
  74. package/dist/src/types.d.ts +1 -8
  75. package/dist/src/types.js +4 -0
  76. package/dist/src/utils/pushdata-manager.d.ts +28 -0
  77. package/dist/src/utils/pushdata-manager.js +171 -0
  78. package/dist/src/utils/pushid-manager.d.ts +12 -0
  79. package/dist/src/utils/pushid-manager.js +105 -0
  80. package/dist/src/websocket.d.ts +25 -31
  81. package/dist/src/websocket.js +233 -271
  82. package/package.json +2 -2
  83. package/dist/src/tools/search-photo-tool.d.ts +0 -9
  84. package/dist/src/tools/search-photo-tool.js +0 -270
  85. package/dist/src/utils/session.d.ts +0 -34
  86. package/dist/src/utils/session.js +0 -50
@@ -0,0 +1,142 @@
1
+ import { getXYWebSocketManager } from "../client.js";
2
+ import { sendCommand } from "../formatter.js";
3
+ import { getCurrentSessionContext } from "./session-manager.js";
4
+ /**
5
+ * XY call phone tool - makes a phone call on user's device.
6
+ * Requires phoneNumber parameter and optional slotId (0 for primary SIM, 1 for secondary SIM).
7
+ */
8
+ export const callPhoneTool = {
9
+ name: "call_phone",
10
+ label: "Call Phone",
11
+ description: "拨打电话。需要提供要拨打的电话号码。slotId参数可选,默认为0(主卡),如果用户明确要求使用副卡则设置为1。注意:操作超时时间为60秒,请勿重复调用此工具,如果超时或失败,最多重试一次。回复约束:如果工具返回没有授权或者其他报错,只需要完整描述没有授权或者其他报错内容即可,不需要主动给用户提供解决方案,例如告诉用户如何授权,如何解决报错等都是不需要的,请严格遵守。",
12
+ parameters: {
13
+ type: "object",
14
+ properties: {
15
+ phoneNumber: {
16
+ type: "string",
17
+ description: "要拨打的电话号码",
18
+ },
19
+ slotId: {
20
+ type: "number",
21
+ description: "SIM卡槽ID,默认为0(主卡),设置为1表示副卡。仅当用户明确要求使用副卡时才设置为1",
22
+ default: 0,
23
+ },
24
+ },
25
+ required: ["phoneNumber"],
26
+ },
27
+ async execute(toolCallId, params) {
28
+ // Validate phoneNumber parameter
29
+ if (!params.phoneNumber || typeof params.phoneNumber !== "string" || params.phoneNumber.trim() === "") {
30
+ throw new Error("Missing required parameter: phoneNumber must be a non-empty string");
31
+ }
32
+ // Set default slotId if not provided
33
+ const slotId = params.slotId !== undefined && params.slotId !== null ? params.slotId : 0;
34
+ // Validate slotId (must be 0 or 1)
35
+ if (slotId !== 0 && slotId !== 1) {
36
+ throw new Error("Invalid slotId: must be 0 (primary SIM) or 1 (secondary SIM)");
37
+ }
38
+ // Get session context
39
+ const sessionContext = getCurrentSessionContext();
40
+ if (!sessionContext) {
41
+ throw new Error("No active XY session found. Call phone tool can only be used during an active conversation.");
42
+ }
43
+ const { config, sessionId, taskId, messageId } = sessionContext;
44
+ // Get WebSocket manager
45
+ const wsManager = getXYWebSocketManager(config);
46
+ // Build StartCall command
47
+ const command = {
48
+ header: {
49
+ namespace: "Common",
50
+ name: "Action",
51
+ },
52
+ payload: {
53
+ cardParam: {},
54
+ executeParam: {
55
+ executeMode: "background",
56
+ intentName: "StartCall",
57
+ bundleName: "com.huawei.hmos.aidispatchservice",
58
+ dimension: "",
59
+ needUnlock: true,
60
+ actionResponse: true,
61
+ timeOut: 5,
62
+ intentParam: {
63
+ phoneNumber: params.phoneNumber.trim(),
64
+ slotId: slotId,
65
+ },
66
+ permissionId: [],
67
+ achieveType: "INTENT",
68
+ },
69
+ responses: [
70
+ {
71
+ resultCode: "",
72
+ displayText: "",
73
+ ttsText: "",
74
+ },
75
+ ],
76
+ needUploadResult: true,
77
+ noHalfPage: false,
78
+ pageControlRelated: false,
79
+ },
80
+ };
81
+ // Send command and wait for response (60 second timeout)
82
+ return new Promise((resolve, reject) => {
83
+ const timeout = setTimeout(() => {
84
+ wsManager.off("data-event", handler);
85
+ reject(new Error("拨打电话超时(60秒)"));
86
+ }, 60000);
87
+ // Listen for data events from WebSocket
88
+ const handler = (event) => {
89
+ if (event.intentName === "StartCall") {
90
+ clearTimeout(timeout);
91
+ wsManager.off("data-event", handler);
92
+ if (event.status === "success" && event.outputs) {
93
+ // Check for error code in outputs
94
+ const code = event.outputs.code !== undefined ? event.outputs.code : null;
95
+ if (code !== null && code !== 0) {
96
+ const errorMsg = event.outputs.errorMsg || event.outputs.errMsg || "未知错误";
97
+ reject(new Error(`拨打电话失败: ${errorMsg} (错误代码: ${code})`));
98
+ return;
99
+ }
100
+ // Return the outputs directly
101
+ const result = {
102
+ success: true,
103
+ code: code,
104
+ phoneNumber: params.phoneNumber,
105
+ slotId: slotId,
106
+ message: "电话拨打成功",
107
+ };
108
+ resolve({
109
+ content: [
110
+ {
111
+ type: "text",
112
+ text: JSON.stringify(result),
113
+ },
114
+ ],
115
+ });
116
+ }
117
+ else {
118
+ const errorDetail = event.outputs ? JSON.stringify(event.outputs) : event.status;
119
+ reject(new Error(`拨打电话失败: ${errorDetail}`));
120
+ }
121
+ }
122
+ };
123
+ // Register event handler
124
+ wsManager.on("data-event", handler);
125
+ // Send the command
126
+ sendCommand({
127
+ config,
128
+ sessionId,
129
+ taskId,
130
+ messageId,
131
+ command,
132
+ })
133
+ .then(() => {
134
+ })
135
+ .catch((error) => {
136
+ clearTimeout(timeout);
137
+ wsManager.off("data-event", handler);
138
+ reject(error);
139
+ });
140
+ });
141
+ },
142
+ };
@@ -0,0 +1,7 @@
1
+ /**
2
+ * XY create alarm tool - creates an alarm on user's device.
3
+ * Requires alarmTime parameter. Other parameters are optional with sensible defaults.
4
+ *
5
+ * Time format: YYYYMMDD hhmmss (e.g., 20240315 143000)
6
+ */
7
+ export declare const createAlarmTool: any;
@@ -0,0 +1,349 @@
1
+ import { getXYWebSocketManager } from "../client.js";
2
+ import { sendCommand } from "../formatter.js";
3
+ import { getCurrentSessionContext } from "./session-manager.js";
4
+ // Enum definitions for alarm parameters
5
+ const ALARM_SNOOZE_DURATION_VALUES = [5, 10, 15, 20, 25, 30];
6
+ const ALARM_SNOOZE_TOTAL_VALUES = [0, 1, 3, 5, 10];
7
+ const ALARM_RING_DURATION_VALUES = [1, 5, 10, 15, 20, 30];
8
+ const DAYS_OF_WAKE_TYPE_VALUES = [0, 1, 2, 3, 4];
9
+ const DAYS_OF_WEEK_VALUES = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
10
+ /**
11
+ * XY create alarm tool - creates an alarm on user's device.
12
+ * Requires alarmTime parameter. Other parameters are optional with sensible defaults.
13
+ *
14
+ * Time format: YYYYMMDD hhmmss (e.g., 20240315 143000)
15
+ */
16
+ export const createAlarmTool = {
17
+ name: "create_alarm",
18
+ label: "Create Alarm",
19
+ description: `在用户设备上创建闹钟。
20
+
21
+ 必需参数:
22
+ - alarmTime: 闹钟时间,格式必须为:YYYYMMDD hhmmss(例如:20240315 143000,表示2024年3月15日14:30:00)
23
+
24
+ 可选参数(针对用户没有提及的参数,如果有默认参数,则发送请求时使用默认参数):
25
+ - alarmTitle: 闹钟名称/标题,默认为"闹钟"
26
+ - alarmSnoozeDuration: 小睡间隔(分钟),枚举值:5,10,15,20,25,30,默认10
27
+ - alarmSnoozeTotal: 再响次数,枚举值:0,1,3,5,10,默认0(表示不再响)
28
+ - alarmRingDuration: 响铃时长(分钟),枚举值:1,5,10,15,20,30,默认5
29
+ - daysOfWakeType: 闹钟响铃类型,枚举值:0=单次响铃,1=法定节假日,2=每天,3=自定义时间,4=法定工作日,默认0
30
+ - daysOfWeek: 自定义响铃星期,仅当daysOfWakeType=3(自定义时间)时必需且有效,其他情况不要传递此参数。数组或JSON字符串,枚举值:Mon,Tue,Wed,Thu,Fri,Sat,Sun。注意:仅支持长度为1的数组,如果需要一周中不同的几天,需要多次调用此工具
31
+
32
+ 注意事项:
33
+ a. 操作超时时间为60秒,请勿重复调用此工具,如果超时或失败,最多重试一次。
34
+ b. 使用该工具之前需获取当前真实时间
35
+
36
+ 回复约束:如果工具返回没有授权或者其他报错,只需要完整描述没有授权或者其他报错内容即可,不需要主动给用户提供解决方案,例如告诉用户如何授权,如何解决报错等都是不需要的,请严格遵守。`,
37
+ parameters: {
38
+ type: "object",
39
+ properties: {
40
+ alarmTime: {
41
+ type: "string",
42
+ description: "闹钟时间,格式必须为:YYYYMMDD hhmmss(例如:20240315 143000)",
43
+ },
44
+ alarmTitle: {
45
+ type: "string",
46
+ description: "闹钟名称/标题,默认为'闹钟'",
47
+ },
48
+ alarmSnoozeDuration: {
49
+ type: "number",
50
+ description: "小睡间隔(分钟),枚举值:5,10,15,20,25,30,默认10",
51
+ },
52
+ alarmSnoozeTotal: {
53
+ type: "number",
54
+ description: "再响次数,枚举值:0,1,3,5,10,默认0",
55
+ },
56
+ alarmRingDuration: {
57
+ type: "number",
58
+ description: "响铃时长(分钟),枚举值:1,5,10,15,20,30,默认5",
59
+ },
60
+ daysOfWakeType: {
61
+ type: "number",
62
+ description: "闹钟响铃类型:0=单次,1=法定节假日,2=每天,3=自定义,4=法定工作日,默认0",
63
+ },
64
+ daysOfWeek: {
65
+ // 不指定 type,允许传入数组或 JSON 字符串
66
+ // 具体的类型验证和转换在 execute 函数内部进行
67
+ description: "自定义响铃星期(仅当daysOfWakeType=3时需要,其他情况不要传递),数组或JSON字符串,枚举值:Mon,Tue,Wed,Thu,Fri,Sat,Sun。注意:仅支持长度为1的数组,如果需要一周中不同的几天,需要多次调用此工具",
68
+ },
69
+ },
70
+ required: ["alarmTime"],
71
+ },
72
+ async execute(toolCallId, params) {
73
+ // ===== Validate required parameter: alarmTime =====
74
+ if (!params.alarmTime || typeof params.alarmTime !== "string") {
75
+ throw new Error("Missing required parameter: alarmTime must be a string in format YYYYMMDD hhmmss");
76
+ }
77
+ // Parse and convert alarmTime to timestamp
78
+ const alarmTimeMs = parseAlarmTimeToTimestamp(params.alarmTime);
79
+ if (alarmTimeMs === null) {
80
+ throw new Error("Invalid alarmTime format. Required format: YYYYMMDD hhmmss (e.g., 20240315 143000)");
81
+ }
82
+ // ===== Validate and set optional parameters with defaults =====
83
+ // alarmTitle - default to "闹钟"
84
+ const alarmTitle = params.alarmTitle && typeof params.alarmTitle === "string"
85
+ ? params.alarmTitle
86
+ : "闹钟";
87
+ // alarmSnoozeDuration - default 10
88
+ let alarmSnoozeDuration = 10;
89
+ if (params.alarmSnoozeDuration !== undefined && params.alarmSnoozeDuration !== null) {
90
+ if (typeof params.alarmSnoozeDuration !== "number") {
91
+ throw new Error("alarmSnoozeDuration must be a number");
92
+ }
93
+ if (!ALARM_SNOOZE_DURATION_VALUES.includes(params.alarmSnoozeDuration)) {
94
+ throw new Error(`alarmSnoozeDuration must be one of: ${ALARM_SNOOZE_DURATION_VALUES.join(", ")}`);
95
+ }
96
+ alarmSnoozeDuration = params.alarmSnoozeDuration;
97
+ }
98
+ // alarmSnoozeTotal - default 0
99
+ let alarmSnoozeTotal = 0;
100
+ if (params.alarmSnoozeTotal !== undefined && params.alarmSnoozeTotal !== null) {
101
+ if (typeof params.alarmSnoozeTotal !== "number") {
102
+ throw new Error("alarmSnoozeTotal must be a number");
103
+ }
104
+ if (!ALARM_SNOOZE_TOTAL_VALUES.includes(params.alarmSnoozeTotal)) {
105
+ throw new Error(`alarmSnoozeTotal must be one of: ${ALARM_SNOOZE_TOTAL_VALUES.join(", ")}`);
106
+ }
107
+ alarmSnoozeTotal = params.alarmSnoozeTotal;
108
+ }
109
+ // alarmRingDuration - default 20
110
+ let alarmRingDuration = 20;
111
+ if (params.alarmRingDuration !== undefined && params.alarmRingDuration !== null) {
112
+ if (typeof params.alarmRingDuration !== "number") {
113
+ throw new Error("alarmRingDuration must be a number");
114
+ }
115
+ if (!ALARM_RING_DURATION_VALUES.includes(params.alarmRingDuration)) {
116
+ throw new Error(`alarmRingDuration must be one of: ${ALARM_RING_DURATION_VALUES.join(", ")}`);
117
+ }
118
+ alarmRingDuration = params.alarmRingDuration;
119
+ }
120
+ // daysOfWakeType - default 0
121
+ let daysOfWakeType = 0;
122
+ if (params.daysOfWakeType !== undefined && params.daysOfWakeType !== null) {
123
+ if (typeof params.daysOfWakeType !== "number") {
124
+ throw new Error("daysOfWakeType must be a number");
125
+ }
126
+ if (!DAYS_OF_WAKE_TYPE_VALUES.includes(params.daysOfWakeType)) {
127
+ throw new Error(`daysOfWakeType must be one of: ${DAYS_OF_WAKE_TYPE_VALUES.join(", ")}`);
128
+ }
129
+ daysOfWakeType = params.daysOfWakeType;
130
+ }
131
+ // daysOfWeek - only required when daysOfWakeType is 3
132
+ let daysOfWeek = [];
133
+ if (daysOfWakeType === 3) {
134
+ if (!params.daysOfWeek) {
135
+ throw new Error("daysOfWeek is required when daysOfWakeType is 3 (custom)");
136
+ }
137
+ // ===== 参数规范化:兼容数组和 JSON 字符串 =====
138
+ let normalizedDaysOfWeek = null;
139
+ // 情况1: 已经是数组
140
+ if (Array.isArray(params.daysOfWeek)) {
141
+ normalizedDaysOfWeek = params.daysOfWeek;
142
+ }
143
+ // 情况2: 是字符串,尝试解析为 JSON 数组
144
+ else if (typeof params.daysOfWeek === 'string') {
145
+ try {
146
+ const parsed = JSON.parse(params.daysOfWeek);
147
+ if (Array.isArray(parsed)) {
148
+ normalizedDaysOfWeek = parsed;
149
+ }
150
+ else {
151
+ throw new Error("daysOfWeek must be an array or a JSON string representing an array");
152
+ }
153
+ }
154
+ catch (parseError) {
155
+ throw new Error(`daysOfWeek must be a valid JSON array string. Parse error: ${parseError instanceof Error ? parseError.message : String(parseError)}`);
156
+ }
157
+ }
158
+ // 情况3: 其他类型,报错
159
+ else {
160
+ throw new Error(`daysOfWeek must be an array or a JSON string, got ${typeof params.daysOfWeek}`);
161
+ }
162
+ // 验证数组非空
163
+ if (!normalizedDaysOfWeek || normalizedDaysOfWeek.length === 0) {
164
+ throw new Error("daysOfWeek array cannot be empty");
165
+ }
166
+ // 验证数组长度必须为1
167
+ if (normalizedDaysOfWeek.length !== 1) {
168
+ throw new Error("daysOfWeek 仅支持长度为1的数组。如果需要一周中不同的几天,需要多次调用此工具");
169
+ }
170
+ // Validate each day
171
+ for (const day of normalizedDaysOfWeek) {
172
+ if (typeof day !== "string" || !DAYS_OF_WEEK_VALUES.includes(day)) {
173
+ throw new Error(`daysOfWeek must contain only: ${DAYS_OF_WEEK_VALUES.join(", ")}`);
174
+ }
175
+ }
176
+ daysOfWeek = normalizedDaysOfWeek;
177
+ }
178
+ else {
179
+ // daysOfWakeType is not 3, daysOfWeek should not be provided
180
+ if (params.daysOfWeek) {
181
+ }
182
+ // Explicitly set to empty array
183
+ daysOfWeek = [];
184
+ }
185
+ // Get session context
186
+ const sessionContext = getCurrentSessionContext();
187
+ if (!sessionContext) {
188
+ throw new Error("No active XY session found. Create alarm tool can only be used during an active conversation.");
189
+ }
190
+ const { config, sessionId, taskId, messageId } = sessionContext;
191
+ // Get WebSocket manager
192
+ const wsManager = getXYWebSocketManager(config);
193
+ // Build CreateAlarm command
194
+ // Build intentParam - only include daysOfWeek when daysOfWakeType is 3
195
+ const intentParam = {
196
+ entityName: "Alarm",
197
+ alarmTime: alarmTimeMs,
198
+ alarmTitle: alarmTitle,
199
+ alarmSnoozeDuration: alarmSnoozeDuration,
200
+ alarmSnoozeTotal: alarmSnoozeTotal,
201
+ alarmRingDuration: alarmRingDuration,
202
+ daysOfWakeType: daysOfWakeType,
203
+ };
204
+ // Only include daysOfWeek when daysOfWakeType is 3
205
+ if (daysOfWakeType === 3 && daysOfWeek.length > 0) {
206
+ intentParam.daysOfWeek = daysOfWeek;
207
+ }
208
+ else {
209
+ }
210
+ const command = {
211
+ header: {
212
+ namespace: "Common",
213
+ name: "Action",
214
+ },
215
+ payload: {
216
+ cardParam: {},
217
+ executeParam: {
218
+ executeMode: "background",
219
+ intentName: "CreateAlarm",
220
+ bundleName: "com.huawei.hmos.clock",
221
+ needUnlock: true,
222
+ actionResponse: true,
223
+ appType: "OHOS_APP",
224
+ timeOut: 5,
225
+ intentParam: intentParam,
226
+ permissionId: [],
227
+ achieveType: "INTENT",
228
+ },
229
+ responses: [
230
+ {
231
+ resultCode: "",
232
+ displayText: "",
233
+ ttsText: "",
234
+ },
235
+ ],
236
+ needUploadResult: true,
237
+ noHalfPage: false,
238
+ pageControlRelated: false,
239
+ },
240
+ };
241
+ // Send command and wait for response (60 second timeout)
242
+ return new Promise((resolve, reject) => {
243
+ const timeout = setTimeout(() => {
244
+ wsManager.off("data-event", handler);
245
+ reject(new Error("创建闹钟超时(60秒)"));
246
+ }, 60000);
247
+ // Listen for data events from WebSocket
248
+ const handler = (event) => {
249
+ if (event.intentName === "CreateAlarm") {
250
+ clearTimeout(timeout);
251
+ wsManager.off("data-event", handler);
252
+ if (event.status === "success" && event.outputs) {
253
+ // 成功,直接返回完整的 event.outputs JSON 字符串
254
+ resolve({
255
+ content: [
256
+ {
257
+ type: "text",
258
+ text: JSON.stringify(event.outputs),
259
+ },
260
+ ],
261
+ });
262
+ }
263
+ else {
264
+ reject(new Error(`创建闹钟失败: ${event.status}`));
265
+ }
266
+ }
267
+ };
268
+ // Register event handler
269
+ wsManager.on("data-event", handler);
270
+ // Send the command
271
+ sendCommand({
272
+ config,
273
+ sessionId,
274
+ taskId,
275
+ messageId,
276
+ command,
277
+ })
278
+ .then(() => {
279
+ })
280
+ .catch((error) => {
281
+ clearTimeout(timeout);
282
+ wsManager.off("data-event", handler);
283
+ reject(error);
284
+ });
285
+ });
286
+ },
287
+ };
288
+ /**
289
+ * Parse alarmTime string (YYYYMMDD hhmmss) to timestamp in milliseconds
290
+ * @param alarmTime - Time string in format "YYYYMMDD hhmmss" (e.g., "20240315 143000")
291
+ * @returns Timestamp in milliseconds, or null if parsing fails
292
+ */
293
+ function parseAlarmTimeToTimestamp(alarmTime) {
294
+ try {
295
+ // Expected format: YYYYMMDD hhmmss
296
+ // Example: 20240315 143000
297
+ const trimmed = alarmTime.trim();
298
+ // Check basic format (should have at least 13 characters: YYYYMMDD hhmmss)
299
+ if (trimmed.length < 13) {
300
+ return null;
301
+ }
302
+ // Extract date and time parts
303
+ // Format: YYYYMMDD hhmmss
304
+ const datePart = trimmed.substring(0, 8); // YYYYMMDD
305
+ const timePart = trimmed.substring(8).trim(); // hhmmss (may have leading space)
306
+ // Validate lengths
307
+ if (datePart.length !== 8 || timePart.length !== 6) {
308
+ return null;
309
+ }
310
+ // Parse components
311
+ const year = parseInt(datePart.substring(0, 4), 10);
312
+ const month = parseInt(datePart.substring(4, 6), 10);
313
+ const day = parseInt(datePart.substring(6, 8), 10);
314
+ const hour = parseInt(timePart.substring(0, 2), 10);
315
+ const minute = parseInt(timePart.substring(2, 4), 10);
316
+ const second = parseInt(timePart.substring(4, 6), 10);
317
+ // Validate values
318
+ if (isNaN(year) || isNaN(month) || isNaN(day) ||
319
+ isNaN(hour) || isNaN(minute) || isNaN(second)) {
320
+ return null;
321
+ }
322
+ // Validate ranges
323
+ if (month < 1 || month > 12) {
324
+ return null;
325
+ }
326
+ if (day < 1 || day > 31) {
327
+ return null;
328
+ }
329
+ if (hour < 0 || hour > 23) {
330
+ return null;
331
+ }
332
+ if (minute < 0 || minute > 59) {
333
+ return null;
334
+ }
335
+ if (second < 0 || second > 59) {
336
+ return null;
337
+ }
338
+ // Create Date object and get timestamp
339
+ const date = new Date(year, month - 1, day, hour, minute, second);
340
+ const timestamp = date.getTime();
341
+ if (isNaN(timestamp)) {
342
+ return null;
343
+ }
344
+ return timestamp;
345
+ }
346
+ catch (error) {
347
+ return null;
348
+ }
349
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * XY delete alarm tool - deletes existing alarms on user's device.
3
+ * Requires entityId(s) from search_alarm or create_alarm tool as prerequisite.
4
+ *
5
+ * Prerequisites:
6
+ * 1. Call search_alarm or create_alarm tool first to get entityId(s) of alarms
7
+ * 2. Use the entityId(s) to delete those alarms
8
+ *
9
+ * Supports deleting single or multiple alarms in one call.
10
+ */
11
+ export declare const deleteAlarmTool: any;
@@ -0,0 +1,174 @@
1
+ import { getXYWebSocketManager } from "../client.js";
2
+ import { sendCommand } from "../formatter.js";
3
+ import { getCurrentSessionContext } from "./session-manager.js";
4
+ /**
5
+ * XY delete alarm tool - deletes existing alarms on user's device.
6
+ * Requires entityId(s) from search_alarm or create_alarm tool as prerequisite.
7
+ *
8
+ * Prerequisites:
9
+ * 1. Call search_alarm or create_alarm tool first to get entityId(s) of alarms
10
+ * 2. Use the entityId(s) to delete those alarms
11
+ *
12
+ * Supports deleting single or multiple alarms in one call.
13
+ */
14
+ export const deleteAlarmTool = {
15
+ name: "delete_alarm",
16
+ label: "Delete Alarm",
17
+ description: `删除用户设备上的闹钟。使用前必须先调用 search_alarm 或 create_alarm 工具获取闹钟的 entityId。
18
+
19
+ 工具参数:
20
+ - items: 要删除的闹钟列表,每个元素包含 entityId 字段。支持数组或 JSON 字符串格式。entityId 是闹钟的唯一标识符(从 search_alarm 或 create_alarm 工具获取)。
21
+
22
+ 使用示例:
23
+ - 删除单个闹钟:{"items": [{"entityId": "6"}]}
24
+ - 删除多个闹钟:{"items": [{"entityId": "6"}, {"entityId": "8"}]}
25
+
26
+ 注意事项:
27
+ 1. 操作超时时间为60秒,请勿重复调用此工具,如果超时或失败,最多重试一次。
28
+ 2. 删除操作不可撤销,请确认 entityId 正确后再删除。
29
+ 3. items 参数支持数组或 JSON 字符串格式,代码会自动解析。
30
+
31
+ 回复约束:如果工具返回没有授权或者其他报错,只需要完整描述没有授权或者其他报错内容即可,不需要主动给用户提供解决方案,例如告诉用户如何授权,如何解决报错等都是不需要的,请严格遵守。`,
32
+ parameters: {
33
+ type: "object",
34
+ properties: {
35
+ items: {
36
+ // 不指定 type,允许传入数组或 JSON 字符串
37
+ // 具体的类型验证和转换在 execute 函数内部进行
38
+ description: "要删除的闹钟列表,每个元素包含 entityId 字段。支持数组或 JSON 字符串格式。",
39
+ },
40
+ },
41
+ required: ["items"],
42
+ },
43
+ async execute(toolCallId, params) {
44
+ // ===== 参数规范化:兼容数组和 JSON 字符串 =====
45
+ let items = null;
46
+ if (!params.items) {
47
+ throw new Error("Missing required parameter: items");
48
+ }
49
+ // 情况1: 已经是数组
50
+ if (Array.isArray(params.items)) {
51
+ items = params.items;
52
+ }
53
+ // 情况2: 是字符串,尝试解析为 JSON 数组
54
+ else if (typeof params.items === 'string') {
55
+ try {
56
+ const parsed = JSON.parse(params.items);
57
+ if (Array.isArray(parsed)) {
58
+ items = parsed;
59
+ }
60
+ else {
61
+ throw new Error("items must be an array or a JSON string representing an array");
62
+ }
63
+ }
64
+ catch (parseError) {
65
+ throw new Error(`items must be a valid JSON array string. Parse error: ${parseError instanceof Error ? parseError.message : String(parseError)}`);
66
+ }
67
+ }
68
+ // 情况3: 其他类型,报错
69
+ else {
70
+ throw new Error(`items must be an array or a JSON string, got ${typeof params.items}`);
71
+ }
72
+ // 验证数组非空
73
+ if (!items || items.length === 0) {
74
+ throw new Error("items array cannot be empty");
75
+ }
76
+ // 验证每个 item 是否有有效的 entityId
77
+ for (let i = 0; i < items.length; i++) {
78
+ const item = items[i];
79
+ if (!item || typeof item !== 'object') {
80
+ throw new Error(`items[${i}] must be an object with entityId property`);
81
+ }
82
+ if (!item.entityId || typeof item.entityId !== 'string') {
83
+ throw new Error(`items[${i}] must have a valid entityId string property`);
84
+ }
85
+ }
86
+ // Get session context
87
+ const sessionContext = getCurrentSessionContext();
88
+ if (!sessionContext) {
89
+ throw new Error("No active XY session found. Delete alarm tool can only be used during an active conversation.");
90
+ }
91
+ const { config, sessionId, taskId, messageId } = sessionContext;
92
+ // Get WebSocket manager
93
+ const wsManager = getXYWebSocketManager(config);
94
+ // Build DeleteAlarm command
95
+ const command = {
96
+ header: {
97
+ namespace: "Common",
98
+ name: "Action",
99
+ },
100
+ payload: {
101
+ cardParam: {},
102
+ executeParam: {
103
+ executeMode: "background",
104
+ intentName: "DeleteAlarm",
105
+ bundleName: "com.huawei.hmos.clock",
106
+ needUnlock: true,
107
+ actionResponse: true,
108
+ appType: "OHOS_APP",
109
+ timeOut: 5,
110
+ intentParam: {
111
+ items: items,
112
+ },
113
+ permissionId: [],
114
+ achieveType: "INTENT",
115
+ },
116
+ responses: [
117
+ {
118
+ resultCode: "",
119
+ displayText: "",
120
+ ttsText: "",
121
+ },
122
+ ],
123
+ needUploadResult: true,
124
+ noHalfPage: false,
125
+ pageControlRelated: false,
126
+ },
127
+ };
128
+ // Send command and wait for response (60 second timeout)
129
+ return new Promise((resolve, reject) => {
130
+ const timeout = setTimeout(() => {
131
+ wsManager.off("data-event", handler);
132
+ reject(new Error("删除闹钟超时(60秒)"));
133
+ }, 60000);
134
+ // Listen for data events from WebSocket
135
+ const handler = (event) => {
136
+ if (event.intentName === "DeleteAlarm") {
137
+ clearTimeout(timeout);
138
+ wsManager.off("data-event", handler);
139
+ if (event.status === "success" && event.outputs) {
140
+ // 成功,直接返回完整的 event.outputs JSON 字符串
141
+ resolve({
142
+ content: [
143
+ {
144
+ type: "text",
145
+ text: JSON.stringify(event.outputs),
146
+ },
147
+ ],
148
+ });
149
+ }
150
+ else {
151
+ reject(new Error(`删除闹钟失败: ${event.status}`));
152
+ }
153
+ }
154
+ };
155
+ // Register event handler
156
+ wsManager.on("data-event", handler);
157
+ // Send the command
158
+ sendCommand({
159
+ config,
160
+ sessionId,
161
+ taskId,
162
+ messageId,
163
+ command,
164
+ })
165
+ .then(() => {
166
+ })
167
+ .catch((error) => {
168
+ clearTimeout(timeout);
169
+ wsManager.off("data-event", handler);
170
+ reject(error);
171
+ });
172
+ });
173
+ },
174
+ };