@ynhcj/xiaoyi-channel 0.0.88-beta → 0.0.88-next
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +6 -9
- package/dist/index.js +26 -21
- package/dist/src/bot.js +26 -3
- package/dist/src/channel.js +2 -30
- package/dist/src/client.js +7 -1
- package/dist/src/login-token-handler.d.ts +8 -0
- package/dist/src/login-token-handler.js +60 -0
- package/dist/src/message-queue.d.ts +17 -0
- package/dist/src/message-queue.js +51 -0
- package/dist/src/monitor.js +64 -4
- package/dist/src/provider.d.ts +2 -1
- package/dist/src/provider.js +440 -31
- package/dist/src/reply-dispatcher.js +6 -0
- package/dist/src/runtime.d.ts +3 -11
- package/dist/src/runtime.js +6 -18
- package/dist/src/self-evolution-handler.d.ts +7 -0
- package/dist/src/self-evolution-handler.js +140 -0
- package/dist/src/self-evolution-keyword.d.ts +9 -0
- package/dist/src/self-evolution-keyword.js +147 -0
- package/dist/src/self-evolution-tool-result-nudge.d.ts +3 -0
- package/dist/src/self-evolution-tool-result-nudge.js +96 -0
- package/dist/src/skill-retriever/config.d.ts +4 -0
- package/dist/src/skill-retriever/config.js +23 -0
- package/dist/src/skill-retriever/hooks.d.ts +22 -0
- package/dist/src/skill-retriever/hooks.js +82 -0
- package/dist/src/skill-retriever/tool-search.d.ts +16 -0
- package/dist/src/skill-retriever/tool-search.js +172 -0
- package/dist/src/skill-retriever/types.d.ts +36 -0
- package/dist/src/skill-retriever/types.js +1 -0
- package/dist/src/task-manager.d.ts +4 -0
- package/dist/src/task-manager.js +12 -1
- package/dist/src/tools/calendar-tool.d.ts +2 -1
- package/dist/src/tools/calendar-tool.js +112 -116
- package/dist/src/tools/call-device-tool.d.ts +6 -0
- package/dist/src/tools/call-device-tool.js +153 -0
- package/dist/src/tools/call-phone-tool.d.ts +2 -1
- package/dist/src/tools/call-phone-tool.js +109 -113
- package/dist/src/tools/create-alarm-tool.d.ts +2 -1
- package/dist/src/tools/create-alarm-tool.js +227 -231
- package/dist/src/tools/create-all-tools.d.ts +16 -0
- package/dist/src/tools/create-all-tools.js +50 -0
- package/dist/src/tools/delete-alarm-tool.d.ts +2 -1
- package/dist/src/tools/delete-alarm-tool.js +131 -135
- package/dist/src/tools/device-tool-map.js +2 -0
- package/dist/src/tools/get-alarm-tool-schema.d.ts +17 -0
- package/dist/src/tools/get-alarm-tool-schema.js +17 -0
- package/dist/src/tools/get-calendar-tool-schema.d.ts +17 -0
- package/dist/src/tools/get-calendar-tool-schema.js +13 -0
- package/dist/src/tools/get-collection-tool-schema.d.ts +17 -0
- package/dist/src/tools/get-collection-tool-schema.js +12 -0
- package/dist/src/tools/get-contact-tool-schema.d.ts +17 -0
- package/dist/src/tools/get-contact-tool-schema.js +17 -0
- package/dist/src/tools/get-device-file-tool-schema.d.ts +17 -0
- package/dist/src/tools/get-device-file-tool-schema.js +14 -0
- package/dist/src/tools/get-email-tool-schema.d.ts +17 -0
- package/dist/src/tools/get-email-tool-schema.js +12 -0
- package/dist/src/tools/get-note-tool-schema.d.ts +17 -0
- package/dist/src/tools/get-note-tool-schema.js +15 -0
- package/dist/src/tools/get-photo-tool-schema.d.ts +17 -0
- package/dist/src/tools/get-photo-tool-schema.js +13 -0
- package/dist/src/tools/image-reading-tool.d.ts +2 -1
- package/dist/src/tools/image-reading-tool.js +86 -90
- package/dist/src/tools/location-tool.d.ts +2 -1
- package/dist/src/tools/location-tool.js +87 -91
- package/dist/src/tools/login-token-tool.d.ts +6 -0
- package/dist/src/tools/login-token-tool.js +133 -0
- package/dist/src/tools/modify-alarm-tool.d.ts +2 -1
- package/dist/src/tools/modify-alarm-tool.js +232 -236
- package/dist/src/tools/modify-note-tool.d.ts +2 -1
- package/dist/src/tools/modify-note-tool.js +104 -108
- package/dist/src/tools/note-tool.d.ts +2 -1
- package/dist/src/tools/note-tool.js +103 -107
- package/dist/src/tools/query-app-message-tool.d.ts +5 -0
- package/dist/src/tools/query-app-message-tool.js +135 -0
- package/dist/src/tools/query-memory-data-tool.d.ts +5 -0
- package/dist/src/tools/query-memory-data-tool.js +151 -0
- package/dist/src/tools/query-todo-task-tool.d.ts +5 -0
- package/dist/src/tools/query-todo-task-tool.js +130 -0
- package/dist/src/tools/save-file-to-phone-tool.d.ts +2 -1
- package/dist/src/tools/save-file-to-phone-tool.js +127 -131
- package/dist/src/tools/save-media-to-gallery-tool.d.ts +2 -1
- package/dist/src/tools/save-media-to-gallery-tool.js +134 -138
- package/dist/src/tools/save-self-evolution-skill-tool.d.ts +2 -0
- package/dist/src/tools/save-self-evolution-skill-tool.js +410 -0
- package/dist/src/tools/schema-tool-factory.d.ts +27 -0
- package/dist/src/tools/schema-tool-factory.js +32 -0
- package/dist/src/tools/search-alarm-tool.d.ts +2 -1
- package/dist/src/tools/search-alarm-tool.js +171 -175
- package/dist/src/tools/search-calendar-tool.d.ts +2 -1
- package/dist/src/tools/search-calendar-tool.js +145 -149
- package/dist/src/tools/search-contact-tool.d.ts +2 -1
- package/dist/src/tools/search-contact-tool.js +98 -102
- package/dist/src/tools/search-email-tool.d.ts +2 -1
- package/dist/src/tools/search-email-tool.js +107 -111
- package/dist/src/tools/search-file-tool.d.ts +2 -1
- package/dist/src/tools/search-file-tool.js +99 -103
- package/dist/src/tools/search-message-tool.d.ts +2 -1
- package/dist/src/tools/search-message-tool.js +100 -104
- package/dist/src/tools/search-note-tool.d.ts +2 -1
- package/dist/src/tools/search-note-tool.js +95 -99
- package/dist/src/tools/search-photo-gallery-tool.d.ts +2 -1
- package/dist/src/tools/search-photo-gallery-tool.js +34 -38
- package/dist/src/tools/send-email-tool.d.ts +5 -0
- package/dist/src/tools/send-email-tool.js +131 -0
- package/dist/src/tools/send-file-to-user-tool.d.ts +2 -1
- package/dist/src/tools/send-file-to-user-tool.js +153 -155
- package/dist/src/tools/send-message-tool.d.ts +2 -1
- package/dist/src/tools/send-message-tool.js +119 -123
- package/dist/src/tools/session-manager.d.ts +21 -6
- package/dist/src/tools/session-manager.js +147 -18
- package/dist/src/tools/upload-file-tool.d.ts +2 -1
- package/dist/src/tools/upload-file-tool.js +79 -83
- package/dist/src/tools/upload-photo-tool.d.ts +2 -1
- package/dist/src/tools/upload-photo-tool.js +70 -74
- package/dist/src/tools/xiaoyi-add-collection-tool.d.ts +2 -1
- package/dist/src/tools/xiaoyi-add-collection-tool.js +143 -147
- package/dist/src/tools/xiaoyi-collection-tool.d.ts +2 -1
- package/dist/src/tools/xiaoyi-collection-tool.js +112 -116
- package/dist/src/tools/xiaoyi-delete-collection-tool.d.ts +2 -1
- package/dist/src/tools/xiaoyi-delete-collection-tool.js +124 -128
- package/dist/src/tools/xiaoyi-gui-tool.d.ts +2 -1
- package/dist/src/tools/xiaoyi-gui-tool.js +84 -88
- package/dist/src/utils/runtime-manager.js +24 -2
- package/dist/src/utils/self-evolution-manager.d.ts +10 -0
- package/dist/src/utils/self-evolution-manager.js +68 -0
- package/dist/src/utils/tool-call-nudge-manager.d.ts +16 -0
- package/dist/src/utils/tool-call-nudge-manager.js +47 -0
- package/dist/src/websocket.d.ts +3 -0
- package/dist/src/websocket.js +94 -24
- package/openclaw.plugin.json +21 -0
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
2
|
-
|
|
3
|
-
* Xiaoyi Channel Plugin Entry Point.
|
|
4
|
-
* Exports the plugin for OpenClaw to load.
|
|
5
|
-
* Located at root level following feishu pattern for proper plugin registration.
|
|
6
|
-
*/
|
|
7
|
-
declare const plugin: {
|
|
2
|
+
declare const _default: {
|
|
8
3
|
id: string;
|
|
9
4
|
name: string;
|
|
10
5
|
description: string;
|
|
11
|
-
configSchema: import("openclaw/plugin-sdk").
|
|
12
|
-
register(api: OpenClawPluginApi)
|
|
6
|
+
configSchema: import("openclaw/plugin-sdk").ChannelConfigSchema;
|
|
7
|
+
register: (api: OpenClawPluginApi) => void;
|
|
8
|
+
channelPlugin: import("openclaw/plugin-sdk").ChannelPlugin;
|
|
9
|
+
setChannelRuntime?: (runtime: import("openclaw/plugin-sdk").PluginRuntime) => void;
|
|
13
10
|
};
|
|
14
|
-
export default
|
|
11
|
+
export default _default;
|
package/dist/index.js
CHANGED
|
@@ -1,27 +1,34 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { xyPlugin } from "./src/channel.js";
|
|
1
|
+
import { defineChannelPluginEntry } from "openclaw/plugin-sdk/core";
|
|
3
2
|
import { xiaoyiProvider } from "./src/provider.js";
|
|
3
|
+
import { xyPlugin } from "./src/channel.js";
|
|
4
|
+
import { callCsplApi } from "./src/cspl/call-api.js";
|
|
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
7
|
import { setXYRuntime } from "./src/runtime.js";
|
|
5
8
|
import { tryInjectSteer } from "./src/steer-injector.js";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
* Xiaoyi Channel Plugin Entry Point.
|
|
11
|
-
* Exports the plugin for OpenClaw to load.
|
|
12
|
-
* Located at root level following feishu pattern for proper plugin registration.
|
|
13
|
-
*/
|
|
14
|
-
const plugin = {
|
|
9
|
+
import { registerSelfEvolutionToolResultNudge } from "./src/self-evolution-tool-result-nudge.js";
|
|
10
|
+
import { createBeforePromptBuildHandler } from "./src/skill-retriever/hooks.js";
|
|
11
|
+
import { normalizeToolRetrieverConfig } from "./src/skill-retriever/config.js";
|
|
12
|
+
export default defineChannelPluginEntry({
|
|
15
13
|
id: "xiaoyi-channel",
|
|
16
14
|
name: "Xiaoyi Channel",
|
|
17
15
|
description: "Xiaoyi channel plugin - Xiaoyi A2A protocol integration",
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
api.registerChannel({ plugin: xyPlugin });
|
|
16
|
+
plugin: xyPlugin,
|
|
17
|
+
setRuntime: setXYRuntime,
|
|
18
|
+
registerFull(api) {
|
|
22
19
|
api.registerProvider(xiaoyiProvider);
|
|
23
|
-
//
|
|
24
|
-
|
|
20
|
+
// SKILL RETRIEVER HOOK: before_prompt_build hook
|
|
21
|
+
const pluginConfig = api.pluginConfig || {};
|
|
22
|
+
const skillRetrieverConfig = normalizeToolRetrieverConfig({
|
|
23
|
+
enabled: pluginConfig.skillRetrieverEnabled ?? true,
|
|
24
|
+
maxTools: pluginConfig.skillRetrieverMaxTools ?? 2,
|
|
25
|
+
includeUninstalledOnly: true,
|
|
26
|
+
envFilePath: "~/.openclaw/.xiaoyienv",
|
|
27
|
+
timeoutMs: pluginConfig.skillRetrieverTimeoutMs ?? 1000,
|
|
28
|
+
});
|
|
29
|
+
const beforePromptBuildHandler = createBeforePromptBuildHandler(skillRetrieverConfig);
|
|
30
|
+
api.on("before_prompt_build", beforePromptBuildHandler);
|
|
31
|
+
registerSelfEvolutionToolResultNudge(api);
|
|
25
32
|
api.on("after_tool_call", async (event, ctx) => {
|
|
26
33
|
if (!ALLOWED_TOOLS.includes(event.toolName)) {
|
|
27
34
|
return;
|
|
@@ -33,9 +40,8 @@ const plugin = {
|
|
|
33
40
|
if (resultLength <= MIN_TEXT_LENGTH || resultLength > MAX_TOTAL_LENGTH) {
|
|
34
41
|
return;
|
|
35
42
|
}
|
|
36
|
-
// 构造 sentinel_hook 格式的 payload: { tool, output: [{ content }] }
|
|
37
43
|
const questionText = {
|
|
38
|
-
subSceneID:
|
|
44
|
+
subSceneID: "TOOL_OUTPUT",
|
|
39
45
|
tool: event.toolName,
|
|
40
46
|
output: [{ content: "" }],
|
|
41
47
|
};
|
|
@@ -60,5 +66,4 @@ const plugin = {
|
|
|
60
66
|
}
|
|
61
67
|
});
|
|
62
68
|
},
|
|
63
|
-
};
|
|
64
|
-
export default plugin;
|
|
69
|
+
});
|
package/dist/src/bot.js
CHANGED
|
@@ -5,11 +5,14 @@ import { parseA2AMessage, extractTextFromParts, extractFileParts, extractPushId,
|
|
|
5
5
|
import { downloadFilesFromParts } from "./file-download.js";
|
|
6
6
|
import { resolveXYConfig } from "./config.js";
|
|
7
7
|
import { sendStatusUpdate, sendClearContextResponse, sendTasksCancelResponse, sendA2AResponse } from "./formatter.js";
|
|
8
|
+
import { appendSelfEvolutionKeywordNudge, shouldNudgeForSelfEvolutionKeyword, } from "./self-evolution-keyword.js";
|
|
8
9
|
import { registerSession, unregisterSession, runWithSessionContext } from "./tools/session-manager.js";
|
|
9
10
|
import { configManager } from "./utils/config-manager.js";
|
|
10
11
|
import { addPushId } from "./utils/pushid-manager.js";
|
|
11
12
|
import { getPushDataById } from "./utils/pushdata-manager.js";
|
|
13
|
+
import { selfEvolutionManager } from "./utils/self-evolution-manager.js";
|
|
12
14
|
import { saveRuntimeInfo } from "./utils/runtime-manager.js";
|
|
15
|
+
import { toolCallNudgeManager } from "./utils/tool-call-nudge-manager.js";
|
|
13
16
|
import { registerTaskId, decrementTaskIdRef, lockTaskId, unlockTaskId, hasActiveTask, } from "./task-manager.js";
|
|
14
17
|
/**
|
|
15
18
|
* Handle an incoming A2A message.
|
|
@@ -174,6 +177,26 @@ export async function handleXYMessage(params) {
|
|
|
174
177
|
});
|
|
175
178
|
// Extract text and files from parts
|
|
176
179
|
const text = extractTextFromParts(parsed.parts);
|
|
180
|
+
let textForAgent = text || "";
|
|
181
|
+
if (route.sessionKey && textForAgent) {
|
|
182
|
+
try {
|
|
183
|
+
const selfEvolutionEnabled = await selfEvolutionManager.isEnabled();
|
|
184
|
+
if (selfEvolutionEnabled && shouldNudgeForSelfEvolutionKeyword(textForAgent)) {
|
|
185
|
+
const shouldNudge = toolCallNudgeManager.tryMarkKeywordNudge(route.sessionKey);
|
|
186
|
+
log(`[SELF_EVOLUTION] Keyword check hit during inbound build: sessionKey=${route.sessionKey}, shouldNudge=${shouldNudge}`);
|
|
187
|
+
if (shouldNudge) {
|
|
188
|
+
const augmented = appendSelfEvolutionKeywordNudge(textForAgent);
|
|
189
|
+
textForAgent = augmented.text;
|
|
190
|
+
if (augmented.appended) {
|
|
191
|
+
log(`[SELF_EVOLUTION] Keyword-triggered inline nudge appended: sessionKey=${route.sessionKey}`);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
catch (selfEvolutionError) {
|
|
197
|
+
error(`[SELF_EVOLUTION] Failed to append inline keyword nudge: ${String(selfEvolutionError)}`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
177
200
|
const fileParts = extractFileParts(parsed.parts);
|
|
178
201
|
// Download files to local disk
|
|
179
202
|
const downloadedFiles = await downloadFilesFromParts(fileParts);
|
|
@@ -182,7 +205,7 @@ export async function handleXYMessage(params) {
|
|
|
182
205
|
// Resolve envelope format options (following feishu pattern)
|
|
183
206
|
const envelopeOptions = core.channel.reply.resolveEnvelopeFormatOptions(cfg);
|
|
184
207
|
// Build message body with speaker prefix (following feishu pattern)
|
|
185
|
-
let messageBody =
|
|
208
|
+
let messageBody = textForAgent;
|
|
186
209
|
// Add speaker prefix for clarity
|
|
187
210
|
const speaker = parsed.sessionId;
|
|
188
211
|
messageBody = `${speaker}: ${messageBody}`;
|
|
@@ -198,8 +221,8 @@ export async function handleXYMessage(params) {
|
|
|
198
221
|
// Use route.accountId and route.sessionKey instead of parsed fields
|
|
199
222
|
const ctxPayload = core.channel.reply.finalizeInboundContext({
|
|
200
223
|
Body: body,
|
|
201
|
-
RawBody:
|
|
202
|
-
CommandBody:
|
|
224
|
+
RawBody: textForAgent,
|
|
225
|
+
CommandBody: textForAgent,
|
|
203
226
|
From: parsed.sessionId,
|
|
204
227
|
To: parsed.sessionId, // ✅ Simplified: use sessionId as target (context is managed by SessionKey)
|
|
205
228
|
SessionKey: route.sessionKey, // ✅ Use route.sessionKey
|
package/dist/src/channel.js
CHANGED
|
@@ -1,37 +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 { noteTool } from "./tools/note-tool.js";
|
|
6
|
-
import { searchNoteTool } from "./tools/search-note-tool.js";
|
|
7
|
-
import { modifyNoteTool } from "./tools/modify-note-tool.js";
|
|
8
|
-
import { calendarTool } from "./tools/calendar-tool.js";
|
|
9
|
-
import { searchCalendarTool } from "./tools/search-calendar-tool.js";
|
|
10
|
-
import { searchContactTool } from "./tools/search-contact-tool.js";
|
|
11
|
-
import { searchPhotoGalleryTool } from "./tools/search-photo-gallery-tool.js";
|
|
12
|
-
import { uploadPhotoTool } from "./tools/upload-photo-tool.js";
|
|
13
|
-
import { xiaoyiGuiTool } from "./tools/xiaoyi-gui-tool.js";
|
|
14
|
-
import { callPhoneTool } from "./tools/call-phone-tool.js";
|
|
15
|
-
import { searchMessageTool } from "./tools/search-message-tool.js";
|
|
16
|
-
import { sendMessageTool } from "./tools/send-message-tool.js";
|
|
17
|
-
import { searchFileTool } from "./tools/search-file-tool.js";
|
|
18
|
-
import { uploadFileTool } from "./tools/upload-file-tool.js";
|
|
19
|
-
import { createAlarmTool } from "./tools/create-alarm-tool.js";
|
|
20
|
-
import { searchAlarmTool } from "./tools/search-alarm-tool.js";
|
|
21
|
-
import { modifyAlarmTool } from "./tools/modify-alarm-tool.js";
|
|
22
|
-
import { deleteAlarmTool } from "./tools/delete-alarm-tool.js";
|
|
23
|
-
import { sendFileToUserTool } from "./tools/send-file-to-user-tool.js";
|
|
24
|
-
import { viewPushResultTool } from "./tools/view-push-result-tool.js";
|
|
25
|
-
import { imageReadingTool } from "./tools/image-reading-tool.js";
|
|
26
|
-
import { timestampToUtc8Tool } from "./tools/timestamp-to-utc8-tool.js";
|
|
27
|
-
import { xiaoyiCollectionTool } from "./tools/xiaoyi-collection-tool.js";
|
|
28
|
-
import { xiaoyiAddCollectionTool } from "./tools/xiaoyi-add-collection-tool.js";
|
|
29
|
-
import { xiaoyiDeleteCollectionTool } from "./tools/xiaoyi-delete-collection-tool.js";
|
|
30
|
-
import { saveMediaToGalleryTool } from "./tools/save-media-to-gallery-tool.js";
|
|
31
|
-
import { saveFileToPhoneTool } from "./tools/save-file-to-phone-tool.js";
|
|
32
|
-
import { searchEmailTool } from "./tools/search-email-tool.js";
|
|
33
4
|
import { filterToolsByDevice } from "./tools/device-tool-map.js";
|
|
34
5
|
import { getCurrentSessionContext } from "./tools/session-manager.js";
|
|
6
|
+
import { createAllTools } from "./tools/create-all-tools.js";
|
|
35
7
|
import { logger } from "./utils/logger.js";
|
|
36
8
|
/**
|
|
37
9
|
* Xiaoyi Channel Plugin for OpenClaw.
|
|
@@ -72,8 +44,8 @@ export const xyPlugin = {
|
|
|
72
44
|
},
|
|
73
45
|
outbound: xyOutbound,
|
|
74
46
|
agentTools: () => {
|
|
75
|
-
const allTools = [locationTool, noteTool, searchNoteTool, modifyNoteTool, calendarTool, searchCalendarTool, searchContactTool, searchPhotoGalleryTool, uploadPhotoTool, xiaoyiGuiTool, callPhoneTool, searchMessageTool, sendMessageTool, searchFileTool, uploadFileTool, createAlarmTool, searchAlarmTool, modifyAlarmTool, deleteAlarmTool, sendFileToUserTool, viewPushResultTool, imageReadingTool, timestampToUtc8Tool, xiaoyiCollectionTool, xiaoyiAddCollectionTool, xiaoyiDeleteCollectionTool, saveMediaToGalleryTool, saveFileToPhoneTool, searchEmailTool];
|
|
76
47
|
const ctx = getCurrentSessionContext();
|
|
48
|
+
const allTools = createAllTools(ctx);
|
|
77
49
|
const filtered = filterToolsByDevice(allTools, ctx?.deviceType);
|
|
78
50
|
logger.log(`[DEVICE-FILTER] deviceType=${ctx?.deviceType ?? "(none)"}, tools: ${allTools.length} → ${filtered.length} (${filtered.map(t => t.name).join(", ")})`);
|
|
79
51
|
return filtered;
|
package/dist/src/client.js
CHANGED
|
@@ -12,8 +12,14 @@ export function setClientRuntime(rt) {
|
|
|
12
12
|
/**
|
|
13
13
|
* Global cache for WebSocket managers.
|
|
14
14
|
* Key format: `${apiKey}-${agentId}`
|
|
15
|
+
* Uses globalThis to ensure a single cache across all module copies
|
|
16
|
+
* (same fix as session-manager.ts for openclaw multi-instance loading).
|
|
15
17
|
*/
|
|
16
|
-
const
|
|
18
|
+
const _g = globalThis;
|
|
19
|
+
if (!_g.__xyWsManagerCache) {
|
|
20
|
+
_g.__xyWsManagerCache = new Map();
|
|
21
|
+
}
|
|
22
|
+
const wsManagerCache = _g.__xyWsManagerCache;
|
|
17
23
|
/**
|
|
18
24
|
* Get or create a WebSocket manager for the given configuration.
|
|
19
25
|
* Reuses existing managers if config matches.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// Login Token 事件处理器
|
|
2
|
+
// 监听 LoginTokenEvent.ClawAutoLogin 事件,将 clientId 写入 .xiaoyitoken.json
|
|
3
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
4
|
+
import { dirname } from "path";
|
|
5
|
+
const TOKEN_FILE_PATH = "/home/sandbox/.openclaw/.xiaoyitoken.json";
|
|
6
|
+
/**
|
|
7
|
+
* 处理 LoginTokenEvent.ClawAutoLogin 事件
|
|
8
|
+
* 将 clientId 和当前时间戳写入 .xiaoyitoken.json 文件
|
|
9
|
+
*
|
|
10
|
+
* @param context - 事件上下文,包含 event 对象
|
|
11
|
+
* @param runtime - 运行时环境
|
|
12
|
+
*/
|
|
13
|
+
export function handleLoginTokenEvent(context, runtime) {
|
|
14
|
+
const log = runtime?.log ?? console.log;
|
|
15
|
+
const error = runtime?.error ?? console.error;
|
|
16
|
+
try {
|
|
17
|
+
const clientId = context.event?.payload?.clientId;
|
|
18
|
+
if (!clientId || typeof clientId !== "string") {
|
|
19
|
+
error("[LOGIN_TOKEN_HANDLER] invalid payload: missing clientId");
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
log(`[LOGIN_TOKEN_HANDLER] received login token event, clientId=${clientId}`);
|
|
23
|
+
// Ensure directory exists
|
|
24
|
+
const dir = dirname(TOKEN_FILE_PATH);
|
|
25
|
+
if (!existsSync(dir)) {
|
|
26
|
+
mkdirSync(dir, { recursive: true });
|
|
27
|
+
}
|
|
28
|
+
let tokens = [];
|
|
29
|
+
if (existsSync(TOKEN_FILE_PATH)) {
|
|
30
|
+
try {
|
|
31
|
+
const content = readFileSync(TOKEN_FILE_PATH, "utf-8");
|
|
32
|
+
tokens = JSON.parse(content);
|
|
33
|
+
if (!Array.isArray(tokens)) {
|
|
34
|
+
tokens = [];
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
tokens = [];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// Check if clientId already exists
|
|
42
|
+
const now = String(Date.now());
|
|
43
|
+
const existing = tokens.find((t) => t.clientId === clientId);
|
|
44
|
+
if (existing) {
|
|
45
|
+
// Update timestamp
|
|
46
|
+
existing.timestamp = now;
|
|
47
|
+
log(`[LOGIN_TOKEN_HANDLER] updated timestamp for clientId=${clientId}`);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
// Insert new entry
|
|
51
|
+
tokens.push({ clientId, timestamp: now });
|
|
52
|
+
log(`[LOGIN_TOKEN_HANDLER] inserted new entry for clientId=${clientId}`);
|
|
53
|
+
}
|
|
54
|
+
writeFileSync(TOKEN_FILE_PATH, JSON.stringify(tokens, null, 2), "utf-8");
|
|
55
|
+
log(`[LOGIN_TOKEN_HANDLER] wrote token file: ${TOKEN_FILE_PATH}`);
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
error("[LOGIN_TOKEN_HANDLER] failed to handle event:", err);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { OutboundWebSocketMessage } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Simple message queue for buffering outbound WebSocket messages
|
|
4
|
+
* during disconnection and reconnection stabilization period.
|
|
5
|
+
*/
|
|
6
|
+
export declare class MessageQueue {
|
|
7
|
+
private items;
|
|
8
|
+
private log;
|
|
9
|
+
constructor(log?: (msg: string, ...args: any[]) => void);
|
|
10
|
+
/** Enqueue a message. Drops oldest if over limit. */
|
|
11
|
+
enqueue(message: OutboundWebSocketMessage): void;
|
|
12
|
+
/** Flush all queued messages by calling sendFn for each, then clear. */
|
|
13
|
+
flush(sendFn: (message: OutboundWebSocketMessage) => void): void;
|
|
14
|
+
/** Clear all queued messages without sending. */
|
|
15
|
+
clear(): void;
|
|
16
|
+
get size(): number;
|
|
17
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
const MAX_QUEUE_SIZE = 1000;
|
|
2
|
+
/**
|
|
3
|
+
* Simple message queue for buffering outbound WebSocket messages
|
|
4
|
+
* during disconnection and reconnection stabilization period.
|
|
5
|
+
*/
|
|
6
|
+
export class MessageQueue {
|
|
7
|
+
items = [];
|
|
8
|
+
log;
|
|
9
|
+
constructor(log) {
|
|
10
|
+
this.log = log ?? console.log;
|
|
11
|
+
}
|
|
12
|
+
/** Enqueue a message. Drops oldest if over limit. */
|
|
13
|
+
enqueue(message) {
|
|
14
|
+
if (this.items.length >= MAX_QUEUE_SIZE) {
|
|
15
|
+
this.log(`[MessageQueue] Queue full (${MAX_QUEUE_SIZE}), dropping oldest message`);
|
|
16
|
+
this.items.shift();
|
|
17
|
+
}
|
|
18
|
+
this.items.push(message);
|
|
19
|
+
this.log(`[MessageQueue] Enqueued message, queue size: ${this.items.length}`);
|
|
20
|
+
}
|
|
21
|
+
/** Flush all queued messages by calling sendFn for each, then clear. */
|
|
22
|
+
flush(sendFn) {
|
|
23
|
+
const count = this.items.length;
|
|
24
|
+
if (count === 0) {
|
|
25
|
+
this.log("[MessageQueue] Queue empty, nothing to flush");
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
this.log(`[MessageQueue] Flushing ${count} queued messages`);
|
|
29
|
+
for (const msg of this.items) {
|
|
30
|
+
try {
|
|
31
|
+
sendFn(msg);
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
this.log(`[MessageQueue] Error flushing message: ${err}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
this.items = [];
|
|
38
|
+
this.log(`[MessageQueue] Flush complete`);
|
|
39
|
+
}
|
|
40
|
+
/** Clear all queued messages without sending. */
|
|
41
|
+
clear() {
|
|
42
|
+
const count = this.items.length;
|
|
43
|
+
this.items = [];
|
|
44
|
+
if (count > 0) {
|
|
45
|
+
this.log(`[MessageQueue] Cleared ${count} messages`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
get size() {
|
|
49
|
+
return this.items.length;
|
|
50
|
+
}
|
|
51
|
+
}
|
package/dist/src/monitor.js
CHANGED
|
@@ -2,9 +2,13 @@ import { resolveXYConfig } from "./config.js";
|
|
|
2
2
|
import { getXYWebSocketManager, diagnoseAllManagers, cleanupOrphanConnections, removeXYWebSocketManager } from "./client.js";
|
|
3
3
|
import { handleXYMessage } from "./bot.js";
|
|
4
4
|
import { parseA2AMessage } from "./parser.js";
|
|
5
|
-
import { hasActiveTask } from "./task-manager.js";
|
|
5
|
+
import { hasActiveTask, getAllActiveTaskBindings } from "./task-manager.js";
|
|
6
|
+
import { sendA2AResponse } from "./formatter.js";
|
|
6
7
|
import { handleTriggerEvent } from "./trigger-handler.js";
|
|
8
|
+
import { handleSelfEvolutionEvent, handleSelfEvolutionStateGetEvent } from "./self-evolution-handler.js";
|
|
9
|
+
import { handleLoginTokenEvent } from "./login-token-handler.js";
|
|
7
10
|
import { cleanupStaleTempFiles } from "./reply-dispatcher.js";
|
|
11
|
+
import { cleanupStaleSessions, getActiveSessionCount, cleanupAllSessions } from "./tools/session-manager.js";
|
|
8
12
|
/**
|
|
9
13
|
* Per-session serial queue that ensures messages from the same session are processed
|
|
10
14
|
* in arrival order while allowing different sessions to run concurrently.
|
|
@@ -156,6 +160,20 @@ export async function monitorXYProvider(opts = {}) {
|
|
|
156
160
|
error(`[MONITOR] Failed to handle trigger-event:`, err);
|
|
157
161
|
});
|
|
158
162
|
};
|
|
163
|
+
const selfEvolutionHandler = (context) => {
|
|
164
|
+
log(`[MONITOR] Received self-evolution-event, dispatching to handler...`);
|
|
165
|
+
handleSelfEvolutionEvent(context, runtime);
|
|
166
|
+
};
|
|
167
|
+
const selfEvolutionStateGetHandler = (context) => {
|
|
168
|
+
log(`[MONITOR] Received self-evolution-state-get-event, dispatching to handler...`);
|
|
169
|
+
handleSelfEvolutionStateGetEvent(context, account, runtime, wsManager).catch((err) => {
|
|
170
|
+
error(`[MONITOR] Failed to handle self-evolution-state-get-event:`, err);
|
|
171
|
+
});
|
|
172
|
+
};
|
|
173
|
+
const loginTokenEventHandler = (context) => {
|
|
174
|
+
log(`[MONITOR] Received login-token-event, dispatching to handler...`);
|
|
175
|
+
handleLoginTokenEvent(context, runtime);
|
|
176
|
+
};
|
|
159
177
|
const cleanup = () => {
|
|
160
178
|
log("XY gateway: cleaning up...");
|
|
161
179
|
// 🔍 Diagnose before cleanup
|
|
@@ -173,20 +191,53 @@ export async function monitorXYProvider(opts = {}) {
|
|
|
173
191
|
wsManager.off("disconnected", disconnectedHandler);
|
|
174
192
|
wsManager.off("error", errorHandler);
|
|
175
193
|
wsManager.off("trigger-event", triggerEventHandler);
|
|
194
|
+
wsManager.off("self-evolution-event", selfEvolutionHandler);
|
|
195
|
+
wsManager.off("self-evolution-state-get-event", selfEvolutionStateGetHandler);
|
|
196
|
+
wsManager.off("login-token-event", loginTokenEventHandler);
|
|
176
197
|
// ✅ Disconnect the wsManager to prevent connection leaks
|
|
177
198
|
// This is safe because each gateway lifecycle should have clean connections
|
|
178
199
|
wsManager.disconnect();
|
|
179
200
|
// ✅ Remove manager from cache to prevent reusing dirty state
|
|
180
201
|
removeXYWebSocketManager(account);
|
|
202
|
+
// Clean up all active sessions
|
|
203
|
+
cleanupAllSessions();
|
|
181
204
|
loggedServers.clear();
|
|
182
205
|
activeMessages.clear();
|
|
183
|
-
log(`[MONITOR-HANDLER] 🧹 Cleanup complete, cleared active messages`);
|
|
206
|
+
log(`[MONITOR-HANDLER] 🧹 Cleanup complete, cleared active messages and sessions`);
|
|
184
207
|
// 🔍 Diagnose after cleanup
|
|
185
208
|
console.log("🔍 [DIAGNOSTICS] Checking WebSocket managers after cleanup...");
|
|
186
209
|
diagnoseAllManagers();
|
|
187
210
|
};
|
|
188
|
-
const handleAbort = () => {
|
|
189
|
-
log("XY gateway: abort signal received, stopping");
|
|
211
|
+
const handleAbort = async () => {
|
|
212
|
+
log("XY gateway: abort signal received, sending notifications before stopping");
|
|
213
|
+
// 📤 Send restart notification to all active sessions before disconnecting
|
|
214
|
+
try {
|
|
215
|
+
const activeBindings = getAllActiveTaskBindings();
|
|
216
|
+
if (activeBindings.length > 0) {
|
|
217
|
+
const config = resolveXYConfig(cfg);
|
|
218
|
+
const notificationText = "Gateway即将重启,重启期间可能短暂出现\u201c环境异常\u201d提示,请稍候并耐心重试~";
|
|
219
|
+
log(`[MONITOR] 📤 Sending restart notifications to ${activeBindings.length} active session(s)`);
|
|
220
|
+
const sendPromises = activeBindings.map(binding => sendA2AResponse({
|
|
221
|
+
config,
|
|
222
|
+
sessionId: binding.sessionId,
|
|
223
|
+
taskId: binding.currentTaskId,
|
|
224
|
+
messageId: binding.currentMessageId,
|
|
225
|
+
text: notificationText,
|
|
226
|
+
append: false,
|
|
227
|
+
final: true,
|
|
228
|
+
}).catch(err => {
|
|
229
|
+
error(`[MONITOR] Failed to send restart notification to session ${binding.sessionId}: ${String(err)}`);
|
|
230
|
+
}));
|
|
231
|
+
await Promise.all(sendPromises);
|
|
232
|
+
log(`[MONITOR] ✅ Restart notifications sent to ${activeBindings.length} session(s)`);
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
log(`[MONITOR] No active sessions, skipping restart notifications`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
catch (err) {
|
|
239
|
+
error(`[MONITOR] Error sending restart notifications: ${String(err)}`);
|
|
240
|
+
}
|
|
190
241
|
cleanup();
|
|
191
242
|
log("XY gateway stopped");
|
|
192
243
|
resolve();
|
|
@@ -203,6 +254,9 @@ export async function monitorXYProvider(opts = {}) {
|
|
|
203
254
|
wsManager.on("disconnected", disconnectedHandler);
|
|
204
255
|
wsManager.on("error", errorHandler);
|
|
205
256
|
wsManager.on("trigger-event", triggerEventHandler);
|
|
257
|
+
wsManager.on("self-evolution-event", selfEvolutionHandler);
|
|
258
|
+
wsManager.on("self-evolution-state-get-event", selfEvolutionStateGetHandler);
|
|
259
|
+
wsManager.on("login-token-event", loginTokenEventHandler);
|
|
206
260
|
// Start periodic health check (every 6 hours)
|
|
207
261
|
console.log("🏥 Starting periodic health check (every 6 hours)...");
|
|
208
262
|
healthCheckInterval = setInterval(() => {
|
|
@@ -213,6 +267,12 @@ export async function monitorXYProvider(opts = {}) {
|
|
|
213
267
|
if (cleaned > 0) {
|
|
214
268
|
console.log(`🧹 [HEALTH CHECK] Auto-cleaned ${cleaned} manager(s) with orphan connections`);
|
|
215
269
|
}
|
|
270
|
+
// Cleanup stale sessions (older than 10min TTL)
|
|
271
|
+
const cleanedSessions = cleanupStaleSessions();
|
|
272
|
+
const remainingSessions = getActiveSessionCount();
|
|
273
|
+
if (cleanedSessions > 0 || remainingSessions > 0) {
|
|
274
|
+
console.log(`🧹 [HEALTH CHECK] Sessions: cleaned=${cleanedSessions}, active=${remainingSessions}`);
|
|
275
|
+
}
|
|
216
276
|
// Cleanup stale temp files (older than 24 hours)
|
|
217
277
|
void cleanupStaleTempFiles();
|
|
218
278
|
}, 6 * 60 * 60 * 1000); // 6 hours
|
package/dist/src/provider.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import type { ProviderPlugin } from "openclaw/plugin-sdk/provider-
|
|
1
|
+
import type { ProviderPlugin } from "openclaw/plugin-sdk/provider-model-shared";
|
|
2
|
+
export declare function applySelfEvolutionPrompt(systemPrompt: string | undefined, enabled: boolean): string;
|
|
2
3
|
export declare const xiaoyiProvider: ProviderPlugin;
|