f5368c825f
重构了editor agent. 使得它能进行多轮工具调用, 把工具调用的结果嵌入到上下文里。 对于上下文的图片, 使用哈希后的id用来引用,不暴露细节信息to llm。 当前实现, 状态直接维护在json doc里, 需要对整个doc加锁,任务目前只能串行。 把SSE改成一个简单请求( 因为生图工具耗时需要二次确认, 不需要再实时展示给用户进度)。 增加确认/取消生图操作。 把tool的参数和错误情况做了反馈。 TODO: 工具调用的规范/prompt还可以改进。 改用external job来做素材生成, 针对来自editor agent 的生成会把生成资产的引用加入到结果json里, 客户端轮询 external job 确定生成状态, 发现结束了或者失败了就 重新get 会话,后端重新提供会话的时候把 结果插入回会话历史里,用来让 ai 引用 以及显示 --------- Co-authored-by: 段舒康 <kdletters@qq.com> Reviewed-on: https://git.genarrative.world/git/GenarrativeAI/Genarrative/pulls/76 Reviewed-by: 段舒康 <kdletters@qq.com> Co-authored-by: 王德宇 <kvtodev@outlook.com> Co-committed-by: 王德宇 <kvtodev@outlook.com>
3.9 KiB
3.9 KiB
【ADR】画布Agent会话消息存OSS-2026-07-03
状态:已接受
背景
画布Agent对话需要保存历史记录并支持新开会话。消息正文会随对话和工具结果持续增长;SpacetimeDB 是后端唯一结构化真相存储,但表行不适合承载不断增长的长文本;画布工程快照已有独立保存链路,对话消息也不应与布局保存互相竞争。
决策
- SpacetimeDB 表
editor_agent_conversation只存会话元数据:会话 ID、projectId、ownerUserId、标题、软删标记、聊天记录 OSS 对象引用、时间戳。 - 完整消息内容以会话粒度 JSON 对象存 OSS(
editor-agent/{conversationId}.json),追加消息即整体重写对象。 editor-agent/是服务端内部消息文档前缀,只保存editor-agent/{conversationId}.json形态的会话级 JSON 文档;它不是浏览器直传前缀,也不是公开 generated 资源前缀。- 浏览器禁止直接上传、覆盖或签名写入
editor-agent/对象;前端只通过api-server的会话接口创建会话、发送消息、读取历史,OSS 读写由服务端完成。 - 消息文档序列化后的读写上限为 2 MiB;超过上限时后端拒绝继续读写该会话消息文档,并返回 payload too large 语义错误。
- 同一会话内的消息追加采用
conversationId级串行锁,避免同一会话的“读-改-写”整对象过程互相覆盖。 - Agent 规划失败使用
role=system、正文以ERROR开头的消息持久化;首次响应和同clientMessageId重放都通过deltaMessages返回该消息,errorMessage不重复携带。前端隐藏前缀并显示红色错误气泡,后端构建后续 LLM memory 时仍保留该消息,让 Agent 获取上一轮失败上下文。工具调用失败继续保留status=failed工具记录、模型和错误信息;失败记录都是会话历史的一部分。 - 不把消息明细写入 SpacetimeDB 表,不把对话混入画布工程快照,不在 api-server 内存中保存会话真相。
备选方案与取舍
- 独立 message 表(逐条入 SpacetimeDB):查询灵活,但消息文本长、附件结构嵌套,行数与行体积随聊天无界增长,挤占 SpacetimeDB 订阅与快照成本;对话消息没有跨会话结构化查询需求,放表里收益低。
- 消息塞进画布工程快照 payload:省一张表,但每条消息都会触发整个工程快照保存,与画布布局保存互相竞争,流式期间冲突概率高。
- 每条消息一个 OSS 对象:追加成本最低,但加载历史需要 N 次取对象或额外清单维护;对话消息量级小,整体读写实现最简单。
选择"表存引用 + OSS 存整段 JSON":与仓库既有「画布资源」「敲击音效」等 OSS 对象引用模式一致,加载历史一次取对象即可。
影响
- 消息写入是"读-改-写"整对象;当前由
api-server按conversationId做会话内串行化,保证同一进程内同一会话不会并发覆写。若未来横向多实例部署,需要补充分布式锁、对象版本条件写或等价的跨实例并发控制。 - 会话表仍只保存元数据和
messagesObjectKey;API 可以在读取时把 OSS 消息文档拼装为会话详情返回,但完整消息正文的持久化真相仍是 OSS JSON 文档。 - 消息文档最大 2 MiB;该限制用于阻止单个会话无限增长。后续如果需要更长历史,应引入归档、分页对象或摘要压缩,不应把正文回填进 SpacetimeDB 表。
- 会话软删只打表标记,OSS 对象保留,便于恢复与审计。
- 规划或工具生成失败也必须写入消息文档:规划失败保存
ERRORsystem 消息,工具失败保存失败状态、模型和错误信息,便于用户回看失败原因和后续排障。 - 若未来出现跨会话消息检索需求,需另建投影或索引,不回退为消息入表。