@ynhcj/xiaoyi-channel 0.0.87-beta → 0.0.87-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 +6 -9
- package/dist/index.js +26 -21
- package/dist/src/bot.js +26 -3
- package/dist/src/channel.js +2 -30
- package/dist/src/client.js +7 -1
- package/dist/src/login-token-handler.d.ts +8 -0
- package/dist/src/login-token-handler.js +60 -0
- package/dist/src/message-queue.d.ts +17 -0
- package/dist/src/message-queue.js +51 -0
- package/dist/src/monitor.js +64 -4
- package/dist/src/provider.d.ts +2 -1
- package/dist/src/provider.js +440 -31
- package/dist/src/reply-dispatcher.js +6 -0
- package/dist/src/runtime.d.ts +3 -11
- package/dist/src/runtime.js +6 -18
- package/dist/src/self-evolution-handler.d.ts +7 -0
- package/dist/src/self-evolution-handler.js +140 -0
- package/dist/src/self-evolution-keyword.d.ts +9 -0
- package/dist/src/self-evolution-keyword.js +147 -0
- package/dist/src/self-evolution-tool-result-nudge.d.ts +3 -0
- package/dist/src/self-evolution-tool-result-nudge.js +96 -0
- package/dist/src/skill-retriever/config.d.ts +4 -0
- package/dist/src/skill-retriever/config.js +23 -0
- package/dist/src/skill-retriever/hooks.d.ts +22 -0
- package/dist/src/skill-retriever/hooks.js +82 -0
- package/dist/src/skill-retriever/tool-search.d.ts +16 -0
- package/dist/src/skill-retriever/tool-search.js +172 -0
- package/dist/src/skill-retriever/types.d.ts +36 -0
- package/dist/src/skill-retriever/types.js +1 -0
- package/dist/src/task-manager.d.ts +4 -0
- package/dist/src/task-manager.js +12 -1
- package/dist/src/tools/calendar-tool.d.ts +2 -1
- package/dist/src/tools/calendar-tool.js +112 -116
- package/dist/src/tools/call-device-tool.d.ts +6 -0
- package/dist/src/tools/call-device-tool.js +153 -0
- package/dist/src/tools/call-phone-tool.d.ts +2 -1
- package/dist/src/tools/call-phone-tool.js +109 -113
- package/dist/src/tools/create-alarm-tool.d.ts +2 -1
- package/dist/src/tools/create-alarm-tool.js +227 -231
- package/dist/src/tools/create-all-tools.d.ts +16 -0
- package/dist/src/tools/create-all-tools.js +50 -0
- package/dist/src/tools/delete-alarm-tool.d.ts +2 -1
- package/dist/src/tools/delete-alarm-tool.js +131 -135
- package/dist/src/tools/device-tool-map.js +2 -0
- package/dist/src/tools/get-alarm-tool-schema.d.ts +17 -0
- package/dist/src/tools/get-alarm-tool-schema.js +17 -0
- package/dist/src/tools/get-calendar-tool-schema.d.ts +17 -0
- package/dist/src/tools/get-calendar-tool-schema.js +13 -0
- package/dist/src/tools/get-collection-tool-schema.d.ts +17 -0
- package/dist/src/tools/get-collection-tool-schema.js +12 -0
- package/dist/src/tools/get-contact-tool-schema.d.ts +17 -0
- package/dist/src/tools/get-contact-tool-schema.js +17 -0
- package/dist/src/tools/get-device-file-tool-schema.d.ts +17 -0
- package/dist/src/tools/get-device-file-tool-schema.js +14 -0
- package/dist/src/tools/get-email-tool-schema.d.ts +17 -0
- package/dist/src/tools/get-email-tool-schema.js +12 -0
- package/dist/src/tools/get-note-tool-schema.d.ts +17 -0
- package/dist/src/tools/get-note-tool-schema.js +15 -0
- package/dist/src/tools/get-photo-tool-schema.d.ts +17 -0
- package/dist/src/tools/get-photo-tool-schema.js +13 -0
- package/dist/src/tools/image-reading-tool.d.ts +2 -1
- package/dist/src/tools/image-reading-tool.js +86 -90
- package/dist/src/tools/location-tool.d.ts +2 -1
- package/dist/src/tools/location-tool.js +87 -91
- package/dist/src/tools/login-token-tool.d.ts +6 -0
- package/dist/src/tools/login-token-tool.js +133 -0
- package/dist/src/tools/modify-alarm-tool.d.ts +2 -1
- package/dist/src/tools/modify-alarm-tool.js +232 -236
- package/dist/src/tools/modify-note-tool.d.ts +2 -1
- package/dist/src/tools/modify-note-tool.js +104 -108
- package/dist/src/tools/note-tool.d.ts +2 -1
- package/dist/src/tools/note-tool.js +103 -107
- package/dist/src/tools/query-app-message-tool.d.ts +5 -0
- package/dist/src/tools/query-app-message-tool.js +135 -0
- package/dist/src/tools/query-memory-data-tool.d.ts +5 -0
- package/dist/src/tools/query-memory-data-tool.js +151 -0
- package/dist/src/tools/query-todo-task-tool.d.ts +5 -0
- package/dist/src/tools/query-todo-task-tool.js +130 -0
- package/dist/src/tools/save-file-to-phone-tool.d.ts +2 -1
- package/dist/src/tools/save-file-to-phone-tool.js +127 -131
- package/dist/src/tools/save-media-to-gallery-tool.d.ts +2 -1
- package/dist/src/tools/save-media-to-gallery-tool.js +134 -138
- package/dist/src/tools/save-self-evolution-skill-tool.d.ts +2 -0
- package/dist/src/tools/save-self-evolution-skill-tool.js +410 -0
- package/dist/src/tools/schema-tool-factory.d.ts +27 -0
- package/dist/src/tools/schema-tool-factory.js +32 -0
- package/dist/src/tools/search-alarm-tool.d.ts +2 -1
- package/dist/src/tools/search-alarm-tool.js +171 -175
- package/dist/src/tools/search-calendar-tool.d.ts +2 -1
- package/dist/src/tools/search-calendar-tool.js +145 -149
- package/dist/src/tools/search-contact-tool.d.ts +2 -1
- package/dist/src/tools/search-contact-tool.js +98 -102
- package/dist/src/tools/search-email-tool.d.ts +2 -1
- package/dist/src/tools/search-email-tool.js +107 -111
- package/dist/src/tools/search-file-tool.d.ts +2 -1
- package/dist/src/tools/search-file-tool.js +99 -103
- package/dist/src/tools/search-message-tool.d.ts +2 -1
- package/dist/src/tools/search-message-tool.js +100 -104
- package/dist/src/tools/search-note-tool.d.ts +2 -1
- package/dist/src/tools/search-note-tool.js +95 -99
- package/dist/src/tools/search-photo-gallery-tool.d.ts +2 -1
- package/dist/src/tools/search-photo-gallery-tool.js +34 -38
- package/dist/src/tools/send-email-tool.d.ts +5 -0
- package/dist/src/tools/send-email-tool.js +131 -0
- package/dist/src/tools/send-file-to-user-tool.d.ts +2 -1
- package/dist/src/tools/send-file-to-user-tool.js +153 -155
- package/dist/src/tools/send-message-tool.d.ts +2 -1
- package/dist/src/tools/send-message-tool.js +119 -123
- package/dist/src/tools/session-manager.d.ts +21 -6
- package/dist/src/tools/session-manager.js +135 -18
- package/dist/src/tools/upload-file-tool.d.ts +2 -1
- package/dist/src/tools/upload-file-tool.js +79 -83
- package/dist/src/tools/upload-photo-tool.d.ts +2 -1
- package/dist/src/tools/upload-photo-tool.js +70 -74
- package/dist/src/tools/xiaoyi-add-collection-tool.d.ts +2 -1
- package/dist/src/tools/xiaoyi-add-collection-tool.js +143 -147
- package/dist/src/tools/xiaoyi-collection-tool.d.ts +2 -1
- package/dist/src/tools/xiaoyi-collection-tool.js +112 -116
- package/dist/src/tools/xiaoyi-delete-collection-tool.d.ts +2 -1
- package/dist/src/tools/xiaoyi-delete-collection-tool.js +124 -128
- package/dist/src/tools/xiaoyi-gui-tool.d.ts +2 -1
- package/dist/src/tools/xiaoyi-gui-tool.js +84 -88
- package/dist/src/utils/runtime-manager.js +24 -2
- package/dist/src/utils/self-evolution-manager.d.ts +10 -0
- package/dist/src/utils/self-evolution-manager.js +68 -0
- package/dist/src/utils/tool-call-nudge-manager.d.ts +16 -0
- package/dist/src/utils/tool-call-nudge-manager.js +47 -0
- package/dist/src/websocket.d.ts +3 -0
- package/dist/src/websocket.js +94 -24
- package/openclaw.plugin.json +21 -0
- package/package.json +3 -3
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// Image Reading tool implementation
|
|
2
2
|
import { XYFileUploadService } from "../file-upload.js";
|
|
3
|
-
import { getCurrentSessionContext } from "./session-manager.js";
|
|
4
3
|
import fetch from "node-fetch";
|
|
5
4
|
import fs from "fs/promises";
|
|
6
5
|
import path from "path";
|
|
@@ -201,10 +200,12 @@ async function callImageUnderstandingAPI(imageUrl, text, apiKey, uid, fileUpload
|
|
|
201
200
|
* XY Image Reading tool - performs image understanding using local or remote image URLs.
|
|
202
201
|
* Supports both local file paths and remote URLs.
|
|
203
202
|
*/
|
|
204
|
-
export
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
203
|
+
export function createImageReadingTool(ctx) {
|
|
204
|
+
const { config, sessionId, taskId, messageId } = ctx;
|
|
205
|
+
return {
|
|
206
|
+
name: "image_reading",
|
|
207
|
+
label: "Image Reading",
|
|
208
|
+
description: `
|
|
208
209
|
工具使用场景:
|
|
209
210
|
【必须调用此工具的情况】
|
|
210
211
|
1. 用户消息中包含 mediaPath 字段且不为空(表示用户发送了图片)
|
|
@@ -230,96 +231,91 @@ a. 支持常见图片格式(jpg, png, gif等)
|
|
|
230
231
|
b. 远程图片会先下载到本地再处理
|
|
231
232
|
c. 操作超时时间为2分钟(120秒)
|
|
232
233
|
d. 返回图像理解的文本描述内容`,
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
234
|
+
parameters: {
|
|
235
|
+
type: "object",
|
|
236
|
+
properties: {
|
|
237
|
+
localUrl: {
|
|
238
|
+
type: "string",
|
|
239
|
+
description: "本地图片文件路径(可选,通常从用户消息的 mediaPath 字段获取)",
|
|
240
|
+
},
|
|
241
|
+
remoteUrl: {
|
|
242
|
+
type: "string",
|
|
243
|
+
description: "公网图片地址(可选),公网图片地址(HTTP/HTTPS URL),注意不要对原始url做任何截断(例如裁减掉链接后面的鉴权信息或者修改域名后缀),必须使用上下文中完整的图片地址",
|
|
244
|
+
},
|
|
245
|
+
prompt: {
|
|
246
|
+
type: "string",
|
|
247
|
+
description: "对图片的提示问题,默认为'描述这张图片内容',可根据用户的具体问题自定义",
|
|
248
|
+
},
|
|
247
249
|
},
|
|
248
250
|
},
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
throw new Error("At least one of localUrl or remoteUrl must be provided");
|
|
254
|
-
}
|
|
255
|
-
// Get prompt (default to "描述这张图片内容")
|
|
256
|
-
const prompt = params.prompt || "描述这张图片内容";
|
|
257
|
-
// Get session context
|
|
258
|
-
const sessionContext = getCurrentSessionContext();
|
|
259
|
-
if (!sessionContext) {
|
|
260
|
-
throw new Error("No active XY session found. Image reading tool can only be used during an active conversation.");
|
|
261
|
-
}
|
|
262
|
-
const { config } = sessionContext;
|
|
263
|
-
// Create upload service
|
|
264
|
-
const uploadService = new XYFileUploadService(config.fileUploadUrl, config.apiKey, config.uid);
|
|
265
|
-
let processedImage = null;
|
|
266
|
-
let downloadedFile = null;
|
|
267
|
-
try {
|
|
268
|
-
// Process image input (prefer localUrl over remoteUrl)
|
|
269
|
-
const imageInput = params.localUrl || params.remoteUrl;
|
|
270
|
-
processedImage = await processImageInput(imageInput, uploadService);
|
|
271
|
-
// Track downloaded file for cleanup
|
|
272
|
-
if (processedImage.localPath) {
|
|
273
|
-
downloadedFile = processedImage.localPath;
|
|
251
|
+
async execute(toolCallId, params) {
|
|
252
|
+
// Validate that at least one parameter is provided
|
|
253
|
+
if (!params.localUrl && !params.remoteUrl) {
|
|
254
|
+
throw new Error("At least one of localUrl or remoteUrl must be provided");
|
|
274
255
|
}
|
|
275
|
-
//
|
|
276
|
-
const
|
|
277
|
-
//
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
256
|
+
// Get prompt (default to "描述这张图片内容")
|
|
257
|
+
const prompt = params.prompt || "描述这张图片内容";
|
|
258
|
+
// Create upload service
|
|
259
|
+
const uploadService = new XYFileUploadService(config.fileUploadUrl, config.apiKey, config.uid);
|
|
260
|
+
let processedImage = null;
|
|
261
|
+
let downloadedFile = null;
|
|
262
|
+
try {
|
|
263
|
+
// Process image input (prefer localUrl over remoteUrl)
|
|
264
|
+
const imageInput = params.localUrl || params.remoteUrl;
|
|
265
|
+
processedImage = await processImageInput(imageInput, uploadService);
|
|
266
|
+
// Track downloaded file for cleanup
|
|
267
|
+
if (processedImage.localPath) {
|
|
268
|
+
downloadedFile = processedImage.localPath;
|
|
281
269
|
}
|
|
282
|
-
|
|
270
|
+
// Call image understanding API
|
|
271
|
+
const caption = await callImageUnderstandingAPI(processedImage.imageUrl, prompt, config.apiKey, config.uid, config.fileUploadUrl);
|
|
272
|
+
// Clean up downloaded file if any
|
|
273
|
+
if (downloadedFile) {
|
|
274
|
+
try {
|
|
275
|
+
await fs.unlink(downloadedFile);
|
|
276
|
+
}
|
|
277
|
+
catch (error) {
|
|
278
|
+
}
|
|
283
279
|
}
|
|
280
|
+
return {
|
|
281
|
+
content: [
|
|
282
|
+
{
|
|
283
|
+
type: "text",
|
|
284
|
+
text: JSON.stringify({
|
|
285
|
+
caption,
|
|
286
|
+
prompt,
|
|
287
|
+
imageSource: params.localUrl ? "local" : "remote",
|
|
288
|
+
success: true,
|
|
289
|
+
}),
|
|
290
|
+
},
|
|
291
|
+
],
|
|
292
|
+
};
|
|
284
293
|
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
success: true,
|
|
294
|
-
}),
|
|
295
|
-
},
|
|
296
|
-
],
|
|
297
|
-
};
|
|
298
|
-
}
|
|
299
|
-
catch (error) {
|
|
300
|
-
// Clean up downloaded file on error
|
|
301
|
-
if (downloadedFile) {
|
|
302
|
-
try {
|
|
303
|
-
await fs.unlink(downloadedFile);
|
|
304
|
-
}
|
|
305
|
-
catch (cleanupError) {
|
|
294
|
+
catch (error) {
|
|
295
|
+
// Clean up downloaded file on error
|
|
296
|
+
if (downloadedFile) {
|
|
297
|
+
try {
|
|
298
|
+
await fs.unlink(downloadedFile);
|
|
299
|
+
}
|
|
300
|
+
catch (cleanupError) {
|
|
301
|
+
}
|
|
306
302
|
}
|
|
303
|
+
const errorMessage = error instanceof Error ? error.message : "图片分析失败";
|
|
304
|
+
// Return error result instead of throwing
|
|
305
|
+
return {
|
|
306
|
+
content: [
|
|
307
|
+
{
|
|
308
|
+
type: "text",
|
|
309
|
+
text: JSON.stringify({
|
|
310
|
+
error: errorMessage,
|
|
311
|
+
prompt,
|
|
312
|
+
imageSource: params.localUrl ? "local" : "remote",
|
|
313
|
+
success: false,
|
|
314
|
+
}),
|
|
315
|
+
},
|
|
316
|
+
],
|
|
317
|
+
};
|
|
307
318
|
}
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
content: [
|
|
312
|
-
{
|
|
313
|
-
type: "text",
|
|
314
|
-
text: JSON.stringify({
|
|
315
|
-
error: errorMessage,
|
|
316
|
-
prompt,
|
|
317
|
-
imageSource: params.localUrl ? "local" : "remote",
|
|
318
|
-
success: false,
|
|
319
|
-
}),
|
|
320
|
-
},
|
|
321
|
-
],
|
|
322
|
-
};
|
|
323
|
-
}
|
|
324
|
-
},
|
|
325
|
-
};
|
|
319
|
+
},
|
|
320
|
+
};
|
|
321
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import type { SessionContext } from "./session-manager.js";
|
|
1
2
|
/**
|
|
2
3
|
* XY location tool - gets user's current location.
|
|
3
4
|
* Returns WGS84 coordinates (latitude, longitude).
|
|
4
5
|
*/
|
|
5
|
-
export declare
|
|
6
|
+
export declare function createLocationTool(ctx: SessionContext): any;
|
|
@@ -1,102 +1,98 @@
|
|
|
1
1
|
import { getXYWebSocketManager } from "../client.js";
|
|
2
2
|
import { sendCommand } from "../formatter.js";
|
|
3
|
-
import { getCurrentSessionContext } from "./session-manager.js";
|
|
4
3
|
/**
|
|
5
4
|
* XY location tool - gets user's current location.
|
|
6
5
|
* Returns WGS84 coordinates (latitude, longitude).
|
|
7
6
|
*/
|
|
8
|
-
export
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
7
|
+
export function createLocationTool(ctx) {
|
|
8
|
+
const { config, sessionId, taskId, messageId } = ctx;
|
|
9
|
+
return {
|
|
10
|
+
name: "get_user_location",
|
|
11
|
+
label: "Get User Location",
|
|
12
|
+
description: "获取用户当前位置(经纬度坐标,WGS84坐标系)。需要用户设备授权位置访问权限。注意:操作超时时间为60秒,请勿重复调用此工具,如果超时或失败,最多重试一次。回复约束:如果工具返回没有授权或者其他报错,只需要完整描述没有授权或者其他报错内容即可,不需要主动给用户提供解决方案,例如告诉用户如何授权,如何解决报错等都是不需要的,请严格遵守。",
|
|
13
|
+
parameters: {
|
|
14
|
+
type: "object",
|
|
15
|
+
properties: {},
|
|
16
|
+
required: [],
|
|
17
|
+
},
|
|
18
|
+
async execute(toolCallId, params) {
|
|
19
|
+
// Get WebSocket manager
|
|
20
|
+
const wsManager = getXYWebSocketManager(config);
|
|
21
|
+
// Build GetCurrentLocation command
|
|
22
|
+
const command = {
|
|
23
|
+
header: {
|
|
24
|
+
namespace: "Common",
|
|
25
|
+
name: "Action",
|
|
26
|
+
},
|
|
27
|
+
payload: {
|
|
28
|
+
cardParam: {},
|
|
29
|
+
executeParam: {
|
|
30
|
+
achieveType: "INTENT",
|
|
31
|
+
actionResponse: true,
|
|
32
|
+
bundleName: "com.huawei.hmos.aidispatchservice",
|
|
33
|
+
dimension: "",
|
|
34
|
+
executeMode: "background",
|
|
35
|
+
intentName: "GetCurrentLocation",
|
|
36
|
+
intentParam: {
|
|
37
|
+
isNeedGeoAddress: true,
|
|
38
|
+
},
|
|
39
|
+
needUnlock: true,
|
|
40
|
+
permissionId: [],
|
|
41
|
+
timeOut: 5,
|
|
43
42
|
},
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
needUploadResult: true,
|
|
44
|
+
pageControlRelated: false,
|
|
45
|
+
responses: [{
|
|
46
|
+
displayText: "",
|
|
47
|
+
resultCode: "",
|
|
48
|
+
ttsText: "",
|
|
49
|
+
}],
|
|
47
50
|
},
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
resultCode: "",
|
|
53
|
-
ttsText: "",
|
|
54
|
-
}],
|
|
55
|
-
},
|
|
56
|
-
};
|
|
57
|
-
// Send command and wait for response (60 second timeout)
|
|
58
|
-
return new Promise((resolve, reject) => {
|
|
59
|
-
const timeout = setTimeout(() => {
|
|
60
|
-
wsManager.off("data-event", handler);
|
|
61
|
-
reject(new Error("获取位置超时(60秒)"));
|
|
62
|
-
}, 60000);
|
|
63
|
-
// Listen for data events from WebSocket
|
|
64
|
-
const handler = (event) => {
|
|
65
|
-
if (event.intentName === "GetCurrentLocation") {
|
|
66
|
-
clearTimeout(timeout);
|
|
51
|
+
};
|
|
52
|
+
// Send command and wait for response (60 second timeout)
|
|
53
|
+
return new Promise((resolve, reject) => {
|
|
54
|
+
const timeout = setTimeout(() => {
|
|
67
55
|
wsManager.off("data-event", handler);
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
56
|
+
reject(new Error("获取位置超时(60秒)"));
|
|
57
|
+
}, 60000);
|
|
58
|
+
// Listen for data events from WebSocket
|
|
59
|
+
const handler = (event) => {
|
|
60
|
+
if (event.intentName === "GetCurrentLocation") {
|
|
61
|
+
clearTimeout(timeout);
|
|
62
|
+
wsManager.off("data-event", handler);
|
|
63
|
+
if (event.status === "success" && event.outputs) {
|
|
64
|
+
// 成功,直接返回完整的 event.outputs JSON 字符串
|
|
65
|
+
resolve({
|
|
66
|
+
content: [
|
|
67
|
+
{
|
|
68
|
+
type: "text",
|
|
69
|
+
text: JSON.stringify(event.outputs),
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
reject(new Error(`获取位置失败: ${event.status}`));
|
|
76
|
+
}
|
|
81
77
|
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
78
|
+
};
|
|
79
|
+
// Register event handler
|
|
80
|
+
// Note: The WebSocket manager needs to emit 'data-event' when receiving data events
|
|
81
|
+
wsManager.on("data-event", handler);
|
|
82
|
+
// Send the command
|
|
83
|
+
sendCommand({
|
|
84
|
+
config,
|
|
85
|
+
sessionId,
|
|
86
|
+
taskId,
|
|
87
|
+
messageId,
|
|
88
|
+
command,
|
|
89
|
+
}).then(() => {
|
|
90
|
+
}).catch((error) => {
|
|
91
|
+
clearTimeout(timeout);
|
|
92
|
+
wsManager.off("data-event", handler);
|
|
93
|
+
reject(error);
|
|
94
|
+
});
|
|
99
95
|
});
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// Login Token tool - 自动获取用户授权信息
|
|
2
|
+
import { v4 as uuidv4 } from "uuid";
|
|
3
|
+
import { getXYWebSocketManager } from "../client.js";
|
|
4
|
+
import { getCurrentTaskId, getCurrentMessageId } from "../task-manager.js";
|
|
5
|
+
import { readFileSync, existsSync } from "fs";
|
|
6
|
+
import { logger } from "../utils/logger.js";
|
|
7
|
+
const TOKEN_FILE_PATH = "/home/sandbox/.openclaw/.xiaoyitoken.json";
|
|
8
|
+
const POLL_INTERVAL_MS = 5000; // 5 seconds
|
|
9
|
+
const TIMEOUT_MS = 60000; // 1 minute
|
|
10
|
+
const TOKEN_VALIDITY_MS = 5 * 60 * 1000; // 5 minutes
|
|
11
|
+
/**
|
|
12
|
+
* huawei_id_tool 工具
|
|
13
|
+
* 当 skill 依赖用户获取鉴权信息时,此工具协助用户快速获取鉴权信息。
|
|
14
|
+
*/
|
|
15
|
+
export function createLoginTokenTool(ctx) {
|
|
16
|
+
const { config, sessionId, taskId, messageId } = ctx;
|
|
17
|
+
return {
|
|
18
|
+
name: "huawei_id_tool",
|
|
19
|
+
label: "Get Login Token",
|
|
20
|
+
description: "获取用户授权信息。当skill需要用户鉴权时调用此工具,工具会向用户端发送授权请求,等待用户完成授权后返回结果。请勿重复调用此工具。",
|
|
21
|
+
parameters: {
|
|
22
|
+
type: "object",
|
|
23
|
+
properties: {
|
|
24
|
+
clientId: {
|
|
25
|
+
type: "string",
|
|
26
|
+
description: "账号服务唯一标识,在执行具体skill过程中会提供",
|
|
27
|
+
},
|
|
28
|
+
skillName: {
|
|
29
|
+
type: "string",
|
|
30
|
+
description: "具体skill的名称",
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
required: ["clientId", "skillName"],
|
|
34
|
+
},
|
|
35
|
+
async execute(toolCallId, params) {
|
|
36
|
+
const { clientId, skillName } = params;
|
|
37
|
+
if (!clientId || typeof clientId !== "string" || clientId.trim() === "") {
|
|
38
|
+
throw new Error("Missing required parameter: clientId must be a non-empty string");
|
|
39
|
+
}
|
|
40
|
+
if (!skillName || typeof skillName !== "string" || skillName.trim() === "") {
|
|
41
|
+
throw new Error("Missing required parameter: skillName must be a non-empty string");
|
|
42
|
+
}
|
|
43
|
+
const currentTaskId = getCurrentTaskId(sessionId) ?? taskId;
|
|
44
|
+
const currentMessageId = getCurrentMessageId(sessionId) ?? messageId;
|
|
45
|
+
// (1) Build and send getLoginToken artifact
|
|
46
|
+
const artifactId = uuidv4();
|
|
47
|
+
const artifact = {
|
|
48
|
+
taskId: currentTaskId,
|
|
49
|
+
kind: "artifact-update",
|
|
50
|
+
append: false,
|
|
51
|
+
lastChunk: true,
|
|
52
|
+
final: false,
|
|
53
|
+
artifact: {
|
|
54
|
+
artifactId,
|
|
55
|
+
parts: [
|
|
56
|
+
{
|
|
57
|
+
kind: "getLoginToken",
|
|
58
|
+
clientId: clientId.trim(),
|
|
59
|
+
skillName: skillName.trim(),
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
const jsonRpcResponse = {
|
|
65
|
+
jsonrpc: "2.0",
|
|
66
|
+
id: currentMessageId,
|
|
67
|
+
result: artifact,
|
|
68
|
+
};
|
|
69
|
+
const wsManager = getXYWebSocketManager(config);
|
|
70
|
+
const outboundMessage = {
|
|
71
|
+
msgType: "agent_response",
|
|
72
|
+
agentId: config.agentId,
|
|
73
|
+
sessionId,
|
|
74
|
+
taskId: currentTaskId,
|
|
75
|
+
msgDetail: JSON.stringify(jsonRpcResponse),
|
|
76
|
+
};
|
|
77
|
+
logger.log(`[LOGIN_TOKEN] Sending getLoginToken artifact for clientId=${clientId}, skillName=${skillName}`);
|
|
78
|
+
await wsManager.sendMessage(sessionId, outboundMessage);
|
|
79
|
+
logger.log(`[LOGIN_TOKEN] Artifact sent successfully`);
|
|
80
|
+
// (2) Poll .xiaoyitoken.json every 5 seconds
|
|
81
|
+
const startTime = Date.now();
|
|
82
|
+
return new Promise((resolve) => {
|
|
83
|
+
const poll = () => {
|
|
84
|
+
const elapsed = Date.now() - startTime;
|
|
85
|
+
if (elapsed >= TIMEOUT_MS) {
|
|
86
|
+
// (4) Timeout after 1 minute
|
|
87
|
+
logger.log(`[LOGIN_TOKEN] Timeout: failed to get login token for clientId=${clientId}`);
|
|
88
|
+
resolve({
|
|
89
|
+
content: [
|
|
90
|
+
{
|
|
91
|
+
type: "text",
|
|
92
|
+
text: "获取用户授权失败",
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
});
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
if (existsSync(TOKEN_FILE_PATH)) {
|
|
100
|
+
const content = readFileSync(TOKEN_FILE_PATH, "utf-8");
|
|
101
|
+
const tokens = JSON.parse(content);
|
|
102
|
+
const match = tokens.find((t) => t.clientId === clientId.trim());
|
|
103
|
+
if (match) {
|
|
104
|
+
const tokenTime = Number(match.timestamp);
|
|
105
|
+
const diff = Date.now() - tokenTime;
|
|
106
|
+
if (diff <= TOKEN_VALIDITY_MS) {
|
|
107
|
+
// (3) Found valid token
|
|
108
|
+
logger.log(`[LOGIN_TOKEN] Successfully got login token for clientId=${clientId}`);
|
|
109
|
+
resolve({
|
|
110
|
+
content: [
|
|
111
|
+
{
|
|
112
|
+
type: "text",
|
|
113
|
+
text: "获取用户授权成功",
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
});
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
logger.log(`[LOGIN_TOKEN] Error reading token file: ${err}`);
|
|
124
|
+
}
|
|
125
|
+
// Not found or not valid, poll again after 5 seconds
|
|
126
|
+
setTimeout(poll, POLL_INTERVAL_MS);
|
|
127
|
+
};
|
|
128
|
+
// Start polling after 5 seconds
|
|
129
|
+
setTimeout(poll, POLL_INTERVAL_MS);
|
|
130
|
+
});
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { SessionContext } from "./session-manager.js";
|
|
1
2
|
/**
|
|
2
3
|
* XY modify alarm tool - modifies an existing alarm on user's device.
|
|
3
4
|
* Requires entityId from search_alarm or create_alarm tool.
|
|
@@ -6,4 +7,4 @@
|
|
|
6
7
|
* 1. Call search_alarm or create_alarm tool first to get entityId
|
|
7
8
|
* 2. Use the entityId to identify which alarm to modify
|
|
8
9
|
*/
|
|
9
|
-
export declare
|
|
10
|
+
export declare function createModifyAlarmTool(ctx: SessionContext): any;
|