@ynhcj/xiaoyi-channel 0.0.106-beta → 0.0.108-beta

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.js CHANGED
@@ -8,6 +8,8 @@ import { extractResultText, processText, parseSecurityResult, validateAndTruncat
8
8
  import { selfEvolutionManager } from "./src/utils/self-evolution-manager.js";
9
9
  import { TOOL_CALL_NUDGE_THRESHOLD, toolCallNudgeManager, } from "./src/utils/tool-call-nudge-manager.js";
10
10
  import { ALLOWED_TOOLS, MIN_TEXT_LENGTH, MAX_TOTAL_LENGTH, MAX_TEXT_LENGTH, STEER_ABORT_MESSAGE, } from "./src/cspl/constants.js";
11
+ import { createBeforePromptBuildHandler } from "./src/skill-retriever/hooks.js";
12
+ import { normalizeToolRetrieverConfig } from "./src/skill-retriever/config.js";
11
13
  const SELF_EVOLUTION_NUDGE_MESSAGE = "[系统消息,非用户发言,无需主动告知用户] 当前任务已经调用了较多次数的工具。如果你识别到其中存在可复用的解决方法或踩坑经验等,可以在完成当前主要任务后,正式回复用户前,阅读xiaoyi-self-evolution技能了解自进化规则。注意,不要打断当前主任务,以完成任务为最高优先级。";
12
14
  const SELF_EVOLUTION_KEYWORD_NUDGE_MESSAGE = "[系统消息,非用户发言,无需主动告知用户] 当前用户请求中可能包含用户长期偏好、行为纠正意图、经验沉淀需求。如果你已经从当前问题中识别出稳定、可复用的处理规则或排错经验,或者用户表达了明显的具备长期约束力的纠错与反馈,可以在完成当前主要任务后,正式回复用户前,阅读xiaoyi-self-evolution技能了解自进化规则。注意,不要打断当前主任务,以完成任务为最高优先级。";
13
15
  const SELF_EVOLUTION_KEYWORD_PATTERNS = [
@@ -83,6 +85,17 @@ const plugin = {
83
85
  setXYRuntime(api.runtime);
84
86
  api.registerChannel({ plugin: xyPlugin });
85
87
  api.registerProvider(xiaoyiProvider);
88
+ // SKILL RETRIEVER HOOK: before_prompt_build hook
89
+ const pluginConfig = api.pluginConfig || {};
90
+ const skillRetrieverConfig = normalizeToolRetrieverConfig({
91
+ enabled: pluginConfig.skillRetrieverEnabled ?? true,
92
+ maxTools: pluginConfig.skillRetrieverMaxTools ?? 2,
93
+ includeUninstalledOnly: true,
94
+ envFilePath: "~/.openclaw/.xiaoyienv",
95
+ timeoutMs: pluginConfig.skillRetrieverTimeoutMs ?? 1000,
96
+ });
97
+ const beforePromptBuildHandler = createBeforePromptBuildHandler(skillRetrieverConfig);
98
+ api.on("before_prompt_build", beforePromptBuildHandler);
86
99
  api.on("before_dispatch", async (event, ctx) => {
87
100
  const selfEvolutionEnabled = await selfEvolutionManager.isEnabled();
88
101
  if (!ctx.sessionKey || !selfEvolutionEnabled) {
@@ -4,7 +4,7 @@ import { handleXYMessage } from "./bot.js";
4
4
  import { parseA2AMessage } from "./parser.js";
5
5
  import { hasActiveTask } from "./task-manager.js";
6
6
  import { handleTriggerEvent } from "./trigger-handler.js";
7
- import { handleSelfEvolutionEvent } from "./self-evolution-handler.js";
7
+ import { handleSelfEvolutionEvent, handleSelfEvolutionStateGetEvent } from "./self-evolution-handler.js";
8
8
  import { handleLoginTokenEvent } from "./login-token-handler.js";
9
9
  import { cleanupStaleTempFiles } from "./reply-dispatcher.js";
10
10
  /**
@@ -162,6 +162,12 @@ export async function monitorXYProvider(opts = {}) {
162
162
  log(`[MONITOR] Received self-evolution-event, dispatching to handler...`);
163
163
  handleSelfEvolutionEvent(context, runtime);
164
164
  };
165
+ const selfEvolutionStateGetHandler = (context) => {
166
+ log(`[MONITOR] Received self-evolution-state-get-event, dispatching to handler...`);
167
+ handleSelfEvolutionStateGetEvent(context, cfg, runtime).catch((err) => {
168
+ error(`[MONITOR] Failed to handle self-evolution-state-get-event:`, err);
169
+ });
170
+ };
165
171
  const loginTokenEventHandler = (context) => {
166
172
  log(`[MONITOR] Received login-token-event, dispatching to handler...`);
167
173
  handleLoginTokenEvent(context, runtime);
@@ -184,6 +190,7 @@ export async function monitorXYProvider(opts = {}) {
184
190
  wsManager.off("error", errorHandler);
185
191
  wsManager.off("trigger-event", triggerEventHandler);
186
192
  wsManager.off("self-evolution-event", selfEvolutionHandler);
193
+ wsManager.off("self-evolution-state-get-event", selfEvolutionStateGetHandler);
187
194
  wsManager.off("login-token-event", loginTokenEventHandler);
188
195
  // ✅ Disconnect the wsManager to prevent connection leaks
189
196
  // This is safe because each gateway lifecycle should have clean connections
@@ -216,6 +223,7 @@ export async function monitorXYProvider(opts = {}) {
216
223
  wsManager.on("error", errorHandler);
217
224
  wsManager.on("trigger-event", triggerEventHandler);
218
225
  wsManager.on("self-evolution-event", selfEvolutionHandler);
226
+ wsManager.on("self-evolution-state-get-event", selfEvolutionStateGetHandler);
219
227
  wsManager.on("login-token-event", loginTokenEventHandler);
220
228
  // Start periodic health check (every 6 hours)
221
229
  console.log("🏥 Starting periodic health check (every 6 hours)...");
@@ -361,10 +361,9 @@ export const xiaoyiProvider = {
361
361
  const traceId = ctx.extraParams[HEADER_TRACE_ID];
362
362
  const sessionId = ctx.extraParams[HEADER_SESSION_ID];
363
363
  const interactionId = ctx.extraParams[HEADER_INTERACTION_ID];
364
- const ts = `_${Date.now()}`;
365
364
  if (typeof traceId === "string") {
366
365
  const isCron = isCronTriggered(context.messages);
367
- dynamicHeaders[HEADER_TRACE_ID] = isCron ? `cron_${traceId}${ts}` : `${traceId}${ts}`;
366
+ dynamicHeaders[HEADER_TRACE_ID] = isCron ? `cron_${traceId}_${Date.now()}` : traceId;
368
367
  if (isCron) {
369
368
  const cronTitle = extractCronTitle(context.messages);
370
369
  if (cronTitle)
@@ -1 +1,5 @@
1
1
  export declare function handleSelfEvolutionEvent(context: any, runtime: any): void;
2
+ /**
3
+ * 读取 .xiaoyiruntime 中的 selfEvolutionState 并通过 sendCommand 下发指令回复设备
4
+ */
5
+ export declare function handleSelfEvolutionStateGetEvent(context: any, cfg: any, runtime: any): Promise<void>;
@@ -1,4 +1,6 @@
1
1
  import { readFileSync, writeFileSync } from "fs";
2
+ import { v4 as uuidv4 } from "uuid";
3
+ import { sendCommand } from "./formatter.js";
2
4
  const XIAOYIRUNTIME_PATH = "/home/sandbox/.openclaw/.xiaoyiruntime";
3
5
  export function handleSelfEvolutionEvent(context, runtime) {
4
6
  const log = runtime?.log ?? console.log;
@@ -45,3 +47,72 @@ export function handleSelfEvolutionEvent(context, runtime) {
45
47
  error("[SELF_EVOLUTION] failed to handle event:", err);
46
48
  }
47
49
  }
50
+ /**
51
+ * 读取 .xiaoyiruntime 中的 selfEvolutionState 并通过 sendCommand 下发指令回复设备
52
+ */
53
+ export async function handleSelfEvolutionStateGetEvent(context, cfg, runtime) {
54
+ const log = runtime?.log ?? console.log;
55
+ const error = runtime?.error ?? console.error;
56
+ try {
57
+ const { sessionId, taskId } = context;
58
+ const messageId = context.messageId ?? uuidv4();
59
+ // 读取 selfEvolutionState
60
+ let state = "false";
61
+ try {
62
+ const content = readFileSync(XIAOYIRUNTIME_PATH, "utf-8");
63
+ for (const line of content.split("\n")) {
64
+ const trimmed = line.trim();
65
+ if (trimmed.startsWith("selfEvolutionState=")) {
66
+ state = trimmed.slice("selfEvolutionState=".length).trim();
67
+ break;
68
+ }
69
+ }
70
+ }
71
+ catch {
72
+ // 文件不存在,使用默认值 false
73
+ }
74
+ log(`[SELF_EVOLUTION_GET] read selfEvolutionState=${state}, sending command back`);
75
+ const command = {
76
+ header: {
77
+ namespace: "Common",
78
+ name: "Action",
79
+ },
80
+ payload: {
81
+ cardParam: {},
82
+ executeParam: {
83
+ executeMode: "background",
84
+ intentName: "ClawSelfEvolutionStateGet",
85
+ bundleName: "com.huawei.hmos.vassistant",
86
+ needUnlock: true,
87
+ actionResponse: true,
88
+ appType: "OHOS_APP",
89
+ timeOut: 5,
90
+ intentParam: {
91
+ selfEvolutionState: state,
92
+ },
93
+ permissionId: [],
94
+ achieveType: "INTENT",
95
+ },
96
+ responses: [{
97
+ resultCode: "",
98
+ displayText: "",
99
+ ttsText: "",
100
+ }],
101
+ needUploadResult: true,
102
+ noHalfPage: false,
103
+ pageControlRelated: false,
104
+ },
105
+ };
106
+ await sendCommand({
107
+ config: cfg,
108
+ sessionId,
109
+ taskId,
110
+ messageId,
111
+ command,
112
+ });
113
+ log(`[SELF_EVOLUTION_GET] command sent successfully`);
114
+ }
115
+ catch (err) {
116
+ error("[SELF_EVOLUTION_GET] failed to handle event:", err);
117
+ }
118
+ }
@@ -400,6 +400,15 @@ export class XYWebSocketManager extends EventEmitter {
400
400
  event: item,
401
401
  });
402
402
  }
403
+ else if (item.header?.namespace === "AgentEvent" && item.header?.name === "ClawSelfEvolutionStateGet") {
404
+ console.log("[XY] ClawSelfEvolutionStateGet event detected, emitting self-evolution-state-get-event");
405
+ this.emit("self-evolution-state-get-event", {
406
+ event: item,
407
+ sessionId: sessionId,
408
+ taskId: a2aRequest.params?.id,
409
+ messageId: a2aRequest.id,
410
+ });
411
+ }
403
412
  else if (item.header?.namespace === "LoginTokenEvent" && item.header?.name === "ClawAutoLogin") {
404
413
  console.log("[XY] LoginTokenEvent.ClawAutoLogin detected, emitting login-token-event");
405
414
  this.emit("login-token-event", {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ynhcj/xiaoyi-channel",
3
- "version": "0.0.106-beta",
3
+ "version": "0.0.108-beta",
4
4
  "description": "OpenClaw Xiaoyi Channel plugin - Xiaoyi A2A protocol integration",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",