没有服务负担,每条记忆是 .md 可人读;LLM 生成读取自然;内容可对照 manifest 定位。代价:不支持语义检索,本章用名称匹配。手工修改是受支持的操作,但要守契约(frontmatter 格式、预算、不删 manifest 引用的文件)。
---
name: user-preference-tabs
description: User prefers tabs for indentation
type: user
---
User prefers using tabs, not spaces……
.memory/manifest.json 唯一权威;MEMORY.md 由当前集合生成的有界目录;<name>-<id>.md 是单条记忆。读取端不信任任何东西:manifest 必须精确含 version+files(version:true 也拒)、文件名唯一且安全、realpath 不得逃出 workspace、每条记录重新构造校验。目录里未登记的 .md 一律忽略。
.memory/manifest.json 权威指针
.memory/MEMORY.md 可重建有界目录
.memory/<name>-<id>.md 单条记忆 (frontmatter + body)
MemorySession.beginTurn(query) 把查询和有界目录交给选择器,模型返回 name 数组(最多 5 条)。side-query 三条硬要求:没有工具调用、finishReason 精确等于 stop、正文非空——length 时 "[]" 看着合法其实是截断,不检查就静默丢信息。集合为空时短路,不叫 selector。选择失败降级为确定性关键词匹配(英文 3 字符 token,中文 bigram),只扫 name+description。
[["user-preference-tabs", "project-database-rule"]]
→ 选中正文包在 <relevant_memories> 中
→ 只进入本次请求,不污染 canonical history
完整回答后 MemorySession.complete() 调用 extractor,必须读完整 canonical history——读 request history 会漏掉被 snip 裁掉的用户消息。例外:大 ToolResult 落盘发生在进 canonical 之前,中段事实 extractor 看不到,要先读回 artifact。任意一项非法,整批不提交(合法项也不写);提取失败只记 lastError,主任务照常。
[
{
"name": "windows-examples",
"type": "project",
"description": "Project examples target Windows",
"body": "Use PowerShell for commands."
}
]
达到阈值(默认 10 条)时,consolidator 返回 source_names + records。未列入 source 的记忆必须保留;整理期间并发新增保留,基础记录被改则直接失败。触发条件只有阈值一个:达到后每回合结束都会调 consolidator(教学上的刻意简化,真实项目建议加时间/会话门控)。提取失败后不整理;整理失败时本轮提取结果也不写。
验证基础记录未变
→ 合并未参与/并发新增/本轮记录
→ 生成并 fsync 新文件
→ 原子写入索引
→ 原子替换 manifest ← 提交点
→ 提交成功后才清理被替换旧文件
200 行 / 4096 bytes 都是算整个文件,不是只算正文。frontmatter 占 6 行,所以正文实际上限是 194 行;4096 bytes 里 frontmatter 也占一份,纯中文正文约 1340 多字到顶(随 name/description 长短浮动)。名称是封闭校验:安全小写 slug,还专门挡 Windows 保留名 com1/lpt9、NTFS 流语法 file:stream、结尾点 trailing.。
正文 194 行: 通过 正文 195 行: 拒绝
中文 1348 字: 通过 1349 字: 拒绝(4047 bytes + frontmatter > 4096)
预算原因: 记忆要注入上下文,8KB×5 条 = 40KB 直接进请求
读取当前集合;为空则短路返回,否则选择相关记忆(最多 5 条,失败降级关键词匹配)。
只进本次请求,不污染 canonical history。
canonical history 完整追加。
从完整 canonical 提取;达到阈值时与整理一次提交(达到阈值后每回合都会尝试)。