@melandlabs/memory-store 0.1.5 → 0.2.0

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.
Files changed (42) hide show
  1. package/dist/{config-D6MzksfT.d.ts → config-BYfTzG3h.d.ts} +17 -0
  2. package/dist/contracts.d.ts +7 -0
  3. package/dist/contracts.js +0 -2
  4. package/dist/http.d.ts +1 -1
  5. package/dist/http.js +144 -23
  6. package/dist/index.d.ts +2 -2
  7. package/dist/index.js +144 -23
  8. package/dist/mcp.d.ts +1 -1
  9. package/dist/mcp.js +144 -23
  10. package/dist/policies/memory-graph-correction-policy.js +0 -2
  11. package/dist/policies/memory-graph-write-policy.js +0 -2
  12. package/dist/search/unified-search.d.ts +39 -3
  13. package/dist/search/unified-search.js +145 -24
  14. package/dist/server/cli-http.js +144 -23
  15. package/dist/server/cli-mcp.js +144 -23
  16. package/dist/server/cli-shared.d.ts +1 -1
  17. package/dist/server/cli-shared.js +0 -2
  18. package/dist/storage/chroma-memory-index.js +0 -2
  19. package/dist/storage/postgres-raw-message-factory.d.ts +1 -1
  20. package/dist/storage/postgres-raw-message-factory.js +0 -2
  21. package/dist/storage/raw-message-store.d.ts +9 -1
  22. package/dist/storage/raw-message-store.js +0 -2
  23. package/dist/storage/sqlite-raw-message-store.d.ts +15 -2
  24. package/dist/storage/sqlite-raw-message-store.js +8 -3
  25. package/dist/storage/sqlite-vector-index.d.ts +1 -1
  26. package/dist/storage/sqlite-vector-index.js +0 -2
  27. package/package.json +8 -8
  28. package/dist/contracts.js.map +0 -1
  29. package/dist/http.js.map +0 -1
  30. package/dist/index.js.map +0 -1
  31. package/dist/mcp.js.map +0 -1
  32. package/dist/policies/memory-graph-correction-policy.js.map +0 -1
  33. package/dist/policies/memory-graph-write-policy.js.map +0 -1
  34. package/dist/search/unified-search.js.map +0 -1
  35. package/dist/server/cli-http.js.map +0 -1
  36. package/dist/server/cli-mcp.js.map +0 -1
  37. package/dist/server/cli-shared.js.map +0 -1
  38. package/dist/storage/chroma-memory-index.js.map +0 -1
  39. package/dist/storage/postgres-raw-message-factory.js.map +0 -1
  40. package/dist/storage/raw-message-store.js.map +0 -1
  41. package/dist/storage/sqlite-raw-message-store.js.map +0 -1
  42. package/dist/storage/sqlite-vector-index.js.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import { VectorSearchResult } from '@melandlabs/rag/vector-service';
2
- import { b as MemoryStoreEnv } from '../config-D6MzksfT.js';
2
+ import { b as MemoryStoreEnv } from '../config-BYfTzG3h.js';
3
3
 
4
4
  /**
5
5
  * SQLite-vec-backed raw-message + insight vector index.
@@ -95,5 +95,3 @@ function toBooleanValue(value) {
95
95
  }
96
96
 
97
97
  export { isInsightSQLiteVecEnabled, searchInsightsWithSQLiteVec, upsertInsightsToSQLiteVec };
98
- //# sourceMappingURL=sqlite-vector-index.js.map
99
- //# sourceMappingURL=sqlite-vector-index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@melandlabs/memory-store",
3
- "version": "0.1.5",
3
+ "version": "0.2.0",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
@@ -61,13 +61,13 @@
61
61
  "hono": "^4.6.14",
62
62
  "zod": "^4.3.6",
63
63
  "@melandlabs/ai": "0.2.0",
64
- "@melandlabs/rag": "0.1.4",
65
- "@melandlabs/shared": "0.1.4",
66
- "@melandlabs/sqlite": "0.1.4"
64
+ "@melandlabs/rag": "0.2.0",
65
+ "@melandlabs/shared": "0.2.0",
66
+ "@melandlabs/sqlite": "0.2.0"
67
67
  },
68
68
  "peerDependencies": {
69
- "@melandlabs/ai-rag": "0.1.4",
70
- "@melandlabs/indexeddb": "0.1.4"
69
+ "@melandlabs/ai-rag": "0.2.0",
70
+ "@melandlabs/indexeddb": "0.2.0"
71
71
  },
72
72
  "peerDependenciesMeta": {
73
73
  "@melandlabs/ai-rag": {
@@ -80,8 +80,8 @@
80
80
  "devDependencies": {
81
81
  "@types/node": "^22.13.10",
82
82
  "typescript": "^5.6.3",
83
- "@melandlabs/ai-rag": "0.1.4",
84
- "@melandlabs/config": "0.1.4"
83
+ "@melandlabs/config": "0.2.0",
84
+ "@melandlabs/ai-rag": "0.2.0"
85
85
  },
86
86
  "scripts": {
87
87
  "build": "tsup",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/contracts.ts"],"names":[],"mappings":";AAkBO,IAAM,8BAAA,GAAiC;AA0C9C,SAAS,uBAAuB,KAAA,EAAmC;AAClE,EAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,KAAK,CAAA,EAAG;AAC5B,IAAA,OAAO,CAAA;AAAA,EACR;AACA,EAAA,IAAK,QAAmB,IAAA,EAAM;AAC7B,IAAA,OAAO,IAAA,CAAK,KAAA,CAAO,KAAA,GAAmB,GAAI,CAAA;AAAA,EAC3C;AACA,EAAA,OAAO,IAAA,CAAK,MAAM,KAAe,CAAA;AAClC;AAKO,SAAS,yBAAyB,OAAA,EAAmC;AAC3E,EAAA,OAAO;AAAA,IACN,IAAI,OAAA,CAAQ,SAAA;AAAA,IACZ,QAAQ,OAAA,CAAQ,MAAA;AAAA,IAChB,SAAA,EAAW,sBAAA,CAAuB,OAAA,CAAQ,SAAS,CAAA;AAAA,IACnD,IAAA,EAAM,OAAA,CAAQ,UAAA,GAAa,MAAA,GAAY,OAAA,CAAQ,OAAA;AAAA,IAC/C,SAAA,EAAW,OAAA,CAAQ,WAAA,EAAa,GAAA,CAAI,CAAC,SAAS,IAAA,CAAK,GAAG,CAAA,CAAE,MAAA,CAAO,OAAO,CAAA;AAAA,IACtE,WAAW,OAAA,CAAQ,SAAA;AAAA,IACnB,gBAAgB,OAAA,CAAQ,cAAA;AAAA,IACxB,sBAAsB,OAAA,CAAQ;AAAA,GAC/B;AACD","file":"contracts.js","sourcesContent":["/**\n * Memory-store contracts — types and constants that were originally re-exported\n * from `@melandlabs/indexeddb` but pulled in browser-only code (IndexedDB\n * globals) at module evaluation time, breaking the standalone HTTP/MCP\n * daemons.\n *\n * Anything defined here can be safely imported on the server without any\n * browser globals being resolved. The `@melandlabs/indexeddb` peer dependency\n * is optional in `@melandlabs/memory-store/package.json`; consumers can\n * depend on it directly for IndexedDB-backed storage.\n *\n * Re-export from this module is stable. New domain types belong in\n * dedicated files; this module only hosts the boundary contracts.\n */\n\nimport type { MemoryRecord } from \"@melandlabs/ai/memory\";\n\n/** Prefix used to reserve chat-memory evidence IDs that must not collide. */\nexport const CHAT_MEMORY_EVIDENCE_ID_PREFIX = \"opencontext-chat:\";\n\n/** A locally-defined re-export of the raw-message shape used by the SDK.\n * Kept as a structural type so consumers (SQLite, postgres factories)\n * can pass either the IndexedDB `RawMessage` or this shape. */\n// biome-ignore lint/suspicious/noExplicitAny: structural mirror of `@melandlabs/indexeddb/storage`'s `RawMessage`.\nexport interface RawMessage {\n\tid?: number;\n\tmessageId: string;\n\tplatform: string;\n\tbotId: string;\n\tuserId: string;\n\tchannel?: string;\n\tperson?: string;\n\ttimestamp: number;\n\tcontent: string;\n\tattachments?: Array<{\n\t\tname: string;\n\t\turl: string;\n\t\tcontentType?: string;\n\t\tsizeBytes?: number;\n\t}>;\n\tembedding?: number[];\n\tembeddingModel?: string;\n\tembeddingContentHash?: string;\n\tembeddingDimensions?: number;\n\tembeddingUpdatedAt?: number;\n\t// biome-ignore lint/suspicious/noExplicitAny: Preserve the public raw metadata contract.\n\tmetadata?: Record<string, any>;\n\tcreatedAt: number;\n\tmemoryStage?: \"short\" | \"mid\" | \"long\";\n\taccessCount?: number;\n\tlastAccessAt?: number;\n\timportanceScore?: number;\n\tarchivedAt?: number;\n\tisPinned?: boolean;\n\tsummaryRefId?: string;\n\tdeprecatedAt?: number;\n\tdeprecationReason?: string;\n\tsupersededBySummaryId?: string;\n}\n\nfunction normalizeTimestampToMs(value: number | undefined): number {\n\tif (!Number.isFinite(value)) {\n\t\treturn 0;\n\t}\n\tif ((value as number) < 1e11) {\n\t\treturn Math.floor((value as number) * 1000);\n\t}\n\treturn Math.floor(value as number);\n}\n\n/** Convert a RawMessage to a MemoryRecord for embedding. Local copy of the\n * helper that previously lived in `@melandlabs/indexeddb/embedding` and pulled\n * in browser-only modules. */\nexport function rawMessageToMemoryRecord(message: RawMessage): MemoryRecord {\n\treturn {\n\t\tid: message.messageId,\n\t\tuserId: message.userId,\n\t\ttimestamp: normalizeTimestampToMs(message.timestamp),\n\t\ttext: message.archivedAt ? undefined : message.content,\n\t\tmediaRefs: message.attachments?.map((item) => item.url).filter(Boolean),\n\t\tembedding: message.embedding,\n\t\tembeddingModel: message.embeddingModel,\n\t\tembeddingContentHash: message.embeddingContentHash,\n\t} as unknown as MemoryRecord;\n}\n"]}
package/dist/http.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/contracts.ts","../src/storage/chroma-memory-index.ts","../src/storage/postgres-raw-message-factory.ts","../src/storage/sqlite-raw-message-store.ts","../src/storage/raw-message-store.ts","../src/search/utilities.ts","../src/search/unified-search.ts","../src/http.ts"],"names":["normalizeTimestampToMs","manager"],"mappings":"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","file":"http.js","sourcesContent":["/**\n * Memory-store contracts — types and constants that were originally re-exported\n * from `@melandlabs/indexeddb` but pulled in browser-only code (IndexedDB\n * globals) at module evaluation time, breaking the standalone HTTP/MCP\n * daemons.\n *\n * Anything defined here can be safely imported on the server without any\n * browser globals being resolved. The `@melandlabs/indexeddb` peer dependency\n * is optional in `@melandlabs/memory-store/package.json`; consumers can\n * depend on it directly for IndexedDB-backed storage.\n *\n * Re-export from this module is stable. New domain types belong in\n * dedicated files; this module only hosts the boundary contracts.\n */\n\nimport type { MemoryRecord } from \"@melandlabs/ai/memory\";\n\n/** Prefix used to reserve chat-memory evidence IDs that must not collide. */\nexport const CHAT_MEMORY_EVIDENCE_ID_PREFIX = \"opencontext-chat:\";\n\n/** A locally-defined re-export of the raw-message shape used by the SDK.\n * Kept as a structural type so consumers (SQLite, postgres factories)\n * can pass either the IndexedDB `RawMessage` or this shape. */\n// biome-ignore lint/suspicious/noExplicitAny: structural mirror of `@melandlabs/indexeddb/storage`'s `RawMessage`.\nexport interface RawMessage {\n\tid?: number;\n\tmessageId: string;\n\tplatform: string;\n\tbotId: string;\n\tuserId: string;\n\tchannel?: string;\n\tperson?: string;\n\ttimestamp: number;\n\tcontent: string;\n\tattachments?: Array<{\n\t\tname: string;\n\t\turl: string;\n\t\tcontentType?: string;\n\t\tsizeBytes?: number;\n\t}>;\n\tembedding?: number[];\n\tembeddingModel?: string;\n\tembeddingContentHash?: string;\n\tembeddingDimensions?: number;\n\tembeddingUpdatedAt?: number;\n\t// biome-ignore lint/suspicious/noExplicitAny: Preserve the public raw metadata contract.\n\tmetadata?: Record<string, any>;\n\tcreatedAt: number;\n\tmemoryStage?: \"short\" | \"mid\" | \"long\";\n\taccessCount?: number;\n\tlastAccessAt?: number;\n\timportanceScore?: number;\n\tarchivedAt?: number;\n\tisPinned?: boolean;\n\tsummaryRefId?: string;\n\tdeprecatedAt?: number;\n\tdeprecationReason?: string;\n\tsupersededBySummaryId?: string;\n}\n\nfunction normalizeTimestampToMs(value: number | undefined): number {\n\tif (!Number.isFinite(value)) {\n\t\treturn 0;\n\t}\n\tif ((value as number) < 1e11) {\n\t\treturn Math.floor((value as number) * 1000);\n\t}\n\treturn Math.floor(value as number);\n}\n\n/** Convert a RawMessage to a MemoryRecord for embedding. Local copy of the\n * helper that previously lived in `@melandlabs/indexeddb/embedding` and pulled\n * in browser-only modules. */\nexport function rawMessageToMemoryRecord(message: RawMessage): MemoryRecord {\n\treturn {\n\t\tid: message.messageId,\n\t\tuserId: message.userId,\n\t\ttimestamp: normalizeTimestampToMs(message.timestamp),\n\t\ttext: message.archivedAt ? undefined : message.content,\n\t\tmediaRefs: message.attachments?.map((item) => item.url).filter(Boolean),\n\t\tembedding: message.embedding,\n\t\tembeddingModel: message.embeddingModel,\n\t\tembeddingContentHash: message.embeddingContentHash,\n\t} as unknown as MemoryRecord;\n}\n","/**\n * Chroma-backed raw-message + insight vector index.\n *\n * Detects the active backend at call time (defaults to sqlite-vec if\n * no env override is present). The actual URL/collection values come\n * from env vars so the standalone memory daemon can pick them up\n * without an injected config.\n */\n\nimport { buildMemoryRecordEmbeddingDocument } from \"@melandlabs/ai/memory\";\nimport { ChromaVectorStore } from \"@melandlabs/rag\";\nimport type { DocumentChunk } from \"@melandlabs/rag/vector-service\";\n\nimport { type RawMessage, rawMessageToMemoryRecord } from \"../contracts\";\n\nconst DEFAULT_RAW_MESSAGES_COLLECTION = \"opencontext_raw_messages\";\nconst DEFAULT_INSIGHTS_COLLECTION = \"opencontext_insights\";\nconst RAW_VECTOR_BACKEND_ENV_KEYS = [\n\t\"RAW_MESSAGE_VECTOR_STORE_BACKEND\",\n\t\"MEMORY_VECTOR_STORE_BACKEND\",\n\t\"VECTOR_STORE_BACKEND\",\n] as const;\nconst INSIGHT_VECTOR_BACKEND_ENV_KEYS = [\n\t\"INSIGHT_VECTOR_STORE_BACKEND\",\n\t\"MEMORY_VECTOR_STORE_BACKEND\",\n\t\"VECTOR_STORE_BACKEND\",\n] as const;\n\nexport interface ChromaInsightVectorInput {\n\tinsightId: string;\n\tuserId: string;\n\tbotId: string;\n\tcontent: string;\n\tcontentHash: string;\n\tembedding: number[];\n\tembeddingModel: string;\n\tembeddingDimensions: number;\n\ttitle?: unknown;\n\tdescription?: unknown;\n\ttaskLabel?: unknown;\n\timportance?: unknown;\n\turgency?: unknown;\n\tplatform?: unknown;\n\taccount?: unknown;\n\ttime?: unknown;\n\tarchived?: unknown;\n}\n\nexport interface ChromaInsightSearchResult {\n\tid: string;\n\tcontent: string;\n\tsimilarity: number;\n\tmetadata: {\n\t\tbotId: string;\n\t\ttitle: string;\n\t\tdescription: string;\n\t\ttaskLabel: string;\n\t\timportance: string;\n\t\turgency: string;\n\t\tplatform: string | null;\n\t\taccount: string | null;\n\t\ttime: Date | null;\n\t\tembeddingModel: string;\n\t\tembeddingDimensions: number;\n\t\tcontentHash: string;\n\t};\n}\n\nfunction getBackend(keys: readonly string[]): string {\n\tfor (const key of keys) {\n\t\tconst value = process.env[key]?.trim().toLowerCase();\n\t\tif (value) {\n\t\t\treturn value;\n\t\t}\n\t}\n\treturn \"\";\n}\n\nexport function isRawMessageChromaEnabled(): boolean {\n\treturn getBackend(RAW_VECTOR_BACKEND_ENV_KEYS) === \"chroma\";\n}\n\nexport function isInsightChromaEnabled(): boolean {\n\treturn getBackend(INSIGHT_VECTOR_BACKEND_ENV_KEYS) === \"chroma\";\n}\n\nfunction getRawMessagesCollectionName(): string {\n\treturn (\n\t\tprocess.env.CHROMA_RAW_MESSAGES_COLLECTION ||\n\t\tprocess.env.CHROMA_MEMORY_COLLECTION ||\n\t\tDEFAULT_RAW_MESSAGES_COLLECTION\n\t);\n}\n\nfunction getInsightsCollectionName(): string {\n\treturn process.env.CHROMA_INSIGHTS_COLLECTION || DEFAULT_INSIGHTS_COLLECTION;\n}\n\nfunction getChromaStore(collectionName: string): ChromaVectorStore {\n\treturn new ChromaVectorStore({\n\t\turl: process.env.CHROMA_URL,\n\t\tcollectionName,\n\t});\n}\n\nfunction normalizeTimestampToMs(value: number | undefined): number {\n\tif (!Number.isFinite(value)) {\n\t\treturn 0;\n\t}\n\tif ((value as number) < 1e11) {\n\t\treturn Math.floor((value as number) * 1000);\n\t}\n\treturn Math.floor(value as number);\n}\n\nfunction toStringValue(value: unknown, fallback = \"\"): string {\n\treturn typeof value === \"string\" && value.trim().length > 0 ? value.trim() : fallback;\n}\n\nfunction toNullableString(value: unknown): string | null {\n\treturn typeof value === \"string\" && value.trim().length > 0 ? value.trim() : null;\n}\n\nfunction toBooleanValue(value: unknown): boolean {\n\treturn value === true || value === \"true\" || value === 1 || value === \"1\";\n}\n\nfunction toDateValue(value: unknown): Date | null {\n\tif (value instanceof Date) {\n\t\treturn Number.isNaN(value.getTime()) ? null : value;\n\t}\n\tif (typeof value === \"string\" || typeof value === \"number\") {\n\t\tconst date = new Date(value);\n\t\treturn Number.isNaN(date.getTime()) ? null : date;\n\t}\n\treturn null;\n}\n\nfunction rawMessageToChunk(message: RawMessage): DocumentChunk | null {\n\tif (!message.embedding || message.embedding.length === 0) {\n\t\treturn null;\n\t}\n\n\tconst record = rawMessageToMemoryRecord(message);\n\tconst document = buildMemoryRecordEmbeddingDocument(record);\n\tif (!document.content) {\n\t\treturn null;\n\t}\n\n\treturn {\n\t\tid: message.messageId,\n\t\tdocumentId: message.messageId,\n\t\tcontent: document.content,\n\t\tembedding: message.embedding,\n\t\tmetadata: {\n\t\t\tsourceType: \"raw_message\",\n\t\t\tuserId: message.userId,\n\t\t\tplatform: message.platform,\n\t\t\tbotId: message.botId,\n\t\t\tchannel: message.channel,\n\t\t\tperson: message.person,\n\t\t\ttimestamp: normalizeTimestampToMs(message.timestamp),\n\t\t\tmemoryStage: message.memoryStage,\n\t\t\tembeddingModel: message.embeddingModel,\n\t\t\tembeddingDimensions: message.embeddingDimensions,\n\t\t\tcontentHash: message.embeddingContentHash,\n\t\t\tarchived: Boolean(message.archivedAt),\n\t\t\trole: typeof message.metadata?.role === \"string\" ? message.metadata.role : undefined,\n\t\t},\n\t};\n}\n\nexport async function upsertRawMessagesToChroma(messages: RawMessage[]): Promise<number> {\n\tif (!isRawMessageChromaEnabled() || messages.length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst chunks = messages.map(rawMessageToChunk).filter((chunk): chunk is DocumentChunk => chunk !== null);\n\tif (chunks.length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst store = getChromaStore(getRawMessagesCollectionName());\n\tawait store.addChunks(chunks);\n\treturn chunks.length;\n}\n\nexport async function searchRawMessagesWithChroma(input: {\n\tuserId: string;\n\tqueryEmbedding: number[];\n\tlimit: number;\n\tthreshold: number;\n\tbotId?: string;\n}): Promise<\n\tArray<{\n\t\tid: string;\n\t\tcontent: string;\n\t\tsimilarity: number;\n\t\tmetadata: Record<string, unknown>;\n\t}>\n> {\n\tif (!isRawMessageChromaEnabled() || input.queryEmbedding.length === 0) {\n\t\treturn [];\n\t}\n\n\tconst store = getChromaStore(getRawMessagesCollectionName());\n\tconst results = await store.similaritySearch(\n\t\tinput.queryEmbedding,\n\t\tMath.max(input.limit * 5, input.limit),\n\t\tinput.userId,\n\t);\n\n\treturn results\n\t\t.filter((result) => {\n\t\t\tconst metadata = result.metadata ?? {};\n\t\t\tif (toBooleanValue(metadata.archived)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (input.botId && metadata.botId !== input.botId) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn result.score >= input.threshold;\n\t\t})\n\t\t.map((result) => ({\n\t\t\tid: result.id,\n\t\t\tcontent: result.content,\n\t\t\tsimilarity: result.score,\n\t\t\tmetadata: result.metadata ?? {},\n\t\t}))\n\t\t.slice(0, input.limit);\n}\n\nexport async function upsertInsightsToChroma(insights: ChromaInsightVectorInput[]): Promise<number> {\n\tif (!isInsightChromaEnabled() || insights.length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst chunks = insights\n\t\t.filter(\n\t\t\t(item) => item.content.trim().length > 0 && Array.isArray(item.embedding) && item.embedding.length > 0,\n\t\t)\n\t\t.map<DocumentChunk>((item) => ({\n\t\t\tid: item.insightId,\n\t\t\tdocumentId: item.insightId,\n\t\t\tcontent: item.content,\n\t\t\tembedding: item.embedding,\n\t\t\tmetadata: {\n\t\t\t\tsourceType: \"insight\",\n\t\t\t\tinsightId: item.insightId,\n\t\t\t\tuserId: item.userId,\n\t\t\t\tbotId: item.botId,\n\t\t\t\ttitle: toStringValue(item.title),\n\t\t\t\tdescription: toStringValue(item.description),\n\t\t\t\ttaskLabel: toStringValue(item.taskLabel),\n\t\t\t\timportance: toStringValue(item.importance),\n\t\t\t\turgency: toStringValue(item.urgency),\n\t\t\t\tplatform: toNullableString(item.platform),\n\t\t\t\taccount: toNullableString(item.account),\n\t\t\t\ttime: toDateValue(item.time)?.toISOString(),\n\t\t\t\tembeddingModel: item.embeddingModel,\n\t\t\t\tembeddingDimensions: item.embeddingDimensions,\n\t\t\t\tcontentHash: item.contentHash,\n\t\t\t\tarchived: toBooleanValue(item.archived),\n\t\t\t},\n\t\t}));\n\n\tif (chunks.length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst store = getChromaStore(getInsightsCollectionName());\n\tawait store.addChunks(chunks);\n\treturn chunks.length;\n}\n\nexport async function searchInsightsWithChroma(input: {\n\tuserId: string;\n\tqueryEmbedding: number[];\n\tlimit: number;\n\tthreshold: number;\n\tbotIds?: string[];\n\tincludeArchived?: boolean;\n}): Promise<ChromaInsightSearchResult[]> {\n\tif (!isInsightChromaEnabled() || input.queryEmbedding.length === 0) {\n\t\treturn [];\n\t}\n\n\tconst botIdSet = input.botIds && input.botIds.length > 0 ? new Set(input.botIds) : null;\n\tconst store = getChromaStore(getInsightsCollectionName());\n\tconst results = await store.similaritySearch(\n\t\tinput.queryEmbedding,\n\t\tMath.max(input.limit * 5, input.limit),\n\t\tinput.userId,\n\t);\n\n\treturn results\n\t\t.filter((result) => {\n\t\t\tconst metadata = result.metadata ?? {};\n\t\t\tif (!input.includeArchived && toBooleanValue(metadata.archived)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (botIdSet && !botIdSet.has(String(metadata.botId ?? \"\"))) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn result.score >= input.threshold;\n\t\t})\n\t\t.map((result) => {\n\t\t\tconst metadata = result.metadata ?? {};\n\t\t\treturn {\n\t\t\t\tid: result.id,\n\t\t\t\tcontent: result.content,\n\t\t\t\tsimilarity: result.score,\n\t\t\t\tmetadata: {\n\t\t\t\t\tbotId: toStringValue(metadata.botId),\n\t\t\t\t\ttitle: toStringValue(metadata.title),\n\t\t\t\t\tdescription: toStringValue(metadata.description),\n\t\t\t\t\ttaskLabel: toStringValue(metadata.taskLabel),\n\t\t\t\t\timportance: toStringValue(metadata.importance),\n\t\t\t\t\turgency: toStringValue(metadata.urgency),\n\t\t\t\t\tplatform: toNullableString(metadata.platform),\n\t\t\t\t\taccount: toNullableString(metadata.account),\n\t\t\t\t\ttime: toDateValue(metadata.time),\n\t\t\t\t\tembeddingModel: toStringValue(metadata.embeddingModel),\n\t\t\t\t\tembeddingDimensions: Number(metadata.embeddingDimensions ?? 0),\n\t\t\t\t\tcontentHash: toStringValue(metadata.contentHash),\n\t\t\t\t},\n\t\t\t};\n\t\t})\n\t\t.slice(0, input.limit);\n}\n","/**\n * Lazy registration slot for the host's Postgres-backed raw message\n * manager. The actual `PostgresRawMessageManager` implementation lives\n * in the host application because it owns the schema-bound Drizzle\n * table references.\n *\n * The package ships this factory so consumers can wire up their own\n * postgres implementation without forcing the package to take a\n * hard dependency on Drizzle schema files.\n */\n\nimport type { MemoryStoreEnv } from \"../config\";\n\nexport interface PostgresRawMessageManagerLike {\n\tinit?(): Promise<void>;\n\tclose?(): Promise<void>;\n\tupsertRawMessages?(input: {\n\t\tuserId: string;\n\t\tmessages: unknown[];\n\t}): Promise<unknown>;\n\tgetMessageById?(input: {\n\t\tuserId: string;\n\t\tmessageId: string;\n\t}): Promise<unknown>;\n\tsearchMessagesSemantically?(input: {\n\t\tuserId: string;\n\t\tqueryEmbedding: number[];\n\t\tembeddingModel?: string;\n\t\tlimit?: number;\n\t\tscanLimit?: number;\n\t\tthreshold?: number;\n\t\tincludeArchived?: boolean;\n\t\tincludeDeprecated?: boolean;\n\t\tplatform?: string;\n\t\tbotId?: string;\n\t\tchannel?: string;\n\t\tperson?: string;\n\t\tstartTime?: number;\n\t\tendTime?: number;\n\t}): Promise<unknown[]>;\n}\n\nexport type PostgresFactoryFn = (env?: MemoryStoreEnv) => Promise<PostgresRawMessageManagerLike>;\n\nlet factory: PostgresFactoryFn | null = null;\n\nexport function registerPostgresFactory(fn: PostgresFactoryFn): void {\n\tfactory = fn;\n}\n\nexport function clearPostgresFactory(): void {\n\tfactory = null;\n}\n\nexport async function resolvePostgresFactory(\n\tenv?: MemoryStoreEnv,\n): Promise<PostgresRawMessageManagerLike | null> {\n\tif (!factory) return null;\n\treturn await factory(env);\n}\n\nexport function hasPostgresFactory(): boolean {\n\treturn factory !== null;\n}\n","/**\n * SQLite-backed raw message store.\n *\n * Singleton manager. Local SQLite is the default backend for the memory\n * store — no host-mode check, no env-var opt-in. The DB path is resolved\n * from (in order):\n * 1. `MEMORY_STORE_DB_PATH` — recommended knob\n * 2. `~/.opencontext/memory/store.db` — last-resort default\n *\n * The `env?` parameter on the exported functions is kept for back-compat\n * with the historical `MemoryStoreEnv` interface but is no longer read.\n */\n\nimport { mkdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { SQLiteRawMessageManager } from \"@melandlabs/sqlite\";\nimport type { MemoryStoreEnv } from \"../config\";\nimport { isRawMessageChromaEnabled } from \"./chroma-memory-index\";\n\nlet manager: SQLiteRawMessageManager | null = null;\n\nconst DEFAULT_SQLITE_PATH = join(homedir(), \".opencontext\", \"memory\", \"store.db\");\n\n/**\n * Resolve the SQLite DB file path from env vars. Exposed so other storage\n * layers (vector index) can stay in sync with the same default.\n */\nexport function resolveSQLiteRawMessageDbPath(): string {\n\tconst fromEnv = process.env.MEMORY_STORE_DB_PATH?.trim();\n\treturn fromEnv && fromEnv.length > 0 ? fromEnv : DEFAULT_SQLITE_PATH;\n}\n\n/**\n * Local SQLite is the default. Every host (Tauri, server, CLI, tests) can\n * open the manager; the only failure mode is filesystem write permission.\n */\nexport function isSQLiteRawMessageStorageAvailable(_env?: MemoryStoreEnv): boolean {\n\treturn true;\n}\n\nexport async function getSQLiteRawMessageManager(_env?: MemoryStoreEnv): Promise<SQLiteRawMessageManager> {\n\tif (!manager) {\n\t\tconst dbPath = resolveSQLiteRawMessageDbPath();\n\t\tmkdirSync(dirname(dbPath), { recursive: true });\n\t\tmanager = new SQLiteRawMessageManager({\n\t\t\tdbPath,\n\t\t\tenableVectorSearch: !isRawMessageChromaEnabled(),\n\t\t});\n\t\tawait manager.init();\n\t}\n\n\treturn manager;\n}\n\nexport async function closeSQLiteRawMessageManager(): Promise<void> {\n\tif (!manager) {\n\t\treturn;\n\t}\n\tawait manager.close();\n\tmanager = null;\n}\n\n/**\n * Test-only: reset the singleton. Used by vitest between test cases.\n */\nexport function __resetSQLiteRawMessageManagerForTests(): void {\n\tmanager = null;\n}\n\n// Kept for back-compat with the historical `MemoryStoreEnv` interface.\n// The resolved env is no longer read by the SQLite layer, but the symbol\n// stays exported so external code that still calls `resolveEnv` compiles.\nfunction resolveEnv(_env?: MemoryStoreEnv): MemoryStoreEnv {\n\treturn {};\n}\n","/**\n * Top-level raw-message store facade.\n *\n * Backend selection is env-var driven:\n *\n * - `OPENCONTEXT_MEMORY_STORE_BACKEND=postgres` → use the host's\n * registered Postgres factory. A factory MUST be registered first\n * via `registerPostgresFactory()`; otherwise this throws a clear\n * error rather than silently falling back.\n * - Any other value (including unset) → local SQLite. The default\n * works in every host environment with no extra configuration.\n *\n * The facade exposes the common `RawMessageStorageManager` contract plus\n * a typed `searchMessagesSemantically` extension when present.\n */\n\nimport type { RawMessageStorageManager } from \"@melandlabs/indexeddb/storage\";\nimport type { MemoryStoreConfig, MemoryStoreEnv } from \"../config\";\nimport { hasPostgresFactory, resolvePostgresFactory } from \"./postgres-raw-message-factory\";\nimport { closeSQLiteRawMessageManager, getSQLiteRawMessageManager } from \"./sqlite-raw-message-store\";\n\nexport type RawMessageStorageBackend = \"sqlite\" | \"postgres\";\n\nexport type RawMessageStorageManagerWithSearch = RawMessageStorageManager & {\n\tsearchMessagesSemantically?: (input: {\n\t\tuserId: string;\n\t\tqueryEmbedding: number[];\n\t\tembeddingModel?: string;\n\t\tlimit?: number;\n\t\tscanLimit?: number;\n\t\tthreshold?: number;\n\t\tincludeArchived?: boolean;\n\t\tplatform?: string;\n\t\tbotId?: string;\n\t\tchannel?: string;\n\t\tperson?: string;\n\t\tstartTime?: number;\n\t\tendTime?: number;\n\t}) => Promise<unknown[]>;\n};\n\nexport interface CreateRawMessageStoreOptions {\n\tenv?: MemoryStoreEnv;\n}\n\nexport interface RawMessageStore {\n\tgetManager(): Promise<RawMessageStorageManagerWithSearch>;\n\tgetBackend(): RawMessageStorageBackend;\n\tisAvailable(): boolean;\n\tclose(): Promise<void>;\n}\n\nfunction resolveBackend(env: MemoryStoreEnv | undefined): RawMessageStorageBackend {\n\tconst explicit = process.env.OPENCONTEXT_MEMORY_STORE_BACKEND?.trim().toLowerCase();\n\tif (explicit === \"postgres\") return \"postgres\";\n\t// Any other value — including the default \"sqlite\", an unknown value,\n\t// or the env var being unset — falls through to local SQLite.\n\treturn \"sqlite\";\n}\n\nfunction resolveEnv(_env?: MemoryStoreEnv): MemoryStoreEnv {\n\treturn {};\n}\n\nexport function createRawMessageStore(options: CreateRawMessageStoreOptions = {}): RawMessageStore {\n\tconst env = resolveEnv(options.env);\n\n\treturn {\n\t\tgetBackend(): RawMessageStorageBackend {\n\t\t\treturn resolveBackend(env);\n\t\t},\n\t\tisAvailable(): boolean {\n\t\t\t// SQLite is always available; postgres is only available when the\n\t\t\t// env var asks for it AND a factory has been registered.\n\t\t\treturn resolveBackend(env) === \"sqlite\" || hasPostgresFactory();\n\t\t},\n\t\tasync getManager(): Promise<RawMessageStorageManagerWithSearch> {\n\t\t\tif (resolveBackend(env) === \"postgres\") {\n\t\t\t\tconst pg = await resolvePostgresFactory(env);\n\t\t\t\tif (!pg) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\"OPENCONTEXT_MEMORY_STORE_BACKEND=postgres but no Postgres factory is registered. \" +\n\t\t\t\t\t\t\t\"Call registerPostgresFactory() at startup, or unset the env var to use the default SQLite backend.\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn pg as unknown as RawMessageStorageManagerWithSearch;\n\t\t\t}\n\t\t\treturn (await getSQLiteRawMessageManager(env)) as unknown as RawMessageStorageManagerWithSearch;\n\t\t},\n\t\tasync close(): Promise<void> {\n\t\t\t// The sqlite singleton is process-wide, so close regardless of the\n\t\t\t// env var's current value — the previous call may have used it.\n\t\t\tawait closeSQLiteRawMessageManager();\n\t\t},\n\t};\n}\n\n// Module-level singleton so existing call sites that imported the\n// legacy `getRawMessageManager()` keep working without a refactor.\nlet moduleStore: RawMessageStore | null = null;\nlet moduleConfig: MemoryStoreConfig | null = null;\n\nexport function configureRawMessageStore(config: MemoryStoreConfig): RawMessageStore {\n\tmoduleConfig = config;\n\tmoduleStore = createRawMessageStore({ env: config.env });\n\treturn moduleStore;\n}\n\nexport function getRawMessageStorageBackend(): RawMessageStorageBackend {\n\tif (!moduleStore) {\n\t\tmoduleStore = createRawMessageStore({ env: moduleConfig?.env });\n\t}\n\treturn moduleStore.getBackend();\n}\n\nexport function isRawMessageStorageAvailable(): boolean {\n\tif (!moduleStore) {\n\t\tmoduleStore = createRawMessageStore({ env: moduleConfig?.env });\n\t}\n\treturn moduleStore.isAvailable();\n}\n\nexport async function getRawMessageManager(): Promise<RawMessageStorageManagerWithSearch> {\n\tif (!moduleStore) {\n\t\tmoduleStore = createRawMessageStore({ env: moduleConfig?.env });\n\t}\n\treturn moduleStore.getManager();\n}\n\nexport async function closeRawMessageStore(): Promise<void> {\n\tif (!moduleStore) return;\n\tawait moduleStore.close();\n\tmoduleStore = null;\n}\n","/**\n * Pure helpers used by the unified memory search pipeline.\n *\n * Kept side-effect free so they can be reused by tests, MCP tools,\n * and the HTTP daemon without pulling in any of the heavier\n * storage/search implementations.\n */\n\nexport type UnifiedMemorySearchSource = \"memory\" | \"insights\" | \"knowledge\";\n\nexport interface UnifiedMemorySearchWarning {\n\tsource: UnifiedMemorySearchSource;\n\tcode: string;\n\tmessage: string;\n}\n\nexport interface UnifiedMemorySearchInput {\n\tuserId: string;\n\tquery: string;\n\tsources?: UnifiedMemorySearchSource[];\n\tlimit?: number;\n\tthreshold?: number;\n\tauthToken?: string;\n\tincludeArchivedInsights?: boolean;\n\tbotIds?: string[];\n\tdocumentIds?: string[];\n}\n\nexport interface UnifiedMemorySearchResult {\n\ttype: \"memory\" | \"insight\" | \"knowledge\";\n\tid: string;\n\tcontent: string;\n\tsimilarity: number;\n\tmetadata: Record<string, unknown>;\n}\n\nexport interface UnifiedMemorySearchOutput {\n\tquery: string;\n\tsources: UnifiedMemorySearchSource[];\n\tresults: UnifiedMemorySearchResult[];\n\tcount: number;\n\twarnings: UnifiedMemorySearchWarning[];\n}\n\nconst DEFAULT_LIMIT = 10;\nconst DEFAULT_THRESHOLD = 0.7;\nconst DEFAULT_SOURCES: UnifiedMemorySearchSource[] = [\"memory\", \"insights\", \"knowledge\"];\nconst SOURCE_SET = new Set<UnifiedMemorySearchSource>(DEFAULT_SOURCES);\n\nexport function normalizeUnifiedMemorySearchSources(sources: unknown): UnifiedMemorySearchSource[] {\n\tif (!Array.isArray(sources) || sources.length === 0) {\n\t\treturn [...DEFAULT_SOURCES];\n\t}\n\n\tconst normalized = sources\n\t\t.filter((source): source is string => typeof source === \"string\")\n\t\t.map((source) => source.trim().toLowerCase())\n\t\t.filter((source): source is UnifiedMemorySearchSource =>\n\t\t\tSOURCE_SET.has(source as UnifiedMemorySearchSource),\n\t\t);\n\n\treturn normalized.length > 0 ? Array.from(new Set(normalized)) : [...DEFAULT_SOURCES];\n}\n\nexport function clampUnifiedMemorySearchLimit(limit: unknown): number {\n\tconst parsed = typeof limit === \"number\" ? limit : Number(limit ?? DEFAULT_LIMIT);\n\tif (!Number.isFinite(parsed)) {\n\t\treturn DEFAULT_LIMIT;\n\t}\n\treturn Math.min(50, Math.max(1, Math.floor(parsed)));\n}\n\nexport function clampUnifiedMemorySearchThreshold(threshold: unknown): number {\n\tconst parsed = typeof threshold === \"number\" ? threshold : Number(threshold ?? DEFAULT_THRESHOLD);\n\tif (!Number.isFinite(parsed)) {\n\t\treturn DEFAULT_THRESHOLD;\n\t}\n\treturn Math.min(1, Math.max(-1, parsed));\n}\n\nexport function mergeUnifiedMemorySearchResults(\n\tresults: UnifiedMemorySearchResult[],\n\tlimit: number,\n): UnifiedMemorySearchResult[] {\n\treturn [...results]\n\t\t.sort((a, b) => {\n\t\t\tconst scoreDelta = b.similarity - a.similarity;\n\t\t\tif (scoreDelta !== 0) {\n\t\t\t\treturn scoreDelta;\n\t\t\t}\n\t\t\treturn a.type.localeCompare(b.type) || a.id.localeCompare(b.id);\n\t\t})\n\t\t.slice(0, limit);\n}\n\nexport function toKnowledgeResult(result: {\n\tchunkId: string;\n\tdocumentId: string;\n\tdocumentName: string;\n\tcontent: string;\n\tsimilarity: number;\n\tchunkIndex: number;\n}): UnifiedMemorySearchResult {\n\treturn {\n\t\ttype: \"knowledge\",\n\t\tid: result.chunkId,\n\t\tcontent: result.content,\n\t\tsimilarity: result.similarity,\n\t\tmetadata: {\n\t\t\tdocumentId: result.documentId,\n\t\t\tdocumentName: result.documentName,\n\t\t\tchunkIndex: result.chunkIndex,\n\t\t},\n\t};\n}\n\nexport function toMemoryResult(result: {\n\tid: string;\n\tcontent: string;\n\tsimilarity: number;\n\tmetadata: Record<string, unknown>;\n}): UnifiedMemorySearchResult {\n\treturn {\n\t\ttype: \"memory\",\n\t\tid: result.id,\n\t\tcontent: result.content,\n\t\tsimilarity: result.similarity,\n\t\tmetadata: result.metadata,\n\t};\n}\n\nexport function isRawMemorySemanticResult(result: unknown): result is {\n\tid: string;\n\tcontent: string;\n\tsimilarity: number;\n\tmetadata: Record<string, unknown>;\n} {\n\tif (!result || typeof result !== \"object\") {\n\t\treturn false;\n\t}\n\tconst item = result as Record<string, unknown>;\n\treturn (\n\t\ttypeof item.id === \"string\" &&\n\t\ttypeof item.content === \"string\" &&\n\t\ttypeof item.similarity === \"number\" &&\n\t\tBoolean(item.metadata) &&\n\t\ttypeof item.metadata === \"object\"\n\t);\n}\n","/**\n * Unified semantic search facade.\n *\n * Cross-source search over raw messages (always), insights, and\n * uploaded knowledge documents. The host wires up the cross-domain\n * dependencies via `UnifiedSearchDeps` so this module stays\n * framework-agnostic.\n */\n\nimport type { UnifiedSearchDeps } from \"../config\";\nimport { isRawMessageChromaEnabled, searchRawMessagesWithChroma } from \"../storage/chroma-memory-index\";\nimport { isRawMessageStorageAvailable } from \"../storage/raw-message-store\";\nimport {\n\ttype UnifiedMemorySearchInput,\n\ttype UnifiedMemorySearchOutput,\n\ttype UnifiedMemorySearchResult,\n\ttype UnifiedMemorySearchWarning,\n\tclampUnifiedMemorySearchLimit,\n\tclampUnifiedMemorySearchThreshold,\n\tisRawMemorySemanticResult,\n\tmergeUnifiedMemorySearchResults,\n\tnormalizeUnifiedMemorySearchSources,\n\ttoKnowledgeResult,\n\ttoMemoryResult,\n} from \"./utilities\";\n\nexport type {\n\tUnifiedMemorySearchInput,\n\tUnifiedMemorySearchOutput,\n\tUnifiedMemorySearchResult,\n\tUnifiedMemorySearchSource,\n\tUnifiedMemorySearchWarning,\n} from \"./utilities\";\n\nexport {\n\tclampUnifiedMemorySearchLimit,\n\tclampUnifiedMemorySearchThreshold,\n\tisRawMemorySemanticResult,\n\tmergeUnifiedMemorySearchResults,\n\tnormalizeUnifiedMemorySearchSources,\n\ttoKnowledgeResult,\n\ttoMemoryResult,\n} from \"./utilities\";\n\nexport interface UnifiedSearch {\n\tsearchUnifiedMemory(input: UnifiedMemorySearchInput): Promise<UnifiedMemorySearchOutput>;\n\tsearchRawMemorySemantically(input: UnifiedMemorySearchInput): Promise<UnifiedMemorySearchResult[]>;\n}\n\nexport function createUnifiedSearch(deps: UnifiedSearchDeps = {}): UnifiedSearch {\n\tconst logger = (deps as { logger?: Console }).logger ?? console;\n\n\tasync function searchUnifiedMemory(input: UnifiedMemorySearchInput): Promise<UnifiedMemorySearchOutput> {\n\t\tconst query = input.query.trim();\n\t\tconst sources = normalizeUnifiedMemorySearchSources(input.sources);\n\t\tconst limit = clampUnifiedMemorySearchLimit(input.limit);\n\t\tconst threshold = clampUnifiedMemorySearchThreshold(input.threshold);\n\t\tconst warnings: UnifiedMemorySearchWarning[] = [];\n\t\tconst results: UnifiedMemorySearchResult[] = [];\n\n\t\tif (!query) {\n\t\t\treturn {\n\t\t\t\tquery,\n\t\t\t\tsources,\n\t\t\t\tresults: [],\n\t\t\t\tcount: 0,\n\t\t\t\twarnings,\n\t\t\t};\n\t\t}\n\n\t\tif (sources.includes(\"memory\")) {\n\t\t\tif (isRawMessageStorageAvailable()) {\n\t\t\t\ttry {\n\t\t\t\t\tconst memoryHits = await runMemorySource(input, limit, threshold);\n\t\t\t\t\tresults.push(...memoryHits);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tlogger.warn?.(\"[memory-store] memory source failed:\", error);\n\t\t\t\t\twarnings.push({\n\t\t\t\t\t\tsource: \"memory\",\n\t\t\t\t\t\tcode: \"memory_search_failed\",\n\t\t\t\t\t\tmessage: (error as Error).message ?? \"memory_search_failed\",\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twarnings.push({\n\t\t\t\t\tsource: \"memory\",\n\t\t\t\t\tcode: \"raw_message_storage_unavailable\",\n\t\t\t\t\tmessage: \"Raw memory storage is not available in this environment.\",\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tif (sources.includes(\"insights\") && typeof deps.searchInsights === \"function\") {\n\t\t\ttry {\n\t\t\t\tconst insightHits = await deps.searchInsights({\n\t\t\t\t\tuserId: input.userId,\n\t\t\t\t\tquery: input.query,\n\t\t\t\t\tlimit,\n\t\t\t\t\tthreshold,\n\t\t\t\t\tbotIds: input.botIds,\n\t\t\t\t\tincludeArchived: input.includeArchivedInsights,\n\t\t\t\t\tauthToken: input.authToken,\n\t\t\t\t});\n\t\t\t\tfor (const hit of insightHits) {\n\t\t\t\t\tresults.push({\n\t\t\t\t\t\ttype: \"insight\",\n\t\t\t\t\t\tid: hit.id,\n\t\t\t\t\t\tcontent: hit.content,\n\t\t\t\t\t\tsimilarity: hit.similarity,\n\t\t\t\t\t\tmetadata: hit.metadata,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tlogger.warn?.(\"[memory-store] insights source failed:\", error);\n\t\t\t\twarnings.push({\n\t\t\t\t\tsource: \"insights\",\n\t\t\t\t\tcode: \"insights_search_failed\",\n\t\t\t\t\tmessage: (error as Error).message ?? \"insights_search_failed\",\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (sources.includes(\"insights\")) {\n\t\t\twarnings.push({\n\t\t\t\tsource: \"insights\",\n\t\t\t\tcode: \"insights_search_not_configured\",\n\t\t\t\tmessage: \"Insights search is not configured for this host.\",\n\t\t\t});\n\t\t}\n\n\t\tif (sources.includes(\"knowledge\") && typeof deps.searchKnowledge === \"function\") {\n\t\t\ttry {\n\t\t\t\tconst knowledgeHits = await deps.searchKnowledge({\n\t\t\t\t\tuserId: input.userId,\n\t\t\t\t\tquery: input.query,\n\t\t\t\t\toptions: {\n\t\t\t\t\t\tlimit,\n\t\t\t\t\t\tthreshold,\n\t\t\t\t\t\tdocumentIds: input.documentIds,\n\t\t\t\t\t},\n\t\t\t\t\tauthToken: input.authToken,\n\t\t\t\t});\n\t\t\t\tfor (const hit of knowledgeHits) {\n\t\t\t\t\tresults.push(toKnowledgeResult(hit));\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tlogger.warn?.(\"[memory-store] knowledge source failed:\", error);\n\t\t\t\twarnings.push({\n\t\t\t\t\tsource: \"knowledge\",\n\t\t\t\t\tcode: \"knowledge_search_failed\",\n\t\t\t\t\tmessage: (error as Error).message ?? \"knowledge_search_failed\",\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (sources.includes(\"knowledge\")) {\n\t\t\twarnings.push({\n\t\t\t\tsource: \"knowledge\",\n\t\t\t\tcode: \"knowledge_search_not_configured\",\n\t\t\t\tmessage: \"Knowledge search is not configured for this host.\",\n\t\t\t});\n\t\t}\n\n\t\tconst merged = mergeUnifiedMemorySearchResults(results, limit);\n\n\t\treturn {\n\t\t\tquery: input.query,\n\t\t\tsources,\n\t\t\tresults: merged,\n\t\t\tcount: merged.length,\n\t\t\twarnings,\n\t\t};\n\t}\n\n\tasync function runMemorySource(\n\t\tinput: UnifiedMemorySearchInput,\n\t\tlimit: number,\n\t\tthreshold: number,\n\t): Promise<UnifiedMemorySearchResult[]> {\n\t\tif (typeof deps.embedQuery !== \"function\") {\n\t\t\tthrow new Error(\"embedQuery is not configured\");\n\t\t}\n\n\t\tconst queryEmbedding = await deps.embedQuery({\n\t\t\tuserId: input.userId,\n\t\t\tquery: input.query,\n\t\t\tauthToken: input.authToken,\n\t\t});\n\n\t\tconst filters = input.botIds && input.botIds.length > 0 ? input.botIds.map((botId) => ({ botId })) : [{}];\n\n\t\tif (isRawMessageChromaEnabled()) {\n\t\t\ttry {\n\t\t\t\tconst chromaHits = (\n\t\t\t\t\tawait Promise.all(\n\t\t\t\t\t\tfilters.map((filter) => {\n\t\t\t\t\t\t\tconst botId = \"botId\" in filter ? filter.botId : undefined;\n\t\t\t\t\t\t\treturn searchRawMessagesWithChroma({\n\t\t\t\t\t\t\t\tuserId: input.userId,\n\t\t\t\t\t\t\t\tqueryEmbedding,\n\t\t\t\t\t\t\t\tlimit,\n\t\t\t\t\t\t\t\tthreshold,\n\t\t\t\t\t\t\t\tbotId,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}),\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t\t\t.flat()\n\t\t\t\t\t.map(toMemoryResult);\n\t\t\t\tlogger.log?.(\"[memory-store] Raw message semantic search completed\", {\n\t\t\t\t\tbackend: \"chroma\",\n\t\t\t\t\tdimensions: queryEmbedding.length,\n\t\t\t\t\tcount: chromaHits.length,\n\t\t\t\t});\n\t\t\t\treturn chromaHits;\n\t\t\t} catch (error) {\n\t\t\t\tlogger.warn?.(\n\t\t\t\t\t\"[memory-store] Chroma raw message search failed; falling back to database search:\",\n\t\t\t\t\terror,\n\t\t\t\t);\n\t\t\t\t// fall through to the ANN/database search below\n\t\t\t}\n\t\t}\n\n\t\tif (typeof deps.searchRawMessagesAnn === \"function\") {\n\t\t\tconst rows = (\n\t\t\t\tawait Promise.all(\n\t\t\t\t\tfilters.map((filter) =>\n\t\t\t\t\t\tdeps.searchRawMessagesAnn!({\n\t\t\t\t\t\t\tuserId: input.userId,\n\t\t\t\t\t\t\tqueryEmbedding,\n\t\t\t\t\t\t\tlimit,\n\t\t\t\t\t\t\tthreshold,\n\t\t\t\t\t\t\tbotId: \"botId\" in filter ? filter.botId : undefined,\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t)\n\t\t\t\t.flat()\n\t\t\t\t.filter(isRawMemorySemanticResult)\n\t\t\t\t.map(toMemoryResult);\n\t\t\treturn rows;\n\t\t}\n\n\t\treturn [];\n\t}\n\n\tasync function searchRawMemorySemantically(\n\t\tinput: UnifiedMemorySearchInput,\n\t): Promise<UnifiedMemorySearchResult[]> {\n\t\tconst limit = clampUnifiedMemorySearchLimit(input.limit);\n\t\tconst threshold = clampUnifiedMemorySearchThreshold(input.threshold);\n\t\treturn runMemorySource(input, limit, threshold);\n\t}\n\n\treturn { searchUnifiedMemory, searchRawMemorySemantically };\n}\n","/**\n * @melandlabs/memory-store/http — HTTP server entry.\n *\n * Usage:\n * import { startHttpServer } from \"@melandlabs/memory-store/http\";\n * const { url, stop } = await startHttpServer({\n * port: 7421,\n * db: { getDb: () => drizzleDb() },\n * });\n *\n * Endpoints (all POST, JSON in/out):\n * GET /health → { ok: true }\n * POST /v1/search → UnifiedMemorySearchOutput\n * POST /v1/raw-messages → upsert raw messages (returns count)\n * GET /v1/raw-messages/:id → single raw message\n *\n * `POST /v1/raw-messages` supports two body keys beyond `userId` /\n * `messages[]`:\n *\n * - `embedOnInsert: true` — when set AND `unified.embedQuery` is wired\n * (i.e. the host passed `--embedding-provider local|openrouter` or\n * supplied its own embedder), the server fills in any message\n * whose `embedding` field is missing by calling `embedQuery`\n * against `message.content` server-side. This is what makes the\n * daemon usable end-to-end with `--memory-backend=sqlite-vec` and\n * bare curl POSTs — without this flag, the bin logs the warning\n * and the messages persist without an embedding (so ANN search\n * won't return them).\n *\n * The HTTP server speaks only to the raw-message + vector layers; it does\n * not expose RAG/insights cross-source search (callers wire those up\n * server-side or use the MCP server with a fully-wired store).\n */\n\nimport { serve } from \"@hono/node-server\";\nimport type { RawMessage } from \"@melandlabs/indexeddb/storage\";\nimport { Hono } from \"hono\";\nimport type { UnifiedSearchDeps } from \"./config\";\nimport type { MemoryStoreConfig } from \"./index\";\nimport { createUnifiedSearch } from \"./search/unified-search\";\nimport { upsertRawMessagesToChroma } from \"./storage/chroma-memory-index\";\nimport { createRawMessageStore } from \"./storage/raw-message-store\";\n\nexport interface StartHttpServerOptions extends MemoryStoreConfig {\n\t/** Port to bind. Defaults to 7421. */\n\tport?: number;\n\t/** Bind address. Defaults to 127.0.0.1 (loopback only — change to 0.0.0.0 for LAN). */\n\thost?: string;\n}\n\nexport interface StartedHttpServer {\n\turl: string;\n\tport: number;\n\tstop(): Promise<void>;\n}\n\ntype RawMessageUpsertFn = (input: { userId: string; messages: RawMessage[] }) => Promise<unknown>;\ntype RawMessageStoreFn = (messages: RawMessage[]) => Promise<number[]>;\ntype RawMessageGetFn = (messageId: string) => Promise<RawMessage | null | undefined>;\n\ninterface RawMessageManagerLike {\n\tupsertRawMessages?: RawMessageUpsertFn;\n\tstoreMessages?: RawMessageStoreFn;\n\tgetMessageById?: RawMessageGetFn;\n}\n\nasync function embedMissingMessages(messages: RawMessage[], deps: UnifiedSearchDeps): Promise<RawMessage[]> {\n\tif (typeof deps.embedQuery !== \"function\") {\n\t\treturn messages;\n\t}\n\tconst out: RawMessage[] = [];\n\tfor (const message of messages) {\n\t\tif (Array.isArray(message.embedding) && message.embedding.length > 0) {\n\t\t\tout.push(message);\n\t\t\tcontinue;\n\t\t}\n\t\tif (typeof message.content !== \"string\" || message.content.length === 0) {\n\t\t\tout.push(message);\n\t\t\tcontinue;\n\t\t}\n\t\tconst vector = await deps.embedQuery({\n\t\t\tuserId: message.userId,\n\t\t\tquery: message.content,\n\t\t});\n\t\tout.push({\n\t\t\t...message,\n\t\t\tembedding: vector,\n\t\t\tembeddingModel: message.embeddingModel ?? \"server\",\n\t\t\tembeddingDimensions: vector.length,\n\t\t\tembeddingUpdatedAt: Date.now(),\n\t\t});\n\t}\n\treturn out;\n}\n\nexport async function startHttpServer(options: StartHttpServerOptions = {}): Promise<StartedHttpServer> {\n\tconst port = options.port ?? Number.parseInt(process.env.MEMORY_HTTP_PORT ?? \"7421\", 10);\n\tconst host = options.host ?? process.env.MEMORY_HTTP_HOST ?? \"127.0.0.1\";\n\n\tconst rawStore = createRawMessageStore({\n\t\tenv: options.env,\n\t});\n\tconst search = createUnifiedSearch(options.unified);\n\n\tconst app = new Hono();\n\n\tapp.get(\"/health\", (c) => c.json({ ok: true, store: \"memory\", ts: Date.now() }));\n\n\tapp.post(\"/v1/search\", async (c) => {\n\t\tconst body = await c.req.json().catch(() => ({}));\n\t\tconst userId = typeof body.userId === \"string\" ? body.userId : null;\n\t\tconst query = typeof body.query === \"string\" ? body.query : \"\";\n\t\tif (!userId || !query) {\n\t\t\treturn c.json({ error: \"userId and query are required\" }, 400);\n\t\t}\n\t\tconst result = await search.searchUnifiedMemory({\n\t\t\tuserId,\n\t\t\tquery,\n\t\t\tsources: body.sources,\n\t\t\tlimit: body.limit,\n\t\t\tthreshold: body.threshold,\n\t\t\tbotIds: body.botIds,\n\t\t\tdocumentIds: body.documentIds,\n\t\t\tincludeArchivedInsights: body.includeArchivedInsights,\n\t\t\tauthToken: body.authToken,\n\t\t});\n\t\treturn c.json(result);\n\t});\n\n\tapp.post(\"/v1/raw-messages\", async (c) => {\n\t\tconst body = await c.req.json().catch(() => ({}));\n\t\tif (!Array.isArray(body.messages) || !body.userId) {\n\t\t\treturn c.json({ error: \"userId and messages[] required\" }, 400);\n\t\t}\n\t\tconst manager = (await rawStore.getManager()) as RawMessageManagerLike;\n\t\tconst incoming = body.messages as RawMessage[];\n\n\t\t// ── 1. Auto-embed messages that lack an embedding — but only when\n\t\t// the client explicitly opted in via `embedOnInsert: true`\n\t\t// AND an embedder is wired into `unified.*`. We deliberately\n\t\t// don't auto-embed without the opt-in: hosts that send\n\t\t// pre-embedded rows from a sidecar shouldn't pay the cost of\n\t\t// a server-side inference call per message.\n\t\tconst messages =\n\t\t\tbody.embedOnInsert === true\n\t\t\t\t? await embedMissingMessages(\n\t\t\t\t\t\tincoming.map((m) => ({ ...m, userId: m.userId ?? body.userId })),\n\t\t\t\t\t\toptions.unified ?? {},\n\t\t\t\t\t)\n\t\t\t\t: incoming.map((m) => ({ ...m, userId: m.userId ?? body.userId }));\n\n\t\t// ── 2. Insert into the active backend. Host-supplied Postgres\n\t\t// factories take precedence (their `upsertRawMessages` is a\n\t\t// richer upsert); the default SQLite manager falls through\n\t\t// to `storeMessages`, which is an idempotent INSERT … ON\n\t\t// CONFLICT(message_id) DO UPDATE.\n\t\tlet result: unknown;\n\t\tif (typeof manager.upsertRawMessages === \"function\") {\n\t\t\tresult = await manager.upsertRawMessages({\n\t\t\t\tuserId: body.userId,\n\t\t\t\tmessages,\n\t\t\t});\n\t\t} else if (typeof manager.storeMessages === \"function\") {\n\t\t\tconst ids = await manager.storeMessages(messages);\n\t\t\tresult = { inserted: ids.length, ids };\n\t\t} else {\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\terror: \"active raw-message manager exposes neither upsertRawMessages nor storeMessages\",\n\t\t\t\t},\n\t\t\t\t500,\n\t\t\t);\n\t\t}\n\n\t\t// ── 3. Parallel chroma upsert, best-effort. The legacy\n\t\t// `isRawMessageChromaEnabled()` env path still applies.\n\t\ttry {\n\t\t\tawait upsertRawMessagesToChroma(messages as never);\n\t\t} catch (error) {\n\t\t\tconsole.warn(\"[memory-store/http] chroma upsert failed:\", error);\n\t\t}\n\n\t\treturn c.json({ ok: true, count: messages.length, result });\n\t});\n\n\tapp.get(\"/v1/raw-messages/:id\", async (c) => {\n\t\tconst id = c.req.param(\"id\");\n\t\tconst userId = c.req.query(\"userId\");\n\t\tif (!userId) return c.json({ error: \"userId query param required\" }, 400);\n\t\tconst manager = (await rawStore.getManager()) as RawMessageManagerLike;\n\t\tconst row = await manager.getMessageById?.(id);\n\t\tif (!row) return c.json({ error: \"not found\" }, 404);\n\t\treturn c.json({ message: row });\n\t});\n\n\tconst server = serve({ fetch: app.fetch, port, hostname: host });\n\n\treturn {\n\t\turl: `http://${host}:${port}`,\n\t\tport,\n\t\tasync stop() {\n\t\t\tawait rawStore.close();\n\t\t\tserver.close();\n\t\t},\n\t};\n}\n\nexport type { MemoryStoreConfig };\n"]}
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/storage/chroma-memory-index.ts","../src/storage/postgres-raw-message-factory.ts","../src/storage/sqlite-raw-message-store.ts","../src/storage/raw-message-store.ts","../src/search/utilities.ts","../src/search/unified-search.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Chroma-backed raw-message + insight vector index.\n *\n * Detects the active backend at call time (defaults to sqlite-vec if\n * no env override is present). The actual URL/collection values come\n * from env vars so the standalone memory daemon can pick them up\n * without an injected config.\n */\n\nimport { buildMemoryRecordEmbeddingDocument } from \"@melandlabs/ai/memory\";\nimport { ChromaVectorStore } from \"@melandlabs/rag\";\nimport type { DocumentChunk } from \"@melandlabs/rag/vector-service\";\n\nimport { type RawMessage, rawMessageToMemoryRecord } from \"../contracts\";\n\nconst DEFAULT_RAW_MESSAGES_COLLECTION = \"opencontext_raw_messages\";\nconst DEFAULT_INSIGHTS_COLLECTION = \"opencontext_insights\";\nconst RAW_VECTOR_BACKEND_ENV_KEYS = [\n\t\"RAW_MESSAGE_VECTOR_STORE_BACKEND\",\n\t\"MEMORY_VECTOR_STORE_BACKEND\",\n\t\"VECTOR_STORE_BACKEND\",\n] as const;\nconst INSIGHT_VECTOR_BACKEND_ENV_KEYS = [\n\t\"INSIGHT_VECTOR_STORE_BACKEND\",\n\t\"MEMORY_VECTOR_STORE_BACKEND\",\n\t\"VECTOR_STORE_BACKEND\",\n] as const;\n\nexport interface ChromaInsightVectorInput {\n\tinsightId: string;\n\tuserId: string;\n\tbotId: string;\n\tcontent: string;\n\tcontentHash: string;\n\tembedding: number[];\n\tembeddingModel: string;\n\tembeddingDimensions: number;\n\ttitle?: unknown;\n\tdescription?: unknown;\n\ttaskLabel?: unknown;\n\timportance?: unknown;\n\turgency?: unknown;\n\tplatform?: unknown;\n\taccount?: unknown;\n\ttime?: unknown;\n\tarchived?: unknown;\n}\n\nexport interface ChromaInsightSearchResult {\n\tid: string;\n\tcontent: string;\n\tsimilarity: number;\n\tmetadata: {\n\t\tbotId: string;\n\t\ttitle: string;\n\t\tdescription: string;\n\t\ttaskLabel: string;\n\t\timportance: string;\n\t\turgency: string;\n\t\tplatform: string | null;\n\t\taccount: string | null;\n\t\ttime: Date | null;\n\t\tembeddingModel: string;\n\t\tembeddingDimensions: number;\n\t\tcontentHash: string;\n\t};\n}\n\nfunction getBackend(keys: readonly string[]): string {\n\tfor (const key of keys) {\n\t\tconst value = process.env[key]?.trim().toLowerCase();\n\t\tif (value) {\n\t\t\treturn value;\n\t\t}\n\t}\n\treturn \"\";\n}\n\nexport function isRawMessageChromaEnabled(): boolean {\n\treturn getBackend(RAW_VECTOR_BACKEND_ENV_KEYS) === \"chroma\";\n}\n\nexport function isInsightChromaEnabled(): boolean {\n\treturn getBackend(INSIGHT_VECTOR_BACKEND_ENV_KEYS) === \"chroma\";\n}\n\nfunction getRawMessagesCollectionName(): string {\n\treturn (\n\t\tprocess.env.CHROMA_RAW_MESSAGES_COLLECTION ||\n\t\tprocess.env.CHROMA_MEMORY_COLLECTION ||\n\t\tDEFAULT_RAW_MESSAGES_COLLECTION\n\t);\n}\n\nfunction getInsightsCollectionName(): string {\n\treturn process.env.CHROMA_INSIGHTS_COLLECTION || DEFAULT_INSIGHTS_COLLECTION;\n}\n\nfunction getChromaStore(collectionName: string): ChromaVectorStore {\n\treturn new ChromaVectorStore({\n\t\turl: process.env.CHROMA_URL,\n\t\tcollectionName,\n\t});\n}\n\nfunction normalizeTimestampToMs(value: number | undefined): number {\n\tif (!Number.isFinite(value)) {\n\t\treturn 0;\n\t}\n\tif ((value as number) < 1e11) {\n\t\treturn Math.floor((value as number) * 1000);\n\t}\n\treturn Math.floor(value as number);\n}\n\nfunction toStringValue(value: unknown, fallback = \"\"): string {\n\treturn typeof value === \"string\" && value.trim().length > 0 ? value.trim() : fallback;\n}\n\nfunction toNullableString(value: unknown): string | null {\n\treturn typeof value === \"string\" && value.trim().length > 0 ? value.trim() : null;\n}\n\nfunction toBooleanValue(value: unknown): boolean {\n\treturn value === true || value === \"true\" || value === 1 || value === \"1\";\n}\n\nfunction toDateValue(value: unknown): Date | null {\n\tif (value instanceof Date) {\n\t\treturn Number.isNaN(value.getTime()) ? null : value;\n\t}\n\tif (typeof value === \"string\" || typeof value === \"number\") {\n\t\tconst date = new Date(value);\n\t\treturn Number.isNaN(date.getTime()) ? null : date;\n\t}\n\treturn null;\n}\n\nfunction rawMessageToChunk(message: RawMessage): DocumentChunk | null {\n\tif (!message.embedding || message.embedding.length === 0) {\n\t\treturn null;\n\t}\n\n\tconst record = rawMessageToMemoryRecord(message);\n\tconst document = buildMemoryRecordEmbeddingDocument(record);\n\tif (!document.content) {\n\t\treturn null;\n\t}\n\n\treturn {\n\t\tid: message.messageId,\n\t\tdocumentId: message.messageId,\n\t\tcontent: document.content,\n\t\tembedding: message.embedding,\n\t\tmetadata: {\n\t\t\tsourceType: \"raw_message\",\n\t\t\tuserId: message.userId,\n\t\t\tplatform: message.platform,\n\t\t\tbotId: message.botId,\n\t\t\tchannel: message.channel,\n\t\t\tperson: message.person,\n\t\t\ttimestamp: normalizeTimestampToMs(message.timestamp),\n\t\t\tmemoryStage: message.memoryStage,\n\t\t\tembeddingModel: message.embeddingModel,\n\t\t\tembeddingDimensions: message.embeddingDimensions,\n\t\t\tcontentHash: message.embeddingContentHash,\n\t\t\tarchived: Boolean(message.archivedAt),\n\t\t\trole: typeof message.metadata?.role === \"string\" ? message.metadata.role : undefined,\n\t\t},\n\t};\n}\n\nexport async function upsertRawMessagesToChroma(messages: RawMessage[]): Promise<number> {\n\tif (!isRawMessageChromaEnabled() || messages.length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst chunks = messages.map(rawMessageToChunk).filter((chunk): chunk is DocumentChunk => chunk !== null);\n\tif (chunks.length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst store = getChromaStore(getRawMessagesCollectionName());\n\tawait store.addChunks(chunks);\n\treturn chunks.length;\n}\n\nexport async function searchRawMessagesWithChroma(input: {\n\tuserId: string;\n\tqueryEmbedding: number[];\n\tlimit: number;\n\tthreshold: number;\n\tbotId?: string;\n}): Promise<\n\tArray<{\n\t\tid: string;\n\t\tcontent: string;\n\t\tsimilarity: number;\n\t\tmetadata: Record<string, unknown>;\n\t}>\n> {\n\tif (!isRawMessageChromaEnabled() || input.queryEmbedding.length === 0) {\n\t\treturn [];\n\t}\n\n\tconst store = getChromaStore(getRawMessagesCollectionName());\n\tconst results = await store.similaritySearch(\n\t\tinput.queryEmbedding,\n\t\tMath.max(input.limit * 5, input.limit),\n\t\tinput.userId,\n\t);\n\n\treturn results\n\t\t.filter((result) => {\n\t\t\tconst metadata = result.metadata ?? {};\n\t\t\tif (toBooleanValue(metadata.archived)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (input.botId && metadata.botId !== input.botId) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn result.score >= input.threshold;\n\t\t})\n\t\t.map((result) => ({\n\t\t\tid: result.id,\n\t\t\tcontent: result.content,\n\t\t\tsimilarity: result.score,\n\t\t\tmetadata: result.metadata ?? {},\n\t\t}))\n\t\t.slice(0, input.limit);\n}\n\nexport async function upsertInsightsToChroma(insights: ChromaInsightVectorInput[]): Promise<number> {\n\tif (!isInsightChromaEnabled() || insights.length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst chunks = insights\n\t\t.filter(\n\t\t\t(item) => item.content.trim().length > 0 && Array.isArray(item.embedding) && item.embedding.length > 0,\n\t\t)\n\t\t.map<DocumentChunk>((item) => ({\n\t\t\tid: item.insightId,\n\t\t\tdocumentId: item.insightId,\n\t\t\tcontent: item.content,\n\t\t\tembedding: item.embedding,\n\t\t\tmetadata: {\n\t\t\t\tsourceType: \"insight\",\n\t\t\t\tinsightId: item.insightId,\n\t\t\t\tuserId: item.userId,\n\t\t\t\tbotId: item.botId,\n\t\t\t\ttitle: toStringValue(item.title),\n\t\t\t\tdescription: toStringValue(item.description),\n\t\t\t\ttaskLabel: toStringValue(item.taskLabel),\n\t\t\t\timportance: toStringValue(item.importance),\n\t\t\t\turgency: toStringValue(item.urgency),\n\t\t\t\tplatform: toNullableString(item.platform),\n\t\t\t\taccount: toNullableString(item.account),\n\t\t\t\ttime: toDateValue(item.time)?.toISOString(),\n\t\t\t\tembeddingModel: item.embeddingModel,\n\t\t\t\tembeddingDimensions: item.embeddingDimensions,\n\t\t\t\tcontentHash: item.contentHash,\n\t\t\t\tarchived: toBooleanValue(item.archived),\n\t\t\t},\n\t\t}));\n\n\tif (chunks.length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst store = getChromaStore(getInsightsCollectionName());\n\tawait store.addChunks(chunks);\n\treturn chunks.length;\n}\n\nexport async function searchInsightsWithChroma(input: {\n\tuserId: string;\n\tqueryEmbedding: number[];\n\tlimit: number;\n\tthreshold: number;\n\tbotIds?: string[];\n\tincludeArchived?: boolean;\n}): Promise<ChromaInsightSearchResult[]> {\n\tif (!isInsightChromaEnabled() || input.queryEmbedding.length === 0) {\n\t\treturn [];\n\t}\n\n\tconst botIdSet = input.botIds && input.botIds.length > 0 ? new Set(input.botIds) : null;\n\tconst store = getChromaStore(getInsightsCollectionName());\n\tconst results = await store.similaritySearch(\n\t\tinput.queryEmbedding,\n\t\tMath.max(input.limit * 5, input.limit),\n\t\tinput.userId,\n\t);\n\n\treturn results\n\t\t.filter((result) => {\n\t\t\tconst metadata = result.metadata ?? {};\n\t\t\tif (!input.includeArchived && toBooleanValue(metadata.archived)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (botIdSet && !botIdSet.has(String(metadata.botId ?? \"\"))) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn result.score >= input.threshold;\n\t\t})\n\t\t.map((result) => {\n\t\t\tconst metadata = result.metadata ?? {};\n\t\t\treturn {\n\t\t\t\tid: result.id,\n\t\t\t\tcontent: result.content,\n\t\t\t\tsimilarity: result.score,\n\t\t\t\tmetadata: {\n\t\t\t\t\tbotId: toStringValue(metadata.botId),\n\t\t\t\t\ttitle: toStringValue(metadata.title),\n\t\t\t\t\tdescription: toStringValue(metadata.description),\n\t\t\t\t\ttaskLabel: toStringValue(metadata.taskLabel),\n\t\t\t\t\timportance: toStringValue(metadata.importance),\n\t\t\t\t\turgency: toStringValue(metadata.urgency),\n\t\t\t\t\tplatform: toNullableString(metadata.platform),\n\t\t\t\t\taccount: toNullableString(metadata.account),\n\t\t\t\t\ttime: toDateValue(metadata.time),\n\t\t\t\t\tembeddingModel: toStringValue(metadata.embeddingModel),\n\t\t\t\t\tembeddingDimensions: Number(metadata.embeddingDimensions ?? 0),\n\t\t\t\t\tcontentHash: toStringValue(metadata.contentHash),\n\t\t\t\t},\n\t\t\t};\n\t\t})\n\t\t.slice(0, input.limit);\n}\n","/**\n * Lazy registration slot for the host's Postgres-backed raw message\n * manager. The actual `PostgresRawMessageManager` implementation lives\n * in the host application because it owns the schema-bound Drizzle\n * table references.\n *\n * The package ships this factory so consumers can wire up their own\n * postgres implementation without forcing the package to take a\n * hard dependency on Drizzle schema files.\n */\n\nimport type { MemoryStoreEnv } from \"../config\";\n\nexport interface PostgresRawMessageManagerLike {\n\tinit?(): Promise<void>;\n\tclose?(): Promise<void>;\n\tupsertRawMessages?(input: {\n\t\tuserId: string;\n\t\tmessages: unknown[];\n\t}): Promise<unknown>;\n\tgetMessageById?(input: {\n\t\tuserId: string;\n\t\tmessageId: string;\n\t}): Promise<unknown>;\n\tsearchMessagesSemantically?(input: {\n\t\tuserId: string;\n\t\tqueryEmbedding: number[];\n\t\tembeddingModel?: string;\n\t\tlimit?: number;\n\t\tscanLimit?: number;\n\t\tthreshold?: number;\n\t\tincludeArchived?: boolean;\n\t\tincludeDeprecated?: boolean;\n\t\tplatform?: string;\n\t\tbotId?: string;\n\t\tchannel?: string;\n\t\tperson?: string;\n\t\tstartTime?: number;\n\t\tendTime?: number;\n\t}): Promise<unknown[]>;\n}\n\nexport type PostgresFactoryFn = (env?: MemoryStoreEnv) => Promise<PostgresRawMessageManagerLike>;\n\nlet factory: PostgresFactoryFn | null = null;\n\nexport function registerPostgresFactory(fn: PostgresFactoryFn): void {\n\tfactory = fn;\n}\n\nexport function clearPostgresFactory(): void {\n\tfactory = null;\n}\n\nexport async function resolvePostgresFactory(\n\tenv?: MemoryStoreEnv,\n): Promise<PostgresRawMessageManagerLike | null> {\n\tif (!factory) return null;\n\treturn await factory(env);\n}\n\nexport function hasPostgresFactory(): boolean {\n\treturn factory !== null;\n}\n","/**\n * SQLite-backed raw message store.\n *\n * Singleton manager. Local SQLite is the default backend for the memory\n * store — no host-mode check, no env-var opt-in. The DB path is resolved\n * from (in order):\n * 1. `MEMORY_STORE_DB_PATH` — recommended knob\n * 2. `~/.opencontext/memory/store.db` — last-resort default\n *\n * The `env?` parameter on the exported functions is kept for back-compat\n * with the historical `MemoryStoreEnv` interface but is no longer read.\n */\n\nimport { mkdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { SQLiteRawMessageManager } from \"@melandlabs/sqlite\";\nimport type { MemoryStoreEnv } from \"../config\";\nimport { isRawMessageChromaEnabled } from \"./chroma-memory-index\";\n\nlet manager: SQLiteRawMessageManager | null = null;\n\nconst DEFAULT_SQLITE_PATH = join(homedir(), \".opencontext\", \"memory\", \"store.db\");\n\n/**\n * Resolve the SQLite DB file path from env vars. Exposed so other storage\n * layers (vector index) can stay in sync with the same default.\n */\nexport function resolveSQLiteRawMessageDbPath(): string {\n\tconst fromEnv = process.env.MEMORY_STORE_DB_PATH?.trim();\n\treturn fromEnv && fromEnv.length > 0 ? fromEnv : DEFAULT_SQLITE_PATH;\n}\n\n/**\n * Local SQLite is the default. Every host (Tauri, server, CLI, tests) can\n * open the manager; the only failure mode is filesystem write permission.\n */\nexport function isSQLiteRawMessageStorageAvailable(_env?: MemoryStoreEnv): boolean {\n\treturn true;\n}\n\nexport async function getSQLiteRawMessageManager(_env?: MemoryStoreEnv): Promise<SQLiteRawMessageManager> {\n\tif (!manager) {\n\t\tconst dbPath = resolveSQLiteRawMessageDbPath();\n\t\tmkdirSync(dirname(dbPath), { recursive: true });\n\t\tmanager = new SQLiteRawMessageManager({\n\t\t\tdbPath,\n\t\t\tenableVectorSearch: !isRawMessageChromaEnabled(),\n\t\t});\n\t\tawait manager.init();\n\t}\n\n\treturn manager;\n}\n\nexport async function closeSQLiteRawMessageManager(): Promise<void> {\n\tif (!manager) {\n\t\treturn;\n\t}\n\tawait manager.close();\n\tmanager = null;\n}\n\n/**\n * Test-only: reset the singleton. Used by vitest between test cases.\n */\nexport function __resetSQLiteRawMessageManagerForTests(): void {\n\tmanager = null;\n}\n\n// Kept for back-compat with the historical `MemoryStoreEnv` interface.\n// The resolved env is no longer read by the SQLite layer, but the symbol\n// stays exported so external code that still calls `resolveEnv` compiles.\nfunction resolveEnv(_env?: MemoryStoreEnv): MemoryStoreEnv {\n\treturn {};\n}\n","/**\n * Top-level raw-message store facade.\n *\n * Backend selection is env-var driven:\n *\n * - `OPENCONTEXT_MEMORY_STORE_BACKEND=postgres` → use the host's\n * registered Postgres factory. A factory MUST be registered first\n * via `registerPostgresFactory()`; otherwise this throws a clear\n * error rather than silently falling back.\n * - Any other value (including unset) → local SQLite. The default\n * works in every host environment with no extra configuration.\n *\n * The facade exposes the common `RawMessageStorageManager` contract plus\n * a typed `searchMessagesSemantically` extension when present.\n */\n\nimport type { RawMessageStorageManager } from \"@melandlabs/indexeddb/storage\";\nimport type { MemoryStoreConfig, MemoryStoreEnv } from \"../config\";\nimport { hasPostgresFactory, resolvePostgresFactory } from \"./postgres-raw-message-factory\";\nimport { closeSQLiteRawMessageManager, getSQLiteRawMessageManager } from \"./sqlite-raw-message-store\";\n\nexport type RawMessageStorageBackend = \"sqlite\" | \"postgres\";\n\nexport type RawMessageStorageManagerWithSearch = RawMessageStorageManager & {\n\tsearchMessagesSemantically?: (input: {\n\t\tuserId: string;\n\t\tqueryEmbedding: number[];\n\t\tembeddingModel?: string;\n\t\tlimit?: number;\n\t\tscanLimit?: number;\n\t\tthreshold?: number;\n\t\tincludeArchived?: boolean;\n\t\tplatform?: string;\n\t\tbotId?: string;\n\t\tchannel?: string;\n\t\tperson?: string;\n\t\tstartTime?: number;\n\t\tendTime?: number;\n\t}) => Promise<unknown[]>;\n};\n\nexport interface CreateRawMessageStoreOptions {\n\tenv?: MemoryStoreEnv;\n}\n\nexport interface RawMessageStore {\n\tgetManager(): Promise<RawMessageStorageManagerWithSearch>;\n\tgetBackend(): RawMessageStorageBackend;\n\tisAvailable(): boolean;\n\tclose(): Promise<void>;\n}\n\nfunction resolveBackend(env: MemoryStoreEnv | undefined): RawMessageStorageBackend {\n\tconst explicit = process.env.OPENCONTEXT_MEMORY_STORE_BACKEND?.trim().toLowerCase();\n\tif (explicit === \"postgres\") return \"postgres\";\n\t// Any other value — including the default \"sqlite\", an unknown value,\n\t// or the env var being unset — falls through to local SQLite.\n\treturn \"sqlite\";\n}\n\nfunction resolveEnv(_env?: MemoryStoreEnv): MemoryStoreEnv {\n\treturn {};\n}\n\nexport function createRawMessageStore(options: CreateRawMessageStoreOptions = {}): RawMessageStore {\n\tconst env = resolveEnv(options.env);\n\n\treturn {\n\t\tgetBackend(): RawMessageStorageBackend {\n\t\t\treturn resolveBackend(env);\n\t\t},\n\t\tisAvailable(): boolean {\n\t\t\t// SQLite is always available; postgres is only available when the\n\t\t\t// env var asks for it AND a factory has been registered.\n\t\t\treturn resolveBackend(env) === \"sqlite\" || hasPostgresFactory();\n\t\t},\n\t\tasync getManager(): Promise<RawMessageStorageManagerWithSearch> {\n\t\t\tif (resolveBackend(env) === \"postgres\") {\n\t\t\t\tconst pg = await resolvePostgresFactory(env);\n\t\t\t\tif (!pg) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\"OPENCONTEXT_MEMORY_STORE_BACKEND=postgres but no Postgres factory is registered. \" +\n\t\t\t\t\t\t\t\"Call registerPostgresFactory() at startup, or unset the env var to use the default SQLite backend.\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn pg as unknown as RawMessageStorageManagerWithSearch;\n\t\t\t}\n\t\t\treturn (await getSQLiteRawMessageManager(env)) as unknown as RawMessageStorageManagerWithSearch;\n\t\t},\n\t\tasync close(): Promise<void> {\n\t\t\t// The sqlite singleton is process-wide, so close regardless of the\n\t\t\t// env var's current value — the previous call may have used it.\n\t\t\tawait closeSQLiteRawMessageManager();\n\t\t},\n\t};\n}\n\n// Module-level singleton so existing call sites that imported the\n// legacy `getRawMessageManager()` keep working without a refactor.\nlet moduleStore: RawMessageStore | null = null;\nlet moduleConfig: MemoryStoreConfig | null = null;\n\nexport function configureRawMessageStore(config: MemoryStoreConfig): RawMessageStore {\n\tmoduleConfig = config;\n\tmoduleStore = createRawMessageStore({ env: config.env });\n\treturn moduleStore;\n}\n\nexport function getRawMessageStorageBackend(): RawMessageStorageBackend {\n\tif (!moduleStore) {\n\t\tmoduleStore = createRawMessageStore({ env: moduleConfig?.env });\n\t}\n\treturn moduleStore.getBackend();\n}\n\nexport function isRawMessageStorageAvailable(): boolean {\n\tif (!moduleStore) {\n\t\tmoduleStore = createRawMessageStore({ env: moduleConfig?.env });\n\t}\n\treturn moduleStore.isAvailable();\n}\n\nexport async function getRawMessageManager(): Promise<RawMessageStorageManagerWithSearch> {\n\tif (!moduleStore) {\n\t\tmoduleStore = createRawMessageStore({ env: moduleConfig?.env });\n\t}\n\treturn moduleStore.getManager();\n}\n\nexport async function closeRawMessageStore(): Promise<void> {\n\tif (!moduleStore) return;\n\tawait moduleStore.close();\n\tmoduleStore = null;\n}\n","/**\n * Pure helpers used by the unified memory search pipeline.\n *\n * Kept side-effect free so they can be reused by tests, MCP tools,\n * and the HTTP daemon without pulling in any of the heavier\n * storage/search implementations.\n */\n\nexport type UnifiedMemorySearchSource = \"memory\" | \"insights\" | \"knowledge\";\n\nexport interface UnifiedMemorySearchWarning {\n\tsource: UnifiedMemorySearchSource;\n\tcode: string;\n\tmessage: string;\n}\n\nexport interface UnifiedMemorySearchInput {\n\tuserId: string;\n\tquery: string;\n\tsources?: UnifiedMemorySearchSource[];\n\tlimit?: number;\n\tthreshold?: number;\n\tauthToken?: string;\n\tincludeArchivedInsights?: boolean;\n\tbotIds?: string[];\n\tdocumentIds?: string[];\n}\n\nexport interface UnifiedMemorySearchResult {\n\ttype: \"memory\" | \"insight\" | \"knowledge\";\n\tid: string;\n\tcontent: string;\n\tsimilarity: number;\n\tmetadata: Record<string, unknown>;\n}\n\nexport interface UnifiedMemorySearchOutput {\n\tquery: string;\n\tsources: UnifiedMemorySearchSource[];\n\tresults: UnifiedMemorySearchResult[];\n\tcount: number;\n\twarnings: UnifiedMemorySearchWarning[];\n}\n\nconst DEFAULT_LIMIT = 10;\nconst DEFAULT_THRESHOLD = 0.7;\nconst DEFAULT_SOURCES: UnifiedMemorySearchSource[] = [\"memory\", \"insights\", \"knowledge\"];\nconst SOURCE_SET = new Set<UnifiedMemorySearchSource>(DEFAULT_SOURCES);\n\nexport function normalizeUnifiedMemorySearchSources(sources: unknown): UnifiedMemorySearchSource[] {\n\tif (!Array.isArray(sources) || sources.length === 0) {\n\t\treturn [...DEFAULT_SOURCES];\n\t}\n\n\tconst normalized = sources\n\t\t.filter((source): source is string => typeof source === \"string\")\n\t\t.map((source) => source.trim().toLowerCase())\n\t\t.filter((source): source is UnifiedMemorySearchSource =>\n\t\t\tSOURCE_SET.has(source as UnifiedMemorySearchSource),\n\t\t);\n\n\treturn normalized.length > 0 ? Array.from(new Set(normalized)) : [...DEFAULT_SOURCES];\n}\n\nexport function clampUnifiedMemorySearchLimit(limit: unknown): number {\n\tconst parsed = typeof limit === \"number\" ? limit : Number(limit ?? DEFAULT_LIMIT);\n\tif (!Number.isFinite(parsed)) {\n\t\treturn DEFAULT_LIMIT;\n\t}\n\treturn Math.min(50, Math.max(1, Math.floor(parsed)));\n}\n\nexport function clampUnifiedMemorySearchThreshold(threshold: unknown): number {\n\tconst parsed = typeof threshold === \"number\" ? threshold : Number(threshold ?? DEFAULT_THRESHOLD);\n\tif (!Number.isFinite(parsed)) {\n\t\treturn DEFAULT_THRESHOLD;\n\t}\n\treturn Math.min(1, Math.max(-1, parsed));\n}\n\nexport function mergeUnifiedMemorySearchResults(\n\tresults: UnifiedMemorySearchResult[],\n\tlimit: number,\n): UnifiedMemorySearchResult[] {\n\treturn [...results]\n\t\t.sort((a, b) => {\n\t\t\tconst scoreDelta = b.similarity - a.similarity;\n\t\t\tif (scoreDelta !== 0) {\n\t\t\t\treturn scoreDelta;\n\t\t\t}\n\t\t\treturn a.type.localeCompare(b.type) || a.id.localeCompare(b.id);\n\t\t})\n\t\t.slice(0, limit);\n}\n\nexport function toKnowledgeResult(result: {\n\tchunkId: string;\n\tdocumentId: string;\n\tdocumentName: string;\n\tcontent: string;\n\tsimilarity: number;\n\tchunkIndex: number;\n}): UnifiedMemorySearchResult {\n\treturn {\n\t\ttype: \"knowledge\",\n\t\tid: result.chunkId,\n\t\tcontent: result.content,\n\t\tsimilarity: result.similarity,\n\t\tmetadata: {\n\t\t\tdocumentId: result.documentId,\n\t\t\tdocumentName: result.documentName,\n\t\t\tchunkIndex: result.chunkIndex,\n\t\t},\n\t};\n}\n\nexport function toMemoryResult(result: {\n\tid: string;\n\tcontent: string;\n\tsimilarity: number;\n\tmetadata: Record<string, unknown>;\n}): UnifiedMemorySearchResult {\n\treturn {\n\t\ttype: \"memory\",\n\t\tid: result.id,\n\t\tcontent: result.content,\n\t\tsimilarity: result.similarity,\n\t\tmetadata: result.metadata,\n\t};\n}\n\nexport function isRawMemorySemanticResult(result: unknown): result is {\n\tid: string;\n\tcontent: string;\n\tsimilarity: number;\n\tmetadata: Record<string, unknown>;\n} {\n\tif (!result || typeof result !== \"object\") {\n\t\treturn false;\n\t}\n\tconst item = result as Record<string, unknown>;\n\treturn (\n\t\ttypeof item.id === \"string\" &&\n\t\ttypeof item.content === \"string\" &&\n\t\ttypeof item.similarity === \"number\" &&\n\t\tBoolean(item.metadata) &&\n\t\ttypeof item.metadata === \"object\"\n\t);\n}\n","/**\n * Unified semantic search facade.\n *\n * Cross-source search over raw messages (always), insights, and\n * uploaded knowledge documents. The host wires up the cross-domain\n * dependencies via `UnifiedSearchDeps` so this module stays\n * framework-agnostic.\n */\n\nimport type { UnifiedSearchDeps } from \"../config\";\nimport { isRawMessageChromaEnabled, searchRawMessagesWithChroma } from \"../storage/chroma-memory-index\";\nimport { isRawMessageStorageAvailable } from \"../storage/raw-message-store\";\nimport {\n\ttype UnifiedMemorySearchInput,\n\ttype UnifiedMemorySearchOutput,\n\ttype UnifiedMemorySearchResult,\n\ttype UnifiedMemorySearchWarning,\n\tclampUnifiedMemorySearchLimit,\n\tclampUnifiedMemorySearchThreshold,\n\tisRawMemorySemanticResult,\n\tmergeUnifiedMemorySearchResults,\n\tnormalizeUnifiedMemorySearchSources,\n\ttoKnowledgeResult,\n\ttoMemoryResult,\n} from \"./utilities\";\n\nexport type {\n\tUnifiedMemorySearchInput,\n\tUnifiedMemorySearchOutput,\n\tUnifiedMemorySearchResult,\n\tUnifiedMemorySearchSource,\n\tUnifiedMemorySearchWarning,\n} from \"./utilities\";\n\nexport {\n\tclampUnifiedMemorySearchLimit,\n\tclampUnifiedMemorySearchThreshold,\n\tisRawMemorySemanticResult,\n\tmergeUnifiedMemorySearchResults,\n\tnormalizeUnifiedMemorySearchSources,\n\ttoKnowledgeResult,\n\ttoMemoryResult,\n} from \"./utilities\";\n\nexport interface UnifiedSearch {\n\tsearchUnifiedMemory(input: UnifiedMemorySearchInput): Promise<UnifiedMemorySearchOutput>;\n\tsearchRawMemorySemantically(input: UnifiedMemorySearchInput): Promise<UnifiedMemorySearchResult[]>;\n}\n\nexport function createUnifiedSearch(deps: UnifiedSearchDeps = {}): UnifiedSearch {\n\tconst logger = (deps as { logger?: Console }).logger ?? console;\n\n\tasync function searchUnifiedMemory(input: UnifiedMemorySearchInput): Promise<UnifiedMemorySearchOutput> {\n\t\tconst query = input.query.trim();\n\t\tconst sources = normalizeUnifiedMemorySearchSources(input.sources);\n\t\tconst limit = clampUnifiedMemorySearchLimit(input.limit);\n\t\tconst threshold = clampUnifiedMemorySearchThreshold(input.threshold);\n\t\tconst warnings: UnifiedMemorySearchWarning[] = [];\n\t\tconst results: UnifiedMemorySearchResult[] = [];\n\n\t\tif (!query) {\n\t\t\treturn {\n\t\t\t\tquery,\n\t\t\t\tsources,\n\t\t\t\tresults: [],\n\t\t\t\tcount: 0,\n\t\t\t\twarnings,\n\t\t\t};\n\t\t}\n\n\t\tif (sources.includes(\"memory\")) {\n\t\t\tif (isRawMessageStorageAvailable()) {\n\t\t\t\ttry {\n\t\t\t\t\tconst memoryHits = await runMemorySource(input, limit, threshold);\n\t\t\t\t\tresults.push(...memoryHits);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tlogger.warn?.(\"[memory-store] memory source failed:\", error);\n\t\t\t\t\twarnings.push({\n\t\t\t\t\t\tsource: \"memory\",\n\t\t\t\t\t\tcode: \"memory_search_failed\",\n\t\t\t\t\t\tmessage: (error as Error).message ?? \"memory_search_failed\",\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twarnings.push({\n\t\t\t\t\tsource: \"memory\",\n\t\t\t\t\tcode: \"raw_message_storage_unavailable\",\n\t\t\t\t\tmessage: \"Raw memory storage is not available in this environment.\",\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tif (sources.includes(\"insights\") && typeof deps.searchInsights === \"function\") {\n\t\t\ttry {\n\t\t\t\tconst insightHits = await deps.searchInsights({\n\t\t\t\t\tuserId: input.userId,\n\t\t\t\t\tquery: input.query,\n\t\t\t\t\tlimit,\n\t\t\t\t\tthreshold,\n\t\t\t\t\tbotIds: input.botIds,\n\t\t\t\t\tincludeArchived: input.includeArchivedInsights,\n\t\t\t\t\tauthToken: input.authToken,\n\t\t\t\t});\n\t\t\t\tfor (const hit of insightHits) {\n\t\t\t\t\tresults.push({\n\t\t\t\t\t\ttype: \"insight\",\n\t\t\t\t\t\tid: hit.id,\n\t\t\t\t\t\tcontent: hit.content,\n\t\t\t\t\t\tsimilarity: hit.similarity,\n\t\t\t\t\t\tmetadata: hit.metadata,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tlogger.warn?.(\"[memory-store] insights source failed:\", error);\n\t\t\t\twarnings.push({\n\t\t\t\t\tsource: \"insights\",\n\t\t\t\t\tcode: \"insights_search_failed\",\n\t\t\t\t\tmessage: (error as Error).message ?? \"insights_search_failed\",\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (sources.includes(\"insights\")) {\n\t\t\twarnings.push({\n\t\t\t\tsource: \"insights\",\n\t\t\t\tcode: \"insights_search_not_configured\",\n\t\t\t\tmessage: \"Insights search is not configured for this host.\",\n\t\t\t});\n\t\t}\n\n\t\tif (sources.includes(\"knowledge\") && typeof deps.searchKnowledge === \"function\") {\n\t\t\ttry {\n\t\t\t\tconst knowledgeHits = await deps.searchKnowledge({\n\t\t\t\t\tuserId: input.userId,\n\t\t\t\t\tquery: input.query,\n\t\t\t\t\toptions: {\n\t\t\t\t\t\tlimit,\n\t\t\t\t\t\tthreshold,\n\t\t\t\t\t\tdocumentIds: input.documentIds,\n\t\t\t\t\t},\n\t\t\t\t\tauthToken: input.authToken,\n\t\t\t\t});\n\t\t\t\tfor (const hit of knowledgeHits) {\n\t\t\t\t\tresults.push(toKnowledgeResult(hit));\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tlogger.warn?.(\"[memory-store] knowledge source failed:\", error);\n\t\t\t\twarnings.push({\n\t\t\t\t\tsource: \"knowledge\",\n\t\t\t\t\tcode: \"knowledge_search_failed\",\n\t\t\t\t\tmessage: (error as Error).message ?? \"knowledge_search_failed\",\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (sources.includes(\"knowledge\")) {\n\t\t\twarnings.push({\n\t\t\t\tsource: \"knowledge\",\n\t\t\t\tcode: \"knowledge_search_not_configured\",\n\t\t\t\tmessage: \"Knowledge search is not configured for this host.\",\n\t\t\t});\n\t\t}\n\n\t\tconst merged = mergeUnifiedMemorySearchResults(results, limit);\n\n\t\treturn {\n\t\t\tquery: input.query,\n\t\t\tsources,\n\t\t\tresults: merged,\n\t\t\tcount: merged.length,\n\t\t\twarnings,\n\t\t};\n\t}\n\n\tasync function runMemorySource(\n\t\tinput: UnifiedMemorySearchInput,\n\t\tlimit: number,\n\t\tthreshold: number,\n\t): Promise<UnifiedMemorySearchResult[]> {\n\t\tif (typeof deps.embedQuery !== \"function\") {\n\t\t\tthrow new Error(\"embedQuery is not configured\");\n\t\t}\n\n\t\tconst queryEmbedding = await deps.embedQuery({\n\t\t\tuserId: input.userId,\n\t\t\tquery: input.query,\n\t\t\tauthToken: input.authToken,\n\t\t});\n\n\t\tconst filters = input.botIds && input.botIds.length > 0 ? input.botIds.map((botId) => ({ botId })) : [{}];\n\n\t\tif (isRawMessageChromaEnabled()) {\n\t\t\ttry {\n\t\t\t\tconst chromaHits = (\n\t\t\t\t\tawait Promise.all(\n\t\t\t\t\t\tfilters.map((filter) => {\n\t\t\t\t\t\t\tconst botId = \"botId\" in filter ? filter.botId : undefined;\n\t\t\t\t\t\t\treturn searchRawMessagesWithChroma({\n\t\t\t\t\t\t\t\tuserId: input.userId,\n\t\t\t\t\t\t\t\tqueryEmbedding,\n\t\t\t\t\t\t\t\tlimit,\n\t\t\t\t\t\t\t\tthreshold,\n\t\t\t\t\t\t\t\tbotId,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}),\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t\t\t.flat()\n\t\t\t\t\t.map(toMemoryResult);\n\t\t\t\tlogger.log?.(\"[memory-store] Raw message semantic search completed\", {\n\t\t\t\t\tbackend: \"chroma\",\n\t\t\t\t\tdimensions: queryEmbedding.length,\n\t\t\t\t\tcount: chromaHits.length,\n\t\t\t\t});\n\t\t\t\treturn chromaHits;\n\t\t\t} catch (error) {\n\t\t\t\tlogger.warn?.(\n\t\t\t\t\t\"[memory-store] Chroma raw message search failed; falling back to database search:\",\n\t\t\t\t\terror,\n\t\t\t\t);\n\t\t\t\t// fall through to the ANN/database search below\n\t\t\t}\n\t\t}\n\n\t\tif (typeof deps.searchRawMessagesAnn === \"function\") {\n\t\t\tconst rows = (\n\t\t\t\tawait Promise.all(\n\t\t\t\t\tfilters.map((filter) =>\n\t\t\t\t\t\tdeps.searchRawMessagesAnn!({\n\t\t\t\t\t\t\tuserId: input.userId,\n\t\t\t\t\t\t\tqueryEmbedding,\n\t\t\t\t\t\t\tlimit,\n\t\t\t\t\t\t\tthreshold,\n\t\t\t\t\t\t\tbotId: \"botId\" in filter ? filter.botId : undefined,\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t)\n\t\t\t\t.flat()\n\t\t\t\t.filter(isRawMemorySemanticResult)\n\t\t\t\t.map(toMemoryResult);\n\t\t\treturn rows;\n\t\t}\n\n\t\treturn [];\n\t}\n\n\tasync function searchRawMemorySemantically(\n\t\tinput: UnifiedMemorySearchInput,\n\t): Promise<UnifiedMemorySearchResult[]> {\n\t\tconst limit = clampUnifiedMemorySearchLimit(input.limit);\n\t\tconst threshold = clampUnifiedMemorySearchThreshold(input.threshold);\n\t\treturn runMemorySource(input, limit, threshold);\n\t}\n\n\treturn { searchUnifiedMemory, searchRawMemorySemantically };\n}\n","/**\n * @melandlabs/memory-store — SDK entry point.\n *\n * Wires up a top-level `MemoryStore` facade combining the raw message\n * manager, the unified search facade, and vector index helpers. Hosts\n * that want a non-web backend (CLI daemon, custom server) can use\n * this as the only entry point.\n */\n\nimport type { MemoryStoreConfig } from \"./config\";\nimport { type UnifiedSearch, createUnifiedSearch } from \"./search/unified-search\";\nimport {\n\ttype RawMessageStore,\n\tconfigureRawMessageStore,\n\tcreateRawMessageStore,\n\tgetRawMessageManager,\n} from \"./storage/raw-message-store\";\n\nexport interface MemoryStore {\n\t/** Underlying raw-message store (sqlite vs postgres). */\n\traw: RawMessageStore;\n\t/** Unified semantic search facade (memory + insights + knowledge). */\n\tsearch: UnifiedSearch;\n\t/** Resolve the active raw-message manager. */\n\tgetRawMessageManager: typeof getRawMessageManager;\n\t/** Run `searchUnifiedMemory` against the wired-up unified search. */\n\tsearchUnifiedMemory: UnifiedSearch[\"searchUnifiedMemory\"];\n\t/** Convenience: semantic search over raw messages only. */\n\tsearchRawMemorySemantically: UnifiedSearch[\"searchRawMemorySemantically\"];\n}\n\nexport async function createMemoryStore(config: MemoryStoreConfig = {}): Promise<MemoryStore> {\n\tconst raw = createRawMessageStore({ env: config.env });\n\tconst search = createUnifiedSearch(config.unified);\n\n\t// Make the legacy `getRawMessageManager()` module-level facade\n\t// point at this configuration so callers that don't go through\n\t// `createMemoryStore` still get the right backend.\n\tconfigureRawMessageStore(config);\n\n\treturn {\n\t\traw,\n\t\tsearch,\n\t\tgetRawMessageManager,\n\t\tsearchUnifiedMemory: search.searchUnifiedMemory,\n\t\tsearchRawMemorySemantically: search.searchRawMemorySemantically,\n\t};\n}\n\nexport type { MemoryStoreConfig };\nexport {\n\tcreateRawMessageStore,\n\tgetRawMessageManager,\n\tisRawMessageStorageAvailable,\n\tgetRawMessageStorageBackend,\n\tcloseRawMessageStore,\n\ttype RawMessageStorageBackend,\n\ttype RawMessageStorageManagerWithSearch,\n} from \"./storage/raw-message-store\";\nexport {\n\tregisterPostgresFactory,\n\tclearPostgresFactory,\n\thasPostgresFactory,\n\tresolvePostgresFactory,\n\ttype PostgresFactoryFn,\n\ttype PostgresRawMessageManagerLike,\n} from \"./storage/postgres-raw-message-factory\";\nexport {\n\tcreateUnifiedSearch,\n\ttype UnifiedSearch,\n} from \"./search/unified-search\";\nexport type {\n\tUnifiedMemorySearchInput,\n\tUnifiedMemorySearchOutput,\n\tUnifiedMemorySearchResult,\n\tUnifiedMemorySearchSource,\n\tUnifiedMemorySearchWarning,\n} from \"./search/utilities\";\nexport {\n\tclampUnifiedMemorySearchLimit,\n\tclampUnifiedMemorySearchThreshold,\n\tisRawMemorySemanticResult,\n\tmergeUnifiedMemorySearchResults,\n\tnormalizeUnifiedMemorySearchSources,\n\ttoKnowledgeResult,\n\ttoMemoryResult,\n} from \"./search/utilities\";\nexport type {\n\tMemoryStoreDb,\n\tMemoryStoreEnv,\n\tVectorBackend,\n\tEmbedQueryFn,\n\tUnifiedSearchKnowledgeResult,\n\tUnifiedSearchInsightsResult,\n} from \"./config\";\nexport type { RawMessage } from \"./config\";\n"]}
package/dist/mcp.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/contracts.ts","../src/storage/chroma-memory-index.ts","../src/storage/postgres-raw-message-factory.ts","../src/storage/sqlite-raw-message-store.ts","../src/storage/raw-message-store.ts","../src/search/utilities.ts","../src/search/unified-search.ts","../src/mcp.ts"],"names":["normalizeTimestampToMs","manager"],"mappings":"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","file":"mcp.js","sourcesContent":["/**\n * Memory-store contracts — types and constants that were originally re-exported\n * from `@melandlabs/indexeddb` but pulled in browser-only code (IndexedDB\n * globals) at module evaluation time, breaking the standalone HTTP/MCP\n * daemons.\n *\n * Anything defined here can be safely imported on the server without any\n * browser globals being resolved. The `@melandlabs/indexeddb` peer dependency\n * is optional in `@melandlabs/memory-store/package.json`; consumers can\n * depend on it directly for IndexedDB-backed storage.\n *\n * Re-export from this module is stable. New domain types belong in\n * dedicated files; this module only hosts the boundary contracts.\n */\n\nimport type { MemoryRecord } from \"@melandlabs/ai/memory\";\n\n/** Prefix used to reserve chat-memory evidence IDs that must not collide. */\nexport const CHAT_MEMORY_EVIDENCE_ID_PREFIX = \"opencontext-chat:\";\n\n/** A locally-defined re-export of the raw-message shape used by the SDK.\n * Kept as a structural type so consumers (SQLite, postgres factories)\n * can pass either the IndexedDB `RawMessage` or this shape. */\n// biome-ignore lint/suspicious/noExplicitAny: structural mirror of `@melandlabs/indexeddb/storage`'s `RawMessage`.\nexport interface RawMessage {\n\tid?: number;\n\tmessageId: string;\n\tplatform: string;\n\tbotId: string;\n\tuserId: string;\n\tchannel?: string;\n\tperson?: string;\n\ttimestamp: number;\n\tcontent: string;\n\tattachments?: Array<{\n\t\tname: string;\n\t\turl: string;\n\t\tcontentType?: string;\n\t\tsizeBytes?: number;\n\t}>;\n\tembedding?: number[];\n\tembeddingModel?: string;\n\tembeddingContentHash?: string;\n\tembeddingDimensions?: number;\n\tembeddingUpdatedAt?: number;\n\t// biome-ignore lint/suspicious/noExplicitAny: Preserve the public raw metadata contract.\n\tmetadata?: Record<string, any>;\n\tcreatedAt: number;\n\tmemoryStage?: \"short\" | \"mid\" | \"long\";\n\taccessCount?: number;\n\tlastAccessAt?: number;\n\timportanceScore?: number;\n\tarchivedAt?: number;\n\tisPinned?: boolean;\n\tsummaryRefId?: string;\n\tdeprecatedAt?: number;\n\tdeprecationReason?: string;\n\tsupersededBySummaryId?: string;\n}\n\nfunction normalizeTimestampToMs(value: number | undefined): number {\n\tif (!Number.isFinite(value)) {\n\t\treturn 0;\n\t}\n\tif ((value as number) < 1e11) {\n\t\treturn Math.floor((value as number) * 1000);\n\t}\n\treturn Math.floor(value as number);\n}\n\n/** Convert a RawMessage to a MemoryRecord for embedding. Local copy of the\n * helper that previously lived in `@melandlabs/indexeddb/embedding` and pulled\n * in browser-only modules. */\nexport function rawMessageToMemoryRecord(message: RawMessage): MemoryRecord {\n\treturn {\n\t\tid: message.messageId,\n\t\tuserId: message.userId,\n\t\ttimestamp: normalizeTimestampToMs(message.timestamp),\n\t\ttext: message.archivedAt ? undefined : message.content,\n\t\tmediaRefs: message.attachments?.map((item) => item.url).filter(Boolean),\n\t\tembedding: message.embedding,\n\t\tembeddingModel: message.embeddingModel,\n\t\tembeddingContentHash: message.embeddingContentHash,\n\t} as unknown as MemoryRecord;\n}\n","/**\n * Chroma-backed raw-message + insight vector index.\n *\n * Detects the active backend at call time (defaults to sqlite-vec if\n * no env override is present). The actual URL/collection values come\n * from env vars so the standalone memory daemon can pick them up\n * without an injected config.\n */\n\nimport { buildMemoryRecordEmbeddingDocument } from \"@melandlabs/ai/memory\";\nimport { ChromaVectorStore } from \"@melandlabs/rag\";\nimport type { DocumentChunk } from \"@melandlabs/rag/vector-service\";\n\nimport { type RawMessage, rawMessageToMemoryRecord } from \"../contracts\";\n\nconst DEFAULT_RAW_MESSAGES_COLLECTION = \"opencontext_raw_messages\";\nconst DEFAULT_INSIGHTS_COLLECTION = \"opencontext_insights\";\nconst RAW_VECTOR_BACKEND_ENV_KEYS = [\n\t\"RAW_MESSAGE_VECTOR_STORE_BACKEND\",\n\t\"MEMORY_VECTOR_STORE_BACKEND\",\n\t\"VECTOR_STORE_BACKEND\",\n] as const;\nconst INSIGHT_VECTOR_BACKEND_ENV_KEYS = [\n\t\"INSIGHT_VECTOR_STORE_BACKEND\",\n\t\"MEMORY_VECTOR_STORE_BACKEND\",\n\t\"VECTOR_STORE_BACKEND\",\n] as const;\n\nexport interface ChromaInsightVectorInput {\n\tinsightId: string;\n\tuserId: string;\n\tbotId: string;\n\tcontent: string;\n\tcontentHash: string;\n\tembedding: number[];\n\tembeddingModel: string;\n\tembeddingDimensions: number;\n\ttitle?: unknown;\n\tdescription?: unknown;\n\ttaskLabel?: unknown;\n\timportance?: unknown;\n\turgency?: unknown;\n\tplatform?: unknown;\n\taccount?: unknown;\n\ttime?: unknown;\n\tarchived?: unknown;\n}\n\nexport interface ChromaInsightSearchResult {\n\tid: string;\n\tcontent: string;\n\tsimilarity: number;\n\tmetadata: {\n\t\tbotId: string;\n\t\ttitle: string;\n\t\tdescription: string;\n\t\ttaskLabel: string;\n\t\timportance: string;\n\t\turgency: string;\n\t\tplatform: string | null;\n\t\taccount: string | null;\n\t\ttime: Date | null;\n\t\tembeddingModel: string;\n\t\tembeddingDimensions: number;\n\t\tcontentHash: string;\n\t};\n}\n\nfunction getBackend(keys: readonly string[]): string {\n\tfor (const key of keys) {\n\t\tconst value = process.env[key]?.trim().toLowerCase();\n\t\tif (value) {\n\t\t\treturn value;\n\t\t}\n\t}\n\treturn \"\";\n}\n\nexport function isRawMessageChromaEnabled(): boolean {\n\treturn getBackend(RAW_VECTOR_BACKEND_ENV_KEYS) === \"chroma\";\n}\n\nexport function isInsightChromaEnabled(): boolean {\n\treturn getBackend(INSIGHT_VECTOR_BACKEND_ENV_KEYS) === \"chroma\";\n}\n\nfunction getRawMessagesCollectionName(): string {\n\treturn (\n\t\tprocess.env.CHROMA_RAW_MESSAGES_COLLECTION ||\n\t\tprocess.env.CHROMA_MEMORY_COLLECTION ||\n\t\tDEFAULT_RAW_MESSAGES_COLLECTION\n\t);\n}\n\nfunction getInsightsCollectionName(): string {\n\treturn process.env.CHROMA_INSIGHTS_COLLECTION || DEFAULT_INSIGHTS_COLLECTION;\n}\n\nfunction getChromaStore(collectionName: string): ChromaVectorStore {\n\treturn new ChromaVectorStore({\n\t\turl: process.env.CHROMA_URL,\n\t\tcollectionName,\n\t});\n}\n\nfunction normalizeTimestampToMs(value: number | undefined): number {\n\tif (!Number.isFinite(value)) {\n\t\treturn 0;\n\t}\n\tif ((value as number) < 1e11) {\n\t\treturn Math.floor((value as number) * 1000);\n\t}\n\treturn Math.floor(value as number);\n}\n\nfunction toStringValue(value: unknown, fallback = \"\"): string {\n\treturn typeof value === \"string\" && value.trim().length > 0 ? value.trim() : fallback;\n}\n\nfunction toNullableString(value: unknown): string | null {\n\treturn typeof value === \"string\" && value.trim().length > 0 ? value.trim() : null;\n}\n\nfunction toBooleanValue(value: unknown): boolean {\n\treturn value === true || value === \"true\" || value === 1 || value === \"1\";\n}\n\nfunction toDateValue(value: unknown): Date | null {\n\tif (value instanceof Date) {\n\t\treturn Number.isNaN(value.getTime()) ? null : value;\n\t}\n\tif (typeof value === \"string\" || typeof value === \"number\") {\n\t\tconst date = new Date(value);\n\t\treturn Number.isNaN(date.getTime()) ? null : date;\n\t}\n\treturn null;\n}\n\nfunction rawMessageToChunk(message: RawMessage): DocumentChunk | null {\n\tif (!message.embedding || message.embedding.length === 0) {\n\t\treturn null;\n\t}\n\n\tconst record = rawMessageToMemoryRecord(message);\n\tconst document = buildMemoryRecordEmbeddingDocument(record);\n\tif (!document.content) {\n\t\treturn null;\n\t}\n\n\treturn {\n\t\tid: message.messageId,\n\t\tdocumentId: message.messageId,\n\t\tcontent: document.content,\n\t\tembedding: message.embedding,\n\t\tmetadata: {\n\t\t\tsourceType: \"raw_message\",\n\t\t\tuserId: message.userId,\n\t\t\tplatform: message.platform,\n\t\t\tbotId: message.botId,\n\t\t\tchannel: message.channel,\n\t\t\tperson: message.person,\n\t\t\ttimestamp: normalizeTimestampToMs(message.timestamp),\n\t\t\tmemoryStage: message.memoryStage,\n\t\t\tembeddingModel: message.embeddingModel,\n\t\t\tembeddingDimensions: message.embeddingDimensions,\n\t\t\tcontentHash: message.embeddingContentHash,\n\t\t\tarchived: Boolean(message.archivedAt),\n\t\t\trole: typeof message.metadata?.role === \"string\" ? message.metadata.role : undefined,\n\t\t},\n\t};\n}\n\nexport async function upsertRawMessagesToChroma(messages: RawMessage[]): Promise<number> {\n\tif (!isRawMessageChromaEnabled() || messages.length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst chunks = messages.map(rawMessageToChunk).filter((chunk): chunk is DocumentChunk => chunk !== null);\n\tif (chunks.length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst store = getChromaStore(getRawMessagesCollectionName());\n\tawait store.addChunks(chunks);\n\treturn chunks.length;\n}\n\nexport async function searchRawMessagesWithChroma(input: {\n\tuserId: string;\n\tqueryEmbedding: number[];\n\tlimit: number;\n\tthreshold: number;\n\tbotId?: string;\n}): Promise<\n\tArray<{\n\t\tid: string;\n\t\tcontent: string;\n\t\tsimilarity: number;\n\t\tmetadata: Record<string, unknown>;\n\t}>\n> {\n\tif (!isRawMessageChromaEnabled() || input.queryEmbedding.length === 0) {\n\t\treturn [];\n\t}\n\n\tconst store = getChromaStore(getRawMessagesCollectionName());\n\tconst results = await store.similaritySearch(\n\t\tinput.queryEmbedding,\n\t\tMath.max(input.limit * 5, input.limit),\n\t\tinput.userId,\n\t);\n\n\treturn results\n\t\t.filter((result) => {\n\t\t\tconst metadata = result.metadata ?? {};\n\t\t\tif (toBooleanValue(metadata.archived)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (input.botId && metadata.botId !== input.botId) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn result.score >= input.threshold;\n\t\t})\n\t\t.map((result) => ({\n\t\t\tid: result.id,\n\t\t\tcontent: result.content,\n\t\t\tsimilarity: result.score,\n\t\t\tmetadata: result.metadata ?? {},\n\t\t}))\n\t\t.slice(0, input.limit);\n}\n\nexport async function upsertInsightsToChroma(insights: ChromaInsightVectorInput[]): Promise<number> {\n\tif (!isInsightChromaEnabled() || insights.length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst chunks = insights\n\t\t.filter(\n\t\t\t(item) => item.content.trim().length > 0 && Array.isArray(item.embedding) && item.embedding.length > 0,\n\t\t)\n\t\t.map<DocumentChunk>((item) => ({\n\t\t\tid: item.insightId,\n\t\t\tdocumentId: item.insightId,\n\t\t\tcontent: item.content,\n\t\t\tembedding: item.embedding,\n\t\t\tmetadata: {\n\t\t\t\tsourceType: \"insight\",\n\t\t\t\tinsightId: item.insightId,\n\t\t\t\tuserId: item.userId,\n\t\t\t\tbotId: item.botId,\n\t\t\t\ttitle: toStringValue(item.title),\n\t\t\t\tdescription: toStringValue(item.description),\n\t\t\t\ttaskLabel: toStringValue(item.taskLabel),\n\t\t\t\timportance: toStringValue(item.importance),\n\t\t\t\turgency: toStringValue(item.urgency),\n\t\t\t\tplatform: toNullableString(item.platform),\n\t\t\t\taccount: toNullableString(item.account),\n\t\t\t\ttime: toDateValue(item.time)?.toISOString(),\n\t\t\t\tembeddingModel: item.embeddingModel,\n\t\t\t\tembeddingDimensions: item.embeddingDimensions,\n\t\t\t\tcontentHash: item.contentHash,\n\t\t\t\tarchived: toBooleanValue(item.archived),\n\t\t\t},\n\t\t}));\n\n\tif (chunks.length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst store = getChromaStore(getInsightsCollectionName());\n\tawait store.addChunks(chunks);\n\treturn chunks.length;\n}\n\nexport async function searchInsightsWithChroma(input: {\n\tuserId: string;\n\tqueryEmbedding: number[];\n\tlimit: number;\n\tthreshold: number;\n\tbotIds?: string[];\n\tincludeArchived?: boolean;\n}): Promise<ChromaInsightSearchResult[]> {\n\tif (!isInsightChromaEnabled() || input.queryEmbedding.length === 0) {\n\t\treturn [];\n\t}\n\n\tconst botIdSet = input.botIds && input.botIds.length > 0 ? new Set(input.botIds) : null;\n\tconst store = getChromaStore(getInsightsCollectionName());\n\tconst results = await store.similaritySearch(\n\t\tinput.queryEmbedding,\n\t\tMath.max(input.limit * 5, input.limit),\n\t\tinput.userId,\n\t);\n\n\treturn results\n\t\t.filter((result) => {\n\t\t\tconst metadata = result.metadata ?? {};\n\t\t\tif (!input.includeArchived && toBooleanValue(metadata.archived)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (botIdSet && !botIdSet.has(String(metadata.botId ?? \"\"))) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn result.score >= input.threshold;\n\t\t})\n\t\t.map((result) => {\n\t\t\tconst metadata = result.metadata ?? {};\n\t\t\treturn {\n\t\t\t\tid: result.id,\n\t\t\t\tcontent: result.content,\n\t\t\t\tsimilarity: result.score,\n\t\t\t\tmetadata: {\n\t\t\t\t\tbotId: toStringValue(metadata.botId),\n\t\t\t\t\ttitle: toStringValue(metadata.title),\n\t\t\t\t\tdescription: toStringValue(metadata.description),\n\t\t\t\t\ttaskLabel: toStringValue(metadata.taskLabel),\n\t\t\t\t\timportance: toStringValue(metadata.importance),\n\t\t\t\t\turgency: toStringValue(metadata.urgency),\n\t\t\t\t\tplatform: toNullableString(metadata.platform),\n\t\t\t\t\taccount: toNullableString(metadata.account),\n\t\t\t\t\ttime: toDateValue(metadata.time),\n\t\t\t\t\tembeddingModel: toStringValue(metadata.embeddingModel),\n\t\t\t\t\tembeddingDimensions: Number(metadata.embeddingDimensions ?? 0),\n\t\t\t\t\tcontentHash: toStringValue(metadata.contentHash),\n\t\t\t\t},\n\t\t\t};\n\t\t})\n\t\t.slice(0, input.limit);\n}\n","/**\n * Lazy registration slot for the host's Postgres-backed raw message\n * manager. The actual `PostgresRawMessageManager` implementation lives\n * in the host application because it owns the schema-bound Drizzle\n * table references.\n *\n * The package ships this factory so consumers can wire up their own\n * postgres implementation without forcing the package to take a\n * hard dependency on Drizzle schema files.\n */\n\nimport type { MemoryStoreEnv } from \"../config\";\n\nexport interface PostgresRawMessageManagerLike {\n\tinit?(): Promise<void>;\n\tclose?(): Promise<void>;\n\tupsertRawMessages?(input: {\n\t\tuserId: string;\n\t\tmessages: unknown[];\n\t}): Promise<unknown>;\n\tgetMessageById?(input: {\n\t\tuserId: string;\n\t\tmessageId: string;\n\t}): Promise<unknown>;\n\tsearchMessagesSemantically?(input: {\n\t\tuserId: string;\n\t\tqueryEmbedding: number[];\n\t\tembeddingModel?: string;\n\t\tlimit?: number;\n\t\tscanLimit?: number;\n\t\tthreshold?: number;\n\t\tincludeArchived?: boolean;\n\t\tincludeDeprecated?: boolean;\n\t\tplatform?: string;\n\t\tbotId?: string;\n\t\tchannel?: string;\n\t\tperson?: string;\n\t\tstartTime?: number;\n\t\tendTime?: number;\n\t}): Promise<unknown[]>;\n}\n\nexport type PostgresFactoryFn = (env?: MemoryStoreEnv) => Promise<PostgresRawMessageManagerLike>;\n\nlet factory: PostgresFactoryFn | null = null;\n\nexport function registerPostgresFactory(fn: PostgresFactoryFn): void {\n\tfactory = fn;\n}\n\nexport function clearPostgresFactory(): void {\n\tfactory = null;\n}\n\nexport async function resolvePostgresFactory(\n\tenv?: MemoryStoreEnv,\n): Promise<PostgresRawMessageManagerLike | null> {\n\tif (!factory) return null;\n\treturn await factory(env);\n}\n\nexport function hasPostgresFactory(): boolean {\n\treturn factory !== null;\n}\n","/**\n * SQLite-backed raw message store.\n *\n * Singleton manager. Local SQLite is the default backend for the memory\n * store — no host-mode check, no env-var opt-in. The DB path is resolved\n * from (in order):\n * 1. `MEMORY_STORE_DB_PATH` — recommended knob\n * 2. `~/.opencontext/memory/store.db` — last-resort default\n *\n * The `env?` parameter on the exported functions is kept for back-compat\n * with the historical `MemoryStoreEnv` interface but is no longer read.\n */\n\nimport { mkdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { SQLiteRawMessageManager } from \"@melandlabs/sqlite\";\nimport type { MemoryStoreEnv } from \"../config\";\nimport { isRawMessageChromaEnabled } from \"./chroma-memory-index\";\n\nlet manager: SQLiteRawMessageManager | null = null;\n\nconst DEFAULT_SQLITE_PATH = join(homedir(), \".opencontext\", \"memory\", \"store.db\");\n\n/**\n * Resolve the SQLite DB file path from env vars. Exposed so other storage\n * layers (vector index) can stay in sync with the same default.\n */\nexport function resolveSQLiteRawMessageDbPath(): string {\n\tconst fromEnv = process.env.MEMORY_STORE_DB_PATH?.trim();\n\treturn fromEnv && fromEnv.length > 0 ? fromEnv : DEFAULT_SQLITE_PATH;\n}\n\n/**\n * Local SQLite is the default. Every host (Tauri, server, CLI, tests) can\n * open the manager; the only failure mode is filesystem write permission.\n */\nexport function isSQLiteRawMessageStorageAvailable(_env?: MemoryStoreEnv): boolean {\n\treturn true;\n}\n\nexport async function getSQLiteRawMessageManager(_env?: MemoryStoreEnv): Promise<SQLiteRawMessageManager> {\n\tif (!manager) {\n\t\tconst dbPath = resolveSQLiteRawMessageDbPath();\n\t\tmkdirSync(dirname(dbPath), { recursive: true });\n\t\tmanager = new SQLiteRawMessageManager({\n\t\t\tdbPath,\n\t\t\tenableVectorSearch: !isRawMessageChromaEnabled(),\n\t\t});\n\t\tawait manager.init();\n\t}\n\n\treturn manager;\n}\n\nexport async function closeSQLiteRawMessageManager(): Promise<void> {\n\tif (!manager) {\n\t\treturn;\n\t}\n\tawait manager.close();\n\tmanager = null;\n}\n\n/**\n * Test-only: reset the singleton. Used by vitest between test cases.\n */\nexport function __resetSQLiteRawMessageManagerForTests(): void {\n\tmanager = null;\n}\n\n// Kept for back-compat with the historical `MemoryStoreEnv` interface.\n// The resolved env is no longer read by the SQLite layer, but the symbol\n// stays exported so external code that still calls `resolveEnv` compiles.\nfunction resolveEnv(_env?: MemoryStoreEnv): MemoryStoreEnv {\n\treturn {};\n}\n","/**\n * Top-level raw-message store facade.\n *\n * Backend selection is env-var driven:\n *\n * - `OPENCONTEXT_MEMORY_STORE_BACKEND=postgres` → use the host's\n * registered Postgres factory. A factory MUST be registered first\n * via `registerPostgresFactory()`; otherwise this throws a clear\n * error rather than silently falling back.\n * - Any other value (including unset) → local SQLite. The default\n * works in every host environment with no extra configuration.\n *\n * The facade exposes the common `RawMessageStorageManager` contract plus\n * a typed `searchMessagesSemantically` extension when present.\n */\n\nimport type { RawMessageStorageManager } from \"@melandlabs/indexeddb/storage\";\nimport type { MemoryStoreConfig, MemoryStoreEnv } from \"../config\";\nimport { hasPostgresFactory, resolvePostgresFactory } from \"./postgres-raw-message-factory\";\nimport { closeSQLiteRawMessageManager, getSQLiteRawMessageManager } from \"./sqlite-raw-message-store\";\n\nexport type RawMessageStorageBackend = \"sqlite\" | \"postgres\";\n\nexport type RawMessageStorageManagerWithSearch = RawMessageStorageManager & {\n\tsearchMessagesSemantically?: (input: {\n\t\tuserId: string;\n\t\tqueryEmbedding: number[];\n\t\tembeddingModel?: string;\n\t\tlimit?: number;\n\t\tscanLimit?: number;\n\t\tthreshold?: number;\n\t\tincludeArchived?: boolean;\n\t\tplatform?: string;\n\t\tbotId?: string;\n\t\tchannel?: string;\n\t\tperson?: string;\n\t\tstartTime?: number;\n\t\tendTime?: number;\n\t}) => Promise<unknown[]>;\n};\n\nexport interface CreateRawMessageStoreOptions {\n\tenv?: MemoryStoreEnv;\n}\n\nexport interface RawMessageStore {\n\tgetManager(): Promise<RawMessageStorageManagerWithSearch>;\n\tgetBackend(): RawMessageStorageBackend;\n\tisAvailable(): boolean;\n\tclose(): Promise<void>;\n}\n\nfunction resolveBackend(env: MemoryStoreEnv | undefined): RawMessageStorageBackend {\n\tconst explicit = process.env.OPENCONTEXT_MEMORY_STORE_BACKEND?.trim().toLowerCase();\n\tif (explicit === \"postgres\") return \"postgres\";\n\t// Any other value — including the default \"sqlite\", an unknown value,\n\t// or the env var being unset — falls through to local SQLite.\n\treturn \"sqlite\";\n}\n\nfunction resolveEnv(_env?: MemoryStoreEnv): MemoryStoreEnv {\n\treturn {};\n}\n\nexport function createRawMessageStore(options: CreateRawMessageStoreOptions = {}): RawMessageStore {\n\tconst env = resolveEnv(options.env);\n\n\treturn {\n\t\tgetBackend(): RawMessageStorageBackend {\n\t\t\treturn resolveBackend(env);\n\t\t},\n\t\tisAvailable(): boolean {\n\t\t\t// SQLite is always available; postgres is only available when the\n\t\t\t// env var asks for it AND a factory has been registered.\n\t\t\treturn resolveBackend(env) === \"sqlite\" || hasPostgresFactory();\n\t\t},\n\t\tasync getManager(): Promise<RawMessageStorageManagerWithSearch> {\n\t\t\tif (resolveBackend(env) === \"postgres\") {\n\t\t\t\tconst pg = await resolvePostgresFactory(env);\n\t\t\t\tif (!pg) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\"OPENCONTEXT_MEMORY_STORE_BACKEND=postgres but no Postgres factory is registered. \" +\n\t\t\t\t\t\t\t\"Call registerPostgresFactory() at startup, or unset the env var to use the default SQLite backend.\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn pg as unknown as RawMessageStorageManagerWithSearch;\n\t\t\t}\n\t\t\treturn (await getSQLiteRawMessageManager(env)) as unknown as RawMessageStorageManagerWithSearch;\n\t\t},\n\t\tasync close(): Promise<void> {\n\t\t\t// The sqlite singleton is process-wide, so close regardless of the\n\t\t\t// env var's current value — the previous call may have used it.\n\t\t\tawait closeSQLiteRawMessageManager();\n\t\t},\n\t};\n}\n\n// Module-level singleton so existing call sites that imported the\n// legacy `getRawMessageManager()` keep working without a refactor.\nlet moduleStore: RawMessageStore | null = null;\nlet moduleConfig: MemoryStoreConfig | null = null;\n\nexport function configureRawMessageStore(config: MemoryStoreConfig): RawMessageStore {\n\tmoduleConfig = config;\n\tmoduleStore = createRawMessageStore({ env: config.env });\n\treturn moduleStore;\n}\n\nexport function getRawMessageStorageBackend(): RawMessageStorageBackend {\n\tif (!moduleStore) {\n\t\tmoduleStore = createRawMessageStore({ env: moduleConfig?.env });\n\t}\n\treturn moduleStore.getBackend();\n}\n\nexport function isRawMessageStorageAvailable(): boolean {\n\tif (!moduleStore) {\n\t\tmoduleStore = createRawMessageStore({ env: moduleConfig?.env });\n\t}\n\treturn moduleStore.isAvailable();\n}\n\nexport async function getRawMessageManager(): Promise<RawMessageStorageManagerWithSearch> {\n\tif (!moduleStore) {\n\t\tmoduleStore = createRawMessageStore({ env: moduleConfig?.env });\n\t}\n\treturn moduleStore.getManager();\n}\n\nexport async function closeRawMessageStore(): Promise<void> {\n\tif (!moduleStore) return;\n\tawait moduleStore.close();\n\tmoduleStore = null;\n}\n","/**\n * Pure helpers used by the unified memory search pipeline.\n *\n * Kept side-effect free so they can be reused by tests, MCP tools,\n * and the HTTP daemon without pulling in any of the heavier\n * storage/search implementations.\n */\n\nexport type UnifiedMemorySearchSource = \"memory\" | \"insights\" | \"knowledge\";\n\nexport interface UnifiedMemorySearchWarning {\n\tsource: UnifiedMemorySearchSource;\n\tcode: string;\n\tmessage: string;\n}\n\nexport interface UnifiedMemorySearchInput {\n\tuserId: string;\n\tquery: string;\n\tsources?: UnifiedMemorySearchSource[];\n\tlimit?: number;\n\tthreshold?: number;\n\tauthToken?: string;\n\tincludeArchivedInsights?: boolean;\n\tbotIds?: string[];\n\tdocumentIds?: string[];\n}\n\nexport interface UnifiedMemorySearchResult {\n\ttype: \"memory\" | \"insight\" | \"knowledge\";\n\tid: string;\n\tcontent: string;\n\tsimilarity: number;\n\tmetadata: Record<string, unknown>;\n}\n\nexport interface UnifiedMemorySearchOutput {\n\tquery: string;\n\tsources: UnifiedMemorySearchSource[];\n\tresults: UnifiedMemorySearchResult[];\n\tcount: number;\n\twarnings: UnifiedMemorySearchWarning[];\n}\n\nconst DEFAULT_LIMIT = 10;\nconst DEFAULT_THRESHOLD = 0.7;\nconst DEFAULT_SOURCES: UnifiedMemorySearchSource[] = [\"memory\", \"insights\", \"knowledge\"];\nconst SOURCE_SET = new Set<UnifiedMemorySearchSource>(DEFAULT_SOURCES);\n\nexport function normalizeUnifiedMemorySearchSources(sources: unknown): UnifiedMemorySearchSource[] {\n\tif (!Array.isArray(sources) || sources.length === 0) {\n\t\treturn [...DEFAULT_SOURCES];\n\t}\n\n\tconst normalized = sources\n\t\t.filter((source): source is string => typeof source === \"string\")\n\t\t.map((source) => source.trim().toLowerCase())\n\t\t.filter((source): source is UnifiedMemorySearchSource =>\n\t\t\tSOURCE_SET.has(source as UnifiedMemorySearchSource),\n\t\t);\n\n\treturn normalized.length > 0 ? Array.from(new Set(normalized)) : [...DEFAULT_SOURCES];\n}\n\nexport function clampUnifiedMemorySearchLimit(limit: unknown): number {\n\tconst parsed = typeof limit === \"number\" ? limit : Number(limit ?? DEFAULT_LIMIT);\n\tif (!Number.isFinite(parsed)) {\n\t\treturn DEFAULT_LIMIT;\n\t}\n\treturn Math.min(50, Math.max(1, Math.floor(parsed)));\n}\n\nexport function clampUnifiedMemorySearchThreshold(threshold: unknown): number {\n\tconst parsed = typeof threshold === \"number\" ? threshold : Number(threshold ?? DEFAULT_THRESHOLD);\n\tif (!Number.isFinite(parsed)) {\n\t\treturn DEFAULT_THRESHOLD;\n\t}\n\treturn Math.min(1, Math.max(-1, parsed));\n}\n\nexport function mergeUnifiedMemorySearchResults(\n\tresults: UnifiedMemorySearchResult[],\n\tlimit: number,\n): UnifiedMemorySearchResult[] {\n\treturn [...results]\n\t\t.sort((a, b) => {\n\t\t\tconst scoreDelta = b.similarity - a.similarity;\n\t\t\tif (scoreDelta !== 0) {\n\t\t\t\treturn scoreDelta;\n\t\t\t}\n\t\t\treturn a.type.localeCompare(b.type) || a.id.localeCompare(b.id);\n\t\t})\n\t\t.slice(0, limit);\n}\n\nexport function toKnowledgeResult(result: {\n\tchunkId: string;\n\tdocumentId: string;\n\tdocumentName: string;\n\tcontent: string;\n\tsimilarity: number;\n\tchunkIndex: number;\n}): UnifiedMemorySearchResult {\n\treturn {\n\t\ttype: \"knowledge\",\n\t\tid: result.chunkId,\n\t\tcontent: result.content,\n\t\tsimilarity: result.similarity,\n\t\tmetadata: {\n\t\t\tdocumentId: result.documentId,\n\t\t\tdocumentName: result.documentName,\n\t\t\tchunkIndex: result.chunkIndex,\n\t\t},\n\t};\n}\n\nexport function toMemoryResult(result: {\n\tid: string;\n\tcontent: string;\n\tsimilarity: number;\n\tmetadata: Record<string, unknown>;\n}): UnifiedMemorySearchResult {\n\treturn {\n\t\ttype: \"memory\",\n\t\tid: result.id,\n\t\tcontent: result.content,\n\t\tsimilarity: result.similarity,\n\t\tmetadata: result.metadata,\n\t};\n}\n\nexport function isRawMemorySemanticResult(result: unknown): result is {\n\tid: string;\n\tcontent: string;\n\tsimilarity: number;\n\tmetadata: Record<string, unknown>;\n} {\n\tif (!result || typeof result !== \"object\") {\n\t\treturn false;\n\t}\n\tconst item = result as Record<string, unknown>;\n\treturn (\n\t\ttypeof item.id === \"string\" &&\n\t\ttypeof item.content === \"string\" &&\n\t\ttypeof item.similarity === \"number\" &&\n\t\tBoolean(item.metadata) &&\n\t\ttypeof item.metadata === \"object\"\n\t);\n}\n","/**\n * Unified semantic search facade.\n *\n * Cross-source search over raw messages (always), insights, and\n * uploaded knowledge documents. The host wires up the cross-domain\n * dependencies via `UnifiedSearchDeps` so this module stays\n * framework-agnostic.\n */\n\nimport type { UnifiedSearchDeps } from \"../config\";\nimport { isRawMessageChromaEnabled, searchRawMessagesWithChroma } from \"../storage/chroma-memory-index\";\nimport { isRawMessageStorageAvailable } from \"../storage/raw-message-store\";\nimport {\n\ttype UnifiedMemorySearchInput,\n\ttype UnifiedMemorySearchOutput,\n\ttype UnifiedMemorySearchResult,\n\ttype UnifiedMemorySearchWarning,\n\tclampUnifiedMemorySearchLimit,\n\tclampUnifiedMemorySearchThreshold,\n\tisRawMemorySemanticResult,\n\tmergeUnifiedMemorySearchResults,\n\tnormalizeUnifiedMemorySearchSources,\n\ttoKnowledgeResult,\n\ttoMemoryResult,\n} from \"./utilities\";\n\nexport type {\n\tUnifiedMemorySearchInput,\n\tUnifiedMemorySearchOutput,\n\tUnifiedMemorySearchResult,\n\tUnifiedMemorySearchSource,\n\tUnifiedMemorySearchWarning,\n} from \"./utilities\";\n\nexport {\n\tclampUnifiedMemorySearchLimit,\n\tclampUnifiedMemorySearchThreshold,\n\tisRawMemorySemanticResult,\n\tmergeUnifiedMemorySearchResults,\n\tnormalizeUnifiedMemorySearchSources,\n\ttoKnowledgeResult,\n\ttoMemoryResult,\n} from \"./utilities\";\n\nexport interface UnifiedSearch {\n\tsearchUnifiedMemory(input: UnifiedMemorySearchInput): Promise<UnifiedMemorySearchOutput>;\n\tsearchRawMemorySemantically(input: UnifiedMemorySearchInput): Promise<UnifiedMemorySearchResult[]>;\n}\n\nexport function createUnifiedSearch(deps: UnifiedSearchDeps = {}): UnifiedSearch {\n\tconst logger = (deps as { logger?: Console }).logger ?? console;\n\n\tasync function searchUnifiedMemory(input: UnifiedMemorySearchInput): Promise<UnifiedMemorySearchOutput> {\n\t\tconst query = input.query.trim();\n\t\tconst sources = normalizeUnifiedMemorySearchSources(input.sources);\n\t\tconst limit = clampUnifiedMemorySearchLimit(input.limit);\n\t\tconst threshold = clampUnifiedMemorySearchThreshold(input.threshold);\n\t\tconst warnings: UnifiedMemorySearchWarning[] = [];\n\t\tconst results: UnifiedMemorySearchResult[] = [];\n\n\t\tif (!query) {\n\t\t\treturn {\n\t\t\t\tquery,\n\t\t\t\tsources,\n\t\t\t\tresults: [],\n\t\t\t\tcount: 0,\n\t\t\t\twarnings,\n\t\t\t};\n\t\t}\n\n\t\tif (sources.includes(\"memory\")) {\n\t\t\tif (isRawMessageStorageAvailable()) {\n\t\t\t\ttry {\n\t\t\t\t\tconst memoryHits = await runMemorySource(input, limit, threshold);\n\t\t\t\t\tresults.push(...memoryHits);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tlogger.warn?.(\"[memory-store] memory source failed:\", error);\n\t\t\t\t\twarnings.push({\n\t\t\t\t\t\tsource: \"memory\",\n\t\t\t\t\t\tcode: \"memory_search_failed\",\n\t\t\t\t\t\tmessage: (error as Error).message ?? \"memory_search_failed\",\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twarnings.push({\n\t\t\t\t\tsource: \"memory\",\n\t\t\t\t\tcode: \"raw_message_storage_unavailable\",\n\t\t\t\t\tmessage: \"Raw memory storage is not available in this environment.\",\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tif (sources.includes(\"insights\") && typeof deps.searchInsights === \"function\") {\n\t\t\ttry {\n\t\t\t\tconst insightHits = await deps.searchInsights({\n\t\t\t\t\tuserId: input.userId,\n\t\t\t\t\tquery: input.query,\n\t\t\t\t\tlimit,\n\t\t\t\t\tthreshold,\n\t\t\t\t\tbotIds: input.botIds,\n\t\t\t\t\tincludeArchived: input.includeArchivedInsights,\n\t\t\t\t\tauthToken: input.authToken,\n\t\t\t\t});\n\t\t\t\tfor (const hit of insightHits) {\n\t\t\t\t\tresults.push({\n\t\t\t\t\t\ttype: \"insight\",\n\t\t\t\t\t\tid: hit.id,\n\t\t\t\t\t\tcontent: hit.content,\n\t\t\t\t\t\tsimilarity: hit.similarity,\n\t\t\t\t\t\tmetadata: hit.metadata,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tlogger.warn?.(\"[memory-store] insights source failed:\", error);\n\t\t\t\twarnings.push({\n\t\t\t\t\tsource: \"insights\",\n\t\t\t\t\tcode: \"insights_search_failed\",\n\t\t\t\t\tmessage: (error as Error).message ?? \"insights_search_failed\",\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (sources.includes(\"insights\")) {\n\t\t\twarnings.push({\n\t\t\t\tsource: \"insights\",\n\t\t\t\tcode: \"insights_search_not_configured\",\n\t\t\t\tmessage: \"Insights search is not configured for this host.\",\n\t\t\t});\n\t\t}\n\n\t\tif (sources.includes(\"knowledge\") && typeof deps.searchKnowledge === \"function\") {\n\t\t\ttry {\n\t\t\t\tconst knowledgeHits = await deps.searchKnowledge({\n\t\t\t\t\tuserId: input.userId,\n\t\t\t\t\tquery: input.query,\n\t\t\t\t\toptions: {\n\t\t\t\t\t\tlimit,\n\t\t\t\t\t\tthreshold,\n\t\t\t\t\t\tdocumentIds: input.documentIds,\n\t\t\t\t\t},\n\t\t\t\t\tauthToken: input.authToken,\n\t\t\t\t});\n\t\t\t\tfor (const hit of knowledgeHits) {\n\t\t\t\t\tresults.push(toKnowledgeResult(hit));\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tlogger.warn?.(\"[memory-store] knowledge source failed:\", error);\n\t\t\t\twarnings.push({\n\t\t\t\t\tsource: \"knowledge\",\n\t\t\t\t\tcode: \"knowledge_search_failed\",\n\t\t\t\t\tmessage: (error as Error).message ?? \"knowledge_search_failed\",\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (sources.includes(\"knowledge\")) {\n\t\t\twarnings.push({\n\t\t\t\tsource: \"knowledge\",\n\t\t\t\tcode: \"knowledge_search_not_configured\",\n\t\t\t\tmessage: \"Knowledge search is not configured for this host.\",\n\t\t\t});\n\t\t}\n\n\t\tconst merged = mergeUnifiedMemorySearchResults(results, limit);\n\n\t\treturn {\n\t\t\tquery: input.query,\n\t\t\tsources,\n\t\t\tresults: merged,\n\t\t\tcount: merged.length,\n\t\t\twarnings,\n\t\t};\n\t}\n\n\tasync function runMemorySource(\n\t\tinput: UnifiedMemorySearchInput,\n\t\tlimit: number,\n\t\tthreshold: number,\n\t): Promise<UnifiedMemorySearchResult[]> {\n\t\tif (typeof deps.embedQuery !== \"function\") {\n\t\t\tthrow new Error(\"embedQuery is not configured\");\n\t\t}\n\n\t\tconst queryEmbedding = await deps.embedQuery({\n\t\t\tuserId: input.userId,\n\t\t\tquery: input.query,\n\t\t\tauthToken: input.authToken,\n\t\t});\n\n\t\tconst filters = input.botIds && input.botIds.length > 0 ? input.botIds.map((botId) => ({ botId })) : [{}];\n\n\t\tif (isRawMessageChromaEnabled()) {\n\t\t\ttry {\n\t\t\t\tconst chromaHits = (\n\t\t\t\t\tawait Promise.all(\n\t\t\t\t\t\tfilters.map((filter) => {\n\t\t\t\t\t\t\tconst botId = \"botId\" in filter ? filter.botId : undefined;\n\t\t\t\t\t\t\treturn searchRawMessagesWithChroma({\n\t\t\t\t\t\t\t\tuserId: input.userId,\n\t\t\t\t\t\t\t\tqueryEmbedding,\n\t\t\t\t\t\t\t\tlimit,\n\t\t\t\t\t\t\t\tthreshold,\n\t\t\t\t\t\t\t\tbotId,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}),\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t\t\t.flat()\n\t\t\t\t\t.map(toMemoryResult);\n\t\t\t\tlogger.log?.(\"[memory-store] Raw message semantic search completed\", {\n\t\t\t\t\tbackend: \"chroma\",\n\t\t\t\t\tdimensions: queryEmbedding.length,\n\t\t\t\t\tcount: chromaHits.length,\n\t\t\t\t});\n\t\t\t\treturn chromaHits;\n\t\t\t} catch (error) {\n\t\t\t\tlogger.warn?.(\n\t\t\t\t\t\"[memory-store] Chroma raw message search failed; falling back to database search:\",\n\t\t\t\t\terror,\n\t\t\t\t);\n\t\t\t\t// fall through to the ANN/database search below\n\t\t\t}\n\t\t}\n\n\t\tif (typeof deps.searchRawMessagesAnn === \"function\") {\n\t\t\tconst rows = (\n\t\t\t\tawait Promise.all(\n\t\t\t\t\tfilters.map((filter) =>\n\t\t\t\t\t\tdeps.searchRawMessagesAnn!({\n\t\t\t\t\t\t\tuserId: input.userId,\n\t\t\t\t\t\t\tqueryEmbedding,\n\t\t\t\t\t\t\tlimit,\n\t\t\t\t\t\t\tthreshold,\n\t\t\t\t\t\t\tbotId: \"botId\" in filter ? filter.botId : undefined,\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t)\n\t\t\t\t.flat()\n\t\t\t\t.filter(isRawMemorySemanticResult)\n\t\t\t\t.map(toMemoryResult);\n\t\t\treturn rows;\n\t\t}\n\n\t\treturn [];\n\t}\n\n\tasync function searchRawMemorySemantically(\n\t\tinput: UnifiedMemorySearchInput,\n\t): Promise<UnifiedMemorySearchResult[]> {\n\t\tconst limit = clampUnifiedMemorySearchLimit(input.limit);\n\t\tconst threshold = clampUnifiedMemorySearchThreshold(input.threshold);\n\t\treturn runMemorySource(input, limit, threshold);\n\t}\n\n\treturn { searchUnifiedMemory, searchRawMemorySemantically };\n}\n","/**\n * @melandlabs/memory-store/mcp — MCP server entry.\n *\n * Spawns an MCP server (stdio transport by default) that exposes the\n * memory-store as tools any MCP client (Claude Code, etc.) can invoke.\n *\n * Tools registered:\n * - memory.searchUnified → UnifiedMemorySearchOutput\n * - memory.writeRawMessage → { ok: boolean }\n * - memory.getRawMessage → RawMessage | null\n * - memory.health → { ok: true }\n *\n * Usage:\n * import { startMcpServer } from \"@melandlabs/memory-store/mcp\";\n * await startMcpServer({ db: { getDb } });\n */\n\nimport type { RawMessage } from \"@melandlabs/indexeddb/storage\";\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\nimport type { ZodRawShape } from \"zod\";\nimport type { UnifiedSearchDeps } from \"./config\";\nimport type { MemoryStoreConfig } from \"./index\";\nimport { createUnifiedSearch } from \"./search/unified-search\";\nimport { upsertRawMessagesToChroma } from \"./storage/chroma-memory-index\";\nimport { createRawMessageStore } from \"./storage/raw-message-store\";\n\nexport interface StartMcpServerOptions extends MemoryStoreConfig {\n\t/** Server name surfaced to the MCP client. */\n\tname?: string;\n\t/** Server version surfaced to the MCP client. */\n\tversion?: string;\n}\n\nconst DEFAULT_NAME = \"@melandlabs/memory-store\";\nconst DEFAULT_VERSION = \"0.1.0\";\n\ntype RawMessageStoreFn = (messages: RawMessage[]) => Promise<number[]>;\ntype RawMessageGetFn = (messageId: string) => Promise<RawMessage | null | undefined>;\n\ninterface RawMessageManagerLike {\n\tupsertRawMessages?: (input: { userId: string; messages: RawMessage[] }) => Promise<unknown>;\n\tstoreMessages?: RawMessageStoreFn;\n\tgetMessageById?: RawMessageGetFn;\n}\n\nasync function embedMissingMessages(messages: RawMessage[], deps: UnifiedSearchDeps): Promise<RawMessage[]> {\n\tif (typeof deps.embedQuery !== \"function\") {\n\t\treturn messages;\n\t}\n\tconst out: RawMessage[] = [];\n\tfor (const message of messages) {\n\t\tif (Array.isArray(message.embedding) && message.embedding.length > 0) {\n\t\t\tout.push(message);\n\t\t\tcontinue;\n\t\t}\n\t\tif (typeof message.content !== \"string\" || message.content.length === 0) {\n\t\t\tout.push(message);\n\t\t\tcontinue;\n\t\t}\n\t\tconst vector = await deps.embedQuery({\n\t\t\tuserId: message.userId,\n\t\t\tquery: message.content,\n\t\t});\n\t\tout.push({\n\t\t\t...message,\n\t\t\tembedding: vector,\n\t\t\tembeddingModel: message.embeddingModel ?? \"server\",\n\t\t\tembeddingDimensions: vector.length,\n\t\t\tembeddingUpdatedAt: Date.now(),\n\t\t});\n\t}\n\treturn out;\n}\n\nexport async function startMcpServer(options: StartMcpServerOptions = {}): Promise<McpServer> {\n\tconst server = new McpServer({\n\t\tname: options.name ?? DEFAULT_NAME,\n\t\tversion: options.version ?? DEFAULT_VERSION,\n\t});\n\n\tconst rawStore = createRawMessageStore({\n\t\tenv: options.env,\n\t});\n\tconst search = createUnifiedSearch(options.unified);\n\n\tserver.tool(\"memory.health\", \"Returns the health status of the memory store.\", async () => ({\n\t\tcontent: [{ type: \"text\" as const, text: JSON.stringify({ ok: true }) }],\n\t}));\n\n\tconst searchSchema: ZodRawShape = {\n\t\tuserId: z.string(),\n\t\tquery: z.string().min(1),\n\t\tsources: z\n\t\t\t.array(z.enum([\"memory\", \"insights\", \"knowledge\"]))\n\t\t\t.optional()\n\t\t\t.describe(\"Default: ['memory','insights','knowledge']\"),\n\t\tlimit: z.number().int().min(1).max(50).default(10),\n\t\tthreshold: z.number().min(-1).max(1).default(0.7),\n\t\tbotIds: z.array(z.string()).optional(),\n\t\tdocumentIds: z.array(z.string()).optional(),\n\t\tincludeArchivedInsights: z.boolean().default(false),\n\t\tauthToken: z.string().optional(),\n\t};\n\n\tconst writeSchema: ZodRawShape = {\n\t\tuserId: z.string(),\n\t\tembedOnInsert: z\n\t\t\t.boolean()\n\t\t\t.optional()\n\t\t\t.describe(\n\t\t\t\t\"When true AND the host wired `unified.embedQuery`, fill in any missing \" +\n\t\t\t\t\t\"`embedding` server-side via that embedder. Required when the active \" +\n\t\t\t\t\t\"memory backend is sqlite-vec and the caller doesn't pre-embed.\",\n\t\t\t),\n\t\tmessage: z\n\t\t\t.object({\n\t\t\t\tid: z.string().optional(),\n\t\t\t\tmessageId: z.string().optional(),\n\t\t\t\trole: z.string(),\n\t\t\t\tcontent: z.union([z.string(), z.array(z.unknown())]),\n\t\t\t\tplatform: z.string().optional(),\n\t\t\t\tbotId: z.string().optional(),\n\t\t\t\tchannel: z.string().optional(),\n\t\t\t\tperson: z.string().optional(),\n\t\t\t\ttimestamp: z.number().optional(),\n\t\t\t\tembedding: z.array(z.number()).optional(),\n\t\t\t\tembeddingModel: z.string().optional(),\n\t\t\t\tembeddingDimensions: z.number().optional(),\n\t\t\t\tmetadata: z.record(z.string(), z.unknown()).optional(),\n\t\t\t})\n\t\t\t.passthrough(),\n\t};\n\n\tconst getSchema: ZodRawShape = {\n\t\tuserId: z.string(),\n\t\tmessageId: z.string(),\n\t};\n\n\t// Zod 4 schemas are not directly assignable to the MCP SDK's\n\t// AnySchema (z3.ZodTypeAny | z4.$ZodType) due to TypeScript's\n\t// structural checks. The runtime works correctly — only the\n\t// static type relationship needs the explicit cast.\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tserver.registerTool(\n\t\t\"memory.searchUnified\",\n\t\t{\n\t\t\ttitle: \"Search Unified Memory\",\n\t\t\tdescription:\n\t\t\t\t\"Semantic search across raw messages (always), and optionally insights and uploaded knowledge.\",\n\t\t\tinputSchema: searchSchema as any,\n\t\t},\n\t\tasync (args: unknown) => {\n\t\t\tconst a = args as {\n\t\t\t\tuserId: string;\n\t\t\t\tquery: string;\n\t\t\t\tsources?: (\"memory\" | \"insights\" | \"knowledge\")[];\n\t\t\t\tlimit?: number;\n\t\t\t\tthreshold?: number;\n\t\t\t\tbotIds?: string[];\n\t\t\t\tdocumentIds?: string[];\n\t\t\t\tincludeArchivedInsights?: boolean;\n\t\t\t\tauthToken?: string;\n\t\t\t};\n\t\t\tconst result = await search.searchUnifiedMemory(a);\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\" as const, text: JSON.stringify(result) }],\n\t\t\t};\n\t\t},\n\t);\n\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tserver.registerTool(\n\t\t\"memory.writeRawMessage\",\n\t\t{\n\t\t\ttitle: \"Write Raw Message\",\n\t\t\tdescription: \"Persist a single raw message to the user's memory store.\",\n\t\t\tinputSchema: writeSchema as any,\n\t\t},\n\t\tasync (args: unknown) => {\n\t\t\tconst a = args as {\n\t\t\t\tuserId: string;\n\t\t\t\tembedOnInsert?: boolean;\n\t\t\t\tmessage: unknown;\n\t\t\t};\n\t\t\tconst manager = (await rawStore.getManager()) as RawMessageManagerLike;\n\t\t\tconst incoming = [a.message as RawMessage].map((m) => ({ ...m, userId: m.userId ?? a.userId }));\n\t\t\tconst messages =\n\t\t\t\ta.embedOnInsert === true ? await embedMissingMessages(incoming, options.unified ?? {}) : incoming;\n\n\t\t\tlet result: unknown;\n\t\t\tif (typeof manager.upsertRawMessages === \"function\") {\n\t\t\t\tresult = await manager.upsertRawMessages({\n\t\t\t\t\tuserId: a.userId,\n\t\t\t\t\tmessages,\n\t\t\t\t});\n\t\t\t} else if (typeof manager.storeMessages === \"function\") {\n\t\t\t\tconst ids = await manager.storeMessages(messages);\n\t\t\t\tresult = { inserted: ids.length, ids };\n\t\t\t} else {\n\t\t\t\tthrow new Error(\"active raw-message manager exposes neither upsertRawMessages nor storeMessages\");\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tawait upsertRawMessagesToChroma(messages as never);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.warn(\"[memory-store/mcp] chroma upsert failed:\", error);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\ttext: JSON.stringify({ ok: true, count: messages.length, result }),\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t};\n\t\t},\n\t);\n\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tserver.registerTool(\n\t\t\"memory.getRawMessage\",\n\t\t{\n\t\t\ttitle: \"Get Raw Message\",\n\t\t\tdescription: \"Fetch a single raw message by its message id.\",\n\t\t\tinputSchema: getSchema as any,\n\t\t},\n\t\tasync (args: unknown) => {\n\t\t\tconst a = args as { userId: string; messageId: string };\n\t\t\tconst manager = (await rawStore.getManager()) as RawMessageManagerLike;\n\t\t\tconst row = await manager.getMessageById?.(a.messageId);\n\t\t\treturn {\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\ttext: JSON.stringify({ message: row ?? null }),\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t};\n\t\t},\n\t);\n\n\tconst transport = new StdioServerTransport();\n\tawait server.connect(transport);\n\treturn server;\n}\n\nexport type { MemoryStoreConfig };\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/policies/memory-graph-write-policy.ts","../../src/policies/memory-graph-correction-policy.ts"],"names":[],"mappings":";AA+BA,SAAS,QAAQ,KAAA,EAAoC;AACpD,EAAA,OAAO,KAAA,EAAO,IAAA,EAAK,CAAE,WAAA,EAAY,KAAM,MAAA;AACxC;AAEA,SAAS,cAAc,KAAA,EAAwC;AAC9D,EAAA,OAAO,IAAI,GAAA;AAAA,IAAA,CACT,KAAA,IAAS,EAAA,EACR,KAAA,CAAM,GAAG,CAAA,CACT,GAAA,CAAI,CAAC,IAAA,KAAS,IAAA,CAAK,IAAA,EAAM,CAAA,CACzB,OAAO,OAAO;AAAA,GACjB;AACD;AAEO,SAAS,oCAAoC,KAAA,EAWjB;AAClC,EAAA,IAAI,OAAA,CAAQ,KAAA,CAAM,UAAU,CAAA,EAAG;AAC9B,IAAA,OAAO,EAAE,SAAS,KAAA,EAAO,WAAA,EAAa,CAAC,KAAA,CAAM,WAAA,CAAY,MAAM,CAAA,EAAE;AAAA,EAClE;AACA,EAAA,IAAI,CAAC,OAAA,CAAQ,KAAA,CAAM,OAAO,CAAA,EAAG;AAC5B,IAAA,OAAO,EAAE,SAAS,KAAA,EAAO,WAAA,EAAa,CAAC,KAAA,CAAM,WAAA,CAAY,QAAQ,CAAA,EAAE;AAAA,EACpE;AACA,EAAA,IAAI,CAAC,cAAc,KAAA,CAAM,SAAS,EAAE,GAAA,CAAI,KAAA,CAAM,MAAM,CAAA,EAAG;AACtD,IAAA,OAAO,EAAE,SAAS,KAAA,EAAO,WAAA,EAAa,CAAC,KAAA,CAAM,WAAA,CAAY,MAAM,CAAA,EAAE;AAAA,EAClE;AACA,EAAA,OAAO,EAAE,SAAS,IAAA,EAAM,WAAA,EAAa,CAAC,KAAA,CAAM,WAAA,CAAY,OAAO,CAAA,EAAE;AAClE;;;ACrDO,SAAS,kCAAA,CACf,MAAA,EACA,WAAA,GAA2C,OAAA,CAAQ,GAAA,EAClB;AACjC,EAAA,OAAO,mCAAA,CAAoC;AAAA,IAC1C,MAAA;AAAA,IACA,SAAS,WAAA,CAAY,2CAAA;AAAA,IACrB,YAAY,WAAA,CAAY,+CAAA;AAAA,IACxB,WAAW,WAAA,CAAY,qDAAA;AAAA,IACvB,WAAA,EAAa;AAAA,MACZ,MAAA,EAAQ,qCAAA;AAAA,MACR,QAAA,EAAU,kCAAA;AAAA,MACV,MAAA,EAAQ,uCAAA;AAAA,MACR,OAAA,EAAS;AAAA;AACV,GACA,CAAA;AACF","file":"memory-graph-correction-policy.js","sourcesContent":["/**\n * Memory-graph write policy.\n *\n * Pure functions, no env imports — callers pass the env snapshot\n * explicitly.\n */\n\nimport { CHAT_MEMORY_EVIDENCE_ID_PREFIX } from \"../contracts\";\n\nexport { CHAT_MEMORY_EVIDENCE_ID_PREFIX };\n\nexport const MEMORY_GRAPH_SUMMARY_ID_PREFIXES = [\n\t\"memory-graph-summary:\",\n\t\"memory-graph-correction:\",\n] as const;\n\nexport interface MemoryGraphWritePolicyDecision {\n\tenabled: boolean;\n\treasonCodes: string[];\n}\n\nexport type MemoryGraphWriteEnvironment = Readonly<Record<string, string | undefined>>;\n\nexport function isReservedChatMemoryEvidenceId(messageId: string): boolean {\n\treturn messageId.startsWith(CHAT_MEMORY_EVIDENCE_ID_PREFIX);\n}\n\nexport function isReservedMemoryGraphSummaryId(summaryId: string): boolean {\n\treturn MEMORY_GRAPH_SUMMARY_ID_PREFIXES.some((prefix) => summaryId.startsWith(prefix));\n}\n\nfunction enabled(value: string | undefined): boolean {\n\treturn value?.trim().toLowerCase() === \"true\";\n}\n\nfunction cohortUserIds(value: string | undefined): Set<string> {\n\treturn new Set(\n\t\t(value ?? \"\")\n\t\t\t.split(\",\")\n\t\t\t.map((item) => item.trim())\n\t\t\t.filter(Boolean),\n\t);\n}\n\nexport function resolveAllowlistedMemoryGraphPolicy(input: {\n\tuserId: string;\n\tenabled: string | undefined;\n\tkillSwitch: string | undefined;\n\tallowlist: string | undefined;\n\treasonCodes: {\n\t\tkilled: string;\n\t\tdisabled: string;\n\t\tmissed: string;\n\t\tenabled: string;\n\t};\n}): MemoryGraphWritePolicyDecision {\n\tif (enabled(input.killSwitch)) {\n\t\treturn { enabled: false, reasonCodes: [input.reasonCodes.killed] };\n\t}\n\tif (!enabled(input.enabled)) {\n\t\treturn { enabled: false, reasonCodes: [input.reasonCodes.disabled] };\n\t}\n\tif (!cohortUserIds(input.allowlist).has(input.userId)) {\n\t\treturn { enabled: false, reasonCodes: [input.reasonCodes.missed] };\n\t}\n\treturn { enabled: true, reasonCodes: [input.reasonCodes.enabled] };\n}\n\nexport function resolveMemoryGraphWritePolicy(\n\tuserId: string,\n\tenvironment: MemoryGraphWriteEnvironment = process.env,\n): MemoryGraphWritePolicyDecision {\n\treturn resolveAllowlistedMemoryGraphPolicy({\n\t\tuserId,\n\t\tenabled: environment.OPENCONTEXT_MEMORY_GRAPH_WRITE_ENABLED,\n\t\tkillSwitch: environment.OPENCONTEXT_MEMORY_GRAPH_WRITE_KILL_SWITCH,\n\t\tallowlist: environment.OPENCONTEXT_MEMORY_GRAPH_WRITE_COHORT_USER_IDS,\n\t\treasonCodes: {\n\t\t\tkilled: \"memory_graph_write_kill_switch\",\n\t\t\tdisabled: \"memory_graph_write_disabled\",\n\t\t\tmissed: \"memory_graph_write_cohort_miss\",\n\t\t\tenabled: \"memory_graph_write_cohort_enabled\",\n\t\t},\n\t});\n}\n\nconst UNTRUSTED_GRAPH_METADATA_KEYS = [\n\t\"relationGroup\",\n\t\"relationValue\",\n\t\"topicKeys\",\n\t\"memoryTopicKeys\",\n\t\"memoryApplicability\",\n\t\"memoryRelation\",\n\t\"sourceIdentity\",\n\t\"memoryOwnerScope\",\n] as const;\n\nexport function sanitizeUntrustedMemoryMetadata(metadata: unknown): Record<string, unknown> | undefined {\n\tif (typeof metadata !== \"object\" || metadata === null || Array.isArray(metadata)) {\n\t\treturn undefined;\n\t}\n\n\tconst sanitized = { ...metadata } as Record<string, unknown>;\n\tfor (const key of UNTRUSTED_GRAPH_METADATA_KEYS) {\n\t\tdelete sanitized[key];\n\t}\n\treturn sanitized;\n}\n\nexport function resolveUntrustedRawMemoryGraphWritePolicy(): MemoryGraphWritePolicyDecision {\n\treturn {\n\t\tenabled: false,\n\t\treasonCodes: [\"memory_graph_write_untrusted_raw_baseline_only\", \"untrusted_graph_metadata_discarded\"],\n\t};\n}\n","/**\n * Memory-graph correction policy.\n *\n * Wraps the same allowlist machinery as the write policy but with\n * correction-specific env keys and reason codes.\n */\n\nimport {\n\ttype MemoryGraphWriteEnvironment,\n\ttype MemoryGraphWritePolicyDecision,\n\tresolveAllowlistedMemoryGraphPolicy,\n} from \"./memory-graph-write-policy\";\n\nexport function resolveMemoryGraphCorrectionPolicy(\n\tuserId: string,\n\tenvironment: MemoryGraphWriteEnvironment = process.env,\n): MemoryGraphWritePolicyDecision {\n\treturn resolveAllowlistedMemoryGraphPolicy({\n\t\tuserId,\n\t\tenabled: environment.OPENCONTEXT_MEMORY_GRAPH_CORRECTION_ENABLED,\n\t\tkillSwitch: environment.OPENCONTEXT_MEMORY_GRAPH_CORRECTION_KILL_SWITCH,\n\t\tallowlist: environment.OPENCONTEXT_MEMORY_GRAPH_CORRECTION_OPERATOR_USER_IDS,\n\t\treasonCodes: {\n\t\t\tkilled: \"memory_graph_correction_kill_switch\",\n\t\t\tdisabled: \"memory_graph_correction_disabled\",\n\t\t\tmissed: \"memory_graph_correction_operator_miss\",\n\t\t\tenabled: \"memory_graph_correction_operator_enabled\",\n\t\t},\n\t});\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/contracts.ts","../../src/policies/memory-graph-write-policy.ts"],"names":[],"mappings":"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","file":"memory-graph-write-policy.js","sourcesContent":["/**\n * Memory-store contracts — types and constants that were originally re-exported\n * from `@melandlabs/indexeddb` but pulled in browser-only code (IndexedDB\n * globals) at module evaluation time, breaking the standalone HTTP/MCP\n * daemons.\n *\n * Anything defined here can be safely imported on the server without any\n * browser globals being resolved. The `@melandlabs/indexeddb` peer dependency\n * is optional in `@melandlabs/memory-store/package.json`; consumers can\n * depend on it directly for IndexedDB-backed storage.\n *\n * Re-export from this module is stable. New domain types belong in\n * dedicated files; this module only hosts the boundary contracts.\n */\n\nimport type { MemoryRecord } from \"@melandlabs/ai/memory\";\n\n/** Prefix used to reserve chat-memory evidence IDs that must not collide. */\nexport const CHAT_MEMORY_EVIDENCE_ID_PREFIX = \"opencontext-chat:\";\n\n/** A locally-defined re-export of the raw-message shape used by the SDK.\n * Kept as a structural type so consumers (SQLite, postgres factories)\n * can pass either the IndexedDB `RawMessage` or this shape. */\n// biome-ignore lint/suspicious/noExplicitAny: structural mirror of `@melandlabs/indexeddb/storage`'s `RawMessage`.\nexport interface RawMessage {\n\tid?: number;\n\tmessageId: string;\n\tplatform: string;\n\tbotId: string;\n\tuserId: string;\n\tchannel?: string;\n\tperson?: string;\n\ttimestamp: number;\n\tcontent: string;\n\tattachments?: Array<{\n\t\tname: string;\n\t\turl: string;\n\t\tcontentType?: string;\n\t\tsizeBytes?: number;\n\t}>;\n\tembedding?: number[];\n\tembeddingModel?: string;\n\tembeddingContentHash?: string;\n\tembeddingDimensions?: number;\n\tembeddingUpdatedAt?: number;\n\t// biome-ignore lint/suspicious/noExplicitAny: Preserve the public raw metadata contract.\n\tmetadata?: Record<string, any>;\n\tcreatedAt: number;\n\tmemoryStage?: \"short\" | \"mid\" | \"long\";\n\taccessCount?: number;\n\tlastAccessAt?: number;\n\timportanceScore?: number;\n\tarchivedAt?: number;\n\tisPinned?: boolean;\n\tsummaryRefId?: string;\n\tdeprecatedAt?: number;\n\tdeprecationReason?: string;\n\tsupersededBySummaryId?: string;\n}\n\nfunction normalizeTimestampToMs(value: number | undefined): number {\n\tif (!Number.isFinite(value)) {\n\t\treturn 0;\n\t}\n\tif ((value as number) < 1e11) {\n\t\treturn Math.floor((value as number) * 1000);\n\t}\n\treturn Math.floor(value as number);\n}\n\n/** Convert a RawMessage to a MemoryRecord for embedding. Local copy of the\n * helper that previously lived in `@melandlabs/indexeddb/embedding` and pulled\n * in browser-only modules. */\nexport function rawMessageToMemoryRecord(message: RawMessage): MemoryRecord {\n\treturn {\n\t\tid: message.messageId,\n\t\tuserId: message.userId,\n\t\ttimestamp: normalizeTimestampToMs(message.timestamp),\n\t\ttext: message.archivedAt ? undefined : message.content,\n\t\tmediaRefs: message.attachments?.map((item) => item.url).filter(Boolean),\n\t\tembedding: message.embedding,\n\t\tembeddingModel: message.embeddingModel,\n\t\tembeddingContentHash: message.embeddingContentHash,\n\t} as unknown as MemoryRecord;\n}\n","/**\n * Memory-graph write policy.\n *\n * Pure functions, no env imports — callers pass the env snapshot\n * explicitly.\n */\n\nimport { CHAT_MEMORY_EVIDENCE_ID_PREFIX } from \"../contracts\";\n\nexport { CHAT_MEMORY_EVIDENCE_ID_PREFIX };\n\nexport const MEMORY_GRAPH_SUMMARY_ID_PREFIXES = [\n\t\"memory-graph-summary:\",\n\t\"memory-graph-correction:\",\n] as const;\n\nexport interface MemoryGraphWritePolicyDecision {\n\tenabled: boolean;\n\treasonCodes: string[];\n}\n\nexport type MemoryGraphWriteEnvironment = Readonly<Record<string, string | undefined>>;\n\nexport function isReservedChatMemoryEvidenceId(messageId: string): boolean {\n\treturn messageId.startsWith(CHAT_MEMORY_EVIDENCE_ID_PREFIX);\n}\n\nexport function isReservedMemoryGraphSummaryId(summaryId: string): boolean {\n\treturn MEMORY_GRAPH_SUMMARY_ID_PREFIXES.some((prefix) => summaryId.startsWith(prefix));\n}\n\nfunction enabled(value: string | undefined): boolean {\n\treturn value?.trim().toLowerCase() === \"true\";\n}\n\nfunction cohortUserIds(value: string | undefined): Set<string> {\n\treturn new Set(\n\t\t(value ?? \"\")\n\t\t\t.split(\",\")\n\t\t\t.map((item) => item.trim())\n\t\t\t.filter(Boolean),\n\t);\n}\n\nexport function resolveAllowlistedMemoryGraphPolicy(input: {\n\tuserId: string;\n\tenabled: string | undefined;\n\tkillSwitch: string | undefined;\n\tallowlist: string | undefined;\n\treasonCodes: {\n\t\tkilled: string;\n\t\tdisabled: string;\n\t\tmissed: string;\n\t\tenabled: string;\n\t};\n}): MemoryGraphWritePolicyDecision {\n\tif (enabled(input.killSwitch)) {\n\t\treturn { enabled: false, reasonCodes: [input.reasonCodes.killed] };\n\t}\n\tif (!enabled(input.enabled)) {\n\t\treturn { enabled: false, reasonCodes: [input.reasonCodes.disabled] };\n\t}\n\tif (!cohortUserIds(input.allowlist).has(input.userId)) {\n\t\treturn { enabled: false, reasonCodes: [input.reasonCodes.missed] };\n\t}\n\treturn { enabled: true, reasonCodes: [input.reasonCodes.enabled] };\n}\n\nexport function resolveMemoryGraphWritePolicy(\n\tuserId: string,\n\tenvironment: MemoryGraphWriteEnvironment = process.env,\n): MemoryGraphWritePolicyDecision {\n\treturn resolveAllowlistedMemoryGraphPolicy({\n\t\tuserId,\n\t\tenabled: environment.OPENCONTEXT_MEMORY_GRAPH_WRITE_ENABLED,\n\t\tkillSwitch: environment.OPENCONTEXT_MEMORY_GRAPH_WRITE_KILL_SWITCH,\n\t\tallowlist: environment.OPENCONTEXT_MEMORY_GRAPH_WRITE_COHORT_USER_IDS,\n\t\treasonCodes: {\n\t\t\tkilled: \"memory_graph_write_kill_switch\",\n\t\t\tdisabled: \"memory_graph_write_disabled\",\n\t\t\tmissed: \"memory_graph_write_cohort_miss\",\n\t\t\tenabled: \"memory_graph_write_cohort_enabled\",\n\t\t},\n\t});\n}\n\nconst UNTRUSTED_GRAPH_METADATA_KEYS = [\n\t\"relationGroup\",\n\t\"relationValue\",\n\t\"topicKeys\",\n\t\"memoryTopicKeys\",\n\t\"memoryApplicability\",\n\t\"memoryRelation\",\n\t\"sourceIdentity\",\n\t\"memoryOwnerScope\",\n] as const;\n\nexport function sanitizeUntrustedMemoryMetadata(metadata: unknown): Record<string, unknown> | undefined {\n\tif (typeof metadata !== \"object\" || metadata === null || Array.isArray(metadata)) {\n\t\treturn undefined;\n\t}\n\n\tconst sanitized = { ...metadata } as Record<string, unknown>;\n\tfor (const key of UNTRUSTED_GRAPH_METADATA_KEYS) {\n\t\tdelete sanitized[key];\n\t}\n\treturn sanitized;\n}\n\nexport function resolveUntrustedRawMemoryGraphWritePolicy(): MemoryGraphWritePolicyDecision {\n\treturn {\n\t\tenabled: false,\n\t\treasonCodes: [\"memory_graph_write_untrusted_raw_baseline_only\", \"untrusted_graph_metadata_discarded\"],\n\t};\n}\n"]}