Skip to content

feat(agent_teams): spill message/task content into session files - #546

Open
openjiuwen-sync-bot[bot] wants to merge 2 commits into
openJiuwen-ai:developfrom
openjiuwenai:sync/pr-2338
Open

feat(agent_teams): spill message/task content into session files#546
openjiuwen-sync-bot[bot] wants to merge 2 commits into
openJiuwen-ai:developfrom
openjiuwenai:sync/pr-2338

Conversation

@openjiuwen-sync-bot

@openjiuwen-sync-bot openjiuwen-sync-bot Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Paired: GitHub #546GitCode !2338

What type of PR is this?

/kind

Self-checklist:(请自检,在[ ]内打上x,我们将检视你的完成情况,否则会导致pr无法合入

    • 设计:PR对应的方案是否已经经过Maintainer评审,方案检视意见是否均已答复并完成方案修改
    • 测试:PR中的代码是否已有UT/ST测试用例进行充分的覆盖,新增测试用例是否随本PR一并上库或已经上库
    • 验证:PR描述信息中是否已包含对该PR对应的Feature、Refactor、Bugfix的预期目标达成情况的详细验证结果描述
    • 接口:是否涉及对外接口变更,相应变更已得到接口评审组织的通过,API对应的注释信息已经刷新正确
    • 文档:是否涉及官网文档修改,如果涉及请及时提交资料到Doc仓

Message and task bodies that exceed inline storage spill to files under
the session workspace root; the SQLite ``content`` column keeps only the
``#file#`` placeholder and the DAOs transparently dereference it on read.
The file path is derived from the row's own fields (kind + object id +
to-member), never stored as a pointer.

- SessionFileStore: session-scoped content store; atomic tmp+replace
  writes, path-traversal rejected, remove_session reclaims the whole
  spill directory (best-effort).
- TeamWorkspacePaths.session_root is the single root source.
- MessageDao/TaskDao: _is_placeholder + _deref_row hydrate rows on read;
  multicast writes one file per row; update_task overwrites the same
  task file in place and always counts the content path as a change;
  empty content stays inline (no file, no placeholder).
- create_direct_messages spills all files before the SQLite write
  transaction to avoid file IO under the write lock.
- _to_stored catches (OSError, ValueError) to match _deref_row: a
  path-escape ValueError degrades to inline content like any spill
  failure instead of propagating.
- FileAddress.kind uses exported KIND_DIRECT / KIND_BROADCAST /
  KIND_TASK constants instead of raw strings.
- delete_team / release_session reclaim the session spill directory
  via SessionFileStore.remove_session (best-effort, narrowed except).
- Hydration gap fixed in list readers (get_messages /
  get_broadcast_messages / get_team_messages / get_tasks_by_assignee
  were returning #file# rows).
- UT: tests/unit_tests/agent_teams/team_workspace/test_session_file_store.py
  (store round-trip, path derivation, traversal rejection, session
  cleanup, DAO placeholder round-trip, multicast per-row files, task
  update overwrite, failed-insert orphan reclaim, templated empty
  content stays inline).
F_81 (feature) + S_23 (spec): message/task content spills to session
files, the DB keeps the ``#file#`` placeholder, and paths are derived
from row fields. Records the SessionFileStore naming, 9 decisions, 5
rejected options, 10 invariants, the interface contract, and the
session lifecycle.
@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@openjiuwen-collaboration-bot

openjiuwen-collaboration-bot Bot commented Aug 13, 2026

Copy link
Copy Markdown

head_sha: 502fb9d0a8bc12d9514f2ca3f19301c279d39f34

变更摘要

本 PR 将 agent_teams 中消息与任务正文从 SQLite 的 content 列下沉到会话级文件存储:数据库仅保存 #file# 占位符,正文写入 TeamWorkspacePaths.session_root 下的 messages/tasks/ 目录,路径由行字段(kind、对象 id、to_member)派生而非存储在库中。新增 TeamWorkspacePathsSessionFileStore 承担路径规则与文件读写,MessageDaoTaskDao 接入该存储并对读写透明解引用,TeamRuntimeManager 在删除动态表后回收会话文件,并补充了对应单元测试。

主要改动

  • 新增 SessionFileStoreFileAddress: openjiuwen/agent_teams/team_workspace/session_file_store.py 定义 CONTENT_IN_FILE = "#file#" 占位符,put 原子写入正文并返回占位符,get 根据 kind/object_id/to_member 派生路径读取正文,remove_session 删除会话的 messages/tasks/ 目录,并对路径越界与文件缺失分别抛出 ValueErrorFileNotFoundError

  • 新增 TeamWorkspacePaths 路径规则: openjiuwen/agent_teams/team_workspace/paths.py 集中定义团队根、会话根、成员真实目录与 junction 链接的布局,session_root 为会话文件提供统一根目录。

  • DAO 层接入文件存储并透明解引用: TeamDatabase 构造 SessionFileStore(TeamWorkspacePaths()) 并注入 TaskDaoMessageDao;两个 DAO 新增可选 file_store 参数与 _to_stored/_deref_row/_hydrate_row(s)create_messagecreate_direct_messagescreate_task 落盘并写 #file#,读取时自动还原正文,IO 失败则降级为内联存储原始文本。

  • 会话删除时回收溢出文件: TeamRuntimeManager.delete_teamrelease_sessiondrop_session_tables_by_id 后调用新增的 _remove_session_content_files,通过 SessionFileStore.remove_session 清理 messages/tasks/ 目录,避免磁盘内容比动态表行存活更久。

  • update_task 内容更新语义调整: TaskDao.update_task 中内容更新时始终重写同一会话文件(task_id 不变即路径不变),成功时数据库保持 #file# 不变,IO 失败则由 _to_stored 降级为原始文本并写回库。

  • 补充文件存储与 DAO 集成测试: tests/unit_tests/agent_teams/team_workspace/test_session_file_store.py 覆盖 put/get 路径派生、占位符往返、路径越界拒绝、失败插入产生的孤儿文件回收、空内容模板消息不落盘及任务更新覆盖等场景。

@openjiuwen-collaboration-bot

openjiuwen-collaboration-bot Bot commented Aug 13, 2026

Copy link
Copy Markdown

head_sha: 502fb9d0a8bc12d9514f2ca3f19301c279d39f34

代码审查

✅ 未发现问题

@openjiuwen-collaboration-bot

Copy link
Copy Markdown

head_sha: 502fb9d0a8bc12d9514f2ca3f19301c279d39f34

任务名称 结果 日志操作
静态检查 ❌FAILED 点此跳转
禁用词扫描 N/A N/A
防投毒检查 ✅SUCCESS 点此跳转
开源合规检查 ✅SUCCESS 点此跳转
UT测试 ✅SUCCESS 点此跳转
ST测试 N/A N/A
build 编译包 N/A N/A
ruff codecheck ✅SUCCESS N/A

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants