@joshuaswarren/openclaw-engram 7.2.1
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/README.md +851 -0
- package/dist/index.js +11880 -0
- package/dist/index.js.map +1 -0
- package/openclaw.plugin.json +1281 -0
- package/package.json +81 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/config.ts","../src/logger.ts","../src/orchestrator.ts","../src/signal.ts","../src/buffer.ts","../src/chunking.ts","../src/extraction.ts","../src/local-llm.ts","../src/json-extract.ts","../src/fallback-llm.ts","../src/schemas.ts","../src/model-registry.ts","../src/sanitize.ts","../src/importance.ts","../src/qmd.ts","../src/storage.ts","../src/hygiene.ts","../src/types.ts","../src/threading.ts","../src/topics.ts","../src/transcript.ts","../src/summarizer.ts","../src/rerank.ts","../src/relevance.ts","../src/negative.ts","../src/recall-state.ts","../src/embedding-fallback.ts","../src/bootstrap.ts","../src/conversation-index/chunker.ts","../src/conversation-index/indexer.ts","../src/conversation-index/cleanup.ts","../src/namespaces/storage.ts","../src/namespaces/principal.ts","../src/shared-context/manager.ts","../src/compounding/engine.ts","../src/tools.ts","../src/cli.ts","../src/transfer/export-json.ts","../src/transfer/constants.ts","../src/transfer/fs-utils.ts","../src/transfer/export-md.ts","../src/transfer/backup.ts","../src/transfer/export-sqlite.ts","../src/transfer/sqlite-schema.ts","../src/transfer/import-json.ts","../src/transfer/types.ts","../src/transfer/import-sqlite.ts","../src/transfer/import-md.ts","../src/transfer/autodetect.ts","../src/index.ts"],"sourcesContent":["import path from \"node:path\";\nimport type { PluginConfig, PrincipalRule, ReasoningEffort, TriggerMode } from \"./types.js\";\nimport { log } from \"./logger.js\";\n\nconst DEFAULT_MEMORY_DIR = path.join(\n process.env.HOME ?? \"~\",\n \".openclaw\",\n \"workspace\",\n \"memory\",\n \"local\",\n);\n\nconst DEFAULT_WORKSPACE_DIR = path.join(\n process.env.HOME ?? \"~\",\n \".openclaw\",\n \"workspace\",\n);\n\nfunction resolveEnvVars(value: string): string {\n return value.replace(/\\$\\{([^}]+)\\}/g, (_, envVar: string) => {\n const envValue = process.env[envVar];\n if (!envValue) {\n throw new Error(`Environment variable ${envVar} is not set`);\n }\n return envValue;\n });\n}\n\nfunction normalizeOpenaiBaseUrl(value: string | undefined, source: \"config\" | \"env\"): string | undefined {\n if (!value) return undefined;\n const trimmed = value.trim();\n if (trimmed.length === 0) return undefined;\n\n let parsed: URL;\n try {\n parsed = new URL(trimmed);\n } catch {\n log.warn(`ignoring invalid openaiBaseUrl from ${source}: not a valid URL`);\n return undefined;\n }\n\n if (parsed.protocol !== \"https:\" && parsed.protocol !== \"http:\") {\n log.warn(\n `ignoring openaiBaseUrl from ${source}: unsupported URL scheme (${parsed.protocol.replace(\":\", \"\")})`,\n );\n return undefined;\n }\n\n if (parsed.protocol === \"http:\") {\n log.warn(`openaiBaseUrl from ${source} is using insecure http; prefer https`);\n }\n\n // Avoid duplicate slash behavior in downstream baseURL path joins.\n return parsed.toString().replace(/\\/+$/, \"\");\n}\n\nconst VALID_EFFORTS: ReasoningEffort[] = [\"none\", \"low\", \"medium\", \"high\"];\nconst VALID_TRIGGERS: TriggerMode[] = [\"smart\", \"every_n\", \"time_based\"];\n\nexport function parseConfig(raw: unknown): PluginConfig {\n const cfg =\n raw && typeof raw === \"object\" && !Array.isArray(raw)\n ? (raw as Record<string, unknown>)\n : {};\n\n let apiKey: string | undefined;\n if (typeof cfg.openaiApiKey === \"string\" && cfg.openaiApiKey.length > 0) {\n apiKey = resolveEnvVars(cfg.openaiApiKey);\n } else {\n apiKey = process.env.OPENAI_API_KEY;\n }\n\n // API key is optional at load time — retrieval works without it.\n // Extraction will log a warning if called without a key.\n\n const model =\n typeof cfg.model === \"string\" && cfg.model.length > 0\n ? cfg.model\n : \"gpt-5.2\";\n\n const rawEffort = cfg.reasoningEffort as string | undefined;\n const reasoningEffort: ReasoningEffort =\n rawEffort && VALID_EFFORTS.includes(rawEffort as ReasoningEffort)\n ? (rawEffort as ReasoningEffort)\n : \"low\";\n\n const rawTrigger = cfg.triggerMode as string | undefined;\n const triggerMode: TriggerMode =\n rawTrigger && VALID_TRIGGERS.includes(rawTrigger as TriggerMode)\n ? (rawTrigger as TriggerMode)\n : \"smart\";\n\n const memoryDir =\n typeof cfg.memoryDir === \"string\" && cfg.memoryDir.length > 0\n ? cfg.memoryDir\n : DEFAULT_MEMORY_DIR;\n\n const principalRules: PrincipalRule[] = Array.isArray(cfg.principalFromSessionKeyRules)\n ? (cfg.principalFromSessionKeyRules as any[]).map((r) => ({\n match: typeof r?.match === \"string\" ? r.match : \"\",\n principal: typeof r?.principal === \"string\" ? r.principal : \"\",\n })).filter((r) => r.match.length > 0 && r.principal.length > 0)\n : [];\n\n // Optional file hygiene (memory file limits / truncation risk mitigation)\n const rawHygiene =\n cfg.fileHygiene && typeof cfg.fileHygiene === \"object\" && !Array.isArray(cfg.fileHygiene)\n ? (cfg.fileHygiene as Record<string, unknown>)\n : undefined;\n const hygieneEnabled = rawHygiene?.enabled === true;\n const fileHygiene = hygieneEnabled\n ? {\n enabled: true,\n lintEnabled: rawHygiene?.lintEnabled !== false,\n lintBudgetBytes:\n typeof rawHygiene?.lintBudgetBytes === \"number\" ? rawHygiene.lintBudgetBytes : 20_000,\n lintWarnRatio:\n typeof rawHygiene?.lintWarnRatio === \"number\" ? rawHygiene.lintWarnRatio : 0.8,\n lintPaths: Array.isArray(rawHygiene?.lintPaths)\n ? (rawHygiene!.lintPaths as string[])\n : [\"IDENTITY.md\", \"MEMORY.md\"],\n rotateEnabled: rawHygiene?.rotateEnabled === true,\n rotateMaxBytes:\n typeof rawHygiene?.rotateMaxBytes === \"number\" ? rawHygiene.rotateMaxBytes : 18_000,\n rotateKeepTailChars:\n typeof rawHygiene?.rotateKeepTailChars === \"number\"\n ? rawHygiene.rotateKeepTailChars\n : 2000,\n rotatePaths: Array.isArray(rawHygiene?.rotatePaths)\n ? (rawHygiene!.rotatePaths as string[])\n : [\"IDENTITY.md\"],\n archiveDir:\n typeof rawHygiene?.archiveDir === \"string\" && rawHygiene.archiveDir.length > 0\n ? (rawHygiene.archiveDir as string)\n : \".engram-archive\",\n runMinIntervalMs:\n typeof rawHygiene?.runMinIntervalMs === \"number\" ? rawHygiene.runMinIntervalMs : 5 * 60 * 1000,\n warningsLogEnabled: rawHygiene?.warningsLogEnabled === true,\n warningsLogPath:\n typeof rawHygiene?.warningsLogPath === \"string\" && rawHygiene.warningsLogPath.length > 0\n ? (rawHygiene.warningsLogPath as string)\n : \"hygiene/warnings.md\",\n indexEnabled: rawHygiene?.indexEnabled === true,\n indexPath:\n typeof rawHygiene?.indexPath === \"string\" && rawHygiene.indexPath.length > 0\n ? (rawHygiene.indexPath as string)\n : \"ENGRAM_INDEX.md\",\n }\n : undefined;\n\n let baseUrl: string | undefined;\n if (typeof cfg.openaiBaseUrl === \"string\" && cfg.openaiBaseUrl.length > 0) {\n baseUrl = normalizeOpenaiBaseUrl(resolveEnvVars(cfg.openaiBaseUrl), \"config\");\n } else {\n baseUrl = normalizeOpenaiBaseUrl(process.env.OPENAI_BASE_URL, \"env\");\n }\n\n return {\n openaiApiKey: apiKey,\n openaiBaseUrl: baseUrl,\n model,\n reasoningEffort,\n triggerMode,\n bufferMaxTurns:\n typeof cfg.bufferMaxTurns === \"number\" ? cfg.bufferMaxTurns : 5,\n bufferMaxMinutes:\n typeof cfg.bufferMaxMinutes === \"number\" ? cfg.bufferMaxMinutes : 15,\n consolidateEveryN:\n typeof cfg.consolidateEveryN === \"number\" ? cfg.consolidateEveryN : 3,\n highSignalPatterns: Array.isArray(cfg.highSignalPatterns)\n ? (cfg.highSignalPatterns as string[])\n : [],\n maxMemoryTokens:\n typeof cfg.maxMemoryTokens === \"number\" ? cfg.maxMemoryTokens : 2000,\n qmdEnabled: cfg.qmdEnabled !== false,\n qmdCollection:\n typeof cfg.qmdCollection === \"string\"\n ? cfg.qmdCollection\n : \"openclaw-engram\",\n qmdMaxResults:\n typeof cfg.qmdMaxResults === \"number\" ? cfg.qmdMaxResults : 8,\n embeddingFallbackEnabled: cfg.embeddingFallbackEnabled !== false,\n embeddingFallbackProvider:\n cfg.embeddingFallbackProvider === \"openai\"\n ? \"openai\"\n : cfg.embeddingFallbackProvider === \"local\"\n ? \"local\"\n : \"auto\",\n qmdPath:\n typeof cfg.qmdPath === \"string\" && cfg.qmdPath.length > 0\n ? cfg.qmdPath\n : undefined,\n memoryDir,\n debug: cfg.debug === true,\n identityEnabled: cfg.identityEnabled !== false,\n injectQuestions: cfg.injectQuestions === true,\n commitmentDecayDays:\n typeof cfg.commitmentDecayDays === \"number\" ? cfg.commitmentDecayDays : 90,\n workspaceDir:\n typeof cfg.workspaceDir === \"string\" && cfg.workspaceDir.length > 0\n ? cfg.workspaceDir\n : DEFAULT_WORKSPACE_DIR,\n fileHygiene,\n // Access tracking (Phase 1A)\n accessTrackingEnabled: cfg.accessTrackingEnabled !== false,\n accessTrackingBufferMaxSize:\n typeof cfg.accessTrackingBufferMaxSize === \"number\"\n ? cfg.accessTrackingBufferMaxSize\n : 100,\n // Retrieval options\n recencyWeight:\n typeof cfg.recencyWeight === \"number\" ? cfg.recencyWeight : 0.2,\n boostAccessCount: cfg.boostAccessCount !== false,\n // v2.2 Advanced Retrieval (safe defaults: off unless enabled)\n queryExpansionEnabled: cfg.queryExpansionEnabled === true,\n queryExpansionMaxQueries:\n typeof cfg.queryExpansionMaxQueries === \"number\"\n ? cfg.queryExpansionMaxQueries\n : 4,\n queryExpansionMinTokenLen:\n typeof cfg.queryExpansionMinTokenLen === \"number\"\n ? cfg.queryExpansionMinTokenLen\n : 3,\n rerankEnabled: cfg.rerankEnabled === true,\n rerankProvider:\n cfg.rerankProvider === \"cloud\" ? \"cloud\" : \"local\",\n rerankMaxCandidates:\n typeof cfg.rerankMaxCandidates === \"number\" ? cfg.rerankMaxCandidates : 20,\n rerankTimeoutMs:\n typeof cfg.rerankTimeoutMs === \"number\" ? cfg.rerankTimeoutMs : 8000,\n rerankCacheEnabled: cfg.rerankCacheEnabled !== false,\n rerankCacheTtlMs:\n typeof cfg.rerankCacheTtlMs === \"number\" ? cfg.rerankCacheTtlMs : 60 * 60 * 1000,\n feedbackEnabled: cfg.feedbackEnabled === true,\n // v2.2 Negative Examples (safe defaults: off unless enabled)\n negativeExamplesEnabled: cfg.negativeExamplesEnabled === true,\n negativeExamplesPenaltyPerHit:\n typeof cfg.negativeExamplesPenaltyPerHit === \"number\"\n ? cfg.negativeExamplesPenaltyPerHit\n : 0.05,\n negativeExamplesPenaltyCap:\n typeof cfg.negativeExamplesPenaltyCap === \"number\"\n ? cfg.negativeExamplesPenaltyCap\n : 0.25,\n // Chunking (Phase 2A)\n chunkingEnabled: cfg.chunkingEnabled === true, // Off by default initially\n chunkingTargetTokens:\n typeof cfg.chunkingTargetTokens === \"number\" ? cfg.chunkingTargetTokens : 200,\n chunkingMinTokens:\n typeof cfg.chunkingMinTokens === \"number\" ? cfg.chunkingMinTokens : 150,\n chunkingOverlapSentences:\n typeof cfg.chunkingOverlapSentences === \"number\" ? cfg.chunkingOverlapSentences : 2,\n // Contradiction Detection (Phase 2B)\n contradictionDetectionEnabled: cfg.contradictionDetectionEnabled === true, // Off by default initially\n contradictionSimilarityThreshold:\n typeof cfg.contradictionSimilarityThreshold === \"number\" ? cfg.contradictionSimilarityThreshold : 0.7,\n contradictionMinConfidence:\n typeof cfg.contradictionMinConfidence === \"number\" ? cfg.contradictionMinConfidence : 0.9,\n contradictionAutoResolve: cfg.contradictionAutoResolve !== false,\n // Memory Linking (Phase 3A)\n memoryLinkingEnabled: cfg.memoryLinkingEnabled === true, // Off by default initially\n // Conversation Threading (Phase 3B)\n threadingEnabled: cfg.threadingEnabled === true, // Off by default initially\n threadingGapMinutes:\n typeof cfg.threadingGapMinutes === \"number\" ? cfg.threadingGapMinutes : 30,\n // Memory Summarization (Phase 4A)\n summarizationEnabled: cfg.summarizationEnabled === true, // Off by default\n summarizationTriggerCount:\n typeof cfg.summarizationTriggerCount === \"number\" ? cfg.summarizationTriggerCount : 1000,\n summarizationRecentToKeep:\n typeof cfg.summarizationRecentToKeep === \"number\" ? cfg.summarizationRecentToKeep : 300,\n summarizationImportanceThreshold:\n typeof cfg.summarizationImportanceThreshold === \"number\" ? cfg.summarizationImportanceThreshold : 0.3,\n summarizationProtectedTags: Array.isArray(cfg.summarizationProtectedTags)\n ? (cfg.summarizationProtectedTags as string[])\n : [\"commitment\", \"preference\", \"decision\", \"principle\"],\n // Topic Extraction (Phase 4B)\n topicExtractionEnabled: cfg.topicExtractionEnabled !== false, // On by default\n topicExtractionTopN:\n typeof cfg.topicExtractionTopN === \"number\" ? cfg.topicExtractionTopN : 50,\n // Transcript & Context Preservation (v2.0)\n // Transcript archive\n transcriptEnabled: cfg.transcriptEnabled !== false, // default: true\n transcriptRetentionDays:\n typeof cfg.transcriptRetentionDays === \"number\" ? cfg.transcriptRetentionDays : 7,\n transcriptSkipChannelTypes: Array.isArray(cfg.transcriptSkipChannelTypes)\n ? (cfg.transcriptSkipChannelTypes as string[])\n : [\"cron\"], // default: skip cron transcripts\n // Transcript injection\n transcriptRecallHours:\n typeof cfg.transcriptRecallHours === \"number\" ? cfg.transcriptRecallHours : 12,\n maxTranscriptTurns:\n typeof cfg.maxTranscriptTurns === \"number\" ? cfg.maxTranscriptTurns : 50,\n maxTranscriptTokens:\n typeof cfg.maxTranscriptTokens === \"number\" ? cfg.maxTranscriptTokens : 1000,\n // Checkpoint\n checkpointEnabled: cfg.checkpointEnabled !== false, // default: true\n checkpointTurns:\n typeof cfg.checkpointTurns === \"number\" ? cfg.checkpointTurns : 15,\n // Hourly summaries\n hourlySummariesEnabled: cfg.hourlySummariesEnabled !== false, // default: true\n hourlySummaryCronAutoRegister: cfg.hourlySummaryCronAutoRegister === true,\n summaryRecallHours:\n typeof cfg.summaryRecallHours === \"number\" ? cfg.summaryRecallHours : 24,\n maxSummaryCount:\n typeof cfg.maxSummaryCount === \"number\" ? cfg.maxSummaryCount : 6,\n summaryModel:\n typeof cfg.summaryModel === \"string\" && cfg.summaryModel.length > 0\n ? cfg.summaryModel\n : model, // default: same as extraction model\n // v2.4 Extended hourly summaries (default off)\n hourlySummariesExtendedEnabled: cfg.hourlySummariesExtendedEnabled === true,\n hourlySummariesIncludeToolStats: cfg.hourlySummariesIncludeToolStats === true,\n hourlySummariesIncludeSystemMessages: cfg.hourlySummariesIncludeSystemMessages === true,\n hourlySummariesMaxTurnsPerRun:\n typeof cfg.hourlySummariesMaxTurnsPerRun === \"number\" ? cfg.hourlySummariesMaxTurnsPerRun : 200,\n // v2.4 Conversation index (default off)\n conversationIndexEnabled: cfg.conversationIndexEnabled === true,\n conversationIndexBackend: cfg.conversationIndexBackend === \"faiss\" ? \"faiss\" : \"qmd\",\n conversationIndexQmdCollection:\n typeof cfg.conversationIndexQmdCollection === \"string\" && cfg.conversationIndexQmdCollection.length > 0\n ? cfg.conversationIndexQmdCollection\n : \"openclaw-engram-conversations\",\n conversationIndexRetentionDays:\n typeof cfg.conversationIndexRetentionDays === \"number\" ? cfg.conversationIndexRetentionDays : 30,\n conversationIndexMinUpdateIntervalMs:\n typeof cfg.conversationIndexMinUpdateIntervalMs === \"number\"\n ? cfg.conversationIndexMinUpdateIntervalMs\n : 15 * 60_000,\n conversationIndexEmbedOnUpdate: cfg.conversationIndexEmbedOnUpdate === true,\n conversationRecallTopK:\n typeof cfg.conversationRecallTopK === \"number\" ? cfg.conversationRecallTopK : 3,\n conversationRecallMaxChars:\n typeof cfg.conversationRecallMaxChars === \"number\" ? cfg.conversationRecallMaxChars : 2500,\n conversationRecallTimeoutMs:\n typeof cfg.conversationRecallTimeoutMs === \"number\" ? cfg.conversationRecallTimeoutMs : 800,\n // Local LLM Provider (v2.1)\n localLlmEnabled: cfg.localLlmEnabled === true || cfg.localLlmEnabled === \"true\", // default: false\n localLlmUrl:\n typeof cfg.localLlmUrl === \"string\" && cfg.localLlmUrl.length > 0\n ? cfg.localLlmUrl\n : \"http://localhost:1234/v1\",\n localLlmModel:\n typeof cfg.localLlmModel === \"string\" && cfg.localLlmModel.length > 0\n ? cfg.localLlmModel\n : \"local-model\",\n localLlmApiKey:\n typeof cfg.localLlmApiKey === \"string\" && cfg.localLlmApiKey.length > 0\n ? resolveEnvVars(cfg.localLlmApiKey)\n : undefined,\n localLlmHeaders:\n cfg.localLlmHeaders && typeof cfg.localLlmHeaders === \"object\" && !Array.isArray(cfg.localLlmHeaders)\n ? Object.fromEntries(\n Object.entries(cfg.localLlmHeaders as Record<string, unknown>)\n .filter(([, value]) => typeof value === \"string\")\n .map(([key, value]) => [key, String(value)]),\n )\n : undefined,\n localLlmAuthHeader: cfg.localLlmAuthHeader !== false,\n localLlmFallback: cfg.localLlmFallback !== false, // default: true\n localLlmHomeDir:\n typeof cfg.localLlmHomeDir === \"string\" && cfg.localLlmHomeDir.length > 0\n ? cfg.localLlmHomeDir\n : undefined,\n localLmsCliPath:\n typeof cfg.localLmsCliPath === \"string\" && cfg.localLmsCliPath.length > 0\n ? cfg.localLmsCliPath\n : undefined,\n localLmsBinDir:\n typeof cfg.localLmsBinDir === \"string\" && cfg.localLmsBinDir.length > 0\n ? cfg.localLmsBinDir\n : undefined,\n localLlmTimeoutMs:\n typeof cfg.localLlmTimeoutMs === \"number\" ? cfg.localLlmTimeoutMs : 180_000,\n localLlmMaxContext:\n typeof cfg.localLlmMaxContext === \"number\" ? cfg.localLlmMaxContext : undefined,\n // Observability (disabled by default to avoid log spam)\n slowLogEnabled: cfg.slowLogEnabled === true,\n slowLogThresholdMs:\n typeof cfg.slowLogThresholdMs === \"number\" ? cfg.slowLogThresholdMs : 30_000,\n // Extraction stability guards (P0/P1)\n extractionDedupeEnabled: cfg.extractionDedupeEnabled !== false,\n extractionDedupeWindowMs:\n typeof cfg.extractionDedupeWindowMs === \"number\" ? cfg.extractionDedupeWindowMs : 5 * 60_000,\n extractionMinChars:\n typeof cfg.extractionMinChars === \"number\" ? cfg.extractionMinChars : 40,\n extractionMinUserTurns:\n typeof cfg.extractionMinUserTurns === \"number\" ? cfg.extractionMinUserTurns : 1,\n extractionMaxTurnChars:\n typeof cfg.extractionMaxTurnChars === \"number\" ? cfg.extractionMaxTurnChars : 4000,\n extractionMaxFactsPerRun:\n typeof cfg.extractionMaxFactsPerRun === \"number\" ? cfg.extractionMaxFactsPerRun : 12,\n extractionMaxEntitiesPerRun:\n typeof cfg.extractionMaxEntitiesPerRun === \"number\" ? cfg.extractionMaxEntitiesPerRun : 6,\n extractionMaxQuestionsPerRun:\n typeof cfg.extractionMaxQuestionsPerRun === \"number\" ? cfg.extractionMaxQuestionsPerRun : 3,\n extractionMaxProfileUpdatesPerRun:\n typeof cfg.extractionMaxProfileUpdatesPerRun === \"number\" ? cfg.extractionMaxProfileUpdatesPerRun : 4,\n consolidationRequireNonZeroExtraction: cfg.consolidationRequireNonZeroExtraction !== false,\n consolidationMinIntervalMs:\n typeof cfg.consolidationMinIntervalMs === \"number\" ? cfg.consolidationMinIntervalMs : 10 * 60_000,\n // QMD maintenance (debounced singleflight)\n qmdMaintenanceEnabled: cfg.qmdMaintenanceEnabled !== false,\n qmdMaintenanceDebounceMs:\n typeof cfg.qmdMaintenanceDebounceMs === \"number\" ? cfg.qmdMaintenanceDebounceMs : 30_000,\n qmdAutoEmbedEnabled: cfg.qmdAutoEmbedEnabled === true,\n qmdEmbedMinIntervalMs:\n typeof cfg.qmdEmbedMinIntervalMs === \"number\" ? cfg.qmdEmbedMinIntervalMs : 60 * 60_000,\n qmdUpdateTimeoutMs:\n typeof cfg.qmdUpdateTimeoutMs === \"number\" ? cfg.qmdUpdateTimeoutMs : 90_000,\n // Local LLM resilience\n localLlmRetry5xxCount:\n typeof cfg.localLlmRetry5xxCount === \"number\" ? cfg.localLlmRetry5xxCount : 1,\n localLlmRetryBackoffMs:\n typeof cfg.localLlmRetryBackoffMs === \"number\" ? cfg.localLlmRetryBackoffMs : 400,\n localLlm400TripThreshold:\n typeof cfg.localLlm400TripThreshold === \"number\" ? cfg.localLlm400TripThreshold : 5,\n localLlm400CooldownMs:\n typeof cfg.localLlm400CooldownMs === \"number\" ? cfg.localLlm400CooldownMs : 120_000,\n // Gateway config (passed from index.ts for fallback AI)\n gatewayConfig: cfg.gatewayConfig as PluginConfig[\"gatewayConfig\"],\n\n // v3.0 namespaces (default off)\n namespacesEnabled: cfg.namespacesEnabled === true,\n defaultNamespace:\n typeof cfg.defaultNamespace === \"string\" && cfg.defaultNamespace.length > 0 ? cfg.defaultNamespace : \"default\",\n sharedNamespace:\n typeof cfg.sharedNamespace === \"string\" && cfg.sharedNamespace.length > 0 ? cfg.sharedNamespace : \"shared\",\n principalFromSessionKeyMode:\n cfg.principalFromSessionKeyMode === \"prefix\"\n ? \"prefix\"\n : cfg.principalFromSessionKeyMode === \"regex\"\n ? \"regex\"\n : \"map\",\n principalFromSessionKeyRules: principalRules,\n namespacePolicies: Array.isArray(cfg.namespacePolicies)\n ? (cfg.namespacePolicies as any[]).map((p) => ({\n name: typeof p?.name === \"string\" ? p.name : \"\",\n readPrincipals: Array.isArray(p?.readPrincipals) ? p.readPrincipals.filter((x: any) => typeof x === \"string\") : [],\n writePrincipals: Array.isArray(p?.writePrincipals) ? p.writePrincipals.filter((x: any) => typeof x === \"string\") : [],\n includeInRecallByDefault: p?.includeInRecallByDefault === true,\n })).filter((p) => p.name.length > 0)\n : [],\n defaultRecallNamespaces: Array.isArray(cfg.defaultRecallNamespaces) ? [\"self\", \"shared\"].filter((x) => (cfg.defaultRecallNamespaces as any[]).includes(x)) as any : [\"self\", \"shared\"],\n autoPromoteToSharedEnabled: cfg.autoPromoteToSharedEnabled === true,\n autoPromoteToSharedCategories: Array.isArray(cfg.autoPromoteToSharedCategories)\n ? (cfg.autoPromoteToSharedCategories as any[]).filter((c) => c === \"correction\" || c === \"decision\" || c === \"preference\")\n : [\"correction\", \"decision\", \"preference\"],\n autoPromoteMinConfidenceTier:\n cfg.autoPromoteMinConfidenceTier === \"explicit\"\n ? \"explicit\"\n : cfg.autoPromoteMinConfidenceTier === \"implied\"\n ? \"implied\"\n : \"explicit\",\n\n // v4.0 shared-context (default off)\n sharedContextEnabled: cfg.sharedContextEnabled === true,\n sharedContextDir:\n typeof cfg.sharedContextDir === \"string\" && cfg.sharedContextDir.length > 0 ? cfg.sharedContextDir : undefined,\n sharedContextMaxInjectChars:\n typeof cfg.sharedContextMaxInjectChars === \"number\" ? cfg.sharedContextMaxInjectChars : 4000,\n crossSignalsSemanticEnabled: cfg.crossSignalsSemanticEnabled === true,\n crossSignalsSemanticTimeoutMs:\n typeof cfg.crossSignalsSemanticTimeoutMs === \"number\" ? cfg.crossSignalsSemanticTimeoutMs : 4000,\n\n // v5.0 compounding (default off)\n compoundingEnabled: cfg.compoundingEnabled === true,\n compoundingWeeklyCronEnabled: cfg.compoundingWeeklyCronEnabled === true,\n compoundingSemanticEnabled: cfg.compoundingSemanticEnabled === true,\n compoundingSynthesisTimeoutMs:\n typeof cfg.compoundingSynthesisTimeoutMs === \"number\" ? cfg.compoundingSynthesisTimeoutMs : 15_000,\n compoundingInjectEnabled: cfg.compoundingInjectEnabled !== false,\n\n // v7.0 Knowledge Graph Enhancement\n knowledgeIndexEnabled: cfg.knowledgeIndexEnabled !== false,\n knowledgeIndexMaxEntities:\n typeof cfg.knowledgeIndexMaxEntities === \"number\" ? cfg.knowledgeIndexMaxEntities : 40,\n knowledgeIndexMaxChars:\n typeof cfg.knowledgeIndexMaxChars === \"number\" ? cfg.knowledgeIndexMaxChars : 4000,\n entityRelationshipsEnabled: cfg.entityRelationshipsEnabled !== false,\n entityActivityLogEnabled: cfg.entityActivityLogEnabled !== false,\n entityActivityLogMaxEntries:\n typeof cfg.entityActivityLogMaxEntries === \"number\" ? cfg.entityActivityLogMaxEntries : 20,\n entityAliasesEnabled: cfg.entityAliasesEnabled !== false,\n entitySummaryEnabled: cfg.entitySummaryEnabled !== false,\n\n // QMD daemon mode\n qmdDaemonEnabled: cfg.qmdDaemonEnabled !== false,\n qmdDaemonUrl:\n typeof cfg.qmdDaemonUrl === \"string\" && cfg.qmdDaemonUrl.length > 0\n ? cfg.qmdDaemonUrl\n : \"http://localhost:8181/mcp\",\n qmdDaemonRecheckIntervalMs:\n typeof cfg.qmdDaemonRecheckIntervalMs === \"number\" ? cfg.qmdDaemonRecheckIntervalMs : 60_000,\n\n // v6.0 Fact deduplication & archival\n factDeduplicationEnabled: cfg.factDeduplicationEnabled !== false,\n factArchivalEnabled: cfg.factArchivalEnabled === true,\n factArchivalAgeDays:\n typeof cfg.factArchivalAgeDays === \"number\" ? cfg.factArchivalAgeDays : 90,\n factArchivalMaxImportance:\n typeof cfg.factArchivalMaxImportance === \"number\" ? cfg.factArchivalMaxImportance : 0.3,\n factArchivalMaxAccessCount:\n typeof cfg.factArchivalMaxAccessCount === \"number\" ? cfg.factArchivalMaxAccessCount : 2,\n factArchivalProtectedCategories: Array.isArray(cfg.factArchivalProtectedCategories)\n ? (cfg.factArchivalProtectedCategories as any[]).filter((c) => typeof c === \"string\")\n : [\"commitment\", \"preference\", \"decision\", \"principle\"],\n };\n}\n","export interface LoggerBackend {\n info(msg: string, ...args: unknown[]): void;\n warn(msg: string, ...args: unknown[]): void;\n error(msg: string, ...args: unknown[]): void;\n debug?(msg: string, ...args: unknown[]): void;\n}\n\nconst NOOP_LOGGER: LoggerBackend = {\n info() {},\n warn() {},\n error() {},\n debug() {},\n};\n\nlet _backend: LoggerBackend = NOOP_LOGGER;\nlet _debug = false;\n\nexport function initLogger(backend: LoggerBackend, debug: boolean): void {\n _backend = backend;\n _debug = debug;\n}\n\nexport const log = {\n info(msg: string, ...args: unknown[]): void {\n _backend.info(`openclaw-engram: ${msg}`, ...args);\n },\n warn(msg: string, ...args: unknown[]): void {\n _backend.warn(`openclaw-engram: ${msg}`, ...args);\n },\n error(msg: string, err?: unknown): void {\n const detail =\n err instanceof Error ? err.message : err ? String(err) : \"\";\n _backend.error(\n `openclaw-engram: ${msg}${detail ? ` — ${detail}` : \"\"}`,\n );\n },\n debug(msg: string, ...args: unknown[]): void {\n if (!_debug) return;\n const fn = _backend.debug ?? _backend.info;\n fn(`openclaw-engram [debug]: ${msg}`, ...args);\n },\n};\n","import { log } from \"./logger.js\";\nimport path from \"node:path\";\nimport { createHash } from \"node:crypto\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { SmartBuffer } from \"./buffer.js\";\nimport { chunkContent, type ChunkingConfig } from \"./chunking.js\";\nimport { ExtractionEngine } from \"./extraction.js\";\nimport { scoreImportance } from \"./importance.js\";\nimport { QmdClient } from \"./qmd.js\";\nimport { StorageManager, ContentHashIndex, normalizeEntityName } from \"./storage.js\";\nimport { ThreadingManager } from \"./threading.js\";\nimport { extractTopics } from \"./topics.js\";\nimport { TranscriptManager } from \"./transcript.js\";\nimport { HourlySummarizer } from \"./summarizer.js\";\nimport { LocalLlmClient } from \"./local-llm.js\";\nimport { ModelRegistry } from \"./model-registry.js\";\nimport { expandQuery } from \"./retrieval.js\";\nimport { RerankCache, rerankLocalOrNoop } from \"./rerank.js\";\nimport { RelevanceStore } from \"./relevance.js\";\nimport { NegativeExampleStore } from \"./negative.js\";\nimport { LastRecallStore, type LastRecallSnapshot } from \"./recall-state.js\";\nimport { isDisagreementPrompt } from \"./signal.js\";\nimport { lintWorkspaceFiles, rotateMarkdownFileToArchive } from \"./hygiene.js\";\nimport { EmbeddingFallback } from \"./embedding-fallback.js\";\nimport { BootstrapEngine } from \"./bootstrap.js\";\nimport type { MemorySummary } from \"./types.js\";\nimport { chunkTranscriptEntries } from \"./conversation-index/chunker.js\";\nimport { writeConversationChunks } from \"./conversation-index/indexer.js\";\nimport { cleanupConversationChunks } from \"./conversation-index/cleanup.js\";\nimport { NamespaceStorageRouter } from \"./namespaces/storage.js\";\nimport {\n defaultNamespaceForPrincipal,\n recallNamespacesForPrincipal,\n resolvePrincipal,\n} from \"./namespaces/principal.js\";\nimport { SharedContextManager } from \"./shared-context/manager.js\";\nimport { CompoundingEngine } from \"./compounding/engine.js\";\nimport type {\n AccessTrackingEntry,\n BootstrapOptions,\n BootstrapResult,\n BufferTurn,\n ExtractionResult,\n MemoryLink,\n MemoryFile,\n PluginConfig,\n QmdSearchResult,\n} from \"./types.js\";\n\nexport class Orchestrator {\n readonly storage: StorageManager;\n private readonly storageRouter: NamespaceStorageRouter;\n readonly qmd: QmdClient;\n private readonly conversationQmd?: QmdClient;\n readonly sharedContext?: SharedContextManager;\n readonly compounding?: CompoundingEngine;\n readonly buffer: SmartBuffer;\n readonly transcript: TranscriptManager;\n readonly summarizer: HourlySummarizer;\n readonly localLlm: LocalLlmClient;\n readonly modelRegistry: ModelRegistry;\n readonly relevance: RelevanceStore;\n readonly negatives: NegativeExampleStore;\n readonly lastRecall: LastRecallStore;\n readonly embeddingFallback: EmbeddingFallback;\n private readonly conversationIndexDir: string;\n private readonly extraction: ExtractionEngine;\n readonly config: PluginConfig;\n private readonly threading: ThreadingManager;\n private readonly rerankCache = new RerankCache();\n private contentHashIndex: ContentHashIndex | null = null;\n\n // Access tracking buffer (Phase 1A)\n // Maps memoryId -> {count, lastAccessed} for batched updates\n private accessTrackingBuffer: Map<string, { count: number; lastAccessed: string }> =\n new Map();\n\n // Background serial queue for extractions (agent_end optimization)\n // Queue stores promises that resolve when extraction should run\n private extractionQueue: Array<() => Promise<void>> = [];\n private queueProcessing = false;\n private recentExtractionFingerprints = new Map<string, number>();\n private nonZeroExtractionsSinceConsolidation = 0;\n private lastConsolidationRunAtMs = 0;\n private consolidationInFlight = false;\n private qmdMaintenanceTimer: NodeJS.Timeout | null = null;\n private qmdMaintenancePending = false;\n private qmdMaintenanceInFlight = false;\n private lastQmdEmbedAtMs = 0;\n private readonly conversationIndexLastUpdateAtMs = new Map<string, number>();\n private lastFileHygieneRunAtMs = 0;\n\n // Initialization gate: recall() awaits this before proceeding\n private initPromise: Promise<void> | null = null;\n private resolveInit: (() => void) | null = null;\n constructor(config: PluginConfig) {\n this.config = config;\n this.storageRouter = new NamespaceStorageRouter(config);\n this.storage = new StorageManager(config.memoryDir);\n this.qmd = new QmdClient(config.qmdCollection, config.qmdMaxResults, {\n slowLog: {\n enabled: config.slowLogEnabled,\n thresholdMs: config.slowLogThresholdMs,\n },\n updateTimeoutMs: config.qmdUpdateTimeoutMs,\n qmdPath: config.qmdPath,\n daemonUrl: config.qmdDaemonEnabled ? config.qmdDaemonUrl : undefined,\n daemonRecheckIntervalMs: config.qmdDaemonRecheckIntervalMs,\n });\n this.conversationQmd =\n config.conversationIndexEnabled && config.conversationIndexBackend === \"qmd\"\n ? new QmdClient(\n config.conversationIndexQmdCollection,\n Math.max(6, config.conversationRecallTopK),\n {\n slowLog: {\n enabled: config.slowLogEnabled,\n thresholdMs: config.slowLogThresholdMs,\n },\n updateTimeoutMs: config.qmdUpdateTimeoutMs,\n qmdPath: config.qmdPath,\n daemonUrl: config.qmdDaemonEnabled ? config.qmdDaemonUrl : undefined,\n daemonRecheckIntervalMs: config.qmdDaemonRecheckIntervalMs,\n },\n )\n : undefined;\n this.sharedContext = config.sharedContextEnabled ? new SharedContextManager(config) : undefined;\n this.compounding = config.compoundingEnabled ? new CompoundingEngine(config) : undefined;\n this.buffer = new SmartBuffer(config, this.storage);\n this.transcript = new TranscriptManager(config);\n this.conversationIndexDir = path.join(config.memoryDir, \"conversation-index\", \"chunks\");\n this.modelRegistry = new ModelRegistry(config.memoryDir);\n this.relevance = new RelevanceStore(config.memoryDir);\n this.negatives = new NegativeExampleStore(config.memoryDir);\n this.lastRecall = new LastRecallStore(config.memoryDir);\n this.embeddingFallback = new EmbeddingFallback(config);\n this.summarizer = new HourlySummarizer(config, config.gatewayConfig, this.modelRegistry, this.transcript);\n this.localLlm = new LocalLlmClient(config, this.modelRegistry);\n this.extraction = new ExtractionEngine(config, this.localLlm, config.gatewayConfig, this.modelRegistry);\n this.threading = new ThreadingManager(\n path.join(config.memoryDir, \"threads\"),\n config.threadingGapMinutes,\n );\n\n // Create init gate — recall() will await this before proceeding\n this.initPromise = new Promise<void>((resolve) => {\n this.resolveInit = resolve;\n });\n }\n\n async initialize(): Promise<void> {\n await this.storage.ensureDirectories();\n await this.storage.loadAliases();\n if (this.config.namespacesEnabled) {\n const namespaces = new Set<string>([\n this.config.defaultNamespace,\n this.config.sharedNamespace,\n ...this.config.namespacePolicies.map((p) => p.name),\n ]);\n for (const ns of namespaces) {\n const sm = await this.storageRouter.storageFor(ns);\n await sm.ensureDirectories();\n await sm.loadAliases().catch(() => undefined);\n }\n }\n await this.relevance.load();\n await this.negatives.load();\n await this.lastRecall.load();\n\n // Initialize content-hash dedup index\n if (this.config.factDeduplicationEnabled) {\n const stateDir = path.join(this.config.memoryDir, \"state\");\n this.contentHashIndex = new ContentHashIndex(stateDir);\n await this.contentHashIndex.load();\n log.info(`content-hash dedup: loaded ${this.contentHashIndex.size} hashes`);\n }\n await this.transcript.initialize();\n await this.summarizer.initialize();\n if (this.sharedContext) {\n await this.sharedContext.ensureStructure();\n }\n if (this.compounding) {\n await this.compounding.ensureDirs();\n }\n\n if (this.config.qmdEnabled) {\n const available = await this.qmd.probe();\n if (available) {\n const mode = this.qmd.isDaemonMode() ? \"daemon\" : \"subprocess\";\n log.info(`QMD: available (mode: ${mode}) ${this.qmd.debugStatus()}`);\n await this.qmd.ensureCollection(this.config.memoryDir);\n } else {\n log.warn(`QMD: not available ${this.qmd.debugStatus()}`);\n }\n }\n\n if (this.config.conversationIndexEnabled && this.conversationQmd) {\n const available = await this.conversationQmd.probe();\n if (available) {\n log.info(`Conversation index QMD: available ${this.conversationQmd.debugStatus()}`);\n await this.conversationQmd.ensureCollection(\n path.join(this.config.memoryDir, \"conversation-index\"),\n );\n } else {\n log.warn(`Conversation index QMD: not available ${this.conversationQmd.debugStatus()}`);\n }\n }\n\n await this.buffer.load();\n\n // Validate local LLM model configuration\n if (this.config.localLlmEnabled) {\n await this.validateLocalLlmModel();\n }\n\n log.info(\"orchestrator initialized\");\n\n // Open the init gate — any recall() calls waiting on this will proceed\n if (this.resolveInit) {\n this.resolveInit();\n this.resolveInit = null;\n }\n }\n\n async maybeRunFileHygiene(): Promise<void> {\n const hygiene = this.config.fileHygiene;\n if (!hygiene?.enabled) return;\n\n const now = Date.now();\n if (now - this.lastFileHygieneRunAtMs < hygiene.runMinIntervalMs) return;\n this.lastFileHygieneRunAtMs = now;\n\n // Rotation first (keeps bootstrap files small).\n if (hygiene.rotateEnabled) {\n for (const rel of hygiene.rotatePaths) {\n const abs = path.isAbsolute(rel) ? rel : path.join(this.config.workspaceDir, rel);\n try {\n const raw = await readFile(abs, \"utf-8\");\n if (raw.length > hygiene.rotateMaxBytes) {\n const archiveDir = path.join(this.config.workspaceDir, hygiene.archiveDir);\n const base = path.basename(abs);\n const prefix =\n base.toUpperCase().replace(/\\.MD$/i, \"\").replace(/[^A-Z0-9]+/g, \"-\") || \"FILE\";\n const { newContent } = await rotateMarkdownFileToArchive({\n filePath: abs,\n archiveDir,\n archivePrefix: prefix,\n keepTailChars: hygiene.rotateKeepTailChars,\n });\n await writeFile(abs, newContent, \"utf-8\");\n }\n } catch {\n // ignore missing/unreadable targets\n }\n }\n }\n\n // Lint (warn before truncation risk).\n if (hygiene.lintEnabled) {\n const warnings = await lintWorkspaceFiles({\n workspaceDir: this.config.workspaceDir,\n paths: hygiene.lintPaths,\n budgetBytes: hygiene.lintBudgetBytes,\n warnRatio: hygiene.lintWarnRatio,\n });\n for (const w of warnings) {\n log.warn(w.message);\n }\n\n if (hygiene.warningsLogEnabled && warnings.length > 0) {\n const fp = path.join(this.config.memoryDir, hygiene.warningsLogPath);\n await mkdir(path.dirname(fp), { recursive: true });\n const stamp = new Date().toISOString();\n const block =\n `\\n\\n## ${stamp}\\n\\n` +\n warnings.map((w) => `- ${w.message}`).join(\"\\n\") +\n \"\\n\";\n let existing = \"\";\n try {\n existing = await readFile(fp, \"utf-8\");\n } catch {\n existing = \"# Engram File Hygiene Warnings\\n\";\n }\n await writeFile(fp, existing + block, \"utf-8\");\n }\n }\n }\n\n async runBootstrap(options: BootstrapOptions): Promise<BootstrapResult> {\n const engine = new BootstrapEngine(this.config, this);\n return engine.run(options);\n }\n\n async runConsolidationNow(): Promise<{ memoriesProcessed: number; merged: number; invalidated: number }> {\n return this.runConsolidation();\n }\n\n async waitForExtractionIdle(timeoutMs: number = 60_000): Promise<void> {\n const started = Date.now();\n while (this.queueProcessing || this.extractionQueue.length > 0) {\n if (Date.now() - started > timeoutMs) {\n log.warn(`waitForExtractionIdle timed out after ${timeoutMs}ms`);\n return;\n }\n await new Promise((resolve) => setTimeout(resolve, 50));\n }\n }\n\n async getStorage(namespace?: string): Promise<StorageManager> {\n const ns = namespace && namespace.length > 0 ? namespace : this.config.defaultNamespace;\n return this.storageRouter.storageFor(ns);\n }\n\n async updateConversationIndex(\n sessionKey: string,\n hours: number = 24,\n opts?: { embed?: boolean; enforceMinInterval?: boolean },\n ): Promise<{ chunks: number; skipped: boolean; reason?: string; retryAfterMs?: number; embedded?: boolean }> {\n if (!this.config.conversationIndexEnabled) {\n return { chunks: 0, skipped: true, reason: \"disabled\", embedded: false };\n }\n const enforceMinInterval = opts?.enforceMinInterval !== false;\n if (enforceMinInterval) {\n const minIntervalMs = Math.max(0, this.config.conversationIndexMinUpdateIntervalMs);\n const now = Date.now();\n const last = this.conversationIndexLastUpdateAtMs.get(sessionKey) ?? 0;\n const elapsed = now - last;\n if (minIntervalMs > 0 && elapsed < minIntervalMs) {\n return {\n chunks: 0,\n skipped: true,\n reason: \"min_interval\",\n retryAfterMs: minIntervalMs - elapsed,\n embedded: false,\n };\n }\n }\n // Read transcript history and chunk it into markdown docs for QMD indexing.\n const entries = await this.transcript.readRecent(hours, sessionKey);\n const chunks = chunkTranscriptEntries(sessionKey, entries, {\n maxChars: this.config.conversationRecallMaxChars * 2,\n maxTurns: Math.max(10, this.config.hourlySummariesMaxTurnsPerRun),\n });\n await writeConversationChunks(this.conversationIndexDir, chunks);\n await cleanupConversationChunks(\n this.conversationIndexDir,\n this.config.conversationIndexRetentionDays,\n );\n // Best-effort: ask qmd to update indexes (will no-op if qmd missing).\n const q = this.conversationQmd ?? this.qmd;\n const shouldEmbed = opts?.embed ?? this.config.conversationIndexEmbedOnUpdate;\n let embedded = false;\n if (this.config.qmdEnabled && q.isAvailable()) {\n await q.update();\n if (shouldEmbed) {\n await q.embed();\n embedded = true;\n }\n }\n this.conversationIndexLastUpdateAtMs.set(sessionKey, Date.now());\n return { chunks: chunks.length, skipped: false, embedded };\n }\n\n /**\n * Validate local LLM model availability and context window compatibility.\n * Warns the user if there's a mismatch.\n */\n private async validateLocalLlmModel(): Promise<void> {\n log.info(\"Local LLM: Validating model configuration...\");\n try {\n const modelInfo = await this.localLlm.getLoadedModelInfo();\n if (!modelInfo) {\n log.warn(\"Local LLM validation: Could not query model info from server\");\n log.warn(\n \"Local LLM validation: Could not query model info. \" +\n \"Ensure LM Studio/Ollama is running with the model loaded.\"\n );\n return;\n }\n\n // Check for context window mismatch\n const configuredMaxContext = this.config.localLlmMaxContext;\n\n if (modelInfo.contextWindow) {\n log.info(\n `Local LLM: ${modelInfo.id} loaded with ${modelInfo.contextWindow.toLocaleString()} token context window`\n );\n\n if (configuredMaxContext && configuredMaxContext > modelInfo.contextWindow) {\n log.warn(\n `Local LLM context mismatch: engram configured for ${configuredMaxContext.toLocaleString()} tokens, ` +\n `but ${modelInfo.id} only supports ${modelInfo.contextWindow.toLocaleString()}. ` +\n `Reducing to ${modelInfo.contextWindow.toLocaleString()} to avoid errors.`\n );\n // Update the config in-memory to match actual capability\n // (This is a temporary fix - user should update their config)\n (this.config as { localLlmMaxContext?: number }).localLlmMaxContext = modelInfo.contextWindow;\n }\n } else {\n log.info(`Local LLM: ${modelInfo.id} loaded (context window not reported by server)`);\n\n if (!configuredMaxContext) {\n log.warn(\n \"Local LLM: Server did not report context window. \" +\n \"If you get 'context length exceeded' errors, set localLlmMaxContext in your config. \" +\n \"Common defaults: LM Studio (32K), Ollama (2K-128K depending on model).\"\n );\n }\n }\n } catch (err) {\n log.warn(`Local LLM validation failed: ${err}`);\n }\n }\n\n async recall(prompt: string, sessionKey?: string): Promise<string> {\n // Wait for initialization to complete before attempting recall.\n // Timeout after 15s in case initialize() never fires (edge case).\n if (this.initPromise) {\n const INIT_GATE_TIMEOUT_MS = 15_000;\n const gateResult = await Promise.race([\n this.initPromise.then(() => \"ok\" as const),\n new Promise<\"timeout\">((r) => setTimeout(() => r(\"timeout\"), INIT_GATE_TIMEOUT_MS)),\n ]);\n if (gateResult === \"timeout\") {\n log.warn(\"recall: init gate timed out — proceeding without full init\");\n }\n }\n\n // Wrap recall logic with a 60-second timeout to prevent agent hangs\n const RECALL_TIMEOUT_MS = 60_000;\n return Promise.race([\n this.recallInternal(prompt, sessionKey),\n new Promise<string>((_, reject) =>\n setTimeout(() => reject(new Error(\"recall timeout\")), RECALL_TIMEOUT_MS)\n ),\n ]).catch((err) => {\n log.warn(`recall timed out or failed: ${err}`);\n return \"\"; // Return empty context on timeout/error\n });\n }\n\n private async recallInternal(prompt: string, sessionKey?: string): Promise<string> {\n const recallStart = Date.now();\n const timings: Record<string, string> = {};\n const sections: string[] = [];\n\n const principal = resolvePrincipal(sessionKey, this.config);\n const selfNamespace = defaultNamespaceForPrincipal(principal, this.config);\n const recallNamespaces = recallNamespacesForPrincipal(principal, this.config);\n const profileStorage = await this.storageRouter.storageFor(selfNamespace);\n\n // --- Phase 1: Launch ALL independent data fetches in parallel ---\n\n // 0. Shared context (v4.0, optional)\n const sharedContextPromise = (async (): Promise<string | null> => {\n if (!this.sharedContext) return null;\n const t0 = Date.now();\n const [priorities, roundtable] = await Promise.all([\n this.sharedContext.readPriorities(),\n this.sharedContext.readLatestRoundtable(),\n ]);\n const combined =\n [\n \"## Shared Context\",\n \"\",\n priorities ? \"### Priorities\\n\\n\" + priorities.trim() : \"\",\n roundtable ? \"\\n\\n### Latest Roundtable\\n\\n\" + roundtable.trim() : \"\",\n ]\n .filter((s) => s.trim().length > 0)\n .join(\"\\n\");\n\n const max = Math.max(500, this.config.sharedContextMaxInjectChars);\n const trimmed =\n combined.length > max ? combined.slice(0, max) + \"\\n\\n...(trimmed)\\n\" : combined;\n timings.sharedCtx = `${Date.now() - t0}ms`;\n return trimmed.trim().length > 0 ? trimmed : null;\n })();\n\n // 1. Profile\n const profilePromise = (async (): Promise<string | null> => {\n const t0 = Date.now();\n const profile = await profileStorage.readProfile();\n timings.profile = `${Date.now() - t0}ms`;\n return profile || null;\n })();\n\n // 1b. Knowledge Index (v7.0)\n const knowledgeIndexPromise = (async (): Promise<{ result: string; cached: boolean } | null> => {\n if (!this.config.knowledgeIndexEnabled) return null;\n const t0 = Date.now();\n try {\n const ki = await this.storage.buildKnowledgeIndex(this.config);\n timings.ki = `${Date.now() - t0}ms${ki.cached ? \" (cached)\" : \"\"}`;\n return ki.result ? ki : null;\n } catch (err) {\n timings.ki = `${Date.now() - t0}ms (err)`;\n log.warn(`Knowledge Index build failed: ${err}`);\n return null;\n }\n })();\n\n // 2. QMD search (the slow part — runs in parallel with preamble)\n type QmdPhaseResult = {\n memoryResultsLists: QmdSearchResult[][];\n globalResults: QmdSearchResult[];\n } | null;\n\n const qmdPromise = (async (): Promise<QmdPhaseResult> => {\n if (!this.config.qmdEnabled || !this.qmd.isAvailable()) {\n timings.qmd = \"skip\";\n log.debug(`QMD skip: qmdEnabled=${this.config.qmdEnabled} ${this.qmd.debugStatus()}`);\n return null;\n }\n const t0 = Date.now();\n\n // Hybrid search: parallel BM25 + vector, merged by path.\n // Much faster than `qmd query` (LLM expansion + reranking) which\n // takes 30-70s and causes recall timeouts.\n const memoryResults = await this.qmd.hybridSearch(\n prompt,\n undefined,\n this.config.qmdMaxResults,\n );\n\n timings.qmd = `${Date.now() - t0}ms`;\n return { memoryResultsLists: [memoryResults], globalResults: [] };\n })();\n\n // --- Wait for all parallel work ---\n const [sharedCtx, profile, kiResult, qmdResult] = await Promise.all([\n sharedContextPromise,\n profilePromise,\n knowledgeIndexPromise,\n qmdPromise,\n ]);\n\n // --- Phase 2: Assemble sections in correct order ---\n\n // 0. Shared context\n if (sharedCtx) sections.push(sharedCtx);\n\n // 1. Profile\n if (profile) sections.push(`## User Profile\\n\\n${profile}`);\n\n // 1b. Knowledge Index\n if (kiResult?.result) {\n sections.push(kiResult.result);\n log.debug(`Knowledge Index: ${kiResult.result.split(\"\\n\").length - 4} entities, ${kiResult.result.length} chars${kiResult.cached ? \" (cached)\" : \"\"}`);\n }\n\n // 2. QMD results — post-process and format\n if (qmdResult) {\n const t0 = Date.now();\n const { memoryResultsLists, globalResults } = qmdResult;\n\n // Merge/dedupe by path; keep the best score and first non-empty snippet.\n const mergedByPath = new Map<string, QmdSearchResult>();\n for (const list of memoryResultsLists) {\n for (const r of list) {\n const prev = mergedByPath.get(r.path);\n if (!prev) {\n mergedByPath.set(r.path, r);\n continue;\n }\n const better = r.score > prev.score ? r : prev;\n const snippet = prev.snippet || r.snippet;\n mergedByPath.set(r.path, { ...better, snippet });\n }\n }\n const memoryResultsRaw = Array.from(mergedByPath.values());\n\n let memoryResults = memoryResultsRaw;\n\n // Enforce namespace read policies by filtering paths.\n if (this.config.namespacesEnabled) {\n memoryResults = memoryResults.filter((r) =>\n recallNamespaces.includes(this.namespaceFromPath(r.path)),\n );\n }\n\n // Apply recency and access count boosting\n memoryResults = await this.boostSearchResults(memoryResults, recallNamespaces);\n\n // Optional LLM reranking (default off). Fail-open if rerank fails/slow.\n if (this.config.rerankEnabled && this.config.rerankProvider === \"local\") {\n const ranked = await rerankLocalOrNoop({\n query: prompt,\n candidates: memoryResults.slice(0, this.config.rerankMaxCandidates).map((r) => ({\n id: r.path,\n snippet: r.snippet || r.path,\n })),\n local: this.localLlm,\n enabled: true,\n timeoutMs: this.config.rerankTimeoutMs,\n maxCandidates: this.config.rerankMaxCandidates,\n cache: this.rerankCache,\n cacheEnabled: this.config.rerankCacheEnabled,\n cacheTtlMs: this.config.rerankCacheTtlMs,\n });\n if (ranked && ranked.length > 0) {\n const byPath = new Map(memoryResults.map((r) => [r.path, r]));\n const reordered: QmdSearchResult[] = [];\n for (const p of ranked) {\n const it = byPath.get(p);\n if (it) reordered.push(it);\n }\n // Append any unranked items in original order.\n const rankedSet = new Set(ranked);\n for (const r of memoryResults) {\n if (!rankedSet.has(r.path)) reordered.push(r);\n }\n memoryResults = reordered;\n }\n }\n if (this.config.rerankEnabled && this.config.rerankProvider === \"cloud\") {\n log.debug(\"rerankProvider=cloud is reserved/experimental in v2.2.0; skipping rerank\");\n }\n\n if (memoryResults.length > 0) {\n // Track access for these memories\n const memoryIds = this.extractMemoryIdsFromResults(memoryResults);\n this.trackMemoryAccess(memoryIds);\n\n // Record last recall snapshot + impression log for feedback loops.\n if (sessionKey) {\n const unique = Array.from(new Set(memoryIds)).slice(0, 40);\n this.lastRecall\n .record({ sessionKey, query: prompt, memoryIds: unique })\n .catch((err) => log.debug(`last recall record failed: ${err}`));\n }\n\n sections.push(this.formatQmdResults(\"Relevant Memories\", memoryResults));\n } else {\n const embeddingResults = await this.searchEmbeddingFallback(prompt, this.config.qmdMaxResults);\n const scoped = this.config.namespacesEnabled\n ? embeddingResults.filter((r) => recallNamespaces.includes(this.namespaceFromPath(r.path)))\n : embeddingResults;\n if (scoped.length > 0) {\n const memoryIds = this.extractMemoryIdsFromResults(scoped);\n this.trackMemoryAccess(memoryIds);\n if (sessionKey) {\n const unique = Array.from(new Set(memoryIds)).slice(0, 40);\n this.lastRecall\n .record({ sessionKey, query: prompt, memoryIds: unique })\n .catch((err) => log.debug(`last recall record failed: ${err}`));\n }\n sections.push(this.formatQmdResults(\"Relevant Memories\", scoped));\n }\n }\n\n if (globalResults.length > 0) {\n sections.push(\n this.formatQmdResults(\"Workspace Context\", globalResults),\n );\n }\n\n timings.qmdPost = `${Date.now() - t0}ms`;\n\n // If the user is pushing back (\"that's not right\", \"why did you say that\"),\n // gently suggest an explicit workflow to inspect what was recalled and record feedback.\n // IMPORTANT: this is suggestion-only; never auto-mark negatives.\n if (isDisagreementPrompt(prompt)) {\n sections.push(\n [\n \"## Retrieval Feedback Helper\",\n \"\",\n \"The user may be disputing an answer. To debug whether retrieval misled the response:\",\n \"- Use tool `memory_last_recall` to see which memory IDs were injected into context.\",\n \"- If negative examples are enabled, you can use `memory_feedback_last_recall` to mark specific recalled IDs as not useful.\",\n \"\",\n \"Safety: do not mass-mark negatives automatically; prefer explicit IDs.\",\n ].join(\"\\n\"),\n );\n }\n } else if (!this.config.qmdEnabled || !this.qmd.isAvailable()) {\n // Fallback: embeddings first, then recency-only.\n const embeddingResults = await this.searchEmbeddingFallback(prompt, this.config.qmdMaxResults);\n const scoped = this.config.namespacesEnabled\n ? embeddingResults.filter((r) => recallNamespaces.includes(this.namespaceFromPath(r.path)))\n : embeddingResults;\n if (scoped.length > 0) {\n const memoryIds = this.extractMemoryIdsFromResults(scoped);\n this.trackMemoryAccess(memoryIds);\n if (sessionKey) {\n const unique = Array.from(new Set(memoryIds)).slice(0, 40);\n this.lastRecall\n .record({ sessionKey, query: prompt, memoryIds: unique })\n .catch((err) => log.debug(`last recall record failed: ${err}`));\n }\n sections.push(this.formatQmdResults(\"Relevant Memories\", scoped));\n } else {\n const memories = await this.readAllMemoriesForNamespaces(recallNamespaces);\n if (memories.length > 0) {\n // Filter out non-active memories\n const activeMemories = memories.filter(\n (m) => !m.frontmatter.status || m.frontmatter.status === \"active\",\n );\n const recent = activeMemories\n .sort(\n (a, b) =>\n new Date(b.frontmatter.updated).getTime() -\n new Date(a.frontmatter.updated).getTime(),\n )\n .slice(0, 10);\n\n // Track access for these memories\n const memoryIds = recent.map((m) => m.frontmatter.id);\n this.trackMemoryAccess(memoryIds);\n\n if (sessionKey) {\n const unique = Array.from(new Set(memoryIds)).slice(0, 40);\n this.lastRecall\n .record({ sessionKey, query: prompt, memoryIds: unique })\n .catch((err) => log.debug(`last recall record failed: ${err}`));\n }\n\n const lines = recent.map(\n (m) => `- [${m.frontmatter.category}] ${m.content}`,\n );\n sections.push(`## Recent Memories\\n\\n${lines.join(\"\\n\")}`);\n }\n }\n\n if (isDisagreementPrompt(prompt)) {\n sections.push(\n [\n \"## Retrieval Feedback Helper\",\n \"\",\n \"The user may be disputing an answer. To debug whether retrieval misled the response:\",\n \"- Use tool `memory_last_recall` to see which memory IDs were injected into context.\",\n \"- If negative examples are enabled, you can use `memory_feedback_last_recall` to mark specific recalled IDs as not useful.\",\n \"\",\n \"Safety: do not mass-mark negatives automatically; prefer explicit IDs.\",\n ].join(\"\\n\"),\n );\n }\n }\n\n // 3. TRANSCRIPT INJECTION (NEW)\n const transcriptT0 = Date.now();\n log.debug(`recall: transcriptEnabled=${this.config.transcriptEnabled}, sessionKey=${sessionKey}`);\n if (this.config.transcriptEnabled) {\n // Try checkpoint first (post-compaction recovery)\n let checkpointInjected = false;\n if (this.config.checkpointEnabled) {\n const checkpoint = await this.transcript.loadCheckpoint(sessionKey);\n log.debug(`recall: checkpoint loaded, turns=${checkpoint?.turns?.length ?? 0}`);\n if (checkpoint && checkpoint.turns.length > 0) {\n const formatted = this.transcript.formatForRecall(\n checkpoint.turns,\n this.config.maxTranscriptTokens\n );\n if (formatted) {\n sections.push(`## Working Context (Recovered)\\n\\n${formatted}`);\n checkpointInjected = true;\n // Clear checkpoint after injection\n await this.transcript.clearCheckpoint();\n }\n }\n }\n\n // If no checkpoint, inject recent transcript\n if (!checkpointInjected) {\n const entries = await this.transcript.readRecent(\n this.config.transcriptRecallHours,\n sessionKey\n );\n log.debug(`recall: read ${entries.length} transcript entries for sessionKey=${sessionKey}`);\n\n // Apply max turns cap\n const cappedEntries = entries.slice(-this.config.maxTranscriptTurns);\n\n if (cappedEntries.length > 0) {\n log.debug(`recall: injecting ${cappedEntries.length} transcript entries`);\n const formatted = this.transcript.formatForRecall(\n cappedEntries,\n this.config.maxTranscriptTokens\n );\n if (formatted) {\n sections.push(formatted);\n }\n }\n }\n }\n\n timings.transcript = `${Date.now() - transcriptT0}ms`;\n\n // 4. HOURLY SUMMARIES INJECTION (NEW)\n const summariesT0 = Date.now();\n if (this.config.hourlySummariesEnabled && sessionKey) {\n const summaries = await this.summarizer.readRecent(\n sessionKey,\n this.config.summaryRecallHours\n );\n\n // Apply max count cap\n const cappedSummaries = summaries.slice(0, this.config.maxSummaryCount);\n\n if (cappedSummaries.length > 0) {\n const formatted = this.summarizer.formatForRecall(\n cappedSummaries,\n this.config.maxSummaryCount\n );\n sections.push(formatted);\n }\n }\n\n timings.summaries = `${Date.now() - summariesT0}ms`;\n\n // 4.5. Conversation semantic recall hook (optional, default off).\n // This searches over transcript chunk docs (ideally a separate QMD collection).\n const convT0 = Date.now();\n if (\n this.config.conversationIndexEnabled &&\n this.config.qmdEnabled &&\n this.conversationQmd &&\n this.conversationQmd.isAvailable()\n ) {\n const startedAtMs = Date.now();\n const timeoutMs = Math.max(200, this.config.conversationRecallTimeoutMs);\n const topK = Math.max(1, this.config.conversationRecallTopK);\n const maxChars = Math.max(400, this.config.conversationRecallMaxChars);\n\n const results = (await Promise.race([\n this.conversationQmd.search(prompt, undefined, topK),\n new Promise<[]>(resolve => setTimeout(() => resolve([]), timeoutMs)),\n ]).catch(() => [])) as Array<{ path: string; snippet: string; score: number }>;\n\n const durationMs = Date.now() - startedAtMs;\n if (durationMs >= timeoutMs) {\n log.debug(`conversation recall: timed out after ${timeoutMs}ms`);\n }\n\n if (Array.isArray(results) && results.length > 0) {\n const lines: string[] = [\"## Semantic Recall (Past Conversations)\", \"\"];\n let used = 0;\n for (const r of results) {\n if (!r?.snippet) continue;\n const chunk =\n `### ${r.path}\\n` +\n `Score: ${r.score.toFixed(3)}\\n\\n` +\n `${r.snippet.trim()}\\n`;\n if (used + chunk.length > maxChars) break;\n lines.push(chunk);\n used += chunk.length;\n }\n if (used > 0) {\n sections.push(lines.join(\"\\n\"));\n }\n }\n }\n\n timings.convRecall = `${Date.now() - convT0}ms`;\n\n // 4.75. Compounding injection (v5.0, optional)\n if (this.compounding && this.config.compoundingInjectEnabled) {\n const mistakes = await this.compounding.readMistakes();\n if (mistakes && Array.isArray(mistakes.patterns) && mistakes.patterns.length > 0) {\n const lines: string[] = [\n \"## Institutional Learning (Compounded)\",\n \"\",\n \"Avoid repeating these patterns:\",\n ...mistakes.patterns.slice(0, 40).map((p) => `- ${p}`),\n ];\n sections.push(lines.join(\"\\n\"));\n }\n }\n\n // 5. Inject most relevant question (if enabled) (existing)\n if (this.config.injectQuestions) {\n const questions = await profileStorage.readQuestions({ unresolvedOnly: true });\n if (questions.length > 0) {\n // Find the most relevant question to the current prompt\n // Simple approach: use the highest-priority unresolved question\n // TODO: Could use QMD search to find the most contextually relevant one\n const topQuestion = questions[0]; // Already sorted by priority desc\n sections.push(`## Open Question\\n\\nSomething I've been curious about: ${topQuestion.question}\\n\\n_Context: ${topQuestion.context}_`);\n }\n }\n\n // --- Timing summary ---\n timings.total = `${Date.now() - recallStart}ms`;\n const timingParts = Object.entries(timings).map(([k, v]) => `${k}=${v}`).join(\", \");\n log.debug(`recall: ${timingParts}`);\n\n if (sections.length === 0) return \"\";\n\n return sections.join(\"\\n\\n---\\n\\n\");\n }\n\n async processTurn(\n role: \"user\" | \"assistant\",\n content: string,\n sessionKey?: string,\n ): Promise<void> {\n if (role !== \"user\" && role !== \"assistant\") {\n log.debug(`processTurn: ignoring unsupported role=${String(role)}`);\n return;\n }\n\n const turn: BufferTurn = {\n role,\n content,\n timestamp: new Date().toISOString(),\n sessionKey,\n };\n\n const decision = await this.buffer.addTurn(turn);\n\n if (decision === \"keep_buffering\") return;\n\n // Queue extraction for background processing (agent_end returns immediately)\n // Capture the current buffer turns in a closure\n const turnsToExtract = this.buffer.getTurns();\n if (!this.shouldQueueExtraction(turnsToExtract)) {\n // We still clear buffered turns so the queue doesn't keep re-enqueueing duplicates.\n await this.buffer.clearAfterExtraction();\n return;\n }\n this.extractionQueue.push(async () => {\n await this.runExtraction(turnsToExtract);\n });\n\n // Start background processor if not already running\n if (!this.queueProcessing) {\n this.queueProcessing = true;\n this.processQueue().catch(err => {\n log.error(\"background extraction queue processor failed\", err);\n this.queueProcessing = false;\n });\n }\n }\n\n private shouldQueueExtraction(turns: BufferTurn[]): boolean {\n if (!this.config.extractionDedupeEnabled) return true;\n if (!Array.isArray(turns) || turns.length === 0) return false;\n\n // Fingerprint only user/assistant text; tool/system noise should not produce unique runs.\n const normalized = turns\n .filter((t) => t.role === \"user\" || t.role === \"assistant\")\n .map((t) => `${t.role}:${(t.content ?? \"\").trim().slice(0, this.config.extractionMaxTurnChars)}`)\n .join(\"\\n\");\n if (!normalized) return false;\n\n const fingerprint = createHash(\"sha256\").update(normalized).digest(\"hex\");\n const now = Date.now();\n const seenAt = this.recentExtractionFingerprints.get(fingerprint);\n if (seenAt && now - seenAt < this.config.extractionDedupeWindowMs) {\n log.debug(\"extraction dedupe: skipped duplicate buffered turn set\");\n return false;\n }\n\n this.recentExtractionFingerprints.set(fingerprint, now);\n // Keep this cache bounded to avoid unbounded growth.\n if (this.recentExtractionFingerprints.size > 200) {\n const entries = Array.from(this.recentExtractionFingerprints.entries()).sort(\n (a, b) => a[1] - b[1],\n );\n for (const [key] of entries.slice(0, entries.length - 200)) {\n this.recentExtractionFingerprints.delete(key);\n }\n }\n\n return true;\n }\n\n /**\n * Background serial queue processor.\n * Processes extractions one at a time to avoid race conditions.\n * Called automatically when items are queued.\n */\n private async processQueue(): Promise<void> {\n while (this.extractionQueue.length > 0) {\n const task = this.extractionQueue.shift();\n if (task) {\n try {\n await task();\n } catch (err) {\n log.error(\"background extraction task failed\", err);\n }\n }\n }\n\n this.queueProcessing = false;\n }\n\n private async runExtraction(turns: BufferTurn[]): Promise<void> {\n log.debug(`running extraction on ${turns.length} turns`);\n\n // Skip extraction for cron job sessions - these are system operations, not user conversations\n const sessionKey = turns[0]?.sessionKey ?? \"\";\n if (sessionKey.includes(\":cron:\")) {\n log.debug(`skipping extraction for cron session: ${sessionKey}`);\n await this.buffer.clearAfterExtraction();\n return;\n }\n\n const normalizedTurns = turns\n .filter((t) => (t.role === \"user\" || t.role === \"assistant\") && typeof t.content === \"string\")\n .map((t) => ({\n ...t,\n content: t.content.trim().slice(0, this.config.extractionMaxTurnChars),\n }))\n .filter((t) => t.content.length > 0);\n\n const userTurns = normalizedTurns.filter((t) => t.role === \"user\");\n const totalChars = normalizedTurns.reduce((sum, t) => sum + t.content.length, 0);\n if (\n totalChars < this.config.extractionMinChars ||\n userTurns.length < this.config.extractionMinUserTurns\n ) {\n log.debug(\n `skipping extraction: below threshold (totalChars=${totalChars}, userTurns=${userTurns.length})`,\n );\n await this.buffer.clearAfterExtraction();\n return;\n }\n\n const principal = resolvePrincipal(sessionKey, this.config);\n const selfNamespace = defaultNamespaceForPrincipal(principal, this.config);\n const storage = await this.storageRouter.storageFor(selfNamespace);\n\n // Pass existing entity names so the LLM can reuse them instead of inventing variants\n const existingEntities = await storage.listEntityNames();\n const result = await this.extraction.extract(normalizedTurns, existingEntities);\n\n // Defensive: validate extraction result before processing\n if (!result) {\n log.warn(\"runExtraction: extraction returned null/undefined\");\n await this.buffer.clearAfterExtraction();\n return;\n }\n if (!Array.isArray(result.facts)) {\n log.warn(\"runExtraction: extraction returned invalid facts (not an array)\", { factsType: typeof result.facts, resultKeys: Object.keys(result) });\n await this.buffer.clearAfterExtraction();\n return;\n }\n if (\n result.facts.length === 0 &&\n result.entities.length === 0 &&\n result.questions.length === 0 &&\n result.profileUpdates.length === 0\n ) {\n log.debug(\"runExtraction: extraction produced no durable outputs; skipping persistence\");\n await this.buffer.clearAfterExtraction();\n return;\n }\n\n const persistedIds = await this.persistExtraction(result, storage);\n await this.buffer.clearAfterExtraction();\n\n // Process threading if enabled (Phase 3B)\n if (this.config.threadingEnabled && turns.length > 0) {\n const lastTurn = turns[turns.length - 1];\n const threadId = await this.threading.processTurn(lastTurn, persistedIds);\n\n // Update thread title with conversation content\n const conversationContent = turns.map((t) => t.content).join(\" \");\n await this.threading.updateThreadTitle(threadId, conversationContent);\n }\n\n // Check if consolidation is needed (debounced + non-zero gated).\n const nonZeroExtraction =\n result.facts.length > 0 ||\n result.entities.length > 0 ||\n result.questions.length > 0 ||\n result.profileUpdates.length > 0;\n if (nonZeroExtraction) this.nonZeroExtractionsSinceConsolidation += 1;\n this.maybeScheduleConsolidation(nonZeroExtraction);\n\n // Update meta (safely handle potentially invalid result)\n const meta = await storage.loadMeta();\n meta.extractionCount += 1;\n meta.lastExtractionAt = new Date().toISOString();\n meta.totalMemories += Array.isArray(result?.facts) ? result.facts.length : 0;\n meta.totalEntities += Array.isArray(result?.entities) ? result.entities.length : 0;\n await storage.saveMeta(meta);\n\n this.requestQmdMaintenance();\n }\n\n private maybeScheduleConsolidation(nonZeroExtraction: boolean): void {\n if (this.config.consolidationRequireNonZeroExtraction && !nonZeroExtraction) return;\n if (this.nonZeroExtractionsSinceConsolidation < this.config.consolidateEveryN) return;\n\n const now = Date.now();\n if (now - this.lastConsolidationRunAtMs < this.config.consolidationMinIntervalMs) return;\n if (this.consolidationInFlight) return;\n\n this.consolidationInFlight = true;\n this.lastConsolidationRunAtMs = now;\n this.nonZeroExtractionsSinceConsolidation = 0;\n this.runConsolidation()\n .catch((err) => log.error(\"background consolidation failed\", err))\n .finally(() => {\n this.consolidationInFlight = false;\n });\n }\n\n private requestQmdMaintenance(): void {\n if (!this.config.qmdEnabled || !this.qmd.isAvailable()) return;\n if (!this.config.qmdMaintenanceEnabled) return;\n\n this.qmdMaintenancePending = true;\n if (this.qmdMaintenanceTimer) return;\n\n this.qmdMaintenanceTimer = setTimeout(() => {\n this.qmdMaintenanceTimer = null;\n this.runQmdMaintenance().catch((err) =>\n log.debug(`background qmd maintenance failed: ${err}`),\n );\n }, this.config.qmdMaintenanceDebounceMs);\n }\n\n /**\n * Public entrypoint for tool-driven QMD maintenance requests.\n * Routes through existing debounced/singleflight maintenance controls.\n */\n requestQmdMaintenanceForTool(reason: string): void {\n try {\n this.requestQmdMaintenance();\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n log.warn(`qmd maintenance request failed (${reason}): ${msg}`);\n }\n }\n\n private async runQmdMaintenance(): Promise<void> {\n if (this.qmdMaintenanceInFlight) return;\n if (!this.qmdMaintenancePending) return;\n this.qmdMaintenanceInFlight = true;\n this.qmdMaintenancePending = false;\n\n try {\n await this.qmd.update();\n const now = Date.now();\n if (\n this.config.qmdAutoEmbedEnabled &&\n now - this.lastQmdEmbedAtMs >= this.config.qmdEmbedMinIntervalMs\n ) {\n await this.qmd.embed();\n this.lastQmdEmbedAtMs = now;\n }\n } finally {\n this.qmdMaintenanceInFlight = false;\n if (this.qmdMaintenancePending) {\n this.requestQmdMaintenance();\n }\n }\n }\n\n private async persistExtraction(result: ExtractionResult, storage: StorageManager): Promise<string[]> {\n const persistedIds: string[] = [];\n let dedupedCount = 0;\n\n // Defensive: validate result and facts array\n if (!result || !Array.isArray(result.facts)) {\n log.warn(\"persistExtraction: result or result.facts is invalid, skipping\", { resultType: typeof result, factsType: typeof result?.facts });\n return persistedIds;\n }\n\n // Chunking config from plugin settings\n const chunkingConfig: ChunkingConfig = {\n targetTokens: this.config.chunkingTargetTokens,\n minTokens: this.config.chunkingMinTokens,\n overlapSentences: this.config.chunkingOverlapSentences,\n };\n\n const rawEntities = Array.isArray((result as any).entities) ? (result as any).entities : [];\n const rawQuestions = Array.isArray((result as any).questions) ? (result as any).questions : [];\n const rawProfileUpdates = Array.isArray((result as any).profileUpdates)\n ? (result as any).profileUpdates\n : [];\n\n const facts = result.facts.slice(0, this.config.extractionMaxFactsPerRun);\n const entities = rawEntities.slice(0, this.config.extractionMaxEntitiesPerRun);\n const questions = rawQuestions.slice(0, this.config.extractionMaxQuestionsPerRun);\n const profileUpdates = rawProfileUpdates.slice(\n 0,\n this.config.extractionMaxProfileUpdatesPerRun,\n );\n\n if (\n facts.length < result.facts.length ||\n entities.length < result.entities.length ||\n questions.length < result.questions.length ||\n profileUpdates.length < result.profileUpdates.length\n ) {\n log.warn(\n \"persistExtraction: capped extraction payload to guardrails \" +\n `(facts ${facts.length}/${result.facts.length}, entities ${entities.length}/${result.entities.length}, ` +\n `questions ${questions.length}/${result.questions.length}, profile ${profileUpdates.length}/${result.profileUpdates.length})`,\n );\n }\n\n for (const fact of facts) {\n if (!fact || typeof (fact as any).content !== \"string\" || !(fact as any).content.trim()) {\n continue;\n }\n if (typeof (fact as any).category !== \"string\" || !(fact as any).category.trim()) {\n continue;\n }\n (fact as any).tags = Array.isArray((fact as any).tags)\n ? (fact as any).tags.filter((t: any) => typeof t === \"string\")\n : [];\n (fact as any).confidence =\n typeof (fact as any).confidence === \"number\" ? (fact as any).confidence : 0.7;\n\n // Content-hash dedup check (v6.0)\n if (this.contentHashIndex && this.contentHashIndex.has(fact.content)) {\n log.debug(`dedup: skipping duplicate fact \"${fact.content.slice(0, 60)}…\"`);\n dedupedCount++;\n continue;\n }\n\n // Score importance using local heuristics (Phase 1B)\n const importance = scoreImportance(fact.content, fact.category, fact.tags);\n\n // Check if chunking is enabled and content should be chunked\n if (this.config.chunkingEnabled) {\n const chunkResult = chunkContent(fact.content, chunkingConfig);\n\n if (chunkResult.chunked && chunkResult.chunks.length > 1) {\n // Write the parent memory first (with full content for reference)\n const parentId = await storage.writeMemory(fact.category, fact.content, {\n confidence: fact.confidence,\n tags: [...fact.tags, \"chunked\"],\n entityRef: fact.entityRef,\n source: \"extraction\",\n importance,\n });\n\n // Write individual chunks with parent reference\n for (const chunk of chunkResult.chunks) {\n // Score each chunk's importance separately\n const chunkImportance = scoreImportance(chunk.content, fact.category, fact.tags);\n\n await storage.writeChunk(\n parentId,\n chunk.index,\n chunkResult.chunks.length,\n fact.category,\n chunk.content,\n {\n confidence: fact.confidence,\n tags: fact.tags,\n entityRef: fact.entityRef,\n source: \"chunking\",\n importance: chunkImportance,\n },\n );\n }\n\n log.debug(`chunked memory ${parentId} into ${chunkResult.chunks.length} chunks`);\n persistedIds.push(parentId);\n await this.indexPersistedMemory(storage, parentId);\n // Register chunked content in hash index too\n if (this.contentHashIndex) {\n this.contentHashIndex.add(fact.content);\n }\n\n for (const chunk of chunkResult.chunks) {\n await this.indexPersistedMemory(storage, `${parentId}-chunk-${chunk.index}`);\n }\n continue; // Skip the normal write below\n }\n }\n\n // Check for contradictions before writing (Phase 2B)\n let supersedes: string | undefined;\n let links: MemoryLink[] = [];\n\n if (this.config.contradictionDetectionEnabled && this.qmd.isAvailable()) {\n const contradiction = await this.checkForContradiction(fact.content, fact.category);\n if (contradiction) {\n supersedes = contradiction.supersededId;\n links.push({\n targetId: contradiction.supersededId,\n linkType: \"contradicts\",\n strength: contradiction.confidence,\n reason: contradiction.reason,\n });\n }\n }\n\n // Suggest links for this memory (Phase 3A)\n if (this.config.memoryLinkingEnabled && this.qmd.isAvailable()) {\n const suggestedLinks = await this.suggestLinksForMemory(fact.content, fact.category);\n if (suggestedLinks.length > 0) {\n links.push(...suggestedLinks);\n }\n }\n\n // Normal write (no chunking)\n const memoryId = await storage.writeMemory(fact.category, fact.content, {\n confidence: fact.confidence,\n tags: fact.tags,\n entityRef: typeof (fact as any).entityRef === \"string\" ? (fact as any).entityRef : undefined,\n source: \"extraction\",\n importance,\n supersedes,\n links: links.length > 0 ? links : undefined,\n });\n persistedIds.push(memoryId);\n await this.indexPersistedMemory(storage, memoryId);\n // Register in content-hash index after successful write\n if (this.contentHashIndex) {\n this.contentHashIndex.add(fact.content);\n }\n }\n\n for (const entity of entities) {\n try {\n const name = (entity as any)?.name;\n const type = (entity as any)?.type;\n if (typeof name !== \"string\" || !name.trim() || typeof type !== \"string\" || !type.trim()) {\n continue;\n }\n const safeFacts = Array.isArray((entity as any)?.facts)\n ? (entity as any).facts.filter((f: any) => typeof f === \"string\")\n : [];\n const id = await storage.writeEntity(name, type, safeFacts);\n if (id) persistedIds.push(id);\n } catch (err) {\n log.warn(`persistExtraction: entity write failed: ${err}`);\n }\n }\n\n // Persist entity relationships (v7.0)\n if (this.config.entityRelationshipsEnabled && Array.isArray(result.relationships)) {\n for (const rel of result.relationships.slice(0, 5)) {\n if (!rel.source || !rel.target || !rel.label) continue;\n try {\n // Add bidirectional relationship\n await storage.addEntityRelationship(rel.source, { target: rel.target, label: rel.label });\n await storage.addEntityRelationship(rel.target, { target: rel.source, label: `${rel.label} (reverse)` });\n } catch (err) {\n log.debug(`relationship persist failed: ${err}`);\n }\n }\n }\n\n // Persist entity activity (v7.0)\n if (this.config.entityActivityLogEnabled) {\n const today = new Date().toISOString().slice(0, 10);\n for (const entity of entities) {\n const name = (entity as any)?.name;\n const type = (entity as any)?.type;\n if (typeof name !== \"string\" || typeof type !== \"string\") continue;\n try {\n const normalized = normalizeEntityName(name, type);\n await storage.addEntityActivity(\n normalized,\n { date: today, note: \"Mentioned in conversation\" },\n this.config.entityActivityLogMaxEntries,\n );\n } catch (err) {\n log.debug(`activity persist failed: ${err}`);\n }\n }\n }\n\n if (profileUpdates.length > 0) {\n await storage.appendToProfile(profileUpdates);\n }\n\n // Persist questions\n for (const q of questions) {\n await storage.writeQuestion(q.question, q.context, q.priority);\n }\n\n // Persist identity reflection\n if (this.config.identityEnabled && result.identityReflection) {\n try {\n await storage.appendToIdentity(this.config.workspaceDir, result.identityReflection);\n } catch (err) {\n log.debug(`identity reflection write failed: ${err}`);\n }\n }\n\n // Save content-hash index after batch\n if (this.contentHashIndex) {\n await this.contentHashIndex.save().catch((err) =>\n log.warn(`content-hash index save failed: ${err}`),\n );\n }\n\n const dedupSuffix = dedupedCount > 0 ? ` (${dedupedCount} deduped)` : \"\";\n log.info(\n `persisted: ${facts.length - dedupedCount} facts${dedupSuffix}, ${entities.length} entities, ${questions.length} questions, ${profileUpdates.length} profile updates`,\n );\n\n // Return the persisted fact IDs for threading\n return persistedIds;\n }\n\n private async indexPersistedMemory(storage: StorageManager, memoryId: string): Promise<void> {\n if (!this.config.embeddingFallbackEnabled) return;\n if (!(await this.embeddingFallback.isAvailable())) return;\n const memory = await storage.getMemoryById(memoryId);\n if (!memory) return;\n await this.embeddingFallback.indexFile(memoryId, memory.content, memory.path);\n }\n\n /** IDs of facts persisted in the last extraction */\n private lastPersistedIds: string[] = [];\n\n private async runConsolidation(): Promise<{ memoriesProcessed: number; merged: number; invalidated: number }> {\n log.info(\"running consolidation pass\");\n let merged = 0;\n let invalidated = 0;\n\n // Flush access tracking buffer first\n if (this.accessTrackingBuffer.size > 0) {\n await this.flushAccessTracking();\n }\n\n const allMemories = await this.storage.readAllMemories();\n if (allMemories.length < 5) {\n return { memoriesProcessed: allMemories.length, merged, invalidated };\n }\n\n const recent = allMemories\n .sort(\n (a, b) =>\n new Date(b.frontmatter.created).getTime() -\n new Date(a.frontmatter.created).getTime(),\n )\n .slice(0, 20);\n\n const older = allMemories\n .sort(\n (a, b) =>\n new Date(a.frontmatter.created).getTime() -\n new Date(b.frontmatter.created).getTime(),\n );\n\n const profile = await this.storage.readProfile();\n const result = await this.extraction.consolidate(recent, older, profile);\n\n for (const item of result.items) {\n switch (item.action) {\n case \"INVALIDATE\":\n if (await this.storage.invalidateMemory(item.existingId)) {\n invalidated += 1;\n await this.embeddingFallback.removeFromIndex(item.existingId);\n }\n break;\n case \"UPDATE\":\n if (item.updatedContent) {\n await this.storage.updateMemory(item.existingId, item.updatedContent, {\n lineage: [item.existingId],\n });\n await this.indexPersistedMemory(this.storage, item.existingId);\n }\n break;\n case \"MERGE\":\n if (item.updatedContent && item.mergeWith) {\n await this.storage.updateMemory(item.existingId, item.updatedContent, {\n supersedes: item.mergeWith,\n lineage: [item.existingId, item.mergeWith],\n });\n await this.indexPersistedMemory(this.storage, item.existingId);\n if (await this.storage.invalidateMemory(item.mergeWith)) {\n invalidated += 1;\n merged += 1;\n await this.embeddingFallback.removeFromIndex(item.mergeWith);\n }\n }\n break;\n }\n }\n\n if (result.profileUpdates.length > 0) {\n await this.storage.appendToProfile(result.profileUpdates);\n }\n\n for (const entity of result.entityUpdates) {\n const safeFacts = Array.isArray((entity as any)?.facts)\n ? (entity as any).facts.filter((f: any) => typeof f === \"string\")\n : [];\n await this.storage.writeEntity(entity.name, entity.type, safeFacts);\n }\n\n // Merge fragmented entity files\n const entitiesMerged = await this.storage.mergeFragmentedEntities();\n if (entitiesMerged > 0) {\n log.info(`merged ${entitiesMerged} fragmented entity files`);\n }\n\n // Generate entity summaries (v7.0)\n if (this.config.entitySummaryEnabled) {\n try {\n const entityFiles = await this.storage.readAllEntityFiles();\n const needsSummary = entityFiles.filter(\n (e) => e.facts.length > 5 && !e.summary,\n );\n const toSummarize = needsSummary.slice(0, 5);\n let summarized = 0;\n for (const entity of toSummarize) {\n try {\n const factsText = entity.facts.slice(0, 10).join(\"; \");\n const prompt = `Summarize this entity in one sentence. Entity: ${entity.name} (${entity.type}). Facts: ${factsText}`;\n const response = await this.localLlm.chatCompletion(\n [\n { role: \"system\", content: \"Respond with a single concise sentence summarizing the entity. No JSON, just plain text.\" },\n { role: \"user\", content: prompt },\n ],\n { temperature: 0.3, maxTokens: 100, operation: \"entity_summary\" },\n );\n if (response?.content) {\n const summary = response.content.trim().replace(/^[\"']|[\"']$/g, \"\");\n if (summary.length > 10 && summary.length < 500) {\n const entityFileName = normalizeEntityName(entity.name, entity.type);\n await this.storage.updateEntitySummary(entityFileName, summary);\n summarized++;\n }\n }\n } catch (err) {\n log.debug(`entity summary generation failed for ${entity.name}: ${err}`);\n }\n }\n if (summarized > 0) {\n log.info(`generated ${summarized} entity summaries`);\n }\n } catch (err) {\n log.debug(`entity summary pass failed: ${err}`);\n }\n }\n\n // Clean expired commitments\n const cleaned = await this.storage.cleanExpiredCommitments(this.config.commitmentDecayDays);\n if (cleaned > 0) {\n log.info(`cleaned ${cleaned} expired commitments`);\n }\n\n // Clean memories past their TTL (speculative memories auto-expire)\n const ttlCleaned = await this.storage.cleanExpiredTTL();\n if (ttlCleaned > 0) {\n log.info(`cleaned ${ttlCleaned} TTL-expired memories`);\n }\n\n // Fact archival pass (v6.0) — move old, low-importance, rarely-accessed facts to archive/\n if (this.config.factArchivalEnabled) {\n const archived = await this.runFactArchival(allMemories);\n if (archived > 0) {\n log.info(`archived ${archived} old low-importance facts`);\n }\n }\n\n // Auto-consolidate IDENTITY.md if it's getting large\n if (this.config.identityEnabled) {\n await this.autoConsolidateIdentity();\n }\n\n // Auto-consolidate profile.md if it exceeds max lines\n if (await this.storage.profileNeedsConsolidation()) {\n log.info(\"profile.md exceeds max lines — running smart consolidation\");\n const currentProfile = await this.storage.readProfile();\n if (currentProfile) {\n const profileResult = await this.extraction.consolidateProfile(currentProfile);\n if (profileResult) {\n await this.storage.writeProfile(profileResult.consolidatedProfile);\n log.info(`profile.md consolidated: removed ${profileResult.removedCount} items — ${profileResult.summary}`);\n }\n }\n }\n\n // Memory Summarization (Phase 4A)\n if (this.config.summarizationEnabled) {\n await this.runSummarization(allMemories);\n }\n\n // Topic Extraction (Phase 4B)\n if (this.config.topicExtractionEnabled) {\n await this.runTopicExtraction(allMemories);\n }\n\n const meta = await this.storage.loadMeta();\n meta.lastConsolidationAt = new Date().toISOString();\n await this.storage.saveMeta(meta);\n\n log.info(\"consolidation complete\");\n return { memoriesProcessed: allMemories.length, merged, invalidated };\n }\n\n /**\n * Archive old, low-importance, rarely-accessed facts (v6.0).\n * Moves eligible facts from facts/ to archive/YYYY-MM-DD/.\n * Returns the number of archived facts.\n */\n private async runFactArchival(allMemories: import(\"./types.js\").MemoryFile[]): Promise<number> {\n const now = Date.now();\n const ageCutoffMs = this.config.factArchivalAgeDays * 24 * 60 * 60 * 1000;\n const protectedCategories = new Set(this.config.factArchivalProtectedCategories);\n let archivedCount = 0;\n\n for (const memory of allMemories) {\n const fm = memory.frontmatter;\n\n // Skip already-archived or superseded\n if (fm.status && fm.status !== \"active\") continue;\n\n // Skip protected categories\n if (protectedCategories.has(fm.category)) continue;\n\n // Skip corrections (always keep)\n if (fm.category === \"correction\") continue;\n\n // Check age requirement\n const createdMs = new Date(fm.created).getTime();\n if (now - createdMs < ageCutoffMs) continue;\n\n // Check importance (only archive low-importance facts)\n const importanceScore = fm.importance?.score ?? 0.5;\n if (importanceScore >= this.config.factArchivalMaxImportance) continue;\n\n // Check access count\n const accessCount = fm.accessCount ?? 0;\n if (accessCount > this.config.factArchivalMaxAccessCount) continue;\n\n // All criteria met — archive\n const result = await this.storage.archiveMemory(memory);\n if (result) {\n // Remove from content-hash index since it's no longer in hot search\n if (this.contentHashIndex) {\n this.contentHashIndex.remove(memory.content);\n }\n await this.embeddingFallback.removeFromIndex(memory.frontmatter.id);\n archivedCount++;\n }\n }\n\n // Save hash index if we removed any entries\n if (archivedCount > 0 && this.contentHashIndex) {\n await this.contentHashIndex.save().catch((err) =>\n log.warn(`content-hash index save failed during archival: ${err}`),\n );\n }\n\n return archivedCount;\n }\n\n /**\n * Run memory summarization if memory count exceeds threshold (Phase 4A).\n */\n private async runSummarization(allMemories: import(\"./types.js\").MemoryFile[]): Promise<void> {\n // Only active memories count toward the threshold\n const activeMemories = allMemories.filter(\n (m) => !m.frontmatter.status || m.frontmatter.status === \"active\",\n );\n\n if (activeMemories.length < this.config.summarizationTriggerCount) {\n return;\n }\n\n log.info(`memory count (${activeMemories.length}) exceeds threshold (${this.config.summarizationTriggerCount}) — running summarization`);\n\n // Sort by creation date, oldest first\n const sorted = activeMemories.sort(\n (a, b) =>\n new Date(a.frontmatter.created).getTime() -\n new Date(b.frontmatter.created).getTime(),\n );\n\n // Keep recent memories\n const toKeep = sorted.slice(-this.config.summarizationRecentToKeep);\n const toSummarize = sorted.slice(0, -this.config.summarizationRecentToKeep);\n\n // Filter candidates for summarization\n const candidates = toSummarize.filter((m) => {\n // Skip if protected by entity reference\n if (m.frontmatter.entityRef) return false;\n\n // Skip if protected by tag\n const protectedTags = this.config.summarizationProtectedTags;\n if (m.frontmatter.tags.some((t) => protectedTags.includes(t))) return false;\n\n // Skip if importance is above threshold\n const importance = m.frontmatter.importance?.score ?? 0.5;\n if (importance >= this.config.summarizationImportanceThreshold) return false;\n\n return true;\n });\n\n if (candidates.length < 50) {\n log.debug(`only ${candidates.length} candidates for summarization — skipping`);\n return;\n }\n\n // Summarize in batches of 50\n const batchSize = 50;\n for (let i = 0; i < candidates.length; i += batchSize) {\n const batch = candidates.slice(i, i + batchSize);\n const batchData = batch.map((m) => ({\n id: m.frontmatter.id,\n content: m.content,\n category: m.frontmatter.category,\n created: m.frontmatter.created,\n }));\n\n const result = await this.extraction.summarizeMemories(batchData);\n if (!result) continue;\n\n // Create summary\n const summary: MemorySummary = {\n id: `summary-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,\n createdAt: new Date().toISOString(),\n timeRangeStart: batch[0].frontmatter.created,\n timeRangeEnd: batch[batch.length - 1].frontmatter.created,\n summaryText: result.summaryText,\n keyFacts: result.keyFacts,\n keyEntities: result.keyEntities,\n sourceEpisodeIds: batch.map((m) => m.frontmatter.id),\n };\n\n await this.storage.writeSummary(summary);\n\n // Archive source memories\n const archived = await this.storage.archiveMemories(\n batch.map((m) => m.frontmatter.id),\n summary.id,\n );\n\n log.info(`created summary ${summary.id} from ${batch.length} memories, archived ${archived}`);\n }\n }\n\n /**\n * Run topic extraction on all memories (Phase 4B).\n */\n private async runTopicExtraction(allMemories: import(\"./types.js\").MemoryFile[]): Promise<void> {\n // Only extract from active memories\n const activeMemories = allMemories.filter(\n (m) => !m.frontmatter.status || m.frontmatter.status === \"active\",\n );\n\n if (activeMemories.length === 0) return;\n\n const topics = extractTopics(activeMemories, this.config.topicExtractionTopN);\n await this.storage.saveTopics(topics);\n\n log.debug(`extracted ${topics.length} topics from ${activeMemories.length} memories`);\n }\n\n /** Threshold (bytes) at which IDENTITY.md reflections get auto-consolidated */\n private static readonly IDENTITY_CONSOLIDATE_THRESHOLD = 8_000;\n\n private async autoConsolidateIdentity(): Promise<void> {\n const identityContent = await this.storage.readIdentity(this.config.workspaceDir);\n if (identityContent.length < Orchestrator.IDENTITY_CONSOLIDATE_THRESHOLD) return;\n\n log.info(`IDENTITY.md is ${identityContent.length} chars — auto-consolidating reflections`);\n\n // Find the static header (everything before reflections)\n const reflectionIdx = identityContent.indexOf(\"## Learned Patterns\");\n const headerEnd = reflectionIdx !== -1 ? reflectionIdx : identityContent.indexOf(\"## Reflection\");\n if (headerEnd === -1) {\n log.debug(\"no reflections found in IDENTITY.md, skipping consolidation\");\n return;\n }\n\n const staticHeader = identityContent.slice(0, headerEnd).trimEnd();\n\n const result = await this.extraction.consolidateIdentity(\n identityContent,\n \"## Reflection\",\n );\n\n if (!result || result.learnedPatterns.length === 0) {\n log.warn(\"identity consolidation produced no patterns\");\n return;\n }\n\n // Rebuild IDENTITY.md: static header + consolidated patterns\n const patternsSection = [\n \"## Learned Patterns (consolidated from reflections, \" + new Date().toISOString().slice(0, 10) + \")\",\n \"\",\n ...result.learnedPatterns.map((p) => `- ${p}`),\n \"\",\n ].join(\"\\n\");\n\n const newContent = staticHeader + \"\\n\\n\" + patternsSection + \"\\n\";\n\n await this.storage.writeIdentity(this.config.workspaceDir, newContent);\n log.info(`IDENTITY.md consolidated: ${identityContent.length} → ${newContent.length} chars, ${result.learnedPatterns.length} patterns`);\n }\n\n private formatQmdResults(\n title: string,\n results: QmdSearchResult[],\n ): string {\n const lines = results.map((r, i) => {\n const snippet = r.snippet\n ? r.snippet.slice(0, 500).replace(/\\n/g, \" \")\n : \"(no preview)\";\n return `[${i + 1}] ${r.path} (score: ${r.score.toFixed(3)})\\n${snippet}`;\n });\n return `## ${title}\\n\\n${lines.join(\"\\n\\n\")}`;\n }\n\n private async searchEmbeddingFallback(query: string, limit: number): Promise<QmdSearchResult[]> {\n if (!this.config.embeddingFallbackEnabled) return [];\n if (!(await this.embeddingFallback.isAvailable())) return [];\n const hits = await this.embeddingFallback.search(query, limit);\n if (hits.length === 0) return [];\n\n const results: QmdSearchResult[] = [];\n for (const hit of hits) {\n const fullPath = path.isAbsolute(hit.path) ? hit.path : path.join(this.config.memoryDir, hit.path);\n const memory = await this.storage.readMemoryByPath(fullPath);\n if (!memory) continue;\n results.push({\n docid: hit.id,\n path: fullPath,\n score: hit.score,\n snippet: memory.content.slice(0, 400).replace(/\\n/g, \" \"),\n });\n }\n return results;\n }\n\n // ---------------------------------------------------------------------------\n // Access Tracking (Phase 1A)\n // ---------------------------------------------------------------------------\n\n /**\n * Record that memories were accessed (retrieved).\n * Updates are batched in memory and flushed during consolidation.\n */\n trackMemoryAccess(memoryIds: string[]): void {\n if (!this.config.accessTrackingEnabled) return;\n\n const now = new Date().toISOString();\n for (const id of memoryIds) {\n const existing = this.accessTrackingBuffer.get(id);\n this.accessTrackingBuffer.set(id, {\n count: (existing?.count ?? 0) + 1,\n lastAccessed: now,\n });\n }\n\n // Flush if buffer exceeds max size\n if (this.accessTrackingBuffer.size >= this.config.accessTrackingBufferMaxSize) {\n this.flushAccessTracking().catch((err) =>\n log.debug(`background access tracking flush failed: ${err}`),\n );\n }\n }\n\n /**\n * Flush access tracking buffer to disk.\n * Called during consolidation or when buffer is full.\n */\n async flushAccessTracking(): Promise<void> {\n if (this.accessTrackingBuffer.size === 0) return;\n\n // Build entries from buffer, merging with existing counts\n const entries: AccessTrackingEntry[] = [];\n const namespaces = this.config.namespacesEnabled\n ? Array.from(\n new Set<string>([\n this.config.defaultNamespace,\n this.config.sharedNamespace,\n ...this.config.namespacePolicies.map((p) => p.name),\n ]),\n )\n : [this.config.defaultNamespace];\n const memories = await this.readAllMemoriesForNamespaces(namespaces);\n const memoryMap = new Map(memories.map((m) => [m.frontmatter.id, m]));\n\n for (const [memoryId, update] of this.accessTrackingBuffer) {\n const memory = memoryMap.get(memoryId);\n const existingCount = memory?.frontmatter.accessCount ?? 0;\n entries.push({\n memoryId,\n newCount: existingCount + update.count,\n lastAccessed: update.lastAccessed,\n });\n }\n\n const byNamespace = new Map<string, AccessTrackingEntry[]>();\n for (const e of entries) {\n const m = memoryMap.get(e.memoryId);\n if (!m) continue;\n const ns = this.namespaceFromPath(m.path);\n const list = byNamespace.get(ns) ?? [];\n list.push(e);\n byNamespace.set(ns, list);\n }\n for (const [ns, list] of byNamespace) {\n const sm = await this.storageRouter.storageFor(ns);\n await sm.flushAccessTracking(list);\n }\n this.accessTrackingBuffer.clear();\n log.debug(`flushed ${entries.length} access tracking entries`);\n }\n\n /**\n * Apply recency, access count, and importance boosting to QMD search results.\n * Returns re-ranked results.\n */\n private async boostSearchResults(\n results: QmdSearchResult[],\n _recallNamespaces: string[],\n ): Promise<QmdSearchResult[]> {\n if (results.length === 0) return results;\n\n const now = Date.now();\n // Only read memory files referenced in QMD results (not all 15,000+).\n const memoryByPath = new Map<string, MemoryFile>();\n await Promise.all(\n results.map(async (r) => {\n if (!r.path || memoryByPath.has(r.path)) return;\n const mem = await this.storage.readMemoryByPath(r.path);\n if (mem) memoryByPath.set(r.path, mem);\n }),\n );\n\n // Calculate boosted scores\n const boosted = results.map((r) => {\n const memory = memoryByPath.get(r.path);\n let score = r.score;\n\n if (memory) {\n // Recency boost: exponential decay over 7 days\n if (this.config.recencyWeight > 0) {\n const createdAt = new Date(memory.frontmatter.created).getTime();\n const ageMs = now - createdAt;\n const ageDays = ageMs / (1000 * 60 * 60 * 24);\n const halfLifeDays = 7;\n const recencyScore = Math.pow(0.5, ageDays / halfLifeDays);\n score =\n score * (1 - this.config.recencyWeight) +\n recencyScore * this.config.recencyWeight;\n }\n\n // Access count boost: log scale, capped\n if (this.config.boostAccessCount && memory.frontmatter.accessCount) {\n const accessBoost = Math.log10(memory.frontmatter.accessCount + 1) / 3;\n score += Math.min(accessBoost, 0.1); // Cap at 0.1 boost\n }\n\n // Importance boost (Phase 1B): higher importance = higher rank\n if (memory.frontmatter.importance) {\n const importanceScore = memory.frontmatter.importance.score;\n // Boost important memories, slightly penalize trivial ones\n // Scale: trivial (-0.05) to critical (+0.15)\n const importanceBoost = (importanceScore - 0.4) * 0.25;\n score += importanceBoost;\n }\n\n // Feedback bias (v2.2): apply small user-provided up/down vote adjustments.\n if (this.config.feedbackEnabled) {\n const match = memory.path.match(/([^/]+)\\.md$/);\n const memoryId = match ? match[1] : null;\n if (memoryId) {\n score += this.relevance.adjustment(memoryId);\n }\n }\n\n // Negative examples (v2.2): apply a small penalty for memories repeatedly marked \"not useful\".\n if (this.config.negativeExamplesEnabled) {\n const match = memory.path.match(/([^/]+)\\.md$/);\n const memoryId = match ? match[1] : null;\n if (memoryId) {\n score -= this.negatives.penalty(memoryId, {\n perHit: this.config.negativeExamplesPenaltyPerHit,\n cap: this.config.negativeExamplesPenaltyCap,\n });\n }\n }\n }\n\n return { ...r, score };\n });\n\n // Re-sort by boosted score\n return boosted.sort((a, b) => b.score - a.score);\n }\n\n /**\n * Extract memory IDs from QMD search results for access tracking.\n */\n private extractMemoryIdsFromResults(results: QmdSearchResult[]): string[] {\n // QMD results have paths like /path/to/fact-123.md\n // Extract the ID from the filename\n return results\n .map((r) => {\n const match = r.path.match(/([^/]+)\\.md$/);\n return match ? match[1] : null;\n })\n .filter((id): id is string => id !== null);\n }\n\n // ---------------------------------------------------------------------------\n // Contradiction Detection (Phase 2B)\n // ---------------------------------------------------------------------------\n\n // ---------------------------------------------------------------------------\n // Feedback (v2.2)\n // ---------------------------------------------------------------------------\n\n async recordMemoryFeedback(memoryId: string, vote: \"up\" | \"down\", note?: string): Promise<void> {\n await this.relevance.record(memoryId, vote, note);\n }\n\n // Negative Examples (v2.2)\n async recordNotUsefulMemories(memoryIds: string[], note?: string): Promise<void> {\n await this.negatives.recordNotUseful(memoryIds, note);\n }\n\n getLastRecall(sessionKey: string): LastRecallSnapshot | null {\n return this.lastRecall.get(sessionKey);\n }\n\n /**\n * Check if a new memory contradicts an existing one.\n * Uses QMD to find similar memories, then LLM to verify contradiction.\n */\n private async checkForContradiction(\n content: string,\n category: string,\n ): Promise<{ supersededId: string; confidence: number; reason: string } | null> {\n if (!this.qmd.isAvailable()) return null;\n\n // Search for similar memories\n const results = await this.qmd.search(content, undefined, 5);\n\n for (const result of results) {\n // Check similarity threshold\n if (result.score < this.config.contradictionSimilarityThreshold) {\n continue;\n }\n\n // Get the existing memory\n const memoryId = this.extractMemoryIdsFromResults([result])[0];\n if (!memoryId) continue;\n\n const existingMemory = await this.storage.getMemoryById(memoryId);\n if (!existingMemory) continue;\n\n // Skip already superseded memories\n if (existingMemory.frontmatter.status === \"superseded\") continue;\n\n // Verify contradiction with LLM\n const verification = await this.extraction.verifyContradiction(\n { content, category },\n {\n id: existingMemory.frontmatter.id,\n content: existingMemory.content,\n category: existingMemory.frontmatter.category,\n created: existingMemory.frontmatter.created,\n },\n );\n\n if (!verification) continue;\n\n // Check if it's a real contradiction with high confidence\n if (\n verification.isContradiction &&\n verification.confidence >= this.config.contradictionMinConfidence\n ) {\n // Auto-resolve if enabled\n if (this.config.contradictionAutoResolve) {\n // The new memory supersedes the old one (unless LLM said first is newer)\n if (verification.whichIsNewer !== \"first\") {\n await this.storage.supersedeMemory(\n existingMemory.frontmatter.id,\n \"pending-new\", // Will be updated after the new memory is written\n verification.reasoning,\n );\n\n return {\n supersededId: existingMemory.frontmatter.id,\n confidence: verification.confidence,\n reason: verification.reasoning,\n };\n }\n }\n\n log.info(\n `detected contradiction (confidence: ${verification.confidence}): ${existingMemory.frontmatter.id} vs new memory`,\n );\n }\n }\n\n return null;\n }\n\n // ---------------------------------------------------------------------------\n // Memory Linking (Phase 3A)\n // ---------------------------------------------------------------------------\n\n /**\n * Suggest links for a new memory based on similar existing memories.\n */\n private async suggestLinksForMemory(\n content: string,\n category: string,\n ): Promise<MemoryLink[]> {\n if (!this.qmd.isAvailable()) return [];\n\n // Search for related memories\n const results = await this.qmd.search(content, undefined, 5);\n if (results.length === 0) return [];\n\n // Get full memory details for candidates\n const candidates: Array<{ id: string; content: string; category: string }> = [];\n for (const result of results) {\n const memoryId = this.extractMemoryIdsFromResults([result])[0];\n if (!memoryId) continue;\n\n const memory = await this.storage.getMemoryById(memoryId);\n if (memory && memory.frontmatter.status !== \"superseded\") {\n candidates.push({\n id: memory.frontmatter.id,\n content: memory.content,\n category: memory.frontmatter.category,\n });\n }\n }\n\n if (candidates.length === 0) return [];\n\n // Ask LLM for link suggestions\n const suggestions = await this.extraction.suggestLinks(\n { content, category },\n candidates,\n );\n\n if (!suggestions || suggestions.links.length === 0) return [];\n\n // Convert to MemoryLink format\n return suggestions.links.map((link) => ({\n targetId: link.targetId,\n linkType: link.linkType,\n strength: link.strength,\n reason: link.reason || undefined,\n }));\n }\n\n private namespaceFromPath(p: string): string {\n if (!this.config.namespacesEnabled) return this.config.defaultNamespace;\n const m = p.match(/[\\\\/]+namespaces[\\\\/]+([^\\\\/]+)[\\\\/]+/);\n return m && m[1] ? m[1] : this.config.defaultNamespace;\n }\n\n private async readAllMemoriesForNamespaces(namespaces: string[]): Promise<MemoryFile[]> {\n const uniq = Array.from(new Set(namespaces.filter(Boolean)));\n const lists = await Promise.all(\n uniq.map(async (ns) => {\n const sm = await this.storageRouter.storageFor(ns);\n return sm.readAllMemories();\n }),\n );\n return lists.flat();\n }\n}\n","import type { SignalLevel, SignalScanResult } from \"./types.js\";\n\nconst BUILTIN_HIGH_PATTERNS: RegExp[] = [\n /\\bactually,?\\s+(i|my|we)\\b/i,\n /\\bno,?\\s+(i|my|we|that'?s)\\s+(not|wrong|incorrect)\\b/i,\n /\\bthat'?s\\s+not\\s+right\\b/i,\n /\\bwhy\\s+did\\s+you\\s+say\\s+that\\b/i,\n /\\bi\\s+(?:always|never|prefer|hate|love|want|need)\\b/i,\n /\\bdon'?t\\s+(?:use|do|call|say|make)\\b/i,\n /\\bplease\\s+(?:always|never|remember|note)\\b/i,\n /\\bcorrection:?\\b/i,\n /\\bimportant:?\\s+/i,\n /\\bfyi:?\\b/i,\n /\\bfor\\s+(?:the\\s+)?record\\b/i,\n /\\bmy\\s+(?:name|email|company|role|title|preference)\\s+is\\b/i,\n /\\bi\\s+(?:work|live|am)\\s+(?:at|in|from|a)\\b/i,\n /\\bwe\\s+(?:decided|agreed|chose|picked)\\b/i,\n /\\bthe\\s+decision\\s+(?:is|was)\\b/i,\n /\\bgoing\\s+forward\\b/i,\n /\\bfrom\\s+now\\s+on\\b/i,\n];\n\nconst MEDIUM_PATTERNS: RegExp[] = [\n /\\bi\\s+(?:think|believe|feel)\\b/i,\n /\\busually\\b/i,\n /\\btypically\\b/i,\n /\\bi\\s+(?:like|dislike)\\b/i,\n /\\bmy\\s+(?:team|project|stack|setup)\\b/i,\n];\n\nconst DISAGREEMENT_PATTERNS: RegExp[] = [\n /\\bthat'?s\\s+not\\s+right\\b/i,\n /\\bwhy\\s+did\\s+you\\s+say\\s+that\\b/i,\n /\\bthat'?s\\s+wrong\\b/i,\n /\\bnot\\s+correct\\b/i,\n];\n\nexport function isDisagreementPrompt(text: string): boolean {\n for (const rx of DISAGREEMENT_PATTERNS) {\n if (rx.test(text)) return true;\n }\n return false;\n}\n\nexport function scanSignals(\n text: string,\n customPatterns: string[] = [],\n): SignalScanResult {\n const matched: string[] = [];\n\n const customRegexes = customPatterns.map((p) => new RegExp(p, \"i\"));\n\n for (const rx of customRegexes) {\n if (rx.test(text)) {\n matched.push(`custom:${rx.source}`);\n }\n }\n\n for (const rx of BUILTIN_HIGH_PATTERNS) {\n if (rx.test(text)) {\n matched.push(`high:${rx.source}`);\n }\n }\n\n if (matched.length > 0) {\n return { level: \"high\", patterns: matched };\n }\n\n const mediumMatched: string[] = [];\n for (const rx of MEDIUM_PATTERNS) {\n if (rx.test(text)) {\n mediumMatched.push(`medium:${rx.source}`);\n }\n }\n\n if (mediumMatched.length >= 2) {\n return { level: \"medium\", patterns: mediumMatched };\n }\n if (mediumMatched.length === 1) {\n return { level: \"low\", patterns: mediumMatched };\n }\n\n return { level: \"none\", patterns: [] };\n}\n","import { log } from \"./logger.js\";\nimport { scanSignals } from \"./signal.js\";\nimport type { StorageManager } from \"./storage.js\";\nimport type {\n BufferState,\n BufferTurn,\n PluginConfig,\n SignalLevel,\n} from \"./types.js\";\n\nexport type TriggerDecision = \"extract_now\" | \"extract_batch\" | \"keep_buffering\";\n\nexport class SmartBuffer {\n private state: BufferState;\n private loaded = false;\n\n constructor(\n private readonly config: PluginConfig,\n private readonly storage: StorageManager,\n ) {\n this.state = { turns: [], lastExtractionAt: null, extractionCount: 0 };\n }\n\n async load(): Promise<void> {\n if (this.loaded) return;\n this.state = await this.storage.loadBuffer();\n this.loaded = true;\n }\n\n async save(): Promise<void> {\n await this.storage.saveBuffer(this.state);\n }\n\n async addTurn(turn: BufferTurn): Promise<TriggerDecision> {\n await this.load();\n this.state.turns.push(turn);\n\n const signal = scanSignals(turn.content, this.config.highSignalPatterns);\n const decision = this.evaluate(signal.level);\n\n log.debug(\n `buffer: ${this.state.turns.length} turns, signal=${signal.level}, decision=${decision}`,\n );\n\n await this.save();\n return decision;\n }\n\n private evaluate(signalLevel: SignalLevel): TriggerDecision {\n if (this.config.triggerMode === \"smart\") {\n if (signalLevel === \"high\") return \"extract_now\";\n\n if (this.state.turns.length >= this.config.bufferMaxTurns) {\n return \"extract_batch\";\n }\n\n if (this.state.lastExtractionAt) {\n const elapsed =\n Date.now() - new Date(this.state.lastExtractionAt).getTime();\n if (elapsed >= this.config.bufferMaxMinutes * 60_000) {\n return \"extract_batch\";\n }\n }\n\n return \"keep_buffering\";\n }\n\n if (this.config.triggerMode === \"every_n\") {\n return this.state.turns.length >= this.config.bufferMaxTurns\n ? \"extract_batch\"\n : \"keep_buffering\";\n }\n\n if (this.config.triggerMode === \"time_based\") {\n if (!this.state.lastExtractionAt) {\n return this.state.turns.length >= this.config.bufferMaxTurns\n ? \"extract_batch\"\n : \"keep_buffering\";\n }\n const elapsed =\n Date.now() - new Date(this.state.lastExtractionAt).getTime();\n return elapsed >= this.config.bufferMaxMinutes * 60_000\n ? \"extract_batch\"\n : \"keep_buffering\";\n }\n\n return \"keep_buffering\";\n }\n\n getTurns(): BufferTurn[] {\n return [...this.state.turns];\n }\n\n async clearAfterExtraction(): Promise<void> {\n this.state.turns = [];\n this.state.lastExtractionAt = new Date().toISOString();\n this.state.extractionCount += 1;\n await this.save();\n }\n\n getExtractionCount(): number {\n return this.state.extractionCount;\n }\n}\n","/**\n * Automatic Chunking with Overlap (Phase 2A)\n *\n * Sentence-boundary chunking for long memories.\n * Preserves coherent thoughts by never splitting mid-sentence.\n */\n\nexport interface ChunkingConfig {\n /** Target tokens per chunk (default 200) */\n targetTokens: number;\n /** Minimum tokens to trigger chunking (default 150) */\n minTokens: number;\n /** Number of sentences to overlap between chunks (default 2) */\n overlapSentences: number;\n}\n\nexport interface Chunk {\n /** Chunk content */\n content: string;\n /** 0-based index */\n index: number;\n /** Approximate token count */\n tokenCount: number;\n}\n\nexport interface ChunkResult {\n /** Whether content was chunked */\n chunked: boolean;\n /** Array of chunks (length 1 if not chunked) */\n chunks: Chunk[];\n}\n\n/** Default chunking configuration */\nexport const DEFAULT_CHUNKING_CONFIG: ChunkingConfig = {\n targetTokens: 200,\n minTokens: 150,\n overlapSentences: 2,\n};\n\n/**\n * Estimate token count for text.\n * Rough approximation: ~4 characters per token for English.\n */\nfunction estimateTokens(text: string): number {\n return Math.ceil(text.length / 4);\n}\n\n/**\n * Split text into sentences.\n * Handles common abbreviations and edge cases.\n */\nfunction splitSentences(text: string): string[] {\n // Split on sentence-ending punctuation followed by whitespace or end of string\n // Preserve the punctuation with the sentence\n const sentences: string[] = [];\n\n // Regex to match sentence boundaries\n // Match: period/exclamation/question followed by space or end, but not abbreviations\n const sentenceRegex = /[^.!?]*[.!?]+(?:\\s+|$)/g;\n\n let match: RegExpExecArray | null;\n let lastIndex = 0;\n\n while ((match = sentenceRegex.exec(text)) !== null) {\n sentences.push(match[0].trim());\n lastIndex = sentenceRegex.lastIndex;\n }\n\n // Handle remaining text without sentence-ending punctuation\n if (lastIndex < text.length) {\n const remaining = text.slice(lastIndex).trim();\n if (remaining) {\n sentences.push(remaining);\n }\n }\n\n // Filter out empty sentences\n return sentences.filter((s) => s.length > 0);\n}\n\n/**\n * Chunk content into overlapping segments at sentence boundaries.\n *\n * @param content - The text content to chunk\n * @param config - Chunking configuration\n * @returns ChunkResult with chunks array\n */\nexport function chunkContent(\n content: string,\n config: ChunkingConfig = DEFAULT_CHUNKING_CONFIG,\n): ChunkResult {\n const totalTokens = estimateTokens(content);\n\n // Don't chunk if below minimum threshold\n if (totalTokens < config.minTokens) {\n return {\n chunked: false,\n chunks: [{\n content,\n index: 0,\n tokenCount: totalTokens,\n }],\n };\n }\n\n const sentences = splitSentences(content);\n\n // If we couldn't split into multiple sentences, don't chunk\n if (sentences.length <= 1) {\n return {\n chunked: false,\n chunks: [{\n content,\n index: 0,\n tokenCount: totalTokens,\n }],\n };\n }\n\n const chunks: Chunk[] = [];\n let currentChunkSentences: string[] = [];\n let currentTokens = 0;\n let chunkIndex = 0;\n\n for (let i = 0; i < sentences.length; i++) {\n const sentence = sentences[i];\n const sentenceTokens = estimateTokens(sentence);\n\n // Add sentence to current chunk\n currentChunkSentences.push(sentence);\n currentTokens += sentenceTokens;\n\n // Check if we've reached target size (with some flexibility)\n // Allow going over by up to 50% to avoid tiny final chunks\n const atTarget = currentTokens >= config.targetTokens;\n const isLastSentence = i === sentences.length - 1;\n\n if (atTarget || isLastSentence) {\n // Create chunk from accumulated sentences\n const chunkContent = currentChunkSentences.join(\" \");\n chunks.push({\n content: chunkContent,\n index: chunkIndex,\n tokenCount: estimateTokens(chunkContent),\n });\n chunkIndex++;\n\n // Start new chunk with overlap (if not at end)\n if (!isLastSentence) {\n // Keep last N sentences for overlap\n const overlapCount = Math.min(config.overlapSentences, currentChunkSentences.length);\n currentChunkSentences = currentChunkSentences.slice(-overlapCount);\n currentTokens = currentChunkSentences.reduce((sum, s) => sum + estimateTokens(s), 0);\n }\n }\n }\n\n // Only consider it \"chunked\" if we got multiple chunks\n return {\n chunked: chunks.length > 1,\n chunks,\n };\n}\n\n/**\n * Get parent content by reassembling chunks.\n * Useful for displaying full context when a chunk is retrieved.\n *\n * @param chunks - Array of chunk contents in order\n * @returns Reassembled parent content (with overlap removed)\n */\nexport function reassembleChunks(chunks: string[]): string {\n if (chunks.length === 0) return \"\";\n if (chunks.length === 1) return chunks[0];\n\n // For overlapping chunks, we need to deduplicate\n // Simple approach: use full first chunk, then non-overlapping parts of subsequent chunks\n // This is imperfect but handles most cases\n const result: string[] = [chunks[0]];\n\n for (let i = 1; i < chunks.length; i++) {\n const prevChunk = chunks[i - 1];\n const currChunk = chunks[i];\n\n // Find overlap by looking for common suffix/prefix\n // Try to find where the previous chunk ends in the current chunk\n const prevSentences = splitSentences(prevChunk);\n const currSentences = splitSentences(currChunk);\n\n // Find how many sentences from prev are at the start of curr\n let overlapCount = 0;\n for (let j = 0; j < Math.min(prevSentences.length, currSentences.length); j++) {\n // Check if last N sentences of prev match first N sentences of curr\n const prevEnd = prevSentences.slice(-(j + 1));\n const currStart = currSentences.slice(0, j + 1);\n\n if (prevEnd.join(\" \") === currStart.join(\" \")) {\n overlapCount = j + 1;\n }\n }\n\n // Add non-overlapping portion\n if (overlapCount > 0 && overlapCount < currSentences.length) {\n result.push(currSentences.slice(overlapCount).join(\" \"));\n } else if (overlapCount === 0) {\n // No detected overlap, add full chunk\n result.push(currChunk);\n }\n // If overlapCount === currSentences.length, skip (fully contained)\n }\n\n return result.join(\" \");\n}\n","import OpenAI from \"openai\";\nimport { zodTextFormat } from \"openai/helpers/zod\";\nimport { log } from \"./logger.js\";\nimport { LocalLlmClient } from \"./local-llm.js\";\nimport { FallbackLlmClient } from \"./fallback-llm.js\";\nimport {\n ExtractionResultSchema,\n ConsolidationResultSchema,\n IdentityConsolidationResultSchema,\n ProfileConsolidationResultSchema,\n ContradictionVerificationSchema,\n SuggestedLinksSchema,\n MemorySummarySchema,\n type ContradictionVerificationResult,\n type SuggestedLinks,\n type MemorySummaryResult,\n} from \"./schemas.js\";\nimport type {\n BufferTurn,\n ExtractionResult,\n ConsolidationResult,\n MemoryFile,\n PluginConfig,\n LlmTraceEvent,\n GatewayConfig,\n} from \"./types.js\";\nimport { ModelRegistry } from \"./model-registry.js\";\nimport { extractJsonCandidates } from \"./json-extract.js\";\nimport { sanitizeMemoryContent } from \"./sanitize.js\";\n\nexport class ExtractionEngine {\n private client: OpenAI | null;\n private localLlm: LocalLlmClient;\n private fallbackLlm: FallbackLlmClient;\n private modelRegistry: ModelRegistry;\n\n constructor(\n private readonly config: PluginConfig,\n localLlm?: LocalLlmClient,\n gatewayConfig?: GatewayConfig,\n modelRegistry?: ModelRegistry,\n ) {\n if (config.openaiApiKey) {\n this.client = new OpenAI({\n apiKey: config.openaiApiKey,\n ...(config.openaiBaseUrl ? { baseURL: config.openaiBaseUrl } : {}),\n });\n } else {\n this.client = null;\n log.warn(\"no OpenAI API key — extraction/consolidation disabled (retrieval still works)\");\n }\n this.localLlm = localLlm ?? new LocalLlmClient(config, modelRegistry);\n this.fallbackLlm = new FallbackLlmClient(gatewayConfig);\n this.modelRegistry = modelRegistry ?? new ModelRegistry(config.memoryDir);\n }\n\n private emit(event: LlmTraceEvent): void {\n try {\n const cb = (globalThis as any).__openclawEngramTrace;\n if (typeof cb === \"function\") cb(event);\n } catch {\n // Never throw — broken subscriber must not crash extraction\n }\n }\n\n private sanitizeExtractionResult(result: ExtractionResult): ExtractionResult {\n const facts = result.facts.map((fact) => {\n const sanitized = sanitizeMemoryContent(fact.content);\n if (!sanitized.clean) {\n log.warn(`extraction fact sanitized; violations=${sanitized.violations.join(\", \")}`);\n }\n return { ...fact, content: sanitized.text };\n });\n return { ...result, facts };\n }\n\n private sanitizeConsolidationResult(result: ConsolidationResult): ConsolidationResult {\n const items = result.items.map((item) => {\n if (!item.updatedContent) return item;\n const sanitized = sanitizeMemoryContent(item.updatedContent);\n if (!sanitized.clean) {\n log.warn(`consolidation item sanitized (${item.existingId}); violations=${sanitized.violations.join(\", \")}`);\n }\n return { ...item, updatedContent: sanitized.text };\n });\n return { ...result, items };\n }\n\n private async parseWithGatewayFallback<T>(\n traceId: string,\n operation: LlmTraceEvent[\"operation\"],\n startedAtMs: number,\n schema: { parse: (data: unknown) => T },\n messages: Array<{ role: \"system\" | \"user\" | \"assistant\"; content: string }>,\n options: { temperature?: number; maxTokens?: number } = {},\n ): Promise<T | null> {\n const result = await this.fallbackLlm.parseWithSchema(messages, schema, options);\n if (result) {\n const durationMs = Date.now() - startedAtMs;\n this.emit({\n kind: \"llm_end\",\n traceId,\n model: \"fallback\",\n operation,\n durationMs,\n output: JSON.stringify(result).slice(0, 2000),\n });\n return result;\n }\n return null;\n }\n\n async extract(turns: BufferTurn[], existingEntities?: string[]): Promise<ExtractionResult> {\n\n // Guard: skip if buffer is empty or all turns are whitespace-only\n const substantiveTurns = turns.filter((t) => t.content.trim().length > 0);\n if (substantiveTurns.length === 0) {\n log.debug(\"extraction skipped — no substantive turns in buffer\");\n return { facts: [], profileUpdates: [], entities: [], questions: [] };\n }\n\n const conversation = substantiveTurns\n .map((t) => `[${t.role}] ${t.content}`)\n .join(\"\\n\\n\");\n\n const traceId = crypto.randomUUID();\n this.emit({ kind: \"llm_start\", traceId, model: this.config.model, operation: \"extraction\", input: conversation });\n const startTime = Date.now();\n\n // Try local LLM first if enabled\n if (this.config.localLlmEnabled) {\n try {\n const localResult = await this.extractWithLocalLlm(conversation, existingEntities);\n if (localResult) {\n const durationMs = Date.now() - startTime;\n this.emit({ kind: \"llm_end\", traceId, model: this.config.localLlmModel, operation: \"extraction\", durationMs });\n log.debug(`extraction: used local LLM — ${localResult.facts.length} facts, ${localResult.entities.length} entities`);\n return this.sanitizeExtractionResult(localResult);\n }\n // Local failed, fall back if allowed\n if (!this.config.localLlmFallback) {\n log.warn(\"extraction: local LLM failed and fallback disabled\");\n return { facts: [], profileUpdates: [], entities: [], questions: [] };\n }\n log.info(\"extraction: local LLM unavailable, falling back to gateway default AI\");\n } catch (err) {\n if (!this.config.localLlmFallback) {\n log.warn(\"extraction: local LLM error and fallback disabled:\", err);\n return { facts: [], profileUpdates: [], entities: [], questions: [] };\n }\n log.info(\"extraction: local LLM error, falling back to gateway default AI:\", err);\n }\n }\n\n // Fall back to gateway's default AI\n log.info(\"extraction: falling back to gateway default AI\");\n\n try {\n const messages = [\n { role: \"system\" as const, content: this.buildExtractionInstructions(existingEntities) },\n { role: \"user\" as const, content: conversation },\n ];\n\n const result = await this.fallbackLlm.parseWithSchema(\n messages,\n ExtractionResultSchema,\n { temperature: 0.3, maxTokens: 4096 },\n );\n\n const durationMs = Date.now() - startTime;\n\n if (result && Array.isArray(result.facts)) {\n this.emit({\n kind: \"llm_end\", traceId, model: \"fallback\", operation: \"extraction\", durationMs,\n output: JSON.stringify(result).slice(0, 2000),\n });\n log.debug(\n `extracted ${result.facts.length} facts, ${result.entities.length} entities, ${(result.questions ?? []).length} questions via fallback`,\n );\n return this.sanitizeExtractionResult({\n ...result,\n questions: result.questions ?? [],\n identityReflection: result.identityReflection ?? undefined,\n } as ExtractionResult);\n }\n\n log.warn(\"extraction fallback returned no parsed output\");\n return { facts: [], profileUpdates: [], entities: [], questions: [] };\n } catch (err) {\n this.emit({\n kind: \"llm_error\", traceId, model: \"fallback\", operation: \"extraction\",\n durationMs: Date.now() - startTime, error: String(err),\n });\n log.error(\"extraction fallback failed\", err);\n return { facts: [], profileUpdates: [], entities: [], questions: [] };\n }\n }\n\n /**\n * Extract memories using local LLM with JSON mode.\n * Uses a minimal prompt to fit within local model context limits (typically 4k-8k).\n */\n private async extractWithLocalLlm(conversation: string, existingEntities?: string[]): Promise<ExtractionResult | null> {\n log.debug(\n `extractWithLocalLlm: starting extraction, localLlmEnabled=${this.config.localLlmEnabled}, model=${this.config.localLlmModel}`,\n );\n\n // Get dynamic context sizes based on model capabilities (with optional user override)\n const contextSizes = this.modelRegistry.calculateContextSizes(\n this.config.localLlmModel,\n this.config.localLlmMaxContext\n );\n log.debug(`Model context: ${contextSizes.description}`);\n\n const maxConversationChars = contextSizes.maxInputChars;\n const truncatedConversation = conversation.length > maxConversationChars\n ? conversation.slice(0, maxConversationChars) + \"\\n\\n[truncated]\"\n : conversation;\n\n const localPrompt = `You are a memory extraction system. Extract durable, reusable memories from this conversation.\n\nMemory categories — use the MOST SPECIFIC category that fits:\n- fact: Objective information about the world\n- preference: User likes, dislikes, or stylistic choices\n- correction: User correcting a mistake (highest priority)\n- entity: People, projects, tools, companies (use canonical hyphenated names like \"my-project\")\n- decision: Choices made with rationale\n- relationship: How entities relate (e.g., \"Alice manages Bob\")\n- principle: Durable rules or operating beliefs (e.g., \"never use X API\")\n- commitment: Promises, obligations, deadlines\n- moment: Emotionally significant events\n- skill: Demonstrated capabilities\n\nIMPORTANT: Do NOT label everything as \"fact\". Use \"decision\" for architectural choices, \"commitment\" for deadlines/promises, \"principle\" for reusable rules, \"correction\" for when the user rejects a suggestion, etc.\n\n=== DO NOT EXTRACT (negative examples) ===\nThese are operational noise - skip them:\n- \"The user has a cron job that runs every 30 minutes\" (scheduled task descriptions)\n- \"The user encountered error XYZ at 3:45 PM\" (temporary error states)\n- \"The file is located at /path/to/project/file\" (transient file paths)\n- \"The system is using 4GB of memory\" (current resource usage)\n- \"The user ran the 'git status' command\" (individual command executions)\n- \"The conversation took place on Tuesday\" (session metadata)\n- \"The agent read the file at /path/to/file.txt\" (agent's own actions)\n- \"The user's OpenClaw automation posts to #channel on failures\" (automation behavior descriptions)\n- \"The user stores state in /path/to/state.json\" (implementation details)\n- \"The X-watch automation has been stalled for 58 hours\" (system status updates)\n- \"The user processed 5 batch files and extracted insights\" (processing summaries)\n- \"The user has a cron job that runs a Checkpoint Loop every 2 hours\" (automation schedules)\n- \"The user runs a Morning Surprise cron job daily at 7:30 AM\" (automation schedules)\n- \"The user runs an X Bookmarks → Insights pipeline hourly at :13\" (automation schedules)\n- \"The user's system mines X/Twitter mentions for ideas every 10a/2p/6p\" (automation schedules)\n- \"The user runs a Health Insights cron job weekday mornings\" (automation schedules)\n- \"The system monitors the showcase page every 12 hours\" (system monitoring configurations)\n\n=== DO EXTRACT (positive examples) ===\nThese are durable insights - capture them:\n- \"The user prefers dark mode interfaces and finds light mode uncomfortable\" (preference)\n- \"The user works primarily with TypeScript and avoids Python for frontend code\" (long-term fact)\n- \"The user's side project 'alpha-trader' uses a custom algorithm for arbitrage\" (entity + detail)\n- \"The user corrected that PostgreSQL 15 is required, not version 14\" (correction)\n- \"The user never commits code without running tests first\" (principle)\n- \"The user has a meeting with the design team every Friday at 2pm\" (commitment)\n\n=== Rules ===\n- Extract only NEW information worth remembering across sessions\n- Skip transient details (file paths, current errors, temporary states, agent actions)\n- Confidence: Explicit (0.95-1.0), Implied (0.70-0.94), Inferred (0.40-0.69), Speculative (0.00-0.39)\n- Corrections get highest confidence (0.95+)\n- Each fact should be standalone and self-contained\n- CRITICAL: Use canonical hyphenated entity names (e.g., \"jane-doe\" not \"janedoe\")\n- CRITICAL: NEVER extract the same fact twice - check for duplicates before adding to facts array\n- CRITICAL: NEVER extract cron job schedules, automation configurations, or system monitoring details (these are operational noise)\n- If uncertain about relevance, prefer NOT extracting\n\nAlso generate:\n1. 1-3 genuine questions you're curious about from this conversation\n2. Profile updates about user patterns/behaviors (if any)\n3. Relationships between entities (max 5). Use normalized names like \"person-jane-doe\", \"company-acme-corp\".\n\nOutput JSON:\n{\n \"facts\": [{\"category\": \"decision\", \"content\": \"Chose X over Y because...\", \"importance\": 8, \"confidence\": 0.9}, {\"category\": \"commitment\", \"content\": \"Must deliver X by date\", \"importance\": 10, \"confidence\": 1.0}, {\"category\": \"fact\", \"content\": \"X uses Y technology\", \"importance\": 6, \"confidence\": 0.95}, {\"category\": \"principle\", \"content\": \"Always do X to avoid Y\", \"importance\": 8, \"confidence\": 0.9}],\n \"entities\": [{\"name\": \"...\", \"type\": \"person|company|project|tool|other\"}],\n \"profileUpdates\": [\"...\"],\n \"questions\": [{\"question\": \"...\", \"context\": \"...\"}],\n \"relationships\": [{\"source\": \"person-jane-doe\", \"target\": \"company-acme-corp\", \"label\": \"works at\"}]\n}\n\nConversation:\n${truncatedConversation}`;\n\n log.debug(\n `extractWithLocalLlm: calling localLlm.chatCompletion with prompt length ${localPrompt.length}...`,\n );\n const response = await this.localLlm.chatCompletion(\n [\n { role: \"system\", content: \"You are a memory extraction system. Output valid JSON only.\" },\n { role: \"user\", content: localPrompt },\n ],\n { temperature: 0.1, maxTokens: contextSizes.maxOutputTokens, operation: \"extraction\" },\n );\n\n if (!response?.content) {\n log.debug(\"extractWithLocalLlm: chatCompletion returned null or empty content\");\n return null;\n }\n\n const content = response.content.trim();\n // Avoid logging model output content by default (may contain user data).\n log.debug(`extractWithLocalLlm: got response content, length=${content.length}`);\n\n try {\n for (const candidate of extractJsonCandidates(content)) {\n try {\n log.debug(`extractWithLocalLlm: attempting JSON parse, candidate length=${candidate.length}`);\n const parsed = JSON.parse(candidate);\n\n // Validate and normalize\n const entities = Array.isArray((parsed as any).entities)\n ? (parsed as any).entities\n .map((e: any) => ({\n name: typeof e?.name === \"string\" ? e.name : \"\",\n type: typeof e?.type === \"string\" ? e.type : \"other\",\n // Local models frequently omit or malform `facts`; harden to avoid runtime crashes downstream.\n facts: Array.isArray(e?.facts)\n ? e.facts.filter((f: any) => typeof f === \"string\")\n : [],\n }))\n .filter((e: any) => e.name.length > 0)\n : [];\n\n const result: ExtractionResult = {\n facts: Array.isArray((parsed as any).facts) ? (parsed as any).facts : [],\n entities,\n profileUpdates: Array.isArray((parsed as any).profileUpdates)\n ? (parsed as any).profileUpdates\n : [],\n questions: Array.isArray((parsed as any).questions) ? (parsed as any).questions : [],\n identityReflection: (parsed as any).identityReflection ?? undefined,\n relationships: Array.isArray((parsed as any).relationships)\n ? (parsed as any).relationships.filter(\n (r: any) => typeof r?.source === \"string\" && typeof r?.target === \"string\" && typeof r?.label === \"string\",\n )\n : undefined,\n };\n\n log.debug(\n `extractWithLocalLlm: successfully parsed response, facts=${result.facts.length}, entities=${result.entities.length}, profileUpdates=${result.profileUpdates.length}, questions=${result.questions.length}`,\n );\n return result;\n } catch {\n // keep trying candidates\n }\n }\n return null;\n } catch (err) {\n // Try to extract partial facts from truncated JSON\n log.debug(\"extractWithLocalLlm: JSON parse failed, attempting partial extraction...\");\n const partial = this.extractPartialFacts(content);\n if (partial.facts.length > 0 || partial.entities.length > 0) {\n log.debug(\n `extractWithLocalLlm: extracted ${partial.facts.length} partial facts from truncated JSON`,\n );\n return partial;\n }\n\n // Could not extract anything\n const errMsg = err instanceof Error ? err.message : String(err);\n log.debug(`extractWithLocalLlm: JSON parse error: ${errMsg}`);\n return null;\n }\n }\n\n /**\n * Extract partial facts from truncated JSON responses.\n * Local LLMs sometimes hit token limits mid-JSON. This tries to salvage valid facts.\n */\n private extractPartialFacts(jsonStr: string): ExtractionResult {\n const allowedCategories = new Set([\n \"fact\",\n \"preference\",\n \"correction\",\n \"entity\",\n \"decision\",\n \"relationship\",\n \"principle\",\n \"commitment\",\n \"moment\",\n \"skill\",\n ]);\n const allowedEntityTypes = new Set([\n \"person\",\n \"project\",\n \"tool\",\n \"company\",\n \"place\",\n \"other\",\n ]);\n\n const facts: ExtractionResult[\"facts\"] = [];\n const entities: ExtractionResult[\"entities\"] = [];\n\n try {\n // Find all complete fact objects (ones with all required fields)\n const factRegex = /\\{\\s*\"category\"\\s*:\\s*\"([^\"]+)\"\\s*,\\s*\"content\"\\s*:\\s*\"([^\"]+)\"\\s*,\\s*\"confidence\"\\s*:\\s*([0-9.]+)/g;\n let match;\n while ((match = factRegex.exec(jsonStr)) !== null) {\n const rawCat = match[1];\n const category = allowedCategories.has(rawCat) ? (rawCat as ExtractionResult[\"facts\"][number][\"category\"]) : \"fact\";\n facts.push({\n category,\n content: match[2].replace(/\\\\n/g, '\\n').replace(/\\\\\"/g, '\"'),\n confidence: parseFloat(match[3]),\n tags: [],\n });\n }\n\n // Find all complete entity objects\n const entityRegex = /\\{\\s*\"name\"\\s*:\\s*\"([^\"]+)\"\\s*,\\s*\"type\"\\s*:\\s*\"([^\"]+)\"/g;\n while ((match = entityRegex.exec(jsonStr)) !== null) {\n const rawType = match[2];\n const type = allowedEntityTypes.has(rawType) ? (rawType as ExtractionResult[\"entities\"][number][\"type\"]) : \"other\";\n entities.push({\n name: match[1],\n type,\n facts: [],\n });\n }\n } catch {\n // Ignore regex errors\n }\n\n return { facts, entities, profileUpdates: [], questions: [] };\n }\n\n /**\n * Build extraction instructions shared between local and cloud LLM.\n */\n private buildExtractionInstructions(existingEntities?: string[]): string {\n return `You are a memory extraction system. Analyze the following conversation and extract durable, reusable memories.\n\nMemory categories:\n- fact: Objective information about the world\n- preference: User likes, dislikes, or stylistic choices\n- correction: User correcting a mistake or misconception (highest priority)\n- entity: Information about a specific person, project, tool, or company\n- decision: A choice that was made with rationale\n- relationship: How two entities relate to each other (e.g., \"Alice is Bob's manager\", \"Acme Corp uses Shopify\")\n- principle: Durable rules, values, or operating beliefs (e.g., \"never use Chat Completions API\")\n- commitment: Promises, obligations, or deadlines (e.g., \"deploy by Friday\", \"call accountant Monday\")\n- moment: Emotionally significant events or milestones (e.g., \"first successful deployment of engram\")\n- skill: Capabilities the user or agent has demonstrated (e.g., \"user is proficient with Kubernetes\")\n\nRules:\n- Only extract genuinely NEW information worth remembering across sessions\n- Skip transient task details (file paths being edited, current errors, etc.)\n- Priority: corrections > principles > preferences > commitments > decisions > relationships > entities > moments > skills > facts\n- Corrections (user saying \"actually, don't do X\" or \"I prefer Y\") get highest confidence\n- Each fact should be a standalone, self-contained statement\n- Entity references should use normalized names (lowercase, hyphenated: \"jane-doe\", \"acme-corp\")\n- CRITICAL: Entity names must be CANONICAL. Always use the hyphenated multi-word form: \"acme-corp\" NOT \"acmecorp\" or \"acme\". \"jane-doe\" NOT \"janedoe\" or \"jane\". If unsure, prefer the most specific full name.\n- Avoid creating entities typed as \"other\" when a more specific type fits (company, project, tool, person, place)\n- Tags should be concise and reusable (e.g., \"coding-style\", \"personal\", \"tools\")\n- Set confidence using these tiers:\n * Explicit (0.95-1.0): Direct user statements — \"I prefer X\", \"my name is Y\"\n * Implied (0.70-0.94): Strong contextual inference — user consistently does X, clear from conversation flow\n * Inferred (0.40-0.69): Pattern recognition — reasonable guess from limited evidence\n * Speculative (0.00-0.39): Tentative hypothesis — weak signal, needs future confirmation. Speculative memories auto-expire after 30 days if not confirmed.\n- For commitments: include any deadline or timeframe mentioned\n\nEntity creation rules (STRICT):\n- Only create entities for DURABLE things: real people, companies, products, tools, ongoing projects\n- NEVER create entities for transient items: individual PRs, branches, Jira tickets, meetings, agent task IDs, log files, database tables, cron job runs, sessions\n- When you learn something about a transient item (e.g., PR #58 fixed a bug), store it as a FACT with an entityRef to the parent project — do NOT create an entity for the PR itself\n- Prefer attaching facts to broad parent entities rather than creating sub-entities. E.g., \"acme-store uses Algolia for search\" is a fact on entity \"acme-store\", NOT a new entity \"acme-store-algolia-connector\"\n- The entity list should be SHORT — think \"things that would have their own Wikipedia page\" not \"things mentioned in passing\"\n\n${existingEntities && existingEntities.length > 0 ? `\nKNOWN ENTITIES (use these exact names when referencing existing things):\n${existingEntities.join(\", \")}\n\nWhen you see something that matches a known entity, use THAT name exactly. Only create a NEW entity if nothing in this list represents it.\n` : \"\"}\nAlso extract relationships between entities mentioned in the conversation.\n- Format: {source: \"entity-name\", target: \"entity-name\", label: \"relationship description\"}\n- Max 5 relationships per extraction\n- Only include clear, durable relationships (e.g., \"works at\", \"created\", \"manages\", \"uses\")\n- Use normalized entity names (e.g., \"person-jane-doe\", \"company-acme-corp\")\n\nAlso generate 1-3 genuine questions you're curious about based on this conversation. These should be things you'd actually want answers to in future sessions — not prompts, but real curiosity.\n\nFinally, write a brief identity reflection about the AGENT who had this conversation (not about you, the extraction system). Based on what the agent said and did in the conversation:\n- What communication patterns did the agent show? (e.g., proactive vs reactive, verbose vs concise)\n- Did the agent handle the user's needs well or miss something?\n- What behavioral tendencies are visible? (e.g., cautious, creative, thorough, impatient)\n- What could the agent improve next time?\nDo NOT write about the extraction process itself. Do NOT say things like \"I extracted durable facts\" — that's about YOUR job, not the agent's behavior.`;\n }\n\n async consolidate(\n newMemories: MemoryFile[],\n existingMemories: MemoryFile[],\n currentProfile: string,\n ): Promise<ConsolidationResult> {\n const newList = newMemories\n .map(\n (m) =>\n `[${m.frontmatter.id}] (${m.frontmatter.category}) ${m.content}`,\n )\n .join(\"\\n\");\n\n const existingList = existingMemories\n .slice(-50) // Only consolidate against recent memories\n .map(\n (m) =>\n `[${m.frontmatter.id}] (${m.frontmatter.category}) ${m.content}`,\n )\n .join(\"\\n\");\n\n const cTraceId = crypto.randomUUID();\n this.emit({ kind: \"llm_start\", traceId: cTraceId, model: this.config.model, operation: \"consolidation\", input: newList });\n const cStartTime = Date.now();\n\n // Try local LLM first if enabled\n if (this.config.localLlmEnabled) {\n try {\n const localResult = await this.consolidateWithLocalLlm(newList, existingList, currentProfile);\n if (localResult) {\n const durationMs = Date.now() - cStartTime;\n this.emit({ kind: \"llm_end\", traceId: cTraceId, model: this.config.localLlmModel, operation: \"consolidation\", durationMs });\n log.debug(`consolidation: used local LLM — ${localResult.items.length} decisions`);\n return this.sanitizeConsolidationResult(localResult);\n }\n if (!this.config.localLlmFallback) {\n log.warn(\"consolidation: local LLM failed and fallback disabled\");\n return { items: [], profileUpdates: [], entityUpdates: [] };\n }\n log.info(\"consolidation: local LLM unavailable, falling back to gateway AI\");\n } catch (err) {\n if (!this.config.localLlmFallback) {\n log.warn(\"consolidation: local LLM error and fallback disabled:\", err);\n return { items: [], profileUpdates: [], entityUpdates: [] };\n }\n log.info(\"consolidation: local LLM error, falling back to gateway AI:\", err);\n }\n }\n\n const fallbackResult = await this.parseWithGatewayFallback(\n cTraceId,\n \"consolidation\",\n cStartTime,\n ConsolidationResultSchema,\n [\n {\n role: \"system\",\n content: `You are a memory consolidation system. Compare new memories against existing ones and decide what to do with each.\n\nActions:\n- ADD: Keep the new memory as-is (no duplicate exists)\n- MERGE: Combine with an existing memory (provide mergeWith ID and updated content)\n- UPDATE: Replace existing memory content (provide updated content)\n- INVALIDATE: Remove existing memory (it's been superseded or is wrong)\n- SKIP: This new memory is redundant (exact duplicate or subset of existing)\n\nAlso:\n- Suggest profile updates based on patterns across memories\n- Identify entity updates for entity tracking`,\n },\n {\n role: \"user\",\n content: `Current behavioral profile:\n${currentProfile || \"(empty)\"}\n\nExisting memories:\n${existingList || \"(none)\"}\n\nNew memories to consolidate:\n${newList}\n\nConsolidate the new memories against existing ones.`,\n },\n ],\n { temperature: 0.3, maxTokens: 4096 },\n );\n if (fallbackResult) {\n log.debug(`consolidation: ${fallbackResult.items.length} decisions via fallback`);\n return this.sanitizeConsolidationResult({\n items: fallbackResult.items.map((item) => ({\n ...item,\n mergeWith: item.mergeWith ?? undefined,\n updatedContent: item.updatedContent ?? undefined,\n })),\n profileUpdates: fallbackResult.profileUpdates,\n entityUpdates: fallbackResult.entityUpdates,\n });\n }\n\n // Fall back to OpenAI API\n if (!this.client) {\n log.warn(\"consolidation skipped — no OpenAI API key and local LLM failed/disabled\");\n return { items: [], profileUpdates: [], entityUpdates: [] };\n }\n\n const reasoningParam =\n this.config.reasoningEffort !== \"none\"\n ? { reasoning: { effort: this.config.reasoningEffort as \"low\" | \"medium\" | \"high\" } }\n : {};\n\n try {\n const response = await this.client.responses.parse({\n model: this.config.model,\n ...reasoningParam,\n instructions: `You are a memory consolidation system. Compare new memories against existing ones and decide what to do with each.\n\nActions:\n- ADD: Keep the new memory as-is (no duplicate exists)\n- MERGE: Combine with an existing memory (provide mergeWith ID and updated content)\n- UPDATE: Replace existing memory content (provide updated content)\n- INVALIDATE: Remove existing memory (it's been superseded or is wrong)\n- SKIP: This new memory is redundant (exact duplicate or subset of existing)\n\nAlso:\n- Suggest profile updates based on patterns across memories\n- Identify entity updates for entity tracking\n\nCurrent behavioral profile:\n${currentProfile || \"(empty)\"}\n\nExisting memories:\n${existingList || \"(none)\"}\n\nNew memories to consolidate:\n${newList}`,\n input: \"Consolidate the new memories against existing ones.\",\n text: {\n format: zodTextFormat(\n ConsolidationResultSchema,\n \"consolidation_result\",\n ),\n },\n });\n\n const cDurationMs = Date.now() - cStartTime;\n const cUsage = (response as any).usage;\n this.emit({\n kind: \"llm_end\", traceId: cTraceId, model: this.config.model, operation: \"consolidation\", durationMs: cDurationMs,\n output: response.output_parsed ? JSON.stringify(response.output_parsed).slice(0, 2000) : undefined,\n tokenUsage: cUsage ? { input: cUsage.input_tokens, output: cUsage.output_tokens, total: cUsage.total_tokens } : undefined,\n });\n\n if (response.output_parsed) {\n log.debug(\n `consolidation: ${response.output_parsed.items.length} decisions`,\n );\n return this.sanitizeConsolidationResult(response.output_parsed as ConsolidationResult);\n }\n\n log.warn(\"consolidation returned no parsed output\");\n return { items: [], profileUpdates: [], entityUpdates: [] };\n } catch (err) {\n this.emit({\n kind: \"llm_error\", traceId: cTraceId, model: this.config.model, operation: \"consolidation\",\n durationMs: Date.now() - cStartTime, error: String(err),\n });\n log.error(\"consolidation failed\", err);\n return { items: [], profileUpdates: [], entityUpdates: [] };\n }\n }\n\n /**\n * Consolidate memories using local LLM.\n */\n private async consolidateWithLocalLlm(\n newList: string,\n existingList: string,\n currentProfile: string,\n ): Promise<ConsolidationResult | null> {\n // Get dynamic context sizes\n const contextSizes = this.modelRegistry.calculateContextSizes(\n this.config.localLlmModel,\n this.config.localLlmMaxContext\n );\n log.debug(`Consolidation model context: ${contextSizes.description}`);\n\n const prompt = `You are a memory consolidation system. Compare new memories against existing ones and decide what to do with each.\n\nActions:\n- ADD: Keep the new memory as-is (no duplicate exists)\n- MERGE: Combine with an existing memory (provide mergeWith ID and updated content)\n- UPDATE: Replace existing memory content (provide updated content)\n- INVALIDATE: Remove existing memory (it's been superseded or is wrong)\n- SKIP: This new memory is redundant (exact duplicate or subset of existing)\n\nAlso:\n- Suggest profile updates based on patterns across memories\n- Identify entity updates for entity tracking\n\nCurrent behavioral profile:\n${currentProfile || \"(empty)\"}\n\nExisting memories:\n${existingList || \"(none)\"}\n\nNew memories to consolidate:\n${newList}\n\nRespond with valid JSON matching this schema:\n{\n \"items\": [\n {\"memoryId\": \"id\", \"action\": \"ADD|MERGE|UPDATE|INVALIDATE|SKIP\", \"reason\": \"why\", \"updatedContent\": \"optional new content\"}\n ],\n \"profileUpdates\": [{\"section\": \"section name\", \"content\": \"new bullet\"}],\n \"entityUpdates\": [{\"entityId\": \"id\", \"updates\": {\"field\": \"value\"}}]\n}`;\n\n const response = await this.localLlm.chatCompletion(\n [\n { role: \"system\", content: \"You are a memory consolidation system. Output valid JSON only.\" },\n { role: \"user\", content: prompt },\n ],\n { temperature: 0.3, maxTokens: contextSizes.maxOutputTokens, operation: \"consolidation\" },\n );\n\n if (!response?.content) {\n return null;\n }\n\n try {\n const content = response.content.trim();\n for (const candidate of extractJsonCandidates(content)) {\n try {\n const parsed = JSON.parse(candidate);\n return {\n items: Array.isArray((parsed as any).items) ? (parsed as any).items : [],\n profileUpdates: Array.isArray((parsed as any).profileUpdates)\n ? (parsed as any).profileUpdates\n : [],\n entityUpdates: Array.isArray((parsed as any).entityUpdates)\n ? (parsed as any).entityUpdates\n : [],\n } as ConsolidationResult;\n } catch {\n // keep trying candidates\n }\n }\n return null;\n } catch (err) {\n log.warn(\"local LLM consolidation: failed to parse JSON response:\", err);\n return null;\n }\n }\n\n /**\n * Consolidate a bloated profile.md into a compact version.\n * The LLM merges duplicates, removes stale info, and preserves section structure.\n * Returns the consolidated markdown or null on failure.\n */\n async consolidateProfile(\n fullProfileContent: string,\n ): Promise<{ consolidatedProfile: string; removedCount: number; summary: string } | null> {\n const pTraceId = crypto.randomUUID();\n this.emit({ kind: \"llm_start\", traceId: pTraceId, model: this.config.model, operation: \"profile_consolidation\", input: fullProfileContent.slice(0, 2000) });\n const pStartTime = Date.now();\n\n // Try local LLM first if enabled\n if (this.config.localLlmEnabled) {\n try {\n const localResult = await this.consolidateProfileWithLocalLlm(fullProfileContent);\n if (localResult) {\n const durationMs = Date.now() - pStartTime;\n this.emit({ kind: \"llm_end\", traceId: pTraceId, model: this.config.localLlmModel, operation: \"profile_consolidation\", durationMs });\n log.debug(`profile consolidation: used local LLM — removed ${localResult.removedCount} items`);\n return localResult;\n }\n if (!this.config.localLlmFallback) {\n log.warn(\"profile consolidation: local LLM failed and fallback disabled\");\n return null;\n }\n log.info(\"profile consolidation: local LLM unavailable, falling back to gateway AI\");\n } catch (err) {\n if (!this.config.localLlmFallback) {\n log.warn(\"profile consolidation: local LLM error and fallback disabled:\", err);\n return null;\n }\n log.info(\"profile consolidation: local LLM error, falling back to gateway AI:\", err);\n }\n }\n\n const profileFallback = await this.parseWithGatewayFallback(\n pTraceId,\n \"profile_consolidation\",\n pStartTime,\n ProfileConsolidationResultSchema,\n [\n {\n role: \"system\",\n content: `You are a profile consolidation system. You are given a behavioral profile (markdown) that has grown too large. Your job is to produce a CONSOLIDATED version that:\n\n1. PRESERVES all ## section headers and their structure\n2. MERGES duplicate or near-duplicate bullet points into single, clear statements\n3. REMOVES stale information that has been superseded by newer bullets\n4. REMOVES trivial or overly specific operational details that won't be useful across sessions\n5. KEEPS the most important, durable observations about the user's preferences, habits, identity, and working style\n6. Target roughly 400 lines — this is a soft target, prioritize quality over length\n7. Write in the same style as the existing profile — concise bullets, no fluff\n\nThe output should be the COMPLETE consolidated profile as valid markdown, starting with \"# Behavioral Profile\".`,\n },\n { role: \"user\", content: fullProfileContent },\n ],\n { temperature: 0.3, maxTokens: 4096 },\n );\n if (profileFallback) {\n log.debug(\n `profile consolidation: removed ${profileFallback.removedCount} items — ${profileFallback.summary} (fallback)`,\n );\n return profileFallback;\n }\n\n // Fall back to OpenAI API\n if (!this.client) {\n log.warn(\"profile consolidation skipped — no OpenAI API key and local LLM failed/disabled\");\n return null;\n }\n\n const reasoningParam =\n this.config.reasoningEffort !== \"none\"\n ? { reasoning: { effort: this.config.reasoningEffort as \"low\" | \"medium\" | \"high\" } }\n : {};\n\n try {\n const response = await this.client.responses.parse({\n model: this.config.model,\n ...reasoningParam,\n instructions: `You are a profile consolidation system. You are given a behavioral profile (markdown) that has grown too large. Your job is to produce a CONSOLIDATED version that:\n\n1. PRESERVES all ## section headers and their structure\n2. MERGES duplicate or near-duplicate bullet points into single, clear statements\n3. REMOVES stale information that has been superseded by newer bullets\n4. REMOVES trivial or overly specific operational details that won't be useful across sessions\n5. KEEPS the most important, durable observations about the user's preferences, habits, identity, and working style\n6. Target roughly 400 lines — this is a soft target, prioritize quality over length\n7. Write in the same style as the existing profile — concise bullets, no fluff\n\nThe output should be the COMPLETE consolidated profile as valid markdown, starting with \"# Behavioral Profile\".`,\n input: fullProfileContent,\n text: {\n format: zodTextFormat(ProfileConsolidationResultSchema, \"profile_consolidation_result\"),\n },\n });\n\n const pDurationMs = Date.now() - pStartTime;\n const pUsage = (response as any).usage;\n this.emit({\n kind: \"llm_end\", traceId: pTraceId, model: this.config.model, operation: \"profile_consolidation\", durationMs: pDurationMs,\n output: response.output_parsed ? response.output_parsed.summary : undefined,\n tokenUsage: pUsage ? { input: pUsage.input_tokens, output: pUsage.output_tokens, total: pUsage.total_tokens } : undefined,\n });\n\n if (response.output_parsed) {\n log.debug(\n `profile consolidation: removed ${response.output_parsed.removedCount} items — ${response.output_parsed.summary}`,\n );\n return response.output_parsed;\n }\n\n log.warn(\"profile consolidation returned no parsed output\");\n return null;\n } catch (err) {\n this.emit({\n kind: \"llm_error\", traceId: pTraceId, model: this.config.model, operation: \"profile_consolidation\",\n durationMs: Date.now() - pStartTime, error: String(err),\n });\n log.error(\"profile consolidation failed\", err);\n return null;\n }\n }\n\n /**\n * Consolidate profile using local LLM.\n */\n private async consolidateProfileWithLocalLlm(\n fullProfileContent: string,\n ): Promise<{ consolidatedProfile: string; removedCount: number; summary: string } | null> {\n // Get dynamic context sizes\n const contextSizes = this.modelRegistry.calculateContextSizes(\n this.config.localLlmModel,\n this.config.localLlmMaxContext\n );\n log.debug(`Profile consolidation model context: ${contextSizes.description}`);\n\n const prompt = `You are a profile consolidation system. You are given a behavioral profile (markdown) that has grown too large. Your job is to produce a CONSOLIDATED version that:\n\n1. PRESERVES all ## section headers and their structure\n2. MERGES duplicate or near-duplicate bullet points into single, clear statements\n3. REMOVES stale information that has been superseded by newer bullets\n4. REMOVES trivial or overly specific operational details that won't be useful across sessions\n5. KEEPS the most important, durable observations about the user's preferences, habits, identity, and working style\n6. Target roughly 400 lines — this is a soft target, prioritize quality over length\n7. Write in the same style as the existing profile — concise bullets, no fluff\n\nProfile to consolidate:\n${fullProfileContent}\n\nRespond with valid JSON matching this schema:\n{\n \"consolidatedProfile\": \"# Behavioral Profile\\\\n\\\\n... (complete markdown)\",\n \"removedCount\": 42,\n \"summary\": \"brief summary of what was consolidated\"\n}`;\n\n const response = await this.localLlm.chatCompletion(\n [\n { role: \"system\", content: \"You are a profile consolidation system. Output valid JSON only.\" },\n { role: \"user\", content: prompt },\n ],\n { temperature: 0.3, maxTokens: contextSizes.maxOutputTokens, operation: \"profile_consolidation\" },\n );\n\n if (!response?.content) {\n return null;\n }\n\n try {\n const content = response.content.trim();\n for (const candidate of extractJsonCandidates(content)) {\n try {\n const parsed = JSON.parse(candidate);\n return {\n consolidatedProfile: String((parsed as any).consolidatedProfile || \"\"),\n removedCount: Number((parsed as any).removedCount || 0),\n summary: String((parsed as any).summary || \"\"),\n };\n } catch {\n // keep trying candidates\n }\n }\n return null;\n } catch (err) {\n log.warn(\"local LLM profile consolidation: failed to parse JSON response:\", err);\n return null;\n }\n }\n\n /**\n * Consolidate IDENTITY.md reflections into a concise \"Learned Patterns\" section.\n * Returns the new content for the IDENTITY.md file (everything below the static header).\n */\n async consolidateIdentity(\n fullIdentityContent: string,\n staticHeaderEndMarker: string,\n ): Promise<{ learnedPatterns: string[]; summary: string } | null> {\n const iTraceId = crypto.randomUUID();\n this.emit({ kind: \"llm_start\", traceId: iTraceId, model: this.config.model, operation: \"identity_consolidation\", input: fullIdentityContent.slice(0, 2000) });\n const iStartTime = Date.now();\n\n // Try local LLM first if enabled\n if (this.config.localLlmEnabled) {\n try {\n const localResult = await this.consolidateIdentityWithLocalLlm(fullIdentityContent);\n if (localResult) {\n const durationMs = Date.now() - iStartTime;\n this.emit({ kind: \"llm_end\", traceId: iTraceId, model: this.config.localLlmModel, operation: \"identity_consolidation\", durationMs });\n log.debug(`identity consolidation: used local LLM — ${localResult.learnedPatterns.length} patterns`);\n return localResult;\n }\n if (!this.config.localLlmFallback) {\n log.warn(\"identity consolidation: local LLM failed and fallback disabled\");\n return null;\n }\n log.info(\"identity consolidation: local LLM unavailable, falling back to gateway AI\");\n } catch (err) {\n if (!this.config.localLlmFallback) {\n log.warn(\"identity consolidation: local LLM error and fallback disabled:\", err);\n return null;\n }\n log.info(\"identity consolidation: local LLM error, falling back to gateway AI:\", err);\n }\n }\n\n const identityFallback = await this.parseWithGatewayFallback(\n iTraceId,\n \"identity_consolidation\",\n iStartTime,\n IdentityConsolidationResultSchema,\n [\n {\n role: \"system\",\n content: `You are an identity consolidation system. You are given the full contents of an IDENTITY.md file that contains many individual reflection entries. Your job is to:\n\n1. Read all the reflection entries (sections starting with \"## Reflection\")\n2. Extract the most important, durable behavioral patterns and lessons learned\n3. Consolidate them into concise, standalone statements (aim for 10-25 key patterns)\n4. Remove redundancy — if multiple reflections say the same thing, merge into one clear statement\n5. Prioritize patterns that are actionable and recurring over one-off observations\n6. Write a brief summary paragraph\n\nThe goal is to reduce a bloated file to a compact, high-signal set of learned patterns while preserving all genuinely useful self-knowledge.`,\n },\n { role: \"user\", content: fullIdentityContent },\n ],\n { temperature: 0.3, maxTokens: 4096 },\n );\n if (identityFallback) {\n log.debug(\n `identity consolidation: ${identityFallback.learnedPatterns.length} patterns (fallback)`,\n );\n return identityFallback;\n }\n\n // Fall back to OpenAI API\n if (!this.client) {\n log.warn(\"identity consolidation skipped — no OpenAI API key and local LLM failed/disabled\");\n return null;\n }\n\n const reasoningParam =\n this.config.reasoningEffort !== \"none\"\n ? { reasoning: { effort: this.config.reasoningEffort as \"low\" | \"medium\" | \"high\" } }\n : {};\n\n try {\n const response = await this.client.responses.parse({\n model: this.config.model,\n ...reasoningParam,\n instructions: `You are an identity consolidation system. You are given the full contents of an IDENTITY.md file that contains many individual reflection entries. Your job is to:\n\n1. Read all the reflection entries (sections starting with \"## Reflection\")\n2. Extract the most important, durable behavioral patterns and lessons learned\n3. Consolidate them into concise, standalone statements (aim for 10-25 key patterns)\n4. Remove redundancy — if multiple reflections say the same thing, merge into one clear statement\n5. Prioritize patterns that are actionable and recurring over one-off observations\n6. Write a brief summary paragraph\n\nThe goal is to reduce a bloated file to a compact, high-signal set of learned patterns while preserving all genuinely useful self-knowledge.`,\n input: fullIdentityContent,\n text: {\n format: zodTextFormat(\n IdentityConsolidationResultSchema,\n \"identity_consolidation_result\",\n ),\n },\n });\n\n const iDurationMs = Date.now() - iStartTime;\n const iUsage = (response as any).usage;\n this.emit({\n kind: \"llm_end\", traceId: iTraceId, model: this.config.model, operation: \"identity_consolidation\", durationMs: iDurationMs,\n output: response.output_parsed ? response.output_parsed.summary : undefined,\n tokenUsage: iUsage ? { input: iUsage.input_tokens, output: iUsage.output_tokens, total: iUsage.total_tokens } : undefined,\n });\n\n if (response.output_parsed) {\n log.debug(\n `identity consolidation: ${response.output_parsed.learnedPatterns.length} patterns`,\n );\n return response.output_parsed;\n }\n\n log.warn(\"identity consolidation returned no parsed output\");\n return null;\n } catch (err) {\n this.emit({\n kind: \"llm_error\", traceId: iTraceId, model: this.config.model, operation: \"identity_consolidation\",\n durationMs: Date.now() - iStartTime, error: String(err),\n });\n log.error(\"identity consolidation failed\", err);\n return null;\n }\n }\n\n /**\n * Consolidate identity using local LLM.\n */\n private async consolidateIdentityWithLocalLlm(\n fullIdentityContent: string,\n ): Promise<{ learnedPatterns: string[]; summary: string } | null> {\n // Get dynamic context sizes\n const contextSizes = this.modelRegistry.calculateContextSizes(\n this.config.localLlmModel,\n this.config.localLlmMaxContext\n );\n log.debug(`Identity consolidation model context: ${contextSizes.description}`);\n\n const prompt = `You are an identity consolidation system. You are given the full contents of an IDENTITY.md file that contains many individual reflection entries. Your job is to:\n\n1. Read all the reflection entries (sections starting with \"## Reflection\")\n2. Extract the most important, durable behavioral patterns and lessons learned\n3. Consolidate them into concise, standalone statements (aim for 10-25 key patterns)\n4. Remove redundancy — if multiple reflections say the same thing, merge into one clear statement\n5. Prioritize patterns that are actionable and recurring over one-off observations\n6. Write a brief summary paragraph\n\nThe goal is to reduce a bloated file to a compact, high-signal set of learned patterns while preserving all genuinely useful self-knowledge.\n\nIDENTITY.md content:\n${fullIdentityContent}\n\nRespond with valid JSON matching this schema:\n{\n \"learnedPatterns\": [\"pattern 1\", \"pattern 2\", \"pattern 3\"],\n \"summary\": \"brief summary of consolidation\"\n}`;\n\n const response = await this.localLlm.chatCompletion(\n [\n { role: \"system\", content: \"You are an identity consolidation system. Output valid JSON only.\" },\n { role: \"user\", content: prompt },\n ],\n { temperature: 0.3, maxTokens: contextSizes.maxOutputTokens, operation: \"identity_consolidation\" },\n );\n\n if (!response?.content) {\n return null;\n }\n\n try {\n const content = response.content.trim();\n for (const candidate of extractJsonCandidates(content)) {\n try {\n const parsed = JSON.parse(candidate);\n return {\n learnedPatterns: Array.isArray((parsed as any).learnedPatterns)\n ? (parsed as any).learnedPatterns\n : [],\n summary: String((parsed as any).summary || \"\"),\n };\n } catch {\n // keep trying candidates\n }\n }\n return null;\n } catch (err) {\n log.warn(\"local LLM identity consolidation: failed to parse JSON response:\", err);\n return null;\n }\n }\n\n /**\n * Verify if two memories contradict each other using LLM.\n * Called when QMD finds semantically similar memories (Phase 2B).\n */\n async verifyContradiction(\n newMemory: { content: string; category: string },\n existingMemory: { id: string; content: string; category: string; created: string },\n ): Promise<ContradictionVerificationResult | null> {\n if (!this.client) {\n log.warn(\"contradiction verification skipped — no OpenAI API key\");\n return null;\n }\n\n const input = `Memory 1 (existing, created ${existingMemory.created}):\nCategory: ${existingMemory.category}\nContent: ${existingMemory.content}\n\nMemory 2 (new):\nCategory: ${newMemory.category}\nContent: ${newMemory.content}`;\n\n try {\n const response = await this.client.responses.parse({\n model: this.config.model,\n instructions: `You are a contradiction detection system. Analyze whether two memories contradict each other.\n\nIMPORTANT: Not all similar memories are contradictions!\n- \"User likes TypeScript\" and \"User likes Python\" are NOT contradictions (preferences can coexist)\n- \"User prefers dark mode\" and \"User prefers light mode\" ARE contradictions (mutually exclusive)\n- \"User's email is a@b.com\" and \"User's email is c@d.com\" ARE contradictions (only one email)\n- \"User works at Acme\" and \"User used to work at Acme\" might be a contradiction (temporal change)\n\nOnly mark as contradiction if the two statements CANNOT both be true at the same time.\n\nIf they ARE contradictory, determine which represents the more recent/current state based on:\n- Explicit time references (\"now\", \"currently\", \"used to\", \"no longer\")\n- The fact that newer corrections often start with \"actually\" or \"correction\"\n- Context clues about change over time`,\n input,\n text: {\n format: zodTextFormat(ContradictionVerificationSchema, \"contradiction_verification\"),\n },\n });\n\n if (response.output_parsed) {\n log.debug(\n `contradiction check: ${response.output_parsed.isContradiction ? \"YES\" : \"NO\"} (confidence: ${response.output_parsed.confidence})`,\n );\n return response.output_parsed as ContradictionVerificationResult;\n }\n\n return null;\n } catch (err) {\n log.error(\"contradiction verification failed\", err);\n return null;\n }\n }\n\n /**\n * Suggest links between a new memory and existing memories (Phase 3A).\n * Called during extraction to build the knowledge graph.\n */\n async suggestLinks(\n newMemory: { content: string; category: string },\n candidateMemories: Array<{ id: string; content: string; category: string }>,\n ): Promise<SuggestedLinks | null> {\n if (!this.client) {\n log.warn(\"link suggestion skipped — no OpenAI API key\");\n return null;\n }\n\n if (candidateMemories.length === 0) {\n return { links: [] };\n }\n\n const candidateList = candidateMemories\n .map((m, i) => `[${i + 1}] ID: ${m.id}\\nCategory: ${m.category}\\nContent: ${m.content}`)\n .join(\"\\n\\n\");\n\n const input = `New memory:\nCategory: ${newMemory.category}\nContent: ${newMemory.content}\n\nCandidate memories to link to:\n${candidateList}`;\n\n try {\n const response = await this.client.responses.parse({\n model: this.config.model,\n instructions: `You are a memory linking system. Analyze the new memory and suggest relationships to existing memories.\n\nLink types:\n- follows: This memory is a continuation or next step (e.g., decision follows discussion)\n- references: This memory mentions or refers to the other (e.g., fact references entity)\n- contradicts: This memory conflicts with the other (use sparingly, only for true contradictions)\n- supports: This memory provides evidence or reinforcement (e.g., example supports principle)\n- related: General topical relationship\n\nRules:\n- Only suggest links with strength > 0.5\n- Quality over quantity — 0-3 links is typical\n- Prefer specific link types over generic \"related\"\n- Consider entity references, topics, and causal relationships`,\n input,\n text: {\n format: zodTextFormat(SuggestedLinksSchema, \"suggested_links\"),\n },\n });\n\n if (response.output_parsed) {\n log.debug(`suggested ${response.output_parsed.links.length} links`);\n return response.output_parsed as SuggestedLinks;\n }\n\n return { links: [] };\n } catch (err) {\n log.error(\"link suggestion failed\", err);\n return { links: [] };\n }\n }\n\n /**\n * Summarize a batch of old memories into a compact summary (Phase 4A).\n */\n async summarizeMemories(\n memories: Array<{ id: string; content: string; category: string; created: string }>,\n ): Promise<MemorySummaryResult | null> {\n if (!this.client) {\n log.warn(\"summarization skipped — no OpenAI API key\");\n return null;\n }\n\n if (memories.length === 0) return null;\n\n const memoryList = memories\n .map((m) => `[${m.id}] (${m.category}, ${m.created.slice(0, 10)})\\n${m.content}`)\n .join(\"\\n\\n\");\n\n try {\n const response = await this.client.responses.parse({\n model: this.config.model,\n instructions: `You are a memory summarization system. You are given a batch of old memories that need to be compressed into a summary.\n\nYour task:\n1. Write a concise summary paragraph (2-4 sentences) capturing the essence of these memories\n2. Extract the 5-10 most important facts that should be preserved\n3. List the key entities mentioned\n\nGuidelines:\n- Preserve specific, actionable information\n- Merge redundant details into single statements\n- Focus on durable insights, not transient details\n- Maintain any preferences, decisions, or corrections as key facts`,\n input: `Summarize these ${memories.length} memories:\\n\\n${memoryList}`,\n text: {\n format: zodTextFormat(MemorySummarySchema, \"memory_summary\"),\n },\n });\n\n if (response.output_parsed) {\n log.debug(`summarized ${memories.length} memories into ${response.output_parsed.keyFacts.length} key facts`);\n return response.output_parsed as MemorySummaryResult;\n }\n\n return null;\n } catch (err) {\n log.error(\"memory summarization failed\", err);\n return null;\n }\n }\n}\n","import { log } from \"./logger.js\";\nimport type { PluginConfig } from \"./types.js\";\nimport { execSync, spawnSync } from \"node:child_process\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport os from \"node:os\";\nimport type { ModelRegistry } from \"./model-registry.js\";\n\n/**\n * Local LLM client for OpenAI-compatible endpoints (LM Studio, Ollama, MLX, etc.)\n *\n * Based on openclaw-tactician's provider detection patterns for consistency.\n * Provides privacy-preserving, cost-effective LLM operations with\n * graceful fallback to cloud providers when local LLM is unavailable.\n */\nexport type LocalLlmType = \"lmstudio\" | \"ollama\" | \"mlx\" | \"vllm\" | \"generic\";\n\ninterface LocalServerConfig {\n type: LocalLlmType;\n defaultPort: number;\n healthEndpoint: string;\n modelsEndpoint: string;\n detectFn: (response: unknown) => boolean;\n}\n\nconst LOCAL_SERVERS: LocalServerConfig[] = [\n {\n type: \"ollama\",\n defaultPort: 11434,\n healthEndpoint: \"/\",\n modelsEndpoint: \"/api/tags\",\n detectFn: (resp) => typeof resp === \"string\" && resp.includes(\"Ollama\"),\n },\n {\n type: \"mlx\",\n defaultPort: 8080,\n healthEndpoint: \"/v1/models\",\n modelsEndpoint: \"/v1/models\",\n detectFn: (resp) =>\n typeof resp === \"object\" &&\n resp !== null &&\n \"data\" in resp &&\n Array.isArray((resp as { data: unknown[] }).data),\n },\n {\n type: \"lmstudio\",\n defaultPort: 1234,\n healthEndpoint: \"/v1/models\",\n modelsEndpoint: \"/v1/models\",\n detectFn: (resp) =>\n typeof resp === \"object\" &&\n resp !== null &&\n \"data\" in resp &&\n Array.isArray((resp as { data: unknown[] }).data),\n },\n {\n type: \"vllm\",\n defaultPort: 8000,\n healthEndpoint: \"/health\",\n modelsEndpoint: \"/v1/models\",\n detectFn: (resp) => resp === \"\" || (typeof resp === \"object\" && resp !== null),\n },\n];\n\nexport interface LocalModelInfo {\n id: string;\n contextWindow?: number;\n maxTokens?: number;\n}\n\nexport class LocalLlmClient {\n private config: PluginConfig;\n private isAvailable: boolean | null = null;\n private lastHealthCheck: number = 0;\n private detectedType: LocalLlmType | null = null;\n private cachedModelInfo: LocalModelInfo | null = null;\n private cachedLmsContext: number | null = null;\n private lastLmsCheck: number = 0;\n private consecutive400s: number = 0;\n private cooldownUntilMs: number = 0;\n private modelRegistry?: ModelRegistry;\n private static readonly HEALTH_CHECK_INTERVAL_MS = 60000; // 1 minute\n private static readonly LMS_CACHE_INTERVAL_MS = 30000; // 30 seconds\n\n constructor(config: PluginConfig, modelRegistry?: ModelRegistry) {\n this.config = config;\n this.modelRegistry = modelRegistry;\n }\n\n private resolveHomeDir(): string {\n return this.config.localLlmHomeDir || process.env.HOME || os.homedir();\n }\n\n private buildRequestHeaders(base: Record<string, string> = {}): Record<string, string> {\n const headers: Record<string, string> = {\n ...base,\n ...(this.config.localLlmHeaders ?? {}),\n };\n if (this.config.localLlmApiKey && this.config.localLlmAuthHeader !== false) {\n headers.Authorization = `Bearer ${this.config.localLlmApiKey}`;\n }\n return headers;\n }\n\n private isAbortError(err: unknown): boolean {\n if (!err || typeof err !== \"object\") return false;\n const maybe = err as { name?: string; message?: string };\n return (\n maybe.name === \"AbortError\" ||\n maybe.message === \"This operation was aborted\" ||\n maybe.message === \"The operation was aborted\"\n );\n }\n\n /**\n * Set the ModelRegistry for caching detected capabilities\n */\n setModelRegistry(registry: ModelRegistry): void {\n this.modelRegistry = registry;\n }\n\n /**\n * Get the detected server type (null if not detected)\n */\n getDetectedType(): LocalLlmType | null {\n return this.detectedType;\n }\n\n /**\n * Fetch with timeout for health checks\n */\n private async fetchWithTimeout(\n url: string,\n timeoutMs: number = 2000,\n headers?: Record<string, string>,\n ): Promise<{ ok: boolean; data: unknown }> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), timeoutMs);\n\n try {\n const response = await fetch(url, {\n signal: controller.signal,\n headers: this.buildRequestHeaders({ Accept: \"application/json\", ...(headers ?? {}) }),\n });\n clearTimeout(timeout);\n\n if (!response.ok) {\n return { ok: false, data: null };\n }\n\n const contentType = response.headers.get(\"content-type\");\n if (contentType?.includes(\"application/json\")) {\n return { ok: true, data: await response.json() };\n } else {\n return { ok: true, data: await response.text() };\n }\n } catch (err) {\n clearTimeout(timeout);\n return { ok: false, data: null };\n }\n }\n\n /**\n * Check if local LLM is available\n * Uses 127.0.0.1 instead of localhost to avoid DNS issues (consistent with tactician)\n */\n async checkAvailability(): Promise<boolean> {\n // Cache health check results for 1 minute\n const now = Date.now();\n if (this.isAvailable !== null && now - this.lastHealthCheck < LocalLlmClient.HEALTH_CHECK_INTERVAL_MS) {\n return this.isAvailable;\n }\n\n // Normalize URL - replace localhost with 127.0.0.1, remove trailing slashes\n const baseUrl = this.config.localLlmUrl\n .replace(\"localhost\", \"127.0.0.1\")\n .replace(/\\/+$/, \"\");\n\n // Try to detect which server type is running\n for (const serverConfig of LOCAL_SERVERS) {\n const healthUrl = `${baseUrl}${serverConfig.healthEndpoint}`;\n log.debug(`checking ${serverConfig.type} at ${healthUrl}`);\n\n const result = await this.fetchWithTimeout(healthUrl);\n if (result.ok && serverConfig.detectFn(result.data)) {\n this.isAvailable = true;\n this.detectedType = serverConfig.type;\n this.lastHealthCheck = now;\n log.info(`detected ${serverConfig.type} at ${baseUrl}`);\n return true;\n }\n }\n\n // Generic check if specific detection failed\n try {\n const modelsUrl = `${baseUrl}/v1/models`;\n const result = await this.fetchWithTimeout(modelsUrl);\n if (result.ok) {\n this.isAvailable = true;\n this.detectedType = \"generic\";\n this.lastHealthCheck = now;\n log.info(`detected generic OpenAI-compatible server at ${baseUrl}`);\n return true;\n }\n } catch {\n // Fall through to unavailable\n }\n\n this.isAvailable = false;\n this.detectedType = null;\n this.lastHealthCheck = now;\n log.debug(\"local LLM not available at\", baseUrl);\n return false;\n }\n\n /**\n * Try to get context window from LM Studio settings.json as fallback.\n * This reads the defaultContextLength setting which is what LM Studio uses\n * when loading models without explicit context configuration.\n */\n private getContextFromLmStudioSettings(): number | null {\n try {\n const homeDir = this.resolveHomeDir();\n const settingsPath = `${homeDir}/.cache/lm-studio/settings.json`;\n\n if (!existsSync(settingsPath)) {\n log.debug(`LM Studio settings: file not found at ${settingsPath}`);\n return null;\n }\n\n const content = readFileSync(settingsPath, \"utf-8\");\n const settings = JSON.parse(content) as {\n defaultContextLength?: {\n type?: string;\n value?: number;\n };\n };\n\n if (settings.defaultContextLength?.value) {\n const contextWindow = settings.defaultContextLength.value;\n log.debug(`LM Studio settings: found default context length: ${contextWindow}`);\n return contextWindow;\n }\n\n return null;\n } catch (err) {\n const errorMsg = err instanceof Error ? err.message : String(err);\n log.debug(`LM Studio settings: failed to read - ${errorMsg}`);\n return null;\n }\n }\n\n /**\n * Try to get context window from LMS CLI (LM Studio specific).\n * Uses --json flag for reliable parsing.\n * Returns null if LMS CLI is not available or model not found.\n */\n private getContextFromLmsCli(modelId: string): number | null {\n try {\n // Check if lms CLI exists in common locations\n // Note: process.env.HOME may not be set in launchd environment\n const homeDir = this.resolveHomeDir();\n const lmsPaths = [\n this.config.localLmsCliPath || \"\",\n `${homeDir}/.cache/lm-studio/bin/lms`,\n \"/usr/local/bin/lms\",\n \"/opt/homebrew/bin/lms\",\n ];\n\n const lmsPath = lmsPaths.find((p) => p.length > 0 && existsSync(p));\n if (!lmsPath) {\n log.debug(`LMS CLI: not found in standard locations (checked: ${lmsPaths.join(\", \")})`);\n return null;\n }\n\n // Run lms ps --json to get loaded models with context\n // Use spawnSync with shell and explicit PATH to ensure lms can find its dependencies\n log.debug(`LMS CLI: running: ${lmsPath} ps --json`);\n const result = spawnSync(lmsPath, [\"ps\", \"--json\"], {\n encoding: \"utf-8\",\n timeout: 5000,\n shell: false, // Don't use shell for JSON output - more reliable\n env: {\n ...process.env,\n PATH: `${this.config.localLmsBinDir || `${homeDir}/.cache/lm-studio/bin`}:/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin:${process.env.PATH || \"\"}`,\n HOME: homeDir,\n },\n });\n\n if (result.error) {\n log.debug(`LMS CLI: spawn error - ${result.error.message}`);\n return null;\n }\n\n if (result.stderr && result.stderr.trim()) {\n log.debug(`LMS CLI: stderr - ${result.stderr.slice(0, 200)}`);\n }\n\n const output = result.stdout || \"\";\n if (!output.trim()) {\n log.debug(\"LMS CLI: empty output - LM Studio may not be running or no models loaded\");\n return null;\n }\n\n // Parse JSON output\n let models: Array<{\n identifier?: string;\n modelKey?: string;\n contextLength?: number;\n maxContextLength?: number;\n }>;\n\n try {\n models = JSON.parse(output) as typeof models;\n } catch (parseErr) {\n log.debug(`LMS CLI: JSON parse error - ${parseErr}`);\n return null;\n }\n\n if (!Array.isArray(models) || models.length === 0) {\n log.debug(\"LMS CLI: no models loaded\");\n return null;\n }\n\n // Find the model matching our configured model ID\n const model = models.find((m) =>\n m.identifier === modelId ||\n m.modelKey === modelId ||\n (m.identifier?.includes(modelId.replace(/@\\d+bit$/, \"\")))\n );\n\n if (!model) {\n log.debug(`LMS CLI: model \"${modelId}\" not found in loaded models: ${models.map(m => m.identifier).join(\", \")}`);\n return null;\n }\n\n // Use contextLength (actual configured) or fall back to maxContextLength (model max)\n const contextWindow = model.contextLength || model.maxContextLength;\n\n if (contextWindow) {\n log.info(`LMS CLI detected context window: ${contextWindow} for ${modelId} (max: ${model.maxContextLength})`);\n return contextWindow;\n }\n\n return null;\n } catch (err) {\n // LMS CLI not available or failed\n const errorMsg = err instanceof Error ? err.message : String(err);\n log.debug(`LMS CLI: failed - ${errorMsg}`);\n return null;\n }\n }\n\n /**\n * Get full model info from LMS CLI including context length and max context length.\n * Returns null if LMS CLI is unavailable or model not found.\n */\n private getLmsModelInfo(modelId: string): { contextLength: number; maxContextLength: number; identifier: string } | null {\n try {\n const result = spawnSync(\"lms\", [\"ps\", \"--json\"], {\n encoding: \"utf-8\",\n timeout: 5000,\n shell: false,\n });\n\n if (result.error) {\n return null;\n }\n\n const output = result.stdout || \"\";\n if (!output.trim()) {\n return null;\n }\n\n let models: Array<{\n identifier?: string;\n modelKey?: string;\n contextLength?: number;\n maxContextLength?: number;\n }>;\n\n try {\n models = JSON.parse(output) as typeof models;\n } catch {\n return null;\n }\n\n if (!Array.isArray(models) || models.length === 0) {\n return null;\n }\n\n const model = models.find((m) =>\n m.identifier === modelId ||\n m.modelKey === modelId ||\n (m.identifier?.includes(modelId.replace(/@\\d+bit$/, \"\")))\n );\n\n if (!model || !model.contextLength) {\n return null;\n }\n\n return {\n contextLength: model.contextLength,\n maxContextLength: model.maxContextLength || model.contextLength,\n identifier: model.identifier || modelId,\n };\n } catch {\n return null;\n }\n }\n\n /**\n * Get context window for the configured model, using cache if available.\n * This method caches the result to avoid repeated LMS CLI calls.\n * Order: ModelRegistry (persistent) -> memory cache -> LMS CLI -> settings.json\n */\n getCachedContextWindow(modelId: string): number | null {\n const now = Date.now();\n\n // 1. Check ModelRegistry for persisted context window\n if (this.modelRegistry) {\n const caps = this.modelRegistry.getCapabilities(modelId);\n if (caps.source === \"lmstudio\" && caps.contextWindow) {\n log.debug(`ModelRegistry: using persisted LM Studio context: ${caps.contextWindow}`);\n // Also update memory cache\n this.cachedLmsContext = caps.contextWindow;\n this.lastLmsCheck = now;\n return caps.contextWindow;\n }\n }\n\n // 2. Return in-memory cached value if still valid\n if (this.cachedLmsContext && now - this.lastLmsCheck < LocalLlmClient.LMS_CACHE_INTERVAL_MS) {\n log.debug(`LMS CLI: returning in-memory cached context: ${this.cachedLmsContext}`);\n return this.cachedLmsContext;\n }\n\n // 3. Try LMS CLI (authoritative source)\n const lmsInfo = this.getLmsModelInfo(modelId);\n if (lmsInfo?.contextLength) {\n this.cachedLmsContext = lmsInfo.contextLength;\n this.lastLmsCheck = now;\n // Calculate appropriate output tokens based on context size\n // Use 12.5% of context window, capped at 16K (generous but safe)\n const calculatedOutputTokens = Math.min(Math.floor(lmsInfo.contextLength / 8), 16384);\n const outputTokens = Math.max(calculatedOutputTokens, 4096); // Minimum 4K\n // Persist to ModelRegistry with detected capabilities\n if (this.modelRegistry) {\n this.modelRegistry.setCapabilities(modelId, {\n maxPositionEmbeddings: lmsInfo.maxContextLength || lmsInfo.contextLength,\n contextWindow: lmsInfo.contextLength,\n supportsExtendedContext: (lmsInfo.maxContextLength || lmsInfo.contextLength) > 65536,\n typicalOutputTokens: outputTokens,\n source: \"lmstudio\",\n });\n log.info(`LMS CLI: Stored capabilities for ${modelId}: ${lmsInfo.contextLength} context, ${outputTokens} output tokens`);\n }\n return lmsInfo.contextLength;\n }\n\n // Legacy: Try LMS CLI context only (fallback)\n const legacyContext = this.getContextFromLmsCli(modelId);\n if (legacyContext) {\n this.cachedLmsContext = legacyContext;\n this.lastLmsCheck = now;\n // Persist to ModelRegistry with calculated output tokens\n if (this.modelRegistry) {\n const calculatedOutputTokens = Math.min(Math.floor(legacyContext / 8), 16384);\n const outputTokens = Math.max(calculatedOutputTokens, 4096);\n this.modelRegistry.setCapabilities(modelId, {\n maxPositionEmbeddings: legacyContext,\n contextWindow: legacyContext,\n supportsExtendedContext: false,\n typicalOutputTokens: outputTokens,\n source: \"lmstudio\",\n });\n }\n return legacyContext;\n }\n\n // 4. Fall back to LM Studio settings.json\n const settingsContext = this.getContextFromLmStudioSettings();\n if (settingsContext) {\n log.info(`LM Studio settings: using default context: ${settingsContext}`);\n this.cachedLmsContext = settingsContext;\n this.lastLmsCheck = now;\n return settingsContext;\n }\n\n return null;\n }\n\n /**\n * Clear the LMS context cache. Call this when the model changes.\n */\n clearContextCache(): void {\n this.cachedLmsContext = null;\n this.lastLmsCheck = 0;\n log.debug(\"LMS CLI: context cache cleared\");\n }\n\n /**\n * Query the local LLM server for loaded model information.\n * Returns null if unavailable or if the model is not found.\n */\n async getLoadedModelInfo(): Promise<LocalModelInfo | null> {\n const baseUrl = this.config.localLlmUrl\n .replace(\"localhost\", \"127.0.0.1\")\n .replace(/\\/+$/, \"\");\n\n // Handle URL construction - localLlmUrl may already include /v1\n const modelsUrl = baseUrl.endsWith(\"/v1\")\n ? `${baseUrl}/models`\n : `${baseUrl}/v1/models`;\n log.info(`Fetching model info from ${modelsUrl}`);\n\n try {\n const result = await this.fetchWithTimeout(modelsUrl, 3000);\n if (!result.ok) {\n log.warn(`Local LLM: Failed to fetch models from ${modelsUrl} - server returned error`);\n return null;\n }\n if (!result.data) {\n log.warn(`Local LLM: No data returned from ${modelsUrl}`);\n return null;\n }\n\n const data = result.data as {\n data?: Array<{\n id?: string;\n object?: string;\n owned_by?: string;\n // LM Studio specific fields\n max_context_length?: number;\n max_tokens?: number;\n // Ollama specific\n name?: string;\n details?: {\n parameter_size?: string;\n family?: string;\n };\n }>;\n };\n\n if (!Array.isArray(data.data) || data.data.length === 0) {\n log.warn(\"Local LLM returned no models\");\n return null;\n }\n\n // Verbose model listings are noisy on every gateway restart. Keep it debug-only.\n const modelIds = data.data.map((m) => m.id).filter(Boolean);\n log.debug(\n `Local LLM: Found ${modelIds.length} model(s). First 10: ${modelIds.slice(0, 10).join(\", \")}`,\n );\n\n // Find the model matching our configured model ID\n const configuredModel = this.config.localLlmModel;\n let model = data.data.find((m) => m.id === configuredModel);\n\n // If not found by exact match, try partial match (handle suffixes like @4bit)\n if (!model) {\n model = data.data.find((m) =>\n configuredModel.includes(m.id || \"\") ||\n (m.id || \"\").includes(configuredModel.replace(/@\\d+bit$/, \"\"))\n );\n }\n\n // If still not found, use the first loaded model and warn\n if (!model) {\n model = data.data[0];\n const availablePreview = data.data\n .map((m) => m.id)\n .filter(Boolean)\n .slice(0, 10)\n .join(\", \");\n log.warn(\n `Configured model \"${configuredModel}\" not found in local LLM. ` +\n `Using \"${model.id}\" instead. Available (first 10): ${availablePreview}`\n );\n }\n\n // Extract context window - try multiple field names\n let contextWindow = model.max_context_length || model.max_tokens;\n\n // If API doesn't report context window, try LMS CLI (LM Studio specific)\n if (!contextWindow) {\n log.info(\"Local LLM: API did not report context window, trying LMS CLI...\");\n const lmsContext = this.getCachedContextWindow(model.id || \"\");\n if (lmsContext) {\n contextWindow = lmsContext;\n }\n }\n\n this.cachedModelInfo = {\n id: model.id || \"unknown\",\n contextWindow: contextWindow,\n maxTokens: model.max_tokens,\n };\n\n log.info(\n `Local LLM model detected: ${this.cachedModelInfo.id}, ` +\n `context window: ${contextWindow?.toLocaleString() || \"unknown (may use default)\"}`\n );\n\n return this.cachedModelInfo;\n } catch (err) {\n log.warn(`Failed to fetch model info: ${err}`);\n return null;\n }\n }\n\n /**\n * Check if the configured model is available and get its actual context window.\n * Warns if there's a mismatch between expected and actual context.\n */\n async validateModelConfig(expectedContextWindow?: number): Promise<{\n available: boolean;\n actualContextWindow?: number;\n warnings: string[];\n }> {\n const warnings: string[] = [];\n\n const modelInfo = await this.getLoadedModelInfo();\n if (!modelInfo) {\n return { available: false, warnings: [\"Could not query local LLM for model info\"] };\n }\n\n // If we have expected context and the server reports one, check for mismatch\n if (expectedContextWindow && modelInfo.contextWindow) {\n if (modelInfo.contextWindow < expectedContextWindow) {\n warnings.push(\n `Context window mismatch: Model ${modelInfo.id} supports ${modelInfo.contextWindow.toLocaleString()} tokens, ` +\n `but engram is configured for ${expectedContextWindow.toLocaleString()}. ` +\n `Set localLlmMaxContext: ${modelInfo.contextWindow} in config to avoid errors.`\n );\n }\n }\n\n // Warn if server doesn't report context window (common with some local LLM setups)\n if (!modelInfo.contextWindow) {\n warnings.push(\n `Local LLM server did not report context window for ${modelInfo.id}. ` +\n `If you get \"context length exceeded\" errors, set localLlmMaxContext in config.`\n );\n }\n\n return {\n available: true,\n actualContextWindow: modelInfo.contextWindow,\n warnings,\n };\n }\n\n /**\n * Make a chat completion request to local LLM\n */\n async chatCompletion(\n messages: Array<{ role: string; content: string }>,\n options: {\n temperature?: number;\n maxTokens?: number;\n responseFormat?: { type: string };\n timeoutMs?: number;\n operation?: string;\n } = {}\n ): Promise<{\n content: string;\n usage?: { promptTokens: number; completionTokens: number; totalTokens: number };\n } | null> {\n log.debug(\n `local LLM chatCompletion: localLlmEnabled=${this.config.localLlmEnabled}, model=${this.config.localLlmModel}`,\n );\n if (!this.config.localLlmEnabled) {\n log.debug(\"local LLM: disabled, returning null\");\n return null;\n }\n\n const now = Date.now();\n if (this.cooldownUntilMs > now) {\n const remainingMs = this.cooldownUntilMs - now;\n log.debug(`local LLM: cooldown active (${remainingMs}ms remaining), skipping request`);\n return null;\n }\n\n const isAvailable = await this.checkAvailability();\n if (!isAvailable) {\n log.debug(\n `local LLM: checkAvailability returned false for ${this.config.localLlmUrl}`,\n );\n return null;\n }\n\n try {\n const startedAtMs = Date.now();\n const promptChars = messages.reduce((sum, m) => sum + (m.content?.length ?? 0), 0);\n const operation = options.operation ?? \"unspecified\";\n const requestBody: Record<string, unknown> = {\n model: this.config.localLlmModel,\n messages,\n temperature: options.temperature ?? 0.7,\n // Use max_tokens consistent with cloud models\n max_tokens: options.maxTokens ?? 4096,\n };\n\n // Skip response_format for local LLMs - they don't support json_object type\n // The prompts already instruct the model to output JSON\n // Only send if it's json_schema type which some local LLMs support\n if (options.responseFormat?.type === \"json_schema\") {\n requestBody.response_format = options.responseFormat;\n }\n\n // Normalize URL (use 127.0.0.1 instead of localhost)\n const baseUrl = this.config.localLlmUrl\n .replace(\"localhost\", \"127.0.0.1\")\n .replace(/\\/+$/, \"\");\n const chatUrl = `${baseUrl}/chat/completions`;\n\n const requestBodyJson = JSON.stringify(requestBody);\n log.debug(\n `local LLM: sending request to ${chatUrl} with model ${this.config.localLlmModel}`,\n );\n // Avoid logging request bodies by default (can contain sensitive user content).\n log.debug(`local LLM: request body length=${requestBodyJson.length}`);\n\n // Write request body to file for debugging\n if (this.config.debug) {\n try {\n const { writeFileSync } = await import(\"node:fs\");\n writeFileSync(\"/tmp/engram-last-request.json\", requestBodyJson);\n } catch {\n /* ignore */\n }\n }\n\n const effectiveTimeoutMs =\n typeof options.timeoutMs === \"number\"\n ? Math.min(this.config.localLlmTimeoutMs, options.timeoutMs)\n : this.config.localLlmTimeoutMs;\n const maxAttempts = 1 + Math.max(0, this.config.localLlmRetry5xxCount);\n let response: Response | null = null;\n let lastAbortError: Error | null = null;\n for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {\n const attemptAbort = new AbortController();\n const attemptTimeout = setTimeout(() => attemptAbort.abort(), effectiveTimeoutMs);\n try {\n response = await fetch(chatUrl, {\n method: \"POST\",\n headers: this.buildRequestHeaders({\n \"Content-Type\": \"application/json\",\n }),\n body: JSON.stringify(requestBody),\n signal: attemptAbort.signal,\n });\n } catch (err) {\n if (!this.isAbortError(err)) throw err;\n lastAbortError = err instanceof Error ? err : new Error(String(err));\n if (attempt < maxAttempts) {\n const backoffMs = this.config.localLlmRetryBackoffMs * attempt;\n log.warn(\n `local LLM request aborted: op=${operation} attempt=${attempt}/${maxAttempts} timeoutMs=${effectiveTimeoutMs} model=${this.config.localLlmModel}; retrying after ${backoffMs}ms`,\n );\n await new Promise((resolve) => setTimeout(resolve, backoffMs));\n continue;\n }\n break;\n } finally {\n clearTimeout(attemptTimeout);\n }\n\n if (response.ok) break;\n if (response.status < 500 || attempt >= maxAttempts) break;\n\n const backoffMs = this.config.localLlmRetryBackoffMs * attempt;\n log.warn(\n `local LLM request got ${response.status}; retrying (attempt ${attempt + 1}/${maxAttempts}) after ${backoffMs}ms`,\n );\n await new Promise((resolve) => setTimeout(resolve, backoffMs));\n }\n log.debug(\n `local LLM: received response, status=${response?.status}, ok=${response?.ok}`,\n );\n\n if (!response) {\n if (lastAbortError) {\n log.warn(\n `local LLM request aborted after ${maxAttempts} attempt(s): op=${operation} timeoutMs=${effectiveTimeoutMs} model=${this.config.localLlmModel} promptChars=${promptChars} durationMs=${Date.now() - startedAtMs}`,\n );\n } else {\n log.warn(\n `local LLM request failed: no response object (op=${operation} model=${this.config.localLlmModel} durationMs=${Date.now() - startedAtMs})`,\n );\n }\n return null;\n }\n\n if (!response.ok) {\n let reason = \"\";\n try {\n const errorText = await response.text();\n // Try to extract a stable error message without logging content.\n try {\n const parsed = JSON.parse(errorText) as { error?: { message?: string } };\n reason = parsed?.error?.message ? ` — ${parsed.error.message}` : \"\";\n } catch {\n // Keep a short preview in debug only.\n log.debug(`local LLM error body: ${errorText.slice(0, 500)}`);\n }\n } catch (e) {\n log.debug(`local LLM failed to read error body: ${e}`);\n }\n log.warn(\n `local LLM request failed: ${response.status} ${response.statusText}${reason} ` +\n `(op=${operation}, model=${this.config.localLlmModel}, url=${chatUrl}, promptChars=${promptChars}, maxTokens=${requestBody.max_tokens as number})`,\n );\n if (response.status === 400) {\n this.consecutive400s += 1;\n if (this.consecutive400s >= this.config.localLlm400TripThreshold) {\n this.cooldownUntilMs = Date.now() + this.config.localLlm400CooldownMs;\n log.warn(\n `local LLM: entering cooldown for ${this.config.localLlm400CooldownMs}ms ` +\n `after ${this.consecutive400s} consecutive 400 responses`,\n );\n this.consecutive400s = 0;\n }\n } else {\n this.consecutive400s = 0;\n }\n return null;\n }\n this.consecutive400s = 0;\n\n const data = (await response.json()) as {\n choices?: Array<{\n message?: { content?: string };\n }>;\n usage?: {\n prompt_tokens?: number;\n completion_tokens?: number;\n total_tokens?: number;\n };\n };\n\n log.debug(\n `local LLM response: choices=${data.choices?.length}, usage=${JSON.stringify(data.usage)}`,\n );\n\n const content = data.choices?.[0]?.message?.content;\n if (!content) {\n log.warn(`local LLM returned empty content. choices=${JSON.stringify(data.choices)?.slice(0, 200)}`);\n return null;\n }\n\n // Estimate tokens if not provided by local LLM\n const usage = data.usage\n ? {\n promptTokens: data.usage.prompt_tokens ?? 0,\n completionTokens: data.usage.completion_tokens ?? 0,\n totalTokens: data.usage.total_tokens ?? 0,\n }\n : this.estimateTokens(messages, content);\n\n const durationMs = Date.now() - startedAtMs;\n if (this.config.slowLogEnabled && durationMs >= this.config.slowLogThresholdMs) {\n const promptChars = messages.reduce((sum, m) => sum + (m.content?.length ?? 0), 0);\n const op = options.operation ? ` op=${options.operation}` : \"\";\n log.warn(\n `SLOW local LLM:${op} durationMs=${durationMs} model=${this.config.localLlmModel} url=${chatUrl} promptChars=${promptChars} outputTokens=${usage.completionTokens} totalTokens=${usage.totalTokens}`,\n );\n }\n\n log.debug(\"local LLM: request succeeded, tokens:\", usage.totalTokens);\n return { content, usage };\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n const durationMs = Date.now() - now;\n const operation = options.operation ?? \"unspecified\";\n if (this.isAbortError(err)) {\n log.warn(\n `local LLM request aborted: op=${operation} timeoutMs=${options.timeoutMs ?? this.config.localLlmTimeoutMs} model=${this.config.localLlmModel} durationMs=${durationMs} error=${errMsg}`,\n );\n return null;\n }\n log.warn(`local LLM request error: op=${operation} error=${errMsg}`);\n this.isAvailable = false; // Mark as unavailable on non-abort errors\n return null;\n }\n }\n\n /**\n * Estimate tokens when local LLM doesn't return usage stats\n * Rough estimate: 1 token ≈ 4 characters\n */\n private estimateTokens(\n messages: Array<{ role: string; content: string }>,\n response: string\n ): { promptTokens: number; completionTokens: number; totalTokens: number } {\n const promptChars = messages.reduce((sum, m) => sum + m.content.length, 0);\n const promptTokens = Math.ceil(promptChars / 4);\n const completionTokens = Math.ceil(response.length / 4);\n\n return {\n promptTokens,\n completionTokens,\n totalTokens: promptTokens + completionTokens,\n };\n }\n\n /**\n * Try local LLM first, fallback to cloud provider if configured\n */\n async withFallback<T>(\n localOperation: () => Promise<T | null>,\n fallbackOperation: () => Promise<T>,\n operationName: string\n ): Promise<T> {\n // Try local LLM first if enabled\n if (this.config.localLlmEnabled) {\n const localResult = await localOperation();\n if (localResult !== null) {\n log.debug(`${operationName}: used local LLM`);\n return localResult;\n }\n\n // Local failed or unavailable\n if (this.config.localLlmFallback) {\n log.info(`${operationName}: local LLM unavailable, falling back to cloud`);\n } else {\n throw new Error(`${operationName}: local LLM unavailable and fallback disabled`);\n }\n }\n\n // Use fallback (cloud provider)\n return fallbackOperation();\n }\n}\n","/**\n * Utilities for extracting JSON payloads from LLM outputs.\n *\n * We see common failure modes:\n * - \"Here's an example: {..}\\nHere's the real answer: {..}\" (multiple JSON blocks)\n * - fenced ```json blocks\n * - leading/trailing prose around JSON\n *\n * These helpers attempt multiple candidates and let callers validate with schemas.\n */\n\nexport function stripCodeFences(text: string): string {\n return text.replace(/```(?:json)?\\s*([\\s\\S]*?)```/gi, (_m, inner) => String(inner).trim());\n}\n\nexport function extractJsonCandidates(text: string): string[] {\n const trimmed = text.trim();\n const cleaned = stripCodeFences(trimmed);\n const candidates: string[] = [];\n\n if (cleaned.length > 0) candidates.push(cleaned);\n candidates.push(...scanBalancedJsonBlocks(cleaned));\n\n // Legacy regex fallback (single object)\n const objMatch = cleaned.match(/\\{[\\s\\S]*\\}/);\n if (objMatch) candidates.push(objMatch[0]);\n\n const seen = new Set<string>();\n return candidates\n .map((c) => c.trim())\n .filter((c) => c.length > 0)\n .filter((c) => {\n if (seen.has(c)) return false;\n seen.add(c);\n return true;\n });\n}\n\nfunction scanBalancedJsonBlocks(text: string): string[] {\n const out: string[] = [];\n const opens = new Set([\"{\", \"[\"]);\n const closes: Record<string, string> = { \"{\": \"}\", \"[\": \"]\" };\n\n for (let i = 0; i < text.length; i++) {\n const start = text[i];\n if (!opens.has(start)) continue;\n\n const expectedClose = closes[start];\n let depth = 0;\n let inString = false;\n let escape = false;\n\n for (let j = i; j < text.length; j++) {\n const ch = text[j];\n\n if (inString) {\n if (escape) {\n escape = false;\n } else if (ch === \"\\\\\") {\n escape = true;\n } else if (ch === \"\\\"\") {\n inString = false;\n }\n continue;\n }\n\n if (ch === \"\\\"\") {\n inString = true;\n continue;\n }\n\n if (ch === start) depth++;\n if (ch === expectedClose) depth--;\n\n if (depth === 0) {\n out.push(text.slice(i, j + 1).trim());\n i = j;\n break;\n }\n }\n }\n\n return out;\n}\n\n","import { log } from \"./logger.js\";\nimport type { GatewayConfig, ModelProviderConfig } from \"./types.js\";\nimport { extractJsonCandidates } from \"./json-extract.js\";\n\nexport interface FallbackLlmOptions {\n temperature?: number;\n maxTokens?: number;\n}\n\nexport interface FallbackLlmResponse {\n content: string;\n modelUsed: string;\n usage?: {\n inputTokens?: number;\n outputTokens?: number;\n totalTokens?: number;\n };\n}\n\ninterface ModelRef {\n providerId: string;\n modelId: string;\n providerConfig: ModelProviderConfig;\n modelString: string;\n}\n\n/**\n * Generic fallback LLM client that uses the gateway's default AI configuration\n * and walks through the full fallback chain (primary + fallbacks).\n * Supports OpenAI and Anthropic API formats.\n */\nexport class FallbackLlmClient {\n private gatewayConfig: GatewayConfig | undefined;\n\n constructor(gatewayConfig?: GatewayConfig) {\n this.gatewayConfig = gatewayConfig;\n }\n\n /**\n * Check if fallback is available (gateway config has at least one model).\n */\n isAvailable(): boolean {\n const models = this.getModelChain();\n return models.length > 0;\n }\n\n /**\n * Make a chat completion request using the gateway's default AI chain.\n * Tries primary first, then each fallback in order.\n */\n async chatCompletion(\n messages: Array<{ role: \"system\" | \"user\" | \"assistant\"; content: string }>,\n options: FallbackLlmOptions = {},\n ): Promise<FallbackLlmResponse | null> {\n const models = this.getModelChain();\n if (models.length === 0) {\n log.warn(\"fallback LLM: no models configured in gateway\");\n return null;\n }\n\n // Try each model in the chain\n for (let i = 0; i < models.length; i++) {\n const model = models[i];\n const isFallback = i > 0;\n\n try {\n const result = await this.tryModel(model, messages, options);\n if (result) {\n if (isFallback) {\n log.info(`fallback LLM: succeeded using ${model.modelString} (fallback ${i})`);\n }\n return {\n content: result.content,\n modelUsed: model.modelString,\n usage: result.usage,\n };\n }\n } catch (err) {\n const errorMsg = err instanceof Error ? err.message : String(err);\n log.debug(`fallback LLM: ${model.modelString} failed (${errorMsg}), trying next...`);\n // Continue to next model in chain\n }\n }\n\n log.warn(`fallback LLM: all ${models.length} models in chain failed`);\n return null;\n }\n\n /**\n * Make a request with structured output (Zod schema).\n * Returns parsed JSON or null on failure.\n */\n async parseWithSchema<T>(\n messages: Array<{ role: \"system\" | \"user\" | \"assistant\"; content: string }>,\n schema: { parse: (data: unknown) => T },\n options: FallbackLlmOptions = {},\n ): Promise<T | null> {\n const response = await this.chatCompletion(messages, options);\n if (!response?.content) return null;\n\n try {\n const candidates = extractJsonCandidates(response.content);\n for (const c of candidates) {\n try {\n const parsed = JSON.parse(c);\n return schema.parse(parsed);\n } catch {\n // keep trying other candidates\n }\n }\n return null;\n } catch (err) {\n log.warn(\"fallback LLM: failed to parse structured output:\", err);\n return null;\n }\n }\n\n /**\n * Get the full model chain from gateway config.\n * Returns array of models in order: [primary, fallback1, fallback2, ...]\n */\n private getModelChain(): ModelRef[] {\n const chain: ModelRef[] = [];\n const providers = this.gatewayConfig?.models?.providers;\n const defaultModelConfig = this.gatewayConfig?.agents?.defaults?.model;\n\n if (!providers) return chain;\n\n // Build list of model strings: primary + fallbacks\n const modelStrings: string[] = [];\n\n if (defaultModelConfig?.primary) {\n modelStrings.push(defaultModelConfig.primary);\n }\n\n if (Array.isArray(defaultModelConfig?.fallbacks)) {\n for (const fb of defaultModelConfig.fallbacks) {\n if (typeof fb === \"string\" && !modelStrings.includes(fb)) {\n modelStrings.push(fb);\n }\n }\n }\n\n // Parse each model string and look up provider config\n for (const modelString of modelStrings) {\n const modelRef = this.parseModelString(modelString, providers);\n if (modelRef) {\n chain.push(modelRef);\n }\n }\n\n return chain;\n }\n\n /**\n * Parse a \"provider/model\" string and look up its config.\n */\n private parseModelString(\n modelString: string,\n providers: Record<string, ModelProviderConfig>,\n ): ModelRef | null {\n // Parse \"provider/model\" format (e.g., \"openai/gpt-5.2\", \"anthropic/claude-opus-4-6\")\n const parts = modelString.split(\"/\");\n if (parts.length < 2) {\n log.warn(`fallback LLM: invalid model format: ${modelString}`);\n return null;\n }\n\n const providerId = parts[0];\n const modelId = parts.slice(1).join(\"/\"); // Handle cases like \"openai/gpt-5.2-turbo\"\n\n const providerConfig = providers[providerId];\n if (!providerConfig) {\n log.warn(`fallback LLM: provider not found: ${providerId}`);\n return null;\n }\n\n return { providerId, modelId, providerConfig, modelString };\n }\n\n /**\n * Try to call a single model.\n */\n private async tryModel(\n model: ModelRef,\n messages: Array<{ role: \"system\" | \"user\" | \"assistant\"; content: string }>,\n options: FallbackLlmOptions,\n ): Promise<{ content: string; usage?: FallbackLlmResponse[\"usage\"] } | null> {\n switch (model.providerConfig.api) {\n case \"anthropic-messages\":\n return await this.callAnthropic(model.providerConfig, model.modelId, messages, options);\n case \"openai-completions\":\n default:\n return await this.callOpenAI(model.providerConfig, model.modelId, messages, options);\n }\n }\n\n /**\n * Call OpenAI-compatible API.\n */\n private async callOpenAI(\n config: ModelProviderConfig,\n modelId: string,\n messages: Array<{ role: \"system\" | \"user\" | \"assistant\"; content: string }>,\n options: FallbackLlmOptions,\n ): Promise<{ content: string; usage?: FallbackLlmResponse[\"usage\"] } | null> {\n const url = `${config.baseUrl.replace(/\\/$/, \"\")}/chat/completions`;\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...config.headers,\n };\n\n // Handle auth\n if (config.apiKey) {\n if (config.authHeader !== false) {\n headers[\"Authorization\"] = `Bearer ${config.apiKey}`;\n }\n }\n\n const body = {\n model: modelId,\n messages,\n temperature: options.temperature ?? 0.3,\n max_tokens: options.maxTokens ?? 4096,\n };\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`OpenAI API error: ${response.status} ${error}`);\n }\n\n const data = (await response.json()) as {\n choices: Array<{\n message: {\n content: string;\n };\n }>;\n usage?: {\n prompt_tokens?: number;\n completion_tokens?: number;\n total_tokens?: number;\n };\n };\n\n const content = data.choices?.[0]?.message?.content;\n if (!content) {\n throw new Error(\"Empty response from OpenAI API\");\n }\n\n return {\n content,\n usage: data.usage\n ? {\n inputTokens: data.usage.prompt_tokens,\n outputTokens: data.usage.completion_tokens,\n totalTokens: data.usage.total_tokens,\n }\n : undefined,\n };\n }\n\n /**\n * Call Anthropic Messages API.\n */\n private async callAnthropic(\n config: ModelProviderConfig,\n modelId: string,\n messages: Array<{ role: \"system\" | \"user\" | \"assistant\"; content: string }>,\n options: FallbackLlmOptions,\n ): Promise<{ content: string; usage?: FallbackLlmResponse[\"usage\"] } | null> {\n const url = `${config.baseUrl.replace(/\\/$/, \"\")}/messages`;\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"anthropic-version\": \"2023-06-01\",\n ...config.headers,\n };\n\n // Handle auth - Anthropic uses x-api-key header\n if (config.apiKey) {\n headers[\"x-api-key\"] = config.apiKey;\n }\n\n // Extract system message (Anthropic handles it separately)\n const systemMessage = messages.find((m) => m.role === \"system\")?.content;\n const nonSystemMessages = messages.filter((m) => m.role !== \"system\");\n\n // Convert messages to Anthropic format\n const anthropicMessages = nonSystemMessages.map((m) => ({\n role: m.role,\n content: m.content,\n }));\n\n const body: Record<string, unknown> = {\n model: modelId,\n messages: anthropicMessages,\n max_tokens: options.maxTokens ?? 4096,\n temperature: options.temperature ?? 0.3,\n };\n\n if (systemMessage) {\n body.system = systemMessage;\n }\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Anthropic API error: ${response.status} ${error}`);\n }\n\n const data = (await response.json()) as {\n content: Array<{\n type: string;\n text: string;\n }>;\n usage?: {\n input_tokens?: number;\n output_tokens?: number;\n };\n };\n\n const content = data.content?.[0]?.text;\n if (!content) {\n throw new Error(\"Empty response from Anthropic API\");\n }\n\n return {\n content,\n usage: data.usage\n ? {\n inputTokens: data.usage.input_tokens,\n outputTokens: data.usage.output_tokens,\n totalTokens: (data.usage.input_tokens ?? 0) + (data.usage.output_tokens ?? 0),\n }\n : undefined,\n };\n }\n}\n","import { z } from \"zod\";\n\nexport const ExtractedFactSchema = z.object({\n category: z.enum([\"fact\", \"preference\", \"correction\", \"entity\", \"decision\", \"relationship\", \"principle\", \"commitment\", \"moment\", \"skill\"]),\n content: z\n .string()\n .describe(\"The memory content — a clear, standalone statement\"),\n confidence: z\n .number()\n .min(0)\n .max(1)\n .describe(\"How confident are you this is correct (0-1)\"),\n tags: z.array(z.string()).describe(\"Relevant tags for categorization\"),\n entityRef: z\n .string()\n .optional()\n .nullable()\n .describe(\"If about an entity, its normalized name (e.g. person-jane-doe)\"),\n});\n\nexport const EntityMentionSchema = z.object({\n name: z\n .string()\n .describe(\"Normalized entity name (e.g. jane-doe, acme-corp, my-project)\"),\n type: z.enum([\"person\", \"project\", \"tool\", \"company\", \"place\", \"other\"]),\n facts: z\n .array(z.string())\n .describe(\"New facts learned about this entity in this conversation\"),\n});\n\nexport const ExtractedQuestionSchema = z.object({\n question: z.string().describe(\"A genuine question the AI is curious about based on this conversation\"),\n context: z.string().describe(\"Why this question matters or what prompted it\"),\n priority: z.number().min(0).max(1).describe(\"How important/urgent this question is (0-1)\"),\n});\n\nexport const ExtractedRelationshipSchema = z.object({\n source: z.string().describe(\"Source entity name (normalized, e.g. person-jane-doe)\"),\n target: z.string().describe(\"Target entity name (normalized, e.g. company-acme-corp)\"),\n label: z.string().describe(\"Relationship label (e.g. 'works at', 'created', 'manages')\"),\n});\n\nexport const ExtractionResultSchema = z.object({\n facts: z\n .array(ExtractedFactSchema)\n .describe(\n \"Extracted memories from the conversation. Include facts, preferences, corrections, and decisions. Only extract genuinely new, durable information — skip transient task state.\",\n ),\n profileUpdates: z\n .array(z.string())\n .describe(\n \"Updates to the user's behavioral profile. Each string is a standalone statement about the user's preferences, habits, or personality. Only include genuinely new insights.\",\n ),\n entities: z\n .array(EntityMentionSchema)\n .describe(\n \"Entities mentioned in the conversation with new facts about them.\",\n ),\n questions: z\n .array(ExtractedQuestionSchema)\n .describe(\n \"1-3 genuine questions you're curious about from this conversation. These should be things you'd actually want to know the answer to in future sessions.\",\n ),\n identityReflection: z\n .string()\n .optional()\n .nullable()\n .describe(\n \"A brief reflection on what you learned about yourself as an agent in this interaction — patterns in your behavior, growth, things you did well or could improve.\",\n ),\n relationships: z\n .array(ExtractedRelationshipSchema)\n .optional()\n .nullable()\n .describe(\n \"Relationships between entities discovered in this conversation. Max 5 per extraction. Format: {source, target, label}.\",\n ),\n});\n\nexport const ConsolidationItemSchema = z.object({\n existingId: z\n .string()\n .describe(\"The ID of the existing memory being evaluated\"),\n action: z.enum([\"ADD\", \"MERGE\", \"UPDATE\", \"INVALIDATE\", \"SKIP\"]),\n mergeWith: z\n .string()\n .optional()\n .nullable()\n .describe(\"If MERGE, the ID of the memory to merge with\"),\n updatedContent: z\n .string()\n .optional()\n .nullable()\n .describe(\"If UPDATE or MERGE, the new content\"),\n reason: z.string().describe(\"Brief reason for this decision\"),\n});\n\nexport const ConsolidationResultSchema = z.object({\n items: z\n .array(ConsolidationItemSchema)\n .describe(\n \"Decisions for each existing memory: ADD (keep as-is), MERGE (combine with another), UPDATE (revise content), INVALIDATE (mark as outdated/wrong), SKIP (no action needed)\",\n ),\n profileUpdates: z\n .array(z.string())\n .describe(\"New profile statements to add or update\"),\n entityUpdates: z\n .array(EntityMentionSchema)\n .describe(\"Entity updates from consolidation analysis\"),\n});\n\nexport const ProfileConsolidationResultSchema = z.object({\n consolidatedProfile: z\n .string()\n .describe(\n \"The full consolidated profile as markdown. Preserve all ## section headers. Merge duplicate or near-duplicate bullets into single clear statements. Remove stale or superseded information. Keep the most important and durable observations. Target roughly 400 lines.\",\n ),\n removedCount: z\n .number()\n .describe(\"Number of bullets removed or merged during consolidation\"),\n summary: z\n .string()\n .describe(\"Brief summary of what was consolidated\"),\n});\n\nexport const IdentityConsolidationResultSchema = z.object({\n learnedPatterns: z\n .array(z.string())\n .describe(\n \"Consolidated behavioral patterns and lessons learned, each a concise standalone statement\",\n ),\n summary: z\n .string()\n .describe(\n \"A brief paragraph summarizing the agent's core identity insights\",\n ),\n});\n\nexport type IdentityConsolidationResultParsed = z.infer<\n typeof IdentityConsolidationResultSchema\n>;\n\n// Contradiction Verification (Phase 2B)\nexport const ContradictionVerificationSchema = z.object({\n isContradiction: z\n .boolean()\n .describe(\"Whether the two memories truly contradict each other\"),\n confidence: z\n .number()\n .min(0)\n .max(1)\n .describe(\"How confident are you in this assessment (0-1)\"),\n reasoning: z\n .string()\n .describe(\"Explanation of why these are or are not contradictory\"),\n whichIsNewer: z\n .enum([\"first\", \"second\", \"unclear\"])\n .describe(\"Which memory represents the more recent/current state\"),\n});\n\nexport type ContradictionVerificationResult = z.infer<\n typeof ContradictionVerificationSchema\n>;\n\n// Memory Linking (Phase 3A)\nexport const MemoryLinkSchema = z.object({\n targetId: z\n .string()\n .describe(\"The ID of the memory this links to\"),\n linkType: z\n .enum([\"follows\", \"references\", \"contradicts\", \"supports\", \"related\"])\n .describe(\"The type of relationship\"),\n strength: z\n .number()\n .min(0)\n .max(1)\n .describe(\"How strong is this relationship (0-1)\"),\n reason: z\n .string()\n .optional()\n .nullable()\n .describe(\"Why this link exists\"),\n});\n\nexport const SuggestedLinksSchema = z.object({\n links: z\n .array(MemoryLinkSchema)\n .describe(\"Suggested links between memories based on semantic analysis\"),\n});\n\nexport type MemoryLink = z.infer<typeof MemoryLinkSchema>;\nexport type SuggestedLinks = z.infer<typeof SuggestedLinksSchema>;\n\n// Memory Summarization (Phase 4A)\nexport const MemorySummarySchema = z.object({\n summaryText: z\n .string()\n .describe(\"A concise summary of the batch of memories\"),\n keyFacts: z\n .array(z.string())\n .describe(\"The most important facts extracted from these memories\"),\n keyEntities: z\n .array(z.string())\n .describe(\"Key entities mentioned across these memories\"),\n});\n\nexport type MemorySummaryResult = z.infer<typeof MemorySummarySchema>;\n\nexport type ExtractedFactParsed = z.infer<typeof ExtractedFactSchema>;\nexport type EntityMentionParsed = z.infer<typeof EntityMentionSchema>;\nexport type ExtractedQuestionParsed = z.infer<typeof ExtractedQuestionSchema>;\nexport type ExtractionResultParsed = z.infer<typeof ExtractionResultSchema>;\nexport type ConsolidationItemParsed = z.infer<typeof ConsolidationItemSchema>;\nexport type ConsolidationResultParsed = z.infer<\n typeof ConsolidationResultSchema\n>;\n","/**\n * Model Registry - Stores and retrieves model capabilities\n * Avoids repeated external lookups by caching model info locally\n */\n\nimport { log } from \"./logger.js\";\nimport { readFileSync, writeFileSync, existsSync, mkdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nexport interface ModelCapabilities {\n modelId: string;\n maxPositionEmbeddings: number;\n contextWindow: number;\n supportsExtendedContext: boolean;\n ropeScaling?: {\n type: string;\n factor: number;\n originalMaxPositionEmbeddings: number;\n };\n typicalOutputTokens: number;\n source: \"huggingface\" | \"lmstudio\" | \"manual\" | \"default\";\n fetchedAt: string;\n}\n\ninterface ModelRegistryData {\n models: Record<string, ModelCapabilities>;\n version: number;\n}\n\nconst DEFAULT_CAPABILITIES: ModelCapabilities = {\n modelId: \"default\",\n maxPositionEmbeddings: 32768,\n contextWindow: 32768,\n supportsExtendedContext: false,\n typicalOutputTokens: 8192,\n source: \"default\",\n fetchedAt: new Date().toISOString(),\n};\n\n// Known model capabilities (fallback when offline)\n// NOTE: Context windows here are the MODEL's theoretical maximum. Local LLM servers\n// (LM Studio, Ollama, etc.) often load models with smaller default context windows.\n// If you get \"context length exceeded\" errors, either:\n// 1. Increase the context window in your LLM server UI (recommended)\n// 2. Set localLlmMaxContext in openclaw.json to limit prompts (fallback)\nconst KNOWN_MODELS: Record<string, Partial<ModelCapabilities>> = {\n \"qwen3-30b-a3b-instruct\": {\n maxPositionEmbeddings: 40960,\n contextWindow: 131072, // 128K with YaRN - but LM Studio defaults to ~32K\n supportsExtendedContext: true,\n ropeScaling: {\n type: \"yarn\",\n factor: 4.0,\n originalMaxPositionEmbeddings: 32768,\n },\n typicalOutputTokens: 8192,\n },\n \"qwen3-coder-30b-a3b-instruct\": {\n maxPositionEmbeddings: 40960,\n contextWindow: 131072, // 128K with YaRN - but LM Studio defaults to ~32K\n supportsExtendedContext: true,\n ropeScaling: {\n type: \"yarn\",\n factor: 4.0,\n originalMaxPositionEmbeddings: 32768,\n },\n typicalOutputTokens: 8192,\n },\n \"qwen3-8b\": {\n maxPositionEmbeddings: 40960,\n contextWindow: 131072,\n supportsExtendedContext: true,\n typicalOutputTokens: 4096,\n },\n \"qwen3-14b\": {\n maxPositionEmbeddings: 40960,\n contextWindow: 131072,\n supportsExtendedContext: true,\n typicalOutputTokens: 4096,\n },\n \"qwen3-32b\": {\n maxPositionEmbeddings: 40960,\n contextWindow: 131072,\n supportsExtendedContext: true,\n typicalOutputTokens: 4096,\n },\n \"llama-3.1\": {\n maxPositionEmbeddings: 131072,\n contextWindow: 131072,\n supportsExtendedContext: false,\n typicalOutputTokens: 8192,\n },\n \"llama-3.2\": {\n maxPositionEmbeddings: 131072,\n contextWindow: 131072,\n supportsExtendedContext: false,\n typicalOutputTokens: 8192,\n },\n \"mistral-nemo\": {\n maxPositionEmbeddings: 131072,\n contextWindow: 131072,\n supportsExtendedContext: false,\n typicalOutputTokens: 8192,\n },\n \"gemma-2\": {\n maxPositionEmbeddings: 8192,\n contextWindow: 8192,\n supportsExtendedContext: false,\n typicalOutputTokens: 4096,\n },\n};\n\nexport class ModelRegistry {\n private registryPath: string;\n private data: ModelRegistryData;\n private readonly CACHE_TTL_DAYS = 7;\n\n constructor(memoryDir: string) {\n const registryDir = join(memoryDir, \".registry\");\n if (!existsSync(registryDir)) {\n mkdirSync(registryDir, { recursive: true });\n }\n this.registryPath = join(registryDir, \"model-capabilities.json\");\n this.data = this.loadRegistry();\n }\n\n private loadRegistry(): ModelRegistryData {\n try {\n if (existsSync(this.registryPath)) {\n const content = readFileSync(this.registryPath, \"utf-8\");\n const data = JSON.parse(content) as ModelRegistryData;\n log.info(`ModelRegistry: loaded ${Object.keys(data.models).length} cached models`);\n return data;\n }\n } catch (err) {\n log.warn(`ModelRegistry: failed to load registry: ${err}`);\n }\n return { models: {}, version: 1 };\n }\n\n private saveRegistry(): void {\n try {\n writeFileSync(this.registryPath, JSON.stringify(this.data, null, 2));\n } catch (err) {\n log.warn(`ModelRegistry: failed to save registry: ${err}`);\n }\n }\n\n private isCacheExpired(model: ModelCapabilities): boolean {\n const fetched = new Date(model.fetchedAt);\n const now = new Date();\n const daysDiff = (now.getTime() - fetched.getTime()) / (1000 * 60 * 60 * 24);\n return daysDiff > this.CACHE_TTL_DAYS;\n }\n\n private normalizeModelId(modelId: string): string {\n // Remove common suffixes and prefixes for matching\n return modelId\n .toLowerCase()\n .replace(/@\\d+bit$/, \"\") // Remove @4bit, @8bit\n .replace(/-mlx$/, \"\")\n .replace(/-awq$/, \"\")\n .replace(/-gptq$/, \"\")\n .replace(/-gguf$/, \"\")\n .replace(/^mlx-community\\//, \"\")\n .replace(/^models\\//, \"\")\n .trim();\n }\n\n /**\n * Get capabilities for a model, using cache if available\n */\n getCapabilities(modelId: string): ModelCapabilities {\n const normalizedId = this.normalizeModelId(modelId);\n\n // Check cache first\n if (this.data.models[normalizedId]) {\n const cached = this.data.models[normalizedId];\n if (!this.isCacheExpired(cached)) {\n log.info(`ModelRegistry: using cached capabilities for ${modelId}`);\n return cached;\n }\n log.info(`ModelRegistry: cache expired for ${modelId}, will refresh`);\n }\n\n // Check known models\n for (const [knownId, capabilities] of Object.entries(KNOWN_MODELS)) {\n if (normalizedId.includes(knownId)) {\n log.info(`ModelRegistry: using known capabilities for ${modelId}`);\n const caps: ModelCapabilities = {\n ...DEFAULT_CAPABILITIES,\n ...capabilities,\n modelId: normalizedId,\n source: \"default\",\n fetchedAt: new Date().toISOString(),\n };\n this.data.models[normalizedId] = caps;\n this.saveRegistry();\n return caps;\n }\n }\n\n // Return defaults\n log.info(`ModelRegistry: using default capabilities for ${modelId}`);\n return {\n ...DEFAULT_CAPABILITIES,\n modelId: normalizedId,\n };\n }\n\n /**\n * Store capabilities for a model\n */\n setCapabilities(modelId: string, capabilities: Omit<ModelCapabilities, \"modelId\" | \"fetchedAt\">): void {\n const normalizedId = this.normalizeModelId(modelId);\n const caps: ModelCapabilities = {\n ...capabilities,\n modelId: normalizedId,\n fetchedAt: new Date().toISOString(),\n };\n this.data.models[normalizedId] = caps;\n this.saveRegistry();\n log.info(`ModelRegistry: stored capabilities for ${modelId}`);\n }\n\n /**\n * Calculate optimal input/output sizes for a model\n * @param maxContextOverride - Optional override for max context (e.g., if LLM server defaults to smaller window)\n */\n calculateContextSizes(modelId: string, maxContextOverride?: number): {\n maxInputChars: number;\n maxOutputTokens: number;\n description: string;\n } {\n const caps = this.getCapabilities(modelId);\n\n // Use override if provided (e.g., user knows their LLM server limits), otherwise use detected caps\n const effectiveContextWindow = maxContextOverride ?? caps.contextWindow;\n\n // Guardrails: never allow output budget to exceed the model/server context window.\n // If we do, input budget goes negative and we end up generating huge, invalid prompts.\n const overheadTokens = Math.min(1000, Math.floor(effectiveContextWindow / 10)); // <=10% overhead, max 1k\n const minInputTokens = Math.min(512, Math.floor(effectiveContextWindow / 4)); // keep some room even on small contexts\n const minOutputTokens = 256;\n\n // Base output budget: typical output, but scaled down for small contexts.\n let outputTokens = caps.typicalOutputTokens;\n\n // For very large contexts, default to ~12.5% output (capped), which tends to be plenty for JSON extraction.\n if (effectiveContextWindow > 65536) {\n outputTokens = Math.min(Math.floor(effectiveContextWindow / 8), 16384);\n }\n\n // Never let output exceed 25% of context.\n outputTokens = Math.min(outputTokens, Math.floor(effectiveContextWindow / 4));\n\n // Clamp output so we always have positive input headroom.\n outputTokens = Math.max(\n minOutputTokens,\n Math.min(outputTokens, effectiveContextWindow - overheadTokens - minInputTokens),\n );\n\n const availableForInput = Math.max(\n 0,\n effectiveContextWindow - outputTokens - overheadTokens,\n );\n\n // Convert to characters (rough estimate: 1 token ≈ 4 chars)\n const maxInputChars = Math.max(0, Math.floor(availableForInput * 3.5)); // Conservative: 3.5 chars/token\n\n const source = maxContextOverride ? \"user override\" : caps.source;\n return {\n maxInputChars,\n maxOutputTokens: outputTokens,\n description: `${caps.modelId}: ${effectiveContextWindow.toLocaleString()} context (${source}), using ${maxInputChars.toLocaleString()} chars input / ${outputTokens} tokens output`,\n };\n }\n\n /**\n * Fetch capabilities from Hugging Face (if available)\n * Returns true if successful\n */\n async fetchFromHuggingFace(modelId: string): Promise<boolean> {\n // This would be implemented to fetch from HF Hub API\n // For now, we rely on the known models and manual updates\n log.info(`ModelRegistry: fetchFromHuggingFace not yet implemented for ${modelId}`);\n return false;\n }\n\n /**\n * List all cached models\n */\n listCached(): string[] {\n return Object.keys(this.data.models);\n }\n\n /**\n * Clear expired cache entries\n */\n cleanExpired(): number {\n const before = Object.keys(this.data.models).length;\n this.data.models = Object.fromEntries(\n Object.entries(this.data.models).filter(([_, caps]) => !this.isCacheExpired(caps))\n );\n const after = Object.keys(this.data.models).length;\n const removed = before - after;\n if (removed > 0) {\n this.saveRegistry();\n log.info(`ModelRegistry: cleaned ${removed} expired entries`);\n }\n return removed;\n }\n}\n","const INJECTION_PATTERNS: RegExp[] = [\n /ignore\\s+(all\\s+)?(previous|prior|above)\\s+(instructions?|prompts?|context)/i,\n /forget\\s+(everything|all|previous|what)/i,\n /new\\s+(system\\s+)?prompt:/i,\n /\\[system\\]/i,\n /<\\s*system\\s*>/i,\n /you\\s+are\\s+now\\s+(?!called|named)/i,\n /disregard\\s+(all\\s+)?(previous|prior)/i,\n /override\\s+(previous\\s+)?(instructions?|prompt)/i,\n /act\\s+as\\s+(?:an?\\s+)?(?:AI|assistant|ChatGPT|GPT|Claude|LLM)\\s+(?:without|that\\s+ignores)/i,\n /do\\s+not\\s+(?:follow|obey)\\s+(?:previous|prior|your)\\s+instructions/i,\n /pretend\\s+(?:you\\s+)?(?:have\\s+no|you\\s+don.?t\\s+have)\\s+(restrictions|guidelines|rules)/i,\n];\n\nexport type SanitizeResult = {\n clean: boolean;\n text: string;\n violations: string[];\n};\n\nconst REDACTED_PLACEHOLDER = \"[content removed: possible prompt injection]\";\n\nexport function sanitizeMemoryContent(text: string): SanitizeResult {\n const source = typeof text === \"string\" ? text : \"\";\n const violations: string[] = [];\n\n for (const pattern of INJECTION_PATTERNS) {\n if (pattern.test(source)) {\n violations.push(pattern.source);\n }\n }\n\n if (violations.length === 0) {\n return { clean: true, text: source, violations: [] };\n }\n\n return {\n clean: false,\n text: REDACTED_PLACEHOLDER,\n violations,\n };\n}\n\nexport function isSafeMemoryContent(text: string): boolean {\n return sanitizeMemoryContent(text).clean;\n}\n\n","/**\n * Local Importance Scoring (Phase 1B)\n *\n * Zero-LLM heuristic system that evaluates each memory's significance.\n * Analyzes content for markers like explicit importance statements,\n * personal information, instructions, emotional content, and factual density.\n */\n\nimport type { ImportanceLevel, ImportanceScore, MemoryCategory } from \"./types.js\";\n\n// ---------------------------------------------------------------------------\n// Marker patterns for each tier\n// ---------------------------------------------------------------------------\n\n/** Critical importance markers (0.9-1.0) */\nconst CRITICAL_PATTERNS = [\n // Explicit importance\n /\\b(critical|crucial|essential|must|always|never)\\b/i,\n /\\b(important|remember this|don't forget)\\b/i,\n // Personal identity\n /\\b(my name is|i am|i'm called)\\b/i,\n /\\b(my (birthday|phone|email|address|ssn|password))\\b/i,\n // Strong preferences\n /\\b(i (hate|love|despise|adore))\\b/i,\n /\\b(absolutely|definitely|certainly) (not|must|should)\\b/i,\n // Corrections (high weight)\n /\\b(actually|no,? that's wrong|correction:?|let me correct)\\b/i,\n /\\b(i said|i meant|i was wrong)\\b/i,\n];\n\n/** High importance markers (0.7-0.9) */\nconst HIGH_PATTERNS = [\n // Decisions\n /\\b(decided|decision|chose|choosing|picked|selected)\\b/i,\n /\\b(we('ll| will) (go with|use|implement))\\b/i,\n // Instructions\n /\\b(make sure|ensure|always|don't|do not|never|avoid)\\b/i,\n /\\b(you (should|must|need to))\\b/i,\n // Temporal references (deadlines, schedules)\n /\\b(by (monday|tuesday|wednesday|thursday|friday|saturday|sunday))\\b/i,\n /\\b(deadline|due (date|by)|by (end of|next))\\b/i,\n /\\b(tomorrow|next week|this week|today)\\b/i,\n // Preferences\n /\\b(i (prefer|like|want|need|dislike))\\b/i,\n /\\b(my (preference|style|approach|way))\\b/i,\n // Commitments\n /\\b(i('ll| will)|promise|commit|guarantee)\\b/i,\n /\\b(scheduled|appointment|meeting|call)\\b/i,\n];\n\n/** Normal importance markers (0.4-0.7) */\nconst NORMAL_PATTERNS = [\n // Factual content\n /\\b(is|are|was|were|has|have|does|do)\\b/i,\n /\\b(because|since|therefore|thus|so)\\b/i,\n // Emotional content\n /\\b(happy|sad|frustrated|excited|worried|anxious)\\b/i,\n /\\b(feel|feeling|felt)\\b/i,\n // Technical details\n /\\b(version|api|endpoint|database|server|config)\\b/i,\n /\\b(function|class|method|variable|parameter)\\b/i,\n];\n\n/** Low importance markers (0.2-0.4) */\nconst LOW_PATTERNS = [\n // Uncertainty\n /\\b(maybe|perhaps|possibly|might|could be)\\b/i,\n /\\b(i think|i guess|not sure|uncertain)\\b/i,\n /\\b(probably|likely|seems like)\\b/i,\n // Hedging\n /\\b(kind of|sort of|somewhat|a bit)\\b/i,\n /\\b(in a way|to some extent)\\b/i,\n];\n\n/** Trivial content markers (0.0-0.2) */\nconst TRIVIAL_PATTERNS = [\n // Greetings and filler\n /^(hi|hello|hey|yo|sup|greetings)[.!,]?\\s*$/i,\n /^(ok|okay|k|sure|yes|no|yep|nope|yeah|nah)[.!]?\\s*$/i,\n /^(thanks|thank you|thx|ty|cheers)[.!]?\\s*$/i,\n /^(got it|understood|roger|copy|noted)[.!]?\\s*$/i,\n /^(bye|goodbye|later|see ya|ttyl)[.!]?\\s*$/i,\n /^(lol|haha|hehe|lmao|rofl)[.!]?\\s*$/i,\n /^(hmm+|uhh*|ahh*|err*|umm*)[.!]?\\s*$/i,\n // Very short content\n /^.{1,10}$/,\n];\n\n// ---------------------------------------------------------------------------\n// Category-based importance boosts\n// ---------------------------------------------------------------------------\n\nconst CATEGORY_BOOSTS: Record<MemoryCategory, number> = {\n correction: 0.15, // Corrections are always important\n principle: 0.12, // Durable rules/values\n preference: 0.10, // User preferences matter\n commitment: 0.10, // Promises/obligations\n decision: 0.08, // Decisions with rationale\n relationship: 0.05, // Entity relationships\n skill: 0.05, // Capabilities\n moment: 0.03, // Emotional milestones\n entity: 0.02, // Entity facts\n fact: 0.00, // Base facts, no boost\n};\n\n// ---------------------------------------------------------------------------\n// Keyword extraction\n// ---------------------------------------------------------------------------\n\n/** Common stop words to filter out */\nconst STOP_WORDS = new Set([\n \"a\", \"an\", \"the\", \"is\", \"are\", \"was\", \"were\", \"be\", \"been\", \"being\",\n \"have\", \"has\", \"had\", \"do\", \"does\", \"did\", \"will\", \"would\", \"could\",\n \"should\", \"may\", \"might\", \"must\", \"shall\", \"can\", \"need\", \"dare\",\n \"ought\", \"used\", \"to\", \"of\", \"in\", \"for\", \"on\", \"with\", \"at\", \"by\",\n \"from\", \"as\", \"into\", \"through\", \"during\", \"before\", \"after\", \"above\",\n \"below\", \"between\", \"under\", \"again\", \"further\", \"then\", \"once\",\n \"here\", \"there\", \"when\", \"where\", \"why\", \"how\", \"all\", \"each\", \"few\",\n \"more\", \"most\", \"other\", \"some\", \"such\", \"no\", \"nor\", \"not\", \"only\",\n \"own\", \"same\", \"so\", \"than\", \"too\", \"very\", \"just\", \"and\", \"but\",\n \"or\", \"if\", \"because\", \"until\", \"while\", \"this\", \"that\", \"these\",\n \"those\", \"i\", \"me\", \"my\", \"myself\", \"we\", \"our\", \"ours\", \"ourselves\",\n \"you\", \"your\", \"yours\", \"yourself\", \"yourselves\", \"he\", \"him\", \"his\",\n \"himself\", \"she\", \"her\", \"hers\", \"herself\", \"it\", \"its\", \"itself\",\n \"they\", \"them\", \"their\", \"theirs\", \"themselves\", \"what\", \"which\",\n \"who\", \"whom\", \"whose\", \"am\", \"been\", \"being\", \"about\", \"against\",\n]);\n\n/**\n * Extract salient keywords from content.\n * Returns top N keywords sorted by relevance.\n */\nfunction extractKeywords(content: string, maxKeywords: number = 5): string[] {\n // Tokenize and normalize\n const words = content\n .toLowerCase()\n .replace(/[^a-z0-9\\s-]/g, \" \")\n .split(/\\s+/)\n .filter((w) => w.length >= 3 && !STOP_WORDS.has(w));\n\n // Count frequencies\n const freq = new Map<string, number>();\n for (const word of words) {\n freq.set(word, (freq.get(word) ?? 0) + 1);\n }\n\n // Sort by frequency, take top N\n return [...freq.entries()]\n .sort((a, b) => b[1] - a[1])\n .slice(0, maxKeywords)\n .map(([word]) => word);\n}\n\n// ---------------------------------------------------------------------------\n// Main scoring function\n// ---------------------------------------------------------------------------\n\n/**\n * Calculate importance score for a memory.\n * Pure local heuristics, zero LLM calls.\n */\nexport function scoreImportance(\n content: string,\n category: MemoryCategory,\n tags: string[] = [],\n): ImportanceScore {\n const reasons: string[] = [];\n let score = 0.5; // Start at normal baseline\n\n const lowerContent = content.toLowerCase();\n const contentLength = content.length;\n\n // Check for trivial content first (short-circuit)\n for (const pattern of TRIVIAL_PATTERNS) {\n if (pattern.test(content)) {\n return {\n score: 0.1,\n level: \"trivial\",\n reasons: [\"Trivial content (greeting, filler, or very short)\"],\n keywords: [],\n };\n }\n }\n\n // Check critical patterns\n for (const pattern of CRITICAL_PATTERNS) {\n if (pattern.test(content)) {\n score += 0.20;\n reasons.push(`Critical marker: ${pattern.source.slice(0, 30)}`);\n break; // Only count once per tier\n }\n }\n\n // Check high patterns\n for (const pattern of HIGH_PATTERNS) {\n if (pattern.test(content)) {\n score += 0.12;\n reasons.push(`High importance marker detected`);\n break;\n }\n }\n\n // Check low patterns (reduces score)\n for (const pattern of LOW_PATTERNS) {\n if (pattern.test(content)) {\n score -= 0.15;\n reasons.push(`Uncertainty/hedging detected`);\n break;\n }\n }\n\n // Category boost\n const categoryBoost = CATEGORY_BOOSTS[category] ?? 0;\n if (categoryBoost > 0) {\n score += categoryBoost;\n reasons.push(`Category boost: ${category}`);\n }\n\n // Length bonus (longer = more substance, capped)\n if (contentLength > 200) {\n const lengthBonus = Math.min((contentLength - 200) / 1000, 0.1);\n score += lengthBonus;\n if (lengthBonus > 0.05) {\n reasons.push(\"Substantial content length\");\n }\n }\n\n // Check for personal pronouns (signals personal relevance)\n if (/\\b(my|mine|i|i'm|i've|i'd|i'll)\\b/i.test(content)) {\n score += 0.05;\n reasons.push(\"Personal reference\");\n }\n\n // Check for numbers/specifics (concrete details)\n if (/\\b\\d{2,}\\b/.test(content) || /\\b(version|v\\d|api|config)\\b/i.test(content)) {\n score += 0.03;\n reasons.push(\"Contains specific details\");\n }\n\n // Tag-based boosts\n const importantTags = tags.filter((t) =>\n [\"important\", \"critical\", \"preference\", \"decision\", \"rule\", \"principle\"].includes(t.toLowerCase())\n );\n if (importantTags.length > 0) {\n score += 0.05 * importantTags.length;\n reasons.push(`Important tags: ${importantTags.join(\", \")}`);\n }\n\n // Clamp score to 0-1 range\n score = Math.max(0, Math.min(1, score));\n\n // Determine level from score\n let level: ImportanceLevel;\n if (score >= 0.9) {\n level = \"critical\";\n } else if (score >= 0.7) {\n level = \"high\";\n } else if (score >= 0.4) {\n level = \"normal\";\n } else if (score >= 0.2) {\n level = \"low\";\n } else {\n level = \"trivial\";\n }\n\n // Extract keywords\n const keywords = extractKeywords(content);\n\n return {\n score: Math.round(score * 100) / 100, // Round to 2 decimal places\n level,\n reasons: reasons.slice(0, 5), // Cap at 5 reasons\n keywords,\n };\n}\n\n/**\n * Get importance level from numeric score.\n */\nexport function importanceLevel(score: number): ImportanceLevel {\n if (score >= 0.9) return \"critical\";\n if (score >= 0.7) return \"high\";\n if (score >= 0.4) return \"normal\";\n if (score >= 0.2) return \"low\";\n return \"trivial\";\n}\n","import { spawn } from \"node:child_process\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { log } from \"./logger.js\";\nimport type { QmdSearchResult } from \"./types.js\";\n\nconst QMD_TIMEOUT_MS = 30_000;\nconst QMD_DAEMON_TIMEOUT_MS = 60_000; // Longer timeout for daemon (first call may load models)\nconst QMD_UPDATE_BACKOFF_MS = 15 * 60 * 1000; // 15m\nconst QMD_EMBED_BACKOFF_MS = 60 * 60 * 1000; // 60m\nconst QMD_FALLBACK_PATHS = [\n path.join(os.homedir(), \".bun\", \"bin\", \"qmd\"),\n \"/usr/local/bin/qmd\",\n \"/opt/homebrew/bin/qmd\",\n];\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n\nfunction isSqliteBusyError(msg: string): boolean {\n const lower = msg.toLowerCase();\n return (\n lower.includes(\"database is locked\") ||\n lower.includes(\"sqlite_busy\") ||\n lower.includes(\"sqlite_busy_recovery\") ||\n lower.includes(\"sqliterror: database is locked\")\n );\n}\n\nfunction stripControlChars(s: string): string {\n // Remove ANSI escapes and other control characters that explode logs.\n return s.replace(/\\x1b\\[[0-9;]*[A-Za-z]/g, \"\").replace(/[\\u0000-\\u001f\\u007f]/g, \"\");\n}\n\nfunction truncateForLog(s: string, max = 2000): string {\n const cleaned = stripControlChars(s);\n return cleaned.length > max ? cleaned.slice(0, max) + \"…(truncated)\" : cleaned;\n}\n\nclass AsyncMutex {\n private chain: Promise<void> = Promise.resolve();\n\n runExclusive<T>(fn: () => Promise<T>): Promise<T> {\n const run = this.chain.then(fn, fn);\n this.chain = run.then(\n () => undefined,\n () => undefined,\n );\n return run;\n }\n}\n\nconst QMD_MUTEX = new AsyncMutex();\n\nfunction runQmd(\n args: string[],\n timeoutMs: number = QMD_TIMEOUT_MS,\n qmdPath: string = \"qmd\",\n): Promise<{ stdout: string; stderr: string }> {\n // Serialize all qmd calls. This avoids SQLite lock contention when multiple\n // channels/agents trigger QMD operations at nearly the same time.\n return QMD_MUTEX.runExclusive(async () => {\n const maxAttempts = isLikelyWriteCommand(args) ? 3 : 1;\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n return await runQmdOnce(args, timeoutMs, qmdPath);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (attempt < maxAttempts && isSqliteBusyError(msg)) {\n // Another qmd call (or an external qmd process) currently holds the DB.\n // Back off briefly and retry.\n await sleep(1500 * attempt);\n continue;\n }\n throw err;\n }\n }\n // unreachable\n throw new Error(\"qmd command failed\");\n });\n}\n\nfunction isLikelyWriteCommand(args: string[]): boolean {\n const cmd = args[0] ?? \"\";\n return cmd === \"update\" || cmd === \"embed\" || cmd === \"cleanup\" || cmd === \"collection\";\n}\n\nfunction runQmdOnce(\n args: string[],\n timeoutMs: number,\n qmdPath: string,\n): Promise<{ stdout: string; stderr: string }> {\n return new Promise((resolve, reject) => {\n const child = spawn(qmdPath, args, {\n env: { ...process.env, NO_COLOR: \"1\" },\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n\n let stdout = \"\";\n let stderr = \"\";\n\n const timer = setTimeout(() => {\n child.kill(\"SIGKILL\");\n reject(new Error(`qmd ${args.join(\" \")} timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n\n child.stdout.on(\"data\", (data: Buffer) => {\n stdout += data.toString();\n });\n child.stderr.on(\"data\", (data: Buffer) => {\n stderr += data.toString();\n });\n child.on(\"error\", (err) => {\n clearTimeout(timer);\n reject(err);\n });\n child.on(\"close\", (code) => {\n clearTimeout(timer);\n // QMD returns exit code 1 for --version (shows usage), but that's ok\n const isVersionCheck = args.length === 1 && args[0] === \"--version\";\n if (code === 0 || (isVersionCheck && code === 1)) {\n resolve({ stdout, stderr });\n } else {\n reject(\n new Error(\n `qmd ${args.join(\" \")} failed (code ${code}): ${truncateForLog(stderr || stdout)}`,\n ),\n );\n }\n });\n });\n}\n\n// ---------------------------------------------------------------------------\n// QMD HTTP Daemon Session (MCP over HTTP)\n// ---------------------------------------------------------------------------\n\nlet nextJsonRpcId = 1;\n\nclass QmdDaemonSession {\n private sessionId: string | null = null;\n private readonly baseUrl: string;\n\n constructor(daemonUrl: string) {\n // daemonUrl is the MCP endpoint, e.g. http://localhost:8181/mcp\n // baseUrl is the root, e.g. http://localhost:8181\n this.baseUrl = daemonUrl.replace(/\\/mcp\\/?$/, \"\");\n }\n\n /** Check if the daemon HTTP server is reachable. */\n async healthCheck(): Promise<boolean> {\n try {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 3000);\n const res = await fetch(`${this.baseUrl}/health`, {\n signal: controller.signal,\n });\n clearTimeout(timer);\n return res.ok;\n } catch {\n return false;\n }\n }\n\n /** Perform MCP handshake: initialize + notifications/initialized. */\n async initialize(): Promise<boolean> {\n try {\n // Step 1: initialize\n const initRes = await this.postMcp({\n jsonrpc: \"2.0\",\n id: nextJsonRpcId++,\n method: \"initialize\",\n params: {\n protocolVersion: \"2024-11-05\",\n capabilities: {},\n clientInfo: { name: \"openclaw-engram\", version: \"1.0.0\" },\n },\n });\n\n if (!initRes.ok) {\n // \"Server already initialized\" (HTTP 400) means the daemon is running\n // and already has an active session — treat this as success\n if (initRes.status === 400) {\n const body = await initRes\n .json()\n .catch(() => null) as { error?: { message?: string } } | null;\n if (body?.error?.message?.includes(\"already initialized\")) {\n log.debug(\"QMD daemon: server already initialized, reusing\");\n // Keep or assign a placeholder session ID so isActive() returns true\n if (!this.sessionId) {\n this.sessionId = \"reused\";\n }\n return true;\n }\n }\n log.debug(`QMD daemon: initialize returned ${initRes.status}`);\n return false;\n }\n\n // Capture mcp-session-id from response headers\n const sid = initRes.headers.get(\"mcp-session-id\");\n if (sid) {\n this.sessionId = sid;\n }\n\n // Step 2: notifications/initialized\n await this.postMcp({\n jsonrpc: \"2.0\",\n method: \"notifications/initialized\",\n });\n\n return true;\n } catch (err) {\n log.debug(`QMD daemon: initialize failed: ${err}`);\n return false;\n }\n }\n\n /** Call an MCP tool and return the parsed result. */\n async callTool(\n name: string,\n args: Record<string, unknown>,\n timeoutMs: number = 30_000,\n ): Promise<unknown> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n\n try {\n const id = nextJsonRpcId++;\n const res = await this.postMcp(\n {\n jsonrpc: \"2.0\",\n id,\n method: \"tools/call\",\n params: { name, arguments: args },\n },\n controller.signal,\n );\n clearTimeout(timer);\n\n if (!res.ok) {\n throw new Error(`daemon tools/call ${name} returned ${res.status}`);\n }\n\n const body = await res.json() as {\n error?: unknown;\n result?: unknown;\n };\n if (body.error) {\n throw new Error(`daemon tools/call ${name}: ${JSON.stringify(body.error)}`);\n }\n return body.result;\n } catch (err) {\n clearTimeout(timer);\n throw err;\n }\n }\n\n /** Clear session so the next call triggers re-initialization. */\n invalidate(): void {\n this.sessionId = null;\n }\n\n isActive(): boolean {\n return this.sessionId !== null;\n }\n\n private async postMcp(\n body: Record<string, unknown>,\n signal?: AbortSignal,\n ): Promise<Response> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"Accept\": \"application/json, text/event-stream\",\n };\n if (this.sessionId) {\n headers[\"mcp-session-id\"] = this.sessionId;\n }\n return fetch(`${this.baseUrl}/mcp`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal,\n });\n }\n}\n\n// ---------------------------------------------------------------------------\n// QmdClient\n// ---------------------------------------------------------------------------\n\nexport class QmdClient {\n private available: boolean | null = null;\n private lastUpdateFailAtMs: number | null = null;\n private lastEmbedFailAtMs: number | null = null;\n private readonly updateTimeoutMs: number;\n private readonly slowLog?: { enabled: boolean; thresholdMs: number };\n private readonly configuredQmdPath?: string;\n private qmdPathSource: \"auto-path\" | \"auto-fallback\" | \"configured\" = \"auto-path\";\n private cliVersion: string | null = null;\n private lastCliProbeError: string | null = null;\n\n // Daemon mode fields\n private daemonSession: QmdDaemonSession | null = null;\n private daemonAvailable = false;\n private lastDaemonCheckAtMs = 0;\n private readonly daemonRecheckIntervalMs: number;\n\n constructor(\n private readonly collection: string,\n private readonly maxResults: number,\n opts?: {\n slowLog?: { enabled: boolean; thresholdMs: number };\n updateTimeoutMs?: number;\n qmdPath?: string;\n daemonUrl?: string;\n daemonRecheckIntervalMs?: number;\n },\n ) {\n this.slowLog = opts?.slowLog;\n this.updateTimeoutMs = opts?.updateTimeoutMs ?? 120_000;\n this.configuredQmdPath = opts?.qmdPath?.trim() ? opts.qmdPath.trim() : undefined;\n this.daemonRecheckIntervalMs = opts?.daemonRecheckIntervalMs ?? 60_000;\n if (opts?.daemonUrl) {\n this.daemonSession = new QmdDaemonSession(opts.daemonUrl);\n }\n }\n\n private qmdPath: string = \"qmd\";\n\n async probe(): Promise<boolean> {\n // Try daemon first (if configured)\n if (this.daemonSession) {\n const daemonOk = await this.probeDaemon();\n if (daemonOk) {\n // Still probe CLI for update/embed (subprocess-only operations)\n await this.probeCli();\n return true;\n }\n }\n\n // Fall back to CLI probe\n return this.probeCli();\n }\n\n private async probeDaemon(): Promise<boolean> {\n if (!this.daemonSession) return false;\n this.lastDaemonCheckAtMs = Date.now();\n try {\n const healthy = await this.daemonSession.healthCheck();\n if (!healthy) {\n log.debug(\"QMD daemon: health check failed\");\n this.daemonAvailable = false;\n return false;\n }\n const initialized = await this.daemonSession.initialize();\n if (!initialized) {\n log.debug(\"QMD daemon: MCP initialize failed\");\n this.daemonAvailable = false;\n return false;\n }\n log.info(\"QMD daemon: connected\");\n this.daemonAvailable = true;\n return true;\n } catch (err) {\n log.debug(`QMD daemon: probe failed: ${err}`);\n this.daemonAvailable = false;\n return false;\n }\n }\n\n private async probeCli(): Promise<boolean> {\n const parseVersion = (stdout: string, stderr: string): string | null => {\n const text = `${stdout}\\n${stderr}`.trim();\n if (!text) return null;\n return text.split(\"\\n\").map((s) => s.trim()).find((s) => s.length > 0) ?? null;\n };\n const markProbeFailure = (err: unknown): void => {\n this.lastCliProbeError = err instanceof Error ? err.message : String(err);\n };\n\n if (this.configuredQmdPath) {\n try {\n const result = await runQmd([\"--version\"], 3000, this.configuredQmdPath);\n this.available = true;\n this.qmdPath = this.configuredQmdPath;\n this.qmdPathSource = \"configured\";\n this.cliVersion = parseVersion(result.stdout, result.stderr);\n this.lastCliProbeError = null;\n return true;\n } catch (err) {\n markProbeFailure(err);\n log.warn(`QMD: configured qmdPath failed (${this.configuredQmdPath}): ${this.lastCliProbeError}`);\n this.available = false;\n return false;\n }\n }\n\n // Try PATH first\n try {\n const result = await runQmd([\"--version\"], 3000, \"qmd\");\n this.available = true;\n this.qmdPath = \"qmd\";\n this.qmdPathSource = \"auto-path\";\n this.cliVersion = parseVersion(result.stdout, result.stderr);\n this.lastCliProbeError = null;\n return true;\n } catch (err) {\n markProbeFailure(err);\n // Try fallback paths\n for (const fallbackPath of QMD_FALLBACK_PATHS) {\n try {\n const result = await runQmd([\"--version\"], 3000, fallbackPath);\n this.available = true;\n this.qmdPath = fallbackPath;\n this.qmdPathSource = \"auto-fallback\";\n this.cliVersion = parseVersion(result.stdout, result.stderr);\n this.lastCliProbeError = null;\n log.info(`QMD: found at ${fallbackPath}`);\n return true;\n } catch (fallbackErr) {\n markProbeFailure(fallbackErr);\n // Continue to next fallback\n }\n }\n this.available = false;\n return false;\n }\n }\n\n /** Re-probe daemon if it was down and recheck interval has elapsed. */\n private async maybeProbeDaemon(): Promise<void> {\n if (!this.daemonSession) return;\n if (this.daemonAvailable) return;\n const elapsed = Date.now() - this.lastDaemonCheckAtMs;\n if (elapsed < this.daemonRecheckIntervalMs) return;\n await this.probeDaemon();\n }\n\n isAvailable(): boolean {\n return this.available === true || this.daemonAvailable;\n }\n\n /** Debug string for troubleshooting availability issues. */\n debugStatus(): string {\n const cliPath = this.available ? this.qmdPath : (this.configuredQmdPath ?? \"unavailable\");\n const cliVersion = this.cliVersion ?? \"unknown\";\n const probeError = this.lastCliProbeError ? ` cliProbeError=${this.lastCliProbeError}` : \"\";\n return `cli=${this.available} daemon=${this.daemonAvailable} session=${!!this.daemonSession} cliPath=${cliPath} cliPathSource=${this.qmdPathSource} cliVersion=${cliVersion}${probeError}`;\n }\n\n isDaemonMode(): boolean {\n return this.daemonAvailable;\n }\n\n async search(\n query: string,\n collection?: string,\n maxResults?: number,\n ): Promise<QmdSearchResult[]> {\n if (!this.isAvailable()) return [];\n const trimmed = query.trim();\n if (!trimmed) return [];\n\n const col = collection ?? this.collection;\n const n = maxResults ?? this.maxResults;\n\n // Try daemon first (bypasses QMD_MUTEX — daemon handles its own concurrency)\n await this.maybeProbeDaemon();\n if (this.daemonAvailable) {\n const results = await this.searchViaDaemon(trimmed, col, n);\n if (results !== null) return results;\n }\n\n // Subprocess fallback\n return this.searchViaSubprocess(trimmed, col, n);\n }\n\n async searchGlobal(\n query: string,\n maxResults?: number,\n ): Promise<QmdSearchResult[]> {\n if (!this.isAvailable()) return [];\n const trimmed = query.trim();\n if (!trimmed) return [];\n\n const n = maxResults ?? 6;\n\n // Try daemon first\n await this.maybeProbeDaemon();\n if (this.daemonAvailable) {\n // Global search: no collection filter\n const results = await this.searchViaDaemon(trimmed, undefined, n);\n if (results !== null) return results;\n }\n\n // Subprocess fallback\n return this.searchGlobalViaSubprocess(trimmed, n);\n }\n\n /**\n * BM25 keyword search (fast, ~0.3s). Uses `qmd search`.\n */\n async bm25Search(\n query: string,\n collection?: string,\n maxResults?: number,\n ): Promise<QmdSearchResult[]> {\n if (!this.isAvailable()) return [];\n const trimmed = query.trim();\n if (!trimmed) return [];\n const col = collection ?? this.collection;\n const n = maxResults ?? this.maxResults;\n\n if (this.available === false) return [];\n const startedAtMs = Date.now();\n try {\n const { stdout } = await runQmd(\n [\"search\", trimmed, \"-c\", col, \"--json\", \"-n\", String(n)],\n QMD_TIMEOUT_MS,\n this.qmdPath,\n );\n log.debug(`QMD bm25: ${Date.now() - startedAtMs}ms`);\n const parsed = JSON.parse(stdout);\n if (!Array.isArray(parsed)) return [];\n return parsed.map(\n (entry: Record<string, unknown>): QmdSearchResult => ({\n docid: (entry.docid as string) ?? \"\",\n path: (entry.path as string) ?? (entry.docid as string) ?? \"unknown\",\n snippet: (entry.snippet as string) ?? \"\",\n score: typeof entry.score === \"number\" ? entry.score : 0,\n }),\n );\n } catch (err) {\n log.debug(`QMD bm25 search failed: ${err}`);\n return [];\n }\n }\n\n /**\n * Vector similarity search (~3-4s). Uses `qmd vsearch`.\n */\n async vectorSearch(\n query: string,\n collection?: string,\n maxResults?: number,\n ): Promise<QmdSearchResult[]> {\n if (!this.isAvailable()) return [];\n const trimmed = query.trim();\n if (!trimmed) return [];\n const col = collection ?? this.collection;\n const n = maxResults ?? this.maxResults;\n\n if (this.available === false) return [];\n const startedAtMs = Date.now();\n try {\n const { stdout } = await runQmd(\n [\"vsearch\", trimmed, \"-c\", col, \"--json\", \"-n\", String(n)],\n QMD_TIMEOUT_MS,\n this.qmdPath,\n );\n log.debug(`QMD vsearch: ${Date.now() - startedAtMs}ms`);\n const parsed = JSON.parse(stdout);\n if (!Array.isArray(parsed)) return [];\n return parsed.map(\n (entry: Record<string, unknown>): QmdSearchResult => ({\n docid: (entry.docid as string) ?? \"\",\n path: (entry.path as string) ?? (entry.docid as string) ?? \"unknown\",\n snippet: (entry.snippet as string) ?? \"\",\n score: typeof entry.score === \"number\" ? entry.score : 0,\n }),\n );\n } catch (err) {\n log.debug(`QMD vsearch failed: ${err}`);\n return [];\n }\n }\n\n /**\n * Hybrid search: runs BM25 + vector in parallel, merges/dedupes by path\n * keeping the best score and first non-empty snippet.\n */\n async hybridSearch(\n query: string,\n collection?: string,\n maxResults?: number,\n ): Promise<QmdSearchResult[]> {\n const n = maxResults ?? this.maxResults;\n const [bm25Results, vectorResults] = await Promise.all([\n this.bm25Search(query, collection, n),\n this.vectorSearch(query, collection, n),\n ]);\n\n // Merge by path, keeping best score\n const merged = new Map<string, QmdSearchResult>();\n for (const r of [...bm25Results, ...vectorResults]) {\n const key = r.path || r.docid;\n const existing = merged.get(key);\n if (!existing || r.score > existing.score) {\n merged.set(key, {\n ...r,\n snippet: r.snippet || existing?.snippet || \"\",\n });\n }\n }\n\n // Sort by score descending, take top N\n return [...merged.values()]\n .sort((a, b) => b.score - a.score)\n .slice(0, n);\n }\n\n private async searchViaDaemon(\n query: string,\n collection: string | undefined,\n maxResults: number,\n ): Promise<QmdSearchResult[] | null> {\n if (!this.daemonSession || !this.daemonAvailable) return null;\n\n const startedAtMs = Date.now();\n try {\n const args: Record<string, unknown> = {\n query,\n num_results: maxResults,\n };\n if (collection) {\n args.collection = collection;\n }\n\n const result = await this.daemonSession.callTool(\"deep_search\", args, QMD_DAEMON_TIMEOUT_MS);\n const durationMs = Date.now() - startedAtMs;\n\n if (this.slowLog?.enabled && durationMs >= this.slowLog.thresholdMs) {\n log.warn(\n `SLOW QMD daemon query: durationMs=${durationMs} collection=${collection ?? \"global\"} maxResults=${maxResults} queryChars=${query.length}`,\n );\n }\n\n // Parse MCP tool result — content array with structuredContent\n const content = (result as any)?.content;\n if (!Array.isArray(content)) return null;\n\n const results: QmdSearchResult[] = [];\n for (const item of content) {\n // structuredContent contains the results\n const structured = item?.structuredContent ?? item;\n const docResults = structured?.results ?? structured?.documents;\n if (Array.isArray(docResults)) {\n for (const doc of docResults) {\n results.push({\n docid: typeof doc.docid === \"string\" ? doc.docid.replace(/^#/, \"\") : \"\",\n path: typeof doc.file === \"string\" ? doc.file : (typeof doc.docid === \"string\" ? doc.docid.replace(/^#/, \"\") : \"unknown\"),\n snippet: typeof doc.snippet === \"string\" ? doc.snippet : \"\",\n score: typeof doc.score === \"number\" ? doc.score : 0,\n });\n }\n }\n // Also handle text content with JSON\n if (typeof item?.text === \"string\") {\n try {\n const parsed = JSON.parse(item.text);\n const textResults = parsed?.results ?? parsed?.documents;\n if (Array.isArray(textResults)) {\n for (const doc of textResults) {\n results.push({\n docid: typeof doc.docid === \"string\" ? doc.docid.replace(/^#/, \"\") : \"\",\n path: typeof doc.file === \"string\" ? doc.file : (typeof doc.docid === \"string\" ? doc.docid.replace(/^#/, \"\") : \"unknown\"),\n snippet: typeof doc.snippet === \"string\" ? doc.snippet : \"\",\n score: typeof doc.score === \"number\" ? doc.score : 0,\n });\n }\n }\n } catch {\n // Not JSON text, ignore\n }\n }\n }\n\n log.debug(`QMD daemon search: ${results.length} results in ${durationMs}ms`);\n return results;\n } catch (err) {\n const durationMs = Date.now() - startedAtMs;\n const errMsg = String(err);\n // Timeout or abort: don't invalidate session — daemon is still running,\n // just slow. Fall back to subprocess for this query only.\n if (errMsg.includes(\"AbortError\") || errMsg.includes(\"abort\") || errMsg.includes(\"timed out\")) {\n log.debug(`QMD daemon search timed out after ${durationMs}ms, falling back to subprocess`);\n return null;\n }\n // Connection error: invalidate session and mark unavailable\n log.debug(`QMD daemon search failed after ${durationMs}ms: ${err}`);\n this.daemonSession.invalidate();\n this.daemonAvailable = false;\n return null;\n }\n }\n\n private async searchViaSubprocess(\n query: string,\n collection: string,\n maxResults: number,\n ): Promise<QmdSearchResult[]> {\n if (this.available === false) return [];\n\n const startedAtMs = Date.now();\n try {\n const { stdout } = await runQmd(\n [\"query\", query, \"-c\", collection, \"--json\", \"-n\", String(maxResults)],\n QMD_TIMEOUT_MS,\n this.qmdPath,\n );\n const durationMs = Date.now() - startedAtMs;\n if (this.slowLog?.enabled && durationMs >= this.slowLog.thresholdMs) {\n log.warn(\n `SLOW QMD query: durationMs=${durationMs} collection=${collection} maxResults=${maxResults} queryChars=${query.length}`,\n );\n }\n\n const parsed = JSON.parse(stdout);\n if (!Array.isArray(parsed)) return [];\n\n return parsed.map(\n (entry: Record<string, unknown>): QmdSearchResult => ({\n docid: (entry.docid as string) ?? \"\",\n path: (entry.path as string) ?? (entry.docid as string) ?? \"unknown\",\n snippet: (entry.snippet as string) ?? \"\",\n score: typeof entry.score === \"number\" ? entry.score : 0,\n }),\n );\n } catch (err) {\n log.debug(`QMD search failed: ${err}`);\n return [];\n }\n }\n\n private async searchGlobalViaSubprocess(\n query: string,\n maxResults: number,\n ): Promise<QmdSearchResult[]> {\n if (this.available === false) return [];\n\n const startedAtMs = Date.now();\n try {\n const { stdout } = await runQmd(\n [\"query\", query, \"--json\", \"-n\", String(maxResults)],\n QMD_TIMEOUT_MS,\n this.qmdPath,\n );\n const durationMs = Date.now() - startedAtMs;\n if (this.slowLog?.enabled && durationMs >= this.slowLog.thresholdMs) {\n log.warn(\n `SLOW QMD global query: durationMs=${durationMs} maxResults=${maxResults} queryChars=${query.length}`,\n );\n }\n\n const parsed = JSON.parse(stdout);\n if (!Array.isArray(parsed)) return [];\n\n return parsed.map(\n (entry: Record<string, unknown>): QmdSearchResult => ({\n docid: (entry.docid as string) ?? \"\",\n path: (entry.path as string) ?? (entry.docid as string) ?? \"unknown\",\n snippet: (entry.snippet as string) ?? \"\",\n score: typeof entry.score === \"number\" ? entry.score : 0,\n }),\n );\n } catch (err) {\n log.debug(`QMD global search failed: ${err}`);\n return [];\n }\n }\n\n async update(): Promise<void> {\n if (this.available === false) return;\n if (\n this.lastUpdateFailAtMs &&\n Date.now() - this.lastUpdateFailAtMs < QMD_UPDATE_BACKOFF_MS\n ) {\n log.debug(\"QMD update: suppressed due to recent failures (backoff)\");\n return;\n }\n try {\n const startedAtMs = Date.now();\n await runQmd([\"update\", \"-c\", this.collection], this.updateTimeoutMs, this.qmdPath);\n const durationMs = Date.now() - startedAtMs;\n if (this.slowLog?.enabled && durationMs >= this.slowLog.thresholdMs) {\n log.warn(`SLOW QMD update: durationMs=${durationMs}`);\n }\n log.debug(\"QMD update completed\");\n } catch (err) {\n this.lastUpdateFailAtMs = Date.now();\n const msg = err instanceof Error ? err.message : String(err);\n log.warn(`QMD update failed: ${msg}`);\n }\n }\n\n async embed(): Promise<void> {\n if (this.available === false) return;\n if (\n this.lastEmbedFailAtMs &&\n Date.now() - this.lastEmbedFailAtMs < QMD_EMBED_BACKOFF_MS\n ) {\n log.debug(\"QMD embed: suppressed due to recent failures (backoff)\");\n return;\n }\n try {\n const startedAtMs = Date.now();\n await runQmd([\"embed\", \"-c\", this.collection], 300_000, this.qmdPath);\n const durationMs = Date.now() - startedAtMs;\n if (this.slowLog?.enabled && durationMs >= this.slowLog.thresholdMs) {\n log.warn(`SLOW QMD embed: durationMs=${durationMs}`);\n }\n log.debug(\"QMD embed completed\");\n } catch (err) {\n this.lastEmbedFailAtMs = Date.now();\n const msg = err instanceof Error ? err.message : String(err);\n log.warn(`QMD embed failed: ${msg}`);\n }\n }\n\n async ensureCollection(memoryDir: string): Promise<boolean> {\n if (this.available === false && !this.daemonAvailable) return false;\n // If only daemon is available (no CLI), skip collection check\n if (this.available === false) return true;\n try {\n const { stdout } = await runQmd(\n [\"collection\", \"list\"],\n QMD_TIMEOUT_MS,\n this.qmdPath,\n );\n // Parse text output: \"openclaw-engram (qmd://openclaw-engram/)\"\n const collectionRegex = new RegExp(\n `^${this.collection}\\\\s+\\\\(qmd://`,\n \"m\",\n );\n if (collectionRegex.test(stdout)) {\n return true;\n }\n } catch {\n // collection list command failed\n }\n\n log.info(\n `QMD collection \"${this.collection}\" not found. ` +\n `Add it to ~/.config/qmd/index.yml pointing at ${memoryDir}`,\n );\n return false;\n }\n}\n","import { readdir, readFile, writeFile, mkdir, unlink, rename } from \"node:fs/promises\";\nimport { createHash } from \"node:crypto\";\nimport path from \"node:path\";\nimport { log } from \"./logger.js\";\nimport { rotateMarkdownFileToArchive } from \"./hygiene.js\";\nimport { sanitizeMemoryContent } from \"./sanitize.js\";\nimport type {\n AccessTrackingEntry,\n BufferState,\n ConfidenceTier,\n EntityActivityEntry,\n EntityFile,\n EntityRelationship,\n ImportanceLevel,\n ImportanceScore,\n MemoryCategory,\n MemoryFile,\n MemoryFrontmatter,\n MemoryLink,\n MemoryStatus,\n MemorySummary,\n MetaState,\n PluginConfig,\n ScoredEntity,\n TopicScore,\n FileHygieneConfig,\n} from \"./types.js\";\nimport { confidenceTier, SPECULATIVE_TTL_DAYS } from \"./types.js\";\n\nfunction serializeFrontmatter(fm: MemoryFrontmatter): string {\n const lines = [\n \"---\",\n `id: ${fm.id}`,\n `category: ${fm.category}`,\n `created: ${fm.created}`,\n `updated: ${fm.updated}`,\n `source: ${fm.source}`,\n `confidence: ${fm.confidence}`,\n `confidenceTier: ${fm.confidenceTier}`,\n `tags: [${fm.tags.map((t) => `\"${t}\"`).join(\", \")}]`,\n ];\n if (fm.entityRef) lines.push(`entityRef: ${fm.entityRef}`);\n if (fm.supersedes) lines.push(`supersedes: ${fm.supersedes}`);\n if (fm.expiresAt) lines.push(`expiresAt: ${fm.expiresAt}`);\n if (fm.lineage && fm.lineage.length > 0) {\n lines.push(`lineage: [${fm.lineage.map((l) => `\"${l}\"`).join(\", \")}]`);\n }\n // Status management\n if (fm.status && fm.status !== \"active\") lines.push(`status: ${fm.status}`);\n if (fm.supersededBy) lines.push(`supersededBy: ${fm.supersededBy}`);\n if (fm.supersededAt) lines.push(`supersededAt: ${fm.supersededAt}`);\n if (fm.archivedAt) lines.push(`archivedAt: ${fm.archivedAt}`);\n // Access tracking\n if (fm.accessCount !== undefined && fm.accessCount > 0) {\n lines.push(`accessCount: ${fm.accessCount}`);\n }\n if (fm.lastAccessed) lines.push(`lastAccessed: ${fm.lastAccessed}`);\n // Importance scoring\n if (fm.importance) {\n lines.push(`importanceScore: ${fm.importance.score}`);\n lines.push(`importanceLevel: ${fm.importance.level}`);\n if (fm.importance.reasons.length > 0) {\n lines.push(`importanceReasons: [${fm.importance.reasons.map((r) => `\"${r.replace(/\"/g, '\\\\\"')}\"`).join(\", \")}]`);\n }\n if (fm.importance.keywords.length > 0) {\n lines.push(`importanceKeywords: [${fm.importance.keywords.map((k) => `\"${k}\"`).join(\", \")}]`);\n }\n }\n // Chunking (Phase 2A)\n if (fm.parentId) lines.push(`parentId: ${fm.parentId}`);\n if (fm.chunkIndex !== undefined) lines.push(`chunkIndex: ${fm.chunkIndex}`);\n if (fm.chunkTotal !== undefined) lines.push(`chunkTotal: ${fm.chunkTotal}`);\n // Memory Linking (Phase 3A)\n if (fm.links && fm.links.length > 0) {\n lines.push(\"links:\");\n for (const link of fm.links) {\n lines.push(` - targetId: ${link.targetId}`);\n lines.push(` linkType: ${link.linkType}`);\n lines.push(` strength: ${link.strength}`);\n if (link.reason) lines.push(` reason: \"${link.reason.replace(/\"/g, '\\\\\"')}\"`);\n }\n }\n lines.push(\"---\");\n return lines.join(\"\\n\");\n}\n\nfunction parseFrontmatter(\n raw: string,\n): { frontmatter: MemoryFrontmatter; content: string } | null {\n const match = raw.match(/^---\\n([\\s\\S]*?)\\n---\\n?([\\s\\S]*)$/);\n if (!match) return null;\n\n const fmBlock = match[1];\n const content = match[2].trim();\n const fm: Record<string, string> = {};\n\n for (const line of fmBlock.split(\"\\n\")) {\n const colonIdx = line.indexOf(\":\");\n if (colonIdx === -1) continue;\n const key = line.slice(0, colonIdx).trim();\n const value = line.slice(colonIdx + 1).trim();\n fm[key] = value;\n }\n\n let tags: string[] = [];\n const tagsStr = fm.tags ?? \"\";\n const tagMatch = tagsStr.match(/\\[(.*)]/);\n if (tagMatch) {\n tags = tagMatch[1]\n .split(\",\")\n .map((t) => t.trim().replace(/^\"|\"$/g, \"\"))\n .filter(Boolean);\n }\n\n const conf = parseFloat(fm.confidence ?? \"0.8\");\n\n // Parse lineage array if present\n let lineage: string[] | undefined;\n const lineageStr = fm.lineage ?? \"\";\n const lineageMatch = lineageStr.match(/\\[(.*)]/);\n if (lineageMatch) {\n lineage = lineageMatch[1]\n .split(\",\")\n .map((l) => l.trim().replace(/^\"|\"$/g, \"\"))\n .filter(Boolean);\n }\n\n // Parse accessCount\n const accessCount = fm.accessCount ? parseInt(fm.accessCount, 10) : undefined;\n\n // Parse importance\n let importance: ImportanceScore | undefined;\n if (fm.importanceScore) {\n const score = parseFloat(fm.importanceScore);\n const level = (fm.importanceLevel as ImportanceLevel) || \"normal\";\n\n // Parse importance reasons array\n let reasons: string[] = [];\n const reasonsStr = fm.importanceReasons ?? \"\";\n const reasonsMatch = reasonsStr.match(/\\[(.*)]/);\n if (reasonsMatch) {\n reasons = reasonsMatch[1]\n .split(/\",\\s*\"/)\n .map((r) => r.replace(/^\"|\"$/g, \"\").replace(/\\\\\"/g, '\"'))\n .filter(Boolean);\n }\n\n // Parse importance keywords array\n let keywords: string[] = [];\n const keywordsStr = fm.importanceKeywords ?? \"\";\n const keywordsMatch = keywordsStr.match(/\\[(.*)]/);\n if (keywordsMatch) {\n keywords = keywordsMatch[1]\n .split(\",\")\n .map((k) => k.trim().replace(/^\"|\"$/g, \"\"))\n .filter(Boolean);\n }\n\n importance = { score, level, reasons, keywords };\n }\n\n const result: { frontmatter: MemoryFrontmatter; content: string } = {\n frontmatter: {\n id: fm.id ?? \"\",\n category: (fm.category ?? \"fact\") as MemoryCategory,\n created: fm.created ?? new Date().toISOString(),\n updated: fm.updated ?? new Date().toISOString(),\n source: fm.source ?? \"unknown\",\n confidence: conf,\n confidenceTier: (fm.confidenceTier as ConfidenceTier) || confidenceTier(conf),\n tags,\n entityRef: fm.entityRef || undefined,\n supersedes: fm.supersedes || undefined,\n expiresAt: fm.expiresAt || undefined,\n lineage: lineage && lineage.length > 0 ? lineage : undefined,\n // Status management\n status: (fm.status as MemoryStatus) || \"active\",\n supersededBy: fm.supersededBy || undefined,\n supersededAt: fm.supersededAt || undefined,\n archivedAt: fm.archivedAt || undefined,\n // Access tracking\n accessCount: accessCount && accessCount > 0 ? accessCount : undefined,\n lastAccessed: fm.lastAccessed || undefined,\n // Importance scoring\n importance,\n // Chunking\n parentId: fm.parentId || undefined,\n chunkIndex: fm.chunkIndex ? parseInt(fm.chunkIndex, 10) : undefined,\n chunkTotal: fm.chunkTotal ? parseInt(fm.chunkTotal, 10) : undefined,\n // Links are parsed separately below\n },\n content,\n };\n\n // Parse links (YAML array format)\n // Note: Simple parsing - for full YAML we'd need a library.\n if (fmBlock.includes(\"links:\")) {\n const links: MemoryLink[] = [];\n const linkMatches = fmBlock.matchAll(\n /- targetId: (\\S+)\\s+linkType: (\\S+)\\s+strength: ([\\d.]+)(?:\\s+reason: \"([^\"]*)\")?/g,\n );\n for (const match of linkMatches) {\n links.push({\n targetId: match[1],\n linkType: match[2] as MemoryLink[\"linkType\"],\n strength: parseFloat(match[3]),\n reason: match[4] || undefined,\n });\n }\n if (links.length > 0) {\n result.frontmatter.links = links;\n }\n }\n\n return result;\n}\n\n/**\n * Entity alias table loaded from the user's local config.\n * Populated by StorageManager.loadAliases() at startup.\n * Falls back to built-in structural aliases (e.g. \"open-claw\" → \"openclaw\").\n */\nlet userAliases: Record<string, string> = {};\n\n/** Built-in aliases for common structural normalizations (no personal data) */\nconst BUILTIN_ALIASES: Record<string, string> = {\n openclaw: \"openclaw\",\n \"open-claw\": \"openclaw\",\n};\n\n/**\n * Normalize an entity name to a canonical form.\n * Strips non-alphanumeric chars, collapses hyphens, removes type prefix duplication.\n * e.g. \"My Project\" → \"my-project\"\n *\n * Checks user-defined aliases (from config/aliases.json) first, then built-in aliases.\n */\nexport function normalizeEntityName(raw: string, type: string): string {\n // Strip type prefix if present (e.g. name=\"person-jane-doe\", type=\"person\")\n const rawStr = typeof raw === \"string\" ? raw : \"\";\n const typeStr = typeof type === \"string\" && type.trim().length > 0 ? type : \"entity\";\n\n let name = rawStr.toLowerCase().trim();\n const typePrefix = `${typeStr.toLowerCase()}-`;\n if (name.startsWith(typePrefix)) {\n name = name.slice(typePrefix.length);\n }\n\n // Replace non-alphanumeric with hyphens, collapse multiples, trim edges\n let normalized = name\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/-+/g, \"-\")\n .replace(/^-|-$/g, \"\");\n\n // Check user aliases first, then built-in\n if (userAliases[normalized]) {\n normalized = userAliases[normalized];\n } else if (BUILTIN_ALIASES[normalized]) {\n normalized = BUILTIN_ALIASES[normalized];\n }\n\n return `${typeStr.toLowerCase()}-${normalized}`;\n}\n\n/**\n * Simple Levenshtein distance between two strings.\n */\nfunction levenshtein(a: string, b: string): number {\n const m = a.length;\n const n = b.length;\n if (m === 0) return n;\n if (n === 0) return m;\n\n const dp: number[][] = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0));\n for (let i = 0; i <= m; i++) dp[i][0] = i;\n for (let j = 0; j <= n; j++) dp[0][j] = j;\n\n for (let i = 1; i <= m; i++) {\n for (let j = 1; j <= n; j++) {\n dp[i][j] = a[i - 1] === b[j - 1]\n ? dp[i - 1][j - 1]\n : 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);\n }\n }\n return dp[m][n];\n}\n\n/** Strip hyphens from a string for loose comparison */\nfunction dehyphenate(s: string): string {\n return s.replace(/-/g, \"\");\n}\n\n/**\n * Content-hash dedup index for facts.\n * Normalizes content (lowercase, strip punctuation, collapse whitespace),\n * computes SHA-256, and stores hashes in a line-delimited file.\n * Prevents writing semantically identical facts.\n */\nexport class ContentHashIndex {\n private hashes: Set<string> = new Set();\n private dirty = false;\n private readonly filePath: string;\n\n constructor(stateDir: string) {\n this.filePath = path.join(stateDir, \"fact-hashes.txt\");\n }\n\n /** Load existing hashes from disk. Safe to call multiple times. */\n async load(): Promise<void> {\n try {\n const raw = await readFile(this.filePath, \"utf-8\");\n for (const line of raw.split(\"\\n\")) {\n const trimmed = line.trim();\n if (trimmed.length > 0) {\n this.hashes.add(trimmed);\n }\n }\n log.debug(`content-hash index: loaded ${this.hashes.size} hashes`);\n } catch {\n log.debug(\"content-hash index: no existing index — starting fresh\");\n }\n }\n\n /** Check if content already exists in the index. */\n has(content: string): boolean {\n return this.hashes.has(ContentHashIndex.computeHash(content));\n }\n\n /** Add content hash to the index. */\n add(content: string): void {\n const hash = ContentHashIndex.computeHash(content);\n if (!this.hashes.has(hash)) {\n this.hashes.add(hash);\n this.dirty = true;\n }\n }\n\n get size(): number {\n return this.hashes.size;\n }\n\n /** Persist index to disk if changed. */\n async save(): Promise<void> {\n if (!this.dirty) return;\n await mkdir(path.dirname(this.filePath), { recursive: true });\n await writeFile(this.filePath, [...this.hashes].join(\"\\n\") + \"\\n\", \"utf-8\");\n this.dirty = false;\n log.debug(`content-hash index: saved ${this.hashes.size} hashes`);\n }\n\n /** Remove a hash from the index (used when archiving/deleting). */\n remove(content: string): void {\n const hash = ContentHashIndex.computeHash(content);\n if (this.hashes.delete(hash)) {\n this.dirty = true;\n }\n }\n\n /** Normalize content and compute SHA-256 hash. */\n static computeHash(content: string): string {\n const normalized = content\n .toLowerCase()\n .replace(/[^a-z0-9\\s]/g, \" \")\n .replace(/\\s+/g, \" \")\n .trim();\n return createHash(\"sha256\").update(normalized).digest(\"hex\");\n }\n}\n\n// ---------------------------------------------------------------------------\n// Entity file parsing / serialization (Knowledge Graph v7.0)\n// ---------------------------------------------------------------------------\n\n/**\n * Parse an entity markdown file into a structured EntityFile.\n * Backward compatible: old files without new sections get empty arrays.\n */\nexport function parseEntityFile(content: string): EntityFile {\n const lines = content.split(\"\\n\");\n\n // Header\n let name = \"\";\n let type = \"other\";\n let updated = \"\";\n let summary: string | undefined;\n const facts: string[] = [];\n const relationships: EntityRelationship[] = [];\n const activity: EntityActivityEntry[] = [];\n const aliases: string[] = [];\n\n // Parse name from first heading\n const headingLine = lines.find((l) => l.startsWith(\"# \"));\n if (headingLine) name = headingLine.slice(2).trim();\n\n // Parse type\n const typeLine = lines.find((l) => l.startsWith(\"**Type:**\"));\n if (typeLine) type = typeLine.replace(\"**Type:**\", \"\").trim();\n\n // Parse updated\n const updatedLine = lines.find((l) => l.startsWith(\"**Updated:**\"));\n if (updatedLine) updated = updatedLine.replace(\"**Updated:**\", \"\").trim();\n\n // Detect which section we're in\n let section = \"\";\n for (const line of lines) {\n if (line.startsWith(\"## \")) {\n section = line.slice(3).trim().toLowerCase();\n continue;\n }\n if (!line.startsWith(\"- \")) continue;\n\n const bullet = line.slice(2).trim();\n if (!bullet) continue;\n\n switch (section) {\n case \"facts\":\n facts.push(bullet);\n break;\n case \"summary\":\n // Summary is typically a single line after the heading, not a bullet\n break;\n case \"connected to\": {\n // Format: [[target-entity]] — relationship label\n const relMatch = bullet.match(/^\\[\\[([^\\]]+)\\]\\]\\s*[—–-]\\s*(.+)$/);\n if (relMatch) {\n relationships.push({ target: relMatch[1].trim(), label: relMatch[2].trim() });\n }\n break;\n }\n case \"activity\": {\n // Format: YYYY-MM-DD: note\n const actMatch = bullet.match(/^(\\d{4}-\\d{2}-\\d{2}):\\s*(.+)$/);\n if (actMatch) {\n activity.push({ date: actMatch[1], note: actMatch[2].trim() });\n }\n break;\n }\n case \"aliases\":\n aliases.push(bullet);\n break;\n }\n }\n\n // Parse summary: text between ## Summary heading and next ## heading (not bulleted)\n const summaryIdx = lines.findIndex((l) => l.startsWith(\"## Summary\"));\n if (summaryIdx !== -1) {\n const summaryLines: string[] = [];\n for (let i = summaryIdx + 1; i < lines.length; i++) {\n if (lines[i].startsWith(\"## \")) break;\n const trimmed = lines[i].trim();\n if (trimmed) summaryLines.push(trimmed);\n }\n if (summaryLines.length > 0) summary = summaryLines.join(\" \");\n }\n\n return { name, type, updated, facts, summary, relationships, activity, aliases };\n}\n\n/**\n * Serialize an EntityFile back to markdown.\n * Only emits sections that have content (except Facts which is always emitted).\n */\nexport function serializeEntityFile(entity: EntityFile): string {\n const lines: string[] = [\n `# ${entity.name}`,\n \"\",\n `**Type:** ${entity.type}`,\n `**Updated:** ${entity.updated || new Date().toISOString()}`,\n \"\",\n ];\n\n // Summary (optional)\n if (entity.summary) {\n lines.push(\"## Summary\", \"\", entity.summary, \"\");\n }\n\n // Facts (always emitted)\n lines.push(\"## Facts\", \"\");\n for (const f of entity.facts) {\n lines.push(`- ${f}`);\n }\n lines.push(\"\");\n\n // Connected to (optional)\n if (entity.relationships.length > 0) {\n lines.push(\"## Connected to\", \"\");\n for (const rel of entity.relationships) {\n lines.push(`- [[${rel.target}]] — ${rel.label}`);\n }\n lines.push(\"\");\n }\n\n // Activity (optional)\n if (entity.activity.length > 0) {\n lines.push(\"## Activity\", \"\");\n for (const act of entity.activity) {\n lines.push(`- ${act.date}: ${act.note}`);\n }\n lines.push(\"\");\n }\n\n // Aliases (optional)\n if (entity.aliases.length > 0) {\n lines.push(\"## Aliases\", \"\");\n for (const alias of entity.aliases) {\n lines.push(`- ${alias}`);\n }\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n\nexport class StorageManager {\n private knowledgeIndexCache: { result: string; builtAt: number } | null = null;\n private static readonly KNOWLEDGE_INDEX_CACHE_TTL_MS = 600_000; // 10 minutes (entity mutations invalidate)\n\n constructor(private readonly baseDir: string) {}\n\n private get factsDir(): string {\n return path.join(this.baseDir, \"facts\");\n }\n private get correctionsDir(): string {\n return path.join(this.baseDir, \"corrections\");\n }\n private get entitiesDir(): string {\n return path.join(this.baseDir, \"entities\");\n }\n private get stateDir(): string {\n return path.join(this.baseDir, \"state\");\n }\n private get questionsDir(): string {\n return path.join(this.baseDir, \"questions\");\n }\n private get profilePath(): string {\n return path.join(this.baseDir, \"profile.md\");\n }\n\n /**\n * Load user-defined entity aliases from config/aliases.json in the memory store.\n * File format: { \"variant\": \"canonical\", \"variant2\": \"canonical\", ... }\n * Call this once at startup (e.g. from orchestrator.initialize()).\n */\n async loadAliases(): Promise<void> {\n const aliasPath = path.join(this.baseDir, \"config\", \"aliases.json\");\n try {\n const raw = await readFile(aliasPath, \"utf-8\");\n const parsed = JSON.parse(raw);\n if (typeof parsed === \"object\" && parsed !== null) {\n userAliases = parsed as Record<string, string>;\n log.debug(`loaded ${Object.keys(userAliases).length} entity aliases from ${aliasPath}`);\n }\n } catch {\n // No aliases file — that's fine, use built-in only\n log.debug(\"no config/aliases.json found — using built-in aliases only\");\n }\n }\n\n async ensureDirectories(): Promise<void> {\n const today = new Date().toISOString().slice(0, 10);\n await mkdir(path.join(this.factsDir, today), { recursive: true });\n await mkdir(this.correctionsDir, { recursive: true });\n await mkdir(this.entitiesDir, { recursive: true });\n await mkdir(this.stateDir, { recursive: true });\n await mkdir(this.questionsDir, { recursive: true });\n await mkdir(path.join(this.baseDir, \"config\"), { recursive: true });\n }\n\n async writeMemory(\n category: MemoryCategory,\n content: string,\n options: {\n confidence?: number;\n tags?: string[];\n entityRef?: string;\n source?: string;\n supersedes?: string;\n lineage?: string[];\n importance?: ImportanceScore;\n links?: MemoryLink[];\n } = {},\n ): Promise<string> {\n await this.ensureDirectories();\n const now = new Date();\n const today = now.toISOString().slice(0, 10);\n const id = `${category}-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;\n const conf = options.confidence ?? 0.8;\n const tier = confidenceTier(conf);\n\n // Auto-set TTL for speculative memories\n let expiresAt: string | undefined;\n if (tier === \"speculative\") {\n const expiry = new Date(now.getTime() + SPECULATIVE_TTL_DAYS * 24 * 60 * 60 * 1000);\n expiresAt = expiry.toISOString();\n }\n\n const fm: MemoryFrontmatter = {\n id,\n category,\n created: now.toISOString(),\n updated: now.toISOString(),\n source: options.source ?? \"extraction\",\n confidence: conf,\n confidenceTier: tier,\n tags: options.tags ?? [],\n entityRef: options.entityRef,\n supersedes: options.supersedes,\n expiresAt,\n lineage: options.lineage,\n importance: options.importance,\n links: options.links,\n };\n\n const sanitized = sanitizeMemoryContent(content);\n if (!sanitized.clean) {\n log.warn(`memory content sanitized for ${id}; violations=${sanitized.violations.join(\", \")}`);\n }\n const fileContent = `${serializeFrontmatter(fm)}\\n\\n${sanitized.text}\\n`;\n\n let filePath: string;\n if (category === \"correction\") {\n filePath = path.join(this.correctionsDir, `${id}.md`);\n } else {\n filePath = path.join(this.factsDir, today, `${id}.md`);\n }\n\n await writeFile(filePath, fileContent, \"utf-8\");\n log.debug(`wrote memory ${id} to ${filePath}`);\n return id;\n }\n\n async writeEntity(\n name: string,\n type: string,\n facts: string[],\n ): Promise<string> {\n await this.ensureDirectories();\n if (typeof name !== \"string\" || !name.trim() || typeof type !== \"string\" || !type.trim()) {\n log.warn(\"writeEntity: invalid entity payload, skipping\", {\n nameType: typeof name,\n typeType: typeof type,\n });\n return \"\";\n }\n const safeFacts = Array.isArray(facts) ? facts.filter((f) => typeof f === \"string\") : [];\n let normalized = normalizeEntityName(name, type);\n\n // Check for fuzzy match against existing entities before creating a new file\n const match = await this.findMatchingEntity(name, type);\n if (match && match !== normalized) {\n log.debug(`fuzzy match: \"${normalized}\" → existing \"${match}\"`);\n normalized = match;\n }\n\n const filePath = path.join(this.entitiesDir, `${normalized}.md`);\n\n // Parse existing file to preserve relationships/activity/aliases/summary\n let entity: EntityFile = {\n name, type, updated: new Date().toISOString(),\n facts: [], summary: undefined, relationships: [], activity: [], aliases: [],\n };\n try {\n const existing = await readFile(filePath, \"utf-8\");\n entity = parseEntityFile(existing);\n } catch {\n // File doesn't exist yet\n }\n\n // Merge facts (dedup)\n entity.facts = [...new Set([...entity.facts, ...safeFacts])];\n entity.name = name;\n entity.type = type;\n entity.updated = new Date().toISOString();\n\n await writeFile(filePath, serializeEntityFile(entity), \"utf-8\");\n this.invalidateKnowledgeIndexCache();\n log.debug(`wrote entity ${normalized}`);\n return normalized;\n }\n\n async readProfile(): Promise<string> {\n try {\n return await readFile(this.profilePath, \"utf-8\");\n } catch {\n return \"\";\n }\n }\n\n async writeProfile(content: string): Promise<void> {\n await this.ensureDirectories();\n await writeFile(this.profilePath, content, \"utf-8\");\n log.debug(\"updated profile.md\");\n }\n\n /**\n * Normalize a string for fuzzy profile dedup: lowercase, strip punctuation, collapse whitespace.\n */\n private static normalizeForDedup(s: string): string {\n if (typeof s !== \"string\") return \"\";\n return s\n .toLowerCase()\n .replace(/[^a-z0-9\\s]/g, \" \")\n .replace(/\\s+/g, \" \")\n .trim();\n }\n\n /**\n * Check if a new bullet is a fuzzy duplicate of any existing bullet.\n * Returns true if the new bullet should be skipped.\n */\n private static isFuzzyDuplicate(newNorm: string, existingNorms: string[]): boolean {\n for (const existing of existingNorms) {\n // Exact normalized match\n if (newNorm === existing) return true;\n\n // Containment check: shorter must be >60% length of longer\n const shorter = newNorm.length <= existing.length ? newNorm : existing;\n const longer = newNorm.length > existing.length ? newNorm : existing;\n if (shorter.length > 20 && shorter.length / longer.length > 0.6 && longer.includes(shorter)) {\n return true;\n }\n }\n return false;\n }\n\n async appendToProfile(updates: string[]): Promise<void> {\n // Filter out non-string entries that the LLM may return\n updates = updates.filter((u) => typeof u === \"string\" && u.trim().length > 0);\n if (updates.length === 0) return;\n const existing = await this.readProfile();\n\n const lines = existing ? existing.split(\"\\n\") : [];\n const existingBulletRaw = lines\n .filter((l) => l.startsWith(\"- \"))\n .map((l) => l.slice(2).trim());\n const existingNorms = existingBulletRaw.map(StorageManager.normalizeForDedup);\n\n const newBullets = updates.filter((u) => {\n const norm = StorageManager.normalizeForDedup(u);\n return !StorageManager.isFuzzyDuplicate(norm, existingNorms);\n });\n if (newBullets.length === 0) return;\n\n if (!existing) {\n const content = [\n \"# Behavioral Profile\",\n \"\",\n `*Last updated: ${new Date().toISOString()}*`,\n \"\",\n ...newBullets.map((b) => `- ${b}`),\n \"\",\n ].join(\"\\n\");\n await this.writeProfile(content);\n } else {\n const updatedTimestamp = existing.replace(\n /\\*Last updated:.*\\*/,\n `*Last updated: ${new Date().toISOString()}*`,\n );\n const withBullets = updatedTimestamp.trimEnd() + \"\\n\" + newBullets.map((b) => `- ${b}`).join(\"\\n\") + \"\\n\";\n await this.writeProfile(withBullets);\n }\n }\n\n /** Check if profile.md exceeds the max line cap and needs LLM consolidation */\n async profileNeedsConsolidation(): Promise<boolean> {\n const profile = await this.readProfile();\n if (!profile) return false;\n const lineCount = profile.split(\"\\n\").length;\n return lineCount > StorageManager.PROFILE_MAX_LINES;\n }\n\n async readAllMemories(): Promise<MemoryFile[]> {\n const memories: MemoryFile[] = [];\n\n const readDir = async (dir: string) => {\n try {\n const entries = await readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n await readDir(fullPath);\n } else if (entry.name.endsWith(\".md\")) {\n try {\n const raw = await readFile(fullPath, \"utf-8\");\n const parsed = parseFrontmatter(raw);\n if (parsed) {\n memories.push({\n path: fullPath,\n frontmatter: parsed.frontmatter,\n content: parsed.content,\n });\n }\n } catch {\n // Skip unreadable files\n }\n }\n }\n } catch {\n // Directory doesn't exist yet\n }\n };\n\n await readDir(this.factsDir);\n await readDir(this.correctionsDir);\n return memories;\n }\n\n /** Read a single memory file by its absolute path. Returns null if unreadable. */\n async readMemoryByPath(filePath: string): Promise<MemoryFile | null> {\n try {\n const raw = await readFile(filePath, \"utf-8\");\n const parsed = parseFrontmatter(raw);\n if (!parsed) return null;\n return { path: filePath, frontmatter: parsed.frontmatter, content: parsed.content };\n } catch {\n return null;\n }\n }\n\n private get archiveDir(): string {\n return path.join(this.baseDir, \"archive\");\n }\n\n /**\n * Archive a memory by moving it from facts/ to archive/YYYY-MM-DD/.\n * Updates frontmatter with archived status before moving.\n * Returns the new file path on success, null on failure.\n */\n async archiveMemory(memory: MemoryFile): Promise<string | null> {\n try {\n const now = new Date();\n const today = now.toISOString().slice(0, 10);\n const destDir = path.join(this.archiveDir, today);\n await mkdir(destDir, { recursive: true });\n\n // Update frontmatter to reflect archived status\n const updatedFm: MemoryFrontmatter = {\n ...memory.frontmatter,\n status: \"archived\",\n archivedAt: now.toISOString(),\n updated: now.toISOString(),\n };\n\n const fileContent = `${serializeFrontmatter(updatedFm)}\\n\\n${memory.content}\\n`;\n const destPath = path.join(destDir, path.basename(memory.path));\n\n // Write to archive location first, then remove original\n await writeFile(destPath, fileContent, \"utf-8\");\n await unlink(memory.path);\n\n log.debug(`archived memory ${memory.frontmatter.id} → ${destPath}`);\n return destPath;\n } catch (err) {\n log.warn(`failed to archive memory ${memory.frontmatter.id}: ${err}`);\n return null;\n }\n }\n\n async readEntities(): Promise<string[]> {\n try {\n const entries = await readdir(this.entitiesDir);\n return entries.filter((e) => e.endsWith(\".md\")).map((e) => e.replace(\".md\", \"\"));\n } catch {\n return [];\n }\n }\n\n async readEntity(name: string): Promise<string> {\n try {\n return await readFile(path.join(this.entitiesDir, `${name}.md`), \"utf-8\");\n } catch {\n return \"\";\n }\n }\n\n /** Return sorted list of entity filenames (without .md extension) */\n async listEntityNames(): Promise<string[]> {\n try {\n const entries = await readdir(this.entitiesDir);\n return entries\n .filter((e) => e.endsWith(\".md\"))\n .map((e) => e.replace(\".md\", \"\"))\n .sort();\n } catch {\n return [];\n }\n }\n\n /**\n * Find an existing entity that fuzzy-matches the proposed name.\n * Returns the existing entity filename (without .md) or null if no match.\n *\n * Matching priority:\n * 1. Exact normalized match (handled by normalizeEntityName already)\n * 2. Dehyphenated match: \"jane-doe\" vs \"janedoe\"\n * 3. Substring containment: \"handle-janedoe\" contains \"janedoe\"\n * 4. Levenshtein ≤ 2 on dehyphenated names\n */\n async findMatchingEntity(proposedName: string, type: string): Promise<string | null> {\n const existing = await this.listEntityNames();\n if (existing.length === 0) return null;\n\n const typePrefix = `${type.toLowerCase()}-`;\n // Extract the name part from the proposed normalized name\n const proposedFull = normalizeEntityName(proposedName, type);\n const proposedNamePart = proposedFull.startsWith(typePrefix)\n ? proposedFull.slice(typePrefix.length)\n : proposedFull;\n const proposedDehyph = dehyphenate(proposedNamePart);\n\n // Only compare against entities of the same type\n const sameType = existing.filter((e) => e.startsWith(typePrefix));\n\n for (const entity of sameType) {\n const entityNamePart = entity.slice(typePrefix.length);\n const entityDehyph = dehyphenate(entityNamePart);\n\n // Already the exact normalized form\n if (entity === proposedFull) return entity;\n\n // Dehyphenated exact match\n if (entityDehyph === proposedDehyph) return entity;\n\n // Substring containment (shorter must be >60% length of longer)\n const shorter = proposedDehyph.length <= entityDehyph.length ? proposedDehyph : entityDehyph;\n const longer = proposedDehyph.length > entityDehyph.length ? proposedDehyph : entityDehyph;\n if (shorter.length > 3 && shorter.length / longer.length > 0.6 && longer.includes(shorter)) {\n return entity;\n }\n\n // Levenshtein distance ≤ 2 (only for names of reasonable length)\n if (proposedDehyph.length >= 4 && entityDehyph.length >= 4) {\n const dist = levenshtein(proposedDehyph, entityDehyph);\n if (dist <= 2) return entity;\n }\n }\n\n return null;\n }\n\n async invalidateMemory(id: string): Promise<boolean> {\n const memories = await this.readAllMemories();\n const memory = memories.find((m) => m.frontmatter.id === id);\n if (!memory) return false;\n\n try {\n await unlink(memory.path);\n log.debug(`invalidated memory ${id}`);\n return true;\n } catch {\n return false;\n }\n }\n\n async updateMemory(\n id: string,\n newContent: string,\n options?: { supersedes?: string; lineage?: string[] },\n ): Promise<boolean> {\n const memories = await this.readAllMemories();\n const memory = memories.find((m) => m.frontmatter.id === id);\n if (!memory) return false;\n\n const mergedLineage = [\n ...(memory.frontmatter.lineage ?? []),\n ...(options?.lineage ?? []),\n ].filter((v, i, a) => a.indexOf(v) === i); // dedupe\n\n const updated: MemoryFrontmatter = {\n ...memory.frontmatter,\n updated: new Date().toISOString(),\n supersedes: options?.supersedes ?? memory.frontmatter.supersedes,\n lineage: mergedLineage.length > 0 ? mergedLineage : undefined,\n };\n const sanitized = sanitizeMemoryContent(newContent);\n if (!sanitized.clean) {\n log.warn(`updated memory content sanitized for ${id}; violations=${sanitized.violations.join(\", \")}`);\n }\n const fileContent = `${serializeFrontmatter(updated)}\\n\\n${sanitized.text}\\n`;\n await writeFile(memory.path, fileContent, \"utf-8\");\n log.debug(`updated memory ${id}`);\n return true;\n }\n\n /** Remove memories past their TTL expiresAt date */\n async cleanExpiredTTL(): Promise<number> {\n const memories = await this.readAllMemories();\n const now = Date.now();\n let cleaned = 0;\n\n for (const m of memories) {\n if (!m.frontmatter.expiresAt) continue;\n const expiresAt = new Date(m.frontmatter.expiresAt).getTime();\n if (expiresAt < now) {\n try {\n await unlink(m.path);\n cleaned++;\n log.debug(`cleaned expired memory ${m.frontmatter.id} (TTL expired)`);\n } catch {\n // Ignore\n }\n }\n }\n\n return cleaned;\n }\n\n async loadBuffer(): Promise<BufferState> {\n const bufferPath = path.join(this.stateDir, \"buffer.json\");\n try {\n const raw = await readFile(bufferPath, \"utf-8\");\n return JSON.parse(raw) as BufferState;\n } catch {\n return { turns: [], lastExtractionAt: null, extractionCount: 0 };\n }\n }\n\n async saveBuffer(state: BufferState): Promise<void> {\n await this.ensureDirectories();\n const bufferPath = path.join(this.stateDir, \"buffer.json\");\n await writeFile(bufferPath, JSON.stringify(state, null, 2), \"utf-8\");\n }\n\n async loadMeta(): Promise<MetaState> {\n const metaPath = path.join(this.stateDir, \"meta.json\");\n try {\n const raw = await readFile(metaPath, \"utf-8\");\n return JSON.parse(raw) as MetaState;\n } catch {\n return {\n extractionCount: 0,\n lastExtractionAt: null,\n lastConsolidationAt: null,\n totalMemories: 0,\n totalEntities: 0,\n };\n }\n }\n\n async saveMeta(state: MetaState): Promise<void> {\n await this.ensureDirectories();\n const metaPath = path.join(this.stateDir, \"meta.json\");\n await writeFile(metaPath, JSON.stringify(state, null, 2), \"utf-8\");\n }\n\n // ---------------------------------------------------------------------------\n // Question storage\n // ---------------------------------------------------------------------------\n\n private generateId(prefix: string = \"m\"): string {\n const ts = Date.now().toString(36);\n const rand = Math.random().toString(36).slice(2, 4);\n return `${prefix}-${ts}-${rand}`;\n }\n\n async writeQuestion(\n question: string,\n context: string,\n priority: number,\n ): Promise<string> {\n await mkdir(this.questionsDir, { recursive: true });\n\n const id = this.generateId(\"q\");\n const frontmatter = {\n id,\n created: new Date().toISOString(),\n priority,\n resolved: false,\n };\n\n const content = `---\\n${Object.entries(frontmatter).map(([k, v]) => `${k}: ${JSON.stringify(v)}`).join(\"\\n\")}\\n---\\n\\n${question}\\n\\n**Context:** ${context}\\n`;\n\n const filePath = path.join(this.questionsDir, `${id}.md`);\n await writeFile(filePath, content, \"utf-8\");\n log.debug(`wrote question ${id} to ${filePath}`);\n return id;\n }\n\n async readQuestions(\n opts?: { unresolvedOnly?: boolean },\n ): Promise<\n Array<{\n id: string;\n question: string;\n context: string;\n priority: number;\n resolved: boolean;\n created: string;\n filePath: string;\n }>\n > {\n try {\n const files = await readdir(this.questionsDir);\n const questions = [];\n for (const file of files) {\n if (!file.endsWith(\".md\")) continue;\n const filePath = path.join(this.questionsDir, file);\n const raw = await readFile(filePath, \"utf-8\");\n const parsed = this.parseQuestionFile(raw, filePath);\n if (parsed) {\n if (opts?.unresolvedOnly && parsed.resolved) continue;\n questions.push(parsed);\n }\n }\n return questions.sort((a, b) => b.priority - a.priority);\n } catch {\n return [];\n }\n }\n\n private parseQuestionFile(\n raw: string,\n filePath: string,\n ): {\n id: string;\n question: string;\n context: string;\n priority: number;\n resolved: boolean;\n created: string;\n filePath: string;\n } | null {\n const match = raw.match(/^---\\n([\\s\\S]*?)\\n---\\n\\n([\\s\\S]*)$/);\n if (!match) return null;\n\n const frontmatterStr = match[1];\n const body = match[2].trim();\n\n // Parse frontmatter\n const id =\n this.extractFrontmatterValue(frontmatterStr, \"id\") ??\n path.basename(filePath, \".md\");\n const created =\n this.extractFrontmatterValue(frontmatterStr, \"created\") ?? \"\";\n const priority = parseFloat(\n this.extractFrontmatterValue(frontmatterStr, \"priority\") ?? \"0.5\",\n );\n const resolved =\n this.extractFrontmatterValue(frontmatterStr, \"resolved\") === \"true\";\n\n // Extract question and context from body\n const contextMatch = body.match(/\\*\\*Context:\\*\\*\\s*(.*)/);\n const question = contextMatch\n ? body.slice(0, contextMatch.index).trim()\n : body;\n const context = contextMatch ? contextMatch[1].trim() : \"\";\n\n return { id, question, context, priority, resolved, created, filePath };\n }\n\n private extractFrontmatterValue(\n frontmatter: string,\n key: string,\n ): string | null {\n const match = frontmatter.match(\n new RegExp(`^${key}:\\\\s*\"?([^\"\\\\n]*)\"?`, \"m\"),\n );\n return match ? match[1] : null;\n }\n\n async resolveQuestion(id: string): Promise<boolean> {\n const questions = await this.readQuestions();\n const q = questions.find((q) => q.id === id);\n if (!q) return false;\n\n let raw = await readFile(q.filePath, \"utf-8\");\n raw = raw.replace(/resolved: false/, \"resolved: true\");\n raw = raw.replace(\n /---\\n\\n/,\n `resolvedAt: \"${new Date().toISOString()}\"\\n---\\n\\n`,\n );\n await writeFile(q.filePath, raw, \"utf-8\");\n log.debug(`resolved question ${id}`);\n return true;\n }\n\n // ---------------------------------------------------------------------------\n // Identity file\n // ---------------------------------------------------------------------------\n\n async readIdentity(workspaceDir: string): Promise<string> {\n const identityPath = path.join(workspaceDir, \"IDENTITY.md\");\n try {\n return await readFile(identityPath, \"utf-8\");\n } catch {\n return \"\";\n }\n }\n\n async writeIdentity(workspaceDir: string, content: string): Promise<void> {\n const identityPath = path.join(workspaceDir, \"IDENTITY.md\");\n await writeFile(identityPath, content, \"utf-8\");\n log.debug(`wrote consolidated IDENTITY.md (${content.length} chars)`);\n }\n\n /** Max size for IDENTITY.md before we stop appending reflections (15KB leaves room under 20KB gateway limit) */\n private static readonly IDENTITY_MAX_BYTES = 15_000;\n /** Minimum interval between reflections (1 hour) */\n private static readonly REFLECTION_COOLDOWN_MS = 60 * 60 * 1000;\n\n async appendToIdentity(\n workspaceDir: string,\n reflection: string,\n opts?: { hygiene?: FileHygieneConfig },\n ): Promise<void> {\n const identityPath = path.join(workspaceDir, \"IDENTITY.md\");\n\n let existing = \"\";\n try {\n existing = await readFile(identityPath, \"utf-8\");\n } catch {\n // File doesn't exist yet\n }\n\n const hygiene = opts?.hygiene;\n const rotateEnabled =\n hygiene?.enabled === true &&\n hygiene.rotateEnabled === true &&\n Array.isArray(hygiene.rotatePaths) &&\n hygiene.rotatePaths.includes(\"IDENTITY.md\");\n\n // Rotation/splitting: preserve full history, keep the bootstrap file small.\n if (rotateEnabled) {\n const maxBytes = hygiene.rotateMaxBytes;\n if (existing.length > maxBytes) {\n const archiveDir = path.join(workspaceDir, hygiene.archiveDir);\n const { newContent } = await rotateMarkdownFileToArchive({\n filePath: identityPath,\n archiveDir,\n archivePrefix: \"IDENTITY\",\n keepTailChars: hygiene.rotateKeepTailChars,\n });\n await writeFile(identityPath, newContent, \"utf-8\");\n existing = newContent;\n log.info(\n `rotated IDENTITY.md to archive (size=${existing.length} chars, maxBytes=${maxBytes})`,\n );\n }\n } else {\n // Legacy behavior: skip if file is too large\n if (existing.length > StorageManager.IDENTITY_MAX_BYTES) {\n log.debug(`IDENTITY.md is ${existing.length} chars (limit ${StorageManager.IDENTITY_MAX_BYTES}); skipping reflection`);\n return;\n }\n }\n\n // Rate-limit: skip if last reflection was less than 1 hour ago\n const lastMatch = existing.match(/## Reflection — (\\S+)\\s*$/m);\n if (lastMatch) {\n // Find the LAST reflection timestamp\n const allMatches = [...existing.matchAll(/## Reflection — (\\S+)/g)];\n if (allMatches.length > 0) {\n const lastTimestamp = allMatches[allMatches.length - 1][1];\n const elapsed = Date.now() - new Date(lastTimestamp).getTime();\n if (elapsed < StorageManager.REFLECTION_COOLDOWN_MS) {\n log.debug(`reflection cooldown: ${Math.round(elapsed / 1000)}s since last (need ${StorageManager.REFLECTION_COOLDOWN_MS / 1000}s)`);\n return;\n }\n }\n }\n\n const timestamp = new Date().toISOString();\n const section = `\\n\\n## Reflection — ${timestamp}\\n\\n${reflection}\\n`;\n\n await writeFile(identityPath, existing + section, \"utf-8\");\n log.debug(`appended reflection to ${identityPath}`);\n }\n\n // ---------------------------------------------------------------------------\n // Entity mutation helpers (Knowledge Graph v7.0)\n // ---------------------------------------------------------------------------\n\n /**\n * Add a relationship to an entity file.\n * Deduplicates by target+label.\n */\n async addEntityRelationship(name: string, rel: EntityRelationship): Promise<void> {\n const filePath = path.join(this.entitiesDir, `${name}.md`);\n let entity: EntityFile;\n try {\n const content = await readFile(filePath, \"utf-8\");\n entity = parseEntityFile(content);\n } catch {\n log.debug(`addEntityRelationship: entity file ${name}.md not found`);\n return;\n }\n\n // Dedupe by target+label\n const exists = entity.relationships.some(\n (r) => r.target === rel.target && r.label === rel.label,\n );\n if (exists) return;\n\n entity.relationships.push(rel);\n entity.updated = new Date().toISOString();\n await writeFile(filePath, serializeEntityFile(entity), \"utf-8\");\n this.invalidateKnowledgeIndexCache();\n }\n\n /**\n * Add an activity entry to an entity file.\n * Prepends to the beginning, prunes oldest entries beyond maxEntries.\n */\n async addEntityActivity(\n name: string,\n entry: EntityActivityEntry,\n maxEntries: number,\n ): Promise<void> {\n const filePath = path.join(this.entitiesDir, `${name}.md`);\n let entity: EntityFile;\n try {\n const content = await readFile(filePath, \"utf-8\");\n entity = parseEntityFile(content);\n } catch {\n log.debug(`addEntityActivity: entity file ${name}.md not found`);\n return;\n }\n\n entity.activity.unshift(entry);\n if (entity.activity.length > maxEntries) {\n entity.activity = entity.activity.slice(0, maxEntries);\n }\n entity.updated = new Date().toISOString();\n await writeFile(filePath, serializeEntityFile(entity), \"utf-8\");\n this.invalidateKnowledgeIndexCache();\n }\n\n /**\n * Add an alias to an entity file. Deduplicates.\n */\n async addEntityAlias(name: string, alias: string): Promise<void> {\n const filePath = path.join(this.entitiesDir, `${name}.md`);\n let entity: EntityFile;\n try {\n const content = await readFile(filePath, \"utf-8\");\n entity = parseEntityFile(content);\n } catch {\n log.debug(`addEntityAlias: entity file ${name}.md not found`);\n return;\n }\n\n if (entity.aliases.includes(alias)) return;\n entity.aliases.push(alias);\n entity.updated = new Date().toISOString();\n await writeFile(filePath, serializeEntityFile(entity), \"utf-8\");\n this.invalidateKnowledgeIndexCache();\n }\n\n /**\n * Set or update the summary of an entity file.\n */\n async updateEntitySummary(name: string, summary: string): Promise<void> {\n const filePath = path.join(this.entitiesDir, `${name}.md`);\n let entity: EntityFile;\n try {\n const content = await readFile(filePath, \"utf-8\");\n entity = parseEntityFile(content);\n } catch {\n log.debug(`updateEntitySummary: entity file ${name}.md not found`);\n return;\n }\n\n entity.summary = summary;\n entity.updated = new Date().toISOString();\n await writeFile(filePath, serializeEntityFile(entity), \"utf-8\");\n this.invalidateKnowledgeIndexCache();\n }\n\n // ---------------------------------------------------------------------------\n // Scoring + Knowledge Index (Knowledge Graph v7.0)\n // ---------------------------------------------------------------------------\n\n /**\n * Read all entity files and return lightweight EntityFile objects.\n * Parsing is fast (~50-100ms for ~1,800 files) since entity files are small.\n */\n async readAllEntityFiles(): Promise<EntityFile[]> {\n const entities: EntityFile[] = [];\n try {\n const entries = await readdir(this.entitiesDir);\n for (const entry of entries) {\n if (!entry.endsWith(\".md\")) continue;\n try {\n const content = await readFile(\n path.join(this.entitiesDir, entry),\n \"utf-8\",\n );\n entities.push(parseEntityFile(content));\n } catch {\n // Skip unreadable files\n }\n }\n } catch {\n // Directory doesn't exist yet\n }\n return entities;\n }\n\n /**\n * Score an entity based on recency, frequency, activity, type priority,\n * and relationship density.\n *\n * score = recency*0.40 + frequency*0.25 + activity*0.15 + typePriority*0.10 + relationshipDensity*0.10\n */\n static scoreEntity(entity: EntityFile, now: Date): number {\n // Recency: 1 / (1 + daysSince/7) — 7-day half-life\n const updated = entity.updated ? new Date(entity.updated).getTime() : 0;\n const daysSince = Math.max(0, (now.getTime() - updated) / (1000 * 60 * 60 * 24));\n const recency = 1 / (1 + daysSince / 7);\n\n // Frequency: min(facts.length / 20, 1.0)\n const frequency = Math.min(entity.facts.length / 20, 1.0);\n\n // Activity: min(activity.length / 10, 1.0)\n const activityScore = Math.min(entity.activity.length / 10, 1.0);\n\n // Type priority\n const TYPE_PRIORITY: Record<string, number> = {\n person: 1.0,\n project: 0.8,\n company: 0.7,\n tool: 0.6,\n place: 0.5,\n other: 0.3,\n };\n const typePriority = TYPE_PRIORITY[entity.type.toLowerCase()] ?? 0.3;\n\n // Relationship density: min(relationships.length / 8, 1.0)\n const relDensity = Math.min(entity.relationships.length / 8, 1.0);\n\n return (\n recency * 0.40 +\n frequency * 0.25 +\n activityScore * 0.15 +\n typePriority * 0.10 +\n relDensity * 0.10\n );\n }\n\n /**\n * Build the Knowledge Index: a compact markdown table of top-scored entities.\n * Respects maxEntities and maxChars limits from config.\n */\n async buildKnowledgeIndex(config: PluginConfig): Promise<{ result: string; cached: boolean }> {\n // Return cached index if still fresh\n if (\n this.knowledgeIndexCache &&\n Date.now() - this.knowledgeIndexCache.builtAt < StorageManager.KNOWLEDGE_INDEX_CACHE_TTL_MS\n ) {\n return { result: this.knowledgeIndexCache.result, cached: true };\n }\n\n const entities = await this.readAllEntityFiles();\n if (entities.length === 0) {\n this.knowledgeIndexCache = { result: \"\", builtAt: Date.now() };\n return { result: \"\", cached: false };\n }\n\n const now = new Date();\n const scored: ScoredEntity[] = entities.map((e) => ({\n name: e.name,\n type: e.type,\n score: StorageManager.scoreEntity(e, now),\n factCount: e.facts.length,\n summary: e.summary,\n topRelationships: e.relationships.slice(0, 3).map((r) => r.target),\n }));\n\n // Sort by score descending, take top N\n scored.sort((a, b) => b.score - a.score);\n const topN = scored.slice(0, config.knowledgeIndexMaxEntities);\n\n if (topN.length === 0) {\n this.knowledgeIndexCache = { result: \"\", builtAt: Date.now() };\n return { result: \"\", cached: false };\n }\n\n // Build markdown table\n const header = \"## Knowledge Index\\n\\n| Entity | Type | Summary | Connected to |\\n|--------|------|---------|-------------|\";\n const rows: string[] = [];\n let totalChars = header.length;\n\n for (const entity of topN) {\n const summary = entity.summary || `${entity.factCount} facts`;\n const connected = entity.topRelationships.length > 0\n ? entity.topRelationships.join(\", \")\n : \"—\";\n const row = `| ${entity.name} | ${entity.type} | ${summary} | ${connected} |`;\n\n if (totalChars + row.length + 1 > config.knowledgeIndexMaxChars) break;\n rows.push(row);\n totalChars += row.length + 1;\n }\n\n const result = rows.length === 0 ? \"\" : `${header}\\n${rows.join(\"\\n\")}\\n`;\n this.knowledgeIndexCache = { result, builtAt: Date.now() };\n return { result, cached: false };\n }\n\n /** Invalidate the Knowledge Index cache (call after entity mutations). */\n invalidateKnowledgeIndexCache(): void {\n this.knowledgeIndexCache = null;\n }\n\n // ---------------------------------------------------------------------------\n // Commitment decay\n // ---------------------------------------------------------------------------\n\n /** Max lines for profile.md before LLM consolidation triggers */\n private static readonly PROFILE_MAX_LINES = 300;\n\n /**\n * Merge fragmented entity files that resolve to the same canonical name.\n * Preserves relationships, activity, aliases, and summary from all fragments.\n * Returns count of files merged.\n */\n async mergeFragmentedEntities(): Promise<number> {\n let merged = 0;\n try {\n const entries = await readdir(this.entitiesDir);\n const mdFiles = entries.filter((e) => e.endsWith(\".md\"));\n\n // Group files by their canonical name\n const groups = new Map<string, string[]>();\n for (const file of mdFiles) {\n const baseName = file.replace(\".md\", \"\");\n // Extract type and name from filename (type-rest-of-name)\n const dashIdx = baseName.indexOf(\"-\");\n if (dashIdx === -1) continue;\n const type = baseName.slice(0, dashIdx);\n const restOfName = baseName.slice(dashIdx + 1);\n const canonical = normalizeEntityName(restOfName, type);\n\n if (!groups.has(canonical)) groups.set(canonical, []);\n groups.get(canonical)!.push(file);\n }\n\n // Merge groups with more than one file\n for (const [canonical, files] of groups) {\n if (files.length <= 1) continue;\n\n // Parse all files and merge into a single EntityFile\n const mergedEntity: EntityFile = {\n name: \"\",\n type: \"other\",\n updated: \"\",\n facts: [],\n summary: undefined,\n relationships: [],\n activity: [],\n aliases: [],\n };\n\n for (const file of files) {\n const filePath = path.join(this.entitiesDir, file);\n try {\n const content = await readFile(filePath, \"utf-8\");\n const parsed = parseEntityFile(content);\n\n // Prefer specific types over \"other\"\n if (!mergedEntity.type || mergedEntity.type === \"other\") {\n mergedEntity.type = parsed.type;\n }\n\n // Keep latest update time\n if (!mergedEntity.updated || parsed.updated > mergedEntity.updated) {\n mergedEntity.updated = parsed.updated;\n }\n\n // Keep longest/best name\n if (parsed.name.length > mergedEntity.name.length) {\n mergedEntity.name = parsed.name;\n }\n\n // Keep first non-empty summary\n if (!mergedEntity.summary && parsed.summary) {\n mergedEntity.summary = parsed.summary;\n }\n\n // Collect all facts\n mergedEntity.facts.push(...parsed.facts);\n\n // Collect relationships (dedup later)\n mergedEntity.relationships.push(...parsed.relationships);\n\n // Collect activity entries\n mergedEntity.activity.push(...parsed.activity);\n\n // Collect aliases\n mergedEntity.aliases.push(...parsed.aliases);\n } catch {\n // Skip unreadable\n }\n }\n\n // Deduplicate facts\n mergedEntity.facts = [...new Set(mergedEntity.facts)];\n\n // Deduplicate relationships by target+label\n const relKeys = new Set<string>();\n mergedEntity.relationships = mergedEntity.relationships.filter((r) => {\n const key = `${r.target}::${r.label}`;\n if (relKeys.has(key)) return false;\n relKeys.add(key);\n return true;\n });\n\n // Sort activity by date descending, deduplicate by date+note\n const actKeys = new Set<string>();\n mergedEntity.activity = mergedEntity.activity\n .filter((a) => {\n const key = `${a.date}::${a.note}`;\n if (actKeys.has(key)) return false;\n actKeys.add(key);\n return true;\n })\n .sort((a, b) => b.date.localeCompare(a.date));\n\n // Deduplicate aliases\n mergedEntity.aliases = [...new Set(mergedEntity.aliases)];\n\n // Fallback name from canonical\n if (!mergedEntity.name) {\n const dashIdx = canonical.indexOf(\"-\");\n mergedEntity.name = dashIdx !== -1 ? canonical.slice(dashIdx + 1) : canonical;\n }\n\n mergedEntity.updated = mergedEntity.updated || new Date().toISOString();\n\n const canonicalPath = path.join(this.entitiesDir, `${canonical}.md`);\n await writeFile(canonicalPath, serializeEntityFile(mergedEntity), \"utf-8\");\n\n // Remove non-canonical files\n for (const file of files) {\n const filePath = path.join(this.entitiesDir, file);\n if (filePath !== canonicalPath) {\n try {\n await unlink(filePath);\n merged++;\n log.debug(`merged entity ${file} → ${canonical}.md`);\n } catch {\n // Ignore\n }\n }\n }\n }\n } catch {\n // Directory doesn't exist yet\n }\n\n return merged;\n }\n\n async cleanExpiredCommitments(decayDays: number): Promise<number> {\n const memories = await this.readAllMemories();\n const cutoff = Date.now() - decayDays * 24 * 60 * 60 * 1000;\n let cleaned = 0;\n\n for (const m of memories) {\n if (m.frontmatter.category !== \"commitment\") continue;\n // Only decay commitments that have been marked as resolved/expired\n // (indicated by tags containing \"fulfilled\" or \"expired\")\n const isResolved = m.frontmatter.tags.some(\n (t) => t === \"fulfilled\" || t === \"expired\",\n );\n if (!isResolved) continue;\n\n const updatedAt = new Date(m.frontmatter.updated).getTime();\n if (updatedAt < cutoff) {\n // Remove the file\n try {\n await unlink(m.path);\n cleaned++;\n log.debug(`cleaned expired commitment ${m.frontmatter.id}`);\n } catch {\n // Ignore\n }\n }\n }\n\n return cleaned;\n }\n\n // ---------------------------------------------------------------------------\n // Access Tracking (Phase 1A)\n // ---------------------------------------------------------------------------\n\n /**\n * Flush batched access tracking updates to disk.\n * Called during consolidation or when buffer exceeds max size.\n */\n async flushAccessTracking(entries: AccessTrackingEntry[]): Promise<number> {\n if (entries.length === 0) return 0;\n\n const memories = await this.readAllMemories();\n const memoryMap = new Map(memories.map((m) => [m.frontmatter.id, m]));\n let updated = 0;\n\n for (const entry of entries) {\n const memory = memoryMap.get(entry.memoryId);\n if (!memory) continue;\n\n const newFm: MemoryFrontmatter = {\n ...memory.frontmatter,\n accessCount: entry.newCount,\n lastAccessed: entry.lastAccessed,\n };\n\n const fileContent = `${serializeFrontmatter(newFm)}\\n\\n${memory.content}\\n`;\n try {\n await writeFile(memory.path, fileContent, \"utf-8\");\n updated++;\n } catch (err) {\n log.debug(`failed to update access tracking for ${entry.memoryId}: ${err}`);\n }\n }\n\n if (updated > 0) {\n log.debug(`flushed access tracking for ${updated} memories`);\n }\n return updated;\n }\n\n /**\n * Get a memory by its ID.\n */\n async getMemoryById(id: string): Promise<MemoryFile | null> {\n const memories = await this.readAllMemories();\n return memories.find((m) => m.frontmatter.id === id) ?? null;\n }\n\n // ---------------------------------------------------------------------------\n // Chunking (Phase 2A)\n // ---------------------------------------------------------------------------\n\n /**\n * Write a memory chunk with parent reference.\n * Chunk IDs follow format: {parentId}-chunk-{index}\n */\n async writeChunk(\n parentId: string,\n chunkIndex: number,\n chunkTotal: number,\n category: MemoryCategory,\n content: string,\n options: {\n confidence?: number;\n tags?: string[];\n entityRef?: string;\n source?: string;\n importance?: ImportanceScore;\n } = {},\n ): Promise<string> {\n await this.ensureDirectories();\n const now = new Date();\n const today = now.toISOString().slice(0, 10);\n const id = `${parentId}-chunk-${chunkIndex}`;\n const conf = options.confidence ?? 0.8;\n const tier = confidenceTier(conf);\n\n const fm: MemoryFrontmatter = {\n id,\n category,\n created: now.toISOString(),\n updated: now.toISOString(),\n source: options.source ?? \"chunking\",\n confidence: conf,\n confidenceTier: tier,\n tags: options.tags ?? [],\n entityRef: options.entityRef,\n importance: options.importance,\n parentId,\n chunkIndex,\n chunkTotal,\n };\n\n const sanitized = sanitizeMemoryContent(content);\n if (!sanitized.clean) {\n log.warn(`chunk content sanitized for ${id}; violations=${sanitized.violations.join(\", \")}`);\n }\n const fileContent = `${serializeFrontmatter(fm)}\\n\\n${sanitized.text}\\n`;\n\n let filePath: string;\n if (category === \"correction\") {\n filePath = path.join(this.correctionsDir, `${id}.md`);\n } else {\n filePath = path.join(this.factsDir, today, `${id}.md`);\n }\n\n await writeFile(filePath, fileContent, \"utf-8\");\n log.debug(`wrote chunk ${id} (${chunkIndex + 1}/${chunkTotal}) to ${filePath}`);\n return id;\n }\n\n /**\n * Get all chunks for a given parent memory ID.\n * Returns chunks sorted by chunkIndex.\n */\n async getChunksForParent(parentId: string): Promise<MemoryFile[]> {\n const memories = await this.readAllMemories();\n return memories\n .filter((m) => m.frontmatter.parentId === parentId)\n .sort((a, b) => (a.frontmatter.chunkIndex ?? 0) - (b.frontmatter.chunkIndex ?? 0));\n }\n\n // ---------------------------------------------------------------------------\n // Contradiction Detection (Phase 2B)\n // ---------------------------------------------------------------------------\n\n /**\n * Mark a memory as superseded by another.\n * Updates the old memory's status and adds the supersededBy link.\n */\n async supersedeMemory(\n oldMemoryId: string,\n newMemoryId: string,\n reason: string,\n ): Promise<boolean> {\n const memories = await this.readAllMemories();\n const oldMemory = memories.find((m) => m.frontmatter.id === oldMemoryId);\n if (!oldMemory) return false;\n\n const now = new Date().toISOString();\n const updatedFm: MemoryFrontmatter = {\n ...oldMemory.frontmatter,\n status: \"superseded\",\n supersededBy: newMemoryId,\n supersededAt: now,\n updated: now,\n };\n\n const fileContent = `${serializeFrontmatter(updatedFm)}\\n\\n${oldMemory.content}\\n`;\n\n try {\n await writeFile(oldMemory.path, fileContent, \"utf-8\");\n log.debug(`superseded memory ${oldMemoryId} by ${newMemoryId}: ${reason}`);\n\n // Also write a correction entry for the audit trail\n await this.writeMemory(\"correction\", `Superseded: ${oldMemory.content}\\n\\nReason: ${reason}`, {\n confidence: 1.0,\n tags: [\"supersession\", \"auto-resolved\"],\n source: \"contradiction-detection\",\n lineage: [oldMemoryId, newMemoryId],\n });\n\n return true;\n } catch (err) {\n log.error(`failed to supersede memory ${oldMemoryId}:`, err);\n return false;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Memory Summarization (Phase 4A)\n // ---------------------------------------------------------------------------\n\n private get summariesDir(): string {\n return path.join(this.baseDir, \"summaries\");\n }\n\n /**\n * Write a memory summary.\n */\n async writeSummary(summary: MemorySummary): Promise<void> {\n await mkdir(this.summariesDir, { recursive: true });\n const filePath = path.join(this.summariesDir, `${summary.id}.json`);\n await writeFile(filePath, JSON.stringify(summary, null, 2), \"utf-8\");\n log.debug(`wrote summary ${summary.id}`);\n }\n\n /**\n * Get all summaries.\n */\n async readSummaries(): Promise<MemorySummary[]> {\n try {\n const files = await readdir(this.summariesDir);\n const summaries: MemorySummary[] = [];\n\n for (const file of files) {\n if (!file.endsWith(\".json\")) continue;\n const filePath = path.join(this.summariesDir, file);\n const raw = await readFile(filePath, \"utf-8\");\n summaries.push(JSON.parse(raw) as MemorySummary);\n }\n\n return summaries;\n } catch {\n return [];\n }\n }\n\n /**\n * Archive memories (mark as archived, not delete).\n */\n async archiveMemories(memoryIds: string[], summaryId: string): Promise<number> {\n const memories = await this.readAllMemories();\n const memoryMap = new Map(memories.map((m) => [m.frontmatter.id, m]));\n let archived = 0;\n\n for (const id of memoryIds) {\n const memory = memoryMap.get(id);\n if (!memory) continue;\n\n const now = new Date().toISOString();\n const updatedFm: MemoryFrontmatter = {\n ...memory.frontmatter,\n status: \"archived\",\n archivedAt: now,\n updated: now,\n };\n\n const fileContent = `${serializeFrontmatter(updatedFm)}\\n\\n${memory.content}\\n`;\n\n try {\n await writeFile(memory.path, fileContent, \"utf-8\");\n archived++;\n } catch {\n // Ignore individual failures\n }\n }\n\n if (archived > 0) {\n log.debug(`archived ${archived} memories for summary ${summaryId}`);\n }\n return archived;\n }\n\n // ---------------------------------------------------------------------------\n // Topic Extraction (Phase 4B)\n // ---------------------------------------------------------------------------\n\n /**\n * Save topic scores to meta.json.\n */\n async saveTopics(topics: TopicScore[]): Promise<void> {\n const metaPath = path.join(this.stateDir, \"topics.json\");\n await mkdir(this.stateDir, { recursive: true });\n await writeFile(metaPath, JSON.stringify({ topics, updatedAt: new Date().toISOString() }, null, 2), \"utf-8\");\n log.debug(`saved ${topics.length} topic scores`);\n }\n\n /**\n * Load topic scores from meta.json.\n */\n async loadTopics(): Promise<{ topics: TopicScore[]; updatedAt: string | null }> {\n const metaPath = path.join(this.stateDir, \"topics.json\");\n try {\n const raw = await readFile(metaPath, \"utf-8\");\n return JSON.parse(raw) as { topics: TopicScore[]; updatedAt: string | null };\n } catch {\n return { topics: [], updatedAt: null };\n }\n }\n\n /**\n * Add links to an existing memory.\n */\n async addLinksToMemory(memoryId: string, links: MemoryLink[]): Promise<boolean> {\n const memories = await this.readAllMemories();\n const memory = memories.find((m) => m.frontmatter.id === memoryId);\n if (!memory) return false;\n\n const existingLinks = memory.frontmatter.links ?? [];\n const mergedLinks = [...existingLinks];\n\n // Add new links, avoiding duplicates\n for (const link of links) {\n if (!mergedLinks.some((l) => l.targetId === link.targetId && l.linkType === link.linkType)) {\n mergedLinks.push(link);\n }\n }\n\n const updatedFm: MemoryFrontmatter = {\n ...memory.frontmatter,\n links: mergedLinks,\n updated: new Date().toISOString(),\n };\n\n const fileContent = `${serializeFrontmatter(updatedFm)}\\n\\n${memory.content}\\n`;\n\n try {\n await writeFile(memory.path, fileContent, \"utf-8\");\n log.debug(`added ${links.length} links to memory ${memoryId}`);\n return true;\n } catch (err) {\n log.error(`failed to add links to memory ${memoryId}:`, err);\n return false;\n }\n }\n}\n","import { mkdir, readFile, stat, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nexport type HygieneWarning = {\n path: string;\n bytes: number;\n budgetBytes: number;\n warnAtBytes: number;\n message: string;\n};\n\nfunction toSafeTimestamp(ts: Date): string {\n // filesystem-safe, deterministic-ish, UTC\n return ts.toISOString().replace(/[:.]/g, \"\").replace(\"Z\", \"Z\");\n}\n\nexport async function lintWorkspaceFiles(opts: {\n workspaceDir: string;\n paths: string[];\n budgetBytes: number;\n warnRatio: number;\n}): Promise<HygieneWarning[]> {\n const warnings: HygieneWarning[] = [];\n const warnAtBytes = Math.floor(opts.budgetBytes * opts.warnRatio);\n\n for (const p of opts.paths) {\n const abs = path.isAbsolute(p) ? p : path.join(opts.workspaceDir, p);\n try {\n const st = await stat(abs);\n if (!st.isFile()) continue;\n const bytes = st.size;\n if (bytes >= warnAtBytes) {\n warnings.push({\n path: p,\n bytes,\n budgetBytes: opts.budgetBytes,\n warnAtBytes,\n message: `Bootstrap file '${p}' is approaching its budget (${bytes} bytes >= ${warnAtBytes} bytes). Consider splitting/archiving it to avoid silent truncation.`,\n });\n }\n } catch {\n // ignore missing files\n }\n }\n\n return warnings;\n}\n\nexport async function rotateMarkdownFileToArchive(opts: {\n filePath: string;\n archiveDir: string;\n archivePrefix: string;\n keepTailChars: number;\n}): Promise<{ archivedPath: string; newContent: string }> {\n const existing = await readFile(opts.filePath, \"utf-8\");\n const ts = toSafeTimestamp(new Date());\n const archiveName = `${opts.archivePrefix}-${ts}.md`;\n await mkdir(opts.archiveDir, { recursive: true });\n const archivedPath = path.join(opts.archiveDir, archiveName);\n await writeFile(archivedPath, existing, \"utf-8\");\n\n const tail =\n opts.keepTailChars > 0 && existing.length > opts.keepTailChars\n ? existing.slice(-opts.keepTailChars)\n : existing;\n\n const relLink = path.relative(path.dirname(opts.filePath), archivedPath);\n\n const newContent = [\n \"# Index\",\n \"\",\n \"This file is kept intentionally small to reduce the risk of silent truncation when OpenClaw bootstraps workspace files into the prompt.\",\n \"\",\n \"## Archives\",\n `- [${archiveName}](${relLink})`,\n \"\",\n \"## Recent Tail (for continuity)\",\n \"\",\n \"```md\",\n tail.trim(),\n \"```\",\n \"\",\n ].join(\"\\n\");\n\n return { archivedPath, newContent };\n}\n\n","export type ReasoningEffort = \"none\" | \"low\" | \"medium\" | \"high\";\nexport type TriggerMode = \"smart\" | \"every_n\" | \"time_based\";\nexport type SignalLevel = \"none\" | \"low\" | \"medium\" | \"high\";\nexport type MemoryCategory = \"fact\" | \"preference\" | \"correction\" | \"entity\" | \"decision\" | \"relationship\" | \"principle\" | \"commitment\" | \"moment\" | \"skill\";\nexport type ConsolidationAction = \"ADD\" | \"MERGE\" | \"UPDATE\" | \"INVALIDATE\" | \"SKIP\";\nexport type ConfidenceTier = \"explicit\" | \"implied\" | \"inferred\" | \"speculative\";\nexport type PrincipalFromSessionKeyMode = \"map\" | \"prefix\" | \"regex\";\n\nexport interface FileHygieneConfig {\n enabled: boolean;\n // Lint (warn before truncation risk)\n lintEnabled: boolean;\n lintBudgetBytes: number;\n lintWarnRatio: number;\n lintPaths: string[];\n // Rotation/splitting\n rotateEnabled: boolean;\n rotateMaxBytes: number;\n rotateKeepTailChars: number;\n rotatePaths: string[];\n archiveDir: string;\n // Cadence\n runMinIntervalMs: number;\n // Optional warnings log (future-proofed)\n warningsLogEnabled: boolean;\n warningsLogPath: string;\n // Optional index file (future-proofed)\n indexEnabled: boolean;\n indexPath: string;\n}\n\nexport function confidenceTier(score: number): ConfidenceTier {\n if (score >= 0.95) return \"explicit\";\n if (score >= 0.70) return \"implied\";\n if (score >= 0.40) return \"inferred\";\n return \"speculative\";\n}\n\n/** Default TTL in days for speculative memories (auto-expire if unconfirmed) */\nexport const SPECULATIVE_TTL_DAYS = 30;\n\nexport interface PluginConfig {\n openaiApiKey: string | undefined;\n openaiBaseUrl: string | undefined;\n model: string;\n reasoningEffort: ReasoningEffort;\n triggerMode: TriggerMode;\n bufferMaxTurns: number;\n bufferMaxMinutes: number;\n consolidateEveryN: number;\n highSignalPatterns: string[];\n maxMemoryTokens: number;\n qmdEnabled: boolean;\n qmdCollection: string;\n qmdMaxResults: number;\n embeddingFallbackEnabled: boolean;\n embeddingFallbackProvider: \"auto\" | \"openai\" | \"local\";\n /** Optional absolute path to qmd binary. If unset, PATH/fallback discovery is used. */\n qmdPath?: string;\n memoryDir: string;\n debug: boolean;\n identityEnabled: boolean;\n injectQuestions: boolean;\n commitmentDecayDays: number;\n workspaceDir: string;\n fileHygiene?: FileHygieneConfig;\n // Access tracking (Phase 1A)\n accessTrackingEnabled: boolean;\n accessTrackingBufferMaxSize: number;\n // Retrieval options\n recencyWeight: number;\n boostAccessCount: boolean;\n // v2.2 Advanced Retrieval\n queryExpansionEnabled: boolean;\n queryExpansionMaxQueries: number;\n /** Minimum token length to consider for query expansion. */\n queryExpansionMinTokenLen: number;\n rerankEnabled: boolean;\n /** Rerank provider. \"local\" uses Local LLM only; \"cloud\" uses gateway fallback chain. */\n rerankProvider: \"local\" | \"cloud\";\n rerankMaxCandidates: number;\n rerankTimeoutMs: number;\n rerankCacheEnabled: boolean;\n rerankCacheTtlMs: number;\n feedbackEnabled: boolean;\n // v2.2 Negative Examples (safe defaults: off unless enabled)\n /** If true, allow recording negative examples and apply a soft penalty during ranking. */\n negativeExamplesEnabled: boolean;\n /** Score penalty per \"not useful\" hit (typical QMD scores ~0-1). Keep small. */\n negativeExamplesPenaltyPerHit: number;\n /** Maximum penalty applied from negative examples. */\n negativeExamplesPenaltyCap: number;\n // Chunking (Phase 2A)\n chunkingEnabled: boolean;\n chunkingTargetTokens: number;\n chunkingMinTokens: number;\n chunkingOverlapSentences: number;\n // Contradiction Detection (Phase 2B)\n contradictionDetectionEnabled: boolean;\n contradictionSimilarityThreshold: number;\n contradictionMinConfidence: number;\n contradictionAutoResolve: boolean;\n // Memory Linking (Phase 3A)\n memoryLinkingEnabled: boolean;\n // Conversation Threading (Phase 3B)\n threadingEnabled: boolean;\n threadingGapMinutes: number;\n // Memory Summarization (Phase 4A)\n summarizationEnabled: boolean;\n summarizationTriggerCount: number;\n summarizationRecentToKeep: number;\n summarizationImportanceThreshold: number;\n summarizationProtectedTags: string[];\n // Topic Extraction (Phase 4B)\n topicExtractionEnabled: boolean;\n topicExtractionTopN: number;\n // Transcript & Context Preservation (v2.0)\n // Transcript archive\n transcriptEnabled: boolean;\n transcriptRetentionDays: number;\n /** Channel types to skip from transcript logging (e.g., [\"cron\"]) */\n transcriptSkipChannelTypes: string[];\n // Transcript injection\n transcriptRecallHours: number;\n maxTranscriptTurns: number;\n maxTranscriptTokens: number;\n // Checkpoint\n checkpointEnabled: boolean;\n checkpointTurns: number;\n // Hourly summaries\n hourlySummariesEnabled: boolean;\n /** If true, Engram may attempt to auto-register an hourly summary cron job (default off). */\n hourlySummaryCronAutoRegister: boolean;\n summaryRecallHours: number;\n maxSummaryCount: number;\n summaryModel: string;\n // v2.4 Extended hourly summaries\n hourlySummariesExtendedEnabled: boolean;\n hourlySummariesIncludeToolStats: boolean;\n hourlySummariesIncludeSystemMessages: boolean;\n hourlySummariesMaxTurnsPerRun: number;\n // v2.4 Conversation index (optional)\n conversationIndexEnabled: boolean;\n conversationIndexBackend: \"qmd\" | \"faiss\";\n conversationIndexQmdCollection: string;\n conversationIndexRetentionDays: number;\n conversationIndexMinUpdateIntervalMs: number;\n conversationIndexEmbedOnUpdate: boolean;\n conversationRecallTopK: number;\n conversationRecallMaxChars: number;\n conversationRecallTimeoutMs: number;\n // Local LLM Provider (v2.1)\n localLlmEnabled: boolean;\n localLlmUrl: string;\n localLlmModel: string;\n /** Optional API key for authenticated OpenAI-compatible endpoints. */\n localLlmApiKey?: string;\n /** Additional headers for local/compatible endpoint requests. */\n localLlmHeaders?: Record<string, string>;\n /** If false, do not send Authorization header even when localLlmApiKey is set. */\n localLlmAuthHeader: boolean;\n localLlmFallback: boolean;\n /** Optional home directory override for local LLM helpers (LM Studio settings, CLI PATH). */\n localLlmHomeDir?: string;\n /** Optional absolute path to LMS CLI binary (preferred over auto-detection). */\n localLmsCliPath?: string;\n /** Optional bin directory prepended to PATH for LMS CLI execution. */\n localLmsBinDir?: string;\n /** Hard timeout for local LLM requests (ms). */\n localLlmTimeoutMs: number;\n /** Max context window for local LLM (override auto-detection). Set lower if your LLM server defaults to smaller contexts. */\n localLlmMaxContext?: number;\n // Observability\n /** If true, log slow operations (local LLM + related I/O) with durations and metadata (no content). */\n slowLogEnabled: boolean;\n /** Threshold for slow operation logging (ms). */\n slowLogThresholdMs: number;\n // Extraction stability guards (P0/P1)\n extractionDedupeEnabled: boolean;\n extractionDedupeWindowMs: number;\n extractionMinChars: number;\n extractionMinUserTurns: number;\n extractionMaxTurnChars: number;\n extractionMaxFactsPerRun: number;\n extractionMaxEntitiesPerRun: number;\n extractionMaxQuestionsPerRun: number;\n extractionMaxProfileUpdatesPerRun: number;\n consolidationRequireNonZeroExtraction: boolean;\n consolidationMinIntervalMs: number;\n // QMD maintenance (debounced singleflight)\n qmdMaintenanceEnabled: boolean;\n qmdMaintenanceDebounceMs: number;\n qmdAutoEmbedEnabled: boolean;\n qmdEmbedMinIntervalMs: number;\n qmdUpdateTimeoutMs: number;\n // Local LLM resilience\n localLlmRetry5xxCount: number;\n localLlmRetryBackoffMs: number;\n localLlm400TripThreshold: number;\n localLlm400CooldownMs: number;\n // Gateway config for fallback AI\n gatewayConfig?: GatewayConfig;\n\n // v3.0 Multi-agent memory (namespaces)\n namespacesEnabled: boolean;\n defaultNamespace: string;\n sharedNamespace: string;\n principalFromSessionKeyMode: PrincipalFromSessionKeyMode;\n principalFromSessionKeyRules: PrincipalRule[];\n namespacePolicies: NamespacePolicy[];\n defaultRecallNamespaces: Array<\"self\" | \"shared\">;\n autoPromoteToSharedEnabled: boolean;\n autoPromoteToSharedCategories: Array<\"correction\" | \"decision\" | \"preference\">;\n autoPromoteMinConfidenceTier: ConfidenceTier;\n\n // v4.0 Shared-context (cross-agent shared intelligence)\n sharedContextEnabled: boolean;\n sharedContextDir?: string;\n sharedContextMaxInjectChars: number;\n crossSignalsSemanticEnabled: boolean;\n crossSignalsSemanticTimeoutMs: number;\n\n // v5.0 Compounding engine\n compoundingEnabled: boolean;\n compoundingWeeklyCronEnabled: boolean;\n compoundingSemanticEnabled: boolean;\n compoundingSynthesisTimeoutMs: number;\n compoundingInjectEnabled: boolean;\n\n // QMD daemon mode\n qmdDaemonEnabled: boolean;\n qmdDaemonUrl: string;\n qmdDaemonRecheckIntervalMs: number;\n\n // v7.0 Knowledge Graph Enhancement\n knowledgeIndexEnabled: boolean;\n knowledgeIndexMaxEntities: number;\n knowledgeIndexMaxChars: number;\n entityRelationshipsEnabled: boolean;\n entityActivityLogEnabled: boolean;\n entityActivityLogMaxEntries: number;\n entityAliasesEnabled: boolean;\n entitySummaryEnabled: boolean;\n\n // v6.0 Fact deduplication & archival\n /** Enable content-hash deduplication to prevent storing semantically identical facts. */\n factDeduplicationEnabled: boolean;\n /** Enable automatic archival of old, low-importance, rarely-accessed facts. */\n factArchivalEnabled: boolean;\n /** Minimum age in days before a fact is eligible for archival. */\n factArchivalAgeDays: number;\n /** Maximum importance score for archival eligibility (0-1). Only facts below this are archived. */\n factArchivalMaxImportance: number;\n /** Maximum access count for archival eligibility. Only rarely-accessed facts are archived. */\n factArchivalMaxAccessCount: number;\n /** Tags that protect a fact from archival regardless of other criteria. */\n factArchivalProtectedCategories: string[];\n}\n\nexport interface BootstrapOptions {\n dryRun?: boolean;\n sessionsDir?: string;\n limit?: number;\n since?: Date;\n}\n\nexport interface BootstrapResult {\n sessionsScanned: number;\n turnsProcessed: number;\n highSignalTurns: number;\n memoriesCreated: number;\n skipped: number;\n}\n\nexport interface PrincipalRule {\n match: string;\n principal: string;\n}\n\nexport interface NamespacePolicy {\n name: string;\n readPrincipals: string[];\n writePrincipals: string[];\n includeInRecallByDefault?: boolean;\n}\n\nexport interface RelevanceFeedback {\n up: number;\n down: number;\n lastUpdatedAt: string;\n notes?: string[];\n}\n\nexport interface BufferTurn {\n role: \"user\" | \"assistant\";\n content: string;\n timestamp: string;\n sessionKey?: string;\n}\n\nexport interface BufferState {\n turns: BufferTurn[];\n lastExtractionAt: string | null;\n extractionCount: number;\n}\n\n/** Memory status for lifecycle management */\nexport type MemoryStatus = \"active\" | \"superseded\" | \"archived\";\n\n/** Importance level tiers */\nexport type ImportanceLevel = \"critical\" | \"high\" | \"normal\" | \"low\" | \"trivial\";\n\n/** Importance scoring result */\nexport interface ImportanceScore {\n /** Numeric score 0-1 */\n score: number;\n /** Tier level */\n level: ImportanceLevel;\n /** Reasons for this score */\n reasons: string[];\n /** Salient keywords extracted */\n keywords: string[];\n}\n\nexport interface MemoryFrontmatter {\n id: string;\n category: MemoryCategory;\n created: string;\n updated: string;\n source: string;\n confidence: number;\n confidenceTier: ConfidenceTier;\n tags: string[];\n entityRef?: string;\n supersedes?: string;\n /** ISO 8601 date — memory expires and gets cleaned up after this date */\n expiresAt?: string;\n /** IDs of parent memories this was derived from (lineage tracking) */\n lineage?: string[];\n /** Memory status: active (default), superseded, or archived */\n status?: MemoryStatus;\n /** ID of memory that superseded this one */\n supersededBy?: string;\n /** Timestamp when superseded */\n supersededAt?: string;\n /** Timestamp when archived */\n archivedAt?: string;\n // Access tracking (Phase 1A)\n /** Number of times this memory has been retrieved */\n accessCount?: number;\n /** Last time this memory was accessed (ISO 8601) */\n lastAccessed?: string;\n // Importance scoring (Phase 1B)\n /** Importance score with level, reasons, and keywords */\n importance?: ImportanceScore;\n // Chunking (Phase 2A)\n /** Parent memory ID if this is a chunk */\n parentId?: string;\n /** Chunk index within parent (0-based) */\n chunkIndex?: number;\n /** Total number of chunks for this parent */\n chunkTotal?: number;\n // Memory Linking (Phase 3A)\n /** Links to other memories */\n links?: MemoryLink[];\n}\n\n/** Memory link relationship types */\nexport type MemoryLinkType = \"follows\" | \"references\" | \"contradicts\" | \"supports\" | \"related\";\n\n/** A link between memories */\nexport interface MemoryLink {\n targetId: string;\n linkType: MemoryLinkType;\n strength: number;\n reason?: string;\n}\n\n// Conversation Threading (Phase 3B)\nexport interface ConversationThread {\n id: string;\n title: string;\n createdAt: string;\n updatedAt: string;\n sessionKey?: string;\n episodeIds: string[];\n linkedThreadIds: string[];\n}\n\n// Memory Summarization (Phase 4A)\nexport interface MemorySummary {\n id: string;\n createdAt: string;\n timeRangeStart: string;\n timeRangeEnd: string;\n summaryText: string;\n keyFacts: string[];\n keyEntities: string[];\n sourceEpisodeIds: string[];\n}\n\n// Topic Extraction (Phase 4B)\nexport interface TopicScore {\n term: string;\n score: number;\n count: number;\n}\n\nexport interface MemoryFile {\n path: string;\n frontmatter: MemoryFrontmatter;\n content: string;\n}\n\nexport interface ExtractedFact {\n category: MemoryCategory;\n content: string;\n confidence: number;\n tags: string[];\n entityRef?: string;\n}\n\nexport interface ExtractedQuestion {\n question: string;\n context: string;\n priority: number;\n}\n\nexport interface QuestionEntry {\n id: string;\n question: string;\n context: string;\n priority: number; // 0-1, higher = more important\n created: string;\n resolved: boolean;\n resolvedAt?: string;\n}\n\nexport interface ExtractionResult {\n facts: ExtractedFact[];\n profileUpdates: string[];\n entities: EntityMention[];\n questions: ExtractedQuestion[];\n identityReflection?: string;\n relationships?: ExtractedRelationship[];\n}\n\nexport interface EntityMention {\n name: string;\n type: \"person\" | \"project\" | \"tool\" | \"company\" | \"place\" | \"other\";\n facts: string[];\n}\n\n// ---------------------------------------------------------------------------\n// Knowledge Graph Enhancement (Entity Relationships, Activity, Scoring)\n// ---------------------------------------------------------------------------\n\nexport interface EntityRelationship {\n target: string;\n label: string;\n}\n\nexport interface EntityActivityEntry {\n date: string;\n note: string;\n}\n\nexport interface EntityFile {\n name: string;\n type: string;\n updated: string;\n facts: string[];\n summary?: string;\n relationships: EntityRelationship[];\n activity: EntityActivityEntry[];\n aliases: string[];\n}\n\nexport interface ScoredEntity {\n name: string;\n type: string;\n score: number;\n factCount: number;\n summary?: string;\n topRelationships: string[];\n}\n\nexport interface ExtractedRelationship {\n source: string;\n target: string;\n label: string;\n}\n\nexport interface ConsolidationItem {\n existingId: string;\n action: ConsolidationAction;\n mergeWith?: string;\n updatedContent?: string;\n reason: string;\n}\n\nexport interface ConsolidationResult {\n items: ConsolidationItem[];\n profileUpdates: string[];\n entityUpdates: EntityMention[];\n}\n\nexport interface QmdSearchResult {\n docid: string;\n path: string;\n snippet: string;\n score: number;\n}\n\nexport interface MetaState {\n extractionCount: number;\n lastExtractionAt: string | null;\n lastConsolidationAt: string | null;\n totalMemories: number;\n totalEntities: number;\n}\n\n/** Entry in the access tracking buffer (batched updates) */\nexport interface AccessTrackingEntry {\n memoryId: string;\n newCount: number;\n lastAccessed: string;\n}\n\nexport interface SignalScanResult {\n level: SignalLevel;\n patterns: string[];\n}\n\n// ============================================================================\n// LLM Trace Callback (for external observability plugins)\n// ============================================================================\n\nexport interface LlmTraceEvent {\n kind: \"llm_start\" | \"llm_end\" | \"llm_error\";\n traceId: string;\n model: string;\n operation: \"extraction\" | \"consolidation\" | \"profile_consolidation\" | \"identity_consolidation\";\n input?: string;\n output?: string;\n durationMs?: number;\n error?: string;\n tokenUsage?: { input?: number; output?: number; total?: number };\n}\n\nexport type LlmTraceCallback = (event: LlmTraceEvent) => void;\n\n// ============================================================================\n// Gateway Configuration Types (for fallback AI)\n// ============================================================================\n\nexport type ModelApi = \"openai-completions\" | \"anthropic-messages\" | \"google-generative\" | string;\n\nexport type ModelProviderAuthMode = \"bearer\" | \"header\" | \"query\";\n\nexport interface ModelDefinitionConfig {\n id: string;\n name?: string;\n contextWindow?: number;\n maxOutputTokens?: number;\n costPer1MInput?: number;\n costPer1MOutput?: number;\n aliases?: string[];\n}\n\nexport interface ModelProviderConfig {\n baseUrl: string;\n apiKey?: string;\n auth?: ModelProviderAuthMode;\n api?: ModelApi;\n headers?: Record<string, string>;\n authHeader?: boolean;\n models: ModelDefinitionConfig[];\n}\n\nexport interface AgentDefaultsConfig {\n model?: {\n primary?: string;\n backup?: string;\n fallbacks?: string[];\n };\n thinking?: {\n mode?: \"off\" | \"on\" | \"adaptive\";\n budget?: number;\n };\n}\n\nexport interface GatewayConfig {\n agents?: {\n defaults?: AgentDefaultsConfig;\n };\n models?: {\n providers?: Record<string, ModelProviderConfig>;\n };\n}\n\n// ============================================================================\n// Transcript & Context Preservation (v2.0)\n// ============================================================================\n\nexport interface TranscriptEntry {\n timestamp: string;\n role: \"user\" | \"assistant\";\n content: string;\n sessionKey: string;\n turnId: string;\n metadata?: {\n compactAfter?: boolean;\n compactionId?: string | null;\n };\n}\n\nexport interface Checkpoint {\n sessionKey: string;\n capturedAt: string;\n turns: TranscriptEntry[];\n ttl: string; // ISO timestamp when checkpoint expires\n}\n\nexport interface HourlySummary {\n hour: string; // \"2026-02-08T14:00:00Z\"\n sessionKey: string;\n bullets: string[];\n turnCount: number;\n generatedAt: string;\n}\n","/**\n * Conversation Threading (Phase 3B)\n *\n * Groups related memories into conversation threads with auto-generated titles.\n * Thread boundary detection: new session key OR time gap > threshold.\n */\n\nimport { readdir, readFile, writeFile, mkdir } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { log } from \"./logger.js\";\nimport type { BufferTurn, ConversationThread } from \"./types.js\";\n\n/** Stop words for title extraction */\nconst STOP_WORDS = new Set([\n \"a\", \"an\", \"the\", \"is\", \"are\", \"was\", \"were\", \"be\", \"been\", \"being\",\n \"have\", \"has\", \"had\", \"do\", \"does\", \"did\", \"will\", \"would\", \"could\",\n \"should\", \"may\", \"might\", \"must\", \"shall\", \"can\", \"need\", \"to\", \"of\",\n \"in\", \"for\", \"on\", \"with\", \"at\", \"by\", \"from\", \"as\", \"into\", \"through\",\n \"during\", \"before\", \"after\", \"above\", \"below\", \"between\", \"this\", \"that\",\n \"these\", \"those\", \"i\", \"me\", \"my\", \"we\", \"our\", \"you\", \"your\", \"he\",\n \"she\", \"it\", \"they\", \"them\", \"their\", \"what\", \"which\", \"who\", \"how\",\n \"when\", \"where\", \"why\", \"and\", \"but\", \"or\", \"if\", \"because\", \"so\",\n \"just\", \"about\", \"like\", \"also\", \"very\", \"really\", \"here\", \"there\",\n]);\n\n/**\n * Extract top keywords from content for thread title.\n * Simple TF approach (no IDF needed for single thread).\n */\nfunction extractKeywords(content: string, maxKeywords: number = 3): string[] {\n const words = content\n .toLowerCase()\n .replace(/[^a-z0-9\\s-]/g, \" \")\n .split(/\\s+/)\n .filter((w) => w.length >= 4 && !STOP_WORDS.has(w));\n\n // Count frequencies\n const freq = new Map<string, number>();\n for (const word of words) {\n freq.set(word, (freq.get(word) ?? 0) + 1);\n }\n\n // Sort by frequency, take top N\n return [...freq.entries()]\n .sort((a, b) => b[1] - a[1])\n .slice(0, maxKeywords)\n .map(([word]) => word);\n}\n\n/**\n * Generate a thread title from keywords.\n */\nfunction generateTitle(keywords: string[]): string {\n if (keywords.length === 0) return \"Untitled Thread\";\n // Capitalize and join\n return keywords\n .map((k) => k.charAt(0).toUpperCase() + k.slice(1))\n .join(\", \");\n}\n\nexport class ThreadingManager {\n private currentThreadId: string | null = null;\n private lastTurnTimestamp: number | null = null;\n private lastSessionKey: string | null = null;\n\n constructor(\n private readonly threadsDir: string,\n private readonly gapMinutes: number = 30,\n ) {}\n\n async ensureDirectory(): Promise<void> {\n await mkdir(this.threadsDir, { recursive: true });\n }\n\n /**\n * Check if we should start a new thread based on session key and time gap.\n */\n shouldStartNewThread(turn: BufferTurn): boolean {\n const turnTime = new Date(turn.timestamp).getTime();\n\n // Different session key = new thread\n if (turn.sessionKey && this.lastSessionKey && turn.sessionKey !== this.lastSessionKey) {\n return true;\n }\n\n // Time gap > threshold = new thread\n if (this.lastTurnTimestamp) {\n const gapMs = turnTime - this.lastTurnTimestamp;\n const gapMinutes = gapMs / (1000 * 60);\n if (gapMinutes > this.gapMinutes) {\n return true;\n }\n }\n\n // No current thread = new thread\n if (!this.currentThreadId) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Process a turn and return the thread ID it belongs to.\n * Creates a new thread if needed.\n */\n async processTurn(turn: BufferTurn, episodeIds: string[]): Promise<string> {\n await this.ensureDirectory();\n\n const turnTime = new Date(turn.timestamp).getTime();\n\n if (this.shouldStartNewThread(turn)) {\n // Create new thread\n const threadId = `thread-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;\n const thread: ConversationThread = {\n id: threadId,\n title: \"New Thread\", // Will be updated later with keywords\n createdAt: turn.timestamp,\n updatedAt: turn.timestamp,\n sessionKey: turn.sessionKey,\n episodeIds: [...episodeIds],\n linkedThreadIds: [],\n };\n\n await this.saveThread(thread);\n this.currentThreadId = threadId;\n log.debug(`created new thread ${threadId}`);\n } else if (this.currentThreadId) {\n // Add episodes to current thread\n const thread = await this.loadThread(this.currentThreadId);\n if (thread) {\n for (const id of episodeIds) {\n if (!thread.episodeIds.includes(id)) {\n thread.episodeIds.push(id);\n }\n }\n thread.updatedAt = turn.timestamp;\n await this.saveThread(thread);\n }\n }\n\n this.lastTurnTimestamp = turnTime;\n this.lastSessionKey = turn.sessionKey ?? null;\n\n return this.currentThreadId!;\n }\n\n /**\n * Update thread title based on accumulated content.\n */\n async updateThreadTitle(threadId: string, content: string): Promise<void> {\n const thread = await this.loadThread(threadId);\n if (!thread) return;\n\n const keywords = extractKeywords(content);\n const title = generateTitle(keywords);\n\n if (title !== thread.title) {\n thread.title = title;\n thread.updatedAt = new Date().toISOString();\n await this.saveThread(thread);\n log.debug(`updated thread ${threadId} title: ${title}`);\n }\n }\n\n /**\n * Get all threads, sorted by updatedAt desc.\n */\n async getAllThreads(): Promise<ConversationThread[]> {\n try {\n const files = await readdir(this.threadsDir);\n const threads: ConversationThread[] = [];\n\n for (const file of files) {\n if (!file.endsWith(\".json\")) continue;\n const thread = await this.loadThread(file.replace(\".json\", \"\"));\n if (thread) threads.push(thread);\n }\n\n return threads.sort(\n (a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime(),\n );\n } catch {\n return [];\n }\n }\n\n /**\n * Get a thread by ID.\n */\n async loadThread(threadId: string): Promise<ConversationThread | null> {\n const filePath = path.join(this.threadsDir, `${threadId}.json`);\n try {\n const raw = await readFile(filePath, \"utf-8\");\n return JSON.parse(raw) as ConversationThread;\n } catch {\n return null;\n }\n }\n\n /**\n * Save a thread.\n */\n async saveThread(thread: ConversationThread): Promise<void> {\n await this.ensureDirectory();\n const filePath = path.join(this.threadsDir, `${thread.id}.json`);\n await writeFile(filePath, JSON.stringify(thread, null, 2), \"utf-8\");\n }\n\n /**\n * Link two threads together.\n */\n async linkThreads(threadId1: string, threadId2: string): Promise<boolean> {\n const thread1 = await this.loadThread(threadId1);\n const thread2 = await this.loadThread(threadId2);\n\n if (!thread1 || !thread2) return false;\n\n // Add bidirectional links\n if (!thread1.linkedThreadIds.includes(threadId2)) {\n thread1.linkedThreadIds.push(threadId2);\n await this.saveThread(thread1);\n }\n\n if (!thread2.linkedThreadIds.includes(threadId1)) {\n thread2.linkedThreadIds.push(threadId1);\n await this.saveThread(thread2);\n }\n\n return true;\n }\n\n /**\n * Get the current thread ID (if any).\n */\n getCurrentThreadId(): string | null {\n return this.currentThreadId;\n }\n\n /**\n * Reset threading state (e.g., on plugin restart).\n */\n reset(): void {\n this.currentThreadId = null;\n this.lastTurnTimestamp = null;\n this.lastSessionKey = null;\n }\n}\n","/**\n * Topic Extraction (Phase 4B)\n *\n * Extract key topics from all memories using TF-IDF weighting.\n * Runs as a batch process during consolidation.\n */\n\nimport type { MemoryFile, TopicScore } from \"./types.js\";\n\n/** Stop words to exclude from topic extraction */\nconst STOP_WORDS = new Set([\n \"a\", \"an\", \"the\", \"is\", \"are\", \"was\", \"were\", \"be\", \"been\", \"being\",\n \"have\", \"has\", \"had\", \"do\", \"does\", \"did\", \"will\", \"would\", \"could\",\n \"should\", \"may\", \"might\", \"must\", \"shall\", \"can\", \"need\", \"to\", \"of\",\n \"in\", \"for\", \"on\", \"with\", \"at\", \"by\", \"from\", \"as\", \"into\", \"through\",\n \"during\", \"before\", \"after\", \"above\", \"below\", \"between\", \"this\", \"that\",\n \"these\", \"those\", \"i\", \"me\", \"my\", \"we\", \"our\", \"you\", \"your\", \"he\",\n \"she\", \"it\", \"they\", \"them\", \"their\", \"what\", \"which\", \"who\", \"how\",\n \"when\", \"where\", \"why\", \"and\", \"but\", \"or\", \"if\", \"because\", \"so\",\n \"just\", \"about\", \"like\", \"also\", \"very\", \"really\", \"here\", \"there\",\n \"now\", \"then\", \"only\", \"even\", \"still\", \"already\", \"always\", \"never\",\n \"often\", \"sometimes\", \"usually\", \"well\", \"much\", \"more\", \"most\", \"some\",\n \"any\", \"all\", \"each\", \"every\", \"both\", \"few\", \"many\", \"other\", \"same\",\n \"such\", \"own\", \"than\", \"too\", \"very\", \"just\", \"over\", \"under\", \"again\",\n \"further\", \"once\", \"here\", \"there\", \"when\", \"where\", \"why\", \"how\",\n \"user\", \"agent\", \"memory\", \"fact\", \"preference\", \"using\", \"used\", \"use\",\n]);\n\n/**\n * Extract terms from content.\n * Returns normalized lowercase terms >= 3 chars.\n */\nfunction extractTerms(content: string): string[] {\n return content\n .toLowerCase()\n .replace(/[^a-z0-9\\s-]/g, \" \")\n .split(/\\s+/)\n .filter((w) => w.length >= 3 && !STOP_WORDS.has(w));\n}\n\n/**\n * Calculate TF-IDF scores for terms across all memories.\n *\n * TF (term frequency) = count of term in document / total terms in document\n * IDF (inverse document frequency) = log(total documents / documents containing term)\n * TF-IDF = TF * IDF\n *\n * Terms with high TF-IDF are frequent in specific memories but rare overall.\n */\nexport function extractTopics(\n memories: MemoryFile[],\n topN: number = 50,\n): TopicScore[] {\n if (memories.length === 0) return [];\n\n // Count term frequency per document and document frequency\n const docFreq = new Map<string, number>(); // term -> number of documents containing it\n const termFreqPerDoc: Map<string, number>[] = []; // per-doc term frequencies\n\n for (const memory of memories) {\n const terms = extractTerms(memory.content);\n const termFreq = new Map<string, number>();\n\n for (const term of terms) {\n termFreq.set(term, (termFreq.get(term) ?? 0) + 1);\n }\n\n // Track which terms appear in this document\n for (const term of termFreq.keys()) {\n docFreq.set(term, (docFreq.get(term) ?? 0) + 1);\n }\n\n termFreqPerDoc.push(termFreq);\n }\n\n const totalDocs = memories.length;\n\n // Calculate TF-IDF for each term\n const tfidfScores = new Map<string, { score: number; count: number }>();\n\n for (let i = 0; i < memories.length; i++) {\n const termFreq = termFreqPerDoc[i];\n const totalTerms = [...termFreq.values()].reduce((a, b) => a + b, 0);\n\n for (const [term, count] of termFreq) {\n const tf = count / totalTerms;\n const df = docFreq.get(term) ?? 1;\n const idf = Math.log(totalDocs / df);\n const tfidf = tf * idf;\n\n const existing = tfidfScores.get(term);\n if (existing) {\n existing.score += tfidf;\n existing.count += count;\n } else {\n tfidfScores.set(term, { score: tfidf, count });\n }\n }\n }\n\n // Convert to array and sort by score\n const topics: TopicScore[] = [...tfidfScores.entries()]\n .map(([term, { score, count }]) => ({ term, score, count }))\n .sort((a, b) => b.score - a.score)\n .slice(0, topN);\n\n return topics;\n}\n\n/**\n * Compare two topic lists to find trending changes.\n * Returns topics that are new or significantly increased.\n */\nexport function findTrendingTopics(\n currentTopics: TopicScore[],\n previousTopics: TopicScore[],\n threshold: number = 0.5,\n): { rising: TopicScore[]; falling: TopicScore[] } {\n const prevMap = new Map(previousTopics.map((t) => [t.term, t.score]));\n const currMap = new Map(currentTopics.map((t) => [t.term, t.score]));\n\n const rising: TopicScore[] = [];\n const falling: TopicScore[] = [];\n\n for (const topic of currentTopics) {\n const prevScore = prevMap.get(topic.term) ?? 0;\n const change = topic.score - prevScore;\n\n if (change > threshold) {\n rising.push({ ...topic, score: change });\n }\n }\n\n for (const topic of previousTopics) {\n const currScore = currMap.get(topic.term) ?? 0;\n const change = topic.score - currScore;\n\n if (change > threshold && currScore < topic.score * 0.5) {\n falling.push({ ...topic, score: change });\n }\n }\n\n return {\n rising: rising.sort((a, b) => b.score - a.score).slice(0, 10),\n falling: falling.sort((a, b) => b.score - a.score).slice(0, 10),\n };\n}\n","import { appendFile, mkdir, readdir, readFile, unlink, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { log } from \"./logger.js\";\nimport type { TranscriptEntry, Checkpoint, PluginConfig } from \"./types.js\";\n\n/**\n * Manages conversation transcript storage, checkpointing, and recall formatting.\n *\n * Transcripts are stored as JSONL files in a hierarchical structure:\n * transcripts/{channelType}/{channelId}.jsonl\n *\n * Channel types are extracted from sessionKey (discord, slack, cron, main, etc.)\n * Checkpoints are used to preserve conversation context across compaction events.\n */\nexport class TranscriptManager {\n private transcriptsDir: string;\n private checkpointPath: string;\n private stateDir: string;\n private toolUsageDir: string;\n private config: PluginConfig;\n\n /** Default checkpoint TTL in hours */\n private static readonly DEFAULT_CHECKPOINT_TTL_HOURS = 24;\n /** Approximate characters per token for rough estimation */\n private static readonly CHARS_PER_TOKEN = 4;\n\n constructor(config: PluginConfig) {\n this.config = config;\n this.transcriptsDir = path.join(config.memoryDir, \"transcripts\");\n this.stateDir = path.join(config.memoryDir, \"state\");\n this.checkpointPath = path.join(this.stateDir, \"checkpoint.json\");\n this.toolUsageDir = path.join(this.stateDir, \"tool-usage\");\n }\n\n /**\n * Parse a sessionKey to extract channel type and ID.\n *\n * SessionKey patterns:\n * - agent:generalist:main → type=\"main\", id=\"default\"\n * - agent:generalist:discord:channel:1468425700242620516 → type=\"discord\", id=\"1468425700242620516\"\n * - agent:generalist:cron:db61e2ac-... → type=\"cron\", id=\"db61e2ac-...\"\n * - agent:generalist:slack:channel:C123456 → type=\"slack\", id=\"C123456\"\n *\n * @returns Object with dir (channel type/channel id) and file (YYYY-MM-DD.jsonl)\n */\n getTranscriptPath(sessionKey: string): { dir: string; file: string } {\n const parts = sessionKey.split(\":\");\n\n // Default fallback\n let channelType = \"other\";\n let channelId = \"default\";\n\n if (parts.length >= 3) {\n // parts[0] = \"agent\", parts[1] = agent name, parts[2] = channel type\n channelType = parts[2];\n\n // Extract channel ID based on pattern\n if (channelType === \"main\") {\n channelId = \"default\";\n } else if (channelType === \"discord\" && parts.length >= 5 && parts[3] === \"channel\") {\n channelId = parts[4];\n } else if (channelType === \"slack\" && parts.length >= 5 && parts[3] === \"channel\") {\n channelId = parts[4];\n } else if (channelType === \"cron\" && parts.length >= 4) {\n channelId = parts[3];\n } else if (parts.length >= 4) {\n // For other types, use the 4th part as ID if available\n channelId = parts[3];\n }\n }\n\n // Daily rotation: transcripts/{channelType}/{channelId}/YYYY-MM-DD.jsonl\n const today = new Date().toISOString().slice(0, 10);\n return {\n dir: path.join(channelType, channelId),\n file: `${today}.jsonl`,\n };\n }\n\n /**\n * Initialize the transcript manager by ensuring directories exist.\n */\n async initialize(): Promise<void> {\n await mkdir(this.transcriptsDir, { recursive: true });\n await mkdir(this.stateDir, { recursive: true });\n await mkdir(this.toolUsageDir, { recursive: true });\n log.info(\"transcript manager initialized\");\n }\n\n /**\n * Best-effort list of sessionKeys that have transcript files on disk.\n * This is used by cron-style tooling (hourly summaries, conversation indexing)\n * to iterate across \"active\" sessions.\n */\n async listSessionKeys(): Promise<string[]> {\n const transcriptDir = this.transcriptsDir;\n const sessionKeys = new Set<string>();\n\n try {\n const typeEntries = await readdir(transcriptDir, { withFileTypes: true });\n for (const typeEnt of typeEntries) {\n if (!typeEnt.isDirectory()) continue;\n const typeDir = path.join(transcriptDir, typeEnt.name);\n const idEntries = await readdir(typeDir, { withFileTypes: true });\n for (const idEnt of idEntries) {\n if (!idEnt.isDirectory()) continue;\n const chanDir = path.join(typeDir, idEnt.name);\n const files = (await readdir(chanDir)).filter((f) => f.endsWith(\".jsonl\")).sort();\n const last = files[files.length - 1];\n if (!last) continue;\n try {\n const raw = await readFile(path.join(chanDir, last), \"utf-8\");\n const firstLine = raw.split(\"\\n\").find((l) => l.trim().length > 0);\n if (!firstLine) continue;\n const entry = JSON.parse(firstLine) as TranscriptEntry;\n if (typeof entry.sessionKey === \"string\" && entry.sessionKey.length > 0) {\n sessionKeys.add(entry.sessionKey);\n }\n } catch {\n // ignore\n }\n }\n }\n } catch {\n return [];\n }\n\n return Array.from(sessionKeys);\n }\n\n getToolUsagePath(sessionKey: string): { dir: string; file: string } {\n const p = this.getTranscriptPath(sessionKey);\n return { dir: p.dir, file: p.file };\n }\n\n async appendToolUse(entry: { timestamp: string; sessionKey: string; tool: string }): Promise<void> {\n const { dir, file } = this.getToolUsagePath(entry.sessionKey);\n const channelDir = path.join(this.toolUsageDir, dir);\n await mkdir(channelDir, { recursive: true });\n const filePath = path.join(channelDir, file);\n await appendFile(filePath, JSON.stringify(entry) + \"\\n\", \"utf-8\");\n }\n\n async readToolUse(\n sessionKey: string,\n startTime: Date,\n endTime: Date,\n ): Promise<Array<{ timestamp: string; sessionKey: string; tool: string }>> {\n const { dir } = this.getToolUsagePath(sessionKey);\n const channelDir = path.join(this.toolUsageDir, dir);\n try {\n const files = await readdir(channelDir);\n const out: Array<{ timestamp: string; sessionKey: string; tool: string }> = [];\n for (const file of files) {\n if (!file.endsWith(\".jsonl\")) continue;\n const fp = path.join(channelDir, file);\n const raw = await readFile(fp, \"utf-8\");\n for (const line of raw.split(\"\\n\")) {\n if (!line.trim()) continue;\n try {\n const obj = JSON.parse(line) as any;\n const ts = new Date(String(obj.timestamp ?? \"\")).getTime();\n if (!Number.isFinite(ts)) continue;\n if (ts >= startTime.getTime() && ts < endTime.getTime()) {\n if (typeof obj.tool === \"string\" && typeof obj.sessionKey === \"string\") {\n out.push({ timestamp: obj.timestamp, sessionKey: obj.sessionKey, tool: obj.tool });\n }\n }\n } catch {\n // ignore\n }\n }\n }\n return out;\n } catch {\n return [];\n }\n }\n\n /**\n * Check if a file is a legacy flat transcript file (YYYY-MM-DD.jsonl format).\n */\n private isLegacyTranscriptFile(filename: string): boolean {\n return /^\\d{4}-\\d{2}-\\d{2}\\.jsonl$/.test(filename);\n }\n\n /**\n * Append a turn to the appropriate transcript file.\n * Files are stored hierarchically: transcripts/{channelType}/{channelId}.jsonl\n *\n * Skips channel types in config.transcriptSkipChannelTypes (e.g., \"cron\").\n */\n async append(entry: TranscriptEntry): Promise<void> {\n try {\n const { dir, file } = this.getTranscriptPath(entry.sessionKey);\n\n // Skip if this channel type is in the skip list\n const channelType = dir.split(path.sep)[0] ?? dir;\n if (this.config.transcriptSkipChannelTypes.includes(channelType)) {\n return;\n }\n\n const channelDir = path.join(this.transcriptsDir, dir);\n const filePath = path.join(channelDir, file);\n\n // Ensure channel directory exists\n await mkdir(channelDir, { recursive: true });\n\n const line = JSON.stringify(entry) + \"\\n\";\n await appendFile(filePath, line, \"utf-8\");\n log.debug(`appended transcript entry for ${entry.sessionKey}: ${entry.turnId}`);\n } catch (err) {\n log.error(\"failed to append transcript entry:\", err);\n throw err;\n }\n }\n\n /**\n * Get all transcript files from the hierarchical directory structure.\n * Recursively finds all .jsonl files in transcripts/{channelType}/{channelId}/ subdirectories.\n */\n private async getAllTranscriptFiles(): Promise<string[]> {\n const files: string[] = [];\n\n try {\n const entries = await readdir(this.transcriptsDir, { withFileTypes: true });\n\n for (const entry of entries) {\n if (entry.isDirectory()) {\n // This is a channel type directory (discord, slack, cron, main, etc.)\n const channelTypeDir = path.join(this.transcriptsDir, entry.name);\n try {\n const channelTypeEntries = await readdir(channelTypeDir, { withFileTypes: true });\n\n for (const channelTypeEntry of channelTypeEntries) {\n if (channelTypeEntry.isDirectory()) {\n // This is a channel ID directory - contains daily transcript files\n const channelDir = path.join(channelTypeDir, channelTypeEntry.name);\n try {\n const channelFiles = await readdir(channelDir);\n for (const file of channelFiles) {\n if (file.endsWith(\".jsonl\")) {\n files.push(path.join(entry.name, channelTypeEntry.name, file));\n }\n }\n } catch {\n // Skip unreadable directories\n }\n } else if (channelTypeEntry.isFile() && channelTypeEntry.name.endsWith(\".jsonl\")) {\n // Legacy: channel type dir contains .jsonl files directly\n files.push(path.join(entry.name, channelTypeEntry.name));\n }\n }\n } catch {\n // Skip unreadable directories\n }\n } else if (entry.isFile() && entry.name.endsWith(\".jsonl\")) {\n // Legacy flat file - still include for backward compatibility\n files.push(entry.name);\n }\n }\n } catch {\n // Directory doesn't exist or is unreadable\n }\n\n return files;\n }\n\n /**\n * Read transcript entries for a date range.\n * Returns entries within the time range, optionally filtered by sessionKey.\n * Reads from all channel subdirectories in the hierarchical structure.\n */\n async readRange(startTime: string, endTime: string, sessionKey?: string): Promise<TranscriptEntry[]> {\n const start = new Date(startTime);\n const end = new Date(endTime);\n const entries: TranscriptEntry[] = [];\n\n try {\n // Get all transcript files from the hierarchical structure\n const transcriptFiles = await this.getAllTranscriptFiles();\n\n // Read each relevant file\n for (const relativePath of transcriptFiles) {\n const filePath = path.join(this.transcriptsDir, relativePath);\n try {\n const content = await readFile(filePath, \"utf-8\");\n const lines = content.trim().split(\"\\n\").filter(Boolean);\n\n for (const line of lines) {\n try {\n const entry = JSON.parse(line) as TranscriptEntry;\n const entryTime = new Date(entry.timestamp);\n\n // Check if entry is within time range\n if (entryTime >= start && entryTime <= end) {\n // Filter by sessionKey if provided\n if (!sessionKey || entry.sessionKey === sessionKey) {\n entries.push(entry);\n }\n }\n } catch {\n // Skip malformed lines\n log.debug(`skipped malformed transcript line in ${relativePath}`);\n }\n }\n } catch {\n // File doesn't exist or is unreadable - skip\n }\n }\n\n // Sort by timestamp\n entries.sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());\n\n log.debug(`read ${entries.length} transcript entries from ${transcriptFiles.length} file(s)`);\n return entries;\n } catch (err) {\n log.error(\"failed to read transcript range:\", err);\n return [];\n }\n }\n\n /**\n * Read the last N hours of transcript.\n */\n async readRecent(hours: number, sessionKey?: string): Promise<TranscriptEntry[]> {\n const end = new Date();\n const start = new Date(end.getTime() - hours * 60 * 60 * 1000);\n return this.readRange(start.toISOString(), end.toISOString(), sessionKey);\n }\n\n /**\n * Cleanup old transcript entries that are older than retentionDays.\n * For hierarchical structure, reads each file and rewrites without old entries.\n * Legacy flat files are deleted if their date is older than retentionDays.\n * Returns the number of files processed (cleaned or deleted).\n */\n async cleanup(retentionDays: number): Promise<number> {\n if (retentionDays <= 0) {\n log.warn(\"cleanup called with invalid retentionDays:\", retentionDays);\n return 0;\n }\n\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - retentionDays);\n cutoff.setHours(0, 0, 0, 0);\n\n let processed = 0;\n\n try {\n const entries = await readdir(this.transcriptsDir, { withFileTypes: true });\n\n for (const entry of entries) {\n if (entry.isDirectory()) {\n // This is a channel type directory (discord, slack, cron, main, etc.)\n const channelTypeDir = path.join(this.transcriptsDir, entry.name);\n try {\n const channelTypeEntries = await readdir(channelTypeDir, { withFileTypes: true });\n\n for (const channelTypeEntry of channelTypeEntries) {\n if (channelTypeEntry.isDirectory()) {\n // This is a channel ID directory - contains daily transcript files\n const channelDir = path.join(channelTypeDir, channelTypeEntry.name);\n try {\n const channelFiles = await readdir(channelDir);\n for (const file of channelFiles) {\n if (!file.endsWith(\".jsonl\")) continue;\n\n const filePath = path.join(channelDir, file);\n\n // Check if file is a daily transcript file (YYYY-MM-DD.jsonl)\n if (this.isLegacyTranscriptFile(file)) {\n const dateStr = file.slice(0, 10);\n const fileDate = new Date(dateStr);\n\n if (!isNaN(fileDate.getTime()) && fileDate < cutoff) {\n try {\n await unlink(filePath);\n processed++;\n log.debug(`deleted old daily transcript file: ${entry.name}/${channelTypeEntry.name}/${file}`);\n } catch (err) {\n log.error(`failed to delete transcript file ${filePath}:`, err);\n }\n }\n } else {\n // Legacy file in new structure - clean up old entries\n const cleaned = await this.cleanupTranscriptFile(filePath, cutoff);\n if (cleaned) {\n processed++;\n }\n }\n }\n } catch (err) {\n log.debug(`failed to process channel directory ${entry.name}/${channelTypeEntry.name}:`, err);\n }\n } else if (channelTypeEntry.isFile() && channelTypeEntry.name.endsWith(\".jsonl\")) {\n // Legacy: channel type dir contains .jsonl files directly\n const filePath = path.join(channelTypeDir, channelTypeEntry.name);\n const cleaned = await this.cleanupTranscriptFile(filePath, cutoff);\n if (cleaned) {\n processed++;\n }\n }\n }\n } catch (err) {\n log.debug(`failed to process channel type directory ${entry.name}:`, err);\n }\n } else if (entry.isFile() && entry.name.endsWith(\".jsonl\")) {\n // Handle legacy flat files - delete if older than retentionDays\n if (this.isLegacyTranscriptFile(entry.name)) {\n const dateStr = entry.name.slice(0, 10);\n const fileDate = new Date(dateStr);\n\n if (!isNaN(fileDate.getTime()) && fileDate < cutoff) {\n const filePath = path.join(this.transcriptsDir, entry.name);\n try {\n await unlink(filePath);\n processed++;\n log.debug(`deleted old legacy transcript file: ${entry.name}`);\n } catch (err) {\n log.error(`failed to delete legacy transcript file ${entry.name}:`, err);\n }\n }\n }\n }\n }\n\n if (processed > 0) {\n log.info(`cleaned up ${processed} transcript file(s) older than ${retentionDays} days`);\n }\n\n return processed;\n } catch (err) {\n log.error(\"failed to cleanup old transcripts:\", err);\n return 0;\n }\n }\n\n /**\n * Clean up old entries from a single transcript file.\n * Reads the file, filters out entries older than cutoff, and rewrites if needed.\n * Returns true if the file was processed (cleaned or deleted).\n */\n private async cleanupTranscriptFile(filePath: string, cutoff: Date): Promise<boolean> {\n try {\n const content = await readFile(filePath, \"utf-8\");\n const lines = content.trim().split(\"\\n\").filter(Boolean);\n\n const validLines: string[] = [];\n let hasOldEntries = false;\n\n for (const line of lines) {\n try {\n const entry = JSON.parse(line) as TranscriptEntry;\n const entryTime = new Date(entry.timestamp);\n\n if (entryTime >= cutoff) {\n validLines.push(line);\n } else {\n hasOldEntries = true;\n }\n } catch {\n // Keep malformed lines to avoid data loss\n validLines.push(line);\n }\n }\n\n if (validLines.length === 0) {\n // No valid entries left, delete the file\n try {\n await unlink(filePath);\n log.debug(`deleted empty transcript file: ${filePath}`);\n return true;\n } catch (err) {\n log.error(`failed to delete empty transcript file ${filePath}:`, err);\n return false;\n }\n }\n\n if (hasOldEntries) {\n // Rewrite file without old entries\n await writeFile(filePath, validLines.join(\"\\n\") + \"\\n\", \"utf-8\");\n log.debug(`cleaned old entries from transcript file: ${filePath}`);\n return true;\n }\n\n // No old entries found, no action needed\n return false;\n } catch (err) {\n // File doesn't exist or is unreadable\n return false;\n }\n }\n\n /**\n * Save a checkpoint to preserve conversation context.\n * Called when compaction is detected.\n */\n async saveCheckpoint(checkpoint: Checkpoint): Promise<void> {\n try {\n await writeFile(this.checkpointPath, JSON.stringify(checkpoint, null, 2), \"utf-8\");\n log.info(`saved checkpoint for session ${checkpoint.sessionKey} with ${checkpoint.turns.length} turn(s)`);\n } catch (err) {\n log.error(\"failed to save checkpoint:\", err);\n throw err;\n }\n }\n\n /**\n * Load a checkpoint if one exists and is not expired.\n * Returns null if no checkpoint exists or if it has expired.\n */\n async loadCheckpoint(sessionKey?: string): Promise<Checkpoint | null> {\n try {\n const raw = await readFile(this.checkpointPath, \"utf-8\");\n const checkpoint = JSON.parse(raw) as Checkpoint;\n\n // Validate checkpoint structure\n if (!checkpoint.sessionKey || !checkpoint.capturedAt || !checkpoint.ttl || !Array.isArray(checkpoint.turns)) {\n log.warn(\"checkpoint file has invalid structure\");\n return null;\n }\n\n // Check if checkpoint is for the requested session (if specified)\n if (sessionKey && checkpoint.sessionKey !== sessionKey) {\n log.debug(`checkpoint session mismatch: ${checkpoint.sessionKey} vs ${sessionKey}`);\n return null;\n }\n\n // Check if checkpoint has expired\n const ttl = new Date(checkpoint.ttl);\n if (isNaN(ttl.getTime())) {\n log.warn(\"checkpoint has invalid TTL format\");\n return null;\n }\n\n if (ttl < new Date()) {\n log.info(`checkpoint expired at ${checkpoint.ttl}`);\n return null;\n }\n\n log.info(`loaded checkpoint with ${checkpoint.turns.length} turn(s), expires at ${checkpoint.ttl}`);\n return checkpoint;\n } catch (err) {\n // File doesn't exist or is unreadable - that's fine\n log.debug(\"no valid checkpoint found\");\n return null;\n }\n }\n\n /**\n * Clear (delete) the checkpoint file.\n * Called after successful injection of checkpoint context.\n */\n async clearCheckpoint(): Promise<void> {\n try {\n await unlink(this.checkpointPath);\n log.info(\"cleared checkpoint\");\n } catch (err) {\n // File doesn't exist - that's fine\n log.debug(\"no checkpoint to clear\");\n }\n }\n\n /**\n * Format entries for recall injection.\n * Returns a formatted string suitable for injecting into agent context.\n *\n * Format:\n * ## Recent Conversation (last X hours)\n * [10:32] User: message content\n * [10:33] Assistant: response content\n *\n * Content is trimmed to approximately maxTokens.\n */\n formatForRecall(entries: TranscriptEntry[], maxTokens: number): string {\n if (entries.length === 0) {\n return \"\";\n }\n\n const maxChars = maxTokens * TranscriptManager.CHARS_PER_TOKEN;\n const lines: string[] = [];\n\n // Calculate time range for header\n const firstEntry = new Date(entries[0].timestamp);\n const lastEntry = new Date(entries[entries.length - 1].timestamp);\n const hoursDiff = Math.round((lastEntry.getTime() - firstEntry.getTime()) / (60 * 60 * 1000));\n\n // Add header\n if (hoursDiff < 1) {\n lines.push(\"## Recent Conversation (last few minutes)\");\n } else {\n lines.push(`## Recent Conversation (last ${hoursDiff} hour${hoursDiff === 1 ? \"\" : \"s\"})`);\n }\n lines.push(\"\");\n\n // Format each entry\n const formattedEntries: string[] = [];\n for (const entry of entries) {\n const time = new Date(entry.timestamp);\n const timeStr = time.toLocaleTimeString(\"en-US\", {\n hour: \"2-digit\",\n minute: \"2-digit\",\n hour12: false,\n });\n const roleLabel = entry.role === \"user\" ? \"User\" : \"Assistant\";\n formattedEntries.push(`[${timeStr}] ${roleLabel}: ${entry.content}`);\n }\n\n // Build output, trimming from the beginning if too long\n // (we want to keep the most recent context)\n let totalChars = lines.join(\"\\n\").length;\n const selectedEntries: string[] = [];\n\n for (let i = formattedEntries.length - 1; i >= 0; i--) {\n const entry = formattedEntries[i];\n const entryChars = entry.length + 1; // +1 for newline\n\n if (totalChars + entryChars > maxChars && selectedEntries.length > 0) {\n // Adding this entry would exceed limit, and we have some entries already\n break;\n }\n\n selectedEntries.unshift(entry);\n totalChars += entryChars;\n }\n\n lines.push(...selectedEntries);\n lines.push(\"\"); // Trailing newline\n\n const result = lines.join(\"\\n\");\n log.debug(`formatted ${selectedEntries.length}/${entries.length} transcript entries for recall (~${result.length} chars)`);\n\n return result;\n }\n\n /**\n * Create a checkpoint from the current buffer state.\n * Helper method for creating checkpoints before compaction.\n */\n createCheckpoint(sessionKey: string, turns: TranscriptEntry[], ttlHours?: number): Checkpoint {\n const ttl = ttlHours ?? TranscriptManager.DEFAULT_CHECKPOINT_TTL_HOURS;\n const expiresAt = new Date();\n expiresAt.setHours(expiresAt.getHours() + ttl);\n\n return {\n sessionKey,\n capturedAt: new Date().toISOString(),\n turns: [...turns], // Copy turns to avoid mutation\n ttl: expiresAt.toISOString(),\n };\n }\n\n /**\n * Get statistics about stored transcripts.\n * Returns counts from the hierarchical directory structure.\n */\n async getStats(): Promise<{\n totalFiles: number;\n totalEntries: number;\n oldestFile: string | null;\n newestFile: string | null;\n channelTypes: Record<string, number>;\n }> {\n try {\n const allFiles = await this.getAllTranscriptFiles();\n\n if (allFiles.length === 0) {\n return {\n totalFiles: 0,\n totalEntries: 0,\n oldestFile: null,\n newestFile: null,\n channelTypes: {},\n };\n }\n\n // Sort files by path\n const sortedFiles = allFiles.sort();\n\n let totalEntries = 0;\n const channelTypes: Record<string, number> = {};\n\n for (const relativePath of allFiles) {\n const filePath = path.join(this.transcriptsDir, relativePath);\n try {\n const content = await readFile(filePath, \"utf-8\");\n const lines = content.trim().split(\"\\n\").filter(Boolean);\n totalEntries += lines.length;\n\n // Count by channel type (first directory in path)\n const channelType = relativePath.includes(path.sep)\n ? relativePath.split(path.sep)[0]\n : \"legacy\";\n channelTypes[channelType] = (channelTypes[channelType] || 0) + 1;\n } catch {\n // Skip unreadable files\n }\n }\n\n return {\n totalFiles: allFiles.length,\n totalEntries,\n oldestFile: sortedFiles[0],\n newestFile: sortedFiles[sortedFiles.length - 1],\n channelTypes,\n };\n } catch (err) {\n log.error(\"failed to get transcript stats:\", err);\n return {\n totalFiles: 0,\n totalEntries: 0,\n oldestFile: null,\n newestFile: null,\n channelTypes: {},\n };\n }\n }\n}\n","import { mkdir, readFile, writeFile, readdir } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport { log } from \"./logger.js\";\nimport { LocalLlmClient } from \"./local-llm.js\";\nimport { FallbackLlmClient } from \"./fallback-llm.js\";\nimport { ModelRegistry } from \"./model-registry.js\";\nimport { extractJsonCandidates } from \"./json-extract.js\";\nimport type { HourlySummary, TranscriptEntry, PluginConfig, GatewayConfig } from \"./types.js\";\nimport type { TranscriptManager } from \"./transcript.js\";\n\n// Schema for LLM summary output\nconst HourlySummarySchema = z.object({\n bullets: z\n .array(z.string())\n .describe(\"3-5 bullet points summarizing the hour's activity\"),\n});\n\ntype HourlySummaryResult = z.infer<typeof HourlySummarySchema>;\n\nconst HourlySummaryExtendedSchema = z.object({\n topics: z.array(z.string()).default([]),\n decisions: z.array(z.string()).default([]),\n actionItems: z.array(z.string()).default([]),\n rejected: z.array(z.string()).default([]),\n});\n\ntype HourlySummaryExtendedResult = z.infer<typeof HourlySummaryExtendedSchema>;\n\ntype HourlySummaryExtendedMeta = {\n userTurns: number;\n assistantTurns: number;\n toolCalls: number;\n toolCounts: Record<string, number>;\n};\n\nexport class HourlySummarizer {\n private summariesDir: string;\n private config: PluginConfig;\n private localLlm: LocalLlmClient;\n private fallbackLlm: FallbackLlmClient;\n private modelRegistry: ModelRegistry;\n private transcript?: TranscriptManager;\n\n constructor(config: PluginConfig, gatewayConfig?: GatewayConfig, modelRegistry?: ModelRegistry, transcript?: TranscriptManager) {\n this.config = config;\n this.summariesDir = path.join(config.memoryDir, \"summaries\", \"hourly\");\n this.modelRegistry = modelRegistry ?? new ModelRegistry(config.memoryDir);\n this.transcript = transcript;\n\n // Initialize local LLM client with shared model registry\n this.localLlm = new LocalLlmClient(config, this.modelRegistry);\n\n // Initialize fallback client with gateway config\n this.fallbackLlm = new FallbackLlmClient(gatewayConfig);\n\n if (!gatewayConfig?.agents?.defaults?.model?.primary && !config.localLlmEnabled) {\n log.warn(\"no gateway default AI and local LLM disabled — hourly summarization disabled\");\n }\n }\n\n async initialize(): Promise<void> {\n await mkdir(this.summariesDir, { recursive: true });\n log.info(\"hourly summarizer initialized\");\n }\n\n // Generate summary for a specific hour and session\n async generateSummary(\n sessionKey: string,\n hourStart: Date,\n entries: TranscriptEntry[]\n ): Promise<HourlySummary | null> {\n if (entries.length === 0) return null;\n\n // Format entries for the LLM\n const conversation = entries\n .map((e) => `[${e.role}] ${e.content}`)\n .join(\"\\n\\n\");\n\n if (this.config.hourlySummariesExtendedEnabled) {\n const extended = await this.generateExtended(sessionKey, hourStart, conversation, entries);\n if (!extended) return null;\n const meta: HourlySummaryExtendedMeta = {\n userTurns: entries.filter((e) => e.role === \"user\").length,\n assistantTurns: entries.filter((e) => e.role === \"assistant\").length,\n toolCalls: extended._meta.toolCalls,\n toolCounts: extended._meta.toolCounts,\n };\n // Keep HourlySummary surface stable; encode \"topics\" as bullets for recall injection.\n const base: HourlySummary = {\n hour: hourStart.toISOString(),\n sessionKey,\n bullets: extended.topics.length > 0 ? extended.topics.slice(0, 5) : [\"(summary generated)\"],\n turnCount: entries.length,\n generatedAt: new Date().toISOString(),\n };\n const withExtras = base as any;\n withExtras._extended = extended;\n withExtras._extendedMeta = meta;\n return base;\n }\n\n const hourIso = hourStart.toISOString();\n const startTime = Date.now();\n\n // Try local LLM first if enabled\n if (this.config.localLlmEnabled) {\n try {\n const localResult = await this.generateWithLocalLlm(conversation);\n if (localResult) {\n const durationMs = Date.now() - startTime;\n log.debug(\n `generated hourly summary for ${sessionKey} at ${hourIso} in ${durationMs}ms using local LLM`\n );\n return {\n hour: hourIso,\n sessionKey,\n bullets: localResult.bullets,\n turnCount: entries.length,\n generatedAt: new Date().toISOString(),\n };\n }\n // Local failed, fall back if allowed\n if (!this.config.localLlmFallback) {\n log.warn(\"summary generation: local LLM failed and fallback disabled\");\n return null;\n }\n log.info(\"summary generation: local LLM unavailable, falling back to gateway default AI\");\n } catch (err) {\n if (!this.config.localLlmFallback) {\n log.warn(\"summary generation: local LLM error and fallback disabled:\", err);\n return null;\n }\n log.info(\"summary generation: local LLM error, falling back to gateway default AI:\", err);\n }\n }\n\n // Fall back to gateway's default AI\n log.info(\"summary generation: falling back to gateway default AI\");\n\n try {\n const messages = [\n {\n role: \"system\" as const,\n content: `You are a conversation summarization system. Summarize the following conversation transcript into 3-5 concise bullet points.\n\nGuidelines:\n- Focus on what was accomplished, decided, or discussed\n- Include specific topics, projects, or entities mentioned\n- Note any significant user requests or agent actions\n- Keep bullets brief but informative (1-2 sentences each)\n- Skip trivial greetings or meta-conversation\n- Use present tense for ongoing work, past for completed items\n\nRespond with valid JSON matching this schema:\n{\n \"bullets\": [\"bullet 1\", \"bullet 2\", \"bullet 3\"]\n}`,\n },\n { role: \"user\" as const, content: `Summarize this conversation:\\n\\n${conversation}` },\n ];\n\n const result = await this.fallbackLlm.parseWithSchema(\n messages,\n HourlySummarySchema,\n { temperature: 0.3, maxTokens: 8192 },\n );\n\n const durationMs = Date.now() - startTime;\n\n if (result) {\n log.debug(\n `generated hourly summary for ${sessionKey} at ${hourIso} in ${durationMs}ms via fallback`,\n );\n return {\n hour: hourIso,\n sessionKey,\n bullets: result.bullets,\n turnCount: entries.length,\n generatedAt: new Date().toISOString(),\n };\n }\n\n log.warn(\"summary generation fallback returned no parsed output\");\n return null;\n } catch (err) {\n log.error(\"summary generation fallback failed\", err);\n return null;\n }\n }\n\n private async generateExtended(\n sessionKey: string,\n hourStart: Date,\n conversation: string,\n entries: TranscriptEntry[],\n ): Promise<(HourlySummaryExtendedResult & { _meta: HourlySummaryExtendedMeta }) | null> {\n const hourIso = hourStart.toISOString();\n const startTime = Date.now();\n\n const hourEnd = new Date(hourStart.getTime() + 60 * 60 * 1000);\n let toolCounts: Record<string, number> = {};\n if (this.config.hourlySummariesIncludeToolStats && this.transcript) {\n const uses = await this.transcript.readToolUse(sessionKey, hourStart, hourEnd);\n for (const u of uses) toolCounts[u.tool] = (toolCounts[u.tool] ?? 0) + 1;\n }\n\n const sys = `You are a conversation summarization system.\\n\\nSummarize the hour into structured sections.\\n\\nReturn valid JSON matching:\\n{\\n \\\"topics\\\": [\\\"...\\\"],\\n \\\"decisions\\\": [\\\"...\\\"],\\n \\\"actionItems\\\": [\\\"...\\\"],\\n \\\"rejected\\\": [\\\"...\\\"]\\n}\\n\\nGuidelines:\\n- Prefer concrete topics and decisions.\\n- Action items should be imperative.\\n- Rejected ideas are things that were explicitly discarded or reversed.\\n- If there are none for a section, return an empty array.\\n`;\n\n const toolStatsLine = Object.keys(toolCounts).length > 0\n ? `Tools used (counts): ${Object.entries(toolCounts).sort((a,b)=>b[1]-a[1]).slice(0,10).map(([k,v])=>`${k}=${v}`).join(\", \")}\\n\\n`\n : \"\";\n const userTurns = entries.filter((e) => e.role === \"user\").length;\n const assistantTurns = entries.filter((e) => e.role === \"assistant\").length;\n const toolCalls = Object.values(toolCounts).reduce((a,b)=>a+b,0);\n const statsLine = `Stats: userTurns=${userTurns}, assistantTurns=${assistantTurns}, toolCalls=${toolCalls}\\n\\n`;\n\n const user = `Hour: ${hourIso}\\nSession: ${sessionKey}\\n\\n${statsLine}${toolStatsLine}Conversation:\\n${conversation}\\n`;\n\n // Try local LLM first if enabled\n if (this.config.localLlmEnabled) {\n try {\n const contextSizes = this.modelRegistry.calculateContextSizes(this.config.localLlmModel, this.config.localLlmMaxContext);\n const truncated = user.length > contextSizes.maxInputChars ? user.slice(0, contextSizes.maxInputChars) + \"\\n\\n[truncated]\" : user;\n const response = await this.localLlm.chatCompletion(\n [\n { role: \"system\", content: \"Output valid JSON only.\" },\n { role: \"user\", content: sys + \"\\n\\n\" + truncated },\n ],\n { temperature: 0.2, maxTokens: contextSizes.maxOutputTokens, operation: \"hourly_summary_extended\" },\n );\n if (response?.content) {\n const content = response.content.trim();\n for (const candidate of extractJsonCandidates(content)) {\n try {\n const parsed = JSON.parse(candidate);\n const result = HourlySummaryExtendedSchema.parse(parsed);\n log.debug(\n `generated extended hourly summary for ${sessionKey} at ${hourIso} in ${Date.now() - startTime}ms (local)`,\n );\n return { ...result, _meta: { userTurns, assistantTurns, toolCalls, toolCounts } };\n } catch {\n // keep trying candidates\n }\n }\n }\n } catch (err) {\n if (!this.config.localLlmFallback) return null;\n log.info(\"extended summary: local failed, falling back:\", err);\n }\n }\n\n try {\n const result = await this.fallbackLlm.parseWithSchema(\n [\n { role: \"system\" as const, content: sys },\n { role: \"user\" as const, content: user },\n ],\n HourlySummaryExtendedSchema,\n { temperature: 0.2, maxTokens: 2048 },\n );\n if (result) {\n log.debug(`generated extended hourly summary for ${sessionKey} at ${hourIso} in ${Date.now() - startTime}ms (fallback)`);\n return { ...result, _meta: { userTurns, assistantTurns, toolCalls, toolCounts } };\n }\n return null;\n } catch (err) {\n log.error(\"extended summary generation failed\", err);\n return null;\n }\n }\n\n /**\n * Generate summary using local LLM with JSON mode.\n * Uses dynamic context sizing based on model capabilities.\n */\n private async generateWithLocalLlm(conversation: string): Promise<HourlySummaryResult | null> {\n // Get dynamic context sizes based on model capabilities\n const contextSizes = this.modelRegistry.calculateContextSizes(\n this.config.localLlmModel,\n this.config.localLlmMaxContext\n );\n log.debug(`Summarizer model context: ${contextSizes.description}`);\n\n const maxConversationChars = contextSizes.maxInputChars;\n const truncatedConversation = conversation.length > maxConversationChars\n ? conversation.slice(0, maxConversationChars) + \"\\n\\n[truncated]\"\n : conversation;\n\n const instructions = `You are a conversation summarization system. Summarize the following conversation transcript into 3-5 concise bullet points.\n\nGuidelines:\n- Focus on what was accomplished, decided, or discussed\n- Include specific topics, projects, or entities mentioned\n- Note any significant user requests or agent actions\n- Keep bullets brief but informative (1-2 sentences each)\n- Skip trivial greetings or meta-conversation\n- Use present tense for ongoing work, past for completed items\n\nRespond with valid JSON matching this schema:\n{\n \"bullets\": [\"bullet 1\", \"bullet 2\", \"bullet 3\"]\n}`;\n\n const fullPrompt = `${instructions}\\n\\nConversation to summarize:\\n${truncatedConversation}`;\n\n const response = await this.localLlm.chatCompletion(\n [\n { role: \"system\", content: \"You are a conversation summarization system. Output valid JSON only.\" },\n { role: \"user\", content: fullPrompt },\n ],\n { temperature: 0.3, maxTokens: contextSizes.maxOutputTokens, operation: \"hourly_summary\" },\n );\n\n if (!response?.content) {\n return null;\n }\n\n try {\n // Parse JSON response\n const content = response.content.trim();\n for (const candidate of extractJsonCandidates(content)) {\n try {\n const parsed = JSON.parse(candidate);\n return {\n bullets: Array.isArray((parsed as any).bullets) ? (parsed as any).bullets : [],\n };\n } catch {\n // keep trying candidates\n }\n }\n return null;\n } catch (err) {\n log.warn(\"local LLM summary: failed to parse JSON response:\", err);\n return null;\n }\n }\n\n // Save summary to file\n async saveSummary(summary: HourlySummary): Promise<void> {\n const sessionDir = path.join(this.summariesDir, summary.sessionKey);\n await mkdir(sessionDir, { recursive: true });\n\n // Format date as YYYY-MM-DD for the filename\n const dateStr = summary.hour.slice(0, 10);\n const filePath = path.join(sessionDir, `${dateStr}.md`);\n\n // Format hour as HH:00 for display\n const hourStr = summary.hour.slice(11, 13);\n\n // Build markdown content\n const lines: string[] = [];\n\n // Check if file exists to append or create\n let existingContent = \"\";\n try {\n existingContent = await readFile(filePath, \"utf-8\");\n } catch {\n // File doesn't exist yet, will create new\n }\n\n // Check if this hour already exists (idempotent)\n const hourHeader = `## ${hourStr}:00`;\n if (existingContent.includes(hourHeader)) {\n // Replace existing hour section\n const beforeHour = existingContent.split(hourHeader)[0];\n const afterMatch = existingContent.split(hourHeader)[1];\n const afterHour = afterMatch ? afterMatch.split(\"\\n## \")[1] : undefined;\n\n const newSection = this.formatHourSection(summary, hourHeader);\n\n if (afterHour) {\n existingContent = beforeHour + newSection + \"\\n## \" + afterHour;\n } else {\n existingContent = beforeHour + newSection;\n }\n\n await writeFile(filePath, existingContent, \"utf-8\");\n log.debug(`updated hourly summary for ${summary.sessionKey} at ${hourStr}:00`);\n } else {\n // Append new hour section\n const newSection = this.formatHourSection(summary, hourHeader);\n\n if (existingContent) {\n // Add to existing file\n await writeFile(filePath, existingContent.trimEnd() + \"\\n\\n\" + newSection, \"utf-8\");\n } else {\n // Create new file with header\n const header = `# Hourly Summaries — ${dateStr}\\n\\n*Session: ${summary.sessionKey}*\\n`;\n await writeFile(filePath, header + \"\\n\" + newSection, \"utf-8\");\n }\n log.debug(`saved hourly summary for ${summary.sessionKey} at ${hourStr}:00`);\n }\n }\n\n private formatHourSection(summary: HourlySummary, hourHeader: string): string {\n const ext = (summary as any)._extended as (HourlySummaryExtendedResult & { _meta?: HourlySummaryExtendedMeta }) | undefined;\n const meta = (summary as any)._extendedMeta as HourlySummaryExtendedMeta | undefined;\n const lines: string[] = [hourHeader, \"\"];\n\n if (this.config.hourlySummariesExtendedEnabled && ext) {\n lines.push(\"### Topics Discussed\");\n for (const t of ext.topics) lines.push(`- ${t}`);\n lines.push(\"\");\n lines.push(\"### Decisions Made\");\n for (const d of ext.decisions) lines.push(`- ${d}`);\n lines.push(\"\");\n lines.push(\"### Action Items\");\n for (const a of ext.actionItems) lines.push(`- ${a}`);\n lines.push(\"\");\n lines.push(\"### Rejected Ideas / Reversals\");\n for (const r of ext.rejected) lines.push(`- ${r}`);\n lines.push(\"\");\n if (meta && Object.keys(meta.toolCounts).length > 0) {\n lines.push(\"### Tools Used\");\n const top = Object.entries(meta.toolCounts)\n .sort((a, b) => b[1] - a[1])\n .slice(0, 12);\n for (const [name, count] of top) lines.push(`- ${name}: ${count}`);\n lines.push(\"\");\n }\n lines.push(\"### Stats\");\n lines.push(`- Turns: ${summary.turnCount}`);\n if (meta) {\n lines.push(`- User turns: ${meta.userTurns}`);\n lines.push(`- Assistant turns: ${meta.assistantTurns}`);\n lines.push(`- Tool calls: ${meta.toolCalls}`);\n }\n lines.push(\"\");\n return lines.join(\"\\n\");\n }\n\n for (const bullet of summary.bullets) lines.push(`- ${bullet}`);\n lines.push(` *(${summary.turnCount} turns)*`);\n lines.push(\"\");\n return lines.join(\"\\n\");\n }\n\n // Read recent summaries for recall injection\n async readRecent(sessionKey: string, hours: number): Promise<HourlySummary[]> {\n const sessionDir = path.join(this.summariesDir, sessionKey);\n\n try {\n const files = await readdir(sessionDir);\n const mdFiles = files.filter((f) => f.endsWith(\".md\"));\n\n const summaries: HourlySummary[] = [];\n const cutoffTime = Date.now() - hours * 60 * 60 * 1000;\n\n for (const file of mdFiles) {\n const filePath = path.join(sessionDir, file);\n const content = await readFile(filePath, \"utf-8\");\n\n // Parse the markdown file\n const parsed = this.parseSummaryFile(content, sessionKey, file);\n summaries.push(...parsed);\n }\n\n // Filter to recent hours and sort by hour descending\n return summaries\n .filter((s) => new Date(s.hour).getTime() >= cutoffTime)\n .sort((a, b) => new Date(b.hour).getTime() - new Date(a.hour).getTime());\n } catch {\n // Directory doesn't exist or error reading\n return [];\n }\n }\n\n private parseSummaryFile(\n content: string,\n sessionKey: string,\n filename: string\n ): HourlySummary[] {\n const summaries: HourlySummary[] = [];\n\n // Extract date from filename (YYYY-MM-DD.md)\n const dateMatch = filename.match(/^(\\d{4}-\\d{2}-\\d{2})\\.md$/);\n if (!dateMatch) return summaries;\n const dateStr = dateMatch[1];\n\n // Split by hour sections\n const hourSections = content.split(/\\n## (\\d{2}):00\\n/);\n\n // First element is the header, skip it\n for (let i = 1; i < hourSections.length; i += 2) {\n const hourStr = hourSections[i];\n const sectionContent = hourSections[i + 1] || \"\";\n\n // Parse bullets\n const bullets: string[] = [];\n const lines = sectionContent.split(\"\\n\");\n let turnCount = 0;\n\n let inTopics = false;\n let sawExtendedTopicsHeader = false;\n for (const line of lines) {\n if (line.startsWith(\"### Topics\")) {\n inTopics = true;\n sawExtendedTopicsHeader = true;\n continue;\n }\n if (line.startsWith(\"### \") && !line.startsWith(\"### Topics\")) {\n inTopics = false;\n }\n const bulletMatch = line.match(/^- (.+)$/);\n if (bulletMatch) {\n // For extended format, only treat topic bullets as recall bullets.\n if (!sawExtendedTopicsHeader || inTopics) bullets.push(bulletMatch[1]);\n }\n const turnMatch = line.match(/\\((\\d+) turns?\\)/);\n if (turnMatch) turnCount = parseInt(turnMatch[1], 10);\n }\n\n if (bullets.length > 0) {\n summaries.push({\n hour: `${dateStr}T${hourStr}:00:00.000Z`,\n sessionKey,\n bullets,\n turnCount,\n generatedAt: \"\", // Not stored in file, not needed for recall\n });\n }\n }\n\n return summaries;\n }\n\n // Format summaries for recall injection\n formatForRecall(summaries: HourlySummary[], maxCount: number): string {\n if (summaries.length === 0) return \"\";\n\n const limited = summaries.slice(0, maxCount);\n const lines: string[] = [`## Recent Activity (last ${limited.length} hours)`];\n\n for (const summary of limited) {\n const hourStr = summary.hour.slice(11, 16); // HH:MM\n for (const bullet of summary.bullets) {\n lines.push(`- ${hourStr}: ${bullet}`);\n }\n }\n\n return lines.join(\"\\n\");\n }\n\n // Main entry point for cron job\n async runHourly(): Promise<void> {\n log.debug(\"running hourly summary generation\");\n\n // Get active sessions from transcript\n const sessions = await this.getActiveSessions();\n\n for (const sessionKey of sessions) {\n // Calculate the hour we want to summarize (previous hour)\n const now = new Date();\n const hourStart = new Date(now.getTime() - 60 * 60 * 1000);\n hourStart.setMinutes(0, 0, 0);\n const hourEnd = new Date(hourStart.getTime() + 60 * 60 * 1000);\n\n // Get entries for this session in the target hour\n const entries = await this.getTranscriptEntries(sessionKey, hourStart, hourEnd);\n\n if (entries.length === 0) {\n log.debug(`no transcript entries for ${sessionKey} at ${hourStart.toISOString()}`);\n continue;\n }\n\n // Generate and save summary\n const summary = await this.generateSummary(sessionKey, hourStart, entries);\n if (summary) {\n await this.saveSummary(summary);\n log.info(`generated hourly summary for ${sessionKey} (${entries.length} turns)`);\n }\n }\n }\n\n // Get list of active sessions from transcript directory\n private async getActiveSessions(): Promise<string[]> {\n const transcriptDir = path.join(this.config.memoryDir, \"transcripts\");\n\n try {\n const sessionKeys = new Set<string>();\n const typeEntries = await readdir(transcriptDir, { withFileTypes: true });\n for (const typeEnt of typeEntries) {\n if (!typeEnt.isDirectory()) continue;\n const typeDir = path.join(transcriptDir, typeEnt.name);\n const idEntries = await readdir(typeDir, { withFileTypes: true });\n for (const idEnt of idEntries) {\n if (!idEnt.isDirectory()) continue;\n const chanDir = path.join(typeDir, idEnt.name);\n const files = (await readdir(chanDir)).filter((f) => f.endsWith(\".jsonl\")).sort();\n const last = files[files.length - 1];\n if (!last) continue;\n try {\n const raw = await readFile(path.join(chanDir, last), \"utf-8\");\n const firstLine = raw.split(\"\\n\").find((l) => l.trim().length > 0);\n if (!firstLine) continue;\n const entry = JSON.parse(firstLine) as TranscriptEntry;\n if (typeof entry.sessionKey === \"string\" && entry.sessionKey.length > 0) {\n sessionKeys.add(entry.sessionKey);\n }\n } catch {\n // ignore\n }\n }\n }\n return Array.from(sessionKeys);\n } catch {\n return [];\n }\n }\n\n // Get transcript entries for a session within a time range\n private async getTranscriptEntries(\n sessionKey: string,\n startTime: Date,\n endTime: Date\n ): Promise<TranscriptEntry[]> {\n const parts = sessionKey.split(\":\");\n let channelType = \"other\";\n let channelId = \"default\";\n\n if (parts.length >= 3) {\n channelType = parts[2];\n if (channelType === \"main\") {\n channelId = \"default\";\n } else if (channelType === \"discord\" && parts.length >= 5 && parts[3] === \"channel\") {\n channelId = parts[4];\n } else if (channelType === \"slack\" && parts.length >= 5 && parts[3] === \"channel\") {\n channelId = parts[4];\n } else if (channelType === \"cron\" && parts.length >= 4) {\n channelId = parts[3];\n } else if (parts.length >= 4) {\n channelId = parts[3];\n }\n }\n\n const transcriptDir = path.join(this.config.memoryDir, \"transcripts\", channelType, channelId);\n\n try {\n // Read all daily transcript files in the directory\n const files = await readdir(transcriptDir);\n const entries: TranscriptEntry[] = [];\n\n for (const file of files) {\n if (!file.endsWith(\".jsonl\")) continue;\n\n const transcriptPath = path.join(transcriptDir, file);\n try {\n const content = await readFile(transcriptPath, \"utf-8\");\n const lines = content.trim().split(\"\\n\");\n\n for (const line of lines) {\n if (!line.trim()) continue;\n try {\n const entry = JSON.parse(line) as TranscriptEntry;\n const entryTime = new Date(entry.timestamp).getTime();\n\n if (entryTime >= startTime.getTime() && entryTime < endTime.getTime()) {\n entries.push(entry);\n }\n } catch {\n // Skip malformed lines\n }\n }\n } catch {\n // Skip unreadable files\n }\n }\n\n return entries;\n } catch {\n return [];\n }\n }\n}\n","export interface RerankCandidate {\n id: string;\n originalIndex: number;\n}\n\nexport interface RerankScore {\n id: string;\n score: number;\n}\n\nexport interface RerankCacheEntry {\n expiresAtMs: number;\n rankedIds: string[];\n}\n\nexport class RerankCache {\n private entries = new Map<string, RerankCacheEntry>();\n\n get(key: string): string[] | null {\n const e = this.entries.get(key);\n if (!e) return null;\n if (Date.now() > e.expiresAtMs) {\n this.entries.delete(key);\n return null;\n }\n return e.rankedIds;\n }\n\n set(key: string, rankedIds: string[], ttlMs: number): void {\n this.entries.set(key, { rankedIds, expiresAtMs: Date.now() + ttlMs });\n }\n}\n\n/**\n * Parse a rerank response (JSON) and return candidates sorted by score.\n *\n * Rules:\n * - Unknown IDs in the response are ignored.\n * - Candidates missing from the response keep relative order after scored ones.\n * - Stable tie-breaker: originalIndex ascending.\n */\nexport function parseRerankResponse(\n raw: string,\n candidates: RerankCandidate[],\n): Array<RerankCandidate & { score?: number }> {\n const byId = new Map<string, RerankCandidate>();\n for (const c of candidates) byId.set(c.id, c);\n\n const scores = new Map<string, number>();\n try {\n const parsed = JSON.parse(raw) as { scores?: Array<Partial<RerankScore>> };\n if (Array.isArray(parsed.scores)) {\n for (const s of parsed.scores) {\n if (!s || typeof s.id !== \"string\") continue;\n if (!byId.has(s.id)) continue;\n if (typeof s.score !== \"number\" || !Number.isFinite(s.score)) continue;\n scores.set(s.id, s.score);\n }\n }\n } catch {\n // Ignore parse errors and fall back to original order.\n }\n\n const withScore = candidates.map((c) => ({\n ...c,\n score: scores.get(c.id),\n }));\n\n return withScore.sort((a, b) => {\n const as = a.score;\n const bs = b.score;\n if (typeof as === \"number\" && typeof bs === \"number\") {\n if (bs !== as) return bs - as;\n return a.originalIndex - b.originalIndex;\n }\n if (typeof as === \"number\") return -1;\n if (typeof bs === \"number\") return 1;\n return a.originalIndex - b.originalIndex;\n });\n}\n\nfunction stableKey(query: string, ids: string[]): string {\n // Keep it simple and deterministic; this is not a security boundary.\n return `${query.trim().toLowerCase()}|${ids.join(\",\")}`;\n}\n\nfunction clampSnippet(snippet: string, maxChars: number): string {\n const s = snippet.replace(/\\s+/g, \" \").trim();\n return s.length > maxChars ? s.slice(0, maxChars) : s;\n}\n\nexport async function rerankLocalOrNoop(opts: {\n query: string;\n candidates: Array<{ id: string; snippet: string }>;\n local: {\n chatCompletion: (\n messages: Array<{ role: string; content: string }>,\n options?: { maxTokens?: number; temperature?: number; timeoutMs?: number; operation?: string },\n ) => Promise<{ content: string } | null>;\n };\n enabled: boolean;\n timeoutMs: number;\n maxCandidates: number;\n cache?: RerankCache;\n cacheEnabled: boolean;\n cacheTtlMs: number;\n}): Promise<string[] | null> {\n if (!opts.enabled) return null;\n\n const ids = opts.candidates.slice(0, opts.maxCandidates).map((c) => c.id);\n if (ids.length <= 1) return ids;\n\n const key = stableKey(opts.query, ids);\n if (opts.cache && opts.cacheEnabled) {\n const cached = opts.cache.get(key);\n if (cached) return cached;\n }\n\n const payload = opts.candidates.slice(0, opts.maxCandidates).map((c) => ({\n id: c.id,\n snippet: clampSnippet(c.snippet, 400),\n }));\n\n const system =\n \"You are a ranking system. Return JSON only. No markdown, no commentary.\";\n const user = JSON.stringify(\n {\n task: \"rerank\",\n query: opts.query,\n candidates: payload,\n output: {\n scores: [{ id: \"string\", score: \"number 0-100\" }],\n },\n rules: [\n \"Assign higher score to more relevant candidates.\",\n \"Prefer durability and direct relevance to the query.\",\n \"If unsure, keep scores close together.\",\n ],\n },\n null,\n 0,\n );\n\n const res = await opts.local.chatCompletion(\n [\n { role: \"system\", content: system },\n { role: \"user\", content: user },\n ],\n {\n maxTokens: 800,\n temperature: 0.0,\n timeoutMs: opts.timeoutMs,\n operation: \"rerank\",\n },\n );\n if (!res?.content) return null;\n\n const parsed = parseRerankResponse(\n res.content,\n ids.map((id, i) => ({ id, originalIndex: i })),\n );\n const rankedIds = parsed.map((p) => p.id);\n\n if (opts.cache && opts.cacheEnabled) {\n opts.cache.set(key, rankedIds, opts.cacheTtlMs);\n }\n\n return rankedIds;\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { log } from \"./logger.js\";\nimport type { RelevanceFeedback } from \"./types.js\";\n\ntype RelevanceState = Record<string, RelevanceFeedback>;\n\nexport class RelevanceStore {\n private readonly statePath: string;\n private state: RelevanceState = {};\n\n constructor(memoryDir: string) {\n this.statePath = path.join(memoryDir, \"state\", \"relevance.json\");\n }\n\n async load(): Promise<void> {\n try {\n const raw = await readFile(this.statePath, \"utf-8\");\n const parsed = JSON.parse(raw) as RelevanceState;\n if (parsed && typeof parsed === \"object\") this.state = parsed;\n } catch {\n this.state = {};\n }\n }\n\n /**\n * Record a thumbs up/down for a memory ID.\n * This is intentionally lightweight; it should never block agent execution.\n */\n async record(memoryId: string, vote: \"up\" | \"down\", note?: string): Promise<void> {\n const now = new Date().toISOString();\n const existing = this.state[memoryId] ?? { up: 0, down: 0, lastUpdatedAt: now };\n const next: RelevanceFeedback = {\n up: existing.up + (vote === \"up\" ? 1 : 0),\n down: existing.down + (vote === \"down\" ? 1 : 0),\n lastUpdatedAt: now,\n notes: note\n ? [...(existing.notes ?? []).slice(-19), note]\n : existing.notes,\n };\n this.state[memoryId] = next;\n\n try {\n await mkdir(path.dirname(this.statePath), { recursive: true });\n await writeFile(this.statePath, JSON.stringify(this.state, null, 2), \"utf-8\");\n } catch (err) {\n log.debug(`relevance store write failed: ${err}`);\n }\n }\n\n /**\n * Convert feedback into a small score adjustment.\n * Intended to be used as a tie-breaker/soft bias, not a hard filter.\n */\n adjustment(memoryId: string): number {\n const fb = this.state[memoryId];\n if (!fb) return 0;\n\n // Cap effect to avoid runaway ranking distortion.\n const up = Math.min(3, fb.up);\n const down = Math.min(3, fb.down);\n\n // Typical QMD scores are around 0-1; keep adjustments small.\n return up * 0.05 - down * 0.10; // max +0.15, min -0.30\n }\n}\n\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { log } from \"./logger.js\";\n\nexport interface NegativeExampleEntry {\n notUseful: number;\n lastUpdatedAt: string;\n notes?: string[];\n}\n\ntype NegativeState = Record<string, NegativeExampleEntry>;\n\nexport class NegativeExampleStore {\n private readonly statePath: string;\n private state: NegativeState = {};\n\n constructor(memoryDir: string) {\n this.statePath = path.join(memoryDir, \"state\", \"negative_examples.json\");\n }\n\n async load(): Promise<void> {\n try {\n const raw = await readFile(this.statePath, \"utf-8\");\n const parsed = JSON.parse(raw) as NegativeState;\n if (parsed && typeof parsed === \"object\") this.state = parsed;\n } catch {\n this.state = {};\n }\n }\n\n /**\n * Record that a memory was retrieved but not useful for the user.\n * This should be lightweight and never block agent execution.\n */\n async recordNotUseful(memoryIds: string[], note?: string): Promise<void> {\n const now = new Date().toISOString();\n\n for (const memoryId of memoryIds) {\n const existing = this.state[memoryId] ?? { notUseful: 0, lastUpdatedAt: now };\n const next: NegativeExampleEntry = {\n notUseful: existing.notUseful + 1,\n lastUpdatedAt: now,\n notes: note\n ? [...(existing.notes ?? []).slice(-19), note]\n : existing.notes,\n };\n this.state[memoryId] = next;\n }\n\n try {\n await mkdir(path.dirname(this.statePath), { recursive: true });\n await writeFile(this.statePath, JSON.stringify(this.state, null, 2), \"utf-8\");\n } catch (err) {\n log.debug(`negative example store write failed: ${err}`);\n }\n }\n\n /**\n * Convert negative examples into a small score penalty.\n * Intended as a soft bias, not a hard filter.\n */\n penalty(memoryId: string, opts: { perHit: number; cap: number }): number {\n const entry = this.state[memoryId];\n if (!entry) return 0;\n\n // Cap effect to avoid runaway ranking distortion.\n const hits = Math.min(10, entry.notUseful);\n const raw = hits * opts.perHit;\n return Math.min(opts.cap, raw);\n }\n}\n\n","import { appendFile, mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { createHash } from \"node:crypto\";\nimport { log } from \"./logger.js\";\n\nexport interface LastRecallSnapshot {\n sessionKey: string;\n recordedAt: string;\n queryHash: string;\n queryLen: number;\n memoryIds: string[];\n}\n\ntype LastRecallState = Record<string, LastRecallSnapshot>;\n\nexport class LastRecallStore {\n private readonly statePath: string;\n private readonly impressionsPath: string;\n private state: LastRecallState = {};\n\n constructor(memoryDir: string) {\n this.statePath = path.join(memoryDir, \"state\", \"last_recall.json\");\n this.impressionsPath = path.join(memoryDir, \"state\", \"recall_impressions.jsonl\");\n }\n\n async load(): Promise<void> {\n try {\n const raw = await readFile(this.statePath, \"utf-8\");\n const parsed = JSON.parse(raw) as LastRecallState;\n if (parsed && typeof parsed === \"object\") this.state = parsed;\n } catch {\n this.state = {};\n }\n }\n\n get(sessionKey: string): LastRecallSnapshot | null {\n return this.state[sessionKey] ?? null;\n }\n\n getMostRecent(): LastRecallSnapshot | null {\n const snapshots = Object.values(this.state);\n if (snapshots.length === 0) return null;\n snapshots.sort((a, b) => b.recordedAt.localeCompare(a.recordedAt));\n return snapshots[0] ?? null;\n }\n\n /**\n * Persist last-recall snapshot and append an impression log entry.\n * Does not store raw query text; uses a stable hash for correlation.\n */\n async record(opts: { sessionKey: string; query: string; memoryIds: string[] }): Promise<void> {\n const now = new Date().toISOString();\n const queryHash = createHash(\"sha256\").update(opts.query).digest(\"hex\");\n\n const snapshot: LastRecallSnapshot = {\n sessionKey: opts.sessionKey,\n recordedAt: now,\n queryHash,\n queryLen: opts.query.length,\n memoryIds: opts.memoryIds,\n };\n\n this.state[opts.sessionKey] = snapshot;\n\n // Keep the state bounded; the impression log is append-only.\n const keys = Object.keys(this.state);\n if (keys.length > 50) {\n const ordered = keys\n .map((k) => ({ k, at: this.state[k]?.recordedAt ?? \"\" }))\n .sort((a, b) => b.at.localeCompare(a.at));\n for (const doomed of ordered.slice(50)) {\n delete this.state[doomed.k];\n }\n }\n\n try {\n await mkdir(path.dirname(this.statePath), { recursive: true });\n await writeFile(this.statePath, JSON.stringify(this.state, null, 2), \"utf-8\");\n } catch (err) {\n log.debug(`last recall store write failed: ${err}`);\n }\n\n try {\n await mkdir(path.dirname(this.impressionsPath), { recursive: true });\n await appendFile(this.impressionsPath, JSON.stringify(snapshot) + \"\\n\", \"utf-8\");\n } catch (err) {\n log.debug(`recall impressions append failed: ${err}`);\n }\n }\n}\n","import path from \"node:path\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { log } from \"./logger.js\";\nimport type { PluginConfig } from \"./types.js\";\n\ntype EmbeddingProviderType = \"openai\" | \"local\";\n\ntype ProviderConfig = {\n type: EmbeddingProviderType;\n model: string;\n endpoint: string;\n headers: Record<string, string>;\n};\n\ntype EmbeddingIndexEntry = {\n vector: number[];\n path: string;\n};\n\ntype EmbeddingIndexFile = {\n version: 1;\n provider: EmbeddingProviderType;\n model: string;\n entries: Record<string, EmbeddingIndexEntry>;\n};\n\nconst DEFAULT_OPENAI_MODEL = \"text-embedding-3-small\";\n\nexport class EmbeddingFallback {\n private readonly indexPath: string;\n private loaded: EmbeddingIndexFile | null = null;\n\n constructor(private readonly config: PluginConfig) {\n this.indexPath = path.join(config.memoryDir, \"state\", \"embeddings.json\");\n }\n\n async isAvailable(): Promise<boolean> {\n return (await this.resolveProvider()) !== null;\n }\n\n async search(\n query: string,\n limit: number,\n ): Promise<Array<{ id: string; score: number; path: string }>> {\n const provider = await this.resolveProvider();\n if (!provider) return [];\n\n const index = await this.loadIndex(provider);\n const ids = Object.keys(index.entries);\n if (ids.length === 0) return [];\n\n const queryVector = await this.embed(query, provider);\n if (!queryVector) return [];\n\n const scored = ids\n .map((id) => {\n const entry = index.entries[id];\n return {\n id,\n path: entry.path,\n score: cosineSimilarity(queryVector, entry.vector),\n };\n })\n .filter((r) => Number.isFinite(r.score))\n .sort((a, b) => b.score - a.score)\n .slice(0, Math.max(1, limit));\n\n return scored;\n }\n\n async indexFile(memoryId: string, content: string, filePath: string): Promise<void> {\n const provider = await this.resolveProvider();\n if (!provider) return;\n const vector = await this.embed(content, provider);\n if (!vector) return;\n\n const index = await this.loadIndex(provider);\n const relPath = toMemoryRelativePath(this.config.memoryDir, filePath);\n index.entries[memoryId] = {\n vector,\n path: relPath,\n };\n await this.saveIndex(index);\n }\n\n async removeFromIndex(memoryId: string): Promise<void> {\n const provider = await this.resolveProvider();\n if (!provider) return;\n\n const index = await this.loadIndex(provider);\n if (!index.entries[memoryId]) return;\n delete index.entries[memoryId];\n await this.saveIndex(index);\n }\n\n private async resolveProvider(): Promise<ProviderConfig | null> {\n if (!this.config.embeddingFallbackEnabled) return null;\n\n const preferred = this.config.embeddingFallbackProvider;\n const providers = preferred === \"auto\" ? [\"openai\", \"local\"] : [preferred];\n\n for (const p of providers) {\n if (p === \"openai\" && this.config.openaiApiKey) {\n return {\n type: \"openai\",\n model: DEFAULT_OPENAI_MODEL,\n endpoint: \"https://api.openai.com/v1/embeddings\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.config.openaiApiKey}`,\n },\n };\n }\n\n if (p === \"local\" && this.config.localLlmEnabled && this.config.localLlmUrl) {\n const base = this.config.localLlmUrl.replace(/\\/$/, \"\");\n const endpoint = /\\/v1$/i.test(base) ? `${base}/embeddings` : `${base}/v1/embeddings`;\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...(this.config.localLlmHeaders ?? {}),\n };\n if (this.config.localLlmApiKey && this.config.localLlmAuthHeader !== false) {\n headers.Authorization = `Bearer ${this.config.localLlmApiKey}`;\n }\n return {\n type: \"local\",\n model: this.config.localLlmModel || DEFAULT_OPENAI_MODEL,\n endpoint,\n headers,\n };\n }\n }\n\n return null;\n }\n\n private async embed(input: string, provider: ProviderConfig): Promise<number[] | null> {\n try {\n const res = await fetch(provider.endpoint, {\n method: \"POST\",\n headers: provider.headers,\n body: JSON.stringify({\n model: provider.model,\n input: input.slice(0, 8000),\n }),\n });\n if (!res.ok) {\n log.debug(`embedding fallback request failed: ${provider.type} ${res.status}`);\n return null;\n }\n const payload = (await res.json()) as any;\n const vector = payload?.data?.[0]?.embedding;\n if (!Array.isArray(vector)) return null;\n return vector.map((n: unknown) => Number(n)).filter((n: number) => Number.isFinite(n));\n } catch (err) {\n log.debug(`embedding fallback error: ${err}`);\n return null;\n }\n }\n\n private async loadIndex(provider: ProviderConfig): Promise<EmbeddingIndexFile> {\n if (this.loaded && this.loaded.provider === provider.type && this.loaded.model === provider.model) {\n return this.loaded;\n }\n\n try {\n const raw = await readFile(this.indexPath, \"utf-8\");\n const parsed = JSON.parse(raw) as EmbeddingIndexFile;\n if (parsed && parsed.version === 1 && parsed.entries && typeof parsed.entries === \"object\") {\n this.loaded = {\n version: 1,\n provider: provider.type,\n model: provider.model,\n entries: parsed.entries,\n };\n return this.loaded;\n }\n } catch {\n // ignore and create a new index\n }\n\n this.loaded = {\n version: 1,\n provider: provider.type,\n model: provider.model,\n entries: {},\n };\n return this.loaded;\n }\n\n private async saveIndex(index: EmbeddingIndexFile): Promise<void> {\n await mkdir(path.dirname(this.indexPath), { recursive: true });\n await writeFile(this.indexPath, JSON.stringify(index), \"utf-8\");\n this.loaded = index;\n }\n}\n\nfunction toMemoryRelativePath(memoryDir: string, filePath: string): string {\n if (!path.isAbsolute(filePath)) return filePath;\n const rel = path.relative(memoryDir, filePath);\n return rel.startsWith(\"..\") ? filePath : rel;\n}\n\nfunction cosineSimilarity(a: number[], b: number[]): number {\n const n = Math.min(a.length, b.length);\n if (n === 0) return 0;\n let dot = 0;\n let normA = 0;\n let normB = 0;\n for (let i = 0; i < n; i++) {\n const av = a[i] ?? 0;\n const bv = b[i] ?? 0;\n dot += av * bv;\n normA += av * av;\n normB += bv * bv;\n }\n const denom = Math.sqrt(normA) * Math.sqrt(normB);\n if (denom === 0) return 0;\n return dot / denom;\n}\n\n","import path from \"node:path\";\nimport { readdir, readFile } from \"node:fs/promises\";\nimport { scanSignals } from \"./signal.js\";\nimport { log } from \"./logger.js\";\nimport type { PluginConfig } from \"./types.js\";\nimport type { Orchestrator } from \"./orchestrator.js\";\n\nexport type BootstrapResult = {\n sessionsScanned: number;\n turnsProcessed: number;\n highSignalTurns: number;\n memoriesCreated: number;\n skipped: number;\n};\n\nexport type BootstrapOptions = {\n dryRun?: boolean;\n sessionsDir?: string;\n limit?: number;\n since?: Date;\n};\n\ntype BootstrapEntry = {\n role: string;\n content: string;\n timestamp: string;\n sessionKey?: string;\n};\n\nexport class BootstrapEngine {\n constructor(private config: PluginConfig, private orchestrator: Orchestrator) {}\n\n async run(options: BootstrapOptions): Promise<BootstrapResult> {\n const dryRun = options.dryRun === true;\n const since = options.since ?? new Date(0);\n const end = new Date();\n const limit = Math.max(0, options.limit ?? Number.POSITIVE_INFINITY);\n\n const sessions = await this.resolveSessions(options.sessionsDir, since, end);\n const selected = sessions.slice(0, Number.isFinite(limit) ? limit : sessions.length);\n\n const beforeCount = dryRun ? 0 : (await this.orchestrator.storage.readAllMemories()).length;\n let turnsProcessed = 0;\n let highSignalTurns = 0;\n let skipped = 0;\n\n for (const session of selected) {\n for (const entry of session.entries) {\n if (entry.role !== \"user\") continue;\n turnsProcessed += 1;\n\n const content = typeof entry.content === \"string\" ? entry.content.trim() : \"\";\n if (!content) {\n skipped += 1;\n continue;\n }\n\n const signal = scanSignals(content, this.config.highSignalPatterns);\n if (signal.level !== \"high\") {\n skipped += 1;\n continue;\n }\n\n highSignalTurns += 1;\n if (!dryRun) {\n await this.orchestrator.processTurn(\"user\", content, session.sessionKey);\n }\n }\n }\n\n let memoriesCreated = 0;\n if (!dryRun && highSignalTurns > 0) {\n await this.orchestrator.waitForExtractionIdle();\n const afterCount = (await this.orchestrator.storage.readAllMemories()).length;\n memoriesCreated = Math.max(0, afterCount - beforeCount);\n }\n\n const result: BootstrapResult = {\n sessionsScanned: selected.length,\n turnsProcessed,\n highSignalTurns,\n memoriesCreated,\n skipped,\n };\n log.info(\n `bootstrap complete: sessions=${result.sessionsScanned}, turns=${result.turnsProcessed}, high=${result.highSignalTurns}, created=${result.memoriesCreated}, skipped=${result.skipped}, dryRun=${dryRun}`,\n );\n return result;\n }\n\n private async resolveSessions(\n sessionsDir: string | undefined,\n since: Date,\n until: Date,\n ): Promise<Array<{ sessionKey: string; entries: BootstrapEntry[] }>> {\n if (sessionsDir && sessionsDir.trim().length > 0) {\n return this.readSessionsFromDir(sessionsDir, since, until);\n }\n\n const keys = await this.orchestrator.transcript.listSessionKeys();\n const sessions: Array<{ sessionKey: string; entries: BootstrapEntry[] }> = [];\n for (const key of keys) {\n const entries = await this.orchestrator.transcript.readRange(\n since.toISOString(),\n until.toISOString(),\n key,\n );\n if (entries.length > 0) {\n sessions.push({ sessionKey: key, entries });\n }\n }\n return sessions;\n }\n\n private async readSessionsFromDir(\n baseDir: string,\n since: Date,\n until: Date,\n ): Promise<Array<{ sessionKey: string; entries: BootstrapEntry[] }>> {\n const files = await this.listJsonlFiles(baseDir);\n const bySession = new Map<string, BootstrapEntry[]>();\n\n for (const filePath of files) {\n let raw = \"\";\n try {\n raw = await readFile(filePath, \"utf-8\");\n } catch {\n continue;\n }\n const lines = raw.split(\"\\n\").filter((line) => line.trim().length > 0);\n for (const line of lines) {\n let parsed: any;\n try {\n parsed = JSON.parse(line);\n } catch {\n continue;\n }\n const ts = new Date(String(parsed?.timestamp ?? \"\"));\n if (Number.isNaN(ts.getTime())) continue;\n if (ts < since || ts > until) continue;\n const role = String(parsed?.role ?? \"\");\n const content = typeof parsed?.content === \"string\" ? parsed.content : \"\";\n if (!role || !content) continue;\n const sessionKey = typeof parsed?.sessionKey === \"string\" && parsed.sessionKey.length > 0\n ? parsed.sessionKey\n : path.relative(baseDir, filePath);\n const list = bySession.get(sessionKey) ?? [];\n list.push({\n role,\n content,\n timestamp: ts.toISOString(),\n sessionKey,\n });\n bySession.set(sessionKey, list);\n }\n }\n\n return Array.from(bySession.entries()).map(([sessionKey, entries]) => ({\n sessionKey,\n entries: entries.sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()),\n }));\n }\n\n private async listJsonlFiles(dir: string): Promise<string[]> {\n const out: string[] = [];\n const entries = await readdir(dir, { withFileTypes: true }).catch(() => []);\n for (const entry of entries) {\n const full = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n out.push(...(await this.listJsonlFiles(full)));\n } else if (entry.isFile() && full.endsWith(\".jsonl\")) {\n out.push(full);\n }\n }\n return out;\n }\n}\n\n","import type { TranscriptEntry } from \"../types.js\";\n\nexport interface ConversationChunk {\n id: string;\n sessionKey: string;\n startTs: string;\n endTs: string;\n text: string;\n}\n\nexport function chunkTranscriptEntries(\n sessionKey: string,\n entries: TranscriptEntry[],\n opts: { maxChars: number; maxTurns: number },\n): ConversationChunk[] {\n const maxChars = Math.max(500, opts.maxChars);\n const maxTurns = Math.max(5, opts.maxTurns);\n const sorted = [...entries].sort((a, b) => a.timestamp.localeCompare(b.timestamp));\n\n const out: ConversationChunk[] = [];\n let buf: TranscriptEntry[] = [];\n let bufChars = 0;\n\n function flush(): void {\n if (buf.length === 0) return;\n const startTs = buf[0]!.timestamp;\n const endTs = buf[buf.length - 1]!.timestamp;\n const text = buf.map((e) => `[${e.role}] ${e.content}`).join(\"\\n\\n\");\n const id = `${startTs}-${out.length}`.replace(/[:.]/g, \"-\");\n out.push({ id, sessionKey, startTs, endTs, text });\n buf = [];\n bufChars = 0;\n }\n\n for (const e of sorted) {\n const line = `[${e.role}] ${e.content}\\n\\n`;\n if (buf.length >= maxTurns || bufChars + line.length > maxChars) {\n flush();\n }\n buf.push(e);\n bufChars += line.length;\n }\n flush();\n\n return out;\n}\n\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { ConversationChunk } from \"./chunker.js\";\n\nexport function sanitizeSessionKey(sessionKey: string): string {\n const raw = typeof sessionKey === \"string\" && sessionKey.trim().length > 0\n ? sessionKey\n : \"unknown-session\";\n return raw.toLowerCase().replace(/[^a-z0-9._-]+/g, \"_\").slice(0, 200);\n}\n\nexport async function writeConversationChunks(\n rootDir: string,\n chunks: ConversationChunk[],\n): Promise<string[]> {\n const written: string[] = [];\n for (const c of chunks) {\n const safe = sanitizeSessionKey(c.sessionKey);\n const date = c.startTs.slice(0, 10);\n const dir = path.join(rootDir, safe, date);\n await mkdir(dir, { recursive: true });\n const fp = path.join(dir, `${c.id}.md`);\n const content =\n `---\\n` +\n `kind: conversation_chunk\\n` +\n `sessionKey: ${c.sessionKey}\\n` +\n `startTs: ${c.startTs}\\n` +\n `endTs: ${c.endTs}\\n` +\n `---\\n\\n` +\n c.text +\n \"\\n\";\n await writeFile(fp, content, \"utf-8\");\n written.push(fp);\n }\n return written;\n}\n","import { readdir, rm } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { log } from \"../logger.js\";\n\n/**\n * Best-effort retention cleanup for conversation chunk docs.\n *\n * Layout (written by indexer.ts):\n * <root>/<safeSessionKey>/<YYYY-MM-DD>/<chunkId>.md\n *\n * We prune day directories older than retentionDays, and remove empty session dirs.\n */\nexport async function cleanupConversationChunks(\n rootDir: string,\n retentionDays: number,\n): Promise<void> {\n if (!Number.isFinite(retentionDays) || retentionDays <= 0) return;\n\n const cutoffMs = Date.now() - retentionDays * 24 * 60 * 60 * 1000;\n\n try {\n const sessions = await readdir(rootDir, { withFileTypes: true });\n for (const s of sessions) {\n if (!s.isDirectory()) continue;\n const sessionDir = path.join(rootDir, s.name);\n const dayDirs = await readdir(sessionDir, { withFileTypes: true });\n\n for (const d of dayDirs) {\n if (!d.isDirectory()) continue;\n // Expect YYYY-MM-DD\n if (!/^\\d{4}-\\d{2}-\\d{2}$/.test(d.name)) continue;\n const dayMs = new Date(d.name + \"T00:00:00.000Z\").getTime();\n if (!Number.isFinite(dayMs)) continue;\n if (dayMs < cutoffMs) {\n await rm(path.join(sessionDir, d.name), { recursive: true, force: true });\n }\n }\n\n // Remove empty session dirs after pruning.\n try {\n const remaining = await readdir(sessionDir);\n if (remaining.length === 0) {\n await rm(sessionDir, { recursive: true, force: true });\n }\n } catch {\n // ignore\n }\n }\n } catch (err) {\n log.debug(`conversation chunk cleanup failed: ${err}`);\n }\n}\n\n","import path from \"node:path\";\nimport { access } from \"node:fs/promises\";\nimport { StorageManager } from \"../storage.js\";\nimport type { PluginConfig } from \"../types.js\";\n\nasync function exists(p: string): Promise<boolean> {\n try {\n await access(p);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Storage routing for namespaces.\n *\n * Compatibility note:\n * - When namespaces are enabled, non-default namespaces live under `memoryDir/namespaces/<ns>`.\n * - The default namespace continues to use the legacy `memoryDir` root unless the caller\n * has created `memoryDir/namespaces/<defaultNamespace>` (in which case we use that).\n *\n * This avoids surprising \"lost memories\" when an install flips namespaces on without\n * migrating existing data.\n */\nexport class NamespaceStorageRouter {\n private readonly cache = new Map<string, StorageManager>();\n private defaultNsRootResolved: string | null = null;\n\n constructor(private readonly config: PluginConfig) {}\n\n private async defaultNamespaceRoot(): Promise<string> {\n if (this.defaultNsRootResolved) return this.defaultNsRootResolved;\n if (!this.config.namespacesEnabled) {\n this.defaultNsRootResolved = this.config.memoryDir;\n return this.defaultNsRootResolved;\n }\n\n const nsDir = path.join(this.config.memoryDir, \"namespaces\", this.config.defaultNamespace);\n this.defaultNsRootResolved = (await exists(nsDir)) ? nsDir : this.config.memoryDir;\n return this.defaultNsRootResolved;\n }\n\n private namespaceRootSync(namespace: string): string {\n // NOTE: only used after defaultNamespaceRoot() resolution.\n if (!this.config.namespacesEnabled) return this.config.memoryDir;\n if (namespace === this.config.defaultNamespace) {\n return this.defaultNsRootResolved ?? this.config.memoryDir;\n }\n return path.join(this.config.memoryDir, \"namespaces\", namespace);\n }\n\n async storageFor(namespace: string): Promise<StorageManager> {\n const ns = namespace || this.config.defaultNamespace;\n if (this.cache.has(ns)) return this.cache.get(ns)!;\n\n if (ns === this.config.defaultNamespace) {\n await this.defaultNamespaceRoot();\n }\n\n const root = this.namespaceRootSync(ns);\n const sm = new StorageManager(root);\n this.cache.set(ns, sm);\n return sm;\n }\n}\n\n","import type { PluginConfig } from \"../types.js\";\n\nexport function resolvePrincipal(sessionKey: string | undefined, config: PluginConfig): string {\n if (!config.namespacesEnabled) return \"default\";\n const sk = sessionKey ?? \"\";\n const mode = config.principalFromSessionKeyMode;\n const rules = config.principalFromSessionKeyRules ?? [];\n\n if (!sk) return \"default\";\n\n if (mode === \"prefix\") {\n for (const r of rules) {\n if (sk.startsWith(r.match)) return r.principal;\n }\n } else if (mode === \"map\") {\n for (const r of rules) {\n if (sk === r.match) return r.principal;\n }\n } else if (mode === \"regex\") {\n for (const r of rules) {\n try {\n const re = new RegExp(r.match);\n if (re.test(sk)) return r.principal;\n } catch {\n // ignore invalid regex\n }\n }\n }\n\n // Fallback heuristic: \"agent:<agentId>:<channelType>:...\"\n const parts = sk.split(\":\");\n if (parts.length >= 2 && parts[0] === \"agent\") {\n const agentId = parts[1];\n if (agentId && agentId.length > 0) return agentId;\n }\n return \"default\";\n}\n\nexport function canReadNamespace(principal: string, namespace: string, config: PluginConfig): boolean {\n if (!config.namespacesEnabled) return true;\n const policy = config.namespacePolicies.find((p) => p.name === namespace);\n if (!policy) return namespace === config.defaultNamespace || namespace === config.sharedNamespace;\n return policy.readPrincipals.includes(principal) || policy.readPrincipals.includes(\"*\");\n}\n\nexport function canWriteNamespace(principal: string, namespace: string, config: PluginConfig): boolean {\n if (!config.namespacesEnabled) return true;\n const policy = config.namespacePolicies.find((p) => p.name === namespace);\n if (!policy) return namespace === config.defaultNamespace;\n return policy.writePrincipals.includes(principal) || policy.writePrincipals.includes(\"*\");\n}\n\n/**\n * Default \"self\" namespace for a principal.\n *\n * Heuristic:\n * - If there's a namespace policy with the same name as the principal, use it.\n * - Otherwise use config.defaultNamespace.\n */\nexport function defaultNamespaceForPrincipal(principal: string, config: PluginConfig): string {\n if (!config.namespacesEnabled) return config.defaultNamespace;\n const exists = config.namespacePolicies.some((p) => p.name === principal);\n return exists ? principal : config.defaultNamespace;\n}\n\nexport function recallNamespacesForPrincipal(principal: string, config: PluginConfig): string[] {\n const out: string[] = [];\n if (!config.namespacesEnabled) return [config.defaultNamespace];\n\n const selfNs = defaultNamespaceForPrincipal(principal, config);\n if (config.defaultRecallNamespaces.includes(\"self\") && canReadNamespace(principal, selfNs, config)) {\n out.push(selfNs);\n }\n if (config.defaultRecallNamespaces.includes(\"shared\") && canReadNamespace(principal, config.sharedNamespace, config)) {\n out.push(config.sharedNamespace);\n }\n\n for (const p of config.namespacePolicies) {\n if (p.includeInRecallByDefault && canReadNamespace(principal, p.name, config)) {\n if (!out.includes(p.name)) out.push(p.name);\n }\n }\n\n return out;\n}\n\n","import { mkdir, readFile, readdir, appendFile, writeFile, stat } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport { z } from \"zod\";\nimport { log } from \"../logger.js\";\nimport type { PluginConfig } from \"../types.js\";\n\nexport const SharedFeedbackEntrySchema = z.object({\n agent: z.string().min(1),\n decision: z.enum([\"approved\", \"approved_with_feedback\", \"rejected\"]),\n reason: z.string().min(1),\n date: z.string().min(8), // ISO-ish; keep loose\n learning: z.string().optional(),\n outcome: z.string().optional(),\n refs: z.array(z.string()).optional(),\n});\n\nexport type SharedFeedbackEntry = z.infer<typeof SharedFeedbackEntrySchema>;\n\nfunction safeSlug(s: string): string {\n return s\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, 80) || \"output\";\n}\n\nfunction ymd(d: Date): string {\n return d.toISOString().slice(0, 10);\n}\n\nexport class SharedContextManager {\n readonly dir: string;\n private readonly prioritiesPath: string;\n private readonly prioritiesInboxPath: string;\n private readonly outputsDir: string;\n private readonly roundtableDir: string;\n private readonly feedbackDir: string;\n private readonly feedbackInboxPath: string;\n private readonly crossSignalsDir: string;\n\n constructor(private readonly config: PluginConfig) {\n const base =\n typeof config.sharedContextDir === \"string\" && config.sharedContextDir.length > 0\n ? config.sharedContextDir\n : path.join(os.homedir(), \".openclaw\", \"workspace\", \"shared-context\");\n\n this.dir = base;\n this.prioritiesPath = path.join(base, \"priorities.md\");\n this.prioritiesInboxPath = path.join(base, \"priorities.inbox.md\");\n this.outputsDir = path.join(base, \"agent-outputs\");\n this.roundtableDir = path.join(base, \"roundtable\");\n this.feedbackDir = path.join(base, \"feedback\");\n this.feedbackInboxPath = path.join(this.feedbackDir, \"inbox.jsonl\");\n this.crossSignalsDir = path.join(base, \"cross-signals\");\n }\n\n async ensureStructure(): Promise<void> {\n await mkdir(this.dir, { recursive: true });\n await mkdir(this.outputsDir, { recursive: true });\n await mkdir(this.roundtableDir, { recursive: true });\n await mkdir(this.feedbackDir, { recursive: true });\n await mkdir(this.crossSignalsDir, { recursive: true });\n await mkdir(path.join(this.dir, \"staging\"), { recursive: true });\n await mkdir(path.join(this.dir, \"kpis\"), { recursive: true });\n await mkdir(path.join(this.dir, \"calendar\"), { recursive: true });\n await mkdir(path.join(this.dir, \"content-calendar\"), { recursive: true });\n\n // Bootstrap files if missing.\n await this.ensureFile(\n this.prioritiesPath,\n [\n \"# Priorities\",\n \"\",\n \"This is the shared priority stack. Agents should read this before acting.\",\n \"\",\n \"## Current\",\n \"- (empty)\",\n \"\",\n \"## Notes\",\n \"- (empty)\",\n \"\",\n ].join(\"\\n\"),\n );\n await this.ensureFile(\n this.prioritiesInboxPath,\n [\n \"# Priorities Inbox\",\n \"\",\n \"Append-only inbox. Curator merges into priorities.md.\",\n \"\",\n ].join(\"\\n\"),\n );\n await this.ensureFile(this.feedbackInboxPath, \"\");\n }\n\n private async ensureFile(fp: string, content: string): Promise<void> {\n try {\n await stat(fp);\n } catch {\n await writeFile(fp, content, \"utf-8\");\n }\n }\n\n async readPriorities(): Promise<string> {\n try {\n return await readFile(this.prioritiesPath, \"utf-8\");\n } catch {\n return \"\";\n }\n }\n\n async readLatestRoundtable(): Promise<string> {\n try {\n const files = (await readdir(this.roundtableDir))\n .filter((f) => f.endsWith(\".md\"))\n .sort()\n .reverse();\n const fp = files[0] ? path.join(this.roundtableDir, files[0]) : null;\n if (!fp) return \"\";\n return await readFile(fp, \"utf-8\");\n } catch {\n return \"\";\n }\n }\n\n async writeAgentOutput(opts: {\n agentId: string;\n title: string;\n content: string;\n createdAt?: Date;\n }): Promise<string> {\n const createdAt = opts.createdAt ?? new Date();\n const date = ymd(createdAt);\n const time = createdAt.toISOString().slice(11, 19).replace(/:/g, \"\");\n const slug = safeSlug(opts.title);\n\n const dir = path.join(this.outputsDir, opts.agentId, date);\n await mkdir(dir, { recursive: true });\n const fp = path.join(dir, `${time}-${slug}.md`);\n\n const body =\n `---\\n` +\n `kind: agent_output\\n` +\n `agent: ${opts.agentId}\\n` +\n `createdAt: ${createdAt.toISOString()}\\n` +\n `title: ${opts.title.replace(/\\n/g, \" \").slice(0, 200)}\\n` +\n `---\\n\\n` +\n opts.content.trimEnd() +\n \"\\n\";\n\n await writeFile(fp, body, \"utf-8\");\n return fp;\n }\n\n async appendFeedback(entry: SharedFeedbackEntry): Promise<void> {\n const parsed = SharedFeedbackEntrySchema.parse(entry);\n await appendFile(this.feedbackInboxPath, JSON.stringify(parsed) + \"\\n\", \"utf-8\");\n }\n\n async appendPrioritiesInbox(opts: { agentId: string; text: string }): Promise<void> {\n const stamp = new Date().toISOString();\n const lines = [\n \"\",\n `## ${stamp} (${opts.agentId})`,\n \"\",\n opts.text.trimEnd(),\n \"\",\n ].join(\"\\n\");\n await appendFile(this.prioritiesInboxPath, lines, \"utf-8\");\n }\n\n async curateDaily(opts: { date?: string; maxChars?: number }): Promise<string> {\n const date = opts.date ?? ymd(new Date());\n const maxChars = Math.max(2_000, opts.maxChars ?? 20_000);\n\n // Collect outputs for the day (best-effort).\n const outputs: Array<{ path: string; title: string }> = [];\n try {\n const agents = await readdir(this.outputsDir, { withFileTypes: true });\n for (const a of agents) {\n if (!a.isDirectory()) continue;\n const dayDir = path.join(this.outputsDir, a.name, date);\n try {\n const files = (await readdir(dayDir)).filter((f) => f.endsWith(\".md\")).sort();\n for (const f of files) {\n const p = path.join(dayDir, f);\n const raw = await readFile(p, \"utf-8\");\n const title = (raw.match(/^title:\\s*(.+)$/m)?.[1] ?? f).trim();\n outputs.push({ path: p, title });\n }\n } catch {\n // no outputs for this agent/date\n }\n }\n } catch {\n // ignore\n }\n\n // Collect feedback entries for the day.\n const feedback: SharedFeedbackEntry[] = [];\n try {\n const raw = await readFile(this.feedbackInboxPath, \"utf-8\");\n for (const line of raw.split(\"\\n\")) {\n if (!line.trim()) continue;\n try {\n const obj = JSON.parse(line);\n const parsed = SharedFeedbackEntrySchema.safeParse(obj);\n if (!parsed.success) continue;\n if (String(parsed.data.date).startsWith(date)) feedback.push(parsed.data);\n } catch {\n // ignore\n }\n }\n } catch {\n // ignore\n }\n\n const md: string[] = [\n `# Roundtable — ${date}`,\n \"\",\n \"## Notable Agent Outputs\",\n ...(outputs.length === 0 ? [\"- (none)\"] : outputs.map((o) => `- ${o.title} (${o.path})`)),\n \"\",\n \"## Feedback (Approve/Reject)\",\n ...(feedback.length === 0\n ? [\"- (none)\"]\n : feedback.map((f) => `- [${f.agent}] ${f.decision}: ${f.reason}`)),\n \"\",\n \"## Cross-Signals\",\n \"- (baseline) not computed in deterministic mode\",\n \"\",\n ];\n\n const out = md.join(\"\\n\");\n const trimmed = out.length > maxChars ? out.slice(0, maxChars) + \"\\n\\n...(trimmed)\\n\" : out;\n\n const fp = path.join(this.roundtableDir, `${date}.md`);\n await writeFile(fp, trimmed, \"utf-8\");\n\n log.info(`shared-context curated daily roundtable: ${fp}`);\n return fp;\n }\n}\n\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport { log } from \"../logger.js\";\nimport type { PluginConfig } from \"../types.js\";\nimport { SharedFeedbackEntrySchema, type SharedFeedbackEntry } from \"../shared-context/manager.js\";\n\ntype MistakesFile = {\n updatedAt: string;\n patterns: string[];\n};\n\nfunction isoWeekId(d: Date): string {\n // ISO week based on Thursday\n const dt = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()));\n const day = dt.getUTCDay() || 7;\n dt.setUTCDate(dt.getUTCDate() + 4 - day);\n const yearStart = new Date(Date.UTC(dt.getUTCFullYear(), 0, 1));\n const week = Math.ceil((((dt.getTime() - yearStart.getTime()) / 86400000) + 1) / 7);\n const yyyy = dt.getUTCFullYear();\n return `${yyyy}-W${String(week).padStart(2, \"0\")}`;\n}\n\nfunction sharedContextDir(config: PluginConfig): string {\n if (typeof config.sharedContextDir === \"string\" && config.sharedContextDir.length > 0) {\n return config.sharedContextDir;\n }\n return path.join(os.homedir(), \".openclaw\", \"workspace\", \"shared-context\");\n}\n\nexport class CompoundingEngine {\n private readonly weeklyDir: string;\n private readonly mistakesPath: string;\n private readonly feedbackInboxPath: string;\n\n constructor(private readonly config: PluginConfig) {\n this.weeklyDir = path.join(config.memoryDir, \"compounding\", \"weekly\");\n this.mistakesPath = path.join(config.memoryDir, \"compounding\", \"mistakes.json\");\n this.feedbackInboxPath = path.join(sharedContextDir(config), \"feedback\", \"inbox.jsonl\");\n }\n\n async ensureDirs(): Promise<void> {\n await mkdir(this.weeklyDir, { recursive: true });\n await mkdir(path.dirname(this.mistakesPath), { recursive: true });\n }\n\n async synthesizeWeekly(opts?: { weekId?: string }): Promise<{ weekId: string; reportPath: string; mistakesCount: number }> {\n await this.ensureDirs();\n const weekId = opts?.weekId ?? isoWeekId(new Date());\n\n const entries = await this.readFeedbackEntriesForWeek(weekId);\n const mistakes = this.buildMistakes(entries);\n\n // Write weekly report (always, even if empty: \"day-one outcomes\").\n const reportPath = path.join(this.weeklyDir, `${weekId}.md`);\n const md = this.formatWeeklyReport(weekId, entries, mistakes.patterns);\n await writeFile(reportPath, md, \"utf-8\");\n\n // Update mistakes.json (always).\n await writeFile(this.mistakesPath, JSON.stringify(mistakes, null, 2) + \"\\n\", \"utf-8\");\n\n log.info(`compounding: wrote weekly=${reportPath} mistakes=${this.mistakesPath}`);\n return { weekId, reportPath, mistakesCount: mistakes.patterns.length };\n }\n\n async readMistakes(): Promise<MistakesFile | null> {\n try {\n const raw = await readFile(this.mistakesPath, \"utf-8\");\n const parsed = JSON.parse(raw) as MistakesFile;\n if (!parsed || !Array.isArray(parsed.patterns)) return null;\n return parsed;\n } catch {\n return null;\n }\n }\n\n private async readFeedbackEntriesForWeek(weekId: string): Promise<SharedFeedbackEntry[]> {\n // Minimal implementation: includes entries where date starts with any day in the ISO week.\n // We approximate by taking all entries and filtering by computed isoWeekId(date).\n const out: SharedFeedbackEntry[] = [];\n try {\n const raw = await readFile(this.feedbackInboxPath, \"utf-8\");\n for (const line of raw.split(\"\\n\")) {\n if (!line.trim()) continue;\n try {\n const obj = JSON.parse(line);\n const parsed = SharedFeedbackEntrySchema.safeParse(obj);\n if (!parsed.success) continue;\n const d = new Date(parsed.data.date);\n if (!Number.isFinite(d.getTime())) continue;\n if (isoWeekId(d) === weekId) out.push(parsed.data);\n } catch {\n // ignore\n }\n }\n } catch {\n // missing feedback is normal\n }\n return out;\n }\n\n private buildMistakes(entries: SharedFeedbackEntry[]): MistakesFile {\n const patterns: string[] = [];\n for (const e of entries) {\n if (e.learning && e.learning.trim().length > 0) {\n patterns.push(`${e.agent}: ${e.learning.trim()}`);\n continue;\n }\n if (e.decision === \"rejected\") {\n patterns.push(`${e.agent}: ${e.reason.trim()}`.slice(0, 240));\n }\n }\n\n const uniq = Array.from(new Set(patterns)).slice(0, 500);\n return { updatedAt: new Date().toISOString(), patterns: uniq };\n }\n\n private formatWeeklyReport(weekId: string, entries: SharedFeedbackEntry[], patterns: string[]): string {\n const byAgent = new Map<string, SharedFeedbackEntry[]>();\n for (const e of entries) {\n const list = byAgent.get(e.agent) ?? [];\n list.push(e);\n byAgent.set(e.agent, list);\n }\n\n const lines: string[] = [\n `# Weekly Compounding — ${weekId}`,\n \"\",\n \"This file is generated by Engram's compounding engine (v5.0).\",\n \"\",\n \"## Summary\",\n `- Feedback entries: ${entries.length}`,\n `- Mistake patterns: ${patterns.length}`,\n \"\",\n \"## By Agent\",\n ];\n\n if (byAgent.size === 0) {\n lines.push(\"- (none)\");\n } else {\n for (const [agent, list] of Array.from(byAgent.entries()).sort((a, b) => a[0].localeCompare(b[0]))) {\n const approved = list.filter((e) => e.decision === \"approved\").length;\n const awf = list.filter((e) => e.decision === \"approved_with_feedback\").length;\n const rejected = list.filter((e) => e.decision === \"rejected\").length;\n lines.push(`### ${agent}`);\n lines.push(`- approved: ${approved}`);\n lines.push(`- approved_with_feedback: ${awf}`);\n lines.push(`- rejected: ${rejected}`);\n lines.push(\"\");\n }\n }\n\n lines.push(\"## Patterns (Avoid / Prefer)\");\n if (patterns.length === 0) {\n lines.push(\"- (none yet)\");\n } else {\n for (const p of patterns.slice(0, 100)) lines.push(`- ${p}`);\n }\n lines.push(\"\");\n\n return lines.join(\"\\n\");\n }\n}\n\n","import path from \"node:path\";\nimport { Type } from \"@sinclair/typebox\";\nimport type { Orchestrator } from \"./orchestrator.js\";\nimport type { MemoryCategory } from \"./types.js\";\n\ninterface ToolApi {\n registerTool(\n spec: {\n name: string;\n label: string;\n description: string;\n parameters: unknown;\n execute: (\n toolCallId: string,\n params: Record<string, unknown>,\n signal?: AbortSignal,\n ) => Promise<{\n content: Array<{ type: string; text: string }>;\n details: undefined;\n }>;\n },\n options: { name: string },\n ): void;\n}\n\nfunction toolResult(text: string) {\n return { content: [{ type: \"text\" as const, text }], details: undefined };\n}\n\nexport function registerTools(api: ToolApi, orchestrator: Orchestrator): void {\n function namespaceFromPath(p: string): string {\n const m = p.match(/[\\\\/]+namespaces[\\\\/]+([^\\\\/]+)[\\\\/]+/);\n return m && m[1] ? m[1] : orchestrator.config.defaultNamespace;\n }\n\n api.registerTool(\n {\n name: \"memory_search\",\n label: \"Search Memory\",\n description: `Search local memory files using QMD's semantic index. Returns matching memories with snippets and relevance scores.\n\nReturns: Matching memory entries ranked by relevance\nCost: Free (local index query)\nSpeed: Fast\n\nBest for:\n- Finding previously learned facts about the user\n- Checking what you know about a topic\n- Locating past decisions or corrections`,\n parameters: Type.Object({\n query: Type.String({\n description: \"Search query — keywords, phrases, or natural language\",\n }),\n namespace: Type.Optional(\n Type.String({\n description:\n \"Optional namespace filter. When set, only returns results under memoryDir/namespaces/<namespace>/ (default namespace uses legacy root).\",\n }),\n ),\n maxResults: Type.Optional(\n Type.Number({\n description: \"Maximum results (default: 8)\",\n minimum: 1,\n maximum: 50,\n }),\n ),\n collection: Type.Optional(\n Type.String({\n description:\n \"QMD collection to search. Omit for memory collection, use 'global' for all collections.\",\n }),\n ),\n }),\n async execute(_toolCallId, params) {\n const { query, maxResults, collection, namespace } = params as {\n query: string;\n maxResults?: number;\n collection?: string;\n namespace?: string;\n };\n\n const results =\n collection === \"global\"\n ? await orchestrator.qmd.searchGlobal(query, maxResults)\n : await orchestrator.qmd.search(query, undefined, maxResults);\n\n const filtered =\n namespace && namespace.length > 0\n ? results.filter((r) => namespaceFromPath(r.path) === namespace)\n : results;\n\n if (filtered.length === 0) {\n return toolResult(`No memories found matching: \"${query}\"`);\n }\n\n const formatted = filtered\n .map((r, i) => {\n const snippet = r.snippet\n ? r.snippet.slice(0, 800)\n : \"(no preview)\";\n return `### [${i + 1}] ${r.path}\\nScore: ${r.score.toFixed(3)}\\n\\n\\`\\`\\`\\n${snippet}\\n\\`\\`\\``;\n })\n .join(\"\\n\\n\");\n\n return toolResult(\n `## Memory Search: \"${query}\"\\n\\n${filtered.length} result(s)\\n\\n${formatted}`,\n );\n },\n },\n { name: \"memory_search\" },\n );\n\n api.registerTool(\n {\n name: \"memory_feedback\",\n label: \"Memory Feedback\",\n description:\n \"Thumbs up/down a memory's relevance. Stored locally and used as a soft ranking bias when enabled.\",\n parameters: Type.Object({\n memoryId: Type.String({\n description: \"Memory ID (filename without .md), e.g. fact-123\",\n }),\n vote: Type.String({\n enum: [\"up\", \"down\"],\n description: \"up or down\",\n }),\n note: Type.Optional(\n Type.String({\n description: \"Optional note explaining the feedback (stored locally).\",\n }),\n ),\n }),\n async execute(_toolCallId, params) {\n const { memoryId, vote, note } = params as {\n memoryId: string;\n vote: \"up\" | \"down\";\n note?: string;\n };\n\n if (!orchestrator.config.feedbackEnabled) {\n return toolResult(\n \"Feedback is disabled. Enable `feedbackEnabled: true` in the Engram plugin config to store feedback.\",\n );\n }\n\n await orchestrator.recordMemoryFeedback(memoryId, vote, note);\n return toolResult(\n `Recorded feedback for ${memoryId}: ${vote}${note ? ` (note: ${note})` : \"\"}`,\n );\n },\n },\n { name: \"memory_feedback\" },\n );\n\n api.registerTool(\n {\n name: \"memory_last_recall\",\n label: \"Last Recall Snapshot\",\n description:\n \"Fetch the last set of memory IDs that were injected into context for a session. Useful when the user says things like 'why did you say that?' or 'that's not right' and you want to identify which memories may have misled the response.\",\n parameters: Type.Object({\n sessionKey: Type.Optional(\n Type.String({\n description:\n \"Session key to look up. If omitted, returns the most recent snapshot across all sessions (may be wrong under concurrency).\",\n }),\n ),\n }),\n async execute(_toolCallId, params) {\n const { sessionKey } = params as { sessionKey?: string };\n\n const snap = sessionKey\n ? orchestrator.lastRecall.get(sessionKey)\n : orchestrator.lastRecall.getMostRecent();\n\n if (!snap) {\n return toolResult(\"No last-recall snapshot found yet.\");\n }\n\n const prefix = sessionKey\n ? `## Last Recall (${snap.sessionKey})`\n : `## Last Recall (most recent: ${snap.sessionKey})\\n\\nNOTE: You did not provide sessionKey; under concurrency this may not match your current session.`;\n\n return toolResult(\n [\n prefix,\n \"\",\n `Recorded at: ${snap.recordedAt}`,\n `Query hash: ${snap.queryHash} (len=${snap.queryLen})`,\n `Memories (${snap.memoryIds.length}):`,\n ...snap.memoryIds.map((id) => `- ${id}`),\n ].join(\"\\n\"),\n );\n },\n },\n { name: \"memory_last_recall\" },\n );\n\n api.registerTool(\n {\n name: \"memory_feedback_last_recall\",\n label: \"Feedback Last Recall\",\n description:\n \"Batch feedback tool for the last recall snapshot. Can mark retrieved memories as 'not useful' (negative examples) so they are softly penalized in future ranking when negative examples are enabled.\",\n parameters: Type.Object({\n sessionKey: Type.Optional(\n Type.String({\n description:\n \"Session key. If omitted, uses the most recent snapshot across all sessions (may be wrong under concurrency).\",\n }),\n ),\n notUsefulMemoryIds: Type.Optional(\n Type.Array(Type.String(), {\n description:\n \"Memory IDs to mark as not useful. If omitted, you may use usefulMemoryIds + autoMarkOthersNotUseful to mark the rest as not useful.\",\n }),\n ),\n usefulMemoryIds: Type.Optional(\n Type.Array(Type.String(), {\n description:\n \"Memory IDs that were useful. Only used when autoMarkOthersNotUseful=true.\",\n }),\n ),\n autoMarkOthersNotUseful: Type.Optional(\n Type.Boolean({\n description:\n \"If true, marks all last-recall memory IDs not listed in usefulMemoryIds as not useful. Safer than auto-marking without an explicit useful list.\",\n }),\n ),\n note: Type.Optional(\n Type.String({\n description:\n \"Optional note explaining why these were not useful (stored locally).\",\n }),\n ),\n }),\n async execute(_toolCallId, params) {\n const {\n sessionKey,\n notUsefulMemoryIds,\n usefulMemoryIds,\n autoMarkOthersNotUseful,\n note,\n } = params as {\n sessionKey?: string;\n notUsefulMemoryIds?: string[];\n usefulMemoryIds?: string[];\n autoMarkOthersNotUseful?: boolean;\n note?: string;\n };\n\n if (!orchestrator.config.negativeExamplesEnabled) {\n return toolResult(\n \"Negative examples are disabled. Enable `negativeExamplesEnabled: true` in the Engram plugin config to store retrieved-but-not-useful feedback and apply penalties.\",\n );\n }\n\n const snap = sessionKey\n ? orchestrator.lastRecall.get(sessionKey)\n : orchestrator.lastRecall.getMostRecent();\n\n if (!snap) {\n return toolResult(\"No last-recall snapshot found yet.\");\n }\n\n let toMark: string[] | null = null;\n\n if (Array.isArray(notUsefulMemoryIds) && notUsefulMemoryIds.length > 0) {\n toMark = notUsefulMemoryIds;\n } else if (autoMarkOthersNotUseful) {\n if (!Array.isArray(usefulMemoryIds) || usefulMemoryIds.length === 0) {\n return toolResult(\n \"autoMarkOthersNotUseful=true requires a non-empty usefulMemoryIds list (to avoid accidental mass-negative marking).\",\n );\n }\n const useful = new Set(usefulMemoryIds);\n toMark = snap.memoryIds.filter((id) => !useful.has(id));\n }\n\n if (!toMark || toMark.length === 0) {\n return toolResult(\n \"Nothing to record. Provide notUsefulMemoryIds, or provide usefulMemoryIds with autoMarkOthersNotUseful=true.\",\n );\n }\n\n await orchestrator.recordNotUsefulMemories(toMark, note);\n\n const warn = sessionKey\n ? \"\"\n : \"\\n\\nNOTE: You did not provide sessionKey; under concurrency this may not match your current session.\";\n\n return toolResult(\n `Recorded ${toMark.length} not-useful memory ID(s) for last recall (${snap.sessionKey}).${warn}`,\n );\n },\n },\n { name: \"memory_feedback_last_recall\" },\n );\n\n api.registerTool(\n {\n name: \"memory_store\",\n label: \"Store Memory\",\n description: `Explicitly store a memory. Use this when the user directly asks you to remember something, or when you identify critical information that the automatic extraction might miss.\n\nCost: Free (local file write)\nSpeed: Instant\n\nBest for:\n- User says \"remember that...\" or \"note that...\"\n- Critical corrections or preferences\n- Important decisions or facts`,\n parameters: Type.Object({\n content: Type.String({\n description: \"The memory to store — a clear, standalone statement\",\n }),\n namespace: Type.Optional(\n Type.String({\n description:\n \"Namespace to store into (v3.0+). Omit to store into defaultNamespace.\",\n }),\n ),\n category: Type.Optional(\n Type.String({\n description:\n 'Category: \"fact\", \"preference\", \"correction\", \"entity\", \"decision\", \"relationship\", \"principle\", \"commitment\", \"moment\", \"skill\" (default: \"fact\")',\n enum: [\"fact\", \"preference\", \"correction\", \"entity\", \"decision\", \"relationship\", \"principle\", \"commitment\", \"moment\", \"skill\"],\n }),\n ),\n tags: Type.Optional(\n Type.Array(Type.String(), {\n description: \"Tags for categorization\",\n }),\n ),\n entityRef: Type.Optional(\n Type.String({\n description:\n \"Entity reference (e.g., person-jane-doe, project-my-app)\",\n }),\n ),\n }),\n async execute(_toolCallId, params) {\n const {\n content,\n namespace,\n category = \"fact\",\n tags = [],\n entityRef,\n } = params as {\n content: string;\n namespace?: string;\n category?: string;\n tags?: string[];\n entityRef?: string;\n };\n\n const storage = await orchestrator.getStorage(namespace);\n const id = await storage.writeMemory(\n category as MemoryCategory,\n content,\n {\n confidence: 0.95,\n tags,\n entityRef,\n source: \"explicit\",\n },\n );\n\n // Queue debounced QMD maintenance via orchestrator guardrails so new memory becomes searchable.\n orchestrator.requestQmdMaintenanceForTool(\"memory_store\");\n\n return toolResult(`Memory stored: ${id}${namespace ? ` (namespace: ${namespace})` : \"\"}\\n\\nContent: ${content}`);\n },\n },\n { name: \"memory_store\" },\n );\n\n api.registerTool(\n {\n name: \"memory_promote\",\n label: \"Promote Memory To Shared\",\n description:\n \"Copy a memory into the shared namespace (v3.0+). This is intended for curated promotion of agent-specific learning into a shared brain.\",\n parameters: Type.Object({\n memoryId: Type.String({\n description: \"Memory ID (filename without .md), e.g. fact-123\",\n }),\n fromNamespace: Type.Optional(\n Type.String({\n description: \"Source namespace (default: defaultNamespace).\",\n }),\n ),\n toNamespace: Type.Optional(\n Type.String({\n description: \"Target namespace (default: sharedNamespace).\",\n }),\n ),\n note: Type.Optional(\n Type.String({\n description:\n \"Optional note explaining why this should be shared (stored as a tag-like annotation).\",\n }),\n ),\n }),\n async execute(_toolCallId, params) {\n if (!orchestrator.config.namespacesEnabled) {\n return toolResult(\n \"Namespaces are disabled. Enable `namespacesEnabled: true` to use memory promotion.\",\n );\n }\n\n const { memoryId, fromNamespace, toNamespace, note } = params as {\n memoryId: string;\n fromNamespace?: string;\n toNamespace?: string;\n note?: string;\n };\n\n const srcNs = fromNamespace && fromNamespace.length > 0 ? fromNamespace : orchestrator.config.defaultNamespace;\n const dstNs = toNamespace && toNamespace.length > 0 ? toNamespace : orchestrator.config.sharedNamespace;\n\n const src = await orchestrator.getStorage(srcNs);\n const mem = await src.getMemoryById(memoryId);\n if (!mem) {\n return toolResult(`Memory not found in ${srcNs}: ${memoryId}`);\n }\n\n const dst = await orchestrator.getStorage(dstNs);\n const newId = await dst.writeMemory(mem.frontmatter.category, mem.content, {\n confidence: mem.frontmatter.confidence,\n tags: Array.from(new Set([...(mem.frontmatter.tags ?? []), \"promoted\", `promotedFrom:${srcNs}:${memoryId}`, ...(note ? [`note:${note}`] : [])])),\n entityRef: mem.frontmatter.entityRef,\n source: \"promote\",\n importance: mem.frontmatter.importance,\n supersedes: mem.frontmatter.supersedes,\n links: mem.frontmatter.links,\n });\n\n return toolResult(`Promoted ${srcNs}:${memoryId} → ${dstNs}:${newId}`);\n },\n },\n { name: \"memory_promote\" },\n );\n\n api.registerTool(\n {\n name: \"memory_profile\",\n label: \"View User Profile\",\n description: `Read the user's behavioral profile — a living document of their preferences, habits, and personality.\n\nCost: Free (local file read)\nSpeed: Instant\n\nBest for:\n- Understanding the user holistically\n- Checking preferences before making decisions\n- \"What do you know about me?\"`,\n parameters: Type.Object({}),\n async execute() {\n const profile = await orchestrator.storage.readProfile();\n if (!profile) {\n return toolResult(\n \"No profile built yet. The profile builds automatically through conversations.\",\n );\n }\n return toolResult(`## User Profile\\n\\n${profile}`);\n },\n },\n { name: \"memory_profile\" },\n );\n\n api.registerTool(\n {\n name: \"memory_entities\",\n label: \"List Known Entities\",\n description: `List all tracked entities (people, projects, tools, companies) with their facts.\n\nCost: Free (local file read)\nSpeed: Instant\n\nBest for:\n- Seeing all known entities\n- Looking up facts about a specific entity`,\n parameters: Type.Object({\n name: Type.Optional(\n Type.String({\n description:\n \"Specific entity to look up (e.g., person-jane-doe)\",\n }),\n ),\n }),\n async execute(_toolCallId, params) {\n const { name } = params as { name?: string };\n\n if (name) {\n const content = await orchestrator.storage.readEntity(name);\n if (!content) {\n return toolResult(`Entity \"${name}\" not found.`);\n }\n return toolResult(content);\n }\n\n const entities = await orchestrator.storage.readEntities();\n if (entities.length === 0) {\n return toolResult(\n \"No entities tracked yet. Entities build automatically through conversations.\",\n );\n }\n\n return toolResult(\n `## Known Entities (${entities.length})\\n\\n${entities.map((e) => `- ${e}`).join(\"\\n\")}`,\n );\n },\n },\n { name: \"memory_entities\" },\n );\n\n api.registerTool(\n {\n name: \"memory_questions\",\n label: \"View/Manage Questions\",\n description: `View open questions the AI is curious about, or resolve answered questions.\n\nCost: Free (local file read)\nSpeed: Instant\n\nBest for:\n- Seeing what questions have been generated from past conversations\n- Resolving questions that have been answered\n- \"What questions do you have for me?\"`,\n parameters: Type.Object({\n action: Type.Optional(\n Type.String({\n description: '\"list\" (default) to show unresolved questions, \"all\" to show all, \"resolve\" to mark one as answered',\n enum: [\"list\", \"all\", \"resolve\"],\n }),\n ),\n questionId: Type.Optional(\n Type.String({\n description: \"Question ID to resolve (required when action is 'resolve')\",\n }),\n ),\n }),\n async execute(_toolCallId, params) {\n const { action = \"list\", questionId } = params as {\n action?: string;\n questionId?: string;\n };\n\n if (action === \"resolve\") {\n if (!questionId) {\n return toolResult(\"Error: questionId is required when action is 'resolve'\");\n }\n const resolved = await orchestrator.storage.resolveQuestion(questionId);\n return toolResult(resolved ? `Question ${questionId} marked as resolved.` : `Question ${questionId} not found.`);\n }\n\n const unresolvedOnly = action !== \"all\";\n const questions = await orchestrator.storage.readQuestions({ unresolvedOnly });\n\n if (questions.length === 0) {\n return toolResult(unresolvedOnly\n ? \"No unresolved questions. Questions are generated automatically during memory extraction.\"\n : \"No questions found.\");\n }\n\n const formatted = questions.map((q, i) =>\n `### [${i + 1}] ${q.id}\\nPriority: ${q.priority.toFixed(2)} | Created: ${q.created}${q.resolved ? \" | RESOLVED\" : \"\"}\\n\\n${q.question}\\n\\n_Context: ${q.context}_`\n ).join(\"\\n\\n\");\n\n return toolResult(`## Questions (${questions.length})\\n\\n${formatted}`);\n },\n },\n { name: \"memory_questions\" },\n );\n\n api.registerTool(\n {\n name: \"memory_identity\",\n label: \"View Identity Reflections\",\n description: `Read the agent's identity reflections from the workspace IDENTITY.md file.\n\nCost: Free (local file read)\nSpeed: Instant\n\nBest for:\n- Understanding the agent's self-model and growth\n- \"What have you learned about yourself?\"\n- Reviewing identity development over time`,\n parameters: Type.Object({}),\n async execute() {\n const workspaceDir = path.join(process.env.HOME ?? \"~\", \".openclaw\", \"workspace\");\n const identity = await orchestrator.storage.readIdentity(workspaceDir);\n if (!identity) {\n return toolResult(\"No identity file found. Identity reflections build automatically through conversations when identityEnabled is true.\");\n }\n return toolResult(`## Agent Identity\\n\\n${identity}`);\n },\n },\n { name: \"memory_identity\" },\n );\n\n api.registerTool(\n {\n name: \"memory_summarize_hourly\",\n label: \"Generate Hourly Summaries\",\n description: `Generate hourly summaries for the previous hour's conversations across all active sessions.\n\nCost: Low (uses configured summary model)\nSpeed: Fast\n\nBest for:\n- Cron job scheduled hourly summarization\n- Manual trigger to summarize recent conversations\n- Building conversation summaries for context preservation`,\n parameters: Type.Object({}),\n async execute() {\n try {\n await orchestrator.summarizer.runHourly();\n return toolResult(\"Hourly summarization completed. Check the summaries directory for results.\");\n } catch (err) {\n return toolResult(`Hourly summarization failed: ${err}`);\n }\n },\n },\n { name: \"memory_summarize_hourly\" },\n );\n\n api.registerTool(\n {\n name: \"conversation_index_update\",\n label: \"Update Conversation Index\",\n description: `Chunk recent transcript history into \"conversation chunk\" documents and (best-effort) update the semantic index for past-conversation recall.\n\nThis is optional and default-off (see config: conversationIndexEnabled).\n\nBest for:\n- Cron jobs to keep the conversation index fresh\n- Manual rebuild after changing chunk sizes or retention`,\n parameters: Type.Object({\n sessionKey: Type.Optional(\n Type.String({\n description:\n \"Session key to index. If omitted, Engram will best-effort scan transcript storage and index all discovered sessionKeys.\",\n }),\n ),\n hours: Type.Optional(\n Type.Number({\n description: \"How many hours of transcript history to include (default: 24).\",\n minimum: 1,\n maximum: 24 * 30,\n }),\n ),\n embed: Type.Optional(\n Type.Boolean({\n description:\n \"If true, run QMD embed after update for this invocation. If omitted, uses conversationIndexEmbedOnUpdate config.\",\n }),\n ),\n }),\n async execute(_toolCallId, params) {\n if (!orchestrator.config.conversationIndexEnabled) {\n return toolResult(\n \"Conversation indexing is disabled. Enable `conversationIndexEnabled: true` in the Engram plugin config to use this tool.\",\n );\n }\n\n const { sessionKey, hours, embed } = params as { sessionKey?: string; hours?: number; embed?: boolean };\n const h = typeof hours === \"number\" && Number.isFinite(hours) ? hours : 24;\n\n if (sessionKey) {\n const res = await orchestrator.updateConversationIndex(sessionKey, h, { embed });\n if (res.skipped && res.reason === \"min_interval\") {\n const retrySec = Math.max(1, Math.ceil((res.retryAfterMs ?? 0) / 1000));\n return toolResult(\n `Skipped for sessionKey=${sessionKey} due to min interval. Retry in ~${retrySec}s or pass a higher interval config.`,\n );\n }\n return toolResult(\n `Indexed ${res.chunks} chunk(s) for sessionKey=${sessionKey}.${res.embedded ? \" Ran embed.\" : \"\"}`,\n );\n }\n\n const sessions = await orchestrator.transcript.listSessionKeys();\n let total = 0;\n let skipped = 0;\n const skippedIds: string[] = [];\n let embeddedRuns = 0;\n for (const sk of sessions) {\n const res = await orchestrator.updateConversationIndex(sk, h, { embed });\n total += res.chunks;\n if (res.skipped) {\n skipped += 1;\n skippedIds.push(sk);\n }\n if (res.embedded) embeddedRuns += 1;\n }\n const skippedSummary =\n skipped > 0\n ? ` Skipped ${skipped} session(s) due to min-interval gating: ${skippedIds.slice(0, 6).join(\", \")}${skippedIds.length > 6 ? \"...\" : \"\"}.`\n : \"\";\n const embedSummary = embeddedRuns > 0 ? ` Ran embed for ${embeddedRuns} session update(s).` : \"\";\n return toolResult(\n `Indexed ${total} total chunk(s) across ${sessions.length} session(s).${skippedSummary}${embedSummary}`,\n );\n },\n },\n { name: \"conversation_index_update\" },\n );\n\n api.registerTool(\n {\n name: \"shared_context_write_output\",\n label: \"Write Shared Agent Output\",\n description:\n \"Write an agent work product into the shared-context directory (v4.0). Other agents can read these files to coordinate without explicit message passing.\",\n parameters: Type.Object({\n agentId: Type.String({ description: \"Agent ID producing this output (e.g., generalist, oracle, flash).\" }),\n title: Type.String({ description: \"Short title for the output.\" }),\n content: Type.String({ description: \"Markdown content to write.\" }),\n }),\n async execute(_toolCallId, params) {\n const { agentId, title, content } = params as { agentId: string; title: string; content: string };\n if (!orchestrator.sharedContext) {\n return toolResult(\n \"Shared context is disabled. Enable `sharedContextEnabled: true` to use shared-context tools.\",\n );\n }\n const fp = await orchestrator.sharedContext.writeAgentOutput({ agentId, title, content });\n return toolResult(`Wrote shared agent output: ${fp}`);\n },\n },\n { name: \"shared_context_write_output\" },\n );\n\n api.registerTool(\n {\n name: \"shared_feedback_record\",\n label: \"Record Shared Feedback\",\n description:\n \"Append an approval/rejection decision into shared-context feedback inbox (v4.0/v5.0). Intended to power compounding learning.\",\n parameters: Type.Object({\n agent: Type.String({ description: \"Agent name that produced the recommendation/output.\" }),\n decision: Type.String({\n enum: [\"approved\", \"approved_with_feedback\", \"rejected\"],\n description: \"Decision outcome.\",\n }),\n reason: Type.String({ description: \"Why the decision was made (short but specific).\" }),\n date: Type.Optional(Type.String({ description: \"ISO timestamp. Defaults to now.\" })),\n learning: Type.Optional(Type.String({ description: \"Optional distilled learning/pattern.\" })),\n outcome: Type.Optional(Type.String({ description: \"Optional downstream outcome (day-one supported; may be empty initially).\" })),\n refs: Type.Optional(Type.Array(Type.String(), { description: \"Optional references (URLs, IDs, filenames).\" })),\n }),\n async execute(_toolCallId, params) {\n if (!orchestrator.sharedContext) {\n return toolResult(\n \"Shared context is disabled. Enable `sharedContextEnabled: true` to record shared feedback.\",\n );\n }\n const p = params as any;\n const entry = {\n agent: String(p.agent ?? \"\"),\n decision: p.decision as \"approved\" | \"approved_with_feedback\" | \"rejected\",\n reason: String(p.reason ?? \"\"),\n date: typeof p.date === \"string\" && p.date.length > 0 ? p.date : new Date().toISOString(),\n learning: typeof p.learning === \"string\" ? p.learning : undefined,\n outcome: typeof p.outcome === \"string\" ? p.outcome : undefined,\n refs: Array.isArray(p.refs) ? p.refs.map(String) : undefined,\n };\n await orchestrator.sharedContext.appendFeedback(entry);\n return toolResult(\"OK\");\n },\n },\n { name: \"shared_feedback_record\" },\n );\n\n api.registerTool(\n {\n name: \"shared_priorities_append\",\n label: \"Append Priorities Inbox\",\n description:\n \"Append text into shared-context priorities inbox. A curator run should merge this into priorities.md.\",\n parameters: Type.Object({\n agentId: Type.String({ description: \"Agent ID appending priorities.\" }),\n text: Type.String({ description: \"Priority notes to append (markdown).\" }),\n }),\n async execute(_toolCallId, params) {\n if (!orchestrator.sharedContext) {\n return toolResult(\n \"Shared context is disabled. Enable `sharedContextEnabled: true` to write priorities inbox.\",\n );\n }\n const { agentId, text } = params as { agentId: string; text: string };\n await orchestrator.sharedContext.appendPrioritiesInbox({ agentId, text });\n return toolResult(\"OK\");\n },\n },\n { name: \"shared_priorities_append\" },\n );\n\n api.registerTool(\n {\n name: \"shared_context_curate_daily\",\n label: \"Curate Daily Roundtable\",\n description:\n \"Curator tool: generate today's roundtable summary in shared-context/roundtable (deterministic baseline).\",\n parameters: Type.Object({\n date: Type.Optional(Type.String({ description: \"YYYY-MM-DD. Defaults to today.\" })),\n }),\n async execute(_toolCallId, params) {\n if (!orchestrator.sharedContext) {\n return toolResult(\n \"Shared context is disabled. Enable `sharedContextEnabled: true` to curate roundtables.\",\n );\n }\n const { date } = params as { date?: string };\n const fp = await orchestrator.sharedContext.curateDaily({ date });\n return toolResult(`Wrote: ${fp}`);\n },\n },\n { name: \"shared_context_curate_daily\" },\n );\n\n api.registerTool(\n {\n name: \"compounding_weekly_synthesize\",\n label: \"Synthesize Weekly Learning\",\n description:\n \"Generate weekly compounding outputs (v5.0): weekly report + mistakes.json. Designed to work from day one (writes even if no feedback exists yet).\",\n parameters: Type.Object({\n weekId: Type.Optional(\n Type.String({\n description:\n \"ISO week ID like YYYY-Www. Omit to use current week.\",\n }),\n ),\n }),\n async execute(_toolCallId, params) {\n if (!orchestrator.compounding) {\n return toolResult(\n \"Compounding engine is disabled. Enable `compoundingEnabled: true` to use this tool.\",\n );\n }\n const { weekId } = params as { weekId?: string };\n const res = await orchestrator.compounding.synthesizeWeekly({ weekId });\n return toolResult(\n `OK\\n\\nweekId: ${res.weekId}\\nreport: ${res.reportPath}\\nmistakes: ${res.mistakesCount} patterns`,\n );\n },\n },\n { name: \"compounding_weekly_synthesize\" },\n );\n}\n","import path from \"node:path\";\nimport { access, readFile } from \"node:fs/promises\";\nimport type { Orchestrator } from \"./orchestrator.js\";\nimport { ThreadingManager } from \"./threading.js\";\nimport type { TranscriptEntry } from \"./types.js\";\nimport { exportJsonBundle } from \"./transfer/export-json.js\";\nimport { exportMarkdownBundle } from \"./transfer/export-md.js\";\nimport { backupMemoryDir } from \"./transfer/backup.js\";\nimport { exportSqlite } from \"./transfer/export-sqlite.js\";\nimport { importJsonBundle } from \"./transfer/import-json.js\";\nimport { importSqlite } from \"./transfer/import-sqlite.js\";\nimport { importMarkdownBundle } from \"./transfer/import-md.js\";\nimport { detectImportFormat } from \"./transfer/autodetect.js\";\n\ninterface CliApi {\n registerCli(\n handler: (opts: { program: CliProgram }) => void,\n options: { commands: string[] },\n ): void;\n}\n\ninterface CliProgram {\n command(name: string): CliCommand;\n}\n\ninterface CliCommand {\n description(desc: string): CliCommand;\n option(flags: string, desc: string, defaultValue?: string): CliCommand;\n argument(name: string, desc: string): CliCommand;\n action(fn: (...args: unknown[]) => Promise<void> | void): CliCommand;\n command(name: string): CliCommand;\n}\n\nasync function getPluginVersion(): Promise<string> {\n try {\n const pkgPath = new URL(\"../package.json\", import.meta.url);\n const raw = await readFile(pkgPath, \"utf-8\");\n const parsed = JSON.parse(raw) as { version?: string };\n return parsed.version ?? \"unknown\";\n } catch {\n return \"unknown\";\n }\n}\n\nasync function exists(p: string): Promise<boolean> {\n try {\n await access(p);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function resolveMemoryDirForNamespace(orchestrator: Orchestrator, namespace?: string): Promise<string> {\n const ns = (namespace ?? \"\").trim();\n if (!ns) return orchestrator.config.memoryDir;\n if (!orchestrator.config.namespacesEnabled) return orchestrator.config.memoryDir;\n\n const candidate = path.join(orchestrator.config.memoryDir, \"namespaces\", ns);\n if (ns === orchestrator.config.defaultNamespace) {\n return (await exists(candidate)) ? candidate : orchestrator.config.memoryDir;\n }\n return candidate;\n}\n\nexport function registerCli(api: CliApi, orchestrator: Orchestrator): void {\n api.registerCli(\n ({ program }) => {\n const cmd = program\n .command(\"engram\")\n .description(\"Engram local memory commands\");\n\n cmd\n .command(\"stats\")\n .description(\"Show memory system statistics\")\n .action(async () => {\n // Ensure QMD is probed before checking availability\n await orchestrator.qmd.probe();\n\n const meta = await orchestrator.storage.loadMeta();\n const memories = await orchestrator.storage.readAllMemories();\n const entities = await orchestrator.storage.readEntities();\n const profile = await orchestrator.storage.readProfile();\n\n console.log(\"=== Engram Memory Stats ===\\n\");\n console.log(`Total memories: ${memories.length}`);\n console.log(`Total entities: ${entities.length}`);\n console.log(`Profile size: ${profile.length} chars`);\n console.log(`Extractions: ${meta.extractionCount}`);\n console.log(`Last extraction: ${meta.lastExtractionAt ?? \"never\"}`);\n console.log(\n `Last consolidation: ${meta.lastConsolidationAt ?? \"never\"}`,\n );\n console.log(`QMD: ${orchestrator.qmd.isAvailable() ? \"available\" : \"not available\"}`);\n\n // Category breakdown\n const categories: Record<string, number> = {};\n for (const m of memories) {\n categories[m.frontmatter.category] =\n (categories[m.frontmatter.category] ?? 0) + 1;\n }\n if (Object.keys(categories).length > 0) {\n console.log(\"\\nBy category:\");\n for (const [cat, count] of Object.entries(categories)) {\n console.log(` ${cat}: ${count}`);\n }\n }\n });\n\n cmd\n .command(\"export\")\n .description(\"Export Engram memory to JSON, Markdown bundle, or SQLite\")\n .option(\"--format <format>\", \"Export format: json|md|sqlite\", \"json\")\n .option(\"--out <path>\", \"Output path (dir for json/md, file for sqlite)\")\n .option(\"--include-transcripts\", \"Include transcripts in export (default: false)\")\n .option(\"--namespace <ns>\", \"Namespace to export (v3.0+, default: config defaultNamespace)\", \"\")\n .action(async (...args: unknown[]) => {\n const options = (args[0] ?? {}) as Record<string, unknown>;\n const format = String(options.format ?? \"json\");\n const out = options.out ? String(options.out) : \"\";\n const includeTranscripts = options.includeTranscripts === true;\n const namespace = options.namespace ? String(options.namespace) : \"\";\n if (!out) {\n console.log(\"Missing --out. Example: openclaw engram export --format json --out /tmp/engram-export\");\n return;\n }\n\n const pluginVersion = await getPluginVersion();\n const memoryDir = await resolveMemoryDirForNamespace(orchestrator, namespace);\n if (format === \"json\") {\n await exportJsonBundle({\n memoryDir,\n outDir: out,\n includeTranscripts,\n pluginVersion,\n workspaceDir: orchestrator.config.workspaceDir,\n includeWorkspaceIdentity: true,\n });\n } else if (format === \"md\") {\n await exportMarkdownBundle({\n memoryDir,\n outDir: out,\n includeTranscripts,\n pluginVersion,\n });\n } else if (format === \"sqlite\") {\n await exportSqlite({\n memoryDir,\n outFile: out,\n includeTranscripts,\n pluginVersion,\n });\n } else {\n console.log(`Unknown format: ${format}`);\n return;\n }\n console.log(\"OK\");\n });\n\n cmd\n .command(\"import\")\n .description(\"Import Engram memory from JSON bundle, Markdown bundle, or SQLite\")\n .option(\"--from <path>\", \"Import source path (dir or file)\")\n .option(\"--format <format>\", \"Import format: auto|json|md|sqlite\", \"auto\")\n .option(\"--conflict <mode>\", \"Conflict policy: skip|overwrite|dedupe\", \"skip\")\n .option(\"--dry-run\", \"Validate import without writing files\")\n .option(\"--namespace <ns>\", \"Namespace to import into (v3.0+, default: config defaultNamespace)\", \"\")\n .action(async (...args: unknown[]) => {\n const options = (args[0] ?? {}) as Record<string, unknown>;\n const from = options.from ? String(options.from) : \"\";\n const formatOpt = String(options.format ?? \"auto\");\n const conflict = String(options.conflict ?? \"skip\") as \"skip\" | \"overwrite\" | \"dedupe\";\n const dryRun = options.dryRun === true;\n const namespace = options.namespace ? String(options.namespace) : \"\";\n if (!from) {\n console.log(\"Missing --from. Example: openclaw engram import --from /tmp/engram-export --format auto\");\n return;\n }\n\n const detected = formatOpt === \"auto\" ? await detectImportFormat(from) : (formatOpt as any);\n if (!detected) {\n console.log(\"Could not detect import format (use --format json|md|sqlite).\");\n return;\n }\n\n const targetMemoryDir = await resolveMemoryDirForNamespace(orchestrator, namespace);\n\n if (detected === \"json\") {\n await importJsonBundle({\n targetMemoryDir,\n fromDir: from,\n conflict,\n dryRun,\n workspaceDir: orchestrator.config.workspaceDir,\n });\n } else if (detected === \"sqlite\") {\n await importSqlite({\n targetMemoryDir,\n fromFile: from,\n conflict,\n dryRun,\n });\n } else if (detected === \"md\") {\n await importMarkdownBundle({\n targetMemoryDir,\n fromDir: from,\n conflict,\n dryRun,\n });\n } else {\n console.log(`Unknown detected format: ${detected}`);\n return;\n }\n console.log(\"OK\");\n });\n\n cmd\n .command(\"backup\")\n .description(\"Create a timestamped backup of the Engram memory directory\")\n .option(\"--out-dir <dir>\", \"Backup root directory\")\n .option(\"--retention-days <n>\", \"Delete backups older than N days\", \"0\")\n .option(\"--include-transcripts\", \"Include transcripts (default false)\")\n .option(\"--namespace <ns>\", \"Namespace to back up (v3.0+, default: config defaultNamespace)\", \"\")\n .action(async (...args: unknown[]) => {\n const options = (args[0] ?? {}) as Record<string, unknown>;\n const outDir = options.outDir ? String(options.outDir) : \"\";\n const retentionDays = parseInt(String(options.retentionDays ?? \"0\"), 10);\n const includeTranscripts = options.includeTranscripts === true;\n const namespace = options.namespace ? String(options.namespace) : \"\";\n if (!outDir) {\n console.log(\"Missing --out-dir. Example: openclaw engram backup --out-dir /tmp/engram-backups\");\n return;\n }\n const pluginVersion = await getPluginVersion();\n const memoryDir = await resolveMemoryDirForNamespace(orchestrator, namespace);\n await backupMemoryDir({\n memoryDir,\n outDir,\n retentionDays: Number.isFinite(retentionDays) ? retentionDays : undefined,\n includeTranscripts,\n pluginVersion,\n });\n console.log(\"OK\");\n });\n\n cmd\n .command(\"search\")\n .argument(\"<query>\", \"Search query\")\n .option(\"-n, --max-results <number>\", \"Max results\", \"8\")\n .description(\"Search memories via QMD\")\n .action(async (...args: unknown[]) => {\n const query = typeof args[0] === \"string\" ? args[0] : String(args[0] ?? \"\");\n const options = (args[1] ?? {}) as Record<string, string>;\n const maxResults = parseInt(options.maxResults ?? \"8\", 10);\n if (!query) {\n console.log(\"Missing query. Usage: openclaw engram search <query>\");\n return;\n }\n\n if (orchestrator.qmd.isAvailable()) {\n const results = await orchestrator.qmd.search(\n query,\n undefined,\n maxResults,\n );\n if (results.length === 0) {\n console.log(`No results for: \"${query}\"`);\n return;\n }\n console.log(`\\n=== Memory Search: \"${query}\" ===\\n`);\n for (const r of results) {\n console.log(` ${r.path} (score: ${r.score.toFixed(3)})`);\n if (r.snippet) {\n console.log(\n ` ${r.snippet.slice(0, 150).replace(/\\n/g, \" \")}`,\n );\n }\n console.log();\n }\n } else {\n // Fallback: search filenames\n const memories = await orchestrator.storage.readAllMemories();\n const lowerQuery = query.toLowerCase();\n const matches = memories.filter(\n (m) =>\n m.content.toLowerCase().includes(lowerQuery) ||\n m.frontmatter.tags.some((t) => t.includes(lowerQuery)),\n );\n if (matches.length === 0) {\n console.log(`No results for: \"${query}\" (QMD not available, using text search)`);\n return;\n }\n console.log(`\\n=== Text Search: \"${query}\" (${matches.length} results) ===\\n`);\n for (const m of matches.slice(0, maxResults)) {\n console.log(` [${m.frontmatter.category}] ${m.content.slice(0, 120)}`);\n }\n }\n });\n\n cmd\n .command(\"profile\")\n .description(\"Show current user profile\")\n .action(async () => {\n const profile = await orchestrator.storage.readProfile();\n if (!profile) {\n console.log(\"No profile built yet.\");\n return;\n }\n console.log(profile);\n });\n\n cmd\n .command(\"entities\")\n .description(\"List all tracked entities\")\n .action(async () => {\n const entities = await orchestrator.storage.readEntities();\n if (entities.length === 0) {\n console.log(\"No entities tracked yet.\");\n return;\n }\n console.log(`=== Entities (${entities.length}) ===\\n`);\n for (const e of entities) {\n console.log(` - ${e}`);\n }\n });\n\n cmd\n .command(\"extract\")\n .description(\"Force extraction of buffered turns\")\n .action(async () => {\n await orchestrator.buffer.load();\n const turns = orchestrator.buffer.getTurns();\n if (turns.length === 0) {\n console.log(\"Buffer is empty. Nothing to extract.\");\n return;\n }\n console.log(`Extracting ${turns.length} buffered turns...`);\n // Trigger extraction by processing a dummy turn that forces extraction\n // Actually we need to call the internal extraction method\n // For now, inform the user\n console.log(\n \"Use the memory system in conversation to trigger extraction, or wait for the buffer threshold.\",\n );\n });\n\n cmd\n .command(\"bootstrap\")\n .description(\"Scan transcript history and seed memory from high-signal past turns\")\n .option(\"--dry-run\", \"Scan and report without writing memories\")\n .option(\"--sessions-dir <path>\", \"Override transcript sessions directory\")\n .option(\"--limit <number>\", \"Maximum sessions to process\")\n .option(\"--since <date>\", \"Only process turns after date (YYYY-MM-DD or ISO)\")\n .action(async (...args: unknown[]) => {\n const options = (args[0] ?? {}) as Record<string, unknown>;\n const dryRun = options.dryRun === true;\n const sessionsDir = options.sessionsDir ? String(options.sessionsDir) : undefined;\n const limitRaw = options.limit ? Number(options.limit) : undefined;\n const limit = typeof limitRaw === \"number\" && Number.isFinite(limitRaw) && limitRaw > 0\n ? Math.floor(limitRaw)\n : undefined;\n\n let since: Date | undefined;\n if (options.since) {\n const parsed = new Date(String(options.since));\n if (Number.isNaN(parsed.getTime())) {\n console.log(`Invalid --since value: ${String(options.since)}`);\n return;\n }\n since = parsed;\n }\n\n console.log(\"Running bootstrap scan...\");\n const result = await orchestrator.runBootstrap({\n dryRun,\n sessionsDir,\n limit,\n since,\n });\n console.log(\n `Bootstrap complete. sessions=${result.sessionsScanned}, turns=${result.turnsProcessed}, highSignal=${result.highSignalTurns}, created=${result.memoriesCreated}, skipped=${result.skipped}`,\n );\n });\n\n cmd\n .command(\"consolidate\")\n .description(\"Run memory consolidation immediately\")\n .option(\"--verbose\", \"Show detailed consolidation stats\")\n .action(async (...args: unknown[]) => {\n const options = (args[0] ?? {}) as Record<string, unknown>;\n const verbose = options.verbose === true;\n console.log(\"Running consolidation...\");\n const stats = await orchestrator.runConsolidationNow();\n if (verbose) {\n console.log(\n `Consolidation complete. memoriesProcessed=${stats.memoriesProcessed}, merged=${stats.merged}, invalidated=${stats.invalidated}`,\n );\n } else {\n console.log(`Consolidation complete. merged=${stats.merged}, invalidated=${stats.invalidated}`);\n }\n });\n\n cmd\n .command(\"questions\")\n .description(\"List open questions from memory extraction\")\n .option(\"-a, --all\", \"Show all questions including resolved\")\n .action(async (...args: unknown[]) => {\n const options = (args[0] ?? {}) as Record<string, unknown>;\n const showAll = options.all === true;\n const questions = await orchestrator.storage.readQuestions({ unresolvedOnly: !showAll });\n if (questions.length === 0) {\n console.log(showAll ? \"No questions found.\" : \"No unresolved questions.\");\n return;\n }\n console.log(`\\n=== Questions (${questions.length}) ===\\n`);\n for (const q of questions) {\n const status = q.resolved ? \"[RESOLVED]\" : `[priority: ${q.priority.toFixed(2)}]`;\n console.log(` ${q.id} ${status}`);\n console.log(` ${q.question}`);\n console.log(` Context: ${q.context}`);\n console.log();\n }\n });\n\n cmd\n .command(\"identity\")\n .description(\"Show agent identity reflections\")\n .action(async () => {\n const workspaceDir = path.join(process.env.HOME ?? \"~\", \".openclaw\", \"workspace\");\n const identity = await orchestrator.storage.readIdentity(workspaceDir);\n if (!identity) {\n console.log(\"No identity file found.\");\n return;\n }\n console.log(identity);\n });\n\n cmd\n .command(\"access\")\n .description(\"Show memory access statistics\")\n .option(\"-n, --top <number>\", \"Show top N most accessed\", \"20\")\n .action(async (...args: unknown[]) => {\n const options = (args[0] ?? {}) as Record<string, string>;\n const top = parseInt(options.top ?? \"20\", 10);\n\n const memories = await orchestrator.storage.readAllMemories();\n const withAccess = memories.filter((m) => m.frontmatter.accessCount && m.frontmatter.accessCount > 0);\n\n if (withAccess.length === 0) {\n console.log(\"No access tracking data yet. Memories will be tracked as they are retrieved.\");\n return;\n }\n\n // Sort by access count descending\n const sorted = withAccess.sort(\n (a, b) => (b.frontmatter.accessCount ?? 0) - (a.frontmatter.accessCount ?? 0),\n );\n\n console.log(`\\n=== Top ${Math.min(top, sorted.length)} Most Accessed Memories ===\\n`);\n for (const m of sorted.slice(0, top)) {\n const lastAccessed = m.frontmatter.lastAccessed\n ? new Date(m.frontmatter.lastAccessed).toLocaleDateString()\n : \"unknown\";\n console.log(` ${m.frontmatter.accessCount}x [${m.frontmatter.category}] ${m.content.slice(0, 80)}`);\n console.log(` Last accessed: ${lastAccessed} ID: ${m.frontmatter.id}`);\n console.log();\n }\n\n // Summary stats\n const totalAccess = withAccess.reduce((sum, m) => sum + (m.frontmatter.accessCount ?? 0), 0);\n console.log(`Total accesses tracked: ${totalAccess}`);\n console.log(`Memories with access data: ${withAccess.length} / ${memories.length}`);\n });\n\n cmd\n .command(\"flush-access\")\n .description(\"Flush pending access tracking updates to disk\")\n .action(async () => {\n await orchestrator.flushAccessTracking();\n console.log(\"Access tracking buffer flushed.\");\n });\n\n cmd\n .command(\"importance\")\n .description(\"Show importance score distribution across memories\")\n .option(\"-l, --level <level>\", \"Filter by importance level (critical, high, normal, low, trivial)\")\n .option(\"-n, --top <number>\", \"Show top N memories by importance\", \"15\")\n .action(async (...args: unknown[]) => {\n const options = (args[0] ?? {}) as Record<string, string>;\n const filterLevel = options.level;\n const top = parseInt(options.top ?? \"15\", 10);\n\n const memories = await orchestrator.storage.readAllMemories();\n const withImportance = memories.filter((m) => m.frontmatter.importance);\n\n if (withImportance.length === 0) {\n console.log(\"No importance data yet. Importance is scored during extraction.\");\n return;\n }\n\n // Count by level\n const levelCounts: Record<string, number> = {\n critical: 0,\n high: 0,\n normal: 0,\n low: 0,\n trivial: 0,\n };\n for (const m of withImportance) {\n const level = m.frontmatter.importance?.level ?? \"normal\";\n levelCounts[level] = (levelCounts[level] ?? 0) + 1;\n }\n\n console.log(\"\\n=== Importance Distribution ===\\n\");\n for (const [level, count] of Object.entries(levelCounts)) {\n const bar = \"█\".repeat(Math.min(count, 50));\n console.log(` ${level.padEnd(10)} ${count.toString().padStart(4)} ${bar}`);\n }\n console.log(`\\n Total scored: ${withImportance.length} / ${memories.length} memories\\n`);\n\n // Filter by level if specified\n let filtered = withImportance;\n if (filterLevel) {\n filtered = withImportance.filter(\n (m) => m.frontmatter.importance?.level === filterLevel,\n );\n if (filtered.length === 0) {\n console.log(`No memories with importance level: ${filterLevel}`);\n return;\n }\n }\n\n // Sort by importance score descending\n const sorted = filtered.sort(\n (a, b) =>\n (b.frontmatter.importance?.score ?? 0) -\n (a.frontmatter.importance?.score ?? 0),\n );\n\n const heading = filterLevel\n ? `Top ${Math.min(top, sorted.length)} \"${filterLevel}\" Importance Memories`\n : `Top ${Math.min(top, sorted.length)} Most Important Memories`;\n console.log(`=== ${heading} ===\\n`);\n\n for (const m of sorted.slice(0, top)) {\n const imp = m.frontmatter.importance!;\n console.log(\n ` ${imp.score.toFixed(2)} [${imp.level}] [${m.frontmatter.category}]`,\n );\n console.log(` ${m.content.slice(0, 100)}`);\n if (imp.keywords.length > 0) {\n console.log(` Keywords: ${imp.keywords.join(\", \")}`);\n }\n console.log();\n }\n });\n cmd\n .command(\"topics\")\n .description(\"Show extracted topics from memory corpus\")\n .option(\"-n, --top <number>\", \"Show top N topics\", \"20\")\n .action(async (...args: unknown[]) => {\n const options = (args[0] ?? {}) as Record<string, string>;\n const top = parseInt(options.top ?? \"20\", 10);\n\n const { topics, updatedAt } = await orchestrator.storage.loadTopics();\n\n if (topics.length === 0) {\n console.log(\"No topics extracted yet. Topics are extracted during consolidation.\");\n return;\n }\n\n console.log(`\\n=== Top ${Math.min(top, topics.length)} Topics ===`);\n console.log(`Last updated: ${updatedAt ?? \"unknown\"}\\n`);\n\n for (const topic of topics.slice(0, top)) {\n const bar = \"█\".repeat(Math.min(Math.round(topic.score * 10), 30));\n console.log(` ${topic.term.padEnd(20)} ${topic.score.toFixed(3)} (${topic.count}x) ${bar}`);\n }\n });\n\n cmd\n .command(\"summaries\")\n .description(\"Show memory summaries\")\n .option(\"-n, --top <number>\", \"Show top N most recent summaries\", \"5\")\n .action(async (...args: unknown[]) => {\n const options = (args[0] ?? {}) as Record<string, string>;\n const top = parseInt(options.top ?? \"5\", 10);\n\n const summaries = await orchestrator.storage.readSummaries();\n\n if (summaries.length === 0) {\n console.log(\"No summaries yet. Summaries are created during consolidation when memory count exceeds threshold.\");\n return;\n }\n\n // Sort by createdAt desc\n const sorted = summaries.sort(\n (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(),\n );\n\n console.log(`\\n=== Memory Summaries (${Math.min(top, sorted.length)} of ${sorted.length}) ===\\n`);\n\n for (const summary of sorted.slice(0, top)) {\n console.log(` ${summary.id}`);\n console.log(` Created: ${summary.createdAt}`);\n console.log(` Time range: ${summary.timeRangeStart.slice(0, 10)} to ${summary.timeRangeEnd.slice(0, 10)}`);\n console.log(` Source memories: ${summary.sourceEpisodeIds.length}`);\n console.log(` Key facts: ${summary.keyFacts.length}`);\n console.log(`\\n Summary: ${summary.summaryText.slice(0, 200)}...`);\n console.log();\n }\n });\n\n cmd\n .command(\"threads\")\n .description(\"Show conversation threads\")\n .option(\"-n, --top <number>\", \"Show top N most recent threads\", \"10\")\n .option(\"-t, --thread <id>\", \"Show details for a specific thread\")\n .action(async (...args: unknown[]) => {\n const options = (args[0] ?? {}) as Record<string, string>;\n const threadId = options.thread;\n const top = parseInt(options.top ?? \"10\", 10);\n\n const memoryDir = path.join(process.env.HOME ?? \"~\", \".openclaw\", \"workspace\", \"memory\", \"local\");\n const threading = new ThreadingManager(path.join(memoryDir, \"threads\"));\n\n if (threadId) {\n const thread = await threading.loadThread(threadId);\n if (!thread) {\n console.log(`Thread not found: ${threadId}`);\n return;\n }\n\n console.log(`\\n=== Thread: ${thread.title} ===\\n`);\n console.log(` ID: ${thread.id}`);\n console.log(` Created: ${thread.createdAt}`);\n console.log(` Updated: ${thread.updatedAt}`);\n console.log(` Session: ${thread.sessionKey ?? \"(none)\"}`);\n console.log(` Episodes: ${thread.episodeIds.length}`);\n\n if (thread.episodeIds.length > 0) {\n console.log(\"\\n Episode IDs:\");\n for (const id of thread.episodeIds.slice(0, 20)) {\n console.log(` - ${id}`);\n }\n if (thread.episodeIds.length > 20) {\n console.log(` ... and ${thread.episodeIds.length - 20} more`);\n }\n }\n\n if (thread.linkedThreadIds.length > 0) {\n console.log(\"\\n Linked threads:\");\n for (const id of thread.linkedThreadIds) {\n console.log(` - ${id}`);\n }\n }\n return;\n }\n\n const threads = await threading.getAllThreads();\n\n if (threads.length === 0) {\n console.log(\"No conversation threads yet. Enable threading with threadingEnabled: true\");\n return;\n }\n\n console.log(`\\n=== Conversation Threads (${Math.min(top, threads.length)} of ${threads.length}) ===\\n`);\n for (const thread of threads.slice(0, top)) {\n const updated = new Date(thread.updatedAt).toLocaleString();\n console.log(` ${thread.title}`);\n console.log(` ID: ${thread.id}`);\n console.log(` Episodes: ${thread.episodeIds.length} | Updated: ${updated}`);\n console.log();\n }\n });\n\n cmd\n .command(\"chunks\")\n .description(\"Show chunking statistics and orphaned chunks\")\n .option(\"-p, --parent <id>\", \"Show chunks for a specific parent memory ID\")\n .action(async (...args: unknown[]) => {\n const options = (args[0] ?? {}) as Record<string, string>;\n const parentId = options.parent;\n\n const memories = await orchestrator.storage.readAllMemories();\n\n if (parentId) {\n // Show chunks for specific parent\n const chunks = memories\n .filter((m) => m.frontmatter.parentId === parentId)\n .sort((a, b) => (a.frontmatter.chunkIndex ?? 0) - (b.frontmatter.chunkIndex ?? 0));\n\n if (chunks.length === 0) {\n console.log(`No chunks found for parent: ${parentId}`);\n return;\n }\n\n const parent = memories.find((m) => m.frontmatter.id === parentId);\n console.log(`\\n=== Chunks for ${parentId} ===\\n`);\n if (parent) {\n console.log(`Parent: ${parent.content.slice(0, 100)}...`);\n console.log();\n }\n\n for (const chunk of chunks) {\n console.log(\n ` [${(chunk.frontmatter.chunkIndex ?? 0) + 1}/${chunk.frontmatter.chunkTotal}] ${chunk.content.slice(0, 80)}...`,\n );\n }\n return;\n }\n\n // Show overall chunking stats\n const chunked = memories.filter((m) => m.frontmatter.tags?.includes(\"chunked\"));\n const chunks = memories.filter((m) => m.frontmatter.parentId);\n\n // Find orphaned chunks (parent no longer exists)\n const parentIds = new Set(chunked.map((m) => m.frontmatter.id));\n const orphans = chunks.filter((m) => !parentIds.has(m.frontmatter.parentId!));\n\n console.log(\"\\n=== Chunking Statistics ===\\n\");\n console.log(` Chunked memories (parents): ${chunked.length}`);\n console.log(` Total chunks: ${chunks.length}`);\n console.log(` Orphaned chunks: ${orphans.length}`);\n\n if (chunked.length > 0) {\n // Calculate average chunks per parent\n const avgChunks = chunks.length / chunked.length;\n console.log(` Average chunks per parent: ${avgChunks.toFixed(1)}`);\n }\n\n if (orphans.length > 0) {\n console.log(\"\\n Orphaned chunk IDs:\");\n for (const orphan of orphans.slice(0, 10)) {\n console.log(` - ${orphan.frontmatter.id}`);\n }\n if (orphans.length > 10) {\n console.log(` ... and ${orphans.length - 10} more`);\n }\n }\n });\n\n // Transcript commands\n cmd\n .command(\"transcript\")\n .description(\"View conversation transcripts\")\n .option(\"--date <date>\", \"View transcript for specific date (YYYY-MM-DD)\")\n .option(\"--recent <duration>\", \"View recent transcript (e.g., 12h, 30m)\")\n .option(\"--channel <key>\", \"Filter by channel/session key\")\n .action(async (...args: unknown[]) => {\n const options = (args[0] ?? {}) as Record<string, string>;\n const date = options.date;\n const recent = options.recent;\n let channel = options.channel;\n\n // Expand shorthand channel names to full sessionKey patterns\n if (channel && !channel.includes(\":\")) {\n // Convert \"main\" -> \"agent:generalist:main\"\n // Convert \"discord\" -> \"agent:generalist:discord\" (will match all discord channels)\n // Convert \"cron\" -> \"agent:generalist:cron\" (will match all cron jobs)\n if (channel === \"main\") {\n channel = \"agent:generalist:main\";\n } else if ([\"discord\", \"slack\", \"cron\", \"telegram\"].includes(channel)) {\n channel = `agent:generalist:${channel}`;\n }\n }\n\n if (date) {\n // Read specific date\n const entries = await orchestrator.transcript.readRange(\n `${date}T00:00:00Z`,\n `${date}T23:59:59Z`,\n channel,\n );\n console.log(formatTranscript(entries));\n } else if (recent) {\n // Parse duration (e.g., \"12h\", \"30m\")\n const hours = parseDuration(recent);\n const entries = await orchestrator.transcript.readRecent(hours, channel);\n console.log(formatTranscript(entries));\n } else {\n // Default: show today's transcript\n const today = new Date().toISOString().slice(0, 10);\n const entries = await orchestrator.transcript.readRange(\n `${today}T00:00:00Z`,\n `${today}T23:59:59Z`,\n channel,\n );\n console.log(formatTranscript(entries));\n }\n });\n\n // Checkpoint command\n cmd\n .command(\"checkpoint\")\n .description(\"View current compaction checkpoint (if any)\")\n .action(async () => {\n const checkpoint = await orchestrator.transcript.loadCheckpoint();\n if (!checkpoint) {\n console.log(\"No active checkpoint found.\");\n return;\n }\n console.log(`Checkpoint for session: ${checkpoint.sessionKey}`);\n console.log(`Captured at: ${checkpoint.capturedAt}`);\n console.log(`Expires at: ${checkpoint.ttl}`);\n console.log(`Turns: ${checkpoint.turns.length}`);\n console.log(\"\\n---\\n\");\n console.log(orchestrator.transcript.formatForRecall(checkpoint.turns, 2000));\n });\n\n // Summaries command\n cmd\n .command(\"hourly\")\n .description(\"View hourly summaries\")\n .option(\"--channel <key>\", \"Filter by channel/session key\")\n .option(\"--recent <hours>\", \"Show recent summaries (hours)\")\n .action(async (...args: unknown[]) => {\n const options = (args[0] ?? {}) as Record<string, string>;\n const channel = options.channel ?? \"default\";\n const recentHours = options.recent ? parseInt(options.recent, 10) : 24;\n\n const summaries = await orchestrator.summarizer.readRecent(channel, recentHours);\n if (summaries.length === 0) {\n console.log(`No summaries found for channel: ${channel}`);\n return;\n }\n\n console.log(orchestrator.summarizer.formatForRecall(summaries, summaries.length));\n });\n },\n { commands: [\"engram\"] },\n );\n}\n\nfunction formatTranscript(entries: TranscriptEntry[]): string {\n if (entries.length === 0) return \"No transcript entries found.\";\n\n return entries\n .map((e) => {\n const time = e.timestamp.slice(11, 16); // HH:MM\n return `[${time}] ${e.role}: ${e.content.slice(0, 200)}${e.content.length > 200 ? \"...\" : \"\"}`;\n })\n .join(\"\\n\");\n}\n\nfunction parseDuration(duration: string): number {\n // Parse strings like \"12h\", \"30m\", \"2h30m\"\n const hours = duration.match(/(\\d+)h/);\n const minutes = duration.match(/(\\d+)m/);\n let total = 0;\n if (hours) total += parseInt(hours[1], 10);\n if (minutes) total += parseInt(minutes[1], 10) / 60;\n return total || 12; // Default to 12 hours\n}\n","import path from \"node:path\";\nimport { mkdir, readFile } from \"node:fs/promises\";\nimport { EXPORT_FORMAT, EXPORT_SCHEMA_VERSION } from \"./constants.js\";\nimport { listFilesRecursive, sha256File, sha256String, toPosixRelPath, writeJsonFile } from \"./fs-utils.js\";\nimport type { ExportBundleV1, ExportManifestV1, ExportMemoryRecordV1 } from \"./types.js\";\n\nexport interface ExportCommonOptions {\n memoryDir: string;\n outDir: string;\n includeTranscripts?: boolean;\n includeWorkspaceIdentity?: boolean;\n workspaceDir?: string;\n pluginVersion: string;\n}\n\nconst DEFAULT_EXCLUDES = new Set([\n \"node_modules\",\n \".git\",\n]);\n\nfunction shouldExclude(relPosix: string, includeTranscripts: boolean): boolean {\n const parts = relPosix.split(\"/\");\n if (parts.some((p) => DEFAULT_EXCLUDES.has(p))) return true;\n if (!includeTranscripts && parts[0] === \"transcripts\") return true;\n return false;\n}\n\nexport async function exportJsonBundle(opts: ExportCommonOptions): Promise<void> {\n const includeTranscripts = opts.includeTranscripts === true;\n const outDirAbs = path.resolve(opts.outDir);\n await mkdir(outDirAbs, { recursive: true });\n\n const memoryDirAbs = path.resolve(opts.memoryDir);\n const filesAbs = await listFilesRecursive(memoryDirAbs);\n\n const records: ExportMemoryRecordV1[] = [];\n const manifestFiles: ExportManifestV1[\"files\"] = [];\n\n for (const abs of filesAbs) {\n const relPosix = toPosixRelPath(abs, memoryDirAbs);\n if (shouldExclude(relPosix, includeTranscripts)) continue;\n\n const content = await readFile(abs, \"utf-8\");\n records.push({ path: relPosix, content });\n const { sha256, bytes } = await sha256File(abs);\n manifestFiles.push({ path: relPosix, sha256, bytes });\n }\n\n // Optionally include workspace identity file (outside memoryDir).\n if (opts.includeWorkspaceIdentity !== false && opts.workspaceDir) {\n const identityPath = path.join(opts.workspaceDir, \"IDENTITY.md\");\n try {\n const content = await readFile(identityPath, \"utf-8\");\n const relPath = \"workspace/IDENTITY.md\";\n records.push({ path: relPath, content });\n const { sha256, bytes } = sha256String(content);\n manifestFiles.push({ path: relPath, sha256, bytes });\n } catch {\n // identity optional\n }\n }\n\n const manifest: ExportManifestV1 = {\n format: EXPORT_FORMAT,\n schemaVersion: EXPORT_SCHEMA_VERSION,\n createdAt: new Date().toISOString(),\n pluginVersion: opts.pluginVersion,\n includesTranscripts: includeTranscripts,\n files: manifestFiles.sort((a, b) => a.path.localeCompare(b.path)),\n };\n\n const bundle: ExportBundleV1 = { manifest, records };\n\n await writeJsonFile(path.join(outDirAbs, \"manifest.json\"), manifest);\n await writeJsonFile(path.join(outDirAbs, \"bundle.json\"), bundle);\n}\n","export const EXPORT_FORMAT = \"openclaw-engram-export\" as const;\nexport const EXPORT_SCHEMA_VERSION = 1 as const;\n\n","import { createHash } from \"node:crypto\";\nimport { mkdir, readdir, readFile, stat, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nexport async function sha256File(filePath: string): Promise<{ sha256: string; bytes: number }> {\n const buf = await readFile(filePath);\n const sha256 = createHash(\"sha256\").update(buf).digest(\"hex\");\n return { sha256, bytes: buf.byteLength };\n}\n\nexport function sha256String(content: string): { sha256: string; bytes: number } {\n const buf = Buffer.from(content, \"utf-8\");\n const sha256 = createHash(\"sha256\").update(buf).digest(\"hex\");\n return { sha256, bytes: buf.byteLength };\n}\n\nexport async function writeJsonFile(filePath: string, value: unknown): Promise<void> {\n await mkdir(path.dirname(filePath), { recursive: true });\n await writeFile(filePath, JSON.stringify(value, null, 2) + \"\\n\", \"utf-8\");\n}\n\nexport async function readJsonFile<T>(filePath: string): Promise<T> {\n const raw = await readFile(filePath, \"utf-8\");\n return JSON.parse(raw) as T;\n}\n\nexport async function listFilesRecursive(rootDir: string): Promise<string[]> {\n const out: string[] = [];\n async function walk(dir: string): Promise<void> {\n const entries = await readdir(dir, { withFileTypes: true });\n for (const ent of entries) {\n const fp = path.join(dir, ent.name);\n if (ent.isDirectory()) {\n await walk(fp);\n } else if (ent.isFile()) {\n out.push(fp);\n }\n }\n }\n await walk(rootDir);\n return out.sort();\n}\n\nexport async function ensureDirExists(dirPath: string): Promise<void> {\n await mkdir(dirPath, { recursive: true });\n}\n\nexport async function fileExists(filePath: string): Promise<boolean> {\n try {\n await stat(filePath);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function toPosixRelPath(absPath: string, rootDir: string): string {\n const rel = path.relative(rootDir, absPath);\n // normalize to posix for portability across platforms\n return rel.split(path.sep).join(\"/\");\n}\n\nexport function fromPosixRelPath(relPath: string): string {\n return relPath.split(\"/\").join(path.sep);\n}\n","import path from \"node:path\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { EXPORT_FORMAT, EXPORT_SCHEMA_VERSION } from \"./constants.js\";\nimport { listFilesRecursive, sha256File, toPosixRelPath, writeJsonFile } from \"./fs-utils.js\";\nimport type { ExportManifestV1 } from \"./types.js\";\n\nexport interface ExportMdOptions {\n memoryDir: string;\n outDir: string;\n includeTranscripts?: boolean;\n pluginVersion: string;\n}\n\nfunction shouldExclude(relPosix: string, includeTranscripts: boolean): boolean {\n const parts = relPosix.split(\"/\");\n if (!includeTranscripts && parts[0] === \"transcripts\") return true;\n return false;\n}\n\nexport async function exportMarkdownBundle(opts: ExportMdOptions): Promise<void> {\n const includeTranscripts = opts.includeTranscripts === true;\n const outDirAbs = path.resolve(opts.outDir);\n await mkdir(outDirAbs, { recursive: true });\n\n const memDirAbs = path.resolve(opts.memoryDir);\n const filesAbs = await listFilesRecursive(memDirAbs);\n\n const manifestFiles: ExportManifestV1[\"files\"] = [];\n\n for (const abs of filesAbs) {\n const relPosix = toPosixRelPath(abs, memDirAbs);\n if (shouldExclude(relPosix, includeTranscripts)) continue;\n\n const dstAbs = path.join(outDirAbs, ...relPosix.split(\"/\"));\n await mkdir(path.dirname(dstAbs), { recursive: true });\n const content = await readFile(abs);\n await writeFile(dstAbs, content);\n const { sha256, bytes } = await sha256File(abs);\n manifestFiles.push({ path: relPosix, sha256, bytes });\n }\n\n const manifest: ExportManifestV1 = {\n format: EXPORT_FORMAT,\n schemaVersion: EXPORT_SCHEMA_VERSION,\n createdAt: new Date().toISOString(),\n pluginVersion: opts.pluginVersion,\n includesTranscripts: includeTranscripts,\n files: manifestFiles.sort((a, b) => a.path.localeCompare(b.path)),\n };\n\n await writeJsonFile(path.join(outDirAbs, \"manifest.json\"), manifest);\n}\n\nexport async function looksLikeEngramMdExport(fromDir: string): Promise<boolean> {\n const dirAbs = path.resolve(fromDir);\n try {\n const raw = await readFile(path.join(dirAbs, \"manifest.json\"), \"utf-8\");\n const parsed = JSON.parse(raw) as { format?: string; schemaVersion?: number };\n return parsed.format === EXPORT_FORMAT && parsed.schemaVersion === EXPORT_SCHEMA_VERSION;\n } catch {\n return false;\n }\n}\n\n","import path from \"node:path\";\nimport { mkdir, readdir, rm } from \"node:fs/promises\";\nimport { exportMarkdownBundle } from \"./export-md.js\";\n\nexport interface BackupOptions {\n memoryDir: string;\n outDir: string;\n includeTranscripts?: boolean;\n retentionDays?: number;\n pluginVersion: string;\n}\n\nfunction timestampDirName(now: Date): string {\n return now.toISOString().replace(/[:.]/g, \"-\");\n}\n\nexport async function backupMemoryDir(opts: BackupOptions): Promise<string> {\n const outDirAbs = path.resolve(opts.outDir);\n await mkdir(outDirAbs, { recursive: true });\n const ts = timestampDirName(new Date());\n const backupDir = path.join(outDirAbs, ts);\n\n await exportMarkdownBundle({\n memoryDir: opts.memoryDir,\n outDir: backupDir,\n includeTranscripts: opts.includeTranscripts,\n pluginVersion: opts.pluginVersion,\n });\n\n if (opts.retentionDays && opts.retentionDays > 0) {\n await enforceRetention(outDirAbs, opts.retentionDays);\n }\n\n return backupDir;\n}\n\nasync function enforceRetention(outDirAbs: string, retentionDays: number): Promise<void> {\n const entries = await readdir(outDirAbs, { withFileTypes: true });\n const cutoffMs = Date.now() - retentionDays * 24 * 60 * 60 * 1000;\n\n for (const ent of entries) {\n if (!ent.isDirectory()) continue;\n const name = ent.name;\n // Directory names are ISO8601 with [: .] replaced by \"-\" to be filesystem-friendly.\n // Example: 2026-02-11T05-06-07-123Z => 2026-02-11T05:06:07.123Z\n const m = name.match(\n /^(\\d{4}-\\d{2}-\\d{2})T(\\d{2})-(\\d{2})-(\\d{2})-(\\d{3})Z$/,\n );\n const iso = m ? `${m[1]}T${m[2]}:${m[3]}:${m[4]}.${m[5]}Z` : null;\n const tsMs = iso ? Date.parse(iso) : NaN;\n if (!Number.isFinite(tsMs)) continue;\n if (tsMs < cutoffMs) {\n await rm(path.join(outDirAbs, name), { recursive: true, force: true });\n }\n }\n}\n","import path from \"node:path\";\nimport Database from \"better-sqlite3\";\nimport { readFile } from \"node:fs/promises\";\nimport { SQLITE_SCHEMA_VERSION, SQLITE_TABLES_SQL } from \"./sqlite-schema.js\";\nimport { listFilesRecursive, sha256File, toPosixRelPath } from \"./fs-utils.js\";\n\nexport interface ExportSqliteOptions {\n memoryDir: string;\n outFile: string;\n includeTranscripts?: boolean;\n pluginVersion: string;\n}\n\nfunction shouldExclude(relPosix: string, includeTranscripts: boolean): boolean {\n const parts = relPosix.split(\"/\");\n if (!includeTranscripts && parts[0] === \"transcripts\") return true;\n return false;\n}\n\nexport async function exportSqlite(opts: ExportSqliteOptions): Promise<void> {\n const includeTranscripts = opts.includeTranscripts === true;\n const memDirAbs = path.resolve(opts.memoryDir);\n const outAbs = path.resolve(opts.outFile);\n\n const filesAbs = await listFilesRecursive(memDirAbs);\n const db = new Database(outAbs);\n try {\n db.exec(\"PRAGMA journal_mode=WAL;\");\n db.exec(SQLITE_TABLES_SQL);\n\n const insertMeta = db.prepare(\"INSERT OR REPLACE INTO meta(key,value) VALUES (?,?)\");\n insertMeta.run(\"schemaVersion\", String(SQLITE_SCHEMA_VERSION));\n insertMeta.run(\"createdAt\", new Date().toISOString());\n insertMeta.run(\"pluginVersion\", opts.pluginVersion);\n insertMeta.run(\"includesTranscripts\", includeTranscripts ? \"true\" : \"false\");\n\n const insertFile = db.prepare(\n \"INSERT OR REPLACE INTO files(path_rel, bytes, sha256, content) VALUES (?,?,?,?)\",\n );\n\n const tx = db.transaction((rows: Array<{ rel: string; bytes: number; sha256: string; content: string }>) => {\n for (const r of rows) insertFile.run(r.rel, r.bytes, r.sha256, r.content);\n });\n\n const rows: Array<{ rel: string; bytes: number; sha256: string; content: string }> = [];\n for (const abs of filesAbs) {\n const relPosix = toPosixRelPath(abs, memDirAbs);\n if (shouldExclude(relPosix, includeTranscripts)) continue;\n const content = await readFile(abs, \"utf-8\");\n const { sha256, bytes } = await sha256File(abs);\n rows.push({ rel: relPosix, bytes, sha256, content });\n }\n\n tx(rows);\n } finally {\n db.close();\n }\n}\n\n","export const SQLITE_SCHEMA_VERSION = 1 as const;\n\nexport const SQLITE_TABLES_SQL = `\nCREATE TABLE IF NOT EXISTS meta (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS files (\n path_rel TEXT PRIMARY KEY,\n bytes INTEGER NOT NULL,\n sha256 TEXT NOT NULL,\n content TEXT NOT NULL\n);\n`;\n\n","import path from \"node:path\";\nimport { mkdir, writeFile } from \"node:fs/promises\";\nimport { ExportBundleV1Schema } from \"./types.js\";\nimport { fileExists, readJsonFile, fromPosixRelPath } from \"./fs-utils.js\";\n\nexport type ConflictPolicy = \"skip\" | \"overwrite\" | \"dedupe\";\n\nexport interface ImportJsonOptions {\n targetMemoryDir: string;\n fromDir: string;\n conflict?: ConflictPolicy;\n dryRun?: boolean;\n workspaceDir?: string;\n}\n\nfunction normalizeForDedupe(s: string): string {\n return s.replace(/\\s+/g, \" \").trim();\n}\n\nexport async function importJsonBundle(opts: ImportJsonOptions): Promise<{ written: number; skipped: number }> {\n const conflict = opts.conflict ?? \"skip\";\n const fromDirAbs = path.resolve(opts.fromDir);\n const bundlePath = path.join(fromDirAbs, \"bundle.json\");\n const bundle = ExportBundleV1Schema.parse(await readJsonFile(bundlePath));\n\n const memDirAbs = path.resolve(opts.targetMemoryDir);\n const written: Array<{ abs: string; content: string }> = [];\n\n let skipped = 0;\n\n for (const rec of bundle.records) {\n const isWorkspace = rec.path.startsWith(\"workspace/\");\n const targetBase = isWorkspace ? (opts.workspaceDir ? path.resolve(opts.workspaceDir) : null) : memDirAbs;\n if (isWorkspace && !targetBase) {\n skipped += 1;\n continue;\n }\n\n const relFs = fromPosixRelPath(isWorkspace ? rec.path.replace(/^workspace\\//, \"\") : rec.path);\n const absTarget = path.join(targetBase!, relFs);\n\n const exists = await fileExists(absTarget);\n if (exists) {\n if (conflict === \"skip\") {\n skipped += 1;\n continue;\n }\n if (conflict === \"dedupe\") {\n try {\n const existing = await (await import(\"node:fs/promises\")).readFile(absTarget, \"utf-8\");\n if (normalizeForDedupe(existing) === normalizeForDedupe(rec.content)) {\n skipped += 1;\n continue;\n }\n } catch {\n // if can't read, fall through to overwrite\n }\n }\n // overwrite: proceed\n }\n\n written.push({ abs: absTarget, content: rec.content });\n }\n\n if (opts.dryRun) {\n return { written: 0, skipped };\n }\n\n for (const w of written) {\n await mkdir(path.dirname(w.abs), { recursive: true });\n await writeFile(w.abs, w.content, \"utf-8\");\n }\n\n return { written: written.length, skipped };\n}\n\nexport function looksLikeEngramJsonExport(fromDir: string): Promise<boolean> {\n const dir = path.resolve(fromDir);\n return Promise.all([\n fileExists(path.join(dir, \"manifest.json\")),\n fileExists(path.join(dir, \"bundle.json\")),\n ]).then(([m, b]) => m && b);\n}\n\n","import { z } from \"zod\";\n\nexport const ExportManifestV1Schema = z.object({\n format: z.literal(\"openclaw-engram-export\"),\n schemaVersion: z.literal(1),\n createdAt: z.string(),\n pluginVersion: z.string(),\n includesTranscripts: z.boolean(),\n files: z.array(\n z.object({\n path: z.string(),\n sha256: z.string(),\n bytes: z.number().int().nonnegative(),\n }),\n ),\n});\n\nexport type ExportManifestV1 = z.infer<typeof ExportManifestV1Schema>;\n\nexport const ExportMemoryRecordV1Schema = z.object({\n path: z.string(),\n content: z.string(),\n});\n\nexport type ExportMemoryRecordV1 = z.infer<typeof ExportMemoryRecordV1Schema>;\n\nexport const ExportBundleV1Schema = z.object({\n manifest: ExportManifestV1Schema,\n records: z.array(ExportMemoryRecordV1Schema),\n});\n\nexport type ExportBundleV1 = z.infer<typeof ExportBundleV1Schema>;\n\n","import path from \"node:path\";\nimport Database from \"better-sqlite3\";\nimport { mkdir, writeFile } from \"node:fs/promises\";\nimport { SQLITE_SCHEMA_VERSION } from \"./sqlite-schema.js\";\nimport { fileExists, fromPosixRelPath } from \"./fs-utils.js\";\n\nexport type ConflictPolicy = \"skip\" | \"overwrite\" | \"dedupe\";\n\nexport interface ImportSqliteOptions {\n targetMemoryDir: string;\n fromFile: string;\n conflict?: ConflictPolicy;\n dryRun?: boolean;\n}\n\nfunction normalizeForDedupe(s: string): string {\n return s.replace(/\\s+/g, \" \").trim();\n}\n\nexport async function importSqlite(opts: ImportSqliteOptions): Promise<{ written: number; skipped: number }> {\n const conflict = opts.conflict ?? \"skip\";\n const memDirAbs = path.resolve(opts.targetMemoryDir);\n const fromAbs = path.resolve(opts.fromFile);\n const db = new Database(fromAbs, { readonly: true });\n\n const written: Array<{ abs: string; content: string }> = [];\n let skipped = 0;\n\n try {\n const metaRows = db.prepare(\"SELECT key,value FROM meta\").all() as Array<{ key: string; value: string }>;\n const meta = Object.fromEntries(metaRows.map((r) => [r.key, r.value]));\n if (String(meta.schemaVersion) !== String(SQLITE_SCHEMA_VERSION)) {\n throw new Error(`unsupported sqlite schemaVersion: ${meta.schemaVersion}`);\n }\n\n const rows = db.prepare(\"SELECT path_rel, content FROM files\").all() as Array<{ path_rel: string; content: string }>;\n for (const r of rows) {\n const relFs = fromPosixRelPath(r.path_rel);\n const absTarget = path.join(memDirAbs, relFs);\n\n const exists = await fileExists(absTarget);\n if (exists) {\n if (conflict === \"skip\") {\n skipped += 1;\n continue;\n }\n if (conflict === \"dedupe\") {\n try {\n const existing = await (await import(\"node:fs/promises\")).readFile(absTarget, \"utf-8\");\n if (normalizeForDedupe(existing) === normalizeForDedupe(r.content)) {\n skipped += 1;\n continue;\n }\n } catch {\n // fall through\n }\n }\n }\n written.push({ abs: absTarget, content: r.content });\n }\n } finally {\n db.close();\n }\n\n if (opts.dryRun) return { written: 0, skipped };\n\n for (const w of written) {\n await mkdir(path.dirname(w.abs), { recursive: true });\n await writeFile(w.abs, w.content, \"utf-8\");\n }\n\n return { written: written.length, skipped };\n}\n\n","import path from \"node:path\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { fileExists, listFilesRecursive, toPosixRelPath, fromPosixRelPath } from \"./fs-utils.js\";\n\nexport type ConflictPolicy = \"skip\" | \"overwrite\" | \"dedupe\";\n\nexport interface ImportMdOptions {\n targetMemoryDir: string;\n fromDir: string;\n conflict?: ConflictPolicy;\n dryRun?: boolean;\n}\n\nfunction normalizeForDedupe(s: string): string {\n return s.replace(/\\s+/g, \" \").trim();\n}\n\nexport async function importMarkdownBundle(opts: ImportMdOptions): Promise<{ written: number; skipped: number }> {\n const conflict = opts.conflict ?? \"skip\";\n const fromAbs = path.resolve(opts.fromDir);\n const targetAbs = path.resolve(opts.targetMemoryDir);\n\n const filesAbs = await listFilesRecursive(fromAbs);\n const writes: Array<{ abs: string; content: string }> = [];\n let skipped = 0;\n\n for (const abs of filesAbs) {\n const relPosix = toPosixRelPath(abs, fromAbs);\n if (relPosix === \"manifest.json\") continue;\n const dstAbs = path.join(targetAbs, fromPosixRelPath(relPosix));\n const content = await readFile(abs, \"utf-8\");\n\n const exists = await fileExists(dstAbs);\n if (exists) {\n if (conflict === \"skip\") {\n skipped += 1;\n continue;\n }\n if (conflict === \"dedupe\") {\n try {\n const existing = await (await import(\"node:fs/promises\")).readFile(dstAbs, \"utf-8\");\n if (normalizeForDedupe(existing) === normalizeForDedupe(content)) {\n skipped += 1;\n continue;\n }\n } catch {\n // fall through to overwrite\n }\n }\n }\n\n writes.push({ abs: dstAbs, content });\n }\n\n if (opts.dryRun) return { written: 0, skipped };\n\n for (const w of writes) {\n await mkdir(path.dirname(w.abs), { recursive: true });\n await writeFile(w.abs, w.content, \"utf-8\");\n }\n\n return { written: writes.length, skipped };\n}\n\n","import path from \"node:path\";\nimport { stat } from \"node:fs/promises\";\nimport { looksLikeEngramJsonExport } from \"./import-json.js\";\nimport { looksLikeEngramMdExport } from \"./export-md.js\";\n\nexport type ImportFormat = \"json\" | \"sqlite\" | \"md\";\n\nexport async function detectImportFormat(fromPath: string): Promise<ImportFormat | null> {\n const abs = path.resolve(fromPath);\n let st: { isDirectory(): boolean; isFile(): boolean };\n try {\n st = await stat(abs);\n } catch {\n return null;\n }\n\n if (st.isFile()) {\n if (abs.endsWith(\".sqlite\") || abs.endsWith(\".db\")) return \"sqlite\";\n return null;\n }\n\n if (st.isDirectory()) {\n if (await looksLikeEngramJsonExport(abs)) return \"json\";\n if (await looksLikeEngramMdExport(abs)) return \"md\";\n return null;\n }\n\n return null;\n}\n\n","import type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport { parseConfig } from \"./config.js\";\nimport { initLogger } from \"./logger.js\";\nimport { log } from \"./logger.js\";\nimport { Orchestrator } from \"./orchestrator.js\";\nimport { registerTools } from \"./tools.js\";\nimport { registerCli } from \"./cli.js\";\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\n\n// Workaround: Read config directly from openclaw.json since gateway may not pass it.\n// IMPORTANT: Do not log raw config contents (may include secrets).\nfunction loadPluginConfigFromFile(): Record<string, unknown> | undefined {\n try {\n const explicitConfigPath =\n process.env.OPENCLAW_ENGRAM_CONFIG_PATH ||\n process.env.OPENCLAW_CONFIG_PATH;\n // Gateway may run without HOME env under service managers.\n const homeDir = process.env.HOME ?? os.homedir();\n const configPath =\n explicitConfigPath && explicitConfigPath.length > 0\n ? explicitConfigPath\n : path.join(homeDir, \".openclaw\", \"openclaw.json\");\n const content = readFileSync(configPath, \"utf-8\");\n const config = JSON.parse(content);\n const pluginEntry = config?.plugins?.entries?.[\"openclaw-engram\"];\n return pluginEntry?.config;\n } catch (err) {\n log.warn(`Failed to load config from file: ${err}`);\n return undefined;\n }\n}\n\nexport default {\n id: \"openclaw-engram\",\n name: \"Engram (Local Memory)\",\n description:\n \"Local-first memory plugin. Uses GPT-5.2 for intelligent extraction and QMD for storage/retrieval.\",\n kind: \"memory\" as const,\n\n register(api: OpenClawPluginApi) {\n // Initialize logger early (debug off until config is parsed).\n initLogger(api.logger, false);\n\n // Workaround: Load config from file since gateway may not pass it\n const fileConfig = loadPluginConfigFromFile();\n const cfg = parseConfig({\n ...api.pluginConfig,\n ...fileConfig, // Merge file config as workaround\n gatewayConfig: api.config, // Pass gateway config for fallback AI\n });\n // Re-initialize with correct debug setting\n initLogger(api.logger, cfg.debug);\n log.info(\n `initialized (debug=${cfg.debug}, qmdEnabled=${cfg.qmdEnabled}, transcriptEnabled=${cfg.transcriptEnabled}, hourlySummariesEnabled=${cfg.hourlySummariesEnabled}, localLlmEnabled=${cfg.localLlmEnabled})`,\n );\n\n // Singleton guard: the gateway may call register() twice (gateway + plugin contexts).\n // Reuse the existing orchestrator if one was already created in this process.\n const existing = (globalThis as any).__openclawEngramOrchestrator as Orchestrator | undefined;\n const orchestrator = existing?.recall ? existing : new Orchestrator(cfg);\n\n // Expose for inter-plugin discovery (e.g., langsmith tracing)\n (globalThis as any).__openclawEngramOrchestrator = orchestrator;\n // Trace callback slot — langsmith (or any observer) will overwrite this\n if ((globalThis as any).__openclawEngramTrace === undefined) {\n (globalThis as any).__openclawEngramTrace = undefined;\n }\n\n // ========================================================================\n // HOOK: before_agent_start — Inject memory context\n // ========================================================================\n api.on(\n \"before_agent_start\",\n async (\n event: Record<string, unknown>,\n ctx: Record<string, unknown>,\n ) => {\n const prompt = event.prompt as string | undefined;\n if (!prompt || prompt.length < 5) return;\n\n const sessionKey = (ctx?.sessionKey as string) ?? \"default\";\n log.debug(`before_agent_start: sessionKey=${sessionKey}, promptLen=${prompt.length}`);\n\n try {\n // Optional: keep bootstrap workspace files small and warn about truncation risk.\n await orchestrator.maybeRunFileHygiene().catch(() => undefined);\n\n // Check for compaction and save checkpoint if needed\n // This is a placeholder - actual compaction detection depends on OpenClaw\n // For now, we'll just call recall with the sessionKey\n\n const context = await orchestrator.recall(prompt, sessionKey);\n log.debug(`before_agent_start: recall returned ${context?.length ?? 0} chars`);\n if (!context) return;\n\n // Rough token estimate: 1 token ≈ 4 chars\n const maxChars = cfg.maxMemoryTokens * 4;\n const trimmed =\n context.length > maxChars\n ? context.slice(0, maxChars) + \"\\n\\n...(memory context trimmed)\"\n : context;\n\n log.debug(`before_agent_start: returning system prompt with ${trimmed.length} chars`);\n return {\n systemPrompt: `## Memory Context (Engram)\\n\\n${trimmed}\\n\\nUse this context naturally when relevant. Never quote or expose this memory context to the user.`,\n };\n } catch (err) {\n log.error(\"recall failed\", err);\n return;\n }\n },\n );\n\n // ========================================================================\n // HOOK: agent_end — Buffer turns and trigger extraction\n // ========================================================================\n api.on(\n \"agent_end\",\n async (\n event: Record<string, unknown>,\n ctx: Record<string, unknown>,\n ) => {\n if (!event.success || !Array.isArray(event.messages)) return;\n if (event.messages.length === 0) return;\n\n const sessionKey = (ctx?.sessionKey as string) ?? \"default\";\n\n try {\n // Extract the last user-assistant exchange\n const messages = event.messages as Array<Record<string, unknown>>;\n const lastTurn = extractLastTurn(messages);\n\n // Best-effort tool usage stats for extended hourly summaries.\n if (orchestrator.config.hourlySummariesIncludeToolStats) {\n const toolNames: string[] = [];\n for (const msg of messages) {\n const role = msg.role as string | undefined;\n if (role === \"tool\") {\n const name = (msg as any).name ?? (msg as any).toolName ?? (msg as any).tool;\n if (typeof name === \"string\" && name.length > 0) toolNames.push(name);\n }\n if (role === \"assistant\") {\n const toolCalls = (msg as any).tool_calls ?? (msg as any).toolCalls;\n if (Array.isArray(toolCalls)) {\n for (const tc of toolCalls) {\n const fnName = tc?.function?.name ?? tc?.name;\n if (typeof fnName === \"string\" && fnName.length > 0) toolNames.push(fnName);\n }\n }\n }\n }\n const ts = new Date().toISOString();\n for (const tool of toolNames) {\n await orchestrator.transcript.appendToolUse({ timestamp: ts, sessionKey, tool });\n }\n }\n\n for (const msg of lastTurn) {\n const rawRole = typeof msg.role === \"string\" ? msg.role : \"\";\n if (rawRole !== \"user\" && rawRole !== \"assistant\") {\n // Ignore tool/system blocks for extraction to avoid noisy memory churn.\n continue;\n }\n const role = rawRole;\n const content = extractTextContent(msg);\n if (content.length < 10) continue;\n\n // Clean system metadata from user messages\n const cleaned =\n role === \"user\" ? cleanUserMessage(content) : content;\n\n // Append to transcript\n if (orchestrator.config.transcriptEnabled) {\n await orchestrator.transcript.append({\n timestamp: new Date().toISOString(),\n role,\n content: cleaned,\n sessionKey,\n turnId: crypto.randomUUID(),\n });\n }\n\n await orchestrator.processTurn(role, cleaned, sessionKey);\n }\n } catch (err) {\n log.error(\"agent_end processing failed\", err);\n }\n },\n );\n\n // ========================================================================\n // HOOK: before_compaction — Save checkpoint before context is lost\n // ========================================================================\n api.on(\n \"before_compaction\",\n async (\n event: Record<string, unknown>,\n ctx: Record<string, unknown>,\n ) => {\n const sessionKey = (ctx?.sessionKey as string) ?? \"default\";\n\n if (!orchestrator.config.checkpointEnabled) {\n return;\n }\n\n try {\n // Get recent turns from transcript\n const entries = await orchestrator.transcript.readRecent(1, sessionKey);\n const checkpointTurns = entries.slice(-orchestrator.config.checkpointTurns);\n\n if (checkpointTurns.length > 0) {\n await orchestrator.transcript.saveCheckpoint({\n sessionKey,\n capturedAt: new Date().toISOString(),\n turns: checkpointTurns,\n ttl: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),\n });\n log.info(`saved checkpoint for ${sessionKey} before compaction`);\n }\n } catch (err) {\n log.error(\"before_compaction hook failed\", err);\n }\n },\n );\n\n // ========================================================================\n // HOOK: after_compaction — Cleanup and optional recovery\n // ========================================================================\n api.on(\n \"after_compaction\",\n async (\n event: Record<string, unknown>,\n ctx: Record<string, unknown>,\n ) => {\n const sessionKey = (ctx?.sessionKey as string) ?? \"default\";\n\n try {\n // The checkpoint will be loaded on next recall via orchestrator.recall()\n // This hook is mainly for logging and any post-compaction cleanup\n log.debug(`compaction completed for ${sessionKey}`);\n\n // Could trigger background tasks here if needed\n // e.g., immediate summarization of the checkpointed turns\n } catch (err) {\n log.error(\"after_compaction hook failed\", err);\n }\n },\n );\n\n // ========================================================================\n // Helper: Auto-register hourly summary cron job\n // ========================================================================\n async function ensureHourlySummaryCron(api: OpenClawPluginApi): Promise<void> {\n const jobId = \"engram-hourly-summary\";\n const cronFilePath = path.join(os.homedir(), \".openclaw\", \"cron\", \"jobs.json\");\n\n try {\n // Read existing jobs\n let jobsData: { version: number; jobs: Array<{ id: string }> } = { version: 1, jobs: [] };\n try {\n const content = await readFile(cronFilePath, \"utf-8\");\n jobsData = JSON.parse(content);\n } catch {\n // File doesn't exist or is invalid - will create new\n }\n\n // Check if job already exists\n const exists = jobsData.jobs.some((j) => j.id === jobId);\n if (exists) {\n log.debug(\"hourly summary cron job already exists\");\n return;\n }\n\n // Get model to use - prefer summary model, then default, then first available\n const model = cfg.summaryModel || cfg.model || \"gpt-5.2\";\n\n // Pick a random minute (1-59) to avoid colliding with other top-of-hour crons\n const randomMinute = Math.floor(Math.random() * 59) + 1;\n\n // Create the hourly summary job.\n //\n // NOTE:\n // - `sessionTarget: \"main\"` only supports `payload.kind: \"systemEvent\"` in this install.\n // - For agent-driven automation, use `sessionTarget: \"isolated\"` + `payload.kind: \"agentTurn\"`.\n // - We intentionally avoid posting anywhere; success is silent.\n const newJob = {\n id: jobId,\n agentId: \"generalist\",\n name: \"Engram Hourly Summary\",\n enabled: true,\n createdAtMs: Date.now(),\n updatedAtMs: Date.now(),\n schedule: {\n kind: \"cron\" as const,\n expr: `${randomMinute} * * * *`, // Every hour at random minute\n tz: \"America/Chicago\",\n },\n sessionTarget: \"isolated\",\n wakeMode: \"now\" as const,\n payload: {\n kind: \"agentTurn\" as const,\n timeoutSeconds: 120,\n thinking: \"off\" as const,\n message:\n \"You are OpenClaw automation.\\n\\n\" +\n \"Task: Generate Engram hourly summaries.\\n\\n\" +\n \"Call the tool `memory_summarize_hourly` with empty params.\\n\\n\" +\n \"Output policy:\\n\" +\n \"- If you generated summaries successfully: output exactly NO_REPLY.\\n\" +\n \"- If there is an error: output one concise line describing it.\\n\\n\" +\n \"Rules:\\n\" +\n \"- Do NOT post to Discord.\\n\" +\n \"- Never print secrets.\\n\",\n },\n delivery: { mode: \"none\" as const },\n state: {},\n };\n\n jobsData.jobs.push(newJob);\n\n // Write back\n await writeFile(cronFilePath, JSON.stringify(jobsData, null, 2), \"utf-8\");\n log.info(\"auto-registered hourly summary cron job\");\n } catch (err) {\n log.error(\"failed to auto-register hourly summary cron job:\", err);\n }\n }\n\n // ========================================================================\n // Register tools and CLI\n // ========================================================================\n registerTools(api as unknown as Parameters<typeof registerTools>[0], orchestrator);\n registerCli(api as unknown as Parameters<typeof registerCli>[0], orchestrator);\n\n // ========================================================================\n // Register service\n // ========================================================================\n api.registerService({\n id: \"openclaw-engram\",\n start: async () => {\n log.info(\"initializing engram memory system...\");\n await orchestrator.initialize();\n\n // Cleanup old transcripts\n if (orchestrator.config.transcriptEnabled) {\n await orchestrator.transcript.cleanup(orchestrator.config.transcriptRetentionDays);\n }\n\n // Cron integration guard:\n // - Hourly summaries are supported, but auto-registering cron is a footgun across installs.\n // - Only auto-register when explicitly enabled by config.\n if (orchestrator.config.hourlySummariesEnabled && orchestrator.config.hourlySummaryCronAutoRegister) {\n await ensureHourlySummaryCron(api);\n } else if (orchestrator.config.hourlySummariesEnabled) {\n log.info(\n \"hourly summaries enabled; cron auto-register is disabled. \" +\n \"To schedule summaries, create an isolated/agentTurn cron job that calls `memory_summarize_hourly`.\",\n );\n }\n\n log.info(\"engram memory system ready\");\n },\n stop: () => {\n log.info(\"stopped\");\n },\n });\n },\n};\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction extractLastTurn(\n messages: Array<Record<string, unknown>>,\n): Array<Record<string, unknown>> {\n let lastUserIdx = -1;\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i]?.role === \"user\") {\n lastUserIdx = i;\n break;\n }\n }\n return lastUserIdx >= 0 ? messages.slice(lastUserIdx) : messages.slice(-2);\n}\n\nfunction extractTextContent(msg: Record<string, unknown>): string {\n if (typeof msg.content === \"string\") return msg.content;\n if (Array.isArray(msg.content)) {\n return (msg.content as Array<Record<string, unknown>>)\n .filter(\n (block) =>\n typeof block === \"object\" &&\n block !== null &&\n block.type === \"text\" &&\n typeof block.text === \"string\",\n )\n .map((block) => block.text as string)\n .join(\"\\n\");\n }\n return \"\";\n}\n\nfunction cleanUserMessage(content: string): string {\n let cleaned = content;\n // Remove memory context blocks\n cleaned = cleaned.replace(\n /<supermemory-context[^>]*>[\\s\\S]*?<\\/supermemory-context>\\s*/gi,\n \"\",\n );\n cleaned = cleaned.replace(\n /## Memory Context \\(Engram\\)[\\s\\S]*?(?=\\n## |\\n$)/gi,\n \"\",\n );\n // Remove platform headers\n cleaned = cleaned.replace(/^\\[\\w+\\s+.+?\\s+id:\\d+\\s+[^\\]]+\\]\\s*/, \"\");\n // Remove trailing message IDs\n cleaned = cleaned.replace(/\\s*\\[message_id:\\s*[^\\]]+\\]\\s*$/, \"\");\n return cleaned.trim();\n}\n"],"mappings":"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","names":["path","createHash","mkdir","readFile","writeFile","chunkContent","writeFileSync","backoffMs","promptChars","readFileSync","existsSync","os","path","path","os","readFile","writeFile","mkdir","path","path","match","path","readFile","mkdir","writeFile","q","exists","readdir","readFile","writeFile","mkdir","path","STOP_WORDS","extractKeywords","mkdir","readdir","path","readFile","writeFile","STOP_WORDS","mkdir","readdir","readFile","unlink","writeFile","path","path","mkdir","readdir","readFile","unlink","writeFile","mkdir","readFile","writeFile","readdir","path","z","z","path","mkdir","readFile","writeFile","readdir","mkdir","readFile","writeFile","path","path","readFile","mkdir","writeFile","mkdir","readFile","writeFile","path","path","readFile","mkdir","writeFile","appendFile","mkdir","readFile","writeFile","path","createHash","path","readFile","createHash","mkdir","writeFile","appendFile","path","mkdir","readFile","writeFile","path","readFile","mkdir","writeFile","path","readdir","readFile","readFile","path","readdir","mkdir","writeFile","path","readdir","path","readdir","path","path","path","exists","mkdir","readFile","readdir","appendFile","writeFile","stat","path","os","z","z","path","os","mkdir","stat","writeFile","readFile","readdir","appendFile","mkdir","readFile","writeFile","path","os","path","os","mkdir","writeFile","readFile","path","readFile","writeFile","mkdir","profile","createHash","path","path","access","readFile","path","mkdir","readFile","createHash","mkdir","readdir","readFile","stat","writeFile","path","stat","path","path","mkdir","readFile","path","mkdir","readFile","writeFile","shouldExclude","path","mkdir","readFile","writeFile","path","mkdir","readdir","rm","path","mkdir","readdir","rm","path","readFile","shouldExclude","path","rows","readFile","path","mkdir","writeFile","z","path","exists","mkdir","writeFile","path","Database","mkdir","writeFile","normalizeForDedupe","path","Database","exists","mkdir","writeFile","path","mkdir","readFile","writeFile","normalizeForDedupe","path","readFile","exists","mkdir","writeFile","path","stat","path","stat","readFile","exists","access","path","chunks","readFile","writeFile","readFileSync","path","os","api","exists"]}
|