UNPKG

@tencentdb-agent-memory/memory-tencentdb

Version:

Four-layer local memory system plugin for OpenClaw — auto-captures, structures, and profiles conversational knowledge using local LLM + SQLite vector search (L0→L1→L2→L3 pipeline)

135 lines (134 loc) 4.32 kB
import { t as StoragePaths } from "./types-ChShWHv_.mjs"; //#region src/core/scene/scene-format.ts const META_START = "-----META-START-----"; const META_END = "-----META-END-----"; /** * Parse a Scene Block file into structured data. */ function parseSceneBlock(raw, filename) { const startIdx = raw.indexOf(META_START); const endIdx = raw.indexOf(META_END); if (startIdx === -1 || endIdx === -1) return { filename, meta: { created: "", updated: "", summary: "", heat: 0 }, content: raw.trim() }; const metaBlock = raw.slice(startIdx + 20, endIdx).trim(); const content = raw.slice(endIdx + 18).trim(); return { filename, meta: { created: extractMetaField(metaBlock, "created"), updated: extractMetaField(metaBlock, "updated"), summary: extractMetaField(metaBlock, "summary"), heat: parseInt(extractMetaField(metaBlock, "heat"), 10) || 0 }, content }; } function extractMetaField(metaBlock, field) { const re = new RegExp(`^${field}:\\s*(.*)$`, "m"); const m = metaBlock.match(re); return m ? m[1].trim() : ""; } //#endregion //#region src/core/scene/scene-index.ts /** * Scene Index: maintains a JSON index of all scene blocks for quick lookup. */ async function fsReadFile(absPath) { const fs = await import("node:fs/promises"); try { return await fs.default.readFile(absPath, "utf-8"); } catch { return null; } } async function fsWriteFile(absPath, content) { const fs = await import("node:fs/promises"); const path = await import("node:path"); await fs.default.mkdir(path.default.dirname(absPath), { recursive: true }); await fs.default.writeFile(absPath, content, "utf-8"); } async function fsReaddir(absDir, suffix) { const fs = await import("node:fs/promises"); try { return (await fs.default.readdir(absDir)).filter((f) => f.endsWith(suffix)); } catch { return []; } } /** * Read the scene index from disk. * * The index is written exclusively by syncSceneIndex() (engineering side). * The LLM is sandboxed to scene_blocks/ and cannot access this file. */ async function readSceneIndex(dataDir, storage) { try { let raw; if (storage) raw = await storage.readFile(StoragePaths.sceneIndex); else raw = await fsReadFile((await import("node:path")).default.join(dataDir, ".metadata", "scene_index.json")); if (!raw) return []; const parsed = JSON.parse(raw); if (!Array.isArray(parsed)) return []; const entries = []; for (const item of parsed) { if (!item || typeof item !== "object") continue; const filename = typeof item.filename === "string" ? item.filename : ""; if (!filename) continue; entries.push({ filename, summary: typeof item.summary === "string" ? item.summary : "", heat: typeof item.heat === "number" ? item.heat : 0, created: typeof item.created === "string" ? item.created : "", updated: typeof item.updated === "string" ? item.updated : "" }); } return entries; } catch { return []; } } /** * Write the scene index to disk. */ async function writeSceneIndex(dataDir, entries, storage) { const content = JSON.stringify(entries, null, 2); if (storage) await storage.writeFile(StoragePaths.sceneIndex, content); else await fsWriteFile((await import("node:path")).default.join(dataDir, ".metadata", "scene_index.json"), content); } /** * Rebuild scene index by scanning all .md files in the scene_blocks directory. */ async function syncSceneIndex(dataDir, storage) { let files; if (storage) files = await storage.readdirNames(StoragePaths.sceneBlocksDir, ".md"); else files = await fsReaddir((await import("node:path")).default.join(dataDir, "scene_blocks"), ".md"); const entries = []; for (const file of files) try { let raw; if (storage) raw = await storage.readFile(`${StoragePaths.sceneBlocksDir}${file}`); else raw = await fsReadFile((await import("node:path")).default.join(dataDir, "scene_blocks", file)); if (!raw) continue; const block = parseSceneBlock(raw, file); entries.push({ filename: file, summary: block.meta.summary, heat: block.meta.heat, created: block.meta.created, updated: block.meta.updated }); } catch { continue; } await writeSceneIndex(dataDir, entries, storage); return entries; } //#endregion export { parseSceneBlock as i, syncSceneIndex as n, writeSceneIndex as r, readSceneIndex as t };