@remnic/plugin-openclaw 9.7.15 → 9.9.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/dist/index.js +149 -62
- package/openclaw.plugin.json +168 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -24,7 +24,7 @@ import * as day_summary_star from "@remnic/core/day-summary";
|
|
|
24
24
|
// ../../src/index.ts
|
|
25
25
|
import OpenAI from "openai";
|
|
26
26
|
import { createRequire } from "module";
|
|
27
|
-
import { createHash as
|
|
27
|
+
import { createHash as createHash4 } from "crypto";
|
|
28
28
|
|
|
29
29
|
// ../../src/config.ts
|
|
30
30
|
var config_exports = {};
|
|
@@ -43,7 +43,7 @@ import { detectSdkCapabilities } from "@remnic/core/sdk-compat";
|
|
|
43
43
|
import { Orchestrator, sanitizeSessionKeyForFilename, defaultWorkspaceDir } from "@remnic/core/orchestrator";
|
|
44
44
|
|
|
45
45
|
// ../../src/tools.ts
|
|
46
|
-
import { createHash } from "crypto";
|
|
46
|
+
import { createHash as createHash2 } from "crypto";
|
|
47
47
|
import { Type } from "@sinclair/typebox";
|
|
48
48
|
|
|
49
49
|
// ../../src/temporal-index.ts
|
|
@@ -74,6 +74,102 @@ import * as temporal_index_star from "@remnic/core/temporal-index";
|
|
|
74
74
|
// ../../src/explicit-capture.ts
|
|
75
75
|
import { hasInlineExplicitCaptureMarkup, parseInlineExplicitCaptureNotes, persistExplicitCapture, queueExplicitCaptureForReview, shouldProcessInlineExplicitCapture, shouldSkipImplicitExtraction, stripInlineExplicitCaptureNotes, validateExplicitCaptureInput } from "@remnic/core/explicit-capture";
|
|
76
76
|
|
|
77
|
+
// ../../src/tools.ts
|
|
78
|
+
import { composeSalvagedEnvelope as composeSalvagedEnvelope2 } from "@remnic/core/salvage-envelope";
|
|
79
|
+
|
|
80
|
+
// ../../src/memory-promote.ts
|
|
81
|
+
import { createHash } from "crypto";
|
|
82
|
+
import { composeSalvagedEnvelope } from "@remnic/core/salvage-envelope";
|
|
83
|
+
import { STRUCTURED_ATTRIBUTE_LIMITS, TAG_LIMITS } from "@remnic/core/write-envelope";
|
|
84
|
+
import { stripAttributesSuffix } from "@remnic/core/storage";
|
|
85
|
+
import { displayErrorDetail } from "@remnic/core/runtime/better-sqlite";
|
|
86
|
+
import { isSafeRouteNamespace } from "@remnic/core/routing/engine";
|
|
87
|
+
function buildPromotionOrigin(srcNamespace, memoryId) {
|
|
88
|
+
const memoryIdHash = createHash("sha256").update(memoryId).digest("hex");
|
|
89
|
+
const fullTag = `promotedFrom:${srcNamespace}:${memoryId}`;
|
|
90
|
+
return {
|
|
91
|
+
tag: fullTag.length <= TAG_LIMITS.maxTagLength ? fullTag : `promotedFromHash:${memoryIdHash}`,
|
|
92
|
+
structuredAttributes: {
|
|
93
|
+
promotedFromNamespace: srcNamespace,
|
|
94
|
+
promotedFromMemoryIdHash: memoryIdHash,
|
|
95
|
+
...memoryId.length <= STRUCTURED_ATTRIBUTE_LIMITS.maxValueLength ? { promotedFromMemoryId: memoryId } : {}
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
async function executeMemoryPromote(orchestrator, params) {
|
|
100
|
+
const { memoryId, fromNamespace, toNamespace, note } = params;
|
|
101
|
+
if (typeof memoryId !== "string" || memoryId.length === 0) {
|
|
102
|
+
return `Invalid memoryId: ${JSON.stringify(memoryId)} \u2014 expected a non-empty memory ID.`;
|
|
103
|
+
}
|
|
104
|
+
for (const [name, value] of [
|
|
105
|
+
["fromNamespace", fromNamespace],
|
|
106
|
+
["toNamespace", toNamespace]
|
|
107
|
+
]) {
|
|
108
|
+
if (value !== void 0 && value !== null && (typeof value !== "string" || !isSafeRouteNamespace(value))) {
|
|
109
|
+
return `Invalid ${name}: ${JSON.stringify(value)} \u2014 expected a path-safe namespace name.`;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const srcNs = fromNamespace ?? orchestrator.config.defaultNamespace;
|
|
113
|
+
const dstNs = toNamespace ?? orchestrator.config.sharedNamespace;
|
|
114
|
+
const src = await orchestrator.getStorage(srcNs);
|
|
115
|
+
const mem = await src.getMemoryById(memoryId);
|
|
116
|
+
if (!mem) {
|
|
117
|
+
return `Memory not found in ${srcNs}: ${memoryId}`;
|
|
118
|
+
}
|
|
119
|
+
const dst = await orchestrator.getStorage(dstNs);
|
|
120
|
+
const promotionOrigin = buildPromotionOrigin(srcNs, memoryId);
|
|
121
|
+
const promoteEnvelope = composeSalvagedEnvelope(
|
|
122
|
+
"promote",
|
|
123
|
+
{
|
|
124
|
+
content: mem.frontmatter.structuredAttributes ? stripAttributesSuffix(mem.content) : mem.content,
|
|
125
|
+
category: mem.frontmatter.category,
|
|
126
|
+
confidence: mem.frontmatter.confidence,
|
|
127
|
+
tags: (() => {
|
|
128
|
+
const promotionTags = [
|
|
129
|
+
"promoted",
|
|
130
|
+
promotionOrigin.tag,
|
|
131
|
+
...note ? [`note:${note}`] : []
|
|
132
|
+
];
|
|
133
|
+
const sourceTags = mem.frontmatter.tags ?? [];
|
|
134
|
+
return Array.from(/* @__PURE__ */ new Set([...promotionTags, ...sourceTags])).slice(
|
|
135
|
+
0,
|
|
136
|
+
TAG_LIMITS.maxTags
|
|
137
|
+
);
|
|
138
|
+
})(),
|
|
139
|
+
structuredAttributes: promotionOrigin.structuredAttributes,
|
|
140
|
+
entityRef: mem.frontmatter.entityRef
|
|
141
|
+
},
|
|
142
|
+
{ source: "promote" }
|
|
143
|
+
);
|
|
144
|
+
const { id: newId, tombstoneBlocked } = await dst.writeSealedMemory(
|
|
145
|
+
promoteEnvelope,
|
|
146
|
+
{
|
|
147
|
+
importance: mem.frontmatter.importance,
|
|
148
|
+
supersedes: mem.frontmatter.supersedes,
|
|
149
|
+
links: mem.frontmatter.links
|
|
150
|
+
}
|
|
151
|
+
);
|
|
152
|
+
if (tombstoneBlocked) {
|
|
153
|
+
return `Promotion of ${srcNs}:${memoryId} \u2192 ${dstNs}:${newId} is queued for review (tombstone-blocked): no active promoted copy was created.`;
|
|
154
|
+
}
|
|
155
|
+
try {
|
|
156
|
+
if (orchestrator.config.queryAwareIndexingEnabled && await indexesExistAsync(orchestrator.config.memoryDir)) {
|
|
157
|
+
const promoted = await dst.getMemoryById(newId).catch(() => null);
|
|
158
|
+
if (promoted?.path && promoted.frontmatter?.created) {
|
|
159
|
+
await indexMemoryAsync(
|
|
160
|
+
orchestrator.config.memoryDir,
|
|
161
|
+
promoted.path,
|
|
162
|
+
promoted.frontmatter.created,
|
|
163
|
+
promoted.frontmatter.tags ?? []
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
} catch (err) {
|
|
168
|
+
return `Promoted ${srcNs}:${memoryId} \u2192 ${dstNs}:${newId} (index refresh failed \u2014 recall picks it up on the next maintenance pass: ${displayErrorDetail(err)})`;
|
|
169
|
+
}
|
|
170
|
+
return `Promoted ${srcNs}:${memoryId} \u2192 ${dstNs}:${newId}`;
|
|
171
|
+
}
|
|
172
|
+
|
|
77
173
|
// ../../src/tools.ts
|
|
78
174
|
import { WorkStorage } from "@remnic/core/work/storage";
|
|
79
175
|
import { exportWorkBoardMarkdown, exportWorkBoardSnapshot, importWorkBoardSnapshot } from "@remnic/core/work/board";
|
|
@@ -310,7 +406,7 @@ function registerTools(api, orchestrator) {
|
|
|
310
406
|
const actionTypeSet = new Set(actionTypes);
|
|
311
407
|
function promptHashForTelemetry(input) {
|
|
312
408
|
if (typeof input !== "string" || input.trim().length === 0) return void 0;
|
|
313
|
-
return
|
|
409
|
+
return createHash2("sha256").update(input).digest("hex").slice(0, 16);
|
|
314
410
|
}
|
|
315
411
|
function normalizeMemoryCategory(value, fallback) {
|
|
316
412
|
const normalized = asNonEmptyString(value);
|
|
@@ -1503,9 +1599,13 @@ NOTE: You did not provide sessionKey; under concurrency this may not match your
|
|
|
1503
1599
|
let queuedForReview = false;
|
|
1504
1600
|
switch (action) {
|
|
1505
1601
|
case "store_episode": {
|
|
1506
|
-
const
|
|
1602
|
+
const episodeEnvelope = composeSalvagedEnvelope2(
|
|
1603
|
+
"memory-action",
|
|
1604
|
+
{ content: contentValue, category: normalizedCategory ?? "fact" },
|
|
1605
|
+
{ source: "memory_action_apply" }
|
|
1606
|
+
);
|
|
1607
|
+
const { id: createdId, tombstoneBlocked } = await storage.writeSealedMemory(episodeEnvelope, {
|
|
1507
1608
|
actor: "tool.memory_action_apply",
|
|
1508
|
-
source: "memory_action_apply",
|
|
1509
1609
|
memoryKind: "episode"
|
|
1510
1610
|
});
|
|
1511
1611
|
outputMemoryIds.push(createdId);
|
|
@@ -1518,9 +1618,13 @@ NOTE: You did not provide sessionKey; under concurrency this may not match your
|
|
|
1518
1618
|
break;
|
|
1519
1619
|
}
|
|
1520
1620
|
case "store_note": {
|
|
1521
|
-
const
|
|
1522
|
-
|
|
1523
|
-
|
|
1621
|
+
const noteEnvelope = composeSalvagedEnvelope2(
|
|
1622
|
+
"memory-action",
|
|
1623
|
+
{ content: contentValue, category: normalizedCategory ?? "fact" },
|
|
1624
|
+
{ source: "memory_action_apply" }
|
|
1625
|
+
);
|
|
1626
|
+
const { id: createdId, tombstoneBlocked } = await storage.writeSealedMemory(noteEnvelope, {
|
|
1627
|
+
actor: "tool.memory_action_apply"
|
|
1524
1628
|
});
|
|
1525
1629
|
outputMemoryIds.push(createdId);
|
|
1526
1630
|
if (tombstoneBlocked) {
|
|
@@ -1572,9 +1676,13 @@ NOTE: You did not provide sessionKey; under concurrency this may not match your
|
|
|
1572
1676
|
break;
|
|
1573
1677
|
}
|
|
1574
1678
|
case "summarize_node": {
|
|
1575
|
-
const
|
|
1679
|
+
const summaryEnvelope = composeSalvagedEnvelope2(
|
|
1680
|
+
"memory-action",
|
|
1681
|
+
{ content: contentValue, category: normalizedCategory ?? "fact" },
|
|
1682
|
+
{ source: "memory_action_apply" }
|
|
1683
|
+
);
|
|
1684
|
+
const { id: createdId, tombstoneBlocked } = await storage.writeSealedMemory(summaryEnvelope, {
|
|
1576
1685
|
actor: "tool.memory_action_apply",
|
|
1577
|
-
source: "memory_action_apply",
|
|
1578
1686
|
sourceMemoryId: memoryIdValue
|
|
1579
1687
|
});
|
|
1580
1688
|
outputMemoryIds.push(createdId);
|
|
@@ -1922,36 +2030,11 @@ Best for:
|
|
|
1922
2030
|
"Namespaces are disabled. Enable `namespacesEnabled: true` to use memory promotion."
|
|
1923
2031
|
);
|
|
1924
2032
|
}
|
|
1925
|
-
const
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
if (!mem) {
|
|
1931
|
-
return toolResult(`Memory not found in ${srcNs}: ${memoryId}`);
|
|
1932
|
-
}
|
|
1933
|
-
const dst = await orchestrator.getStorage(dstNs);
|
|
1934
|
-
const { id: newId, tombstoneBlocked } = await dst.writeMemory(mem.frontmatter.category, mem.content, {
|
|
1935
|
-
confidence: mem.frontmatter.confidence,
|
|
1936
|
-
tags: Array.from(/* @__PURE__ */ new Set([...mem.frontmatter.tags ?? [], "promoted", `promotedFrom:${srcNs}:${memoryId}`, ...note ? [`note:${note}`] : []])),
|
|
1937
|
-
entityRef: mem.frontmatter.entityRef,
|
|
1938
|
-
source: "promote",
|
|
1939
|
-
importance: mem.frontmatter.importance,
|
|
1940
|
-
supersedes: mem.frontmatter.supersedes,
|
|
1941
|
-
links: mem.frontmatter.links
|
|
1942
|
-
});
|
|
1943
|
-
if (tombstoneBlocked) {
|
|
1944
|
-
return toolResult(
|
|
1945
|
-
`Promotion of ${srcNs}:${memoryId} \u2192 ${dstNs}:${newId} is queued for review (tombstone-blocked): no active promoted copy was created.`
|
|
1946
|
-
);
|
|
1947
|
-
}
|
|
1948
|
-
if (orchestrator.config.queryAwareIndexingEnabled && await indexesExistAsync(orchestrator.config.memoryDir)) {
|
|
1949
|
-
const promoted = await dst.getMemoryById(newId).catch(() => null);
|
|
1950
|
-
if (promoted?.path && promoted.frontmatter?.created) {
|
|
1951
|
-
await indexMemoryAsync(orchestrator.config.memoryDir, promoted.path, promoted.frontmatter.created, promoted.frontmatter.tags ?? []);
|
|
1952
|
-
}
|
|
1953
|
-
}
|
|
1954
|
-
return toolResult(`Promoted ${srcNs}:${memoryId} \u2192 ${dstNs}:${newId}`);
|
|
2033
|
+
const message = await executeMemoryPromote(
|
|
2034
|
+
orchestrator,
|
|
2035
|
+
params
|
|
2036
|
+
);
|
|
2037
|
+
return toolResult(message);
|
|
1955
2038
|
}
|
|
1956
2039
|
},
|
|
1957
2040
|
{ name: "memory_promote" }
|
|
@@ -2989,7 +3072,7 @@ import { createOpikExporter, OpikExporter } from "@remnic/core/opik-exporter";
|
|
|
2989
3072
|
|
|
2990
3073
|
// ../../src/index.ts
|
|
2991
3074
|
import { readEnvVar, resolveHomeDir } from "@remnic/core/runtime/env";
|
|
2992
|
-
import { displayErrorDetail } from "@remnic/core/runtime/better-sqlite";
|
|
3075
|
+
import { displayErrorDetail as displayErrorDetail2 } from "@remnic/core/runtime/better-sqlite";
|
|
2993
3076
|
|
|
2994
3077
|
// ../../src/migrate/from-engram.ts
|
|
2995
3078
|
import { migrateFromEngram, rollbackFromEngramMigration } from "@remnic/core/migrate/from-engram";
|
|
@@ -3275,6 +3358,7 @@ function buildMemorySearchTool(orchestrator, options = {}) {
|
|
|
3275
3358
|
}
|
|
3276
3359
|
|
|
3277
3360
|
// src/runtime-surfaces.ts
|
|
3361
|
+
import { composeSalvagedEnvelope as composeSalvagedEnvelope3 } from "@remnic/core/salvage-envelope";
|
|
3278
3362
|
import { gatewayTaskChainOptions } from "@remnic/core/fallback-llm";
|
|
3279
3363
|
function resolveDreamNarrativeRoute(config, directClientAvailable) {
|
|
3280
3364
|
if (config.modelSource === "gateway") {
|
|
@@ -3484,13 +3568,14 @@ async function syncDreamSurfaceEntries(params) {
|
|
|
3484
3568
|
};
|
|
3485
3569
|
const existing = findSurfaceMemoryByAttribute(memories, DREAM_ENTRY_ID_KEY, entry.id);
|
|
3486
3570
|
if (!existing) {
|
|
3487
|
-
const { id: memoryId } = await storage.
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3571
|
+
const { id: memoryId } = await storage.writeSealedMemory(
|
|
3572
|
+
composeSalvagedEnvelope3(
|
|
3573
|
+
"dreams-surface",
|
|
3574
|
+
{ content, category: "moment", confidence: 0.85, tags, structuredAttributes },
|
|
3575
|
+
{ source: "dreams.md" }
|
|
3576
|
+
),
|
|
3577
|
+
{ memoryKind: "dream" }
|
|
3578
|
+
);
|
|
3494
3579
|
memories.push(
|
|
3495
3580
|
makeSurfaceMemorySnapshot({
|
|
3496
3581
|
id: memoryId,
|
|
@@ -3543,13 +3628,14 @@ async function syncHeartbeatSurfaceEntries(params) {
|
|
|
3543
3628
|
};
|
|
3544
3629
|
const existing = findSurfaceMemoryByAttribute(memories, HEARTBEAT_ENTRY_ID_KEY, entry.id) ?? findUniqueSurfaceMemoryBySlug(memories, HEARTBEAT_SURFACE_TYPE, entry.slug);
|
|
3545
3630
|
if (!existing) {
|
|
3546
|
-
const { id: memoryId } = await storage.
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3631
|
+
const { id: memoryId } = await storage.writeSealedMemory(
|
|
3632
|
+
composeSalvagedEnvelope3(
|
|
3633
|
+
"heartbeat-surface",
|
|
3634
|
+
{ content, category: "principle", confidence: 0.95, tags, structuredAttributes },
|
|
3635
|
+
{ source: "heartbeat.md" }
|
|
3636
|
+
),
|
|
3637
|
+
{ memoryKind: "procedural" }
|
|
3638
|
+
);
|
|
3553
3639
|
memories.push(
|
|
3554
3640
|
makeSurfaceMemorySnapshot({
|
|
3555
3641
|
id: memoryId,
|
|
@@ -4051,7 +4137,7 @@ function validateSlotSelection(ctx) {
|
|
|
4051
4137
|
|
|
4052
4138
|
// ../../src/openclaw-flush-plan-lifecycle.ts
|
|
4053
4139
|
import path2 from "path";
|
|
4054
|
-
import { createHash as
|
|
4140
|
+
import { createHash as createHash3, randomUUID } from "crypto";
|
|
4055
4141
|
import * as fsReadModule0 from "fs/promises";
|
|
4056
4142
|
const lstat2 = fsReadModule0.lstat;
|
|
4057
4143
|
const mkdir = fsReadModule0.mkdir;
|
|
@@ -4111,7 +4197,7 @@ function isPathInsideOrEqual(parentPath, childPath) {
|
|
|
4111
4197
|
return relative === "" || !relative.startsWith("..") && !path2.isAbsolute(relative);
|
|
4112
4198
|
}
|
|
4113
4199
|
function hashContent(content) {
|
|
4114
|
-
return
|
|
4200
|
+
return createHash3("sha256").update(content, "utf8").digest("hex");
|
|
4115
4201
|
}
|
|
4116
4202
|
function utf8PrefixByByteLength(content, byteLength) {
|
|
4117
4203
|
const buffer = Buffer.from(content, "utf8");
|
|
@@ -5986,7 +6072,7 @@ function stableOpenClawConfigSignature(value, seen = /* @__PURE__ */ new WeakSet
|
|
|
5986
6072
|
return JSON.stringify(String(value));
|
|
5987
6073
|
}
|
|
5988
6074
|
function openClawHostEmbeddingConfigSignature(cfg, apiConfig, workspaceDir) {
|
|
5989
|
-
return `sha256:${
|
|
6075
|
+
return `sha256:${createHash4("sha256").update(JSON.stringify({
|
|
5990
6076
|
enabled: cfg.hostEmbeddingProviderEnabled !== false,
|
|
5991
6077
|
memoryDir: cfg.memoryDir,
|
|
5992
6078
|
providerId: cfg.hostEmbeddingProviderId ?? "",
|
|
@@ -6346,7 +6432,7 @@ var pluginDefinition = {
|
|
|
6346
6432
|
);
|
|
6347
6433
|
}
|
|
6348
6434
|
} catch (error) {
|
|
6349
|
-
const detail =
|
|
6435
|
+
const detail = displayErrorDetail2(error) || "unknown error";
|
|
6350
6436
|
logger_exports.log.warn(`OpenClaw flush-plan processing failed: ${detail}`);
|
|
6351
6437
|
}
|
|
6352
6438
|
}
|
|
@@ -6540,6 +6626,7 @@ Keep the reflection grounded in the evidence below.
|
|
|
6540
6626
|
queryMode: cfg.activeRecallQueryMode,
|
|
6541
6627
|
promptStyle: cfg.activeRecallPromptStyle,
|
|
6542
6628
|
customInstruction: cfg.activeRecallCustomInstruction,
|
|
6629
|
+
promptReplacement: cfg.activeRecallPromptReplacement,
|
|
6543
6630
|
promptAppend: cfg.activeRecallPromptAppend,
|
|
6544
6631
|
maxSummaryChars: cfg.activeRecallMaxSummaryChars,
|
|
6545
6632
|
recentUserTurns: cfg.activeRecallRecentUserTurns,
|
|
@@ -6635,7 +6722,7 @@ Keep the reflection grounded in the evidence below.
|
|
|
6635
6722
|
}
|
|
6636
6723
|
}, buildInlineExplicitCaptureDedupeKey2 = function(messageKey, note) {
|
|
6637
6724
|
if (!messageKey) return null;
|
|
6638
|
-
return `${messageKey}:inline-memory-note:${
|
|
6725
|
+
return `${messageKey}:inline-memory-note:${createHash4("sha256").update(JSON.stringify(note)).digest("hex")}`;
|
|
6639
6726
|
}, resolveStoredCodexThreadId2 = function(sessionKey) {
|
|
6640
6727
|
const threadId = codexThreadBySession.get(sessionKey);
|
|
6641
6728
|
return typeof threadId === "string" && threadId.length > 0 ? threadId : null;
|
|
@@ -9056,7 +9143,7 @@ function buildOpenClawInboundContentFingerprint(content, message, event, ctx, se
|
|
|
9056
9143
|
normalizeThreadId(message.threadId) ?? normalizeThreadId(event.threadId) ?? normalizeThreadId(ctx.threadId) ?? "",
|
|
9057
9144
|
512
|
|
9058
9145
|
);
|
|
9059
|
-
const contentHash =
|
|
9146
|
+
const contentHash = createHash4("sha256").update(normalizedContent).digest("hex");
|
|
9060
9147
|
return [
|
|
9061
9148
|
sessionPart,
|
|
9062
9149
|
"content",
|
|
@@ -9070,7 +9157,7 @@ function buildOpenClawSparseInboundContentFingerprint(content, sessionKey) {
|
|
|
9070
9157
|
const normalizedContent = content.trim();
|
|
9071
9158
|
if (!normalizedContent) return null;
|
|
9072
9159
|
const sessionPart = truncateMetadataValue(sessionKey || "default", 512);
|
|
9073
|
-
const contentHash =
|
|
9160
|
+
const contentHash = createHash4("sha256").update(normalizedContent).digest("hex");
|
|
9074
9161
|
return `${sessionPart}\0sparse-content\0${contentHash}`;
|
|
9075
9162
|
}
|
|
9076
9163
|
function withReplyExtractionHint(content, metadata) {
|
package/openclaw.plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "openclaw-remnic",
|
|
3
3
|
"name": "Remnic OpenClaw Plugin",
|
|
4
|
-
"version": "9.
|
|
4
|
+
"version": "9.9.0",
|
|
5
5
|
"kind": "memory",
|
|
6
6
|
"description": "Local semantic memory for OpenClaw with bundled Remnic core runtime. Requires plugins.slots.memory set to this plugin id for hooks to fire.",
|
|
7
7
|
"setup": {
|
|
@@ -225,6 +225,14 @@
|
|
|
225
225
|
"type": "string",
|
|
226
226
|
"description": "Optional additional guidance for the active-recall builder."
|
|
227
227
|
},
|
|
228
|
+
"activeRecallPromptOverride": {
|
|
229
|
+
"type": "string",
|
|
230
|
+
"description": "Legacy optional custom instruction for the active-recall builder."
|
|
231
|
+
},
|
|
232
|
+
"activeRecallPromptReplacement": {
|
|
233
|
+
"type": "string",
|
|
234
|
+
"description": "Optional complete replacement prompt for the active-recall builder."
|
|
235
|
+
},
|
|
228
236
|
"activeRecallPromptStyle": {
|
|
229
237
|
"type": "string",
|
|
230
238
|
"enum": [
|
|
@@ -585,6 +593,13 @@
|
|
|
585
593
|
"default": 5,
|
|
586
594
|
"description": "Max turns before forced extraction"
|
|
587
595
|
},
|
|
596
|
+
"bufferSaveDebounceMs": {
|
|
597
|
+
"type": "integer",
|
|
598
|
+
"default": 3000,
|
|
599
|
+
"minimum": 0,
|
|
600
|
+
"maximum": 2147483647,
|
|
601
|
+
"description": "Debounce window (ms) for persisting the smart buffer to state/buffer.json. Steady-state buffering coalesces the whole-state write onto a trailing-edge timer instead of rewriting every turn; extraction trigger/clear and shutdown force an immediate flush. 0 restores save-every-turn. Capped at 2147483647 (Node's 32-bit setTimeout limit)."
|
|
602
|
+
},
|
|
588
603
|
"bufferSurpriseK": {
|
|
589
604
|
"type": "number",
|
|
590
605
|
"default": 5,
|
|
@@ -1496,6 +1511,68 @@
|
|
|
1496
1511
|
"default": "off",
|
|
1497
1512
|
"description": "Passive correction capture (#1581) — detects corrections expressed in conversation during extraction and routes them to the Correction Contract (#1580). \"off\" disables detection (default, rule 48); \"queue\" plans corrections for human review in the review list; \"auto\" applies immediately when all safety guards pass (confidence floor, blast-radius cap, allowed action/classification), otherwise falls back to queue. Invalid values are rejected (rule 51)."
|
|
1498
1513
|
},
|
|
1514
|
+
"correction": {
|
|
1515
|
+
"type": "object",
|
|
1516
|
+
"description": "Memory-correction contract (issue #1580) — nested form; nested keys win over the flat legacy correction* keys.",
|
|
1517
|
+
"properties": {
|
|
1518
|
+
"enabled": {
|
|
1519
|
+
"type": "boolean",
|
|
1520
|
+
"description": "Enable the correction contract (plan/apply). Default true."
|
|
1521
|
+
},
|
|
1522
|
+
"applyRequiresConfirm": {
|
|
1523
|
+
"type": "boolean",
|
|
1524
|
+
"description": "Require confirm: true on memory_correct_apply. Default true."
|
|
1525
|
+
},
|
|
1526
|
+
"maxAffected": {
|
|
1527
|
+
"type": "integer",
|
|
1528
|
+
"minimum": 1,
|
|
1529
|
+
"description": "Maximum memories one correction plan may touch. Default 10."
|
|
1530
|
+
},
|
|
1531
|
+
"planTtlHours": {
|
|
1532
|
+
"type": "number",
|
|
1533
|
+
"minimum": 1,
|
|
1534
|
+
"description": "Hours a planned correction stays applicable. Default 24."
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
},
|
|
1538
|
+
"correctionCapture": {
|
|
1539
|
+
"type": "object",
|
|
1540
|
+
"description": "Implicit correction capture (nested form; nested keys win over the flat legacy correctionCapture* keys).",
|
|
1541
|
+
"properties": {
|
|
1542
|
+
"mode": {
|
|
1543
|
+
"type": "string",
|
|
1544
|
+
"enum": [
|
|
1545
|
+
"off",
|
|
1546
|
+
"queue",
|
|
1547
|
+
"auto"
|
|
1548
|
+
],
|
|
1549
|
+
"description": "Implicit capture mode. Default off."
|
|
1550
|
+
},
|
|
1551
|
+
"confidenceFloor": {
|
|
1552
|
+
"type": "number",
|
|
1553
|
+
"minimum": 0,
|
|
1554
|
+
"maximum": 1,
|
|
1555
|
+
"description": "Minimum detector confidence to act on. Default 0.85."
|
|
1556
|
+
},
|
|
1557
|
+
"autoApplyMaxAffected": {
|
|
1558
|
+
"type": "integer",
|
|
1559
|
+
"minimum": 1,
|
|
1560
|
+
"description": "Auto-apply ceiling on affected memories. Default 2."
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
},
|
|
1564
|
+
"openclawHostEmbeddingProviderEnabled": {
|
|
1565
|
+
"type": "boolean",
|
|
1566
|
+
"description": "Legacy alias for hostEmbeddingProviderEnabled (OpenClaw host embedding provider). Default true."
|
|
1567
|
+
},
|
|
1568
|
+
"openclawHostEmbeddingProviderId": {
|
|
1569
|
+
"type": "string",
|
|
1570
|
+
"description": "Legacy alias for hostEmbeddingProviderId."
|
|
1571
|
+
},
|
|
1572
|
+
"openclawHostEmbeddingProviderModel": {
|
|
1573
|
+
"type": "string",
|
|
1574
|
+
"description": "Legacy alias for hostEmbeddingProviderModel."
|
|
1575
|
+
},
|
|
1499
1576
|
"correctionEnabled": {
|
|
1500
1577
|
"type": "boolean",
|
|
1501
1578
|
"default": true,
|
|
@@ -3163,6 +3240,18 @@
|
|
|
3163
3240
|
"default": "",
|
|
3164
3241
|
"description": "Root directory for memory extensions. Empty string derives from memoryDir (go up to Remnic home and append memory_extensions)."
|
|
3165
3242
|
},
|
|
3243
|
+
"memoryLifecycleLedgerCompactBytes": {
|
|
3244
|
+
"type": "integer",
|
|
3245
|
+
"default": 67108864,
|
|
3246
|
+
"minimum": 0,
|
|
3247
|
+
"description": "Auto-compact state/memory-lifecycle-ledger.jsonl when it exceeds this many bytes, triggered off the debounced maintenance path (issue #1910). Set 0 to disable. Default 64MB."
|
|
3248
|
+
},
|
|
3249
|
+
"memoryLifecycleLedgerCompactMinIntervalMs": {
|
|
3250
|
+
"type": "integer",
|
|
3251
|
+
"default": 21600000,
|
|
3252
|
+
"minimum": 60000,
|
|
3253
|
+
"description": "Minimum interval between auto-compactions of the lifecycle ledger (issue #1910). Default 6 hours."
|
|
3254
|
+
},
|
|
3166
3255
|
"memoryLinkingEnabled": {
|
|
3167
3256
|
"type": "boolean",
|
|
3168
3257
|
"default": false,
|
|
@@ -3771,6 +3860,11 @@
|
|
|
3771
3860
|
"default": 900,
|
|
3772
3861
|
"description": "Token budget for each proactive extraction sub-call (0 disables the proactive second pass)."
|
|
3773
3862
|
},
|
|
3863
|
+
"proactiveExtractionSkipWhenLocalLlmBusy": {
|
|
3864
|
+
"type": "boolean",
|
|
3865
|
+
"default": true,
|
|
3866
|
+
"description": "Skip the optional proactive extraction second pass when the local LLM background lane is already busy, instead of queueing behind an in-flight extraction and losing its shorter deadline (issue #2011). Set false to always attempt the second pass."
|
|
3867
|
+
},
|
|
3774
3868
|
"proactiveExtractionTimeoutMs": {
|
|
3775
3869
|
"type": "number",
|
|
3776
3870
|
"default": 2500,
|
|
@@ -4015,6 +4109,12 @@
|
|
|
4015
4109
|
"default": true,
|
|
4016
4110
|
"description": "Enable debounced background QMD maintenance instead of immediate updates on extraction."
|
|
4017
4111
|
},
|
|
4112
|
+
"qmdEmbeddingBacklogThreshold": {
|
|
4113
|
+
"type": "integer",
|
|
4114
|
+
"minimum": 0,
|
|
4115
|
+
"default": 1000,
|
|
4116
|
+
"description": "Pending-embedding count above which QMD health reports degraded. Set to 0 to disable backlog degradation."
|
|
4117
|
+
},
|
|
4018
4118
|
"qmdMaxResults": {
|
|
4019
4119
|
"type": "number",
|
|
4020
4120
|
"default": 8,
|
|
@@ -4197,6 +4297,13 @@
|
|
|
4197
4297
|
"type": "number",
|
|
4198
4298
|
"description": "Hard character cap for total recall context. Defaults to maxMemoryTokens * 4."
|
|
4199
4299
|
},
|
|
4300
|
+
"recallProfileMaxRatio": {
|
|
4301
|
+
"type": "number",
|
|
4302
|
+
"minimum": 0,
|
|
4303
|
+
"maximum": 1,
|
|
4304
|
+
"default": 0.3,
|
|
4305
|
+
"description": "Maximum fraction of the total recall budget available to the behavioral profile. Set to 1 to disable the share cap."
|
|
4306
|
+
},
|
|
4200
4307
|
"recallConfidenceGateEnabled": {
|
|
4201
4308
|
"type": "boolean",
|
|
4202
4309
|
"default": false,
|
|
@@ -4329,6 +4436,25 @@
|
|
|
4329
4436
|
"default": 5,
|
|
4330
4437
|
"description": "Issue #1582 — number of recent per-session recall snapshots searched when resolving a `[m:xxxx]` handle to a memory id. Older-than-N snapshots are not searched; a miss is tagged rather than widening the window."
|
|
4331
4438
|
},
|
|
4439
|
+
"recallImpressionsRotateBytes": {
|
|
4440
|
+
"type": "integer",
|
|
4441
|
+
"default": 33554432,
|
|
4442
|
+
"minimum": 0,
|
|
4443
|
+
"description": "Rotate state/recall_impressions.jsonl to .1..N when it exceeds this many bytes (issue #1910). Set 0 to disable. Default 32MB."
|
|
4444
|
+
},
|
|
4445
|
+
"recallImpressionsRotateKeep": {
|
|
4446
|
+
"type": "integer",
|
|
4447
|
+
"default": 5,
|
|
4448
|
+
"minimum": 1,
|
|
4449
|
+
"maximum": 1000,
|
|
4450
|
+
"description": "Number of rotated recall-impression archives to keep (.1 .. .N) (issue #1910). Default 5. Max 1000: each retained slot costs one rename under the held impressions lock per rotation, so a larger value is rejected at config-parse time before it can stall recall recording."
|
|
4451
|
+
},
|
|
4452
|
+
"recallMaxConcurrentPerPrincipal": {
|
|
4453
|
+
"type": "integer",
|
|
4454
|
+
"minimum": 0,
|
|
4455
|
+
"default": 4,
|
|
4456
|
+
"description": "Maximum concurrent recalls executed per principal (issue #1906). Recalls beyond this cap queue FIFO; an aborted waiter leaves the queue immediately. 0 = unlimited (no cap). Replaces the former width-1 budget-lock serialization; budget accounting stays correct because peek/record are synchronous. Set 1 to restore exact serialization."
|
|
4457
|
+
},
|
|
4332
4458
|
"recallMemoryHandles": {
|
|
4333
4459
|
"type": "boolean",
|
|
4334
4460
|
"default": false,
|
|
@@ -4339,6 +4465,11 @@
|
|
|
4339
4465
|
"default": true,
|
|
4340
4466
|
"description": "When true, recall multiplies candidate scores by the Memory Worth factor (mw_success / mw_fail counters, see issue #560). Memories with a history of failed sessions sink; neutral/uninstrumented memories are untouched. PR 5 bench: +0.60 precision@5 vs baseline on all 50 seeded cases. Operators can opt out with false."
|
|
4341
4467
|
},
|
|
4468
|
+
"recallTrustStageCorpusFallbackEnabled": {
|
|
4469
|
+
"type": "boolean",
|
|
4470
|
+
"default": true,
|
|
4471
|
+
"description": "When true (default), the Memory-Worth/TrustScore recall rerank stage probes a per-namespace corpus counter/signal map for candidates whose frontmatter was NOT already loaded on the hot path (cold-tier / embedding-fallback / archive rows). The map is version-keyed (invalidated on corpus mutation) and age-bounded for trust signals, so it hits in steady state without the old 30s-TTL permanent-miss. Set false to disable the corpus fallback entirely (only preloaded-candidate + direct-read paths run) — max performance when every candidate is hot, at the cost of neutral treatment for cold candidates."
|
|
4472
|
+
},
|
|
4342
4473
|
"hotMemoriesCacheEnabled": {
|
|
4343
4474
|
"type": "boolean",
|
|
4344
4475
|
"default": true,
|
|
@@ -4433,6 +4564,26 @@
|
|
|
4433
4564
|
},
|
|
4434
4565
|
"forceGeneric": {
|
|
4435
4566
|
"type": "boolean"
|
|
4567
|
+
},
|
|
4568
|
+
"maxHints": {
|
|
4569
|
+
"type": "number",
|
|
4570
|
+
"description": "Per-section cap on injected hint lines."
|
|
4571
|
+
},
|
|
4572
|
+
"maxSupportingFacts": {
|
|
4573
|
+
"type": "number",
|
|
4574
|
+
"description": "Per-section cap on supporting facts."
|
|
4575
|
+
},
|
|
4576
|
+
"maxRelatedEntities": {
|
|
4577
|
+
"type": "number",
|
|
4578
|
+
"description": "Per-section cap on related entities."
|
|
4579
|
+
},
|
|
4580
|
+
"recentTurns": {
|
|
4581
|
+
"type": "number",
|
|
4582
|
+
"description": "Per-section recent-turn scan window."
|
|
4583
|
+
},
|
|
4584
|
+
"maxRubrics": {
|
|
4585
|
+
"type": "number",
|
|
4586
|
+
"description": "Per-section cap on injected rubrics."
|
|
4436
4587
|
}
|
|
4437
4588
|
},
|
|
4438
4589
|
"required": [
|
|
@@ -4500,6 +4651,11 @@
|
|
|
4500
4651
|
"default": false,
|
|
4501
4652
|
"description": "Boost stored reasoning_trace memories in recall results when the incoming query reads like a problem-solving ask (e.g. 'how do I...', 'step by step', 'walk me through...'). Default false - opt in after benchmarking (issue #564)."
|
|
4502
4653
|
},
|
|
4654
|
+
"recallSingleFlightEnabled": {
|
|
4655
|
+
"type": "boolean",
|
|
4656
|
+
"default": true,
|
|
4657
|
+
"description": "When true (default), identical concurrent recalls for the same principal share a single in-flight execution (single-flight coalescing, issue #1906); each caller still receives its own cloned response and records its own budget event. Set false to restore per-request execution."
|
|
4658
|
+
},
|
|
4503
4659
|
"recallTranscriptRetentionDays": {
|
|
4504
4660
|
"type": "integer",
|
|
4505
4661
|
"minimum": 1,
|
|
@@ -6878,6 +7034,11 @@
|
|
|
6878
7034
|
"advanced": true,
|
|
6879
7035
|
"placeholder": "2500"
|
|
6880
7036
|
},
|
|
7037
|
+
"proactiveExtractionSkipWhenLocalLlmBusy": {
|
|
7038
|
+
"label": "Skip Proactive When Local LLM Busy",
|
|
7039
|
+
"advanced": true,
|
|
7040
|
+
"help": "Skip the optional proactive extraction pass when the local LLM background lane is saturated, rather than queueing behind an in-flight extraction (issue #2011, default on)"
|
|
7041
|
+
},
|
|
6881
7042
|
"proactiveExtractionMaxTokens": {
|
|
6882
7043
|
"label": "Proactive Extraction Max Tokens",
|
|
6883
7044
|
"advanced": true,
|
|
@@ -6997,6 +7158,12 @@
|
|
|
6997
7158
|
"advanced": true,
|
|
6998
7159
|
"placeholder": "8000"
|
|
6999
7160
|
},
|
|
7161
|
+
"recallProfileMaxRatio": {
|
|
7162
|
+
"label": "Recall Profile Budget Share",
|
|
7163
|
+
"advanced": true,
|
|
7164
|
+
"placeholder": "0.3",
|
|
7165
|
+
"help": "Maximum fraction of the total recall budget available to the behavioral profile. Set to 1 to disable the share cap."
|
|
7166
|
+
},
|
|
7000
7167
|
"recallPipeline": {
|
|
7001
7168
|
"label": "Recall Pipeline",
|
|
7002
7169
|
"advanced": true,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remnic/plugin-openclaw",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.9.0",
|
|
4
4
|
"description": "OpenClaw adapter for Remnic memory with bundled @remnic/core runtime",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"dependencies": {
|
|
73
73
|
"@sinclair/typebox": "^0.34.0",
|
|
74
74
|
"openai": "^6.0.0",
|
|
75
|
-
"@remnic/core": "^9.
|
|
75
|
+
"@remnic/core": "^9.9.0"
|
|
76
76
|
},
|
|
77
77
|
"peerDependencies": {
|
|
78
78
|
"openclaw": ">=2026.4.1 || 2026.4.7-1 || 2026.4.9-beta.1 || 2026.4.11-beta.1 || 2026.4.12-beta.1 || 2026.4.14-beta.1 || 2026.4.15-beta.1 || 2026.4.15-beta.2 || 2026.4.19-beta.1 || 2026.4.19-beta.2 || 2026.4.20-beta.1 || 2026.4.20-beta.2 || 2026.4.22-beta.1 || 2026.4.23-beta.1 || 2026.4.23-beta.2 || 2026.4.23-beta.3 || 2026.4.23-beta.4 || 2026.4.23-beta.5 || 2026.4.23-beta.6 || 2026.4.24-beta.1 || 2026.4.24-beta.2 || 2026.4.24-beta.3 || 2026.4.24-beta.4 || 2026.4.24-beta.5 || 2026.4.24-beta.6 || 2026.4.25-beta.1 || 2026.4.25-beta.2 || 2026.4.25-beta.3 || 2026.4.25-beta.4 || 2026.4.25-beta.5 || 2026.4.25-beta.6 || 2026.4.25-beta.7 || 2026.4.25-beta.8 || 2026.4.25-beta.9 || 2026.4.25-beta.10 || 2026.4.25-beta.11 || 2026.4.26-beta.1 || 2026.4.27-beta.1 || 2026.4.29-beta.1 || 2026.4.29-beta.2 || 2026.4.29-beta.3 || 2026.4.29-beta.4 || 2026.4.30-beta.1 || 2026.5.2-beta.1 || 2026.5.2-beta.2 || 2026.5.2-beta.3 || 2026.5.3-beta.1 || 2026.5.3-beta.2 || 2026.5.3-beta.3 || 2026.5.3-beta.4 || 2026.5.3-1 || 2026.5.4-beta.1 || 2026.5.4-beta.2 || 2026.5.4-beta.3 || 2026.5.5-beta.1 || 2026.5.5-beta.2 || 2026.5.6-beta.1 || 2026.5.7-beta.1 || 2026.5.9-beta.1 || 2026.5.10-beta.1 || 2026.5.10-beta.2 || 2026.5.10-beta.3 || 2026.5.10-beta.4 || 2026.5.10-beta.5 || 2026.5.10-beta.6 || 2026.5.12-beta.1 || 2026.5.12-beta.2 || 2026.5.12-beta.3 || 2026.5.12-beta.4 || 2026.5.12-beta.5 || 2026.5.12-beta.6 || 2026.5.12-beta.7 || 2026.5.12-beta.8 || 2026.5.14-beta.1 || 2026.5.14-beta.2 || 2026.5.16-beta.1 || 2026.5.16-beta.2 || 2026.5.16-beta.3 || 2026.5.16-beta.4 || 2026.5.16-beta.5 || 2026.5.16-beta.6 || 2026.5.16-beta.7 || 2026.5.18-beta.1 || 2026.5.19-alpha.1 || 2026.5.19-beta.1 || 2026.5.19-beta.2 || 2026.5.20-beta.1 || 2026.5.20-beta.2 || 2026.5.21-alpha.1 || 2026.5.21-beta.1 || 2026.5.22-beta.1 || 2026.5.23-alpha.1 || 2026.5.24-alpha.1 || 2026.5.24-beta.1 || 2026.5.24-beta.2 || 2026.5.25-alpha.1 || 2026.5.25-alpha.2 || 2026.5.25-beta.1 || 2026.5.26-beta.1 || 2026.5.26-beta.2 || 2026.5.27-alpha.1 || 2026.5.27-beta.1 || 2026.5.28-alpha.1 || 2026.5.28-beta.1 || 2026.5.28-beta.2 || 2026.5.28-beta.3 || 2026.5.28-beta.4 || 2026.5.29-alpha.1 || 2026.5.30-beta.1 || 2026.5.30-beta.2 || 2026.5.31-alpha.1 || 2026.5.31-beta.1 || 2026.5.31-beta.2 || 2026.5.31-beta.3 || 2026.5.31-beta.4 || 2026.6.1-alpha.1 || 2026.6.1-alpha.2 || 2026.6.1-alpha.3 || 2026.6.1-beta.1 || 2026.6.1-beta.2 || 2026.6.1-beta.3 || 2026.6.2-alpha.1 || 2026.6.2-alpha.2 || 2026.6.2-beta.1 || 2026.6.3-alpha.1 || 2026.6.4-alpha.1 || 2026.6.5-alpha.1 || 2026.6.5-alpha.2 || 2026.6.5-beta.1 || 2026.6.5-beta.2 || 2026.6.5-beta.3 || 2026.6.5-beta.5 || 2026.6.5-beta.6 || 2026.6.6-alpha.1 || 2026.6.6-beta.2 || 2026.6.6 || 2026.6.7-beta.1 || 2026.6.8-beta.1 || 2026.6.8-beta.2 || 2026.6.9-beta.1 || 2026.6.10-beta.1 || 2026.6.10-beta.2 || 2026.6.11-beta.1"
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
"acorn": "^8.16.0",
|
|
83
83
|
"tsup": "^8.5.1",
|
|
84
84
|
"typescript": "^5.9.3",
|
|
85
|
-
"@remnic/core": "^9.
|
|
85
|
+
"@remnic/core": "^9.9.0"
|
|
86
86
|
},
|
|
87
87
|
"license": "MIT",
|
|
88
88
|
"repository": {
|