@ynhcj/xiaoyi-channel 0.0.168-next → 0.0.169-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/src/channel.js +53 -63
- package/dist/src/client.d.ts +5 -0
- package/dist/src/client.js +10 -0
- package/dist/src/tools/agent-as-skill-tool.d.ts +45 -2
- package/dist/src/tools/agent-as-skill-tool.js +148 -150
- package/dist/src/tools/calendar-tool.d.ts +24 -2
- package/dist/src/tools/calendar-tool.js +114 -116
- package/dist/src/tools/call-device-tool.d.ts +20 -6
- package/dist/src/tools/call-device-tool.js +115 -136
- package/dist/src/tools/call-phone-tool.d.ts +21 -2
- package/dist/src/tools/call-phone-tool.js +111 -113
- package/dist/src/tools/check-plugin-privilege-tool.d.ts +16 -2
- package/dist/src/tools/check-plugin-privilege-tool.js +140 -142
- package/dist/src/tools/create-alarm-tool.d.ts +39 -2
- package/dist/src/tools/create-alarm-tool.js +228 -230
- package/dist/src/tools/delete-alarm-tool.d.ts +15 -2
- package/dist/src/tools/delete-alarm-tool.js +133 -135
- package/dist/src/tools/discover-cross-devices-tool.d.ts +16 -2
- package/dist/src/tools/discover-cross-devices-tool.js +121 -123
- package/dist/src/tools/display-a2ui-card-tool.d.ts +27 -2
- package/dist/src/tools/display-a2ui-card-tool.js +64 -66
- package/dist/src/tools/get-alarm-tool-schema.d.ts +1 -2
- package/dist/src/tools/get-alarm-tool-schema.js +10 -16
- package/dist/src/tools/get-calendar-tool-schema.d.ts +1 -2
- package/dist/src/tools/get-calendar-tool-schema.js +8 -12
- package/dist/src/tools/get-collection-tool-schema.d.ts +1 -2
- package/dist/src/tools/get-collection-tool-schema.js +9 -11
- package/dist/src/tools/get-contact-tool-schema.d.ts +1 -2
- package/dist/src/tools/get-contact-tool-schema.js +10 -16
- package/dist/src/tools/get-device-file-tool-schema.d.ts +1 -2
- package/dist/src/tools/get-device-file-tool-schema.js +9 -13
- package/dist/src/tools/get-email-tool-schema.d.ts +1 -2
- package/dist/src/tools/get-email-tool-schema.js +8 -11
- package/dist/src/tools/get-note-tool-schema.d.ts +1 -2
- package/dist/src/tools/get-note-tool-schema.js +9 -14
- package/dist/src/tools/get-photo-tool-schema.d.ts +1 -2
- package/dist/src/tools/get-photo-tool-schema.js +9 -12
- package/dist/src/tools/image-reading-tool.d.ts +28 -2
- package/dist/src/tools/image-reading-tool.js +76 -78
- package/dist/src/tools/location-tool.d.ts +11 -2
- package/dist/src/tools/location-tool.js +93 -92
- package/dist/src/tools/login-token-tool.d.ts +20 -2
- package/dist/src/tools/login-token-tool.js +121 -123
- package/dist/src/tools/modify-alarm-tool.d.ts +47 -2
- package/dist/src/tools/modify-alarm-tool.js +249 -251
- package/dist/src/tools/modify-note-tool.d.ts +20 -2
- package/dist/src/tools/modify-note-tool.js +106 -108
- package/dist/src/tools/note-tool.d.ts +20 -2
- package/dist/src/tools/note-tool.js +105 -107
- package/dist/src/tools/query-app-message-tool.d.ts +28 -2
- package/dist/src/tools/query-app-message-tool.js +110 -112
- package/dist/src/tools/query-memory-data-tool.d.ts +28 -2
- package/dist/src/tools/query-memory-data-tool.js +111 -113
- package/dist/src/tools/query-todo-task-tool.d.ts +24 -2
- package/dist/src/tools/query-todo-task-tool.js +105 -107
- package/dist/src/tools/save-file-to-phone-tool.d.ts +24 -2
- package/dist/src/tools/save-file-to-phone-tool.js +129 -131
- package/dist/src/tools/save-media-to-gallery-tool.d.ts +24 -2
- package/dist/src/tools/save-media-to-gallery-tool.js +136 -138
- package/dist/src/tools/save-self-evolution-skill-tool.d.ts +54 -2
- package/dist/src/tools/save-self-evolution-skill-tool.js +194 -196
- package/dist/src/tools/search-alarm-tool.d.ts +34 -2
- package/dist/src/tools/search-alarm-tool.js +173 -175
- package/dist/src/tools/search-calendar-tool.d.ts +24 -2
- package/dist/src/tools/search-calendar-tool.js +147 -149
- package/dist/src/tools/search-contact-tool.d.ts +16 -2
- package/dist/src/tools/search-contact-tool.js +100 -102
- package/dist/src/tools/search-email-tool.d.ts +21 -2
- package/dist/src/tools/search-email-tool.js +109 -111
- package/dist/src/tools/search-file-tool.d.ts +16 -2
- package/dist/src/tools/search-file-tool.js +103 -105
- package/dist/src/tools/search-message-tool.d.ts +16 -2
- package/dist/src/tools/search-message-tool.js +102 -104
- package/dist/src/tools/search-note-tool.d.ts +16 -2
- package/dist/src/tools/search-note-tool.js +97 -99
- package/dist/src/tools/search-photo-gallery-tool.d.ts +21 -2
- package/dist/src/tools/search-photo-gallery-tool.js +34 -36
- package/dist/src/tools/send-cross-device-task-tool.d.ts +34 -2
- package/dist/src/tools/send-cross-device-task-tool.js +134 -137
- package/dist/src/tools/send-email-tool.d.ts +24 -2
- package/dist/src/tools/send-email-tool.js +107 -109
- package/dist/src/tools/send-file-to-user-tool.d.ts +20 -2
- package/dist/src/tools/send-file-to-user-tool.js +171 -173
- package/dist/src/tools/send-html-card-tool.d.ts +20 -2
- package/dist/src/tools/send-html-card-tool.js +84 -86
- package/dist/src/tools/send-message-tool.d.ts +20 -2
- package/dist/src/tools/send-message-tool.js +121 -123
- package/dist/src/tools/session-manager.d.ts +4 -6
- package/dist/src/tools/session-manager.js +4 -6
- package/dist/src/tools/upload-file-tool.d.ts +20 -2
- package/dist/src/tools/upload-file-tool.js +79 -81
- package/dist/src/tools/upload-photo-tool.d.ts +20 -2
- package/dist/src/tools/upload-photo-tool.js +67 -69
- package/dist/src/tools/xiaoyi-add-collection-tool.d.ts +32 -2
- package/dist/src/tools/xiaoyi-add-collection-tool.js +145 -147
- package/dist/src/tools/xiaoyi-collection-tool.d.ts +20 -2
- package/dist/src/tools/xiaoyi-collection-tool.js +113 -115
- package/dist/src/tools/xiaoyi-delete-collection-tool.d.ts +15 -2
- package/dist/src/tools/xiaoyi-delete-collection-tool.js +126 -128
- package/dist/src/tools/xiaoyi-gui-tool.d.ts +16 -2
- package/dist/src/tools/xiaoyi-gui-tool.js +91 -93
- package/dist/src/websocket.d.ts +1 -1
- package/package.json +1 -1
package/dist/src/channel.js
CHANGED
|
@@ -3,14 +3,54 @@ import { xyConfigSchema } from "./config-schema.js";
|
|
|
3
3
|
import { xyOutbound } from "./outbound.js";
|
|
4
4
|
import { filterToolsByDevice } from "./tools/device-tool-map.js";
|
|
5
5
|
import { getCurrentSessionContext } from "./tools/session-manager.js";
|
|
6
|
-
import { createAllTools } from "./tools/create-all-tools.js";
|
|
7
6
|
import { logger } from "./utils/logger.js";
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
// Static tool imports (3.24 pattern)
|
|
8
|
+
import { locationTool } from "./tools/location-tool.js";
|
|
9
|
+
import { xiaoyiGuiTool } from "./tools/xiaoyi-gui-tool.js";
|
|
10
|
+
import { sendFileToUserTool } from "./tools/send-file-to-user-tool.js";
|
|
11
|
+
import { sendHtmlCardTool } from "./tools/send-html-card-tool.js";
|
|
12
|
+
import { viewPushResultTool } from "./tools/view-push-result-tool.js";
|
|
13
|
+
import { imageReadingTool } from "./tools/image-reading-tool.js";
|
|
14
|
+
import { timestampToUtc8Tool } from "./tools/timestamp-to-utc8-tool.js";
|
|
15
|
+
import { saveSelfEvolutionSkillTool } from "./tools/save-self-evolution-skill-tool.js";
|
|
16
|
+
import { callDeviceTool } from "./tools/call-device-tool.js";
|
|
17
|
+
import { getNoteToolSchemaTool } from "./tools/get-note-tool-schema.js";
|
|
18
|
+
import { getCalendarToolSchemaTool } from "./tools/get-calendar-tool-schema.js";
|
|
19
|
+
import { getContactToolSchemaTool } from "./tools/get-contact-tool-schema.js";
|
|
20
|
+
import { getPhotoToolSchemaTool } from "./tools/get-photo-tool-schema.js";
|
|
21
|
+
import { getDeviceFileToolSchemaTool } from "./tools/get-device-file-tool-schema.js";
|
|
22
|
+
import { getAlarmToolSchemaTool } from "./tools/get-alarm-tool-schema.js";
|
|
23
|
+
import { getCollectionToolSchemaTool } from "./tools/get-collection-tool-schema.js";
|
|
24
|
+
import { loginTokenTool } from "./tools/login-token-tool.js";
|
|
25
|
+
import { agentAsSkillTool } from "./tools/agent-as-skill-tool.js";
|
|
26
|
+
import { discoverCrossDevicesTool } from "./tools/discover-cross-devices-tool.js";
|
|
27
|
+
import { sendCrossDeviceTaskTool } from "./tools/send-cross-device-task-tool.js";
|
|
28
|
+
import { displayA2UICardTool } from "./tools/display-a2ui-card-tool.js";
|
|
29
|
+
import { checkPluginPrivilegeTool } from "./tools/check-plugin-privilege-tool.js";
|
|
30
|
+
const ALL_TOOLS = [
|
|
31
|
+
locationTool,
|
|
32
|
+
discoverCrossDevicesTool,
|
|
33
|
+
sendCrossDeviceTaskTool,
|
|
34
|
+
displayA2UICardTool,
|
|
35
|
+
callDeviceTool,
|
|
36
|
+
getNoteToolSchemaTool,
|
|
37
|
+
getCalendarToolSchemaTool,
|
|
38
|
+
getContactToolSchemaTool,
|
|
39
|
+
getPhotoToolSchemaTool,
|
|
40
|
+
xiaoyiGuiTool,
|
|
41
|
+
getDeviceFileToolSchemaTool,
|
|
42
|
+
getAlarmToolSchemaTool,
|
|
43
|
+
getCollectionToolSchemaTool,
|
|
44
|
+
sendFileToUserTool,
|
|
45
|
+
sendHtmlCardTool,
|
|
46
|
+
viewPushResultTool,
|
|
47
|
+
imageReadingTool,
|
|
48
|
+
timestampToUtc8Tool,
|
|
49
|
+
saveSelfEvolutionSkillTool,
|
|
50
|
+
loginTokenTool,
|
|
51
|
+
agentAsSkillTool,
|
|
52
|
+
checkPluginPrivilegeTool,
|
|
53
|
+
];
|
|
14
54
|
/**
|
|
15
55
|
* Xiaoyi Channel Plugin for OpenClaw.
|
|
16
56
|
* Implements Xiaoyi A2A protocol with dual WebSocket connections.
|
|
@@ -32,7 +72,7 @@ export const xyPlugin = {
|
|
|
32
72
|
],
|
|
33
73
|
},
|
|
34
74
|
capabilities: {
|
|
35
|
-
chatTypes: ["direct"],
|
|
75
|
+
chatTypes: ["direct"],
|
|
36
76
|
polls: false,
|
|
37
77
|
threads: false,
|
|
38
78
|
media: true,
|
|
@@ -49,59 +89,11 @@ export const xyPlugin = {
|
|
|
49
89
|
schema: xyConfigSchema,
|
|
50
90
|
},
|
|
51
91
|
outbound: xyOutbound,
|
|
52
|
-
/**
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
* 1. **Normal (WebSocket) session** – `getCurrentSessionContext()` returns
|
|
58
|
-
* a context that was registered by bot.ts during message processing.
|
|
59
|
-
* Tools send commands through the WebSocket and listen for responses.
|
|
60
|
-
*
|
|
61
|
-
* 2. **Cron / scheduled-task session** – openclaw's cron runner calls
|
|
62
|
-
* `agentTools({ cfg })` without an active WebSocket session. When no
|
|
63
|
-
* session context exists but `cfg` is provided, we create a synthetic
|
|
64
|
-
* "cron session" with `isCron: true` and a `cron-`-prefixed sessionId.
|
|
65
|
-
* `sendCommand()` detects this prefix and routes commands through the
|
|
66
|
-
* push channel. Response listening (WebSocket events) works unchanged
|
|
67
|
-
* because the gateway WebSocket connection is always active.
|
|
68
|
-
*/
|
|
69
|
-
agentTools: (params) => {
|
|
70
|
-
let ctx = getCurrentSessionContext();
|
|
71
|
-
// ── Cron / non-session fallback ──────────────────────────────
|
|
72
|
-
// cron 路径不进 ALS: openclaw 的 cron runner 同步调 agentTools({cfg})
|
|
73
|
-
// 返回工具后才在别处跑 turn, xy_channel 没有 wrap 整个 turn 的点。
|
|
74
|
-
// 这里同步构造合成 ctx 给工具闭包捕获, 工具调用走 sendCommand/push,
|
|
75
|
-
// 不依赖 getCurrentSessionContext。所以不注册任何全局状态。
|
|
76
|
-
if (!ctx && params?.cfg) {
|
|
77
|
-
try {
|
|
78
|
-
const config = resolveXYConfig(params.cfg);
|
|
79
|
-
const cronId = `${CRON_SESSION_PREFIX}${Date.now()}-${Math.random().toString(36).substring(2, 8)}`;
|
|
80
|
-
ctx = {
|
|
81
|
-
config,
|
|
82
|
-
sessionId: cronId,
|
|
83
|
-
taskId: cronId,
|
|
84
|
-
messageId: cronId,
|
|
85
|
-
agentId: "default",
|
|
86
|
-
isCron: true,
|
|
87
|
-
};
|
|
88
|
-
logger.log(`[ALS-PROOF] agentTools ctx from ALS miss, using synthetic cron ctx sessionId=${cronId} isCron=true`);
|
|
89
|
-
logger.log(`[CRON-TOOLS] Created cron session context: ${cronId}`);
|
|
90
|
-
}
|
|
91
|
-
catch (err) {
|
|
92
|
-
logger.error("[CRON-TOOLS] Failed to create cron context:", err);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
else {
|
|
96
|
-
logger.log(`[ALS-PROOF] agentTools ctx from ALS sessionId=${ctx?.sessionId} taskId=${ctx?.taskId} isCron=${ctx?.isCron === true}`);
|
|
97
|
-
}
|
|
98
|
-
if (!ctx) {
|
|
99
|
-
logger.log("[CREATE-ALL-TOOLS] no session context, returning empty tools list");
|
|
100
|
-
return [];
|
|
101
|
-
}
|
|
102
|
-
const allTools = createAllTools(ctx);
|
|
103
|
-
const filtered = filterToolsByDevice(allTools, ctx.deviceType);
|
|
104
|
-
logger.log(`[DEVICE-FILTER] deviceType=${ctx.deviceType ?? "(none)"}, tools: ${allTools.length} → ${filtered.length} (${filtered.map(t => t.name).join(", ")})`);
|
|
92
|
+
/** Static tool list (3.24 pattern). Tools read SessionContext at execute time via ALS. */
|
|
93
|
+
agentTools: () => {
|
|
94
|
+
const ctx = getCurrentSessionContext();
|
|
95
|
+
const filtered = filterToolsByDevice(ALL_TOOLS, ctx?.deviceType);
|
|
96
|
+
logger.log(`[DEVICE-FILTER] deviceType=${ctx?.deviceType ?? "(none)"}, tools: ${ALL_TOOLS.length} → ${filtered.length} (${filtered.map(t => t.name).join(", ")})`);
|
|
105
97
|
return filtered;
|
|
106
98
|
},
|
|
107
99
|
messaging: {
|
|
@@ -113,7 +105,6 @@ export const xyPlugin = {
|
|
|
113
105
|
},
|
|
114
106
|
targetResolver: {
|
|
115
107
|
looksLikeId: (raw) => {
|
|
116
|
-
// 信任所有非空字符串作为有效的 sessionId
|
|
117
108
|
const trimmed = raw.trim();
|
|
118
109
|
return trimmed.length > 0;
|
|
119
110
|
},
|
|
@@ -139,7 +130,6 @@ export const xyPlugin = {
|
|
|
139
130
|
reload: {
|
|
140
131
|
configPrefixes: ["channels.xiaoyi-channel"],
|
|
141
132
|
},
|
|
142
|
-
// Gateway adapter for receiving messages
|
|
143
133
|
gateway: {
|
|
144
134
|
async startAccount(context) {
|
|
145
135
|
const { monitorXYProvider } = await import("./monitor.js");
|
package/dist/src/client.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { XYWebSocketManager } from "./websocket.js";
|
|
2
2
|
import type { XYChannelConfig } from "./types.js";
|
|
3
3
|
import type { RuntimeEnv } from "openclaw/plugin-sdk";
|
|
4
|
+
/**
|
|
5
|
+
* Get a cached WebSocket manager without requiring config.
|
|
6
|
+
* Returns the first available manager. Use when ALS has no SessionContext.
|
|
7
|
+
*/
|
|
8
|
+
export declare function getCachedXYWebSocketManager(): XYWebSocketManager;
|
|
4
9
|
/**
|
|
5
10
|
* Get or create a WebSocket manager for the given configuration.
|
|
6
11
|
* Reuses existing managers if config matches.
|
package/dist/src/client.js
CHANGED
|
@@ -13,6 +13,16 @@ if (!_g.__xyWsManagerCache) {
|
|
|
13
13
|
_g.__xyWsManagerCache = new Map();
|
|
14
14
|
}
|
|
15
15
|
const wsManagerCache = _g.__xyWsManagerCache;
|
|
16
|
+
/**
|
|
17
|
+
* Get a cached WebSocket manager without requiring config.
|
|
18
|
+
* Returns the first available manager. Use when ALS has no SessionContext.
|
|
19
|
+
*/
|
|
20
|
+
export function getCachedXYWebSocketManager() {
|
|
21
|
+
if (wsManagerCache.size === 0) {
|
|
22
|
+
throw new Error("No WebSocket manager available in cache");
|
|
23
|
+
}
|
|
24
|
+
return wsManagerCache.values().next().value;
|
|
25
|
+
}
|
|
16
26
|
/**
|
|
17
27
|
* Get or create a WebSocket manager for the given configuration.
|
|
18
28
|
* Reuses existing managers if config matches.
|
|
@@ -1,7 +1,50 @@
|
|
|
1
|
-
import type { SessionContext } from "./session-manager.js";
|
|
2
1
|
/**
|
|
3
2
|
* Agent-as-skill tool - invokes a registered agent by agentId as a skill.
|
|
4
3
|
* The tool receives the agentId, query, and optional file attachments,
|
|
5
4
|
* forwards the request to the target agent via WebSocket, and returns the result.
|
|
6
5
|
*/
|
|
7
|
-
export declare
|
|
6
|
+
export declare const agentAsSkillTool: {
|
|
7
|
+
name: string;
|
|
8
|
+
label: string;
|
|
9
|
+
description: string;
|
|
10
|
+
parameters: {
|
|
11
|
+
type: string;
|
|
12
|
+
properties: {
|
|
13
|
+
agentId: {
|
|
14
|
+
type: string;
|
|
15
|
+
description: string;
|
|
16
|
+
};
|
|
17
|
+
query: {
|
|
18
|
+
type: string;
|
|
19
|
+
description: string;
|
|
20
|
+
};
|
|
21
|
+
filesInfo: {
|
|
22
|
+
description: string;
|
|
23
|
+
items: {
|
|
24
|
+
type: string;
|
|
25
|
+
properties: {
|
|
26
|
+
fileType: {
|
|
27
|
+
type: string;
|
|
28
|
+
description: string;
|
|
29
|
+
enum: string[];
|
|
30
|
+
};
|
|
31
|
+
fileId: {
|
|
32
|
+
type: string;
|
|
33
|
+
description: string;
|
|
34
|
+
};
|
|
35
|
+
fileUrl: {
|
|
36
|
+
type: string;
|
|
37
|
+
description: string;
|
|
38
|
+
};
|
|
39
|
+
fileUrlLocal: {
|
|
40
|
+
type: string;
|
|
41
|
+
description: string;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
required: string[];
|
|
48
|
+
};
|
|
49
|
+
execute(toolCallId: string, params: any): Promise<unknown>;
|
|
50
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Agent-as-skill tool implementation - invokes another agent as a skill
|
|
2
|
-
import {
|
|
2
|
+
import { getCachedXYWebSocketManager } from "../client.js";
|
|
3
3
|
import { sendCommand } from "../formatter.js";
|
|
4
4
|
import { getCurrentSessionContext } from './session-manager.js';
|
|
5
5
|
import { logger } from "../utils/logger.js";
|
|
@@ -9,11 +9,10 @@ import { XYFileUploadService } from "../file-upload.js";
|
|
|
9
9
|
* The tool receives the agentId, query, and optional file attachments,
|
|
10
10
|
* forwards the request to the target agent via WebSocket, and returns the result.
|
|
11
11
|
*/
|
|
12
|
-
export
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
description: `智能体作为skill的执行元工具。当需要调用其他已注册的Agent来执行特定任务时使用此工具。
|
|
12
|
+
export const agentAsSkillTool = {
|
|
13
|
+
name: "agent_as_a_tool",
|
|
14
|
+
label: "Agent as Skill Tool",
|
|
15
|
+
description: `智能体作为skill的执行元工具。当需要调用其他已注册的Agent来执行特定任务时使用此工具。
|
|
17
16
|
该工具会将用户请求和可选的附件文件转发给目标Agent执行,并返回执行结果。
|
|
18
17
|
|
|
19
18
|
使用场景:
|
|
@@ -25,166 +24,165 @@ export function createAgentAsSkillTool(ctx) {
|
|
|
25
24
|
- 操作超时时间为5分钟
|
|
26
25
|
- 该工具执行期间必须严格等待结果返回,不要执行其他操作
|
|
27
26
|
- 如果超时或失败,最多重试一次`,
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
},
|
|
27
|
+
parameters: {
|
|
28
|
+
type: "object",
|
|
29
|
+
properties: {
|
|
30
|
+
agentId: {
|
|
31
|
+
type: "string",
|
|
32
|
+
description: "待执行的AgentId,精准匹配系统注册的AgentId",
|
|
33
|
+
},
|
|
34
|
+
query: {
|
|
35
|
+
type: "string",
|
|
36
|
+
description: "用户原始请求文本,原样转发给目标Agent执行",
|
|
37
|
+
},
|
|
38
|
+
filesInfo: {
|
|
39
|
+
description: "附件文件/图片信息列表,无文件时可传null或空数组,支持传入数组或JSON字符串",
|
|
40
|
+
items: {
|
|
41
|
+
type: "object",
|
|
42
|
+
properties: {
|
|
43
|
+
fileType: {
|
|
44
|
+
type: "string",
|
|
45
|
+
description: "文件类型:file 或 image",
|
|
46
|
+
enum: ["file", "image"],
|
|
47
|
+
},
|
|
48
|
+
fileId: {
|
|
49
|
+
type: "string",
|
|
50
|
+
description: "文件全局唯一标识",
|
|
51
|
+
},
|
|
52
|
+
fileUrl: {
|
|
53
|
+
type: "string",
|
|
54
|
+
description: "文件可访问下载链接(完整HTTP/HTTPS地址)",
|
|
55
|
+
},
|
|
56
|
+
fileUrlLocal: {
|
|
57
|
+
type: "string",
|
|
58
|
+
description: "文件本地路径,如果提供此字段,工具会自动上传文件并将公网URL填入fileUrl",
|
|
61
59
|
},
|
|
62
60
|
},
|
|
63
61
|
},
|
|
64
62
|
},
|
|
65
|
-
required: ["agentId", "query"],
|
|
66
63
|
},
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
64
|
+
required: ["agentId", "query"],
|
|
65
|
+
},
|
|
66
|
+
async execute(toolCallId, params) {
|
|
67
|
+
const _c = getCurrentSessionContext();
|
|
68
|
+
const { config, sessionId, taskId, messageId } = _c;
|
|
69
|
+
// Dynamic lookup: use latest taskId from task-manager (handles steer/interrupt)
|
|
70
|
+
// Validate parameters
|
|
71
|
+
if (!params.agentId || typeof params.agentId !== "string") {
|
|
72
|
+
throw new Error("Missing or invalid required parameter: agentId must be a non-empty string");
|
|
73
|
+
}
|
|
74
|
+
if (!params.query || typeof params.query !== "string") {
|
|
75
|
+
throw new Error("Missing or invalid required parameter: query must be a non-empty string");
|
|
76
|
+
}
|
|
77
|
+
// Robust parsing: normalize filesInfo from array or JSON string
|
|
78
|
+
let filesInfo = null;
|
|
79
|
+
if (params.filesInfo) {
|
|
80
|
+
if (Array.isArray(params.filesInfo)) {
|
|
81
|
+
filesInfo = params.filesInfo;
|
|
77
82
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
else if (typeof params.filesInfo === 'string') {
|
|
85
|
-
try {
|
|
86
|
-
const parsed = JSON.parse(params.filesInfo);
|
|
87
|
-
if (Array.isArray(parsed)) {
|
|
88
|
-
filesInfo = parsed;
|
|
89
|
-
}
|
|
90
|
-
else {
|
|
91
|
-
throw new Error("filesInfo must be an array or a JSON string representing an array");
|
|
92
|
-
}
|
|
83
|
+
else if (typeof params.filesInfo === 'string') {
|
|
84
|
+
try {
|
|
85
|
+
const parsed = JSON.parse(params.filesInfo);
|
|
86
|
+
if (Array.isArray(parsed)) {
|
|
87
|
+
filesInfo = parsed;
|
|
93
88
|
}
|
|
94
|
-
|
|
95
|
-
throw new Error(
|
|
89
|
+
else {
|
|
90
|
+
throw new Error("filesInfo must be an array or a JSON string representing an array");
|
|
96
91
|
}
|
|
97
92
|
}
|
|
98
|
-
|
|
99
|
-
filesInfo
|
|
93
|
+
catch (parseError) {
|
|
94
|
+
throw new Error(`filesInfo JSON解析失败: ${parseError instanceof Error ? parseError.message : String(parseError)}`);
|
|
100
95
|
}
|
|
101
96
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
const uploadService = new XYFileUploadService(config.fileUploadUrl, config.apiKey, config.uid);
|
|
105
|
-
for (const fileInfo of filesInfo) {
|
|
106
|
-
if (fileInfo.fileUrlLocal && !fileInfo.fileUrl) {
|
|
107
|
-
try {
|
|
108
|
-
const publicUrl = await uploadService.uploadFileAndGetUrl(fileInfo.fileUrlLocal, "TEMPORARY_MATERIAL_DOC");
|
|
109
|
-
if (publicUrl) {
|
|
110
|
-
fileInfo.fileUrl = publicUrl;
|
|
111
|
-
}
|
|
112
|
-
else {
|
|
113
|
-
logger.warn("[AGENT-AS-SKILL] 上传文件未返回公网URL", { fileUrlLocal: fileInfo.fileUrlLocal });
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
catch (uploadError) {
|
|
117
|
-
logger.error("[AGENT-AS-SKILL] 上传本地文件失败", { fileUrlLocal: fileInfo.fileUrlLocal, error: uploadError });
|
|
118
|
-
throw new Error(`上传本地文件失败 (${fileInfo.fileUrlLocal}): ${uploadError instanceof Error ? uploadError.message : String(uploadError)}`);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
// Remove fileUrlLocal from the final payload
|
|
122
|
-
delete fileInfo.fileUrlLocal;
|
|
123
|
-
}
|
|
97
|
+
else {
|
|
98
|
+
filesInfo = null;
|
|
124
99
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
query: params.query,
|
|
136
|
-
filesInfo: filesInfo || null,
|
|
137
|
-
},
|
|
138
|
-
};
|
|
139
|
-
// Send command and wait for response (5 minute timeout)
|
|
140
|
-
return new Promise((resolve, reject) => {
|
|
141
|
-
const timeout = setTimeout(() => {
|
|
142
|
-
wsManager.off("agent-as-skill-response", handler);
|
|
143
|
-
logger.error("超时: Agent-as-Skill 操作超时(5分钟)", { agentId: params.agentId, toolCallId });
|
|
144
|
-
reject(new Error("Agent-as-Skill 操作超时(5分钟)"));
|
|
145
|
-
}, 300000); // 5 minutes timeout
|
|
146
|
-
// Listen for Agent-as-Skill response events
|
|
147
|
-
const handler = (event) => {
|
|
148
|
-
// Check if this is the ExecuteAgentAsSkillResponse we're waiting for
|
|
149
|
-
if (event.header?.namespace === "System" &&
|
|
150
|
-
event.header?.name === "ExecuteAgentAsSkillResponse") {
|
|
151
|
-
clearTimeout(timeout);
|
|
152
|
-
wsManager.off("agent-as-skill-response", handler);
|
|
153
|
-
// Return the payload directly as the tool result
|
|
154
|
-
const payload = event.payload;
|
|
155
|
-
if (payload) {
|
|
156
|
-
resolve({
|
|
157
|
-
content: [
|
|
158
|
-
{
|
|
159
|
-
type: "text",
|
|
160
|
-
text: typeof payload === "string" ? payload : JSON.stringify(payload),
|
|
161
|
-
},
|
|
162
|
-
],
|
|
163
|
-
});
|
|
100
|
+
}
|
|
101
|
+
// Upload local files and fill fileUrl
|
|
102
|
+
if (filesInfo && filesInfo.length > 0) {
|
|
103
|
+
const uploadService = new XYFileUploadService(config.fileUploadUrl, config.apiKey, config.uid);
|
|
104
|
+
for (const fileInfo of filesInfo) {
|
|
105
|
+
if (fileInfo.fileUrlLocal && !fileInfo.fileUrl) {
|
|
106
|
+
try {
|
|
107
|
+
const publicUrl = await uploadService.uploadFileAndGetUrl(fileInfo.fileUrlLocal, "TEMPORARY_MATERIAL_DOC");
|
|
108
|
+
if (publicUrl) {
|
|
109
|
+
fileInfo.fileUrl = publicUrl;
|
|
164
110
|
}
|
|
165
111
|
else {
|
|
166
|
-
|
|
112
|
+
logger.warn("[AGENT-AS-SKILL] 上传文件未返回公网URL", { fileUrlLocal: fileInfo.fileUrlLocal });
|
|
167
113
|
}
|
|
168
114
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
115
|
+
catch (uploadError) {
|
|
116
|
+
logger.error("[AGENT-AS-SKILL] 上传本地文件失败", { fileUrlLocal: fileInfo.fileUrlLocal, error: uploadError });
|
|
117
|
+
throw new Error(`上传本地文件失败 (${fileInfo.fileUrlLocal}): ${uploadError instanceof Error ? uploadError.message : String(uploadError)}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// Remove fileUrlLocal from the final payload
|
|
121
|
+
delete fileInfo.fileUrlLocal;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// Get WebSocket manager
|
|
125
|
+
const wsManager = getCachedXYWebSocketManager();
|
|
126
|
+
// Build ExecuteAgentAsSkill command
|
|
127
|
+
const command = {
|
|
128
|
+
header: {
|
|
129
|
+
namespace: "System",
|
|
130
|
+
name: "ExecuteAgentAsSkill",
|
|
131
|
+
},
|
|
132
|
+
payload: {
|
|
133
|
+
agentId: params.agentId,
|
|
134
|
+
query: params.query,
|
|
135
|
+
filesInfo: filesInfo || null,
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
// Send command and wait for response (5 minute timeout)
|
|
139
|
+
return new Promise((resolve, reject) => {
|
|
140
|
+
const timeout = setTimeout(() => {
|
|
141
|
+
wsManager.off("agent-as-skill-response", handler);
|
|
142
|
+
logger.error("超时: Agent-as-Skill 操作超时(5分钟)", { agentId: params.agentId, toolCallId });
|
|
143
|
+
reject(new Error("Agent-as-Skill 操作超时(5分钟)"));
|
|
144
|
+
}, 300000); // 5 minutes timeout
|
|
145
|
+
// Listen for Agent-as-Skill response events
|
|
146
|
+
const handler = (event) => {
|
|
147
|
+
// Check if this is the ExecuteAgentAsSkillResponse we're waiting for
|
|
148
|
+
if (event.header?.namespace === "System" &&
|
|
149
|
+
event.header?.name === "ExecuteAgentAsSkillResponse") {
|
|
183
150
|
clearTimeout(timeout);
|
|
184
151
|
wsManager.off("agent-as-skill-response", handler);
|
|
185
|
-
|
|
186
|
-
|
|
152
|
+
// Return the payload directly as the tool result
|
|
153
|
+
const payload = event.payload;
|
|
154
|
+
if (payload) {
|
|
155
|
+
resolve({
|
|
156
|
+
content: [
|
|
157
|
+
{
|
|
158
|
+
type: "text",
|
|
159
|
+
text: typeof payload === "string" ? payload : JSON.stringify(payload),
|
|
160
|
+
},
|
|
161
|
+
],
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
reject(new Error("Agent-as-Skill 响应格式错误:缺少 payload"));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
// Register event handler
|
|
170
|
+
wsManager.on("agent-as-skill-response", handler);
|
|
171
|
+
// Send the command
|
|
172
|
+
sendCommand({
|
|
173
|
+
config,
|
|
174
|
+
sessionId,
|
|
175
|
+
taskId,
|
|
176
|
+
messageId,
|
|
177
|
+
command,
|
|
178
|
+
toolCallId,
|
|
179
|
+
}).then(() => {
|
|
180
|
+
logger.log("[AGENT-AS-SKILL] Command sent successfully", { agentId: params.agentId });
|
|
181
|
+
}).catch((error) => {
|
|
182
|
+
clearTimeout(timeout);
|
|
183
|
+
wsManager.off("agent-as-skill-response", handler);
|
|
184
|
+
reject(error);
|
|
187
185
|
});
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
186
|
+
});
|
|
187
|
+
},
|
|
188
|
+
};
|
|
@@ -1,7 +1,29 @@
|
|
|
1
|
-
import type { SessionContext } from "./session-manager.js";
|
|
2
1
|
/**
|
|
3
2
|
* XY calendar event tool - creates a calendar event on user's device.
|
|
4
3
|
* Requires title, dtStart (start time), and dtEnd (end time) parameters.
|
|
5
4
|
* Time format must be: yyyy-mm-dd hh:mm:ss
|
|
6
5
|
*/
|
|
7
|
-
export declare
|
|
6
|
+
export declare const calendarTool: {
|
|
7
|
+
name: string;
|
|
8
|
+
label: string;
|
|
9
|
+
description: string;
|
|
10
|
+
parameters: {
|
|
11
|
+
type: string;
|
|
12
|
+
properties: {
|
|
13
|
+
title: {
|
|
14
|
+
type: string;
|
|
15
|
+
description: string;
|
|
16
|
+
};
|
|
17
|
+
dtStart: {
|
|
18
|
+
type: string;
|
|
19
|
+
description: string;
|
|
20
|
+
};
|
|
21
|
+
dtEnd: {
|
|
22
|
+
type: string;
|
|
23
|
+
description: string;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
required: string[];
|
|
27
|
+
};
|
|
28
|
+
execute(toolCallId: string, params: any): Promise<unknown>;
|
|
29
|
+
};
|