const MS_PER_HOUR = 3600000; const MS_PER_DAY = 86400000; const FALSE_STORE_PATTERNS = [ { code: 'question_mark', pattern: /[??]\s*$/, message: 'Content ends with a question mark', }, { code: 'what_is_question', pattern: /^(?:什么是|解释一下|介绍一下|请问|能不能|是否可以|怎么|如何|为什么|啥是)/u, message: 'Content looks like a question rather than a fact', }, { code: 'imperative_only', pattern: /^(?:查一下|搜一下|看看|继续|下一步|帮我|请帮我)/u, message: 'Content looks like an instruction without durable facts', }, { code: 'trivial_greeting', pattern: /^(?:你好|您好|谢谢|好的|可以|收到|再见|hi|hello|thanks)[!!。.\s]*$/iu, message: 'Content is a trivial greeting or acknowledgement', }, { code: 'routing_leak', pattern: /(?:\[Memory Context\]|【Memind 任务编排】|agent_orchestration)/u, message: 'Content contains internal routing or memory envelope text', }, ]; export function parseSinceArg(value, now = Date.now()) { const raw = String(value ?? '7d').trim().toLowerCase(); const match = raw.match(/^(\d+)(h|d|w)$/); if (!match) { throw new Error(`Invalid --since value "${value}". Expected formats like 24h, 7d, 2w.`); } const amount = Number(match[1]); if (!Number.isFinite(amount) || amount <= 0) { throw new Error(`Invalid --since value "${value}". Amount must be positive.`); } const unit = match[2]; const multiplier = unit === 'h' ? MS_PER_HOUR : unit === 'w' ? MS_PER_DAY * 7 : MS_PER_DAY; return { sinceMs: now - amount * multiplier, label: raw, }; } export function detectFalseStoreCandidate(content) { const text = String(content ?? '').replace(/\s+/g, ' ').trim(); if (!text) { return { suspicious: true, code: 'empty_content', message: 'Content is empty' }; } for (const rule of FALSE_STORE_PATTERNS) { if (rule.pattern.test(text)) { return { suspicious: true, code: rule.code, message: rule.message }; } } return { suspicious: false }; } function normalizeCandidate(row) { return { id: String(row.id), userId: String(row.user_id ?? row.userId), sessionId: row.session_id == null ? null : String(row.session_id ?? row.sessionId), memoryType: String(row.memory_type ?? row.memoryType ?? ''), content: String(row.content ?? ''), status: String(row.status ?? ''), policyReason: String(row.policy_reason ?? row.policyReason ?? ''), confidence: Number(row.confidence ?? 0), importance: Number(row.importance ?? 0), createdAt: Number(row.created_at ?? row.createdAt ?? 0), updatedAt: Number(row.updated_at ?? row.updatedAt ?? 0), }; } function normalizeMemoryItem(row) { return { id: String(row.id), userId: String(row.user_id ?? row.userId), label: String(row.label ?? ''), content: String(row.memory_text ?? row.content ?? ''), status: String(row.status ?? ''), createdAt: Number(row.created_at ?? row.createdAt ?? 0), updatedAt: Number(row.updated_at ?? row.updatedAt ?? 0), }; } function countByField(items, field) { const counts = new Map(); for (const item of items) { const key = String(item[field] ?? 'unknown'); counts.set(key, (counts.get(key) ?? 0) + 1); } return Object.fromEntries([...counts.entries()].sort((a, b) => b[1] - a[1])); } function topEntries(counts, limit = 10) { return Object.entries(counts) .sort((a, b) => b[1] - a[1]) .slice(0, limit) .map(([key, count]) => ({ key, count })); } export function auditMemoryV2Shadow({ candidates = [], memoryItems = [], pgvectorMemoryIds = new Set(), pgvectorConfigured = false, agentMemoryEvents = [], sinceMs = 0, nowMs = Date.now(), falseStoreSampleLimit = 20, pgvectorLagSampleLimit = 20, } = {}) { const normalizedCandidates = candidates.map(normalizeCandidate); const normalizedItems = memoryItems.map(normalizeMemoryItem); const inWindowCandidates = normalizedCandidates.filter((item) => item.createdAt >= sinceMs); const inWindowItems = normalizedItems.filter((item) => item.updatedAt >= sinceMs); const candidateStatusCounts = countByField(inWindowCandidates, 'status'); const policyReasonCounts = countByField(inWindowCandidates, 'policyReason'); const memoryTypeCounts = countByField(inWindowCandidates, 'memoryType'); const suspiciousCandidates = inWindowCandidates .filter((item) => ['candidate', 'accepted'].includes(item.status)) .map((item) => { const verdict = detectFalseStoreCandidate(item.content); if (!verdict.suspicious) return null; return { id: item.id, userId: item.userId, status: item.status, policyReason: item.policyReason, code: verdict.code, message: verdict.message, contentPreview: item.content.slice(0, 120), createdAt: item.createdAt, }; }) .filter(Boolean); const activeItems = normalizedItems.filter((item) => item.status === 'active'); const pgvectorLagUsers = new Map(); const pgvectorMissingSamples = []; if (pgvectorConfigured) { for (const item of activeItems) { if (pgvectorMemoryIds.has(item.id)) continue; pgvectorLagUsers.set(item.userId, (pgvectorLagUsers.get(item.userId) ?? 0) + 1); if (pgvectorMissingSamples.length < pgvectorLagSampleLimit) { pgvectorMissingSamples.push({ memoryId: item.id, userId: item.userId, label: item.label, updatedAt: item.updatedAt, contentPreview: item.content.slice(0, 120), }); } } } const resolvedEvents = agentMemoryEvents.filter((event) => { const createdAt = Number(event.created_at ?? event.createdAt ?? 0); return createdAt >= sinceMs; }); const resolvedWithHits = resolvedEvents.filter((event) => { const data = event.data_json ?? event.data ?? {}; const count = Number(data.count ?? data.memoryCount ?? data.memories?.length ?? 0); return count > 0; }); const acceptedCount = candidateStatusCounts.accepted ?? 0; const candidateCount = candidateStatusCounts.candidate ?? 0; const reviewedCount = acceptedCount + (candidateStatusCounts.rejected ?? 0); const autoAcceptRate = reviewedCount > 0 ? acceptedCount / reviewedCount : null; const falseStoreRate = inWindowCandidates.length > 0 ? suspiciousCandidates.length / inWindowCandidates.length : null; const resolveHitRate = resolvedEvents.length > 0 ? resolvedWithHits.length / resolvedEvents.length : null; const thresholds = { falseStoreRateMax: 0.05, pgvectorLagUsersMax: 0, }; const issues = []; if (falseStoreRate != null && falseStoreRate > thresholds.falseStoreRateMax) { issues.push({ code: 'false_store_rate_high', message: `False-store sample rate ${(falseStoreRate * 100).toFixed(1)}% exceeds ${thresholds.falseStoreRateMax * 100}%`, }); } if (pgvectorConfigured && pgvectorLagUsers.size > thresholds.pgvectorLagUsersMax) { issues.push({ code: 'pgvector_sync_lag', message: `${pgvectorLagUsers.size} user(s) have active memories missing from pgvector`, }); } return { ok: issues.length === 0, generatedAt: nowMs, window: { sinceMs, untilMs: nowMs, candidateCount: inWindowCandidates.length, memoryItemCount: inWindowItems.length, agentMemoryResolvedEvents: resolvedEvents.length, }, summary: { candidateStatusCounts, policyReasonCounts, memoryTypeCounts, autoAcceptRate, falseStoreRate, resolveHitRate, suspiciousCandidateCount: suspiciousCandidates.length, pgvectorLagUserCount: pgvectorConfigured ? pgvectorLagUsers.size : null, activeMemoryCount: activeItems.length, pgvectorMemoryCount: pgvectorConfigured ? pgvectorMemoryIds.size : null, }, topPolicyReasons: topEntries(policyReasonCounts), pgvectorLagUsers: [...pgvectorLagUsers.entries()] .sort((a, b) => b[1] - a[1]) .slice(0, pgvectorLagSampleLimit) .map(([userId, missingCount]) => ({ userId, missingCount })), sampleFalseStores: suspiciousCandidates.slice(0, falseStoreSampleLimit), pgvectorMissingSamples, issues, }; } export function formatMemoryV2ShadowAuditReport(report) { const lines = [ `memory v2 shadow audit: ${report.ok ? 'ok' : 'issues found'}`, `window: ${new Date(report.window.sinceMs).toISOString()} -> ${new Date(report.window.untilMs).toISOString()}`, `candidates: ${report.window.candidateCount}`, `memory items updated: ${report.window.memoryItemCount}`, `agent_memory_resolved events: ${report.window.agentMemoryResolvedEvents}`, '', 'summary:', JSON.stringify(report.summary, null, 2), ]; if (report.topPolicyReasons.length > 0) { lines.push('', 'top policy reasons:'); for (const item of report.topPolicyReasons) { lines.push(`- ${item.key}: ${item.count}`); } } if (report.pgvectorLagUsers.length > 0) { lines.push('', 'pgvector lag users:'); for (const item of report.pgvectorLagUsers) { lines.push(`- ${item.userId}: ${item.missingCount} missing`); } } if (report.sampleFalseStores.length > 0) { lines.push('', 'sample false stores:'); for (const item of report.sampleFalseStores) { lines.push(`- [${item.code}] ${item.id} (${item.policyReason}): ${item.contentPreview}`); } } if (report.issues.length > 0) { lines.push('', 'issues:'); for (const item of report.issues) { lines.push(`- ${item.code}: ${item.message}`); } } return lines.join('\n'); }