feat: 支持会商 Markdown 产物提交到任务过程,并补充 Angular 对接文档

8BF/会商工作区可将 Markdown 产物一键提交到任务过程报告,后端记录提交状态以便跨用户与刷新后保持已提交;同时为 Angular 智能体对话对接文档补上前后端参考代码索引。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
董宏凯andCursor committed 2026-08-18 20:08:51 +08:00
1 parent 33b0af333c
commit dcfaa199bf
19 files changed
+1133 -43

No files matched your search

@@ -12,6 +12,12 @@ http://localhost:5173/#/page/workspace/agents/roundtable-structure/chats/new
本文覆盖:**登录拿 Token → 列模型/切模型 → 建会话/存聊天记录 → 流式对话 → 思考内容 → 步骤条(含创建脚本/执行脚本/写入文件及全部工具)→ 用户协助卡片 → 消息列表渲染 → 停止/重连/上传/产物**。
**不包含**智能体配置(创建/编辑智能体、技能绑定等)。
路径约定(均相对本仓库根目录 `deerflow-server/`):
- 前端:`frontend-web/src/…`
- 后端:`offline-backend-20260512/backend/…`(下文若写 `app/`、`deerflow/`,都在这个 backend 目录下)
- 每节末尾有 **参考代码**;文末第 20 节是总索引。
---
## 0. 先看这一页
@@ -45,6 +51,17 @@ Content-Type: application/json
用 Bearer **不必**再带 CSRF。不要用 cookie 登录(`/login/local` 只把 JWT 写进 HttpOnly cookie,不适合 Angular 跨域 API 客户端)。
**参考代码**
| 说明 | 路径 |
|------|------|
| 前端两个 Base URL | `frontend-web/src/core/config/index.ts`(`getBackendBaseURL` / `getLangGraphBaseURL`) |
| 环境变量注入 | `frontend-web/src/env.ts` |
| LangGraph SDK 客户端(自动带 Bearer) | `frontend-web/src/core/api/api-client.ts` |
| Gateway fetch 自动带 Authorization | `frontend-web/src/core/api/fetch-client.ts` |
| CSRF:有 Bearer 则跳过 | `offline-backend-20260512/backend/app/gateway/csrf_middleware.py` |
| 登录接口白名单 | `offline-backend-20260512/backend/app/gateway/auth_middleware.py` |
---
## 1. 架构与端到端流程
@@ -77,6 +94,19 @@ sequenceDiagram
2. `context.agent_id = "roundtable-structure"`
3. 会话 `metadata.agent_id = "roundtable-structure"`(历史列表按此过滤)
**参考代码**
| 说明 | 路径 |
|------|------|
| 路由挂载 AgentChatPage | `frontend-web/src/pages/WorkspaceRoutes.tsx`(`agents/:agent_id/chats/:thread_id`) |
| 对话页:`assistantId` + `context.agent_id` | `frontend-web/src/pages/AgentChatPage.tsx` |
| 聊天气泡壳 | `frontend-web/src/components/workspace/chats/chat-box.tsx` |
| 发消息时写入 metadata.agent_id | `frontend-web/src/core/threads/hooks.ts`(`onCreated` / `thread.submit`) |
| 非内置 assistant_id → agent_id | `offline-backend-20260512/backend/app/gateway/services.py`(`build_run_config`) |
| Lead Agent 工厂 | `offline-backend-20260512/backend/packages/harness/deerflow/agents/lead_agent/agent.py` |
| 智能体种子(id / 中文名 / 技能) | `offline-backend-20260512/backend/app/gateway/routers/_roundtable_seed_assets/roundtable-structure/config.yaml` |
| 智能体 SOUL | `offline-backend-20260512/backend/app/gateway/routers/_roundtable_seed_assets/roundtable-structure/SOUL.md` |
---
## 2. CORS / 跨域(Angular 必读)
@@ -94,6 +124,8 @@ GATEWAY_CORS_ORIGINS=http://localhost:4200,http://127.0.0.1:4200,https://your-an
或开发期临时 `GATEWAY_CORS_ALLOW_ALL=1`(勿用于生产)。
**参考代码**:`offline-backend-20260512/backend/app/gateway/app.py`(搜 `GATEWAY_CORS_ORIGINS` / `local_vite_origins` / `cors_expose_headers`)。回归:`offline-backend-20260512/backend/tests/test_taskcop_cors.py`。
浏览器跨域读 SSE 还需要暴露这些响应头(Gateway 已配):
- `Content-Location`(从中解析 `run_id`,取消/重连要用)
@@ -210,6 +242,20 @@ function authHeader(): HttpHeaders {
}
```
**参考代码**
| 说明 | 路径 |
|------|------|
| 前端登录 API | `frontend-web/src/core/auth/api.ts`(`loginByUsername` / `loginByToken`) |
| Token 存取、拼 Bearer | `frontend-web/src/core/auth/index.ts`(`getAuthorizationHeaderValue` / `setStoredAuth`) |
| 类型 `LoginByUsernameResponse` | `frontend-web/src/core/auth/index.ts` |
| 登录页(含 token 换票) | `frontend-web/src/pages/LoginPage.tsx` |
| 后端登录路由 | `offline-backend-20260512/backend/app/gateway/routers/auth.py`(`/login/username`、`/login/token`、`/me`) |
| JWT 签发 | `offline-backend-20260512/backend/app/gateway/auth/jwt.py` |
| 请求里解析 cookie / Bearer | `offline-backend-20260512/backend/app/gateway/deps.py`(`get_current_user`) |
| 登录配置(口令门 / token_login) | `offline-backend-20260512/backend/config.yaml` → `auth_login`;schema:`deerflow/config/login_config.py` |
| 登录契约说明 | `offline-backend-20260512/backend/docs/AUTH_LOGIN.md` |
---
## 4. 模型列表与切换
@@ -266,6 +312,20 @@ Authorization: Bearer <jwt>
每轮都可以换模型;换了只影响 **下一轮**,不会改写历史。
**参考代码**
| 说明 | 路径 |
|------|------|
| 前端拉模型 | `frontend-web/src/core/models/api.ts`、`frontend-web/src/core/models/types.ts` |
| 输入框模型下拉 + 档位 | `frontend-web/src/components/workspace/input-box.tsx`(`InputMode`、`ModelSelector`) |
| 档位写入 context | `frontend-web/src/core/threads/hooks.ts`(`thread.submit` 的 `context`:`thinking_enabled` / `is_plan_mode` / `subagent_enabled`) |
| 本地记住所选模型 | `frontend-web/src/core/settings/local.ts`(`deerflow.thread-model.{threadId}`) |
| 后端模型列表 | `offline-backend-20260512/backend/app/gateway/routers/models.py` |
| context 白名单 | `offline-backend-20260512/backend/app/gateway/services.py`(`_CONTEXT_CONFIGURABLE_KEYS`) |
| 本轮实际用哪个模型 | `offline-backend-20260512/backend/app/gateway/services.py`(`_resolve_effective_run_model_name`) |
| 创建 ChatModel、关思考 | `offline-backend-20260512/backend/packages/harness/deerflow/models/factory.py` |
| 模型配置源 | `offline-backend-20260512/backend/config.yaml` → `models[]` |
---
## 5. 会话(Thread)= 聊天记录的存储单位
@@ -393,6 +453,20 @@ DELETE {LG}/threads/{thread_id}
`status`:`idle` | `busy` | `interrupted` | `error`
正在跑时为 `busy`。同一会话再发会被 `multitask_strategy: "reject"` 打回 **HTTP 409**。
**参考代码**
| 说明 | 路径 |
|------|------|
| 线程类型 / context 类型 | `frontend-web/src/core/threads/types.ts` |
| 列表、标题、路由 | `frontend-web/src/core/threads/utils.ts`(`titleOfThread` / `pathOfThread`) |
| 分页搜索 | `frontend-web/src/core/threads/hooks.ts`(`useThreadsPage`) |
| 智能体最近对话 | `frontend-web/src/components/workspace/agents/agent-recent-chats.tsx` |
| 工作区会话列表 UI | `frontend-web/src/components/workspace/workspace-nav-chat-list.tsx` |
| 建/搜/改/删/state/history | `offline-backend-20260512/backend/app/gateway/routers/threads.py` |
| ThreadResponse / Search 模型 | 同上文件内 `ThreadResponse`、`ThreadCreateRequest`、`ThreadSearchRequest` |
| 删除时清本地目录 | `frontend-web/src/core/threads/hooks.ts`(delete 后再调 Gateway DELETE) |
| 409 中文文案 | `offline-backend-20260512/backend/app/gateway/services.py`(`create_or_reject` / RunManager) |
---
## 6. 发起智能体对话(核心)
@@ -511,6 +585,21 @@ Last-Event-ID: <上一帧 id>
心跳是注释行:`: heartbeat`,忽略即可。
**参考代码**
| 说明 | 路径 |
|------|------|
| 前端 `useStream` + `thread.submit` | `frontend-web/src/core/threads/hooks.ts`(`useThreadStream`、构造 `messages` / `context`) |
| SDK 包装 | `frontend-web/src/core/api/api-client.ts` |
| stream_mode 规范化 | `frontend-web/src/core/api/stream-mode.ts` |
| 停止:`thread.stop` / `runs.cancel` | `frontend-web/src/core/threads/hooks.ts`(`stopThreadRun`) |
| 输入框停止按钮 | `frontend-web/src/components/workspace/input-box.tsx` |
| 后端 stream / cancel / join | `offline-backend-20260512/backend/app/gateway/routers/thread_runs.py`(`RunCreateRequest`、`stream_run`、`cancel_run`、`join_run`) |
| 真正起跑 | `offline-backend-20260512/backend/app/gateway/services.py`(`start_run`) |
| 后台跑图 + 发 SSE | `offline-backend-20260512/backend/packages/harness/deerflow/runtime/runs/worker.py`(`run_agent`) |
| Run 生命周期 | `offline-backend-20260512/backend/packages/harness/deerflow/runtime/runs/manager.py` |
| 流式设计说明 | `offline-backend-20260512/backend/docs/STREAMING.md` |
---
## 7. SSE 事件协议(Angular 必须自己解析 POST 流)
@@ -655,6 +744,18 @@ async function streamRun(
}
```
**参考代码**
| 说明 | 路径 |
|------|------|
| SSE 组帧(`event:` / `data:` / `id:`) | `offline-backend-20260512/backend/app/gateway/services.py`(`format_sse`、`sse_consumer`) |
| 心跳 / 订阅 | `offline-backend-20260512/backend/packages/harness/deerflow/runtime/stream_bridge.py` |
| 首帧 `event: metadata` | `offline-backend-20260512/backend/packages/harness/deerflow/runtime/runs/worker.py`(`bridge.publish(..., "metadata", {run_id, thread_id})`) |
| `messages-tuple` → 内部 `messages` | 同上 `run_agent`;SSE 事件名 `_lg_mode_to_sse_event` |
| chunk 序列化成 `[chunk, meta]` | `offline-backend-20260512/backend/packages/harness/deerflow/runtime/serialization.py`(`serialize_messages_tuple` / `serialize_channel_values`) |
| 前端消费:onCustomEvent / onUpdateEvent | `frontend-web/src/core/threads/hooks.ts` |
| 协议说明 | `offline-backend-20260512/backend/docs/STREAMING.md` |
---
## 8. 消息数据结构(历史 + 实时共用)
@@ -707,6 +808,14 @@ async function streamRun(
| `ai` 有 `tool_calls` 或仅有思考 | **不单独当最终气泡**,进入步骤条 |
| `tool` | **几乎不单独成气泡**,并进步骤条 / 协助卡片 |
**参考代码**
| 说明 | 路径 |
|------|------|
| 分组、抽文本、抽思考、隐藏消息 | `frontend-web/src/core/messages/utils.ts`(`groupMessages` / `extractContentFromMessage` / `extractReasoningContentFromMessage` / `isHiddenFromUIMessage`) |
| 检索结果识别 | `frontend-web/src/core/messages/search-results.ts` |
| 序列化后的 message dict | `offline-backend-20260512/backend/packages/harness/deerflow/runtime/serialization.py` |
---
## 9. 消息列表如何分组渲染
@@ -765,6 +874,20 @@ async function streamRun(
`busy` 且还没有最终 `assistant` 气泡时,在列表底部显示跳动的「正在生成」。
上传文件未完成时可插一条 mock AI:`additional_kwargs.element === "task"`,文案「文件上传中,请稍候...」。
**参考代码**
| 说明 | 路径 |
|------|------|
| 列表入口、分组渲染 | `frontend-web/src/components/workspace/messages/message-list.tsx` |
| 单条用户/助手气泡 | `frontend-web/src/components/workspace/messages/message-list-item.tsx` |
| Markdown | `frontend-web/src/components/workspace/messages/markdown-content.tsx` |
| 气泡/会话滚动容器 | `frontend-web/src/components/ai-elements/message.tsx`、`conversation.tsx` |
| 跳动「正在生成」 | `frontend-web/src/components/workspace/streaming-indicator.tsx` |
| 技能来源展示 | `frontend-web/src/core/skill-display/runtime.ts` |
| 导出 | `frontend-web/src/core/threads/export.ts`;Word:`frontend-web/src/components/workspace/messages/download-word-button.tsx` |
| 删除消息 | `frontend-web/src/components/workspace/messages/delete-message-button.tsx` |
| 问题跳转 | `frontend-web/src/components/workspace/question-navigator.tsx` |
---
## 10. 思考内容如何对接
@@ -809,6 +932,17 @@ function splitThink(content: string): { answer: string; thinking: string | null
`thinking_enabled: false` 时模型不应再吐思考;若仍出现 `<think>`,继续剥掉以免露标签。
**参考代码**
| 说明 | 路径 |
|------|------|
| 抽思考 / 剥 `<think>`(含未闭合) | `frontend-web/src/core/messages/utils.ts`(`extractReasoningContentFromMessage`、`splitInlineReasoning`) |
| 步骤条里的思考步 | `frontend-web/src/components/workspace/messages/message-group.tsx`(`convertToSteps` 的 `reasoning`) |
| 独立思考折叠块 | `frontend-web/src/components/ai-elements/reasoning.tsx` |
| 文案「思考」 | `frontend-web/src/core/i18n/locales/zh-CN.ts`(`t.common.thinking`) |
| 模型思考流字段 | `offline-backend-20260512/backend/packages/harness/deerflow/models/vllm_provider.py` |
| 关思考注入 extra_body | `offline-backend-20260512/backend/packages/harness/deerflow/models/factory.py` |
---
## 11. 步骤条(Chain of Thought)— 请做全
@@ -925,6 +1059,23 @@ interface WebFetchArgs { url: string }
字段名不统一(`content` / `page_content` / `snippet` / `m_title` / `name`),展示时做并集兜底。
**参考代码**
| 说明 | 路径 |
|------|------|
| **步骤条主实现(必看)** | `frontend-web/src/components/workspace/messages/message-group.tsx`(`convertToSteps`、按 `name` 分支、`ArtifactWriteToolCall`) |
| ChainOfThought 组件 | `frontend-web/src/components/ai-elements/chain-of-thought.tsx` |
| 中文底稿 | `frontend-web/src/core/i18n/locales/zh-CN.ts` → `toolCalls`;类型 `frontend-web/src/core/i18n/locales/types.ts` |
| 工具一句话说明 | `frontend-web/src/core/tools/utils.ts`(`explainToolCall`) |
| 检索结果卡片 | `frontend-web/src/core/messages/search-results.ts` |
| 写文件实时预览 | `frontend-web/src/core/artifacts/streaming-write-preview.ts` |
| bash / ls / read / write / glob / grep | `offline-backend-20260512/backend/packages/harness/deerflow/sandbox/tools.py`(参数都要求先填 `description`) |
| 工具装配(含 MCP、内置) | `offline-backend-20260512/backend/packages/harness/deerflow/tools/tools.py` |
| present_files | `offline-backend-20260512/backend/packages/harness/deerflow/tools/builtins/present_file_tool.py` |
| skill_list / skill_view / search_skills | `offline-backend-20260512/backend/packages/harness/deerflow/tools/builtins/skill_tools.py` |
| 启用哪些工具 | `offline-backend-20260512/backend/config.yaml` → `tools[]` |
| 会商页步骤条(对照用,对话页以 message-group 为准) | `frontend-web/src/roundtable-planning/lib/step-display.tsx` |
---
## 12. 用户协助卡片(ask_clarification)
@@ -1007,6 +1158,17 @@ input.messages = [{ type: "human", content: "<上面拼好的文本>" }]
不要调 `/state` 的 resume,也不要自己造 ToolMessage。
**参考代码**
| 说明 | 路径 |
|------|------|
| 卡片 UI、拼「我选择:」、多卡合并提交 | `frontend-web/src/components/workspace/messages/message-list.tsx`(`ClarificationCard`、`handleSubmitAllClarifications`) |
| 识别 tool 消息 | `frontend-web/src/core/messages/utils.ts`(`isClarificationToolMessage`) |
| 工具定义 | `offline-backend-20260512/backend/packages/harness/deerflow/tools/builtins/clarification_tool.py` |
| 截住工具、写 `additional_kwargs.clarification`、goto END | `offline-backend-20260512/backend/packages/harness/deerflow/agents/middlewares/clarification_middleware.py`(`_build_payload`) |
| `allow_multiple` 解析 | `offline-backend-20260512/backend/packages/harness/deerflow/tools/builtins/clarification_utils.py` |
| 提交后又走同一套 sendMessage | `frontend-web/src/pages/AgentChatPage.tsx`、`frontend-web/src/core/threads/hooks.ts`(**不是** Command resume) |
---
## 13. 其它卡片与面板
@@ -1056,6 +1218,18 @@ interface Todo { content?: string; status?: 'pending' | 'in_progress' | 'complet
`setup_agent` / `setup_writing` 带 approval kwargs。普通 `roundtable-structure` 对话 **不会出现**,可忽略。
Deep Research 的 `setup_research_approval` 同理。
**参考代码**
| 说明 | 路径 |
|------|------|
| present_files 分组渲染 | `frontend-web/src/components/workspace/messages/message-list.tsx`(`assistant:present-files`) |
| 产物 API | `offline-backend-20260512/backend/app/gateway/routers/artifacts.py` |
| 产物前端 | `frontend-web/src/components/workspace/artifacts/`(如 `artifact-file-detail.tsx`) |
| 子任务卡 | `frontend-web/src/components/workspace/messages/subtask-card.tsx` |
| `task` 工具 / 子代理 | `offline-backend-20260512/backend/packages/harness/deerflow/subagents/` |
| Todo 面板 | `frontend-web/src/components/workspace/todo-list.tsx`;类型 `frontend-web/src/core/todos/types.ts` |
| write_todos 中间件装配 | `offline-backend-20260512/backend/packages/harness/deerflow/agents/lead_agent/agent.py`(`_build_middlewares`) |
---
## 14. 标题、追问、错误态
@@ -1095,6 +1269,18 @@ POST {GATEWAY}/api/threads/{thread_id}/suggestions
| 上下文压缩 | `custom.context_compacting` | 「正在压缩上下文…」 |
| 会话不属于当前用户 | 403/404 | 回到新建 |
**参考代码**
| 说明 | 路径 |
|------|------|
| 标题展示 | `frontend-web/src/components/workspace/thread-title.tsx` |
| 列表用 title | `frontend-web/src/core/threads/utils.ts`(`titleOfThread`) |
| 临时标题 + LLM 标题 | `offline-backend-20260512/backend/packages/harness/deerflow/agents/middlewares/title_middleware.py` |
| 追问 API 调用 | `frontend-web/src/components/workspace/input-box.tsx`(`/api/threads/${threadId}/suggestions`) |
| 追问后端 | `offline-backend-20260512/backend/app/gateway/routers/suggestions.py` |
| 409 toast | `frontend-web/src/core/threads/hooks.ts`(`isActiveRunConflictError` / `onError`) |
| 压缩 toast | `offline-backend-20260512/backend/packages/harness/deerflow/agents/middlewares/summarization_middleware.py`(`custom.context_compacting`) |
---
## 15. 文件上传(用户侧)
@@ -1138,6 +1324,16 @@ PDF/PPT/Excel/Word 会转成 Markdown 一并放入 uploads。
限额:`GET /api/threads/{thread_id}/uploads/limits`。
列表/删除:`GET …/uploads/list`,`DELETE …/uploads/{filename}`。
**参考代码**
| 说明 | 路径 |
|------|------|
| 前端上传 | `frontend-web/src/components/workspace/input-box.tsx`;预览 `frontend-web/src/components/workspace/messages/uploaded-file-preview-dialog.tsx` |
| 后端上传路由 | `offline-backend-20260512/backend/app/gateway/routers/uploads.py` |
| 目录与虚拟路径 | `offline-backend-20260512/backend/packages/harness/deerflow/uploads/manager.py` |
| 文档转 Markdown | `offline-backend-20260512/backend/packages/harness/deerflow/utils/file_conversion.py` |
| 说明文档 | `offline-backend-20260512/backend/docs/FILE_UPLOAD.md` |
---
## 16. 推荐的页面结构(对标 AgentChatPage)
@@ -1162,6 +1358,20 @@ PDF/PPT/Excel/Word 会转成 Markdown 一并放入 uploads。
`roundtable-structure` 是「结构化抽取」智能体:给它方案报告或席位交付,产出 flow-json 流程图数据,常伴随写文件 + 展示文件。不要当成多智能体会商编排页(`/roundtable` 是另一套 API)。
**参考代码**
| 说明 | 路径 |
|------|------|
| 对话页整页 | `frontend-web/src/pages/AgentChatPage.tsx` |
| 路由 | `frontend-web/src/pages/WorkspaceRoutes.tsx` |
| ChatBox(标题栏 + 列表 + 输入) | `frontend-web/src/components/workspace/chats/chat-box.tsx` |
| 输入框 | `frontend-web/src/components/workspace/input-box.tsx` |
| 左栏最近会话 | `frontend-web/src/components/workspace/agents/agent-chat-sidebar.tsx`、`agent-recent-chats.tsx` |
| 欢迎/推荐问题 | `frontend-web/src/components/workspace/agent-welcome.tsx`、`agents/agent-question-chips.tsx` |
| 智能体种子 | `offline-backend-20260512/backend/app/gateway/routers/_roundtable_seed_assets/roundtable-structure/` |
| 会商编排(不要和本页搞混) | `frontend-web/src/roundtable-planning/`、`offline-backend-20260512/backend/app/gateway/routers/multi_agent.py` |
| iframe 嵌现网 UI(备选) | `frontend-web/docs/embed-iframe-chat.md` |
---
## 17. 最小对接顺序(验收清单)
@@ -1240,22 +1450,95 @@ Base:`{GATEWAY} = http://host:8001`,LangGraph `{LG} = {GATEWAY}/api`。
---
## 20. 参考实现位置(本仓库)
## 20. 参考实现总索引
| 主题 | 文件 |
路径均相对仓库根 `deerflow-server/`。后端根目录 = `offline-backend-20260512/backend/`。
各节正文末尾也有对应表;这里按主题汇总,加粗的是对接时优先打开的文件。
### 20.1 前端:页面与 UI
| 主题 | 路径 |
|------|------|
| 对话页 | `frontend-web/src/pages/AgentChatPage.tsx` |
| 发消息 / SSE | `frontend-web/src/core/threads/hooks.ts` |
| 消息分组 | `frontend-web/src/core/messages/utils.ts` |
| 步骤条 | `frontend-web/src/components/workspace/messages/message-group.tsx` |
| 协助卡片 | `frontend-web/src/components/workspace/messages/message-list.tsx` |
| 中文步骤文案 | `frontend-web/src/core/i18n/locales/zh-CN.ts` → `toolCalls` |
| 登录 | `frontend-web/src/core/auth/api.ts` |
| 模型 | `GET /api/models` ← `app/gateway/routers/models.py` |
| 会话 / 状态 | `app/gateway/routers/threads.py` |
| 流式 | `app/gateway/routers/thread_runs.py` |
| SSE 帧 | `app/gateway/services.py` `format_sse` |
| 协助卡 payload | `deerflow/agents/middlewares/clarification_middleware.py` |
| 沙箱工具 description | `deerflow/sandbox/tools.py`(bash / write_file / …) |
| **智能体对话页** | `frontend-web/src/pages/AgentChatPage.tsx` |
| 路由 `agents/:agent_id/chats/:thread_id` | `frontend-web/src/pages/WorkspaceRoutes.tsx` |
| 对话壳(标题 / 列表 / 输入 / 产物入口) | `frontend-web/src/components/workspace/chats/chat-box.tsx` |
| **消息列表 + 协助卡片** | `frontend-web/src/components/workspace/messages/message-list.tsx` |
| 用户/助手气泡 | `frontend-web/src/components/workspace/messages/message-list-item.tsx` |
| **步骤条(创建脚本/执行脚本/写入文件等)** | `frontend-web/src/components/workspace/messages/message-group.tsx` |
| Markdown | `frontend-web/src/components/workspace/messages/markdown-content.tsx` |
| 子任务卡 | `frontend-web/src/components/workspace/messages/subtask-card.tsx` |
| 思考折叠块 | `frontend-web/src/components/ai-elements/reasoning.tsx` |
| ChainOfThought 控件 | `frontend-web/src/components/ai-elements/chain-of-thought.tsx` |
| 输入框(模型、档位、发送、停止、追问、上传) | `frontend-web/src/components/workspace/input-box.tsx` |
| Todo 条 | `frontend-web/src/components/workspace/todo-list.tsx` |
| 会话标题 | `frontend-web/src/components/workspace/thread-title.tsx` |
| 正在生成 | `frontend-web/src/components/workspace/streaming-indicator.tsx` |
| 会话列表 UI | `frontend-web/src/components/workspace/workspace-nav-chat-list.tsx` |
| 该智能体最近对话 | `frontend-web/src/components/workspace/agents/agent-recent-chats.tsx` |
| 左栏 | `frontend-web/src/components/workspace/agents/agent-chat-sidebar.tsx` |
| 产物预览 | `frontend-web/src/components/workspace/artifacts/` |
| 中文步骤文案 `toolCalls.*` | `frontend-web/src/core/i18n/locales/zh-CN.ts` |
智能体种子:`offline-backend-20260512/backend/app/gateway/routers/_roundtable_seed_assets/roundtable-structure/`(`id: roundtable-structure`,`name: 结构化抽取`)。
### 20.2 前端:协议与状态
| 主题 | 路径 |
|------|------|
| **发消息 / useStream / cancel / 409** | `frontend-web/src/core/threads/hooks.ts` |
| 线程类型 | `frontend-web/src/core/threads/types.ts` |
| 标题与路由 | `frontend-web/src/core/threads/utils.ts` |
| **消息分组、思考、隐藏** | `frontend-web/src/core/messages/utils.ts` |
| 检索结果归一化 | `frontend-web/src/core/messages/search-results.ts` |
| **登录 API** | `frontend-web/src/core/auth/api.ts` |
| Bearer 存取 | `frontend-web/src/core/auth/index.ts` |
| 模型 API / 类型 | `frontend-web/src/core/models/api.ts`、`frontend-web/src/core/models/types.ts` |
| LangGraph Client | `frontend-web/src/core/api/api-client.ts` |
| Gateway fetch + 401 | `frontend-web/src/core/api/fetch-client.ts` |
| Base URL | `frontend-web/src/core/config/index.ts`、`frontend-web/src/env.ts` |
| 写文件流式预览 | `frontend-web/src/core/artifacts/streaming-write-preview.ts` |
| 工具一句话 | `frontend-web/src/core/tools/utils.ts` |
### 20.3 后端:HTTP
| 主题 | 路径 |
|------|------|
| **登录 /me** | `offline-backend-20260512/backend/app/gateway/routers/auth.py` |
| JWT | `offline-backend-20260512/backend/app/gateway/auth/jwt.py` |
| **CORS** | `offline-backend-20260512/backend/app/gateway/app.py` |
| 鉴权中间件 | `offline-backend-20260512/backend/app/gateway/auth_middleware.py` |
| **模型列表** | `offline-backend-20260512/backend/app/gateway/routers/models.py` |
| **会话 CRUD / search / state** | `offline-backend-20260512/backend/app/gateway/routers/threads.py` |
| **runs/stream / cancel / join** | `offline-backend-20260512/backend/app/gateway/routers/thread_runs.py` |
| start_run、SSE、context 白名单 | `offline-backend-20260512/backend/app/gateway/services.py` |
| 上传 | `offline-backend-20260512/backend/app/gateway/routers/uploads.py` |
| 产物 | `offline-backend-20260512/backend/app/gateway/routers/artifacts.py` |
| 追问 | `offline-backend-20260512/backend/app/gateway/routers/suggestions.py` |
| 简化开放聊天(不要用来复刻本页) | `offline-backend-20260512/backend/app/gateway/routers/open_chat.py` |
### 20.4 后端:运行时与工具
| 主题 | 路径 |
|------|------|
| **跑图 + 发 SSE 事件** | `offline-backend-20260512/backend/packages/harness/deerflow/runtime/runs/worker.py` |
| RunManager | `offline-backend-20260512/backend/packages/harness/deerflow/runtime/runs/manager.py` |
| StreamBridge | `offline-backend-20260512/backend/packages/harness/deerflow/runtime/stream_bridge.py` |
| 消息序列化 | `offline-backend-20260512/backend/packages/harness/deerflow/runtime/serialization.py` |
| Lead Agent | `offline-backend-20260512/backend/packages/harness/deerflow/agents/lead_agent/agent.py` |
| **协助卡中间件** | `offline-backend-20260512/backend/packages/harness/deerflow/agents/middlewares/clarification_middleware.py` |
| 协助工具 | `offline-backend-20260512/backend/packages/harness/deerflow/tools/builtins/clarification_tool.py` |
| **bash / write_file 等(description)** | `offline-backend-20260512/backend/packages/harness/deerflow/sandbox/tools.py` |
| 工具总装 | `offline-backend-20260512/backend/packages/harness/deerflow/tools/tools.py` |
| present_files | `offline-backend-20260512/backend/packages/harness/deerflow/tools/builtins/present_file_tool.py` |
| 标题 | `offline-backend-20260512/backend/packages/harness/deerflow/agents/middlewares/title_middleware.py` |
| 模型工厂 | `offline-backend-20260512/backend/packages/harness/deerflow/models/factory.py` |
### 20.5 配置、种子、文档
| 主题 | 路径 |
|------|------|
| **roundtable-structure 种子** | `offline-backend-20260512/backend/app/gateway/routers/_roundtable_seed_assets/roundtable-structure/config.yaml` |
| 同上 SOUL | `offline-backend-20260512/backend/app/gateway/routers/_roundtable_seed_assets/roundtable-structure/SOUL.md` |
| 模型 / 工具开关 | `offline-backend-20260512/backend/config.yaml` |
| 流式协议 | `offline-backend-20260512/backend/docs/STREAMING.md` |
| 登录契约 | `offline-backend-20260512/backend/docs/AUTH_LOGIN.md` |
| 上传 | `offline-backend-20260512/backend/docs/FILE_UPLOAD.md` |
| iframe 嵌入备选 | `frontend-web/docs/embed-iframe-chat.md` |