--- summary: "session.maintenance 密钥、磁盘预算清理层、cron 运行保留和 SQLite 降级路径" read_when: - "调整每个代理会话磁盘预算或保留截止值" - "在 SQLite 翻转后运行 openclaw 会话清理或降级" title: "商店维护和保留" --- ## 存储维护和磁盘控制 `session.maintenance` 控制 SQLite 会话行、SQLite 转录行、归档制品以及轨迹侧车文件的自动维护: | 键 | 默认值 | 笔记 | | ----------------------- | --------------------- | ------------------------------------------------------------------------------------------------- | | `mode` | `"enforce"` | 或 `"warn"`(报告期限、计数和磁盘预算策略而不应用它们) | | `pruneAfter` | `"30d"` | 过期条目的年龄截止时间 | | `archiveDashboardAfter` | `"7d"` | 仪表板存档截止; `false` 或 `0` 仅禁用此触发器 | | `maxEntries` | `5000` | 当保护允许时,限制未归档的会话行 | | `preserveRecent` | 已禁用 | 不活动窗口保护交互式会话及其历史生成; `false` 禁用 | | `resetArchiveRetention` | 保留(无年龄截止时间) | `*.reset.*`/`*.deleted.*` 转录归档的年龄截止时间;设置时长后会启用删除 | | `maxDiskBytes` | `10gb` | 每个 agent 的会话磁盘预算;`false`、`0` 或 `"0"` 可禁用 | | `highWaterBytes` | `maxDiskBytes` 的 80% | 清理后的目标;零解析值使用默认值,负数无效 | | `coldStorage.enabled` | `false` | 将符合条件的非活动转录有效负载移动到后台工作程序中的压缩 JSONL 文件 | | `coldStorage.afterDays` | `30` | 冷存储的正整数不活动截止天数 | 重置边界会启动一个新的历史记录窗口,而不删除较早的转录本行。当会话轮换提前直播时`sessionKey -> sessionId`映射,之前的SQLite会话、记录、轨迹和搜索行也保留;普通条目和会话列表仅显示实时映射。保留的重置历史记录受磁盘预算限制,而不是受磁盘预算限制`resetArchiveRetention`,仅老化档案工件。显式删除则不同:它将压缩的记录存档存储并验证在SQLite在删除已删除会话的行的同一事务中。然后它发布、同步并读回派生的`*.jsonl.deleted..zst`当 zstd 可用时,报告成功之前的文件。 如果在删除提交后存档文件导出失败,其存储的存档将保留在 SQLite 中以供重试。创建不相关的新会话不会重试导出或因此失败。解决文件错误后重试删除以发布保留的存档,即使已删除的会话已经不存在。 归档会话会更改其可见性和保留元数据,同时将其记录行保留在 SQLite 中。将回收的历史记录转换为记录存档会将这些行替换为 SQLite 的 `session_transcript_archives` 表中的压缩记录 blob 以及会话目录中的派生 JSONL 文件。因此,压缩后的有效负载仍然占用数据库空间;该文件不是其唯一的副本。不支持 zstd 的运行时会写入普通 JSONL reset/deletion 存档。可选的[冷转录本存储](/reference/session-management-compaction/maintenance#cold-transcript-storage)将非活动转录本有效负载完全移出SQLite; `pruneAfter` 控制会话保留,`resetArchiveRetention` 控制reset/deletion 存档删除。 `maxDiskBytes` 强制执行使用物理字节:每个代理 SQLite 主文件、其 `-wal` 文件以及代理会话目录中的计数文件。它从不估计行 JSON 大小或从该总数中减去逻辑行大小。这是清理预算,而不是有保证的物理上限:受保护的历史记录和尚无法回收的数据库页面可以使使用率保持在目标之上。 网关模型运行检查会话(匹配 `agent:*:explicit:model-run-` 的密钥)获得单独的固定 `24h` 保留。此修剪是压力门控的:它仅在达到会话条目 maintenance/cap 压力时运行,并且仅在全局过时条目 cleanup/cap 步骤之前运行。其他显式会话不使用此保留。 当组合物理使用量超过 `maxDiskBytes` 时,`mode: "enforce"` 首先回收可检查点数据库空间,然后删除最早保留的 reset/delete 归档。如果使用率仍高于 `highWaterBytes`,则它会按 `sessions.updated_at` 遍历历史 SQLite 会话,最旧的在前。历史意味着会话 ID 未被实时会话条目、路由目标或 admitted/in-flight 运行引用。对于每个受害者,清理将压缩存档存储在同一写入事务中,删除会话行及其转录本、轨迹、活动、索引和 FTS 投影。它在提交后发布、同步并读回派生文件。这包括包含轨迹事件但不包含转录事件的会话。如果这些层不足,清理操作将永久删除记录存档原因为 `active-session-cap` 的最旧会话。手动、遗留、年龄保留、陈旧仪表板和恢复档案保护每一代历史。清理会在删除时重新检查条目身份和准入参考,在每个受害者之后重新测量物理使用情况,并在 `highWaterBytes` 处停止。 提交的写入和删除首先落在 WAL 中。 Cleanup 尝试在不等待读者的情况下截断它。如果截断被阻止,则在 PASSIVE 检查点将每个观察到的 WAL 帧复制到主数据库后,可以继续进行清理;部分检查点仍然推迟清理。增量真空从主文件返回符合条件的空闲尾页。尚未回收的保留 WAL 字节和页仍会在下一次物理测量中计数。 `mode: "warn"` 报告当前物理超额情况,无需设置检查点、写入存档或删除行。 对于大量清理后的完整文件重写,请使用Doctor的离线[`--session-sqlite compact`模式](/cli/doctor/sqlite-maintenance#session-sqlite-migration)。它检查 WAL 并运行 `VACUUM`;它不会选择其他历史记录进行删除或用摘要替换对话内容。在更改大型安装上的保留之前,请参阅 [ 在副本上测试清理 ](/cli/sessions#test-cleanup-on-a-copy)。 按需运行维护: ```bash openclaw sessions cleanup --dry-run openclaw sessions cleanup --enforce ``` `maxEntries` 统计未归档的会话行;归档行不消耗上限。清理会存档最旧的符合条件的普通会话,直到未存档的总数达到 `maxEntries` 或不再有符合条件的受害者。固定会话、活动或已承认的工作、模型锁定会话以及持久的外部会话指针(例如组会话和线程范围的聊天会话)仍然受到保护,因此受保护的行可以使未归档的总数保持在上限之上。 Synthetic 运行时条目(cron、hooks、heartbeat、ACP、子代理)仍然是一次性的,一旦超过配置的寿命、计数或磁盘预算,仍然可以将其删除。隔离的 cron 运行使用单独的 `cron.sessionRetention` 控件,独立于模型运行检查保留。 每个新档案都会自动记录一个结构化的原因。显式归档操作记录`manual`; count-cap 和 stale-dashboard 维护记录各自的原因; `pruneAfter` 使用 `age-retention` 归档符合条件的持久会话,同时删除一次性自动化;恢复档案记录`restart-recovery`。 Control UI 提供了人类可读的解释。缺失或未识别的原因被视为受保护的遗留状态而不是推断的。 `--dry-run` 预览未归档行上限并识别满足该上限的未受保护行; `--enforce` 立即应用该清理,但不会删除保护。要减少受保护的历史记录,请取消存档、取消固定、等待活动工作完成或显式删除您不再希望保留的会话。 普通网关通过会话访问器写入流,该访问器通过运行时写入器路径序列化每个代理 SQLite 突变。运行时代码应该更喜欢 `src/config/sessions/session-accessor.ts` 中的访问器帮助器;旧版 `sessions.json` 帮助程序是迁移和离线维护工具。当网关可访问时,非空运行 `openclaw sessions cleanup` 和 `openclaw agents delete` 将存储突变委托给网关,以便清理加入同一写入队列; `--store ` 是选定旧存储的显式脱机修复路径,并且始终保留在本地(与 `--dry-run` 一样)。 `maxEntries` 清理是针对生产规模的存储进行批处理的,因此在下一次高水位清理重写之前,未归档的数量可能会短暂超过配置的上限。在网关启动期间读取不会修剪或限制条目。普通条目会在下一个年龄边界写入合并的后台通行证,并在数据库连接保持打开状态时进行 30 分钟的定期重新检查,因此保留可以在没有进一步流量的情况下运行。不变的 age/count 事实让写入跳过维护候选扫描。 `openclaw sessions cleanup --enforce` 立即应用上限并修剪旧的未引用的遗留记录、检查点和轨迹工件,即使没有配置磁盘预算也是如此。 后台计划在编写器事务之外进行准备,然后在提交之前重新检查所选行、副本版本和会话保护。不相关的写入不会取消计划。在维护暂停之前,冲突的输入最多会收到三次立即计划尝试,直到稍后写入;解决的拒绝保留工人的联系。保留策略和存储的数据格式保持不变。 OpenClaw 不再在 Gateway 写入期间自动创建 `sessions.json.bak.*` 轮转备份。当前 schema 会拒绝旧的 `session.maintenance.rotateBytes` 键,而 `openclaw doctor --fix` 会将其从旧配置中移除。 迁移恢复原始文件和精确的前 Doctor 恢复文件与普通会话保留是分开的:它们被排除在实时会话磁盘预算之外,并且不会自动过期。验证升级后,使用`openclaw update cleanup --dry-run`在线检查。显式离线[更新清理](/cli/update#update-cleanup)可以废弃已验证的原始文件,而无需删除当前的SQLite历史记录;从磁盘预算中排除并不是删除权限。 转录变更会通过 session accessor 和 SQLite writer 队列进行。 每次变更都会在其提交事务中验证活动运行的持久 writer 声明, 因此被取代的运行无法写入转录。 插件生命周期清理会在加载条目和保存的快照之前从元数据中选择旧的匹配会话。它在页面中规划孤立的转录窗口,释放页面之间的读取事务。归档准备后,删除仍会重新检查当前引用、所选条目、转录快照和实时生命周期权限。此计划变更无需迁移更新;保留和存档持久性不变。 ### 冷转录本存储 启用冷存储以将旧的转录有效负载保留在压缩的 `.jsonl.zst` 文件中,同时保留其会话身份在 SQLite 中: ```json5 { session: { maintenance: { coldStorage: { enabled: true, afterDays: 30 }, }, }, } ``` 一旦其活动早于 `afterDays`,当前和历史记录窗口均符合资格。逻辑会话上的最近活动或运行状态会保护其当前窗口;历史窗口使用自己的活动和运行状态。恢复所有权、实际运行准入和检查点等显式历史参考继续保护所需的窗口。固定或存档会话不算作正在进行的活动,并且本身不会将其有效负载保留在 SQLite 中。网关在启动时检查一次,每分钟一次,运行后台批处理,工作预算为 128 个转录本和 64 MiB,而不需要新消息。对这些设置的更改适用于将来的工作,无需重新启动网关;关闭该功能不会丢弃或搁置现有的冷历史记录。 `coldStorage.enabled` 是一项单独的选择加入政策。即使 `session.maintenance.mode` 为 `warn` 也能运行;该模式控制年龄、计数和磁盘预算清理。禁用 `coldStorage.enabled` 以停止将来的提取。 打开聊天、请求历史记录、通道写入在使用前异步恢复冷历史记录。批量 `sessions.preview` 请求将有效负载存档并返回显式 `cold` 状态,因此菜单预热无法重新填充数据库。会话列表还对冷有效负载进行存档。当脚本标题字段尚未缓存时,列表将使用会话元数据并忽略最后一条消息预览,直到恢复历史记录。相反,低级同步转录 API 在转录处于冷状态时返回需要恢复的错误;它们的调用者必须首先等待异步恢复。存储和使用库存可以对冷记录进行计数,而无需恢复它们。文本搜索排除冷记录内容并报告排除了多少存档记录;恢复的成绩单再次可搜索。导入和跨店修复拒绝未恢复的冷成绩单,而不是复制不完整的历史记录。 恢复后,正在运行的网关会将该记录保持热状态 24 小时,以避免重复提取最近查看的历史记录。此冷却时间是进程本地的,并在重新启动时重置。未压缩的JSONL(包括恢复元数据)超过64 MiB的转录本保留在SQLite中;该界限限制了恢复内存和工作时间。 在受保护的事务记录其位置并删除相应的记录行之前,工作人员会写入、同步并验证不可变的存档。存档保留原始序列化事件及其恢复元数据。失败或中断的准备会使 SQLite 转录本保持完整。在未提交的事务之前发布的文件可能会保留为未引用的存档。 冷存档位于 `cold/` 中代理的会话工件目录下。它们是权威的历史,而不是一次性的缓存。 Reset/deletion 存档保留和普通磁盘预算修剪不会删除它们。还原副本后,文件仍保留,因此正在进行的备份仍可以捕获其原始快照。因此,冷存储减少了工作数据库;它不保证每次传递时总磁盘使用量都会减少。后台维护检查点 SQLite 并回收有界工作通道中的空闲页面,包括没有新归档候选的后续通道。因此,物理数据库大小逐渐缩小;读者可以延迟回收。当需要完全重写时,使用Doctor的离线`compact`操作。 如果存档丢失或其记录的大小或散列不匹配,则读取或恢复该记录会显式失败。 OpenClaw 不会替换空成绩单。从备份中恢复匹配的文件,或恢复完整支持的数据库备份;校验和无法重建已删除的字节。在启用提取之前保留独立备份。 当存档丢失时,不需要转录内容的更新也可以成功。它保留了冷参考;更新包不会恢复丢失的历史记录。 支持完整存档、SQLite 快照和 Git 备份的备份命令在其私有数据库副本中嵌入经过验证的冷负载。他们恢复的数据库是独立的,不需要原始存档目录。启用冷存储后,后台维护会将这些嵌入的压缩有效负载移回经过验证的存档文件,从而回收其数据库空间。这不会将脚本解压到事件行中。设置将这些移动与新存档的记录分开报告。直接数据库复制也需要 `cold/` 文件;请参阅 [ 备份冷记录 ](/install/backups#cold-transcript-backups)。 冷存储使用 [agent 架构 20](/reference/database-schemas/agent-schema-history#cold-transcript-storage)。使用支持的更新路径和经过验证的升级前备份。在冷负载移出其事件表后,旧版本不得打开数据库,因此降低架构标记不是降级过程。 ### 在 SQLite 切换后降级 停止网关并备份其状态。使用当前支持 SQLite- 的 OpenClaw 版本,在启动旧的文件支持版本之前恢复存档的旧会话存储和转录工件: ```bash openclaw doctor --session-sqlite restore --session-sqlite-all-agents ``` 迁移存档导入了热转录本 JSONL 文件,并经过验证、完全覆盖了 `session-sqlite-import-archive/` 中的旧版 `sessions.json` 存储。覆盖不完整或阻碍迁移问题的遗留商店仍然存在。较旧的文件支持运行时在启动前需要 `sessions.json` 及其 `sessionFile` 路径引用的工件位于其原始位置。 恢复使用迁移清单,仅移动原始路径丢失的已记录存档工件,报告冲突而不是覆盖现有文件,并保留 SQLite 数据库以进行正向恢复。 无法再从迁移存档中恢复由 `openclaw update cleanup` 废弃的原始数据。恢复报告有意处置或待清理,而不是将其视为意外丢失的文件。如果您在处置后需要旧工件,则需要包含旧工件的独立备份;请参阅 [ 更新前备份](/install/updating#before-updating-create-a-verified-backup)。 恢复不会导出迁移后仅在 SQLite 中所做的更改。 SQLite 翻转后创建的会话仅是 SQLite-,并且不会出现在较旧的文件支持运行时中。如果您在降级后重新升级,请再次运行 Doctor 检查和验证序列,以便 OpenClaw 可以在导入之前验证恢复的旧工件。 ## Cron 会话和运行日志 隔离的 cron 运行创建自己的会话 entries/transcripts 并具有专用保留: - `cron.sessionRetention`(默认值为 `"24h"`)会从存储中清理旧的隔离 cron 运行会话;设置为 `false` 或 `"0h"` 等零时长值可禁用此功能。 - 终端运行历史记录保留 7 天(`lost` 行保留 24 小时),每个作业和历史记录类强制执行最新的 2000 行作为附加上限。 精确的 cron 运行行仅保留其自己的会话 ID 沿袭,同时共享基本作业的使用系列密钥。网关的 7 天会话注册表扫描会小批量读取和修剪行,因此包含超大继承族列表的旧行可能会过期,而无需将整个存储加载到内存中。现有行不会被重写;主动工作保护和成绩单存档仍然适用。 当 cron 强制创建新的隔离运行会话时,它会在写入新行之前清理先前的 `cron:` 会话条目:它携带安全首选项(thinking/fast/verbose/reasoning 设置、标签、显示名称)和显式用户选择的 model/auth 覆盖,但会删除环境对话上下文(channel/group 路由、send/queue 策略、海拔、原点、 ACP 运行时绑定),因此新的隔离运行无法从旧运行继承过时的交付或运行时权限。