@poprobertdaniel/openclaw-memory 0.1.1 → 0.1.3

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 (49) hide show
  1. package/README.md +22 -10
  2. package/dist/{chunk-RFLG2CCR.js → chunk-7DNVIKQ3.js} +100 -10
  3. package/dist/chunk-7DNVIKQ3.js.map +1 -0
  4. package/dist/{chunk-JSQBXYDM.js → chunk-BTR4T5L3.js} +157 -26
  5. package/dist/chunk-BTR4T5L3.js.map +1 -0
  6. package/dist/{chunk-VXULEX3A.cjs → chunk-CSGZH2SG.cjs} +9 -9
  7. package/dist/chunk-CSGZH2SG.cjs.map +1 -0
  8. package/dist/{chunk-JNWCMHOB.js → chunk-ITGUJZUL.js} +2 -2
  9. package/dist/{chunk-JNWCMHOB.js.map → chunk-ITGUJZUL.js.map} +1 -1
  10. package/dist/{chunk-NHFPLDZK.js → chunk-J2C5USXH.js} +3 -3
  11. package/dist/{chunk-CRPEAZ44.cjs → chunk-JYQB2DOK.cjs} +161 -30
  12. package/dist/chunk-JYQB2DOK.cjs.map +1 -0
  13. package/dist/{chunk-ZY2C2CJQ.cjs → chunk-LA5OP5VI.cjs} +2 -2
  14. package/dist/chunk-LA5OP5VI.cjs.map +1 -0
  15. package/dist/{chunk-NMUPGLJW.cjs → chunk-NYZMAY73.cjs} +110 -20
  16. package/dist/chunk-NYZMAY73.cjs.map +1 -0
  17. package/dist/cli/index.cjs +25 -25
  18. package/dist/cli/index.cjs.map +1 -1
  19. package/dist/cli/index.js +7 -7
  20. package/dist/cli/index.js.map +1 -1
  21. package/dist/index.cjs +5 -5
  22. package/dist/index.cjs.map +1 -1
  23. package/dist/index.d.cts +64 -2
  24. package/dist/index.d.ts +64 -2
  25. package/dist/index.js +4 -4
  26. package/dist/memory-service-B2BAEKR2.cjs +9 -0
  27. package/dist/memory-service-B2BAEKR2.cjs.map +1 -0
  28. package/dist/memory-service-ZTLGPIUH.js +9 -0
  29. package/dist/{server-BTbRv-yX.d.ts → server-CtNlCow7.d.cts} +62 -0
  30. package/dist/{server-BTbRv-yX.d.cts → server-CtNlCow7.d.ts} +62 -0
  31. package/dist/server.cjs +4 -4
  32. package/dist/server.cjs.map +1 -1
  33. package/dist/server.d.cts +1 -1
  34. package/dist/server.d.ts +1 -1
  35. package/dist/server.js +3 -3
  36. package/package.json +2 -2
  37. package/templates/.env.example +1 -1
  38. package/templates/openclaw-memory.config.ts +2 -2
  39. package/dist/chunk-CRPEAZ44.cjs.map +0 -1
  40. package/dist/chunk-JSQBXYDM.js.map +0 -1
  41. package/dist/chunk-NMUPGLJW.cjs.map +0 -1
  42. package/dist/chunk-RFLG2CCR.js.map +0 -1
  43. package/dist/chunk-VXULEX3A.cjs.map +0 -1
  44. package/dist/chunk-ZY2C2CJQ.cjs.map +0 -1
  45. package/dist/memory-service-6WDMF6KX.cjs +0 -9
  46. package/dist/memory-service-6WDMF6KX.cjs.map +0 -1
  47. package/dist/memory-service-GKEG6J2D.js +0 -9
  48. /package/dist/{chunk-NHFPLDZK.js.map → chunk-J2C5USXH.js.map} +0 -0
  49. /package/dist/{memory-service-GKEG6J2D.js.map → memory-service-ZTLGPIUH.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["/Users/robertpop/work/personal/openclaw-memory/dist/chunk-CRPEAZ44.cjs","../src/storage/orchestrator.ts","../src/storage/sqlite.ts","../src/storage/qdrant.ts","../src/storage/age.ts","../src/storage/sync-queue.ts","../src/extraction/embeddings.ts","../src/extraction/entity-extractor.ts","../src/search/strategy.ts","../src/search/ranker.ts","../src/search/engine.ts","../src/extraction/summarizer.ts"],"names":[],"mappings":"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","file":"/Users/robertpop/work/personal/openclaw-memory/dist/chunk-CRPEAZ44.cjs","sourcesContent":[null,"import { createHash } from \"node:crypto\";\nimport type { ResolvedConfig } from \"../config/index.js\";\nimport { SqliteStorage } from \"./sqlite.js\";\nimport { QdrantStorage } from \"./qdrant.js\";\nimport { AgeStorage } from \"./age.js\";\nimport { SyncQueueProcessor } from \"./sync-queue.js\";\nimport { EmbeddingService } from \"../extraction/embeddings.js\";\nimport { EntityExtractor } from \"../extraction/entity-extractor.js\";\nimport type {\n Tier,\n Memory,\n CreateMemoryRequest,\n UpdateMemoryRequest,\n SyncStatus,\n CreateMemoryResponse,\n ExtractedEntity,\n ExtractedRelationship,\n HealthResponse,\n} from \"../core/types.js\";\nimport { v7 as uuidv7 } from \"uuid\";\n\n// ── Storage Orchestrator ────────────────────────────────────────────────\n\nexport class StorageOrchestrator {\n readonly tier: Tier;\n readonly sqlite: SqliteStorage;\n readonly qdrant: QdrantStorage | null;\n readonly age: AgeStorage | null;\n readonly embeddings: EmbeddingService | null;\n readonly entityExtractor: EntityExtractor | null;\n private syncProcessor: SyncQueueProcessor;\n private startTime: number;\n\n constructor(config: ResolvedConfig) {\n this.tier = config.tier;\n this.sqlite = new SqliteStorage(config.sqlite.path);\n this.startTime = Date.now();\n\n // L2: Qdrant — only for standard/full tiers\n if (config.qdrant) {\n this.qdrant = new QdrantStorage(config.qdrant);\n } else {\n this.qdrant = null;\n }\n\n // L3: AGE — only for full tier\n if (config.age) {\n this.age = new AgeStorage(config.age);\n } else {\n this.age = null;\n }\n\n // Embeddings — needed for Qdrant\n if (config.embedding) {\n this.embeddings = new EmbeddingService(config.embedding);\n } else {\n this.embeddings = null;\n }\n\n // Entity extraction — for standard/full\n if (config.extraction && config.extraction.enabled) {\n this.entityExtractor = new EntityExtractor(config.extraction);\n } else {\n this.entityExtractor = null;\n }\n\n this.syncProcessor = new SyncQueueProcessor(\n this.sqlite,\n this.qdrant,\n this.age,\n this.embeddings\n );\n }\n\n async init(): Promise<void> {\n // Initialize L2 if available\n if (this.qdrant) {\n try {\n const dimensions = this.embeddings?.getDimensions() || 1536;\n await this.qdrant.ensureCollection(dimensions);\n console.log(\"[orchestrator] Qdrant collection ready\");\n } catch (error) {\n console.warn(`[orchestrator] Qdrant init failed (will retry): ${error}`);\n }\n }\n\n // Initialize L3 if available\n if (this.age) {\n try {\n await this.age.ensureGraph();\n console.log(\"[orchestrator] AGE graph ready\");\n } catch (error) {\n console.warn(`[orchestrator] AGE init failed (will retry): ${error}`);\n }\n }\n\n // Start sync queue processor if we have L2 or L3\n if (this.qdrant || this.age) {\n this.syncProcessor.start(60_000);\n }\n }\n\n // ── Create Memory ───────────────────────────────────────────────────\n\n async createMemory(req: CreateMemoryRequest): Promise<CreateMemoryResponse> {\n const now = new Date().toISOString();\n const id = uuidv7();\n\n // Extract entities if extractor is available and requested\n let entities: ExtractedEntity[] = [];\n let relationships: ExtractedRelationship[] = [];\n const shouldExtract =\n this.entityExtractor &&\n req.extract_entities !== false &&\n req.content.length >= 20 &&\n req.source !== \"entity_extraction\";\n\n if (shouldExtract) {\n try {\n const extraction = await this.entityExtractor!.extract(req.content);\n entities = extraction.entities;\n relationships = extraction.relationships;\n } catch (error) {\n console.warn(`[orchestrator] Entity extraction failed: ${error}`);\n }\n }\n\n const embeddingHash = contentHash(req.content);\n\n const memory: Memory = {\n id,\n agent_id: req.agent_id,\n scope: req.scope,\n subject_id: req.subject_id ?? null,\n content: req.content,\n tags: req.tags || [],\n entities,\n source: req.source || \"explicit\",\n created_by: req.created_by ?? null,\n created_at: now,\n updated_at: now,\n expires_at: req.expires_at ?? null,\n embedding_hash: embeddingHash,\n };\n\n // L1: SQLite — authoritative, synchronous\n this.sqlite.createMemory(memory);\n\n // L2: Qdrant — async best-effort\n const qdrantStatus = await this.asyncL2Upsert(memory);\n\n // L3: AGE — async best-effort\n const ageStatus = await this.asyncL3Upsert(memory, entities, relationships);\n\n return {\n id: memory.id,\n agent_id: memory.agent_id,\n scope: memory.scope,\n content: memory.content,\n entities: memory.entities,\n created_at: memory.created_at,\n sync_status: {\n sqlite: \"ok\",\n qdrant: qdrantStatus,\n age: ageStatus,\n },\n };\n }\n\n // ── Update Memory ───────────────────────────────────────────────────\n\n async updateMemory(\n id: string,\n req: UpdateMemoryRequest\n ): Promise<CreateMemoryResponse | null> {\n const existing = this.sqlite.getMemory(id);\n if (!existing) return null;\n\n let entities = existing.entities;\n let relationships: ExtractedRelationship[] = [];\n if (req.content && req.content !== existing.content) {\n const shouldExtract =\n this.entityExtractor &&\n req.extract_entities !== false &&\n req.content.length >= 20;\n if (shouldExtract) {\n try {\n const extraction = await this.entityExtractor!.extract(req.content);\n entities = extraction.entities;\n relationships = extraction.relationships;\n } catch (error) {\n console.warn(`[orchestrator] Entity extraction failed on update: ${error}`);\n }\n }\n }\n\n const embeddingHash = req.content\n ? contentHash(req.content)\n : existing.embedding_hash;\n\n const updates: Partial<Memory> = {\n ...(req.content !== undefined && { content: req.content }),\n ...(req.tags !== undefined && { tags: req.tags }),\n ...(req.scope !== undefined && { scope: req.scope }),\n ...(req.subject_id !== undefined && { subject_id: req.subject_id }),\n ...(req.expires_at !== undefined && { expires_at: req.expires_at }),\n entities,\n embedding_hash: embeddingHash,\n };\n\n const updated = this.sqlite.updateMemory(id, updates);\n if (!updated) return null;\n\n const qdrantStatus = await this.asyncL2Upsert(updated);\n const ageStatus = await this.asyncL3Upsert(updated, entities, relationships);\n\n return {\n id: updated.id,\n agent_id: updated.agent_id,\n scope: updated.scope,\n content: updated.content,\n tags: updated.tags,\n entities: updated.entities,\n created_at: updated.created_at,\n updated_at: updated.updated_at,\n sync_status: {\n sqlite: \"ok\",\n qdrant: qdrantStatus,\n age: ageStatus,\n },\n };\n }\n\n // ── Delete Memory ───────────────────────────────────────────────────\n\n async deleteMemory(id: string): Promise<boolean> {\n const deleted = this.sqlite.deleteMemory(id);\n if (!deleted) return false;\n\n // L2: Qdrant\n if (this.qdrant) {\n try {\n await this.qdrant.deleteMemory(id);\n } catch (error) {\n console.warn(`[orchestrator] Qdrant delete failed, queuing: ${error}`);\n this.sqlite.addToSyncQueue(id, \"qdrant\", \"delete\");\n }\n }\n\n // L3: AGE\n if (this.age) {\n try {\n await this.age.deleteMemoryNode(id);\n } catch (error) {\n console.warn(`[orchestrator] AGE delete failed, queuing: ${error}`);\n this.sqlite.addToSyncQueue(id, \"age\", \"delete\");\n }\n }\n\n return true;\n }\n\n // ── Health Check ────────────────────────────────────────────────────\n\n async healthCheck(): Promise<HealthResponse> {\n const details: Record<string, string> = {};\n\n const sqliteOk = this.sqlite.healthCheck();\n if (!sqliteOk) details.sqlite = \"SQLite health check failed\";\n\n let qdrantStatus: \"ok\" | \"error\" | \"disabled\" = \"disabled\";\n if (this.qdrant) {\n try {\n qdrantStatus = (await this.qdrant.healthCheck()) ? \"ok\" : \"error\";\n } catch (error) {\n qdrantStatus = \"error\";\n details.qdrant = String(error);\n }\n }\n\n let ageStatus: \"ok\" | \"error\" | \"disabled\" = \"disabled\";\n if (this.age) {\n try {\n ageStatus = (await this.age.healthCheck()) ? \"ok\" : \"error\";\n } catch (error) {\n ageStatus = \"error\";\n details.age = String(error);\n }\n }\n\n return {\n sqlite: sqliteOk ? \"ok\" : \"error\",\n qdrant: qdrantStatus,\n age: ageStatus,\n tier: this.tier,\n uptime: Math.floor((Date.now() - this.startTime) / 1000),\n ...(Object.keys(details).length > 0 && { details }),\n };\n }\n\n // ── Retry Sync ──────────────────────────────────────────────────────\n\n async retrySyncQueue(): Promise<{\n processed: number;\n succeeded: number;\n failed: number;\n }> {\n return this.syncProcessor.processQueue();\n }\n\n // ── Cleanup ─────────────────────────────────────────────────────────\n\n async close(): Promise<void> {\n this.syncProcessor.stop();\n this.sqlite.close();\n if (this.age) await this.age.close();\n }\n\n // ── Private Helpers ─────────────────────────────────────────────────\n\n private async asyncL2Upsert(\n memory: Memory\n ): Promise<\"ok\" | \"queued\" | \"failed\" | \"disabled\"> {\n if (!this.qdrant || !this.embeddings) return \"disabled\";\n\n try {\n const vector = await this.embeddings.embed(memory.content);\n if (!vector) {\n this.sqlite.addToSyncQueue(memory.id, \"qdrant\", \"upsert\");\n return \"queued\";\n }\n await this.qdrant.upsertMemory(memory, vector);\n this.sqlite.updateMemory(memory.id, {\n embedding_hash: contentHash(memory.content),\n });\n return \"ok\";\n } catch (error) {\n console.warn(`[orchestrator] Qdrant upsert failed, queuing: ${error}`);\n this.sqlite.addToSyncQueue(memory.id, \"qdrant\", \"upsert\");\n return \"queued\";\n }\n }\n\n private async asyncL3Upsert(\n memory: Memory,\n entities: ExtractedEntity[],\n relationships: ExtractedRelationship[]\n ): Promise<\"ok\" | \"queued\" | \"failed\" | \"disabled\"> {\n if (!this.age) return \"disabled\";\n\n try {\n await this.age.upsertMemoryNode(memory);\n\n for (const entity of entities) {\n const entityId = await this.age.upsertEntityNode(entity, memory.agent_id);\n await this.age.linkMemoryToEntity(memory.id, entityId);\n }\n\n for (const rel of relationships) {\n await this.age.createRelationship(rel, memory.agent_id);\n }\n\n return \"ok\";\n } catch (error) {\n console.warn(`[orchestrator] AGE upsert failed, queuing: ${error}`);\n this.sqlite.addToSyncQueue(memory.id, \"age\", \"upsert\");\n return \"queued\";\n }\n }\n}\n\n// ── Utility ─────────────────────────────────────────────────────────────\n\nfunction contentHash(content: string): string {\n // Use crypto.createHash for universal Node/Bun compatibility\n return createHash(\"sha256\").update(content).digest(\"hex\").slice(0, 16);\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { createRequire } from \"node:module\";\nimport type {\n Memory,\n MemoryScope,\n MemorySource,\n ExtractedEntity,\n ConversationLogEntry,\n SyncQueueItem,\n ListMemoriesQuery,\n} from \"../core/types.js\";\n\n// ── SQLite Row Types ────────────────────────────────────────────────────\n\ninterface MemoryRow {\n id: string;\n agent_id: string;\n scope: string;\n subject_id: string | null;\n content: string;\n tags: string;\n entities: string;\n source: string;\n created_by: string | null;\n created_at: string;\n updated_at: string;\n expires_at: string | null;\n embedding_hash: string | null;\n}\n\ninterface SyncQueueRow {\n id: number;\n memory_id: string;\n layer: string;\n operation: string;\n attempts: number;\n last_error: string | null;\n created_at: string;\n}\n\n// ── Database Adapter ────────────────────────────────────────────────────\n// Abstracts over bun:sqlite (Bun) and better-sqlite3 (Node)\n\ninterface DbAdapter {\n exec(sql: string): void;\n prepare(sql: string): StmtAdapter;\n close(): void;\n}\n\ninterface StmtAdapter {\n run(params?: Record<string, unknown>): { changes: number };\n get(params?: Record<string, unknown>): unknown;\n all(params?: Record<string, unknown>): unknown[];\n}\n\nfunction createDatabase(dbPath: string): DbAdapter {\n // Bun: use bun:sqlite\n if (typeof globalThis.Bun !== \"undefined\") {\n // In Bun, require() is available globally\n const req = createRequire(import.meta.url);\n const { Database } = req(\"bun:sqlite\") as {\n Database: new (path: string, opts?: { create?: boolean }) => {\n exec(sql: string): void;\n prepare(sql: string): {\n run(params?: Record<string, unknown>): { changes: number };\n get(params?: Record<string, unknown>): unknown;\n all(params?: Record<string, unknown>): unknown[];\n };\n close(): void;\n };\n };\n const db = new Database(dbPath, { create: true });\n return {\n exec: (sql: string) => db.exec(sql),\n prepare: (sql: string) => {\n const stmt = db.prepare(sql);\n return {\n run: (params?: Record<string, unknown>) => stmt.run(params || {}),\n get: (params?: Record<string, unknown>) => stmt.get(params || {}),\n all: (params?: Record<string, unknown>) => stmt.all(params || {}),\n };\n },\n close: () => db.close(),\n };\n }\n\n // Node: use better-sqlite3\n try {\n // Use createRequire for CommonJS optional dependency in ESM context\n const req = createRequire(import.meta.url);\n const Database = req(\"better-sqlite3\") as typeof import(\"better-sqlite3\");\n const db = new Database(dbPath);\n return {\n exec: (sql: string) => db.exec(sql),\n prepare: (sql: string) => {\n const stmt = db.prepare(sql);\n return {\n run: (params?: Record<string, unknown>) => {\n const result = stmt.run(params || {});\n return { changes: result.changes };\n },\n get: (params?: Record<string, unknown>) => stmt.get(params || {}),\n all: (params?: Record<string, unknown>) => stmt.all(params || {}),\n };\n },\n close: () => db.close(),\n };\n } catch {\n throw new Error(\n \"No SQLite driver available. Install better-sqlite3 for Node.js, or use Bun runtime.\"\n );\n }\n}\n\n// ── SQLite Storage Layer ────────────────────────────────────────────────\n\nexport class SqliteStorage {\n private db: DbAdapter;\n\n constructor(dbPath: string) {\n fs.mkdirSync(path.dirname(dbPath), { recursive: true });\n this.db = createDatabase(dbPath);\n this.db.exec(\"PRAGMA journal_mode = WAL\");\n this.db.exec(\"PRAGMA busy_timeout = 5000\");\n this.db.exec(\"PRAGMA synchronous = NORMAL\");\n this.db.exec(\"PRAGMA foreign_keys = ON\");\n this.initSchema();\n }\n\n // ── Schema ──────────────────────────────────────────────────────────\n\n private initSchema(): void {\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS memories (\n id TEXT PRIMARY KEY,\n agent_id TEXT NOT NULL,\n scope TEXT NOT NULL CHECK (scope IN ('user', 'agent', 'global', 'project', 'session')),\n subject_id TEXT,\n content TEXT NOT NULL,\n tags TEXT NOT NULL DEFAULT '[]',\n entities TEXT NOT NULL DEFAULT '[]',\n source TEXT NOT NULL DEFAULT 'explicit',\n created_by TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n expires_at TEXT,\n embedding_hash TEXT\n );\n\n CREATE INDEX IF NOT EXISTS idx_mem_agent ON memories(agent_id);\n CREATE INDEX IF NOT EXISTS idx_mem_scope ON memories(scope);\n CREATE INDEX IF NOT EXISTS idx_mem_subject ON memories(subject_id);\n CREATE INDEX IF NOT EXISTS idx_mem_agent_scope ON memories(agent_id, scope);\n CREATE INDEX IF NOT EXISTS idx_mem_created ON memories(created_at);\n CREATE INDEX IF NOT EXISTS idx_mem_source ON memories(source);\n `);\n\n // FTS5 virtual table for full-text search\n const ftsExists = this.db\n .prepare(\"SELECT name FROM sqlite_master WHERE type='table' AND name='memories_fts'\")\n .get();\n\n if (!ftsExists) {\n this.db.exec(`\n CREATE VIRTUAL TABLE memories_fts USING fts5(\n content,\n tags,\n content=memories,\n content_rowid=rowid\n );\n\n CREATE TRIGGER mem_fts_insert AFTER INSERT ON memories BEGIN\n INSERT INTO memories_fts(rowid, content, tags)\n VALUES (new.rowid, new.content, new.tags);\n END;\n\n CREATE TRIGGER mem_fts_delete AFTER DELETE ON memories BEGIN\n INSERT INTO memories_fts(memories_fts, rowid, content, tags)\n VALUES ('delete', old.rowid, old.content, old.tags);\n END;\n\n CREATE TRIGGER mem_fts_update AFTER UPDATE ON memories BEGIN\n INSERT INTO memories_fts(memories_fts, rowid, content, tags)\n VALUES ('delete', old.rowid, old.content, old.tags);\n INSERT INTO memories_fts(rowid, content, tags)\n VALUES (new.rowid, new.content, new.tags);\n END;\n `);\n }\n\n // Conversation log table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS conversation_log (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n agent_id TEXT NOT NULL,\n session_id TEXT NOT NULL,\n user_id TEXT NOT NULL,\n channel TEXT NOT NULL,\n role TEXT NOT NULL,\n content TEXT NOT NULL,\n timestamp TEXT NOT NULL\n );\n\n CREATE INDEX IF NOT EXISTS idx_convlog_agent ON conversation_log(agent_id);\n CREATE INDEX IF NOT EXISTS idx_convlog_session ON conversation_log(session_id);\n CREATE INDEX IF NOT EXISTS idx_convlog_ts ON conversation_log(timestamp);\n `);\n\n // Sync queue table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS sync_queue (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n memory_id TEXT NOT NULL,\n layer TEXT NOT NULL CHECK (layer IN ('qdrant', 'age')),\n operation TEXT NOT NULL CHECK (operation IN ('upsert', 'delete')),\n attempts INTEGER NOT NULL DEFAULT 0,\n last_error TEXT,\n created_at TEXT NOT NULL,\n UNIQUE(memory_id, layer, operation)\n );\n `);\n }\n\n // ── Memory CRUD ─────────────────────────────────────────────────────\n\n createMemory(memory: Memory): Memory {\n this.db.prepare(`\n INSERT INTO memories (id, agent_id, scope, subject_id, content, tags, entities, source, created_by, created_at, updated_at, expires_at, embedding_hash)\n VALUES ($id, $agent_id, $scope, $subject_id, $content, $tags, $entities, $source, $created_by, $created_at, $updated_at, $expires_at, $embedding_hash)\n `).run({\n $id: memory.id,\n $agent_id: memory.agent_id,\n $scope: memory.scope,\n $subject_id: memory.subject_id,\n $content: memory.content,\n $tags: JSON.stringify(memory.tags),\n $entities: JSON.stringify(memory.entities),\n $source: memory.source,\n $created_by: memory.created_by,\n $created_at: memory.created_at,\n $updated_at: memory.updated_at,\n $expires_at: memory.expires_at,\n $embedding_hash: memory.embedding_hash,\n });\n return memory;\n }\n\n getMemory(id: string): Memory | null {\n const row = this.db\n .prepare(\"SELECT * FROM memories WHERE id = $id\")\n .get({ $id: id }) as MemoryRow | null;\n if (!row) return null;\n return this.rowToMemory(row);\n }\n\n updateMemory(id: string, updates: Partial<Memory>): Memory | null {\n const existing = this.getMemory(id);\n if (!existing) return null;\n\n const updated: Memory = {\n ...existing,\n ...updates,\n id: existing.id,\n updated_at: new Date().toISOString(),\n };\n\n this.db.prepare(`\n UPDATE memories SET\n content = $content, tags = $tags, entities = $entities, scope = $scope, subject_id = $subject_id,\n expires_at = $expires_at, embedding_hash = $embedding_hash, updated_at = $updated_at\n WHERE id = $id\n `).run({\n $content: updated.content,\n $tags: JSON.stringify(updated.tags),\n $entities: JSON.stringify(updated.entities),\n $scope: updated.scope,\n $subject_id: updated.subject_id,\n $expires_at: updated.expires_at,\n $embedding_hash: updated.embedding_hash,\n $updated_at: updated.updated_at,\n $id: id,\n });\n return updated;\n }\n\n deleteMemory(id: string): boolean {\n const result = this.db.prepare(\"DELETE FROM memories WHERE id = $id\").run({ $id: id });\n return result.changes > 0;\n }\n\n listMemories(query: ListMemoriesQuery): Memory[] {\n const conditions: string[] = [];\n const params: Record<string, unknown> = {};\n\n if (query.agent_id) {\n conditions.push(\"agent_id = $agent_id\");\n params.$agent_id = query.agent_id;\n }\n if (query.scope) {\n conditions.push(\"scope = $scope\");\n params.$scope = query.scope;\n }\n if (query.subject_id) {\n conditions.push(\"subject_id = $subject_id\");\n params.$subject_id = query.subject_id;\n }\n if (query.source) {\n conditions.push(\"source = $source\");\n params.$source = query.source;\n }\n\n const where = conditions.length > 0 ? `WHERE ${conditions.join(\" AND \")}` : \"\";\n const order = query.order === \"asc\" ? \"ASC\" : \"DESC\";\n const limit = query.limit || 50;\n const offset = query.offset || 0;\n\n params.$limit = limit;\n params.$offset = offset;\n\n const sql = `SELECT * FROM memories ${where} ORDER BY created_at ${order} LIMIT $limit OFFSET $offset`;\n const rows = this.db.prepare(sql).all(params) as MemoryRow[];\n\n if (query.tags) {\n const tagList = query.tags.split(\",\").map((t) => t.trim().toLowerCase());\n return rows\n .map((r) => this.rowToMemory(r))\n .filter((m) => {\n const memTags = m.tags.map((t) => t.toLowerCase());\n return tagList.some((t) => memTags.includes(t));\n });\n }\n\n return rows.map((r) => this.rowToMemory(r));\n }\n\n // ── Full-Text Search ────────────────────────────────────────────────\n\n searchFullText(\n query: string,\n agentId?: string,\n scopes?: MemoryScope[],\n subjectId?: string | null,\n limit: number = 10\n ): Array<Memory & { fts_rank: number }> {\n const ftsQuery = query\n .split(/\\s+/)\n .filter(Boolean)\n .map((term) => `\"${term.replace(/\"/g, \"\")}\"`)\n .join(\" OR \");\n\n if (!ftsQuery) return [];\n\n const conditions: string[] = [];\n const params: Record<string, unknown> = { $fts: ftsQuery, $limit: limit };\n\n if (agentId) {\n conditions.push(\"m.agent_id = $agent_id\");\n params.$agent_id = agentId;\n }\n if (scopes && scopes.length > 0) {\n const scopePlaceholders = scopes.map((_, i) => `$scope_${i}`);\n conditions.push(`m.scope IN (${scopePlaceholders.join(\",\")})`);\n scopes.forEach((s, i) => { params[`$scope_${i}`] = s; });\n }\n if (subjectId !== undefined && subjectId !== null) {\n conditions.push(\"m.subject_id = $subject_id\");\n params.$subject_id = subjectId;\n }\n\n const where = conditions.length > 0 ? `AND ${conditions.join(\" AND \")}` : \"\";\n\n const sql = `\n SELECT m.*, rank\n FROM memories_fts fts\n JOIN memories m ON m.rowid = fts.rowid\n WHERE memories_fts MATCH $fts\n ${where}\n ORDER BY rank\n LIMIT $limit\n `;\n\n const rows = this.db.prepare(sql).all(params) as (MemoryRow & { rank: number })[];\n return rows.map((r) => ({\n ...this.rowToMemory(r),\n fts_rank: r.rank,\n }));\n }\n\n // ── Conversation Log ────────────────────────────────────────────────\n\n appendConversationLog(entry: ConversationLogEntry): void {\n this.db.prepare(\n `INSERT INTO conversation_log (agent_id, session_id, user_id, channel, role, content, timestamp)\n VALUES ($agent_id, $session_id, $user_id, $channel, $role, $content, $timestamp)`\n ).run({\n $agent_id: entry.agent_id,\n $session_id: entry.session_id,\n $user_id: entry.user_id,\n $channel: entry.channel,\n $role: entry.role,\n $content: entry.content,\n $timestamp: entry.timestamp,\n });\n }\n\n getConversationLog(\n agentId: string,\n sessionId: string,\n limit: number = 100\n ): ConversationLogEntry[] {\n return this.db.prepare(\n `SELECT agent_id, session_id, user_id, channel, role, content, timestamp\n FROM conversation_log\n WHERE agent_id = $agent_id AND session_id = $session_id\n ORDER BY timestamp ASC\n LIMIT $limit`\n ).all({ $agent_id: agentId, $session_id: sessionId, $limit: limit }) as ConversationLogEntry[];\n }\n\n // ── Sync Queue ──────────────────────────────────────────────────────\n\n addToSyncQueue(memoryId: string, layer: \"qdrant\" | \"age\", operation: \"upsert\" | \"delete\"): void {\n this.db.prepare(\n `INSERT INTO sync_queue (memory_id, layer, operation, created_at)\n VALUES ($memory_id, $layer, $operation, $created_at)\n ON CONFLICT(memory_id, layer, operation) DO UPDATE SET\n attempts = 0,\n last_error = NULL,\n created_at = excluded.created_at`\n ).run({\n $memory_id: memoryId,\n $layer: layer,\n $operation: operation,\n $created_at: new Date().toISOString(),\n });\n }\n\n getSyncQueue(limit: number = 50): SyncQueueItem[] {\n const rows = this.db.prepare(\n `SELECT * FROM sync_queue\n WHERE attempts < 5\n ORDER BY created_at ASC\n LIMIT $limit`\n ).all({ $limit: limit }) as SyncQueueRow[];\n return rows.map((r) => ({\n id: r.id,\n memory_id: r.memory_id,\n layer: r.layer as \"qdrant\" | \"age\",\n operation: r.operation as \"upsert\" | \"delete\",\n attempts: r.attempts,\n last_error: r.last_error,\n created_at: r.created_at,\n }));\n }\n\n updateSyncQueueItem(id: number, attempts: number, lastError: string | null): void {\n this.db.prepare(\"UPDATE sync_queue SET attempts = $attempts, last_error = $last_error WHERE id = $id\")\n .run({ $attempts: attempts, $last_error: lastError, $id: id });\n }\n\n removeSyncQueueItem(id: number): void {\n this.db.prepare(\"DELETE FROM sync_queue WHERE id = $id\").run({ $id: id });\n }\n\n clearCompletedSyncItems(): number {\n const result = this.db.prepare(\"DELETE FROM sync_queue WHERE attempts >= 5\").run();\n return result.changes;\n }\n\n // ── Stats ───────────────────────────────────────────────────────────\n\n getMemoryCount(): number {\n const row = this.db.prepare(\"SELECT COUNT(*) as count FROM memories\").get() as { count: number };\n return row.count;\n }\n\n getDatabaseSize(): number {\n try {\n const row = this.db.prepare(\"SELECT page_count * page_size as size FROM pragma_page_count(), pragma_page_size()\").get() as { size: number };\n return row.size;\n } catch {\n return 0;\n }\n }\n\n // ── Health Check ────────────────────────────────────────────────────\n\n healthCheck(): boolean {\n try {\n this.db.prepare(\"SELECT 1\").get();\n return true;\n } catch {\n return false;\n }\n }\n\n // ── Helpers ─────────────────────────────────────────────────────────\n\n private rowToMemory(row: MemoryRow): Memory {\n return {\n id: row.id,\n agent_id: row.agent_id,\n scope: row.scope as MemoryScope,\n subject_id: row.subject_id,\n content: row.content,\n tags: JSON.parse(row.tags || \"[]\"),\n entities: JSON.parse(row.entities || \"[]\"),\n source: row.source as MemorySource,\n created_by: row.created_by,\n created_at: row.created_at,\n updated_at: row.updated_at,\n expires_at: row.expires_at,\n embedding_hash: row.embedding_hash,\n };\n }\n\n close(): void {\n this.db.close();\n }\n}\n","import type {\n Memory,\n MemoryScope,\n ScoredMemory,\n ExtractedEntity,\n} from \"../core/types.js\";\n\n// ── Qdrant Storage Layer ────────────────────────────────────────────────\n\n// Dynamically imported — this is an optional peer dependency\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype QdrantClient = any;\n\nexport interface QdrantStorageConfig {\n url: string;\n collection: string;\n apiKey?: string;\n}\n\nexport class QdrantStorage {\n private client: QdrantClient | null = null;\n private collection: string;\n private config: QdrantStorageConfig;\n private ready = false;\n\n constructor(config: QdrantStorageConfig) {\n this.config = config;\n this.collection = config.collection;\n }\n\n // ── Lazy Client Init ────────────────────────────────────────────────\n\n private async getClient(): Promise<QdrantClient> {\n if (this.client) return this.client;\n\n try {\n // Dynamic import — @qdrant/js-client-rest is an optional peer dependency\n // @ts-ignore — optional peer dep, may not be installed\n const mod = await import(\"@qdrant/js-client-rest\");\n const QdrantClientClass = mod.QdrantClient;\n this.client = new QdrantClientClass({\n url: this.config.url,\n apiKey: this.config.apiKey,\n });\n return this.client;\n } catch {\n throw new Error(\n \"Qdrant client not available. Install @qdrant/js-client-rest: bun add @qdrant/js-client-rest\"\n );\n }\n }\n\n // ── Collection Init ─────────────────────────────────────────────────\n\n async ensureCollection(vectorSize: number = 1536): Promise<void> {\n if (this.ready) return;\n\n const client = await this.getClient();\n\n try {\n const collections = await client.getCollections();\n const exists = collections.collections?.some(\n (c: { name: string }) => c.name === this.collection\n );\n\n if (!exists) {\n await client.createCollection(this.collection, {\n vectors: {\n size: vectorSize,\n distance: \"Cosine\",\n },\n optimizers_config: {\n default_segment_number: 2,\n },\n replication_factor: 1,\n });\n\n // Create payload indexes for efficient filtering\n const indexFields = [\n { field_name: \"agent_id\", field_schema: \"keyword\" as const },\n { field_name: \"scope\", field_schema: \"keyword\" as const },\n { field_name: \"subject_id\", field_schema: \"keyword\" as const },\n { field_name: \"tags\", field_schema: \"keyword\" as const },\n { field_name: \"entity_types\", field_schema: \"keyword\" as const },\n { field_name: \"entity_names\", field_schema: \"keyword\" as const },\n { field_name: \"source\", field_schema: \"keyword\" as const },\n ];\n\n for (const idx of indexFields) {\n await client.createPayloadIndex(this.collection, idx);\n }\n\n console.log(`[qdrant] Created collection: ${this.collection}`);\n }\n\n this.ready = true;\n } catch (error) {\n console.error(`[qdrant] Failed to ensure collection: ${error}`);\n throw error;\n }\n }\n\n // ── Upsert ──────────────────────────────────────────────────────────\n\n async upsertMemory(memory: Memory, vector: number[]): Promise<void> {\n const client = await this.getClient();\n await this.ensureCollection(vector.length);\n\n const entityTypes = memory.entities.map((e) => e.type);\n const entityNames = memory.entities.map((e) => e.name);\n\n await client.upsert(this.collection, {\n points: [\n {\n id: memory.id,\n vector,\n payload: {\n agent_id: memory.agent_id,\n scope: memory.scope,\n subject_id: memory.subject_id,\n content: memory.content,\n tags: memory.tags,\n entity_types: entityTypes,\n entity_names: entityNames,\n source: memory.source,\n created_by: memory.created_by,\n created_at: memory.created_at,\n updated_at: memory.updated_at,\n },\n },\n ],\n });\n }\n\n // ── Delete ──────────────────────────────────────────────────────────\n\n async deleteMemory(id: string): Promise<void> {\n const client = await this.getClient();\n if (!this.ready) await this.ensureCollection();\n await client.delete(this.collection, {\n points: [id],\n });\n }\n\n // ── Semantic Search ─────────────────────────────────────────────────\n\n async search(\n queryVector: number[],\n agentId?: string,\n scopes?: MemoryScope[],\n subjectId?: string | null,\n limit: number = 10,\n crossAgent: boolean = false\n ): Promise<ScoredMemory[]> {\n const client = await this.getClient();\n await this.ensureCollection(queryVector.length);\n\n const filter = this.buildFilter(agentId, scopes, subjectId, crossAgent);\n\n const results = await client.search(this.collection, {\n vector: queryVector,\n limit,\n with_payload: true,\n filter: filter || undefined,\n score_threshold: 0.3,\n });\n\n return results.map((point: { id: string | number; payload?: Record<string, unknown>; score: number }) => {\n const payload = (point.payload || {}) as Record<string, unknown>;\n return {\n memory: this.payloadToMemory(String(point.id), payload),\n score: point.score,\n source_layer: \"qdrant\" as const,\n };\n });\n }\n\n // ── Health Check ────────────────────────────────────────────────────\n\n async healthCheck(): Promise<boolean> {\n try {\n const client = await this.getClient();\n await client.getCollections();\n return true;\n } catch {\n return false;\n }\n }\n\n // ── Collection Info ─────────────────────────────────────────────────\n\n async getCollectionInfo(): Promise<{ vectorCount: number } | null> {\n try {\n const client = await this.getClient();\n const info = await client.getCollection(this.collection);\n return { vectorCount: info.points_count || 0 };\n } catch {\n return null;\n }\n }\n\n // ── Helpers ─────────────────────────────────────────────────────────\n\n private buildFilter(\n agentId?: string,\n scopes?: MemoryScope[],\n subjectId?: string | null,\n crossAgent: boolean = false\n ): Record<string, unknown> | null {\n const must: Array<Record<string, unknown>> = [];\n\n if (agentId && !crossAgent) {\n must.push({ key: \"agent_id\", match: { value: agentId } });\n }\n if (scopes && scopes.length > 0) {\n must.push({ key: \"scope\", match: { any: scopes } });\n }\n if (subjectId !== undefined && subjectId !== null) {\n must.push({ key: \"subject_id\", match: { value: subjectId } });\n }\n\n if (must.length === 0) return null;\n return { must };\n }\n\n private payloadToMemory(id: string, payload: Record<string, unknown>): Memory {\n return {\n id,\n agent_id: (payload.agent_id as string) || \"\",\n scope: (payload.scope as MemoryScope) || \"agent\",\n subject_id: (payload.subject_id as string | null) ?? null,\n content: (payload.content as string) || \"\",\n tags: (payload.tags as string[]) || [],\n entities: ((payload.entity_names as string[]) || []).map(\n (name, i) => ({\n name,\n type: ((payload.entity_types as string[]) || [])[i] || \"Concept\",\n properties: {},\n })\n ) as ExtractedEntity[],\n source: (payload.source as Memory[\"source\"]) || \"explicit\",\n created_by: (payload.created_by as string | null) ?? null,\n created_at: (payload.created_at as string) || \"\",\n updated_at: (payload.updated_at as string) || \"\",\n expires_at: null,\n embedding_hash: null,\n };\n }\n}\n","import type {\n Memory,\n ExtractedEntity,\n ExtractedRelationship,\n EntityType,\n ScoredMemory,\n} from \"../core/types.js\";\n\n// ── AGE Storage Layer ───────────────────────────────────────────────────\n\n// Dynamically imported — this is an optional peer dependency\ntype Pool = import(\"pg\").Pool;\ntype PoolClient = import(\"pg\").PoolClient;\n\nexport interface AgeStorageConfig {\n host: string;\n port: number;\n user: string;\n password: string;\n database: string;\n graph: string;\n}\n\n// Max input length for user-supplied strings in Cypher queries\nconst MAX_CYPHER_INPUT_LENGTH = 1000;\n\nexport class AgeStorage {\n private pool: Pool | null = null;\n private config: AgeStorageConfig;\n private graph: string;\n private initialized = false;\n\n constructor(config: AgeStorageConfig) {\n this.config = config;\n this.graph = config.graph;\n }\n\n // ── Lazy Pool Init ──────────────────────────────────────────────────\n\n private async getPool(): Promise<Pool> {\n if (this.pool) return this.pool;\n\n try {\n const pg = await import(\"pg\");\n const PoolClass = pg.default?.Pool || pg.Pool;\n this.pool = new PoolClass({\n host: this.config.host,\n port: this.config.port,\n user: this.config.user,\n password: this.config.password,\n database: this.config.database,\n max: 5,\n idleTimeoutMillis: 30000,\n });\n return this.pool;\n } catch {\n throw new Error(\n \"pg client not available. Install pg: bun add pg\"\n );\n }\n }\n\n // ── Graph Init ──────────────────────────────────────────────────────\n\n async ensureGraph(): Promise<void> {\n if (this.initialized) return;\n\n const pool = await this.getPool();\n const client = await pool.connect();\n try {\n await client.query(\"LOAD 'age';\");\n await client.query('SET search_path = ag_catalog, \"$user\", public;');\n\n const exists = await client.query(\n \"SELECT 1 FROM ag_catalog.ag_graph WHERE name = $1\",\n [this.graph]\n );\n\n if (exists.rowCount === 0) {\n await client.query(\"SELECT ag_catalog.create_graph($1)\", [this.graph]);\n console.log(`[age] Created graph: ${this.graph}`);\n }\n\n this.initialized = true;\n } catch (error) {\n console.error(`[age] Failed to ensure graph: ${error}`);\n throw error;\n } finally {\n client.release();\n }\n }\n\n // ── Cypher Query Helper ─────────────────────────────────────────────\n\n private async cypherQuery<T>(\n query: string,\n resultColumns: string = \"v agtype\"\n ): Promise<T[]> {\n await this.ensureGraph();\n const pool = await this.getPool();\n const client = await pool.connect();\n try {\n await client.query(\"LOAD 'age';\");\n await client.query('SET search_path = ag_catalog, \"$user\", public;');\n\n const sql = `SELECT * FROM ag_catalog.cypher('${escGraphName(this.graph)}', $$${query}$$) as (${resultColumns})`;\n const result = await client.query(sql);\n\n return result.rows.map((row: Record<string, unknown>) => {\n const parsed: Record<string, unknown> = {};\n for (const key of Object.keys(row)) {\n parsed[key] = this.parseAgtype(row[key]);\n }\n if (Object.keys(parsed).length === 1 && \"v\" in parsed) {\n return parsed.v as T;\n }\n return parsed as T;\n });\n } finally {\n client.release();\n }\n }\n\n private async cypherExec(query: string): Promise<void> {\n await this.ensureGraph();\n const pool = await this.getPool();\n const client = await pool.connect();\n try {\n await client.query(\"LOAD 'age';\");\n await client.query('SET search_path = ag_catalog, \"$user\", public;');\n\n const sql = `SELECT * FROM ag_catalog.cypher('${escGraphName(this.graph)}', $$${query}$$) as (v agtype)`;\n await client.query(sql);\n } finally {\n client.release();\n }\n }\n\n // ── Memory Node Operations ──────────────────────────────────────────\n\n async upsertMemoryNode(memory: Memory): Promise<void> {\n const contentTruncated = memory.content.slice(0, 500);\n const now = new Date().toISOString();\n\n try {\n await this.cypherExec(\n `MERGE (m:Memory {id: '${esc(memory.id)}'})\n SET m.agent_id = '${esc(memory.agent_id)}',\n m.scope = '${esc(memory.scope)}',\n m.subject_id = '${esc(memory.subject_id || \"\")}',\n m.content = '${esc(contentTruncated)}',\n m.source = '${esc(memory.source)}',\n m.created_at = '${esc(memory.created_at)}',\n m.updated_at = '${esc(now)}'\n RETURN m`\n );\n } catch (error) {\n console.error(`[age] Failed to upsert memory node: ${error}`);\n throw error;\n }\n }\n\n // ── Entity Node Operations ──────────────────────────────────────────\n\n async upsertEntityNode(\n entity: ExtractedEntity,\n agentId: string\n ): Promise<string> {\n const entityId = slugify(`${entity.type}:${entity.name}`);\n const now = new Date().toISOString();\n const propsJson = JSON.stringify(entity.properties || {});\n\n try {\n await this.cypherExec(\n `MERGE (e:Entity {id: '${esc(entityId)}'})\n SET e.name = '${esc(entity.name)}',\n e.entity_type = '${esc(entity.type)}',\n e.agent_id = '${esc(agentId)}',\n e.properties = '${esc(propsJson)}',\n e.updated_at = '${esc(now)}'\n RETURN e`\n );\n } catch (error) {\n console.error(`[age] Failed to upsert entity node ${entityId}: ${error}`);\n throw error;\n }\n\n return entityId;\n }\n\n // ── Relationship Operations ─────────────────────────────────────────\n\n async createRelationship(\n rel: ExtractedRelationship,\n agentId: string\n ): Promise<void> {\n const fromId = slugify(`${this.guessEntityType(rel.from_entity)}:${rel.from_entity}`);\n const toId = slugify(`${this.guessEntityType(rel.to_entity)}:${rel.to_entity}`);\n const context = rel.properties?.context || \"\";\n\n // Validate relationship type is a valid identifier\n const relType = sanitizeLabel(rel.relationship);\n if (!relType) {\n console.warn(`[age] Invalid relationship type: ${rel.relationship}`);\n return;\n }\n\n try {\n await this.cypherExec(\n `MATCH (a:Entity {id: '${esc(fromId)}'}), (b:Entity {id: '${esc(toId)}'})\n MERGE (a)-[r:${relType}]->(b)\n SET r.context = '${esc(context)}',\n r.agent_id = '${esc(agentId)}'\n RETURN r`\n );\n } catch (error) {\n console.warn(`[age] Failed to create relationship ${fromId} -[${relType}]-> ${toId}: ${error}`);\n }\n }\n\n async linkMemoryToEntity(\n memoryId: string,\n entityId: string\n ): Promise<void> {\n try {\n await this.cypherExec(\n `MATCH (m:Memory {id: '${esc(memoryId)}'}), (e:Entity {id: '${esc(entityId)}'})\n MERGE (m)-[r:MENTIONS]->(e)\n RETURN r`\n );\n } catch (error) {\n console.warn(`[age] Failed to link memory ${memoryId} to entity ${entityId}: ${error}`);\n }\n }\n\n // ── Delete ──────────────────────────────────────────────────────────\n\n async deleteMemoryNode(memoryId: string): Promise<void> {\n try {\n try {\n await this.cypherExec(\n `MATCH (m:Memory {id: '${esc(memoryId)}'})-[r]-()\n DELETE r\n RETURN r`\n );\n } catch {\n // No edges to delete\n }\n\n await this.cypherExec(\n `MATCH (m:Memory {id: '${esc(memoryId)}'})\n DELETE m\n RETURN m`\n );\n } catch (error) {\n console.warn(`[age] Failed to delete memory node ${memoryId}: ${error}`);\n throw error;\n }\n }\n\n // ── Graph Queries ───────────────────────────────────────────────────\n\n async getEntityWithRelationships(\n entityType: string,\n entityId: string\n ): Promise<{\n entity: Record<string, unknown> | null;\n relationships: Array<{\n type: string;\n direction: string;\n target: Record<string, unknown>;\n }>;\n }> {\n try {\n const entities = await this.cypherQuery<Record<string, unknown>>(\n `MATCH (e:Entity {id: '${esc(entityId)}'})\n RETURN properties(e) as v`\n );\n\n if (entities.length === 0) {\n return { entity: null, relationships: [] };\n }\n\n const relationships: Array<{\n type: string;\n direction: string;\n target: Record<string, unknown>;\n }> = [];\n\n // Get outgoing relationships\n try {\n const outgoing = await this.cypherQuery<Record<string, unknown>>(\n `MATCH (e:Entity {id: '${esc(entityId)}'})-[r]->(target)\n RETURN type(r) as rel_type, properties(target) as target_props`,\n \"rel_type agtype, target_props agtype\"\n );\n\n for (const r of outgoing) {\n relationships.push({\n type: String(r.rel_type || \"\"),\n direction: \"outgoing\",\n target: (r.target_props as Record<string, unknown>) || {},\n });\n }\n } catch {\n // No outgoing relationships\n }\n\n // Get incoming relationships\n try {\n const incoming = await this.cypherQuery<Record<string, unknown>>(\n `MATCH (e:Entity {id: '${esc(entityId)}'})<-[r]-(source)\n RETURN type(r) as rel_type, properties(source) as source_props`,\n \"rel_type agtype, source_props agtype\"\n );\n\n for (const r of incoming) {\n relationships.push({\n type: String(r.rel_type || \"\"),\n direction: \"incoming\",\n target: (r.source_props as Record<string, unknown>) || {},\n });\n }\n } catch {\n // No incoming relationships\n }\n\n return { entity: entities[0], relationships };\n } catch (error) {\n console.error(`[age] Failed to get entity: ${error}`);\n return { entity: null, relationships: [] };\n }\n }\n\n async getRelatedEntities(\n entityId: string,\n depth: number = 2\n ): Promise<\n Array<{\n entity: Record<string, unknown>;\n relationship: string;\n distance: number;\n }>\n > {\n try {\n const maxDepth = Math.min(depth, 4);\n const results = await this.cypherQuery<Record<string, unknown>>(\n `MATCH (start:Entity {id: '${esc(entityId)}'})-[*1..${maxDepth}]-(target:Entity)\n WHERE target.id <> '${esc(entityId)}'\n RETURN DISTINCT properties(target) as target_props`,\n \"target_props agtype\"\n );\n\n return results.map((r) => ({\n entity: (r.target_props as Record<string, unknown>) || r,\n relationship: \"RELATED_TO\",\n distance: 1,\n }));\n } catch (error) {\n console.error(`[age] Failed to get related entities: ${error}`);\n return [];\n }\n }\n\n async searchByEntity(\n entityName: string,\n entityType?: string,\n agentId?: string,\n limit: number = 10\n ): Promise<ScoredMemory[]> {\n // Validate input length\n if (entityName.length > MAX_CYPHER_INPUT_LENGTH) {\n console.warn(\"[age] Entity name too long, truncating\");\n entityName = entityName.slice(0, MAX_CYPHER_INPUT_LENGTH);\n }\n\n try {\n const entityId = slugify(`${entityType || \"Concept\"}:${entityName}`);\n const safeLimit = Math.min(Math.max(1, limit), 100);\n\n let results: Record<string, unknown>[] = [];\n try {\n results = await this.cypherQuery<Record<string, unknown>>(\n `MATCH (m:Memory)-[:MENTIONS]->(e:Entity {id: '${esc(entityId)}'})\n ${agentId ? `WHERE m.agent_id = '${esc(agentId)}'` : \"\"}\n RETURN properties(m) as mem_props\n ORDER BY m.created_at DESC\n LIMIT ${safeLimit}`,\n \"mem_props agtype\"\n );\n } catch {\n // Exact match failed\n }\n\n if (results.length === 0) {\n return await this.searchByEntityNameFuzzy(entityName, agentId, safeLimit);\n }\n\n return results.map((r, i) => this.graphResultToScoredMemory(r, entityName, entityType, i));\n } catch (error) {\n console.error(`[age] Graph search failed: ${error}`);\n return [];\n }\n }\n\n private async searchByEntityNameFuzzy(\n name: string,\n agentId?: string,\n limit: number = 10\n ): Promise<ScoredMemory[]> {\n // Validate input length\n if (name.length > MAX_CYPHER_INPUT_LENGTH) {\n console.warn(\"[age] Fuzzy search name too long, truncating\");\n name = name.slice(0, MAX_CYPHER_INPUT_LENGTH);\n }\n\n try {\n // Escape regex metacharacters to prevent regex injection\n const escapedName = escRegex(esc(name));\n const safeLimit = Math.min(Math.max(1, limit), 100);\n\n const results = await this.cypherQuery<Record<string, unknown>>(\n `MATCH (m:Memory)-[:MENTIONS]->(e:Entity)\n WHERE e.name =~ '(?i).*${escapedName}.*'\n ${agentId ? `AND m.agent_id = '${esc(agentId)}'` : \"\"}\n RETURN properties(m) as mem_props, e.name as entity_name, e.entity_type as entity_type\n ORDER BY m.created_at DESC\n LIMIT ${safeLimit}`,\n \"mem_props agtype, entity_name agtype, entity_type agtype\"\n );\n\n return results.map((r, i) => {\n const props = (r.mem_props as Record<string, unknown>) || {};\n return {\n memory: this.propsToMemory(props),\n score: 0.8 / (1 + i * 0.1),\n source_layer: \"age\" as const,\n graph_context: {\n related_entities: [\n {\n type: (String(r.entity_type) || \"Concept\") as EntityType,\n name: String(r.entity_name || name),\n relationship: \"MENTIONED_IN\",\n },\n ],\n },\n };\n });\n } catch (error) {\n console.error(`[age] Fuzzy entity search failed: ${error}`);\n return [];\n }\n }\n\n async listEntities(\n entityType?: string,\n agentId?: string,\n limit: number = 50\n ): Promise<Array<Record<string, unknown>>> {\n try {\n const conditions: string[] = [];\n if (entityType) conditions.push(`e.entity_type = '${esc(entityType)}'`);\n if (agentId) conditions.push(`e.agent_id = '${esc(agentId)}'`);\n\n const where = conditions.length > 0 ? `WHERE ${conditions.join(\" AND \")}` : \"\";\n const safeLimit = Math.min(Math.max(1, limit), 200);\n\n const results = await this.cypherQuery<Record<string, unknown>>(\n `MATCH (e:Entity)\n ${where}\n RETURN properties(e) as props\n ORDER BY e.updated_at DESC\n LIMIT ${safeLimit}`,\n \"props agtype\"\n );\n\n return results.map((r) => (r.props as Record<string, unknown>) || r);\n } catch (error) {\n console.error(`[age] Failed to list entities: ${error}`);\n return [];\n }\n }\n\n // ── Agent Node ──────────────────────────────────────────────────────\n\n async ensureAgentNode(\n agentId: string,\n name: string,\n role: string\n ): Promise<void> {\n const now = new Date().toISOString();\n try {\n await this.cypherExec(\n `MERGE (a:Agent {id: '${esc(agentId)}'})\n SET a.name = '${esc(name)}',\n a.role = '${esc(role)}',\n a.created_at = '${esc(now)}'\n RETURN a`\n );\n } catch (error) {\n console.warn(`[age] Failed to ensure agent node: ${error}`);\n }\n }\n\n // ── Stats ───────────────────────────────────────────────────────────\n\n async getStats(): Promise<{ entityCount: number; relationshipCount: number } | null> {\n try {\n const entities = await this.cypherQuery<Record<string, unknown>>(\n `MATCH (e:Entity) RETURN count(e) as cnt`,\n \"cnt agtype\"\n );\n const rels = await this.cypherQuery<Record<string, unknown>>(\n `MATCH ()-[r]->() RETURN count(r) as cnt`,\n \"cnt agtype\"\n );\n return {\n entityCount: Number(entities[0] || 0),\n relationshipCount: Number(rels[0] || 0),\n };\n } catch {\n return null;\n }\n }\n\n // ── Health Check ────────────────────────────────────────────────────\n\n async healthCheck(): Promise<boolean> {\n try {\n const pool = await this.getPool();\n const client = await pool.connect();\n try {\n await client.query(\"SELECT 1\");\n return true;\n } finally {\n client.release();\n }\n } catch {\n return false;\n }\n }\n\n // ── Cleanup ─────────────────────────────────────────────────────────\n\n async close(): Promise<void> {\n if (this.pool) {\n await this.pool.end();\n }\n }\n\n // ── Helpers ─────────────────────────────────────────────────────────\n\n private parseAgtype(value: unknown): unknown {\n if (value === null || value === undefined) return null;\n if (typeof value === \"string\") {\n try {\n return JSON.parse(value);\n } catch {\n const cleaned = value.replace(/::(?:vertex|edge|path|agtype)$/g, \"\").trim();\n try {\n return JSON.parse(cleaned);\n } catch {\n return cleaned;\n }\n }\n }\n return value;\n }\n\n private propsToMemory(props: Record<string, unknown>): Memory {\n return {\n id: String(props.id || \"\"),\n agent_id: String(props.agent_id || \"\"),\n scope: String(props.scope || \"agent\") as Memory[\"scope\"],\n subject_id: (props.subject_id as string) || null,\n content: String(props.content || \"\"),\n tags: [],\n entities: [],\n source: String(props.source || \"explicit\") as Memory[\"source\"],\n created_by: null,\n created_at: String(props.created_at || \"\"),\n updated_at: String(props.updated_at || \"\"),\n expires_at: null,\n embedding_hash: null,\n };\n }\n\n private graphResultToScoredMemory(\n r: Record<string, unknown>,\n entityName: string,\n entityType: string | undefined,\n index: number\n ): ScoredMemory {\n const props = (r.mem_props as Record<string, unknown>) || {};\n return {\n memory: this.propsToMemory(props),\n score: 1.0 / (1 + index * 0.1),\n source_layer: \"age\" as const,\n graph_context: {\n related_entities: [\n {\n type: (entityType || \"Concept\") as EntityType,\n name: entityName,\n relationship: \"MENTIONED_IN\",\n },\n ],\n },\n };\n }\n\n private guessEntityType(_name: string): string {\n return \"Concept\";\n }\n}\n\n// ── Utility Functions ───────────────────────────────────────────────────\n\n/**\n * Escape a string for safe inclusion in a Cypher single-quoted string literal.\n * Also strips dollar signs to prevent $$ dollar-quote breakout in the\n * pg cypher() wrapper.\n *\n * NOTE: This is NOT a complete SQL injection defence on its own.\n * It is a best-effort sanitisation layer for AGE's $$-quoted Cypher\n * passthrough, where parameterised queries are not supported.\n */\nfunction esc(value: string): string {\n if (!value) return \"\";\n // Enforce max length\n const truncated = value.slice(0, MAX_CYPHER_INPUT_LENGTH);\n return truncated\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/'/g, \"\\\\'\")\n .replace(/\\n/g, \"\\\\n\")\n .replace(/\\r/g, \"\\\\r\")\n .replace(/\\$/g, \"\") // strip dollar signs — prevents $$ breakout\n .replace(/\\0/g, \"\"); // strip null bytes\n}\n\n/**\n * Escape the graph name (alphanumeric + underscore only).\n */\nfunction escGraphName(name: string): string {\n return name.replace(/[^a-zA-Z0-9_]/g, \"\");\n}\n\n/**\n * Escape regex metacharacters so user input can be safely embedded in\n * Cypher =~ regex patterns without causing injection or ReDoS.\n */\nfunction escRegex(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\n/**\n * Sanitize a Cypher label/relationship type.\n * Only alphanumeric and underscore are allowed.\n * Returns null if the result is empty.\n */\nfunction sanitizeLabel(label: string): string | null {\n const sanitized = label.replace(/[^a-zA-Z0-9_]/g, \"\");\n return sanitized.length > 0 ? sanitized : null;\n}\n\nfunction slugify(input: string): string {\n return input\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, 128);\n}\n","import type { SqliteStorage } from \"./sqlite.js\";\nimport type { QdrantStorage } from \"./qdrant.js\";\nimport type { AgeStorage } from \"./age.js\";\nimport type { EmbeddingService } from \"../extraction/embeddings.js\";\nimport type { SyncQueueItem } from \"../core/types.js\";\n\n// ── Sync Queue Processor ────────────────────────────────────────────────\n\nexport class SyncQueueProcessor {\n private sqlite: SqliteStorage;\n private qdrant: QdrantStorage | null;\n private age: AgeStorage | null;\n private embeddings: EmbeddingService | null;\n private interval: ReturnType<typeof setInterval> | null = null;\n private processing = false;\n\n constructor(\n sqlite: SqliteStorage,\n qdrant: QdrantStorage | null,\n age: AgeStorage | null,\n embeddings: EmbeddingService | null\n ) {\n this.sqlite = sqlite;\n this.qdrant = qdrant;\n this.age = age;\n this.embeddings = embeddings;\n }\n\n start(intervalMs: number = 60_000): void {\n if (this.interval) return;\n console.log(`[sync-queue] Starting processor (every ${intervalMs / 1000}s)`);\n this.interval = setInterval(() => {\n void this.processQueue();\n }, intervalMs);\n // Also process immediately\n void this.processQueue();\n }\n\n stop(): void {\n if (this.interval) {\n clearInterval(this.interval);\n this.interval = null;\n console.log(\"[sync-queue] Stopped\");\n }\n }\n\n async processQueue(): Promise<{ processed: number; succeeded: number; failed: number }> {\n if (this.processing) return { processed: 0, succeeded: 0, failed: 0 };\n this.processing = true;\n\n let processed = 0;\n let succeeded = 0;\n let failed = 0;\n\n try {\n const items = this.sqlite.getSyncQueue(50);\n if (items.length === 0) {\n return { processed: 0, succeeded: 0, failed: 0 };\n }\n\n console.log(`[sync-queue] Processing ${items.length} items`);\n\n for (const item of items) {\n processed++;\n try {\n await this.processItem(item);\n this.sqlite.removeSyncQueueItem(item.id);\n succeeded++;\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n this.sqlite.updateSyncQueueItem(item.id, item.attempts + 1, errorMsg);\n failed++;\n console.warn(\n `[sync-queue] Failed item ${item.id} (${item.layer}/${item.operation}/${item.memory_id}): ${errorMsg}`\n );\n }\n }\n\n const cleared = this.sqlite.clearCompletedSyncItems();\n if (cleared > 0) {\n console.log(`[sync-queue] Cleared ${cleared} items that exceeded max retries`);\n }\n } finally {\n this.processing = false;\n }\n\n if (processed > 0) {\n console.log(`[sync-queue] Done: ${succeeded} ok, ${failed} failed out of ${processed}`);\n }\n\n return { processed, succeeded, failed };\n }\n\n private async processItem(item: SyncQueueItem): Promise<void> {\n if (item.layer === \"qdrant\") {\n await this.processQdrantItem(item);\n } else if (item.layer === \"age\") {\n await this.processAgeItem(item);\n }\n }\n\n private async processQdrantItem(item: SyncQueueItem): Promise<void> {\n if (!this.qdrant) throw new Error(\"Qdrant layer not configured\");\n\n if (item.operation === \"delete\") {\n await this.qdrant.deleteMemory(item.memory_id);\n return;\n }\n\n const memory = this.sqlite.getMemory(item.memory_id);\n if (!memory) return; // Deleted since queuing\n\n if (!this.embeddings) throw new Error(\"Embedding service not configured\");\n const vector = await this.embeddings.embed(memory.content);\n if (!vector) throw new Error(\"Failed to generate embedding\");\n\n await this.qdrant.upsertMemory(memory, vector);\n }\n\n private async processAgeItem(item: SyncQueueItem): Promise<void> {\n if (!this.age) throw new Error(\"AGE layer not configured\");\n\n if (item.operation === \"delete\") {\n await this.age.deleteMemoryNode(item.memory_id);\n return;\n }\n\n const memory = this.sqlite.getMemory(item.memory_id);\n if (!memory) return;\n\n await this.age.upsertMemoryNode(memory);\n\n for (const entity of memory.entities) {\n const entityId = await this.age.upsertEntityNode(entity, memory.agent_id);\n await this.age.linkMemoryToEntity(memory.id, entityId);\n }\n }\n}\n","import OpenAI from \"openai\";\n\n// ── Embedding Service ───────────────────────────────────────────────────\n\nexport interface EmbeddingConfig {\n apiKey: string;\n baseUrl?: string;\n model: string;\n dimensions: number;\n}\n\nexport class EmbeddingService {\n private client: OpenAI;\n private model: string;\n private dimensions: number;\n\n constructor(config: EmbeddingConfig) {\n this.client = new OpenAI({\n apiKey: config.apiKey,\n baseURL: config.baseUrl,\n });\n this.model = config.model;\n this.dimensions = config.dimensions;\n }\n\n async embed(text: string): Promise<number[] | null> {\n if (!text || text.trim().length === 0) return null;\n\n try {\n const response = await this.client.embeddings.create({\n model: this.model,\n input: text.slice(0, 8000),\n });\n\n const embedding = response.data[0]?.embedding;\n if (!embedding || embedding.length === 0) {\n console.warn(\"[embeddings] Empty embedding returned\");\n return null;\n }\n\n return embedding;\n } catch (error) {\n console.error(`[embeddings] Failed to generate embedding: ${error}`);\n return null;\n }\n }\n\n async embedBatch(texts: string[]): Promise<(number[] | null)[]> {\n if (texts.length === 0) return [];\n\n try {\n const cleanTexts = texts.map((t) => (t || \"\").slice(0, 8000));\n const response = await this.client.embeddings.create({\n model: this.model,\n input: cleanTexts,\n });\n\n return response.data.map((item) =>\n item.embedding && item.embedding.length > 0 ? item.embedding : null\n );\n } catch (error) {\n console.error(`[embeddings] Batch embedding failed: ${error}`);\n return texts.map(() => null);\n }\n }\n\n getDimensions(): number {\n return this.dimensions;\n }\n}\n","import OpenAI from \"openai\";\nimport type { ExtractionResult, ExtractedEntity, ExtractedRelationship } from \"../core/types.js\";\n\n// ── Entity Extraction Prompt ────────────────────────────────────────────\n\nconst ENTITY_EXTRACTION_PROMPT = `Extract entities and relationships from this memory text.\n\nReturn JSON with this exact structure:\n{\n \"entities\": [\n {\n \"name\": \"exact name as mentioned\",\n \"type\": \"Person|Project|Organization|Decision|Preference|Event|Tool|Location|Concept\",\n \"properties\": { \"key\": \"value\" }\n }\n ],\n \"relationships\": [\n {\n \"from_entity\": \"entity name\",\n \"to_entity\": \"entity name\",\n \"relationship\": \"WORKS_ON|DECIDED|PREFERS|KNOWS|USES|LOCATED_AT|BELONGS_TO|RELATED_TO|CREATED_BY|DEPENDS_ON\",\n \"properties\": { \"context\": \"brief context\" }\n }\n ]\n}\n\nRules:\n- Only extract clearly stated entities, don't infer\n- Use the most specific entity type possible\n- Normalize person names to their full form when possible\n- For preferences, use key/value format (key = category, value = preference)\n- Keep properties minimal — only include what's explicitly stated\n- If no entities are found, return {\"entities\": [], \"relationships\": []}`;\n\n// ── Entity Extractor ────────────────────────────────────────────────────\n\nexport interface ExtractionConfig {\n apiKey: string;\n baseUrl?: string;\n model: string;\n enabled: boolean;\n}\n\nexport class EntityExtractor {\n private client: OpenAI;\n private model: string;\n\n constructor(config: ExtractionConfig) {\n this.client = new OpenAI({\n apiKey: config.apiKey,\n baseURL: config.baseUrl,\n });\n this.model = config.model;\n }\n\n async extract(text: string): Promise<ExtractionResult> {\n if (!text || text.trim().length < 20) {\n return { entities: [], relationships: [] };\n }\n\n try {\n const response = await this.client.chat.completions.create({\n model: this.model,\n messages: [\n { role: \"system\", content: ENTITY_EXTRACTION_PROMPT },\n { role: \"user\", content: text.slice(0, 4000) },\n ],\n temperature: 0.1,\n max_tokens: 1500,\n response_format: { type: \"json_object\" },\n });\n\n const content = response.choices[0]?.message?.content;\n if (!content) {\n return { entities: [], relationships: [] };\n }\n\n const parsed = JSON.parse(content);\n return this.validateExtractionResult(parsed);\n } catch (error) {\n console.error(`[entity-extractor] Extraction failed: ${error}`);\n return { entities: [], relationships: [] };\n }\n }\n\n private validateExtractionResult(data: unknown): ExtractionResult {\n if (!data || typeof data !== \"object\") {\n return { entities: [], relationships: [] };\n }\n\n const raw = data as Record<string, unknown>;\n const entities: ExtractedEntity[] = [];\n const relationships: ExtractedRelationship[] = [];\n\n const validTypes = [\n \"Person\", \"Project\", \"Organization\", \"Decision\",\n \"Preference\", \"Event\", \"Tool\", \"Location\", \"Concept\",\n ];\n const validRels = [\n \"WORKS_ON\", \"DECIDED\", \"PREFERS\", \"KNOWS\", \"USES\",\n \"LOCATED_AT\", \"BELONGS_TO\", \"RELATED_TO\", \"CREATED_BY\", \"DEPENDS_ON\",\n ];\n\n if (Array.isArray(raw.entities)) {\n for (const e of raw.entities) {\n if (e && typeof e === \"object\" && typeof e.name === \"string\" && typeof e.type === \"string\") {\n entities.push({\n name: e.name,\n type: validTypes.includes(e.type) ? e.type : \"Concept\",\n properties: (typeof e.properties === \"object\" && e.properties !== null)\n ? Object.fromEntries(\n Object.entries(e.properties as Record<string, unknown>).map(([k, v]) => [k, String(v)])\n )\n : {},\n });\n }\n }\n }\n\n if (Array.isArray(raw.relationships)) {\n for (const r of raw.relationships) {\n if (\n r &&\n typeof r === \"object\" &&\n typeof r.from_entity === \"string\" &&\n typeof r.to_entity === \"string\" &&\n typeof r.relationship === \"string\"\n ) {\n relationships.push({\n from_entity: r.from_entity,\n to_entity: r.to_entity,\n relationship: validRels.includes(r.relationship) ? r.relationship : \"RELATED_TO\",\n properties: (typeof r.properties === \"object\" && r.properties !== null)\n ? Object.fromEntries(\n Object.entries(r.properties as Record<string, unknown>).map(([k, v]) => [k, String(v)])\n )\n : {},\n });\n }\n }\n }\n\n return { entities, relationships };\n }\n}\n","import type { SearchRequest } from \"../core/types.js\";\n\nexport type Strategy =\n | \"fulltext+graph\"\n | \"graph+semantic\"\n | \"semantic+graph\"\n | \"semantic\"\n | \"fulltext\"\n | \"graph\"\n | \"all\";\n\n// ── Key Lookup Patterns ─────────────────────────────────────────────────\n\nconst KEY_LOOKUP_PATTERNS = [\n /what is .+'s/i,\n /what are .+'s/i,\n /.+'s (email|phone|address|preference|setting)/i,\n /^(get|find|show|tell me) .+'s/i,\n /^what (does|did) .+ (like|prefer|use|want)/i,\n];\n\n// ── Relationship Query Patterns ─────────────────────────────────────────\n\nconst RELATIONSHIP_PATTERNS = [\n /who (works on|knows|created|manages|uses)/i,\n /what.+(connected|related|linked|associated) (to|with)/i,\n /how (is|are) .+ (related|connected)/i,\n /relationship between/i,\n /(works on|belongs to|depends on|uses)/i,\n /what projects does/i,\n /who is involved (in|with)/i,\n];\n\n// ── Strategy Selection ──────────────────────────────────────────────────\n\nexport function selectStrategy(request: SearchRequest): Strategy {\n if (request.strategy && request.strategy !== \"auto\") {\n switch (request.strategy) {\n case \"semantic\": return \"semantic\";\n case \"fulltext\": return \"fulltext\";\n case \"graph\": return \"graph\";\n case \"all\": return \"all\";\n default: break;\n }\n }\n\n const query = request.query.toLowerCase();\n\n if (isKeyLookup(query)) return \"fulltext+graph\";\n if (isRelationshipQuery(query)) return \"graph+semantic\";\n\n return \"semantic+graph\";\n}\n\nfunction isKeyLookup(query: string): boolean {\n return KEY_LOOKUP_PATTERNS.some((pattern) => pattern.test(query));\n}\n\nfunction isRelationshipQuery(query: string): boolean {\n return RELATIONSHIP_PATTERNS.some((pattern) => pattern.test(query));\n}\n","import type { ScoredMemory } from \"../core/types.js\";\n\n// ── Score Normalization ─────────────────────────────────────────────────\n\n/**\n * Normalize FTS5 BM25 rank to 0.0-1.0 range.\n * BM25 ranks are negative (more negative = better match).\n */\nexport function normalizeFtsScore(rank: number): number {\n const normalized = Math.min(1.0, Math.max(0.0, -rank / 20.0));\n return normalized;\n}\n\n/**\n * Normalize graph distance to a score (closer = higher).\n */\nexport function normalizeGraphScore(hopDistance: number): number {\n return 1.0 / (1 + hopDistance);\n}\n\n// ── Recency Boost ───────────────────────────────────────────────────────\n\n/**\n * Apply a recency decay factor.\n * Score multiplier = max(0.5, 0.95^days_old)\n */\nexport function recencyBoost(createdAt: string): number {\n const created = new Date(createdAt).getTime();\n const now = Date.now();\n const daysOld = (now - created) / (1000 * 60 * 60 * 24);\n return Math.max(0.5, Math.pow(0.95, daysOld));\n}\n\n// ── Multi-Layer Boost ───────────────────────────────────────────────────\n\n/**\n * Boost score for memories that appear in multiple layers.\n * +0.1 per extra layer.\n */\nexport function multiLayerBoost(layerCount: number): number {\n return (layerCount - 1) * 0.1;\n}\n\n// ── Apply All Boosts ────────────────────────────────────────────────────\n\nexport function applyBoosts(result: ScoredMemory, layerAppearances: number): ScoredMemory {\n let score = result.score;\n\n if (result.memory.created_at) {\n score *= recencyBoost(result.memory.created_at);\n }\n\n score += multiLayerBoost(layerAppearances);\n\n score = Math.min(1.0, Math.max(0.0, score));\n\n return { ...result, score };\n}\n","import type { ScoredMemory, SearchResponse, SearchRequest, MemoryScope } from \"../core/types.js\";\nimport type { StorageOrchestrator } from \"../storage/orchestrator.js\";\nimport { selectStrategy, type Strategy } from \"./strategy.js\";\nimport { normalizeFtsScore, applyBoosts } from \"./ranker.js\";\n\n// ── Search Engine ───────────────────────────────────────────────────────\n\nexport class SearchEngine {\n private orchestrator: StorageOrchestrator;\n\n constructor(orchestrator: StorageOrchestrator) {\n this.orchestrator = orchestrator;\n }\n\n async search(request: SearchRequest): Promise<SearchResponse> {\n const strategy = selectStrategy(request);\n const limit = request.limit || 10;\n const scopes = request.scopes || [\"user\", \"agent\", \"global\"];\n const includeGraph = request.include_graph !== false;\n\n const layerStats = {\n sqlite: { count: 0, ms: 0 },\n qdrant: { count: 0, ms: 0 },\n age: { count: 0, ms: 0 },\n };\n\n const allResults: ScoredMemory[] = [];\n const searches: Promise<void>[] = [];\n\n if (shouldSearchFulltext(strategy)) {\n searches.push(\n this.searchFulltext(request, scopes, limit).then((results) => {\n layerStats.sqlite.count = results.length;\n allResults.push(...results);\n })\n );\n }\n\n if (shouldSearchSemantic(strategy) && this.orchestrator.qdrant && this.orchestrator.embeddings) {\n searches.push(\n this.searchSemantic(request, scopes, limit).then((results) => {\n layerStats.qdrant.count = results.length;\n allResults.push(...results);\n })\n );\n }\n\n if (shouldSearchGraph(strategy) && includeGraph && this.orchestrator.age) {\n searches.push(\n this.searchGraph(request, limit).then((results) => {\n layerStats.age.count = results.length;\n allResults.push(...results);\n })\n );\n }\n\n const startTime = Date.now();\n await Promise.allSettled(searches);\n const elapsed = Date.now() - startTime;\n\n if (layerStats.sqlite.count > 0) layerStats.sqlite.ms = elapsed;\n if (layerStats.qdrant.count > 0) layerStats.qdrant.ms = elapsed;\n if (layerStats.age.count > 0) layerStats.age.ms = elapsed;\n\n const merged = this.mergeResults(allResults, limit);\n\n return {\n results: merged,\n strategy_used: strategy,\n layer_stats: layerStats,\n };\n }\n\n // ── Layer-Specific Searches ─────────────────────────────────────────\n\n private async searchFulltext(\n request: SearchRequest,\n scopes: MemoryScope[],\n limit: number\n ): Promise<ScoredMemory[]> {\n try {\n const results = this.orchestrator.sqlite.searchFullText(\n request.query,\n request.cross_agent ? undefined : request.agent_id,\n scopes,\n request.subject_id,\n limit\n );\n\n return results.map((r) => ({\n memory: r,\n score: normalizeFtsScore(r.fts_rank),\n source_layer: \"sqlite\" as const,\n }));\n } catch (error) {\n console.warn(`[search] Fulltext search failed: ${error}`);\n return [];\n }\n }\n\n private async searchSemantic(\n request: SearchRequest,\n scopes: MemoryScope[],\n limit: number\n ): Promise<ScoredMemory[]> {\n try {\n if (!this.orchestrator.embeddings || !this.orchestrator.qdrant) return [];\n\n const queryVector = await this.orchestrator.embeddings.embed(request.query);\n if (!queryVector) return [];\n\n return await this.orchestrator.qdrant.search(\n queryVector,\n request.cross_agent ? undefined : request.agent_id,\n scopes,\n request.subject_id,\n limit,\n request.cross_agent\n );\n } catch (error) {\n console.warn(`[search] Semantic search failed: ${error}`);\n return [];\n }\n }\n\n private async searchGraph(\n request: SearchRequest,\n limit: number\n ): Promise<ScoredMemory[]> {\n try {\n if (!this.orchestrator.age) return [];\n\n const entityName = extractEntityFromQuery(request.query);\n if (!entityName) return [];\n\n return await this.orchestrator.age.searchByEntity(\n entityName,\n undefined,\n request.cross_agent ? undefined : request.agent_id,\n limit\n );\n } catch (error) {\n console.warn(`[search] Graph search failed: ${error}`);\n return [];\n }\n }\n\n // ── Result Merging ──────────────────────────────────────────────────\n\n private mergeResults(\n allResults: ScoredMemory[],\n limit: number\n ): ScoredMemory[] {\n // 1. Group by memory ID\n const byId = new Map<string, ScoredMemory[]>();\n for (const result of allResults) {\n const existing = byId.get(result.memory.id) || [];\n existing.push(result);\n byId.set(result.memory.id, existing);\n }\n\n // 2. For each group, take best + apply boosts\n const merged: ScoredMemory[] = [];\n for (const [_id, results] of byId) {\n results.sort((a, b) => b.score - a.score);\n const best = results[0];\n\n const graphContext = results\n .filter((r) => r.graph_context)\n .flatMap((r) => r.graph_context!.related_entities);\n\n const boosted = applyBoosts(best, results.length);\n\n if (graphContext.length > 0) {\n boosted.graph_context = { related_entities: graphContext };\n }\n\n merged.push(boosted);\n }\n\n // 3. Sort by final score descending\n merged.sort((a, b) => b.score - a.score);\n\n return merged.slice(0, limit);\n }\n}\n\n// ── Helper Functions ────────────────────────────────────────────────────\n\nfunction shouldSearchFulltext(strategy: Strategy): boolean {\n return [\"fulltext\", \"fulltext+graph\", \"all\"].includes(strategy);\n}\n\nfunction shouldSearchSemantic(strategy: Strategy): boolean {\n return [\"semantic\", \"semantic+graph\", \"graph+semantic\", \"all\"].includes(strategy);\n}\n\nfunction shouldSearchGraph(strategy: Strategy): boolean {\n return [\"graph\", \"fulltext+graph\", \"graph+semantic\", \"semantic+graph\", \"all\"].includes(strategy);\n}\n\n/**\n * Extract potential entity names from natural language queries.\n */\nfunction extractEntityFromQuery(query: string): string | null {\n const quoted = query.match(/[\"']([^\"']+)[\"']/);\n if (quoted) return quoted[1];\n\n const aboutMatch = query.match(\n /(?:about|on|for|regarding|related to|connected to)\\s+([A-Z][a-zA-Z]*(?:\\s+[A-Z][a-zA-Z]*)*)/i\n );\n if (aboutMatch) return aboutMatch[1];\n\n const capitalWords = query.match(/\\b[A-Z][a-zA-Z]+(?:\\s+[A-Z][a-zA-Z]+)*/g);\n if (capitalWords && capitalWords.length > 0) {\n return capitalWords.sort((a, b) => b.length - a.length)[0];\n }\n\n const whoPattern = query.match(\n /who\\s+(?:works on|knows|created|uses|manages)\\s+(.+)/i\n );\n if (whoPattern) return whoPattern[1].trim();\n\n if (query.split(/\\s+/).length <= 3) {\n return query.trim();\n }\n\n return null;\n}\n","import OpenAI from \"openai\";\n\n// ── Summarization Prompt ────────────────────────────────────────────────\n\nconst SUMMARIZE_PROMPT = `Summarize this conversation into 5-10 concise bullet points.\nFocus on:\n- Decisions made\n- Tasks discussed or assigned\n- Preferences expressed\n- Important facts learned\n- Action items or next steps\n\nBe specific. Use names and details. Skip pleasantries and meta-conversation.\nReturn the summary as a plain text bulleted list.`;\n\n// ── Conversation Summarizer ─────────────────────────────────────────────\n\nexport interface SummarizerConfig {\n apiKey: string;\n baseUrl?: string;\n model: string;\n}\n\nexport class ConversationSummarizer {\n private client: OpenAI;\n private model: string;\n\n constructor(config: SummarizerConfig) {\n this.client = new OpenAI({\n apiKey: config.apiKey,\n baseURL: config.baseUrl,\n });\n this.model = config.model;\n }\n\n async summarize(\n messages: Array<{ role: string; content: string; timestamp?: string }>\n ): Promise<string | null> {\n if (messages.length === 0) return null;\n\n const transcript = messages\n .map((m) => {\n const prefix = m.role === \"user\" ? \"User\" : m.role === \"assistant\" ? \"Assistant\" : \"System\";\n return `${prefix}: ${m.content}`;\n })\n .join(\"\\n\");\n\n const truncated = transcript.slice(-6000);\n\n try {\n const response = await this.client.chat.completions.create({\n model: this.model,\n messages: [\n { role: \"system\", content: SUMMARIZE_PROMPT },\n { role: \"user\", content: truncated },\n ],\n temperature: 0.2,\n max_tokens: 500,\n });\n\n const content = response.choices[0]?.message?.content?.trim();\n return content || null;\n } catch (error) {\n console.error(`[summarizer] Summarization failed: ${error}`);\n return null;\n }\n }\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/storage/orchestrator.ts","../src/storage/sqlite.ts","../src/storage/qdrant.ts","../src/storage/age.ts","../src/storage/sync-queue.ts","../src/extraction/embeddings.ts","../src/extraction/entity-extractor.ts","../src/search/strategy.ts","../src/search/ranker.ts","../src/search/engine.ts","../src/extraction/summarizer.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport type { ResolvedConfig } from \"../config/index.js\";\nimport { SqliteStorage } from \"./sqlite.js\";\nimport { QdrantStorage } from \"./qdrant.js\";\nimport { AgeStorage } from \"./age.js\";\nimport { SyncQueueProcessor } from \"./sync-queue.js\";\nimport { EmbeddingService } from \"../extraction/embeddings.js\";\nimport { EntityExtractor } from \"../extraction/entity-extractor.js\";\nimport type {\n Tier,\n Memory,\n CreateMemoryRequest,\n UpdateMemoryRequest,\n SyncStatus,\n CreateMemoryResponse,\n ExtractedEntity,\n ExtractedRelationship,\n HealthResponse,\n} from \"../core/types.js\";\nimport { v7 as uuidv7 } from \"uuid\";\n\n// ── Storage Orchestrator ────────────────────────────────────────────────\n\nexport class StorageOrchestrator {\n readonly tier: Tier;\n readonly sqlite: SqliteStorage;\n readonly qdrant: QdrantStorage | null;\n readonly age: AgeStorage | null;\n readonly embeddings: EmbeddingService | null;\n readonly entityExtractor: EntityExtractor | null;\n private syncProcessor: SyncQueueProcessor;\n private startTime: number;\n\n constructor(config: ResolvedConfig) {\n this.tier = config.tier;\n this.sqlite = new SqliteStorage(config.sqlite.path);\n this.startTime = Date.now();\n\n // L2: Qdrant — only for standard/full tiers\n if (config.qdrant) {\n this.qdrant = new QdrantStorage(config.qdrant);\n } else {\n this.qdrant = null;\n }\n\n // L3: AGE — only for full tier\n if (config.age) {\n this.age = new AgeStorage(config.age);\n } else {\n this.age = null;\n }\n\n // Embeddings — needed for Qdrant\n if (config.embedding) {\n this.embeddings = new EmbeddingService(config.embedding);\n } else {\n this.embeddings = null;\n }\n\n // Entity extraction — for standard/full\n if (config.extraction && config.extraction.enabled) {\n this.entityExtractor = new EntityExtractor(config.extraction);\n } else {\n this.entityExtractor = null;\n }\n\n this.syncProcessor = new SyncQueueProcessor(\n this.sqlite,\n this.qdrant,\n this.age,\n this.embeddings\n );\n }\n\n async init(): Promise<void> {\n // Initialize L2 if available\n if (this.qdrant) {\n try {\n const dimensions = this.embeddings?.getDimensions() || 1536;\n await this.qdrant.ensureCollection(dimensions);\n console.log(\"[orchestrator] Qdrant collection ready\");\n } catch (error) {\n console.warn(`[orchestrator] Qdrant init failed (will retry): ${error}`);\n }\n }\n\n // Initialize L3 if available\n if (this.age) {\n try {\n await this.age.ensureGraph();\n console.log(\"[orchestrator] AGE graph ready\");\n } catch (error) {\n console.warn(`[orchestrator] AGE init failed (will retry): ${error}`);\n }\n }\n\n // Start sync queue processor if we have L2 or L3\n if (this.qdrant || this.age) {\n this.syncProcessor.start(60_000);\n }\n }\n\n // ── Create Memory ───────────────────────────────────────────────────\n\n async createMemory(req: CreateMemoryRequest): Promise<CreateMemoryResponse> {\n const now = new Date().toISOString();\n const id = uuidv7();\n\n // Extract entities if extractor is available and requested\n let entities: ExtractedEntity[] = [];\n let relationships: ExtractedRelationship[] = [];\n const shouldExtract =\n this.entityExtractor &&\n req.extract_entities !== false &&\n req.content.length >= 20 &&\n req.source !== \"entity_extraction\";\n\n if (shouldExtract) {\n try {\n const extraction = await this.entityExtractor!.extract(req.content);\n entities = extraction.entities;\n relationships = extraction.relationships;\n } catch (error) {\n console.warn(`[orchestrator] Entity extraction failed: ${error}`);\n }\n }\n\n const embeddingHash = contentHash(req.content);\n\n const memory: Memory = {\n id,\n agent_id: req.agent_id,\n scope: req.scope,\n subject_id: req.subject_id ?? null,\n content: req.content,\n tags: req.tags || [],\n entities,\n source: req.source || \"explicit\",\n created_by: req.created_by ?? null,\n created_at: now,\n updated_at: now,\n expires_at: req.expires_at ?? null,\n embedding_hash: embeddingHash,\n };\n\n // L1: SQLite — authoritative, synchronous\n this.sqlite.createMemory(memory);\n\n // L2: Qdrant — async best-effort\n const qdrantStatus = await this.asyncL2Upsert(memory);\n\n // L3: AGE — async best-effort\n const ageStatus = await this.asyncL3Upsert(memory, entities, relationships);\n\n return {\n id: memory.id,\n agent_id: memory.agent_id,\n scope: memory.scope,\n content: memory.content,\n entities: memory.entities,\n created_at: memory.created_at,\n sync_status: {\n sqlite: \"ok\",\n qdrant: qdrantStatus,\n age: ageStatus,\n },\n };\n }\n\n // ── Update Memory ───────────────────────────────────────────────────\n\n async updateMemory(\n id: string,\n req: UpdateMemoryRequest\n ): Promise<CreateMemoryResponse | null> {\n const existing = this.sqlite.getMemory(id);\n if (!existing) return null;\n\n let entities = existing.entities;\n let relationships: ExtractedRelationship[] = [];\n if (req.content && req.content !== existing.content) {\n const shouldExtract =\n this.entityExtractor &&\n req.extract_entities !== false &&\n req.content.length >= 20;\n if (shouldExtract) {\n try {\n const extraction = await this.entityExtractor!.extract(req.content);\n entities = extraction.entities;\n relationships = extraction.relationships;\n } catch (error) {\n console.warn(`[orchestrator] Entity extraction failed on update: ${error}`);\n }\n }\n }\n\n const embeddingHash = req.content\n ? contentHash(req.content)\n : existing.embedding_hash;\n\n const updates: Partial<Memory> = {\n ...(req.content !== undefined && { content: req.content }),\n ...(req.tags !== undefined && { tags: req.tags }),\n ...(req.scope !== undefined && { scope: req.scope }),\n ...(req.subject_id !== undefined && { subject_id: req.subject_id }),\n ...(req.expires_at !== undefined && { expires_at: req.expires_at }),\n entities,\n embedding_hash: embeddingHash,\n };\n\n const updated = this.sqlite.updateMemory(id, updates);\n if (!updated) return null;\n\n const qdrantStatus = await this.asyncL2Upsert(updated);\n const ageStatus = await this.asyncL3Upsert(updated, entities, relationships);\n\n return {\n id: updated.id,\n agent_id: updated.agent_id,\n scope: updated.scope,\n content: updated.content,\n tags: updated.tags,\n entities: updated.entities,\n created_at: updated.created_at,\n updated_at: updated.updated_at,\n sync_status: {\n sqlite: \"ok\",\n qdrant: qdrantStatus,\n age: ageStatus,\n },\n };\n }\n\n // ── Delete Memory ───────────────────────────────────────────────────\n\n async deleteMemory(id: string): Promise<boolean> {\n const deleted = this.sqlite.deleteMemory(id);\n if (!deleted) return false;\n\n // L2: Qdrant\n if (this.qdrant) {\n try {\n await this.qdrant.deleteMemory(id);\n } catch (error) {\n console.warn(`[orchestrator] Qdrant delete failed, queuing: ${error}`);\n this.sqlite.addToSyncQueue(id, \"qdrant\", \"delete\");\n }\n }\n\n // L3: AGE\n if (this.age) {\n try {\n await this.age.deleteMemoryNode(id);\n } catch (error) {\n console.warn(`[orchestrator] AGE delete failed, queuing: ${error}`);\n this.sqlite.addToSyncQueue(id, \"age\", \"delete\");\n }\n }\n\n return true;\n }\n\n // ── Health Check ────────────────────────────────────────────────────\n\n async healthCheck(): Promise<HealthResponse> {\n const details: Record<string, string> = {};\n\n const sqliteOk = this.sqlite.healthCheck();\n if (!sqliteOk) details.sqlite = \"SQLite health check failed\";\n\n let qdrantStatus: \"ok\" | \"error\" | \"disabled\" = \"disabled\";\n if (this.qdrant) {\n try {\n qdrantStatus = (await this.qdrant.healthCheck()) ? \"ok\" : \"error\";\n } catch (error) {\n qdrantStatus = \"error\";\n details.qdrant = String(error);\n }\n }\n\n let ageStatus: \"ok\" | \"error\" | \"disabled\" = \"disabled\";\n if (this.age) {\n try {\n ageStatus = (await this.age.healthCheck()) ? \"ok\" : \"error\";\n } catch (error) {\n ageStatus = \"error\";\n details.age = String(error);\n }\n }\n\n return {\n sqlite: sqliteOk ? \"ok\" : \"error\",\n qdrant: qdrantStatus,\n age: ageStatus,\n tier: this.tier,\n uptime: Math.floor((Date.now() - this.startTime) / 1000),\n ...(Object.keys(details).length > 0 && { details }),\n };\n }\n\n // ── Retry Sync ──────────────────────────────────────────────────────\n\n async retrySyncQueue(): Promise<{\n processed: number;\n succeeded: number;\n failed: number;\n }> {\n return this.syncProcessor.processQueue();\n }\n\n // ── Cleanup ─────────────────────────────────────────────────────────\n\n async close(): Promise<void> {\n this.syncProcessor.stop();\n this.sqlite.close();\n if (this.age) await this.age.close();\n }\n\n // ── Private Helpers ─────────────────────────────────────────────────\n\n private async asyncL2Upsert(\n memory: Memory\n ): Promise<\"ok\" | \"queued\" | \"failed\" | \"disabled\"> {\n if (!this.qdrant || !this.embeddings) return \"disabled\";\n\n try {\n const vector = await this.embeddings.embed(memory.content);\n if (!vector) {\n this.sqlite.addToSyncQueue(memory.id, \"qdrant\", \"upsert\");\n return \"queued\";\n }\n await this.qdrant.upsertMemory(memory, vector);\n this.sqlite.updateMemory(memory.id, {\n embedding_hash: contentHash(memory.content),\n });\n return \"ok\";\n } catch (error) {\n console.warn(`[orchestrator] Qdrant upsert failed, queuing: ${error}`);\n this.sqlite.addToSyncQueue(memory.id, \"qdrant\", \"upsert\");\n return \"queued\";\n }\n }\n\n private async asyncL3Upsert(\n memory: Memory,\n entities: ExtractedEntity[],\n relationships: ExtractedRelationship[]\n ): Promise<\"ok\" | \"queued\" | \"failed\" | \"disabled\"> {\n if (!this.age) return \"disabled\";\n\n try {\n await this.age.upsertMemoryNode(memory);\n\n for (const entity of entities) {\n const entityId = await this.age.upsertEntityNode(entity, memory.agent_id);\n await this.age.linkMemoryToEntity(memory.id, entityId);\n }\n\n for (const rel of relationships) {\n await this.age.createRelationship(rel, memory.agent_id);\n }\n\n return \"ok\";\n } catch (error) {\n console.warn(`[orchestrator] AGE upsert failed, queuing: ${error}`);\n this.sqlite.addToSyncQueue(memory.id, \"age\", \"upsert\");\n return \"queued\";\n }\n }\n}\n\n// ── Utility ─────────────────────────────────────────────────────────────\n\nfunction contentHash(content: string): string {\n // Use crypto.createHash for universal Node/Bun compatibility\n return createHash(\"sha256\").update(content).digest(\"hex\").slice(0, 16);\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { createRequire } from \"node:module\";\nimport type {\n Memory,\n MemoryScope,\n MemorySource,\n ExtractedEntity,\n ConversationLogEntry,\n SyncQueueItem,\n ListMemoriesQuery,\n} from \"../core/types.js\";\n\n// ── SQLite Row Types ────────────────────────────────────────────────────\n\ninterface MemoryRow {\n id: string;\n agent_id: string;\n scope: string;\n subject_id: string | null;\n content: string;\n tags: string;\n entities: string;\n source: string;\n created_by: string | null;\n created_at: string;\n updated_at: string;\n expires_at: string | null;\n embedding_hash: string | null;\n}\n\ninterface SyncQueueRow {\n id: number;\n memory_id: string;\n layer: string;\n operation: string;\n attempts: number;\n last_error: string | null;\n created_at: string;\n}\n\n// ── Database Adapter ────────────────────────────────────────────────────\n// Abstracts over bun:sqlite (Bun) and better-sqlite3 (Node)\n\ninterface DbAdapter {\n exec(sql: string): void;\n prepare(sql: string): StmtAdapter;\n close(): void;\n}\n\ninterface StmtAdapter {\n run(params?: Record<string, unknown>): { changes: number };\n get(params?: Record<string, unknown>): unknown;\n all(params?: Record<string, unknown>): unknown[];\n}\n\nfunction createDatabase(dbPath: string): DbAdapter {\n // Bun: use bun:sqlite\n if (typeof globalThis.Bun !== \"undefined\") {\n // In Bun, require() is available globally\n const req = createRequire(import.meta.url);\n const { Database } = req(\"bun:sqlite\") as {\n Database: new (path: string, opts?: { create?: boolean }) => {\n exec(sql: string): void;\n prepare(sql: string): {\n run(params?: Record<string, unknown>): { changes: number };\n get(params?: Record<string, unknown>): unknown;\n all(params?: Record<string, unknown>): unknown[];\n };\n close(): void;\n };\n };\n const db = new Database(dbPath, { create: true });\n return {\n exec: (sql: string) => db.exec(sql),\n prepare: (sql: string) => {\n const stmt = db.prepare(sql);\n return {\n run: (params?: Record<string, unknown>) => stmt.run(params || {}),\n get: (params?: Record<string, unknown>) => stmt.get(params || {}),\n all: (params?: Record<string, unknown>) => stmt.all(params || {}),\n };\n },\n close: () => db.close(),\n };\n }\n\n // Node: use better-sqlite3\n try {\n // Use createRequire for CommonJS optional dependency in ESM context\n const req = createRequire(import.meta.url);\n const Database = req(\"better-sqlite3\") as typeof import(\"better-sqlite3\");\n const db = new Database(dbPath);\n return {\n exec: (sql: string) => db.exec(sql),\n prepare: (sql: string) => {\n const stmt = db.prepare(sql);\n return {\n run: (params?: Record<string, unknown>) => {\n const result = stmt.run(params || {});\n return { changes: result.changes };\n },\n get: (params?: Record<string, unknown>) => stmt.get(params || {}),\n all: (params?: Record<string, unknown>) => stmt.all(params || {}),\n };\n },\n close: () => db.close(),\n };\n } catch {\n throw new Error(\n \"No SQLite driver available. Install better-sqlite3 for Node.js, or use Bun runtime.\"\n );\n }\n}\n\n// ── SQLite Storage Layer ────────────────────────────────────────────────\n\nexport class SqliteStorage {\n private db: DbAdapter;\n\n constructor(dbPath: string) {\n fs.mkdirSync(path.dirname(dbPath), { recursive: true });\n this.db = createDatabase(dbPath);\n this.db.exec(\"PRAGMA journal_mode = WAL\");\n this.db.exec(\"PRAGMA busy_timeout = 5000\");\n this.db.exec(\"PRAGMA synchronous = NORMAL\");\n this.db.exec(\"PRAGMA foreign_keys = ON\");\n this.initSchema();\n }\n\n // ── Schema ──────────────────────────────────────────────────────────\n\n private initSchema(): void {\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS memories (\n id TEXT PRIMARY KEY,\n agent_id TEXT NOT NULL,\n scope TEXT NOT NULL CHECK (scope IN ('user', 'agent', 'global', 'project', 'session')),\n subject_id TEXT,\n content TEXT NOT NULL,\n tags TEXT NOT NULL DEFAULT '[]',\n entities TEXT NOT NULL DEFAULT '[]',\n source TEXT NOT NULL DEFAULT 'explicit',\n created_by TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n expires_at TEXT,\n embedding_hash TEXT\n );\n\n CREATE INDEX IF NOT EXISTS idx_mem_agent ON memories(agent_id);\n CREATE INDEX IF NOT EXISTS idx_mem_scope ON memories(scope);\n CREATE INDEX IF NOT EXISTS idx_mem_subject ON memories(subject_id);\n CREATE INDEX IF NOT EXISTS idx_mem_agent_scope ON memories(agent_id, scope);\n CREATE INDEX IF NOT EXISTS idx_mem_created ON memories(created_at);\n CREATE INDEX IF NOT EXISTS idx_mem_source ON memories(source);\n `);\n\n // FTS5 virtual table for full-text search\n const ftsExists = this.db\n .prepare(\"SELECT name FROM sqlite_master WHERE type='table' AND name='memories_fts'\")\n .get();\n\n if (!ftsExists) {\n this.db.exec(`\n CREATE VIRTUAL TABLE memories_fts USING fts5(\n content,\n tags,\n content=memories,\n content_rowid=rowid\n );\n\n CREATE TRIGGER mem_fts_insert AFTER INSERT ON memories BEGIN\n INSERT INTO memories_fts(rowid, content, tags)\n VALUES (new.rowid, new.content, new.tags);\n END;\n\n CREATE TRIGGER mem_fts_delete AFTER DELETE ON memories BEGIN\n INSERT INTO memories_fts(memories_fts, rowid, content, tags)\n VALUES ('delete', old.rowid, old.content, old.tags);\n END;\n\n CREATE TRIGGER mem_fts_update AFTER UPDATE ON memories BEGIN\n INSERT INTO memories_fts(memories_fts, rowid, content, tags)\n VALUES ('delete', old.rowid, old.content, old.tags);\n INSERT INTO memories_fts(rowid, content, tags)\n VALUES (new.rowid, new.content, new.tags);\n END;\n `);\n }\n\n // Conversation log table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS conversation_log (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n agent_id TEXT NOT NULL,\n session_id TEXT NOT NULL,\n user_id TEXT NOT NULL,\n channel TEXT NOT NULL,\n role TEXT NOT NULL,\n content TEXT NOT NULL,\n timestamp TEXT NOT NULL\n );\n\n CREATE INDEX IF NOT EXISTS idx_convlog_agent ON conversation_log(agent_id);\n CREATE INDEX IF NOT EXISTS idx_convlog_session ON conversation_log(session_id);\n CREATE INDEX IF NOT EXISTS idx_convlog_ts ON conversation_log(timestamp);\n `);\n\n // Sync queue table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS sync_queue (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n memory_id TEXT NOT NULL,\n layer TEXT NOT NULL CHECK (layer IN ('qdrant', 'age')),\n operation TEXT NOT NULL CHECK (operation IN ('upsert', 'delete')),\n attempts INTEGER NOT NULL DEFAULT 0,\n last_error TEXT,\n created_at TEXT NOT NULL,\n UNIQUE(memory_id, layer, operation)\n );\n `);\n }\n\n // ── Memory CRUD ─────────────────────────────────────────────────────\n\n createMemory(memory: Memory): Memory {\n this.db.prepare(`\n INSERT INTO memories (id, agent_id, scope, subject_id, content, tags, entities, source, created_by, created_at, updated_at, expires_at, embedding_hash)\n VALUES ($id, $agent_id, $scope, $subject_id, $content, $tags, $entities, $source, $created_by, $created_at, $updated_at, $expires_at, $embedding_hash)\n `).run({\n $id: memory.id,\n $agent_id: memory.agent_id,\n $scope: memory.scope,\n $subject_id: memory.subject_id,\n $content: memory.content,\n $tags: JSON.stringify(memory.tags),\n $entities: JSON.stringify(memory.entities),\n $source: memory.source,\n $created_by: memory.created_by,\n $created_at: memory.created_at,\n $updated_at: memory.updated_at,\n $expires_at: memory.expires_at,\n $embedding_hash: memory.embedding_hash,\n });\n return memory;\n }\n\n getMemory(id: string): Memory | null {\n const row = this.db\n .prepare(\"SELECT * FROM memories WHERE id = $id\")\n .get({ $id: id }) as MemoryRow | null;\n if (!row) return null;\n return this.rowToMemory(row);\n }\n\n updateMemory(id: string, updates: Partial<Memory>): Memory | null {\n const existing = this.getMemory(id);\n if (!existing) return null;\n\n const updated: Memory = {\n ...existing,\n ...updates,\n id: existing.id,\n updated_at: new Date().toISOString(),\n };\n\n this.db.prepare(`\n UPDATE memories SET\n content = $content, tags = $tags, entities = $entities, scope = $scope, subject_id = $subject_id,\n expires_at = $expires_at, embedding_hash = $embedding_hash, updated_at = $updated_at\n WHERE id = $id\n `).run({\n $content: updated.content,\n $tags: JSON.stringify(updated.tags),\n $entities: JSON.stringify(updated.entities),\n $scope: updated.scope,\n $subject_id: updated.subject_id,\n $expires_at: updated.expires_at,\n $embedding_hash: updated.embedding_hash,\n $updated_at: updated.updated_at,\n $id: id,\n });\n return updated;\n }\n\n deleteMemory(id: string): boolean {\n const result = this.db.prepare(\"DELETE FROM memories WHERE id = $id\").run({ $id: id });\n return result.changes > 0;\n }\n\n listMemories(query: ListMemoriesQuery): Memory[] {\n const conditions: string[] = [];\n const params: Record<string, unknown> = {};\n\n if (query.agent_id) {\n conditions.push(\"agent_id = $agent_id\");\n params.$agent_id = query.agent_id;\n }\n if (query.scope) {\n conditions.push(\"scope = $scope\");\n params.$scope = query.scope;\n }\n if (query.subject_id) {\n conditions.push(\"subject_id = $subject_id\");\n params.$subject_id = query.subject_id;\n }\n if (query.source) {\n conditions.push(\"source = $source\");\n params.$source = query.source;\n }\n\n const where = conditions.length > 0 ? `WHERE ${conditions.join(\" AND \")}` : \"\";\n const order = query.order === \"asc\" ? \"ASC\" : \"DESC\";\n const limit = query.limit || 50;\n const offset = query.offset || 0;\n\n params.$limit = limit;\n params.$offset = offset;\n\n const sql = `SELECT * FROM memories ${where} ORDER BY created_at ${order} LIMIT $limit OFFSET $offset`;\n const rows = this.db.prepare(sql).all(params) as MemoryRow[];\n\n if (query.tags) {\n const tagList = query.tags.split(\",\").map((t) => t.trim().toLowerCase());\n return rows\n .map((r) => this.rowToMemory(r))\n .filter((m) => {\n const memTags = m.tags.map((t) => t.toLowerCase());\n return tagList.some((t) => memTags.includes(t));\n });\n }\n\n return rows.map((r) => this.rowToMemory(r));\n }\n\n // ── Full-Text Search ────────────────────────────────────────────────\n\n searchFullText(\n query: string,\n agentId?: string,\n scopes?: MemoryScope[],\n subjectId?: string | null,\n limit: number = 10\n ): Array<Memory & { fts_rank: number }> {\n const ftsQuery = query\n .split(/\\s+/)\n .filter(Boolean)\n .map((term) => `\"${term.replace(/\"/g, \"\")}\"`)\n .join(\" OR \");\n\n if (!ftsQuery) return [];\n\n const conditions: string[] = [];\n const params: Record<string, unknown> = { $fts: ftsQuery, $limit: limit };\n\n if (agentId) {\n conditions.push(\"m.agent_id = $agent_id\");\n params.$agent_id = agentId;\n }\n if (scopes && scopes.length > 0) {\n const scopePlaceholders = scopes.map((_, i) => `$scope_${i}`);\n conditions.push(`m.scope IN (${scopePlaceholders.join(\",\")})`);\n scopes.forEach((s, i) => { params[`$scope_${i}`] = s; });\n }\n if (subjectId !== undefined && subjectId !== null) {\n conditions.push(\"m.subject_id = $subject_id\");\n params.$subject_id = subjectId;\n }\n\n const where = conditions.length > 0 ? `AND ${conditions.join(\" AND \")}` : \"\";\n\n const sql = `\n SELECT m.*, rank\n FROM memories_fts fts\n JOIN memories m ON m.rowid = fts.rowid\n WHERE memories_fts MATCH $fts\n ${where}\n ORDER BY rank\n LIMIT $limit\n `;\n\n const rows = this.db.prepare(sql).all(params) as (MemoryRow & { rank: number })[];\n return rows.map((r) => ({\n ...this.rowToMemory(r),\n fts_rank: r.rank,\n }));\n }\n\n // ── Conversation Log ────────────────────────────────────────────────\n\n appendConversationLog(entry: ConversationLogEntry): void {\n this.db.prepare(\n `INSERT INTO conversation_log (agent_id, session_id, user_id, channel, role, content, timestamp)\n VALUES ($agent_id, $session_id, $user_id, $channel, $role, $content, $timestamp)`\n ).run({\n $agent_id: entry.agent_id,\n $session_id: entry.session_id,\n $user_id: entry.user_id,\n $channel: entry.channel,\n $role: entry.role,\n $content: entry.content,\n $timestamp: entry.timestamp,\n });\n }\n\n getConversationLog(\n agentId: string,\n sessionId: string,\n limit: number = 100\n ): ConversationLogEntry[] {\n return this.db.prepare(\n `SELECT agent_id, session_id, user_id, channel, role, content, timestamp\n FROM conversation_log\n WHERE agent_id = $agent_id AND session_id = $session_id\n ORDER BY timestamp ASC\n LIMIT $limit`\n ).all({ $agent_id: agentId, $session_id: sessionId, $limit: limit }) as ConversationLogEntry[];\n }\n\n // ── Sync Queue ──────────────────────────────────────────────────────\n\n addToSyncQueue(memoryId: string, layer: \"qdrant\" | \"age\", operation: \"upsert\" | \"delete\"): void {\n this.db.prepare(\n `INSERT INTO sync_queue (memory_id, layer, operation, created_at)\n VALUES ($memory_id, $layer, $operation, $created_at)\n ON CONFLICT(memory_id, layer, operation) DO UPDATE SET\n attempts = 0,\n last_error = NULL,\n created_at = excluded.created_at`\n ).run({\n $memory_id: memoryId,\n $layer: layer,\n $operation: operation,\n $created_at: new Date().toISOString(),\n });\n }\n\n getSyncQueue(limit: number = 50): SyncQueueItem[] {\n const rows = this.db.prepare(\n `SELECT * FROM sync_queue\n WHERE attempts < 5\n ORDER BY created_at ASC\n LIMIT $limit`\n ).all({ $limit: limit }) as SyncQueueRow[];\n return rows.map((r) => ({\n id: r.id,\n memory_id: r.memory_id,\n layer: r.layer as \"qdrant\" | \"age\",\n operation: r.operation as \"upsert\" | \"delete\",\n attempts: r.attempts,\n last_error: r.last_error,\n created_at: r.created_at,\n }));\n }\n\n updateSyncQueueItem(id: number, attempts: number, lastError: string | null): void {\n this.db.prepare(\"UPDATE sync_queue SET attempts = $attempts, last_error = $last_error WHERE id = $id\")\n .run({ $attempts: attempts, $last_error: lastError, $id: id });\n }\n\n removeSyncQueueItem(id: number): void {\n this.db.prepare(\"DELETE FROM sync_queue WHERE id = $id\").run({ $id: id });\n }\n\n clearCompletedSyncItems(): number {\n const result = this.db.prepare(\"DELETE FROM sync_queue WHERE attempts >= 5\").run();\n return result.changes;\n }\n\n // ── Stats ───────────────────────────────────────────────────────────\n\n getMemoryCount(): number {\n const row = this.db.prepare(\"SELECT COUNT(*) as count FROM memories\").get() as { count: number };\n return row.count;\n }\n\n getDatabaseSize(): number {\n try {\n const row = this.db.prepare(\"SELECT page_count * page_size as size FROM pragma_page_count(), pragma_page_size()\").get() as { size: number };\n return row.size;\n } catch {\n return 0;\n }\n }\n\n // ── Health Check ────────────────────────────────────────────────────\n\n healthCheck(): boolean {\n try {\n this.db.prepare(\"SELECT 1\").get();\n return true;\n } catch {\n return false;\n }\n }\n\n // ── Helpers ─────────────────────────────────────────────────────────\n\n private rowToMemory(row: MemoryRow): Memory {\n return {\n id: row.id,\n agent_id: row.agent_id,\n scope: row.scope as MemoryScope,\n subject_id: row.subject_id,\n content: row.content,\n tags: JSON.parse(row.tags || \"[]\"),\n entities: JSON.parse(row.entities || \"[]\"),\n source: row.source as MemorySource,\n created_by: row.created_by,\n created_at: row.created_at,\n updated_at: row.updated_at,\n expires_at: row.expires_at,\n embedding_hash: row.embedding_hash,\n };\n }\n\n close(): void {\n this.db.close();\n }\n}\n","import type {\n Memory,\n MemoryScope,\n ScoredMemory,\n ExtractedEntity,\n} from \"../core/types.js\";\n\n// ── Qdrant Storage Layer ────────────────────────────────────────────────\n\n// Dynamically imported — this is an optional peer dependency\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype QdrantClient = any;\n\nexport interface QdrantStorageConfig {\n url: string;\n collection: string;\n apiKey?: string;\n}\n\nexport class QdrantStorage {\n private client: QdrantClient | null = null;\n private collection: string;\n private config: QdrantStorageConfig;\n private ready = false;\n\n constructor(config: QdrantStorageConfig) {\n this.config = config;\n this.collection = config.collection;\n }\n\n // ── Lazy Client Init ────────────────────────────────────────────────\n\n private async getClient(): Promise<QdrantClient> {\n if (this.client) return this.client;\n\n try {\n // Dynamic import — @qdrant/js-client-rest is an optional peer dependency\n // @ts-ignore — optional peer dep, may not be installed\n const mod = await import(\"@qdrant/js-client-rest\");\n const QdrantClientClass = mod.QdrantClient;\n this.client = new QdrantClientClass({\n url: this.config.url,\n apiKey: this.config.apiKey,\n });\n return this.client;\n } catch {\n throw new Error(\n \"Qdrant client not available. Install @qdrant/js-client-rest: bun add @qdrant/js-client-rest\"\n );\n }\n }\n\n // ── Collection Init ─────────────────────────────────────────────────\n\n async ensureCollection(vectorSize: number = 1536): Promise<void> {\n if (this.ready) return;\n\n const client = await this.getClient();\n\n try {\n const collections = await client.getCollections();\n const exists = collections.collections?.some(\n (c: { name: string }) => c.name === this.collection\n );\n\n if (!exists) {\n await client.createCollection(this.collection, {\n vectors: {\n size: vectorSize,\n distance: \"Cosine\",\n },\n optimizers_config: {\n default_segment_number: 2,\n },\n replication_factor: 1,\n });\n\n // Create payload indexes for efficient filtering\n const indexFields = [\n { field_name: \"agent_id\", field_schema: \"keyword\" as const },\n { field_name: \"scope\", field_schema: \"keyword\" as const },\n { field_name: \"subject_id\", field_schema: \"keyword\" as const },\n { field_name: \"tags\", field_schema: \"keyword\" as const },\n { field_name: \"entity_types\", field_schema: \"keyword\" as const },\n { field_name: \"entity_names\", field_schema: \"keyword\" as const },\n { field_name: \"source\", field_schema: \"keyword\" as const },\n ];\n\n for (const idx of indexFields) {\n await client.createPayloadIndex(this.collection, idx);\n }\n\n console.log(`[qdrant] Created collection: ${this.collection}`);\n }\n\n this.ready = true;\n } catch (error) {\n console.error(`[qdrant] Failed to ensure collection: ${error}`);\n throw error;\n }\n }\n\n // ── Upsert ──────────────────────────────────────────────────────────\n\n async upsertMemory(memory: Memory, vector: number[]): Promise<void> {\n const client = await this.getClient();\n await this.ensureCollection(vector.length);\n\n const entityTypes = memory.entities.map((e) => e.type);\n const entityNames = memory.entities.map((e) => e.name);\n\n await client.upsert(this.collection, {\n points: [\n {\n id: memory.id,\n vector,\n payload: {\n agent_id: memory.agent_id,\n scope: memory.scope,\n subject_id: memory.subject_id,\n content: memory.content,\n tags: memory.tags,\n entity_types: entityTypes,\n entity_names: entityNames,\n source: memory.source,\n created_by: memory.created_by,\n created_at: memory.created_at,\n updated_at: memory.updated_at,\n },\n },\n ],\n });\n }\n\n // ── Delete ──────────────────────────────────────────────────────────\n\n async deleteMemory(id: string): Promise<void> {\n const client = await this.getClient();\n if (!this.ready) await this.ensureCollection();\n await client.delete(this.collection, {\n points: [id],\n });\n }\n\n // ── Semantic Search ─────────────────────────────────────────────────\n\n async search(\n queryVector: number[],\n agentId?: string,\n scopes?: MemoryScope[],\n subjectId?: string | null,\n limit: number = 10,\n crossAgent: boolean = false\n ): Promise<ScoredMemory[]> {\n const client = await this.getClient();\n await this.ensureCollection(queryVector.length);\n\n const filter = this.buildFilter(agentId, scopes, subjectId, crossAgent);\n\n const results = await client.search(this.collection, {\n vector: queryVector,\n limit,\n with_payload: true,\n filter: filter || undefined,\n score_threshold: 0.3,\n });\n\n return results.map((point: { id: string | number; payload?: Record<string, unknown>; score: number }) => {\n const payload = (point.payload || {}) as Record<string, unknown>;\n return {\n memory: this.payloadToMemory(String(point.id), payload),\n score: point.score,\n source_layer: \"qdrant\" as const,\n };\n });\n }\n\n // ── Health Check ────────────────────────────────────────────────────\n\n async healthCheck(): Promise<boolean> {\n try {\n const client = await this.getClient();\n await client.getCollections();\n return true;\n } catch {\n return false;\n }\n }\n\n // ── Collection Info ─────────────────────────────────────────────────\n\n async getCollectionInfo(): Promise<{ vectorCount: number } | null> {\n try {\n const client = await this.getClient();\n const info = await client.getCollection(this.collection);\n return { vectorCount: info.points_count || 0 };\n } catch {\n return null;\n }\n }\n\n // ── Helpers ─────────────────────────────────────────────────────────\n\n private buildFilter(\n agentId?: string,\n scopes?: MemoryScope[],\n subjectId?: string | null,\n crossAgent: boolean = false\n ): Record<string, unknown> | null {\n const must: Array<Record<string, unknown>> = [];\n\n if (agentId && !crossAgent) {\n must.push({ key: \"agent_id\", match: { value: agentId } });\n }\n if (scopes && scopes.length > 0) {\n must.push({ key: \"scope\", match: { any: scopes } });\n }\n if (subjectId !== undefined && subjectId !== null) {\n must.push({ key: \"subject_id\", match: { value: subjectId } });\n }\n\n if (must.length === 0) return null;\n return { must };\n }\n\n private payloadToMemory(id: string, payload: Record<string, unknown>): Memory {\n return {\n id,\n agent_id: (payload.agent_id as string) || \"\",\n scope: (payload.scope as MemoryScope) || \"agent\",\n subject_id: (payload.subject_id as string | null) ?? null,\n content: (payload.content as string) || \"\",\n tags: (payload.tags as string[]) || [],\n entities: ((payload.entity_names as string[]) || []).map(\n (name, i) => ({\n name,\n type: ((payload.entity_types as string[]) || [])[i] || \"Concept\",\n properties: {},\n })\n ) as ExtractedEntity[],\n source: (payload.source as Memory[\"source\"]) || \"explicit\",\n created_by: (payload.created_by as string | null) ?? null,\n created_at: (payload.created_at as string) || \"\",\n updated_at: (payload.updated_at as string) || \"\",\n expires_at: null,\n embedding_hash: null,\n };\n }\n}\n","import type {\n Memory,\n ExtractedEntity,\n ExtractedRelationship,\n EntityType,\n ScoredMemory,\n} from \"../core/types.js\";\n\n// ── AGE Storage Layer ───────────────────────────────────────────────────\n\n// Dynamically imported — this is an optional peer dependency\ntype Pool = import(\"pg\").Pool;\ntype PoolClient = import(\"pg\").PoolClient;\n\nexport interface AgeStorageConfig {\n host: string;\n port: number;\n user: string;\n password: string;\n database: string;\n graph: string;\n}\n\n// Max input length for user-supplied strings in Cypher queries\nconst MAX_CYPHER_INPUT_LENGTH = 1000;\n\nexport class AgeStorage {\n private pool: Pool | null = null;\n private config: AgeStorageConfig;\n private graph: string;\n private initialized = false;\n\n constructor(config: AgeStorageConfig) {\n this.config = config;\n this.graph = config.graph;\n }\n\n // ── Lazy Pool Init ──────────────────────────────────────────────────\n\n private async getPool(): Promise<Pool> {\n if (this.pool) return this.pool;\n\n try {\n const pg = await import(\"pg\");\n const PoolClass = pg.default?.Pool || pg.Pool;\n this.pool = new PoolClass({\n host: this.config.host,\n port: this.config.port,\n user: this.config.user,\n password: this.config.password,\n database: this.config.database,\n max: 5,\n idleTimeoutMillis: 30000,\n });\n return this.pool;\n } catch {\n throw new Error(\n \"pg client not available. Install pg: bun add pg\"\n );\n }\n }\n\n // ── Graph Init ──────────────────────────────────────────────────────\n\n async ensureGraph(): Promise<void> {\n if (this.initialized) return;\n\n const pool = await this.getPool();\n const client = await pool.connect();\n try {\n await client.query(\"LOAD 'age';\");\n await client.query('SET search_path = ag_catalog, \"$user\", public;');\n\n const exists = await client.query(\n \"SELECT 1 FROM ag_catalog.ag_graph WHERE name = $1\",\n [this.graph]\n );\n\n if (exists.rowCount === 0) {\n await client.query(\"SELECT ag_catalog.create_graph($1)\", [this.graph]);\n console.log(`[age] Created graph: ${this.graph}`);\n }\n\n this.initialized = true;\n } catch (error) {\n console.error(`[age] Failed to ensure graph: ${error}`);\n throw error;\n } finally {\n client.release();\n }\n }\n\n // ── Cypher Query Helper ─────────────────────────────────────────────\n\n private async cypherQuery<T>(\n query: string,\n resultColumns: string = \"v agtype\"\n ): Promise<T[]> {\n await this.ensureGraph();\n const pool = await this.getPool();\n const client = await pool.connect();\n try {\n await client.query(\"LOAD 'age';\");\n await client.query('SET search_path = ag_catalog, \"$user\", public;');\n\n const sql = `SELECT * FROM ag_catalog.cypher('${escGraphName(this.graph)}', $$${query}$$) as (${resultColumns})`;\n const result = await client.query(sql);\n\n return result.rows.map((row: Record<string, unknown>) => {\n const parsed: Record<string, unknown> = {};\n for (const key of Object.keys(row)) {\n parsed[key] = this.parseAgtype(row[key]);\n }\n if (Object.keys(parsed).length === 1 && \"v\" in parsed) {\n return parsed.v as T;\n }\n return parsed as T;\n });\n } finally {\n client.release();\n }\n }\n\n private async cypherExec(query: string): Promise<void> {\n await this.ensureGraph();\n const pool = await this.getPool();\n const client = await pool.connect();\n try {\n await client.query(\"LOAD 'age';\");\n await client.query('SET search_path = ag_catalog, \"$user\", public;');\n\n const sql = `SELECT * FROM ag_catalog.cypher('${escGraphName(this.graph)}', $$${query}$$) as (v agtype)`;\n await client.query(sql);\n } finally {\n client.release();\n }\n }\n\n // ── Memory Node Operations ──────────────────────────────────────────\n\n async upsertMemoryNode(memory: Memory): Promise<void> {\n const contentTruncated = memory.content.slice(0, 500);\n const now = new Date().toISOString();\n\n try {\n await this.cypherExec(\n `MERGE (m:Memory {id: '${esc(memory.id)}'})\n SET m.agent_id = '${esc(memory.agent_id)}',\n m.scope = '${esc(memory.scope)}',\n m.subject_id = '${esc(memory.subject_id || \"\")}',\n m.content = '${esc(contentTruncated)}',\n m.source = '${esc(memory.source)}',\n m.created_at = '${esc(memory.created_at)}',\n m.updated_at = '${esc(now)}'\n RETURN m`\n );\n } catch (error) {\n console.error(`[age] Failed to upsert memory node: ${error}`);\n throw error;\n }\n }\n\n // ── Entity Node Operations ──────────────────────────────────────────\n\n async upsertEntityNode(\n entity: ExtractedEntity,\n agentId: string\n ): Promise<string> {\n const entityId = slugify(`${entity.type}:${entity.name}`);\n const now = new Date().toISOString();\n const propsJson = JSON.stringify(entity.properties || {});\n\n try {\n await this.cypherExec(\n `MERGE (e:Entity {id: '${esc(entityId)}'})\n SET e.name = '${esc(entity.name)}',\n e.entity_type = '${esc(entity.type)}',\n e.agent_id = '${esc(agentId)}',\n e.properties = '${esc(propsJson)}',\n e.updated_at = '${esc(now)}'\n RETURN e`\n );\n } catch (error) {\n console.error(`[age] Failed to upsert entity node ${entityId}: ${error}`);\n throw error;\n }\n\n return entityId;\n }\n\n // ── Relationship Operations ─────────────────────────────────────────\n\n async createRelationship(\n rel: ExtractedRelationship,\n agentId: string\n ): Promise<void> {\n const fromId = slugify(`${this.guessEntityType(rel.from_entity)}:${rel.from_entity}`);\n const toId = slugify(`${this.guessEntityType(rel.to_entity)}:${rel.to_entity}`);\n const context = rel.properties?.context || \"\";\n\n // Validate relationship type is a valid identifier\n const relType = sanitizeLabel(rel.relationship);\n if (!relType) {\n console.warn(`[age] Invalid relationship type: ${rel.relationship}`);\n return;\n }\n\n try {\n await this.cypherExec(\n `MATCH (a:Entity {id: '${esc(fromId)}'}), (b:Entity {id: '${esc(toId)}'})\n MERGE (a)-[r:${relType}]->(b)\n SET r.context = '${esc(context)}',\n r.agent_id = '${esc(agentId)}'\n RETURN r`\n );\n } catch (error) {\n console.warn(`[age] Failed to create relationship ${fromId} -[${relType}]-> ${toId}: ${error}`);\n }\n }\n\n async linkMemoryToEntity(\n memoryId: string,\n entityId: string\n ): Promise<void> {\n try {\n await this.cypherExec(\n `MATCH (m:Memory {id: '${esc(memoryId)}'}), (e:Entity {id: '${esc(entityId)}'})\n MERGE (m)-[r:MENTIONS]->(e)\n RETURN r`\n );\n } catch (error) {\n console.warn(`[age] Failed to link memory ${memoryId} to entity ${entityId}: ${error}`);\n }\n }\n\n // ── Delete ──────────────────────────────────────────────────────────\n\n async deleteMemoryNode(memoryId: string): Promise<void> {\n try {\n try {\n await this.cypherExec(\n `MATCH (m:Memory {id: '${esc(memoryId)}'})-[r]-()\n DELETE r\n RETURN r`\n );\n } catch {\n // No edges to delete\n }\n\n await this.cypherExec(\n `MATCH (m:Memory {id: '${esc(memoryId)}'})\n DELETE m\n RETURN m`\n );\n } catch (error) {\n console.warn(`[age] Failed to delete memory node ${memoryId}: ${error}`);\n throw error;\n }\n }\n\n // ── Graph Queries ───────────────────────────────────────────────────\n\n async getEntityWithRelationships(\n entityType: string,\n entityId: string\n ): Promise<{\n entity: Record<string, unknown> | null;\n relationships: Array<{\n type: string;\n direction: string;\n target: Record<string, unknown>;\n }>;\n }> {\n try {\n const entities = await this.cypherQuery<Record<string, unknown>>(\n `MATCH (e:Entity {id: '${esc(entityId)}'})\n RETURN properties(e) as v`\n );\n\n if (entities.length === 0) {\n return { entity: null, relationships: [] };\n }\n\n const relationships: Array<{\n type: string;\n direction: string;\n target: Record<string, unknown>;\n }> = [];\n\n // Get outgoing relationships\n try {\n const outgoing = await this.cypherQuery<Record<string, unknown>>(\n `MATCH (e:Entity {id: '${esc(entityId)}'})-[r]->(target)\n RETURN type(r) as rel_type, properties(target) as target_props`,\n \"rel_type agtype, target_props agtype\"\n );\n\n for (const r of outgoing) {\n relationships.push({\n type: String(r.rel_type || \"\"),\n direction: \"outgoing\",\n target: (r.target_props as Record<string, unknown>) || {},\n });\n }\n } catch {\n // No outgoing relationships\n }\n\n // Get incoming relationships\n try {\n const incoming = await this.cypherQuery<Record<string, unknown>>(\n `MATCH (e:Entity {id: '${esc(entityId)}'})<-[r]-(source)\n RETURN type(r) as rel_type, properties(source) as source_props`,\n \"rel_type agtype, source_props agtype\"\n );\n\n for (const r of incoming) {\n relationships.push({\n type: String(r.rel_type || \"\"),\n direction: \"incoming\",\n target: (r.source_props as Record<string, unknown>) || {},\n });\n }\n } catch {\n // No incoming relationships\n }\n\n return { entity: entities[0], relationships };\n } catch (error) {\n console.error(`[age] Failed to get entity: ${error}`);\n return { entity: null, relationships: [] };\n }\n }\n\n async getRelatedEntities(\n entityId: string,\n depth: number = 2\n ): Promise<\n Array<{\n entity: Record<string, unknown>;\n relationship: string;\n distance: number;\n }>\n > {\n try {\n const maxDepth = Math.min(depth, 4);\n const results = await this.cypherQuery<Record<string, unknown>>(\n `MATCH (start:Entity {id: '${esc(entityId)}'})-[*1..${maxDepth}]-(target:Entity)\n WHERE target.id <> '${esc(entityId)}'\n RETURN DISTINCT properties(target) as target_props`,\n \"target_props agtype\"\n );\n\n return results.map((r) => ({\n entity: (r.target_props as Record<string, unknown>) || r,\n relationship: \"RELATED_TO\",\n distance: 1,\n }));\n } catch (error) {\n console.error(`[age] Failed to get related entities: ${error}`);\n return [];\n }\n }\n\n async searchByEntity(\n entityName: string,\n entityType?: string,\n agentId?: string,\n limit: number = 10\n ): Promise<ScoredMemory[]> {\n // Validate input length\n if (entityName.length > MAX_CYPHER_INPUT_LENGTH) {\n console.warn(\"[age] Entity name too long, truncating\");\n entityName = entityName.slice(0, MAX_CYPHER_INPUT_LENGTH);\n }\n\n try {\n const entityId = slugify(`${entityType || \"Concept\"}:${entityName}`);\n const safeLimit = Math.min(Math.max(1, limit), 100);\n\n let results: Record<string, unknown>[] = [];\n try {\n results = await this.cypherQuery<Record<string, unknown>>(\n `MATCH (m:Memory)-[:MENTIONS]->(e:Entity {id: '${esc(entityId)}'})\n ${agentId ? `WHERE m.agent_id = '${esc(agentId)}'` : \"\"}\n RETURN properties(m) as mem_props\n ORDER BY m.created_at DESC\n LIMIT ${safeLimit}`,\n \"mem_props agtype\"\n );\n } catch {\n // Exact match failed\n }\n\n if (results.length === 0) {\n return await this.searchByEntityNameFuzzy(entityName, agentId, safeLimit);\n }\n\n return results.map((r, i) => this.graphResultToScoredMemory(r, entityName, entityType, i));\n } catch (error) {\n console.error(`[age] Graph search failed: ${error}`);\n return [];\n }\n }\n\n private async searchByEntityNameFuzzy(\n name: string,\n agentId?: string,\n limit: number = 10\n ): Promise<ScoredMemory[]> {\n // Validate input length\n if (name.length > MAX_CYPHER_INPUT_LENGTH) {\n console.warn(\"[age] Fuzzy search name too long, truncating\");\n name = name.slice(0, MAX_CYPHER_INPUT_LENGTH);\n }\n\n try {\n // Escape regex metacharacters to prevent regex injection\n const escapedName = escRegex(esc(name));\n const safeLimit = Math.min(Math.max(1, limit), 100);\n\n const results = await this.cypherQuery<Record<string, unknown>>(\n `MATCH (m:Memory)-[:MENTIONS]->(e:Entity)\n WHERE e.name =~ '(?i).*${escapedName}.*'\n ${agentId ? `AND m.agent_id = '${esc(agentId)}'` : \"\"}\n RETURN properties(m) as mem_props, e.name as entity_name, e.entity_type as entity_type\n ORDER BY m.created_at DESC\n LIMIT ${safeLimit}`,\n \"mem_props agtype, entity_name agtype, entity_type agtype\"\n );\n\n return results.map((r, i) => {\n const props = (r.mem_props as Record<string, unknown>) || {};\n return {\n memory: this.propsToMemory(props),\n score: 0.8 / (1 + i * 0.1),\n source_layer: \"age\" as const,\n graph_context: {\n related_entities: [\n {\n type: (String(r.entity_type) || \"Concept\") as EntityType,\n name: String(r.entity_name || name),\n relationship: \"MENTIONED_IN\",\n },\n ],\n },\n };\n });\n } catch (error) {\n console.error(`[age] Fuzzy entity search failed: ${error}`);\n return [];\n }\n }\n\n async listEntities(\n entityType?: string,\n agentId?: string,\n limit: number = 50\n ): Promise<Array<Record<string, unknown>>> {\n try {\n const conditions: string[] = [];\n if (entityType) conditions.push(`e.entity_type = '${esc(entityType)}'`);\n if (agentId) conditions.push(`e.agent_id = '${esc(agentId)}'`);\n\n const where = conditions.length > 0 ? `WHERE ${conditions.join(\" AND \")}` : \"\";\n const safeLimit = Math.min(Math.max(1, limit), 200);\n\n const results = await this.cypherQuery<Record<string, unknown>>(\n `MATCH (e:Entity)\n ${where}\n RETURN properties(e) as props\n ORDER BY e.updated_at DESC\n LIMIT ${safeLimit}`,\n \"props agtype\"\n );\n\n return results.map((r) => (r.props as Record<string, unknown>) || r);\n } catch (error) {\n console.error(`[age] Failed to list entities: ${error}`);\n return [];\n }\n }\n\n // ── Agent Node ──────────────────────────────────────────────────────\n\n async ensureAgentNode(\n agentId: string,\n name: string,\n role: string\n ): Promise<void> {\n const now = new Date().toISOString();\n try {\n await this.cypherExec(\n `MERGE (a:Agent {id: '${esc(agentId)}'})\n SET a.name = '${esc(name)}',\n a.role = '${esc(role)}',\n a.created_at = '${esc(now)}'\n RETURN a`\n );\n } catch (error) {\n console.warn(`[age] Failed to ensure agent node: ${error}`);\n }\n }\n\n // ── Stats ───────────────────────────────────────────────────────────\n\n async getStats(): Promise<{ entityCount: number; relationshipCount: number } | null> {\n try {\n const entities = await this.cypherQuery<Record<string, unknown>>(\n `MATCH (e:Entity) RETURN count(e) as cnt`,\n \"cnt agtype\"\n );\n const rels = await this.cypherQuery<Record<string, unknown>>(\n `MATCH ()-[r]->() RETURN count(r) as cnt`,\n \"cnt agtype\"\n );\n return {\n entityCount: Number(entities[0] || 0),\n relationshipCount: Number(rels[0] || 0),\n };\n } catch {\n return null;\n }\n }\n\n // ── Health Check ────────────────────────────────────────────────────\n\n async healthCheck(): Promise<boolean> {\n try {\n const pool = await this.getPool();\n const client = await pool.connect();\n try {\n await client.query(\"SELECT 1\");\n return true;\n } finally {\n client.release();\n }\n } catch {\n return false;\n }\n }\n\n // ── Cleanup ─────────────────────────────────────────────────────────\n\n async close(): Promise<void> {\n if (this.pool) {\n await this.pool.end();\n }\n }\n\n // ── Helpers ─────────────────────────────────────────────────────────\n\n private parseAgtype(value: unknown): unknown {\n if (value === null || value === undefined) return null;\n if (typeof value === \"string\") {\n try {\n return JSON.parse(value);\n } catch {\n const cleaned = value.replace(/::(?:vertex|edge|path|agtype)$/g, \"\").trim();\n try {\n return JSON.parse(cleaned);\n } catch {\n return cleaned;\n }\n }\n }\n return value;\n }\n\n private propsToMemory(props: Record<string, unknown>): Memory {\n return {\n id: String(props.id || \"\"),\n agent_id: String(props.agent_id || \"\"),\n scope: String(props.scope || \"agent\") as Memory[\"scope\"],\n subject_id: (props.subject_id as string) || null,\n content: String(props.content || \"\"),\n tags: [],\n entities: [],\n source: String(props.source || \"explicit\") as Memory[\"source\"],\n created_by: null,\n created_at: String(props.created_at || \"\"),\n updated_at: String(props.updated_at || \"\"),\n expires_at: null,\n embedding_hash: null,\n };\n }\n\n private graphResultToScoredMemory(\n r: Record<string, unknown>,\n entityName: string,\n entityType: string | undefined,\n index: number\n ): ScoredMemory {\n const props = (r.mem_props as Record<string, unknown>) || {};\n return {\n memory: this.propsToMemory(props),\n score: 1.0 / (1 + index * 0.1),\n source_layer: \"age\" as const,\n graph_context: {\n related_entities: [\n {\n type: (entityType || \"Concept\") as EntityType,\n name: entityName,\n relationship: \"MENTIONED_IN\",\n },\n ],\n },\n };\n }\n\n private guessEntityType(_name: string): string {\n return \"Concept\";\n }\n}\n\n// ── Utility Functions ───────────────────────────────────────────────────\n\n/**\n * Escape a string for safe inclusion in a Cypher single-quoted string literal.\n * Also strips dollar signs to prevent $$ dollar-quote breakout in the\n * pg cypher() wrapper.\n *\n * NOTE: This is NOT a complete SQL injection defence on its own.\n * It is a best-effort sanitisation layer for AGE's $$-quoted Cypher\n * passthrough, where parameterised queries are not supported.\n */\nfunction esc(value: string): string {\n if (!value) return \"\";\n // Enforce max length\n const truncated = value.slice(0, MAX_CYPHER_INPUT_LENGTH);\n return truncated\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/'/g, \"\\\\'\")\n .replace(/\\n/g, \"\\\\n\")\n .replace(/\\r/g, \"\\\\r\")\n .replace(/\\$/g, \"\") // strip dollar signs — prevents $$ breakout\n .replace(/\\0/g, \"\"); // strip null bytes\n}\n\n/**\n * Escape the graph name (alphanumeric + underscore only).\n */\nfunction escGraphName(name: string): string {\n return name.replace(/[^a-zA-Z0-9_]/g, \"\");\n}\n\n/**\n * Escape regex metacharacters so user input can be safely embedded in\n * Cypher =~ regex patterns without causing injection or ReDoS.\n */\nfunction escRegex(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\n/**\n * Sanitize a Cypher label/relationship type.\n * Only alphanumeric and underscore are allowed.\n * Returns null if the result is empty.\n */\nfunction sanitizeLabel(label: string): string | null {\n const sanitized = label.replace(/[^a-zA-Z0-9_]/g, \"\");\n return sanitized.length > 0 ? sanitized : null;\n}\n\nfunction slugify(input: string): string {\n return input\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, 128);\n}\n","import type { SqliteStorage } from \"./sqlite.js\";\nimport type { QdrantStorage } from \"./qdrant.js\";\nimport type { AgeStorage } from \"./age.js\";\nimport type { EmbeddingService } from \"../extraction/embeddings.js\";\nimport type { SyncQueueItem } from \"../core/types.js\";\n\n// ── Sync Queue Processor ────────────────────────────────────────────────\n\nexport class SyncQueueProcessor {\n private sqlite: SqliteStorage;\n private qdrant: QdrantStorage | null;\n private age: AgeStorage | null;\n private embeddings: EmbeddingService | null;\n private interval: ReturnType<typeof setInterval> | null = null;\n private processing = false;\n\n constructor(\n sqlite: SqliteStorage,\n qdrant: QdrantStorage | null,\n age: AgeStorage | null,\n embeddings: EmbeddingService | null\n ) {\n this.sqlite = sqlite;\n this.qdrant = qdrant;\n this.age = age;\n this.embeddings = embeddings;\n }\n\n start(intervalMs: number = 60_000): void {\n if (this.interval) return;\n console.log(`[sync-queue] Starting processor (every ${intervalMs / 1000}s)`);\n this.interval = setInterval(() => {\n void this.processQueue();\n }, intervalMs);\n // Also process immediately\n void this.processQueue();\n }\n\n stop(): void {\n if (this.interval) {\n clearInterval(this.interval);\n this.interval = null;\n console.log(\"[sync-queue] Stopped\");\n }\n }\n\n async processQueue(): Promise<{ processed: number; succeeded: number; failed: number }> {\n if (this.processing) return { processed: 0, succeeded: 0, failed: 0 };\n this.processing = true;\n\n let processed = 0;\n let succeeded = 0;\n let failed = 0;\n\n try {\n const items = this.sqlite.getSyncQueue(50);\n if (items.length === 0) {\n return { processed: 0, succeeded: 0, failed: 0 };\n }\n\n console.log(`[sync-queue] Processing ${items.length} items`);\n\n for (const item of items) {\n processed++;\n try {\n await this.processItem(item);\n this.sqlite.removeSyncQueueItem(item.id);\n succeeded++;\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n this.sqlite.updateSyncQueueItem(item.id, item.attempts + 1, errorMsg);\n failed++;\n console.warn(\n `[sync-queue] Failed item ${item.id} (${item.layer}/${item.operation}/${item.memory_id}): ${errorMsg}`\n );\n }\n }\n\n const cleared = this.sqlite.clearCompletedSyncItems();\n if (cleared > 0) {\n console.log(`[sync-queue] Cleared ${cleared} items that exceeded max retries`);\n }\n } finally {\n this.processing = false;\n }\n\n if (processed > 0) {\n console.log(`[sync-queue] Done: ${succeeded} ok, ${failed} failed out of ${processed}`);\n }\n\n return { processed, succeeded, failed };\n }\n\n private async processItem(item: SyncQueueItem): Promise<void> {\n if (item.layer === \"qdrant\") {\n await this.processQdrantItem(item);\n } else if (item.layer === \"age\") {\n await this.processAgeItem(item);\n }\n }\n\n private async processQdrantItem(item: SyncQueueItem): Promise<void> {\n if (!this.qdrant) throw new Error(\"Qdrant layer not configured\");\n\n if (item.operation === \"delete\") {\n await this.qdrant.deleteMemory(item.memory_id);\n return;\n }\n\n const memory = this.sqlite.getMemory(item.memory_id);\n if (!memory) return; // Deleted since queuing\n\n if (!this.embeddings) throw new Error(\"Embedding service not configured\");\n const vector = await this.embeddings.embed(memory.content);\n if (!vector) throw new Error(\"Failed to generate embedding\");\n\n await this.qdrant.upsertMemory(memory, vector);\n }\n\n private async processAgeItem(item: SyncQueueItem): Promise<void> {\n if (!this.age) throw new Error(\"AGE layer not configured\");\n\n if (item.operation === \"delete\") {\n await this.age.deleteMemoryNode(item.memory_id);\n return;\n }\n\n const memory = this.sqlite.getMemory(item.memory_id);\n if (!memory) return;\n\n await this.age.upsertMemoryNode(memory);\n\n for (const entity of memory.entities) {\n const entityId = await this.age.upsertEntityNode(entity, memory.agent_id);\n await this.age.linkMemoryToEntity(memory.id, entityId);\n }\n }\n}\n","import OpenAI from \"openai\";\n\n// ── Embedding Service ───────────────────────────────────────────────────\n\nexport interface EmbeddingConfig {\n apiKey: string;\n baseUrl?: string;\n model: string;\n dimensions: number;\n}\n\nexport class EmbeddingService {\n private client: OpenAI;\n private model: string;\n private dimensions: number;\n\n constructor(config: EmbeddingConfig) {\n this.client = new OpenAI({\n apiKey: config.apiKey,\n baseURL: config.baseUrl,\n });\n this.model = config.model;\n this.dimensions = config.dimensions;\n }\n\n async embed(text: string): Promise<number[] | null> {\n if (!text || text.trim().length === 0) return null;\n\n try {\n const response = await this.client.embeddings.create({\n model: this.model,\n input: text.slice(0, 8000),\n });\n\n const embedding = response.data[0]?.embedding;\n if (!embedding || embedding.length === 0) {\n console.warn(\"[embeddings] Empty embedding returned\");\n return null;\n }\n\n return embedding;\n } catch (error) {\n console.error(`[embeddings] Failed to generate embedding: ${error}`);\n return null;\n }\n }\n\n async embedBatch(texts: string[]): Promise<(number[] | null)[]> {\n if (texts.length === 0) return [];\n\n try {\n const cleanTexts = texts.map((t) => (t || \"\").slice(0, 8000));\n const response = await this.client.embeddings.create({\n model: this.model,\n input: cleanTexts,\n });\n\n return response.data.map((item) =>\n item.embedding && item.embedding.length > 0 ? item.embedding : null\n );\n } catch (error) {\n console.error(`[embeddings] Batch embedding failed: ${error}`);\n return texts.map(() => null);\n }\n }\n\n getDimensions(): number {\n return this.dimensions;\n }\n}\n","import OpenAI from \"openai\";\nimport type { ExtractionResult, ExtractedEntity, ExtractedRelationship } from \"../core/types.js\";\n\n// ── Entity Extraction Prompt ────────────────────────────────────────────\n\nconst ENTITY_EXTRACTION_PROMPT = `Extract entities and relationships from this memory text.\n\nReturn JSON with this exact structure:\n{\n \"entities\": [\n {\n \"name\": \"exact name as mentioned\",\n \"type\": \"Person|Project|Organization|Decision|Preference|Event|Tool|Location|Concept\",\n \"properties\": { \"key\": \"value\" }\n }\n ],\n \"relationships\": [\n {\n \"from_entity\": \"entity name\",\n \"to_entity\": \"entity name\",\n \"relationship\": \"WORKS_ON|DECIDED|PREFERS|KNOWS|USES|LOCATED_AT|BELONGS_TO|RELATED_TO|CREATED_BY|DEPENDS_ON\",\n \"properties\": { \"context\": \"brief context\" }\n }\n ]\n}\n\nRules:\n- Only extract clearly stated entities, don't infer\n- Use the most specific entity type possible\n- Normalize person names to their full form when possible\n- For preferences, use key/value format (key = category, value = preference)\n- Keep properties minimal — only include what's explicitly stated\n- If no entities are found, return {\"entities\": [], \"relationships\": []}`;\n\n// ── Entity Extractor ────────────────────────────────────────────────────\n\nexport interface ExtractionConfig {\n apiKey: string;\n baseUrl?: string;\n model: string;\n enabled: boolean;\n}\n\nexport class EntityExtractor {\n private client: OpenAI;\n private model: string;\n\n constructor(config: ExtractionConfig) {\n this.client = new OpenAI({\n apiKey: config.apiKey,\n baseURL: config.baseUrl,\n });\n this.model = config.model;\n }\n\n async extract(text: string): Promise<ExtractionResult> {\n if (!text || text.trim().length < 20) {\n return { entities: [], relationships: [] };\n }\n\n try {\n const response = await this.client.chat.completions.create({\n model: this.model,\n messages: [\n { role: \"system\", content: ENTITY_EXTRACTION_PROMPT },\n { role: \"user\", content: text.slice(0, 4000) },\n ],\n temperature: 0.1,\n max_tokens: 1500,\n response_format: { type: \"json_object\" },\n });\n\n const content = response.choices[0]?.message?.content;\n if (!content) {\n return { entities: [], relationships: [] };\n }\n\n const parsed = JSON.parse(content);\n return this.validateExtractionResult(parsed);\n } catch (error) {\n console.error(`[entity-extractor] Extraction failed: ${error}`);\n return { entities: [], relationships: [] };\n }\n }\n\n private validateExtractionResult(data: unknown): ExtractionResult {\n if (!data || typeof data !== \"object\") {\n return { entities: [], relationships: [] };\n }\n\n const raw = data as Record<string, unknown>;\n const entities: ExtractedEntity[] = [];\n const relationships: ExtractedRelationship[] = [];\n\n const validTypes = [\n \"Person\", \"Project\", \"Organization\", \"Decision\",\n \"Preference\", \"Event\", \"Tool\", \"Location\", \"Concept\",\n ];\n const validRels = [\n \"WORKS_ON\", \"DECIDED\", \"PREFERS\", \"KNOWS\", \"USES\",\n \"LOCATED_AT\", \"BELONGS_TO\", \"RELATED_TO\", \"CREATED_BY\", \"DEPENDS_ON\",\n ];\n\n if (Array.isArray(raw.entities)) {\n for (const e of raw.entities) {\n if (e && typeof e === \"object\" && typeof e.name === \"string\" && typeof e.type === \"string\") {\n entities.push({\n name: e.name,\n type: validTypes.includes(e.type) ? e.type : \"Concept\",\n properties: (typeof e.properties === \"object\" && e.properties !== null)\n ? Object.fromEntries(\n Object.entries(e.properties as Record<string, unknown>).map(([k, v]) => [k, String(v)])\n )\n : {},\n });\n }\n }\n }\n\n if (Array.isArray(raw.relationships)) {\n for (const r of raw.relationships) {\n if (\n r &&\n typeof r === \"object\" &&\n typeof r.from_entity === \"string\" &&\n typeof r.to_entity === \"string\" &&\n typeof r.relationship === \"string\"\n ) {\n relationships.push({\n from_entity: r.from_entity,\n to_entity: r.to_entity,\n relationship: validRels.includes(r.relationship) ? r.relationship : \"RELATED_TO\",\n properties: (typeof r.properties === \"object\" && r.properties !== null)\n ? Object.fromEntries(\n Object.entries(r.properties as Record<string, unknown>).map(([k, v]) => [k, String(v)])\n )\n : {},\n });\n }\n }\n }\n\n return { entities, relationships };\n }\n}\n","import type { SearchRequest } from \"../core/types.js\";\n\nexport type Strategy =\n | \"fulltext+graph\"\n | \"graph+semantic\"\n | \"semantic+graph\"\n | \"semantic\"\n | \"fulltext\"\n | \"graph\"\n | \"all\";\n\n// ── Key Lookup Patterns ─────────────────────────────────────────────────\n\nconst KEY_LOOKUP_PATTERNS = [\n /what is .+'s/i,\n /what are .+'s/i,\n /.+'s (email|phone|address|preference|setting)/i,\n /^(get|find|show|tell me) .+'s/i,\n /^what (does|did) .+ (like|prefer|use|want)/i,\n];\n\n// ── Relationship Query Patterns ─────────────────────────────────────────\n\nconst RELATIONSHIP_PATTERNS = [\n /who (works on|knows|created|manages|uses)/i,\n /what.+(connected|related|linked|associated) (to|with)/i,\n /how (is|are) .+ (related|connected)/i,\n /relationship between/i,\n /(works on|belongs to|depends on|uses)/i,\n /what projects does/i,\n /who is involved (in|with)/i,\n];\n\n// ── Strategy Selection ──────────────────────────────────────────────────\n\nexport function selectStrategy(request: SearchRequest): Strategy {\n if (request.strategy && request.strategy !== \"auto\") {\n switch (request.strategy) {\n case \"semantic\": return \"semantic\";\n case \"fulltext\": return \"fulltext\";\n case \"graph\": return \"graph\";\n case \"all\": return \"all\";\n default: break;\n }\n }\n\n const query = request.query.toLowerCase();\n\n if (isKeyLookup(query)) return \"fulltext+graph\";\n if (isRelationshipQuery(query)) return \"graph+semantic\";\n\n return \"semantic+graph\";\n}\n\nfunction isKeyLookup(query: string): boolean {\n return KEY_LOOKUP_PATTERNS.some((pattern) => pattern.test(query));\n}\n\nfunction isRelationshipQuery(query: string): boolean {\n return RELATIONSHIP_PATTERNS.some((pattern) => pattern.test(query));\n}\n","import type { ScoredMemory } from \"../core/types.js\";\n\n// ── Score Normalization ─────────────────────────────────────────────────\n\n/**\n * Normalize FTS5 BM25 rank to 0.0-1.0 range.\n * BM25 ranks are negative (more negative = better match).\n */\nexport function normalizeFtsScore(rank: number): number {\n const normalized = Math.min(1.0, Math.max(0.0, -rank / 20.0));\n return normalized;\n}\n\n/**\n * Normalize graph distance to a score (closer = higher).\n */\nexport function normalizeGraphScore(hopDistance: number): number {\n return 1.0 / (1 + hopDistance);\n}\n\n// ── Recency Boost ───────────────────────────────────────────────────────\n\n/**\n * Apply a recency decay factor.\n * Score multiplier = max(0.5, 0.95^days_old)\n */\nexport function recencyBoost(createdAt: string): number {\n const created = new Date(createdAt).getTime();\n const now = Date.now();\n const daysOld = (now - created) / (1000 * 60 * 60 * 24);\n return Math.max(0.5, Math.pow(0.95, daysOld));\n}\n\n// ── Multi-Layer Boost ───────────────────────────────────────────────────\n\n/**\n * Boost score for memories that appear in multiple layers.\n * +0.1 per extra layer.\n */\nexport function multiLayerBoost(layerCount: number): number {\n return (layerCount - 1) * 0.1;\n}\n\n// ── Apply All Boosts ────────────────────────────────────────────────────\n\nexport function applyBoosts(result: ScoredMemory, layerAppearances: number): ScoredMemory {\n let score = result.score;\n\n if (result.memory.created_at) {\n score *= recencyBoost(result.memory.created_at);\n }\n\n score += multiLayerBoost(layerAppearances);\n\n score = Math.min(1.0, Math.max(0.0, score));\n\n return { ...result, score };\n}\n","import type { ScoredMemory, SearchResponse, SearchRequest, MemoryScope } from \"../core/types.js\";\nimport type { StorageOrchestrator } from \"../storage/orchestrator.js\";\nimport { selectStrategy, type Strategy } from \"./strategy.js\";\nimport { normalizeFtsScore, applyBoosts } from \"./ranker.js\";\n\n// ── Search Engine ───────────────────────────────────────────────────────\n\nexport class SearchEngine {\n private orchestrator: StorageOrchestrator;\n\n constructor(orchestrator: StorageOrchestrator) {\n this.orchestrator = orchestrator;\n }\n\n async search(request: SearchRequest): Promise<SearchResponse> {\n const strategy = selectStrategy(request);\n const limit = request.limit || 10;\n const scopes = request.scopes || [\"user\", \"agent\", \"global\"];\n const includeGraph = request.include_graph !== false;\n\n const layerStats = {\n sqlite: { count: 0, ms: 0 },\n qdrant: { count: 0, ms: 0 },\n age: { count: 0, ms: 0 },\n };\n\n const allResults: ScoredMemory[] = [];\n const searches: Promise<void>[] = [];\n\n if (shouldSearchFulltext(strategy)) {\n searches.push(\n this.searchFulltext(request, scopes, limit).then((results) => {\n layerStats.sqlite.count = results.length;\n allResults.push(...results);\n })\n );\n }\n\n if (shouldSearchSemantic(strategy) && this.orchestrator.qdrant && this.orchestrator.embeddings) {\n searches.push(\n this.searchSemantic(request, scopes, limit).then((results) => {\n layerStats.qdrant.count = results.length;\n allResults.push(...results);\n })\n );\n }\n\n if (shouldSearchGraph(strategy) && includeGraph && this.orchestrator.age) {\n searches.push(\n this.searchGraph(request, limit).then((results) => {\n layerStats.age.count = results.length;\n allResults.push(...results);\n })\n );\n }\n\n const startTime = Date.now();\n await Promise.allSettled(searches);\n const elapsed = Date.now() - startTime;\n\n if (layerStats.sqlite.count > 0) layerStats.sqlite.ms = elapsed;\n if (layerStats.qdrant.count > 0) layerStats.qdrant.ms = elapsed;\n if (layerStats.age.count > 0) layerStats.age.ms = elapsed;\n\n const merged = this.mergeResults(allResults, limit);\n\n return {\n results: merged,\n strategy_used: strategy,\n layer_stats: layerStats,\n };\n }\n\n // ── Layer-Specific Searches ─────────────────────────────────────────\n\n private async searchFulltext(\n request: SearchRequest,\n scopes: MemoryScope[],\n limit: number\n ): Promise<ScoredMemory[]> {\n try {\n const results = this.orchestrator.sqlite.searchFullText(\n request.query,\n request.cross_agent ? undefined : request.agent_id,\n scopes,\n request.subject_id,\n limit\n );\n\n return results.map((r) => ({\n memory: r,\n score: normalizeFtsScore(r.fts_rank),\n source_layer: \"sqlite\" as const,\n }));\n } catch (error) {\n console.warn(`[search] Fulltext search failed: ${error}`);\n return [];\n }\n }\n\n private async searchSemantic(\n request: SearchRequest,\n scopes: MemoryScope[],\n limit: number\n ): Promise<ScoredMemory[]> {\n try {\n if (!this.orchestrator.embeddings || !this.orchestrator.qdrant) return [];\n\n const queryVector = await this.orchestrator.embeddings.embed(request.query);\n if (!queryVector) return [];\n\n return await this.orchestrator.qdrant.search(\n queryVector,\n request.cross_agent ? undefined : request.agent_id,\n scopes,\n request.subject_id,\n limit,\n request.cross_agent\n );\n } catch (error) {\n console.warn(`[search] Semantic search failed: ${error}`);\n return [];\n }\n }\n\n private async searchGraph(\n request: SearchRequest,\n limit: number\n ): Promise<ScoredMemory[]> {\n try {\n if (!this.orchestrator.age) return [];\n\n const entityName = extractEntityFromQuery(request.query);\n if (!entityName) return [];\n\n return await this.orchestrator.age.searchByEntity(\n entityName,\n undefined,\n request.cross_agent ? undefined : request.agent_id,\n limit\n );\n } catch (error) {\n console.warn(`[search] Graph search failed: ${error}`);\n return [];\n }\n }\n\n // ── Result Merging ──────────────────────────────────────────────────\n\n private mergeResults(\n allResults: ScoredMemory[],\n limit: number\n ): ScoredMemory[] {\n // 1. Group by memory ID\n const byId = new Map<string, ScoredMemory[]>();\n for (const result of allResults) {\n const existing = byId.get(result.memory.id) || [];\n existing.push(result);\n byId.set(result.memory.id, existing);\n }\n\n // 2. For each group, take best + apply boosts\n const merged: ScoredMemory[] = [];\n for (const [_id, results] of byId) {\n results.sort((a, b) => b.score - a.score);\n const best = results[0];\n\n const graphContext = results\n .filter((r) => r.graph_context)\n .flatMap((r) => r.graph_context!.related_entities);\n\n const boosted = applyBoosts(best, results.length);\n\n if (graphContext.length > 0) {\n boosted.graph_context = { related_entities: graphContext };\n }\n\n merged.push(boosted);\n }\n\n // 3. Sort by final score descending\n merged.sort((a, b) => b.score - a.score);\n\n return merged.slice(0, limit);\n }\n}\n\n// ── Helper Functions ────────────────────────────────────────────────────\n\nfunction shouldSearchFulltext(strategy: Strategy): boolean {\n return [\"fulltext\", \"fulltext+graph\", \"all\"].includes(strategy);\n}\n\nfunction shouldSearchSemantic(strategy: Strategy): boolean {\n return [\"semantic\", \"semantic+graph\", \"graph+semantic\", \"all\"].includes(strategy);\n}\n\nfunction shouldSearchGraph(strategy: Strategy): boolean {\n return [\"graph\", \"fulltext+graph\", \"graph+semantic\", \"semantic+graph\", \"all\"].includes(strategy);\n}\n\n/**\n * Extract potential entity names from natural language queries.\n */\nfunction extractEntityFromQuery(query: string): string | null {\n const quoted = query.match(/[\"']([^\"']+)[\"']/);\n if (quoted) return quoted[1];\n\n const aboutMatch = query.match(\n /(?:about|on|for|regarding|related to|connected to)\\s+([A-Z][a-zA-Z]*(?:\\s+[A-Z][a-zA-Z]*)*)/i\n );\n if (aboutMatch) return aboutMatch[1];\n\n const capitalWords = query.match(/\\b[A-Z][a-zA-Z]+(?:\\s+[A-Z][a-zA-Z]+)*/g);\n if (capitalWords && capitalWords.length > 0) {\n return capitalWords.sort((a, b) => b.length - a.length)[0];\n }\n\n const whoPattern = query.match(\n /who\\s+(?:works on|knows|created|uses|manages)\\s+(.+)/i\n );\n if (whoPattern) return whoPattern[1].trim();\n\n if (query.split(/\\s+/).length <= 3) {\n return query.trim();\n }\n\n return null;\n}\n","import OpenAI from \"openai\";\n\n// ── Summarization Prompt ────────────────────────────────────────────────\n\nconst SUMMARIZE_PROMPT = `Summarize this conversation into 5-10 concise bullet points.\nFocus on:\n- Decisions made\n- Tasks discussed or assigned\n- Preferences expressed\n- Important facts learned\n- Action items or next steps\n\nBe specific. Use names and details. Skip pleasantries and meta-conversation.\nReturn the summary as a plain text bulleted list.`;\n\n// ── Conversation Summarizer ─────────────────────────────────────────────\n\nexport interface SummarizerConfig {\n apiKey: string;\n baseUrl?: string;\n model: string;\n}\n\nexport class ConversationSummarizer {\n private client: OpenAI;\n private model: string;\n\n constructor(config: SummarizerConfig) {\n this.client = new OpenAI({\n apiKey: config.apiKey,\n baseURL: config.baseUrl,\n });\n this.model = config.model;\n }\n\n async summarize(\n messages: Array<{ role: string; content: string; timestamp?: string }>\n ): Promise<string | null> {\n if (messages.length === 0) return null;\n\n const transcript = messages\n .map((m) => {\n const prefix = m.role === \"user\" ? \"User\" : m.role === \"assistant\" ? \"Assistant\" : \"System\";\n return `${prefix}: ${m.content}`;\n })\n .join(\"\\n\");\n\n const truncated = transcript.slice(-6000);\n\n try {\n const response = await this.client.chat.completions.create({\n model: this.model,\n messages: [\n { role: \"system\", content: SUMMARIZE_PROMPT },\n { role: \"user\", content: truncated },\n ],\n temperature: 0.2,\n max_tokens: 500,\n });\n\n const content = response.choices[0]?.message?.content?.trim();\n return content || null;\n } catch (error) {\n console.error(`[summarizer] Summarization failed: ${error}`);\n return null;\n }\n }\n}\n"],"mappings":"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","names":["OpenAI","OpenAI"]}