@ynhcj/xiaoyi-channel 0.0.117-beta → 0.0.117-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 +4 -5
- package/dist/index.js +72 -82
- package/dist/provider-discovery.d.ts +2 -0
- package/dist/provider-discovery.js +4 -0
- package/dist/src/bot.d.ts +2 -0
- package/dist/src/bot.js +80 -72
- package/dist/src/channel.js +2 -17
- package/dist/src/client.d.ts +1 -5
- package/dist/src/client.js +32 -37
- 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.js +32 -44
- package/dist/src/heartbeat.js +4 -3
- package/dist/src/login-token-handler.js +7 -8
- package/dist/src/message-queue.js +2 -1
- package/dist/src/monitor.js +62 -41
- package/dist/src/outbound.js +22 -18
- package/dist/src/provider.d.ts +1 -1
- package/dist/src/provider.js +120 -30
- package/dist/src/push.js +16 -15
- package/dist/src/reply-dispatcher.js +47 -48
- package/dist/src/runtime.d.ts +3 -11
- package/dist/src/runtime.js +6 -18
- package/dist/src/self-evolution-handler.js +11 -14
- 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/hooks.js +7 -16
- package/dist/src/skill-retriever/tool-search.js +16 -17
- package/dist/src/steer-injector.js +1 -1
- package/dist/src/task-manager.js +6 -1
- package/dist/src/tools/calendar-tool.d.ts +2 -1
- package/dist/src/tools/calendar-tool.js +116 -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 +113 -113
- package/dist/src/tools/create-alarm-tool.d.ts +2 -1
- package/dist/src/tools/create-alarm-tool.js +231 -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 +135 -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 +3 -2
- package/dist/src/tools/image-reading-tool.js +82 -162
- package/dist/src/tools/location-tool.d.ts +2 -1
- package/dist/src/tools/location-tool.js +91 -91
- package/dist/src/tools/login-token-tool.d.ts +2 -1
- package/dist/src/tools/login-token-tool.js +113 -116
- package/dist/src/tools/modify-alarm-tool.d.ts +2 -1
- package/dist/src/tools/modify-alarm-tool.js +236 -236
- package/dist/src/tools/modify-note-tool.d.ts +2 -1
- package/dist/src/tools/modify-note-tool.js +108 -108
- package/dist/src/tools/note-tool.d.ts +2 -1
- package/dist/src/tools/note-tool.js +107 -107
- package/dist/src/tools/query-app-message-tool.d.ts +2 -1
- package/dist/src/tools/query-app-message-tool.js +112 -111
- package/dist/src/tools/query-memory-data-tool.d.ts +2 -1
- package/dist/src/tools/query-memory-data-tool.js +113 -112
- package/dist/src/tools/query-todo-task-tool.d.ts +2 -1
- package/dist/src/tools/query-todo-task-tool.js +107 -106
- package/dist/src/tools/save-file-to-phone-tool.d.ts +2 -1
- package/dist/src/tools/save-file-to-phone-tool.js +131 -131
- package/dist/src/tools/save-media-to-gallery-tool.d.ts +2 -1
- package/dist/src/tools/save-media-to-gallery-tool.js +138 -138
- package/dist/src/tools/save-self-evolution-skill-tool.d.ts +2 -1
- package/dist/src/tools/save-self-evolution-skill-tool.js +194 -196
- package/dist/src/tools/search-alarm-tool.d.ts +2 -1
- package/dist/src/tools/search-alarm-tool.js +175 -175
- package/dist/src/tools/search-calendar-tool.d.ts +2 -1
- package/dist/src/tools/search-calendar-tool.js +149 -149
- package/dist/src/tools/search-contact-tool.d.ts +2 -1
- package/dist/src/tools/search-contact-tool.js +102 -102
- package/dist/src/tools/search-email-tool.d.ts +2 -1
- package/dist/src/tools/search-email-tool.js +111 -111
- package/dist/src/tools/search-file-tool.d.ts +2 -1
- package/dist/src/tools/search-file-tool.js +103 -103
- package/dist/src/tools/search-message-tool.d.ts +2 -1
- package/dist/src/tools/search-message-tool.js +104 -104
- package/dist/src/tools/search-note-tool.d.ts +2 -1
- package/dist/src/tools/search-note-tool.js +99 -99
- package/dist/src/tools/search-photo-gallery-tool.d.ts +2 -1
- package/dist/src/tools/search-photo-gallery-tool.js +38 -38
- package/dist/src/tools/send-email-tool.d.ts +2 -1
- package/dist/src/tools/send-email-tool.js +109 -108
- package/dist/src/tools/send-file-to-user-tool.d.ts +2 -1
- package/dist/src/tools/send-file-to-user-tool.js +157 -155
- package/dist/src/tools/send-message-tool.d.ts +2 -1
- package/dist/src/tools/send-message-tool.js +123 -123
- package/dist/src/tools/session-helper.d.ts +24 -0
- package/dist/src/tools/session-helper.js +45 -0
- package/dist/src/tools/session-manager.d.ts +29 -6
- package/dist/src/tools/session-manager.js +134 -19
- package/dist/src/tools/upload-file-tool.d.ts +2 -1
- package/dist/src/tools/upload-file-tool.js +82 -82
- package/dist/src/tools/upload-photo-tool.d.ts +2 -1
- package/dist/src/tools/upload-photo-tool.js +73 -73
- package/dist/src/tools/xiaoyi-add-collection-tool.d.ts +2 -1
- package/dist/src/tools/xiaoyi-add-collection-tool.js +147 -147
- package/dist/src/tools/xiaoyi-collection-tool.d.ts +2 -1
- package/dist/src/tools/xiaoyi-collection-tool.js +115 -115
- package/dist/src/tools/xiaoyi-delete-collection-tool.d.ts +2 -1
- package/dist/src/tools/xiaoyi-delete-collection-tool.js +128 -128
- package/dist/src/tools/xiaoyi-gui-tool.d.ts +2 -1
- package/dist/src/tools/xiaoyi-gui-tool.js +89 -88
- package/dist/src/trigger-handler.js +8 -9
- package/dist/src/utils/logger.js +105 -19
- package/dist/src/utils/self-evolution-manager.d.ts +5 -0
- package/dist/src/utils/self-evolution-manager.js +45 -23
- package/dist/src/utils/throw.d.ts +5 -0
- package/dist/src/utils/throw.js +10 -0
- package/dist/src/websocket.js +35 -31
- package/dist/src/xy-session-store.d.ts +79 -0
- package/dist/src/xy-session-store.js +153 -0
- package/openclaw.plugin.json +2 -2
- package/package.json +7 -6
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
declare const plugin: {
|
|
1
|
+
declare const _default: {
|
|
3
2
|
id: string;
|
|
4
3
|
name: string;
|
|
5
4
|
description: string;
|
|
6
5
|
configSchema: import("openclaw/plugin-sdk").OpenClawPluginConfigSchema;
|
|
7
|
-
register
|
|
8
|
-
}
|
|
9
|
-
export default
|
|
6
|
+
register: NonNullable<import("openclaw/plugin-sdk/core").OpenClawPluginDefinition["register"]>;
|
|
7
|
+
} & Pick<import("openclaw/plugin-sdk/core").OpenClawPluginDefinition, "kind" | "reload" | "nodeHostCommands" | "securityAuditCollectors">;
|
|
8
|
+
export default _default;
|
package/dist/index.js
CHANGED
|
@@ -1,98 +1,88 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { definePluginEntry } from "openclaw/plugin-sdk/core";
|
|
2
2
|
import { xiaoyiProvider } from "./src/provider.js";
|
|
3
3
|
import { xyPlugin } from "./src/channel.js";
|
|
4
4
|
import { callCsplApi } from "./src/cspl/call-api.js";
|
|
5
5
|
import { ALLOWED_TOOLS, MAX_TEXT_LENGTH, MAX_TOTAL_LENGTH, MIN_TEXT_LENGTH, STEER_ABORT_MESSAGE, } from "./src/cspl/constants.js";
|
|
6
6
|
import { extractResultText, parseSecurityResult, processText, validateAndTruncateText, } from "./src/cspl/utils.js";
|
|
7
7
|
import { setXYRuntime } from "./src/runtime.js";
|
|
8
|
+
import { logger } from "./src/utils/logger.js";
|
|
8
9
|
import { tryInjectSteer } from "./src/steer-injector.js";
|
|
9
|
-
import {
|
|
10
|
-
import { TOOL_CALL_NUDGE_THRESHOLD, toolCallNudgeManager, } from "./src/utils/tool-call-nudge-manager.js";
|
|
10
|
+
import { registerSelfEvolutionToolResultNudge } from "./src/self-evolution-tool-result-nudge.js";
|
|
11
11
|
import { createBeforePromptBuildHandler } from "./src/skill-retriever/hooks.js";
|
|
12
12
|
import { normalizeToolRetrieverConfig } from "./src/skill-retriever/config.js";
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
13
|
+
function registerFullHooks(api) {
|
|
14
|
+
// SKILL RETRIEVER HOOK: before_prompt_build hook
|
|
15
|
+
const pluginConfig = api.pluginConfig || {};
|
|
16
|
+
const skillRetrieverConfig = normalizeToolRetrieverConfig({
|
|
17
|
+
enabled: pluginConfig.skillRetrieverEnabled ?? true,
|
|
18
|
+
maxTools: pluginConfig.skillRetrieverMaxTools ?? 2,
|
|
19
|
+
includeUninstalledOnly: true,
|
|
20
|
+
envFilePath: "~/.openclaw/.xiaoyienv",
|
|
21
|
+
timeoutMs: pluginConfig.skillRetrieverTimeoutMs ?? 1000,
|
|
22
|
+
});
|
|
23
|
+
const beforePromptBuildHandler = createBeforePromptBuildHandler(skillRetrieverConfig);
|
|
24
|
+
api.on("before_prompt_build", beforePromptBuildHandler);
|
|
25
|
+
registerSelfEvolutionToolResultNudge(api);
|
|
26
|
+
api.on("after_tool_call", async (event, ctx) => {
|
|
27
|
+
if (!ALLOWED_TOOLS.includes(event.toolName)) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
logger.log(`[SENTINEL HOOK] after_tool_call triggered: toolName=${event.toolName}, sessionKey=${ctx.sessionKey ?? "none"}`);
|
|
31
|
+
try {
|
|
32
|
+
const resultText = extractResultText(event, event.toolName);
|
|
33
|
+
const resultLength = resultText.length;
|
|
34
|
+
if (resultLength <= MIN_TEXT_LENGTH || resultLength > MAX_TOTAL_LENGTH) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const questionText = {
|
|
38
|
+
subSceneID: "TOOL_OUTPUT",
|
|
39
|
+
tool: event.toolName,
|
|
40
|
+
output: [{ content: "" }],
|
|
41
|
+
};
|
|
42
|
+
const originText = processText(resultText);
|
|
43
|
+
questionText.output[0].content = originText;
|
|
44
|
+
let finalJson = JSON.stringify(questionText);
|
|
45
|
+
if (finalJson.length > MAX_TEXT_LENGTH) {
|
|
46
|
+
const diff = finalJson.length - MAX_TEXT_LENGTH;
|
|
47
|
+
const { text: trimmed } = validateAndTruncateText(originText, MAX_TEXT_LENGTH - diff);
|
|
48
|
+
questionText.output[0].content = trimmed;
|
|
49
|
+
finalJson = JSON.stringify(questionText);
|
|
50
|
+
}
|
|
51
|
+
const response = await callCsplApi(finalJson, api.config);
|
|
52
|
+
const result = parseSecurityResult(response);
|
|
53
|
+
logger.log(`[SENTINEL HOOK] Security result: status=${result.status}`);
|
|
54
|
+
if (result.status === "REJECT") {
|
|
55
|
+
await tryInjectSteer(ctx.sessionKey, STEER_ABORT_MESSAGE);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
logger.error(`[SENTINEL HOOK] after_tool_call error: ${err}`);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
25
62
|
}
|
|
26
|
-
|
|
63
|
+
export default definePluginEntry({
|
|
27
64
|
id: "xiaoyi-channel",
|
|
28
65
|
name: "Xiaoyi Channel",
|
|
29
66
|
description: "Xiaoyi channel plugin - Xiaoyi A2A protocol integration",
|
|
30
|
-
configSchema: emptyPluginConfigSchema(),
|
|
31
67
|
register(api) {
|
|
32
|
-
|
|
33
|
-
|
|
68
|
+
// Always register the provider so wrapStreamFn/prepareExtraParams work
|
|
69
|
+
// in ALL registration modes (not just "full").
|
|
34
70
|
api.registerProvider(xiaoyiProvider);
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
api.
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
api.logger.debug?.(`[SELF_EVOLUTION] Tool call counted: tool=${event.toolName}, count=${count}, threshold=${TOOL_CALL_NUDGE_THRESHOLD}, sessionKey=${ctx.sessionKey}`);
|
|
52
|
-
if (shouldNudge) {
|
|
53
|
-
api.logger.info?.(`[SELF_EVOLUTION] Tool call threshold reached, injecting nudge: count=${count}, sessionKey=${ctx.sessionKey}`);
|
|
54
|
-
await tryInjectSteer(ctx.sessionKey, SELF_EVOLUTION_NUDGE_MESSAGE);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
catch (err) {
|
|
58
|
-
api.logger.error(`[SELF_EVOLUTION] after_tool_call nudge error: ${err}`);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
if (!ALLOWED_TOOLS.includes(event.toolName)) {
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
console.log(`[SENTINEL HOOK] after_tool_call triggered: toolName=${event.toolName}, sessionKey=${ctx.sessionKey ?? "none"}`);
|
|
65
|
-
try {
|
|
66
|
-
const resultText = extractResultText(event, event.toolName);
|
|
67
|
-
const resultLength = resultText.length;
|
|
68
|
-
if (resultLength <= MIN_TEXT_LENGTH || resultLength > MAX_TOTAL_LENGTH) {
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
const questionText = {
|
|
72
|
-
subSceneID: "TOOL_OUTPUT",
|
|
73
|
-
tool: event.toolName,
|
|
74
|
-
output: [{ content: "" }],
|
|
75
|
-
};
|
|
76
|
-
const originText = processText(resultText);
|
|
77
|
-
questionText.output[0].content = originText;
|
|
78
|
-
let finalJson = JSON.stringify(questionText);
|
|
79
|
-
if (finalJson.length > MAX_TEXT_LENGTH) {
|
|
80
|
-
const diff = finalJson.length - MAX_TEXT_LENGTH;
|
|
81
|
-
const { text: trimmed } = validateAndTruncateText(originText, MAX_TEXT_LENGTH - diff);
|
|
82
|
-
questionText.output[0].content = trimmed;
|
|
83
|
-
finalJson = JSON.stringify(questionText);
|
|
84
|
-
}
|
|
85
|
-
const response = await callCsplApi(finalJson, api.config);
|
|
86
|
-
const result = parseSecurityResult(response);
|
|
87
|
-
console.log(`[SENTINEL HOOK] Security result: status=${result.status}`);
|
|
88
|
-
if (result.status === "REJECT") {
|
|
89
|
-
await tryInjectSteer(ctx.sessionKey, STEER_ABORT_MESSAGE);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
catch (err) {
|
|
93
|
-
api.logger.error(`[SENTINEL HOOK] after_tool_call error: ${err}`);
|
|
94
|
-
}
|
|
95
|
-
});
|
|
71
|
+
if (api.registrationMode === "cli-metadata") {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (api.registrationMode === "tool-discovery") {
|
|
75
|
+
registerFullHooks(api);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
// Register channel plugin and set runtime
|
|
79
|
+
api.registerChannel({ plugin: xyPlugin });
|
|
80
|
+
setXYRuntime(api.runtime);
|
|
81
|
+
if (api.registrationMode === "discovery") {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (api.registrationMode === "full") {
|
|
85
|
+
registerFullHooks(api);
|
|
86
|
+
}
|
|
96
87
|
},
|
|
97
|
-
};
|
|
98
|
-
export default plugin;
|
|
88
|
+
});
|
package/dist/src/bot.d.ts
CHANGED
|
@@ -9,6 +9,8 @@ export interface HandleXYMessageParams {
|
|
|
9
9
|
message: A2AJsonRpcRequest;
|
|
10
10
|
accountId: string;
|
|
11
11
|
webSocketSessionId?: string;
|
|
12
|
+
/** Called after dispatch init is complete (agentTools/wrapStreamFn done). */
|
|
13
|
+
onInitComplete?: () => void;
|
|
12
14
|
}
|
|
13
15
|
/**
|
|
14
16
|
* Handle an incoming A2A message.
|
package/dist/src/bot.js
CHANGED
|
@@ -14,6 +14,7 @@ import { selfEvolutionManager } from "./utils/self-evolution-manager.js";
|
|
|
14
14
|
import { saveRuntimeInfo } from "./utils/runtime-manager.js";
|
|
15
15
|
import { toolCallNudgeManager } from "./utils/tool-call-nudge-manager.js";
|
|
16
16
|
import { registerTaskId, decrementTaskIdRef, lockTaskId, unlockTaskId, hasActiveTask, } from "./task-manager.js";
|
|
17
|
+
import { logger } from "./utils/logger.js";
|
|
17
18
|
/**
|
|
18
19
|
* Handle an incoming A2A message.
|
|
19
20
|
* This is the main entry point for message processing.
|
|
@@ -21,8 +22,6 @@ import { registerTaskId, decrementTaskIdRef, lockTaskId, unlockTaskId, hasActive
|
|
|
21
22
|
*/
|
|
22
23
|
export async function handleXYMessage(params) {
|
|
23
24
|
const { cfg, runtime, message, accountId, webSocketSessionId } = params;
|
|
24
|
-
const log = runtime?.log ?? console.log;
|
|
25
|
-
const error = runtime?.error ?? console.error;
|
|
26
25
|
// 每次收到消息时更新缓存,供 steer 注入使用
|
|
27
26
|
setCachedContext(cfg, runtime, accountId);
|
|
28
27
|
// Get runtime (already validated in monitor.ts, but get reference for use)
|
|
@@ -36,7 +35,7 @@ export async function handleXYMessage(params) {
|
|
|
36
35
|
if (!sessionId) {
|
|
37
36
|
throw new Error("clearContext request missing sessionId in params");
|
|
38
37
|
}
|
|
39
|
-
log(`Clear context request for session ${sessionId}`);
|
|
38
|
+
logger.log(`Clear context request for session ${sessionId}`);
|
|
40
39
|
const config = resolveXYConfig(cfg);
|
|
41
40
|
await sendClearContextResponse({
|
|
42
41
|
config,
|
|
@@ -52,7 +51,7 @@ export async function handleXYMessage(params) {
|
|
|
52
51
|
if (!sessionId) {
|
|
53
52
|
throw new Error("tasks/cancel request missing sessionId in params");
|
|
54
53
|
}
|
|
55
|
-
log(`Tasks cancel request for session ${sessionId}, task ${taskId}`);
|
|
54
|
+
logger.log(`Tasks cancel request for session ${sessionId}, task ${taskId}`);
|
|
56
55
|
const config = resolveXYConfig(cfg);
|
|
57
56
|
await sendTasksCancelResponse({
|
|
58
57
|
config,
|
|
@@ -68,18 +67,18 @@ export async function handleXYMessage(params) {
|
|
|
68
67
|
// 如果消息中包含 Trigger 事件数据,直接返回 pushData 内容,不走正常流程
|
|
69
68
|
const triggerData = extractTriggerData(parsed.parts);
|
|
70
69
|
if (triggerData) {
|
|
71
|
-
log(`[BOT] 📌 Detected Trigger message with pushDataId: ${triggerData.pushDataId}`);
|
|
72
|
-
log(`[BOT] - Session ID: ${parsed.sessionId}`);
|
|
73
|
-
log(`[BOT] - Task ID: ${parsed.taskId}`);
|
|
70
|
+
logger.log(`[BOT] 📌 Detected Trigger message with pushDataId: ${triggerData.pushDataId}`);
|
|
71
|
+
logger.log(`[BOT] - Session ID: ${parsed.sessionId}`);
|
|
72
|
+
logger.log(`[BOT] - Task ID: ${parsed.taskId}`);
|
|
74
73
|
try {
|
|
75
74
|
// 读取 pushData
|
|
76
75
|
const pushDataItem = await getPushDataById(triggerData.pushDataId);
|
|
77
76
|
if (!pushDataItem) {
|
|
78
|
-
error(`[BOT] ❌ pushData not found for ID: ${triggerData.pushDataId}`);
|
|
77
|
+
logger.error(`[BOT] ❌ pushData not found for ID: ${triggerData.pushDataId}`);
|
|
79
78
|
return;
|
|
80
79
|
}
|
|
81
|
-
log(`[BOT] ✅ Found pushData, sending direct response`);
|
|
82
|
-
log(`[BOT] - pushDataId: ${pushDataItem.pushDataId}`);
|
|
80
|
+
logger.log(`[BOT] ✅ Found pushData, sending direct response`);
|
|
81
|
+
logger.log(`[BOT] - pushDataId: ${pushDataItem.pushDataId}`);
|
|
83
82
|
const config = resolveXYConfig(cfg);
|
|
84
83
|
// 直接发送响应(final=true,不走 openclaw 流程)
|
|
85
84
|
await sendA2AResponse({
|
|
@@ -91,11 +90,11 @@ export async function handleXYMessage(params) {
|
|
|
91
90
|
append: false,
|
|
92
91
|
final: true,
|
|
93
92
|
});
|
|
94
|
-
log(`[BOT] ✅ Trigger response sent successfully, exiting early`);
|
|
93
|
+
logger.log(`[BOT] ✅ Trigger response sent successfully, exiting early`);
|
|
95
94
|
return; // 提前返回,不继续处理
|
|
96
95
|
}
|
|
97
96
|
catch (err) {
|
|
98
|
-
error(`[BOT] ❌ Failed to handle Trigger message:`, err);
|
|
97
|
+
logger.error(`[BOT] ❌ Failed to handle Trigger message:`, err);
|
|
99
98
|
return;
|
|
100
99
|
}
|
|
101
100
|
}
|
|
@@ -104,9 +103,9 @@ export async function handleXYMessage(params) {
|
|
|
104
103
|
const isSteerMode = cfg.messages?.queue?.mode === "steer";
|
|
105
104
|
const isSecondMessage = isSteerMode && hasActiveTask(parsed.sessionId);
|
|
106
105
|
if (isSecondMessage) {
|
|
107
|
-
log(`[BOT] 🔄 STEER MODE - Second message detected (will be follower)`);
|
|
108
|
-
log(`[BOT] - Session: ${parsed.sessionId}`);
|
|
109
|
-
log(`[BOT] - New taskId: ${parsed.taskId} (will replace current)`);
|
|
106
|
+
logger.log(`[BOT] 🔄 STEER MODE - Second message detected (will be follower)`);
|
|
107
|
+
logger.log(`[BOT] - Session: ${parsed.sessionId}`);
|
|
108
|
+
logger.log(`[BOT] - New taskId: ${parsed.taskId} (will replace current)`);
|
|
110
109
|
}
|
|
111
110
|
// 🔑 注册taskId(第二条消息会覆盖第一条的taskId)
|
|
112
111
|
const { isUpdate, refCount } = registerTaskId(parsed.sessionId, parsed.taskId, parsed.messageId, { incrementRef: true } // 增加引用计数
|
|
@@ -114,32 +113,32 @@ export async function handleXYMessage(params) {
|
|
|
114
113
|
// 🔑 如果是第一条消息,锁定taskId防止被过早清理
|
|
115
114
|
if (!isUpdate) {
|
|
116
115
|
lockTaskId(parsed.sessionId);
|
|
117
|
-
log(`[BOT] 🔒 Locked taskId for first message`);
|
|
116
|
+
logger.log(`[BOT] 🔒 Locked taskId for first message`);
|
|
118
117
|
}
|
|
119
118
|
// Extract and update push_id if present
|
|
120
119
|
const pushId = extractPushId(parsed.parts);
|
|
121
120
|
if (pushId) {
|
|
122
|
-
log(`[BOT] 📌 Extracted push_id from user message`);
|
|
121
|
+
logger.log(`[BOT] 📌 Extracted push_id from user message`);
|
|
123
122
|
configManager.updatePushId(parsed.sessionId, pushId);
|
|
124
123
|
// 持久化 pushId 到本地文件(异步,不阻塞主流程)
|
|
125
124
|
addPushId(pushId).catch((err) => {
|
|
126
|
-
error(`[BOT] Failed to persist pushId:`, err);
|
|
125
|
+
logger.error(`[BOT] Failed to persist pushId:`, err);
|
|
127
126
|
});
|
|
128
127
|
}
|
|
129
128
|
else {
|
|
130
|
-
log(`[BOT] ℹ️ No push_id found in message, will use config default`);
|
|
129
|
+
logger.log(`[BOT] ℹ️ No push_id found in message, will use config default`);
|
|
131
130
|
}
|
|
132
131
|
// Extract deviceType if present (same level as push_id in systemVariables)
|
|
133
132
|
const deviceType = extractDeviceType(parsed.parts);
|
|
134
133
|
if (deviceType) {
|
|
135
|
-
log(`[BOT] 📱 Extracted deviceType from user message: ${deviceType}`);
|
|
134
|
+
logger.log(`[BOT] 📱 Extracted deviceType from user message: ${deviceType}`);
|
|
136
135
|
}
|
|
137
136
|
// 保存 runtime 信息到 .xiaoyiruntime 文件(异步,不阻塞主流程)
|
|
138
137
|
saveRuntimeInfo(webSocketSessionId || parsed.sessionId, // SESSION_ID (WebSocket 层级,如果没有则 fallback)
|
|
139
138
|
parsed.sessionId, // CONVERSATION_ID (param 里的 sessionId)
|
|
140
139
|
parsed.taskId // TASK_ID (param.id)
|
|
141
140
|
).catch((err) => {
|
|
142
|
-
error(`[BOT] Failed to save runtime info:`, err);
|
|
141
|
+
logger.error(`[BOT] Failed to save runtime info:`, err);
|
|
143
142
|
});
|
|
144
143
|
// Resolve configuration (needed for status updates)
|
|
145
144
|
const config = resolveXYConfig(cfg);
|
|
@@ -155,16 +154,17 @@ export async function handleXYMessage(params) {
|
|
|
155
154
|
id: parsed.sessionId, // ✅ Use sessionId to share context within the same conversation session
|
|
156
155
|
},
|
|
157
156
|
});
|
|
158
|
-
log(`xy: resolved route accountId=${route.accountId}, sessionKey=${route.sessionKey}`);
|
|
157
|
+
logger.log(`xy: resolved route accountId=${route.accountId}, sessionKey=${route.sessionKey}`);
|
|
159
158
|
registerSession(route.sessionKey, {
|
|
160
159
|
config,
|
|
161
160
|
sessionId: parsed.sessionId,
|
|
162
161
|
taskId: parsed.taskId,
|
|
163
162
|
messageId: parsed.messageId,
|
|
164
163
|
agentId: route.accountId,
|
|
164
|
+
deviceType,
|
|
165
165
|
});
|
|
166
166
|
// 🔑 发送初始状态更新(第二条消息也要发,用新taskId)
|
|
167
|
-
log(`[STATUS] Sending initial status update for session ${parsed.sessionId}`);
|
|
167
|
+
logger.log(`[STATUS] Sending initial status update for session ${parsed.sessionId}`);
|
|
168
168
|
void sendStatusUpdate({
|
|
169
169
|
config,
|
|
170
170
|
sessionId: parsed.sessionId,
|
|
@@ -173,7 +173,7 @@ export async function handleXYMessage(params) {
|
|
|
173
173
|
text: isSecondMessage ? "新消息已接收,正在处理..." : "任务正在处理中,请稍候~",
|
|
174
174
|
state: "working",
|
|
175
175
|
}).catch((err) => {
|
|
176
|
-
error(`Failed to send initial status update:`, err);
|
|
176
|
+
logger.error(`Failed to send initial status update:`, err);
|
|
177
177
|
});
|
|
178
178
|
// Extract text and files from parts
|
|
179
179
|
const text = extractTextFromParts(parsed.parts);
|
|
@@ -183,24 +183,24 @@ export async function handleXYMessage(params) {
|
|
|
183
183
|
const selfEvolutionEnabled = await selfEvolutionManager.isEnabled();
|
|
184
184
|
if (selfEvolutionEnabled && shouldNudgeForSelfEvolutionKeyword(textForAgent)) {
|
|
185
185
|
const shouldNudge = toolCallNudgeManager.tryMarkKeywordNudge(route.sessionKey);
|
|
186
|
-
log(`[SELF_EVOLUTION] Keyword check hit during inbound build: sessionKey=${route.sessionKey}, shouldNudge=${shouldNudge}`);
|
|
186
|
+
logger.log(`[SELF_EVOLUTION] Keyword check hit during inbound build: sessionKey=${route.sessionKey}, shouldNudge=${shouldNudge}`);
|
|
187
187
|
if (shouldNudge) {
|
|
188
188
|
const augmented = appendSelfEvolutionKeywordNudge(textForAgent);
|
|
189
189
|
textForAgent = augmented.text;
|
|
190
190
|
if (augmented.appended) {
|
|
191
|
-
log(`[SELF_EVOLUTION] Keyword-triggered inline nudge appended: sessionKey=${route.sessionKey}`);
|
|
191
|
+
logger.log(`[SELF_EVOLUTION] Keyword-triggered inline nudge appended: sessionKey=${route.sessionKey}`);
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
194
|
}
|
|
195
195
|
}
|
|
196
196
|
catch (selfEvolutionError) {
|
|
197
|
-
error(`[SELF_EVOLUTION] Failed to append inline keyword nudge: ${String(selfEvolutionError)}`);
|
|
197
|
+
logger.error(`[SELF_EVOLUTION] Failed to append inline keyword nudge: ${String(selfEvolutionError)}`);
|
|
198
198
|
}
|
|
199
199
|
}
|
|
200
200
|
const fileParts = extractFileParts(parsed.parts);
|
|
201
201
|
// Download files to local disk
|
|
202
202
|
const downloadedFiles = await downloadFilesFromParts(fileParts);
|
|
203
|
-
|
|
203
|
+
logger.log("Downloaded files:", JSON.stringify(downloadedFiles, null, 2));
|
|
204
204
|
const mediaPayload = buildXYMediaPayload(downloadedFiles);
|
|
205
205
|
// Resolve envelope format options (following feishu pattern)
|
|
206
206
|
const envelopeOptions = core.channel.reply.resolveEnvelopeFormatOptions(cfg);
|
|
@@ -233,7 +233,7 @@ export async function handleXYMessage(params) {
|
|
|
233
233
|
SenderId: parsed.sessionId,
|
|
234
234
|
Provider: "xiaoyi-channel",
|
|
235
235
|
Surface: "xiaoyi-channel",
|
|
236
|
-
MessageSid: parsed.
|
|
236
|
+
MessageSid: `${parsed.taskId}_${deviceType}`,
|
|
237
237
|
Timestamp: Date.now(),
|
|
238
238
|
WasMentioned: false,
|
|
239
239
|
CommandAuthorized: true,
|
|
@@ -243,8 +243,8 @@ export async function handleXYMessage(params) {
|
|
|
243
243
|
...mediaPayload,
|
|
244
244
|
});
|
|
245
245
|
// 🔑 创建dispatcher(dispatcher会自动使用动态taskId)
|
|
246
|
-
log(`[BOT-DISPATCHER] 🎯 Creating reply dispatcher`);
|
|
247
|
-
log(`[BOT-DISPATCHER] - taskId: ${parsed.taskId}`);
|
|
246
|
+
logger.log(`[BOT-DISPATCHER] 🎯 Creating reply dispatcher`);
|
|
247
|
+
logger.log(`[BOT-DISPATCHER] - taskId: ${parsed.taskId}`);
|
|
248
248
|
const { dispatcher, replyOptions, markDispatchIdle, startStatusInterval } = createXYReplyDispatcher({
|
|
249
249
|
cfg,
|
|
250
250
|
runtime,
|
|
@@ -258,7 +258,7 @@ export async function handleXYMessage(params) {
|
|
|
258
258
|
// 第二条消息会很快返回,不需要定时器
|
|
259
259
|
if (!isSecondMessage) {
|
|
260
260
|
startStatusInterval();
|
|
261
|
-
log(`[BOT-DISPATCHER] ✅ Status interval started for first message`);
|
|
261
|
+
logger.log(`[BOT-DISPATCHER] ✅ Status interval started for first message`);
|
|
262
262
|
}
|
|
263
263
|
// Build session context for AsyncLocalStorage
|
|
264
264
|
const sessionContext = {
|
|
@@ -269,66 +269,74 @@ export async function handleXYMessage(params) {
|
|
|
269
269
|
agentId: route.accountId,
|
|
270
270
|
deviceType,
|
|
271
271
|
};
|
|
272
|
-
log(`[BOT-DISPATCH] ⏳ withReplyDispatcher starting, sessionKey=${route.sessionKey}`);
|
|
272
|
+
logger.log(`[BOT-DISPATCH] ⏳ withReplyDispatcher starting, sessionKey=${route.sessionKey}`);
|
|
273
273
|
await core.channel.reply.withReplyDispatcher({
|
|
274
274
|
dispatcher,
|
|
275
275
|
onSettled: () => {
|
|
276
|
-
log(`[BOT] 🏁 onSettled called for session: ${route.sessionKey}`);
|
|
277
|
-
log(`[BOT] - isSecondMessage: ${isSecondMessage}`);
|
|
276
|
+
logger.log(`[BOT] 🏁 onSettled called for session: ${route.sessionKey}`);
|
|
277
|
+
logger.log(`[BOT] - isSecondMessage: ${isSecondMessage}`);
|
|
278
278
|
// 🔑 减少引用计数
|
|
279
279
|
decrementTaskIdRef(parsed.sessionId);
|
|
280
280
|
// 🔑 如果是第一条消息完成,解锁
|
|
281
281
|
if (!isSecondMessage) {
|
|
282
282
|
unlockTaskId(parsed.sessionId);
|
|
283
|
-
log(`[BOT] 🔓 Unlocked taskId (first message completed)`);
|
|
283
|
+
logger.log(`[BOT] 🔓 Unlocked taskId (first message completed)`);
|
|
284
284
|
}
|
|
285
285
|
// 减少session引用计数
|
|
286
286
|
unregisterSession(route.sessionKey);
|
|
287
|
-
log(`[BOT] ✅ Cleanup completed`);
|
|
287
|
+
logger.log(`[BOT] ✅ Cleanup completed`);
|
|
288
|
+
},
|
|
289
|
+
run: () => {
|
|
290
|
+
// 🔐 Use AsyncLocalStorage to provide session context to tools.
|
|
291
|
+
// runWithSessionContext returns after the sync part of dispatch
|
|
292
|
+
// (including agentTools + wrapStreamFn) has executed, so we
|
|
293
|
+
// signal init complete to release the global dispatch gate
|
|
294
|
+
// for the next session.
|
|
295
|
+
const dispatchPromise = runWithSessionContext(sessionContext, async () => {
|
|
296
|
+
logger.log(`[BOT-DISPATCH] ⏳ dispatchReplyFromConfig starting...`);
|
|
297
|
+
logger.log(`[BOT-DISPATCH] - sessionKey: ${ctxPayload.SessionKey}`);
|
|
298
|
+
logger.log(`[BOT-DISPATCH] - provider: ${ctxPayload.Provider}`);
|
|
299
|
+
logger.log(`[BOT-DISPATCH] - surface: ${ctxPayload.Surface}`);
|
|
300
|
+
logger.log(`[BOT-DISPATCH] - from: ${ctxPayload.From}`);
|
|
301
|
+
logger.log(`[BOT-DISPATCH] - body length: ${ctxPayload.Body?.length ?? 0}`);
|
|
302
|
+
try {
|
|
303
|
+
const result = await core.channel.reply.dispatchReplyFromConfig({
|
|
304
|
+
ctx: ctxPayload,
|
|
305
|
+
cfg,
|
|
306
|
+
dispatcher,
|
|
307
|
+
replyOptions,
|
|
308
|
+
});
|
|
309
|
+
logger.log(`[BOT-DISPATCH] ✅ dispatchReplyFromConfig returned`);
|
|
310
|
+
logger.log(`[BOT-DISPATCH] - result: ${JSON.stringify(result)}`);
|
|
311
|
+
return result;
|
|
312
|
+
}
|
|
313
|
+
catch (dispatchErr) {
|
|
314
|
+
logger.error(`[BOT-DISPATCH] ❌ dispatchReplyFromConfig threw`);
|
|
315
|
+
logger.error(`[BOT-DISPATCH] - error name: ${dispatchErr instanceof Error ? dispatchErr.name : "unknown"}`);
|
|
316
|
+
logger.error(`[BOT-DISPATCH] - error message: ${String(dispatchErr)}`);
|
|
317
|
+
logger.error(`[BOT-DISPATCH] - error stack: ${dispatchErr instanceof Error ? dispatchErr.stack?.slice(0, 500) : "N/A"}`);
|
|
318
|
+
throw dispatchErr;
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
// Signal init complete — sync part (agentTools, wrapStreamFn) is done
|
|
322
|
+
params.onInitComplete?.();
|
|
323
|
+
return dispatchPromise;
|
|
288
324
|
},
|
|
289
|
-
run: () =>
|
|
290
|
-
// 🔐 Use AsyncLocalStorage to provide session context to tools
|
|
291
|
-
runWithSessionContext(sessionContext, async () => {
|
|
292
|
-
log(`[BOT-DISPATCH] ⏳ dispatchReplyFromConfig starting...`);
|
|
293
|
-
log(`[BOT-DISPATCH] - sessionKey: ${ctxPayload.SessionKey}`);
|
|
294
|
-
log(`[BOT-DISPATCH] - provider: ${ctxPayload.Provider}`);
|
|
295
|
-
log(`[BOT-DISPATCH] - surface: ${ctxPayload.Surface}`);
|
|
296
|
-
log(`[BOT-DISPATCH] - from: ${ctxPayload.From}`);
|
|
297
|
-
log(`[BOT-DISPATCH] - body length: ${ctxPayload.Body?.length ?? 0}`);
|
|
298
|
-
try {
|
|
299
|
-
const result = await core.channel.reply.dispatchReplyFromConfig({
|
|
300
|
-
ctx: ctxPayload,
|
|
301
|
-
cfg,
|
|
302
|
-
dispatcher,
|
|
303
|
-
replyOptions,
|
|
304
|
-
});
|
|
305
|
-
log(`[BOT-DISPATCH] ✅ dispatchReplyFromConfig returned`);
|
|
306
|
-
log(`[BOT-DISPATCH] - result: ${JSON.stringify(result)}`);
|
|
307
|
-
return result;
|
|
308
|
-
}
|
|
309
|
-
catch (dispatchErr) {
|
|
310
|
-
error(`[BOT-DISPATCH] ❌ dispatchReplyFromConfig threw`);
|
|
311
|
-
error(`[BOT-DISPATCH] - error name: ${dispatchErr instanceof Error ? dispatchErr.name : "unknown"}`);
|
|
312
|
-
error(`[BOT-DISPATCH] - error message: ${String(dispatchErr)}`);
|
|
313
|
-
error(`[BOT-DISPATCH] - error stack: ${dispatchErr instanceof Error ? dispatchErr.stack?.slice(0, 500) : "N/A"}`);
|
|
314
|
-
throw dispatchErr;
|
|
315
|
-
}
|
|
316
|
-
}),
|
|
317
325
|
});
|
|
318
|
-
log(`[BOT] ✅ Dispatcher completed for session: ${parsed.sessionId}`);
|
|
319
|
-
log(`xy: dispatch complete (session=${parsed.sessionId})`);
|
|
326
|
+
logger.log(`[BOT] ✅ Dispatcher completed for session: ${parsed.sessionId}`);
|
|
327
|
+
logger.log(`xy: dispatch complete (session=${parsed.sessionId})`);
|
|
320
328
|
}
|
|
321
329
|
catch (err) {
|
|
322
330
|
// ✅ Only log error, don't re-throw to prevent gateway restart
|
|
323
|
-
error("Failed to handle XY message:", err);
|
|
331
|
+
logger.error("Failed to handle XY message:", err);
|
|
324
332
|
runtime.error?.(`xy: Failed to handle message: ${String(err)}`);
|
|
325
|
-
log(`[BOT] ❌ Error occurred, attempting cleanup...`);
|
|
333
|
+
logger.log(`[BOT] ❌ Error occurred, attempting cleanup...`);
|
|
326
334
|
// 🔑 错误时也要清理taskId和session
|
|
327
335
|
try {
|
|
328
336
|
const params = message.params;
|
|
329
337
|
const sessionId = params?.sessionId;
|
|
330
338
|
if (sessionId) {
|
|
331
|
-
log(`[BOT] 🧹 Cleaning up after error: ${sessionId}`);
|
|
339
|
+
logger.log(`[BOT] 🧹 Cleaning up after error: ${sessionId}`);
|
|
332
340
|
// 清理 taskId
|
|
333
341
|
decrementTaskIdRef(sessionId);
|
|
334
342
|
unlockTaskId(sessionId);
|
|
@@ -344,11 +352,11 @@ export async function handleXYMessage(params) {
|
|
|
344
352
|
},
|
|
345
353
|
});
|
|
346
354
|
unregisterSession(route.sessionKey);
|
|
347
|
-
log(`[BOT] ✅ Cleanup completed after error`);
|
|
355
|
+
logger.log(`[BOT] ✅ Cleanup completed after error`);
|
|
348
356
|
}
|
|
349
357
|
}
|
|
350
358
|
catch (cleanupErr) {
|
|
351
|
-
log(`[BOT] ⚠️ Cleanup failed:`, cleanupErr);
|
|
359
|
+
logger.log(`[BOT] ⚠️ Cleanup failed:`, cleanupErr);
|
|
352
360
|
// Ignore cleanup errors
|
|
353
361
|
}
|
|
354
362
|
// ❌ Don't re-throw: message processing error should not affect gateway stability
|
package/dist/src/channel.js
CHANGED
|
@@ -1,24 +1,9 @@
|
|
|
1
1
|
import { resolveXYConfig, listXYAccountIds, getDefaultXYAccountId } from "./config.js";
|
|
2
2
|
import { xyConfigSchema } from "./config-schema.js";
|
|
3
3
|
import { xyOutbound } from "./outbound.js";
|
|
4
|
-
import { locationTool } from "./tools/location-tool.js";
|
|
5
|
-
import { xiaoyiGuiTool } from "./tools/xiaoyi-gui-tool.js";
|
|
6
|
-
import { sendFileToUserTool } from "./tools/send-file-to-user-tool.js";
|
|
7
|
-
import { viewPushResultTool } from "./tools/view-push-result-tool.js";
|
|
8
|
-
import { imageReadingTool } from "./tools/image-reading-tool.js";
|
|
9
|
-
import { timestampToUtc8Tool } from "./tools/timestamp-to-utc8-tool.js";
|
|
10
|
-
import { saveSelfEvolutionSkillTool } from "./tools/save-self-evolution-skill-tool.js";
|
|
11
|
-
import { callDeviceTool } from "./tools/call-device-tool.js";
|
|
12
|
-
import { getNoteToolSchemaTool } from "./tools/get-note-tool-schema.js";
|
|
13
|
-
import { getCalendarToolSchemaTool } from "./tools/get-calendar-tool-schema.js";
|
|
14
|
-
import { getContactToolSchemaTool } from "./tools/get-contact-tool-schema.js";
|
|
15
|
-
import { getPhotoToolSchemaTool } from "./tools/get-photo-tool-schema.js";
|
|
16
|
-
import { getDeviceFileToolSchemaTool } from "./tools/get-device-file-tool-schema.js";
|
|
17
|
-
import { getAlarmToolSchemaTool } from "./tools/get-alarm-tool-schema.js";
|
|
18
|
-
import { getCollectionToolSchemaTool } from "./tools/get-collection-tool-schema.js";
|
|
19
|
-
import { loginTokenTool } from "./tools/login-token-tool.js";
|
|
20
4
|
import { filterToolsByDevice } from "./tools/device-tool-map.js";
|
|
21
5
|
import { getCurrentSessionContext } from "./tools/session-manager.js";
|
|
6
|
+
import { createAllTools } from "./tools/create-all-tools.js";
|
|
22
7
|
import { logger } from "./utils/logger.js";
|
|
23
8
|
/**
|
|
24
9
|
* Xiaoyi Channel Plugin for OpenClaw.
|
|
@@ -59,8 +44,8 @@ export const xyPlugin = {
|
|
|
59
44
|
},
|
|
60
45
|
outbound: xyOutbound,
|
|
61
46
|
agentTools: () => {
|
|
62
|
-
const allTools = [locationTool, callDeviceTool, getNoteToolSchemaTool, getCalendarToolSchemaTool, getContactToolSchemaTool, getPhotoToolSchemaTool, xiaoyiGuiTool, getDeviceFileToolSchemaTool, getAlarmToolSchemaTool, getCollectionToolSchemaTool, sendFileToUserTool, viewPushResultTool, imageReadingTool, timestampToUtc8Tool, saveSelfEvolutionSkillTool, loginTokenTool];
|
|
63
47
|
const ctx = getCurrentSessionContext();
|
|
48
|
+
const allTools = createAllTools(ctx);
|
|
64
49
|
const filtered = filterToolsByDevice(allTools, ctx?.deviceType);
|
|
65
50
|
logger.log(`[DEVICE-FILTER] deviceType=${ctx?.deviceType ?? "(none)"}, tools: ${allTools.length} → ${filtered.length} (${filtered.map(t => t.name).join(", ")})`);
|
|
66
51
|
return filtered;
|
package/dist/src/client.d.ts
CHANGED
|
@@ -1,15 +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
|
-
* Set the runtime for logging in client module.
|
|
6
|
-
*/
|
|
7
|
-
export declare function setClientRuntime(rt: RuntimeEnv | undefined): void;
|
|
8
4
|
/**
|
|
9
5
|
* Get or create a WebSocket manager for the given configuration.
|
|
10
6
|
* Reuses existing managers if config matches.
|
|
11
7
|
*/
|
|
12
|
-
export declare function getXYWebSocketManager(config: XYChannelConfig): XYWebSocketManager;
|
|
8
|
+
export declare function getXYWebSocketManager(config: XYChannelConfig, runtime?: RuntimeEnv): XYWebSocketManager;
|
|
13
9
|
/**
|
|
14
10
|
* Remove a specific WebSocket manager from cache.
|
|
15
11
|
* Disconnects the manager and removes it from the cache.
|