plugin-memory-sqlite — SQLite 记忆存储
包名: @aalis/plugin-memory-sqlite
源码: packages/plugin-memory-sqlite/src/index.ts
概述
基于 Node 自带的 node:sqlite 的 MemoryService 实现,用本地 SQLite 文件保存消息历史和结构化元数据(metadata 表),是 memory 服务的零配置默认后端。
运行要求
需要 Node.js 24.15.0 起:从这一版起使用 node:sqlite 不再打印实验特性警告。在更早的 Node 上安装会收到 engines 不符的警告;Node 22.16 之前与 23.x 的 node:sqlite 缺失或缺本插件要用的接口(事务状态、遇锁等待),插件激活失败,报错写明当前 Node 版本、需要 24.15.0 起,并指向文档站上第一次运行里的升级步骤(报错里写的是完整地址,经 npm 装的项目里没有 docs/)。
升级后照常启动。本插件没有原生模块,换 Node 版本后不用为它重装或重编依赖。
插件声明
typescript
export default definePlugin({
name: '@aalis/plugin-memory-sqlite',
subsystem: 'memory',
reusable: true,
provides: [memory],
uses: {
storage,
provide,
logger,
lifecycle,
config,
},
apply(caps) { /* 见源码 */ },
});注册优先级: 10(高于 plugin-memory-mongodb 的 5 和 plugin-memory-inmemory 的 -100;通过 servicePreferences 显式指定偏好时不按优先级选择)
配置
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
path | string | '' | 数据库路径:SQLite 数据库文件的 storage URI(如 data:/aalis.db;不含 :/ 时首段视为存储根名,单段裸名归 data 根)。留空按实例派生,见下 |
rangeQueryLimit | number | 500 | 范围查询返回上限:区间消息查询(向量召回的上下文窗口扩展等)单次返回的最大条数。命中上限会静默截断 |
crossSessionMaxLimit | number | 1000 | 跨会话查询返回上限:跨会话最近消息查询允许的最大条数;调用方请求超过此值会被收窄到此上限 |
特性
path按 storage URI 解析:首段路径视为存储根名(如data/aalis.db即data:/aalis.db),也可以直接写data:/xxx.db;对应存储根须支持写入和本地路径解析(resolveLocalPath),否则启动时报错。写成本机路径(如/private/tmp/aalis.db、~/aalis.db)时拒绝激活,报一行ConfigError,写明要填 storage URI 并举例;要放到存储根以外的目录,先在本地存储插件的roots里加一个指向它的根,并打开它的「允许写」(这个根文件工具也能访问)path缺省或为null时仍按实例派生;显式给出布尔值、数组或对象等无效类型时拒绝激活,不会回落到默认数据库文件。- 可多实例(
@aalis/plugin-memory-sqlite:<后缀>)。path留空时按实例派生:主实例用data:/aalis.db,带后缀的实例在文件名上加后缀(如:b实例用data:/aalis-b.db);配置里写明的path照用。两个实例打开的是同一个文件时,后激活的那个激活失败,报一行ConfigError,点名占用该文件的实例;两边路径写法不同时一并给出占用者打开的路径。是否同一个文件按文件身份(设备号与 inode)判断,大小写不敏感的卷上只差大小写的路径、硬链接都算同一个文件;文件系统不提供 inode 时退回按本地路径比较 - 开库失败时报错先写怎么修(检查数据库文件所在目录存在且可写,或在
path换个位置;路径解析失败的检查path),再带出 SQLite 给出的原因,原错误作cause;取不到node:sqlite的情况见「运行要求」 - 自动创建
messages表(含(sessionId, timestamp)与(archived, timestamp)两个索引)和metadata表 listMetadata逐行解析:data不是 JSON 对象的行(手改或损坏)跳过并记一条 warn,点名命名空间与键,同一命名空间的其余条目照常返回。listMetadataKeys只取键、不读data,跳过的行也在其中:各插件经/clear整体清空命名空间时连同它们一并删除。updatedAt读不出(被改成无法解析的文本或 BLOB)的行照常返回,updatedAt记为 0- 开库后设 WAL 日志模式与 NORMAL 同步级别:读写互不阻塞;NORMAL 只在检查点时刷盘,系统崩溃或断电可能丢掉最后几次提交,库文件不会损坏。遇锁(别的进程正在写这个库)最多等 5 秒
commitMetadata与deleteMessagesByTimestamps在一个事务里执行,中途出错整批回滚getHistory()(默认 50 条,传Infinity取全部)只取未归档消息,正序返回最近 N 条对话消息与夹在其间的事件标记(标记不占条数:先找到第 N+1 新的那条对话消息,再取它之后的全部);countHistory()同样只数对话消息;archiveSpan()用一条语句把最早的若干条未归档消息标记为归档(调用方列出的位置不归档),不做物理删除/clear经命令插件调用clearSession()(删除该会话全部消息,含归档);/clear all调用clearAll(),只清空messages表。两者均仅在清理类型为空或包含context时执行。metadata表不经这两个方法清理,各命名空间由归属插件在memory:clear中间件里自行删除(见 plugin-commands 的「/clear类型」一节)- dispose 时关闭数据库连接;激活时开库之后的任何一步失败(撞库、设 WAL、建表等),也先关掉刚打开的连接再报错