@memtensor/memos-local-openclaw-plugin 1.0.4-beta.4 → 1.0.4-beta.6
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/README.md +22 -39
- package/dist/capture/index.d.ts.map +1 -1
- package/dist/capture/index.js +6 -0
- package/dist/capture/index.js.map +1 -1
- package/dist/config.d.ts +1 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +3 -72
- package/dist/config.js.map +1 -1
- package/dist/embedding/index.d.ts +2 -4
- package/dist/embedding/index.d.ts.map +1 -1
- package/dist/embedding/index.js +1 -17
- package/dist/embedding/index.js.map +1 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -4
- package/dist/index.js.map +1 -1
- package/dist/ingest/providers/index.d.ts +2 -10
- package/dist/ingest/providers/index.d.ts.map +1 -1
- package/dist/ingest/providers/index.js +43 -209
- package/dist/ingest/providers/index.js.map +1 -1
- package/dist/ingest/providers/openai.d.ts +0 -1
- package/dist/ingest/providers/openai.d.ts.map +1 -1
- package/dist/ingest/providers/openai.js +0 -1
- package/dist/ingest/providers/openai.js.map +1 -1
- package/dist/ingest/task-processor.js +1 -1
- package/dist/ingest/task-processor.js.map +1 -1
- package/dist/recall/engine.js +1 -1
- package/dist/recall/engine.js.map +1 -1
- package/dist/shared/llm-call.d.ts +2 -4
- package/dist/shared/llm-call.d.ts.map +1 -1
- package/dist/shared/llm-call.js +81 -20
- package/dist/shared/llm-call.js.map +1 -1
- package/dist/skill/evaluator.d.ts.map +1 -1
- package/dist/skill/evaluator.js +2 -2
- package/dist/skill/evaluator.js.map +1 -1
- package/dist/skill/evolver.d.ts +2 -0
- package/dist/skill/evolver.d.ts.map +1 -1
- package/dist/skill/evolver.js +3 -0
- package/dist/skill/evolver.js.map +1 -1
- package/dist/skill/generator.d.ts.map +1 -1
- package/dist/skill/generator.js +4 -4
- package/dist/skill/generator.js.map +1 -1
- package/dist/skill/upgrader.js +1 -1
- package/dist/skill/upgrader.js.map +1 -1
- package/dist/skill/validator.js +1 -1
- package/dist/skill/validator.js.map +1 -1
- package/dist/storage/ensure-binding.d.ts.map +1 -1
- package/dist/storage/ensure-binding.js +1 -3
- package/dist/storage/ensure-binding.js.map +1 -1
- package/dist/storage/sqlite.d.ts +0 -294
- package/dist/storage/sqlite.d.ts.map +1 -1
- package/dist/storage/sqlite.js +0 -821
- package/dist/storage/sqlite.js.map +1 -1
- package/dist/telemetry.d.ts +12 -5
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +135 -38
- package/dist/telemetry.js.map +1 -1
- package/dist/tools/index.d.ts +0 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +1 -3
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/memory-search.d.ts +2 -3
- package/dist/tools/memory-search.d.ts.map +1 -1
- package/dist/tools/memory-search.js +7 -48
- package/dist/tools/memory-search.js.map +1 -1
- package/dist/types.d.ts +2 -49
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/viewer/html.d.ts.map +1 -1
- package/dist/viewer/html.js +471 -2974
- package/dist/viewer/html.js.map +1 -1
- package/dist/viewer/server.d.ts +0 -45
- package/dist/viewer/server.d.ts.map +1 -1
- package/dist/viewer/server.js +18 -1155
- package/dist/viewer/server.js.map +1 -1
- package/index.ts +42 -430
- package/openclaw.plugin.json +1 -2
- package/package.json +3 -4
- package/scripts/postinstall.cjs +46 -283
- package/skill/memos-memory-guide/SKILL.md +2 -26
- package/src/capture/index.ts +8 -0
- package/src/config.ts +3 -94
- package/src/embedding/index.ts +1 -21
- package/src/index.ts +4 -7
- package/src/ingest/providers/index.ts +46 -246
- package/src/ingest/providers/openai.ts +1 -1
- package/src/ingest/task-processor.ts +1 -1
- package/src/recall/engine.ts +1 -1
- package/src/shared/llm-call.ts +95 -23
- package/src/skill/evaluator.ts +2 -3
- package/src/skill/evolver.ts +5 -0
- package/src/skill/generator.ts +4 -6
- package/src/skill/upgrader.ts +1 -1
- package/src/skill/validator.ts +1 -1
- package/src/storage/ensure-binding.ts +1 -3
- package/src/storage/sqlite.ts +0 -1085
- package/src/telemetry.ts +152 -39
- package/src/tools/index.ts +0 -1
- package/src/tools/memory-search.ts +8 -57
- package/src/types.ts +2 -44
- package/src/viewer/html.ts +471 -2974
- package/src/viewer/server.ts +21 -1070
- package/dist/client/connector.d.ts +0 -30
- package/dist/client/connector.d.ts.map +0 -1
- package/dist/client/connector.js +0 -219
- package/dist/client/connector.js.map +0 -1
- package/dist/client/hub.d.ts +0 -61
- package/dist/client/hub.d.ts.map +0 -1
- package/dist/client/hub.js +0 -148
- package/dist/client/hub.js.map +0 -1
- package/dist/client/skill-sync.d.ts +0 -29
- package/dist/client/skill-sync.d.ts.map +0 -1
- package/dist/client/skill-sync.js +0 -216
- package/dist/client/skill-sync.js.map +0 -1
- package/dist/hub/auth.d.ts +0 -19
- package/dist/hub/auth.d.ts.map +0 -1
- package/dist/hub/auth.js +0 -70
- package/dist/hub/auth.js.map +0 -1
- package/dist/hub/server.d.ts +0 -41
- package/dist/hub/server.d.ts.map +0 -1
- package/dist/hub/server.js +0 -747
- package/dist/hub/server.js.map +0 -1
- package/dist/hub/user-manager.d.ts +0 -29
- package/dist/hub/user-manager.d.ts.map +0 -1
- package/dist/hub/user-manager.js +0 -125
- package/dist/hub/user-manager.js.map +0 -1
- package/dist/openclaw-api.d.ts +0 -53
- package/dist/openclaw-api.d.ts.map +0 -1
- package/dist/openclaw-api.js +0 -189
- package/dist/openclaw-api.js.map +0 -1
- package/dist/sharing/types.contract.d.ts +0 -2
- package/dist/sharing/types.contract.d.ts.map +0 -1
- package/dist/sharing/types.contract.js +0 -3
- package/dist/sharing/types.contract.js.map +0 -1
- package/dist/sharing/types.d.ts +0 -80
- package/dist/sharing/types.d.ts.map +0 -1
- package/dist/sharing/types.js +0 -3
- package/dist/sharing/types.js.map +0 -1
- package/dist/tools/network-memory-detail.d.ts +0 -4
- package/dist/tools/network-memory-detail.d.ts.map +0 -1
- package/dist/tools/network-memory-detail.js +0 -34
- package/dist/tools/network-memory-detail.js.map +0 -1
- package/src/client/connector.ts +0 -218
- package/src/client/hub.ts +0 -189
- package/src/client/skill-sync.ts +0 -202
- package/src/hub/auth.ts +0 -78
- package/src/hub/server.ts +0 -740
- package/src/hub/user-manager.ts +0 -139
- package/src/openclaw-api.ts +0 -287
- package/src/sharing/types.contract.ts +0 -40
- package/src/sharing/types.ts +0 -102
- package/src/tools/network-memory-detail.ts +0 -34
|
@@ -1,13 +1,47 @@
|
|
|
1
1
|
import * as fs from "fs";
|
|
2
2
|
import * as path from "path";
|
|
3
|
-
import type { SummarizerConfig,
|
|
4
|
-
import { summarizeOpenAI, summarizeTaskOpenAI, generateTaskTitleOpenAI, judgeNewTopicOpenAI, filterRelevantOpenAI, judgeDedupOpenAI
|
|
3
|
+
import type { SummarizerConfig, SummaryProvider, Logger } from "../../types";
|
|
4
|
+
import { summarizeOpenAI, summarizeTaskOpenAI, generateTaskTitleOpenAI, judgeNewTopicOpenAI, filterRelevantOpenAI, judgeDedupOpenAI } from "./openai";
|
|
5
5
|
import type { FilterResult, DedupResult } from "./openai";
|
|
6
6
|
export type { FilterResult, DedupResult } from "./openai";
|
|
7
7
|
import { summarizeAnthropic, summarizeTaskAnthropic, generateTaskTitleAnthropic, judgeNewTopicAnthropic, filterRelevantAnthropic, judgeDedupAnthropic } from "./anthropic";
|
|
8
8
|
import { summarizeGemini, summarizeTaskGemini, generateTaskTitleGemini, judgeNewTopicGemini, filterRelevantGemini, judgeDedupGemini } from "./gemini";
|
|
9
9
|
import { summarizeBedrock, summarizeTaskBedrock, generateTaskTitleBedrock, judgeNewTopicBedrock, filterRelevantBedrock, judgeDedupBedrock } from "./bedrock";
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Detect provider type from provider key name or base URL.
|
|
13
|
+
*/
|
|
14
|
+
function detectProvider(
|
|
15
|
+
providerKey: string | undefined,
|
|
16
|
+
baseUrl: string,
|
|
17
|
+
): SummaryProvider {
|
|
18
|
+
const key = providerKey?.toLowerCase() ?? "";
|
|
19
|
+
const url = baseUrl.toLowerCase();
|
|
20
|
+
if (key.includes("anthropic") || url.includes("anthropic")) return "anthropic";
|
|
21
|
+
if (key.includes("gemini") || url.includes("generativelanguage.googleapis.com")) {
|
|
22
|
+
return "gemini";
|
|
23
|
+
}
|
|
24
|
+
if (key.includes("bedrock") || url.includes("bedrock")) return "bedrock";
|
|
25
|
+
return "openai_compatible";
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Return the correct endpoint for a given provider and base URL.
|
|
30
|
+
*/
|
|
31
|
+
function normalizeEndpointForProvider(
|
|
32
|
+
provider: SummaryProvider,
|
|
33
|
+
baseUrl: string,
|
|
34
|
+
): string {
|
|
35
|
+
const stripped = baseUrl.replace(/\/+$/, "");
|
|
36
|
+
if (provider === "anthropic") {
|
|
37
|
+
if (stripped.endsWith("/v1/messages")) return stripped;
|
|
38
|
+
return `${stripped}/v1/messages`;
|
|
39
|
+
}
|
|
40
|
+
if (stripped.endsWith("/chat/completions")) return stripped;
|
|
41
|
+
if (stripped.endsWith("/completions")) return stripped;
|
|
42
|
+
return `${stripped}/chat/completions`;
|
|
43
|
+
}
|
|
44
|
+
|
|
11
45
|
/**
|
|
12
46
|
* Build a SummarizerConfig from OpenClaw's native model configuration (openclaw.json).
|
|
13
47
|
* This serves as the final fallback when both strongCfg and plugin summarizer fail or are absent.
|
|
@@ -15,7 +49,8 @@ import { summarizeBedrock, summarizeTaskBedrock, generateTaskTitleBedrock, judge
|
|
|
15
49
|
function loadOpenClawFallbackConfig(log: Logger): SummarizerConfig | undefined {
|
|
16
50
|
try {
|
|
17
51
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
18
|
-
const
|
|
52
|
+
const ocHome = process.env.OPENCLAW_STATE_DIR || path.join(home, ".openclaw");
|
|
53
|
+
const cfgPath = path.join(ocHome, "openclaw.json");
|
|
19
54
|
if (!fs.existsSync(cfgPath)) return undefined;
|
|
20
55
|
|
|
21
56
|
const raw = JSON.parse(fs.readFileSync(cfgPath, "utf-8"));
|
|
@@ -36,13 +71,12 @@ function loadOpenClawFallbackConfig(log: Logger): SummarizerConfig | undefined {
|
|
|
36
71
|
const apiKey: string | undefined = providerCfg.apiKey;
|
|
37
72
|
if (!baseUrl || !apiKey) return undefined;
|
|
38
73
|
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
: baseUrl.replace(/\/+$/, "") + "/chat/completions";
|
|
74
|
+
const provider = detectProvider(providerKey, baseUrl);
|
|
75
|
+
const endpoint = normalizeEndpointForProvider(provider, baseUrl);
|
|
42
76
|
|
|
43
|
-
log.debug(`OpenClaw fallback model: ${modelId} via ${baseUrl}`);
|
|
77
|
+
log.debug(`OpenClaw fallback model: ${modelId} via ${baseUrl} (${provider})`);
|
|
44
78
|
return {
|
|
45
|
-
provider
|
|
79
|
+
provider,
|
|
46
80
|
endpoint,
|
|
47
81
|
apiKey,
|
|
48
82
|
model: modelId,
|
|
@@ -120,7 +154,6 @@ export class Summarizer {
|
|
|
120
154
|
constructor(
|
|
121
155
|
private cfg: SummarizerConfig | undefined,
|
|
122
156
|
private log: Logger,
|
|
123
|
-
private openclawAPI?: OpenClawAPI,
|
|
124
157
|
strongCfg?: SummarizerConfig,
|
|
125
158
|
) {
|
|
126
159
|
this.strongCfg = strongCfg;
|
|
@@ -130,20 +163,11 @@ export class Summarizer {
|
|
|
130
163
|
/**
|
|
131
164
|
* Ordered config chain: strongCfg → cfg → fallbackCfg (OpenClaw native model).
|
|
132
165
|
* Returns configs that are defined, in priority order.
|
|
133
|
-
* Openclaw configs without hostCompletion capability or without openclawAPI are excluded.
|
|
134
166
|
*/
|
|
135
167
|
private getConfigChain(): SummarizerConfig[] {
|
|
136
168
|
const chain: SummarizerConfig[] = [];
|
|
137
169
|
if (this.strongCfg) chain.push(this.strongCfg);
|
|
138
|
-
if (this.cfg)
|
|
139
|
-
if (this.cfg.provider === "openclaw") {
|
|
140
|
-
if (this.cfg.capabilities?.hostCompletion === true && this.openclawAPI) {
|
|
141
|
-
chain.push(this.cfg);
|
|
142
|
-
}
|
|
143
|
-
} else {
|
|
144
|
-
chain.push(this.cfg);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
170
|
+
if (this.cfg) chain.push(this.cfg);
|
|
147
171
|
if (this.fallbackCfg) chain.push(this.fallbackCfg);
|
|
148
172
|
return chain;
|
|
149
173
|
}
|
|
@@ -227,9 +251,7 @@ export class Summarizer {
|
|
|
227
251
|
return taskFallback(text);
|
|
228
252
|
}
|
|
229
253
|
|
|
230
|
-
const result = await this.tryChain("summarizeTask", (cfg) =>
|
|
231
|
-
cfg.provider === "openclaw" ? this.summarizeTaskOpenClaw(text) : callSummarizeTask(cfg, text, this.log),
|
|
232
|
-
);
|
|
254
|
+
const result = await this.tryChain("summarizeTask", (cfg) => callSummarizeTask(cfg, text, this.log));
|
|
233
255
|
return result ?? taskFallback(text);
|
|
234
256
|
}
|
|
235
257
|
|
|
@@ -268,11 +290,7 @@ export class Summarizer {
|
|
|
268
290
|
if (!this.cfg && !this.fallbackCfg) return null;
|
|
269
291
|
if (candidates.length === 0) return { relevant: [], sufficient: true };
|
|
270
292
|
|
|
271
|
-
const result = await this.tryChain("filterRelevant", (cfg) =>
|
|
272
|
-
cfg.provider === "openclaw"
|
|
273
|
-
? this.filterRelevantOpenClaw(query, candidates)
|
|
274
|
-
: callFilterRelevant(cfg, query, candidates, this.log),
|
|
275
|
-
);
|
|
293
|
+
const result = await this.tryChain("filterRelevant", (cfg) => callFilterRelevant(cfg, query, candidates, this.log));
|
|
276
294
|
return result ?? null;
|
|
277
295
|
}
|
|
278
296
|
|
|
@@ -283,144 +301,13 @@ export class Summarizer {
|
|
|
283
301
|
if (!this.cfg && !this.fallbackCfg) return null;
|
|
284
302
|
if (candidates.length === 0) return null;
|
|
285
303
|
|
|
286
|
-
const result = await this.tryChain("judgeDedup", (cfg) =>
|
|
287
|
-
cfg.provider === "openclaw"
|
|
288
|
-
? this.judgeDedupOpenClaw(newSummary, candidates)
|
|
289
|
-
: callJudgeDedup(cfg, newSummary, candidates, this.log),
|
|
290
|
-
);
|
|
304
|
+
const result = await this.tryChain("judgeDedup", (cfg) => callJudgeDedup(cfg, newSummary, candidates, this.log));
|
|
291
305
|
return result ?? { action: "NEW", reason: "all_models_failed" };
|
|
292
306
|
}
|
|
293
307
|
|
|
294
308
|
getStrongConfig(): SummarizerConfig | undefined {
|
|
295
309
|
return this.strongCfg;
|
|
296
310
|
}
|
|
297
|
-
|
|
298
|
-
// ─── OpenClaw API Implementation ───
|
|
299
|
-
|
|
300
|
-
private requireOpenClawAPI(): void {
|
|
301
|
-
if (!this.openclawAPI) {
|
|
302
|
-
throw new Error(
|
|
303
|
-
"OpenClaw API not available. Ensure sharing.capabilities.hostCompletion is enabled in config."
|
|
304
|
-
);
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
private async summarizeOpenClaw(text: string): Promise<string> {
|
|
309
|
-
this.requireOpenClawAPI();
|
|
310
|
-
const prompt = [
|
|
311
|
-
`Summarize the text in ONE concise sentence (max 120 characters). IMPORTANT: Use the SAME language as the input text — if the input is Chinese, write Chinese; if English, write English. Preserve exact names, commands, error codes. No bullet points, no preamble — output only the sentence.`,
|
|
312
|
-
``,
|
|
313
|
-
text.slice(0, 2000),
|
|
314
|
-
].join("\n");
|
|
315
|
-
|
|
316
|
-
const response = await this.openclawAPI!.complete({
|
|
317
|
-
prompt,
|
|
318
|
-
maxTokens: 100,
|
|
319
|
-
temperature: 0,
|
|
320
|
-
model: this.cfg?.model,
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
return response.text.trim().slice(0, 200);
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
private async summarizeTaskOpenClaw(text: string): Promise<string> {
|
|
327
|
-
this.requireOpenClawAPI();
|
|
328
|
-
const prompt = [
|
|
329
|
-
OPENCLAW_TASK_SUMMARY_PROMPT,
|
|
330
|
-
``,
|
|
331
|
-
text,
|
|
332
|
-
].join("\n");
|
|
333
|
-
|
|
334
|
-
const response = await this.openclawAPI!.complete({
|
|
335
|
-
prompt,
|
|
336
|
-
maxTokens: 4096,
|
|
337
|
-
temperature: 0.1,
|
|
338
|
-
model: this.cfg?.model,
|
|
339
|
-
});
|
|
340
|
-
|
|
341
|
-
return response.text.trim();
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
private async judgeNewTopicOpenClaw(currentContext: string, newMessage: string): Promise<boolean> {
|
|
345
|
-
this.requireOpenClawAPI();
|
|
346
|
-
const prompt = [
|
|
347
|
-
OPENCLAW_TOPIC_JUDGE_PROMPT,
|
|
348
|
-
``,
|
|
349
|
-
`CURRENT CONVERSATION SUMMARY:`,
|
|
350
|
-
currentContext,
|
|
351
|
-
``,
|
|
352
|
-
`NEW USER MESSAGE:`,
|
|
353
|
-
newMessage,
|
|
354
|
-
].join("\n");
|
|
355
|
-
|
|
356
|
-
const response = await this.openclawAPI!.complete({
|
|
357
|
-
prompt,
|
|
358
|
-
maxTokens: 10,
|
|
359
|
-
temperature: 0,
|
|
360
|
-
model: this.cfg?.model,
|
|
361
|
-
});
|
|
362
|
-
|
|
363
|
-
const answer = response.text.trim().toUpperCase();
|
|
364
|
-
this.log.debug(`Topic judge result: "${answer}"`);
|
|
365
|
-
return answer.startsWith("NEW");
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
private async filterRelevantOpenClaw(
|
|
369
|
-
query: string,
|
|
370
|
-
candidates: Array<{ index: number; role: string; content: string; time?: string }>,
|
|
371
|
-
): Promise<FilterResult> {
|
|
372
|
-
this.requireOpenClawAPI();
|
|
373
|
-
const candidateText = candidates
|
|
374
|
-
.map((c) => `${c.index}. [${c.role}] ${c.content}`)
|
|
375
|
-
.join("\n");
|
|
376
|
-
|
|
377
|
-
const prompt = [
|
|
378
|
-
OPENCLAW_FILTER_RELEVANT_PROMPT,
|
|
379
|
-
``,
|
|
380
|
-
`QUERY: ${query}`,
|
|
381
|
-
``,
|
|
382
|
-
`CANDIDATES:`,
|
|
383
|
-
candidateText,
|
|
384
|
-
].join("\n");
|
|
385
|
-
|
|
386
|
-
const response = await this.openclawAPI!.complete({
|
|
387
|
-
prompt,
|
|
388
|
-
maxTokens: 200,
|
|
389
|
-
temperature: 0,
|
|
390
|
-
model: this.cfg?.model,
|
|
391
|
-
});
|
|
392
|
-
|
|
393
|
-
return parseFilterResult(response.text.trim(), this.log);
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
private async judgeDedupOpenClaw(
|
|
397
|
-
newSummary: string,
|
|
398
|
-
candidates: Array<{ index: number; summary: string; chunkId: string }>,
|
|
399
|
-
): Promise<DedupResult> {
|
|
400
|
-
this.requireOpenClawAPI();
|
|
401
|
-
const candidateText = candidates
|
|
402
|
-
.map((c) => `${c.index}. ${c.summary}`)
|
|
403
|
-
.join("\n");
|
|
404
|
-
|
|
405
|
-
const prompt = [
|
|
406
|
-
OPENCLAW_DEDUP_JUDGE_PROMPT,
|
|
407
|
-
``,
|
|
408
|
-
`NEW MEMORY:`,
|
|
409
|
-
newSummary,
|
|
410
|
-
``,
|
|
411
|
-
`EXISTING MEMORIES:`,
|
|
412
|
-
candidateText,
|
|
413
|
-
].join("\n");
|
|
414
|
-
|
|
415
|
-
const response = await this.openclawAPI!.complete({
|
|
416
|
-
prompt,
|
|
417
|
-
maxTokens: 300,
|
|
418
|
-
temperature: 0,
|
|
419
|
-
model: this.cfg?.model,
|
|
420
|
-
});
|
|
421
|
-
|
|
422
|
-
return parseDedupResult(response.text.trim(), this.log);
|
|
423
|
-
}
|
|
424
311
|
}
|
|
425
312
|
|
|
426
313
|
// ─── Dispatch helpers ───
|
|
@@ -596,90 +483,3 @@ function wordCount(text: string): number {
|
|
|
596
483
|
return count;
|
|
597
484
|
}
|
|
598
485
|
|
|
599
|
-
// ─── OpenClaw Prompt Templates ───
|
|
600
|
-
|
|
601
|
-
const OPENCLAW_TASK_SUMMARY_PROMPT = `You create a DETAILED task summary from a multi-turn conversation. This summary will be the ONLY record of this conversation, so it must preserve ALL important information.
|
|
602
|
-
|
|
603
|
-
CRITICAL LANGUAGE RULE: You MUST write in the SAME language as the user's messages. Chinese input → Chinese output. English input → English output. NEVER mix languages.
|
|
604
|
-
|
|
605
|
-
Output EXACTLY this structure:
|
|
606
|
-
|
|
607
|
-
📌 Title
|
|
608
|
-
A short, descriptive title (10-30 characters). Like a chat group name.
|
|
609
|
-
|
|
610
|
-
🎯 Goal
|
|
611
|
-
One sentence: what the user wanted to accomplish.
|
|
612
|
-
|
|
613
|
-
📋 Key Steps
|
|
614
|
-
- Describe each meaningful step in detail
|
|
615
|
-
- Include the ACTUAL content produced: code snippets, commands, config blocks, formulas, key paragraphs
|
|
616
|
-
- For code: include the function signature and core logic (up to ~30 lines per block), use fenced code blocks
|
|
617
|
-
- For configs: include the actual config values and structure
|
|
618
|
-
- For lists/instructions: include the actual items, not just "provided a list"
|
|
619
|
-
- Merge only truly trivial back-and-forth (like "ok" / "sure")
|
|
620
|
-
- Do NOT over-summarize: "provided a function" is BAD; show the actual function
|
|
621
|
-
|
|
622
|
-
✅ Result
|
|
623
|
-
What was the final outcome? Include the final version of any code/config/content produced.
|
|
624
|
-
|
|
625
|
-
💡 Key Details
|
|
626
|
-
- Decisions made, trade-offs discussed, caveats noted, alternative approaches mentioned
|
|
627
|
-
- Specific values: numbers, versions, thresholds, URLs, file paths, model names
|
|
628
|
-
- Omit this section only if there truly are no noteworthy details
|
|
629
|
-
|
|
630
|
-
RULES:
|
|
631
|
-
- This summary is a KNOWLEDGE BASE ENTRY, not a brief note. Be thorough.
|
|
632
|
-
- PRESERVE verbatim: code, commands, URLs, file paths, error messages, config values, version numbers, names, amounts
|
|
633
|
-
- DISCARD only: greetings, filler, the assistant explaining what it will do before doing it
|
|
634
|
-
- Replace secrets (API keys, tokens, passwords) with [REDACTED]
|
|
635
|
-
- Target length: 30-50% of the original conversation length. Longer conversations need longer summaries.
|
|
636
|
-
- Output summary only, no preamble.`;
|
|
637
|
-
|
|
638
|
-
const OPENCLAW_TOPIC_JUDGE_PROMPT = `You are a conversation topic boundary detector. Given a summary of the CURRENT conversation and a NEW user message, determine if the new message starts a DIFFERENT topic/task.
|
|
639
|
-
|
|
640
|
-
Answer ONLY "NEW" or "SAME".
|
|
641
|
-
|
|
642
|
-
Rules:
|
|
643
|
-
- "NEW" = the new message is about a completely different subject, project, or task
|
|
644
|
-
- "SAME" = the new message continues, follows up on, or is closely related to the current topic
|
|
645
|
-
- Follow-up questions, clarifications, refinements, bug fixes, or next steps on the same task = SAME
|
|
646
|
-
- Greetings or meta-questions like "你好" or "谢谢" without new substance = SAME
|
|
647
|
-
- A clearly unrelated request (e.g., current topic is deployment, new message asks about cooking) = NEW
|
|
648
|
-
|
|
649
|
-
Output exactly one word: NEW or SAME`;
|
|
650
|
-
|
|
651
|
-
const OPENCLAW_FILTER_RELEVANT_PROMPT = `You are a memory relevance judge. Given a user's QUERY and a list of CANDIDATE memory summaries, do two things:
|
|
652
|
-
|
|
653
|
-
1. Select ALL candidates that could be useful for answering the query. When in doubt, INCLUDE the candidate.
|
|
654
|
-
- For questions about lists, history, or "what/where/who" across multiple items, include ALL matching items.
|
|
655
|
-
- For factual lookups, a single direct answer is enough.
|
|
656
|
-
2. Judge whether the selected memories are SUFFICIENT to fully answer the query WITHOUT fetching additional context.
|
|
657
|
-
|
|
658
|
-
IMPORTANT for "sufficient" judgment:
|
|
659
|
-
- sufficient=true ONLY when the memories contain a concrete ANSWER, fact, decision, or actionable information that directly addresses the query.
|
|
660
|
-
- sufficient=false when the memories only repeat the question, show related topics but lack the specific detail, or contain partial information.
|
|
661
|
-
|
|
662
|
-
Output a JSON object with exactly two fields:
|
|
663
|
-
{"relevant":[1,3,5],"sufficient":true}
|
|
664
|
-
|
|
665
|
-
- "relevant": array of candidate numbers that are useful. Empty array [] if none are relevant.
|
|
666
|
-
- "sufficient": true ONLY if the memories contain a direct answer; false otherwise.
|
|
667
|
-
|
|
668
|
-
Output ONLY the JSON object, nothing else.`;
|
|
669
|
-
|
|
670
|
-
const OPENCLAW_DEDUP_JUDGE_PROMPT = `You are a memory deduplication system. Given a NEW memory summary and several EXISTING memory summaries, determine the relationship.
|
|
671
|
-
|
|
672
|
-
For each EXISTING memory, the NEW memory is either:
|
|
673
|
-
- "DUPLICATE": NEW is fully covered by an EXISTING memory — no new information at all
|
|
674
|
-
- "UPDATE": NEW contains information that supplements or updates an EXISTING memory (new data, status change, additional detail)
|
|
675
|
-
- "NEW": NEW is a different topic/event despite surface similarity
|
|
676
|
-
|
|
677
|
-
Pick the BEST match among all candidates. If none match well, choose "NEW".
|
|
678
|
-
|
|
679
|
-
Output a single JSON object:
|
|
680
|
-
- If DUPLICATE: {"action":"DUPLICATE","targetIndex":2,"reason":"..."}
|
|
681
|
-
- If UPDATE: {"action":"UPDATE","targetIndex":3,"reason":"...","mergedSummary":"a combined summary preserving all info from both old and new, same language as input"}
|
|
682
|
-
- If NEW: {"action":"NEW","reason":"..."}
|
|
683
|
-
|
|
684
|
-
CRITICAL: mergedSummary must use the SAME language as the input. Output ONLY the JSON object.`;
|
|
685
|
-
|
|
@@ -316,7 +316,7 @@ export async function filterRelevantOpenAI(
|
|
|
316
316
|
return parseFilterResult(raw, log);
|
|
317
317
|
}
|
|
318
318
|
|
|
319
|
-
|
|
319
|
+
function parseFilterResult(raw: string, log: Logger): FilterResult {
|
|
320
320
|
try {
|
|
321
321
|
const match = raw.match(/\{[\s\S]*\}/);
|
|
322
322
|
if (match) {
|
|
@@ -39,7 +39,7 @@ export class TaskProcessor {
|
|
|
39
39
|
private ctx: PluginContext,
|
|
40
40
|
) {
|
|
41
41
|
const strongCfg = ctx.config.skillEvolution?.summarizer;
|
|
42
|
-
this.summarizer = new Summarizer(ctx.config.summarizer, ctx.log,
|
|
42
|
+
this.summarizer = new Summarizer(ctx.config.summarizer, ctx.log, strongCfg);
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
onTaskCompleted(cb: (task: Task) => void): void {
|
package/src/recall/engine.ts
CHANGED
|
@@ -246,7 +246,7 @@ export class RecallEngine {
|
|
|
246
246
|
if (candidateSkills.length === 0) return [];
|
|
247
247
|
|
|
248
248
|
// LLM relevance judgment
|
|
249
|
-
const summarizer = new Summarizer(this.ctx.config.summarizer, this.ctx.log
|
|
249
|
+
const summarizer = new Summarizer(this.ctx.config.summarizer, this.ctx.log);
|
|
250
250
|
const relevantIndices = await this.judgeSkillRelevance(summarizer, query, candidateSkills);
|
|
251
251
|
|
|
252
252
|
return relevantIndices.map((idx) => {
|
package/src/shared/llm-call.ts
CHANGED
|
@@ -1,6 +1,35 @@
|
|
|
1
1
|
import * as fs from "fs";
|
|
2
2
|
import * as path from "path";
|
|
3
|
-
import type { SummarizerConfig, Logger, PluginContext
|
|
3
|
+
import type { SummarizerConfig, SummaryProvider, Logger, PluginContext } from "../types";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Detect provider type from provider key name or base URL.
|
|
7
|
+
*/
|
|
8
|
+
function detectProvider(providerKey: string | undefined, baseUrl: string): SummaryProvider {
|
|
9
|
+
const key = providerKey?.toLowerCase() ?? "";
|
|
10
|
+
const url = baseUrl.toLowerCase();
|
|
11
|
+
if (key.includes("anthropic") || url.includes("anthropic")) return "anthropic";
|
|
12
|
+
if (key.includes("gemini") || url.includes("generativelanguage.googleapis.com")) {
|
|
13
|
+
return "gemini";
|
|
14
|
+
}
|
|
15
|
+
if (key.includes("bedrock") || url.includes("bedrock")) return "bedrock";
|
|
16
|
+
return "openai_compatible";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Return the correct default endpoint for a given provider.
|
|
21
|
+
*/
|
|
22
|
+
function defaultEndpointForProvider(provider: SummaryProvider, baseUrl: string): string {
|
|
23
|
+
const stripped = baseUrl.replace(/\/+$/, "");
|
|
24
|
+
if (provider === "anthropic") {
|
|
25
|
+
if (stripped.endsWith("/v1/messages")) return stripped;
|
|
26
|
+
return `${stripped}/v1/messages`;
|
|
27
|
+
}
|
|
28
|
+
// OpenAI-compatible providers
|
|
29
|
+
if (stripped.endsWith("/chat/completions")) return stripped;
|
|
30
|
+
if (stripped.endsWith("/completions")) return stripped;
|
|
31
|
+
return `${stripped}/chat/completions`;
|
|
32
|
+
}
|
|
4
33
|
|
|
5
34
|
/**
|
|
6
35
|
* Build a SummarizerConfig from OpenClaw's native model configuration (openclaw.json).
|
|
@@ -30,13 +59,12 @@ export function loadOpenClawFallbackConfig(log: Logger): SummarizerConfig | unde
|
|
|
30
59
|
const apiKey: string | undefined = providerCfg.apiKey;
|
|
31
60
|
if (!baseUrl || !apiKey) return undefined;
|
|
32
61
|
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
: baseUrl.replace(/\/+$/, "") + "/chat/completions";
|
|
62
|
+
const provider = detectProvider(providerKey, baseUrl);
|
|
63
|
+
const endpoint = defaultEndpointForProvider(provider, baseUrl);
|
|
36
64
|
|
|
37
|
-
log.debug(`OpenClaw fallback model: ${modelId} via ${baseUrl}`);
|
|
65
|
+
log.debug(`OpenClaw fallback model: ${modelId} via ${baseUrl} (${provider})`);
|
|
38
66
|
return {
|
|
39
|
-
provider
|
|
67
|
+
provider,
|
|
40
68
|
endpoint,
|
|
41
69
|
apiKey,
|
|
42
70
|
model: modelId,
|
|
@@ -66,42 +94,86 @@ export interface LLMCallOptions {
|
|
|
66
94
|
maxTokens?: number;
|
|
67
95
|
temperature?: number;
|
|
68
96
|
timeoutMs?: number;
|
|
69
|
-
/** Pass ctx.openclawAPI so callLLMOnce can handle provider === "openclaw" */
|
|
70
|
-
openclawAPI?: OpenClawAPI;
|
|
71
97
|
}
|
|
72
98
|
|
|
73
|
-
function
|
|
99
|
+
function normalizeOpenAIEndpoint(url: string): string {
|
|
74
100
|
const stripped = url.replace(/\/+$/, "");
|
|
75
101
|
if (stripped.endsWith("/chat/completions")) return stripped;
|
|
76
102
|
if (stripped.endsWith("/completions")) return stripped;
|
|
77
103
|
return `${stripped}/chat/completions`;
|
|
78
104
|
}
|
|
79
105
|
|
|
106
|
+
function normalizeAnthropicEndpoint(url: string): string {
|
|
107
|
+
const stripped = url.replace(/\/+$/, "");
|
|
108
|
+
if (stripped.endsWith("/v1/messages")) return stripped;
|
|
109
|
+
if (stripped.endsWith("/messages")) return stripped;
|
|
110
|
+
return `${stripped}/v1/messages`;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function isAnthropicProvider(cfg: SummarizerConfig): boolean {
|
|
114
|
+
return cfg.provider === "anthropic";
|
|
115
|
+
}
|
|
116
|
+
|
|
80
117
|
/**
|
|
81
118
|
* Make a single LLM call with the given config. Throws on failure.
|
|
82
|
-
*
|
|
119
|
+
* Dispatches to Anthropic or OpenAI-compatible format based on provider.
|
|
83
120
|
*/
|
|
84
121
|
export async function callLLMOnce(
|
|
85
122
|
cfg: SummarizerConfig,
|
|
86
123
|
prompt: string,
|
|
87
124
|
opts: LLMCallOptions = {},
|
|
88
125
|
): Promise<string> {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
126
|
+
if (isAnthropicProvider(cfg)) {
|
|
127
|
+
return callLLMOnceAnthropic(cfg, prompt, opts);
|
|
128
|
+
}
|
|
129
|
+
return callLLMOnceOpenAI(cfg, prompt, opts);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async function callLLMOnceAnthropic(
|
|
133
|
+
cfg: SummarizerConfig,
|
|
134
|
+
prompt: string,
|
|
135
|
+
opts: LLMCallOptions = {},
|
|
136
|
+
): Promise<string> {
|
|
137
|
+
const endpoint = normalizeAnthropicEndpoint(
|
|
138
|
+
cfg.endpoint ?? "https://api.anthropic.com/v1/messages",
|
|
139
|
+
);
|
|
140
|
+
const model = cfg.model ?? "claude-3-haiku-20240307";
|
|
141
|
+
const headers: Record<string, string> = {
|
|
142
|
+
"Content-Type": "application/json",
|
|
143
|
+
"x-api-key": cfg.apiKey ?? "",
|
|
144
|
+
"anthropic-version": "2023-06-01",
|
|
145
|
+
...cfg.headers,
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
const resp = await fetch(endpoint, {
|
|
149
|
+
method: "POST",
|
|
150
|
+
headers,
|
|
151
|
+
body: JSON.stringify({
|
|
152
|
+
model,
|
|
98
153
|
temperature: opts.temperature ?? 0.1,
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
154
|
+
max_tokens: opts.maxTokens ?? 1024,
|
|
155
|
+
messages: [{ role: "user", content: prompt }],
|
|
156
|
+
}),
|
|
157
|
+
signal: AbortSignal.timeout(opts.timeoutMs ?? 30_000),
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
if (!resp.ok) {
|
|
161
|
+
const body = await resp.text();
|
|
162
|
+
throw new Error(`LLM call failed (${resp.status}): ${body}`);
|
|
102
163
|
}
|
|
103
164
|
|
|
104
|
-
const
|
|
165
|
+
const json = (await resp.json()) as { content: Array<{ type: string; text: string }> };
|
|
166
|
+
return json.content.find((c) => c.type === "text")?.text?.trim() ?? "";
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
async function callLLMOnceOpenAI(
|
|
170
|
+
cfg: SummarizerConfig,
|
|
171
|
+
prompt: string,
|
|
172
|
+
opts: LLMCallOptions = {},
|
|
173
|
+
): Promise<string> {
|
|
174
|
+
const endpoint = normalizeOpenAIEndpoint(
|
|
175
|
+
cfg.endpoint ?? "https://api.openai.com/v1/chat/completions",
|
|
176
|
+
);
|
|
105
177
|
const model = cfg.model ?? "gpt-4o-mini";
|
|
106
178
|
const headers: Record<string, string> = {
|
|
107
179
|
"Content-Type": "application/json",
|
package/src/skill/evaluator.ts
CHANGED
|
@@ -145,7 +145,7 @@ export class SkillEvaluator {
|
|
|
145
145
|
.replace("{SUMMARY}", task.summary.slice(0, 3000));
|
|
146
146
|
|
|
147
147
|
try {
|
|
148
|
-
const raw = await callLLMWithFallback(chain, prompt, this.ctx.log, "SkillEvaluator.create"
|
|
148
|
+
const raw = await callLLMWithFallback(chain, prompt, this.ctx.log, "SkillEvaluator.create");
|
|
149
149
|
return this.parseJSON<CreateEvalResult>(raw, {
|
|
150
150
|
shouldGenerate: false, reason: "parse failed", suggestedName: "", suggestedTags: [], confidence: 0,
|
|
151
151
|
});
|
|
@@ -169,7 +169,7 @@ export class SkillEvaluator {
|
|
|
169
169
|
.replace("{SUMMARY}", task.summary.slice(0, 3000));
|
|
170
170
|
|
|
171
171
|
try {
|
|
172
|
-
const raw = await callLLMWithFallback(chain, prompt, this.ctx.log, "SkillEvaluator.upgrade"
|
|
172
|
+
const raw = await callLLMWithFallback(chain, prompt, this.ctx.log, "SkillEvaluator.upgrade");
|
|
173
173
|
return this.parseJSON<UpgradeEvalResult>(raw, {
|
|
174
174
|
shouldUpgrade: false, upgradeType: "refine", dimensions: [], reason: "parse failed", mergeStrategy: "", confidence: 0,
|
|
175
175
|
});
|
|
@@ -179,7 +179,6 @@ export class SkillEvaluator {
|
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
-
|
|
183
182
|
private parseJSON<T>(raw: string, fallback: T): T {
|
|
184
183
|
const jsonMatch = raw.match(/\{[\s\S]*\}/);
|
|
185
184
|
if (!jsonMatch) return fallback;
|
package/src/skill/evolver.ts
CHANGED
|
@@ -12,6 +12,8 @@ import { SkillUpgrader } from "./upgrader";
|
|
|
12
12
|
import { SkillInstaller } from "./installer";
|
|
13
13
|
import { buildSkillConfigChain, callLLMWithFallback } from "../shared/llm-call";
|
|
14
14
|
|
|
15
|
+
export type SkillEvolvedCallback = (skillName: string, upgradeType: "created" | "upgraded") => void;
|
|
16
|
+
|
|
15
17
|
export class SkillEvolver {
|
|
16
18
|
private evaluator: SkillEvaluator;
|
|
17
19
|
private generator: SkillGenerator;
|
|
@@ -19,6 +21,7 @@ export class SkillEvolver {
|
|
|
19
21
|
private installer: SkillInstaller;
|
|
20
22
|
private processing = false;
|
|
21
23
|
private queue: Task[] = [];
|
|
24
|
+
onSkillEvolved: SkillEvolvedCallback | null = null;
|
|
22
25
|
|
|
23
26
|
constructor(
|
|
24
27
|
private store: SqliteStore,
|
|
@@ -279,6 +282,7 @@ Use selectedIndex 0 when none is highly relevant.`;
|
|
|
279
282
|
if (upgraded) {
|
|
280
283
|
this.store.linkTaskSkill(task.id, freshSkill.id, "evolved_from", freshSkill.version + 1);
|
|
281
284
|
this.installer.syncIfInstalled(freshSkill.name);
|
|
285
|
+
this.onSkillEvolved?.(freshSkill.name, "upgraded");
|
|
282
286
|
} else {
|
|
283
287
|
this.store.linkTaskSkill(task.id, freshSkill.id, "applied_to", freshSkill.version);
|
|
284
288
|
}
|
|
@@ -307,6 +311,7 @@ Use selectedIndex 0 when none is highly relevant.`;
|
|
|
307
311
|
this.markChunksWithSkill(chunks, skill.id);
|
|
308
312
|
this.store.linkTaskSkill(task.id, skill.id, "generated_from", 1);
|
|
309
313
|
this.store.setTaskSkillMeta(task.id, { skillStatus: "generated", skillReason: evalResult.reason });
|
|
314
|
+
this.onSkillEvolved?.(skill.name, "created");
|
|
310
315
|
|
|
311
316
|
const autoInstall = this.ctx.config.skillEvolution?.autoInstall ?? DEFAULTS.skillAutoInstall;
|
|
312
317
|
if (autoInstall && skill.status === "active") {
|
package/src/skill/generator.ts
CHANGED
|
@@ -356,7 +356,7 @@ export class SkillGenerator {
|
|
|
356
356
|
.replace("{CONVERSATION}", conversationText.slice(0, 12000))
|
|
357
357
|
+ langInstruction;
|
|
358
358
|
|
|
359
|
-
const raw = await callLLMWithFallback(chain, prompt, this.ctx.log, "SkillGenerator.step1", { maxTokens: 6000, temperature: 0.2, timeoutMs: 120_000
|
|
359
|
+
const raw = await callLLMWithFallback(chain, prompt, this.ctx.log, "SkillGenerator.step1", { maxTokens: 6000, temperature: 0.2, timeoutMs: 120_000 });
|
|
360
360
|
|
|
361
361
|
const trimmed = raw.trim();
|
|
362
362
|
if (trimmed.startsWith("---")) return trimmed;
|
|
@@ -379,7 +379,7 @@ export class SkillGenerator {
|
|
|
379
379
|
.replace("{CONVERSATION}", conversationText.slice(0, 6000));
|
|
380
380
|
|
|
381
381
|
try {
|
|
382
|
-
const raw = await callLLMWithFallback(chain, prompt, this.ctx.log, "SkillGenerator.scripts", { maxTokens: 3000, temperature: 0.1, timeoutMs: 120_000
|
|
382
|
+
const raw = await callLLMWithFallback(chain, prompt, this.ctx.log, "SkillGenerator.scripts", { maxTokens: 3000, temperature: 0.1, timeoutMs: 120_000 });
|
|
383
383
|
return this.parseJSONArray<{ filename: string; content: string }>(raw);
|
|
384
384
|
} catch (err) {
|
|
385
385
|
this.ctx.log.warn(`SkillGenerator: script extraction failed: ${err}`);
|
|
@@ -401,7 +401,7 @@ export class SkillGenerator {
|
|
|
401
401
|
.replace("{CONVERSATION}", conversationText.slice(0, 6000));
|
|
402
402
|
|
|
403
403
|
try {
|
|
404
|
-
const raw = await callLLMWithFallback(chain, prompt, this.ctx.log, "SkillGenerator.refs", { maxTokens: 3000, temperature: 0.1, timeoutMs: 120_000
|
|
404
|
+
const raw = await callLLMWithFallback(chain, prompt, this.ctx.log, "SkillGenerator.refs", { maxTokens: 3000, temperature: 0.1, timeoutMs: 120_000 });
|
|
405
405
|
return this.parseJSONArray<{ filename: string; content: string }>(raw);
|
|
406
406
|
} catch (err) {
|
|
407
407
|
this.ctx.log.warn(`SkillGenerator: reference extraction failed: ${err}`);
|
|
@@ -423,7 +423,7 @@ export class SkillGenerator {
|
|
|
423
423
|
+ `\n\n⚠️ LANGUAGE: Write test prompts and expectations in ${lang}, matching the skill's language.\n`;
|
|
424
424
|
|
|
425
425
|
try {
|
|
426
|
-
const raw = await callLLMWithFallback(chain, prompt, this.ctx.log, "SkillGenerator.evals", { maxTokens: 2000, temperature: 0.3, timeoutMs: 120_000
|
|
426
|
+
const raw = await callLLMWithFallback(chain, prompt, this.ctx.log, "SkillGenerator.evals", { maxTokens: 2000, temperature: 0.3, timeoutMs: 120_000 });
|
|
427
427
|
return this.parseJSONArray(raw);
|
|
428
428
|
} catch (err) {
|
|
429
429
|
this.ctx.log.warn(`SkillGenerator: eval generation failed: ${err}`);
|
|
@@ -467,7 +467,6 @@ export class SkillGenerator {
|
|
|
467
467
|
return { hitCount, results };
|
|
468
468
|
}
|
|
469
469
|
|
|
470
|
-
|
|
471
470
|
// ─── Helpers ───
|
|
472
471
|
|
|
473
472
|
private parseJSONArray<T>(raw: string): T[] {
|
|
@@ -500,5 +499,4 @@ export class SkillGenerator {
|
|
|
500
499
|
return "";
|
|
501
500
|
}
|
|
502
501
|
|
|
503
|
-
|
|
504
502
|
}
|
package/src/skill/upgrader.ts
CHANGED
|
@@ -190,7 +190,7 @@ export class SkillUpgrader {
|
|
|
190
190
|
.replace("{TASK_ID}", task.id)
|
|
191
191
|
+ langInstruction;
|
|
192
192
|
|
|
193
|
-
const raw = await callLLMWithFallback(chain, prompt, this.ctx.log, "SkillUpgrader.upgrade", { maxTokens: 6000, temperature: 0.2, timeoutMs: 90_000
|
|
193
|
+
const raw = await callLLMWithFallback(chain, prompt, this.ctx.log, "SkillUpgrader.upgrade", { maxTokens: 6000, temperature: 0.2, timeoutMs: 90_000 });
|
|
194
194
|
|
|
195
195
|
const changelogSep = raw.indexOf("---CHANGELOG---");
|
|
196
196
|
if (changelogSep !== -1) {
|