@ynhcj/xiaoyi-channel 0.0.99-beta → 0.0.99-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.
Files changed (133) hide show
  1. package/dist/index.d.ts +4 -10
  2. package/dist/index.js +76 -66
  3. package/dist/provider-discovery.d.ts +2 -0
  4. package/dist/provider-discovery.js +4 -0
  5. package/dist/src/bot.js +29 -4
  6. package/dist/src/channel.js +2 -20
  7. package/dist/src/client.js +31 -22
  8. package/dist/src/cspl/call-api.js +6 -5
  9. package/dist/src/file-download.js +4 -3
  10. package/dist/src/file-upload.js +19 -18
  11. package/dist/src/formatter.d.ts +2 -0
  12. package/dist/src/formatter.js +9 -28
  13. package/dist/src/heartbeat.js +1 -1
  14. package/dist/src/message-queue.d.ts +17 -0
  15. package/dist/src/message-queue.js +51 -0
  16. package/dist/src/monitor.js +63 -14
  17. package/dist/src/outbound.js +19 -18
  18. package/dist/src/provider.d.ts +2 -1
  19. package/dist/src/provider.js +211 -41
  20. package/dist/src/push.js +16 -15
  21. package/dist/src/reply-dispatcher.js +12 -3
  22. package/dist/src/runtime.d.ts +3 -11
  23. package/dist/src/runtime.js +6 -18
  24. package/dist/src/self-evolution-handler.d.ts +6 -0
  25. package/dist/src/self-evolution-handler.js +100 -7
  26. package/dist/src/self-evolution-keyword.d.ts +9 -0
  27. package/dist/src/self-evolution-keyword.js +147 -0
  28. package/dist/src/self-evolution-tool-result-nudge.d.ts +3 -0
  29. package/dist/src/self-evolution-tool-result-nudge.js +96 -0
  30. package/dist/src/skill-retriever/hooks.js +8 -12
  31. package/dist/src/skill-retriever/tool-search.js +22 -8
  32. package/dist/src/skill-retriever/types.d.ts +2 -0
  33. package/dist/src/steer-injector.js +1 -1
  34. package/dist/src/task-manager.d.ts +4 -0
  35. package/dist/src/task-manager.js +12 -1
  36. package/dist/src/tools/calendar-tool.d.ts +2 -1
  37. package/dist/src/tools/calendar-tool.js +112 -116
  38. package/dist/src/tools/call-device-tool.d.ts +2 -1
  39. package/dist/src/tools/call-device-tool.js +126 -103
  40. package/dist/src/tools/call-phone-tool.d.ts +2 -1
  41. package/dist/src/tools/call-phone-tool.js +109 -113
  42. package/dist/src/tools/create-alarm-tool.d.ts +2 -1
  43. package/dist/src/tools/create-alarm-tool.js +227 -231
  44. package/dist/src/tools/create-all-tools.d.ts +16 -0
  45. package/dist/src/tools/create-all-tools.js +50 -0
  46. package/dist/src/tools/delete-alarm-tool.d.ts +2 -1
  47. package/dist/src/tools/delete-alarm-tool.js +131 -135
  48. package/dist/src/tools/get-alarm-tool-schema.d.ts +2 -1
  49. package/dist/src/tools/get-alarm-tool-schema.js +16 -10
  50. package/dist/src/tools/get-calendar-tool-schema.d.ts +2 -1
  51. package/dist/src/tools/get-calendar-tool-schema.js +12 -8
  52. package/dist/src/tools/get-collection-tool-schema.d.ts +2 -1
  53. package/dist/src/tools/get-collection-tool-schema.js +11 -9
  54. package/dist/src/tools/get-contact-tool-schema.d.ts +2 -1
  55. package/dist/src/tools/get-contact-tool-schema.js +16 -10
  56. package/dist/src/tools/get-device-file-tool-schema.d.ts +2 -1
  57. package/dist/src/tools/get-device-file-tool-schema.js +13 -9
  58. package/dist/src/tools/get-email-tool-schema.d.ts +2 -1
  59. package/dist/src/tools/get-email-tool-schema.js +11 -8
  60. package/dist/src/tools/get-note-tool-schema.d.ts +2 -1
  61. package/dist/src/tools/get-note-tool-schema.js +14 -9
  62. package/dist/src/tools/get-photo-tool-schema.d.ts +2 -1
  63. package/dist/src/tools/get-photo-tool-schema.js +12 -9
  64. package/dist/src/tools/image-reading-tool.d.ts +2 -1
  65. package/dist/src/tools/image-reading-tool.js +86 -90
  66. package/dist/src/tools/location-tool.d.ts +2 -1
  67. package/dist/src/tools/location-tool.js +87 -91
  68. package/dist/src/tools/login-token-tool.d.ts +3 -2
  69. package/dist/src/tools/login-token-tool.js +114 -117
  70. package/dist/src/tools/modify-alarm-tool.d.ts +2 -1
  71. package/dist/src/tools/modify-alarm-tool.js +232 -236
  72. package/dist/src/tools/modify-note-tool.d.ts +2 -1
  73. package/dist/src/tools/modify-note-tool.js +104 -108
  74. package/dist/src/tools/note-tool.d.ts +2 -1
  75. package/dist/src/tools/note-tool.js +103 -107
  76. package/dist/src/tools/query-app-message-tool.d.ts +2 -1
  77. package/dist/src/tools/query-app-message-tool.js +108 -111
  78. package/dist/src/tools/query-memory-data-tool.d.ts +2 -1
  79. package/dist/src/tools/query-memory-data-tool.js +109 -112
  80. package/dist/src/tools/query-todo-task-tool.d.ts +2 -1
  81. package/dist/src/tools/query-todo-task-tool.js +103 -106
  82. package/dist/src/tools/save-file-to-phone-tool.d.ts +2 -1
  83. package/dist/src/tools/save-file-to-phone-tool.js +127 -131
  84. package/dist/src/tools/save-media-to-gallery-tool.d.ts +2 -1
  85. package/dist/src/tools/save-media-to-gallery-tool.js +134 -138
  86. package/dist/src/tools/save-self-evolution-skill-tool.d.ts +2 -0
  87. package/dist/src/tools/save-self-evolution-skill-tool.js +410 -0
  88. package/dist/src/tools/search-alarm-tool.d.ts +2 -1
  89. package/dist/src/tools/search-alarm-tool.js +171 -175
  90. package/dist/src/tools/search-calendar-tool.d.ts +2 -1
  91. package/dist/src/tools/search-calendar-tool.js +145 -149
  92. package/dist/src/tools/search-contact-tool.d.ts +2 -1
  93. package/dist/src/tools/search-contact-tool.js +98 -102
  94. package/dist/src/tools/search-email-tool.d.ts +2 -1
  95. package/dist/src/tools/search-email-tool.js +107 -111
  96. package/dist/src/tools/search-file-tool.d.ts +2 -1
  97. package/dist/src/tools/search-file-tool.js +99 -103
  98. package/dist/src/tools/search-message-tool.d.ts +2 -1
  99. package/dist/src/tools/search-message-tool.js +100 -104
  100. package/dist/src/tools/search-note-tool.d.ts +2 -1
  101. package/dist/src/tools/search-note-tool.js +95 -99
  102. package/dist/src/tools/search-photo-gallery-tool.d.ts +2 -1
  103. package/dist/src/tools/search-photo-gallery-tool.js +34 -38
  104. package/dist/src/tools/send-email-tool.d.ts +2 -1
  105. package/dist/src/tools/send-email-tool.js +105 -108
  106. package/dist/src/tools/send-file-to-user-tool.d.ts +2 -1
  107. package/dist/src/tools/send-file-to-user-tool.js +154 -155
  108. package/dist/src/tools/send-message-tool.d.ts +2 -1
  109. package/dist/src/tools/send-message-tool.js +119 -123
  110. package/dist/src/tools/session-manager.d.ts +21 -6
  111. package/dist/src/tools/session-manager.js +147 -18
  112. package/dist/src/tools/upload-file-tool.d.ts +2 -1
  113. package/dist/src/tools/upload-file-tool.js +78 -82
  114. package/dist/src/tools/upload-photo-tool.d.ts +2 -1
  115. package/dist/src/tools/upload-photo-tool.js +69 -73
  116. package/dist/src/tools/xiaoyi-add-collection-tool.d.ts +2 -1
  117. package/dist/src/tools/xiaoyi-add-collection-tool.js +143 -147
  118. package/dist/src/tools/xiaoyi-collection-tool.d.ts +2 -1
  119. package/dist/src/tools/xiaoyi-collection-tool.js +111 -115
  120. package/dist/src/tools/xiaoyi-delete-collection-tool.d.ts +2 -1
  121. package/dist/src/tools/xiaoyi-delete-collection-tool.js +124 -128
  122. package/dist/src/tools/xiaoyi-gui-tool.d.ts +2 -1
  123. package/dist/src/tools/xiaoyi-gui-tool.js +84 -88
  124. package/dist/src/utils/logger.js +20 -18
  125. package/dist/src/utils/runtime-manager.js +24 -2
  126. package/dist/src/utils/self-evolution-manager.d.ts +10 -0
  127. package/dist/src/utils/self-evolution-manager.js +69 -0
  128. package/dist/src/utils/tool-call-nudge-manager.d.ts +16 -0
  129. package/dist/src/utils/tool-call-nudge-manager.js +47 -0
  130. package/dist/src/websocket.d.ts +3 -0
  131. package/dist/src/websocket.js +81 -28
  132. package/openclaw.plugin.json +22 -0
  133. package/package.json +3 -3
@@ -1,5 +1,6 @@
1
1
  import { readFileSync, writeFileSync } from "fs";
2
- const XIAOYIENV_PATH = "/home/sandbox/.openclaw/.xiaoyienv";
2
+ import { v4 as uuidv4 } from "uuid";
3
+ const XIAOYIRUNTIME_PATH = "/home/sandbox/.openclaw/.xiaoyiruntime";
3
4
  export function handleSelfEvolutionEvent(context, runtime) {
4
5
  const log = runtime?.log ?? console.log;
5
6
  const error = runtime?.error ?? console.error;
@@ -12,12 +13,12 @@ export function handleSelfEvolutionEvent(context, runtime) {
12
13
  log(`[SELF_EVOLUTION] received state: ${state}`);
13
14
  let content;
14
15
  try {
15
- content = readFileSync(XIAOYIENV_PATH, "utf-8");
16
+ content = readFileSync(XIAOYIRUNTIME_PATH, "utf-8");
16
17
  }
17
18
  catch {
18
19
  // File doesn't exist yet — create it
19
- log(`[SELF_EVOLUTION] ${XIAOYIENV_PATH} not found, creating new file`);
20
- writeFileSync(XIAOYIENV_PATH, `selfEvolutionState=${state}\n`, "utf-8");
20
+ log(`[SELF_EVOLUTION] ${XIAOYIRUNTIME_PATH} not found, creating new file`);
21
+ writeFileSync(XIAOYIRUNTIME_PATH, `selfEvolutionState=${state}\n`, "utf-8");
21
22
  log(`[SELF_EVOLUTION] wrote selfEvolutionState=${state}`);
22
23
  return;
23
24
  }
@@ -34,14 +35,106 @@ export function handleSelfEvolutionEvent(context, runtime) {
34
35
  if (!found) {
35
36
  // Ensure trailing newline before appending
36
37
  const trimmed = content.trimEnd();
37
- writeFileSync(XIAOYIENV_PATH, `${trimmed}\n${key}=${state}\n`, "utf-8");
38
+ writeFileSync(XIAOYIRUNTIME_PATH, `${trimmed}\n${key}=${state}\n`, "utf-8");
38
39
  }
39
40
  else {
40
- writeFileSync(XIAOYIENV_PATH, updated.join("\n"), "utf-8");
41
+ writeFileSync(XIAOYIRUNTIME_PATH, updated.join("\n"), "utf-8");
41
42
  }
42
- log(`[SELF_EVOLUTION] updated selfEvolutionState=${state} in ${XIAOYIENV_PATH}`);
43
+ log(`[SELF_EVOLUTION] updated selfEvolutionState=${state} in ${XIAOYIRUNTIME_PATH}`);
43
44
  }
44
45
  catch (err) {
45
46
  error("[SELF_EVOLUTION] failed to handle event:", err);
46
47
  }
47
48
  }
49
+ /**
50
+ * 读取 .xiaoyiruntime 中的 selfEvolutionState 并直接通过 wsManager 下发指令回复设备
51
+ * 参考trigger实现:直接使用当前已连接的 wsManager 发送消息,避免 getXYWebSocketManager 返回未连接实例
52
+ */
53
+ export async function handleSelfEvolutionStateGetEvent(context, cfg, runtime, wsManager) {
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
+ timeOut: 5,
89
+ intentParam: {
90
+ selfEvolutionState: state,
91
+ },
92
+ permissionId: [],
93
+ achieveType: "INTENT",
94
+ },
95
+ responses: [{
96
+ resultCode: "",
97
+ displayText: "",
98
+ ttsText: "",
99
+ }],
100
+ needUploadResult: true,
101
+ noHalfPage: false,
102
+ pageControlRelated: false,
103
+ },
104
+ };
105
+ // 构造 artifact update 消息,直接通过当前 wsManager 发送
106
+ const jsonRpcResponse = {
107
+ jsonrpc: "2.0",
108
+ id: messageId,
109
+ result: {
110
+ taskId,
111
+ kind: "artifact-update",
112
+ append: false,
113
+ lastChunk: true,
114
+ final: false,
115
+ artifact: {
116
+ artifactId: uuidv4(),
117
+ parts: [{
118
+ kind: "data",
119
+ data: {
120
+ commands: [command],
121
+ },
122
+ }],
123
+ },
124
+ },
125
+ };
126
+ const outboundMessage = {
127
+ msgType: "agent_response",
128
+ agentId: cfg.agentId,
129
+ sessionId,
130
+ taskId,
131
+ msgDetail: JSON.stringify(jsonRpcResponse),
132
+ };
133
+ log(`[A2A_COMMAND] 📤 Sending A2A command: taskId: ${taskId}`);
134
+ await wsManager.sendMessage(sessionId, outboundMessage);
135
+ log(`[SELF_EVOLUTION_GET] command sent successfully`);
136
+ }
137
+ catch (err) {
138
+ error("[SELF_EVOLUTION_GET] failed to handle event:", err);
139
+ }
140
+ }
@@ -0,0 +1,9 @@
1
+ export declare const SELF_EVOLUTION_KEYWORD_NUDGE_MESSAGE = "[\u7CFB\u7EDF\u6D88\u606F\uFF0C\u975E\u7528\u6237\u53D1\u8A00\uFF0C\u65E0\u9700\u4E3B\u52A8\u544A\u77E5\u7528\u6237] \u5F53\u524D\u7528\u6237\u8BF7\u6C42\u4E2D\u53EF\u80FD\u5305\u542B\u5E0C\u671B\u6C89\u6DC0\u7ECF\u9A8C\u3001\u957F\u671F\u8BB0\u5FC6\u3001\u907F\u514D\u91CD\u590D\u8E29\u5751\u3001\u7EA0\u9519\u7B49\u610F\u56FE\u3002\u5982\u679C\u4F60\u4ECE\u5F53\u524D\u4EFB\u52A1\u8FC7\u7A0B\u4E2D\u8BC6\u522B\u51FA\u53EF\u957F\u671F\u8BB0\u5FC6\u3001\u53EF\u590D\u7528\u7684\u5904\u7406\u89C4\u5219\u6216\u6392\u9519\u7ECF\u9A8C\u7B49\uFF0C\u53EF\u4EE5\u5728\u5B8C\u6210\u5F53\u524D\u4E3B\u8981\u4EFB\u52A1\u540E\uFF0C\u6B63\u5F0F\u56DE\u590D\u7528\u6237\u524D\uFF0C\u9605\u8BFBxiaoyi-self-evolution\u6280\u80FD\u4E86\u89E3\u81EA\u8FDB\u5316\u89C4\u5219\u3002\u6CE8\u610F\uFF0C\u4E0D\u8981\u6253\u65AD\u5F53\u524D\u4E3B\u4EFB\u52A1\uFF0C\u4EE5\u5B8C\u6210\u4EFB\u52A1\u4E3A\u6700\u9AD8\u4F18\u5148\u7EA7\u3002";
2
+ export declare const SELF_EVOLUTION_KEYWORD_PATTERNS: readonly [RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp];
3
+ export declare const SELF_EVOLUTION_MECHANISM_DISCUSSION_PATTERNS: readonly [RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp];
4
+ export declare function isSelfEvolutionMechanismDiscussion(text: string): boolean;
5
+ export declare function shouldNudgeForSelfEvolutionKeyword(text: string): boolean;
6
+ export declare function appendSelfEvolutionKeywordNudge(text: string): {
7
+ text: string;
8
+ appended: boolean;
9
+ };
@@ -0,0 +1,147 @@
1
+ export const SELF_EVOLUTION_KEYWORD_NUDGE_MESSAGE = "[系统消息,非用户发言,无需主动告知用户] 当前用户请求中可能包含希望沉淀经验、长期记忆、避免重复踩坑、纠错等意图。如果你从当前任务过程中识别出可长期记忆、可复用的处理规则或排错经验等,可以在完成当前主要任务后,正式回复用户前,阅读xiaoyi-self-evolution技能了解自进化规则。注意,不要打断当前主任务,以完成任务为最高优先级。";
2
+ export const SELF_EVOLUTION_KEYWORD_PATTERNS = [
3
+ /进化/u,
4
+ /沉淀/u,
5
+ /记住/u,
6
+ /固化/u,
7
+ /下次都/u,
8
+ /记下来/u,
9
+ /记一个/u,
10
+ /记一下/u,
11
+ /给我记住/u,
12
+ /给我记下来/u,
13
+ /把(?:这个|这条|这点|这个要求|这个偏好)(?:记住|记下来|记录下来)/u,
14
+ /以后都/u,
15
+ /以后必须/u,
16
+ /以后统一/u,
17
+ /后面都/u,
18
+ /后续都/u,
19
+ /以后默认/u,
20
+ /下次默认/u,
21
+ /之后默认/u,
22
+ /后续默认/u,
23
+ /长期记住/u,
24
+ /永久记住/u,
25
+ /永远记住/u,
26
+ /记住我的(?:偏好|习惯|要求|规范|规则)/u,
27
+ /记住我(?:喜欢|不喜欢|习惯|偏好|要求|希望|倾向于)/u,
28
+ /记住(?:我|用户)(?:以后|之后|后续)?(?:喜欢|不喜欢|习惯|偏好|要求|希望|倾向于)/u,
29
+ /(?:我的|用户的)(?:偏好|习惯|要求|规范|规则)(?:要)?(?:记住|记录|保留|沿用)/u,
30
+ /以后按(?:我的)?(?:偏好|习惯|要求|规范|规则)/u,
31
+ /(?:以后|下次|后续|之后)(?:都|统一|默认)?(?:按|照|遵循|沿用)(?:我的|用户的)(?:偏好|习惯|要求|规范|规则)/u,
32
+ /形成规范/u,
33
+ /固化下来/u,
34
+ /固定下来/u,
35
+ /固定成(?:规范|规则|流程|模板|标准)/u,
36
+ /列为(?:规范|规则|流程|标准|最佳实践)/u,
37
+ /作为(?:规范|规则|流程|标准|最佳实践)(?:保存|沉淀|记录|保留)/u,
38
+ /记成规则/u,
39
+ /写成规则/u,
40
+ /定成规则/u,
41
+ /定为(?:规则|规范|流程|标准|模板)/u,
42
+ /纳入经验/u,
43
+ /写入经验/u,
44
+ /写进(?:经验|规则|规范|流程|最佳实践)/u,
45
+ /记录到(?:经验|规则|规范|流程|最佳实践)/u,
46
+ /加入(?:经验|规则|规范|流程|最佳实践)/u,
47
+ /保存成(?:经验|规则|规范|流程|模板|最佳实践)/u,
48
+ /沉淀成(?:经验|规则|规范|流程)/u,
49
+ /总结成(?:经验|规则|规范|流程|步骤|模板|最佳实践)/u,
50
+ /归纳成(?:经验|规则|规范|流程|模板|最佳实践)/u,
51
+ /提炼成(?:经验|规则|规范|流程|模板|最佳实践)/u,
52
+ /以后都按这个来/u,
53
+ /下次都这样处理/u,
54
+ /以后统一这样/u,
55
+ /后面都这样/u,
56
+ /以后照这个来/u,
57
+ /下次照这个来/u,
58
+ /后续照这个来/u,
59
+ /之后照这个来/u,
60
+ /以后就这么办/u,
61
+ /下次就这么办/u,
62
+ /以后就这样办/u,
63
+ /下次就这样办/u,
64
+ /以后沿用/u,
65
+ /下次沿用/u,
66
+ /后续沿用/u,
67
+ /后续按这个(?:规范|流程|模板|方案)/u,
68
+ /(?:以后|下次|后续|之后)(?:就)?(?:按|照|沿用|复用)(?:这个|这种|上述|前面这个|刚才这个)(?:规范|流程|模板|方案|格式|标准|做法|套路|模式)/u,
69
+ /(?:以后|下次|后续|之后)(?:回复|回答|输出|生成|整理|总结)(?:时)?(?:都|就|统一|默认|必须|要)(?:按|照|遵循|沿用|使用)(?:这个|这种|上述|当前)?(?:格式|模板|风格|口径|结构|标准)/u,
70
+ /(?:这个|这种|上述|当前)(?:格式|模板|风格|口径|结构|标准)(?:以后|下次|后续|之后)(?:都|就|统一|默认|复用|沿用)/u,
71
+ /以后(?:遇到|碰到)这种情况/u,
72
+ /类似(?:问题|情况|场景)都这样/u,
73
+ /类似(?:问题|情况|场景)都这样处理/u,
74
+ /类似(?:问题|情况|场景)(?:以后|下次|后续|之后)(?:都|就|统一|默认)/u,
75
+ /(?:同类|类似|这种|这类)(?:需求|任务|问题|情况|场景)(?:以后|下次|后续|之后)(?:都|就|统一|默认|按这个|照这个)/u,
76
+ /(?:这类|这种|类似|同类)(?:需求|任务|问题|场景)(?:处理|解决|回答|回复)(?:方式|流程|方法)(?:记住|固定|沉淀|沿用)/u,
77
+ /避免(?:再次|以后|下次)/u,
78
+ /避免再(?:犯错|踩坑|出错)/u,
79
+ /防止以后再犯/u,
80
+ /防止(?:以后|下次|后续|之后)(?:再)?(?:犯错|出错|踩坑|漏掉|遗漏|忘记)/u,
81
+ /别再(?:出错|犯错|踩坑|漏掉|忘记)/u,
82
+ /不要再(?:出错|犯错|踩坑|漏掉|忘记)/u,
83
+ /别再(?:这样|这么)(?:做|处理|回答|回复|输出|写|改)/u,
84
+ /不要再(?:这样|这么)(?:做|处理|回答|回复|输出|写|改)/u,
85
+ /以后别(?:这样|这么)(?:做|处理|回答|回复|输出|写|改)/u,
86
+ /以后不要(?:这样|这么)(?:做|处理|回答|回复|输出|写|改)/u,
87
+ /下次别再/u,
88
+ /以后不要再/u,
89
+ /以后别再/u,
90
+ /(?:下次|以后|后续|之后)(?:不要|别|不能|不许|禁止)(?:再)?(?:这样|这么)?(?:出错|犯错|踩坑|漏掉|遗漏|忘记)/u,
91
+ /(?:下次|以后|后续|之后)(?:不要|别|不能|不许|禁止)(?:再)?(?:省略|跳过|漏掉|遗漏)(?:检查|确认|验证|测试|构建|说明|引用|来源|步骤)/u,
92
+ /(?:下次|以后|后续|之后)(?:记得|一定要|务必|必须)(?:先|先去|优先|默认)?(?:检查|确认|使用|采用|调用|遵循|按照|参考|避免|不要|别|记住|保留|验证|测试|构建|运行)/u,
93
+ /(?:下次|以后|后续|之后)(?:先|优先|默认)(?:检查|确认|查找|搜索|读取|运行|验证|测试|构建|调用|使用)/u,
94
+ /这个坑(?:要)?记住/u,
95
+ /这(?:个|次)?(?:坑|错误|问题|教训)(?:别忘|不要忘|不能忘|得记住)/u,
96
+ /(?:踩坑|翻车|犯错|出错)(?:点|原因|教训)?(?:记住|记下来|沉淀|复盘)/u,
97
+ /吸取这次(?:教训|经验)/u,
98
+ /把(?:这个|这次|上述|刚才的)?(?:坑|问题|错误|教训|经验|做法|流程|规范|要求|偏好|格式|模板|标准)(?:记住|记下来|沉淀下来|固化下来|保存下来|记录下来)/u,
99
+ /(?:以后|下次|后续|之后)(?:遇到|碰到)(?:同类|类似|这种|这类)(?:需求|任务|问题|情况|场景)(?:时)?(?:都|就|统一|默认|应该|要|必须)/u,
100
+ /(?:以后|下次|后续|之后)(?:做|处理|执行)(?:同类|类似|这种|这类)(?:需求|任务|问题|情况|场景)(?:时)?(?:都|就|统一|默认|应该|要|必须)/u,
101
+ /(?:以后|下次|后续|之后)(?:都|统一|默认|应该|要)(?:按这个|这样|这么)(?:来|做|处理|执行)/u,
102
+ /(?:以后|下次|后续|之后)(?:都|统一|默认|应该|要|必须)(?:先|优先|总是|固定)?(?:使用|采用|走|遵循|参考|套用|复用|沿用)(?:这个|这种|上述|当前)?(?:方法|流程|规范|规则|模板|标准|方案|做法|模式|套路)/u,
103
+ /(?:以后|下次|后续|之后)(?:遇到|碰到)(?:类似)?(?:问题|情况|场景)(?:时)?(?:都|就)(?:按这个|这样|这么)(?:来|做|处理|执行)/u,
104
+ /(?:别再|不要再|避免)(?:犯错|出错|踩坑|漏掉|遗漏|忘记)/u,
105
+ /(?:总结|归纳|提炼|沉淀|复盘)(?:一个|一下|下)?(?:这次|这个|上述|刚才的)?(?:经验|教训|问题|规则|规范|流程|模板|标准|最佳实践)?/u,
106
+ /(?:把)?这次(?:经验|教训|规则|做法|流程|格式|模板|标准)(?:记住|记下来|沉淀下来|固化下来|记录下来)/u,
107
+ /(?:形成|整理成|沉淀成|提炼成)(?:一套|一个|一份)?(?:规则|规范|流程|步骤|模板|标准|最佳实践|操作手册|检查清单|checklist)/u,
108
+ /(?:作为|当作|用作)(?:以后|下次|后续|之后)(?:的)?(?:参考|模板|范例|案例|标准|最佳实践|默认做法)/u,
109
+ /(?:这次|这个|上述|刚才的)(?:处理方式|做法|流程|方案|模板|格式|标准|口径|风格)(?:以后|下次|后续|之后)(?:复用|沿用|照着来|照这个来|继续用)/u,
110
+ /(?:以后|下次|后续|之后)(?:工具|skill|技能|命令|脚本|流程)(?:选择|调用|使用)(?:都|就|统一|默认|优先|必须|要)/u,
111
+ /(?:以后|下次|后续|之后)(?:优先|默认|固定)(?:用|使用|调用)(?:这个|这种|上述|当前)?(?:工具|skill|技能|命令|脚本|流程|方法)/u,
112
+ /(?:这个|这种|上述|当前)(?:工具|skill|技能|命令|脚本|流程|方法)(?:以后|下次|后续|之后)(?:优先|默认|固定|继续)(?:用|使用|调用)/u,
113
+ ];
114
+ export const SELF_EVOLUTION_MECHANISM_DISCUSSION_PATTERNS = [
115
+ /自进化(?:机制|功能|流程|原理|实现|设计|架构|链路|优化点|改进点)/u,
116
+ /(?:分析|讨论|了解|解释|看看|研究|检查|梳理|优化|改进|评估)(?:.{0,12})自进化/u,
117
+ /自进化(?:.{0,12})(?:怎么|如何|是否|能否|有没有|为什么)/u,
118
+ /自进化(?:是啥|是什么|的)/u,
119
+ /什么是自进化/u,
120
+ /啥是自进化/u,
121
+ /xiaoyi-self-evolution(?:-skill)?(?:.{0,12})(?:机制|功能|流程|原理|实现|设计|优化点|改进点)/iu,
122
+ ];
123
+ export function isSelfEvolutionMechanismDiscussion(text) {
124
+ return SELF_EVOLUTION_MECHANISM_DISCUSSION_PATTERNS.some((pattern) => pattern.test(text));
125
+ }
126
+ export function shouldNudgeForSelfEvolutionKeyword(text) {
127
+ if (!text) {
128
+ return false;
129
+ }
130
+ if (isSelfEvolutionMechanismDiscussion(text)) {
131
+ return false;
132
+ }
133
+ return SELF_EVOLUTION_KEYWORD_PATTERNS.some((pattern) => pattern.test(text));
134
+ }
135
+ export function appendSelfEvolutionKeywordNudge(text) {
136
+ const trimmed = text.trim();
137
+ if (!trimmed) {
138
+ return { text, appended: false };
139
+ }
140
+ if (trimmed.includes(SELF_EVOLUTION_KEYWORD_NUDGE_MESSAGE)) {
141
+ return { text, appended: false };
142
+ }
143
+ return {
144
+ text: `${trimmed}\n\n${SELF_EVOLUTION_KEYWORD_NUDGE_MESSAGE}`,
145
+ appended: true,
146
+ };
147
+ }
@@ -0,0 +1,3 @@
1
+ import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
2
+ export declare const SELF_EVOLUTION_TOOL_COUNT_NUDGE_MESSAGE = "[\u7CFB\u7EDF\u6D88\u606F] \u5F53\u524D\u4EFB\u52A1\u5DF2\u7ECF\u8C03\u7528\u4E86\u8F83\u591A\u6B21\u6570\u7684\u5DE5\u5177\u3002\u8BF7\u5728\u5B8C\u6210\u4EFB\u52A1\u540E\uFF0C\u5224\u65AD\u662F\u5426\u6709\u7A33\u5B9A\u3001\u901A\u7528\u3001\u53EF\u590D\u7528\u7684\u6D41\u7A0B\u3001\u6392\u9519\u7ECF\u9A8C\u6216\u8E29\u5751\u70B9\uFF0C\u5E76\u8003\u8651\u9605\u8BFB xiaoyi-self-evolution skill \u542F\u52A8\u81EA\u8FDB\u5316\u3002";
3
+ export declare function registerSelfEvolutionToolResultNudge(api: OpenClawPluginApi): void;
@@ -0,0 +1,96 @@
1
+ import { selfEvolutionManager } from "./utils/self-evolution-manager.js";
2
+ import { toolCallNudgeManager, TOOL_CALL_NUDGE_THRESHOLD } from "./utils/tool-call-nudge-manager.js";
3
+ export const SELF_EVOLUTION_TOOL_COUNT_NUDGE_MESSAGE = "[系统消息] 当前任务已经调用了较多次数的工具。请在完成任务后,判断是否有稳定、通用、可复用的流程、排错经验或踩坑点,并考虑阅读 xiaoyi-self-evolution skill 启动自进化。";
4
+ function shouldCountToolCall(toolName) {
5
+ if (toolName === "save_self_evolution_skill") {
6
+ return false;
7
+ }
8
+ if (toolName === "call_device_tool") {
9
+ return false;
10
+ }
11
+ if (toolName.endsWith("_tool_schema")) {
12
+ return false;
13
+ }
14
+ return true;
15
+ }
16
+ function appendNudgeToToolResultPayload(message, nudge) {
17
+ const msg = message;
18
+ const nudgeTrim = nudge.trim();
19
+ if (!nudgeTrim) {
20
+ return message;
21
+ }
22
+ const content = msg.content;
23
+ if (typeof content === "string") {
24
+ if (content.includes(nudgeTrim)) {
25
+ return message;
26
+ }
27
+ return { ...msg, content: `${content}\n\n${nudge}` };
28
+ }
29
+ if (!Array.isArray(content)) {
30
+ return {
31
+ ...msg,
32
+ content: [{ type: "text", text: nudge }],
33
+ };
34
+ }
35
+ const newContent = content.map((block) => block && typeof block === "object" ? { ...block } : block);
36
+ for (let i = newContent.length - 1; i >= 0; i--) {
37
+ const block = newContent[i];
38
+ if (!block || typeof block !== "object") {
39
+ continue;
40
+ }
41
+ const rec = block;
42
+ if (rec.type !== "text") {
43
+ continue;
44
+ }
45
+ const text = rec.text;
46
+ if (typeof text !== "string") {
47
+ continue;
48
+ }
49
+ if (text.includes(nudgeTrim)) {
50
+ return message;
51
+ }
52
+ newContent[i] = { ...rec, type: "text", text: `${text}\n\n${nudge}` };
53
+ return { ...msg, content: newContent };
54
+ }
55
+ newContent.push({ type: "text", text: nudge });
56
+ return { ...msg, content: newContent };
57
+ }
58
+ export function registerSelfEvolutionToolResultNudge(api) {
59
+ api.on("tool_result_persist", (event, ctx) => {
60
+ const message = event.message;
61
+ if (message.role !== "toolResult") {
62
+ return undefined;
63
+ }
64
+ if (event.isSynthetic) {
65
+ return undefined;
66
+ }
67
+ const sessionKey = ctx?.sessionKey;
68
+ if (!sessionKey || sessionKey.includes(":subagent:")) {
69
+ return undefined;
70
+ }
71
+ if (!selfEvolutionManager.isEnabledSync()) {
72
+ return undefined;
73
+ }
74
+ const toolName = (event.toolName ?? message.toolName ?? "").trim();
75
+ if (!toolName || !shouldCountToolCall(toolName)) {
76
+ return undefined;
77
+ }
78
+ let shouldNudge;
79
+ let count = 0;
80
+ try {
81
+ const result = toolCallNudgeManager.recordToolCall(sessionKey);
82
+ shouldNudge = result.shouldNudge;
83
+ count = result.count;
84
+ }
85
+ catch {
86
+ return undefined;
87
+ }
88
+ api.logger.debug?.(`[SELF_EVOLUTION] tool_result_persist: tool=${toolName}, count=${count}, threshold=${TOOL_CALL_NUDGE_THRESHOLD}, sessionKey=${sessionKey}, shouldNudge=${shouldNudge}`);
89
+ if (!shouldNudge) {
90
+ return undefined;
91
+ }
92
+ api.logger.info?.(`[SELF_EVOLUTION] Tool call threshold reached, appending nudge to tool result: tool=${toolName}, count=${count}, sessionKey=${sessionKey}`);
93
+ const next = appendNudgeToToolResultPayload(event.message, SELF_EVOLUTION_TOOL_COUNT_NUDGE_MESSAGE);
94
+ return { message: next };
95
+ });
96
+ }
@@ -1,20 +1,16 @@
1
1
  import { searchTools, formatToolsForContext, extractUserQuery } from "./tool-search.js";
2
- const TOOL_RETRIEVER_HEADER = `## 用户查询相关skill列表如下:
2
+ import { logger } from "../utils/logger.js";
3
+ const TOOL_RETRIEVER_HEADER = `[系统消息,非用户发言]
3
4
 
4
5
  `;
5
6
  const TOOL_RETRIEVER_FOOTER = `
6
- 以上是检索到的、与当前查询相关但用户尚未安装的 skill,优先推荐强相关的 skill(通用兜底工具如 web-search、xiaoyi-gui-agent 仅在无强相关skill时调用)。
7
- 对于强相关skill,你需要主动提醒用户可以考虑安装,但禁止直接给用户安装。用户明确希望安装后,使用find-skill执行安装。
8
- 若用户已有的skill已能很好地完成当前任务,则无需提醒安装功能相似的skill。
7
+ 以上是检索到的、与当前用户请求相关但用户尚未安装的skill,请按照TOOLS.md中find-skills中的[隐式推荐触发规则]来判断是否要给用户推荐。
9
8
  ---以下是用户原始请求---
10
9
  `;
11
10
  const PLUGIN_LOG_PREFIX = "[skill-retriever]";
12
- const SKIP_KEYWORDS = ["安装", "装一下", "下载", "查询", "查找", "install", "卸载", "删除", "重载"];
11
+ const SKIP_KEYWORDS = ["安装", "装一下", "下载", "查询", "查找", "install", "卸载", "删除", "重载", "定时任务", "重装", "进化"];
13
12
  const SKIP_PATTERNS = [
14
- "/new",
15
- "/reset",
16
- "session was started",
17
- "a new session was started",
13
+ "/new", "/reset", "/compact", "/stop", "/think", "/model", "/fast", "/verbose", "/config", "/debug", "/status", "/tasks", "/whoami", "/context", "/skill", "/commands", "/tools"
18
14
  ];
19
15
  function shouldSkipSearch(prompt) {
20
16
  const trimmedPrompt = prompt.trim();
@@ -68,10 +64,10 @@ export function createBeforePromptBuildHandler(config) {
68
64
  if (!searchResult || searchResult.tools.length === 0) {
69
65
  return undefined;
70
66
  }
71
- console.log(`${PLUGIN_LOG_PREFIX} [RESULT] Found ${searchResult.tools.length} skills, building context...`);
67
+ logger.log(`${PLUGIN_LOG_PREFIX} [RESULT] Found ${searchResult.tools.length} skills, building context...`);
72
68
  const toolsContext = formatToolsForContext(searchResult, config.includeUninstalledOnly);
73
69
  if (!toolsContext) {
74
- console.log(`${PLUGIN_LOG_PREFIX} [ERROR] Failed to format skills context`);
70
+ logger.log(`${PLUGIN_LOG_PREFIX} [ERROR] Failed to format skills context`);
75
71
  return undefined;
76
72
  }
77
73
  return {
@@ -80,7 +76,7 @@ export function createBeforePromptBuildHandler(config) {
80
76
  }
81
77
  catch (error) {
82
78
  const errorMessage = error instanceof Error ? error.message : String(error);
83
- console.error(`${PLUGIN_LOG_PREFIX} [ERROR] ${errorMessage}, original query: "${extractedQuery}"`);
79
+ logger.error(`${PLUGIN_LOG_PREFIX} [ERROR] ${errorMessage}, original query: "${extractedQuery}"`);
84
80
  return undefined;
85
81
  }
86
82
  };
@@ -1,6 +1,7 @@
1
1
  import * as fs from "fs";
2
2
  import * as path from "path";
3
3
  import * as os from "os";
4
+ import { logger } from "../utils/logger.js";
4
5
  const SKILL_ID = "celia_find_skills";
5
6
  const PLUGIN_LOG_PREFIX = "[skill-retriever]";
6
7
  export function extractUserQuery(fullPrompt) {
@@ -12,6 +13,9 @@ export function extractUserQuery(fullPrompt) {
12
13
  if (!afterLastNewline || afterLastNewline === "```") {
13
14
  return "";
14
15
  }
16
+ if (fullPrompt.toLowerCase().includes("cron")) {
17
+ return "";
18
+ }
15
19
  return afterLastNewline;
16
20
  }
17
21
  function expandPath(filePath) {
@@ -73,6 +77,7 @@ function formatSkillData(rawSkills, installedSkills) {
73
77
  skillDesc: skill.skillDesc,
74
78
  downloadPath: skill.packUrl,
75
79
  status: isInstalled ? "已安装" : "未安装",
80
+ rrfScore: skill.rrfScore,
76
81
  });
77
82
  }
78
83
  return formattedSkills;
@@ -85,7 +90,7 @@ export async function searchTools(options) {
85
90
  const apiKey = configApiKey ?? envConfig.PERSONAL_API_KEY;
86
91
  const uid = configUid ?? envConfig.PERSONAL_UID;
87
92
  if (!serviceUrl || !apiKey || !uid) {
88
- console.warn(`${PLUGIN_LOG_PREFIX} Missing required configuration. serviceUrl: "${serviceUrl}", apiKey: "${apiKey ? '(set)' : '(missing)'} ", uid: "${uid ? '(set)' : '(missing)'}"`);
93
+ logger.warn(`${PLUGIN_LOG_PREFIX} Missing required configuration. serviceUrl: "${serviceUrl}", apiKey: "${apiKey ? '(set)' : '(missing)'} ", uid: "${uid ? '(set)' : '(missing)'}"`);
89
94
  return null;
90
95
  }
91
96
  const traceId = crypto.randomUUID();
@@ -107,10 +112,10 @@ export async function searchTools(options) {
107
112
  signal: AbortSignal.timeout(timeoutMs),
108
113
  });
109
114
  if (!response.ok) {
110
- console.warn(`${PLUGIN_LOG_PREFIX} HTTP error: ${response.status} ${response.statusText}`);
115
+ logger.warn(`${PLUGIN_LOG_PREFIX} HTTP error: ${response.status} ${response.statusText}`);
111
116
  return null;
112
117
  }
113
- console.log(`${PLUGIN_LOG_PREFIX} Received response, status: ${response.status}`);
118
+ logger.log(`${PLUGIN_LOG_PREFIX} Received response, status: ${response.status}`);
114
119
  const responseData = await response.json();
115
120
  if (responseData.errorCode === "0" &&
116
121
  responseData.content &&
@@ -121,18 +126,27 @@ export async function searchTools(options) {
121
126
  const topTools = formattedData.slice(0, 2);
122
127
  const allInstalled = topTools.every((tool) => tool.status === "已安装");
123
128
  if (allInstalled) {
124
- console.log(`${PLUGIN_LOG_PREFIX} [DEBUG] All top 2 skills are installed, returning null`);
129
+ logger.log(`${PLUGIN_LOG_PREFIX} [DEBUG] All top 2 skills are installed, returning null`);
130
+ return null;
131
+ }
132
+ const hasInstalledWithHighScore = topTools.some((tool) => tool.status === "已安装" && (tool.rrfScore ?? 0) >= 0.016);
133
+ if (hasInstalledWithHighScore) {
134
+ logger.log(`${PLUGIN_LOG_PREFIX} [DEBUG] Top 2 has installed skill with rrfScore >= 0.016, returning null`);
135
+ return null;
136
+ }
137
+ let filteredTools = topTools.filter((tool) => tool.status === "未安装" && (tool.rrfScore ?? 0) >= 0.016);
138
+ logger.log(`${PLUGIN_LOG_PREFIX} [DEBUG] After filtering uninstalled with rrfScore >= 0.016: ${filteredTools.length}, details: ${filteredTools.map((t) => `${t.skillId}(rrfScore=${t.rrfScore})`).join(", ")}`);
139
+ if (filteredTools.length === 0) {
140
+ logger.log(`${PLUGIN_LOG_PREFIX} [DEBUG] No uninstalled skills with rrfScore >= 0.016, returning null`);
125
141
  return null;
126
142
  }
127
- let filteredTools = topTools.filter((tool) => tool.status === "未安装");
128
- console.log(`${PLUGIN_LOG_PREFIX} [DEBUG] After filtering uninstalled: ${filteredTools.length}, ids: ${filteredTools.map((t) => t.skillId).join(", ")}`);
129
143
  return {
130
144
  tools: filteredTools,
131
145
  query,
132
146
  timestamp: Date.now(),
133
147
  };
134
148
  }
135
- console.warn(`${PLUGIN_LOG_PREFIX} Invalid response format: ${JSON.stringify(responseData).slice(0, 200)}`);
149
+ logger.warn(`${PLUGIN_LOG_PREFIX} Invalid response format: ${JSON.stringify(responseData).slice(0, 200)}`);
136
150
  return null;
137
151
  }
138
152
  catch (error) {
@@ -140,7 +154,7 @@ export async function searchTools(options) {
140
154
  const errorMessage = error instanceof Error ? error.message : String(error);
141
155
  const errorCause = error instanceof Error && error.cause ? JSON.stringify(error.cause) : "N/A";
142
156
  const errorStack = error instanceof Error ? error.stack?.split("\n").slice(0, 3).join(" | ") : "N/A";
143
- console.warn(`${PLUGIN_LOG_PREFIX} [ERROR] Fetch failed - name: ${errorName}, message: ${errorMessage}, cause: ${errorCause}, stack: ${errorStack}`);
157
+ logger.warn(`${PLUGIN_LOG_PREFIX} [ERROR] Fetch failed - name: ${errorName}, message: ${errorMessage}, cause: ${errorCause}, stack: ${errorStack}`);
144
158
  return null;
145
159
  }
146
160
  }
@@ -13,6 +13,7 @@ export interface RawSkill {
13
13
  skillName: string;
14
14
  skillDesc: string;
15
15
  packUrl: string;
16
+ rrfScore?: number;
16
17
  }
17
18
  export interface FormattedSkill {
18
19
  skillId: string;
@@ -20,6 +21,7 @@ export interface FormattedSkill {
20
21
  skillDesc: string;
21
22
  downloadPath: string;
22
23
  status: "已安装" | "未安装";
24
+ rrfScore?: number;
23
25
  }
24
26
  export interface ToolSearchResult {
25
27
  tools: FormattedSkill[];
@@ -57,7 +57,7 @@ export async function tryInjectSteer(sessionKey, message) {
57
57
  },
58
58
  },
59
59
  };
60
- console.log(`[STEER] Injecting steer for sessionId=${sessionId}, taskId=${syntheticMessage.params.id}`);
60
+ logger.log(`[STEER] Injecting steer for sessionId=${sessionId}, taskId=${syntheticMessage.params.id}`);
61
61
  try {
62
62
  await handleXYMessage({
63
63
  cfg: cachedCfg,
@@ -48,6 +48,10 @@ export declare function hasActiveTask(sessionId: string): boolean;
48
48
  * 获取完整的binding信息(用于调试)
49
49
  */
50
50
  export declare function getTaskIdBinding(sessionId: string): TaskIdBinding | null;
51
+ /**
52
+ * 获取所有活跃的 task bindings(用于 gateway_stop 通知等场景)
53
+ */
54
+ export declare function getAllActiveTaskBindings(): TaskIdBinding[];
51
55
  /**
52
56
  * 强制清理(错误恢复用)
53
57
  */
@@ -5,8 +5,13 @@ import { logger } from "./utils/logger.js";
5
5
  * Session到活跃TaskId的映射
6
6
  * Key: sessionId (注意:这里用sessionId,不是sessionKey)
7
7
  * Value: TaskIdBinding
8
+ * Uses globalThis to ensure a single Map across all module copies.
8
9
  */
9
- const activeTaskIds = new Map();
10
+ const _g = globalThis;
11
+ if (!_g.__xyActiveTaskIds) {
12
+ _g.__xyActiveTaskIds = new Map();
13
+ }
14
+ const activeTaskIds = _g.__xyActiveTaskIds;
10
15
  /**
11
16
  * 注册或更新session的活跃taskId
12
17
  * 返回是否是更新(用于判断是否是第二条消息)
@@ -127,6 +132,12 @@ export function hasActiveTask(sessionId) {
127
132
  export function getTaskIdBinding(sessionId) {
128
133
  return activeTaskIds.get(sessionId) ?? null;
129
134
  }
135
+ /**
136
+ * 获取所有活跃的 task bindings(用于 gateway_stop 通知等场景)
137
+ */
138
+ export function getAllActiveTaskBindings() {
139
+ return Array.from(activeTaskIds.values());
140
+ }
130
141
  /**
131
142
  * 强制清理(错误恢复用)
132
143
  */
@@ -1,6 +1,7 @@
1
+ import type { SessionContext } from "./session-manager.js";
1
2
  /**
2
3
  * XY calendar event tool - creates a calendar event on user's device.
3
4
  * Requires title, dtStart (start time), and dtEnd (end time) parameters.
4
5
  * Time format must be: yyyy-mm-dd hh:mm:ss
5
6
  */
6
- export declare const calendarTool: any;
7
+ export declare function createCalendarTool(ctx: SessionContext): any;