@ynhcj/xiaoyi-channel 0.0.120-beta → 0.0.120-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 +42 -86
- 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 +101 -103
- 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.d.ts +6 -0
- package/dist/src/cspl/call-api.js +54 -5
- package/dist/src/cspl/config.d.ts +11 -1
- package/dist/src/cspl/config.js +30 -0
- package/dist/src/cspl/middleware.d.ts +8 -0
- package/dist/src/cspl/middleware.js +90 -0
- 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 +13 -10
- 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.d.ts +3 -1
- package/dist/src/reply-dispatcher.js +64 -62
- 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.d.ts +4 -27
- package/dist/src/task-manager.js +19 -79
- 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 +124 -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 +4 -0
- 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,54 @@
|
|
|
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
|
-
import {
|
|
5
|
-
import { ALLOWED_TOOLS, MAX_TEXT_LENGTH, MAX_TOTAL_LENGTH, MIN_TEXT_LENGTH, STEER_ABORT_MESSAGE, } from "./src/cspl/constants.js";
|
|
6
|
-
import { extractResultText, parseSecurityResult, processText, validateAndTruncateText, } from "./src/cspl/utils.js";
|
|
4
|
+
import { createCsplMiddleware } from "./src/cspl/middleware.js";
|
|
7
5
|
import { setXYRuntime } from "./src/runtime.js";
|
|
8
|
-
import {
|
|
9
|
-
import { selfEvolutionManager } from "./src/utils/self-evolution-manager.js";
|
|
10
|
-
import { TOOL_CALL_NUDGE_THRESHOLD, toolCallNudgeManager, } from "./src/utils/tool-call-nudge-manager.js";
|
|
6
|
+
import { registerSelfEvolutionToolResultNudge } from "./src/self-evolution-tool-result-nudge.js";
|
|
11
7
|
import { createBeforePromptBuildHandler } from "./src/skill-retriever/hooks.js";
|
|
12
8
|
import { normalizeToolRetrieverConfig } from "./src/skill-retriever/config.js";
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
9
|
+
function registerFullHooks(api) {
|
|
10
|
+
// SKILL RETRIEVER HOOK: before_prompt_build hook
|
|
11
|
+
const pluginConfig = api.pluginConfig || {};
|
|
12
|
+
const skillRetrieverConfig = normalizeToolRetrieverConfig({
|
|
13
|
+
enabled: pluginConfig.skillRetrieverEnabled ?? true,
|
|
14
|
+
maxTools: pluginConfig.skillRetrieverMaxTools ?? 2,
|
|
15
|
+
includeUninstalledOnly: true,
|
|
16
|
+
envFilePath: "~/.openclaw/.xiaoyienv",
|
|
17
|
+
timeoutMs: pluginConfig.skillRetrieverTimeoutMs ?? 1000,
|
|
18
|
+
});
|
|
19
|
+
const beforePromptBuildHandler = createBeforePromptBuildHandler(skillRetrieverConfig);
|
|
20
|
+
api.on("before_prompt_build", beforePromptBuildHandler);
|
|
21
|
+
registerSelfEvolutionToolResultNudge(api);
|
|
22
|
+
// CSPL security scanning via AgentToolResultMiddleware.
|
|
23
|
+
// Intercepts tool results BEFORE they reach the LLM, replacing them
|
|
24
|
+
// with a security rejection message when CSPL returns REJECT.
|
|
25
|
+
api.registerAgentToolResultMiddleware(createCsplMiddleware(), {
|
|
26
|
+
runtimes: ["pi"],
|
|
27
|
+
});
|
|
25
28
|
}
|
|
26
|
-
|
|
29
|
+
export default definePluginEntry({
|
|
27
30
|
id: "xiaoyi-channel",
|
|
28
31
|
name: "Xiaoyi Channel",
|
|
29
32
|
description: "Xiaoyi channel plugin - Xiaoyi A2A protocol integration",
|
|
30
|
-
configSchema: emptyPluginConfigSchema(),
|
|
31
33
|
register(api) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
// Always register the provider so wrapStreamFn/prepareExtraParams work
|
|
35
|
+
// in ALL registration modes (not just "full").
|
|
34
36
|
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
|
-
});
|
|
37
|
+
if (api.registrationMode === "cli-metadata") {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (api.registrationMode === "tool-discovery") {
|
|
41
|
+
registerFullHooks(api);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
// Register channel plugin and set runtime
|
|
45
|
+
api.registerChannel({ plugin: xyPlugin });
|
|
46
|
+
setXYRuntime(api.runtime);
|
|
47
|
+
if (api.registrationMode === "discovery") {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (api.registrationMode === "full") {
|
|
51
|
+
registerFullHooks(api);
|
|
52
|
+
}
|
|
96
53
|
},
|
|
97
|
-
};
|
|
98
|
-
export default plugin;
|
|
54
|
+
});
|
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
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { getXYRuntime } from "./runtime.js";
|
|
2
|
-
import { setCachedContext } from "./steer-injector.js";
|
|
3
2
|
import { createXYReplyDispatcher } from "./reply-dispatcher.js";
|
|
4
3
|
import { parseA2AMessage, extractTextFromParts, extractFileParts, extractPushId, extractDeviceType, extractTriggerData } from "./parser.js";
|
|
5
4
|
import { downloadFilesFromParts } from "./file-download.js";
|
|
@@ -13,7 +12,8 @@ import { getPushDataById } from "./utils/pushdata-manager.js";
|
|
|
13
12
|
import { selfEvolutionManager } from "./utils/self-evolution-manager.js";
|
|
14
13
|
import { saveRuntimeInfo } from "./utils/runtime-manager.js";
|
|
15
14
|
import { toolCallNudgeManager } from "./utils/tool-call-nudge-manager.js";
|
|
16
|
-
import { registerTaskId, decrementTaskIdRef,
|
|
15
|
+
import { registerTaskId, decrementTaskIdRef, hasActiveTask, } from "./task-manager.js";
|
|
16
|
+
import { logger } from "./utils/logger.js";
|
|
17
17
|
/**
|
|
18
18
|
* Handle an incoming A2A message.
|
|
19
19
|
* This is the main entry point for message processing.
|
|
@@ -21,10 +21,6 @@ import { registerTaskId, decrementTaskIdRef, lockTaskId, unlockTaskId, hasActive
|
|
|
21
21
|
*/
|
|
22
22
|
export async function handleXYMessage(params) {
|
|
23
23
|
const { cfg, runtime, message, accountId, webSocketSessionId } = params;
|
|
24
|
-
const log = runtime?.log ?? console.log;
|
|
25
|
-
const error = runtime?.error ?? console.error;
|
|
26
|
-
// 每次收到消息时更新缓存,供 steer 注入使用
|
|
27
|
-
setCachedContext(cfg, runtime, accountId);
|
|
28
24
|
// Get runtime (already validated in monitor.ts, but get reference for use)
|
|
29
25
|
const core = getXYRuntime();
|
|
30
26
|
try {
|
|
@@ -36,7 +32,7 @@ export async function handleXYMessage(params) {
|
|
|
36
32
|
if (!sessionId) {
|
|
37
33
|
throw new Error("clearContext request missing sessionId in params");
|
|
38
34
|
}
|
|
39
|
-
log(`Clear context request for session ${sessionId}`);
|
|
35
|
+
logger.log(`Clear context request for session ${sessionId}`);
|
|
40
36
|
const config = resolveXYConfig(cfg);
|
|
41
37
|
await sendClearContextResponse({
|
|
42
38
|
config,
|
|
@@ -52,7 +48,7 @@ export async function handleXYMessage(params) {
|
|
|
52
48
|
if (!sessionId) {
|
|
53
49
|
throw new Error("tasks/cancel request missing sessionId in params");
|
|
54
50
|
}
|
|
55
|
-
log(`Tasks cancel request for session ${sessionId}, task ${taskId}`);
|
|
51
|
+
logger.log(`Tasks cancel request for session ${sessionId}, task ${taskId}`);
|
|
56
52
|
const config = resolveXYConfig(cfg);
|
|
57
53
|
await sendTasksCancelResponse({
|
|
58
54
|
config,
|
|
@@ -68,18 +64,18 @@ export async function handleXYMessage(params) {
|
|
|
68
64
|
// 如果消息中包含 Trigger 事件数据,直接返回 pushData 内容,不走正常流程
|
|
69
65
|
const triggerData = extractTriggerData(parsed.parts);
|
|
70
66
|
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}`);
|
|
67
|
+
logger.log(`[BOT] 📌 Detected Trigger message with pushDataId: ${triggerData.pushDataId}`);
|
|
68
|
+
logger.log(`[BOT] - Session ID: ${parsed.sessionId}`);
|
|
69
|
+
logger.log(`[BOT] - Task ID: ${parsed.taskId}`);
|
|
74
70
|
try {
|
|
75
71
|
// 读取 pushData
|
|
76
72
|
const pushDataItem = await getPushDataById(triggerData.pushDataId);
|
|
77
73
|
if (!pushDataItem) {
|
|
78
|
-
error(`[BOT] ❌ pushData not found for ID: ${triggerData.pushDataId}`);
|
|
74
|
+
logger.error(`[BOT] ❌ pushData not found for ID: ${triggerData.pushDataId}`);
|
|
79
75
|
return;
|
|
80
76
|
}
|
|
81
|
-
log(`[BOT] ✅ Found pushData, sending direct response`);
|
|
82
|
-
log(`[BOT] - pushDataId: ${pushDataItem.pushDataId}`);
|
|
77
|
+
logger.log(`[BOT] ✅ Found pushData, sending direct response`);
|
|
78
|
+
logger.log(`[BOT] - pushDataId: ${pushDataItem.pushDataId}`);
|
|
83
79
|
const config = resolveXYConfig(cfg);
|
|
84
80
|
// 直接发送响应(final=true,不走 openclaw 流程)
|
|
85
81
|
await sendA2AResponse({
|
|
@@ -91,55 +87,47 @@ export async function handleXYMessage(params) {
|
|
|
91
87
|
append: false,
|
|
92
88
|
final: true,
|
|
93
89
|
});
|
|
94
|
-
log(`[BOT] ✅ Trigger response sent successfully, exiting early`);
|
|
90
|
+
logger.log(`[BOT] ✅ Trigger response sent successfully, exiting early`);
|
|
95
91
|
return; // 提前返回,不继续处理
|
|
96
92
|
}
|
|
97
93
|
catch (err) {
|
|
98
|
-
error(`[BOT] ❌ Failed to handle Trigger message:`, err);
|
|
94
|
+
logger.error(`[BOT] ❌ Failed to handle Trigger message:`, err);
|
|
99
95
|
return;
|
|
100
96
|
}
|
|
101
97
|
}
|
|
102
98
|
// ========================================
|
|
103
|
-
// 🔑
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
log(`[BOT]
|
|
108
|
-
log(`[BOT] -
|
|
109
|
-
log(`[BOT] - New taskId: ${parsed.taskId} (will replace current)`);
|
|
110
|
-
}
|
|
111
|
-
// 🔑 注册taskId(第二条消息会覆盖第一条的taskId)
|
|
112
|
-
const { isUpdate, refCount } = registerTaskId(parsed.sessionId, parsed.taskId, parsed.messageId, { incrementRef: true } // 增加引用计数
|
|
113
|
-
);
|
|
114
|
-
// 🔑 如果是第一条消息,锁定taskId防止被过早清理
|
|
115
|
-
if (!isUpdate) {
|
|
116
|
-
lockTaskId(parsed.sessionId);
|
|
117
|
-
log(`[BOT] 🔒 Locked taskId for first message`);
|
|
99
|
+
// 🔑 注册taskId(检测是否是已有活跃任务的 session)
|
|
100
|
+
const isUpdate = hasActiveTask(parsed.sessionId);
|
|
101
|
+
if (isUpdate) {
|
|
102
|
+
logger.log(`[BOT] 🔄 STEER MODE - Second message detected (core will handle steer)`);
|
|
103
|
+
logger.log(`[BOT] - Session: ${parsed.sessionId}`);
|
|
104
|
+
logger.log(`[BOT] - New taskId: ${parsed.taskId}`);
|
|
118
105
|
}
|
|
106
|
+
registerTaskId(parsed.sessionId, parsed.taskId, parsed.messageId);
|
|
119
107
|
// Extract and update push_id if present
|
|
120
108
|
const pushId = extractPushId(parsed.parts);
|
|
121
109
|
if (pushId) {
|
|
122
|
-
log(`[BOT] 📌 Extracted push_id from user message`);
|
|
110
|
+
logger.log(`[BOT] 📌 Extracted push_id from user message`);
|
|
123
111
|
configManager.updatePushId(parsed.sessionId, pushId);
|
|
124
112
|
// 持久化 pushId 到本地文件(异步,不阻塞主流程)
|
|
125
113
|
addPushId(pushId).catch((err) => {
|
|
126
|
-
error(`[BOT] Failed to persist pushId:`, err);
|
|
114
|
+
logger.error(`[BOT] Failed to persist pushId:`, err);
|
|
127
115
|
});
|
|
128
116
|
}
|
|
129
117
|
else {
|
|
130
|
-
log(`[BOT] ℹ️ No push_id found in message, will use config default`);
|
|
118
|
+
logger.log(`[BOT] ℹ️ No push_id found in message, will use config default`);
|
|
131
119
|
}
|
|
132
120
|
// Extract deviceType if present (same level as push_id in systemVariables)
|
|
133
121
|
const deviceType = extractDeviceType(parsed.parts);
|
|
134
122
|
if (deviceType) {
|
|
135
|
-
log(`[BOT] 📱 Extracted deviceType from user message: ${deviceType}`);
|
|
123
|
+
logger.log(`[BOT] 📱 Extracted deviceType from user message: ${deviceType}`);
|
|
136
124
|
}
|
|
137
125
|
// 保存 runtime 信息到 .xiaoyiruntime 文件(异步,不阻塞主流程)
|
|
138
126
|
saveRuntimeInfo(webSocketSessionId || parsed.sessionId, // SESSION_ID (WebSocket 层级,如果没有则 fallback)
|
|
139
127
|
parsed.sessionId, // CONVERSATION_ID (param 里的 sessionId)
|
|
140
128
|
parsed.taskId // TASK_ID (param.id)
|
|
141
129
|
).catch((err) => {
|
|
142
|
-
error(`[BOT] Failed to save runtime info:`, err);
|
|
130
|
+
logger.error(`[BOT] Failed to save runtime info:`, err);
|
|
143
131
|
});
|
|
144
132
|
// Resolve configuration (needed for status updates)
|
|
145
133
|
const config = resolveXYConfig(cfg);
|
|
@@ -155,25 +143,26 @@ export async function handleXYMessage(params) {
|
|
|
155
143
|
id: parsed.sessionId, // ✅ Use sessionId to share context within the same conversation session
|
|
156
144
|
},
|
|
157
145
|
});
|
|
158
|
-
log(`xy: resolved route accountId=${route.accountId}, sessionKey=${route.sessionKey}`);
|
|
146
|
+
logger.log(`xy: resolved route accountId=${route.accountId}, sessionKey=${route.sessionKey}`);
|
|
159
147
|
registerSession(route.sessionKey, {
|
|
160
148
|
config,
|
|
161
149
|
sessionId: parsed.sessionId,
|
|
162
150
|
taskId: parsed.taskId,
|
|
163
151
|
messageId: parsed.messageId,
|
|
164
152
|
agentId: route.accountId,
|
|
153
|
+
deviceType,
|
|
165
154
|
});
|
|
166
|
-
// 🔑
|
|
167
|
-
log(`[STATUS] Sending initial status update for session ${parsed.sessionId}`);
|
|
155
|
+
// 🔑 发送初始状态更新
|
|
156
|
+
logger.log(`[STATUS] Sending initial status update for session ${parsed.sessionId}`);
|
|
168
157
|
void sendStatusUpdate({
|
|
169
158
|
config,
|
|
170
159
|
sessionId: parsed.sessionId,
|
|
171
160
|
taskId: parsed.taskId,
|
|
172
161
|
messageId: parsed.messageId,
|
|
173
|
-
text:
|
|
162
|
+
text: "任务正在处理中,请稍候~",
|
|
174
163
|
state: "working",
|
|
175
164
|
}).catch((err) => {
|
|
176
|
-
error(`Failed to send initial status update:`, err);
|
|
165
|
+
logger.error(`Failed to send initial status update:`, err);
|
|
177
166
|
});
|
|
178
167
|
// Extract text and files from parts
|
|
179
168
|
const text = extractTextFromParts(parsed.parts);
|
|
@@ -183,24 +172,29 @@ export async function handleXYMessage(params) {
|
|
|
183
172
|
const selfEvolutionEnabled = await selfEvolutionManager.isEnabled();
|
|
184
173
|
if (selfEvolutionEnabled && shouldNudgeForSelfEvolutionKeyword(textForAgent)) {
|
|
185
174
|
const shouldNudge = toolCallNudgeManager.tryMarkKeywordNudge(route.sessionKey);
|
|
186
|
-
log(`[SELF_EVOLUTION] Keyword check hit during inbound build: sessionKey=${route.sessionKey}, shouldNudge=${shouldNudge}`);
|
|
175
|
+
logger.log(`[SELF_EVOLUTION] Keyword check hit during inbound build: sessionKey=${route.sessionKey}, shouldNudge=${shouldNudge}`);
|
|
187
176
|
if (shouldNudge) {
|
|
188
177
|
const augmented = appendSelfEvolutionKeywordNudge(textForAgent);
|
|
189
178
|
textForAgent = augmented.text;
|
|
190
179
|
if (augmented.appended) {
|
|
191
|
-
log(`[SELF_EVOLUTION] Keyword-triggered inline nudge appended: sessionKey=${route.sessionKey}`);
|
|
180
|
+
logger.log(`[SELF_EVOLUTION] Keyword-triggered inline nudge appended: sessionKey=${route.sessionKey}`);
|
|
192
181
|
}
|
|
193
182
|
}
|
|
194
183
|
}
|
|
195
184
|
}
|
|
196
185
|
catch (selfEvolutionError) {
|
|
197
|
-
error(`[SELF_EVOLUTION] Failed to append inline keyword nudge: ${String(selfEvolutionError)}`);
|
|
186
|
+
logger.error(`[SELF_EVOLUTION] Failed to append inline keyword nudge: ${String(selfEvolutionError)}`);
|
|
198
187
|
}
|
|
199
188
|
}
|
|
189
|
+
// 🔑 Steer消息加 /steer 前缀,触发core的 queueEmbeddedPiMessage
|
|
190
|
+
if (isUpdate && textForAgent) {
|
|
191
|
+
textForAgent = `/steer ${textForAgent}`;
|
|
192
|
+
logger.log(`[BOT] 🔄 Prepended /steer for steer injection`);
|
|
193
|
+
}
|
|
200
194
|
const fileParts = extractFileParts(parsed.parts);
|
|
201
195
|
// Download files to local disk
|
|
202
196
|
const downloadedFiles = await downloadFilesFromParts(fileParts);
|
|
203
|
-
|
|
197
|
+
logger.log("Downloaded files:", JSON.stringify(downloadedFiles, null, 2));
|
|
204
198
|
const mediaPayload = buildXYMediaPayload(downloadedFiles);
|
|
205
199
|
// Resolve envelope format options (following feishu pattern)
|
|
206
200
|
const envelopeOptions = core.channel.reply.resolveEnvelopeFormatOptions(cfg);
|
|
@@ -233,7 +227,7 @@ export async function handleXYMessage(params) {
|
|
|
233
227
|
SenderId: parsed.sessionId,
|
|
234
228
|
Provider: "xiaoyi-channel",
|
|
235
229
|
Surface: "xiaoyi-channel",
|
|
236
|
-
MessageSid: parsed.
|
|
230
|
+
MessageSid: `${parsed.taskId}_${deviceType}`,
|
|
237
231
|
Timestamp: Date.now(),
|
|
238
232
|
WasMentioned: false,
|
|
239
233
|
CommandAuthorized: true,
|
|
@@ -242,9 +236,13 @@ export async function handleXYMessage(params) {
|
|
|
242
236
|
ReplyToBody: undefined, // A2A protocol doesn't support reply/quote
|
|
243
237
|
...mediaPayload,
|
|
244
238
|
});
|
|
245
|
-
// 🔑
|
|
246
|
-
|
|
247
|
-
|
|
239
|
+
// 🔑 Dynamic steer state: when isUpdate (second message), start as steered=true
|
|
240
|
+
// so the dispatcher skips all user-facing callbacks (deliver, onIdle, etc.)
|
|
241
|
+
// and onSettled skips cleanup.
|
|
242
|
+
const steerState = { steered: isUpdate };
|
|
243
|
+
// 🔑 创建dispatcher
|
|
244
|
+
logger.log(`[BOT-DISPATCHER] 🎯 Creating reply dispatcher`);
|
|
245
|
+
logger.log(`[BOT-DISPATCHER] - taskId: ${parsed.taskId}`);
|
|
248
246
|
const { dispatcher, replyOptions, markDispatchIdle, startStatusInterval } = createXYReplyDispatcher({
|
|
249
247
|
cfg,
|
|
250
248
|
runtime,
|
|
@@ -252,14 +250,9 @@ export async function handleXYMessage(params) {
|
|
|
252
250
|
taskId: parsed.taskId,
|
|
253
251
|
messageId: parsed.messageId,
|
|
254
252
|
accountId: route.accountId,
|
|
255
|
-
|
|
253
|
+
steerState,
|
|
256
254
|
});
|
|
257
|
-
|
|
258
|
-
// 第二条消息会很快返回,不需要定时器
|
|
259
|
-
if (!isSecondMessage) {
|
|
260
|
-
startStatusInterval();
|
|
261
|
-
log(`[BOT-DISPATCHER] ✅ Status interval started for first message`);
|
|
262
|
-
}
|
|
255
|
+
startStatusInterval();
|
|
263
256
|
// Build session context for AsyncLocalStorage
|
|
264
257
|
const sessionContext = {
|
|
265
258
|
config,
|
|
@@ -269,69 +262,74 @@ export async function handleXYMessage(params) {
|
|
|
269
262
|
agentId: route.accountId,
|
|
270
263
|
deviceType,
|
|
271
264
|
};
|
|
272
|
-
log(`[BOT-DISPATCH] ⏳ withReplyDispatcher starting, sessionKey=${route.sessionKey}`);
|
|
265
|
+
logger.log(`[BOT-DISPATCH] ⏳ withReplyDispatcher starting, sessionKey=${route.sessionKey}`);
|
|
273
266
|
await core.channel.reply.withReplyDispatcher({
|
|
274
267
|
dispatcher,
|
|
275
268
|
onSettled: () => {
|
|
276
|
-
log(`[BOT] 🏁 onSettled called for session: ${route.sessionKey}`);
|
|
277
|
-
log(`[BOT] -
|
|
278
|
-
// 🔑
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
unlockTaskId(parsed.sessionId);
|
|
283
|
-
log(`[BOT] 🔓 Unlocked taskId (first message completed)`);
|
|
269
|
+
logger.log(`[BOT] 🏁 onSettled called for session: ${route.sessionKey}`);
|
|
270
|
+
logger.log(`[BOT] - steered: ${steerState.steered}`);
|
|
271
|
+
// 🔑 When steered, skip heavy cleanup — the first message's dispatcher is still running
|
|
272
|
+
if (steerState.steered) {
|
|
273
|
+
logger.log(`[BOT] ✅ Steered dispatch settled (skipping cleanup)`);
|
|
274
|
+
return;
|
|
284
275
|
}
|
|
285
|
-
|
|
276
|
+
decrementTaskIdRef(parsed.sessionId);
|
|
286
277
|
unregisterSession(route.sessionKey);
|
|
287
|
-
log(`[BOT] ✅ Cleanup completed`);
|
|
278
|
+
logger.log(`[BOT] ✅ Cleanup completed`);
|
|
279
|
+
},
|
|
280
|
+
run: () => {
|
|
281
|
+
// 🔐 Use AsyncLocalStorage to provide session context to tools.
|
|
282
|
+
// runWithSessionContext returns after the sync part of dispatch
|
|
283
|
+
// (including agentTools + wrapStreamFn) has executed, so we
|
|
284
|
+
// signal init complete to release the global dispatch gate
|
|
285
|
+
// for the next session.
|
|
286
|
+
const dispatchPromise = runWithSessionContext(sessionContext, async () => {
|
|
287
|
+
logger.log(`[BOT-DISPATCH] ⏳ dispatchReplyFromConfig starting...`);
|
|
288
|
+
logger.log(`[BOT-DISPATCH] - sessionKey: ${ctxPayload.SessionKey}`);
|
|
289
|
+
logger.log(`[BOT-DISPATCH] - provider: ${ctxPayload.Provider}`);
|
|
290
|
+
logger.log(`[BOT-DISPATCH] - surface: ${ctxPayload.Surface}`);
|
|
291
|
+
logger.log(`[BOT-DISPATCH] - from: ${ctxPayload.From}`);
|
|
292
|
+
logger.log(`[BOT-DISPATCH] - body length: ${ctxPayload.Body?.length ?? 0}`);
|
|
293
|
+
try {
|
|
294
|
+
const result = await core.channel.reply.dispatchReplyFromConfig({
|
|
295
|
+
ctx: ctxPayload,
|
|
296
|
+
cfg,
|
|
297
|
+
dispatcher,
|
|
298
|
+
replyOptions,
|
|
299
|
+
});
|
|
300
|
+
logger.log(`[BOT-DISPATCH] ✅ dispatchReplyFromConfig returned`);
|
|
301
|
+
logger.log(`[BOT-DISPATCH] - result: ${JSON.stringify(result)}`);
|
|
302
|
+
return result;
|
|
303
|
+
}
|
|
304
|
+
catch (dispatchErr) {
|
|
305
|
+
logger.error(`[BOT-DISPATCH] ❌ dispatchReplyFromConfig threw`);
|
|
306
|
+
logger.error(`[BOT-DISPATCH] - error name: ${dispatchErr instanceof Error ? dispatchErr.name : "unknown"}`);
|
|
307
|
+
logger.error(`[BOT-DISPATCH] - error message: ${String(dispatchErr)}`);
|
|
308
|
+
logger.error(`[BOT-DISPATCH] - error stack: ${dispatchErr instanceof Error ? dispatchErr.stack?.slice(0, 500) : "N/A"}`);
|
|
309
|
+
throw dispatchErr;
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
// Signal init complete — sync part (agentTools, wrapStreamFn) is done
|
|
313
|
+
params.onInitComplete?.();
|
|
314
|
+
return dispatchPromise;
|
|
288
315
|
},
|
|
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
316
|
});
|
|
318
|
-
log(`[BOT] ✅ Dispatcher completed for session: ${parsed.sessionId}`);
|
|
319
|
-
log(`xy: dispatch complete (session=${parsed.sessionId})`);
|
|
317
|
+
logger.log(`[BOT] ✅ Dispatcher completed for session: ${parsed.sessionId}`);
|
|
318
|
+
logger.log(`xy: dispatch complete (session=${parsed.sessionId})`);
|
|
320
319
|
}
|
|
321
320
|
catch (err) {
|
|
322
321
|
// ✅ Only log error, don't re-throw to prevent gateway restart
|
|
323
|
-
error("Failed to handle XY message:", err);
|
|
322
|
+
logger.error("Failed to handle XY message:", err);
|
|
324
323
|
runtime.error?.(`xy: Failed to handle message: ${String(err)}`);
|
|
325
|
-
log(`[BOT] ❌ Error occurred, attempting cleanup...`);
|
|
324
|
+
logger.log(`[BOT] ❌ Error occurred, attempting cleanup...`);
|
|
326
325
|
// 🔑 错误时也要清理taskId和session
|
|
327
326
|
try {
|
|
328
327
|
const params = message.params;
|
|
329
328
|
const sessionId = params?.sessionId;
|
|
330
329
|
if (sessionId) {
|
|
331
|
-
log(`[BOT] 🧹 Cleaning up after error: ${sessionId}`);
|
|
330
|
+
logger.log(`[BOT] 🧹 Cleaning up after error: ${sessionId}`);
|
|
332
331
|
// 清理 taskId
|
|
333
332
|
decrementTaskIdRef(sessionId);
|
|
334
|
-
unlockTaskId(sessionId);
|
|
335
333
|
// 清理 session
|
|
336
334
|
const core = getXYRuntime();
|
|
337
335
|
const route = core.channel.routing.resolveAgentRoute({
|
|
@@ -344,11 +342,11 @@ export async function handleXYMessage(params) {
|
|
|
344
342
|
},
|
|
345
343
|
});
|
|
346
344
|
unregisterSession(route.sessionKey);
|
|
347
|
-
log(`[BOT] ✅ Cleanup completed after error`);
|
|
345
|
+
logger.log(`[BOT] ✅ Cleanup completed after error`);
|
|
348
346
|
}
|
|
349
347
|
}
|
|
350
348
|
catch (cleanupErr) {
|
|
351
|
-
log(`[BOT] ⚠️ Cleanup failed:`, cleanupErr);
|
|
349
|
+
logger.log(`[BOT] ⚠️ Cleanup failed:`, cleanupErr);
|
|
352
350
|
// Ignore cleanup errors
|
|
353
351
|
}
|
|
354
352
|
// ❌ 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.
|