feat(memory): add gated agent recall and lifecycle controls

This commit is contained in:
john
2026-07-16 21:05:27 +08:00
parent c1012da120
commit 6e460336f7
13 changed files with 655 additions and 3 deletions
+42
View File
@@ -67,10 +67,39 @@ export function resolveMemoryV2Policy({ env = process.env, overrides = {} } = {}
vectorEnabled: readFlag(env, 'MEMORY_VECTOR_ENABLED', false),
backend: String(env?.MEMORY_BACKEND ?? 'legacy').trim() || 'legacy',
failOpen: readFlag(env, 'MEMORY_FAIL_OPEN', true),
agentResolveEnabled: readFlag(env, 'MEMORY_AGENT_RESOLVE_ENABLED', false),
agentInjectionMode: normalizeAgentInjectionMode(env?.MEMORY_AGENT_INJECTION_MODE),
agentCanaryUserIds: normalizeUserIdList(env?.MEMORY_AGENT_CANARY_USER_IDS),
agentResolveLimit: resolveBoundedNumber(env?.MEMORY_AGENT_RESOLVE_LIMIT, 3, 1, 50),
agentResolveTimeoutMs: resolveBoundedNumber(env?.MEMORY_AGENT_RESOLVE_TIMEOUT_MS, 1200, 0, 30000),
promotionEnabled: readFlag(env, 'MEMORY_PROMOTION_ENABLED', false),
compactionV2Enabled: readFlag(env, 'MEMORY_COMPACTION_V2_ENABLED', false),
reflectionEnabled: readFlag(env, 'MEMORY_REFLECTION_ENABLED', false),
lifecycleWorkerEnabled: readFlag(env, 'MEMORY_LIFECYCLE_WORKER_ENABLED', false),
lifecycleRolloutMode: String(env?.MEMORY_LIFECYCLE_ROLLOUT_MODE ?? 'off').trim().toLowerCase() || 'off',
lifecycleRolloutUserIds: normalizeUserIdList(env?.MEMORY_LIFECYCLE_ROLLOUT_USER_IDS),
...overrides,
};
}
function resolveBoundedNumber(value, fallback, min, max) {
const parsed = Number(value);
if (!Number.isFinite(parsed)) return fallback;
return Math.min(max, Math.max(min, parsed));
}
function normalizeAgentInjectionMode(value) {
const mode = String(value ?? 'off').trim().toLowerCase();
return ['off', 'shadow', 'canary', 'active'].includes(mode) ? mode : 'off';
}
function normalizeUserIdList(value) {
return [...new Set(String(value ?? '')
.split(/[\s,]+/u)
.map((item) => item.trim())
.filter(Boolean))].slice(0, 1000);
}
export function createLegacyMemoryBackend(conversationMemoryService) {
return {
name: 'legacy-conversation-memory',
@@ -373,6 +402,19 @@ export function createMemoryV2({
eventLogEnabled: Boolean(resolvedPolicy.eventLogEnabled),
vectorEnabled: Boolean(resolvedPolicy.vectorEnabled),
failOpen: Boolean(resolvedPolicy.failOpen),
runtimeControl: {
agentResolveEnabled: Boolean(resolvedPolicy.agentResolveEnabled),
agentInjectionMode: resolvedPolicy.agentInjectionMode,
agentCanaryUserIds: resolvedPolicy.agentCanaryUserIds,
agentResolveLimit: Number(resolvedPolicy.agentResolveLimit),
agentResolveTimeoutMs: Number(resolvedPolicy.agentResolveTimeoutMs),
promotionEnabled: Boolean(resolvedPolicy.promotionEnabled),
compactionV2Enabled: Boolean(resolvedPolicy.compactionV2Enabled),
reflectionEnabled: Boolean(resolvedPolicy.reflectionEnabled),
lifecycleWorkerEnabled: Boolean(resolvedPolicy.lifecycleWorkerEnabled),
lifecycleRolloutMode: resolvedPolicy.lifecycleRolloutMode,
lifecycleRolloutUserIds: resolvedPolicy.lifecycleRolloutUserIds,
},
backends,
};
if (shadowPipeline?.config?.enabled) {