Skip to content

Refactor: storage部分(P0已完成) #184

@Nomikfk1215

Description

@Nomikfk1215

背景

本次 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions