@ynhcj/xiaoyi-channel 0.0.97-beta → 0.0.97-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/provider-discovery.d.ts +2 -0
- package/dist/provider-discovery.js +4 -0
- package/dist/src/bot.js +29 -4
- package/dist/src/channel.js +2 -19
- package/dist/src/client.js +31 -22
- package/dist/src/cspl/call-api.js +6 -5
- package/dist/src/file-download.js +4 -3
- package/dist/src/file-upload.js +19 -18
- package/dist/src/formatter.d.ts +2 -0
- package/dist/src/formatter.js +9 -28
- package/dist/src/heartbeat.js +1 -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 +70 -14
- package/dist/src/outbound.js +19 -18
- package/dist/src/provider.d.ts +2 -1
- package/dist/src/provider.js +245 -38
- package/dist/src/push.js +16 -15
- package/dist/src/reply-dispatcher.js +12 -3
- package/dist/src/runtime.d.ts +3 -11
- package/dist/src/runtime.js +6 -18
- package/dist/src/self-evolution-handler.d.ts +6 -0
- package/dist/src/self-evolution-handler.js +100 -7
- 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 +83 -0
- package/dist/src/skill-retriever/tool-search.d.ts +16 -0
- package/dist/src/skill-retriever/tool-search.js +173 -0
- package/dist/src/skill-retriever/types.d.ts +36 -0
- package/dist/src/skill-retriever/types.js +1 -0
- package/dist/src/steer-injector.js +1 -1
- 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 +2 -1
- package/dist/src/tools/call-device-tool.js +126 -103
- 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/get-alarm-tool-schema.d.ts +2 -1
- package/dist/src/tools/get-alarm-tool-schema.js +16 -10
- package/dist/src/tools/get-calendar-tool-schema.d.ts +2 -1
- package/dist/src/tools/get-calendar-tool-schema.js +12 -8
- package/dist/src/tools/get-collection-tool-schema.d.ts +2 -1
- package/dist/src/tools/get-collection-tool-schema.js +11 -9
- package/dist/src/tools/get-contact-tool-schema.d.ts +2 -1
- package/dist/src/tools/get-contact-tool-schema.js +16 -10
- package/dist/src/tools/get-device-file-tool-schema.d.ts +2 -1
- package/dist/src/tools/get-device-file-tool-schema.js +13 -9
- package/dist/src/tools/get-email-tool-schema.d.ts +2 -1
- package/dist/src/tools/get-email-tool-schema.js +11 -8
- package/dist/src/tools/get-note-tool-schema.d.ts +2 -1
- package/dist/src/tools/get-note-tool-schema.js +14 -9
- package/dist/src/tools/get-photo-tool-schema.d.ts +2 -1
- package/dist/src/tools/get-photo-tool-schema.js +12 -9
- 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 +2 -1
- package/dist/src/tools/query-app-message-tool.js +108 -111
- package/dist/src/tools/query-memory-data-tool.d.ts +2 -1
- package/dist/src/tools/query-memory-data-tool.js +109 -112
- package/dist/src/tools/query-todo-task-tool.d.ts +2 -1
- package/dist/src/tools/query-todo-task-tool.js +103 -106
- 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/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 +2 -1
- package/dist/src/tools/send-email-tool.js +105 -108
- package/dist/src/tools/send-file-to-user-tool.d.ts +2 -1
- package/dist/src/tools/send-file-to-user-tool.js +154 -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 +147 -18
- package/dist/src/tools/upload-file-tool.d.ts +2 -1
- package/dist/src/tools/upload-file-tool.js +78 -82
- package/dist/src/tools/upload-photo-tool.d.ts +2 -1
- package/dist/src/tools/upload-photo-tool.js +69 -73
- 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 +111 -115
- 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/logger.js +20 -18
- 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 +69 -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 +91 -26
- package/openclaw.plugin.json +22 -0
- package/package.json +3 -3
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
import * as os from "os";
|
|
4
|
+
import { logger } from "../utils/logger.js";
|
|
5
|
+
const SKILL_ID = "celia_find_skills";
|
|
6
|
+
const PLUGIN_LOG_PREFIX = "[skill-retriever]";
|
|
7
|
+
export function extractUserQuery(fullPrompt) {
|
|
8
|
+
const lastNewlineIndex = fullPrompt.lastIndexOf("\n");
|
|
9
|
+
if (lastNewlineIndex === -1) {
|
|
10
|
+
return fullPrompt.trim();
|
|
11
|
+
}
|
|
12
|
+
const afterLastNewline = fullPrompt.slice(lastNewlineIndex + 1).trim();
|
|
13
|
+
if (!afterLastNewline || afterLastNewline === "```") {
|
|
14
|
+
return "";
|
|
15
|
+
}
|
|
16
|
+
if (fullPrompt.toLowerCase().includes("cron")) {
|
|
17
|
+
return "";
|
|
18
|
+
}
|
|
19
|
+
return afterLastNewline;
|
|
20
|
+
}
|
|
21
|
+
function expandPath(filePath) {
|
|
22
|
+
if (filePath.startsWith("~")) {
|
|
23
|
+
return path.join(os.homedir(), filePath.slice(1).replace(/^\/+/, ""));
|
|
24
|
+
}
|
|
25
|
+
return filePath;
|
|
26
|
+
}
|
|
27
|
+
export function readEnvFile(filePath) {
|
|
28
|
+
const expandedPath = expandPath(filePath);
|
|
29
|
+
const envDict = {};
|
|
30
|
+
try {
|
|
31
|
+
const content = fs.readFileSync(expandedPath, "utf-8");
|
|
32
|
+
for (const line of content.split("\n")) {
|
|
33
|
+
const trimmed = line.trim();
|
|
34
|
+
if (!trimmed || trimmed.startsWith("#")) {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
const eqIndex = trimmed.indexOf("=");
|
|
38
|
+
if (eqIndex > 0) {
|
|
39
|
+
let key = trimmed.substring(0, eqIndex).trim();
|
|
40
|
+
const value = trimmed.substring(eqIndex + 1).trim();
|
|
41
|
+
key = key.replace(/-/g, "_");
|
|
42
|
+
envDict[key] = value;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// File not found or read error - return empty config
|
|
48
|
+
}
|
|
49
|
+
return envDict;
|
|
50
|
+
}
|
|
51
|
+
export function getInstalledSkills() {
|
|
52
|
+
const skillsDir = expandPath("~/.openclaw/workspace/skills");
|
|
53
|
+
const installedSkills = [];
|
|
54
|
+
try {
|
|
55
|
+
if (fs.existsSync(skillsDir) && fs.statSync(skillsDir).isDirectory()) {
|
|
56
|
+
const entries = fs.readdirSync(skillsDir);
|
|
57
|
+
for (const entry of entries) {
|
|
58
|
+
const entryPath = path.join(skillsDir, entry);
|
|
59
|
+
if (fs.statSync(entryPath).isDirectory()) {
|
|
60
|
+
installedSkills.push(entry);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// Directory doesn't exist or read error - return empty list
|
|
67
|
+
}
|
|
68
|
+
return installedSkills;
|
|
69
|
+
}
|
|
70
|
+
function formatSkillData(rawSkills, installedSkills) {
|
|
71
|
+
const formattedSkills = [];
|
|
72
|
+
for (const skill of rawSkills) {
|
|
73
|
+
const isInstalled = installedSkills.includes(skill.skillId);
|
|
74
|
+
formattedSkills.push({
|
|
75
|
+
skillId: skill.skillId,
|
|
76
|
+
skillName: skill.skillName,
|
|
77
|
+
skillDesc: skill.skillDesc,
|
|
78
|
+
downloadPath: skill.packUrl,
|
|
79
|
+
status: isInstalled ? "已安装" : "未安装",
|
|
80
|
+
rrfScore: skill.rrfScore,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
return formattedSkills;
|
|
84
|
+
}
|
|
85
|
+
export async function searchTools(options) {
|
|
86
|
+
const { query, maxTools = 5, includeUninstalledOnly = true, envFilePath = "~/.openclaw/.xiaoyienv", serviceUrl: configServiceUrl, apiKey: configApiKey, uid: configUid, timeoutMs = 1000, } = options;
|
|
87
|
+
const envConfig = readEnvFile(envFilePath);
|
|
88
|
+
const hasRequiredConfig = !!envConfig.SERVICE_URL && !!envConfig.PERSONAL_API_KEY && !!envConfig.PERSONAL_UID;
|
|
89
|
+
const serviceUrl = configServiceUrl ?? envConfig.SERVICE_URL;
|
|
90
|
+
const apiKey = configApiKey ?? envConfig.PERSONAL_API_KEY;
|
|
91
|
+
const uid = configUid ?? envConfig.PERSONAL_UID;
|
|
92
|
+
if (!serviceUrl || !apiKey || !uid) {
|
|
93
|
+
logger.warn(`${PLUGIN_LOG_PREFIX} Missing required configuration. serviceUrl: "${serviceUrl}", apiKey: "${apiKey ? '(set)' : '(missing)'} ", uid: "${uid ? '(set)' : '(missing)'}"`);
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
const traceId = crypto.randomUUID();
|
|
97
|
+
const apiUrl = `${serviceUrl}/celia-claw/v1/rest-api/skill/execute`;
|
|
98
|
+
const headers = {
|
|
99
|
+
"Content-Type": "application/json",
|
|
100
|
+
"x-skill-id": SKILL_ID,
|
|
101
|
+
"x-hag-trace-id": traceId,
|
|
102
|
+
"x-uid": uid,
|
|
103
|
+
"x-api-key": apiKey,
|
|
104
|
+
"x-request-from": "openclaw",
|
|
105
|
+
};
|
|
106
|
+
const payload = { query };
|
|
107
|
+
try {
|
|
108
|
+
const response = await fetch(apiUrl, {
|
|
109
|
+
method: "POST",
|
|
110
|
+
headers,
|
|
111
|
+
body: JSON.stringify(payload),
|
|
112
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
113
|
+
});
|
|
114
|
+
if (!response.ok) {
|
|
115
|
+
logger.warn(`${PLUGIN_LOG_PREFIX} HTTP error: ${response.status} ${response.statusText}`);
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
logger.log(`${PLUGIN_LOG_PREFIX} Received response, status: ${response.status}`);
|
|
119
|
+
const responseData = await response.json();
|
|
120
|
+
if (responseData.errorCode === "0" &&
|
|
121
|
+
responseData.content &&
|
|
122
|
+
responseData.content.skills) {
|
|
123
|
+
const rawSkills = responseData.content.skills;
|
|
124
|
+
const installedSkills = getInstalledSkills();
|
|
125
|
+
const formattedData = formatSkillData(rawSkills, installedSkills);
|
|
126
|
+
const topTools = formattedData.slice(0, 2);
|
|
127
|
+
const allInstalled = topTools.every((tool) => tool.status === "已安装");
|
|
128
|
+
if (allInstalled) {
|
|
129
|
+
logger.log(`${PLUGIN_LOG_PREFIX} [DEBUG] All top 2 skills are installed, returning null`);
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
const hasInstalledWithHighScore = topTools.some((tool) => tool.status === "已安装" && (tool.rrfScore ?? 0) >= 0.016);
|
|
133
|
+
if (hasInstalledWithHighScore) {
|
|
134
|
+
logger.log(`${PLUGIN_LOG_PREFIX} [DEBUG] Top 2 has installed skill with rrfScore >= 0.016, returning null`);
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
let filteredTools = topTools.filter((tool) => tool.status === "未安装" && (tool.rrfScore ?? 0) >= 0.016);
|
|
138
|
+
logger.log(`${PLUGIN_LOG_PREFIX} [DEBUG] After filtering uninstalled with rrfScore >= 0.016: ${filteredTools.length}, details: ${filteredTools.map((t) => `${t.skillId}(rrfScore=${t.rrfScore})`).join(", ")}`);
|
|
139
|
+
if (filteredTools.length === 0) {
|
|
140
|
+
logger.log(`${PLUGIN_LOG_PREFIX} [DEBUG] No uninstalled skills with rrfScore >= 0.016, returning null`);
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
tools: filteredTools,
|
|
145
|
+
query,
|
|
146
|
+
timestamp: Date.now(),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
logger.warn(`${PLUGIN_LOG_PREFIX} Invalid response format: ${JSON.stringify(responseData).slice(0, 200)}`);
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
const errorName = error instanceof Error ? error.name : "Unknown";
|
|
154
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
155
|
+
const errorCause = error instanceof Error && error.cause ? JSON.stringify(error.cause) : "N/A";
|
|
156
|
+
const errorStack = error instanceof Error ? error.stack?.split("\n").slice(0, 3).join(" | ") : "N/A";
|
|
157
|
+
logger.warn(`${PLUGIN_LOG_PREFIX} [ERROR] Fetch failed - name: ${errorName}, message: ${errorMessage}, cause: ${errorCause}, stack: ${errorStack}`);
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
export function formatToolsForContext(result, includeInstallUrl = true) {
|
|
162
|
+
if (!result.tools || result.tools.length === 0) {
|
|
163
|
+
return "";
|
|
164
|
+
}
|
|
165
|
+
const toolDescriptions = [];
|
|
166
|
+
for (const tool of result.tools) {
|
|
167
|
+
let description = `### ${tool.skillName}\n`;
|
|
168
|
+
description += `name: ${tool.skillId}\n`;
|
|
169
|
+
description += `description: ${tool.skillDesc}\n`;
|
|
170
|
+
toolDescriptions.push(description);
|
|
171
|
+
}
|
|
172
|
+
return toolDescriptions.join("\n\n");
|
|
173
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface ToolRetrieverConfig {
|
|
2
|
+
enabled: boolean;
|
|
3
|
+
maxTools: number;
|
|
4
|
+
includeUninstalledOnly: boolean;
|
|
5
|
+
envFilePath: string;
|
|
6
|
+
serviceUrl?: string;
|
|
7
|
+
apiKey?: string;
|
|
8
|
+
uid?: string;
|
|
9
|
+
timeoutMs?: number;
|
|
10
|
+
}
|
|
11
|
+
export interface RawSkill {
|
|
12
|
+
skillId: string;
|
|
13
|
+
skillName: string;
|
|
14
|
+
skillDesc: string;
|
|
15
|
+
packUrl: string;
|
|
16
|
+
rrfScore?: number;
|
|
17
|
+
}
|
|
18
|
+
export interface FormattedSkill {
|
|
19
|
+
skillId: string;
|
|
20
|
+
skillName: string;
|
|
21
|
+
skillDesc: string;
|
|
22
|
+
downloadPath: string;
|
|
23
|
+
status: "已安装" | "未安装";
|
|
24
|
+
rrfScore?: number;
|
|
25
|
+
}
|
|
26
|
+
export interface ToolSearchResult {
|
|
27
|
+
tools: FormattedSkill[];
|
|
28
|
+
query: string;
|
|
29
|
+
timestamp: number;
|
|
30
|
+
}
|
|
31
|
+
export interface EnvConfig {
|
|
32
|
+
PERSONAL_API_KEY?: string;
|
|
33
|
+
PERSONAL_UID?: string;
|
|
34
|
+
SERVICE_URL?: string;
|
|
35
|
+
[key: string]: string | undefined;
|
|
36
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -57,7 +57,7 @@ export async function tryInjectSteer(sessionKey, message) {
|
|
|
57
57
|
},
|
|
58
58
|
},
|
|
59
59
|
};
|
|
60
|
-
|
|
60
|
+
logger.log(`[STEER] Injecting steer for sessionId=${sessionId}, taskId=${syntheticMessage.params.id}`);
|
|
61
61
|
try {
|
|
62
62
|
await handleXYMessage({
|
|
63
63
|
cfg: cachedCfg,
|
|
@@ -48,6 +48,10 @@ export declare function hasActiveTask(sessionId: string): boolean;
|
|
|
48
48
|
* 获取完整的binding信息(用于调试)
|
|
49
49
|
*/
|
|
50
50
|
export declare function getTaskIdBinding(sessionId: string): TaskIdBinding | null;
|
|
51
|
+
/**
|
|
52
|
+
* 获取所有活跃的 task bindings(用于 gateway_stop 通知等场景)
|
|
53
|
+
*/
|
|
54
|
+
export declare function getAllActiveTaskBindings(): TaskIdBinding[];
|
|
51
55
|
/**
|
|
52
56
|
* 强制清理(错误恢复用)
|
|
53
57
|
*/
|
package/dist/src/task-manager.js
CHANGED
|
@@ -5,8 +5,13 @@ import { logger } from "./utils/logger.js";
|
|
|
5
5
|
* Session到活跃TaskId的映射
|
|
6
6
|
* Key: sessionId (注意:这里用sessionId,不是sessionKey)
|
|
7
7
|
* Value: TaskIdBinding
|
|
8
|
+
* Uses globalThis to ensure a single Map across all module copies.
|
|
8
9
|
*/
|
|
9
|
-
const
|
|
10
|
+
const _g = globalThis;
|
|
11
|
+
if (!_g.__xyActiveTaskIds) {
|
|
12
|
+
_g.__xyActiveTaskIds = new Map();
|
|
13
|
+
}
|
|
14
|
+
const activeTaskIds = _g.__xyActiveTaskIds;
|
|
10
15
|
/**
|
|
11
16
|
* 注册或更新session的活跃taskId
|
|
12
17
|
* 返回是否是更新(用于判断是否是第二条消息)
|
|
@@ -127,6 +132,12 @@ export function hasActiveTask(sessionId) {
|
|
|
127
132
|
export function getTaskIdBinding(sessionId) {
|
|
128
133
|
return activeTaskIds.get(sessionId) ?? null;
|
|
129
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* 获取所有活跃的 task bindings(用于 gateway_stop 通知等场景)
|
|
137
|
+
*/
|
|
138
|
+
export function getAllActiveTaskBindings() {
|
|
139
|
+
return Array.from(activeTaskIds.values());
|
|
140
|
+
}
|
|
130
141
|
/**
|
|
131
142
|
* 强制清理(错误恢复用)
|
|
132
143
|
*/
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import type { SessionContext } from "./session-manager.js";
|
|
1
2
|
/**
|
|
2
3
|
* XY calendar event tool - creates a calendar event on user's device.
|
|
3
4
|
* Requires title, dtStart (start time), and dtEnd (end time) parameters.
|
|
4
5
|
* Time format must be: yyyy-mm-dd hh:mm:ss
|
|
5
6
|
*/
|
|
6
|
-
export declare
|
|
7
|
+
export declare function createCalendarTool(ctx: SessionContext): any;
|
|
@@ -1,134 +1,130 @@
|
|
|
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 calendar event tool - creates a calendar event on user's device.
|
|
6
5
|
* Requires title, dtStart (start time), and dtEnd (end time) parameters.
|
|
7
6
|
* Time format must be: yyyy-mm-dd hh:mm:ss
|
|
8
7
|
*/
|
|
9
|
-
export
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
export function createCalendarTool(ctx) {
|
|
9
|
+
const { config, sessionId, taskId, messageId } = ctx;
|
|
10
|
+
return {
|
|
11
|
+
name: "create_calendar_event",
|
|
12
|
+
label: "Create Calendar Event",
|
|
13
|
+
description: `在用户设备上创建日程。需要提供日程标题、开始时间和结束时间。时间格式必须为:yyyy-mm-dd hh:mm:ss(例如:2024-01-15 14:30:00)。注意:该工具执行时间较长(最多60秒),请勿重复调用,超时或失败时最多重试一次。
|
|
13
14
|
注意事项:使用该工具之前需获取当前真实时间
|
|
14
15
|
|
|
15
16
|
回复约束:如果工具返回没有授权或者其他报错,只需要完整描述没有授权或者其他报错内容即可,不需要主动给用户提供解决方案,例如告诉用户如何授权,如何解决报错等都是不需要的,请严格遵守。
|
|
16
17
|
`,
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
18
|
+
parameters: {
|
|
19
|
+
type: "object",
|
|
20
|
+
properties: {
|
|
21
|
+
title: {
|
|
22
|
+
type: "string",
|
|
23
|
+
description: "日程标题/名称",
|
|
24
|
+
},
|
|
25
|
+
dtStart: {
|
|
26
|
+
type: "string",
|
|
27
|
+
description: "日程开始时间,格式必须为:yyyy-mm-dd hh:mm:ss(例如:2024-01-15 14:30:00)",
|
|
28
|
+
},
|
|
29
|
+
dtEnd: {
|
|
30
|
+
type: "string",
|
|
31
|
+
description: "日程结束时间,格式必须为:yyyy-mm-dd hh:mm:ss(例如:2024-01-15 17:30:00)",
|
|
32
|
+
},
|
|
31
33
|
},
|
|
34
|
+
required: ["title", "dtStart", "dtEnd"],
|
|
32
35
|
},
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const { config, sessionId, taskId, messageId } = sessionContext;
|
|
52
|
-
// Get WebSocket manager
|
|
53
|
-
const wsManager = getXYWebSocketManager(config);
|
|
54
|
-
// Build CreateCalendarEvent command
|
|
55
|
-
const command = {
|
|
56
|
-
header: {
|
|
57
|
-
namespace: "Common",
|
|
58
|
-
name: "ActionAndResult",
|
|
59
|
-
},
|
|
60
|
-
payload: {
|
|
61
|
-
cardParam: {},
|
|
62
|
-
executeParam: {
|
|
63
|
-
executeMode: "background",
|
|
64
|
-
intentName: "CreateCalendarEvent",
|
|
65
|
-
bundleName: "com.huawei.hmos.calendardata",
|
|
66
|
-
dimension: "",
|
|
67
|
-
needUnlock: true,
|
|
68
|
-
actionResponse: true,
|
|
69
|
-
timeOut: 5,
|
|
70
|
-
intentParam: {
|
|
71
|
-
title: params.title,
|
|
72
|
-
dtStart: dtStartMs,
|
|
73
|
-
dtEnd: dtEndMs,
|
|
74
|
-
},
|
|
75
|
-
achieveType: "INTENT",
|
|
36
|
+
async execute(toolCallId, params) {
|
|
37
|
+
// Validate parameters
|
|
38
|
+
if (!params.title || !params.dtStart || !params.dtEnd) {
|
|
39
|
+
throw new Error("Missing required parameters: title, dtStart, and dtEnd are required");
|
|
40
|
+
}
|
|
41
|
+
// Convert time strings to millisecond timestamps
|
|
42
|
+
const dtStartMs = new Date(params.dtStart).getTime();
|
|
43
|
+
const dtEndMs = new Date(params.dtEnd).getTime();
|
|
44
|
+
if (isNaN(dtStartMs) || isNaN(dtEndMs)) {
|
|
45
|
+
throw new Error("Invalid time format. Required format: yyyy-mm-dd hh:mm:ss (e.g., 2024-01-15 14:30:00)");
|
|
46
|
+
}
|
|
47
|
+
// Get WebSocket manager
|
|
48
|
+
const wsManager = getXYWebSocketManager(config);
|
|
49
|
+
// Build CreateCalendarEvent command
|
|
50
|
+
const command = {
|
|
51
|
+
header: {
|
|
52
|
+
namespace: "Common",
|
|
53
|
+
name: "ActionAndResult",
|
|
76
54
|
},
|
|
77
|
-
|
|
78
|
-
{
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
55
|
+
payload: {
|
|
56
|
+
cardParam: {},
|
|
57
|
+
executeParam: {
|
|
58
|
+
executeMode: "background",
|
|
59
|
+
intentName: "CreateCalendarEvent",
|
|
60
|
+
bundleName: "com.huawei.hmos.calendardata",
|
|
61
|
+
dimension: "",
|
|
62
|
+
needUnlock: true,
|
|
63
|
+
actionResponse: true,
|
|
64
|
+
timeOut: 5,
|
|
65
|
+
intentParam: {
|
|
66
|
+
title: params.title,
|
|
67
|
+
dtStart: dtStartMs,
|
|
68
|
+
dtEnd: dtEndMs,
|
|
69
|
+
},
|
|
70
|
+
achieveType: "INTENT",
|
|
82
71
|
},
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
//
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
clearTimeout(timeout);
|
|
72
|
+
responses: [
|
|
73
|
+
{
|
|
74
|
+
resultCode: "",
|
|
75
|
+
displayText: "",
|
|
76
|
+
ttsText: "",
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
needUploadResult: true,
|
|
80
|
+
noHalfPage: false,
|
|
81
|
+
pageControlRelated: false,
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
// Send command and wait for response (60 second timeout)
|
|
85
|
+
return new Promise((resolve, reject) => {
|
|
86
|
+
const timeout = setTimeout(() => {
|
|
99
87
|
wsManager.off("data-event", handler);
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
88
|
+
reject(new Error("创建日程超时(60秒)"));
|
|
89
|
+
}, 60000);
|
|
90
|
+
// Listen for data events from WebSocket
|
|
91
|
+
const handler = (event) => {
|
|
92
|
+
if (event.intentName === "CreateCalendarEvent") {
|
|
93
|
+
clearTimeout(timeout);
|
|
94
|
+
wsManager.off("data-event", handler);
|
|
95
|
+
if (event.status === "success" && event.outputs) {
|
|
96
|
+
resolve({
|
|
97
|
+
content: [
|
|
98
|
+
{
|
|
99
|
+
type: "text",
|
|
100
|
+
text: JSON.stringify(event.outputs),
|
|
101
|
+
},
|
|
102
|
+
],
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
reject(new Error(`创建日程失败: ${event.status}`));
|
|
107
|
+
}
|
|
112
108
|
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
109
|
+
};
|
|
110
|
+
// Register event handler
|
|
111
|
+
wsManager.on("data-event", handler);
|
|
112
|
+
// Send the command
|
|
113
|
+
sendCommand({
|
|
114
|
+
config,
|
|
115
|
+
sessionId,
|
|
116
|
+
taskId,
|
|
117
|
+
messageId,
|
|
118
|
+
command,
|
|
119
|
+
})
|
|
120
|
+
.then(() => {
|
|
121
|
+
})
|
|
122
|
+
.catch((error) => {
|
|
123
|
+
clearTimeout(timeout);
|
|
124
|
+
wsManager.off("data-event", handler);
|
|
125
|
+
reject(error);
|
|
126
|
+
});
|
|
131
127
|
});
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import type { SessionContext } from "./session-manager.js";
|
|
1
2
|
/**
|
|
2
3
|
* call_device_tool - 通用端工具调度器。
|
|
3
4
|
* LLM 必须先通过 get_xxx_tool_schema 获取具体工具 schema,再用本工具执行。
|
|
4
5
|
*/
|
|
5
|
-
export declare
|
|
6
|
+
export declare function createCallDeviceTool(ctx: SessionContext): any;
|