@amaster.ai/pi-memory (英语)

对Pi剂的持续记忆—— MEMORY.md (代理人自己的笔记)和 USER.md (代理对用户的了解). 扩展在会话开始时加载两个文件,并将一个已消毒快照注入系统提示. 写作在磁盘上可以耐用,可以立即看到 memory_read 立即;系统即时快照在成功上下文压缩后或在新会话中刷新.
在Hermes 默认后模拟 MemoryStore 机制(没有提供者/管理者抽象).
存储
- 地点 :
<agentDir>/memories/MEMORY.md财务报告和审定财务报表<agentDir>/memories/USER.md - 由
\n§\n - 原子通过临时文件写作 + 重命名
- 由 :
proper-lockfile - 漂流探测:如果上盘文件包含的内容不会通过解析器/序列器来进行回行走(或任何单个条目超过每个存储字符限制),则该突变被拒绝,并且 a
.bak.<unix-ts>为用户提供快照以恢复功能.
安全问题
每个书写——以及每个系统即时快照的构建——都通过捆绑的内容运行 threat-patterns 扫描仪在 strict 范围。 模式包括即时注射,角色劫持,C2框架名,被过滤,持久性(SSH后门,代理-配置编辑)等,以及隐形unicode.
| 行动 | 比赛时 |
|---|---|
memory_add 编号 : memory_replace | 拒绝匹配的图案 ID; 活状态和磁盘不变 . |
| 快照构建( 装入) | 将条目替换为 [BLOCKED: <filename> entry contained threat pattern(s): <ids>...]。有毒内容 永远 输入系统提示 。 原始状态不变 memory_read 编号 : memory_remove 可以复原. |
工具
4个LLM可调用工具(单独而非多动作):
| 工具 | 目的 |
|---|---|
memory_add | 追加新条目 。 准确的重复是成功的无操作;是空的,超限的,威胁内容被拒绝. |
memory_replace | 以短的独有子字符串更新一个已存在的条目( E)oldText) (中文(简体) ). |
memory_remove | 以短的独有子字符串删除条目(oldText) (中文(简体) ). |
memory_read | 返回现场输入,数,和 <percent>% — <chars>/<limit> 使用字符串. |
target 实值 'memory' (代理人自己的笔记)或 'user' (用户简介事实).
默认
| 存储 | 字符限制 |
|---|---|
| 记忆 | 2200号 |
| 用户 | 1375号 |
这些是之后的总字符 §- 加入所有条目 限制在写出时执行,在装入时作为漂移信号(单入外溢).
整合模式
模式1:扩展自动发现(独立/CLI)
安装为与 pi.extensions 已声明的字段 package.json,运行时自动发现并加载扩展. 扩展创建自己的 MemoryStore 基于文件的存储于 <agentDir>/memories/ ——完全自成一体.
pi.extensions → session_start → initialize store → register tools
→ before_agent_start → append frozen snapshot to systemPrompt
→ session_compact → reload MEMORY.md/USER.md for the next agent run
→ session_shutdown → release
- 存储数字 :
<agentDir>/memories/MEMORY.md财务报告和审定财务报表<agentDir>/memories/USER.md - 生命周期: 抓取新会话和会话的新系统即时快照,在恢复或重新装入时恢复,并在成功压缩后刷新
- 状态命令数字 :
/memory status每个文件显示条目数 - LLM 工具数字 :
memory_add, (中文(简体) ),memory_replace, (中文(简体) ),memory_remove, (中文(简体) ),memory_read
通过 pi-memory 设置密钥 :
项目 .pi/settings.json 数值只有在项目信任被接受之后才被加载,而不是环境插入。 用户和代理设置保留了环境插值.
{
"pi-memory": {
"dataDir": "/custom/memory/path",
"memoryCharLimit": 4000,
"userCharLimit": 2000
}
}
模式2:依赖性导入(主机控制)
当主机进程拥有 MemoryStore (例如,在代理、测试固定装置、自定义存储路径之间共享),自行构建存储和直接注册工具:
import { MemoryStore, createMemoryTools } from "@amaster.ai/pi-memory";
const store = new MemoryStore({
dir: "/var/lib/pi/agent-42/memories",
memoryCharLimit: 4000,
});
await store.loadFromDisk();
// ToolDefinition[] — wire into your tool registry directly
const tools = createMemoryTools(store);
// System prompt fragment (rebuilt by loadFromDisk; freeze it for the session)
const promptBlock = store.formatAllForSystemPrompt();
您也可以通过 injectedConfig 保留扩展寿命周期,但使用自己的存储:
import memoryExtension from "@amaster.ai/pi-memory";
memoryExtension(pi, { store });
漂流回收
若为 memory_add 编号 : memory_replace 编号 : memory_remove 返回时 success: false 与 driftBackup: ".../MEMORY.md.bak.<ts>",则上盘文件不再通过解析器进行回转. 这通常意味着一个补丁工具 / shell 附加/ 手动编辑/ 同时会话写出打破原始内容 §- 有限结构.
追回:
- 打开
.bak.<ts>抓取和识别尚未记录为干净条目的内容 . - 通过
memory_add。 。 。 . - 要么删除原件
MEMORY.md(下一个添加将重现) 或重写为干净§-名单有限.
漂移守护器的存在是为了防止无声数据丢失——从不通过删除来绕过它 .bak.<ts> 盲从快照.
快速快照
loadFromDisk() 从磁盘刷新活条目并重建已消毒的系统即时块. 一个新的或被叉开的会话抓住了这个块,并在 Pi会话中坚持;在再次验证后恢复并重新加载被保存的块. 无效被保存的块返回到新沉入的磁盘快照 。 同样的字节被跨代理运行回用到成功的上下文收缩,而会话-树导航则选择被保存在该分支上的快照. 后续 add 编号 : replace 编号 : remove 调用更新 状态 和磁盘,但不是被冻结的快照。 为什么:
- 重用同一种系统即时保存提供者在会话中跨越代理运行的前缀缓存机会.
- 工具响应总是反映活状态,因此模型仍然看到自己的写作——只是通过工具结果尾巴,而不是系统即时头.
- 快速快照在成功后拾取更改
session_compact或在一个新的会议。 改变的快照仍然会造成该边界的缓存缺失.
扩展框在捕捉它们时会约束非常大的即时快照,并在两个文件都在场时为这两个文件保留空间;内存文件和工具读取保留了全部内容.
生命周期参考
| 钩子 | 行为 |
|---|---|
session_start | 决定 dataDir,构建 MemoryStore, (中文(简体) ), loadFromDisk(),为新的/预设会话抓取新的快照或恢复保存的会话,注册 4 个工具,设置状态 memory: loaded编号 :memory: empty,然后开始一个有门背景的梦想. |
before_agent_start | 将被冻结的快照添加到组装中 systemPrompt (指导只当是空的). |
session_compact | 从磁盘上重新装入内存, 并持续为下一个代理运行执行更改快照 . |
session_tree | 选择新活动的分支上保存的快照 . |
session_shutdown | 丢弃商店参考文献. |
梦想(背景记忆巩固)
在会话开始时,pi-memory检查Pi会话历史是否已经积累了足够的时间,并在到期后开始一个孤立的背景代理,将可持久的事实整合为记忆. 默认的全局内存存储会在所有工程中读取 Pi 会话; 一个被注入的存储或自定义 dataDir 仅读取活动会话目录。 它不会给主动对话添加一个转折,也不会安装一个操作系统的预定任务.
如何运作
-
会话启动触发器 ——扩展在内存初始化后同步启动检查,因此活动会话不会被屏蔽.
-
门和锁 ——每次运行检查是否已经过了足够的时间和转弯,然后取出一个跨进程锁,这样多个 Pi 主机不能同时做梦.
-
合并 ——代理循环(使用pi-agent-core)审查近期的Pi会话并进行更新
MEMORY.md编号 :USER.md通过记忆工具。 遵循4个阶段的快取:东方-收集最近的信号-巩固-核查和报告.
配置
添加为 settings.json 下划线 pi-memory 键 :
{
"pi-memory": {
"dreaming": {
"enabled": true,
"minHoursSinceLastRun": 24,
"minTurnsSinceLastRun": 5,
"model": {
"provider": "openai",
"model": "gpt-4.1-mini"
}
}
}
}
所有字段都是可选的,有合理的默认值。 这个 model 字段接受您配置的任何提供者/模型配对 ~/.pi/agent/models.json (内置或自定义). minSessionsSinceLastRun 被接受为用于 minTurnsSinceLastRun。 。 。 .
设定 "enabled": false 以禁用背景作梦.
梦想是机会主义的:在Pi主机活动的同时运行,并赶上下一场会话开始. 在每个 Pi 主机关闭时它不会运行 .
结构化结果(Pi 0.99+)
memory_read, (中文(简体) ), memory_add, (中文(简体) ), memory_replace,以及 memory_remove 声明 outputSchema 并归还他们的活商店结果为: structuredContent。 Codemode 直接接收条目和使用;写作也曝光 success, (中文(简体) ), target,以及 entryCount创建失败 isError: true 并保存可用 error, (中文(简体) ), matches, (中文(简体) ), currentEntries, (中文(简体) ), usage和漂流补救场。 条目文本仍然是替换/删除所使用的现有子字符串引用;没有引入新的条目ID格式.
const result = await tools.memory_read({ target: "memory" });
if (result.error || result.truncated) throw new Error("Read a complete memory result before updating");
const entry = result.entries.find(e => e.includes("TypeScript"));
if (entry) text(await tools.memory_replace({ target: "memory", oldText: entry, newContent: "Project uses strict TypeScript" }));
结构化输出限于12个KiB,而顶级列表则限于100个完整的记录. truncated: true 表示省略的记录; total 保留已有的原始数。 超大小记录,带有 id 保留完整的ID和小分级元数据,省略大字段,并携带 truncated: true 在记录和信封上;呼叫者必须在重新使用内容进行更新之前检查该旗帜。 没有记录ID的超大小结果返回打出输出限制错误,而不是剪接路径或内容. 当发生这种情况时, 写入可能已经完成: 在重试前检查保存状态 。 可读文本和渲染器细节是独立限定的.
背景转动取出时只保留有界限的最近消息缓冲器,排出每批排出后排出. 序列式审查上下文被封为4000个字符,包括一个单个超大小的信件;处理后的历史不保留在取出缓冲中.
在通过修改时间发现历史并过滤文件之前,梦想检查模型可用性. 每张通行证最多读取32个合格会话文件,最先读取;在下次启动时,一个持续光标会恢复所剩页而无需提前推进已完成的扫描水印. 读取从256个KiB尾巴开始并被扩展到8个米B,当最近的转折被隐藏在大记录后,跟随该窗口内的活分行. 每个文件最多保留了5个最近的转弯(每页160个),其中开头和结尾部分为超大小信息取出,8 000个字符合并迅速在选定的会话中公平分享。 历史发现共享5秒预算 停止取消会话. 会话关闭也会取消运行中的合并代理. 在发现时删除的历史链接和文件被跳过 。 错误的会话历史,权限错误,和 I/O 错误离开检查点不变;在下次运行前恢复访问. 在这些界限之外的内容不是合并输入;省略并不授权删除已存在的事实.