agenr 2.1.0 → 3.0.0
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/CHANGELOG.md +34 -0
- package/dist/adapters/openclaw/index.d.ts +1 -1
- package/dist/adapters/openclaw/index.js +294 -2049
- package/dist/adapters/skeln/index.d.ts +1951 -0
- package/dist/adapters/skeln/index.js +3899 -0
- package/dist/{chunk-IMQIJPIP.js → chunk-575MUIW5.js} +206 -53
- package/dist/{chunk-7TDALVPY.js → chunk-ELR2HSVC.js} +4920 -4659
- package/dist/chunk-GELCEVFA.js +14 -0
- package/dist/{chunk-DGV6D6Q3.js → chunk-LAXNNWHM.js} +3395 -4506
- package/dist/chunk-MYZ2CWY6.js +2738 -0
- package/dist/{chunk-MJIB6J5S.js → chunk-P5SB75FK.js} +6 -4
- package/dist/chunk-TBFAARM5.js +1196 -0
- package/dist/claim-slot-policy-CdrW_1l4.d.ts +13 -0
- package/dist/cli.js +19 -17
- package/dist/core/recall/index.d.ts +5 -14
- package/dist/core/recall/index.js +1 -1
- package/dist/internal-eval-server.js +5 -4
- package/dist/internal-recall-eval-server.js +5 -4
- package/dist/{ports-Nj5nd2Ri.d.ts → ports-CpzWESmZ.d.ts} +208 -2
- package/package.json +7 -5
- /package/dist/{chunk-6T5RXGIR.js → chunk-5LADPJ4C.js} +0 -0
|
@@ -1,60 +1,80 @@
|
|
|
1
1
|
import {
|
|
2
2
|
OpenClawTranscriptParser,
|
|
3
|
-
createOpenClawRepository,
|
|
4
3
|
deriveOpenClawSessionIdFromFilePath,
|
|
5
|
-
ingestEpisodeTranscript,
|
|
6
4
|
openClawTranscriptParser,
|
|
7
5
|
parseTuiSessionKey,
|
|
8
|
-
readOpenClawSessionsStore
|
|
9
|
-
|
|
10
|
-
} from "../../chunk-DGV6D6Q3.js";
|
|
6
|
+
readOpenClawSessionsStore
|
|
7
|
+
} from "../../chunk-TBFAARM5.js";
|
|
11
8
|
import {
|
|
12
9
|
BEFORE_TURN_DEBUG_ARTIFACT_DEFAULT_TOP_K,
|
|
13
10
|
BEFORE_TURN_DEBUG_ARTIFACT_MAX_TOP_K,
|
|
14
11
|
RECALL_DEBUG_ARTIFACT_DEFAULT_TOP_K,
|
|
15
|
-
RECALL_DEBUG_ARTIFACT_MAX_TOP_K
|
|
12
|
+
RECALL_DEBUG_ARTIFACT_MAX_TOP_K
|
|
13
|
+
} from "../../chunk-GELCEVFA.js";
|
|
14
|
+
import {
|
|
15
|
+
EPISODE_SUMMARY_TIMEOUT_MS,
|
|
16
|
+
RECALL_TOOL_PARAMETERS,
|
|
17
|
+
STORE_TOOL_PARAMETERS,
|
|
18
|
+
UPDATE_TOOL_PARAMETERS,
|
|
19
|
+
asRecord,
|
|
20
|
+
buildClaimExtractionRuntime,
|
|
21
|
+
buildRecallToolServices,
|
|
22
|
+
composeHostPluginServices,
|
|
23
|
+
createDeadlineAwareEpisodeSummaryLlm,
|
|
24
|
+
createSessionStartTracker,
|
|
25
|
+
embedEpisodeSummaryWithinBudget,
|
|
26
|
+
extractRecentTurnsFromMessages,
|
|
27
|
+
formatAgenrSessionStartRecall,
|
|
28
|
+
formatErrorMessage,
|
|
29
|
+
formatTargetSelector,
|
|
30
|
+
formatUnifiedRecallResults,
|
|
31
|
+
normalizeOptionalBoolean,
|
|
32
|
+
normalizeOptionalPositiveInteger,
|
|
33
|
+
normalizePluginInjectionMemoryPolicyConfig,
|
|
34
|
+
normalizePromptText,
|
|
35
|
+
parseRecallToolParams,
|
|
36
|
+
parseStoreToolParams,
|
|
37
|
+
parseUpdateToolParams,
|
|
38
|
+
readBooleanParam,
|
|
39
|
+
resolveBeforeTurnPolicy,
|
|
40
|
+
resolveSessionIdentityKey,
|
|
41
|
+
resolveSessionStartPolicy,
|
|
42
|
+
resolveTargetEntry,
|
|
43
|
+
runRecallMemoryTool,
|
|
44
|
+
runSessionStart,
|
|
45
|
+
runStoreMemoryTool,
|
|
46
|
+
runUpdateMemoryTool,
|
|
47
|
+
sanitizeUpdateToolParams,
|
|
48
|
+
writeBoundedSingleTranscriptEpisode
|
|
49
|
+
} from "../../chunk-MYZ2CWY6.js";
|
|
50
|
+
import {
|
|
51
|
+
createSingleTranscriptDiscoveryPort
|
|
52
|
+
} from "../../chunk-LAXNNWHM.js";
|
|
53
|
+
import {
|
|
54
|
+
buildRecallToolDetails,
|
|
16
55
|
containsAgenrMemoryContext,
|
|
17
56
|
formatAgenrBeforeTurnRecall,
|
|
57
|
+
formatRecallToolSummary,
|
|
58
|
+
formatUnifiedRecallLogSummary,
|
|
18
59
|
runBeforeTurn,
|
|
60
|
+
sanitizeRecallToolParams,
|
|
61
|
+
sanitizeStoreToolParams,
|
|
19
62
|
stripAgenrMemoryContext,
|
|
20
|
-
|
|
21
|
-
} from "../../chunk-
|
|
63
|
+
truncate
|
|
64
|
+
} from "../../chunk-575MUIW5.js";
|
|
22
65
|
import {
|
|
23
|
-
EMBEDDING_DIMENSIONS
|
|
24
|
-
|
|
25
|
-
ENTRY_TYPES,
|
|
26
|
-
EXPIRY_LEVELS,
|
|
27
|
-
attachCrossEncoderPort,
|
|
28
|
-
buildActiveEntryClause,
|
|
29
|
-
createDatabase,
|
|
30
|
-
createEmbeddingClient,
|
|
31
|
-
createOpenAICrossEncoder,
|
|
32
|
-
createRecallAdapter,
|
|
33
|
-
mapEntryRow,
|
|
34
|
-
normalizeManualClaimKeyUpdate,
|
|
35
|
-
projectClaimCentricRecallEntry,
|
|
36
|
-
readConfig,
|
|
37
|
-
resolveClaimExtractionConfig,
|
|
38
|
-
resolveConfigPath,
|
|
39
|
-
resolveCrossEncoderApiKey,
|
|
40
|
-
resolveDbPath,
|
|
41
|
-
resolveEmbeddingApiKey,
|
|
42
|
-
resolveEmbeddingModel,
|
|
43
|
-
resolveModel,
|
|
44
|
-
runUnifiedRecall,
|
|
45
|
-
validateTemporalValidityRange
|
|
46
|
-
} from "../../chunk-7TDALVPY.js";
|
|
66
|
+
EMBEDDING_DIMENSIONS
|
|
67
|
+
} from "../../chunk-ELR2HSVC.js";
|
|
47
68
|
import {
|
|
48
|
-
recall,
|
|
49
69
|
resolveClaimSlotPolicy
|
|
50
|
-
} from "../../chunk-
|
|
70
|
+
} from "../../chunk-5LADPJ4C.js";
|
|
51
71
|
|
|
52
72
|
// src/adapters/openclaw/index.ts
|
|
53
73
|
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
|
|
54
74
|
|
|
55
75
|
// src/adapters/openclaw/tools/recall.ts
|
|
76
|
+
import { textResult as textResult2 } from "openclaw/plugin-sdk/agent-runtime";
|
|
56
77
|
import { randomUUID } from "crypto";
|
|
57
|
-
import { readNumberParam, readStringArrayParam, readStringParam as readStringParam2, textResult } from "openclaw/plugin-sdk/agent-runtime";
|
|
58
78
|
|
|
59
79
|
// src/adapters/openclaw/debug/sink.ts
|
|
60
80
|
import { appendFile, mkdir } from "fs/promises";
|
|
@@ -278,96 +298,31 @@ function buildTopCandidates(result, reasonsByEntryId, topK) {
|
|
|
278
298
|
}
|
|
279
299
|
|
|
280
300
|
// src/adapters/openclaw/tools/shared.ts
|
|
281
|
-
import { failedTextResult, readStringParam } from "openclaw/plugin-sdk/agent-runtime";
|
|
282
|
-
var
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
const selectorDescription = options.allowLast ? "id, subject, or last" : "id or subject";
|
|
294
|
-
if (selectorCount !== 1) {
|
|
295
|
-
throw new Error(`Provide exactly one target selector: ${selectorDescription}.`);
|
|
296
|
-
}
|
|
297
|
-
if (last) {
|
|
298
|
-
const entry2 = await services.memory.findMostRecentEntry();
|
|
299
|
-
if (!entry2) {
|
|
300
|
-
throw new Error("No agenr entries exist yet.");
|
|
301
|
-
}
|
|
302
|
-
return entry2;
|
|
303
|
-
}
|
|
304
|
-
if (id) {
|
|
305
|
-
const entry2 = await services.entries.getEntry(id) ?? (await services.memory.getEntryTrace(id))?.entry;
|
|
306
|
-
if (!entry2) {
|
|
307
|
-
throw new Error(`No agenr entry found for id ${id}.`);
|
|
308
|
-
}
|
|
309
|
-
return entry2;
|
|
310
|
-
}
|
|
311
|
-
const entry = await services.memory.findEntryBySubject(subject ?? "");
|
|
312
|
-
if (!entry) {
|
|
313
|
-
throw new Error(`No agenr entry found for subject "${subject}".`);
|
|
314
|
-
}
|
|
315
|
-
return entry;
|
|
316
|
-
}
|
|
317
|
-
function readBooleanParam(params, key) {
|
|
318
|
-
const value = params[key];
|
|
319
|
-
if (value === void 0) {
|
|
320
|
-
return void 0;
|
|
321
|
-
}
|
|
322
|
-
if (typeof value === "boolean") {
|
|
323
|
-
return value;
|
|
324
|
-
}
|
|
325
|
-
throw new Error(`${key} must be a boolean.`);
|
|
326
|
-
}
|
|
327
|
-
function parseEntryTypes(values) {
|
|
328
|
-
return normalizeStringArray(values).map((value) => parseEntryType(value));
|
|
329
|
-
}
|
|
330
|
-
function parseRecallMode(value) {
|
|
331
|
-
if (value === void 0) {
|
|
332
|
-
return void 0;
|
|
333
|
-
}
|
|
334
|
-
if (value === "auto" || value === "entries" || value === "episodes" || value === "procedures") {
|
|
335
|
-
return value;
|
|
336
|
-
}
|
|
337
|
-
throw new Error(`Unsupported recall mode "${value}".`);
|
|
338
|
-
}
|
|
339
|
-
function parseEntryType(value) {
|
|
340
|
-
if (ENTRY_TYPES.includes(value)) {
|
|
341
|
-
return value;
|
|
342
|
-
}
|
|
343
|
-
throw new Error(`Unsupported entry type "${value}".`);
|
|
344
|
-
}
|
|
345
|
-
function parseExpiry(value) {
|
|
346
|
-
if (value === void 0) {
|
|
347
|
-
return void 0;
|
|
348
|
-
}
|
|
349
|
-
if (EXPIRY_LEVELS.includes(value)) {
|
|
350
|
-
return value;
|
|
351
|
-
}
|
|
352
|
-
throw new Error(`Unsupported expiry "${value}".`);
|
|
353
|
-
}
|
|
354
|
-
function normalizeStringArray(values) {
|
|
355
|
-
if (!values) {
|
|
356
|
-
return [];
|
|
301
|
+
import { failedTextResult, readNumberParam, readStringArrayParam, readStringParam, textResult } from "openclaw/plugin-sdk/agent-runtime";
|
|
302
|
+
var OPENCLAW_PARAM_READER = {
|
|
303
|
+
readString: readStringParam,
|
|
304
|
+
readNumber: readNumberParam,
|
|
305
|
+
readStringArray: readStringArrayParam
|
|
306
|
+
};
|
|
307
|
+
function toOpenClawToolResult(outcome) {
|
|
308
|
+
if (outcome.failed) {
|
|
309
|
+
return failedTextResult(outcome.text, {
|
|
310
|
+
...outcome.details,
|
|
311
|
+
status: "failed"
|
|
312
|
+
});
|
|
357
313
|
}
|
|
358
|
-
return
|
|
359
|
-
}
|
|
360
|
-
function buildSessionSourceFile(ctx) {
|
|
361
|
-
const target = ctx.sessionKey ?? ctx.sessionId ?? ctx.agentId ?? "unknown";
|
|
362
|
-
return `openclaw-session:${target}`;
|
|
314
|
+
return textResult(outcome.text, outcome.details);
|
|
363
315
|
}
|
|
364
|
-
function
|
|
365
|
-
return
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
316
|
+
async function resolveTargetEntry2(services, params, options = {}) {
|
|
317
|
+
return resolveTargetEntry(
|
|
318
|
+
{
|
|
319
|
+
getEntryById: async (id) => await services.entries.getEntry(id) ?? (await services.memory.getEntryTrace(id))?.entry ?? null,
|
|
320
|
+
findEntryBySubject: async (subject) => services.memory.findEntryBySubject(subject),
|
|
321
|
+
findMostRecentEntry: async () => services.memory.findMostRecentEntry()
|
|
322
|
+
},
|
|
323
|
+
params,
|
|
324
|
+
options
|
|
325
|
+
);
|
|
371
326
|
}
|
|
372
327
|
function logToolCall(logger, toolName, ctx, summary, sanitizedParams) {
|
|
373
328
|
logger.info(`[agenr] tool=${toolName} ${formatToolSessionContext(ctx)} ${summary}`);
|
|
@@ -376,63 +331,6 @@ function logToolCall(logger, toolName, ctx, summary, sanitizedParams) {
|
|
|
376
331
|
function logToolFailure(logger, toolName, ctx, error) {
|
|
377
332
|
logger.warn(`[agenr] tool=${toolName} ${formatToolSessionContext(ctx)} failed: ${formatErrorMessage(error)}`);
|
|
378
333
|
}
|
|
379
|
-
function formatTargetSelector(id, subject, last) {
|
|
380
|
-
if (last === true) {
|
|
381
|
-
return "last";
|
|
382
|
-
}
|
|
383
|
-
if (id) {
|
|
384
|
-
return `id:${JSON.stringify(id)}`;
|
|
385
|
-
}
|
|
386
|
-
if (subject) {
|
|
387
|
-
return `subject:${JSON.stringify(subject)}`;
|
|
388
|
-
}
|
|
389
|
-
return "unknown";
|
|
390
|
-
}
|
|
391
|
-
function sanitizeStoreToolParams(params) {
|
|
392
|
-
return {
|
|
393
|
-
type: params.type,
|
|
394
|
-
subject: params.subject,
|
|
395
|
-
...params.importance !== void 0 ? { importance: params.importance } : {},
|
|
396
|
-
...params.expiry !== void 0 ? { expiry: params.expiry } : {},
|
|
397
|
-
...params.tags.length > 0 ? { tags: params.tags } : {},
|
|
398
|
-
contentLength: params.content.length,
|
|
399
|
-
...params.sourceContext !== void 0 ? { sourceContextLength: params.sourceContext.length } : {},
|
|
400
|
-
...params.supersedes !== void 0 ? { hasSupersedes: true } : {},
|
|
401
|
-
...params.claimKey !== void 0 ? { hasClaimKey: true } : {},
|
|
402
|
-
...params.validFrom !== void 0 ? { hasValidFrom: true } : {},
|
|
403
|
-
...params.validTo !== void 0 ? { hasValidTo: true } : {}
|
|
404
|
-
};
|
|
405
|
-
}
|
|
406
|
-
function formatRecallToolSummary(params) {
|
|
407
|
-
const parts = [`query=${JSON.stringify(truncate(params.query, 80))}`];
|
|
408
|
-
if (params.mode) {
|
|
409
|
-
parts.push(`mode=${params.mode}`);
|
|
410
|
-
}
|
|
411
|
-
if (params.limit !== void 0 && params.limit !== DEFAULT_RECALL_LIMIT) {
|
|
412
|
-
parts.push(`limit=${params.limit}`);
|
|
413
|
-
}
|
|
414
|
-
if (params.types.length > 0) {
|
|
415
|
-
parts.push(`types=${JSON.stringify(params.types)}`);
|
|
416
|
-
}
|
|
417
|
-
if (params.tags.length > 0) {
|
|
418
|
-
parts.push(`tags=${JSON.stringify(params.tags)}`);
|
|
419
|
-
}
|
|
420
|
-
if (params.asOf) {
|
|
421
|
-
parts.push(`as_of=${JSON.stringify(params.asOf)}`);
|
|
422
|
-
}
|
|
423
|
-
return parts.join(" ");
|
|
424
|
-
}
|
|
425
|
-
function sanitizeRecallToolParams(params) {
|
|
426
|
-
return {
|
|
427
|
-
query: params.query,
|
|
428
|
-
...params.mode ? { mode: params.mode } : {},
|
|
429
|
-
...params.limit !== void 0 ? { limit: params.limit } : {},
|
|
430
|
-
...params.threshold !== void 0 ? { threshold: params.threshold } : {},
|
|
431
|
-
...params.types.length > 0 ? { types: params.types } : {},
|
|
432
|
-
...params.tags.length > 0 ? { tags: params.tags } : {},
|
|
433
|
-
...params.asOf ? { asOf: params.asOf } : {}
|
|
434
|
-
};
|
|
435
|
-
}
|
|
436
334
|
function sanitizeRetireToolParams(params) {
|
|
437
335
|
return {
|
|
438
336
|
...params.id ? { id: params.id } : {},
|
|
@@ -440,17 +338,6 @@ function sanitizeRetireToolParams(params) {
|
|
|
440
338
|
...params.reason !== void 0 ? { reasonLength: params.reason.length } : {}
|
|
441
339
|
};
|
|
442
340
|
}
|
|
443
|
-
function sanitizeUpdateToolParams(params) {
|
|
444
|
-
return {
|
|
445
|
-
...params.id ? { id: params.id } : {},
|
|
446
|
-
...params.subject ? { subject: params.subject } : {},
|
|
447
|
-
...params.importance !== void 0 ? { importance: params.importance } : {},
|
|
448
|
-
...params.expiry !== void 0 ? { expiry: params.expiry } : {},
|
|
449
|
-
...params.claimKey !== void 0 ? { hasClaimKey: true } : {},
|
|
450
|
-
...params.validFrom !== void 0 ? { hasValidFrom: true } : {},
|
|
451
|
-
...params.validTo !== void 0 ? { hasValidTo: true } : {}
|
|
452
|
-
};
|
|
453
|
-
}
|
|
454
341
|
function sanitizeTraceToolParams(params) {
|
|
455
342
|
return {
|
|
456
343
|
...params.id ? { id: params.id } : {},
|
|
@@ -458,211 +345,6 @@ function sanitizeTraceToolParams(params) {
|
|
|
458
345
|
...params.last !== void 0 ? { last: params.last } : {}
|
|
459
346
|
};
|
|
460
347
|
}
|
|
461
|
-
function formatUnifiedRecallResults(result) {
|
|
462
|
-
const lines = [
|
|
463
|
-
"Recall Route",
|
|
464
|
-
`requested=${result.routing.requested} detected=${result.routing.detectedIntent} queried=${result.routing.queried.join(", ") || "none"}`,
|
|
465
|
-
result.routing.reason,
|
|
466
|
-
""
|
|
467
|
-
];
|
|
468
|
-
if (result.timeWindow) {
|
|
469
|
-
lines.push("Resolved Time Window");
|
|
470
|
-
lines.push(`${result.timeWindow.start} -> ${result.timeWindow.end} (${result.timeWindow.timezone}) from ${JSON.stringify(result.timeWindow.resolvedFrom)}`);
|
|
471
|
-
lines.push("");
|
|
472
|
-
}
|
|
473
|
-
if (result.asOf) {
|
|
474
|
-
lines.push("As Of");
|
|
475
|
-
lines.push(result.asOf);
|
|
476
|
-
lines.push("");
|
|
477
|
-
}
|
|
478
|
-
if (result.routing.queried.includes("procedures") || result.procedure || result.procedureCandidates.length > 0 || result.procedureNotices.length > 0) {
|
|
479
|
-
appendProcedureMatches(lines, result);
|
|
480
|
-
lines.push("");
|
|
481
|
-
}
|
|
482
|
-
const renderEntriesFirst = result.routing.detectedIntent === "historical_state";
|
|
483
|
-
if (renderEntriesFirst) {
|
|
484
|
-
appendEntryMatches(lines, result);
|
|
485
|
-
lines.push("");
|
|
486
|
-
appendClaimTransitions(lines, result);
|
|
487
|
-
lines.push("");
|
|
488
|
-
appendEpisodeMatches(lines, result);
|
|
489
|
-
} else {
|
|
490
|
-
appendEpisodeMatches(lines, result);
|
|
491
|
-
lines.push("");
|
|
492
|
-
appendEntryMatches(lines, result);
|
|
493
|
-
lines.push("");
|
|
494
|
-
appendClaimTransitions(lines, result);
|
|
495
|
-
}
|
|
496
|
-
if (result.notices.length > 0) {
|
|
497
|
-
lines.push("");
|
|
498
|
-
lines.push("Notices");
|
|
499
|
-
for (const notice of result.notices) {
|
|
500
|
-
lines.push(`- ${notice}`);
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
return lines.join("\n");
|
|
504
|
-
}
|
|
505
|
-
function appendProcedureMatches(lines, result) {
|
|
506
|
-
lines.push("Procedure Matches");
|
|
507
|
-
if (!result.procedure && result.procedureCandidates.length === 0) {
|
|
508
|
-
lines.push("None.");
|
|
509
|
-
} else {
|
|
510
|
-
if (result.procedure) {
|
|
511
|
-
appendCanonicalProcedure(lines, result.procedure, result.procedureCandidates);
|
|
512
|
-
} else {
|
|
513
|
-
lines.push("Canonical procedure: none.");
|
|
514
|
-
}
|
|
515
|
-
const additionalCandidates = result.procedureCandidates.filter((candidate) => candidate.procedure.id !== result.procedure?.id);
|
|
516
|
-
if (additionalCandidates.length > 0) {
|
|
517
|
-
lines.push("Other Candidates");
|
|
518
|
-
for (const [index, candidate] of additionalCandidates.entries()) {
|
|
519
|
-
lines.push(
|
|
520
|
-
`${index + 1}. ${candidate.procedure.procedure_key} | ${candidate.procedure.title} | score ${candidate.score.toFixed(2)} | lexical=${candidate.scores.lexical.toFixed(2)} | vector=${candidate.scores.vector.toFixed(2)}`
|
|
521
|
-
);
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
if (result.procedureNotices.length > 0) {
|
|
526
|
-
lines.push("Procedure Notices");
|
|
527
|
-
for (const notice of result.procedureNotices) {
|
|
528
|
-
lines.push(`- ${notice}`);
|
|
529
|
-
}
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
function appendEntryMatches(lines, result) {
|
|
533
|
-
lines.push("Entry Matches");
|
|
534
|
-
if (result.projectedEntries.length === 0) {
|
|
535
|
-
lines.push("None.");
|
|
536
|
-
return;
|
|
537
|
-
}
|
|
538
|
-
for (const [familyIndex, family] of result.entryFamilies.entries()) {
|
|
539
|
-
lines.push(
|
|
540
|
-
family.claimKey ? `Family ${familyIndex + 1}. claim_key=${family.claimKey} | slot_policy=${family.slotPolicy} | primary=${family.primary.entryId} | subject=${family.subject}` : `Standalone ${familyIndex + 1}. ${family.primary.entryId} | subject=${family.subject}`
|
|
541
|
-
);
|
|
542
|
-
for (const [entryIndex, entry] of family.entries.entries()) {
|
|
543
|
-
lines.push(
|
|
544
|
-
` ${entryIndex + 1}. ${entry.entryId} | ${entry.recall.entry.type} | ${entry.recall.entry.subject} | score ${entry.recall.score.toFixed(2)} | state=${entry.memoryState} | claim_status=${formatClaimStatus(entry.claimStatus)}`
|
|
545
|
-
);
|
|
546
|
-
lines.push(` ${truncate(entry.recall.entry.content, 220)}`);
|
|
547
|
-
lines.push(` freshness=${entry.freshness.label}`);
|
|
548
|
-
const provenance = formatProjectedEntryProvenance(entry);
|
|
549
|
-
if (provenance) {
|
|
550
|
-
lines.push(` provenance=${provenance}`);
|
|
551
|
-
}
|
|
552
|
-
lines.push(` why_surfaced=${entry.whySurfaced.summary}`);
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
function appendEpisodeMatches(lines, result) {
|
|
557
|
-
lines.push("Episode Matches");
|
|
558
|
-
if (result.episodes.length === 0) {
|
|
559
|
-
lines.push("None.");
|
|
560
|
-
return;
|
|
561
|
-
}
|
|
562
|
-
for (const [index, episode] of result.episodes.entries()) {
|
|
563
|
-
lines.push(
|
|
564
|
-
`${index + 1}. ${episode.episode.id} | ${episode.episode.source} | ${episode.episode.startedAt} -> ${episode.episode.endedAt ?? episode.episode.startedAt} | score ${episode.score.toFixed(2)}`
|
|
565
|
-
);
|
|
566
|
-
lines.push(` ${index < 3 ? episode.episode.summary.trim() : truncate(episode.episode.summary.trim(), 220)}`);
|
|
567
|
-
lines.push(` why_matched=${describeEpisodeMatch(episode)}`);
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
function appendCanonicalProcedure(lines, procedure, candidates) {
|
|
571
|
-
const leadCandidate = candidates.find((candidate) => candidate.procedure.id === procedure.id);
|
|
572
|
-
lines.push(
|
|
573
|
-
leadCandidate ? `Canonical Procedure. ${procedure.procedure_key} | ${procedure.title} | score ${leadCandidate.score.toFixed(2)}` : `Canonical Procedure. ${procedure.procedure_key} | ${procedure.title}`
|
|
574
|
-
);
|
|
575
|
-
lines.push(` goal=${procedure.goal}`);
|
|
576
|
-
appendLabeledList(lines, "when_to_use", procedure.when_to_use);
|
|
577
|
-
appendLabeledList(lines, "when_not_to_use", procedure.when_not_to_use);
|
|
578
|
-
appendLabeledList(lines, "prerequisites", procedure.prerequisites);
|
|
579
|
-
lines.push(" steps");
|
|
580
|
-
for (const [index, step] of procedure.steps.entries()) {
|
|
581
|
-
lines.push(` ${index + 1}. [${step.kind}] ${step.instruction}`);
|
|
582
|
-
const stepDetails = formatProcedureStepDetails(step);
|
|
583
|
-
if (stepDetails.length > 0) {
|
|
584
|
-
for (const detail of stepDetails) {
|
|
585
|
-
lines.push(` ${detail}`);
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
appendLabeledList(lines, "verification", procedure.verification);
|
|
590
|
-
appendLabeledList(lines, "failure_modes", procedure.failure_modes);
|
|
591
|
-
lines.push(" sources");
|
|
592
|
-
for (const source of procedure.sources) {
|
|
593
|
-
lines.push(` - ${formatProcedureSource(source)}`);
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
function appendClaimTransitions(lines, result) {
|
|
597
|
-
lines.push("Claim Transitions");
|
|
598
|
-
if (result.claimTransitions.length === 0) {
|
|
599
|
-
lines.push("None.");
|
|
600
|
-
return;
|
|
601
|
-
}
|
|
602
|
-
for (const [index, transition] of result.claimTransitions.entries()) {
|
|
603
|
-
lines.push(
|
|
604
|
-
`${index + 1}. family=${transition.claimKey ?? transition.familyKey} | slot_policy=${transition.slotPolicy}${transition.currentEntryId ? ` | current=${transition.currentEntryId}` : ""}${transition.priorEntryId ? ` | prior=${transition.priorEntryId}` : ""}`
|
|
605
|
-
);
|
|
606
|
-
lines.push(` ${transition.summary}`);
|
|
607
|
-
if (transition.episodeContext) {
|
|
608
|
-
lines.push(
|
|
609
|
-
` episode=${transition.episodeContext.episodeId} | ${transition.episodeContext.startedAt} -> ${transition.episodeContext.endedAt ?? transition.episodeContext.startedAt}`
|
|
610
|
-
);
|
|
611
|
-
lines.push(` ${truncate(transition.episodeContext.summary.trim(), 220)}`);
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
function formatUnifiedRecallLogSummary(result) {
|
|
616
|
-
const procedureCount = result.procedureCandidates.length;
|
|
617
|
-
const procedureSummary = result.procedure ? ` [procedure: ${JSON.stringify(truncate(result.procedure.title, 80))}]` : "";
|
|
618
|
-
const entrySubjects = result.entries.map((entry) => entry.entry.subject.trim()).filter((subject) => subject.length > 0);
|
|
619
|
-
const displayed = entrySubjects.slice(0, RESULT_SUBJECT_LOG_LIMIT).map((subject) => JSON.stringify(truncate(subject, 80)));
|
|
620
|
-
const remaining = entrySubjects.length - RESULT_SUBJECT_LOG_LIMIT;
|
|
621
|
-
const suffix = displayed.length === 0 ? "" : ` [entry subjects: ${displayed.join(", ")}${remaining > 0 ? `, ... and ${remaining} more` : ""}]`;
|
|
622
|
-
const entryEpisodeSummary = `${result.episodes.length} episode${result.episodes.length === 1 ? "" : "s"}, ${result.entries.length} entr${result.entries.length === 1 ? "y" : "ies"}`;
|
|
623
|
-
if (procedureCount === 0 && !result.procedure) {
|
|
624
|
-
return `${entryEpisodeSummary}${suffix}`;
|
|
625
|
-
}
|
|
626
|
-
return `${procedureCount} procedure candidate${procedureCount === 1 ? "" : "s"}, ${entryEpisodeSummary}${procedureSummary}${suffix}`;
|
|
627
|
-
}
|
|
628
|
-
function appendLabeledList(lines, label, values) {
|
|
629
|
-
lines.push(` ${label}`);
|
|
630
|
-
if (values.length === 0) {
|
|
631
|
-
lines.push(" - none");
|
|
632
|
-
return;
|
|
633
|
-
}
|
|
634
|
-
for (const value of values) {
|
|
635
|
-
lines.push(` - ${value}`);
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
function formatProcedureStepDetails(step) {
|
|
639
|
-
switch (step.kind) {
|
|
640
|
-
case "run_command":
|
|
641
|
-
return [`command=${step.command}`];
|
|
642
|
-
case "read_reference":
|
|
643
|
-
return [`ref=${formatProcedureSource(step.ref)}`];
|
|
644
|
-
case "inspect_state":
|
|
645
|
-
return [step.target ? `target=${step.target}` : void 0, step.query ? `query=${step.query}` : void 0].filter(
|
|
646
|
-
(value) => value !== void 0
|
|
647
|
-
);
|
|
648
|
-
case "edit_file":
|
|
649
|
-
return [`path=${step.path}`, `edit=${step.edit}`];
|
|
650
|
-
case "ask_user":
|
|
651
|
-
return [`prompt=${step.prompt}`];
|
|
652
|
-
case "invoke_tool":
|
|
653
|
-
return [step.tool ? `tool=${step.tool}` : void 0, step.arguments ? `arguments=${JSON.stringify(step.arguments)}` : void 0].filter(
|
|
654
|
-
(value) => value !== void 0
|
|
655
|
-
);
|
|
656
|
-
case "verify":
|
|
657
|
-
return step.checks.map((check) => `check=${check}`);
|
|
658
|
-
default:
|
|
659
|
-
return [];
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
function formatProcedureSource(source) {
|
|
663
|
-
const parts = [source.kind, source.label, source.path, source.locator].filter((value) => Boolean(value && value.length > 0));
|
|
664
|
-
return parts.join(" | ");
|
|
665
|
-
}
|
|
666
348
|
function formatTrace(entry, supersededBy, supersedes, claimFamily, recallEvents) {
|
|
667
349
|
const slotPolicy = entry.claim_key ? claimFamily ? {
|
|
668
350
|
policy: claimFamily.slotPolicy ?? resolveClaimSlotPolicy(claimFamily.claimKey).policy,
|
|
@@ -711,29 +393,11 @@ function formatTrace(entry, supersededBy, supersedes, claimFamily, recallEvents)
|
|
|
711
393
|
}
|
|
712
394
|
return lines.join("\n");
|
|
713
395
|
}
|
|
714
|
-
function truncate(value, maxChars) {
|
|
715
|
-
if (value.length <= maxChars) {
|
|
716
|
-
return value;
|
|
717
|
-
}
|
|
718
|
-
return `${value.slice(0, maxChars - 3).trimEnd()}...`;
|
|
719
|
-
}
|
|
720
396
|
function toolFailureResult(error) {
|
|
721
397
|
return failedTextResult(formatErrorMessage(error), {
|
|
722
398
|
status: "failed"
|
|
723
399
|
});
|
|
724
400
|
}
|
|
725
|
-
function formatErrorMessage(error) {
|
|
726
|
-
if (error instanceof Error) {
|
|
727
|
-
return error.message;
|
|
728
|
-
}
|
|
729
|
-
return String(error);
|
|
730
|
-
}
|
|
731
|
-
function asRecord(value) {
|
|
732
|
-
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
733
|
-
return value;
|
|
734
|
-
}
|
|
735
|
-
throw new Error("Tool parameters must be an object.");
|
|
736
|
-
}
|
|
737
401
|
function formatToolSessionContext(ctx) {
|
|
738
402
|
const normalizedSessionId = ctx.sessionId?.trim();
|
|
739
403
|
const normalizedSessionKey = ctx.sessionKey?.trim();
|
|
@@ -748,33 +412,6 @@ function formatToolSessionContext(ctx) {
|
|
|
748
412
|
}
|
|
749
413
|
return "session=unknown";
|
|
750
414
|
}
|
|
751
|
-
function describeEpisodeMatch(result) {
|
|
752
|
-
if (result.scores.semantic > 0 && result.scores.temporal > 0) {
|
|
753
|
-
return "Semantic match within the resolved time window.";
|
|
754
|
-
}
|
|
755
|
-
if (result.scores.semantic > 0) {
|
|
756
|
-
return "Semantic match to the episode summary.";
|
|
757
|
-
}
|
|
758
|
-
if (result.scores.temporal > 0) {
|
|
759
|
-
return "Session overlaps the resolved time window.";
|
|
760
|
-
}
|
|
761
|
-
return "Matched episodic recall ranking.";
|
|
762
|
-
}
|
|
763
|
-
function formatClaimStatus(status) {
|
|
764
|
-
return status === "no_key" ? "no-key" : status;
|
|
765
|
-
}
|
|
766
|
-
function formatProjectedEntryProvenance(entry) {
|
|
767
|
-
const parts = [
|
|
768
|
-
entry.provenance.supersededById ? `superseded_by=${entry.provenance.supersededById}` : void 0,
|
|
769
|
-
entry.provenance.supersessionKind ? `kind=${entry.provenance.supersessionKind}` : void 0,
|
|
770
|
-
entry.provenance.supersessionReason ? `reason=${truncate(entry.provenance.supersessionReason, 120)}` : void 0,
|
|
771
|
-
entry.provenance.supportSourceKind ? `support=${entry.provenance.supportSourceKind}` : void 0,
|
|
772
|
-
entry.provenance.supportMode ? `support_mode=${entry.provenance.supportMode}` : void 0,
|
|
773
|
-
entry.provenance.supportObservedAt ? `observed=${entry.provenance.supportObservedAt}` : void 0,
|
|
774
|
-
entry.provenance.supportLocator ? `locator=${truncate(entry.provenance.supportLocator, 120)}` : void 0
|
|
775
|
-
].filter((value) => value !== void 0);
|
|
776
|
-
return parts.join(" | ");
|
|
777
|
-
}
|
|
778
415
|
function describeTraceEntryState(entry) {
|
|
779
416
|
if (entry.superseded_by) {
|
|
780
417
|
return "superseded";
|
|
@@ -806,51 +443,6 @@ function summarizeTraceClaimFamilyTransition(entries) {
|
|
|
806
443
|
}
|
|
807
444
|
|
|
808
445
|
// src/adapters/openclaw/tools/recall.ts
|
|
809
|
-
var RECALL_TOOL_PARAMETERS = {
|
|
810
|
-
type: "object",
|
|
811
|
-
additionalProperties: false,
|
|
812
|
-
properties: {
|
|
813
|
-
query: {
|
|
814
|
-
type: "string",
|
|
815
|
-
description: "What you need to remember. Use a focused natural-language query rather than a broad 'everything' search. Phrase prior-state asks directly, for example 'what was the previous approach' or 'what changed from X to Y'. Phrase procedural asks directly, for example 'how do I rotate credentials' or 'what steps should I follow'."
|
|
816
|
-
},
|
|
817
|
-
mode: {
|
|
818
|
-
type: "string",
|
|
819
|
-
enum: [...RECALL_MODES],
|
|
820
|
-
description: "Recall mode: auto routes between exact entry recall, historical-state recall, procedural recall, and episodes; entries forces semantic recall; episodes forces temporal or semantic session recall; procedures forces procedural recall."
|
|
821
|
-
},
|
|
822
|
-
limit: {
|
|
823
|
-
type: "integer",
|
|
824
|
-
minimum: 1,
|
|
825
|
-
maximum: 10,
|
|
826
|
-
description: "Maximum results to return. Lower this when you want a tighter shortlist."
|
|
827
|
-
},
|
|
828
|
-
threshold: {
|
|
829
|
-
type: "number",
|
|
830
|
-
minimum: 0,
|
|
831
|
-
maximum: 1,
|
|
832
|
-
description: "Minimum final score from 0 to 1. Raise this when you want fewer, higher-confidence matches."
|
|
833
|
-
},
|
|
834
|
-
types: {
|
|
835
|
-
type: "array",
|
|
836
|
-
items: {
|
|
837
|
-
type: "string",
|
|
838
|
-
enum: [...ENTRY_TYPES]
|
|
839
|
-
},
|
|
840
|
-
description: "Optional knowledge types to filter by, such as decision, preference, lesson, fact, milestone, or relationship."
|
|
841
|
-
},
|
|
842
|
-
tags: {
|
|
843
|
-
type: "array",
|
|
844
|
-
items: { type: "string" },
|
|
845
|
-
description: "Optional tags to filter by once you already know the relevant entity, system, or theme."
|
|
846
|
-
},
|
|
847
|
-
asOf: {
|
|
848
|
-
type: "string",
|
|
849
|
-
description: "Optional reference time for current-vs-prior resolution. Supports ISO timestamps and the same natural-language date phrases used elsewhere in recall."
|
|
850
|
-
}
|
|
851
|
-
},
|
|
852
|
-
required: ["query"]
|
|
853
|
-
};
|
|
854
446
|
function createAgenrRecallTool(ctx, servicesPromise, logger) {
|
|
855
447
|
return {
|
|
856
448
|
name: "agenr_recall",
|
|
@@ -859,48 +451,10 @@ function createAgenrRecallTool(ctx, servicesPromise, logger) {
|
|
|
859
451
|
parameters: RECALL_TOOL_PARAMETERS,
|
|
860
452
|
async execute(_toolCallId, rawParams) {
|
|
861
453
|
try {
|
|
862
|
-
const params =
|
|
863
|
-
const
|
|
864
|
-
|
|
865
|
-
const limit = readNumberParam(params, "limit", { integer: true, strict: true });
|
|
866
|
-
const threshold = readNumberParam(params, "threshold", { strict: true });
|
|
454
|
+
const params = parseRecallToolParams(rawParams, OPENCLAW_PARAM_READER);
|
|
455
|
+
const sanitizedParams = sanitizeRecallToolParams(params);
|
|
456
|
+
logToolCall(logger, "agenr_recall", ctx, formatRecallToolSummary(params), sanitizedParams);
|
|
867
457
|
const services = await servicesPromise;
|
|
868
|
-
const types = parseEntryTypes(readStringArrayParam(params, "types"));
|
|
869
|
-
const tags = normalizeStringArray(readStringArrayParam(params, "tags"));
|
|
870
|
-
const asOf = readStringParam2(params, "asOf");
|
|
871
|
-
const request = {
|
|
872
|
-
text: query,
|
|
873
|
-
...mode ? { mode } : {},
|
|
874
|
-
...limit !== void 0 ? { limit } : {},
|
|
875
|
-
...threshold !== void 0 ? { threshold } : {},
|
|
876
|
-
...types.length > 0 ? { types } : {},
|
|
877
|
-
...tags.length > 0 ? { tags } : {},
|
|
878
|
-
...asOf ? { asOf } : {},
|
|
879
|
-
sessionKey: ctx.sessionKey
|
|
880
|
-
};
|
|
881
|
-
const sanitizedParams = sanitizeRecallToolParams({
|
|
882
|
-
query,
|
|
883
|
-
mode,
|
|
884
|
-
limit,
|
|
885
|
-
threshold,
|
|
886
|
-
types,
|
|
887
|
-
tags,
|
|
888
|
-
...asOf ? { asOf } : {}
|
|
889
|
-
});
|
|
890
|
-
logToolCall(
|
|
891
|
-
logger,
|
|
892
|
-
"agenr_recall",
|
|
893
|
-
ctx,
|
|
894
|
-
formatRecallToolSummary({
|
|
895
|
-
query,
|
|
896
|
-
mode,
|
|
897
|
-
limit,
|
|
898
|
-
types,
|
|
899
|
-
tags,
|
|
900
|
-
...asOf ? { asOf } : {}
|
|
901
|
-
}),
|
|
902
|
-
sanitizedParams
|
|
903
|
-
);
|
|
904
458
|
void services.debugSink.emit({
|
|
905
459
|
type: "tool_call",
|
|
906
460
|
tool: "agenr_recall",
|
|
@@ -908,163 +462,83 @@ function createAgenrRecallTool(ctx, servicesPromise, logger) {
|
|
|
908
462
|
...ctx.sessionKey ? { sessionKey: ctx.sessionKey } : {},
|
|
909
463
|
params: sanitizedParams
|
|
910
464
|
});
|
|
911
|
-
const result = await
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
recall: services.recall,
|
|
915
|
-
embeddingAvailable: services.embeddingStatus.available,
|
|
916
|
-
embeddingError: services.embeddingStatus.error,
|
|
917
|
-
claimSlotPolicyConfig: services.pluginConfig.memoryPolicy?.slotPolicies,
|
|
465
|
+
const result = await runRecallMemoryTool(params, buildRecallToolServices(services), {
|
|
466
|
+
sessionKey: ctx.sessionKey,
|
|
467
|
+
slotPolicyConfig: services.pluginConfig.memoryPolicy?.slotPolicies,
|
|
918
468
|
debugLog: (message) => {
|
|
919
469
|
logger.debug?.(message);
|
|
920
|
-
},
|
|
921
|
-
embedQuery: services.embeddingStatus.available ? async (text) => {
|
|
922
|
-
const vectors = await services.embedding.embed([text]);
|
|
923
|
-
return vectors[0] ?? [];
|
|
924
|
-
} : void 0,
|
|
925
|
-
recallOptions: {
|
|
926
|
-
slotPolicyConfig: services.pluginConfig.memoryPolicy?.slotPolicies
|
|
927
470
|
}
|
|
928
471
|
});
|
|
929
472
|
logger.info(
|
|
930
473
|
`[agenr] tool=agenr_recall session=${ctx.sessionId ?? "unknown"} key=${ctx.sessionKey ?? "unknown"} result: ${formatUnifiedRecallLogSummary(result)}`
|
|
931
474
|
);
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
const sessionKeyPayload = ctx.sessionKey ? { sessionKey: ctx.sessionKey } : {};
|
|
935
|
-
void services.debugSink.emit({
|
|
936
|
-
type: "tool_result",
|
|
937
|
-
tool: "agenr_recall",
|
|
938
|
-
...sessionIdPayload,
|
|
939
|
-
...sessionKeyPayload,
|
|
940
|
-
summary: {
|
|
941
|
-
count: result.count,
|
|
942
|
-
routing: {
|
|
943
|
-
requested: result.routing.requested,
|
|
944
|
-
detectedIntent: result.routing.detectedIntent,
|
|
945
|
-
queried: [...result.routing.queried],
|
|
946
|
-
reason: result.routing.reason
|
|
947
|
-
},
|
|
948
|
-
selectedEntryIds: result.entries.map((entry) => entry.entry.id),
|
|
949
|
-
episodeIds: result.episodes.map((episode) => episode.episode.id),
|
|
950
|
-
selectedProcedureKey: result.procedure?.procedure_key ?? null,
|
|
951
|
-
notices: [...result.notices],
|
|
952
|
-
procedureNotices: [...result.procedureNotices]
|
|
953
|
-
}
|
|
954
|
-
});
|
|
955
|
-
void services.debugSink.emit({
|
|
956
|
-
type: "unified_recall",
|
|
957
|
-
...sessionIdPayload,
|
|
958
|
-
...sessionKeyPayload,
|
|
959
|
-
debug: buildLiveRecallDebugArtifact({
|
|
960
|
-
caseId: `live-${randomUUID()}`,
|
|
961
|
-
query,
|
|
962
|
-
result,
|
|
963
|
-
eventLevel: services.debugSink.eventLevel,
|
|
964
|
-
maxTopCandidates: services.debugSink.maxTopCandidates
|
|
965
|
-
})
|
|
966
|
-
});
|
|
967
|
-
}
|
|
968
|
-
return textResult(formatUnifiedRecallResults(result), {
|
|
969
|
-
status: "ok",
|
|
970
|
-
count: result.count,
|
|
971
|
-
routing: {
|
|
972
|
-
requested: result.routing.requested,
|
|
973
|
-
detectedIntent: result.routing.detectedIntent,
|
|
974
|
-
queried: result.routing.queried,
|
|
975
|
-
reason: result.routing.reason
|
|
976
|
-
},
|
|
977
|
-
...result.asOf ? { asOf: result.asOf } : {},
|
|
978
|
-
...result.timeWindow ? { timeWindow: result.timeWindow } : {},
|
|
979
|
-
...result.procedure ? {
|
|
980
|
-
procedure: {
|
|
981
|
-
id: result.procedure.id,
|
|
982
|
-
procedureKey: result.procedure.procedure_key,
|
|
983
|
-
title: result.procedure.title,
|
|
984
|
-
goal: result.procedure.goal
|
|
985
|
-
}
|
|
986
|
-
} : {},
|
|
987
|
-
procedures: result.procedureCandidates.map((candidate) => ({
|
|
988
|
-
id: candidate.procedure.id,
|
|
989
|
-
procedureKey: candidate.procedure.procedure_key,
|
|
990
|
-
title: candidate.procedure.title,
|
|
991
|
-
goal: candidate.procedure.goal,
|
|
992
|
-
score: candidate.score,
|
|
993
|
-
lexicalScore: candidate.scores.lexical,
|
|
994
|
-
vectorScore: candidate.scores.vector
|
|
995
|
-
})),
|
|
996
|
-
procedureNotices: result.procedureNotices,
|
|
997
|
-
episodes: result.episodes.map((episode) => ({
|
|
998
|
-
id: episode.episode.id,
|
|
999
|
-
source: episode.episode.source,
|
|
1000
|
-
sourceId: episode.episode.sourceId,
|
|
1001
|
-
startedAt: episode.episode.startedAt,
|
|
1002
|
-
endedAt: episode.episode.endedAt,
|
|
1003
|
-
tags: episode.episode.tags,
|
|
1004
|
-
score: episode.score,
|
|
1005
|
-
activityLevel: episode.episode.activityLevel,
|
|
1006
|
-
summary: episode.episode.summary,
|
|
1007
|
-
whyMatched: episode.scores.semantic > 0 && episode.scores.temporal > 0 ? "Semantic match within the resolved time window." : episode.scores.semantic > 0 ? "Semantic match to the episode summary." : episode.scores.temporal > 0 ? "Session overlaps the resolved time window." : "Matched episodic recall ranking."
|
|
1008
|
-
})),
|
|
1009
|
-
entries: result.entries.map((entry) => ({
|
|
1010
|
-
id: entry.entry.id,
|
|
1011
|
-
subject: entry.entry.subject,
|
|
1012
|
-
type: entry.entry.type,
|
|
1013
|
-
expiry: entry.entry.expiry,
|
|
1014
|
-
importance: entry.entry.importance,
|
|
1015
|
-
score: entry.score,
|
|
1016
|
-
tags: entry.entry.tags,
|
|
1017
|
-
content: entry.entry.content
|
|
1018
|
-
})),
|
|
1019
|
-
projectedEntries: result.projectedEntries.map((entry) => ({
|
|
1020
|
-
id: entry.entryId,
|
|
1021
|
-
familyKey: entry.familyKey,
|
|
1022
|
-
claimKey: entry.claimKey,
|
|
1023
|
-
slotPolicy: entry.slotPolicy,
|
|
1024
|
-
memoryState: entry.memoryState,
|
|
1025
|
-
claimStatus: entry.claimStatus,
|
|
1026
|
-
freshness: entry.freshness,
|
|
1027
|
-
provenance: entry.provenance,
|
|
1028
|
-
whySurfaced: entry.whySurfaced
|
|
1029
|
-
})),
|
|
1030
|
-
entryFamilies: result.entryFamilies.map((family) => ({
|
|
1031
|
-
familyKey: family.familyKey,
|
|
1032
|
-
claimKey: family.claimKey,
|
|
1033
|
-
slotPolicy: family.slotPolicy,
|
|
1034
|
-
subject: family.subject,
|
|
1035
|
-
primaryEntryId: family.primary.entryId,
|
|
1036
|
-
entries: family.entries.map((entry) => ({
|
|
1037
|
-
id: entry.entryId,
|
|
1038
|
-
memoryState: entry.memoryState,
|
|
1039
|
-
claimStatus: entry.claimStatus
|
|
1040
|
-
}))
|
|
1041
|
-
})),
|
|
1042
|
-
claimTransitions: result.claimTransitions,
|
|
1043
|
-
notices: result.notices
|
|
1044
|
-
});
|
|
475
|
+
emitRecallDebugArtifacts(services, ctx, params.query, result);
|
|
476
|
+
return textResult2(formatUnifiedRecallResults(result), buildRecallToolDetails(result));
|
|
1045
477
|
} catch (error) {
|
|
1046
478
|
logToolFailure(logger, "agenr_recall", ctx, error);
|
|
1047
|
-
|
|
1048
|
-
const services = await servicesPromise;
|
|
1049
|
-
if (services.debugSink.enabled) {
|
|
1050
|
-
void services.debugSink.emit({
|
|
1051
|
-
type: "error",
|
|
1052
|
-
...ctx.sessionId ? { sessionId: ctx.sessionId } : {},
|
|
1053
|
-
...ctx.sessionKey ? { sessionKey: ctx.sessionKey } : {},
|
|
1054
|
-
scope: "agenr_recall",
|
|
1055
|
-
error: { message: error instanceof Error ? error.message : String(error) }
|
|
1056
|
-
});
|
|
1057
|
-
}
|
|
1058
|
-
} catch {
|
|
1059
|
-
}
|
|
479
|
+
await emitRecallError(servicesPromise, ctx, error);
|
|
1060
480
|
return toolFailureResult(error);
|
|
1061
481
|
}
|
|
1062
482
|
}
|
|
1063
483
|
};
|
|
1064
484
|
}
|
|
485
|
+
function emitRecallDebugArtifacts(services, ctx, query, result) {
|
|
486
|
+
if (!services.debugSink.enabled) {
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
const sessionIdPayload = ctx.sessionId ? { sessionId: ctx.sessionId } : {};
|
|
490
|
+
const sessionKeyPayload = ctx.sessionKey ? { sessionKey: ctx.sessionKey } : {};
|
|
491
|
+
void services.debugSink.emit({
|
|
492
|
+
type: "tool_result",
|
|
493
|
+
tool: "agenr_recall",
|
|
494
|
+
...sessionIdPayload,
|
|
495
|
+
...sessionKeyPayload,
|
|
496
|
+
summary: {
|
|
497
|
+
count: result.count,
|
|
498
|
+
routing: {
|
|
499
|
+
requested: result.routing.requested,
|
|
500
|
+
detectedIntent: result.routing.detectedIntent,
|
|
501
|
+
queried: [...result.routing.queried],
|
|
502
|
+
reason: result.routing.reason
|
|
503
|
+
},
|
|
504
|
+
selectedEntryIds: result.entries.map((entry) => entry.entry.id),
|
|
505
|
+
episodeIds: result.episodes.map((episode) => episode.episode.id),
|
|
506
|
+
selectedProcedureKey: result.procedure?.procedure_key ?? null,
|
|
507
|
+
notices: [...result.notices],
|
|
508
|
+
procedureNotices: [...result.procedureNotices]
|
|
509
|
+
}
|
|
510
|
+
});
|
|
511
|
+
void services.debugSink.emit({
|
|
512
|
+
type: "unified_recall",
|
|
513
|
+
...sessionIdPayload,
|
|
514
|
+
...sessionKeyPayload,
|
|
515
|
+
debug: buildLiveRecallDebugArtifact({
|
|
516
|
+
caseId: `live-${randomUUID()}`,
|
|
517
|
+
query,
|
|
518
|
+
result,
|
|
519
|
+
eventLevel: services.debugSink.eventLevel,
|
|
520
|
+
maxTopCandidates: services.debugSink.maxTopCandidates
|
|
521
|
+
})
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
async function emitRecallError(servicesPromise, ctx, error) {
|
|
525
|
+
try {
|
|
526
|
+
const services = await servicesPromise;
|
|
527
|
+
if (services.debugSink.enabled) {
|
|
528
|
+
void services.debugSink.emit({
|
|
529
|
+
type: "error",
|
|
530
|
+
...ctx.sessionId ? { sessionId: ctx.sessionId } : {},
|
|
531
|
+
...ctx.sessionKey ? { sessionKey: ctx.sessionKey } : {},
|
|
532
|
+
scope: "agenr_recall",
|
|
533
|
+
error: { message: error instanceof Error ? error.message : String(error) }
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
} catch {
|
|
537
|
+
}
|
|
538
|
+
}
|
|
1065
539
|
|
|
1066
540
|
// src/adapters/openclaw/tools/retire.ts
|
|
1067
|
-
import { failedTextResult as failedTextResult2, readStringParam as
|
|
541
|
+
import { failedTextResult as failedTextResult2, readStringParam as readStringParam2, textResult as textResult3 } from "openclaw/plugin-sdk/agent-runtime";
|
|
1068
542
|
var RETIRE_TOOL_PARAMETERS = {
|
|
1069
543
|
type: "object",
|
|
1070
544
|
additionalProperties: false,
|
|
@@ -1092,12 +566,12 @@ function createAgenrRetireTool(ctx, servicesPromise, logger) {
|
|
|
1092
566
|
async execute(_toolCallId, rawParams) {
|
|
1093
567
|
try {
|
|
1094
568
|
const params = asRecord(rawParams);
|
|
1095
|
-
const id =
|
|
1096
|
-
const subject =
|
|
1097
|
-
const reason =
|
|
569
|
+
const id = readStringParam2(params, "id");
|
|
570
|
+
const subject = readStringParam2(params, "subject");
|
|
571
|
+
const reason = readStringParam2(params, "reason");
|
|
1098
572
|
logToolCall(logger, "agenr_retire", ctx, `target=${formatTargetSelector(id, subject)}`, sanitizeRetireToolParams({ id, subject, reason }));
|
|
1099
573
|
const services = await servicesPromise;
|
|
1100
|
-
const entry = await
|
|
574
|
+
const entry = await resolveTargetEntry2(services, params);
|
|
1101
575
|
const retired = await services.entries.retireEntry(entry.id, reason);
|
|
1102
576
|
if (!retired) {
|
|
1103
577
|
return failedTextResult2(`Entry ${entry.id} is not active, so it could not be retired.`, {
|
|
@@ -1105,7 +579,7 @@ function createAgenrRetireTool(ctx, servicesPromise, logger) {
|
|
|
1105
579
|
entryId: entry.id
|
|
1106
580
|
});
|
|
1107
581
|
}
|
|
1108
|
-
return
|
|
582
|
+
return textResult3(`Retired "${entry.subject}".`, {
|
|
1109
583
|
status: "retired",
|
|
1110
584
|
entryId: entry.id,
|
|
1111
585
|
subject: entry.subject,
|
|
@@ -1120,63 +594,6 @@ function createAgenrRetireTool(ctx, servicesPromise, logger) {
|
|
|
1120
594
|
}
|
|
1121
595
|
|
|
1122
596
|
// src/adapters/openclaw/tools/store.ts
|
|
1123
|
-
import { failedTextResult as failedTextResult3, readNumberParam as readNumberParam2, readStringArrayParam as readStringArrayParam2, readStringParam as readStringParam4, textResult as textResult3 } from "openclaw/plugin-sdk/agent-runtime";
|
|
1124
|
-
var STORE_TOOL_PARAMETERS = {
|
|
1125
|
-
type: "object",
|
|
1126
|
-
additionalProperties: false,
|
|
1127
|
-
properties: {
|
|
1128
|
-
type: {
|
|
1129
|
-
type: "string",
|
|
1130
|
-
enum: [...ENTRY_TYPES],
|
|
1131
|
-
description: ENTRY_TYPE_DESCRIPTION
|
|
1132
|
-
},
|
|
1133
|
-
subject: {
|
|
1134
|
-
type: "string",
|
|
1135
|
-
description: "Short subject line future recall can match. Name the durable takeaway, person, system, rule, relationship, or milestone directly."
|
|
1136
|
-
},
|
|
1137
|
-
content: {
|
|
1138
|
-
type: "string",
|
|
1139
|
-
description: "What a fresh session should remember. Store the durable takeaway, not the activity log, canonical record, or transient progress snapshot."
|
|
1140
|
-
},
|
|
1141
|
-
importance: {
|
|
1142
|
-
type: "integer",
|
|
1143
|
-
minimum: 1,
|
|
1144
|
-
maximum: 10,
|
|
1145
|
-
description: "Importance from 1 to 10. Use 7 for normal durable memory, 9 for critical constraints, and 10 only rarely."
|
|
1146
|
-
},
|
|
1147
|
-
expiry: {
|
|
1148
|
-
type: "string",
|
|
1149
|
-
enum: ["core", "permanent", "temporary"],
|
|
1150
|
-
description: EXPIRY_DESCRIPTION
|
|
1151
|
-
},
|
|
1152
|
-
tags: {
|
|
1153
|
-
type: "array",
|
|
1154
|
-
items: { type: "string" },
|
|
1155
|
-
description: "Optional tags for entities, systems, teams, or themes that should improve later recall."
|
|
1156
|
-
},
|
|
1157
|
-
sourceContext: {
|
|
1158
|
-
type: "string",
|
|
1159
|
-
description: "Optional provenance note explaining why this memory was stored or what situation produced it."
|
|
1160
|
-
},
|
|
1161
|
-
supersedes: {
|
|
1162
|
-
type: "string",
|
|
1163
|
-
description: "ID of an entry this replaces. The old entry will be marked as superseded."
|
|
1164
|
-
},
|
|
1165
|
-
claimKey: {
|
|
1166
|
-
type: "string",
|
|
1167
|
-
description: 'Slot key identifying the specific knowledge slot (entity/attribute format, e.g., "project_name/deploy_strategy" or "postgres/max_connections"). Entries with the same claim key are candidates for supersession.'
|
|
1168
|
-
},
|
|
1169
|
-
validFrom: {
|
|
1170
|
-
type: "string",
|
|
1171
|
-
description: "ISO 8601 timestamp for when this fact became true in the world."
|
|
1172
|
-
},
|
|
1173
|
-
validTo: {
|
|
1174
|
-
type: "string",
|
|
1175
|
-
description: "ISO 8601 timestamp for when this fact stopped being true."
|
|
1176
|
-
}
|
|
1177
|
-
},
|
|
1178
|
-
required: ["type", "subject", "content"]
|
|
1179
|
-
};
|
|
1180
597
|
function createAgenrStoreTool(ctx, servicesPromise, logger) {
|
|
1181
598
|
return {
|
|
1182
599
|
name: "agenr_store",
|
|
@@ -1185,95 +602,17 @@ function createAgenrStoreTool(ctx, servicesPromise, logger) {
|
|
|
1185
602
|
parameters: STORE_TOOL_PARAMETERS,
|
|
1186
603
|
async execute(_toolCallId, rawParams) {
|
|
1187
604
|
try {
|
|
1188
|
-
const params =
|
|
1189
|
-
|
|
1190
|
-
const subject = readStringParam4(params, "subject", { required: true, label: "subject" });
|
|
1191
|
-
const content = readStringParam4(params, "content", { required: true, label: "content" });
|
|
1192
|
-
const importance = readNumberParam2(params, "importance", { integer: true, strict: true });
|
|
1193
|
-
const expiry = parseExpiry(readStringParam4(params, "expiry"));
|
|
1194
|
-
const tags = normalizeStringArray(readStringArrayParam2(params, "tags"));
|
|
1195
|
-
const sourceContext = readStringParam4(params, "sourceContext");
|
|
1196
|
-
const supersedes = readStringParam4(params, "supersedes");
|
|
1197
|
-
const claimKey = readStringParam4(params, "claimKey", { trim: false });
|
|
1198
|
-
const validFrom = readStringParam4(params, "validFrom");
|
|
1199
|
-
const validTo = readStringParam4(params, "validTo");
|
|
1200
|
-
const claimSupportObservedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1201
|
-
logToolCall(
|
|
1202
|
-
logger,
|
|
1203
|
-
"agenr_store",
|
|
1204
|
-
ctx,
|
|
1205
|
-
`store 1 entry subject=${JSON.stringify(subject)} type=${type}`,
|
|
1206
|
-
sanitizeStoreToolParams({
|
|
1207
|
-
type,
|
|
1208
|
-
subject,
|
|
1209
|
-
content,
|
|
1210
|
-
importance,
|
|
1211
|
-
expiry,
|
|
1212
|
-
tags,
|
|
1213
|
-
sourceContext,
|
|
1214
|
-
supersedes,
|
|
1215
|
-
claimKey,
|
|
1216
|
-
validFrom,
|
|
1217
|
-
validTo
|
|
1218
|
-
})
|
|
1219
|
-
);
|
|
605
|
+
const params = parseStoreToolParams(rawParams, OPENCLAW_PARAM_READER);
|
|
606
|
+
logToolCall(logger, "agenr_store", ctx, `store 1 entry subject=${JSON.stringify(params.subject)} type=${params.type}`, sanitizeStoreToolParams(params));
|
|
1220
607
|
const services = await servicesPromise;
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
content,
|
|
1227
|
-
...importance !== void 0 ? { importance } : {},
|
|
1228
|
-
...expiry !== void 0 ? { expiry } : {},
|
|
1229
|
-
...tags.length > 0 ? { tags } : {},
|
|
1230
|
-
...supersedes ? { supersedes } : {},
|
|
1231
|
-
...claimKey ? {
|
|
1232
|
-
claim_key: claimKey,
|
|
1233
|
-
claim_key_raw: claimKey,
|
|
1234
|
-
...buildToolCallClaimSupport(ctx, "agenr_store", claimSupportObservedAt)
|
|
1235
|
-
} : {},
|
|
1236
|
-
...validFrom ? { valid_from: validFrom } : {},
|
|
1237
|
-
...validTo ? { valid_to: validTo } : {},
|
|
1238
|
-
source_file: buildSessionSourceFile(ctx),
|
|
1239
|
-
source_context: sourceContext ?? "Stored via agenr_store from OpenClaw."
|
|
1240
|
-
}
|
|
1241
|
-
],
|
|
1242
|
-
services.entries,
|
|
1243
|
-
services.embedding,
|
|
1244
|
-
{
|
|
1245
|
-
...services.claimExtraction ? {
|
|
1246
|
-
claimExtraction: {
|
|
1247
|
-
llm: services.claimExtraction.llm,
|
|
1248
|
-
db: services.entries,
|
|
1249
|
-
config: services.claimExtraction.config
|
|
1250
|
-
}
|
|
1251
|
-
} : {},
|
|
608
|
+
return toOpenClawToolResult(
|
|
609
|
+
await runStoreMemoryTool(params, services, {
|
|
610
|
+
session: ctx,
|
|
611
|
+
sourcePrefix: "openclaw-session",
|
|
612
|
+
defaultSourceContext: "Stored via agenr_store from OpenClaw.",
|
|
1252
613
|
onWarning: (warning) => logger.warn(`[agenr] tool=agenr_store session=${ctx.sessionId ?? "unknown"} warning: ${warning}`)
|
|
1253
|
-
}
|
|
614
|
+
})
|
|
1254
615
|
);
|
|
1255
|
-
const storedEntry = await services.memory.findEntryBySubject(subject);
|
|
1256
|
-
if (result.stored > 0) {
|
|
1257
|
-
return textResult3(`Stored "${subject}".`, {
|
|
1258
|
-
status: "stored",
|
|
1259
|
-
subject,
|
|
1260
|
-
entryId: storedEntry?.id,
|
|
1261
|
-
result
|
|
1262
|
-
});
|
|
1263
|
-
}
|
|
1264
|
-
if (result.skipped > 0) {
|
|
1265
|
-
return textResult3(`Skipped "${subject}" because an active duplicate already exists.`, {
|
|
1266
|
-
status: "skipped",
|
|
1267
|
-
subject,
|
|
1268
|
-
entryId: storedEntry?.id,
|
|
1269
|
-
result
|
|
1270
|
-
});
|
|
1271
|
-
}
|
|
1272
|
-
return failedTextResult3(`Rejected "${subject}". Check the supplied type, content, and metadata.`, {
|
|
1273
|
-
status: "failed",
|
|
1274
|
-
subject,
|
|
1275
|
-
result
|
|
1276
|
-
});
|
|
1277
616
|
} catch (error) {
|
|
1278
617
|
logToolFailure(logger, "agenr_store", ctx, error);
|
|
1279
618
|
return toolFailureResult(error);
|
|
@@ -1283,7 +622,7 @@ function createAgenrStoreTool(ctx, servicesPromise, logger) {
|
|
|
1283
622
|
}
|
|
1284
623
|
|
|
1285
624
|
// src/adapters/openclaw/tools/trace.ts
|
|
1286
|
-
import { failedTextResult as
|
|
625
|
+
import { failedTextResult as failedTextResult3, readStringParam as readStringParam3, textResult as textResult4 } from "openclaw/plugin-sdk/agent-runtime";
|
|
1287
626
|
var TRACE_TOOL_PARAMETERS = {
|
|
1288
627
|
type: "object",
|
|
1289
628
|
additionalProperties: false,
|
|
@@ -1311,15 +650,15 @@ function createAgenrTraceTool(ctx, servicesPromise, logger) {
|
|
|
1311
650
|
async execute(_toolCallId, rawParams) {
|
|
1312
651
|
try {
|
|
1313
652
|
const params = asRecord(rawParams);
|
|
1314
|
-
const id =
|
|
1315
|
-
const subject =
|
|
653
|
+
const id = readStringParam3(params, "id");
|
|
654
|
+
const subject = readStringParam3(params, "subject");
|
|
1316
655
|
const last = readBooleanParam(params, "last");
|
|
1317
656
|
logToolCall(logger, "agenr_trace", ctx, `target=${formatTargetSelector(id, subject, last)}`, sanitizeTraceToolParams({ id, subject, last }));
|
|
1318
657
|
const services = await servicesPromise;
|
|
1319
|
-
const entry = await
|
|
658
|
+
const entry = await resolveTargetEntry2(services, params, { allowLast: true });
|
|
1320
659
|
const trace = await services.memory.getEntryTrace(entry.id);
|
|
1321
660
|
if (!trace) {
|
|
1322
|
-
return
|
|
661
|
+
return failedTextResult3(`Entry ${entry.id} was not found for tracing.`, {
|
|
1323
662
|
status: "failed",
|
|
1324
663
|
entryId: entry.id
|
|
1325
664
|
});
|
|
@@ -1344,41 +683,6 @@ function createAgenrTraceTool(ctx, servicesPromise, logger) {
|
|
|
1344
683
|
}
|
|
1345
684
|
|
|
1346
685
|
// src/adapters/openclaw/tools/update.ts
|
|
1347
|
-
import { failedTextResult as failedTextResult5, readNumberParam as readNumberParam3, readStringParam as readStringParam6, textResult as textResult5 } from "openclaw/plugin-sdk/agent-runtime";
|
|
1348
|
-
var UPDATE_TOOL_PARAMETERS = {
|
|
1349
|
-
type: "object",
|
|
1350
|
-
additionalProperties: false,
|
|
1351
|
-
properties: {
|
|
1352
|
-
id: {
|
|
1353
|
-
type: "string",
|
|
1354
|
-
description: "Entry id to update. Provide exactly one of id or subject."
|
|
1355
|
-
},
|
|
1356
|
-
subject: {
|
|
1357
|
-
type: "string",
|
|
1358
|
-
description: "Subject text to resolve when the id is unknown. The most recent exact or substring match wins. Provide exactly one of id or subject."
|
|
1359
|
-
},
|
|
1360
|
-
importance: {
|
|
1361
|
-
type: "integer",
|
|
1362
|
-
description: "New importance from 1 to 10. Use 7 for normal durable memory and reserve 9 to 10 for rare critical entries."
|
|
1363
|
-
},
|
|
1364
|
-
expiry: {
|
|
1365
|
-
type: "string",
|
|
1366
|
-
description: UPDATE_EXPIRY_DESCRIPTION
|
|
1367
|
-
},
|
|
1368
|
-
claimKey: {
|
|
1369
|
-
type: "string",
|
|
1370
|
-
description: 'Slot key identifying the specific knowledge slot (entity/attribute format, e.g., "project_name/deploy_strategy" or "postgres/max_connections"). Entries with the same claim key are candidates for supersession.'
|
|
1371
|
-
},
|
|
1372
|
-
validFrom: {
|
|
1373
|
-
type: "string",
|
|
1374
|
-
description: "ISO 8601 timestamp for when this fact became true."
|
|
1375
|
-
},
|
|
1376
|
-
validTo: {
|
|
1377
|
-
type: "string",
|
|
1378
|
-
description: "ISO 8601 timestamp for when this fact stopped being true."
|
|
1379
|
-
}
|
|
1380
|
-
}
|
|
1381
|
-
};
|
|
1382
686
|
function createAgenrUpdateTool(ctx, servicesPromise, logger) {
|
|
1383
687
|
return {
|
|
1384
688
|
name: "agenr_update",
|
|
@@ -1387,72 +691,30 @@ function createAgenrUpdateTool(ctx, servicesPromise, logger) {
|
|
|
1387
691
|
parameters: UPDATE_TOOL_PARAMETERS,
|
|
1388
692
|
async execute(_toolCallId, rawParams) {
|
|
1389
693
|
try {
|
|
1390
|
-
const params =
|
|
1391
|
-
const id = readStringParam6(params, "id");
|
|
1392
|
-
const subject = readStringParam6(params, "subject");
|
|
1393
|
-
const importance = readNumberParam3(params, "importance", { integer: true, strict: true });
|
|
1394
|
-
const expiry = parseExpiry(readStringParam6(params, "expiry"));
|
|
1395
|
-
const claimKeyInput = readStringParam6(params, "claimKey", { trim: false });
|
|
1396
|
-
const validFrom = readStringParam6(params, "validFrom");
|
|
1397
|
-
const validTo = readStringParam6(params, "validTo");
|
|
1398
|
-
const claimSupportObservedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1399
|
-
const claimSupport = claimKeyInput === void 0 ? void 0 : buildToolCallClaimSupport(ctx, "agenr_update", claimSupportObservedAt);
|
|
1400
|
-
const normalizedClaimKeyUpdate = claimKeyInput === void 0 ? void 0 : (() => {
|
|
1401
|
-
try {
|
|
1402
|
-
return normalizeManualClaimKeyUpdate({
|
|
1403
|
-
claimKey: claimKeyInput,
|
|
1404
|
-
rawClaimKey: claimKeyInput,
|
|
1405
|
-
supportSourceKind: claimSupport?.claim_support_source_kind,
|
|
1406
|
-
supportLocator: claimSupport?.claim_support_locator,
|
|
1407
|
-
supportObservedAt: claimSupport?.claim_support_observed_at,
|
|
1408
|
-
supportMode: claimSupport?.claim_support_mode
|
|
1409
|
-
});
|
|
1410
|
-
} catch {
|
|
1411
|
-
throw new Error("claimKey must use canonical entity/attribute format.");
|
|
1412
|
-
}
|
|
1413
|
-
})();
|
|
694
|
+
const params = parseUpdateToolParams(rawParams, OPENCLAW_PARAM_READER);
|
|
1414
695
|
logToolCall(
|
|
1415
696
|
logger,
|
|
1416
697
|
"agenr_update",
|
|
1417
698
|
ctx,
|
|
1418
|
-
`target=${formatTargetSelector(id, subject)}${importance !== void 0 ? ` importance=${importance}` : ""}${expiry !== void 0 ? ` expiry=${expiry}` : ""}`,
|
|
1419
|
-
sanitizeUpdateToolParams({
|
|
699
|
+
`target=${formatTargetSelector(params.id, params.subject)}${params.importance !== void 0 ? ` importance=${params.importance}` : ""}${params.expiry !== void 0 ? ` expiry=${params.expiry}` : ""}`,
|
|
700
|
+
sanitizeUpdateToolParams({
|
|
701
|
+
id: params.id,
|
|
702
|
+
subject: params.subject,
|
|
703
|
+
importance: params.importance,
|
|
704
|
+
expiry: params.expiry,
|
|
705
|
+
claimKey: params.claimKeyInput,
|
|
706
|
+
validFrom: params.validFrom,
|
|
707
|
+
validTo: params.validTo
|
|
708
|
+
})
|
|
1420
709
|
);
|
|
1421
710
|
const services = await servicesPromise;
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
}
|
|
1430
|
-
const normalizedValidFrom = validFrom !== void 0 ? mergedValidity.value.validFrom : void 0;
|
|
1431
|
-
const normalizedValidTo = validTo !== void 0 ? mergedValidity.value.validTo : void 0;
|
|
1432
|
-
const updated = await services.entries.updateEntry(entry.id, {
|
|
1433
|
-
...importance !== void 0 ? { importance } : {},
|
|
1434
|
-
...expiry !== void 0 ? { expiry } : {},
|
|
1435
|
-
...normalizedClaimKeyUpdate?.updateFields ?? {},
|
|
1436
|
-
...validFrom !== void 0 ? { valid_from: normalizedValidFrom } : {},
|
|
1437
|
-
...validTo !== void 0 ? { valid_to: normalizedValidTo } : {}
|
|
1438
|
-
});
|
|
1439
|
-
if (!updated) {
|
|
1440
|
-
return failedTextResult5(`Entry ${entry.id} is not active, so it could not be updated.`, {
|
|
1441
|
-
status: "failed",
|
|
1442
|
-
entryId: entry.id
|
|
1443
|
-
});
|
|
1444
|
-
}
|
|
1445
|
-
return textResult5(`Updated "${entry.subject}".`, {
|
|
1446
|
-
status: "updated",
|
|
1447
|
-
entryId: entry.id,
|
|
1448
|
-
subject: entry.subject,
|
|
1449
|
-
sessionKey: ctx.sessionKey,
|
|
1450
|
-
...importance !== void 0 ? { importance } : {},
|
|
1451
|
-
...expiry !== void 0 ? { expiry } : {},
|
|
1452
|
-
...normalizedClaimKeyUpdate !== void 0 ? { claimKey: normalizedClaimKeyUpdate.claimKey } : {},
|
|
1453
|
-
...validFrom !== void 0 ? { validFrom: normalizedValidFrom } : {},
|
|
1454
|
-
...validTo !== void 0 ? { validTo: normalizedValidTo } : {}
|
|
1455
|
-
});
|
|
711
|
+
return toOpenClawToolResult(
|
|
712
|
+
await runUpdateMemoryTool(params, services, {
|
|
713
|
+
session: ctx,
|
|
714
|
+
sourcePrefix: "openclaw-session",
|
|
715
|
+
successDetails: { sessionKey: ctx.sessionKey }
|
|
716
|
+
})
|
|
717
|
+
);
|
|
1456
718
|
} catch (error) {
|
|
1457
719
|
logToolFailure(logger, "agenr_update", ctx, error);
|
|
1458
720
|
return toolFailureResult(error);
|
|
@@ -1474,7 +736,7 @@ function registerAgenrOpenClawTools(api, servicesPromise, logger) {
|
|
|
1474
736
|
var openclaw_plugin_default = {
|
|
1475
737
|
id: "agenr",
|
|
1476
738
|
name: "agenr",
|
|
1477
|
-
version: "
|
|
739
|
+
version: "3.0.0",
|
|
1478
740
|
description: "agenr memory plugin for OpenClaw",
|
|
1479
741
|
kind: "memory",
|
|
1480
742
|
contracts: {
|
|
@@ -1603,6 +865,14 @@ var openclaw_plugin_default = {
|
|
|
1603
865
|
additionalProperties: false,
|
|
1604
866
|
description: "Optional session-start overrides for prompt-time memory injection behavior.",
|
|
1605
867
|
properties: {
|
|
868
|
+
enabled: {
|
|
869
|
+
type: "boolean",
|
|
870
|
+
description: "Enable or disable all session-start memory injection. Defaults to true."
|
|
871
|
+
},
|
|
872
|
+
coreMemory: {
|
|
873
|
+
type: "boolean",
|
|
874
|
+
description: "Enable or disable always-on Core Memory injection at session start. Defaults to true."
|
|
875
|
+
},
|
|
1606
876
|
relevantDurableMemory: {
|
|
1607
877
|
type: "boolean",
|
|
1608
878
|
description: "Enable or disable artifact-grounded Relevant Durable Memory injection at session start. Defaults to true."
|
|
@@ -1722,7 +992,7 @@ function normalizeAgenrOpenClawPluginConfig(value) {
|
|
|
1722
992
|
if (!storeNudgeResult.ok) {
|
|
1723
993
|
errors.push(...storeNudgeResult.errors);
|
|
1724
994
|
}
|
|
1725
|
-
const memoryPolicyResult =
|
|
995
|
+
const memoryPolicyResult = normalizePluginInjectionMemoryPolicyConfig(value.memoryPolicy);
|
|
1726
996
|
if (!memoryPolicyResult.ok) {
|
|
1727
997
|
errors.push(...memoryPolicyResult.errors);
|
|
1728
998
|
}
|
|
@@ -1882,189 +1152,6 @@ function normalizeStoreNudgeConfig(value) {
|
|
|
1882
1152
|
value: Object.keys(normalizedValue).length > 0 ? resolveStoreNudgeConfig(normalizedValue) : void 0
|
|
1883
1153
|
};
|
|
1884
1154
|
}
|
|
1885
|
-
function normalizeMemoryPolicyConfig(value) {
|
|
1886
|
-
if (value === void 0) {
|
|
1887
|
-
return { ok: true, value: void 0 };
|
|
1888
|
-
}
|
|
1889
|
-
if (!isRecord(value)) {
|
|
1890
|
-
return { ok: false, errors: ["memoryPolicy must be an object when provided"] };
|
|
1891
|
-
}
|
|
1892
|
-
const errors = [];
|
|
1893
|
-
const slotPoliciesResult = normalizeClaimSlotPolicyConfig(value.slotPolicies);
|
|
1894
|
-
if (!slotPoliciesResult.ok) {
|
|
1895
|
-
errors.push(...slotPoliciesResult.errors);
|
|
1896
|
-
}
|
|
1897
|
-
const sessionStartResult = normalizeSessionStartMemoryPolicyConfig(value.sessionStart);
|
|
1898
|
-
if (!sessionStartResult.ok) {
|
|
1899
|
-
errors.push(...sessionStartResult.errors);
|
|
1900
|
-
}
|
|
1901
|
-
const beforeTurnResult = normalizeBeforeTurnMemoryPolicyConfig(value.beforeTurn);
|
|
1902
|
-
if (!beforeTurnResult.ok) {
|
|
1903
|
-
errors.push(...beforeTurnResult.errors);
|
|
1904
|
-
}
|
|
1905
|
-
const allowedKeys = /* @__PURE__ */ new Set(["slotPolicies", "sessionStart", "beforeTurn"]);
|
|
1906
|
-
for (const key of Object.keys(value)) {
|
|
1907
|
-
if (!allowedKeys.has(key)) {
|
|
1908
|
-
errors.push(`unknown config field: memoryPolicy.${key}`);
|
|
1909
|
-
}
|
|
1910
|
-
}
|
|
1911
|
-
if (errors.length > 0) {
|
|
1912
|
-
return { ok: false, errors };
|
|
1913
|
-
}
|
|
1914
|
-
return {
|
|
1915
|
-
ok: true,
|
|
1916
|
-
value: slotPoliciesResult.ok && slotPoliciesResult.value || sessionStartResult.ok && sessionStartResult.value || beforeTurnResult.ok && beforeTurnResult.value ? {
|
|
1917
|
-
...slotPoliciesResult.ok && slotPoliciesResult.value ? { slotPolicies: slotPoliciesResult.value } : {},
|
|
1918
|
-
...sessionStartResult.ok && sessionStartResult.value ? { sessionStart: sessionStartResult.value } : {},
|
|
1919
|
-
...beforeTurnResult.ok && beforeTurnResult.value ? { beforeTurn: beforeTurnResult.value } : {}
|
|
1920
|
-
} : void 0
|
|
1921
|
-
};
|
|
1922
|
-
}
|
|
1923
|
-
function normalizeSessionStartMemoryPolicyConfig(value) {
|
|
1924
|
-
if (value === void 0) {
|
|
1925
|
-
return { ok: true, value: void 0 };
|
|
1926
|
-
}
|
|
1927
|
-
if (!isRecord(value)) {
|
|
1928
|
-
return { ok: false, errors: ["memoryPolicy.sessionStart must be an object when provided"] };
|
|
1929
|
-
}
|
|
1930
|
-
const errors = [];
|
|
1931
|
-
const relevantDurableMemory = normalizeOptionalBoolean(value.relevantDurableMemory, "memoryPolicy.sessionStart.relevantDurableMemory", errors);
|
|
1932
|
-
const allowedKeys = /* @__PURE__ */ new Set(["relevantDurableMemory"]);
|
|
1933
|
-
for (const key of Object.keys(value)) {
|
|
1934
|
-
if (!allowedKeys.has(key)) {
|
|
1935
|
-
errors.push(`unknown config field: memoryPolicy.sessionStart.${key}`);
|
|
1936
|
-
}
|
|
1937
|
-
}
|
|
1938
|
-
if (errors.length > 0) {
|
|
1939
|
-
return { ok: false, errors };
|
|
1940
|
-
}
|
|
1941
|
-
return {
|
|
1942
|
-
ok: true,
|
|
1943
|
-
value: relevantDurableMemory !== void 0 ? { relevantDurableMemory } : void 0
|
|
1944
|
-
};
|
|
1945
|
-
}
|
|
1946
|
-
function normalizeBeforeTurnMemoryPolicyConfig(value) {
|
|
1947
|
-
if (value === void 0) {
|
|
1948
|
-
return { ok: true, value: void 0 };
|
|
1949
|
-
}
|
|
1950
|
-
if (!isRecord(value)) {
|
|
1951
|
-
return { ok: false, errors: ["memoryPolicy.beforeTurn must be an object when provided"] };
|
|
1952
|
-
}
|
|
1953
|
-
const errors = [];
|
|
1954
|
-
const enabled = normalizeOptionalBoolean(value.enabled, "memoryPolicy.beforeTurn.enabled", errors);
|
|
1955
|
-
const procedureSuggestion = normalizeOptionalBoolean(value.procedureSuggestion, "memoryPolicy.beforeTurn.procedureSuggestion", errors);
|
|
1956
|
-
const maxDurableEntries = normalizeOptionalPositiveInteger(value.maxDurableEntries, "memoryPolicy.beforeTurn.maxDurableEntries", errors);
|
|
1957
|
-
const recallThreshold = normalizeOptionalUnitInterval(value.recallThreshold, "memoryPolicy.beforeTurn.recallThreshold", errors);
|
|
1958
|
-
const highConfidenceRecallThreshold = normalizeOptionalUnitInterval(
|
|
1959
|
-
value.highConfidenceRecallThreshold,
|
|
1960
|
-
"memoryPolicy.beforeTurn.highConfidenceRecallThreshold",
|
|
1961
|
-
errors
|
|
1962
|
-
);
|
|
1963
|
-
const procedureThreshold = normalizeOptionalUnitInterval(value.procedureThreshold, "memoryPolicy.beforeTurn.procedureThreshold", errors);
|
|
1964
|
-
const allowedKeys = /* @__PURE__ */ new Set([
|
|
1965
|
-
"enabled",
|
|
1966
|
-
"procedureSuggestion",
|
|
1967
|
-
"maxDurableEntries",
|
|
1968
|
-
"recallThreshold",
|
|
1969
|
-
"highConfidenceRecallThreshold",
|
|
1970
|
-
"procedureThreshold"
|
|
1971
|
-
]);
|
|
1972
|
-
for (const key of Object.keys(value)) {
|
|
1973
|
-
if (!allowedKeys.has(key)) {
|
|
1974
|
-
errors.push(`unknown config field: memoryPolicy.beforeTurn.${key}`);
|
|
1975
|
-
}
|
|
1976
|
-
}
|
|
1977
|
-
if (errors.length > 0) {
|
|
1978
|
-
return { ok: false, errors };
|
|
1979
|
-
}
|
|
1980
|
-
return {
|
|
1981
|
-
ok: true,
|
|
1982
|
-
value: enabled !== void 0 || procedureSuggestion !== void 0 || maxDurableEntries !== void 0 || recallThreshold !== void 0 || highConfidenceRecallThreshold !== void 0 || procedureThreshold !== void 0 ? {
|
|
1983
|
-
...enabled !== void 0 ? { enabled } : {},
|
|
1984
|
-
...procedureSuggestion !== void 0 ? { procedureSuggestion } : {},
|
|
1985
|
-
...maxDurableEntries !== void 0 ? { maxDurableEntries } : {},
|
|
1986
|
-
...recallThreshold !== void 0 ? { recallThreshold } : {},
|
|
1987
|
-
...highConfidenceRecallThreshold !== void 0 ? { highConfidenceRecallThreshold } : {},
|
|
1988
|
-
...procedureThreshold !== void 0 ? { procedureThreshold } : {}
|
|
1989
|
-
} : void 0
|
|
1990
|
-
};
|
|
1991
|
-
}
|
|
1992
|
-
function normalizeClaimSlotPolicyConfig(value) {
|
|
1993
|
-
if (value === void 0) {
|
|
1994
|
-
return { ok: true, value: void 0 };
|
|
1995
|
-
}
|
|
1996
|
-
if (!isRecord(value)) {
|
|
1997
|
-
return { ok: false, errors: ["memoryPolicy.slotPolicies must be an object when provided"] };
|
|
1998
|
-
}
|
|
1999
|
-
const errors = [];
|
|
2000
|
-
const attributeHeads = normalizeClaimSlotPolicyAttributeHeads(value.attributeHeads, errors);
|
|
2001
|
-
const allowedKeys = /* @__PURE__ */ new Set(["attributeHeads"]);
|
|
2002
|
-
for (const key of Object.keys(value)) {
|
|
2003
|
-
if (!allowedKeys.has(key)) {
|
|
2004
|
-
errors.push(`unknown config field: memoryPolicy.slotPolicies.${key}`);
|
|
2005
|
-
}
|
|
2006
|
-
}
|
|
2007
|
-
if (errors.length > 0) {
|
|
2008
|
-
return { ok: false, errors };
|
|
2009
|
-
}
|
|
2010
|
-
return {
|
|
2011
|
-
ok: true,
|
|
2012
|
-
value: attributeHeads ? { attributeHeads } : void 0
|
|
2013
|
-
};
|
|
2014
|
-
}
|
|
2015
|
-
function normalizeClaimSlotPolicyAttributeHeads(value, errors) {
|
|
2016
|
-
if (value === void 0) {
|
|
2017
|
-
return void 0;
|
|
2018
|
-
}
|
|
2019
|
-
if (!isRecord(value)) {
|
|
2020
|
-
errors.push("memoryPolicy.slotPolicies.attributeHeads must be an object when provided");
|
|
2021
|
-
return void 0;
|
|
2022
|
-
}
|
|
2023
|
-
const normalized = {};
|
|
2024
|
-
for (const [rawKey, rawPolicy] of Object.entries(value)) {
|
|
2025
|
-
const attributeHead = rawKey.trim().toLowerCase();
|
|
2026
|
-
if (!/^[a-z0-9][a-z0-9_-]*$/.test(attributeHead)) {
|
|
2027
|
-
errors.push(`memoryPolicy.slotPolicies.attributeHeads.${rawKey} must use a canonical attribute-head label`);
|
|
2028
|
-
continue;
|
|
2029
|
-
}
|
|
2030
|
-
if (rawPolicy !== "exclusive" && rawPolicy !== "multivalued") {
|
|
2031
|
-
errors.push(`memoryPolicy.slotPolicies.attributeHeads.${attributeHead} must be "exclusive" or "multivalued"`);
|
|
2032
|
-
continue;
|
|
2033
|
-
}
|
|
2034
|
-
normalized[attributeHead] = rawPolicy;
|
|
2035
|
-
}
|
|
2036
|
-
return Object.keys(normalized).length > 0 ? normalized : void 0;
|
|
2037
|
-
}
|
|
2038
|
-
function normalizeOptionalBoolean(value, label, errors) {
|
|
2039
|
-
if (value === void 0) {
|
|
2040
|
-
return void 0;
|
|
2041
|
-
}
|
|
2042
|
-
if (typeof value !== "boolean") {
|
|
2043
|
-
errors.push(`${label} must be a boolean when provided`);
|
|
2044
|
-
return void 0;
|
|
2045
|
-
}
|
|
2046
|
-
return value;
|
|
2047
|
-
}
|
|
2048
|
-
function normalizeOptionalPositiveInteger(value, label, errors) {
|
|
2049
|
-
if (value === void 0) {
|
|
2050
|
-
return void 0;
|
|
2051
|
-
}
|
|
2052
|
-
if (typeof value !== "number" || !Number.isFinite(value) || !Number.isInteger(value) || value <= 0) {
|
|
2053
|
-
errors.push(`${label} must be a positive integer when provided`);
|
|
2054
|
-
return void 0;
|
|
2055
|
-
}
|
|
2056
|
-
return value;
|
|
2057
|
-
}
|
|
2058
|
-
function normalizeOptionalUnitInterval(value, label, errors) {
|
|
2059
|
-
if (value === void 0) {
|
|
2060
|
-
return void 0;
|
|
2061
|
-
}
|
|
2062
|
-
if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > 1) {
|
|
2063
|
-
errors.push(`${label} must be a number between 0 and 1 when provided`);
|
|
2064
|
-
return void 0;
|
|
2065
|
-
}
|
|
2066
|
-
return value;
|
|
2067
|
-
}
|
|
2068
1155
|
|
|
2069
1156
|
// src/adapters/openclaw/format/prompt-section.ts
|
|
2070
1157
|
var MEMORY_TOOL_NAMES = {
|
|
@@ -2163,59 +1250,7 @@ function formatErrorMessage2(error) {
|
|
|
2163
1250
|
return error instanceof Error ? error.message : String(error);
|
|
2164
1251
|
}
|
|
2165
1252
|
|
|
2166
|
-
// src/adapters/openclaw/session/identity.ts
|
|
2167
|
-
function resolveSessionIdentityKey(sessionId, sessionKey) {
|
|
2168
|
-
const normalizedSessionId = sessionId?.trim();
|
|
2169
|
-
if (normalizedSessionId) {
|
|
2170
|
-
return `session:${normalizedSessionId}`;
|
|
2171
|
-
}
|
|
2172
|
-
const normalizedSessionKey = sessionKey?.trim();
|
|
2173
|
-
if (normalizedSessionKey) {
|
|
2174
|
-
return `key:${normalizedSessionKey}`;
|
|
2175
|
-
}
|
|
2176
|
-
return void 0;
|
|
2177
|
-
}
|
|
2178
|
-
|
|
2179
1253
|
// src/adapters/openclaw/session/state.ts
|
|
2180
|
-
function createSessionStartTracker() {
|
|
2181
|
-
const seenSessionIdentities = /* @__PURE__ */ new Set();
|
|
2182
|
-
const resumedFromBySessionId = /* @__PURE__ */ new Map();
|
|
2183
|
-
return {
|
|
2184
|
-
consume(sessionId, sessionKey) {
|
|
2185
|
-
const identityKey = resolveSessionIdentityKey(sessionId, sessionKey);
|
|
2186
|
-
if (!identityKey) {
|
|
2187
|
-
return {
|
|
2188
|
-
isFirst: true,
|
|
2189
|
-
activeCount: seenSessionIdentities.size
|
|
2190
|
-
};
|
|
2191
|
-
}
|
|
2192
|
-
if (seenSessionIdentities.has(identityKey)) {
|
|
2193
|
-
return {
|
|
2194
|
-
isFirst: false,
|
|
2195
|
-
activeCount: seenSessionIdentities.size
|
|
2196
|
-
};
|
|
2197
|
-
}
|
|
2198
|
-
seenSessionIdentities.add(identityKey);
|
|
2199
|
-
return {
|
|
2200
|
-
isFirst: true,
|
|
2201
|
-
activeCount: seenSessionIdentities.size
|
|
2202
|
-
};
|
|
2203
|
-
},
|
|
2204
|
-
rememberSessionStart(sessionId, _sessionKey, resumedFrom) {
|
|
2205
|
-
const normalizedSessionId = sessionId?.trim();
|
|
2206
|
-
const normalizedResumedFrom = resumedFrom?.trim();
|
|
2207
|
-
if (!normalizedSessionId || !normalizedResumedFrom) {
|
|
2208
|
-
return;
|
|
2209
|
-
}
|
|
2210
|
-
resumedFromBySessionId.set(normalizedSessionId, normalizedResumedFrom);
|
|
2211
|
-
},
|
|
2212
|
-
getResumedFrom(sessionId) {
|
|
2213
|
-
const normalizedSessionId = sessionId?.trim();
|
|
2214
|
-
return normalizedSessionId ? resumedFromBySessionId.get(normalizedSessionId) : void 0;
|
|
2215
|
-
}
|
|
2216
|
-
};
|
|
2217
|
-
}
|
|
2218
|
-
var MAX_STORED_SUBJECTS = 5;
|
|
2219
1254
|
function createMidSessionTracker() {
|
|
2220
1255
|
const states = /* @__PURE__ */ new Map();
|
|
2221
1256
|
return {
|
|
@@ -2278,6 +1313,7 @@ function createMidSessionState() {
|
|
|
2278
1313
|
storedSubjects: []
|
|
2279
1314
|
};
|
|
2280
1315
|
}
|
|
1316
|
+
var MAX_STORED_SUBJECTS = 5;
|
|
2281
1317
|
|
|
2282
1318
|
// src/adapters/openclaw/hooks/after-tool-call.ts
|
|
2283
1319
|
var STORE_TOOL_NAME = "agenr_store";
|
|
@@ -2356,270 +1392,13 @@ function hasNonEmptyString(value) {
|
|
|
2356
1392
|
|
|
2357
1393
|
// src/adapters/openclaw/hooks/before-prompt-build.ts
|
|
2358
1394
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
2359
|
-
|
|
2360
|
-
// src/app/session-start/service.ts
|
|
2361
|
-
var DEFAULT_MAX_CORE_ENTRIES = 4;
|
|
2362
|
-
var DEFAULT_MAX_ARTIFACT_RECALL_ENTRIES = 3;
|
|
2363
|
-
var DEFAULT_MAX_DURABLE_ENTRIES = 5;
|
|
2364
|
-
var DEFAULT_MAX_ARTIFACT_CHARS = 1200;
|
|
2365
|
-
async function runSessionStart(input, deps) {
|
|
2366
|
-
const policy = normalizePolicy(input.policy);
|
|
2367
|
-
const contextSections = buildContextSections(input);
|
|
2368
|
-
const coreEntries = await deps.repository.listCoreEntries(policy.maxCoreEntries);
|
|
2369
|
-
const coreItems = coreEntries.map((entry) => buildCorePatchItem(entry));
|
|
2370
|
-
const diagnostics = {
|
|
2371
|
-
coreCandidateCount: coreEntries.length,
|
|
2372
|
-
artifactRecallCandidateCount: 0,
|
|
2373
|
-
artifactRecallUsed: false,
|
|
2374
|
-
notices: []
|
|
2375
|
-
};
|
|
2376
|
-
const artifactRecallQuery = policy.enableArtifactRecall ? buildArtifactRecallQuery(contextSections, policy.maxArtifactChars) : void 0;
|
|
2377
|
-
if (!policy.enableArtifactRecall) {
|
|
2378
|
-
diagnostics.notices.push("Artifact-grounded durable recall disabled by session-start policy.");
|
|
2379
|
-
}
|
|
2380
|
-
const artifactRecallItems = artifactRecallQuery ? await runArtifactRecallSelection(artifactRecallQuery, input.sessionKey, policy, deps, diagnostics) : [];
|
|
2381
|
-
const durableMemory = assignRanks(mergeDurableMemory(coreItems, artifactRecallItems, policy.maxDurableEntries));
|
|
2382
|
-
return {
|
|
2383
|
-
contextSections,
|
|
2384
|
-
durableMemory,
|
|
2385
|
-
diagnostics
|
|
2386
|
-
};
|
|
2387
|
-
}
|
|
2388
|
-
function buildContextSections(input) {
|
|
2389
|
-
const sections = [];
|
|
2390
|
-
const continuitySummaryText = normalizeOptionalString(input.continuitySummaryText);
|
|
2391
|
-
if (continuitySummaryText) {
|
|
2392
|
-
sections.push({
|
|
2393
|
-
kind: "continuity_summary",
|
|
2394
|
-
title: "Previous session summary",
|
|
2395
|
-
content: continuitySummaryText
|
|
2396
|
-
});
|
|
2397
|
-
}
|
|
2398
|
-
const recentSessionText = normalizeOptionalString(input.recentSessionText);
|
|
2399
|
-
if (recentSessionText) {
|
|
2400
|
-
sections.push({
|
|
2401
|
-
kind: "recent_session",
|
|
2402
|
-
title: "Recent session",
|
|
2403
|
-
content: recentSessionText
|
|
2404
|
-
});
|
|
2405
|
-
}
|
|
2406
|
-
return sections;
|
|
2407
|
-
}
|
|
2408
|
-
async function runArtifactRecallSelection(query, sessionKey, policy, deps, diagnostics) {
|
|
2409
|
-
diagnostics.artifactRecallUsed = true;
|
|
2410
|
-
diagnostics.artifactRecallQuery = query;
|
|
2411
|
-
let artifactRecallTrace;
|
|
2412
|
-
try {
|
|
2413
|
-
const recalled = await recall(
|
|
2414
|
-
{
|
|
2415
|
-
text: query,
|
|
2416
|
-
limit: policy.maxArtifactRecallEntries,
|
|
2417
|
-
threshold: policy.recallThreshold,
|
|
2418
|
-
sessionKey
|
|
2419
|
-
},
|
|
2420
|
-
deps.recall,
|
|
2421
|
-
{
|
|
2422
|
-
trace: {
|
|
2423
|
-
reportSummary(summary) {
|
|
2424
|
-
artifactRecallTrace = summary;
|
|
2425
|
-
}
|
|
2426
|
-
},
|
|
2427
|
-
slotPolicyConfig: deps.slotPolicyConfig
|
|
2428
|
-
}
|
|
2429
|
-
);
|
|
2430
|
-
diagnostics.artifactRecallTrace = artifactRecallTrace;
|
|
2431
|
-
diagnostics.artifactRecallCandidateCount = recalled.length;
|
|
2432
|
-
if (artifactRecallTrace?.degraded.notices.length) {
|
|
2433
|
-
diagnostics.notices.push(...artifactRecallTrace.degraded.notices);
|
|
2434
|
-
}
|
|
2435
|
-
return recalled.map((item) => buildArtifactRecallPatchItem(item, deps));
|
|
2436
|
-
} catch (error) {
|
|
2437
|
-
diagnostics.artifactRecallTrace = artifactRecallTrace;
|
|
2438
|
-
diagnostics.notices.push(`Artifact-grounded durable recall failed: ${formatErrorMessage3(error)}`);
|
|
2439
|
-
return [];
|
|
2440
|
-
}
|
|
2441
|
-
}
|
|
2442
|
-
function buildCorePatchItem(entry) {
|
|
2443
|
-
return {
|
|
2444
|
-
rank: 0,
|
|
2445
|
-
entry,
|
|
2446
|
-
sourceKind: "core",
|
|
2447
|
-
whySurfaced: {
|
|
2448
|
-
summary: `always-on core memory; importance ${entry.importance}`,
|
|
2449
|
-
reasons: ["always-on core memory", `importance ${entry.importance}`, `expiry ${entry.expiry}`]
|
|
2450
|
-
},
|
|
2451
|
-
memoryState: resolveMemoryState(entry),
|
|
2452
|
-
claimStatus: resolveClaimStatus(entry),
|
|
2453
|
-
freshnessLabel: buildFreshnessLabel(entry),
|
|
2454
|
-
...buildProvenanceSummary(entry) ? { provenanceSummary: buildProvenanceSummary(entry) } : {}
|
|
2455
|
-
};
|
|
2456
|
-
}
|
|
2457
|
-
function buildArtifactRecallPatchItem(recalled, deps) {
|
|
2458
|
-
const projected = projectClaimCentricRecallEntry(recalled, {
|
|
2459
|
-
slotPolicyConfig: deps.slotPolicyConfig
|
|
2460
|
-
});
|
|
2461
|
-
return {
|
|
2462
|
-
rank: 0,
|
|
2463
|
-
entry: recalled.entry,
|
|
2464
|
-
sourceKind: "artifact_recall",
|
|
2465
|
-
score: recalled.score,
|
|
2466
|
-
whySurfaced: projected.whySurfaced,
|
|
2467
|
-
memoryState: projected.memoryState,
|
|
2468
|
-
claimStatus: projected.claimStatus,
|
|
2469
|
-
freshnessLabel: projected.freshness.label,
|
|
2470
|
-
...formatProjectedProvenance(projected.provenance) ? { provenanceSummary: formatProjectedProvenance(projected.provenance) } : {}
|
|
2471
|
-
};
|
|
2472
|
-
}
|
|
2473
|
-
function buildArtifactRecallQuery(sections, maxChars) {
|
|
2474
|
-
if (sections.length === 0 || maxChars <= 0) {
|
|
2475
|
-
return void 0;
|
|
2476
|
-
}
|
|
2477
|
-
let remaining = maxChars;
|
|
2478
|
-
const parts = [];
|
|
2479
|
-
for (const section of sections) {
|
|
2480
|
-
if (remaining <= 0) {
|
|
2481
|
-
break;
|
|
2482
|
-
}
|
|
2483
|
-
const normalizedContent = normalizeWhitespace(section.content);
|
|
2484
|
-
if (normalizedContent.length === 0) {
|
|
2485
|
-
continue;
|
|
2486
|
-
}
|
|
2487
|
-
const labeled = `${section.title}: ${normalizedContent}`;
|
|
2488
|
-
const truncated = truncate2(labeled, remaining);
|
|
2489
|
-
if (truncated.length === 0) {
|
|
2490
|
-
continue;
|
|
2491
|
-
}
|
|
2492
|
-
parts.push(truncated);
|
|
2493
|
-
remaining -= truncated.length;
|
|
2494
|
-
}
|
|
2495
|
-
const query = normalizeWhitespace(parts.join("\n"));
|
|
2496
|
-
return query.length > 0 ? query : void 0;
|
|
2497
|
-
}
|
|
2498
|
-
function mergeDurableMemory(coreItems, artifactRecallItems, maxDurableEntries) {
|
|
2499
|
-
const merged = [];
|
|
2500
|
-
const seenEntryIds = /* @__PURE__ */ new Set();
|
|
2501
|
-
for (const item of [...coreItems, ...artifactRecallItems]) {
|
|
2502
|
-
if (seenEntryIds.has(item.entry.id)) {
|
|
2503
|
-
continue;
|
|
2504
|
-
}
|
|
2505
|
-
seenEntryIds.add(item.entry.id);
|
|
2506
|
-
merged.push(item);
|
|
2507
|
-
if (merged.length >= maxDurableEntries) {
|
|
2508
|
-
break;
|
|
2509
|
-
}
|
|
2510
|
-
}
|
|
2511
|
-
return merged;
|
|
2512
|
-
}
|
|
2513
|
-
function assignRanks(items) {
|
|
2514
|
-
return items.map((item, index) => ({
|
|
2515
|
-
...item,
|
|
2516
|
-
rank: index + 1
|
|
2517
|
-
}));
|
|
2518
|
-
}
|
|
2519
|
-
function normalizePolicy(policy) {
|
|
2520
|
-
const maxCoreEntries = normalizeCount(policy?.maxCoreEntries, DEFAULT_MAX_CORE_ENTRIES);
|
|
2521
|
-
const maxArtifactRecallEntries = normalizeCount(policy?.maxArtifactRecallEntries, DEFAULT_MAX_ARTIFACT_RECALL_ENTRIES);
|
|
2522
|
-
const maxDurableEntries = Math.max(maxCoreEntries, normalizeCount(policy?.maxDurableEntries, DEFAULT_MAX_DURABLE_ENTRIES));
|
|
2523
|
-
return {
|
|
2524
|
-
maxCoreEntries,
|
|
2525
|
-
enableArtifactRecall: policy?.enableArtifactRecall !== false,
|
|
2526
|
-
maxArtifactRecallEntries,
|
|
2527
|
-
maxDurableEntries,
|
|
2528
|
-
maxArtifactChars: normalizeCount(policy?.maxArtifactChars, DEFAULT_MAX_ARTIFACT_CHARS),
|
|
2529
|
-
recallThreshold: normalizeThreshold(policy?.recallThreshold)
|
|
2530
|
-
};
|
|
2531
|
-
}
|
|
2532
|
-
function normalizeCount(value, fallback) {
|
|
2533
|
-
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
2534
|
-
return fallback;
|
|
2535
|
-
}
|
|
2536
|
-
return Math.max(0, Math.trunc(value));
|
|
2537
|
-
}
|
|
2538
|
-
function normalizeThreshold(value) {
|
|
2539
|
-
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
2540
|
-
return 0;
|
|
2541
|
-
}
|
|
2542
|
-
return Math.min(1, Math.max(0, value));
|
|
2543
|
-
}
|
|
2544
|
-
function resolveMemoryState(entry) {
|
|
2545
|
-
if (entry.superseded_by) {
|
|
2546
|
-
return "superseded";
|
|
2547
|
-
}
|
|
2548
|
-
if (entry.retired || entry.valid_to) {
|
|
2549
|
-
return "historical";
|
|
2550
|
-
}
|
|
2551
|
-
return "current";
|
|
2552
|
-
}
|
|
2553
|
-
function resolveClaimStatus(entry) {
|
|
2554
|
-
if (!normalizeOptionalString(entry.claim_key)) {
|
|
2555
|
-
return "no_key";
|
|
2556
|
-
}
|
|
2557
|
-
return entry.claim_key_status ?? "legacy";
|
|
2558
|
-
}
|
|
2559
|
-
function buildFreshnessLabel(entry) {
|
|
2560
|
-
const parts = [`created ${entry.created_at}`];
|
|
2561
|
-
const validFrom = normalizeOptionalString(entry.valid_from);
|
|
2562
|
-
const validTo = normalizeOptionalString(entry.valid_to);
|
|
2563
|
-
if (validFrom || validTo) {
|
|
2564
|
-
parts.push(`valid ${validFrom ?? "?"} -> ${validTo ?? "ongoing"}`);
|
|
2565
|
-
}
|
|
2566
|
-
return parts.join(" | ");
|
|
2567
|
-
}
|
|
2568
|
-
function buildProvenanceSummary(entry) {
|
|
2569
|
-
const parts = [
|
|
2570
|
-
entry.superseded_by ? `superseded_by=${entry.superseded_by}` : void 0,
|
|
2571
|
-
entry.supersession_kind ? `kind=${entry.supersession_kind}` : void 0,
|
|
2572
|
-
entry.supersession_reason ? `reason=${entry.supersession_reason}` : void 0,
|
|
2573
|
-
entry.claim_support_source_kind ? `support=${entry.claim_support_source_kind}` : void 0,
|
|
2574
|
-
entry.claim_support_mode ? `support_mode=${entry.claim_support_mode}` : void 0,
|
|
2575
|
-
entry.claim_support_observed_at ? `observed=${entry.claim_support_observed_at}` : void 0,
|
|
2576
|
-
entry.claim_support_locator ? `locator=${entry.claim_support_locator}` : void 0
|
|
2577
|
-
].filter((value) => value !== void 0);
|
|
2578
|
-
return parts.length > 0 ? parts.join(" | ") : void 0;
|
|
2579
|
-
}
|
|
2580
|
-
function formatProjectedProvenance(provenance) {
|
|
2581
|
-
const parts = [
|
|
2582
|
-
provenance.supersededById ? `superseded_by=${provenance.supersededById}` : void 0,
|
|
2583
|
-
provenance.supersessionKind ? `kind=${provenance.supersessionKind}` : void 0,
|
|
2584
|
-
provenance.supersessionReason ? `reason=${provenance.supersessionReason}` : void 0,
|
|
2585
|
-
provenance.supportSourceKind ? `support=${provenance.supportSourceKind}` : void 0,
|
|
2586
|
-
provenance.supportMode ? `support_mode=${provenance.supportMode}` : void 0,
|
|
2587
|
-
provenance.supportObservedAt ? `observed=${provenance.supportObservedAt}` : void 0,
|
|
2588
|
-
provenance.supportLocator ? `locator=${provenance.supportLocator}` : void 0
|
|
2589
|
-
].filter((value) => value !== void 0);
|
|
2590
|
-
return parts.length > 0 ? parts.join(" | ") : void 0;
|
|
2591
|
-
}
|
|
2592
|
-
function normalizeOptionalString(value) {
|
|
2593
|
-
const normalized = value?.trim();
|
|
2594
|
-
return normalized && normalized.length > 0 ? normalized : void 0;
|
|
2595
|
-
}
|
|
2596
|
-
function normalizeWhitespace(value) {
|
|
2597
|
-
return value.replace(/\s+/g, " ").trim();
|
|
2598
|
-
}
|
|
2599
|
-
function truncate2(value, maxChars) {
|
|
2600
|
-
if (maxChars <= 0) {
|
|
2601
|
-
return "";
|
|
2602
|
-
}
|
|
2603
|
-
if (value.length <= maxChars) {
|
|
2604
|
-
return value;
|
|
2605
|
-
}
|
|
2606
|
-
return `${value.slice(0, Math.max(0, maxChars - 3)).trimEnd()}...`;
|
|
2607
|
-
}
|
|
2608
|
-
function formatErrorMessage3(error) {
|
|
2609
|
-
if (error instanceof Error) {
|
|
2610
|
-
return error.message;
|
|
2611
|
-
}
|
|
2612
|
-
return String(error);
|
|
2613
|
-
}
|
|
2614
|
-
|
|
2615
|
-
// src/adapters/openclaw/hooks/before-prompt-build.ts
|
|
2616
1395
|
import path5 from "path";
|
|
2617
1396
|
|
|
2618
1397
|
// src/adapters/openclaw/episode/episode-writer.ts
|
|
2619
1398
|
import { resolveAgentEffectiveModelPrimary as resolveAgentEffectiveModelPrimary2, resolveDefaultAgentId as resolveDefaultAgentId2 } from "openclaw/plugin-sdk/agent-runtime";
|
|
2620
1399
|
|
|
2621
1400
|
// src/adapters/openclaw/llm/openclaw-llm-client.ts
|
|
2622
|
-
import { completeSimple, getModel } from "@
|
|
1401
|
+
import { completeSimple, getModel } from "@earendil-works/pi-ai";
|
|
2623
1402
|
|
|
2624
1403
|
// src/adapters/openclaw/embedded-agent/task-runner.ts
|
|
2625
1404
|
import * as fs from "fs/promises";
|
|
@@ -2667,7 +1446,7 @@ async function createOpenClawLlmClient(openClaw, modelRef, label = "model overri
|
|
|
2667
1446
|
provider: execution.provider,
|
|
2668
1447
|
cfg: openClaw.config
|
|
2669
1448
|
});
|
|
2670
|
-
const apiKey =
|
|
1449
|
+
const apiKey = normalizeOptionalString(auth.apiKey);
|
|
2671
1450
|
if (!apiKey) {
|
|
2672
1451
|
throw new Error(`OpenClaw auth did not resolve an API-key-compatible credential for ${execution.provider} (source=${auth.source}, mode=${auth.mode}).`);
|
|
2673
1452
|
}
|
|
@@ -2712,7 +1491,7 @@ function stripCodeFence(text) {
|
|
|
2712
1491
|
const match = /^```(?:json)?\s*([\s\S]+?)\s*```$/iu.exec(trimmed);
|
|
2713
1492
|
return match?.[1]?.trim() ?? trimmed;
|
|
2714
1493
|
}
|
|
2715
|
-
function
|
|
1494
|
+
function normalizeOptionalString(value) {
|
|
2716
1495
|
const normalized = value?.trim();
|
|
2717
1496
|
return normalized ? normalized : void 0;
|
|
2718
1497
|
}
|
|
@@ -2721,19 +1500,6 @@ function normalizeOptionalString2(value) {
|
|
|
2721
1500
|
var OPENCLAW_EPISODE_GENERATOR_VERSION = "openclaw-episodic-summary-v1";
|
|
2722
1501
|
|
|
2723
1502
|
// src/adapters/openclaw/episode/episode-writer.ts
|
|
2724
|
-
var EPISODE_SUMMARY_TIMEOUT_MS = 45e3;
|
|
2725
|
-
var EPISODE_SUMMARY_TIMEOUT_ERROR_MESSAGE = "Episode summary generation timed out.";
|
|
2726
|
-
var EPISODE_EMBEDDING_TIMEOUT = /* @__PURE__ */ Symbol("episode-embedding-timeout");
|
|
2727
|
-
var EPISODE_EMBEDDING_MIN_HEADROOM_MS = 5e3;
|
|
2728
|
-
var OpenClawEpisodeSummaryTimeoutError = class extends Error {
|
|
2729
|
-
/**
|
|
2730
|
-
* Creates a timeout error with a stable name for caller-side handling.
|
|
2731
|
-
*/
|
|
2732
|
-
constructor() {
|
|
2733
|
-
super(EPISODE_SUMMARY_TIMEOUT_ERROR_MESSAGE);
|
|
2734
|
-
this.name = "OpenClawEpisodeSummaryTimeoutError";
|
|
2735
|
-
}
|
|
2736
|
-
};
|
|
2737
1503
|
async function writeOpenClawPredecessorEpisode(params) {
|
|
2738
1504
|
const sessionContext = formatSessionContext(params.ctx.sessionId, params.ctx.sessionKey);
|
|
2739
1505
|
const writeStartedAtMs = Date.now();
|
|
@@ -2743,78 +1509,70 @@ async function writeOpenClawPredecessorEpisode(params) {
|
|
|
2743
1509
|
}
|
|
2744
1510
|
const predecessor = params.predecessor;
|
|
2745
1511
|
params.logger.info(`[agenr] session-start predecessor episode write triggered for ${sessionContext} predecessor=${predecessor.sessionFile}`);
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
1512
|
+
const episodeModelRef = resolveOpenClawEpisodeModelRef(params.services.openClaw, params.ctx.agentId, params.services.pluginConfig.episodeModel);
|
|
1513
|
+
const episodeModel = episodeModelRef ?? "default";
|
|
1514
|
+
const summaryDeadlineMs = writeStartedAtMs + EPISODE_SUMMARY_TIMEOUT_MS;
|
|
1515
|
+
const llm = await createOpenClawLlmClient(params.services.openClaw, episodeModelRef, "episode model override");
|
|
1516
|
+
const summaryLlm = createDeadlineAwareEpisodeSummaryLlm(
|
|
1517
|
+
{
|
|
1518
|
+
complete: llm.complete.bind(llm),
|
|
1519
|
+
completeJson: llm.completeJson.bind(llm),
|
|
1520
|
+
metadata: {
|
|
1521
|
+
modelRef: episodeModel,
|
|
1522
|
+
pricing: {
|
|
1523
|
+
input: 0,
|
|
1524
|
+
output: 0,
|
|
1525
|
+
cacheRead: 0,
|
|
1526
|
+
cacheWrite: 0
|
|
1527
|
+
},
|
|
1528
|
+
usage: {
|
|
1529
|
+
calls: 0,
|
|
1530
|
+
inputTokens: 0,
|
|
1531
|
+
outputTokens: 0,
|
|
1532
|
+
cacheReadTokens: 0,
|
|
1533
|
+
cacheWriteTokens: 0,
|
|
1534
|
+
totalTokens: 0,
|
|
1535
|
+
totalCost: 0
|
|
1536
|
+
}
|
|
1537
|
+
}
|
|
1538
|
+
},
|
|
1539
|
+
summaryDeadlineMs
|
|
1540
|
+
);
|
|
1541
|
+
await writeBoundedSingleTranscriptEpisode({
|
|
1542
|
+
filePath: predecessor.sessionFile,
|
|
1543
|
+
context: sessionContext,
|
|
1544
|
+
actionLabel: "session-start predecessor episode write",
|
|
1545
|
+
logger: params.logger,
|
|
1546
|
+
summaryDeadlineMs,
|
|
1547
|
+
fileField: "predecessor",
|
|
1548
|
+
shortCountField: "cleanedMessages",
|
|
1549
|
+
failureModelRef: episodeModel,
|
|
1550
|
+
unexpectedFailureLevel: "info",
|
|
1551
|
+
ports: {
|
|
1552
|
+
files: createSingleTranscriptDiscoveryPort(predecessor.sessionFile),
|
|
1553
|
+
transcript: openClawTranscriptParser,
|
|
1554
|
+
episodes: params.services.episodes,
|
|
1555
|
+
createSummaryLlm: () => summaryLlm,
|
|
1556
|
+
embedSummary: (summary) => embedEpisodeSummaryWithinBudget({
|
|
1557
|
+
summary,
|
|
1558
|
+
embedding: params.services.embedding,
|
|
1559
|
+
embeddingAvailable: params.services.embeddingStatus.available,
|
|
1560
|
+
deadlineMs: summaryDeadlineMs,
|
|
1561
|
+
logger: params.logger,
|
|
1562
|
+
logContext: `[agenr] session-start predecessor episode embedding skipped for ${sessionContext} predecessor=${predecessor.sessionFile}`
|
|
2788
1563
|
})
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
}
|
|
2800
|
-
if (ingestResult.session.action === "failed") {
|
|
2801
|
-
logFailedEpisodeIngest(sessionContext, predecessor.sessionFile, ingestResult.session.error, episodeModel, params.logger);
|
|
2802
|
-
return;
|
|
2803
|
-
}
|
|
2804
|
-
params.logger.info(
|
|
2805
|
-
`[agenr] session-start predecessor episode write ${ingestResult.session.action} for ${sessionContext} predecessor=${predecessor.sessionFile} episode=${ingestResult.session.episodeId}`
|
|
2806
|
-
);
|
|
2807
|
-
} catch (error) {
|
|
2808
|
-
if (error instanceof OpenClawEpisodeSummaryTimeoutError) {
|
|
2809
|
-
params.logger.info(
|
|
2810
|
-
`[agenr] session-start predecessor episode write timed_out for ${sessionContext} predecessor=${predecessor.sessionFile} timeoutMs=${EPISODE_SUMMARY_TIMEOUT_MS}`
|
|
2811
|
-
);
|
|
2812
|
-
return;
|
|
1564
|
+
},
|
|
1565
|
+
ingestOptions: {
|
|
1566
|
+
genVersion: OPENCLAW_EPISODE_GENERATOR_VERSION,
|
|
1567
|
+
skipActiveSessionCheck: true,
|
|
1568
|
+
candidateOverrides: {
|
|
1569
|
+
sessionId: predecessor.sessionId,
|
|
1570
|
+
agentId: trimOptionalString(params.ctx.agentId) ?? null,
|
|
1571
|
+
surface: resolveSessionSurface(params.ctx) ?? null,
|
|
1572
|
+
metadataSource: "registry"
|
|
1573
|
+
}
|
|
2813
1574
|
}
|
|
2814
|
-
|
|
2815
|
-
`[agenr] session-start predecessor episode write failed for ${sessionContext} predecessor=${predecessor.sessionFile} reason=${formatErrorMessage2(error)}`
|
|
2816
|
-
);
|
|
2817
|
-
}
|
|
1575
|
+
});
|
|
2818
1576
|
}
|
|
2819
1577
|
function resolveSessionSurface(ctx) {
|
|
2820
1578
|
const sessionKey = ctx.sessionKey?.trim() ?? "";
|
|
@@ -2827,152 +1585,6 @@ function resolveSessionSurface(ctx) {
|
|
|
2827
1585
|
}
|
|
2828
1586
|
return void 0;
|
|
2829
1587
|
}
|
|
2830
|
-
function createSingleTranscriptDiscoveryPort(filePath) {
|
|
2831
|
-
return {
|
|
2832
|
-
async discoverFiles(_targetPath) {
|
|
2833
|
-
return [filePath];
|
|
2834
|
-
}
|
|
2835
|
-
};
|
|
2836
|
-
}
|
|
2837
|
-
async function createOpenClawEpisodeSummaryLlm(params) {
|
|
2838
|
-
const llm = await createOpenClawLlmClient(params.openClaw, params.resolvedModelRef, "episode model override");
|
|
2839
|
-
const usage = createEmptyUsageStats();
|
|
2840
|
-
const completeWithTimeout = async (task) => {
|
|
2841
|
-
usage.calls += 1;
|
|
2842
|
-
const remainingMs = Math.max(0, params.deadlineMs - Date.now());
|
|
2843
|
-
return Promise.race([
|
|
2844
|
-
task,
|
|
2845
|
-
new Promise((_, reject) => {
|
|
2846
|
-
setTimeout(() => reject(new OpenClawEpisodeSummaryTimeoutError()), remainingMs);
|
|
2847
|
-
})
|
|
2848
|
-
]);
|
|
2849
|
-
};
|
|
2850
|
-
return {
|
|
2851
|
-
complete: async (systemPrompt, userMessage) => completeWithTimeout(llm.complete(systemPrompt, userMessage)),
|
|
2852
|
-
completeJson: async (systemPrompt, userMessage) => {
|
|
2853
|
-
return completeWithTimeout(llm.completeJson(systemPrompt, userMessage));
|
|
2854
|
-
},
|
|
2855
|
-
metadata: {
|
|
2856
|
-
modelRef: params.modelRef,
|
|
2857
|
-
pricing: {
|
|
2858
|
-
input: 0,
|
|
2859
|
-
output: 0,
|
|
2860
|
-
cacheRead: 0,
|
|
2861
|
-
cacheWrite: 0
|
|
2862
|
-
},
|
|
2863
|
-
usage
|
|
2864
|
-
}
|
|
2865
|
-
};
|
|
2866
|
-
}
|
|
2867
|
-
function createPredecessorEpisodeEmbeddingStrategy(params) {
|
|
2868
|
-
return async (summary) => maybeEmbedEpisodeSummary({
|
|
2869
|
-
summary,
|
|
2870
|
-
embedding: params.embedding,
|
|
2871
|
-
embeddingAvailable: params.embeddingAvailable,
|
|
2872
|
-
logger: params.logger,
|
|
2873
|
-
sessionContext: params.sessionContext,
|
|
2874
|
-
predecessorFile: params.predecessorFile,
|
|
2875
|
-
deadlineMs: params.deadlineMs
|
|
2876
|
-
});
|
|
2877
|
-
}
|
|
2878
|
-
function logSkippedEpisodeIngest(sessionContext, predecessorFile, skipped, logger) {
|
|
2879
|
-
if (skipped.reason === "skipped_exists") {
|
|
2880
|
-
logger.info(
|
|
2881
|
-
`[agenr] session-start predecessor episode write skipped for ${sessionContext} predecessor=${predecessorFile} reason=already_exists episode=${skipped.existingEpisode?.id}`
|
|
2882
|
-
);
|
|
2883
|
-
return;
|
|
2884
|
-
}
|
|
2885
|
-
if (skipped.reason === "skipped_short") {
|
|
2886
|
-
logger.info(
|
|
2887
|
-
`[agenr] session-start predecessor episode write skipped for ${sessionContext} predecessor=${predecessorFile} reason=too_short cleanedMessages=${skipped.messageCount}`
|
|
2888
|
-
);
|
|
2889
|
-
return;
|
|
2890
|
-
}
|
|
2891
|
-
logger.info(`[agenr] session-start predecessor episode write skipped for ${sessionContext} predecessor=${predecessorFile} reason=${skipped.reason}`);
|
|
2892
|
-
}
|
|
2893
|
-
function logFailedEpisodeIngest(sessionContext, predecessorFile, error, episodeModel, logger) {
|
|
2894
|
-
if (error === EPISODE_SUMMARY_TIMEOUT_ERROR_MESSAGE) {
|
|
2895
|
-
logger.info(
|
|
2896
|
-
`[agenr] session-start predecessor episode write timed_out for ${sessionContext} predecessor=${predecessorFile} timeoutMs=${EPISODE_SUMMARY_TIMEOUT_MS}`
|
|
2897
|
-
);
|
|
2898
|
-
return;
|
|
2899
|
-
}
|
|
2900
|
-
if (error === "invalid_response") {
|
|
2901
|
-
logger.info(
|
|
2902
|
-
`[agenr] session-start predecessor episode write failed for ${sessionContext} predecessor=${predecessorFile} reason=invalid_response model=${episodeModel}`
|
|
2903
|
-
);
|
|
2904
|
-
return;
|
|
2905
|
-
}
|
|
2906
|
-
logger.info(`[agenr] session-start predecessor episode write failed for ${sessionContext} predecessor=${predecessorFile} reason=${error ?? "unknown"}`);
|
|
2907
|
-
}
|
|
2908
|
-
async function maybeEmbedEpisodeSummary(params) {
|
|
2909
|
-
if (!params.embeddingAvailable) {
|
|
2910
|
-
params.logger.info(
|
|
2911
|
-
`[agenr] session-start predecessor episode embedding skipped for ${params.sessionContext} predecessor=${params.predecessorFile} reason=embedding_unavailable`
|
|
2912
|
-
);
|
|
2913
|
-
return void 0;
|
|
2914
|
-
}
|
|
2915
|
-
const remainingBudgetMs = params.deadlineMs - Date.now();
|
|
2916
|
-
if (remainingBudgetMs < EPISODE_EMBEDDING_MIN_HEADROOM_MS) {
|
|
2917
|
-
params.logger.info(
|
|
2918
|
-
`[agenr] session-start predecessor episode embedding skipped for ${params.sessionContext} predecessor=${params.predecessorFile} reason=budget_tight remainingMs=${Math.max(
|
|
2919
|
-
0,
|
|
2920
|
-
remainingBudgetMs
|
|
2921
|
-
)}`
|
|
2922
|
-
);
|
|
2923
|
-
return void 0;
|
|
2924
|
-
}
|
|
2925
|
-
try {
|
|
2926
|
-
const result = await awaitEmbeddingWithTimeout(params.embedding.embed([params.summary]), remainingBudgetMs);
|
|
2927
|
-
if (result === EPISODE_EMBEDDING_TIMEOUT) {
|
|
2928
|
-
params.logger.info(
|
|
2929
|
-
`[agenr] session-start predecessor episode embedding skipped for ${params.sessionContext} predecessor=${params.predecessorFile} reason=embedding_timeout budgetMs=${remainingBudgetMs}`
|
|
2930
|
-
);
|
|
2931
|
-
return void 0;
|
|
2932
|
-
}
|
|
2933
|
-
const vector = result[0]?.map((value) => Number.isFinite(value) ? value : 0);
|
|
2934
|
-
if (!vector || vector.length === 0) {
|
|
2935
|
-
params.logger.info(
|
|
2936
|
-
`[agenr] session-start predecessor episode embedding skipped for ${params.sessionContext} predecessor=${params.predecessorFile} reason=empty_embedding`
|
|
2937
|
-
);
|
|
2938
|
-
return void 0;
|
|
2939
|
-
}
|
|
2940
|
-
return vector;
|
|
2941
|
-
} catch (error) {
|
|
2942
|
-
params.logger.info(
|
|
2943
|
-
`[agenr] session-start predecessor episode embedding skipped for ${params.sessionContext} predecessor=${params.predecessorFile} reason=${formatErrorMessage2(error)}`
|
|
2944
|
-
);
|
|
2945
|
-
return void 0;
|
|
2946
|
-
}
|
|
2947
|
-
}
|
|
2948
|
-
async function awaitEmbeddingWithTimeout(promise, timeoutMs) {
|
|
2949
|
-
return new Promise((resolve, reject) => {
|
|
2950
|
-
const timeout = setTimeout(() => {
|
|
2951
|
-
resolve(EPISODE_EMBEDDING_TIMEOUT);
|
|
2952
|
-
}, timeoutMs);
|
|
2953
|
-
promise.then(
|
|
2954
|
-
(value) => {
|
|
2955
|
-
clearTimeout(timeout);
|
|
2956
|
-
resolve(value);
|
|
2957
|
-
},
|
|
2958
|
-
(error) => {
|
|
2959
|
-
clearTimeout(timeout);
|
|
2960
|
-
reject(error);
|
|
2961
|
-
}
|
|
2962
|
-
);
|
|
2963
|
-
});
|
|
2964
|
-
}
|
|
2965
|
-
function createEmptyUsageStats() {
|
|
2966
|
-
return {
|
|
2967
|
-
calls: 0,
|
|
2968
|
-
inputTokens: 0,
|
|
2969
|
-
outputTokens: 0,
|
|
2970
|
-
cacheReadTokens: 0,
|
|
2971
|
-
cacheWriteTokens: 0,
|
|
2972
|
-
totalTokens: 0,
|
|
2973
|
-
totalCost: 0
|
|
2974
|
-
};
|
|
2975
|
-
}
|
|
2976
1588
|
function trimOptionalString(value) {
|
|
2977
1589
|
const trimmed = value?.trim();
|
|
2978
1590
|
return trimmed ? trimmed : void 0;
|
|
@@ -3030,80 +1642,6 @@ function truncateSubject(subject) {
|
|
|
3030
1642
|
return `${trimmedSubject.slice(0, MAX_SUBJECT_LENGTH - 3).trimEnd()}...`;
|
|
3031
1643
|
}
|
|
3032
1644
|
|
|
3033
|
-
// src/adapters/openclaw/format/recall-format.ts
|
|
3034
|
-
var MAX_CONTENT_CHARS = 220;
|
|
3035
|
-
function formatAgenrSessionStartRecall(patch) {
|
|
3036
|
-
if (patch.contextSections.length === 0 && patch.durableMemory.length === 0) {
|
|
3037
|
-
return "";
|
|
3038
|
-
}
|
|
3039
|
-
const lines = [];
|
|
3040
|
-
for (const section of patch.contextSections) {
|
|
3041
|
-
lines.push(`## ${section.title}`);
|
|
3042
|
-
lines.push(section.content);
|
|
3043
|
-
lines.push("");
|
|
3044
|
-
}
|
|
3045
|
-
const durableSections = buildSections(patch);
|
|
3046
|
-
if (durableSections.length > 0) {
|
|
3047
|
-
const recallLines = [
|
|
3048
|
-
"## Agenr Session Recall",
|
|
3049
|
-
"Use this as prior context. Confirm anything important if the current conversation conflicts with it.",
|
|
3050
|
-
""
|
|
3051
|
-
];
|
|
3052
|
-
for (const section of durableSections) {
|
|
3053
|
-
recallLines.push(`### ${section.title}`);
|
|
3054
|
-
for (const item of section.entries) {
|
|
3055
|
-
recallLines.push(formatEntryHeader(item));
|
|
3056
|
-
recallLines.push(...formatEntryBodyLines(item));
|
|
3057
|
-
}
|
|
3058
|
-
recallLines.push("");
|
|
3059
|
-
}
|
|
3060
|
-
lines.push(wrapAgenrMemoryContext(recallLines.join("\n").trim()));
|
|
3061
|
-
}
|
|
3062
|
-
return lines.join("\n").trim();
|
|
3063
|
-
}
|
|
3064
|
-
function buildSections(patch) {
|
|
3065
|
-
const sections = [];
|
|
3066
|
-
const coreEntries = patch.durableMemory.filter((item) => item.sourceKind === "core");
|
|
3067
|
-
if (coreEntries.length > 0) {
|
|
3068
|
-
sections.push({ title: "Core Memory", entries: coreEntries });
|
|
3069
|
-
}
|
|
3070
|
-
const artifactRecallEntries = patch.durableMemory.filter((item) => item.sourceKind === "artifact_recall");
|
|
3071
|
-
if (artifactRecallEntries.length > 0) {
|
|
3072
|
-
sections.push({ title: "Relevant Durable Memory", entries: artifactRecallEntries });
|
|
3073
|
-
}
|
|
3074
|
-
return sections;
|
|
3075
|
-
}
|
|
3076
|
-
function formatEntryHeader(item) {
|
|
3077
|
-
const metadata = [
|
|
3078
|
-
`rank ${item.rank}`,
|
|
3079
|
-
item.entry.id,
|
|
3080
|
-
item.entry.type,
|
|
3081
|
-
item.entry.expiry,
|
|
3082
|
-
`importance ${item.entry.importance}`,
|
|
3083
|
-
item.score !== void 0 ? `score ${item.score.toFixed(2)}` : void 0
|
|
3084
|
-
].filter((value) => value !== void 0);
|
|
3085
|
-
return `- [${metadata.join(" | ")}] ${item.entry.subject}`;
|
|
3086
|
-
}
|
|
3087
|
-
function formatEntryBodyLines(item) {
|
|
3088
|
-
const lines = [` ${truncate3(item.entry.content.trim(), MAX_CONTENT_CHARS)}`];
|
|
3089
|
-
lines.push(` why: ${item.whySurfaced.summary}`);
|
|
3090
|
-
const metadata = [
|
|
3091
|
-
item.entry.tags.length > 0 ? `tags: ${item.entry.tags.join(", ")}` : void 0,
|
|
3092
|
-
item.freshnessLabel ? `freshness: ${item.freshnessLabel}` : void 0,
|
|
3093
|
-
item.provenanceSummary ? `provenance: ${truncate3(item.provenanceSummary, MAX_CONTENT_CHARS)}` : void 0
|
|
3094
|
-
].filter((value) => value !== void 0);
|
|
3095
|
-
if (metadata.length > 0) {
|
|
3096
|
-
lines.push(` ${metadata.join(" | ")}`);
|
|
3097
|
-
}
|
|
3098
|
-
return lines;
|
|
3099
|
-
}
|
|
3100
|
-
function truncate3(value, maxChars) {
|
|
3101
|
-
if (value.length <= maxChars) {
|
|
3102
|
-
return value;
|
|
3103
|
-
}
|
|
3104
|
-
return `${value.slice(0, maxChars - 3).trimEnd()}...`;
|
|
3105
|
-
}
|
|
3106
|
-
|
|
3107
1645
|
// src/adapters/openclaw/session/continuity/continuity-summary-generator.ts
|
|
3108
1646
|
import * as fs3 from "fs/promises";
|
|
3109
1647
|
import { resolveAgentEffectiveModelPrimary as resolveAgentEffectiveModelPrimary3, resolveDefaultAgentId as resolveDefaultAgentId3 } from "openclaw/plugin-sdk/agent-runtime";
|
|
@@ -3311,10 +1849,10 @@ async function generateAndWriteOpenClawContinuitySummary(params) {
|
|
|
3311
1849
|
durationMs
|
|
3312
1850
|
};
|
|
3313
1851
|
}
|
|
3314
|
-
debugLog2(params.logger, "continuity-summary", `continuity summary generation error for file=${sessionFile}: ${
|
|
1852
|
+
debugLog2(params.logger, "continuity-summary", `continuity summary generation error for file=${sessionFile}: ${formatErrorMessage3(error)}`);
|
|
3315
1853
|
return {
|
|
3316
1854
|
status: "failed",
|
|
3317
|
-
reason:
|
|
1855
|
+
reason: formatErrorMessage3(error),
|
|
3318
1856
|
continuitySummaryPath,
|
|
3319
1857
|
messageCount: cleanedMessages.length,
|
|
3320
1858
|
transcriptChars: normalizedTranscript.length,
|
|
@@ -3333,7 +1871,7 @@ function normalizeContinuitySummary(value) {
|
|
|
3333
1871
|
const trimmed = value.trim();
|
|
3334
1872
|
return trimmed.replace(/^# .+\n+/u, "").trim();
|
|
3335
1873
|
}
|
|
3336
|
-
function
|
|
1874
|
+
function formatErrorMessage3(error) {
|
|
3337
1875
|
return error instanceof Error ? error.message : String(error);
|
|
3338
1876
|
}
|
|
3339
1877
|
function resolveOpenClawSummaryModelRef(openClaw, agentId, modelOverride) {
|
|
@@ -3847,11 +2385,11 @@ async function renderRecentSessionSection(sessionFile, logger) {
|
|
|
3847
2385
|
logger.debug?.(`[agenr] before_prompt_build: recent session tail for file=${sessionFile}: messages=${tail.length} chars=${body.length}`);
|
|
3848
2386
|
return body;
|
|
3849
2387
|
} catch (error) {
|
|
3850
|
-
logger.debug?.(`[agenr] before_prompt_build: failed to build recent session tail for file=${sessionFile}: ${
|
|
2388
|
+
logger.debug?.(`[agenr] before_prompt_build: failed to build recent session tail for file=${sessionFile}: ${formatErrorMessage4(error)}`);
|
|
3851
2389
|
return "";
|
|
3852
2390
|
}
|
|
3853
2391
|
}
|
|
3854
|
-
function
|
|
2392
|
+
function formatErrorMessage4(error) {
|
|
3855
2393
|
return error instanceof Error ? error.message : String(error);
|
|
3856
2394
|
}
|
|
3857
2395
|
function capRecentSession(value, maxChars) {
|
|
@@ -4039,22 +2577,6 @@ async function awaitWithTimeout(promise, timeoutMs) {
|
|
|
4039
2577
|
}
|
|
4040
2578
|
|
|
4041
2579
|
// src/adapters/openclaw/hooks/before-prompt-build.ts
|
|
4042
|
-
var DEFAULT_SESSION_START_POLICY = {
|
|
4043
|
-
maxCoreEntries: 4,
|
|
4044
|
-
maxArtifactRecallEntries: 3,
|
|
4045
|
-
maxDurableEntries: 5,
|
|
4046
|
-
maxArtifactChars: 1200
|
|
4047
|
-
};
|
|
4048
|
-
var DEFAULT_BEFORE_TURN_POLICY = {
|
|
4049
|
-
maxDurableEntries: 1,
|
|
4050
|
-
maxHighConfidenceDurableEntries: 2,
|
|
4051
|
-
maxRecentTurns: 2,
|
|
4052
|
-
maxQueryChars: 450,
|
|
4053
|
-
maxProcedureCandidates: 3,
|
|
4054
|
-
recallThreshold: 0.6,
|
|
4055
|
-
highConfidenceRecallThreshold: 0.85,
|
|
4056
|
-
procedureThreshold: 0.72
|
|
4057
|
-
};
|
|
4058
2580
|
var NON_USER_TRIGGER_SET = /* @__PURE__ */ new Set(["heartbeat", "cron", "memory"]);
|
|
4059
2581
|
var DEFAULT_STORE_NUDGE_CONFIG = resolveStoreNudgeConfig(void 0);
|
|
4060
2582
|
var INLINE_METADATA_SENTINELS2 = [
|
|
@@ -4079,6 +2601,10 @@ async function handleAgenrBeforePromptBuild(event, ctx, params) {
|
|
|
4079
2601
|
params.logger.info(`[agenr] session-start recall for ${sessionContext}`);
|
|
4080
2602
|
try {
|
|
4081
2603
|
const services = await params.servicesPromise;
|
|
2604
|
+
if (services.pluginConfig.memoryPolicy?.sessionStart?.enabled === false) {
|
|
2605
|
+
params.logger.info(`[agenr] session-start recall disabled by memoryPolicy for ${sessionContext}`);
|
|
2606
|
+
return await resolveNonFirstTurnResult(event, ctx, sessionContext, params);
|
|
2607
|
+
}
|
|
4082
2608
|
const continuity = await resolvePredecessorContinuity(ctx, params.tracker, services, params.logger);
|
|
4083
2609
|
emitContinuityEvent(services.debugSink, ctx, continuity);
|
|
4084
2610
|
void writeOpenClawPredecessorEpisode({
|
|
@@ -4092,7 +2618,7 @@ async function handleAgenrBeforePromptBuild(event, ctx, params) {
|
|
|
4092
2618
|
sessionKey: ctx.sessionKey,
|
|
4093
2619
|
continuitySummaryText: continuity.continuitySummaryContent,
|
|
4094
2620
|
recentSessionText: continuity.recentSessionContent,
|
|
4095
|
-
policy: resolveSessionStartPolicy(services)
|
|
2621
|
+
policy: resolveSessionStartPolicy(services.pluginConfig.memoryPolicy)
|
|
4096
2622
|
},
|
|
4097
2623
|
services.sessionStart
|
|
4098
2624
|
);
|
|
@@ -4186,7 +2712,12 @@ async function resolveBeforeTurnResult(event, ctx, sessionContext, params) {
|
|
|
4186
2712
|
params.logger.debug?.(`[agenr] before_prompt_build: before-turn skipped for ${sessionContext} reason=disabled`);
|
|
4187
2713
|
return void 0;
|
|
4188
2714
|
}
|
|
4189
|
-
const currentTurnText = normalizePromptText(event.prompt
|
|
2715
|
+
const currentTurnText = normalizePromptText(event.prompt, {
|
|
2716
|
+
stripInlineMetadata: true,
|
|
2717
|
+
inlineMetadataSentinels: INLINE_METADATA_SENTINELS2,
|
|
2718
|
+
stripTimestampPrefix: true,
|
|
2719
|
+
stripUserPrefix: true
|
|
2720
|
+
});
|
|
4190
2721
|
if (!currentTurnText) {
|
|
4191
2722
|
params.logger.debug?.(`[agenr] before_prompt_build: before-turn skipped for ${sessionContext} reason=empty_prompt`);
|
|
4192
2723
|
return void 0;
|
|
@@ -4196,9 +2727,12 @@ async function resolveBeforeTurnResult(event, ctx, sessionContext, params) {
|
|
|
4196
2727
|
{
|
|
4197
2728
|
sessionKey: ctx.sessionKey,
|
|
4198
2729
|
currentTurnText,
|
|
4199
|
-
recentTurns:
|
|
2730
|
+
recentTurns: extractRecentTurnsFromMessages(
|
|
2731
|
+
event.messages.filter((message) => Boolean(message) && typeof message === "object"),
|
|
2732
|
+
{ stripMemoryCheck: true }
|
|
2733
|
+
),
|
|
4200
2734
|
trigger: ctx.trigger,
|
|
4201
|
-
policy: resolveBeforeTurnPolicy(services)
|
|
2735
|
+
policy: resolveBeforeTurnPolicy(services.pluginConfig.memoryPolicy)
|
|
4202
2736
|
},
|
|
4203
2737
|
services.beforeTurn
|
|
4204
2738
|
);
|
|
@@ -4356,124 +2890,6 @@ function truncateForLog(value, maxChars) {
|
|
|
4356
2890
|
}
|
|
4357
2891
|
return normalized.length <= maxChars ? normalized : `${normalized.slice(0, Math.max(0, maxChars - 3)).trimEnd()}...`;
|
|
4358
2892
|
}
|
|
4359
|
-
function resolveSessionStartPolicy(services) {
|
|
4360
|
-
return {
|
|
4361
|
-
...DEFAULT_SESSION_START_POLICY,
|
|
4362
|
-
enableArtifactRecall: services.pluginConfig.memoryPolicy?.sessionStart?.relevantDurableMemory !== false
|
|
4363
|
-
};
|
|
4364
|
-
}
|
|
4365
|
-
function resolveBeforeTurnPolicy(services) {
|
|
4366
|
-
return {
|
|
4367
|
-
...DEFAULT_BEFORE_TURN_POLICY,
|
|
4368
|
-
enableProcedureSuggestion: services.pluginConfig.memoryPolicy?.beforeTurn?.procedureSuggestion !== false,
|
|
4369
|
-
...services.pluginConfig.memoryPolicy?.beforeTurn?.maxDurableEntries !== void 0 ? { maxDurableEntries: services.pluginConfig.memoryPolicy.beforeTurn.maxDurableEntries } : {},
|
|
4370
|
-
...services.pluginConfig.memoryPolicy?.beforeTurn?.recallThreshold !== void 0 ? { recallThreshold: services.pluginConfig.memoryPolicy.beforeTurn.recallThreshold } : {},
|
|
4371
|
-
...services.pluginConfig.memoryPolicy?.beforeTurn?.highConfidenceRecallThreshold !== void 0 ? { highConfidenceRecallThreshold: services.pluginConfig.memoryPolicy.beforeTurn.highConfidenceRecallThreshold } : {},
|
|
4372
|
-
...services.pluginConfig.memoryPolicy?.beforeTurn?.procedureThreshold !== void 0 ? { procedureThreshold: services.pluginConfig.memoryPolicy.beforeTurn.procedureThreshold } : {}
|
|
4373
|
-
};
|
|
4374
|
-
}
|
|
4375
|
-
function extractRecentTurns(messages) {
|
|
4376
|
-
const turns = [];
|
|
4377
|
-
for (const message of messages) {
|
|
4378
|
-
if (!message || typeof message !== "object") {
|
|
4379
|
-
continue;
|
|
4380
|
-
}
|
|
4381
|
-
const typed = message;
|
|
4382
|
-
const role = typed.role === "user" || typed.role === "assistant" ? typed.role : void 0;
|
|
4383
|
-
if (!role) {
|
|
4384
|
-
continue;
|
|
4385
|
-
}
|
|
4386
|
-
const text = sanitizeRecentTurnText(extractMessageText(typed.content), role);
|
|
4387
|
-
if (!text) {
|
|
4388
|
-
continue;
|
|
4389
|
-
}
|
|
4390
|
-
turns.push({ role, text });
|
|
4391
|
-
}
|
|
4392
|
-
return turns;
|
|
4393
|
-
}
|
|
4394
|
-
function extractMessageText(content) {
|
|
4395
|
-
if (typeof content === "string") {
|
|
4396
|
-
return content;
|
|
4397
|
-
}
|
|
4398
|
-
if (!Array.isArray(content)) {
|
|
4399
|
-
return "";
|
|
4400
|
-
}
|
|
4401
|
-
const blocks = [];
|
|
4402
|
-
for (const block of content) {
|
|
4403
|
-
if (typeof block === "string") {
|
|
4404
|
-
blocks.push(block);
|
|
4405
|
-
continue;
|
|
4406
|
-
}
|
|
4407
|
-
if (!block || typeof block !== "object") {
|
|
4408
|
-
continue;
|
|
4409
|
-
}
|
|
4410
|
-
const typed = block;
|
|
4411
|
-
if (typeof typed.text === "string") {
|
|
4412
|
-
blocks.push(typed.text);
|
|
4413
|
-
continue;
|
|
4414
|
-
}
|
|
4415
|
-
const type = typeof typed.type === "string" ? typed.type.trim().toLowerCase() : "";
|
|
4416
|
-
if (typeof typed.content === "string" && (type === "text" || type === "input_text" || type === "output_text")) {
|
|
4417
|
-
blocks.push(typed.content);
|
|
4418
|
-
}
|
|
4419
|
-
}
|
|
4420
|
-
return blocks.join("\n");
|
|
4421
|
-
}
|
|
4422
|
-
function sanitizeRecentTurnText(text, role) {
|
|
4423
|
-
if (!text.trim()) {
|
|
4424
|
-
return "";
|
|
4425
|
-
}
|
|
4426
|
-
const wrapperDetected = containsAgenrMemoryContext(text) || text.includes("## Agenr Session Recall") || text.includes("## Agenr Before-Turn Recall") || text.includes("[MEMORY CHECK]");
|
|
4427
|
-
let cleaned = stripAgenrMemoryContext(text);
|
|
4428
|
-
const headings = [
|
|
4429
|
-
"## Previous session summary",
|
|
4430
|
-
"## Recent session",
|
|
4431
|
-
"## Agenr Session Recall",
|
|
4432
|
-
"### Core Memory",
|
|
4433
|
-
"### Relevant Durable Memory",
|
|
4434
|
-
"## Agenr Before-Turn Recall",
|
|
4435
|
-
"### Suggested Procedure"
|
|
4436
|
-
];
|
|
4437
|
-
for (const heading of headings) {
|
|
4438
|
-
cleaned = cleaned.split(heading).join(" ");
|
|
4439
|
-
}
|
|
4440
|
-
cleaned = cleaned.replace(/\[MEMORY CHECK\][^\n]*/gu, " ");
|
|
4441
|
-
cleaned = collapseWhitespace2(cleaned);
|
|
4442
|
-
if (!wrapperDetected) {
|
|
4443
|
-
return cleaned;
|
|
4444
|
-
}
|
|
4445
|
-
const segments = stripAgenrMemoryContext(text).split(/\n\s*\n/gu).map((segment) => collapseWhitespace2(segment)).filter((segment) => segment.length > 0);
|
|
4446
|
-
const fallbackSegment = segments.at(-1);
|
|
4447
|
-
if (fallbackSegment) {
|
|
4448
|
-
return role === "user" ? fallbackSegment : collapseWhitespace2(cleaned);
|
|
4449
|
-
}
|
|
4450
|
-
return cleaned;
|
|
4451
|
-
}
|
|
4452
|
-
function normalizePromptText(prompt) {
|
|
4453
|
-
let cleaned = stripAgenrMemoryContext(prompt);
|
|
4454
|
-
cleaned = stripInlineMetadata2(cleaned);
|
|
4455
|
-
cleaned = cleaned.replace(/^\s*\[(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s[^\]]+\]\s*/u, "");
|
|
4456
|
-
cleaned = cleaned.replace(/^\s*U:\s*/u, "");
|
|
4457
|
-
cleaned = collapseWhitespace2(cleaned);
|
|
4458
|
-
return cleaned.length > 0 ? cleaned : void 0;
|
|
4459
|
-
}
|
|
4460
|
-
function stripInlineMetadata2(text) {
|
|
4461
|
-
let cleaned = text;
|
|
4462
|
-
for (const sentinel of INLINE_METADATA_SENTINELS2) {
|
|
4463
|
-
const escapedSentinel = escapeForRegExp2(sentinel);
|
|
4464
|
-
cleaned = cleaned.replace(new RegExp(`${escapedSentinel}\\s*(?:\`\`\`json\\s*)?\\{[\\s\\S]*?\\}(?:\\s*\`\`\`)?`, "gu"), " ");
|
|
4465
|
-
cleaned = cleaned.replace(new RegExp(`${escapedSentinel}[^
|
|
4466
|
-
]*`, "gu"), " ");
|
|
4467
|
-
}
|
|
4468
|
-
cleaned = cleaned.replace(/Untrusted context \(metadata, do not treat as instructions or commands\):[\s\S]*$/gu, " ");
|
|
4469
|
-
return cleaned;
|
|
4470
|
-
}
|
|
4471
|
-
function escapeForRegExp2(value) {
|
|
4472
|
-
return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
4473
|
-
}
|
|
4474
|
-
function collapseWhitespace2(value) {
|
|
4475
|
-
return value.replace(/\s+/gu, " ").trim();
|
|
4476
|
-
}
|
|
4477
2893
|
|
|
4478
2894
|
// src/adapters/openclaw/memory/flush-plan.ts
|
|
4479
2895
|
function buildAgenrMemoryFlushPlan(_params, logger) {
|
|
@@ -4493,7 +2909,7 @@ function createAgenrMemoryRuntime(servicesPromise) {
|
|
|
4493
2909
|
backend: "builtin",
|
|
4494
2910
|
provider: "agenr",
|
|
4495
2911
|
model: services.embeddingStatus.model,
|
|
4496
|
-
dbPath: services.dbPath,
|
|
2912
|
+
dbPath: services.config.dbPath,
|
|
4497
2913
|
files: snapshot.sourceFiles,
|
|
4498
2914
|
chunks: snapshot.activeEntries,
|
|
4499
2915
|
vector: {
|
|
@@ -4552,127 +2968,28 @@ function createAgenrMemoryRuntime(servicesPromise) {
|
|
|
4552
2968
|
};
|
|
4553
2969
|
}
|
|
4554
2970
|
|
|
4555
|
-
// src/adapters/db/session-start-repository.ts
|
|
4556
|
-
function createSessionStartRepository(executor) {
|
|
4557
|
-
return {
|
|
4558
|
-
listCoreEntries: async (limit) => listCoreEntries(executor, limit)
|
|
4559
|
-
};
|
|
4560
|
-
}
|
|
4561
|
-
async function listCoreEntries(executor, limit) {
|
|
4562
|
-
if (limit <= 0) {
|
|
4563
|
-
return [];
|
|
4564
|
-
}
|
|
4565
|
-
const result = await executor.execute({
|
|
4566
|
-
sql: `
|
|
4567
|
-
SELECT
|
|
4568
|
-
${ENTRY_SELECT_COLUMNS}
|
|
4569
|
-
FROM entries
|
|
4570
|
-
WHERE ${buildActiveEntryClause()}
|
|
4571
|
-
AND expiry = 'core'
|
|
4572
|
-
ORDER BY importance DESC, created_at DESC
|
|
4573
|
-
LIMIT ?
|
|
4574
|
-
`,
|
|
4575
|
-
args: [limit]
|
|
4576
|
-
});
|
|
4577
|
-
return result.rows.map((row) => mapEntryRow(row));
|
|
4578
|
-
}
|
|
4579
|
-
|
|
4580
2971
|
// src/app/openclaw/runtime.ts
|
|
4581
2972
|
import path6 from "path";
|
|
4582
2973
|
async function createAgenrOpenClawServices(config, options) {
|
|
4583
|
-
const
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
4591
|
-
|
|
2974
|
+
const debugSink = createDebugSink(options.openClaw, config);
|
|
2975
|
+
return composeHostPluginServices({
|
|
2976
|
+
config,
|
|
2977
|
+
resolvePath: options.resolvePath,
|
|
2978
|
+
readSlotPolicies: (hostConfig) => hostConfig.memoryPolicy?.slotPolicies,
|
|
2979
|
+
resolveClaimExtraction: ({ agenrConfig, hostConfig }) => buildClaimExtractionRuntime(
|
|
2980
|
+
agenrConfig,
|
|
2981
|
+
() => createOpenClawLlmClient(options.openClaw, hostConfig.claimExtractionModel, "claim extraction model override")
|
|
2982
|
+
),
|
|
2983
|
+
onBeforeClose: () => debugSink.close(),
|
|
2984
|
+
extend: ({ resolvedConfig, agenrConfig, runtimeServices }) => ({
|
|
2985
|
+
...runtimeServices,
|
|
2986
|
+
openClaw: options.openClaw,
|
|
2987
|
+
config: resolvedConfig,
|
|
2988
|
+
pluginConfig: config,
|
|
2989
|
+
agenrConfig,
|
|
2990
|
+
debugSink
|
|
2991
|
+
})
|
|
4592
2992
|
});
|
|
4593
|
-
return {
|
|
4594
|
-
openClaw: options.openClaw,
|
|
4595
|
-
config: resolvedConfig,
|
|
4596
|
-
pluginConfig: config,
|
|
4597
|
-
agenrConfig,
|
|
4598
|
-
dbPath: resolvedConfig.dbPath,
|
|
4599
|
-
entries: runtimeServices.entries,
|
|
4600
|
-
episodes: runtimeServices.episodes,
|
|
4601
|
-
procedures: runtimeServices.procedures,
|
|
4602
|
-
memory: runtimeServices.memory,
|
|
4603
|
-
sessionStart: runtimeServices.sessionStart,
|
|
4604
|
-
beforeTurn: runtimeServices.beforeTurn,
|
|
4605
|
-
embedding: runtimeServices.embedding,
|
|
4606
|
-
recall: runtimeServices.recall,
|
|
4607
|
-
claimExtraction: runtimeServices.claimExtraction,
|
|
4608
|
-
embeddingStatus: toPublicEmbeddingStatus(embeddingStatus),
|
|
4609
|
-
debugSink: runtimeServices.debugSink,
|
|
4610
|
-
close: runtimeServices.close
|
|
4611
|
-
};
|
|
4612
|
-
}
|
|
4613
|
-
function resolveEmbeddingStatus(config) {
|
|
4614
|
-
const model = resolveEmbeddingModel(config);
|
|
4615
|
-
try {
|
|
4616
|
-
return {
|
|
4617
|
-
available: true,
|
|
4618
|
-
provider: "openai",
|
|
4619
|
-
requestedProvider: "openai",
|
|
4620
|
-
model,
|
|
4621
|
-
apiKey: resolveEmbeddingApiKey(config)
|
|
4622
|
-
};
|
|
4623
|
-
} catch (error) {
|
|
4624
|
-
return {
|
|
4625
|
-
available: false,
|
|
4626
|
-
provider: "unconfigured",
|
|
4627
|
-
requestedProvider: "openai",
|
|
4628
|
-
model,
|
|
4629
|
-
error: error instanceof Error ? error.message : String(error)
|
|
4630
|
-
};
|
|
4631
|
-
}
|
|
4632
|
-
}
|
|
4633
|
-
async function createRuntimeServices(dbPath, config, embeddingStatus, openClawContext) {
|
|
4634
|
-
const database = await createDatabase(dbPath);
|
|
4635
|
-
const embedding = embeddingStatus.available ? createEmbeddingClient(requireApiKey(embeddingStatus), embeddingStatus.model) : createUnavailableEmbeddingPort(embeddingStatus.error ?? "Embeddings are unavailable.");
|
|
4636
|
-
const baseRecall = createRecallAdapter(database, embedding);
|
|
4637
|
-
const crossEncoder = resolveCrossEncoder(config);
|
|
4638
|
-
const recall2 = attachCrossEncoderPort(baseRecall, crossEncoder);
|
|
4639
|
-
const claimExtraction = await createClaimExtractionRuntime(config, openClawContext.openClaw, openClawContext.pluginConfig);
|
|
4640
|
-
const debugSink = createDebugSink(openClawContext.openClaw, openClawContext.pluginConfig);
|
|
4641
|
-
let closed = false;
|
|
4642
|
-
return {
|
|
4643
|
-
entries: database,
|
|
4644
|
-
episodes: database,
|
|
4645
|
-
procedures: database,
|
|
4646
|
-
memory: createOpenClawRepository(database, {
|
|
4647
|
-
claimSlotPolicyConfig: openClawContext.pluginConfig.memoryPolicy?.slotPolicies
|
|
4648
|
-
}),
|
|
4649
|
-
sessionStart: {
|
|
4650
|
-
repository: createSessionStartRepository(database),
|
|
4651
|
-
recall: recall2,
|
|
4652
|
-
slotPolicyConfig: openClawContext.pluginConfig.memoryPolicy?.slotPolicies
|
|
4653
|
-
},
|
|
4654
|
-
beforeTurn: {
|
|
4655
|
-
recall: recall2,
|
|
4656
|
-
procedures: database,
|
|
4657
|
-
embedQuery: embeddingStatus.available ? async (text) => {
|
|
4658
|
-
const vectors = await embedding.embed([text]);
|
|
4659
|
-
return vectors[0] ?? [];
|
|
4660
|
-
} : void 0,
|
|
4661
|
-
slotPolicyConfig: openClawContext.pluginConfig.memoryPolicy?.slotPolicies
|
|
4662
|
-
},
|
|
4663
|
-
embedding,
|
|
4664
|
-
recall: recall2,
|
|
4665
|
-
claimExtraction,
|
|
4666
|
-
debugSink,
|
|
4667
|
-
async close() {
|
|
4668
|
-
if (closed) {
|
|
4669
|
-
return;
|
|
4670
|
-
}
|
|
4671
|
-
closed = true;
|
|
4672
|
-
await debugSink.close();
|
|
4673
|
-
await database.close();
|
|
4674
|
-
}
|
|
4675
|
-
};
|
|
4676
2993
|
}
|
|
4677
2994
|
function createDebugSink(openClaw, pluginConfig) {
|
|
4678
2995
|
const resolved = resolveDebugConfig(pluginConfig.debug);
|
|
@@ -4696,78 +3013,6 @@ function ensureDebugLogPath(resolved, openClaw) {
|
|
|
4696
3013
|
return { ...resolved, enabled: false };
|
|
4697
3014
|
}
|
|
4698
3015
|
}
|
|
4699
|
-
function toPublicEmbeddingStatus(status) {
|
|
4700
|
-
return {
|
|
4701
|
-
available: status.available,
|
|
4702
|
-
provider: status.provider,
|
|
4703
|
-
requestedProvider: status.requestedProvider,
|
|
4704
|
-
model: status.model,
|
|
4705
|
-
...status.error ? { error: status.error } : {}
|
|
4706
|
-
};
|
|
4707
|
-
}
|
|
4708
|
-
function createUnavailableEmbeddingPort(errorMessage) {
|
|
4709
|
-
return {
|
|
4710
|
-
async embed() {
|
|
4711
|
-
throw new Error(errorMessage);
|
|
4712
|
-
}
|
|
4713
|
-
};
|
|
4714
|
-
}
|
|
4715
|
-
function resolveRuntimeConfig(config, resolvePath) {
|
|
4716
|
-
const dbPathOverride = resolveOptionalPath(config.dbPath, resolvePath);
|
|
4717
|
-
const configPathOverride = resolveOptionalPath(config.configPath, resolvePath);
|
|
4718
|
-
const configPath = resolveConfigPath({
|
|
4719
|
-
configPath: configPathOverride,
|
|
4720
|
-
dbPath: dbPathOverride
|
|
4721
|
-
});
|
|
4722
|
-
const agenrConfig = readConfig({
|
|
4723
|
-
configPath,
|
|
4724
|
-
dbPath: dbPathOverride
|
|
4725
|
-
});
|
|
4726
|
-
const dbPath = dbPathOverride ?? resolveDbPath(agenrConfig);
|
|
4727
|
-
return {
|
|
4728
|
-
resolvedConfig: {
|
|
4729
|
-
dbPath,
|
|
4730
|
-
configPath
|
|
4731
|
-
},
|
|
4732
|
-
agenrConfig
|
|
4733
|
-
};
|
|
4734
|
-
}
|
|
4735
|
-
function resolveOptionalPath(value, resolvePath) {
|
|
4736
|
-
const normalized = value?.trim();
|
|
4737
|
-
if (!normalized) {
|
|
4738
|
-
return void 0;
|
|
4739
|
-
}
|
|
4740
|
-
return resolvePath ? resolvePath(normalized) : normalized;
|
|
4741
|
-
}
|
|
4742
|
-
function requireApiKey(status) {
|
|
4743
|
-
if (!status.apiKey) {
|
|
4744
|
-
throw new Error("Embedding API key is unavailable.");
|
|
4745
|
-
}
|
|
4746
|
-
return status.apiKey;
|
|
4747
|
-
}
|
|
4748
|
-
function resolveCrossEncoder(config) {
|
|
4749
|
-
try {
|
|
4750
|
-
const apiKey = resolveCrossEncoderApiKey(config);
|
|
4751
|
-
const { modelId } = resolveModel(config, "cross_encoder");
|
|
4752
|
-
return createOpenAICrossEncoder({ apiKey, model: modelId });
|
|
4753
|
-
} catch {
|
|
4754
|
-
return void 0;
|
|
4755
|
-
}
|
|
4756
|
-
}
|
|
4757
|
-
async function createClaimExtractionRuntime(config, openClaw, pluginConfig) {
|
|
4758
|
-
const claimExtractionConfig = resolveClaimExtractionConfig(config);
|
|
4759
|
-
if (!claimExtractionConfig.enabled) {
|
|
4760
|
-
return void 0;
|
|
4761
|
-
}
|
|
4762
|
-
try {
|
|
4763
|
-
return {
|
|
4764
|
-
llm: await createOpenClawLlmClient(openClaw, pluginConfig.claimExtractionModel, "claim extraction model override"),
|
|
4765
|
-
config: claimExtractionConfig
|
|
4766
|
-
};
|
|
4767
|
-
} catch {
|
|
4768
|
-
return void 0;
|
|
4769
|
-
}
|
|
4770
|
-
}
|
|
4771
3016
|
|
|
4772
3017
|
// src/adapters/openclaw/index.ts
|
|
4773
3018
|
var openclaw_default = definePluginEntry({
|