@ynhcj/xiaoyi-channel 0.0.72-beta → 0.0.72-next
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +0 -5
- package/dist/index.js +51 -14
- package/dist/src/bot.js +27 -3
- package/dist/src/channel.js +15 -23
- package/dist/src/cspl/call-api.js +14 -11
- package/dist/src/cspl/config.js +3 -3
- package/dist/src/cspl/constants.d.ts +2 -0
- package/dist/src/cspl/constants.js +12 -0
- package/dist/src/cspl/utils.js +4 -2
- package/dist/src/file-download.js +3 -6
- package/dist/src/file-upload.js +52 -5
- 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 +54 -3
- package/dist/src/outbound.js +2 -7
- package/dist/src/provider.d.ts +1 -0
- package/dist/src/provider.js +442 -43
- package/dist/src/reply-dispatcher.js +6 -0
- package/dist/src/self-evolution-handler.d.ts +7 -0
- package/dist/src/self-evolution-handler.js +141 -0
- package/dist/src/self-evolution-keyword.d.ts +9 -0
- package/dist/src/self-evolution-keyword.js +145 -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 +91 -0
- package/dist/src/skill-retriever/tool-search.d.ts +16 -0
- package/dist/src/skill-retriever/tool-search.js +159 -0
- package/dist/src/skill-retriever/types.d.ts +34 -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 +6 -0
- package/dist/src/tools/call-device-tool.d.ts +5 -0
- package/dist/src/tools/call-device-tool.js +130 -0
- package/dist/src/tools/create-alarm-tool.js +5 -16
- package/dist/src/tools/delete-alarm-tool.js +1 -4
- package/dist/src/tools/device-tool-map.js +5 -1
- package/dist/src/tools/find-pc-devices-tool.d.ts +5 -0
- package/dist/src/tools/find-pc-devices-tool.js +98 -0
- package/dist/src/tools/get-alarm-tool-schema.d.ts +16 -0
- package/dist/src/tools/get-alarm-tool-schema.js +11 -0
- package/dist/src/tools/get-calendar-tool-schema.d.ts +16 -0
- package/dist/src/tools/get-calendar-tool-schema.js +9 -0
- package/dist/src/tools/get-collection-tool-schema.d.ts +16 -0
- package/dist/src/tools/get-collection-tool-schema.js +10 -0
- package/dist/src/tools/get-contact-tool-schema.d.ts +16 -0
- package/dist/src/tools/get-contact-tool-schema.js +11 -0
- package/dist/src/tools/get-device-file-tool-schema.d.ts +16 -0
- package/dist/src/tools/get-device-file-tool-schema.js +10 -0
- package/dist/src/tools/get-email-tool-schema.d.ts +16 -0
- package/dist/src/tools/get-email-tool-schema.js +9 -0
- package/dist/src/tools/get-note-tool-schema.d.ts +16 -0
- package/dist/src/tools/get-note-tool-schema.js +10 -0
- package/dist/src/tools/get-photo-tool-schema.d.ts +16 -0
- package/dist/src/tools/get-photo-tool-schema.js +10 -0
- package/dist/src/tools/image-reading-tool.js +4 -7
- package/dist/src/tools/login-token-tool.d.ts +5 -0
- package/dist/src/tools/login-token-tool.js +136 -0
- package/dist/src/tools/modify-alarm-tool.js +10 -23
- package/dist/src/tools/query-app-message-tool.d.ts +4 -0
- package/dist/src/tools/query-app-message-tool.js +138 -0
- package/dist/src/tools/query-memory-data-tool.d.ts +4 -0
- package/dist/src/tools/query-memory-data-tool.js +154 -0
- package/dist/src/tools/query-todo-task-tool.d.ts +4 -0
- package/dist/src/tools/query-todo-task-tool.js +133 -0
- package/dist/src/tools/save-file-to-phone-tool.d.ts +5 -0
- package/dist/src/tools/save-file-to-phone-tool.js +166 -0
- package/dist/src/tools/save-media-to-gallery-tool.js +3 -7
- package/dist/src/tools/save-self-evolution-skill-tool.d.ts +1 -0
- package/dist/src/tools/save-self-evolution-skill-tool.js +412 -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.js +6 -13
- package/dist/src/tools/search-calendar-tool.js +2 -0
- package/dist/src/tools/search-email-tool.d.ts +5 -0
- package/dist/src/tools/search-email-tool.js +137 -0
- package/dist/src/tools/search-file-tool.js +4 -4
- package/dist/src/tools/search-message-tool.js +1 -0
- package/dist/src/tools/search-photo-gallery-tool.js +2 -2
- package/dist/src/tools/send-email-tool.d.ts +4 -0
- package/dist/src/tools/send-email-tool.js +134 -0
- package/dist/src/tools/send-file-to-user-tool.js +2 -4
- package/dist/src/tools/session-manager.js +2 -0
- package/dist/src/tools/upload-file-tool.js +4 -4
- package/dist/src/tools/upload-photo-tool.js +2 -2
- package/dist/src/tools/xiaoyi-add-collection-tool.js +35 -6
- package/dist/src/tools/xiaoyi-collection-tool.js +2 -1
- package/dist/src/tools/xiaoyi-delete-collection-tool.js +1 -1
- package/dist/src/utils/runtime-manager.js +24 -2
- package/dist/src/utils/self-evolution-manager.d.ts +5 -0
- package/dist/src/utils/self-evolution-manager.js +47 -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 +71 -0
- package/openclaw.plugin.json +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
// Login Token tool - 自动获取用户授权信息
|
|
2
|
+
import { v4 as uuidv4 } from "uuid";
|
|
3
|
+
import { getXYWebSocketManager } from "../client.js";
|
|
4
|
+
import { getCurrentSessionContext } from "./session-manager.js";
|
|
5
|
+
import { getCurrentTaskId, getCurrentMessageId } from "../task-manager.js";
|
|
6
|
+
import { readFileSync, existsSync } from "fs";
|
|
7
|
+
import { logger } from "../utils/logger.js";
|
|
8
|
+
const TOKEN_FILE_PATH = "/home/sandbox/.openclaw/.xiaoyitoken.json";
|
|
9
|
+
const POLL_INTERVAL_MS = 5000; // 5 seconds
|
|
10
|
+
const TIMEOUT_MS = 60000; // 1 minute
|
|
11
|
+
const TOKEN_VALIDITY_MS = 5 * 60 * 1000; // 5 minutes
|
|
12
|
+
/**
|
|
13
|
+
* get_login_token 工具
|
|
14
|
+
* 当 skill 依赖用户获取鉴权信息时,此工具协助用户快速获取鉴权信息。
|
|
15
|
+
*/
|
|
16
|
+
export const loginTokenTool = {
|
|
17
|
+
name: "get_login_token",
|
|
18
|
+
label: "Get Login Token",
|
|
19
|
+
description: "获取用户授权信息。当skill需要用户鉴权时调用此工具,工具会向用户端发送授权请求,等待用户完成授权后返回结果。请勿重复调用此工具。",
|
|
20
|
+
parameters: {
|
|
21
|
+
type: "object",
|
|
22
|
+
properties: {
|
|
23
|
+
clientId: {
|
|
24
|
+
type: "string",
|
|
25
|
+
description: "账号服务唯一标识,在执行具体skill过程中会提供",
|
|
26
|
+
},
|
|
27
|
+
skillName: {
|
|
28
|
+
type: "string",
|
|
29
|
+
description: "具体skill的名称",
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
required: ["clientId", "skillName"],
|
|
33
|
+
},
|
|
34
|
+
async execute(toolCallId, params) {
|
|
35
|
+
const { clientId, skillName } = params;
|
|
36
|
+
if (!clientId || typeof clientId !== "string" || clientId.trim() === "") {
|
|
37
|
+
throw new Error("Missing required parameter: clientId must be a non-empty string");
|
|
38
|
+
}
|
|
39
|
+
if (!skillName || typeof skillName !== "string" || skillName.trim() === "") {
|
|
40
|
+
throw new Error("Missing required parameter: skillName must be a non-empty string");
|
|
41
|
+
}
|
|
42
|
+
const sessionContext = getCurrentSessionContext();
|
|
43
|
+
if (!sessionContext) {
|
|
44
|
+
throw new Error("No active XY session found. Login token tool can only be used during an active conversation.");
|
|
45
|
+
}
|
|
46
|
+
const { config, sessionId, taskId, messageId } = sessionContext;
|
|
47
|
+
const currentTaskId = getCurrentTaskId(sessionId) ?? taskId;
|
|
48
|
+
const currentMessageId = getCurrentMessageId(sessionId) ?? messageId;
|
|
49
|
+
// (1) Build and send getLoginToken artifact
|
|
50
|
+
const artifactId = uuidv4();
|
|
51
|
+
const artifact = {
|
|
52
|
+
taskId: currentTaskId,
|
|
53
|
+
kind: "artifact-update",
|
|
54
|
+
append: false,
|
|
55
|
+
lastChunk: true,
|
|
56
|
+
final: false,
|
|
57
|
+
artifact: {
|
|
58
|
+
artifactId,
|
|
59
|
+
parts: [
|
|
60
|
+
{
|
|
61
|
+
kind: "getLoginToken",
|
|
62
|
+
clientId: clientId.trim(),
|
|
63
|
+
skillName: skillName.trim(),
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
const jsonRpcResponse = {
|
|
69
|
+
jsonrpc: "2.0",
|
|
70
|
+
id: currentMessageId,
|
|
71
|
+
result: artifact,
|
|
72
|
+
};
|
|
73
|
+
const wsManager = getXYWebSocketManager(config);
|
|
74
|
+
const outboundMessage = {
|
|
75
|
+
msgType: "agent_response",
|
|
76
|
+
agentId: config.agentId,
|
|
77
|
+
sessionId,
|
|
78
|
+
taskId: currentTaskId,
|
|
79
|
+
msgDetail: JSON.stringify(jsonRpcResponse),
|
|
80
|
+
};
|
|
81
|
+
logger.log(`[LOGIN_TOKEN] Sending getLoginToken artifact for clientId=${clientId}, skillName=${skillName}`);
|
|
82
|
+
await wsManager.sendMessage(sessionId, outboundMessage);
|
|
83
|
+
logger.log(`[LOGIN_TOKEN] Artifact sent successfully`);
|
|
84
|
+
// (2) Poll .xiaoyitoken.json every 5 seconds
|
|
85
|
+
const startTime = Date.now();
|
|
86
|
+
return new Promise((resolve) => {
|
|
87
|
+
const poll = () => {
|
|
88
|
+
const elapsed = Date.now() - startTime;
|
|
89
|
+
if (elapsed >= TIMEOUT_MS) {
|
|
90
|
+
// (4) Timeout after 1 minute
|
|
91
|
+
logger.log(`[LOGIN_TOKEN] Timeout: failed to get login token for clientId=${clientId}`);
|
|
92
|
+
resolve({
|
|
93
|
+
content: [
|
|
94
|
+
{
|
|
95
|
+
type: "text",
|
|
96
|
+
text: "获取用户授权失败",
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
});
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
if (existsSync(TOKEN_FILE_PATH)) {
|
|
104
|
+
const content = readFileSync(TOKEN_FILE_PATH, "utf-8");
|
|
105
|
+
const tokens = JSON.parse(content);
|
|
106
|
+
const match = tokens.find((t) => t.clientId === clientId.trim());
|
|
107
|
+
if (match) {
|
|
108
|
+
const tokenTime = Number(match.timestamp);
|
|
109
|
+
const diff = Date.now() - tokenTime;
|
|
110
|
+
if (diff <= TOKEN_VALIDITY_MS) {
|
|
111
|
+
// (3) Found valid token
|
|
112
|
+
logger.log(`[LOGIN_TOKEN] Successfully got login token for clientId=${clientId}`);
|
|
113
|
+
resolve({
|
|
114
|
+
content: [
|
|
115
|
+
{
|
|
116
|
+
type: "text",
|
|
117
|
+
text: "获取用户授权成功",
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
});
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
logger.log(`[LOGIN_TOKEN] Error reading token file: ${err}`);
|
|
128
|
+
}
|
|
129
|
+
// Not found or not valid, poll again after 5 seconds
|
|
130
|
+
setTimeout(poll, POLL_INTERVAL_MS);
|
|
131
|
+
};
|
|
132
|
+
// Start polling after 5 seconds
|
|
133
|
+
setTimeout(poll, POLL_INTERVAL_MS);
|
|
134
|
+
});
|
|
135
|
+
},
|
|
136
|
+
};
|
|
@@ -20,23 +20,10 @@ export const modifyAlarmTool = {
|
|
|
20
20
|
label: "Modify Alarm",
|
|
21
21
|
description: `修改用户设备上已存在的闹钟。
|
|
22
22
|
|
|
23
|
-
必需参数:
|
|
24
|
-
- entityId: 闹钟的唯一标识符,必须先通过 search_alarm 或 create_alarm 工具获取
|
|
25
|
-
|
|
26
|
-
可选参数(与创建闹钟的参数完全一致):
|
|
27
|
-
- alarmTime: 闹钟时间,格式必须为:YYYYMMDD hhmmss(例如:20240315 143000)
|
|
28
|
-
- alarmTitle: 闹钟名称/标题
|
|
29
|
-
- alarmState: 闹钟开启状态,0=关闭,1=开启
|
|
30
|
-
- alarmSnoozeDuration: 小睡间隔(分钟),枚举值:5,10,15,20,25,30
|
|
31
|
-
- alarmSnoozeTotal: 再响次数,枚举值:0,1,3,5,10
|
|
32
|
-
- alarmRingDuration: 响铃时长(分钟),枚举值:1,5,10,15,20,30
|
|
33
|
-
- daysOfWakeType: 闹钟响铃类型,枚举值:0=单次,1=法定节假日,2=每天,3=自定义,4=法定工作日
|
|
34
|
-
- daysOfWeek: 自定义响铃星期,仅当daysOfWakeType=3(自定义时间)时必需且有效,其他情况不要传递此参数。数组或JSON字符串,枚举值:Mon,Tues,Wed,Thur,Fri,Sat,Sun。
|
|
35
|
-
|
|
36
23
|
使用流程:
|
|
37
24
|
1. 先调用 search_alarm 工具查询闹钟,获取 entityId,
|
|
38
25
|
2. 调用此工具修改闹钟,传入 entityId 和需要修改的参数
|
|
39
|
-
3.
|
|
26
|
+
3. 其余不涉及修改的参数,如果search_alarm 或 create_alarm的结果中有相应的值,需要一并填上,需要与原有的保持一致,防止不填采用默认值
|
|
40
27
|
|
|
41
28
|
注意事项:操作超时时间为60秒,请勿重复调用此工具,如果超时或失败,最多重试一次。
|
|
42
29
|
|
|
@@ -46,40 +33,40 @@ export const modifyAlarmTool = {
|
|
|
46
33
|
properties: {
|
|
47
34
|
entityId: {
|
|
48
35
|
type: "string",
|
|
49
|
-
description: "
|
|
36
|
+
description: "(必需)闹钟的唯一标识符,必须先通过 search_alarm 或 create_alarm 工具获取",
|
|
50
37
|
},
|
|
51
38
|
alarmTime: {
|
|
52
39
|
type: "string",
|
|
53
|
-
description: "
|
|
40
|
+
description: "(可选)闹钟时间,格式必须为:YYYYMMDD hhmmss(例如:20240315 143000)",
|
|
54
41
|
},
|
|
55
42
|
alarmTitle: {
|
|
56
43
|
type: "string",
|
|
57
|
-
description: "
|
|
44
|
+
description: "(可选)闹钟名称/标题",
|
|
58
45
|
},
|
|
59
46
|
alarmState: {
|
|
60
47
|
type: "number",
|
|
61
|
-
description: "
|
|
48
|
+
description: "(可选)闹钟开启状态,枚举值:0=关闭,1=开启",
|
|
62
49
|
},
|
|
63
50
|
alarmSnoozeDuration: {
|
|
64
51
|
type: "number",
|
|
65
|
-
description: "
|
|
52
|
+
description: "(可选)小睡间隔(分钟),枚举值:5,10,15,20,25,30",
|
|
66
53
|
},
|
|
67
54
|
alarmSnoozeTotal: {
|
|
68
55
|
type: "number",
|
|
69
|
-
description: "
|
|
56
|
+
description: "(可选)再响次数,枚举值:0,1,3,5,10",
|
|
70
57
|
},
|
|
71
58
|
alarmRingDuration: {
|
|
72
59
|
type: "number",
|
|
73
|
-
description: "
|
|
60
|
+
description: "(可选)响铃时长(分钟),枚举值:1,5,10,15,20,30",
|
|
74
61
|
},
|
|
75
62
|
daysOfWakeType: {
|
|
76
63
|
type: "number",
|
|
77
|
-
description: "
|
|
64
|
+
description: "(可选)闹钟响铃类型,枚举值:0=单次,1=法定节假日,2=每天,3=自定义,4=法定工作日",
|
|
78
65
|
},
|
|
79
66
|
daysOfWeek: {
|
|
80
67
|
// 不指定 type,允许传入数组或 JSON 字符串
|
|
81
68
|
// 具体的类型验证和转换在 execute 函数内部进行
|
|
82
|
-
description: "
|
|
69
|
+
description: "(可选)自定义响铃星期,仅当daysOfWakeType=3(自定义时间)时必需且有效,其他情况不要传递此参数。数组或JSON字符串,枚举值:Mon,Tues,Wed,Thur,Fri,Sat,Sun",
|
|
83
70
|
},
|
|
84
71
|
},
|
|
85
72
|
required: ["entityId"],
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
// QueryAppMessage tool implementation
|
|
2
|
+
import { getXYWebSocketManager } from "../client.js";
|
|
3
|
+
import { sendCommand } from "../formatter.js";
|
|
4
|
+
import { getCurrentSessionContext } from "./session-manager.js";
|
|
5
|
+
class ToolInputError extends Error {
|
|
6
|
+
status = 400;
|
|
7
|
+
constructor(message) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.name = "ToolInputError";
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* 查询指定时间范围内的设备通知消息。
|
|
14
|
+
*/
|
|
15
|
+
export const queryAppMessageTool = {
|
|
16
|
+
name: "query_app_message",
|
|
17
|
+
label: "Query App Message",
|
|
18
|
+
description: `获取指定时间范围内的设备通知消息。适用于需要查询历史通知、按应用筛选通知、或仅查看未读通知的场景。支持按时间范围、应用包名、已读/未读状态进行过滤。
|
|
19
|
+
注意:
|
|
20
|
+
a. 操作超时时间为60秒,请勿重复调用此工具
|
|
21
|
+
b. 如果遇到各类调用失败场景,最多只能重试一次,不可以重复调用多次。
|
|
22
|
+
c. 调用工具前需认真检查调用参数是否满足工具要求
|
|
23
|
+
|
|
24
|
+
回复约束:如果工具返回没有授权或者其他报错,只需要完整描述没有授权或者其他报错内容即可,不需要主动给用户提供解决方案,例如告诉用户如何授权,如何解决报错等都是不需要的,请严格遵守。`,
|
|
25
|
+
parameters: {
|
|
26
|
+
type: "object",
|
|
27
|
+
properties: {
|
|
28
|
+
startTime: {
|
|
29
|
+
type: "string",
|
|
30
|
+
description: "查询通知的起始时间(ISO 8601 字符串)。若endTime为空,则默认值为24小时前。",
|
|
31
|
+
},
|
|
32
|
+
endTime: {
|
|
33
|
+
type: "string",
|
|
34
|
+
description: "查询通知的结束时间(ISO 8601 字符串)。默认值为当前时间。",
|
|
35
|
+
},
|
|
36
|
+
packageName: {
|
|
37
|
+
type: "string",
|
|
38
|
+
description: "按应用名称过滤通知(例如「微信」「小红书」)。默认值为所有应用。",
|
|
39
|
+
},
|
|
40
|
+
state: {
|
|
41
|
+
type: "integer",
|
|
42
|
+
description: "通知的已读/未读状态。0 = 全部,1 = 仅未读。默认值为 0。",
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
required: [],
|
|
46
|
+
},
|
|
47
|
+
async execute(_toolCallId, params) {
|
|
48
|
+
const sessionContext = getCurrentSessionContext();
|
|
49
|
+
if (!sessionContext) {
|
|
50
|
+
throw new Error("No active XY session found.");
|
|
51
|
+
}
|
|
52
|
+
const { config, sessionId, taskId, messageId } = sessionContext;
|
|
53
|
+
const wsManager = getXYWebSocketManager(config);
|
|
54
|
+
const intentParam = {};
|
|
55
|
+
if (params.startTime !== undefined)
|
|
56
|
+
intentParam.startTime = params.startTime;
|
|
57
|
+
if (params.endTime !== undefined)
|
|
58
|
+
intentParam.endTime = params.endTime;
|
|
59
|
+
if (params.packageName !== undefined)
|
|
60
|
+
intentParam.packageName = params.packageName;
|
|
61
|
+
if (params.state !== undefined) {
|
|
62
|
+
if (params.state !== 0 && params.state !== 1) {
|
|
63
|
+
throw new ToolInputError("state 参数只能为 0(全部)或 1(仅未读)");
|
|
64
|
+
}
|
|
65
|
+
intentParam.state = params.state;
|
|
66
|
+
}
|
|
67
|
+
const command = {
|
|
68
|
+
header: {
|
|
69
|
+
namespace: "Common",
|
|
70
|
+
name: "Action",
|
|
71
|
+
},
|
|
72
|
+
payload: {
|
|
73
|
+
cardParam: {},
|
|
74
|
+
executeParam: {
|
|
75
|
+
executeMode: "background",
|
|
76
|
+
intentName: "QueryAppMessage",
|
|
77
|
+
bundleName: "com.huawei.hmos.vassistant",
|
|
78
|
+
needUnlock: true,
|
|
79
|
+
actionResponse: true,
|
|
80
|
+
appType: "OHOS_APP",
|
|
81
|
+
timeOut: 5,
|
|
82
|
+
intentParam,
|
|
83
|
+
permissionId: [],
|
|
84
|
+
achieveType: "INTENT",
|
|
85
|
+
},
|
|
86
|
+
responses: [
|
|
87
|
+
{
|
|
88
|
+
resultCode: "",
|
|
89
|
+
displayText: "",
|
|
90
|
+
ttsText: "",
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
needUploadResult: true,
|
|
94
|
+
noHalfPage: false,
|
|
95
|
+
pageControlRelated: false,
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
return new Promise((resolve, reject) => {
|
|
99
|
+
const timeout = setTimeout(() => {
|
|
100
|
+
wsManager.off("data-event", handler);
|
|
101
|
+
reject(new Error("查询通知消息超时(60秒)"));
|
|
102
|
+
}, 60000);
|
|
103
|
+
const handler = (event) => {
|
|
104
|
+
if (event.intentName === "QueryAppMessage") {
|
|
105
|
+
clearTimeout(timeout);
|
|
106
|
+
wsManager.off("data-event", handler);
|
|
107
|
+
if (event.status === "success" && event.outputs) {
|
|
108
|
+
resolve({
|
|
109
|
+
content: [
|
|
110
|
+
{
|
|
111
|
+
type: "text",
|
|
112
|
+
text: JSON.stringify(event.outputs),
|
|
113
|
+
},
|
|
114
|
+
],
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
reject(new Error(`查询通知消息失败: ${event.status}`));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
wsManager.on("data-event", handler);
|
|
123
|
+
sendCommand({
|
|
124
|
+
config,
|
|
125
|
+
sessionId,
|
|
126
|
+
taskId,
|
|
127
|
+
messageId,
|
|
128
|
+
command,
|
|
129
|
+
})
|
|
130
|
+
.then(() => { })
|
|
131
|
+
.catch((error) => {
|
|
132
|
+
clearTimeout(timeout);
|
|
133
|
+
wsManager.off("data-event", handler);
|
|
134
|
+
reject(error);
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
},
|
|
138
|
+
};
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
// QueryMemoryData tool implementation
|
|
2
|
+
import { getXYWebSocketManager } from "../client.js";
|
|
3
|
+
import { sendCommand } from "../formatter.js";
|
|
4
|
+
import { getCurrentSessionContext } from "./session-manager.js";
|
|
5
|
+
class ToolInputError extends Error {
|
|
6
|
+
status = 400;
|
|
7
|
+
constructor(message) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.name = "ToolInputError";
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
const VALID_CATEGORIES = ["ImportantDay", "Address", "Card", "ServiceOrder", "Event"];
|
|
13
|
+
const VALID_SUB_CATEGORIES = {
|
|
14
|
+
ImportantDay: ["Birthday", "Anniversary", "RepaymentDate", "ExamDate", "SalaryDate", "BigDay"],
|
|
15
|
+
Card: [
|
|
16
|
+
"IDCard", "Passport", "DrivingLicense", "VehicleLicense", "EEPtoHKMO",
|
|
17
|
+
"EEPtoTW", "Invoice", "BusinessCard", "VehicleInspectionCertificate",
|
|
18
|
+
"SocialSecurityCard", "BankCard",
|
|
19
|
+
],
|
|
20
|
+
ServiceOrder: ["FilmTicket", "HotelOrder", "TrainTicket", "AirTicket"],
|
|
21
|
+
Event: [
|
|
22
|
+
"Delicacy", "Work", "FamilyActivities", "Travel", "Training",
|
|
23
|
+
"Health", "Life", "Entertainment", "Calendar",
|
|
24
|
+
],
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* 查询存储在设备本地的结构化记忆数据。
|
|
28
|
+
*/
|
|
29
|
+
export const queryMemoryDataTool = {
|
|
30
|
+
name: "query_memory_data",
|
|
31
|
+
label: "Query Memory Data",
|
|
32
|
+
description: `查询存储在设备本地的结构化记忆数据。适用于获取特定类别的个人信息,如重要日子、证件卡证、服务订单或日程事件。支持按分类、子分类进行过滤。
|
|
33
|
+
注意:
|
|
34
|
+
a. 操作超时时间为60秒,请勿重复调用此工具
|
|
35
|
+
b. 如果遇到各类调用失败场景,最多只能重试一次,不可以重复调用多次。
|
|
36
|
+
c. 调用工具前需认真检查调用参数是否满足工具要求
|
|
37
|
+
|
|
38
|
+
回复约束:如果工具返回没有授权或者其他报错,只需要完整描述没有授权或者其他报错内容即可,不需要主动给用户提供解决方案,例如告诉用户如何授权,如何解决报错等都是不需要的,请严格遵守。`,
|
|
39
|
+
parameters: {
|
|
40
|
+
type: "object",
|
|
41
|
+
properties: {
|
|
42
|
+
category: {
|
|
43
|
+
type: "string",
|
|
44
|
+
description: '按数据大类进行过滤。可选值为 ""、"ImportantDay"、"Address"、"Card"、"ServiceOrder"、"Event"。默认值为 ""。',
|
|
45
|
+
},
|
|
46
|
+
subCategory: {
|
|
47
|
+
description: '在指定 category 下的子类别过滤,默认值为""。支持字符串或字符串数组。',
|
|
48
|
+
oneOf: [
|
|
49
|
+
{ type: "string" },
|
|
50
|
+
{ type: "array", items: { type: "string" } },
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
required: [],
|
|
55
|
+
},
|
|
56
|
+
async execute(_toolCallId, params) {
|
|
57
|
+
const { category, subCategory } = params;
|
|
58
|
+
// Validate category
|
|
59
|
+
if (category && !VALID_CATEGORIES.includes(category)) {
|
|
60
|
+
throw new ToolInputError(`category 参数无效,可选值为:${VALID_CATEGORIES.join("、")}`);
|
|
61
|
+
}
|
|
62
|
+
// Validate subCategory when category is specified
|
|
63
|
+
if (category && subCategory && VALID_SUB_CATEGORIES[category]) {
|
|
64
|
+
const validValues = VALID_SUB_CATEGORIES[category];
|
|
65
|
+
const subValues = Array.isArray(subCategory) ? subCategory : [subCategory];
|
|
66
|
+
for (const sv of subValues) {
|
|
67
|
+
if (sv && !validValues.includes(sv)) {
|
|
68
|
+
throw new ToolInputError(`category 为 "${category}" 时,subCategory 可选值为:${validValues.join("、")}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const sessionContext = getCurrentSessionContext();
|
|
73
|
+
if (!sessionContext) {
|
|
74
|
+
throw new Error("No active XY session found.");
|
|
75
|
+
}
|
|
76
|
+
const { config, sessionId, taskId, messageId } = sessionContext;
|
|
77
|
+
const wsManager = getXYWebSocketManager(config);
|
|
78
|
+
const intentParam = {};
|
|
79
|
+
if (category)
|
|
80
|
+
intentParam.category = category;
|
|
81
|
+
if (subCategory !== undefined)
|
|
82
|
+
intentParam.subCategory = subCategory;
|
|
83
|
+
const command = {
|
|
84
|
+
header: {
|
|
85
|
+
namespace: "Common",
|
|
86
|
+
name: "Action",
|
|
87
|
+
},
|
|
88
|
+
payload: {
|
|
89
|
+
cardParam: {},
|
|
90
|
+
executeParam: {
|
|
91
|
+
executeMode: "background",
|
|
92
|
+
intentName: "QueryMemoryData",
|
|
93
|
+
bundleName: "com.huawei.hmos.vassistant",
|
|
94
|
+
needUnlock: true,
|
|
95
|
+
actionResponse: true,
|
|
96
|
+
appType: "OHOS_APP",
|
|
97
|
+
timeOut: 5,
|
|
98
|
+
intentParam,
|
|
99
|
+
permissionId: [],
|
|
100
|
+
achieveType: "INTENT",
|
|
101
|
+
},
|
|
102
|
+
responses: [
|
|
103
|
+
{
|
|
104
|
+
resultCode: "",
|
|
105
|
+
displayText: "",
|
|
106
|
+
ttsText: "",
|
|
107
|
+
},
|
|
108
|
+
],
|
|
109
|
+
needUploadResult: true,
|
|
110
|
+
noHalfPage: false,
|
|
111
|
+
pageControlRelated: false,
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
return new Promise((resolve, reject) => {
|
|
115
|
+
const timeout = setTimeout(() => {
|
|
116
|
+
wsManager.off("data-event", handler);
|
|
117
|
+
reject(new Error("查询记忆数据超时(60秒)"));
|
|
118
|
+
}, 60000);
|
|
119
|
+
const handler = (event) => {
|
|
120
|
+
if (event.intentName === "QueryMemoryData") {
|
|
121
|
+
clearTimeout(timeout);
|
|
122
|
+
wsManager.off("data-event", handler);
|
|
123
|
+
if (event.status === "success" && event.outputs) {
|
|
124
|
+
resolve({
|
|
125
|
+
content: [
|
|
126
|
+
{
|
|
127
|
+
type: "text",
|
|
128
|
+
text: JSON.stringify(event.outputs),
|
|
129
|
+
},
|
|
130
|
+
],
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
reject(new Error(`查询记忆数据失败: ${event.status}`));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
wsManager.on("data-event", handler);
|
|
139
|
+
sendCommand({
|
|
140
|
+
config,
|
|
141
|
+
sessionId,
|
|
142
|
+
taskId,
|
|
143
|
+
messageId,
|
|
144
|
+
command,
|
|
145
|
+
})
|
|
146
|
+
.then(() => { })
|
|
147
|
+
.catch((error) => {
|
|
148
|
+
clearTimeout(timeout);
|
|
149
|
+
wsManager.off("data-event", handler);
|
|
150
|
+
reject(error);
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
},
|
|
154
|
+
};
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// QueryTodoTask tool implementation
|
|
2
|
+
import { getXYWebSocketManager } from "../client.js";
|
|
3
|
+
import { sendCommand } from "../formatter.js";
|
|
4
|
+
import { getCurrentSessionContext } from "./session-manager.js";
|
|
5
|
+
class ToolInputError extends Error {
|
|
6
|
+
status = 400;
|
|
7
|
+
constructor(message) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.name = "ToolInputError";
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* 获取指定时间范围内的全局待办任务列表。
|
|
14
|
+
*/
|
|
15
|
+
export const queryTodoTaskTool = {
|
|
16
|
+
name: "query_todo_task",
|
|
17
|
+
label: "Query Todo Task",
|
|
18
|
+
description: `获取指定时间范围内的全局待办任务列表。适用于需要查询历史任务、按完成状态筛选、或仅查看待处理任务的场景。支持按时间范围、任务状态进行过滤。
|
|
19
|
+
注意:
|
|
20
|
+
a. 操作超时时间为60秒,请勿重复调用此工具
|
|
21
|
+
b. 如果遇到各类调用失败场景,最多只能重试一次,不可以重复调用多次。
|
|
22
|
+
c. 调用工具前需认真检查调用参数是否满足工具要求
|
|
23
|
+
d. 当只传入 startTime 时,返回该时间点之后的所有任务;当只传入 endTime 时,返回该时间点之前的所有任务;两者都不传则返回所有时间段的任务。
|
|
24
|
+
|
|
25
|
+
回复约束:如果工具返回没有授权或者其他报错,只需要完整描述没有授权或者其他报错内容即可,不需要主动给用户提供解决方案,例如告诉用户如何授权,如何解决报错等都是不需要的,请严格遵守。`,
|
|
26
|
+
parameters: {
|
|
27
|
+
type: "object",
|
|
28
|
+
properties: {
|
|
29
|
+
startTime: {
|
|
30
|
+
type: "string",
|
|
31
|
+
description: "查询创建时间大于此值的任务(ISO 8601 字符串,如 2024-01-01T00:00:00Z)。",
|
|
32
|
+
},
|
|
33
|
+
endTime: {
|
|
34
|
+
type: "string",
|
|
35
|
+
description: "查询创建时间小于此值的任务(ISO 8601 字符串,如 2024-01-31T23:59:59Z)。",
|
|
36
|
+
},
|
|
37
|
+
status: {
|
|
38
|
+
type: "string",
|
|
39
|
+
description: '任务完成状态过滤。可选值为 "all"、"completed"、"pending"。默认为 "all"。',
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
required: [],
|
|
43
|
+
},
|
|
44
|
+
async execute(_toolCallId, params) {
|
|
45
|
+
const { status } = params;
|
|
46
|
+
if (status && !["all", "completed", "pending"].includes(status)) {
|
|
47
|
+
throw new ToolInputError('status 参数只能为 "all"、"completed" 或 "pending"');
|
|
48
|
+
}
|
|
49
|
+
const sessionContext = getCurrentSessionContext();
|
|
50
|
+
if (!sessionContext) {
|
|
51
|
+
throw new Error("No active XY session found.");
|
|
52
|
+
}
|
|
53
|
+
const { config, sessionId, taskId, messageId } = sessionContext;
|
|
54
|
+
const wsManager = getXYWebSocketManager(config);
|
|
55
|
+
const intentParam = {};
|
|
56
|
+
if (params.startTime !== undefined)
|
|
57
|
+
intentParam.startTime = params.startTime;
|
|
58
|
+
if (params.endTime !== undefined)
|
|
59
|
+
intentParam.endTime = params.endTime;
|
|
60
|
+
if (status !== undefined)
|
|
61
|
+
intentParam.status = status;
|
|
62
|
+
const command = {
|
|
63
|
+
header: {
|
|
64
|
+
namespace: "Common",
|
|
65
|
+
name: "Action",
|
|
66
|
+
},
|
|
67
|
+
payload: {
|
|
68
|
+
cardParam: {},
|
|
69
|
+
executeParam: {
|
|
70
|
+
executeMode: "background",
|
|
71
|
+
intentName: "QueryTodoTask",
|
|
72
|
+
bundleName: "com.huawei.hmos.vassistant",
|
|
73
|
+
needUnlock: true,
|
|
74
|
+
actionResponse: true,
|
|
75
|
+
appType: "OHOS_APP",
|
|
76
|
+
timeOut: 5,
|
|
77
|
+
intentParam,
|
|
78
|
+
permissionId: [],
|
|
79
|
+
achieveType: "INTENT",
|
|
80
|
+
},
|
|
81
|
+
responses: [
|
|
82
|
+
{
|
|
83
|
+
resultCode: "",
|
|
84
|
+
displayText: "",
|
|
85
|
+
ttsText: "",
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
needUploadResult: true,
|
|
89
|
+
noHalfPage: false,
|
|
90
|
+
pageControlRelated: false,
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
return new Promise((resolve, reject) => {
|
|
94
|
+
const timeout = setTimeout(() => {
|
|
95
|
+
wsManager.off("data-event", handler);
|
|
96
|
+
reject(new Error("查询待办任务超时(60秒)"));
|
|
97
|
+
}, 60000);
|
|
98
|
+
const handler = (event) => {
|
|
99
|
+
if (event.intentName === "QueryTodoTask") {
|
|
100
|
+
clearTimeout(timeout);
|
|
101
|
+
wsManager.off("data-event", handler);
|
|
102
|
+
if (event.status === "success" && event.outputs) {
|
|
103
|
+
resolve({
|
|
104
|
+
content: [
|
|
105
|
+
{
|
|
106
|
+
type: "text",
|
|
107
|
+
text: JSON.stringify(event.outputs),
|
|
108
|
+
},
|
|
109
|
+
],
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
reject(new Error(`查询待办任务失败: ${event.status}`));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
wsManager.on("data-event", handler);
|
|
118
|
+
sendCommand({
|
|
119
|
+
config,
|
|
120
|
+
sessionId,
|
|
121
|
+
taskId,
|
|
122
|
+
messageId,
|
|
123
|
+
command,
|
|
124
|
+
})
|
|
125
|
+
.then(() => { })
|
|
126
|
+
.catch((error) => {
|
|
127
|
+
clearTimeout(timeout);
|
|
128
|
+
wsManager.off("data-event", handler);
|
|
129
|
+
reject(error);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
},
|
|
133
|
+
};
|