背景
本次 issue 仅对齐你指定的两份基线,不新增需求:
total.md
storage/README.md
storage/interface.go
基线要求的 storage 核心是:会话/任务文件化、append-only、offset 增量读取、锁、event_id 幂等去重、回放恢复。
目标
重新拟定 storage issue,严格映射基线条目。
按“是否马上提升用户体验”划分优先级:能立刻提升体验放 P0,其余放 P1/P2。
边界
In Scope:SessionStore/TaskStore/Locker/Deduplicator/Replayer、会话/任务/audit 文件存储与恢复能力。
Out of Scope:任务调度算法、Provider/Tool 协议设计、分布式一致性、UI 视觉改造。
当前根据架构设计已做
已有 internal/storage 基础实现(session 文件、prompt history、audit):
session_files.go
prompt_history.go
audit.go
会话当前是“快照覆盖写”,不是会话事件 append-only:
jsonl_snapshot.go (line 18)
runtime 任务管理仍是内存占位,Stream/Retry 未落地:
manager.go (line 74)
manager.go (line 129)
未做 Issue 清单
P0-1: STORAGE-P0-001 TaskStore Offset Log
做什么:实现 TaskStore.AppendLog/ReadLogFrom,并把 runtime 的任务日志读取接到 offset 增量读取链路。
不做什么:不改任务状态机定义,不做调度策略扩展。
程度:用户可持续看到任务增量输出;进程重启后可继续按 offset 拉取历史。
方案:新增任务日志文件实现(~/.bytemind/tasks/.log),runtime Stream 从文件增量读取。
参考同类内容:OpenHands 事件流写入/观察模式、Temporal 的事件历史顺序语义。
参考链接:OpenHands Events, Temporal API Docs
P0-2: STORAGE-P0-002 SessionStore Append-Only
做什么:实现 SessionStore.Append/ReadFrom,会话改为事件追加写,支持按 offset 读。
不做什么:不引入数据库,不改会话上层业务语义。
程度:会话恢复基于事件流;用户的会话连续性提升(异常中断后更稳定恢复)。
方案:会话文件迁移到 append-only 事件记录;保留旧快照兼容读取窗口。
参考同类内容:OpenHands 的“事件日志 + 状态持久化”、LangGraph 的 thread/checkpoint 恢复模型。
参考链接:OpenHands Persistence, LangGraph Persistence
P0-3: STORAGE-P0-003 Locker Session/Task
做什么:实现 Locker(LockSession/LockTask),接入 session/task 写路径。
不做什么:不承诺跨机器文件系统强一致。
程度:并发写场景下减少乱序/覆盖导致的用户可见异常(会话错乱、任务日志跳变)。
方案:会话和任务维度文件锁,失败返回语义化错误(含 lock timeout)。
参考同类内容:Temporal 单执行流按历史序列推进的思路可作为“单流串行化”参考。
参考链接:Temporal SDK Workflow Constraints
P1-1: STORAGE-P1-001 Deduplicator EventID
做什么:实现 Deduplicator.Seen/Mark,基于 stream + event_id 去重。
不做什么:不承诺全局 exactly-once。
程度:重复事件不重复生效,提升恢复正确性。
方案:为 session/task/audit 建持久化去重索引。
参考同类内容:事件源系统的幂等键实践(OpenHands/Temporal)。
P1-2: STORAGE-P1-002 Replayer SessionTask
做什么:实现 Replayer.ReplaySession/ReplayTask。
不做什么:不扩展业务决策逻辑。
程度:可稳定回放会话与任务事件流,支持排障与恢复验证。
方案:基于 offset 顺序回放 + 去重过滤。
参考同类内容:LangGraph state history / checkpoint replay。
P2-1: STORAGE-P2-001 Audit Minimum Closure
做什么:补齐最小审计范围(permission_decision、permission_ask_resolved、tool_execute_*、task_state_changed)和必记字段。
不做什么:不做复杂脱敏引擎扩展策略。
程度:关键链路可追溯、可回放。
方案:统一审计 schema 与写入点;对敏感字段做基础脱敏。
参考同类内容:OpenHands 可观察事件分类 + Temporal history 可重建思路。
风险
兼容风险:旧会话快照与新事件流并存。
并发风险:锁接入不完整会出现局部乱序。
性能风险:append-only 后文件增长导致读取退化。
运维风险:去重索引损坏会影响恢复正确性。
具体方案
Issue 1: STORAGE-P0-001 TaskStore 增量日志落地并接入 Runtime Stream
背景引用
任务日志按 offset 增量读取:total.md:170
会话与任务写入文件:total.md:8
TaskStore 接口定义:interface.go:45
目标
用户可持续看到任务增量输出,避免“任务有状态但看不到过程”的体验断层。
做什么
实现 TaskStore.AppendLog 与 TaskStore.ReadLogFrom 文件版本(~/.bytemind/tasks/.log)。
在 runtime 中接入 TaskStore,让 Stream 基于 offset 增量读取返回事件。
保持任务日志 append-only。
不做什么
不改任务状态机定义。
不引入数据库。
不改 UI 交互逻辑。
完成程度(DoD)
TaskStore 文件实现可用,支持追加与增量读取。
runtime.TaskManager.Stream 对已存在任务不再返回 ErrTaskNotImplemented。
进程重启后可从指定 offset 继续读取日志。
关键测试覆盖:空日志、边界 offset、limit 截断、顺序一致性。
方案
新增 internal/storage/task_store_file.go(实现 TaskStore)。
新增 runtime 的 file-backed task manager 或在现有 manager 中注入 TaskStore。
app/bootstrap 注入 TaskStore,替代纯内存日志路径。
补充 internal/storage 与 internal/runtime 对应单测。
参考同类内容(仅参考实现思路)
OpenHands Events
Temporal API Docs
Issue 2: STORAGE-P0-002 SessionStore Append-Only 事件流落地
背景引用
append-only 写入:total.md:228
SessionStore 接口定义:interface.go:40
storage 职责:会话事件追加与增量读取:README.md:17
目标
会话恢复更稳定,减少异常退出后会话状态丢失/回退的用户感知问题。
做什么
实现 SessionStore.Append 与 SessionStore.ReadFrom 文件版本。
会话写入从“整快照覆盖”切换为“事件追加(append-only)”。
会话读取支持按 offset 增量恢复。
不做什么
不改变 session 业务语义(创建/加载/展示逻辑保持一致)。
不引入数据库。
不做额外的业务功能扩展。
完成程度(DoD)
新会话写入走 append-only 事件流。
SessionStore.ReadFrom 可从任意 offset 增量读取会话事件。
主流程可通过 SessionStore 恢复当前会话状态。
关键测试覆盖:事件追加、增量读取、恢复一致性。
方案
新增 internal/storage/session_store_file.go(实现 SessionStore)。
internal/session 通过接口依赖 SessionStore,减少直接文件拼路径逻辑。
app/bootstrap 注入 SessionStore。
补充 internal/storage 与 internal/session 回放一致性测试。
参考同类内容(仅参考实现思路)
OpenHands Convo Persistence
LangGraph Persistence
Issue 3: STORAGE-P0-003 Locker 会话/任务文件锁接入关键写路径
背景引用
会话级文件锁,避免并发乱序:total.md:230
Locker 接口定义:interface.go:50
ErrCodeLockTimeout 错误码:interface.go:15
目标
减少并发下会话/任务日志错序带来的用户可见异常(消息错乱、日志跳变)。
做什么
实现 Locker.LockSession 与 Locker.LockTask。
在 SessionStore.Append 与 TaskStore.AppendLog 写路径前接入锁。
锁超时返回语义化错误码(lock_timeout)。
不做什么
不承诺跨机器文件系统一致性。
不新增分布式锁。
不改业务层权限/策略流程。
完成程度(DoD)
会话与任务写入均受对应粒度锁保护。
锁超时行为可判断(错误码明确)。
关键测试覆盖:加锁成功、超时失败、释放后可重入、session/task 锁隔离。
方案
新增 internal/storage/locker_file.go(实现 Locker)。
SessionStore/TaskStore 构造函数接收 Locker 依赖。
写路径统一封装“加锁-写入-释放”流程并处理异常分支。
增加并发一致性单测与错误码断言。
参考同类内容(仅参考实现思路)
Temporal API Docs
OpenHands Events
背景
本次 issue 仅对齐你指定的两份基线,不新增需求:
total.md
storage/README.md
storage/interface.go
基线要求的 storage 核心是:会话/任务文件化、append-only、offset 增量读取、锁、event_id 幂等去重、回放恢复。
目标
重新拟定 storage issue,严格映射基线条目。
按“是否马上提升用户体验”划分优先级:能立刻提升体验放 P0,其余放 P1/P2。
边界
In Scope:SessionStore/TaskStore/Locker/Deduplicator/Replayer、会话/任务/audit 文件存储与恢复能力。
Out of Scope:任务调度算法、Provider/Tool 协议设计、分布式一致性、UI 视觉改造。
当前根据架构设计已做
已有 internal/storage 基础实现(session 文件、prompt history、audit):
session_files.go
prompt_history.go
audit.go
会话当前是“快照覆盖写”,不是会话事件 append-only:
jsonl_snapshot.go (line 18)
runtime 任务管理仍是内存占位,Stream/Retry 未落地:
manager.go (line 74)
manager.go (line 129)
未做 Issue 清单
P0-1: STORAGE-P0-001 TaskStore Offset Log
做什么:实现 TaskStore.AppendLog/ReadLogFrom,并把 runtime 的任务日志读取接到 offset 增量读取链路。
不做什么:不改任务状态机定义,不做调度策略扩展。
程度:用户可持续看到任务增量输出;进程重启后可继续按 offset 拉取历史。
方案:新增任务日志文件实现(~/.bytemind/tasks/.log),runtime Stream 从文件增量读取。
参考同类内容:OpenHands 事件流写入/观察模式、Temporal 的事件历史顺序语义。
参考链接:OpenHands Events, Temporal API Docs
P0-2: STORAGE-P0-002 SessionStore Append-Only
做什么:实现 SessionStore.Append/ReadFrom,会话改为事件追加写,支持按 offset 读。
不做什么:不引入数据库,不改会话上层业务语义。
程度:会话恢复基于事件流;用户的会话连续性提升(异常中断后更稳定恢复)。
方案:会话文件迁移到 append-only 事件记录;保留旧快照兼容读取窗口。
参考同类内容:OpenHands 的“事件日志 + 状态持久化”、LangGraph 的 thread/checkpoint 恢复模型。
参考链接:OpenHands Persistence, LangGraph Persistence
P0-3: STORAGE-P0-003 Locker Session/Task
做什么:实现 Locker(LockSession/LockTask),接入 session/task 写路径。
不做什么:不承诺跨机器文件系统强一致。
程度:并发写场景下减少乱序/覆盖导致的用户可见异常(会话错乱、任务日志跳变)。
方案:会话和任务维度文件锁,失败返回语义化错误(含 lock timeout)。
参考同类内容:Temporal 单执行流按历史序列推进的思路可作为“单流串行化”参考。
参考链接:Temporal SDK Workflow Constraints
P1-1: STORAGE-P1-001 Deduplicator EventID
做什么:实现 Deduplicator.Seen/Mark,基于 stream + event_id 去重。
不做什么:不承诺全局 exactly-once。
程度:重复事件不重复生效,提升恢复正确性。
方案:为 session/task/audit 建持久化去重索引。
参考同类内容:事件源系统的幂等键实践(OpenHands/Temporal)。
P1-2: STORAGE-P1-002 Replayer SessionTask
做什么:实现 Replayer.ReplaySession/ReplayTask。
不做什么:不扩展业务决策逻辑。
程度:可稳定回放会话与任务事件流,支持排障与恢复验证。
方案:基于 offset 顺序回放 + 去重过滤。
参考同类内容:LangGraph state history / checkpoint replay。
P2-1: STORAGE-P2-001 Audit Minimum Closure
做什么:补齐最小审计范围(permission_decision、permission_ask_resolved、tool_execute_*、task_state_changed)和必记字段。
不做什么:不做复杂脱敏引擎扩展策略。
程度:关键链路可追溯、可回放。
方案:统一审计 schema 与写入点;对敏感字段做基础脱敏。
参考同类内容:OpenHands 可观察事件分类 + Temporal history 可重建思路。
风险
兼容风险:旧会话快照与新事件流并存。
并发风险:锁接入不完整会出现局部乱序。
性能风险:append-only 后文件增长导致读取退化。
运维风险:去重索引损坏会影响恢复正确性。
具体方案
Issue 1: STORAGE-P0-001 TaskStore 增量日志落地并接入 Runtime Stream
背景引用
任务日志按 offset 增量读取:total.md:170
会话与任务写入文件:total.md:8
TaskStore 接口定义:interface.go:45
目标
用户可持续看到任务增量输出,避免“任务有状态但看不到过程”的体验断层。
做什么
实现 TaskStore.AppendLog 与 TaskStore.ReadLogFrom 文件版本(~/.bytemind/tasks/.log)。
在 runtime 中接入 TaskStore,让 Stream 基于 offset 增量读取返回事件。
保持任务日志 append-only。
不做什么
不改任务状态机定义。
不引入数据库。
不改 UI 交互逻辑。
完成程度(DoD)
TaskStore 文件实现可用,支持追加与增量读取。
runtime.TaskManager.Stream 对已存在任务不再返回 ErrTaskNotImplemented。
进程重启后可从指定 offset 继续读取日志。
关键测试覆盖:空日志、边界 offset、limit 截断、顺序一致性。
方案
新增 internal/storage/task_store_file.go(实现 TaskStore)。
新增 runtime 的 file-backed task manager 或在现有 manager 中注入 TaskStore。
app/bootstrap 注入 TaskStore,替代纯内存日志路径。
补充 internal/storage 与 internal/runtime 对应单测。
参考同类内容(仅参考实现思路)
OpenHands Events
Temporal API Docs
Issue 2: STORAGE-P0-002 SessionStore Append-Only 事件流落地
背景引用
append-only 写入:total.md:228
SessionStore 接口定义:interface.go:40
storage 职责:会话事件追加与增量读取:README.md:17
目标
会话恢复更稳定,减少异常退出后会话状态丢失/回退的用户感知问题。
做什么
实现 SessionStore.Append 与 SessionStore.ReadFrom 文件版本。
会话写入从“整快照覆盖”切换为“事件追加(append-only)”。
会话读取支持按 offset 增量恢复。
不做什么
不改变 session 业务语义(创建/加载/展示逻辑保持一致)。
不引入数据库。
不做额外的业务功能扩展。
完成程度(DoD)
新会话写入走 append-only 事件流。
SessionStore.ReadFrom 可从任意 offset 增量读取会话事件。
主流程可通过 SessionStore 恢复当前会话状态。
关键测试覆盖:事件追加、增量读取、恢复一致性。
方案
新增 internal/storage/session_store_file.go(实现 SessionStore)。
internal/session 通过接口依赖 SessionStore,减少直接文件拼路径逻辑。
app/bootstrap 注入 SessionStore。
补充 internal/storage 与 internal/session 回放一致性测试。
参考同类内容(仅参考实现思路)
OpenHands Convo Persistence
LangGraph Persistence
Issue 3: STORAGE-P0-003 Locker 会话/任务文件锁接入关键写路径
背景引用
会话级文件锁,避免并发乱序:total.md:230
Locker 接口定义:interface.go:50
ErrCodeLockTimeout 错误码:interface.go:15
目标
减少并发下会话/任务日志错序带来的用户可见异常(消息错乱、日志跳变)。
做什么
实现 Locker.LockSession 与 Locker.LockTask。
在 SessionStore.Append 与 TaskStore.AppendLog 写路径前接入锁。
锁超时返回语义化错误码(lock_timeout)。
不做什么
不承诺跨机器文件系统一致性。
不新增分布式锁。
不改业务层权限/策略流程。
完成程度(DoD)
会话与任务写入均受对应粒度锁保护。
锁超时行为可判断(错误码明确)。
关键测试覆盖:加锁成功、超时失败、释放后可重入、session/task 锁隔离。
方案
新增 internal/storage/locker_file.go(实现 Locker)。
SessionStore/TaskStore 构造函数接收 Locker 依赖。
写路径统一封装“加锁-写入-释放”流程并处理异常分支。
增加并发一致性单测与错误码断言。
参考同类内容(仅参考实现思路)
Temporal API Docs
OpenHands Events