@ynhcj/xiaoyi-channel 0.0.104-beta → 0.0.106-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,35 +8,50 @@ 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
- const SELF_EVOLUTION_NUDGE_MESSAGE = "[系统消息,非用户发言,不需要告知用户] 当前任务已经调用了较多工具。如果你识别到其中存在稳定、可复用的踩坑经验或排错模式,可以在完成当前主要任务后,正式回复用户前,阅读xiaoyi-self-evolution技能了解自进化规则。注意,不要打断当前主任务,已完成任务为最高优先级。";
12
- const SELF_EVOLUTION_KEYWORD_NUDGE_MESSAGE = "[系统消息,非用户发言,不需要告知用户] 当前用户请求中可能包含希望沉淀经验、避免重复踩坑的意图。如果你已经从当前问题中识别出稳定、可复用的处理规则或排错经验,可以在完成当前主要任务后,正式回复用户前,阅读xiaoyi-self-evolution技能了解自进化规则。注意,不要打断当前主任务,已完成任务为最高优先级。";
11
+ const SELF_EVOLUTION_NUDGE_MESSAGE = "[系统消息,非用户发言,无需主动告知用户] 当前任务已经调用了较多次数的工具。如果你识别到其中存在可复用的解决方法或踩坑经验等,可以在完成当前主要任务后,正式回复用户前,阅读xiaoyi-self-evolution技能了解自进化规则。注意,不要打断当前主任务,以完成任务为最高优先级。";
12
+ const SELF_EVOLUTION_KEYWORD_NUDGE_MESSAGE = "[系统消息,非用户发言,无需主动告知用户] 当前用户请求中可能包含用户长期偏好、行为纠正意图、经验沉淀需求。如果你已经从当前问题中识别出稳定、可复用的处理规则或排错经验,或者用户表达了明显的具备长期约束力的纠错与反馈,可以在完成当前主要任务后,正式回复用户前,阅读xiaoyi-self-evolution技能了解自进化规则。注意,不要打断当前主任务,以完成任务为最高优先级。";
13
13
  const SELF_EVOLUTION_KEYWORD_PATTERNS = [
14
14
  /进化/u,
15
+ /沉淀/u,
15
16
  /记住/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,
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,
34
32
  /以后都按这个来/u,
35
- /以后遇到这种情况/u,
36
- /类似情况(?:下)?不要再/u,
37
- /这种问题下次不能再出现/u,
38
- /永远不要再(?:犯|踩|漏)/u,
39
- /永远记住这次(?:教训|经验)/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,
40
55
  ];
41
56
  function shouldCountToolCall(toolName) {
42
57
  if (toolName === "save_self_evolution_skill") {
@@ -11,8 +11,8 @@ import { createHash } from "crypto";
11
11
  import { getCurrentSessionContext } from "./tools/session-manager.js";
12
12
  import { selfEvolutionManager } from "./utils/self-evolution-manager.js";
13
13
  // ── Retry config ──────────────────────────────────────────────
14
- const RETRY_DELAYS_MS = [10_000, 20_000, 40_000, 60_000];
15
- const MAX_RETRY_ATTEMPTS = 4;
14
+ const RETRY_DELAYS_MS = [10_000, 20_000, 40_000, 60_000, 60_000];
15
+ const MAX_RETRY_ATTEMPTS = 5;
16
16
  /** Check if an errorMessage indicates a retryable provider error by type. */
17
17
  function isRetryableProviderError(message) {
18
18
  if (!message)
@@ -4,6 +4,7 @@ import path from "node:path";
4
4
  import { getCurrentSessionContext } from "./session-manager.js";
5
5
  import { selfEvolutionManager } from "../utils/self-evolution-manager.js";
6
6
  const SELF_EVOLVED_SKILL_ROOT = "/home/sandbox/.openclaw/workspace/skills";
7
+ const ISO_DATE_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/u;
7
8
  function slugifyTitle(title) {
8
9
  return title
9
10
  .trim()
@@ -23,19 +24,141 @@ function normalizeStringArray(value) {
23
24
  }
24
25
  return [];
25
26
  }
26
- function containsSensitiveContent(text) {
27
- const lower = text.toLowerCase();
28
- const sensitivePatterns = [
29
- /api[_ -]?key/u,
30
- /access[_ -]?token/u,
31
- /bearer\s+[a-z0-9._-]+/iu,
32
- /password/u,
33
- /secret/u,
34
- /\/home\/sandbox\//u,
35
- /\/tmp\//u,
36
- /[a-z]:\\/iu,
27
+ function normalizeWhitespace(text) {
28
+ return text.replace(/\s+/gu, " ").trim();
29
+ }
30
+ function normalizeForFingerprint(text) {
31
+ return normalizeWhitespace(text)
32
+ .toLowerCase()
33
+ .replace(/[`"'()[\]{}:;,.!?]/gu, "")
34
+ .replace(/\s+/gu, " ")
35
+ .trim();
36
+ }
37
+ function normalizeForComparison(items) {
38
+ return items
39
+ .map((item) => normalizeForFingerprint(item))
40
+ .filter(Boolean)
41
+ .sort();
42
+ }
43
+ function sanitizeLine(text) {
44
+ let value = text;
45
+ let changed = false;
46
+ const replacements = [
47
+ [/(bearer\s+)[a-z0-9._=-]{12,}/giu, "$1[REDACTED_TOKEN]"],
48
+ [/((?:api[_ -]?key|access[_ -]?token|refresh[_ -]?token|password|secret)\s*[:=]\s*)([^\s,;]+)/giu, "$1[REDACTED_SECRET]"],
49
+ [/(-----BEGIN [A-Z ]*PRIVATE KEY-----)[\s\S]*?(-----END [A-Z ]*PRIVATE KEY-----)/gu, "$1\n[REDACTED_PRIVATE_KEY]\n$2"],
50
+ [/\b(?:[a-zA-Z]:\\(?:[^\\\r\n]+\\)*[^\\\r\n\s]+|\/(?:home|Users|tmp|var|private|etc)\/[^\s"'`<>]+)/gu, "[REDACTED_PATH]"],
51
+ [/\b(sk-[a-zA-Z0-9]{16,}|AKIA[0-9A-Z]{16}|AIza[0-9A-Za-z\-_]{20,})\b/gu, "[REDACTED_SECRET]"],
52
+ ];
53
+ for (const [pattern, replacement] of replacements) {
54
+ const next = value.replace(pattern, replacement);
55
+ if (next !== value) {
56
+ value = next;
57
+ changed = true;
58
+ }
59
+ }
60
+ return { value, changed };
61
+ }
62
+ function sanitizeStringArray(values) {
63
+ let changed = false;
64
+ const sanitized = values.map((value) => {
65
+ const result = sanitizeLine(value);
66
+ changed = changed || result.changed;
67
+ return result.value;
68
+ });
69
+ return { values: sanitized, changed };
70
+ }
71
+ function sanitizeSkillContent(params) {
72
+ const titleResult = sanitizeLine(params.title);
73
+ const summaryResult = sanitizeLine(params.summary);
74
+ const whenToUseResult = sanitizeLine(params.whenToUse);
75
+ const supplementResult = sanitizeLine(params.supplement);
76
+ const rulesResult = sanitizeStringArray(params.rules);
77
+ const examplesResult = sanitizeStringArray(params.examples);
78
+ const tagsResult = sanitizeStringArray(params.tags);
79
+ return {
80
+ title: titleResult.value,
81
+ summary: summaryResult.value,
82
+ whenToUse: whenToUseResult.value,
83
+ supplement: supplementResult.value,
84
+ rules: rulesResult.values,
85
+ examples: examplesResult.values,
86
+ tags: tagsResult.values,
87
+ changed: titleResult.changed ||
88
+ summaryResult.changed ||
89
+ whenToUseResult.changed ||
90
+ supplementResult.changed ||
91
+ rulesResult.changed ||
92
+ examplesResult.changed ||
93
+ tagsResult.changed,
94
+ };
95
+ }
96
+ function containsHighlySensitiveContent(text) {
97
+ const highRiskPatterns = [
98
+ /-----BEGIN [A-Z ]*PRIVATE KEY-----/u,
99
+ /bearer\s+[a-z0-9._=-]{12,}/iu,
100
+ /\b(?:sk-[a-zA-Z0-9]{16,}|AKIA[0-9A-Z]{16}|AIza[0-9A-Za-z\-_]{20,})\b/u,
101
+ /(?:api[_ -]?key|access[_ -]?token|refresh[_ -]?token|password|secret)\s*[:=]\s*[^\s,;]{8,}/iu,
37
102
  ];
38
- return sensitivePatterns.some((pattern) => pattern.test(lower));
103
+ return highRiskPatterns.some((pattern) => pattern.test(text));
104
+ }
105
+ function buildSkillFingerprint(params) {
106
+ const normalized = {
107
+ title: normalizeForFingerprint(params.title),
108
+ summary: normalizeForFingerprint(params.summary),
109
+ whenToUse: normalizeForFingerprint(params.whenToUse),
110
+ supplement: normalizeForFingerprint(params.supplement),
111
+ rules: normalizeForComparison(params.rules),
112
+ examples: normalizeForComparison(params.examples),
113
+ tags: normalizeForComparison(params.tags),
114
+ };
115
+ return createHash("sha256").update(JSON.stringify(normalized)).digest("hex");
116
+ }
117
+ function parseFrontmatterValue(content, key) {
118
+ const match = content.match(new RegExp(`^${key}:\\s*"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"`, "m"));
119
+ if (match) {
120
+ return match[1].replace(/\\"/g, '"').replace(/\\n/g, "\n");
121
+ }
122
+ return null;
123
+ }
124
+ function parseTimestampFromExistingSkill(content, key) {
125
+ const value = parseFrontmatterValue(content, key);
126
+ if (!value) {
127
+ return null;
128
+ }
129
+ return ISO_DATE_PATTERN.test(value) ? value : null;
130
+ }
131
+ async function findDuplicateSkillByFingerprint(targetFingerprint) {
132
+ try {
133
+ const entries = await fs.readdir(SELF_EVOLVED_SKILL_ROOT, { withFileTypes: true });
134
+ for (const entry of entries) {
135
+ if (!entry.isDirectory() || !entry.name.startsWith("evolving-")) {
136
+ continue;
137
+ }
138
+ const skillFilePath = path.join(SELF_EVOLVED_SKILL_ROOT, entry.name, "SKILL.md");
139
+ try {
140
+ const existingContent = await fs.readFile(skillFilePath, "utf-8");
141
+ const fingerprint = parseFrontmatterValue(existingContent, "fingerprint");
142
+ if (fingerprint && fingerprint === targetFingerprint) {
143
+ return {
144
+ path: skillFilePath,
145
+ slug: entry.name.replace(/^evolving-/u, ""),
146
+ };
147
+ }
148
+ }
149
+ catch (error) {
150
+ if (error?.code !== "ENOENT") {
151
+ throw error;
152
+ }
153
+ }
154
+ }
155
+ }
156
+ catch (error) {
157
+ if (error?.code !== "ENOENT") {
158
+ throw error;
159
+ }
160
+ }
161
+ return null;
39
162
  }
40
163
  function buildSkillMarkdown(params) {
41
164
  const description = `${params.summary}\n\nWhen to use: ${params.whenToUse}`
@@ -45,12 +168,17 @@ function buildSkillMarkdown(params) {
45
168
  "---",
46
169
  `name: "${params.title.replace(/"/g, '\\"')}"`,
47
170
  `description: "${description}"`,
48
- "---",
49
- "",
50
- `# ${params.title}`,
51
- "",
52
- "## Rules",
171
+ `fingerprint: "${params.fingerprint}"`,
172
+ `created_at: "${params.createdAt}"`,
53
173
  ];
174
+ if (params.updatedAt) {
175
+ lines.push(`updated_at: "${params.updatedAt}"`);
176
+ }
177
+ lines.push("---", "", `# ${params.title}`, "", "## Metadata", `- Created At: ${params.createdAt}`);
178
+ if (params.updatedAt) {
179
+ lines.push(`- Updated At: ${params.updatedAt}`);
180
+ }
181
+ lines.push("", "## Rules");
54
182
  for (const rule of params.rules) {
55
183
  lines.push(`- ${rule}`);
56
184
  }
@@ -60,6 +188,9 @@ function buildSkillMarkdown(params) {
60
188
  lines.push(`- ${example}`);
61
189
  }
62
190
  }
191
+ if (params.supplement) {
192
+ lines.push("", "## Supplement", params.supplement);
193
+ }
63
194
  if (params.tags.length > 0) {
64
195
  lines.push("", "## Tags", params.tags.map((tag) => `- ${tag}`).join("\n"));
65
196
  }
@@ -75,7 +206,7 @@ export const saveSelfEvolutionSkillTool = {
75
206
  properties: {
76
207
  title: {
77
208
  type: "string",
78
- description: "所学技能的简短、可复用标题。",
209
+ description: "所学技能的简短标题。**必须为英文,可用下划线或中划线分割。**",
79
210
  },
80
211
  summary: {
81
212
  type: "string",
@@ -83,7 +214,7 @@ export const saveSelfEvolutionSkillTool = {
83
214
  },
84
215
  when_to_use: {
85
216
  type: "string",
86
- description: "描述在未来任务中什么情况/哪些条件下使用此技能。",
217
+ description: "描述在未来任务中什么情况/哪些条件下使用此技能,描述尽量精准。",
87
218
  },
88
219
  rules: {
89
220
  type: "array",
@@ -93,13 +224,17 @@ export const saveSelfEvolutionSkillTool = {
93
224
  examples: {
94
225
  type: "array",
95
226
  items: { type: "string" },
96
- description: "陷阱示例以及正确模式示例,可选",
227
+ description: "陷阱示例或正确模式示例,可选",
97
228
  },
98
229
  tags: {
99
230
  type: "array",
100
231
  items: { type: "string" },
101
232
  description: "用于未来发现的标签,可选。",
102
233
  },
234
+ supplement: {
235
+ type: "string",
236
+ description: "补充说明。将其他想补充但不属于固定字段的内容放在这里。可选。",
237
+ },
103
238
  },
104
239
  required: ["title", "summary", "when_to_use", "rules"],
105
240
  },
@@ -114,32 +249,114 @@ export const saveSelfEvolutionSkillTool = {
114
249
  const title = typeof params.title === "string" ? params.title.trim() : "";
115
250
  const summary = typeof params.summary === "string" ? params.summary.trim() : "";
116
251
  const whenToUse = typeof params.when_to_use === "string" ? params.when_to_use.trim() : "";
117
- const rules = normalizeStringArray(params.rules);
118
- const examples = normalizeStringArray(params.examples);
119
- const tags = normalizeStringArray(params.tags);
120
- if (!title || !summary || !whenToUse || rules.length === 0) {
252
+ const supplement = typeof params.supplement === "string" ? params.supplement.trim() : "";
253
+ const rawRules = normalizeStringArray(params.rules);
254
+ const rawExamples = normalizeStringArray(params.examples);
255
+ const rawTags = normalizeStringArray(params.tags);
256
+ if (!title || !summary || !whenToUse || rawRules.length === 0) {
121
257
  throw new Error("Missing required fields. title, summary, when_to_use, and at least one rule are required.");
122
258
  }
123
259
  if (title.length < 6 || summary.length < 10 || whenToUse.length < 10) {
124
260
  throw new Error("Skill content is too short. Provide a reusable title, summary, and usage guidance.");
125
261
  }
126
- const combinedText = [title, summary, whenToUse, ...rules, ...examples, ...tags].join("\n");
127
- if (containsSensitiveContent(combinedText)) {
262
+ const sanitized = sanitizeSkillContent({
263
+ title,
264
+ summary,
265
+ whenToUse,
266
+ supplement,
267
+ rules: rawRules,
268
+ examples: rawExamples,
269
+ tags: rawTags,
270
+ });
271
+ const combinedText = [
272
+ sanitized.title,
273
+ sanitized.summary,
274
+ sanitized.whenToUse,
275
+ sanitized.supplement,
276
+ ...sanitized.rules,
277
+ ...sanitized.examples,
278
+ ...sanitized.tags,
279
+ ].join("\n");
280
+ if (containsHighlySensitiveContent(combinedText)) {
128
281
  throw new Error("Skill content appears to contain sensitive or environment-specific data and was rejected.");
129
282
  }
130
- const slug = slugifyTitle(title);
283
+ const slug = slugifyTitle(sanitized.title);
131
284
  if (!slug) {
132
285
  throw new Error("Title could not be normalized into a valid skill name.");
133
286
  }
134
287
  const skillDir = path.join(SELF_EVOLVED_SKILL_ROOT, `evolving-${slug}`);
135
288
  const skillFilePath = path.join(skillDir, "SKILL.md");
289
+ const fingerprint = buildSkillFingerprint({
290
+ title: sanitized.title,
291
+ summary: sanitized.summary,
292
+ whenToUse: sanitized.whenToUse,
293
+ supplement: sanitized.supplement,
294
+ rules: sanitized.rules,
295
+ examples: sanitized.examples,
296
+ tags: sanitized.tags,
297
+ });
298
+ const duplicateSkill = await findDuplicateSkillByFingerprint(fingerprint);
299
+ if (duplicateSkill && duplicateSkill.path !== skillFilePath) {
300
+ return {
301
+ content: [
302
+ {
303
+ type: "text",
304
+ text: JSON.stringify({
305
+ success: true,
306
+ deduped: true,
307
+ sanitized: sanitized.changed,
308
+ skillName: duplicateSkill.slug,
309
+ path: duplicateSkill.path,
310
+ message: "A semantically identical self-evolved skill already exists.",
311
+ }),
312
+ },
313
+ ],
314
+ };
315
+ }
316
+ const nowIso = new Date().toISOString();
317
+ let createdAt = nowIso;
318
+ let updatedAt;
319
+ try {
320
+ const existingContent = await fs.readFile(skillFilePath, "utf-8");
321
+ const existingFingerprint = parseFrontmatterValue(existingContent, "fingerprint");
322
+ const existingCreatedAt = parseTimestampFromExistingSkill(existingContent, "created_at");
323
+ createdAt = existingCreatedAt ?? nowIso;
324
+ if (existingFingerprint === fingerprint) {
325
+ return {
326
+ content: [
327
+ {
328
+ type: "text",
329
+ text: JSON.stringify({
330
+ success: true,
331
+ deduped: true,
332
+ sanitized: sanitized.changed,
333
+ skillName: slug,
334
+ path: skillFilePath,
335
+ createdAt,
336
+ message: "An identical self-evolved skill already exists.",
337
+ }),
338
+ },
339
+ ],
340
+ };
341
+ }
342
+ updatedAt = nowIso;
343
+ }
344
+ catch (error) {
345
+ if (error?.code !== "ENOENT") {
346
+ throw error;
347
+ }
348
+ }
136
349
  const nextContent = buildSkillMarkdown({
137
- title,
138
- summary,
139
- whenToUse,
140
- rules,
141
- examples,
142
- tags,
350
+ title: sanitized.title,
351
+ summary: sanitized.summary,
352
+ whenToUse: sanitized.whenToUse,
353
+ supplement: sanitized.supplement,
354
+ rules: sanitized.rules,
355
+ examples: sanitized.examples,
356
+ tags: sanitized.tags,
357
+ fingerprint,
358
+ createdAt,
359
+ updatedAt,
143
360
  });
144
361
  const nextHash = createHash("sha256").update(nextContent).digest("hex");
145
362
  await fs.mkdir(skillDir, { recursive: true });
@@ -154,15 +371,16 @@ export const saveSelfEvolutionSkillTool = {
154
371
  text: JSON.stringify({
155
372
  success: true,
156
373
  deduped: true,
374
+ sanitized: sanitized.changed,
157
375
  skillName: slug,
158
376
  path: skillFilePath,
377
+ createdAt,
159
378
  message: "An identical self-evolved skill already exists.",
160
379
  }),
161
380
  },
162
381
  ],
163
382
  };
164
383
  }
165
- throw new Error(`A different skill with the same title already exists: ${skillFilePath}`);
166
384
  }
167
385
  catch (error) {
168
386
  if (error?.code !== "ENOENT") {
@@ -177,10 +395,15 @@ export const saveSelfEvolutionSkillTool = {
177
395
  text: JSON.stringify({
178
396
  success: true,
179
397
  deduped: false,
398
+ sanitized: sanitized.changed,
180
399
  skillName: slug,
181
400
  path: skillFilePath,
182
401
  sessionId: sessionContext.sessionId,
183
- message: "Self-evolved skill saved successfully.",
402
+ createdAt,
403
+ updatedAt,
404
+ message: updatedAt
405
+ ? "Self-evolved skill updated successfully."
406
+ : "Self-evolved skill saved successfully.",
184
407
  }),
185
408
  },
186
409
  ],
@@ -11,6 +11,6 @@ declare class ToolCallNudgeManager {
11
11
  tryMarkKeywordNudge(sessionKey: string): boolean;
12
12
  clearSession(sessionKey: string): void;
13
13
  }
14
- export declare const TOOL_CALL_NUDGE_THRESHOLD = 5;
14
+ export declare const TOOL_CALL_NUDGE_THRESHOLD = 6;
15
15
  export declare const toolCallNudgeManager: ToolCallNudgeManager;
16
16
  export {};
@@ -1,4 +1,4 @@
1
- const DEFAULT_TOOL_CALL_NUDGE_THRESHOLD = 5;
1
+ const DEFAULT_TOOL_CALL_NUDGE_THRESHOLD = 6;
2
2
  class ToolCallNudgeManager {
3
3
  threshold;
4
4
  sessions = new Map();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ynhcj/xiaoyi-channel",
3
- "version": "0.0.104-beta",
3
+ "version": "0.0.106-beta",
4
4
  "description": "OpenClaw Xiaoyi Channel plugin - Xiaoyi A2A protocol integration",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -16,7 +16,7 @@
16
16
  "openclaw.plugin.json"
17
17
  ],
18
18
  "scripts": {
19
- "build": "tsc"
19
+ "build": "node ./node_modules/typescript/bin/tsc"
20
20
  },
21
21
  "keywords": [
22
22
  "openclaw",