@remnic/plugin-openclaw 9.69.52 → 9.69.54
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js
CHANGED
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
import { loadDaySummaryPrompt } from "@remnic/core/day-summary";
|
|
18
18
|
import OpenAI from "openai";
|
|
19
19
|
import { createRequire } from "module";
|
|
20
|
-
import { createHash as
|
|
20
|
+
import { createHash as createHash3 } from "crypto";
|
|
21
21
|
import { parseConfig } from "@remnic/core/config";
|
|
22
22
|
import { initLogger, log as log8 } from "@remnic/core/logger";
|
|
23
23
|
import {
|
|
@@ -31,9 +31,9 @@ import {
|
|
|
31
31
|
import { beginCodexSubscriptionShutdown, getCodexSubscriptionRunnerForOwner, terminateActiveCodexSubscriptionChildren } from "@remnic/core";
|
|
32
32
|
|
|
33
33
|
// ../../src/tools.ts
|
|
34
|
-
import { createHash
|
|
34
|
+
import { createHash } from "crypto";
|
|
35
35
|
import { Type as Type2 } from "@sinclair/typebox";
|
|
36
|
-
import { indexMemoryAsync
|
|
36
|
+
import { indexMemoryAsync, indexesExistAsync } from "@remnic/core/temporal-index";
|
|
37
37
|
|
|
38
38
|
// ../../src/explicit-capture.ts
|
|
39
39
|
import {
|
|
@@ -59,105 +59,8 @@ function mergeInlineCaptureDedupeKeys(messageKeys, fallbackDedupeKeys = []) {
|
|
|
59
59
|
|
|
60
60
|
// ../../src/tools.ts
|
|
61
61
|
import { log } from "@remnic/core/logger";
|
|
62
|
-
import { composeSalvagedEnvelope as composeSalvagedEnvelope2 } from "@remnic/core/salvage-envelope";
|
|
63
|
-
|
|
64
|
-
// ../../src/memory-promote.ts
|
|
65
|
-
import { createHash } from "crypto";
|
|
66
62
|
import { composeSalvagedEnvelope } from "@remnic/core/salvage-envelope";
|
|
67
|
-
import {
|
|
68
|
-
STRUCTURED_ATTRIBUTE_LIMITS,
|
|
69
|
-
TAG_LIMITS
|
|
70
|
-
} from "@remnic/core/write-envelope";
|
|
71
|
-
import { stripAttributesSuffix } from "@remnic/core/storage";
|
|
72
|
-
import { isSupportPassportPrivateMemory } from "@remnic/core/support-passport";
|
|
73
|
-
import { displayErrorDetail } from "@remnic/core/runtime/better-sqlite";
|
|
74
|
-
import { isSafeRouteNamespace } from "@remnic/core/routing/engine";
|
|
75
|
-
import { indexMemoryAsync, indexesExistAsync } from "@remnic/core/temporal-index";
|
|
76
|
-
function buildPromotionOrigin(srcNamespace, memoryId) {
|
|
77
|
-
const memoryIdHash = createHash("sha256").update(memoryId).digest("hex");
|
|
78
|
-
const fullTag = `promotedFrom:${srcNamespace}:${memoryId}`;
|
|
79
|
-
return {
|
|
80
|
-
tag: fullTag.length <= TAG_LIMITS.maxTagLength ? fullTag : `promotedFromHash:${memoryIdHash}`,
|
|
81
|
-
structuredAttributes: {
|
|
82
|
-
promotedFromNamespace: srcNamespace,
|
|
83
|
-
promotedFromMemoryIdHash: memoryIdHash,
|
|
84
|
-
...memoryId.length <= STRUCTURED_ATTRIBUTE_LIMITS.maxValueLength ? { promotedFromMemoryId: memoryId } : {}
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
async function executeMemoryPromote(orchestrator, params) {
|
|
89
|
-
const { memoryId, fromNamespace, toNamespace, note } = params;
|
|
90
|
-
if (typeof memoryId !== "string" || memoryId.length === 0) {
|
|
91
|
-
return `Invalid memoryId: ${JSON.stringify(memoryId)} \u2014 expected a non-empty memory ID.`;
|
|
92
|
-
}
|
|
93
|
-
for (const [name, value] of [
|
|
94
|
-
["fromNamespace", fromNamespace],
|
|
95
|
-
["toNamespace", toNamespace]
|
|
96
|
-
]) {
|
|
97
|
-
if (value !== void 0 && value !== null && (typeof value !== "string" || !isSafeRouteNamespace(value))) {
|
|
98
|
-
return `Invalid ${name}: ${JSON.stringify(value)} \u2014 expected a path-safe namespace name.`;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
const srcNs = fromNamespace ?? orchestrator.config.defaultNamespace;
|
|
102
|
-
const dstNs = toNamespace ?? orchestrator.config.sharedNamespace;
|
|
103
|
-
const src = await orchestrator.getStorage(srcNs);
|
|
104
|
-
const mem = await src.getMemoryById(memoryId);
|
|
105
|
-
if (!mem || isSupportPassportPrivateMemory(mem)) {
|
|
106
|
-
return `Memory not found in ${srcNs}: ${memoryId}`;
|
|
107
|
-
}
|
|
108
|
-
const dst = await orchestrator.getStorage(dstNs);
|
|
109
|
-
const promotionOrigin = buildPromotionOrigin(srcNs, memoryId);
|
|
110
|
-
const promoteEnvelope = composeSalvagedEnvelope(
|
|
111
|
-
"promote",
|
|
112
|
-
{
|
|
113
|
-
content: mem.frontmatter.structuredAttributes ? stripAttributesSuffix(mem.content) : mem.content,
|
|
114
|
-
category: mem.frontmatter.category,
|
|
115
|
-
confidence: mem.frontmatter.confidence,
|
|
116
|
-
tags: (() => {
|
|
117
|
-
const promotionTags = [
|
|
118
|
-
"promoted",
|
|
119
|
-
promotionOrigin.tag,
|
|
120
|
-
...note ? [`note:${note}`] : []
|
|
121
|
-
];
|
|
122
|
-
const sourceTags = mem.frontmatter.tags ?? [];
|
|
123
|
-
return Array.from(/* @__PURE__ */ new Set([...promotionTags, ...sourceTags])).slice(
|
|
124
|
-
0,
|
|
125
|
-
TAG_LIMITS.maxTags
|
|
126
|
-
);
|
|
127
|
-
})(),
|
|
128
|
-
structuredAttributes: promotionOrigin.structuredAttributes,
|
|
129
|
-
entityRef: mem.frontmatter.entityRef
|
|
130
|
-
},
|
|
131
|
-
{ source: "promote" }
|
|
132
|
-
);
|
|
133
|
-
const { id: newId, tombstoneBlocked } = await dst.writeSealedMemory(
|
|
134
|
-
promoteEnvelope,
|
|
135
|
-
{
|
|
136
|
-
importance: mem.frontmatter.importance,
|
|
137
|
-
supersedes: mem.frontmatter.supersedes,
|
|
138
|
-
links: mem.frontmatter.links
|
|
139
|
-
}
|
|
140
|
-
);
|
|
141
|
-
if (tombstoneBlocked) {
|
|
142
|
-
return `Promotion of ${srcNs}:${memoryId} \u2192 ${dstNs}:${newId} is queued for review (tombstone-blocked): no active promoted copy was created.`;
|
|
143
|
-
}
|
|
144
|
-
try {
|
|
145
|
-
if (orchestrator.config.queryAwareIndexingEnabled && await indexesExistAsync(orchestrator.config.memoryDir)) {
|
|
146
|
-
const promoted = await dst.getMemoryById(newId).catch(() => null);
|
|
147
|
-
if (promoted?.path && promoted.frontmatter?.created) {
|
|
148
|
-
await indexMemoryAsync(
|
|
149
|
-
orchestrator.config.memoryDir,
|
|
150
|
-
promoted.path,
|
|
151
|
-
promoted.frontmatter.created,
|
|
152
|
-
promoted.frontmatter.tags ?? []
|
|
153
|
-
);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
} catch (err) {
|
|
157
|
-
return `Promoted ${srcNs}:${memoryId} \u2192 ${dstNs}:${newId} (index refresh failed \u2014 recall picks it up on the next maintenance pass: ${displayErrorDetail(err)})`;
|
|
158
|
-
}
|
|
159
|
-
return `Promoted ${srcNs}:${memoryId} \u2192 ${dstNs}:${newId}`;
|
|
160
|
-
}
|
|
63
|
+
import { executeMemoryPromote } from "@remnic/plugin-openclaw/plugin/memory-promote";
|
|
161
64
|
|
|
162
65
|
// ../../src/shared-context-tools.ts
|
|
163
66
|
import { Type } from "@sinclair/typebox";
|
|
@@ -372,49 +275,11 @@ import { wrapWorkLayerContext } from "@remnic/core/work/boundary";
|
|
|
372
275
|
import { VALID_MEMORY_CATEGORIES } from "@remnic/core/config";
|
|
373
276
|
import { formatProfileTraceAscii } from "@remnic/core/profiling";
|
|
374
277
|
import { runMemoryGovernance } from "@remnic/core/maintenance/memory-governance";
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
if (value < 0) return 0;
|
|
381
|
-
if (value > 1) return 1;
|
|
382
|
-
return value;
|
|
383
|
-
}
|
|
384
|
-
function normalizeEligibilitySource(value) {
|
|
385
|
-
switch (value) {
|
|
386
|
-
case "extraction":
|
|
387
|
-
case "consolidation":
|
|
388
|
-
case "replay":
|
|
389
|
-
case "manual":
|
|
390
|
-
return value;
|
|
391
|
-
default:
|
|
392
|
-
return "unknown";
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
function deriveMemoryActionPolicyEligibility(memory) {
|
|
396
|
-
if (!memory) return void 0;
|
|
397
|
-
const frontmatter = memory.frontmatter;
|
|
398
|
-
return {
|
|
399
|
-
confidence: clampUnitInterval(frontmatter.confidence, 0),
|
|
400
|
-
lifecycleState: frontmatter.status === "archived" ? "archived" : frontmatter.lifecycleState ?? "candidate",
|
|
401
|
-
importance: clampUnitInterval(frontmatter.importance?.score, 0),
|
|
402
|
-
source: normalizeEligibilitySource(frontmatter.source)
|
|
403
|
-
};
|
|
404
|
-
}
|
|
405
|
-
async function readReferencedMemoryForPolicyEligibility(storage, memoryId) {
|
|
406
|
-
if (!memoryId) return void 0;
|
|
407
|
-
const direct = await storage.getMemoryById?.(memoryId);
|
|
408
|
-
if (direct) return direct;
|
|
409
|
-
const active = (await storage.readAllMemories?.())?.find((memory) => memory.frontmatter.id === memoryId);
|
|
410
|
-
if (active) return active;
|
|
411
|
-
return (await storage.readArchivedMemories?.())?.find((memory) => memory.frontmatter.id === memoryId);
|
|
412
|
-
}
|
|
413
|
-
function blocksSupportPassportMutation(action, memory) {
|
|
414
|
-
return (action === "update_note" || action === "discard" || action === "link_graph") && Boolean(memory && isSupportPassportPrivateMemory2(memory));
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
// ../../src/tools.ts
|
|
278
|
+
import {
|
|
279
|
+
blocksSupportPassportMutation,
|
|
280
|
+
deriveMemoryActionPolicyEligibility,
|
|
281
|
+
readReferencedMemoryForPolicyEligibility
|
|
282
|
+
} from "@remnic/plugin-openclaw/plugin/memory-action-target";
|
|
418
283
|
function toolResult2(text) {
|
|
419
284
|
return { content: [{ type: "text", text }], details: void 0 };
|
|
420
285
|
}
|
|
@@ -599,7 +464,7 @@ function registerTools(api, orchestrator, hostRuntimeAgentId) {
|
|
|
599
464
|
const actionTypeSet = new Set(actionTypes);
|
|
600
465
|
function promptHashForTelemetry(input) {
|
|
601
466
|
if (typeof input !== "string" || input.trim().length === 0) return void 0;
|
|
602
|
-
return
|
|
467
|
+
return createHash("sha256").update(input).digest("hex").slice(0, 16);
|
|
603
468
|
}
|
|
604
469
|
function normalizeMemoryCategory(value, fallback) {
|
|
605
470
|
const normalized = asNonEmptyString(value);
|
|
@@ -654,11 +519,11 @@ function registerTools(api, orchestrator, hostRuntimeAgentId) {
|
|
|
654
519
|
Content: ${candidate.content}`
|
|
655
520
|
);
|
|
656
521
|
}
|
|
657
|
-
if (!result.duplicateOf && orchestrator.config.queryAwareIndexingEnabled && await
|
|
522
|
+
if (!result.duplicateOf && orchestrator.config.queryAwareIndexingEnabled && await indexesExistAsync(orchestrator.config.memoryDir)) {
|
|
658
523
|
const storage = await orchestrator.getStorage(candidate.namespace);
|
|
659
524
|
const mem = await storage.getMemoryById(result.id).catch(() => null);
|
|
660
525
|
if (mem?.path && mem.frontmatter?.created) {
|
|
661
|
-
await
|
|
526
|
+
await indexMemoryAsync(orchestrator.config.memoryDir, mem.path, mem.frontmatter.created, mem.frontmatter.tags ?? []);
|
|
662
527
|
}
|
|
663
528
|
}
|
|
664
529
|
orchestrator.requestQmdMaintenanceForTool(maintenanceReason);
|
|
@@ -1832,7 +1697,7 @@ NOTE: You did not provide sessionKey; under concurrency this may not match your
|
|
|
1832
1697
|
let queuedForReview = false;
|
|
1833
1698
|
switch (action) {
|
|
1834
1699
|
case "store_episode": {
|
|
1835
|
-
const episodeEnvelope =
|
|
1700
|
+
const episodeEnvelope = composeSalvagedEnvelope(
|
|
1836
1701
|
"memory-action",
|
|
1837
1702
|
{ content: contentValue, category: normalizedCategory ?? "fact" },
|
|
1838
1703
|
{ source: "memory_action_apply" }
|
|
@@ -1851,7 +1716,7 @@ NOTE: You did not provide sessionKey; under concurrency this may not match your
|
|
|
1851
1716
|
break;
|
|
1852
1717
|
}
|
|
1853
1718
|
case "store_note": {
|
|
1854
|
-
const noteEnvelope =
|
|
1719
|
+
const noteEnvelope = composeSalvagedEnvelope(
|
|
1855
1720
|
"memory-action",
|
|
1856
1721
|
{ content: contentValue, category: normalizedCategory ?? "fact" },
|
|
1857
1722
|
{ source: "memory_action_apply" }
|
|
@@ -1909,7 +1774,7 @@ NOTE: You did not provide sessionKey; under concurrency this may not match your
|
|
|
1909
1774
|
break;
|
|
1910
1775
|
}
|
|
1911
1776
|
case "summarize_node": {
|
|
1912
|
-
const summaryEnvelope =
|
|
1777
|
+
const summaryEnvelope = composeSalvagedEnvelope(
|
|
1913
1778
|
"memory-action",
|
|
1914
1779
|
{ content: contentValue, category: normalizedCategory ?? "fact" },
|
|
1915
1780
|
{ source: "memory_action_apply" }
|
|
@@ -3165,7 +3030,7 @@ import path11 from "path";
|
|
|
3165
3030
|
import os from "os";
|
|
3166
3031
|
import { createOpikExporter } from "@remnic/core/opik-exporter";
|
|
3167
3032
|
import { readEnvVar, resolveHomeDir as resolveHomeDir3 } from "@remnic/core/runtime/env";
|
|
3168
|
-
import { displayErrorDetail
|
|
3033
|
+
import { displayErrorDetail } from "@remnic/core/runtime/better-sqlite";
|
|
3169
3034
|
import { migrateFromEngram } from "@remnic/core/migrate/from-engram";
|
|
3170
3035
|
|
|
3171
3036
|
// ../../src/user-message-cleaning.ts
|
|
@@ -3434,7 +3299,7 @@ function buildMemorySearchTool(orchestrator, options = {}) {
|
|
|
3434
3299
|
}
|
|
3435
3300
|
|
|
3436
3301
|
// src/runtime-surfaces.ts
|
|
3437
|
-
import { composeSalvagedEnvelope as
|
|
3302
|
+
import { composeSalvagedEnvelope as composeSalvagedEnvelope2 } from "@remnic/core/salvage-envelope";
|
|
3438
3303
|
import {
|
|
3439
3304
|
gatewayTaskChainOptions
|
|
3440
3305
|
} from "@remnic/core/fallback-llm";
|
|
@@ -3647,7 +3512,7 @@ async function syncDreamSurfaceEntries(params) {
|
|
|
3647
3512
|
const existing = findSurfaceMemoryByAttribute(memories, DREAM_ENTRY_ID_KEY, entry.id);
|
|
3648
3513
|
if (!existing) {
|
|
3649
3514
|
const { id: memoryId } = await storage.writeSealedMemory(
|
|
3650
|
-
|
|
3515
|
+
composeSalvagedEnvelope2(
|
|
3651
3516
|
"dreams-surface",
|
|
3652
3517
|
{ content, category: "moment", confidence: 0.85, tags, structuredAttributes },
|
|
3653
3518
|
{ source: "dreams.md" }
|
|
@@ -3707,7 +3572,7 @@ async function syncHeartbeatSurfaceEntries(params) {
|
|
|
3707
3572
|
const existing = findSurfaceMemoryByAttribute(memories, HEARTBEAT_ENTRY_ID_KEY, entry.id) ?? findUniqueSurfaceMemoryBySlug(memories, HEARTBEAT_SURFACE_TYPE, entry.slug);
|
|
3708
3573
|
if (!existing) {
|
|
3709
3574
|
const { id: memoryId } = await storage.writeSealedMemory(
|
|
3710
|
-
|
|
3575
|
+
composeSalvagedEnvelope2(
|
|
3711
3576
|
"heartbeat-surface",
|
|
3712
3577
|
{ content, category: "principle", confidence: 0.95, tags, structuredAttributes },
|
|
3713
3578
|
{ source: "heartbeat.md" }
|
|
@@ -4213,7 +4078,7 @@ function validateSlotSelection(ctx) {
|
|
|
4213
4078
|
|
|
4214
4079
|
// ../../src/openclaw-flush-plan-lifecycle.ts
|
|
4215
4080
|
import path2 from "path";
|
|
4216
|
-
import { createHash as
|
|
4081
|
+
import { createHash as createHash2, randomUUID } from "crypto";
|
|
4217
4082
|
import {
|
|
4218
4083
|
lstat as lstat2,
|
|
4219
4084
|
mkdir,
|
|
@@ -4346,7 +4211,7 @@ function isPathInsideOrEqual(parentPath, childPath) {
|
|
|
4346
4211
|
return relative === "" || !relative.startsWith("..") && !path2.isAbsolute(relative);
|
|
4347
4212
|
}
|
|
4348
4213
|
function hashContent(content) {
|
|
4349
|
-
return
|
|
4214
|
+
return createHash2("sha256").update(content, "utf8").digest("hex");
|
|
4350
4215
|
}
|
|
4351
4216
|
function utf8PrefixByByteLength(content, byteLength) {
|
|
4352
4217
|
const buffer = Buffer.from(content, "utf8");
|
|
@@ -8147,15 +8012,26 @@ function cwdFrom(event, ctx, fallback) {
|
|
|
8147
8012
|
}
|
|
8148
8013
|
return fallback;
|
|
8149
8014
|
}
|
|
8015
|
+
function readRecallDegradation(candidate) {
|
|
8016
|
+
if (!("degradation" in candidate)) return void 0;
|
|
8017
|
+
const value = candidate.degradation;
|
|
8018
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
8019
|
+
const rec = value;
|
|
8020
|
+
if (typeof rec.state !== "string" || typeof rec.reason !== "string") return void 0;
|
|
8021
|
+
return value;
|
|
8022
|
+
}
|
|
8150
8023
|
function readContextComposition(response, fallbackContext) {
|
|
8151
8024
|
const candidate = response.contextComposition;
|
|
8152
8025
|
if (typeof candidate !== "object" || candidate === null || !("context" in candidate) || typeof candidate.context !== "string") {
|
|
8153
8026
|
return { context: fallbackContext };
|
|
8154
8027
|
}
|
|
8028
|
+
const composition = { context: candidate.context };
|
|
8155
8029
|
if ("footer" in candidate && typeof candidate.footer === "string") {
|
|
8156
|
-
|
|
8030
|
+
composition.footer = candidate.footer;
|
|
8157
8031
|
}
|
|
8158
|
-
|
|
8032
|
+
const degradation = readRecallDegradation(candidate);
|
|
8033
|
+
if (degradation) composition.degradation = degradation;
|
|
8034
|
+
return composition;
|
|
8159
8035
|
}
|
|
8160
8036
|
function registerDelegateRuntime(api, options) {
|
|
8161
8037
|
const { target, namespace, namespaceBindings } = options;
|
|
@@ -8296,8 +8172,9 @@ function registerDelegateRuntime(api, options) {
|
|
|
8296
8172
|
if (typeof rawContext !== "string" || rawContext.trim().length === 0) {
|
|
8297
8173
|
return void 0;
|
|
8298
8174
|
}
|
|
8175
|
+
const composition = readContextComposition(response ?? {}, rawContext);
|
|
8299
8176
|
const rendered = renderMemoryContextPrompt({
|
|
8300
|
-
...
|
|
8177
|
+
...composition,
|
|
8301
8178
|
maxChars: options.recallBudgetChars
|
|
8302
8179
|
});
|
|
8303
8180
|
if (!rendered) return void 0;
|
|
@@ -8306,7 +8183,10 @@ function registerDelegateRuntime(api, options) {
|
|
|
8306
8183
|
promptLinesBySession.set(sessionKey, rendered.lines);
|
|
8307
8184
|
return void 0;
|
|
8308
8185
|
}
|
|
8309
|
-
return {
|
|
8186
|
+
return {
|
|
8187
|
+
prependSystemContext: prompt,
|
|
8188
|
+
...composition.degradation ? { degradation: composition.degradation } : {}
|
|
8189
|
+
};
|
|
8310
8190
|
} catch (err) {
|
|
8311
8191
|
log7.warn(`delegate recall failed: ${String(err)}`);
|
|
8312
8192
|
return void 0;
|
|
@@ -8898,7 +8778,7 @@ function buildTurnFingerprint(input) {
|
|
|
8898
8778
|
import { planRecallMode } from "@remnic/core/intent";
|
|
8899
8779
|
import {
|
|
8900
8780
|
expandTildePath as expandTildePath3,
|
|
8901
|
-
isSupportPassportPrivateMemory
|
|
8781
|
+
isSupportPassportPrivateMemory,
|
|
8902
8782
|
renderMemoryContextPrompt as renderSharedMemoryContextPrompt,
|
|
8903
8783
|
resolveAgentAccessAuthToken,
|
|
8904
8784
|
resolvePrincipal,
|
|
@@ -9618,7 +9498,7 @@ function stableOpenClawConfigSignature(value, seen = /* @__PURE__ */ new WeakSet
|
|
|
9618
9498
|
return JSON.stringify(String(value));
|
|
9619
9499
|
}
|
|
9620
9500
|
function openClawHostEmbeddingConfigSignature(cfg, apiConfig, workspaceDir) {
|
|
9621
|
-
return `sha256:${
|
|
9501
|
+
return `sha256:${createHash3("sha256").update(JSON.stringify({
|
|
9622
9502
|
enabled: cfg.hostEmbeddingProviderEnabled !== false,
|
|
9623
9503
|
memoryDir: cfg.memoryDir,
|
|
9624
9504
|
providerId: cfg.hostEmbeddingProviderId ?? "",
|
|
@@ -10016,7 +9896,7 @@ var pluginDefinition = {
|
|
|
10016
9896
|
);
|
|
10017
9897
|
}
|
|
10018
9898
|
} catch (error) {
|
|
10019
|
-
const detail =
|
|
9899
|
+
const detail = displayErrorDetail(error) || "unknown error";
|
|
10020
9900
|
log8.warn(`OpenClaw flush-plan processing failed: ${detail}`);
|
|
10021
9901
|
}
|
|
10022
9902
|
}
|
|
@@ -12159,7 +12039,7 @@ Keep the reflection grounded in the evidence below.
|
|
|
12159
12039
|
const resolved = await readMemoryByLookup(lookup, agentSessionKey);
|
|
12160
12040
|
if (!resolved) return null;
|
|
12161
12041
|
const { memory, displayPath } = resolved;
|
|
12162
|
-
if (isMemoryArtifactPath(displayPath) || isMemoryArtifactPath(memory.path) ||
|
|
12042
|
+
if (isMemoryArtifactPath(displayPath) || isMemoryArtifactPath(memory.path) || isSupportPassportPrivateMemory(memory)) {
|
|
12163
12043
|
return null;
|
|
12164
12044
|
}
|
|
12165
12045
|
const allLines = memory.content.split(/\r?\n/);
|
|
@@ -12554,7 +12434,7 @@ function buildOpenClawInboundContentFingerprint(content, message, event, ctx, se
|
|
|
12554
12434
|
normalizeThreadId(message.threadId) ?? normalizeThreadId(event.threadId) ?? normalizeThreadId(ctx.threadId) ?? "",
|
|
12555
12435
|
512
|
|
12556
12436
|
);
|
|
12557
|
-
const contentHash =
|
|
12437
|
+
const contentHash = createHash3("sha256").update(normalizedContent).digest("hex");
|
|
12558
12438
|
return [
|
|
12559
12439
|
sessionPart,
|
|
12560
12440
|
"content",
|
|
@@ -12568,7 +12448,7 @@ function buildOpenClawSparseInboundContentFingerprint(content, sessionKey) {
|
|
|
12568
12448
|
const normalizedContent = content.trim();
|
|
12569
12449
|
if (!normalizedContent) return null;
|
|
12570
12450
|
const sessionPart = truncateMetadataValue(sessionKey || "default", 512);
|
|
12571
|
-
const contentHash =
|
|
12451
|
+
const contentHash = createHash3("sha256").update(normalizedContent).digest("hex");
|
|
12572
12452
|
return `${sessionPart}\0sparse-content\0${contentHash}`;
|
|
12573
12453
|
}
|
|
12574
12454
|
function withReplyExtractionHint(content, metadata) {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { MemoryActionType, MemoryFile, MemoryActionEligibilityContext } from '@remnic/core/types';
|
|
2
|
+
|
|
3
|
+
declare function deriveMemoryActionPolicyEligibility(memory: Pick<MemoryFile, "frontmatter"> | null | undefined): MemoryActionEligibilityContext | undefined;
|
|
4
|
+
declare function readReferencedMemoryForPolicyEligibility(storage: {
|
|
5
|
+
getMemoryById?: (id: string) => Promise<MemoryFile | null>;
|
|
6
|
+
readAllMemories?: () => Promise<MemoryFile[]>;
|
|
7
|
+
readArchivedMemories?: () => Promise<MemoryFile[]>;
|
|
8
|
+
}, memoryId: string | undefined): Promise<MemoryFile | null | undefined>;
|
|
9
|
+
declare function blocksSupportPassportMutation(action: MemoryActionType, memory: Pick<MemoryFile, "frontmatter"> | null | undefined): boolean;
|
|
10
|
+
|
|
11
|
+
export { blocksSupportPassportMutation, deriveMemoryActionPolicyEligibility, readReferencedMemoryForPolicyEligibility };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import "../chunk-I2KLQ2HA.js";
|
|
2
|
+
|
|
3
|
+
// src/plugin/memory-action-target.ts
|
|
4
|
+
import { isSupportPassportPrivateMemory } from "@remnic/core";
|
|
5
|
+
function clampUnitInterval(value, fallback) {
|
|
6
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return fallback;
|
|
7
|
+
if (value < 0) return 0;
|
|
8
|
+
if (value > 1) return 1;
|
|
9
|
+
return value;
|
|
10
|
+
}
|
|
11
|
+
function normalizeEligibilitySource(value) {
|
|
12
|
+
switch (value) {
|
|
13
|
+
case "extraction":
|
|
14
|
+
case "consolidation":
|
|
15
|
+
case "replay":
|
|
16
|
+
case "manual":
|
|
17
|
+
return value;
|
|
18
|
+
default:
|
|
19
|
+
return "unknown";
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function deriveMemoryActionPolicyEligibility(memory) {
|
|
23
|
+
if (!memory) return void 0;
|
|
24
|
+
const frontmatter = memory.frontmatter;
|
|
25
|
+
return {
|
|
26
|
+
confidence: clampUnitInterval(frontmatter.confidence, 0),
|
|
27
|
+
lifecycleState: frontmatter.status === "archived" ? "archived" : frontmatter.lifecycleState ?? "candidate",
|
|
28
|
+
importance: clampUnitInterval(frontmatter.importance?.score, 0),
|
|
29
|
+
source: normalizeEligibilitySource(frontmatter.source)
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
async function readReferencedMemoryForPolicyEligibility(storage, memoryId) {
|
|
33
|
+
if (!memoryId) return void 0;
|
|
34
|
+
const direct = await storage.getMemoryById?.(memoryId);
|
|
35
|
+
if (direct) return direct;
|
|
36
|
+
const active = (await storage.readAllMemories?.())?.find((memory) => memory.frontmatter.id === memoryId);
|
|
37
|
+
if (active) return active;
|
|
38
|
+
return (await storage.readArchivedMemories?.())?.find((memory) => memory.frontmatter.id === memoryId);
|
|
39
|
+
}
|
|
40
|
+
function blocksSupportPassportMutation(action, memory) {
|
|
41
|
+
return (action === "update_note" || action === "discard" || action === "link_graph") && Boolean(memory && isSupportPassportPrivateMemory(memory));
|
|
42
|
+
}
|
|
43
|
+
export {
|
|
44
|
+
blocksSupportPassportMutation,
|
|
45
|
+
deriveMemoryActionPolicyEligibility,
|
|
46
|
+
readReferencedMemoryForPolicyEligibility
|
|
47
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Orchestrator } from '@remnic/core/orchestrator';
|
|
2
|
+
|
|
3
|
+
declare function executeMemoryPromote(orchestrator: Orchestrator, params: {
|
|
4
|
+
memoryId: string;
|
|
5
|
+
fromNamespace?: string;
|
|
6
|
+
toNamespace?: string;
|
|
7
|
+
note?: string;
|
|
8
|
+
}): Promise<string>;
|
|
9
|
+
|
|
10
|
+
export { executeMemoryPromote };
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import "../chunk-I2KLQ2HA.js";
|
|
2
|
+
|
|
3
|
+
// src/plugin/memory-promote.ts
|
|
4
|
+
import { createHash } from "crypto";
|
|
5
|
+
import { composeSalvagedEnvelope } from "@remnic/core/salvage-envelope";
|
|
6
|
+
import {
|
|
7
|
+
STRUCTURED_ATTRIBUTE_LIMITS,
|
|
8
|
+
TAG_LIMITS
|
|
9
|
+
} from "@remnic/core/write-envelope";
|
|
10
|
+
import { stripAttributesSuffix } from "@remnic/core/storage";
|
|
11
|
+
import { isSupportPassportPrivateMemory } from "@remnic/core/support-passport";
|
|
12
|
+
import { displayErrorDetail } from "@remnic/core/runtime/better-sqlite";
|
|
13
|
+
import { isSafeRouteNamespace } from "@remnic/core/routing/engine";
|
|
14
|
+
import { indexMemoryAsync, indexesExistAsync } from "@remnic/core/temporal-index";
|
|
15
|
+
function buildPromotionOrigin(srcNamespace, memoryId) {
|
|
16
|
+
const memoryIdHash = createHash("sha256").update(memoryId).digest("hex");
|
|
17
|
+
const fullTag = `promotedFrom:${srcNamespace}:${memoryId}`;
|
|
18
|
+
return {
|
|
19
|
+
tag: fullTag.length <= TAG_LIMITS.maxTagLength ? fullTag : `promotedFromHash:${memoryIdHash}`,
|
|
20
|
+
structuredAttributes: {
|
|
21
|
+
promotedFromNamespace: srcNamespace,
|
|
22
|
+
promotedFromMemoryIdHash: memoryIdHash,
|
|
23
|
+
...memoryId.length <= STRUCTURED_ATTRIBUTE_LIMITS.maxValueLength ? { promotedFromMemoryId: memoryId } : {}
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
async function executeMemoryPromote(orchestrator, params) {
|
|
28
|
+
const { memoryId, fromNamespace, toNamespace, note } = params;
|
|
29
|
+
if (typeof memoryId !== "string" || memoryId.length === 0) {
|
|
30
|
+
return `Invalid memoryId: ${JSON.stringify(memoryId)} \u2014 expected a non-empty memory ID.`;
|
|
31
|
+
}
|
|
32
|
+
for (const [name, value] of [
|
|
33
|
+
["fromNamespace", fromNamespace],
|
|
34
|
+
["toNamespace", toNamespace]
|
|
35
|
+
]) {
|
|
36
|
+
if (value !== void 0 && value !== null && (typeof value !== "string" || !isSafeRouteNamespace(value))) {
|
|
37
|
+
return `Invalid ${name}: ${JSON.stringify(value)} \u2014 expected a path-safe namespace name.`;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const srcNs = fromNamespace ?? orchestrator.config.defaultNamespace;
|
|
41
|
+
const dstNs = toNamespace ?? orchestrator.config.sharedNamespace;
|
|
42
|
+
const src = await orchestrator.getStorage(srcNs);
|
|
43
|
+
const mem = await src.getMemoryById(memoryId);
|
|
44
|
+
if (!mem || isSupportPassportPrivateMemory(mem)) {
|
|
45
|
+
return `Memory not found in ${srcNs}: ${memoryId}`;
|
|
46
|
+
}
|
|
47
|
+
const dst = await orchestrator.getStorage(dstNs);
|
|
48
|
+
const promotionOrigin = buildPromotionOrigin(srcNs, memoryId);
|
|
49
|
+
const promoteEnvelope = composeSalvagedEnvelope(
|
|
50
|
+
"promote",
|
|
51
|
+
{
|
|
52
|
+
content: mem.frontmatter.structuredAttributes ? stripAttributesSuffix(mem.content) : mem.content,
|
|
53
|
+
category: mem.frontmatter.category,
|
|
54
|
+
confidence: mem.frontmatter.confidence,
|
|
55
|
+
tags: (() => {
|
|
56
|
+
const promotionTags = [
|
|
57
|
+
"promoted",
|
|
58
|
+
promotionOrigin.tag,
|
|
59
|
+
...note ? [`note:${note}`] : []
|
|
60
|
+
];
|
|
61
|
+
const sourceTags = mem.frontmatter.tags ?? [];
|
|
62
|
+
return Array.from(/* @__PURE__ */ new Set([...promotionTags, ...sourceTags])).slice(
|
|
63
|
+
0,
|
|
64
|
+
TAG_LIMITS.maxTags
|
|
65
|
+
);
|
|
66
|
+
})(),
|
|
67
|
+
structuredAttributes: promotionOrigin.structuredAttributes,
|
|
68
|
+
entityRef: mem.frontmatter.entityRef
|
|
69
|
+
},
|
|
70
|
+
{ source: "promote" }
|
|
71
|
+
);
|
|
72
|
+
const { id: newId, tombstoneBlocked } = await dst.writeSealedMemory(
|
|
73
|
+
promoteEnvelope,
|
|
74
|
+
{
|
|
75
|
+
importance: mem.frontmatter.importance,
|
|
76
|
+
supersedes: mem.frontmatter.supersedes,
|
|
77
|
+
links: mem.frontmatter.links
|
|
78
|
+
}
|
|
79
|
+
);
|
|
80
|
+
if (tombstoneBlocked) {
|
|
81
|
+
return `Promotion of ${srcNs}:${memoryId} \u2192 ${dstNs}:${newId} is queued for review (tombstone-blocked): no active promoted copy was created.`;
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
if (orchestrator.config.queryAwareIndexingEnabled && await indexesExistAsync(orchestrator.config.memoryDir)) {
|
|
85
|
+
const promoted = await dst.getMemoryById(newId).catch(() => null);
|
|
86
|
+
if (promoted?.path && promoted.frontmatter?.created) {
|
|
87
|
+
await indexMemoryAsync(
|
|
88
|
+
orchestrator.config.memoryDir,
|
|
89
|
+
promoted.path,
|
|
90
|
+
promoted.frontmatter.created,
|
|
91
|
+
promoted.frontmatter.tags ?? []
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
} catch (err) {
|
|
96
|
+
return `Promoted ${srcNs}:${memoryId} \u2192 ${dstNs}:${newId} (index refresh failed \u2014 recall picks it up on the next maintenance pass: ${displayErrorDetail(err)})`;
|
|
97
|
+
}
|
|
98
|
+
return `Promoted ${srcNs}:${memoryId} \u2192 ${dstNs}:${newId}`;
|
|
99
|
+
}
|
|
100
|
+
export {
|
|
101
|
+
executeMemoryPromote
|
|
102
|
+
};
|