Editor agent refactored #76

Merged
kdletters merged 122 commits from editor-agent-refactored into master 2026-07-17 21:03:15 +08:00
Member

重构了editor agent.
使得它能进行多轮工具调用, 把工具调用的结果嵌入到上下文里。
对于上下文的图片, 使用哈希后的id用来引用,不暴露细节信息to llm。
当前实现, 状态直接维护在json doc里, 需要对整个doc加锁,任务目前只能串行。
把SSE改成一个简单请求( 因为生图工具耗时需要二次确认, 不需要再实时展示给用户进度)。
增加确认/取消生图操作。
把tool的参数和错误情况做了反馈。

TODO: 工具调用的规范/prompt还可以改进。

改用external job来做素材生成, 针对来自editor agent 的生成会把生成资产的引用加入到结果json里,
客户端轮询 external job 确定生成状态, 发现结束了或者失败了就 重新get 会话,后端重新提供会话的时候把 结果插入回会话历史里,用来让 ai 引用 以及显示

重构了editor agent. 使得它能进行多轮工具调用, 把工具调用的结果嵌入到上下文里。 对于上下文的图片, 使用哈希后的id用来引用,不暴露细节信息to llm。 当前实现, 状态直接维护在json doc里, 需要对整个doc加锁,任务目前只能串行。 把SSE改成一个简单请求( 因为生图工具耗时需要二次确认, 不需要再实时展示给用户进度)。 增加确认/取消生图操作。 把tool的参数和错误情况做了反馈。 TODO: 工具调用的规范/prompt还可以改进。 改用external job来做素材生成, 针对来自editor agent 的生成会把生成资产的引用加入到结果json里, 客户端轮询 external job 确定生成状态, 发现结束了或者失败了就 重新get 会话,后端重新提供会话的时候把 结果插入回会话历史里,用来让 ai 引用 以及显示
k88936 added 41 commits 2026-07-10 19:48:55 +08:00
k88936 added 2 commits 2026-07-10 19:49:28 +08:00
k88936 added 4 commits 2026-07-10 20:46:58 +08:00
k88936 added 1 commit 2026-07-10 20:52:29 +08:00
# Conflicts:
#	docs/project-memory/shared-memory/decision-log.md
Member

[P1] 旧 OSS 会话文档会在升级后无法读取。[editor_agent.rs (line 9)](/tmp/genarrative-pr76-review/server-rs/crates/shared-contracts/src/editor_agent.rs:9) 仍将文档版本固定为 1,但 [editor_agent.rs (line 168)](/tmp/genarrative-pr76-review/server-rs/crates/shared-contracts/src/editor_agent.rs:168) 已不兼容地修改持久化消息结构,包括 id: String -> usize、删除旧字段并新增必填形状。读取路径在 [utils.rs (line 354)](/tmp/genarrative-pr76-review/server-rs/crates/api-server/src/editor_agent/utils.rs:354) 直接按新结构反序列化,没有版本迁移或兼容解析。已有会话将报 message document JSON invalid,无法打开或继续。建议升级文档版本并实现 v1→v2 转换,补旧版 fixture 回归测试。
[P1] 大部分确认接口没有在执行生成前持久化 executing,无法兑现防重复执行契约。[api.rs (line 989)](/tmp/genarrative-pr76-review/server-rs/crates/api-server/src/editor_agent/api.rs:989) 明确依赖持久化状态阻止重复确认,但视频、音频和多数图片生成分支直接调用 provider,直到完成后才由 [api.rs (line 1560)](/tmp/genarrative-pr76-review/server-rs/crates/api-server/src/editor_agent/api.rs:1560) 写成 completed;只有编辑图片分支在 [api.rs (line 1348)](/tmp/genarrative-pr76-review/server-rs/crates/api-server/src/editor_agent/api.rs:1348) 提前写入 executing。如果请求在扣费或任务提交后断线/进程重启,消息仍是 pending_confirmation,用户重试会再次扣费和生成。应在所有工具的外部副作用前统一持久化 executing,并明确崩溃后的恢复策略。

[P1] 旧 OSS 会话文档会在升级后无法读取。[[editor_agent.rs](http://editor_agent.rs/) (line 9)](/tmp/genarrative-pr76-review/server-rs/crates/shared-contracts/src/[editor_agent.rs:9](http://editor_agent.rs:9/)) 仍将文档版本固定为 1,但 [[editor_agent.rs](http://editor_agent.rs/) (line 168)](/tmp/genarrative-pr76-review/server-rs/crates/shared-contracts/src/[editor_agent.rs:168](http://editor_agent.rs:168/)) 已不兼容地修改持久化消息结构,包括 id: String -> usize、删除旧字段并新增必填形状。读取路径在 [[utils.rs](http://utils.rs/) (line 354)](/tmp/genarrative-pr76-review/server-rs/crates/api-server/src/editor_agent/[utils.rs:354](http://utils.rs:354/)) 直接按新结构反序列化,没有版本迁移或兼容解析。已有会话将报 message document JSON invalid,无法打开或继续。建议升级文档版本并实现 v1→v2 转换,补旧版 fixture 回归测试。 [P1] 大部分确认接口没有在执行生成前持久化 executing,无法兑现防重复执行契约。[[api.rs](http://api.rs/) (line 989)](/tmp/genarrative-pr76-review/server-rs/crates/api-server/src/editor_agent/[api.rs:989](http://api.rs:989/)) 明确依赖持久化状态阻止重复确认,但视频、音频和多数图片生成分支直接调用 provider,直到完成后才由 [[api.rs](http://api.rs/) (line 1560)](/tmp/genarrative-pr76-review/server-rs/crates/api-server/src/editor_agent/[api.rs:1560](http://api.rs:1560/)) 写成 completed;只有编辑图片分支在 [[api.rs](http://api.rs/) (line 1348)](/tmp/genarrative-pr76-review/server-rs/crates/api-server/src/editor_agent/[api.rs:1348](http://api.rs:1348/)) 提前写入 executing。如果请求在扣费或任务提交后断线/进程重启,消息仍是 pending_confirmation,用户重试会再次扣费和生成。应在所有工具的外部副作用前统一持久化 executing,并明确崩溃后的恢复策略。
kdletters requested review from kdletters 2026-07-14 13:09:45 +08:00
k88936 added 26 commits 2026-07-14 20:36:58 +08:00
支持调用方提供任务 ID 和去重键,复用既有外部任务队列。

保存并投影编辑器生成结果,供任务消费者恢复展示。
工具消息改为保存外部任务 ID 与取消事实,不再复制执行状态。

确认请求以稳定身份提交外部任务,并由前端查询任务状态和结果。

同步更新画布 Agent 测试与执行契约文档。
# Conflicts:
#	server-rs/crates/api-server/src/editor_generation_queue.rs
#	src/components/image-editor/ImageCanvasEditorView.test.tsx
#	src/components/image-editor/ImageCanvasEditorView.tsx
移除从轻量任务摘要读取主任务结果载荷的错误实现。

画布 Agent 继续轮询摘要状态,并通过画布完成回写刷新工程结果。
forward call back
合并 origin/master 的资源命名、图集拆分告警与相关后端契约更新

保留编辑 Agent 完成任务后的任务列表和画布刷新流程

保留编辑生成结果的轻量化持久化处理
kdletters added 1 commit 2026-07-14 20:59:03 +08:00
k88936 added 7 commits 2026-07-15 14:50:52 +08:00
恢复外部生成 worker 的 master 行为

恢复画布生成任务默认入队标识

移除 Agent 自定义任务标识入口
新增仅返回任务结果的 SpacetimeDB procedure

编辑器 Agent 回填改用结果查询接口

补齐客户端绑定与接口文档
保留外部生成任务稳定 job id 与去重键

供异步结果查询按固定任务标识回填
# Conflicts:
#	vitest.config.ts
k88936 added 5 commits 2026-07-15 16:23:04 +08:00
k88936 added 1 commit 2026-07-15 16:29:49 +08:00
k88936 added 1 commit 2026-07-15 16:33:10 +08:00
k88936 marked the pull request as work in progress 2026-07-15 16:37:23 +08:00
Author
Member

Screenshot_15-7-2026_162412_localhost.jpeg
Screenshot_15-7-2026_16250_localhost.jpeg
Screenshot_15-7-2026_163141_localhost.jpeg
Screenshot_15-7-2026_163159_localhost.jpeg

改用external job来做素材生成, 针对来自editor agent 的生成会把生成资产的引用加入到结果json里,
客户端轮询 external job 确定生成状态, 发现结束了或者失败了就 重新get 会话,后端重新提供会话的时候把 结果插入回会话历史里,用来让 ai 引用 以及显示

![Screenshot_15-7-2026_162412_localhost.jpeg](/attachments/f193f275-6967-4d5b-87e5-e0a81e433e41) ![Screenshot_15-7-2026_16250_localhost.jpeg](/attachments/768e9bcd-efd3-4997-9a2c-36c63ad45e46) ![Screenshot_15-7-2026_163141_localhost.jpeg](/attachments/ff153b3c-567a-4a5f-ba3f-01e6295b8cd1) ![Screenshot_15-7-2026_163159_localhost.jpeg](/attachments/fefdd6c6-2b04-41d7-adfa-5007f33b7a27) 改用external job来做素材生成, 针对来自editor agent 的生成会把生成资产的引用加入到结果json里, 客户端轮询 external job 确定生成状态, 发现结束了或者失败了就 重新get 会话,后端重新提供会话的时候把 结果插入回会话历史里,用来让 ai 引用 以及显示
k88936 marked the pull request as ready for review 2026-07-15 16:39:39 +08:00
k88936 marked the pull request as work in progress 2026-07-15 16:45:11 +08:00
k88936 added 2 commits 2026-07-15 17:40:49 +08:00
k88936 added 6 commits 2026-07-15 20:30:02 +08:00
k88936 marked the pull request as ready for review 2026-07-16 11:44:48 +08:00
k88936 added 5 commits 2026-07-16 11:45:03 +08:00
k88936 added 1 commit 2026-07-16 13:05:27 +08:00
Member
问题 归因 依据
消息发送丢失 clientMessageId 幂等键 PR 引入 base 有客户端幂等键和重复检查;PR 删除后改用数组下标
SSE 流式回复被改成普通 JSON PR 主动改动 base 有 /messages/stream 和 SSE client;PR 明确删除。若产品已决定取消 SSE,则应降为文档债务,不算缺陷
LLM/规划错误不再持久化 PR 引入 base 会把失败 assistant 消息写入 OSS;PR 只返回瞬时 errorMessage
完整历史无上限发送给 LLM PR 引入 base 限制最近 12 条并单独注入最新生成图;PR 改为遍历全部消息
任务终态回填失败后不重试 PR 新链路缺陷 外部任务确认、轮询和懒回填是本 PR 新增,base 没有这条链路
后端正式数据契约未同步 Agent 结果载荷例外 PR 引入的文档不一致 base 的代码和文档一致;PR 新增轻量媒体结果持久化,只更新了 decision log,未修正正式架构文档
会话快速切换响应乱序 原本就有 base 的 loadConversation 同样无 request token,并无条件应用响应
Agent 与素材/图层栏不互斥 排除 不是 PR 改动,而且按你的确认属于现行设计;是旧文档未更新
问题 | 归因 | 依据 -- | -- | -- 消息发送丢失 clientMessageId 幂等键 | PR 引入 | base 有客户端幂等键和重复检查;PR 删除后改用数组下标 SSE 流式回复被改成普通 JSON | PR 主动改动 | base 有 /messages/stream 和 SSE client;PR 明确删除。若产品已决定取消 SSE,则应降为文档债务,不算缺陷 LLM/规划错误不再持久化 | PR 引入 | base 会把失败 assistant 消息写入 OSS;PR 只返回瞬时 errorMessage 完整历史无上限发送给 LLM | PR 引入 | base 限制最近 12 条并单独注入最新生成图;PR 改为遍历全部消息 任务终态回填失败后不重试 | PR 新链路缺陷 | 外部任务确认、轮询和懒回填是本 PR 新增,base 没有这条链路 后端正式数据契约未同步 Agent 结果载荷例外 | PR 引入的文档不一致 | base 的代码和文档一致;PR 新增轻量媒体结果持久化,只更新了 decision log,未修正正式架构文档 会话快速切换响应乱序 | 原本就有 | base 的 loadConversation 同样无 request token,并无条件应用响应 Agent 与素材/图层栏不互斥 | 排除 | 不是 PR 改动,而且按你的确认属于现行设计;是旧文档未更新
k88936 added 6 commits 2026-07-16 17:51:14 +08:00
Member

发送消息期间切换会话,JSON 响应会落到当前会话面板里。
PR 把原来的 SSE 改成普通 JSON POST 后,useEditorAgentConversation.ts 在 sendMessage 返回后直接 applyDeltaMessages(response.deltaMessages),没有再确认 activeConversationIdRef.current === conversationId。applyDeltaMessages 又是直接 append 当前 messages。所以用户在会话 A 发送消息、等待期间切到会话 B,A 的 assistant/tool card 会插进 B 的 UI,并可能触发错误的画布刷新。base 旧 SSE 路径有 eventConversationId !== activeConversationIdRef.current 的过滤,这个是 PR 引入的回归。

发送消息期间切换会话,JSON 响应会落到当前会话面板里。 PR 把原来的 SSE 改成普通 JSON POST 后,useEditorAgentConversation.ts 在 sendMessage 返回后直接 applyDeltaMessages(response.deltaMessages),没有再确认 activeConversationIdRef.current === conversationId。applyDeltaMessages 又是直接 append 当前 messages。所以用户在会话 A 发送消息、等待期间切到会话 B,A 的 assistant/tool card 会插进 B 的 UI,并可能触发错误的画布刷新。base 旧 SSE 路径有 eventConversationId !== activeConversationIdRef.current 的过滤,这个是 PR 引入的回归。
k88936 added 1 commit 2026-07-16 18:51:00 +08:00
k88936 added 1 commit 2026-07-16 19:33:47 +08:00
# Conflicts:
#	docs/technical/【前端架构】图片画布编辑器MVP接入方案-2026-06-11.md
#	docs/technical/【后端架构】外部生成Worker化方案-2026-06-03.md
#	docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md
#	server-rs/crates/api-server/src/editor_agent.rs
#	server-rs/crates/api-server/src/external_generation_worker.rs
#	server-rs/crates/spacetime-client/src/lib.rs
#	server-rs/crates/spacetime-client/src/mapper.rs
#	server-rs/crates/spacetime-client/src/mapper/external_generation.rs
kdletters added 1 commit 2026-07-16 19:35:55 +08:00
k88936 added 1 commit 2026-07-16 20:58:58 +08:00
k88936 added 1 commit 2026-07-17 10:02:31 +08:00
# Conflicts:
#	server-rs/crates/api-server/src/editor_agent.rs
k88936 added 2 commits 2026-07-17 13:20:27 +08:00
k88936 added 1 commit 2026-07-17 16:09:04 +08:00
解释: 停止是原来sse留下来的, 现在思考时间相对调用各种美术工具时间短, 且美术工具调用不阻塞对话,调用前已有确认取消
k88936 added 1 commit 2026-07-17 16:53:55 +08:00
k88936 added 1 commit 2026-07-17 17:22:17 +08:00
k88936 added 1 commit 2026-07-17 17:39:41 +08:00
# Conflicts:
#	docs/README.md
#	src/components/image-editor/EditorAgentConversation/EditorAgentConversationPanelView.tsx
#	src/components/image-editor/EditorAgentConversation/useEditorAgentConversation.ts
#	src/components/image-editor/EditorAgentConversationPanelView.test.tsx
#	src/components/image-editor/ImageCanvasStageView.tsx
k88936 added 2 commits 2026-07-17 19:05:40 +08:00
kdletters approved these changes 2026-07-17 21:02:53 +08:00
kdletters merged commit f5368c825f into master 2026-07-17 21:03:15 +08:00
kdletters deleted branch editor-agent-refactored 2026-07-17 21:03:15 +08:00
Sign in to join this conversation.