purra-sqlite
v1.0.1
Published
SQLite persistence for PurrA
Readme
purra-sqlite · TypeScript
English | 简体中文
为 PurrA 的 Run、事件、操作、预算、检查点和工具回执提供 SQLite 持久化。
依赖 node:sqlite,要求 Node.js 22.13+。
安装
按照源码安装说明操作,选择
integrations/sqlite/typescript。
配置
已有模型网关 model 时:
import { Agent } from "purra";
import { SqliteAgentAdapters } from "purra-sqlite";
const storage = new SqliteAgentAdapters("agent.db", {
scope: "user-1/project-1",
});
const agent = new Agent({
model,
runRepository: storage.runs,
outputPublisher: storage.publisher,
idempotency: storage.idempotency,
});scope 应由应用根据已认证的用户与项目绑定确定。
该组件还提供 runTree、artifacts 和 longTasks。
恢复
agent.resume(runId, originalRequest) 恢复满足条件的检查点,并保留原有预算和截止时间。
恢复时还原原有模型与工具配置。仓储提供执行所有权控制,阻止并发恢复。
外部工具写入结果不确定时,先确认实际执行情况,再调用
storage.reconcileTool(key, { result }) 或
storage.reconcileTool(key, { notExecuted: true })。
需要保存提问和回答时,使用 SqliteClarification。
适配器状态边界
Core 通过版本化 StorageSession 负责仓储状态格式;SQLite 负责事务、索引、租约及工具
效果对账。这是组件间需要版本匹配的适配契约,不是业务数据交换格式。Core 和集成包
需要成套安装。
purra 导出 StorageSession,统一仓储状态版本与独立日志的恢复。
storage.transaction(async (stores, extra) => ...) 提供事务内端口与扩展元数据。
会话及延迟日志回调不能离开事务后继续使用;仅保存快照正文不是完整备份。
对外仓储方法由显式端口列表声明。
存储与关闭
规范输出事件按行增量保存,通过 Run 序号和 Root 序号索引分页读取。事件追加与执行状态
快照在同一个事务中提交;runs.listEvents()、runs.listRootEvents() 和订阅轮询不加载
执行快照,也不申请写锁。runs.get() 保持只读事务。工具回执、租约续期与释放跳过
Run 状态和输出历史的还原;Agent 树、产物与长任务操作只还原对应仓储。
指向已有 Run 的写入先通过 SQL 校验序号和事件数量,按索引查询幂等键,并缓冲新增事件。
规划、公开进度和终态收尾所需的原始证据仍由 Core 按需读取。已持久化的事件数量和
待提交事件共同决定 Run 与 Root 的序号,兄弟任务仍共享预算。Run 读取完整还原所属
Root 日志;未加载的 Root 不能读取或写入,其检查点与事件计数保持不变。
租约认领、公开 transaction() 和创建 Run 等无法定位既有 Root 的操作仍校验完整作用域。
执行快照仍按作用域加载和保存,包含检查点和回执,适合数据量受控的本地场景。
存储格式为 v4。构造器在修改数据库参数、表或索引之前拒绝其他所有版本(包括
v1/v2/v3);拒绝后原库不变。没有自动迁移或旧格式恢复路径。
Python 与 TypeScript 的执行快照不能互换。
事件幂等键的索引范围是单个 Root(Python 则是整个作用域)。打开已有 v4 数据库时,
通过 SQLite json_extract 建立该索引。序号校验使用选定 Root 的覆盖索引,并按 Run
精确匹配子任务,无需读取事件正文所在的数据行。Root 与 Run 的映射也有覆盖索引。
已有 v4 数据库在打开时补建索引,需要耗时和额外磁盘,新增事件也需要维护索引。
元数据仍按作用域保存,
因此写入成本并非常数。事件正文在读取时校验;租约认领和公开事务仍还原完整日志。
构建 Core 和本包后,在仓库根目录运行空轮询与末尾分页基准:
node integrations/sqlite/typescript/scripts/benchmark-reads.mjs基准使用临时数据库,报告预热后的读取中位耗时,不代表并发吞吐量或真实模型端到端性能。
工具回执写入基准计入认领和结果提交两个事务,使用本地无外部副作用的工具函数:
node integrations/sqlite/typescript/scripts/benchmark-writes.mjs它不计真实业务工具或模型调用耗时。
另一个 Root 的历史数据增长时,活动 Run 的事件写入成本可用以下基准测量:
node integrations/sqlite/typescript/scripts/benchmark-run-writes.mjs它测量无关 Root 的隔离效果,不代表活动 Root 自身历史不断增长时的性能。
同一 Root 内的事件追加、调用登记和检查点提交基准,每种操作预热两次后测量十次:
node integrations/sqlite/typescript/scripts/benchmark-execution-writes.mjs历史数据为私有诊断事件;结果不包含规划证据重放、并发吞吐量或真实 Provider 耗时。
与 Python 的调用登记和检查点接口不同,TypeScript 的这两类操作都会追加输出事件,
因此应分别与各 SDK 自身的基线比较。
追加 --profile 可分别查看日志准备、Run 状态导入导出和事务其余部分的耗时。
其余部分包含外层快照处理、其他仓储和 SQL 写入。各分段的中位数独立计算,
不能直接相加得到总耗时中位数。
应用负责数据库访问、备份和数据保留。检查点包含私有模型数据。
等待活动执行结束后再调用 storage.close()。
TypeScript 支持 opt-in Reactive/Planned/Auto Root 审批等待、同 Run 恢复及 claim/receipt 关联。
配置 toolCheckpointHandler、approval: approvals.gateway() 和同一适配器的
idempotency,旧模型续点类型保持不变。详见运行入口。
Root 在只读 Child 完成后等待审批的组合已验证;用 toolCheckpointNames 明确选择业务写工具。
Child 写审批和 MCP 写验收仍未完成。
合成宿主生命周期检查
在仓库根目录执行:
npm run build --prefix typescript
npm run build --prefix integrations/sqlite/typescript
node integrations/sqlite/typescript/scripts/check-host-lifecycle.mjs检查会把宿主管理的 Run 配置单独持久化,关闭首个宿主,再重建原请求配置、当前
binding/scope revision 和原绝对审批期限。随后启动带持久游标及调度的
RecoveryWorker;合成的已认证审批决定提交后显式唤醒 worker。检查等待规范 Run
完成,停止服务,重开存储,并确认只有一个完成回执,没有遗留 claim 或活动 lease。
这是仓库内的确定性检查,会导入测试宿主,不是生产宿主库。应用必须自行管理认证主体、 配置注册表和当前资源范围解析器;配置缺失或不匹配必须在公共 resume 前失败。检查不调用 Provider 或 MCP 服务,也不代表下游验收。
