@smyslenny/agent-memory 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/LICENSE +21 -0
- package/README.md +180 -0
- package/README.zh-CN.md +170 -0
- package/dist/bin/agent-memory.d.ts +1 -0
- package/dist/bin/agent-memory.js +916 -0
- package/dist/bin/agent-memory.js.map +1 -0
- package/dist/db-CMsKtBt0.d.ts +9 -0
- package/dist/index.d.ts +275 -0
- package/dist/index.js +849 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/server.d.ts +10 -0
- package/dist/mcp/server.js +14859 -0
- package/dist/mcp/server.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/core/db.ts","../../src/core/memory.ts","../../src/search/bm25.ts","../../src/search/intent.ts","../../src/search/rerank.ts","../../src/core/path.ts","../../src/sleep/boot.ts","../../src/sleep/decay.ts","../../src/core/snapshot.ts","../../src/sleep/tidy.ts","../../src/sleep/govern.ts","../../src/core/guard.ts","../../src/sleep/sync.ts","../../src/bin/agent-memory.ts"],"sourcesContent":["// AgentMemory v2 — SQLite database initialization and schema\nimport Database from \"better-sqlite3\";\nimport { randomUUID } from \"crypto\";\n\nexport const SCHEMA_VERSION = 1;\n\nconst SCHEMA_SQL = `\n-- Memory entries\nCREATE TABLE IF NOT EXISTS memories (\n id TEXT PRIMARY KEY,\n content TEXT NOT NULL,\n type TEXT NOT NULL CHECK(type IN ('identity','emotion','knowledge','event')),\n priority INTEGER NOT NULL DEFAULT 2 CHECK(priority BETWEEN 0 AND 3),\n emotion_val REAL NOT NULL DEFAULT 0.0,\n vitality REAL NOT NULL DEFAULT 1.0,\n stability REAL NOT NULL DEFAULT 1.0,\n access_count INTEGER NOT NULL DEFAULT 0,\n last_accessed TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n source TEXT,\n agent_id TEXT NOT NULL DEFAULT 'default',\n hash TEXT,\n UNIQUE(hash, agent_id)\n);\n\n-- URI paths (Content-Path separation, from nocturne)\nCREATE TABLE IF NOT EXISTS paths (\n id TEXT PRIMARY KEY,\n memory_id TEXT NOT NULL REFERENCES memories(id) ON DELETE CASCADE,\n uri TEXT NOT NULL UNIQUE,\n alias TEXT,\n domain TEXT NOT NULL,\n created_at TEXT NOT NULL\n);\n\n-- Association network (knowledge graph)\nCREATE TABLE IF NOT EXISTS links (\n source_id TEXT NOT NULL REFERENCES memories(id) ON DELETE CASCADE,\n target_id TEXT NOT NULL REFERENCES memories(id) ON DELETE CASCADE,\n relation TEXT NOT NULL,\n weight REAL NOT NULL DEFAULT 1.0,\n created_at TEXT NOT NULL,\n PRIMARY KEY (source_id, target_id)\n);\n\n-- Snapshots (version control, from nocturne + Memory Palace)\nCREATE TABLE IF NOT EXISTS snapshots (\n id TEXT PRIMARY KEY,\n memory_id TEXT NOT NULL REFERENCES memories(id) ON DELETE CASCADE,\n content TEXT NOT NULL,\n changed_by TEXT,\n action TEXT NOT NULL CHECK(action IN ('create','update','delete','merge')),\n created_at TEXT NOT NULL\n);\n\n-- Full-text search index (BM25)\nCREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(\n id UNINDEXED,\n content,\n tokenize='unicode61'\n);\n\n-- Schema version tracking\nCREATE TABLE IF NOT EXISTS schema_meta (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n);\n\n-- Indexes for common queries\nCREATE INDEX IF NOT EXISTS idx_memories_type ON memories(type);\nCREATE INDEX IF NOT EXISTS idx_memories_priority ON memories(priority);\nCREATE INDEX IF NOT EXISTS idx_memories_agent ON memories(agent_id);\nCREATE INDEX IF NOT EXISTS idx_memories_vitality ON memories(vitality);\nCREATE INDEX IF NOT EXISTS idx_memories_hash ON memories(hash);\nCREATE INDEX IF NOT EXISTS idx_paths_memory ON paths(memory_id);\nCREATE INDEX IF NOT EXISTS idx_paths_domain ON paths(domain);\nCREATE INDEX IF NOT EXISTS idx_links_source ON links(source_id);\nCREATE INDEX IF NOT EXISTS idx_links_target ON links(target_id);\n`;\n\nexport interface DbOptions {\n path: string;\n walMode?: boolean;\n}\n\nexport function openDatabase(opts: DbOptions): Database.Database {\n const db = new Database(opts.path);\n\n // Enable WAL mode for better concurrent read performance\n if (opts.walMode !== false) {\n db.pragma(\"journal_mode = WAL\");\n }\n db.pragma(\"foreign_keys = ON\");\n db.pragma(\"busy_timeout = 5000\");\n\n // Run schema creation\n db.exec(SCHEMA_SQL);\n\n // Track schema version\n const getVersion = db.prepare(\"SELECT value FROM schema_meta WHERE key = 'version'\");\n const row = getVersion.get() as { value: string } | undefined;\n if (!row) {\n db.prepare(\"INSERT INTO schema_meta (key, value) VALUES ('version', ?)\").run(\n String(SCHEMA_VERSION),\n );\n }\n\n return db;\n}\n\nexport function now(): string {\n return new Date().toISOString();\n}\n\nexport function newId(): string {\n return randomUUID();\n}\n","// AgentMemory v2 — Memory CRUD operations\nimport { createHash } from \"crypto\";\nimport type Database from \"better-sqlite3\";\nimport { newId, now } from \"./db.js\";\n\nexport type MemoryType = \"identity\" | \"emotion\" | \"knowledge\" | \"event\";\nexport type Priority = 0 | 1 | 2 | 3;\n\nexport interface Memory {\n id: string;\n content: string;\n type: MemoryType;\n priority: Priority;\n emotion_val: number;\n vitality: number;\n stability: number;\n access_count: number;\n last_accessed: string | null;\n created_at: string;\n updated_at: string;\n source: string | null;\n agent_id: string;\n hash: string | null;\n}\n\nexport interface CreateMemoryInput {\n content: string;\n type: MemoryType;\n priority?: Priority;\n emotion_val?: number;\n source?: string;\n agent_id?: string;\n}\n\nexport interface UpdateMemoryInput {\n content?: string;\n type?: MemoryType;\n priority?: Priority;\n emotion_val?: number;\n vitality?: number;\n stability?: number;\n source?: string;\n}\n\nexport function contentHash(content: string): string {\n return createHash(\"sha256\").update(content.trim()).digest(\"hex\").slice(0, 16);\n}\n\n// Priority defaults based on type\nconst TYPE_PRIORITY: Record<MemoryType, Priority> = {\n identity: 0,\n emotion: 1,\n knowledge: 2,\n event: 3,\n};\n\n// Initial stability (Ebbinghaus S parameter) based on priority\nconst PRIORITY_STABILITY: Record<Priority, number> = {\n 0: Infinity, // P0: never decays\n 1: 365, // P1: 365-day half-life\n 2: 90, // P2: 90-day half-life\n 3: 14, // P3: 14-day half-life\n};\n\nexport function createMemory(db: Database.Database, input: CreateMemoryInput): Memory | null {\n const hash = contentHash(input.content);\n const agentId = input.agent_id ?? \"default\";\n const priority = input.priority ?? TYPE_PRIORITY[input.type];\n const stability = PRIORITY_STABILITY[priority];\n\n // Dedup: check if identical content already exists for this agent\n const existing = db\n .prepare(\"SELECT id FROM memories WHERE hash = ? AND agent_id = ?\")\n .get(hash, agentId) as { id: string } | undefined;\n if (existing) {\n return null; // Already exists, skip\n }\n\n const id = newId();\n const timestamp = now();\n\n db.prepare(\n `INSERT INTO memories (id, content, type, priority, emotion_val, vitality, stability,\n access_count, created_at, updated_at, source, agent_id, hash)\n VALUES (?, ?, ?, ?, ?, 1.0, ?, 0, ?, ?, ?, ?, ?)`,\n ).run(\n id,\n input.content,\n input.type,\n priority,\n input.emotion_val ?? 0.0,\n stability === Infinity ? 999999 : stability,\n timestamp,\n timestamp,\n input.source ?? null,\n agentId,\n hash,\n );\n\n // Sync to FTS index\n db.prepare(\"INSERT INTO memories_fts (id, content) VALUES (?, ?)\").run(id, input.content);\n\n return getMemory(db, id)!;\n}\n\nexport function getMemory(db: Database.Database, id: string): Memory | null {\n return (db.prepare(\"SELECT * FROM memories WHERE id = ?\").get(id) as Memory) ?? null;\n}\n\nexport function updateMemory(\n db: Database.Database,\n id: string,\n input: UpdateMemoryInput,\n): Memory | null {\n const existing = getMemory(db, id);\n if (!existing) return null;\n\n const fields: string[] = [];\n const values: unknown[] = [];\n\n if (input.content !== undefined) {\n fields.push(\"content = ?\", \"hash = ?\");\n values.push(input.content, contentHash(input.content));\n }\n if (input.type !== undefined) {\n fields.push(\"type = ?\");\n values.push(input.type);\n }\n if (input.priority !== undefined) {\n fields.push(\"priority = ?\");\n values.push(input.priority);\n }\n if (input.emotion_val !== undefined) {\n fields.push(\"emotion_val = ?\");\n values.push(input.emotion_val);\n }\n if (input.vitality !== undefined) {\n fields.push(\"vitality = ?\");\n values.push(input.vitality);\n }\n if (input.stability !== undefined) {\n fields.push(\"stability = ?\");\n values.push(input.stability);\n }\n if (input.source !== undefined) {\n fields.push(\"source = ?\");\n values.push(input.source);\n }\n\n fields.push(\"updated_at = ?\");\n values.push(now());\n values.push(id);\n\n db.prepare(`UPDATE memories SET ${fields.join(\", \")} WHERE id = ?`).run(...values);\n\n // Update FTS if content changed\n if (input.content !== undefined) {\n db.prepare(\"DELETE FROM memories_fts WHERE id = ?\").run(id);\n db.prepare(\"INSERT INTO memories_fts (id, content) VALUES (?, ?)\").run(id, input.content);\n }\n\n return getMemory(db, id);\n}\n\nexport function deleteMemory(db: Database.Database, id: string): boolean {\n // FTS cleanup\n db.prepare(\"DELETE FROM memories_fts WHERE id = ?\").run(id);\n const result = db.prepare(\"DELETE FROM memories WHERE id = ?\").run(id);\n return result.changes > 0;\n}\n\nexport function listMemories(\n db: Database.Database,\n opts?: {\n agent_id?: string;\n type?: MemoryType;\n priority?: Priority;\n min_vitality?: number;\n limit?: number;\n offset?: number;\n },\n): Memory[] {\n const conditions: string[] = [];\n const params: unknown[] = [];\n\n if (opts?.agent_id) {\n conditions.push(\"agent_id = ?\");\n params.push(opts.agent_id);\n }\n if (opts?.type) {\n conditions.push(\"type = ?\");\n params.push(opts.type);\n }\n if (opts?.priority !== undefined) {\n conditions.push(\"priority = ?\");\n params.push(opts.priority);\n }\n if (opts?.min_vitality !== undefined) {\n conditions.push(\"vitality >= ?\");\n params.push(opts.min_vitality);\n }\n\n const where = conditions.length ? `WHERE ${conditions.join(\" AND \")}` : \"\";\n const limit = opts?.limit ?? 100;\n const offset = opts?.offset ?? 0;\n\n return db\n .prepare(`SELECT * FROM memories ${where} ORDER BY priority ASC, updated_at DESC LIMIT ? OFFSET ?`)\n .all(...params, limit, offset) as Memory[];\n}\n\nexport function recordAccess(db: Database.Database, id: string, growthFactor = 1.5): void {\n const mem = getMemory(db, id);\n if (!mem) return;\n\n const newStability = Math.min(999999, mem.stability * growthFactor);\n\n db.prepare(\n `UPDATE memories SET access_count = access_count + 1, last_accessed = ?, stability = ?,\n vitality = MIN(1.0, vitality * 1.2) WHERE id = ?`,\n ).run(now(), newStability, id);\n}\n\nexport function countMemories(\n db: Database.Database,\n agent_id = \"default\",\n): { total: number; by_type: Record<string, number>; by_priority: Record<string, number> } {\n const total = (\n db.prepare(\"SELECT COUNT(*) as c FROM memories WHERE agent_id = ?\").get(agent_id) as {\n c: number;\n }\n ).c;\n\n const byType = db\n .prepare(\"SELECT type, COUNT(*) as c FROM memories WHERE agent_id = ? GROUP BY type\")\n .all(agent_id) as Array<{ type: string; c: number }>;\n\n const byPriority = db\n .prepare(\"SELECT priority, COUNT(*) as c FROM memories WHERE agent_id = ? GROUP BY priority\")\n .all(agent_id) as Array<{ priority: number; c: number }>;\n\n return {\n total,\n by_type: Object.fromEntries(byType.map((r) => [r.type, r.c])),\n by_priority: Object.fromEntries(byPriority.map((r) => [`P${r.priority}`, r.c])),\n };\n}\n","// AgentMemory v2 — BM25 full-text search via SQLite FTS5\nimport type Database from \"better-sqlite3\";\nimport type { Memory } from \"../core/memory.js\";\n\nexport interface SearchResult {\n memory: Memory;\n score: number;\n matchReason: string;\n}\n\n/**\n * BM25 search using SQLite FTS5.\n * Returns memories ranked by relevance.\n */\nexport function searchBM25(\n db: Database.Database,\n query: string,\n opts?: {\n agent_id?: string;\n limit?: number;\n min_vitality?: number;\n },\n): SearchResult[] {\n const limit = opts?.limit ?? 20;\n const agentId = opts?.agent_id ?? \"default\";\n const minVitality = opts?.min_vitality ?? 0.0;\n\n const ftsQuery = buildFtsQuery(query);\n if (!ftsQuery) return [];\n\n try {\n const rows = db\n .prepare(\n `SELECT m.*, rank AS score\n FROM memories_fts f\n JOIN memories m ON m.id = f.id\n WHERE memories_fts MATCH ?\n AND m.agent_id = ?\n AND m.vitality >= ?\n ORDER BY rank\n LIMIT ?`,\n )\n .all(ftsQuery, agentId, minVitality, limit) as Array<Memory & { score: number }>;\n\n return rows.map((row) => ({\n memory: { ...row, score: undefined } as unknown as Memory,\n score: Math.abs(row.score), // FTS5 rank is negative (lower = better)\n matchReason: \"bm25\",\n }));\n } catch {\n // FTS query syntax error — fall back to simpler query\n return searchSimple(db, query, agentId, minVitality, limit);\n }\n}\n\n/**\n * Simple LIKE search as fallback when FTS fails\n */\nfunction searchSimple(\n db: Database.Database,\n query: string,\n agentId: string,\n minVitality: number,\n limit: number,\n): SearchResult[] {\n const rows = db\n .prepare(\n `SELECT * FROM memories\n WHERE agent_id = ? AND vitality >= ? AND content LIKE ?\n ORDER BY priority ASC, updated_at DESC\n LIMIT ?`,\n )\n .all(agentId, minVitality, `%${query}%`, limit) as Memory[];\n\n return rows.map((m, i) => ({\n memory: m,\n score: 1.0 / (i + 1), // Simple rank by position\n matchReason: \"like\",\n }));\n}\n\n/**\n * Build FTS5 query from natural language.\n * Extracts meaningful words, joins with OR for flexible matching.\n */\nfunction buildFtsQuery(text: string): string | null {\n const words = text\n .replace(/[^\\w\\u4e00-\\u9fff\\u3040-\\u30ff\\s]/g, \" \")\n .split(/\\s+/)\n .filter((w) => w.length > 1)\n .slice(0, 10);\n\n if (words.length === 0) return null;\n\n // Use OR for broad matching\n return words.map((w) => `\"${w}\"`).join(\" OR \");\n}\n","// AgentMemory v2 — Intent classifier (from Memory Palace)\n// Routes search queries to optimal strategies\n\nexport type SearchIntent = \"factual\" | \"exploratory\" | \"temporal\" | \"causal\";\n\nexport interface IntentResult {\n intent: SearchIntent;\n confidence: number;\n}\n\n// Keyword patterns for intent detection\nconst INTENT_PATTERNS: Record<SearchIntent, RegExp[]> = {\n factual: [\n /^(what|who|where|which|how much|how many)/i,\n /是(什么|谁|哪)/,\n /叫什么/,\n /名字/,\n /地址/,\n /号码/,\n /密码/,\n /配置/,\n /设置/,\n ],\n temporal: [\n /^(when|what time|how long)/i,\n /(yesterday|today|last week|recently|ago|before|after)/i,\n /什么时候/,\n /(昨天|今天|上周|最近|以前|之前|之后)/,\n /\\d{4}[-/]\\d{1,2}/,\n /(几月|几号|几点)/,\n ],\n causal: [\n /^(why|how come|what caused)/i,\n /^(because|due to|reason)/i,\n /为什么/,\n /原因/,\n /导致/,\n /怎么回事/,\n /为啥/,\n ],\n exploratory: [\n /^(how|tell me about|explain|describe)/i,\n /^(what do you think|what about)/i,\n /怎么样/,\n /介绍/,\n /说说/,\n /讲讲/,\n /有哪些/,\n /关于/,\n ],\n};\n\n/**\n * Classify the intent of a search query.\n * Uses keyword scoring — no LLM needed.\n */\nexport function classifyIntent(query: string): IntentResult {\n const scores: Record<SearchIntent, number> = {\n factual: 0,\n exploratory: 0,\n temporal: 0,\n causal: 0,\n };\n\n for (const [intent, patterns] of Object.entries(INTENT_PATTERNS)) {\n for (const pattern of patterns) {\n if (pattern.test(query)) {\n scores[intent as SearchIntent] += 1;\n }\n }\n }\n\n // Find highest scoring intent\n let maxIntent: SearchIntent = \"factual\"; // default\n let maxScore = 0;\n\n for (const [intent, score] of Object.entries(scores)) {\n if (score > maxScore) {\n maxScore = score;\n maxIntent = intent as SearchIntent;\n }\n }\n\n // If no clear signal, default to factual\n const totalScore = Object.values(scores).reduce((a, b) => a + b, 0);\n const confidence = totalScore > 0 ? maxScore / totalScore : 0.5;\n\n return { intent: maxIntent, confidence };\n}\n\n/**\n * Get search strategy based on intent\n */\nexport function getStrategy(intent: SearchIntent): {\n boostRecent: boolean;\n boostPriority: boolean;\n limit: number;\n} {\n switch (intent) {\n case \"factual\":\n return { boostRecent: false, boostPriority: true, limit: 5 };\n case \"temporal\":\n return { boostRecent: true, boostPriority: false, limit: 10 };\n case \"causal\":\n return { boostRecent: false, boostPriority: false, limit: 10 };\n case \"exploratory\":\n return { boostRecent: false, boostPriority: false, limit: 15 };\n }\n}\n","// AgentMemory v2 — Search result reranking + priority weighting\nimport type { SearchResult } from \"./bm25.js\";\nimport type { SearchIntent } from \"./intent.js\";\n\n/**\n * Rerank search results based on intent strategy and priority weighting.\n */\nexport function rerank(\n results: SearchResult[],\n opts: {\n intent?: SearchIntent;\n boostRecent: boolean;\n boostPriority: boolean;\n limit: number;\n },\n): SearchResult[] {\n const now = Date.now();\n\n const scored = results.map((r) => {\n let finalScore = r.score;\n\n // Priority boost: P0 > P1 > P2 > P3\n if (opts.boostPriority) {\n const priorityMultiplier = [4.0, 3.0, 2.0, 1.0][r.memory.priority] ?? 1.0;\n finalScore *= priorityMultiplier;\n }\n\n // Recency boost for temporal queries\n if (opts.boostRecent && r.memory.updated_at) {\n const age = now - new Date(r.memory.updated_at).getTime();\n const daysSinceUpdate = age / (1000 * 60 * 60 * 24);\n const recencyBoost = Math.max(0.1, 1.0 / (1.0 + daysSinceUpdate * 0.1));\n finalScore *= recencyBoost;\n }\n\n // Vitality factor — higher vitality memories are more relevant\n finalScore *= Math.max(0.1, r.memory.vitality);\n\n return { ...r, score: finalScore };\n });\n\n // Sort by final score (descending)\n scored.sort((a, b) => b.score - a.score);\n\n return scored.slice(0, opts.limit);\n}\n","// AgentMemory v2 — URI path system (from nocturne's Content-Path separation)\nimport type Database from \"better-sqlite3\";\nimport { newId, now } from \"./db.js\";\n\nexport interface Path {\n id: string;\n memory_id: string;\n uri: string;\n alias: string | null;\n domain: string;\n created_at: string;\n}\n\n// Valid domains (extensible)\nconst DEFAULT_DOMAINS = new Set([\"core\", \"emotion\", \"knowledge\", \"event\", \"system\"]);\n\nexport function parseUri(uri: string): { domain: string; path: string } {\n const match = uri.match(/^([a-z]+):\\/\\/(.+)$/);\n if (!match) throw new Error(`Invalid URI: ${uri}. Expected format: domain://path`);\n return { domain: match[1], path: match[2] };\n}\n\nexport function createPath(\n db: Database.Database,\n memoryId: string,\n uri: string,\n alias?: string,\n validDomains?: Set<string>,\n): Path {\n const { domain } = parseUri(uri);\n const domains = validDomains ?? DEFAULT_DOMAINS;\n if (!domains.has(domain)) {\n throw new Error(`Invalid domain \"${domain}\". Valid: ${[...domains].join(\", \")}`);\n }\n\n // Check URI uniqueness\n const existing = db.prepare(\"SELECT id FROM paths WHERE uri = ?\").get(uri) as\n | { id: string }\n | undefined;\n if (existing) {\n throw new Error(`URI already exists: ${uri}`);\n }\n\n const id = newId();\n db.prepare(\n \"INSERT INTO paths (id, memory_id, uri, alias, domain, created_at) VALUES (?, ?, ?, ?, ?, ?)\",\n ).run(id, memoryId, uri, alias ?? null, domain, now());\n\n return getPath(db, id)!;\n}\n\nexport function getPath(db: Database.Database, id: string): Path | null {\n return (db.prepare(\"SELECT * FROM paths WHERE id = ?\").get(id) as Path) ?? null;\n}\n\nexport function getPathByUri(db: Database.Database, uri: string): Path | null {\n return (db.prepare(\"SELECT * FROM paths WHERE uri = ?\").get(uri) as Path) ?? null;\n}\n\nexport function getPathsByMemory(db: Database.Database, memoryId: string): Path[] {\n return db.prepare(\"SELECT * FROM paths WHERE memory_id = ?\").all(memoryId) as Path[];\n}\n\nexport function getPathsByDomain(db: Database.Database, domain: string): Path[] {\n return db\n .prepare(\"SELECT * FROM paths WHERE domain = ? ORDER BY uri\")\n .all(domain) as Path[];\n}\n\nexport function getPathsByPrefix(db: Database.Database, prefix: string): Path[] {\n return db\n .prepare(\"SELECT * FROM paths WHERE uri LIKE ? ORDER BY uri\")\n .all(`${prefix}%`) as Path[];\n}\n\nexport function deletePath(db: Database.Database, id: string): boolean {\n const result = db.prepare(\"DELETE FROM paths WHERE id = ?\").run(id);\n return result.changes > 0;\n}\n\nexport function deletePathsByMemory(db: Database.Database, memoryId: string): number {\n const result = db.prepare(\"DELETE FROM paths WHERE memory_id = ?\").run(memoryId);\n return result.changes;\n}\n","// AgentMemory v2 — Boot loader (system://boot identity loading)\n// From nocturne's CORE_MEMORY_URIS concept\nimport type Database from \"better-sqlite3\";\nimport type { Memory } from \"../core/memory.js\";\nimport { getPathByUri } from \"../core/path.js\";\nimport { getMemory, listMemories, recordAccess } from \"../core/memory.js\";\n\nexport interface BootResult {\n identityMemories: Memory[];\n bootPaths: string[];\n}\n\n/**\n * Load core identity memories at startup.\n * Returns all P0 (identity) memories + any memories referenced by system://boot.\n */\nexport function boot(\n db: Database.Database,\n opts?: { agent_id?: string; corePaths?: string[] },\n): BootResult {\n const agentId = opts?.agent_id ?? \"default\";\n const corePaths = opts?.corePaths ?? [\n \"core://agent\",\n \"core://user\",\n \"core://agent/identity\",\n \"core://user/identity\",\n ];\n\n const memories = new Map<string, Memory>();\n\n // 1. Load all P0 identity memories\n const identities = listMemories(db, { agent_id: agentId, priority: 0 });\n for (const mem of identities) {\n memories.set(mem.id, mem);\n recordAccess(db, mem.id, 1.1); // Light access boost on boot\n }\n\n // 2. Load memories at configured core paths\n const bootPaths: string[] = [];\n for (const uri of corePaths) {\n const path = getPathByUri(db, uri);\n if (path) {\n bootPaths.push(uri);\n if (!memories.has(path.memory_id)) {\n const mem = getMemory(db, path.memory_id);\n if (mem) {\n memories.set(mem.id, mem);\n recordAccess(db, mem.id, 1.1);\n }\n }\n }\n }\n\n // 3. Check system://boot for additional paths\n const bootEntry = getPathByUri(db, \"system://boot\");\n if (bootEntry) {\n const bootMem = getMemory(db, bootEntry.memory_id);\n if (bootMem) {\n // system://boot content may list additional URIs (one per line)\n const additionalUris = bootMem.content\n .split(\"\\n\")\n .map((l) => l.trim())\n .filter((l) => l.match(/^[a-z]+:\\/\\//));\n\n for (const uri of additionalUris) {\n const path = getPathByUri(db, uri);\n if (path && !memories.has(path.memory_id)) {\n const mem = getMemory(db, path.memory_id);\n if (mem) {\n memories.set(mem.id, mem);\n bootPaths.push(uri);\n }\n }\n }\n }\n }\n\n return {\n identityMemories: [...memories.values()],\n bootPaths,\n };\n}\n","// AgentMemory v2 — Ebbinghaus forgetting curve decay engine\n// From PowerMem's cognitive science approach: R = e^(-t/S)\nimport type Database from \"better-sqlite3\";\nimport { now } from \"../core/db.js\";\n\n/**\n * Ebbinghaus forgetting curve: R = e^(-t/S)\n * R = retention (vitality), range [0, 1]\n * t = time elapsed (days)\n * S = stability (increases with each recall)\n *\n * Priority-based minimum vitality:\n * P0 (identity): never decays (min 1.0)\n * P1 (emotion): min 0.3\n * P2 (knowledge): min 0.1\n * P3 (event): min 0.0 (can be cleaned up)\n */\n\nconst MIN_VITALITY: Record<number, number> = {\n 0: 1.0, // P0: identity — never decays\n 1: 0.3, // P1: emotion — slow decay\n 2: 0.1, // P2: knowledge — normal decay\n 3: 0.0, // P3: event — full decay\n};\n\nexport function calculateVitality(\n stability: number,\n daysSinceCreation: number,\n priority: number,\n): number {\n // P0 never decays\n if (priority === 0) return 1.0;\n\n // Prevent division by zero\n const S = Math.max(0.01, stability);\n\n // R = e^(-t/S)\n const retention = Math.exp(-daysSinceCreation / S);\n\n // Apply minimum vitality based on priority\n const minVit = MIN_VITALITY[priority] ?? 0.0;\n return Math.max(minVit, retention);\n}\n\n/**\n * Run decay on all memories.\n * Updates vitality based on Ebbinghaus curve.\n * Returns count of memories updated.\n */\nexport function runDecay(db: Database.Database): {\n updated: number;\n decayed: number;\n belowThreshold: number;\n} {\n const currentTime = now();\n const currentMs = new Date(currentTime).getTime();\n\n // Get all non-P0 memories\n const memories = db\n .prepare(\"SELECT id, priority, stability, created_at, vitality FROM memories WHERE priority > 0\")\n .all() as Array<{\n id: string;\n priority: number;\n stability: number;\n created_at: string;\n vitality: number;\n }>;\n\n let updated = 0;\n let decayed = 0;\n let belowThreshold = 0;\n\n const updateStmt = db.prepare(\"UPDATE memories SET vitality = ?, updated_at = ? WHERE id = ?\");\n\n const transaction = db.transaction(() => {\n for (const mem of memories) {\n const createdMs = new Date(mem.created_at).getTime();\n const daysSince = (currentMs - createdMs) / (1000 * 60 * 60 * 24);\n\n const newVitality = calculateVitality(mem.stability, daysSince, mem.priority);\n\n // Only update if vitality actually changed (>0.001 difference)\n if (Math.abs(newVitality - mem.vitality) > 0.001) {\n updateStmt.run(newVitality, currentTime, mem.id);\n updated++;\n\n if (newVitality < mem.vitality) {\n decayed++;\n }\n\n if (newVitality < 0.05) {\n belowThreshold++;\n }\n }\n }\n });\n\n transaction();\n\n return { updated, decayed, belowThreshold };\n}\n\n/**\n * Get memories that are candidates for cleanup (vitality < threshold).\n * Only P3 (event) memories can be fully cleaned.\n */\nexport function getDecayedMemories(\n db: Database.Database,\n threshold = 0.05,\n): Array<{ id: string; content: string; vitality: number; priority: number }> {\n return db\n .prepare(\n `SELECT id, content, vitality, priority FROM memories\n WHERE vitality < ? AND priority >= 3\n ORDER BY vitality ASC`,\n )\n .all(threshold) as Array<{\n id: string;\n content: string;\n vitality: number;\n priority: number;\n }>;\n}\n","// AgentMemory v2 — Snapshot system (version control, from nocturne + Memory Palace)\nimport type Database from \"better-sqlite3\";\nimport { newId, now } from \"./db.js\";\n\nexport type SnapshotAction = \"create\" | \"update\" | \"delete\" | \"merge\";\n\nexport interface Snapshot {\n id: string;\n memory_id: string;\n content: string;\n changed_by: string | null;\n action: SnapshotAction;\n created_at: string;\n}\n\n/**\n * Create a snapshot before modifying a memory.\n * Call this BEFORE any update/delete operation.\n */\nexport function createSnapshot(\n db: Database.Database,\n memoryId: string,\n action: SnapshotAction,\n changedBy?: string,\n): Snapshot {\n const memory = db.prepare(\"SELECT content FROM memories WHERE id = ?\").get(memoryId) as\n | { content: string }\n | undefined;\n\n if (!memory) throw new Error(`Memory not found: ${memoryId}`);\n\n const id = newId();\n db.prepare(\n `INSERT INTO snapshots (id, memory_id, content, changed_by, action, created_at)\n VALUES (?, ?, ?, ?, ?, ?)`,\n ).run(id, memoryId, memory.content, changedBy ?? null, action, now());\n\n return { id, memory_id: memoryId, content: memory.content, changed_by: changedBy ?? null, action, created_at: now() };\n}\n\nexport function getSnapshots(db: Database.Database, memoryId: string): Snapshot[] {\n return db\n .prepare(\"SELECT * FROM snapshots WHERE memory_id = ? ORDER BY created_at DESC\")\n .all(memoryId) as Snapshot[];\n}\n\nexport function getSnapshot(db: Database.Database, id: string): Snapshot | null {\n return (db.prepare(\"SELECT * FROM snapshots WHERE id = ?\").get(id) as Snapshot) ?? null;\n}\n\n/**\n * Rollback a memory to a specific snapshot.\n * Creates a new snapshot of the current state before rolling back.\n */\nexport function rollback(db: Database.Database, snapshotId: string): boolean {\n const snapshot = getSnapshot(db, snapshotId);\n if (!snapshot) return false;\n\n // Snapshot current state before rollback\n createSnapshot(db, snapshot.memory_id, \"update\", \"rollback\");\n\n // Restore content\n db.prepare(\"UPDATE memories SET content = ?, updated_at = ? WHERE id = ?\").run(\n snapshot.content,\n now(),\n snapshot.memory_id,\n );\n\n // Update FTS\n db.prepare(\"DELETE FROM memories_fts WHERE id = ?\").run(snapshot.memory_id);\n db.prepare(\"INSERT INTO memories_fts (id, content) VALUES (?, ?)\").run(\n snapshot.memory_id,\n snapshot.content,\n );\n\n return true;\n}\n\nexport function deleteSnapshots(db: Database.Database, memoryId: string): number {\n const result = db.prepare(\"DELETE FROM snapshots WHERE memory_id = ?\").run(memoryId);\n return result.changes;\n}\n","// AgentMemory v2 — Sleep tidy engine (deep sleep phase)\n// Compresses, distills, archives old memories\nimport type Database from \"better-sqlite3\";\nimport { deleteMemory, listMemories, type Memory } from \"../core/memory.js\";\nimport { createSnapshot } from \"../core/snapshot.js\";\nimport { getDecayedMemories } from \"./decay.js\";\n\nexport interface TidyResult {\n archived: number;\n orphansCleaned: number;\n snapshotsPruned: number;\n}\n\n/**\n * Run the tidy (deep sleep) cycle:\n * 1. Archive decayed P3 memories (vitality < threshold)\n * 2. Clean orphan paths (paths with no memory)\n * 3. Prune old snapshots (keep last N per memory)\n */\nexport function runTidy(\n db: Database.Database,\n opts?: {\n vitalityThreshold?: number;\n maxSnapshotsPerMemory?: number;\n },\n): TidyResult {\n const threshold = opts?.vitalityThreshold ?? 0.05;\n const maxSnapshots = opts?.maxSnapshotsPerMemory ?? 10;\n\n let archived = 0;\n let orphansCleaned = 0;\n let snapshotsPruned = 0;\n\n const transaction = db.transaction(() => {\n // 1. Archive decayed memories\n const decayed = getDecayedMemories(db, threshold);\n for (const mem of decayed) {\n // Snapshot before delete\n try {\n createSnapshot(db, mem.id, \"delete\", \"tidy\");\n } catch {\n // Memory might already be gone\n }\n deleteMemory(db, mem.id);\n archived++;\n }\n\n // 2. Clean orphan paths (paths pointing to deleted memories)\n const orphans = db\n .prepare(\n `DELETE FROM paths WHERE memory_id NOT IN (SELECT id FROM memories)`,\n )\n .run();\n orphansCleaned = orphans.changes;\n\n // 3. Prune old snapshots (keep only latest N per memory)\n const memoriesWithSnapshots = db\n .prepare(\n `SELECT memory_id, COUNT(*) as cnt FROM snapshots\n GROUP BY memory_id HAVING cnt > ?`,\n )\n .all(maxSnapshots) as Array<{ memory_id: string; cnt: number }>;\n\n for (const { memory_id } of memoriesWithSnapshots) {\n const pruned = db\n .prepare(\n `DELETE FROM snapshots WHERE id NOT IN (\n SELECT id FROM snapshots WHERE memory_id = ?\n ORDER BY created_at DESC LIMIT ?\n ) AND memory_id = ?`,\n )\n .run(memory_id, maxSnapshots, memory_id);\n snapshotsPruned += pruned.changes;\n }\n });\n\n transaction();\n\n return { archived, orphansCleaned, snapshotsPruned };\n}\n","// AgentMemory v2 — Governance cycle (memory health maintenance)\nimport type Database from \"better-sqlite3\";\n\nexport interface GovernResult {\n orphanPaths: number;\n orphanLinks: number;\n emptyMemories: number;\n}\n\n/**\n * Run governance checks and cleanup:\n * 1. Remove orphan paths (no parent memory)\n * 2. Remove orphan links (source or target missing)\n * 3. Remove empty memories (blank content)\n */\nexport function runGovern(db: Database.Database): GovernResult {\n let orphanPaths = 0;\n let orphanLinks = 0;\n let emptyMemories = 0;\n\n const transaction = db.transaction(() => {\n // 1. Orphan paths\n const pathResult = db\n .prepare(\"DELETE FROM paths WHERE memory_id NOT IN (SELECT id FROM memories)\")\n .run();\n orphanPaths = pathResult.changes;\n\n // 2. Orphan links\n const linkResult = db\n .prepare(\n `DELETE FROM links WHERE\n source_id NOT IN (SELECT id FROM memories) OR\n target_id NOT IN (SELECT id FROM memories)`,\n )\n .run();\n orphanLinks = linkResult.changes;\n\n // 3. Empty memories\n const emptyResult = db\n .prepare(\"DELETE FROM memories WHERE TRIM(content) = ''\")\n .run();\n emptyMemories = emptyResult.changes;\n });\n\n transaction();\n\n return { orphanPaths, orphanLinks, emptyMemories };\n}\n","// AgentMemory v2 — Write Guard (dedup + conflict detection + 4-criterion gate)\nimport type Database from \"better-sqlite3\";\nimport { contentHash, type CreateMemoryInput, type Memory } from \"./memory.js\";\nimport { getPathByUri } from \"./path.js\";\n\nexport type GuardAction = \"add\" | \"update\" | \"skip\" | \"merge\";\n\nexport interface GuardResult {\n action: GuardAction;\n reason: string;\n existingId?: string;\n mergedContent?: string;\n}\n\n/**\n * Write Guard — decides whether to add, update, skip, or merge a memory.\n *\n * Pipeline:\n * 1. Hash dedup (exact content match → skip)\n * 2. URI conflict (URI exists → update path)\n * 3. BM25 similarity (>0.85 → conflict detection → merge or update)\n * 4. Four-criterion gate (for P0/P1 only)\n */\nexport function guard(\n db: Database.Database,\n input: CreateMemoryInput & { uri?: string },\n): GuardResult {\n const hash = contentHash(input.content);\n const agentId = input.agent_id ?? \"default\";\n\n // 1. Hash dedup — exact content match\n const exactMatch = db\n .prepare(\"SELECT id FROM memories WHERE hash = ? AND agent_id = ?\")\n .get(hash, agentId) as { id: string } | undefined;\n\n if (exactMatch) {\n return { action: \"skip\", reason: \"Exact duplicate (hash match)\", existingId: exactMatch.id };\n }\n\n // 2. URI conflict — URI already exists, update instead of add\n if (input.uri) {\n const existingPath = getPathByUri(db, input.uri);\n if (existingPath) {\n return {\n action: \"update\",\n reason: `URI ${input.uri} already exists, updating`,\n existingId: existingPath.memory_id,\n };\n }\n }\n\n // 3. BM25 similarity — find similar content\n const similar = db\n .prepare(\n `SELECT m.id, m.content, m.type, rank\n FROM memories_fts f\n JOIN memories m ON m.id = f.id\n WHERE memories_fts MATCH ? AND m.agent_id = ?\n ORDER BY rank\n LIMIT 3`,\n )\n .all(escapeFts(input.content), agentId) as Array<\n Memory & { rank: number }\n >;\n\n if (similar.length > 0 && similar[0].rank < -10) {\n // High similarity — check if it's a conflict (different info about same topic)\n const existing = similar[0];\n if (existing.type === input.type) {\n // Same type + high similarity → merge\n const merged = `${existing.content}\\n\\n[Updated] ${input.content}`;\n return {\n action: \"merge\",\n reason: \"Similar content found, merging\",\n existingId: existing.id,\n mergedContent: merged,\n };\n }\n }\n\n // 4. Four-criterion gate (only for P0/P1 — identity and emotion)\n const priority = input.priority ?? (input.type === \"identity\" ? 0 : input.type === \"emotion\" ? 1 : 2);\n if (priority <= 1) {\n // For high-priority memories, we're more lenient — just check basic validity\n if (!input.content.trim()) {\n return { action: \"skip\", reason: \"Empty content rejected by gate\" };\n }\n }\n\n // All checks passed → add\n return { action: \"add\", reason: \"Passed all guard checks\" };\n}\n\n/**\n * Escape special FTS5 characters in query\n */\nfunction escapeFts(text: string): string {\n // Take first 100 chars, remove special chars, join with OR for flexible matching\n const words = text\n .slice(0, 100)\n .replace(/[^\\w\\u4e00-\\u9fff\\s]/g, \" \")\n .split(/\\s+/)\n .filter((w) => w.length > 1)\n .slice(0, 5);\n\n if (words.length === 0) return '\"\"';\n return words.map((w) => `\"${w}\"`).join(\" OR \");\n}\n","// AgentMemory v2 — Sleep sync engine (light sleep phase)\n// Captures new information, deduplicates, writes structured memories\nimport type Database from \"better-sqlite3\";\nimport { createMemory, type CreateMemoryInput, type Memory } from \"../core/memory.js\";\nimport { createPath, getPathByUri } from \"../core/path.js\";\nimport { createSnapshot } from \"../core/snapshot.js\";\nimport { guard } from \"../core/guard.js\";\nimport { updateMemory } from \"../core/memory.js\";\n\nexport interface SyncInput {\n content: string;\n type?: CreateMemoryInput[\"type\"];\n priority?: CreateMemoryInput[\"priority\"];\n emotion_val?: number;\n uri?: string;\n source?: string;\n agent_id?: string;\n}\n\nexport interface SyncResult {\n action: \"added\" | \"updated\" | \"merged\" | \"skipped\";\n memoryId?: string;\n reason: string;\n}\n\n/**\n * Sync a single piece of information into memory.\n * Runs full Write Guard pipeline before writing.\n */\nexport function syncOne(db: Database.Database, input: SyncInput): SyncResult {\n const memInput: CreateMemoryInput & { uri?: string } = {\n content: input.content,\n type: input.type ?? \"event\",\n priority: input.priority,\n emotion_val: input.emotion_val,\n source: input.source,\n agent_id: input.agent_id,\n uri: input.uri,\n };\n\n // Run Write Guard\n const guardResult = guard(db, memInput);\n\n switch (guardResult.action) {\n case \"skip\":\n return { action: \"skipped\", reason: guardResult.reason, memoryId: guardResult.existingId };\n\n case \"add\": {\n const mem = createMemory(db, memInput);\n if (!mem) return { action: \"skipped\", reason: \"createMemory returned null\" };\n\n // Create URI path if provided\n if (input.uri) {\n try {\n createPath(db, mem.id, input.uri);\n } catch {\n // URI might already exist, that's OK\n }\n }\n return { action: \"added\", memoryId: mem.id, reason: guardResult.reason };\n }\n\n case \"update\": {\n if (!guardResult.existingId) return { action: \"skipped\", reason: \"No existing ID for update\" };\n createSnapshot(db, guardResult.existingId, \"update\", \"sync\");\n updateMemory(db, guardResult.existingId, { content: input.content });\n return { action: \"updated\", memoryId: guardResult.existingId, reason: guardResult.reason };\n }\n\n case \"merge\": {\n if (!guardResult.existingId || !guardResult.mergedContent) {\n return { action: \"skipped\", reason: \"Missing merge data\" };\n }\n createSnapshot(db, guardResult.existingId, \"merge\", \"sync\");\n updateMemory(db, guardResult.existingId, { content: guardResult.mergedContent });\n return { action: \"merged\", memoryId: guardResult.existingId, reason: guardResult.reason };\n }\n }\n}\n\n/**\n * Sync multiple items in a batch (within a transaction).\n */\nexport function syncBatch(db: Database.Database, inputs: SyncInput[]): SyncResult[] {\n const results: SyncResult[] = [];\n const transaction = db.transaction(() => {\n for (const input of inputs) {\n results.push(syncOne(db, input));\n }\n });\n transaction();\n return results;\n}\n","#!/usr/bin/env node\n// AgentMemory v2 — CLI\nimport { openDatabase } from \"../core/db.js\";\nimport { createMemory, countMemories, listMemories } from \"../core/memory.js\";\nimport { createPath } from \"../core/path.js\";\nimport { searchBM25 } from \"../search/bm25.js\";\nimport { classifyIntent, getStrategy } from \"../search/intent.js\";\nimport { rerank } from \"../search/rerank.js\";\nimport { boot } from \"../sleep/boot.js\";\nimport { runDecay } from \"../sleep/decay.js\";\nimport { runTidy } from \"../sleep/tidy.js\";\nimport { runGovern } from \"../sleep/govern.js\";\nimport { syncOne } from \"../sleep/sync.js\";\nimport { existsSync, readFileSync, readdirSync } from \"fs\";\nimport { resolve, basename } from \"path\";\nimport type { MemoryType } from \"../core/memory.js\";\n\nconst args = process.argv.slice(2);\nconst command = args[0];\n\nfunction getDbPath(): string {\n return process.env.AGENT_MEMORY_DB ?? \"./agent-memory.db\";\n}\n\nfunction printHelp() {\n console.log(`\n🧠 AgentMemory v2 — Sleep-cycle memory for AI agents\n\nUsage: agent-memory <command> [options]\n\nCommands:\n init Create database\n remember <content> [--uri X] [--type T] Store a memory\n recall <query> [--limit N] Search memories\n boot Load identity memories\n status Show statistics\n reflect [decay|tidy|govern|all] Run sleep cycle\n migrate <dir> Import from Markdown files\n help Show this help\n\nEnvironment:\n AGENT_MEMORY_DB Database path (default: ./agent-memory.db)\n AGENT_MEMORY_AGENT_ID Agent ID (default: \"default\")\n`);\n}\n\nfunction getFlag(flag: string): string | undefined {\n const idx = args.indexOf(flag);\n if (idx >= 0 && idx + 1 < args.length) return args[idx + 1];\n return undefined;\n}\n\ntry {\n switch (command) {\n case \"init\": {\n const dbPath = getDbPath();\n openDatabase({ path: dbPath });\n console.log(`✅ Database created at ${dbPath}`);\n break;\n }\n\n case \"remember\": {\n const content = args.slice(1).filter((a) => !a.startsWith(\"--\")).join(\" \");\n if (!content) { console.error(\"Usage: agent-memory remember <content>\"); process.exit(1); }\n const db = openDatabase({ path: getDbPath() });\n const uri = getFlag(\"--uri\");\n const type = (getFlag(\"--type\") ?? \"knowledge\") as MemoryType;\n const result = syncOne(db, { content, type, uri });\n console.log(`${result.action}: ${result.reason}${result.memoryId ? ` (${result.memoryId.slice(0, 8)})` : \"\"}`);\n db.close();\n break;\n }\n\n case \"recall\": {\n const query = args.slice(1).filter((a) => !a.startsWith(\"--\")).join(\" \");\n if (!query) { console.error(\"Usage: agent-memory recall <query>\"); process.exit(1); }\n const db = openDatabase({ path: getDbPath() });\n const limit = parseInt(getFlag(\"--limit\") ?? \"10\");\n const { intent } = classifyIntent(query);\n const strategy = getStrategy(intent);\n const raw = searchBM25(db, query, { limit: limit * 2 });\n const results = rerank(raw, { ...strategy, limit });\n\n console.log(`🔍 Intent: ${intent} | Results: ${results.length}\\n`);\n for (const r of results) {\n const p = [\"🔴\", \"🟠\", \"🟡\", \"⚪\"][r.memory.priority];\n const v = (r.memory.vitality * 100).toFixed(0);\n console.log(`${p} P${r.memory.priority} [${v}%] ${r.memory.content.slice(0, 80)}`);\n }\n db.close();\n break;\n }\n\n case \"boot\": {\n const db = openDatabase({ path: getDbPath() });\n const result = boot(db);\n console.log(`🧠 Boot: ${result.identityMemories.length} identity memories loaded\\n`);\n for (const m of result.identityMemories) {\n console.log(` 🔴 ${m.content.slice(0, 100)}`);\n }\n if (result.bootPaths.length) {\n console.log(`\\n📍 Boot paths: ${result.bootPaths.join(\", \")}`);\n }\n db.close();\n break;\n }\n\n case \"status\": {\n const db = openDatabase({ path: getDbPath() });\n const stats = countMemories(db);\n const lowVit = (db.prepare(\"SELECT COUNT(*) as c FROM memories WHERE vitality < 0.1\").get() as { c: number }).c;\n const paths = (db.prepare(\"SELECT COUNT(*) as c FROM paths\").get() as { c: number }).c;\n const links = (db.prepare(\"SELECT COUNT(*) as c FROM links\").get() as { c: number }).c;\n const snaps = (db.prepare(\"SELECT COUNT(*) as c FROM snapshots\").get() as { c: number }).c;\n\n console.log(\"🧠 AgentMemory Status\\n\");\n console.log(` Total memories: ${stats.total}`);\n console.log(` By type: ${Object.entries(stats.by_type).map(([k, v]) => `${k}=${v}`).join(\", \")}`);\n console.log(` By priority: ${Object.entries(stats.by_priority).map(([k, v]) => `${k}=${v}`).join(\", \")}`);\n console.log(` Paths: ${paths} | Links: ${links} | Snapshots: ${snaps}`);\n console.log(` Low vitality (<10%): ${lowVit}`);\n db.close();\n break;\n }\n\n case \"reflect\": {\n const phase = args[1] ?? \"all\";\n const db = openDatabase({ path: getDbPath() });\n console.log(`🌙 Running ${phase} phase...\\n`);\n\n if (phase === \"decay\" || phase === \"all\") {\n const r = runDecay(db);\n console.log(` Decay: ${r.updated} updated, ${r.decayed} decayed, ${r.belowThreshold} below threshold`);\n }\n if (phase === \"tidy\" || phase === \"all\") {\n const r = runTidy(db);\n console.log(` Tidy: ${r.archived} archived, ${r.orphansCleaned} orphans, ${r.snapshotsPruned} snapshots pruned`);\n }\n if (phase === \"govern\" || phase === \"all\") {\n const r = runGovern(db);\n console.log(` Govern: ${r.orphanPaths} paths, ${r.orphanLinks} links, ${r.emptyMemories} empty cleaned`);\n }\n db.close();\n break;\n }\n\n case \"migrate\": {\n const dir = args[1];\n if (!dir) { console.error(\"Usage: agent-memory migrate <directory>\"); process.exit(1); }\n const dirPath = resolve(dir);\n if (!existsSync(dirPath)) { console.error(`Directory not found: ${dirPath}`); process.exit(1); }\n\n const db = openDatabase({ path: getDbPath() });\n let imported = 0;\n\n // Check for MEMORY.md\n const memoryMd = resolve(dirPath, \"MEMORY.md\");\n if (existsSync(memoryMd)) {\n const content = readFileSync(memoryMd, \"utf-8\");\n const sections = content.split(/^## /m).filter((s) => s.trim());\n\n for (const section of sections) {\n const lines = section.split(\"\\n\");\n const title = lines[0]?.trim();\n const body = lines.slice(1).join(\"\\n\").trim();\n if (!body) continue;\n\n const type: MemoryType = title?.toLowerCase().includes(\"关于\") || title?.toLowerCase().includes(\"about\")\n ? \"identity\" : \"knowledge\";\n const uri = `knowledge://memory-md/${title?.replace(/[^a-z0-9\\u4e00-\\u9fff]/gi, \"-\").toLowerCase()}`;\n\n syncOne(db, { content: `## ${title}\\n${body}`, type, uri, source: \"migrate:MEMORY.md\" });\n imported++;\n }\n console.log(`📄 MEMORY.md: ${sections.length} sections imported`);\n }\n\n // Check for daily journals\n const mdFiles = readdirSync(dirPath).filter((f) => /^\\d{4}-\\d{2}-\\d{2}\\.md$/.test(f)).sort();\n for (const file of mdFiles) {\n const content = readFileSync(resolve(dirPath, file), \"utf-8\");\n const date = basename(file, \".md\");\n syncOne(db, {\n content,\n type: \"event\",\n uri: `event://journal/${date}`,\n source: `migrate:${file}`,\n });\n imported++;\n }\n if (mdFiles.length) console.log(`📝 Journals: ${mdFiles.length} files imported`);\n\n // Check for weekly summaries\n const weeklyDir = resolve(dirPath, \"weekly\");\n if (existsSync(weeklyDir)) {\n const weeklyFiles = readdirSync(weeklyDir).filter((f) => f.endsWith(\".md\"));\n for (const file of weeklyFiles) {\n const content = readFileSync(resolve(weeklyDir, file), \"utf-8\");\n const week = basename(file, \".md\");\n syncOne(db, {\n content,\n type: \"knowledge\",\n uri: `knowledge://weekly/${week}`,\n source: `migrate:weekly/${file}`,\n });\n imported++;\n }\n if (weeklyFiles.length) console.log(`📦 Weekly: ${weeklyFiles.length} files imported`);\n }\n\n console.log(`\\n✅ Migration complete: ${imported} items imported`);\n db.close();\n break;\n }\n\n case \"help\":\n case \"--help\":\n case \"-h\":\n case undefined:\n printHelp();\n break;\n\n default:\n console.error(`Unknown command: ${command}`);\n printHelp();\n process.exit(1);\n }\n} catch (err) {\n console.error(\"Error:\", (err as Error).message);\n process.exit(1);\n}\n"],"mappings":"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","names":["now"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
export { D as DbOptions, o as openDatabase } from './db-CMsKtBt0.js';
|
|
2
|
+
import Database from 'better-sqlite3';
|
|
3
|
+
|
|
4
|
+
type MemoryType = "identity" | "emotion" | "knowledge" | "event";
|
|
5
|
+
type Priority = 0 | 1 | 2 | 3;
|
|
6
|
+
interface Memory {
|
|
7
|
+
id: string;
|
|
8
|
+
content: string;
|
|
9
|
+
type: MemoryType;
|
|
10
|
+
priority: Priority;
|
|
11
|
+
emotion_val: number;
|
|
12
|
+
vitality: number;
|
|
13
|
+
stability: number;
|
|
14
|
+
access_count: number;
|
|
15
|
+
last_accessed: string | null;
|
|
16
|
+
created_at: string;
|
|
17
|
+
updated_at: string;
|
|
18
|
+
source: string | null;
|
|
19
|
+
agent_id: string;
|
|
20
|
+
hash: string | null;
|
|
21
|
+
}
|
|
22
|
+
interface CreateMemoryInput {
|
|
23
|
+
content: string;
|
|
24
|
+
type: MemoryType;
|
|
25
|
+
priority?: Priority;
|
|
26
|
+
emotion_val?: number;
|
|
27
|
+
source?: string;
|
|
28
|
+
agent_id?: string;
|
|
29
|
+
}
|
|
30
|
+
interface UpdateMemoryInput {
|
|
31
|
+
content?: string;
|
|
32
|
+
type?: MemoryType;
|
|
33
|
+
priority?: Priority;
|
|
34
|
+
emotion_val?: number;
|
|
35
|
+
vitality?: number;
|
|
36
|
+
stability?: number;
|
|
37
|
+
source?: string;
|
|
38
|
+
}
|
|
39
|
+
declare function contentHash(content: string): string;
|
|
40
|
+
declare function createMemory(db: Database.Database, input: CreateMemoryInput): Memory | null;
|
|
41
|
+
declare function getMemory(db: Database.Database, id: string): Memory | null;
|
|
42
|
+
declare function updateMemory(db: Database.Database, id: string, input: UpdateMemoryInput): Memory | null;
|
|
43
|
+
declare function deleteMemory(db: Database.Database, id: string): boolean;
|
|
44
|
+
declare function listMemories(db: Database.Database, opts?: {
|
|
45
|
+
agent_id?: string;
|
|
46
|
+
type?: MemoryType;
|
|
47
|
+
priority?: Priority;
|
|
48
|
+
min_vitality?: number;
|
|
49
|
+
limit?: number;
|
|
50
|
+
offset?: number;
|
|
51
|
+
}): Memory[];
|
|
52
|
+
declare function recordAccess(db: Database.Database, id: string, growthFactor?: number): void;
|
|
53
|
+
declare function countMemories(db: Database.Database, agent_id?: string): {
|
|
54
|
+
total: number;
|
|
55
|
+
by_type: Record<string, number>;
|
|
56
|
+
by_priority: Record<string, number>;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
interface Path {
|
|
60
|
+
id: string;
|
|
61
|
+
memory_id: string;
|
|
62
|
+
uri: string;
|
|
63
|
+
alias: string | null;
|
|
64
|
+
domain: string;
|
|
65
|
+
created_at: string;
|
|
66
|
+
}
|
|
67
|
+
declare function parseUri(uri: string): {
|
|
68
|
+
domain: string;
|
|
69
|
+
path: string;
|
|
70
|
+
};
|
|
71
|
+
declare function createPath(db: Database.Database, memoryId: string, uri: string, alias?: string, validDomains?: Set<string>): Path;
|
|
72
|
+
declare function getPath(db: Database.Database, id: string): Path | null;
|
|
73
|
+
declare function getPathByUri(db: Database.Database, uri: string): Path | null;
|
|
74
|
+
declare function getPathsByMemory(db: Database.Database, memoryId: string): Path[];
|
|
75
|
+
declare function getPathsByDomain(db: Database.Database, domain: string): Path[];
|
|
76
|
+
declare function getPathsByPrefix(db: Database.Database, prefix: string): Path[];
|
|
77
|
+
declare function deletePath(db: Database.Database, id: string): boolean;
|
|
78
|
+
|
|
79
|
+
type RelationType = "related" | "caused" | "reminds" | "evolved" | "contradicts";
|
|
80
|
+
interface Link {
|
|
81
|
+
source_id: string;
|
|
82
|
+
target_id: string;
|
|
83
|
+
relation: RelationType;
|
|
84
|
+
weight: number;
|
|
85
|
+
created_at: string;
|
|
86
|
+
}
|
|
87
|
+
declare function createLink(db: Database.Database, sourceId: string, targetId: string, relation: RelationType, weight?: number): Link;
|
|
88
|
+
declare function getLinks(db: Database.Database, memoryId: string): Link[];
|
|
89
|
+
declare function getOutgoingLinks(db: Database.Database, sourceId: string): Link[];
|
|
90
|
+
/**
|
|
91
|
+
* Multi-hop traversal: find all memories reachable within N hops
|
|
92
|
+
* Inspired by PowerMem's knowledge graph traversal
|
|
93
|
+
*/
|
|
94
|
+
declare function traverse(db: Database.Database, startId: string, maxHops?: number): Array<{
|
|
95
|
+
id: string;
|
|
96
|
+
hop: number;
|
|
97
|
+
relation: string;
|
|
98
|
+
}>;
|
|
99
|
+
declare function deleteLink(db: Database.Database, sourceId: string, targetId: string): boolean;
|
|
100
|
+
|
|
101
|
+
type SnapshotAction = "create" | "update" | "delete" | "merge";
|
|
102
|
+
interface Snapshot {
|
|
103
|
+
id: string;
|
|
104
|
+
memory_id: string;
|
|
105
|
+
content: string;
|
|
106
|
+
changed_by: string | null;
|
|
107
|
+
action: SnapshotAction;
|
|
108
|
+
created_at: string;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Create a snapshot before modifying a memory.
|
|
112
|
+
* Call this BEFORE any update/delete operation.
|
|
113
|
+
*/
|
|
114
|
+
declare function createSnapshot(db: Database.Database, memoryId: string, action: SnapshotAction, changedBy?: string): Snapshot;
|
|
115
|
+
declare function getSnapshots(db: Database.Database, memoryId: string): Snapshot[];
|
|
116
|
+
declare function getSnapshot(db: Database.Database, id: string): Snapshot | null;
|
|
117
|
+
/**
|
|
118
|
+
* Rollback a memory to a specific snapshot.
|
|
119
|
+
* Creates a new snapshot of the current state before rolling back.
|
|
120
|
+
*/
|
|
121
|
+
declare function rollback(db: Database.Database, snapshotId: string): boolean;
|
|
122
|
+
|
|
123
|
+
type GuardAction = "add" | "update" | "skip" | "merge";
|
|
124
|
+
interface GuardResult {
|
|
125
|
+
action: GuardAction;
|
|
126
|
+
reason: string;
|
|
127
|
+
existingId?: string;
|
|
128
|
+
mergedContent?: string;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Write Guard — decides whether to add, update, skip, or merge a memory.
|
|
132
|
+
*
|
|
133
|
+
* Pipeline:
|
|
134
|
+
* 1. Hash dedup (exact content match → skip)
|
|
135
|
+
* 2. URI conflict (URI exists → update path)
|
|
136
|
+
* 3. BM25 similarity (>0.85 → conflict detection → merge or update)
|
|
137
|
+
* 4. Four-criterion gate (for P0/P1 only)
|
|
138
|
+
*/
|
|
139
|
+
declare function guard(db: Database.Database, input: CreateMemoryInput & {
|
|
140
|
+
uri?: string;
|
|
141
|
+
}): GuardResult;
|
|
142
|
+
|
|
143
|
+
interface SearchResult {
|
|
144
|
+
memory: Memory;
|
|
145
|
+
score: number;
|
|
146
|
+
matchReason: string;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* BM25 search using SQLite FTS5.
|
|
150
|
+
* Returns memories ranked by relevance.
|
|
151
|
+
*/
|
|
152
|
+
declare function searchBM25(db: Database.Database, query: string, opts?: {
|
|
153
|
+
agent_id?: string;
|
|
154
|
+
limit?: number;
|
|
155
|
+
min_vitality?: number;
|
|
156
|
+
}): SearchResult[];
|
|
157
|
+
|
|
158
|
+
type SearchIntent = "factual" | "exploratory" | "temporal" | "causal";
|
|
159
|
+
interface IntentResult {
|
|
160
|
+
intent: SearchIntent;
|
|
161
|
+
confidence: number;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Classify the intent of a search query.
|
|
165
|
+
* Uses keyword scoring — no LLM needed.
|
|
166
|
+
*/
|
|
167
|
+
declare function classifyIntent(query: string): IntentResult;
|
|
168
|
+
/**
|
|
169
|
+
* Get search strategy based on intent
|
|
170
|
+
*/
|
|
171
|
+
declare function getStrategy(intent: SearchIntent): {
|
|
172
|
+
boostRecent: boolean;
|
|
173
|
+
boostPriority: boolean;
|
|
174
|
+
limit: number;
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Rerank search results based on intent strategy and priority weighting.
|
|
179
|
+
*/
|
|
180
|
+
declare function rerank(results: SearchResult[], opts: {
|
|
181
|
+
intent?: SearchIntent;
|
|
182
|
+
boostRecent: boolean;
|
|
183
|
+
boostPriority: boolean;
|
|
184
|
+
limit: number;
|
|
185
|
+
}): SearchResult[];
|
|
186
|
+
|
|
187
|
+
declare function calculateVitality(stability: number, daysSinceCreation: number, priority: number): number;
|
|
188
|
+
/**
|
|
189
|
+
* Run decay on all memories.
|
|
190
|
+
* Updates vitality based on Ebbinghaus curve.
|
|
191
|
+
* Returns count of memories updated.
|
|
192
|
+
*/
|
|
193
|
+
declare function runDecay(db: Database.Database): {
|
|
194
|
+
updated: number;
|
|
195
|
+
decayed: number;
|
|
196
|
+
belowThreshold: number;
|
|
197
|
+
};
|
|
198
|
+
/**
|
|
199
|
+
* Get memories that are candidates for cleanup (vitality < threshold).
|
|
200
|
+
* Only P3 (event) memories can be fully cleaned.
|
|
201
|
+
*/
|
|
202
|
+
declare function getDecayedMemories(db: Database.Database, threshold?: number): Array<{
|
|
203
|
+
id: string;
|
|
204
|
+
content: string;
|
|
205
|
+
vitality: number;
|
|
206
|
+
priority: number;
|
|
207
|
+
}>;
|
|
208
|
+
|
|
209
|
+
interface SyncInput {
|
|
210
|
+
content: string;
|
|
211
|
+
type?: CreateMemoryInput["type"];
|
|
212
|
+
priority?: CreateMemoryInput["priority"];
|
|
213
|
+
emotion_val?: number;
|
|
214
|
+
uri?: string;
|
|
215
|
+
source?: string;
|
|
216
|
+
agent_id?: string;
|
|
217
|
+
}
|
|
218
|
+
interface SyncResult {
|
|
219
|
+
action: "added" | "updated" | "merged" | "skipped";
|
|
220
|
+
memoryId?: string;
|
|
221
|
+
reason: string;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Sync a single piece of information into memory.
|
|
225
|
+
* Runs full Write Guard pipeline before writing.
|
|
226
|
+
*/
|
|
227
|
+
declare function syncOne(db: Database.Database, input: SyncInput): SyncResult;
|
|
228
|
+
/**
|
|
229
|
+
* Sync multiple items in a batch (within a transaction).
|
|
230
|
+
*/
|
|
231
|
+
declare function syncBatch(db: Database.Database, inputs: SyncInput[]): SyncResult[];
|
|
232
|
+
|
|
233
|
+
interface TidyResult {
|
|
234
|
+
archived: number;
|
|
235
|
+
orphansCleaned: number;
|
|
236
|
+
snapshotsPruned: number;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Run the tidy (deep sleep) cycle:
|
|
240
|
+
* 1. Archive decayed P3 memories (vitality < threshold)
|
|
241
|
+
* 2. Clean orphan paths (paths with no memory)
|
|
242
|
+
* 3. Prune old snapshots (keep last N per memory)
|
|
243
|
+
*/
|
|
244
|
+
declare function runTidy(db: Database.Database, opts?: {
|
|
245
|
+
vitalityThreshold?: number;
|
|
246
|
+
maxSnapshotsPerMemory?: number;
|
|
247
|
+
}): TidyResult;
|
|
248
|
+
|
|
249
|
+
interface GovernResult {
|
|
250
|
+
orphanPaths: number;
|
|
251
|
+
orphanLinks: number;
|
|
252
|
+
emptyMemories: number;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Run governance checks and cleanup:
|
|
256
|
+
* 1. Remove orphan paths (no parent memory)
|
|
257
|
+
* 2. Remove orphan links (source or target missing)
|
|
258
|
+
* 3. Remove empty memories (blank content)
|
|
259
|
+
*/
|
|
260
|
+
declare function runGovern(db: Database.Database): GovernResult;
|
|
261
|
+
|
|
262
|
+
interface BootResult {
|
|
263
|
+
identityMemories: Memory[];
|
|
264
|
+
bootPaths: string[];
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Load core identity memories at startup.
|
|
268
|
+
* Returns all P0 (identity) memories + any memories referenced by system://boot.
|
|
269
|
+
*/
|
|
270
|
+
declare function boot(db: Database.Database, opts?: {
|
|
271
|
+
agent_id?: string;
|
|
272
|
+
corePaths?: string[];
|
|
273
|
+
}): BootResult;
|
|
274
|
+
|
|
275
|
+
export { type BootResult, type CreateMemoryInput, type GovernResult, type GuardAction, type GuardResult, type IntentResult, type Link, type Memory, type MemoryType, type Path, type Priority, type RelationType, type SearchIntent, type SearchResult, type Snapshot, type SnapshotAction, type SyncInput, type SyncResult, type TidyResult, type UpdateMemoryInput, boot, calculateVitality, classifyIntent, contentHash, countMemories, createLink, createMemory, createPath, createSnapshot, deleteLink, deleteMemory, deletePath, getDecayedMemories, getLinks, getMemory, getOutgoingLinks, getPath, getPathByUri, getPathsByDomain, getPathsByMemory, getPathsByPrefix, getSnapshot, getSnapshots, getStrategy, guard, listMemories, parseUri, recordAccess, rerank, rollback, runDecay, runGovern, runTidy, searchBM25, syncBatch, syncOne, traverse, updateMemory };
|