@remnic/plugin-openclaw 9.69.53 → 9.69.55
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");
|
|
@@ -5379,9 +5244,10 @@ import { log as log2 } from "@remnic/core/logger";
|
|
|
5379
5244
|
// src/bridge.ts
|
|
5380
5245
|
import fs3 from "fs";
|
|
5381
5246
|
import path6 from "path";
|
|
5382
|
-
import {
|
|
5247
|
+
import { isIPv6 } from "net";
|
|
5383
5248
|
import { Worker } from "worker_threads";
|
|
5384
5249
|
import { configPathCandidates, readCompatEnv } from "@remnic/core";
|
|
5250
|
+
import { isLoopbackHost } from "@remnic/core/runtime/http-transport.js";
|
|
5385
5251
|
|
|
5386
5252
|
// src/bridge-health-worker.ts
|
|
5387
5253
|
function runHealthWorker(request, data) {
|
|
@@ -6183,17 +6049,8 @@ function isDaemonRunning() {
|
|
|
6183
6049
|
}
|
|
6184
6050
|
function isLoopbackDaemonHost(host) {
|
|
6185
6051
|
const normalized = host.trim().toLowerCase().replace(/^\[/, "").replace(/\]$/, "");
|
|
6186
|
-
if (normalized === "localhost") return true;
|
|
6187
6052
|
if (loopbackForWildcardBind(normalized) !== void 0) return true;
|
|
6188
|
-
|
|
6189
|
-
if (ipv6 !== void 0) {
|
|
6190
|
-
if (ipv6 === "::1") return true;
|
|
6191
|
-
const mappedHex = /^::ffff:([0-9a-f]{1,4}):[0-9a-f]{1,4}$/.exec(ipv6);
|
|
6192
|
-
if (mappedHex !== null) return Number.parseInt(mappedHex[1], 16) >> 8 === 127;
|
|
6193
|
-
const mappedDotted = /^::ffff:(\d+\.\d+\.\d+\.\d+)$/.exec(ipv6);
|
|
6194
|
-
return mappedDotted !== null && isIPv4(mappedDotted[1]) && mappedDotted[1].split(".")[0] === "127";
|
|
6195
|
-
}
|
|
6196
|
-
return isIPv4(normalized) && normalized.split(".")[0] === "127";
|
|
6053
|
+
return isLoopbackHost(normalized);
|
|
6197
6054
|
}
|
|
6198
6055
|
function canonicalIPv6(value) {
|
|
6199
6056
|
if (!isIPv6(value)) return void 0;
|
|
@@ -8913,7 +8770,7 @@ function buildTurnFingerprint(input) {
|
|
|
8913
8770
|
import { planRecallMode } from "@remnic/core/intent";
|
|
8914
8771
|
import {
|
|
8915
8772
|
expandTildePath as expandTildePath3,
|
|
8916
|
-
isSupportPassportPrivateMemory
|
|
8773
|
+
isSupportPassportPrivateMemory,
|
|
8917
8774
|
renderMemoryContextPrompt as renderSharedMemoryContextPrompt,
|
|
8918
8775
|
resolveAgentAccessAuthToken,
|
|
8919
8776
|
resolvePrincipal,
|
|
@@ -9633,7 +9490,7 @@ function stableOpenClawConfigSignature(value, seen = /* @__PURE__ */ new WeakSet
|
|
|
9633
9490
|
return JSON.stringify(String(value));
|
|
9634
9491
|
}
|
|
9635
9492
|
function openClawHostEmbeddingConfigSignature(cfg, apiConfig, workspaceDir) {
|
|
9636
|
-
return `sha256:${
|
|
9493
|
+
return `sha256:${createHash3("sha256").update(JSON.stringify({
|
|
9637
9494
|
enabled: cfg.hostEmbeddingProviderEnabled !== false,
|
|
9638
9495
|
memoryDir: cfg.memoryDir,
|
|
9639
9496
|
providerId: cfg.hostEmbeddingProviderId ?? "",
|
|
@@ -10031,7 +9888,7 @@ var pluginDefinition = {
|
|
|
10031
9888
|
);
|
|
10032
9889
|
}
|
|
10033
9890
|
} catch (error) {
|
|
10034
|
-
const detail =
|
|
9891
|
+
const detail = displayErrorDetail(error) || "unknown error";
|
|
10035
9892
|
log8.warn(`OpenClaw flush-plan processing failed: ${detail}`);
|
|
10036
9893
|
}
|
|
10037
9894
|
}
|
|
@@ -12174,7 +12031,7 @@ Keep the reflection grounded in the evidence below.
|
|
|
12174
12031
|
const resolved = await readMemoryByLookup(lookup, agentSessionKey);
|
|
12175
12032
|
if (!resolved) return null;
|
|
12176
12033
|
const { memory, displayPath } = resolved;
|
|
12177
|
-
if (isMemoryArtifactPath(displayPath) || isMemoryArtifactPath(memory.path) ||
|
|
12034
|
+
if (isMemoryArtifactPath(displayPath) || isMemoryArtifactPath(memory.path) || isSupportPassportPrivateMemory(memory)) {
|
|
12178
12035
|
return null;
|
|
12179
12036
|
}
|
|
12180
12037
|
const allLines = memory.content.split(/\r?\n/);
|
|
@@ -12569,7 +12426,7 @@ function buildOpenClawInboundContentFingerprint(content, message, event, ctx, se
|
|
|
12569
12426
|
normalizeThreadId(message.threadId) ?? normalizeThreadId(event.threadId) ?? normalizeThreadId(ctx.threadId) ?? "",
|
|
12570
12427
|
512
|
|
12571
12428
|
);
|
|
12572
|
-
const contentHash =
|
|
12429
|
+
const contentHash = createHash3("sha256").update(normalizedContent).digest("hex");
|
|
12573
12430
|
return [
|
|
12574
12431
|
sessionPart,
|
|
12575
12432
|
"content",
|
|
@@ -12583,7 +12440,7 @@ function buildOpenClawSparseInboundContentFingerprint(content, sessionKey) {
|
|
|
12583
12440
|
const normalizedContent = content.trim();
|
|
12584
12441
|
if (!normalizedContent) return null;
|
|
12585
12442
|
const sessionPart = truncateMetadataValue(sessionKey || "default", 512);
|
|
12586
|
-
const contentHash =
|
|
12443
|
+
const contentHash = createHash3("sha256").update(normalizedContent).digest("hex");
|
|
12587
12444
|
return `${sessionPart}\0sparse-content\0${contentHash}`;
|
|
12588
12445
|
}
|
|
12589
12446
|
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
|
+
};
|