9.5 KiB
9.5 KiB
圆桌 Step 2 沙箱预览 · 开发进度
最后更新:2026-05-27
关联文档:multi-agent-frontend-dev.md(总览)、multi-agent-backend-dev.md(后端)、multi-agent-api.md(接口)
对照参考:主聊天/page/workspace/chats/:threadId(ChatBox+ArtifactsProvider+message-group.tsx)
1. 目标
在 Step 2「多智能体圆桌研讨」中,当子智能体调用 write_file / str_replace / present_files 时,行为与主聊天一致:
| 能力 | 主聊天 | Step 2 目标 |
|---|---|---|
write_file 流式期间自动打开右侧沙箱 |
✅ | ✅ 已实现(虚拟 URL) |
| 步骤卡里点击文件路径打开沙箱 | ✅ | ✅ 已实现 |
消息下方文件卡片(present_files)点击打开 |
✅ | ❌ 未做 |
| 沙箱打开时收起 workspace 左侧栏 | ✅(ArtifactsProvider.select) |
✅ Step 2 左栏联动 |
| 60/40 对话 | 产物预览分栏 | ✅ ChatBox |
✅ Step2SandboxLayout |
| 流式 MD 从 tool_call.args.content 预览 | ✅ 虚拟 URL + stub messages | ✅ seatStubMessages |
| 落盘后 HTTP 拉取真实文件 | ✅ artifacts API | ⚠️ 仅 present_files 手动路径 |
2. 已完成
2.1 Step 2 布局调整
| 项 | 状态 | 说明 |
|---|---|---|
| 推理模型下拉 | ✅ | 从右侧栏迁至 Step 2 顶栏「多智能体圆桌会商中心」右侧 |
| 意图理解 | ✅ | 移至左侧栏顶部,支持展开/收起;收起时仅显示「目标」 |
| 任务概览 | ✅ | 放在「人工参与」下方 |
| 右侧栏 Step 2/3 隐藏 | ✅ | RightSidebar 仅在 currentStep === 1 渲染 |
| 左侧栏整体收起 | ✅ | 宽度 56px;展开按钮在顶部;研讨中角色 ring + ping 动画 |
| 沙箱打开 → 左栏收起 | ✅ | Step2SandboxSidebarSync 监听 useArtifacts().open |
主要文件:RoundtablePlanningPage.tsx(step2SidebarExpanded、LeftSidebar、Step2SandboxSidebarSync)
2.2 沙箱基础设施(Phase 1)
| 项 | 状态 | 说明 |
|---|---|---|
路由包 ChatRuntime |
✅ | WorkspaceRoutes.tsx → roundtable/planning 外包 ArtifactsProvider |
| 60/40 分栏壳 | ✅ | 新建 Step2SandboxLayout.tsx,对齐 chat-box.tsx |
ArtifactFileDetail / ArtifactFileList |
✅ | 嵌在右栏 ResizablePanel |
ThreadContext stub |
✅ | 最小 BaseStream stub,供 useArtifactContent 工作 |
2.3 沙箱打开逻辑(Phase 2)
| 项 | 状态 | 说明 |
|---|---|---|
write_file 自动打开 |
✅ | handleArtifactToolPhase 在 tool_calling + 完整 args.path 时触发 |
| 步骤卡点击打开 | ✅ | MessageStepsCard → openArtifactFromStep |
| 虚拟 URL 机制 | ✅ | write-file:<path>?message_id=...&tool_call_id=...(对齐主聊天) |
| Stub messages 注入 | ✅ | seatStubMessages + upsertSeatToolCall → loadArtifactContentFromToolCall |
| 重置清理 | ✅ | resetStep2State 清空 artifacts / stub / deselect |
present_files 步骤点击 |
✅ | 走真实路径 openArtifactPreview(HTTP API) |
主要文件:
frontend-web/src/pages/WorkspaceRoutes.tsx
frontend-web/src/roundtable-planning/hooks/useStep2Orchestration.ts
frontend-web/src/roundtable-planning/components/Step2SandboxLayout.tsx
frontend-web/src/roundtable-planning/components/Step2Panel.tsx
frontend-web/src/roundtable-planning/components/MessageStepsCard.tsx
frontend-web/src/roundtable-planning/pages/RoundtablePlanningPage.tsx
2.4 与主聊天对齐的核心数据流(当前实现)
special seat SSE (streamMultiAgent)
onPhaseChange("tool_calling", "write_file", args)
↓
upsertSeatToolCall(seatThreadId, "write_file", args)
→ seatStubMessages[seatThreadId] = [{ type:"ai", tool_calls:[{ id, name, args }] }]
↓
buildWriteFileVirtualUrl(path, messageId, toolCallId)
→ "write-file:/mnt/user-data/outputs/foo.md?message_id=...&tool_call_id=..."
↓
openSeatVirtualArtifact(seatThreadId, virtualUrl, auto=true)
→ selectArtifact(virtualUrl) + setArtifactsOpen(true)
↓
Step2SandboxLayout
ThreadContext.thread.messages = seatStubMessages[activeThreadId]
ArtifactFileDetail(filepath=virtualUrl, threadId=seatThreadId)
↓
useArtifactContent → loadArtifactContentFromToolCall
→ 从 thread.messages 读 tool_call.args.content(不发 HTTP)
为何不用真实 path 直接预览:流式期间文件可能尚未落盘,直接调 /api/threads/:id/artifacts/... 会返回 404 {"detail":"Not Found"}。主聊天同样用虚拟 URL 绕过此问题。
3. 未完成 / 待验证
3.1 功能缺口(按优先级)
| 优先级 | 项 | 状态 | 说明 |
|---|---|---|---|
| P0 | 端到端回归 | ⚠️ 待验证 | 虚拟 URL 改造后需确认:自动打开时机、MD 内容、点击步骤、左栏收起 |
| P1 | present_files 文件卡片 |
❌ | 主聊天在消息正文下方渲染 RichFileCard(message-list-item.tsx);Step 2 气泡仅有 Markdown 文本,无文件卡片 UI |
| P1 | onUpstreamFrame 完整消息注入 |
❌ | 当前仅从 onPhaseChange 的 args 写 stub;若 LangGraph 在 tool_call_chunks 阶段不传完整 args.content,预览可能空白,需从上游 messages-tuple 帧补全 |
| P2 | str_replace 流式编辑预览 |
❌ | 主聊天 applyPendingTextEdit 依赖完整 message 链;stub 未模拟 tool result / 多轮 str_replace |
| P2 | 沙箱 artifacts[] 列表与虚拟 URL 混排 |
❌ | 虚拟 URL 不写入 setArtifacts([]);多文件切换、文件名下拉体验未完全对齐主聊天 |
| P2 | 草稿持久化 seatStubMessages |
❌ | Step2Snapshot / hydrateFromDraft 未保存 stub;加载草稿后点击历史 write_file 步骤可能无法预览 |
| P3 | Step 3 与沙箱衔接 | ❌ | Step 3 仍用 HighFidelityReport + listSessionArtifacts;与 Step 2 沙箱选中态无联动 |
| P3 | 文档同步 | ❌ | multi-agent-frontend-dev.md 仍描述旧布局(右侧栏模型选择器等),需更新 § 布局 + 沙箱章节 |
3.2 已知风险 / 边界
- 打开时机:仅在 SSE 进入
tool_calling且tool_calls[0].args为完整对象时触发(multi-agent.ts刻意忽略tool_call_chunks的拼接 args)。若模型只发 chunks、迟迟不发完整 tool_calls,自动打开会延迟到 args 完整那一帧——与主聊天一致,但可能比用户预期晚。 - 多 write_file 同气泡:
upsertSeatToolCall按(toolName, path)幂等;同 path 多次 write 会更新 args,不会新建多条 stub tool_call。 - leader 席位:当前仅 special 流绑定
agentThreadId;总控若直接 write_file,需单独接 thread id。 - 调试日志:控制台
[roundtable-sandbox]前缀;生产环境可考虑加window.__ROUNDTABLE_SANDBOX_DEBUG__门控。
4. 分阶段计划(原始规划 vs 现状)
| 阶段 | 内容 | 状态 |
|---|---|---|
| Phase 1 | ChatRuntime + 分栏壳 + 侧栏联动 |
✅ 完成 |
| Phase 2 | write_file 自动/点击打开 + 虚拟 URL 预览 |
✅ 代码完成,⚠️ 待 E2E 验证 |
| Phase 3 | onUpstreamFrame 注入完整 LangGraph messages |
❌ 未开始 |
| Phase 4 | present_files 卡片 + Step 3 文件区衔接 |
❌ 未开始 |
| Phase 5 | 草稿 stub 持久化 + 文档更新 | ❌ 未开始 |
5. 测试清单
在 /page/workspace/roundtable/planning Step 2 下逐项勾选:
- 子智能体
write_file进入tool_calling后,右侧沙箱 自动 打开(约 100ms 延迟,对齐主聊天) - 沙箱标题为文件名(如
sample-paper.md),不是{"detail":"Not Found"} - 流式期间 MD 内容随
args.content更新(需 stub 收到完整 args) - 点击 ChainOfThought 步骤「写入文件」/ 路径 chip → 手动打开同一文件
- 沙箱打开时左侧「意图理解」栏 自动收起
- 关闭沙箱(X)后对话区恢复全宽
present_files步骤点击 → HTTP 预览(文件已落盘时)- 「新建任务」后 artifacts / 沙箱状态清空
- 与主聊天
/page/workspace/chats/:threadId对比:同一 write_file 行为一致
调试:DevTools Console 过滤 [roundtable-sandbox] 或 [stream:special:...]。
6. 关键代码索引
| 用途 | 路径 |
|---|---|
| 主聊天 write_file 虚拟 URL + 自动打开 | src/components/workspace/messages/message-group.tsx |
| 主聊天 60/40 分栏 | src/components/workspace/chats/chat-box.tsx |
| 虚拟 URL 内容加载 | src/core/artifacts/loader.ts → loadArtifactContentFromToolCall |
| Artifacts 上下文 | src/components/workspace/artifacts/context.tsx |
| Step 2 编排 + 沙箱状态 | src/roundtable-planning/hooks/useStep2Orchestration.ts |
| Step 2 沙箱布局 | src/roundtable-planning/components/Step2SandboxLayout.tsx |
| SSE phase 推断 | src/roundtable-planning/api/multi-agent.ts → setPhase |
| 主页面侧栏 + 联动 | src/roundtable-planning/pages/RoundtablePlanningPage.tsx |
7. 下一步建议(给接续开发者)
- 先跑通 P0 测试清单,确认虚拟 URL 改造后无回归;若内容空白,优先做 Phase 3(
onUpstreamFrame解析 messages-tuple 写入 stub)。 - Phase 4:在
Step2Message/ 气泡 Markdown 渲染后检测present_files或解析 assistant 正文里的文件引用,复用RichFileCard或抽轻量RoundtableFileCard。 - 更新
multi-agent-frontend-dev.md:Step 2 布局、沙箱架构、seatStubMessages数据流,避免与本文档重复——可在总览文档加一节「见roundtable-step2-sandbox-progress.md」。