Skip to content

工作区与聊天界面

本章目标:

  • 理解 /workspace 路由的页面树:认证守卫、侧边栏壳、聊天页(普通/自定义 agent)、agents 画廊与创建向导,以及它们如何围绕 thread + artifacts + todos 三个核心对象组织 UI。
  • 掌握聊天页的关键状态机:isNewThreadisWelcomeMode 的分工、useThreadStream 的流式回填、optimistic 消息、artifacts/todos 面板如何由 thread state 驱动。
  • 看懂计划模式开关、模型/推理强度选择器、文件上传在 InputBox 中如何映射到 LangGraph 的 context,以及自定义 agent 的 setup/bootstrap 向导流程。

TL;DR

工作区是一个有状态的聊天应用:WorkspaceLayout 做服务端认证守卫,WorkspaceContent 提供侧边栏 + 命令面板的整体外壳。每个聊天页通过 useThreadChat 解析 thread id、useThreadStream 接管 LangGraph 流式会话,thread state 中的 messages/artifacts/todos 分别驱动消息列表、右侧可拖拽的 artifacts 面板和输入框上方的 To-do 卡片。InputBox 把 flash/thinking/pro/ultra 四种模式翻译成 thinking_enabled/is_plan_mode/subagent_enabled/reasoning_effort 等 context 字段。自定义 agent 走两步向导:先校验名字,再用 is_bootstrap 上下文与 LeadAgent 对话,最后通过 setup_agent 工具落盘。

Overview

工作区为什么围绕 thread + artifacts + todos 三个对象组织,而不是简单的"输入框 + 消息列表"?根因在于后端是一个 LangGraph super agent:一次对话不只产出文本,还会写出文件(artifacts)、维护一个待办计划(todos)、并在 ultra 模式下委派子代理。前端必须把这三类长生命周期产物都做成可观察、可导航的 UI 一等公民。

AgentThreadState 这个类型把这种组织方式固化下来——一个 thread 的状态就是 { title, messages, artifacts, todos } frontend/src/core/threads/types.ts:5-10。聊天页拿到的不是裸消息流,而是订阅整个 thread state:消息变了刷消息列表,thread.values.artifacts 变了刷右侧面板,thread.values.todos 变了刷 To-do 卡片。这就是为什么 ChatBox 用一个可拖拽的 ResizablePanelGroup 把聊天区和 artifacts 区做成左右双栏,而 ChatPageTodoList 钉在 InputBox 上方——它们都是 thread state 的不同视图 frontend/src/components/workspace/chats/chat-box.tsx:104-176

第二个设计动机是"新会话还没在后端存在"这一现实约束。LangGraph SDK 一旦拿到 thread id 就会立刻拉 /history,而新会话此时后端根本没有该 thread(issue #2746)。所以前端拆出两个状态:isNewThread(后端是否已创建,门控历史拉取)和 isWelcomeMode(纯视觉:居中输入 + hero),提交瞬间翻 isWelcomeMode 让 UI 立即动画,但 isNewThread 要等流真正 onStart 才翻 frontend/src/app/workspace/chats/[thread_id]/page.tsx:38-91

Architecture

/workspace 是一个三层嵌套布局:外层服务端认证守卫 → 中层侧边栏外壳 → 内层各功能页;聊天页自身再叠一层 Provider 栈(Subtasks / Artifacts / PromptInput)。

Source:

WorkspaceLayout 是 server component,getServerSideUser() 返回的 tag 决定走向:authenticated 才渲染 AuthProvider + WorkspaceContent,needs_setup/system_setup_required 重定向到 /setup,unauthenticated/login,gateway_unavailable 渲染降级页 frontend/src/app/workspace/layout.tsx:15-58WorkspaceContent 从 cookie 读 sidebar_state 恢复侧边栏开合,再用 QueryClientProvider + SidebarProvider 包裹 WorkspaceSidebarSidebarInset,并挂载全局 CommandPaletteToaster frontend/src/app/workspace/workspace-content.tsx:20-34

Components / Subsystems

聊天页(chats/[thread_id])

职责:解析 thread id、接管流式会话、把 thread state 渲染成消息流 + artifacts + todos + 输入框。

agents 画廊与自定义 agent 工作流(agents/)

职责:列出已保存 agent、引导用户用对话方式创建新 agent。

threads 侧栏与会话管理 UI

职责:导航(Chats/Agents 入口)+ 最近会话列表 + 重命名/分享/导出/删除。

artifacts 面板

职责:把 thread 产出的文件做成可拖拽展开的右侧详情区。

todos / tasks UI

职责:把 LeadAgent 的计划与子代理实时进度可视化。

Data Flow

下图展示用户在聊天页发一条带附件的消息,到 UI 状态、core hook、流式回填、artifacts/todos 更新的完整链路。

关键细节:

速查表

页面 / 组件角色Source
WorkspaceLayoutserver 认证守卫,按 tag 重定向layout.tsx:12-60
WorkspaceContent侧边栏外壳 + 命令面板 + Toasterworkspace-content.tsx:17-35
chats/[thread_id]/page普通聊天页主壳page.tsx:33-260
agents/[agent_name]/chats/[thread_id]/page自定义 agent 聊天页page.tsx:34-271
agents/page / AgentGalleryagent 画廊列表agent-gallery.tsx:12-69
agents/new/page两步 setup/bootstrap 创建向导new/page.tsx:73-394
chats/page会话搜索/列表页chats/page.tsx:18-71
WorkspaceSidebarHeader + NavChatList + RecentChatListworkspace-sidebar.tsx:17-38
RecentChatList最近会话 + 重命名/分享/导出/删除recent-chat-list.tsx:61-301
ChatBox可拖拽 chat/artifacts 双栏chat-box.tsx:26-178
InputBox输入框 + 模式/模型/推理强度 + 上传input-box.tsx:102-892
TodoList计划卡片(钉在输入框上方)todo-list.tsx:14-99
ArtifactsProvider / ArtifactTriggerartifacts 选中/开合状态context.tsx:34-96
useThreadChatthread id 解析 / new 防御use-thread-chat.ts:8-40
useSpecificChatMode?mode=skill 预填技能创建 promptuse-chat-mode.ts:10-41

Common Pitfalls / Tips

References

章节关系
28-前端技术栈与应用结构上游:本章页面所处的 Next.js App Router 结构、Provider 体系与目录约定
29-AI消息流与流式渲染平行:MessageList 如何把本章 useThreadStream 回填的消息渲染成气泡/工具卡片
31-前端核心服务层下游:本章用到的 getAPIClientcore/threadscore/agents、settings 等服务层细节
19-子代理委派系统后端:本章 task_running 自定义事件与 ultra 模式 subagent_enabled 对应的子代理委派机制

公司内部参考 · 由 claude-wiki-gen 基于源码自动生成的二次分析