@remnic/plugin-openclaw 9.69.53 → 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");
|
|
@@ -8913,7 +8778,7 @@ function buildTurnFingerprint(input) {
|
|
|
8913
8778
|
import { planRecallMode } from "@remnic/core/intent";
|
|
8914
8779
|
import {
|
|
8915
8780
|
expandTildePath as expandTildePath3,
|
|
8916
|
-
isSupportPassportPrivateMemory
|
|
8781
|
+
isSupportPassportPrivateMemory,
|
|
8917
8782
|
renderMemoryContextPrompt as renderSharedMemoryContextPrompt,
|
|
8918
8783
|
resolveAgentAccessAuthToken,
|
|
8919
8784
|
resolvePrincipal,
|
|
@@ -9633,7 +9498,7 @@ function stableOpenClawConfigSignature(value, seen = /* @__PURE__ */ new WeakSet
|
|
|
9633
9498
|
return JSON.stringify(String(value));
|
|
9634
9499
|
}
|
|
9635
9500
|
function openClawHostEmbeddingConfigSignature(cfg, apiConfig, workspaceDir) {
|
|
9636
|
-
return `sha256:${
|
|
9501
|
+
return `sha256:${createHash3("sha256").update(JSON.stringify({
|
|
9637
9502
|
enabled: cfg.hostEmbeddingProviderEnabled !== false,
|
|
9638
9503
|
memoryDir: cfg.memoryDir,
|
|
9639
9504
|
providerId: cfg.hostEmbeddingProviderId ?? "",
|
|
@@ -10031,7 +9896,7 @@ var pluginDefinition = {
|
|
|
10031
9896
|
);
|
|
10032
9897
|
}
|
|
10033
9898
|
} catch (error) {
|
|
10034
|
-
const detail =
|
|
9899
|
+
const detail = displayErrorDetail(error) || "unknown error";
|
|
10035
9900
|
log8.warn(`OpenClaw flush-plan processing failed: ${detail}`);
|
|
10036
9901
|
}
|
|
10037
9902
|
}
|
|
@@ -12174,7 +12039,7 @@ Keep the reflection grounded in the evidence below.
|
|
|
12174
12039
|
const resolved = await readMemoryByLookup(lookup, agentSessionKey);
|
|
12175
12040
|
if (!resolved) return null;
|
|
12176
12041
|
const { memory, displayPath } = resolved;
|
|
12177
|
-
if (isMemoryArtifactPath(displayPath) || isMemoryArtifactPath(memory.path) ||
|
|
12042
|
+
if (isMemoryArtifactPath(displayPath) || isMemoryArtifactPath(memory.path) || isSupportPassportPrivateMemory(memory)) {
|
|
12178
12043
|
return null;
|
|
12179
12044
|
}
|
|
12180
12045
|
const allLines = memory.content.split(/\r?\n/);
|
|
@@ -12569,7 +12434,7 @@ function buildOpenClawInboundContentFingerprint(content, message, event, ctx, se
|
|
|
12569
12434
|
normalizeThreadId(message.threadId) ?? normalizeThreadId(event.threadId) ?? normalizeThreadId(ctx.threadId) ?? "",
|
|
12570
12435
|
512
|
|
12571
12436
|
);
|
|
12572
|
-
const contentHash =
|
|
12437
|
+
const contentHash = createHash3("sha256").update(normalizedContent).digest("hex");
|
|
12573
12438
|
return [
|
|
12574
12439
|
sessionPart,
|
|
12575
12440
|
"content",
|
|
@@ -12583,7 +12448,7 @@ function buildOpenClawSparseInboundContentFingerprint(content, sessionKey) {
|
|
|
12583
12448
|
const normalizedContent = content.trim();
|
|
12584
12449
|
if (!normalizedContent) return null;
|
|
12585
12450
|
const sessionPart = truncateMetadataValue(sessionKey || "default", 512);
|
|
12586
|
-
const contentHash =
|
|
12451
|
+
const contentHash = createHash3("sha256").update(normalizedContent).digest("hex");
|
|
12587
12452
|
return `${sessionPart}\0sparse-content\0${contentHash}`;
|
|
12588
12453
|
}
|
|
12589
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
|
+
};
|