feat(memory-v2): restore personal shadow pipeline and candidate store

Recover WIP modules from stash so admin can persist capability config,
observe chat writes in shadow mode, and review persisted candidates.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
john
2026-07-13 13:59:51 +08:00
parent 249b0697cb
commit e90a2da6cb
9 changed files with 773 additions and 1 deletions
+34 -1
View File
@@ -1,4 +1,5 @@
import { createMemoryV2PluginBackends } from './memory-v2-plugin-backends.mjs';
import { createPersonalMemoryShadowPipeline } from './memory-v2-personal-shadow.mjs';
const TRUE_VALUES = new Set(['1', 'true', 'yes', 'on']);
const FALSE_VALUES = new Set(['0', 'false', 'no', 'off']);
@@ -231,12 +232,14 @@ export function createMemoryV2({
policy = null,
env = process.env,
logger = console,
personalShadowPipeline = null,
} = {}) {
const resolvedPolicy = policy ?? resolveMemoryV2Policy({ env });
const resolvedBackends = backends ?? [
createLegacyMemoryBackend(legacyMemoryService),
...createMemoryV2PluginBackends(),
];
const shadowPipeline = personalShadowPipeline ?? createPersonalMemoryShadowPipeline({ env });
async function failOpen(operation, err, fallback) {
logger?.warn?.(
@@ -278,6 +281,13 @@ export function createMemoryV2({
if (!backend?.write) return skippedWriteResult('no_backend');
try {
const result = await backend.write(input);
if (shadowPipeline?.config?.enabled) {
void Promise.resolve(shadowPipeline.observeWrite(input)).catch((err) => {
logger?.warn?.(
`[memory-v2] personal shadow pipeline skipped: ${err instanceof Error ? err.message : err}`,
);
});
}
return {
ok: true,
enabled: true,
@@ -334,10 +344,28 @@ export function createMemoryV2({
}
}
async function observePersonalMemory(input = {}) {
if (!shadowPipeline?.config?.enabled) {
return { enabled: false, skipped: true, reason: 'disabled' };
}
try {
return await shadowPipeline.observeWrite(input);
} catch (err) {
logger?.warn?.(
`[memory-v2] personal shadow observation skipped: ${err instanceof Error ? err.message : err}`,
);
return {
enabled: true,
skipped: true,
reason: 'pipeline_failure',
};
}
}
function getStatus() {
const backends = resolvedBackends.map((backend) => backendStatus(backend));
const selected = selectBackend(resolvedBackends, resolvedPolicy, 'resolve');
return {
const status = {
enabled: Boolean(resolvedPolicy.enabled),
backend: resolvedPolicy.backend,
selectedBackend: selected?.name ?? null,
@@ -347,6 +375,10 @@ export function createMemoryV2({
failOpen: Boolean(resolvedPolicy.failOpen),
backends,
};
if (shadowPipeline?.config?.enabled) {
status.personalMemory = shadowPipeline.getStatus();
}
return status;
}
return {
@@ -355,5 +387,6 @@ export function createMemoryV2({
resolve,
write,
compact,
observePersonalMemory,
};
}