模型
-
setModelInput(event.currentTarget.value)}
disabled={isModelsLoading}
+ className="border-input bg-background h-9 w-full rounded-md border px-3 text-sm shadow-xs outline-none"
>
-
-
-
-
- {models.map((model) => (
-
- {model.display_name || model.name}
-
- ))}
-
-
+
+ 选择模型
+
+ {models.map((model) => (
+
+ {model.display_name || model.name}
+
+ ))}
+
该专家被使用时调用的模型。
diff --git a/frontend-web/src/pages/PageRoutes.tsx b/frontend-web/src/pages/PageRoutes.tsx
index 1d252412..cd21afd7 100644
--- a/frontend-web/src/pages/PageRoutes.tsx
+++ b/frontend-web/src/pages/PageRoutes.tsx
@@ -8,7 +8,7 @@ import StrategyRoutes from "./StrategyRoutes";
import Header from "@/strategy-components/Header";
// 设为 true 时隐藏侧边栏(开发中,暂未完成)
-const SIDEBAR_ENABLED = false;
+const SIDEBAR_ENABLED = true;
function PageLayout() {
const [collapsed, setCollapsed] = useState(false);
diff --git a/frontend-web/src/pages/StrategyRoutes.tsx b/frontend-web/src/pages/StrategyRoutes.tsx
index 54941cdd..42eadc32 100644
--- a/frontend-web/src/pages/StrategyRoutes.tsx
+++ b/frontend-web/src/pages/StrategyRoutes.tsx
@@ -1,14 +1,12 @@
import { Navigate, Route, Routes } from "react-router-dom";
-import type { ReactNode } from "react";
import { Toaster } from "sonner";
import { getStoredAuth } from "@/core/auth";
import { RouteBaseProvider } from "@/core/route-base";
-import { SubtasksProvider } from "@/core/tasks/context";
-import { ArtifactsProvider } from "@/components/workspace/artifacts";
-import { PromptInputProvider } from "@/components/ai-elements/prompt-input";
+import { SidebarProvider } from "@/components/ui/sidebar";
import GeneralQA from "@/strategy-components/components/qa/GeneralQA";
+import { ChatRuntime } from "./WorkspaceRoutes";
import AgentsPage from "./AgentsPage";
import ChatsPage from "./ChatsPage";
import ChatPage from "./ChatPage";
@@ -18,19 +16,10 @@ import ScheduledTasksPage from "./ScheduledTasksPage";
import ScheduledTaskRunDetailPage from "./ScheduledTaskRunDetailPage";
import RecommendedQuestionsPage from "./RecommendedQuestionsPage";
-function ChatRuntime({ children }: { children: ReactNode }) {
- return (
-
-
- {children}
-
-
- );
-}
-
export default function StrategyRoutes() {
return (
+
} />
@@ -89,6 +78,7 @@ export default function StrategyRoutes() {
/>
+
);
diff --git a/frontend-web/src/pages/WorkspaceRoutes.tsx b/frontend-web/src/pages/WorkspaceRoutes.tsx
index 4357ae5c..5d0ec5c0 100644
--- a/frontend-web/src/pages/WorkspaceRoutes.tsx
+++ b/frontend-web/src/pages/WorkspaceRoutes.tsx
@@ -61,7 +61,7 @@ export function WorkspaceLayout({
);
}
-function ChatRuntime({ children }: { children: ReactNode }) {
+export function ChatRuntime({ children }: { children: ReactNode }) {
return (
From 1ce1db9689e4ee415017d345b8f2559ae115d705 Mon Sep 17 00:00:00 2001
From: fengxiangdebaozi <10845145+fengxiangdebaozi@user.noreply.gitee.com>
Date: Thu, 14 May 2026 19:28:07 +0800
Subject: [PATCH 2/3] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E5=A4=84=E7=90=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
frontend-web/src/pages/PageRoutes.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frontend-web/src/pages/PageRoutes.tsx b/frontend-web/src/pages/PageRoutes.tsx
index cd21afd7..1d252412 100644
--- a/frontend-web/src/pages/PageRoutes.tsx
+++ b/frontend-web/src/pages/PageRoutes.tsx
@@ -8,7 +8,7 @@ import StrategyRoutes from "./StrategyRoutes";
import Header from "@/strategy-components/Header";
// 设为 true 时隐藏侧边栏(开发中,暂未完成)
-const SIDEBAR_ENABLED = true;
+const SIDEBAR_ENABLED = false;
function PageLayout() {
const [collapsed, setCollapsed] = useState(false);
From a0d04cba504f34775dc2b37071d30104b667545f Mon Sep 17 00:00:00 2001
From: fengxiangdebaozi <10845145+fengxiangdebaozi@user.noreply.gitee.com>
Date: Fri, 15 May 2026 10:42:44 +0800
Subject: [PATCH 3/3] =?UTF-8?q?=E6=96=87=E6=A1=A3=E4=BF=AE=E6=94=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../docs/openCanvas-backend-checklist.md | 1031 +++++++++++++
.../docs/openCanvas-frontend-checklist.md | 1373 +++++++++++++++++
frontend-web/docs/openCanvas.md | 950 ++++++++++++
3 files changed, 3354 insertions(+)
create mode 100644 frontend-web/docs/openCanvas-backend-checklist.md
create mode 100644 frontend-web/docs/openCanvas-frontend-checklist.md
create mode 100644 frontend-web/docs/openCanvas.md
diff --git a/frontend-web/docs/openCanvas-backend-checklist.md b/frontend-web/docs/openCanvas-backend-checklist.md
new file mode 100644
index 00000000..31152fbe
--- /dev/null
+++ b/frontend-web/docs/openCanvas-backend-checklist.md
@@ -0,0 +1,1031 @@
+# Open Canvas 后端实施清单
+
+## 1. 文档目标
+
+本文档是 [openCanvas.md](./openCanvas.md) 的后端落地版清单。
+
+目标是把 Canvas 模式在当前 DeerFlow 后端中的实施工作拆成可以直接排期和执行的任务,覆盖:
+
+- 线程状态扩展
+- `canvas_agent` 设计
+- LangGraph 节点拆分
+- Gateway API 扩展
+- 流式输出契约
+- 模型配置与本地模型支持
+- 结构化 artifact 的持久化
+- 测试与验收顺序
+
+本文档默认前端会新增独立的 Canvas 子系统,并通过现有 LangGraph 线程和 Gateway API 与后端通信。
+
+---
+
+## 2. 实施原则
+
+### 2.1 总原则
+
+- 不破坏现有 `lead_agent`
+- 不破坏现有 `artifacts: list[str]` 文件产物体系
+- 优先增量扩展,不做推倒重构
+- 先打通状态和协议,再实现复杂 AI 行为
+- 先支持文本/代码双类型,再逐步扩展快捷动作
+
+### 2.2 推荐路线
+
+推荐采用“新增独立 `canvas_agent`”方案,而不是把所有 Canvas 行为塞进现有 `lead_agent`。
+
+推荐原因:
+
+- 风险更低
+- 图逻辑更清晰
+- 更容易对齐 open-canvas 的状态结构
+- 不影响现有 DeerFlow 普通聊天与文件产物模式
+
+### 2.3 后端目标边界
+
+本次后端实施重点是:
+
+- 新增 Canvas 专用线程状态字段
+- 新增 Canvas Agent 图
+- 新增前端需要的模型能力元数据
+- 支持结构化 artifact 在线程状态中读写
+
+本次不要求:
+
+- 完整复刻 open-canvas 的所有 TS 图结构
+- 完整复刻 Supabase 相关逻辑
+- 把所有模型 provider 完全抽象成统一能力中台
+
+---
+
+## 3. 现有后端基础能力盘点
+
+当前 DeerFlow 后端已经具备非常好的基础设施:
+
+- LangGraph 线程与流式交互
+- FastAPI Gateway
+- 模型动态配置
+- 本地线程状态管理
+- Sandbox/工具体系
+- 上传与文件 artifact 访问
+- Memory 与标题生成
+
+因此 Canvas 模式并不是“从 0 开始做 Agent 平台”,而是“在现有平台上新增一类结构化创作模式”。
+
+---
+
+## 4. 目标代码落点
+
+建议优先关注以下目录:
+
+```text
+offline-backend-20260512/backend/
+ app/gateway/
+ routers/
+ deps.py
+ app.py
+ packages/harness/deerflow/
+ agents/
+ factory.py
+ thread_state.py
+ lead_agent/
+ middlewares/
+ runtime/
+ config/
+ tools/
+```
+
+建议为 Canvas 新增或扩展以下区域:
+
+```text
+packages/harness/deerflow/
+ agents/
+ canvas_agent/
+ __init__.py
+ agent.py
+ prompt.py
+ state.py
+ nodes/
+ route_user_intent.py
+ generate_artifact.py
+ rewrite_artifact.py
+ update_highlighted_text.py
+ update_highlighted_code.py
+ generate_followup.py
+ quick_actions.py
+ web_search.py
+```
+
+如果不想把节点拆得太细,首版也可以把部分逻辑先收在 `agent.py` 里,但建议至少把 `state.py` 和 `prompt.py` 独立出来。
+
+---
+
+## 5. 开发阶段总览
+
+后端建议分为 11 个阶段:
+
+1. 线程状态扩展
+2. 结构化 artifact 协议定义
+3. `canvas_agent` 接入到 Agent 工厂
+4. Canvas 图的最小节点实现
+5. Gateway/线程接口兼容
+6. 流式状态输出适配
+7. 模型能力元数据扩展
+8. 本地模型兼容与配置统一
+9. 快捷动作与局部改写
+10. Web 搜索增强
+11. 测试、回归、验收
+
+---
+
+## 6. 阶段一:线程状态扩展
+
+### 6.1 任务目标
+
+让 DeerFlow 的线程状态能原生保存 Canvas 所需的结构化信息。
+
+### 6.2 任务清单
+
+- 扩展 [thread_state.py](../../offline-backend-20260512/backend/packages/harness/deerflow/agents/thread_state.py)
+- 定义 Canvas 相关 TypedDict 或 dataclass 结构
+- 确保状态字段可序列化
+- 不影响现有 `messages/title/artifacts/todos` 逻辑
+
+### 6.3 建议新增字段
+
+在现有 `ThreadState` 上新增:
+
+- `artifact`
+- `highlighted_text`
+- `highlighted_code`
+- `canvas_mode`
+- `quick_action_id`
+- `web_search_enabled`
+- `web_search_results`
+
+### 6.4 建议数据形态
+
+可先采用 JSON-safe dict 结构,而不是在状态层引入过重的复杂对象。
+
+建议:
+
+```python
+class CanvasArtifactText(TypedDict):
+ index: int
+ type: Literal["text"]
+ title: str
+ fullMarkdown: str
+
+class CanvasArtifactCode(TypedDict):
+ index: int
+ type: Literal["code"]
+ title: str
+ language: str
+ code: str
+
+class CanvasArtifact(TypedDict):
+ currentIndex: int
+ contents: list[CanvasArtifactText | CanvasArtifactCode]
+```
+
+### 6.5 与现有 `artifacts` 的关系
+
+必须保留现有:
+
+- `artifacts: list[str]`
+
+新增:
+
+- `artifact: dict | None`
+
+含义区分:
+
+- `artifacts` 表示文件型产物列表
+- `artifact` 表示 Canvas 当前主文档
+
+### 6.6 验收标准
+
+- 旧线程无 `artifact` 时不报错
+- 新线程可写入 `artifact`
+- 线程状态能被 FastAPI 和 LangGraph 正确序列化
+
+---
+
+## 7. 阶段二:结构化 Artifact 协议定义
+
+### 7.1 任务目标
+
+统一前后端对 Canvas artifact 的字段约定。
+
+### 7.2 任务清单
+
+- 在后端建立一份明确的 artifact 协议定义
+- 明确字段命名、类型、兼容策略
+- 明确版本管理规则
+
+### 7.3 协议要求
+
+必须支持:
+
+- 文本 artifact
+- 代码 artifact
+- 标题
+- 当前版本索引
+- 历史版本列表
+- 后续支持局部改写
+
+### 7.4 版本规则
+
+- 每次 AI 整体生成,生成 `contents[0]`
+- 每次 AI 重写,追加一个新版本
+- `currentIndex` 指向当前版本
+- 历史版本默认只保留在线程状态中,不额外落库
+
+### 7.5 建议约束
+
+- `index` 从 1 开始
+- `currentIndex` 必须落在 `contents` 范围内
+- `type` 只允许 `"text"` 或 `"code"`
+
+### 7.6 验收标准
+
+- 前后端字段完全一致
+- 状态协议有明确默认值和边界规则
+
+---
+
+## 8. 阶段三:接入 `canvas_agent`
+
+### 8.1 任务目标
+
+在现有 Agent 体系中注册一个独立的 Canvas Agent。
+
+### 8.2 任务清单
+
+- 新建 `packages/harness/deerflow/agents/canvas_agent/`
+- 新建 `agent.py`
+- 新建 `prompt.py`
+- 新建 `state.py`
+- 修改 [factory.py](../../offline-backend-20260512/backend/packages/harness/deerflow/agents/factory.py)
+
+### 8.3 注册方式建议
+
+建议将 `canvas_agent` 作为一个显式 assistant id 暴露给 LangGraph 运行时。
+
+前端调用时:
+
+- `assistant_id=canvas_agent`
+
+### 8.4 Agent 设计原则
+
+- Canvas Agent 不负责 DeerFlow 全部工具生态
+- 首版专注于:
+ - 生成文档
+ - 重写文档
+ - 局部改写
+ - 跟进回复
+
+### 8.5 工具策略
+
+首版建议:
+
+- 不强依赖 shell/sandbox
+- 不强依赖 present_files
+- 先把生成与改写链路做好
+
+后续可以根据需要接入文件导出能力。
+
+### 8.6 验收标准
+
+- `canvas_agent` 可被识别
+- 前端能以 assistant id 调用它
+- 不影响 `lead_agent`
+
+---
+
+## 9. 阶段四:Canvas 状态与图定义
+
+### 9.1 任务目标
+
+为 Canvas Agent 定义清晰、最小但可扩展的状态结构。
+
+### 9.2 任务清单
+
+- 新建 `canvas_agent/state.py`
+- 定义图状态
+- 约束与 `ThreadState` 的映射方式
+
+### 9.3 建议状态字段
+
+- `messages`
+- `_messages` 或等价内部消息
+- `artifact`
+- `highlighted_text`
+- `highlighted_code`
+- `quick_action_id`
+- `web_search_enabled`
+- `web_search_results`
+- `next`
+
+### 9.4 状态设计建议
+
+优先复用 LangGraph 原生消息 reducer。
+
+对结构化字段,尽量采用:
+
+- 可整体替换
+- 易序列化
+- 无 Python 特殊对象依赖
+
+### 9.5 验收标准
+
+- 状态能驱动 Canvas 节点运行
+- 状态可被序列化回线程
+
+---
+
+## 10. 阶段五:Canvas 图最小节点闭环
+
+### 10.1 任务目标
+
+先实现最小闭环,不要一开始就追求 open-canvas 全量功能。
+
+### 10.2 首版最小节点
+
+建议至少实现:
+
+- `route_user_intent`
+- `reply_general_input`
+- `generate_artifact`
+- `rewrite_artifact`
+- `generate_followup`
+
+### 10.3 节点职责
+
+#### `route_user_intent`
+
+判断用户当前意图:
+
+- 普通聊天
+- 新建 artifact
+- 重写当前 artifact
+
+#### `reply_general_input`
+
+仅返回普通消息,不更新 artifact。
+
+#### `generate_artifact`
+
+根据用户需求生成第一版 artifact。
+
+#### `rewrite_artifact`
+
+根据当前 artifact 和用户请求生成新版本。
+
+#### `generate_followup`
+
+在 artifact 更新后补一条自然语言消息。
+
+### 10.4 输出要求
+
+必须至少更新:
+
+- `messages`
+- `artifact`
+
+### 10.5 验收标准
+
+- 无 artifact 时能生成新 artifact
+- 有 artifact 时能整体重写
+- 重写后版本数增加
+
+---
+
+## 11. 阶段六:Prompt 设计与模型调用封装
+
+### 11.1 任务目标
+
+把 Canvas 模式的 prompt 和模型调用逻辑集中管理。
+
+### 11.2 任务清单
+
+- 在 `canvas_agent/prompt.py` 中集中定义 prompt 常量
+- 在 `canvas_agent/agent.py` 或节点工具模块中封装模型调用
+
+### 11.3 最少需要的 prompt
+
+- 新建 artifact prompt
+- 整体重写 artifact prompt
+- 路由判断 prompt
+- followup prompt
+
+### 11.4 设计建议
+
+提示词必须显式约束:
+
+- 输出完整文档还是局部片段
+- 是否允许修改类型
+- 是否允许修改标题
+- 对文本和代码的输出格式要求
+
+### 11.5 模型调用封装建议
+
+不要在每个节点里重复拼模型配置。
+
+建议提供统一函数:
+
+- `get_canvas_model(...)`
+- `invoke_canvas_model(...)`
+
+### 11.6 验收标准
+
+- prompt 集中管理
+- 节点中模型调用逻辑可复用
+
+---
+
+## 12. 阶段七:Gateway 线程接口兼容
+
+### 12.1 任务目标
+
+让前端读取线程状态时能拿到结构化 `artifact`。
+
+### 12.2 任务清单
+
+- 检查 [threads.py](../../offline-backend-20260512/backend/app/gateway/routers/threads.py)
+- 扩展线程 state 响应的 `values`
+- 确保 `artifact` 字段会被安全返回
+
+### 12.3 要求
+
+- `GET /api/threads/{id}`
+- 线程历史
+- 状态读取接口
+
+都要兼容 `artifact`
+
+### 12.4 注意事项
+
+- 历史 checkpoint 可能没有 `artifact`
+- 旧线程必须兼容
+- 结构化字段不能被错误裁剪
+
+### 12.5 验收标准
+
+- 前端取线程时能拿到 `artifact`
+- 刷新页面后 Canvas 内容能恢复
+
+---
+
+## 13. 阶段八:流式输出适配
+
+### 13.1 任务目标
+
+让 Canvas 模式的 artifact 能通过 LangGraph 流实时更新。
+
+### 13.2 任务清单
+
+- 检查运行时序列化逻辑
+- 确保 `artifact` 在流事件中可见
+- 明确前端消费 `values` 还是 `updates`
+
+### 13.3 输出建议
+
+首版允许采用较简单策略:
+
+- 每次节点完成后输出完整 `artifact`
+
+不强制首版做精细的 token 级 artifact 局部流。
+
+### 13.4 原因
+
+完整对象覆盖更新:
+
+- 容易实现
+- 容易调试
+- 前后端一致性更好
+
+### 13.5 二期方向
+
+后续再考虑:
+
+- 局部 chunk 更新
+- 文本与代码差异化流式拼接
+
+### 13.6 验收标准
+
+- 前端发送请求时,artifact 能跟随 run 更新
+- 流结束后状态与线程最终值一致
+
+---
+
+## 14. 阶段九:模型接口扩展
+
+### 14.1 任务目标
+
+让前端能拿到适合 Canvas 模式的模型能力信息。
+
+### 14.2 任务清单
+
+- 扩展 [models.py](../../offline-backend-20260512/backend/app/gateway/routers/models.py)
+- 扩展模型响应结构
+
+### 14.3 现有字段之外建议新增
+
+- `provider`
+- `supports_vision`
+- `supports_tool_calling`
+- `supports_canvas_generation`
+- `supports_canvas_rewrite`
+- `supports_canvas_code_edit`
+- `supports_streaming_text`
+- `supports_streaming_tool_calls`
+- `is_local`
+- `base_url`
+
+### 14.4 注意事项
+
+不是所有字段都必须从配置文件显式写出。
+
+可以采用:
+
+- 配置直出
+- provider 推断
+- 默认值补齐
+
+### 14.5 验收标准
+
+- 前端模型选择器能获取足够元数据
+- 本地模型和云模型能区分
+
+---
+
+## 15. 阶段十:本地模型支持与配置统一
+
+### 15.1 任务目标
+
+支持像 open-canvas 一样自由配置本地模型,但配置真源在 DeerFlow。
+
+### 15.2 原则
+
+- 以 `config.yaml` 为唯一真源
+- 前端不依赖 open-canvas 的 TS 模型表
+- 后端负责把配置转换成前端可消费的能力描述
+
+### 15.3 首批支持范围
+
+推荐先支持:
+
+- Ollama
+- OpenAI-compatible 本地服务
+
+例如:
+
+- LM Studio
+- vLLM
+- LocalAI
+- One API/OpenAI 兼容代理
+
+### 15.4 配置要求
+
+建议模型配置支持以下字段:
+
+- `name`
+- `display_name`
+- `use`
+- `model`
+- `api_key`
+- `base_url`
+- `supports_vision`
+- `supports_thinking`
+- `supports_reasoning_effort`
+- `supports_tool_calling`
+- `is_local`
+
+### 15.5 Canvas 额外能力字段
+
+建议再增加:
+
+- `supports_canvas_generation`
+- `supports_canvas_rewrite`
+- `supports_canvas_code_edit`
+
+### 15.6 验收标准
+
+- 配置本地模型后 `/api/models` 可见
+- `canvas_agent` 可调用本地模型
+- 至少文本生成和整体改写可用
+
+---
+
+## 16. 阶段十一:整体重写节点完善
+
+### 16.1 任务目标
+
+让已有 artifact 能被稳定整体重写并产生新版本。
+
+### 16.2 任务清单
+
+- 实现 `rewrite_artifact`
+- 明确文本与代码两种重写路径
+- 维护标题和类型变更规则
+
+### 16.3 规则建议
+
+- 默认保持当前类型
+- 用户明确要求时才允许改类型
+- 默认保持标题
+- 用户明确换主题时可更新标题
+
+### 16.4 结果写入规则
+
+- 新版本追加到 `contents`
+- `currentIndex` 指向新版本
+
+### 16.5 验收标准
+
+- 文本 artifact 整体重写正常
+- 代码 artifact 整体重写正常
+- 历史版本保留
+
+---
+
+## 17. 阶段十二:局部改写节点
+
+### 17.1 任务目标
+
+支持文本和代码的局部选区修改。
+
+### 17.2 任务清单
+
+- 新增 `update_highlighted_text.py`
+- 新增 `update_highlighted_code.py`
+- 在状态中消费选区信息
+
+### 17.3 文本局部改写要求
+
+输入:
+
+- 当前 `fullMarkdown`
+- 选区起止
+- 选中原文
+- 用户修改指令
+
+输出:
+
+- 只返回替换片段或返回完整合并后文本
+
+### 17.4 首版建议
+
+首版优先采用“后端返回完整合并后文本”策略。
+
+原因:
+
+- 前端逻辑更轻
+- 状态更一致
+
+### 17.5 代码局部改写要求
+
+输入:
+
+- 当前代码全文
+- 选区代码片段
+- 选区边界
+- 用户修改指令
+
+输出:
+
+- 新的完整代码文本
+
+### 17.6 验收标准
+
+- 文本局部改写成功
+- 代码局部改写成功
+- 未选中区域不被误改
+
+---
+
+## 18. 阶段十三:快捷动作节点
+
+### 18.1 任务目标
+
+支持前端动作栏触发不同的重写行为。
+
+### 18.2 任务清单
+
+- 新增 `quick_actions.py`
+- 定义动作 id 到 prompt 的映射
+- 在路由节点中识别 `quick_action_id`
+
+### 18.3 首版动作建议
+
+文本:
+
+- `expand`
+- `shorten`
+- `formalize`
+- `casualize`
+
+代码:
+
+- `add_comments`
+- `add_logs`
+- `fix_bugs`
+
+### 18.4 实现建议
+
+动作不要散落在各节点里硬编码。
+
+建议集中成映射表:
+
+- `action_id -> prompt builder`
+
+### 18.5 验收标准
+
+- 指定动作可触发不同结果
+- 动作执行后生成新版本
+
+---
+
+## 19. 阶段十四:Web 搜索增强
+
+### 19.1 任务目标
+
+支持 Canvas 模式在需要时引入搜索结果。
+
+### 19.2 任务清单
+
+- 新增 `web_search.py`
+- 消费 `web_search_enabled`
+- 将搜索结果写入 `web_search_results`
+
+### 19.3 首版策略
+
+首版只做:
+
+- 打开开关后,生成/重写前先搜索
+- 把结果摘要注入 prompt
+
+先不做复杂页面抓取多轮链路。
+
+### 19.4 验收标准
+
+- 开关打开时能引入搜索结果
+- 结果可回传前端展示
+
+---
+
+## 20. 阶段十五:线程创建与 metadata 策略
+
+### 20.1 任务目标
+
+让 Canvas 线程在创建和恢复时保留必要上下文。
+
+### 20.2 任务清单
+
+- 约定前端创建 Canvas thread 时写入 metadata
+- 后端在 thread search / get 中保留这些 metadata
+
+### 20.3 推荐 metadata
+
+- `ui_mode: "canvas"`
+- `agent_id: "canvas_agent"`
+- `model_name`
+- `canvas_type` 可选
+
+### 20.4 验收标准
+
+- Canvas thread 与普通 thread 可区分
+- 恢复线程时前端可据 metadata 恢复 UI
+
+---
+
+## 21. 阶段十六:Gateway 扩展接口评估
+
+### 21.1 任务目标
+
+判断是否需要新增 Canvas 专用 REST API。
+
+### 21.2 原则
+
+能复用现有线程状态与 LangGraph 流,就不要新增太多新接口。
+
+### 21.3 可以先不新增的接口
+
+- Canvas artifact 专用 CRUD
+- Canvas 快捷动作专用接口
+
+这些都可以先通过:
+
+- 线程 state
+- runs.stream
+
+完成。
+
+### 21.4 可能需要新增的接口
+
+二期如果需要,可增加:
+
+- `GET /api/canvas/models`
+- `POST /api/canvas/export`
+- `POST /api/canvas/convert-to-file`
+
+### 21.5 验收标准
+
+- 首版尽量少增接口
+- 协议尽量复用现有线程与 run 模型
+
+---
+
+## 22. 阶段十七:持久化与导出联动
+
+### 22.1 任务目标
+
+让 Canvas 文档能和现有文件 artifact 体系联动。
+
+### 22.2 任务清单
+
+- 规划导出接口
+- 规划 artifact 转文件逻辑
+- 规划从 Canvas 生成 outputs 文件
+
+### 22.3 推荐能力
+
+- 保存为 `.md`
+- 保存为代码文件
+- 将导出文件加入现有 `artifacts: list[str]`
+
+### 22.4 首版建议
+
+这部分不是最早阶段必须做的。
+
+建议等核心 Canvas 生成与重写稳定后再接。
+
+### 22.5 验收标准
+
+- 导出文件能出现在现有 artifact 文件体系中
+
+---
+
+## 23. 测试清单
+
+### 23.1 单元测试建议
+
+优先覆盖:
+
+- artifact 协议校验
+- 版本追加逻辑
+- 标题/类型变更规则
+- 文本局部改写拼接逻辑
+- 代码局部改写拼接逻辑
+
+### 23.2 集成测试建议
+
+应覆盖:
+
+- 创建 Canvas thread
+- 首次生成 artifact
+- 整体重写
+- 局部改写
+- 模型切换
+- 本地模型调用
+
+### 23.3 回归测试重点
+
+重点检查现有功能未被破坏:
+
+- 普通 `lead_agent` 对话
+- 文件型 `artifacts`
+- uploads
+- memory
+- scheduled tasks
+
+### 23.4 验收标准
+
+- Canvas 新功能通过
+- 现有 DeerFlow 核心路径无回归
+
+---
+
+## 24. 推荐开发顺序
+
+强烈建议按以下顺序推进:
+
+1. 线程状态扩展
+2. artifact 协议定稿
+3. `canvas_agent` 注册
+4. 最小图闭环
+5. 线程读取与流式返回
+6. 模型接口扩展
+7. 整体生成与整体改写
+8. 局部改写
+9. 快捷动作
+10. 本地模型增强
+11. Web 搜索增强
+12. 导出联动
+
+不要一开始就做:
+
+- 快捷动作全集
+- 局部 token 级流式 artifact 更新
+- 复杂导出体系
+
+---
+
+## 25. 多人协作拆分建议
+
+### A 组:状态与线程
+
+- `thread_state.py`
+- 线程协议
+- Gateway 线程兼容
+
+### B 组:Canvas Agent 图
+
+- `canvas_agent`
+- prompt
+- route/generate/rewrite/followup
+
+### C 组:模型与配置
+
+- `/api/models`
+- 本地模型配置
+- provider 兼容
+
+### D 组:增强能力
+
+- 局部改写
+- 快捷动作
+- Web 搜索
+
+---
+
+## 26. 首版最小可交付范围
+
+后端首版建议只交付这些:
+
+- 扩展线程状态支持 `artifact`
+- 新增 `canvas_agent`
+- 支持文本/代码 artifact 首次生成
+- 支持整体重写
+- 支持版本历史
+- 扩展 `/api/models` 返回 Canvas 能力元数据
+- 支持至少一种本地模型接入
+
+首版先不强制:
+
+- 局部高亮改写
+- 全量快捷动作
+- 搜索增强
+- 导出文件联动
+
+---
+
+## 27. 总验收标准
+
+### 27.1 功能层
+
+- 无 artifact 时可生成新文档
+- 有 artifact 时可整体重写
+- 版本历史可保留
+- 前端刷新后可恢复
+
+### 27.2 协议层
+
+- `artifact` 字段稳定
+- 流式与最终线程状态一致
+- 模型能力字段可用于前端判断
+
+### 27.3 兼容层
+
+- 不破坏 `lead_agent`
+- 不破坏现有 `artifacts: list[str]`
+- 不破坏现有 Gateway 核心接口
+
+---
+
+## 28. 下一步建议
+
+完成本文档后,建议继续补两份工程文档:
+
+### 28.1 Canvas 状态协议文档
+
+明确:
+
+- `artifact`
+- `highlighted_text`
+- `highlighted_code`
+- `quick_action_id`
+- `web_search_results`
+
+的最终 JSON 格式。
+
+### 28.2 Canvas Agent 节点接口文档
+
+逐节点定义:
+
+- 输入字段
+- 输出字段
+- prompt 责任
+- 错误处理
+
+这样进入实际编码时会更顺畅。
diff --git a/frontend-web/docs/openCanvas-frontend-checklist.md b/frontend-web/docs/openCanvas-frontend-checklist.md
new file mode 100644
index 00000000..26a47ae8
--- /dev/null
+++ b/frontend-web/docs/openCanvas-frontend-checklist.md
@@ -0,0 +1,1373 @@
+# Open Canvas 前端实施清单
+
+## 1. 文档目标
+
+本文档是 [openCanvas.md](./openCanvas.md) 的前端落地版清单。
+
+目标是把 Canvas 模式拆成可以直接开发的前端任务,覆盖:
+
+- 路由接入
+- 目录结构
+- 页面布局
+- 状态管理
+- 组件拆分
+- 接口适配
+- 流式更新
+- 版本管理
+- 局部改写
+- 模型选择
+- 验收标准
+
+本文档默认后端会配合新增结构化 `artifact` 字段与 `canvas_agent`。
+
+---
+
+## 2. 实施原则
+
+### 2.1 总原则
+
+- 不破坏现有 `workspace` 聊天页面
+- 尽量复用现有基础设施
+- 先做骨架,再接数据,再接智能行为
+- 每一步都能跑、能看、能验收
+
+### 2.2 可复用的现有能力
+
+当前项目前端已有以下基础设施,可尽量复用:
+
+- `react-router-dom` 路由体系
+- `WorkspaceLayout` 工作区布局
+- `@langchain/langgraph-sdk` 客户端
+- `useThreadStream` 的流式线程模式
+- 模型列表接口 `/api/models`
+- 现有认证头注入机制
+- `sonner` 提示
+- `react-resizable-panels` 双栏/拖拽布局
+- `CodeMirror` 代码编辑器
+
+### 2.3 新增能力的边界
+
+Canvas 模式前端是一个“新子系统”,但不建议做成完全独立的第二套应用。
+
+建议方式:
+
+- 复用现有壳层和 API 客户端
+- 新建 `src/open-canvas` 目录承载新功能
+- 将 Canvas 模式接到现有 Page 层路由里
+
+---
+
+## 3. 目标目录结构
+
+建议新增如下目录:
+
+```text
+frontend-web/src/open-canvas/
+ api/
+ client.ts
+ models.ts
+ threads.ts
+ runs.ts
+ components/
+ layout/
+ CanvasShell.tsx
+ CanvasHeader.tsx
+ CanvasResizableLayout.tsx
+ chat/
+ CanvasChatPanel.tsx
+ CanvasMessageList.tsx
+ CanvasInputBox.tsx
+ CanvasWelcome.tsx
+ artifact/
+ CanvasArtifactPanel.tsx
+ CanvasArtifactRenderer.tsx
+ CanvasArtifactHeader.tsx
+ CanvasArtifactVersionNav.tsx
+ CanvasEmptyState.tsx
+ TextArtifactRenderer.tsx
+ CodeArtifactRenderer.tsx
+ selectors/
+ CanvasModelSelector.tsx
+ CanvasModeSelector.tsx
+ quick-actions/
+ QuickActionBar.tsx
+ QuickActionButton.tsx
+ web-search/
+ CanvasWebSearchPanel.tsx
+ contexts/
+ CanvasThreadContext.tsx
+ CanvasGraphContext.tsx
+ CanvasUIContext.tsx
+ hooks/
+ useCanvasThread.ts
+ useCanvasStream.ts
+ useCanvasArtifact.ts
+ useCanvasSelection.ts
+ useCanvasQuickActions.ts
+ pages/
+ CanvasHomePage.tsx
+ CanvasThreadPage.tsx
+ routes/
+ OpenCanvasRoutes.tsx
+ types/
+ artifact.ts
+ thread.ts
+ model.ts
+ selection.ts
+ quick-action.ts
+ utils/
+ artifact.ts
+ selection.ts
+ thread.ts
+ stream.ts
+ quick-actions.ts
+ constants/
+ index.ts
+```
+
+---
+
+## 4. 开发阶段总览
+
+前端建议分为 10 个实施阶段:
+
+1. 路由与目录骨架
+2. Canvas 页面布局
+3. 类型与状态协议
+4. API 适配层
+5. 线程和流式状态接入
+6. Artifact 渲染与版本管理
+7. 快速开始与空状态
+8. 局部选区改写交互
+9. 快捷动作系统
+10. 模型选择与增强能力接入
+
+建议每个阶段完成后都做一次可视化验收。
+
+---
+
+## 5. 阶段一:路由与目录骨架
+
+### 5.1 任务目标
+
+把 Canvas 模式先挂到系统里,确保页面可进入。
+
+### 5.2 任务清单
+
+- 新建 `src/open-canvas/` 目录
+- 新建 `src/open-canvas/routes/OpenCanvasRoutes.tsx`
+- 新建 `src/open-canvas/pages/CanvasHomePage.tsx`
+- 新建 `src/open-canvas/pages/CanvasThreadPage.tsx`
+- 修改 [PageRoutes.tsx](../src/pages/PageRoutes.tsx)
+
+### 5.3 路由建议
+
+建议新增:
+
+- `/page/canvas`
+- `/page/canvas/:thread_id`
+
+建议在 `PageLayout` 内部新增:
+
+- `path="canvas/*"`
+
+子路由建议:
+
+- `index -> CanvasHomePage`
+- `:thread_id -> CanvasThreadPage`
+- `new -> 跳转到 CanvasHomePage 或创建临时线程态`
+
+### 5.4 页面行为要求
+
+`CanvasHomePage`:
+
+- 展示 Canvas 欢迎页
+- 展示快速开始入口
+- 可进入新建文本或代码模式
+
+`CanvasThreadPage`:
+
+- 只负责线程级页面装配
+- 挂载所有 Canvas 上下文提供器
+- 渲染主布局组件
+
+### 5.5 验收标准
+
+- 访问 `/page/canvas` 正常
+- 访问 `/page/canvas/xxx` 正常
+- 不影响 `/page/workspace/*`
+- 页面为独立功能入口
+
+---
+
+## 6. 阶段二:Canvas 页面布局
+
+### 6.1 任务目标
+
+先搭出稳定的“左聊天右画布”骨架。
+
+### 6.2 任务清单
+
+- 新建 `layout/CanvasShell.tsx`
+- 新建 `layout/CanvasHeader.tsx`
+- 新建 `layout/CanvasResizableLayout.tsx`
+- 新建 `chat/CanvasChatPanel.tsx`
+- 新建 `artifact/CanvasArtifactPanel.tsx`
+- 新建 `artifact/CanvasEmptyState.tsx`
+
+### 6.3 布局要求
+
+推荐布局:
+
+- 顶部:Canvas 标题栏
+- 左侧:聊天面板
+- 右侧:artifact 面板
+- 可选右抽屉:Web 搜索结果
+
+### 6.4 建议复用
+
+可以优先复用:
+
+- `react-resizable-panels`
+- 现有按钮、分隔线、Tabs、Tooltip 等 UI 组件
+
+### 6.5 初始状态要求
+
+无 thread 或 thread 中无 artifact 时:
+
+- 右侧显示空状态
+- 左侧显示欢迎语和快速开始
+
+### 6.6 验收标准
+
+- 双栏布局稳定
+- 可拖拽调整宽度
+- 空状态显示正常
+- 适配桌面优先,移动端先做降级布局
+
+---
+
+## 7. 阶段三:类型与状态协议
+
+### 7.1 任务目标
+
+先把前端需要消费和管理的数据类型定下来。
+
+### 7.2 任务清单
+
+- 新建 `types/artifact.ts`
+- 新建 `types/thread.ts`
+- 新建 `types/model.ts`
+- 新建 `types/selection.ts`
+- 新建 `types/quick-action.ts`
+
+### 7.3 必要类型
+
+#### artifact.ts
+
+- `CanvasArtifact`
+- `CanvasArtifactText`
+- `CanvasArtifactCode`
+- `CanvasArtifactContent`
+
+#### selection.ts
+
+- `CanvasTextSelection`
+- `CanvasCodeSelection`
+- `CanvasSelectionState`
+
+#### thread.ts
+
+- `CanvasThreadValues`
+- `CanvasThreadMetadata`
+- `CanvasThread`
+
+### 7.4 建议结构
+
+```ts
+export type CanvasArtifact = {
+ currentIndex: number;
+ contents: CanvasArtifactContent[];
+};
+
+export type CanvasArtifactText = {
+ index: number;
+ type: "text";
+ title: string;
+ fullMarkdown: string;
+};
+
+export type CanvasArtifactCode = {
+ index: number;
+ type: "code";
+ title: string;
+ language: string;
+ code: string;
+};
+```
+
+### 7.5 线程值类型建议
+
+```ts
+export type CanvasThreadValues = {
+ title?: string;
+ messages?: Message[];
+ artifact?: CanvasArtifact;
+ web_search_results?: unknown[];
+ todos?: unknown[];
+};
+```
+
+### 7.6 验收标准
+
+- 所有 Canvas 组件只依赖 `open-canvas/types`
+- 不把类型散落到页面或组件内部
+- 前后端协议字段统一命名
+
+---
+
+## 8. 阶段四:前端 Context 设计
+
+### 8.1 任务目标
+
+把 Canvas 的状态拆成职责清晰的三层上下文。
+
+### 8.2 任务清单
+
+- 新建 `CanvasThreadContext.tsx`
+- 新建 `CanvasGraphContext.tsx`
+- 新建 `CanvasUIContext.tsx`
+
+### 8.3 职责划分
+
+#### CanvasThreadContext
+
+负责:
+
+- 当前 thread id
+- thread 基础信息
+- thread 创建/切换
+- 模型名称
+- 模型配置
+
+#### CanvasGraphContext
+
+负责:
+
+- messages
+- artifact
+- runId
+- streaming 状态
+- error 状态
+- 发送消息
+- 停止生成
+- 切换版本
+- 更新 artifact 内容
+
+#### CanvasUIContext
+
+负责:
+
+- 面板折叠状态
+- 是否正在编辑
+- 当前选区
+- Web 搜索面板开关
+- 快捷动作面板开关
+
+### 8.4 验收标准
+
+- 页面组件不直接持有大量跨层 useState
+- 聊天状态和 UI 状态分离
+- 线程切换时可安全重置状态
+
+---
+
+## 9. 阶段五:API 适配层
+
+### 9.1 任务目标
+
+为 Canvas 模式建立专用的前端 API 包装层。
+
+### 9.2 任务清单
+
+- 新建 `api/client.ts`
+- 新建 `api/models.ts`
+- 新建 `api/threads.ts`
+- 新建 `api/runs.ts`
+
+### 9.3 设计要求
+
+不要让页面组件直接到处调用现有 `getAPIClient()` 或裸 `fetch`。
+
+建议统一在 `src/open-canvas/api/` 中封装。
+
+### 9.4 需要封装的能力
+
+#### models.ts
+
+- `loadCanvasModels()`
+- 对现有 `/api/models` 结果做标准化
+
+#### threads.ts
+
+- `createCanvasThread()`
+- `getCanvasThread(threadId)`
+- `updateCanvasThreadMetadata(threadId, metadata)`
+- `updateCanvasThreadState(threadId, values)`
+
+#### runs.ts
+
+- `streamCanvasRun(...)`
+- `stopCanvasRun(...)`
+
+### 9.5 与现有 API 的关系
+
+底层可以复用:
+
+- `src/core/api/api-client.ts`
+- `src/core/api/fetch-client.ts`
+
+但上层调用应走 Canvas 专用 API。
+
+### 9.6 验收标准
+
+- 页面层不直接拼接 URL
+- Canvas API 调用集中管理
+- 后续改协议时只动一层
+
+---
+
+## 10. 阶段六:线程与流式状态接入
+
+### 10.1 任务目标
+
+让 Canvas 页面能像现有 ChatPage 一样收发消息并接流。
+
+### 10.2 任务清单
+
+- 新建 `hooks/useCanvasThread.ts`
+- 新建 `hooks/useCanvasStream.ts`
+- 新建 `utils/stream.ts`
+
+### 10.3 设计建议
+
+可以参考现有:
+
+- [ChatPage.tsx](../src/pages/ChatPage.tsx)
+- [threads/hooks.ts](../src/core/threads/hooks.ts)
+
+但不要直接把现有 `ChatPage` 复制一份。
+
+### 10.4 `useCanvasThread` 负责
+
+- 当前 thread id 管理
+- 新建/切换 thread
+- 从 URL 参数恢复 thread
+
+### 10.5 `useCanvasStream` 负责
+
+- 发送消息
+- 停止生成
+- 处理流式事件
+- 更新 `messages`
+- 更新 `artifact`
+- 更新 `runId`
+
+### 10.6 流式更新要求
+
+首版可以假设后端在 `values` 或 `updates` 中返回:
+
+- `messages`
+- `artifact`
+
+前端需要:
+
+- 新消息追加
+- artifact 覆盖或增量更新
+- 流结束后保持最终状态
+
+### 10.7 验收标准
+
+- 能发消息
+- 能收到消息
+- 能实时更新 artifact
+- 停止按钮可用
+
+---
+
+## 11. 阶段七:Artifact 渲染器
+
+### 11.1 任务目标
+
+实现文本/代码两类 artifact 的基础渲染与切换。
+
+### 11.2 任务清单
+
+- 新建 `artifact/CanvasArtifactRenderer.tsx`
+- 新建 `artifact/CanvasArtifactHeader.tsx`
+- 新建 `artifact/CanvasArtifactVersionNav.tsx`
+- 新建 `artifact/TextArtifactRenderer.tsx`
+- 新建 `artifact/CodeArtifactRenderer.tsx`
+
+### 11.3 组件职责
+
+#### CanvasArtifactRenderer
+
+- 判断当前 artifact 是否存在
+- 判断当前内容是文本还是代码
+- 分发到具体渲染器
+
+#### CanvasArtifactHeader
+
+- 显示标题
+- 显示保存状态
+- 显示版本导航
+
+#### CanvasArtifactVersionNav
+
+- 上一个版本
+- 下一个版本
+- 当前版本号
+
+#### TextArtifactRenderer
+
+- 渲染 markdown 内容
+- 支持编辑模式
+- 支持文本选区
+
+#### CodeArtifactRenderer
+
+- 使用 CodeMirror
+- 支持语言模式切换
+- 支持代码选区
+
+### 11.4 首版策略
+
+文本首版建议:
+
+- 编辑态用 textarea 或现有 markdown 编辑器
+- 展示态用现有 markdown renderer
+
+代码首版建议:
+
+- 直接复用现有 CodeMirror 基础能力
+
+### 11.5 验收标准
+
+- 文本 artifact 可看可编辑
+- 代码 artifact 可看可编辑
+- 版本切换正确
+- 标题与当前版本一致
+
+---
+
+## 12. 阶段八:快速开始与空状态
+
+### 12.1 任务目标
+
+让用户在没有任何 artifact 时也能顺畅开始。
+
+### 12.2 任务清单
+
+- 新建 `chat/CanvasWelcome.tsx`
+- 在 `CanvasHomePage` 中增加快速开始面板
+- 在 `CanvasThreadPage` 空状态时提供快速开始
+
+### 12.3 快速开始项建议
+
+- 空白文本
+- 空白代码
+- React 组件模板
+- HTML 页面模板
+- Python 脚本模板
+
+### 12.4 行为要求
+
+点击后:
+
+- 创建本地前端 artifact 草稿
+- 必要时自动创建 thread
+- 自动进入编辑态
+
+### 12.5 验收标准
+
+- 不发消息也能先建立 artifact
+- 新建文本/代码入口可用
+- 初始编辑体验完整
+
+---
+
+## 13. 阶段九:Artifact 版本管理
+
+### 13.1 任务目标
+
+让每次 AI 生成或修改都成为一个新版本。
+
+### 13.2 任务清单
+
+- 新建 `hooks/useCanvasArtifact.ts`
+- 新建 `utils/artifact.ts`
+
+### 13.3 必要能力
+
+- 获取当前版本内容
+- 切换版本
+- 更新当前版本内容
+- 追加新版本
+- 判断 artifact 是否为空
+
+### 13.4 推荐工具函数
+
+- `getCurrentArtifactContent(artifact)`
+- `setCurrentArtifactIndex(artifact, index)`
+- `appendArtifactVersion(artifact, content)`
+- `replaceCurrentArtifactContent(artifact, content)`
+- `isTextArtifact(content)`
+- `isCodeArtifact(content)`
+
+### 13.5 注意事项
+
+- 前端切版本不能直接修改原对象引用
+- 每次更新要创建新对象,避免渲染异常
+
+### 13.6 验收标准
+
+- AI 更新后版本数增加
+- 手动切换历史版本稳定
+- 当前版本高亮正确
+
+---
+
+## 14. 阶段十:局部选区交互
+
+### 14.1 任务目标
+
+实现局部改写所需的前端选区采集与展示。
+
+### 14.2 任务清单
+
+- 新建 `hooks/useCanvasSelection.ts`
+- 新建 `utils/selection.ts`
+
+### 14.3 文本选区需求
+
+- 获取选中起止位置
+- 获取选中文本
+- 在 UI 上显示“已选中某段内容”
+- 支持清除选区
+
+### 14.4 代码选区需求
+
+- 获取 CodeMirror 选区
+- 保存选中代码内容
+- 保存 start/end 或行列信息
+
+### 14.5 交互建议
+
+可以在选区出现后展示浮层或工具条:
+
+- 改写
+- 精简
+- 扩写
+- 解释
+
+首版先只保留:
+
+- “对所选内容进行修改” 的统一入口
+
+### 14.6 验收标准
+
+- 文本选区可读
+- 代码选区可读
+- 选区状态可清空
+- 切换版本或 thread 时选区自动重置
+
+---
+
+## 15. 阶段十一:聊天面板适配
+
+### 15.1 任务目标
+
+实现 Canvas 模式专用聊天面板,不直接塞回现有 ChatBox。
+
+### 15.2 任务清单
+
+- 新建 `chat/CanvasMessageList.tsx`
+- 新建 `chat/CanvasInputBox.tsx`
+- 新建 `chat/CanvasChatPanel.tsx`
+
+### 15.3 设计建议
+
+可以参考现有 ChatPage 的结构,但建议把 Canvas 模式聊天区做成更轻量版本。
+
+### 15.4 必要功能
+
+- 展示消息列表
+- 展示生成中状态
+- 提交输入
+- 停止生成
+- 显示模型选择器
+- 显示 Web 搜索开关
+
+### 15.5 可以复用
+
+- 现有消息渲染组件中的部分能力
+- 现有 InputBox 的一部分交互逻辑
+
+### 15.6 不建议直接复用
+
+- 当前工作区的文件 artifact 面板耦合
+- 当前以文件产物为中心的 ChatBox 结构
+
+### 15.7 验收标准
+
+- Canvas 聊天区独立可用
+- 能与 artifact 面板联动
+- 布局不受现有文件 artifact 影响
+
+---
+
+## 16. 阶段十二:模型选择器
+
+### 16.1 任务目标
+
+让 Canvas 模式可以使用 DeerFlow 的动态模型列表。
+
+### 16.2 任务清单
+
+- 新建 `selectors/CanvasModelSelector.tsx`
+- 在 `api/models.ts` 中做标准化
+
+### 16.3 UI 要求
+
+- 显示模型名
+- 显示是否本地模型
+- 显示是否支持视觉/推理/Canvas
+
+### 16.4 状态要求
+
+- 当前 thread 记录 `model_name`
+- 必要时记录 `model_config`
+- 切换 thread 时能恢复模型
+
+### 16.5 首版能力
+
+首版可以只做:
+
+- 下拉选择模型
+- 将模型信息写入 thread metadata 或 run configurable
+
+### 16.6 验收标准
+
+- 模型列表正确展示
+- 切换模型后发消息使用新模型
+- 本地模型与云模型能在 UI 中区分
+
+---
+
+## 17. 阶段十三:快捷动作栏
+
+### 17.1 任务目标
+
+实现 artifact 上方或下方的快捷动作入口。
+
+### 17.2 任务清单
+
+- 新建 `quick-actions/QuickActionBar.tsx`
+- 新建 `quick-actions/QuickActionButton.tsx`
+- 新建 `hooks/useCanvasQuickActions.ts`
+- 新建 `utils/quick-actions.ts`
+
+### 17.3 首版动作建议
+
+文本类:
+
+- 扩写
+- 精简
+- 改正式
+- 改口语
+
+代码类:
+
+- 加注释
+- 加日志
+- 修 bug
+
+### 17.4 行为要求
+
+点击动作后:
+
+- 写入 `quick_action_id`
+- 触发一次 Canvas run
+- 生成新的 artifact 版本
+
+### 17.5 验收标准
+
+- 动作栏根据 artifact 类型动态变化
+- 动作点击后有效果
+- 新版本正确生成
+
+---
+
+## 18. 阶段十四:Web 搜索面板
+
+### 18.1 任务目标
+
+为后续搜索增强预留 UI 和交互位置。
+
+### 18.2 任务清单
+
+- 新建 `web-search/CanvasWebSearchPanel.tsx`
+- 在 `CanvasUIContext` 中增加开关状态
+
+### 18.3 首版要求
+
+- 只做抽屉面板
+- 可展示结构化搜索结果列表
+- 可开关显示
+
+### 18.4 二期能力
+
+- 支持点击来源预览
+- 支持从结果插入上下文
+
+### 18.5 验收标准
+
+- 面板开关正常
+- 搜索结果区域可承载数据
+
+---
+
+## 19. 阶段十五:页面装配
+
+### 19.1 任务目标
+
+将所有子模块整合到页面中。
+
+### 19.2 任务清单
+
+`CanvasHomePage.tsx`:
+
+- 欢迎页
+- 快速开始
+- 最近 Canvas 线程入口
+
+`CanvasThreadPage.tsx`:
+
+- 解析 route params
+- 挂载 `CanvasThreadContext`
+- 挂载 `CanvasGraphContext`
+- 挂载 `CanvasUIContext`
+- 渲染 `CanvasShell`
+
+### 19.3 结构建议
+
+```tsx
+
+
+
+
+
+
+
+```
+
+### 19.4 验收标准
+
+- 页面层只负责装配,不承载复杂业务逻辑
+- 子组件依赖上下文而不是层层 props drilling
+
+---
+
+## 20. 推荐逐文件实施顺序
+
+建议按这个顺序建文件:
+
+1. `routes/OpenCanvasRoutes.tsx`
+2. `pages/CanvasHomePage.tsx`
+3. `pages/CanvasThreadPage.tsx`
+4. `types/*`
+5. `contexts/CanvasThreadContext.tsx`
+6. `contexts/CanvasUIContext.tsx`
+7. `contexts/CanvasGraphContext.tsx`
+8. `layout/CanvasShell.tsx`
+9. `layout/CanvasResizableLayout.tsx`
+10. `artifact/CanvasEmptyState.tsx`
+11. `artifact/CanvasArtifactRenderer.tsx`
+12. `artifact/TextArtifactRenderer.tsx`
+13. `artifact/CodeArtifactRenderer.tsx`
+14. `chat/CanvasChatPanel.tsx`
+15. `chat/CanvasInputBox.tsx`
+16. `api/*`
+17. `hooks/useCanvasStream.ts`
+18. `hooks/useCanvasSelection.ts`
+19. `quick-actions/*`
+20. `web-search/*`
+
+---
+
+## 21. 开发任务拆分建议
+
+如果多人协作,建议这样拆:
+
+### A 组:页面与路由
+
+- 路由接入
+- 页面骨架
+- 主布局
+
+### B 组:artifact 视图
+
+- artifact 类型
+- 渲染器
+- 版本导航
+- 代码/文本编辑器
+
+### C 组:聊天与流式
+
+- thread 管理
+- stream 接入
+- 消息面板
+- 模型切换
+
+### D 组:增强交互
+
+- 选区
+- 快捷动作
+- 搜索面板
+
+---
+
+## 22. 每阶段验收清单
+
+### 22.1 阶段一到三
+
+- 路由正常
+- 空页面正常
+- 类型编译通过
+- 目录结构清晰
+
+### 22.2 阶段四到六
+
+- thread 可创建/读取
+- 消息可发送
+- artifact 可展示
+- 流式结果可更新
+
+### 22.3 阶段七到九
+
+- 文本/代码 artifact 渲染正确
+- 版本导航正确
+- 快速开始可用
+- 模型选择可用
+
+### 22.4 阶段十到十四
+
+- 局部选区可采集
+- 快捷动作可触发
+- 搜索面板可显示
+- 各功能互不冲突
+
+---
+
+## 23. 风险点与规避方式
+
+### 23.1 不要直接复制现有 ChatPage
+
+原因:
+
+- 现有页面与文件 artifact 耦合较重
+- Canvas 需要结构化 artifact 而不是文件列表
+
+### 23.2 不要把所有状态都放一个 Context
+
+原因:
+
+- 更新频率高
+- 容易导致全树重渲染
+
+### 23.3 不要先做复杂富文本
+
+原因:
+
+- 选区映射复杂
+- 首版容易卡在编辑器实现而不是业务链路
+
+建议先以:
+
+- `fullMarkdown`
+- `textarea/markdown renderer`
+
+作为最小闭环。
+
+### 23.4 不要前端硬编码模型表
+
+原因:
+
+- 后端才是真源
+- 后期本地模型和自定义 provider 会频繁变化
+
+---
+
+## 24. 首版最小可交付范围
+
+前端首版建议只交付这些:
+
+- `canvas/*` 路由
+- Canvas 双栏布局
+- 文本/代码 artifact 渲染
+- 模型选择器
+- 流式聊天
+- artifact 版本切换
+- 快速开始
+
+首版先不强制包含:
+
+- 复杂文本局部高亮浮层
+- 复杂快捷动作配置中心
+- 高级 Web 搜索结果联动
+
+---
+
+## 25. 下一步建议
+
+完成本文档后,建议继续产出两份更细的执行文件:
+
+### 25.1 前端文件创建顺序清单
+
+按天或按 PR 颗粒度,列出:
+
+- 每一批次新建哪些文件
+- 每一批次修改哪些已有文件
+
+### 25.2 前端组件接口文档
+
+列出关键组件 props:
+
+- `CanvasShell`
+- `CanvasChatPanel`
+- `CanvasArtifactRenderer`
+- `CanvasModelSelector`
+
+这样正式开工时会更顺畅。
+---
+
+## 26. 参考源码映射
+
+前端实施清单建议补充对 `langchain-ai/open-canvas` 源码的“映射式参考”,但不建议把源码大段粘贴进本文档。
+
+推荐做法是:
+
+- 记录参考文件路径
+- 说明它解决了什么问题
+- 说明在 DeerFlow 前端里应该落到哪个模块
+- 只摘能力点,不摘整段实现
+
+这样做的原因:
+
+- 文档更清晰
+- 不会把 Next.js 运行时细节误当成可直接迁移代码
+- 后续维护更轻
+
+### 26.1 推荐参考文件总览
+
+以下文件最值得作为前端实现参考:
+
+- `apps/web/src/contexts/GraphContext.tsx`
+- `apps/web/src/components/canvas/canvas.tsx`
+- `apps/web/src/components/artifacts/ArtifactRenderer.tsx`
+- `apps/web/src/components/artifacts/TextRenderer.tsx`
+- `apps/web/src/components/artifacts/CodeRenderer.tsx`
+- `apps/web/src/contexts/ThreadProvider.tsx`
+- `apps/web/src/contexts/AssistantContext.tsx`
+- `apps/web/src/hooks/useRuns.tsx`
+- `apps/web/src/types.ts`
+- `packages/shared/src/types.ts`
+- `packages/shared/src/models.ts`
+- `packages/shared/src/utils/artifacts.ts`
+
+### 26.2 逐文件映射建议
+
+#### `apps/web/src/contexts/GraphContext.tsx`
+
+参考价值:
+
+- 这是 open-canvas 前端最核心的状态管理文件之一
+- 管理消息、artifact、流式状态、保存状态、版本切换、局部更新
+- 处理流中 artifact 更新和 thread 切换
+
+DeerFlow 对应落点:
+
+- `src/open-canvas/contexts/CanvasGraphContext.tsx`
+- `src/open-canvas/hooks/useCanvasStream.ts`
+- `src/open-canvas/utils/stream.ts`
+- `src/open-canvas/utils/artifact.ts`
+
+重点借鉴内容:
+
+- artifact 如何作为线程主状态存在
+- 流式过程中如何同步 messages 与 artifact
+- 切换 thread 时如何恢复状态
+- 如何维护“当前版本”和“已保存状态”
+
+不建议直接照搬的部分:
+
+- 与 Next.js、`nuqs`、open-canvas 内部 hook 耦合的代码
+- 与其后端返回格式强绑定的处理逻辑
+
+#### `apps/web/src/components/canvas/canvas.tsx`
+
+参考价值:
+
+- Open Canvas 的主页面装配组件
+- 管理左聊天右画布布局
+- 定义快速开始逻辑
+- 管理 chat collapsed、artifact 初始创建
+
+DeerFlow 对应落点:
+
+- `src/open-canvas/components/layout/CanvasShell.tsx`
+- `src/open-canvas/components/layout/CanvasResizableLayout.tsx`
+- `src/open-canvas/pages/CanvasThreadPage.tsx`
+
+重点借鉴内容:
+
+- 快速开始时如何创建文本或代码 artifact
+- 左右双栏如何组织
+- 页面级状态和上下文边界怎么划分
+
+不建议直接照搬的部分:
+
+- Next 路由参数逻辑
+- 与 open-canvas ThreadProvider 强耦合的状态恢复代码
+
+#### `apps/web/src/components/artifacts/ArtifactRenderer.tsx`
+
+参考价值:
+
+- 负责 artifact 总渲染分发
+- 根据当前版本内容选择文本或代码渲染器
+- 负责版本导航和选区交互挂钩
+
+DeerFlow 对应落点:
+
+- `src/open-canvas/components/artifact/CanvasArtifactRenderer.tsx`
+- `src/open-canvas/components/artifact/CanvasArtifactHeader.tsx`
+- `src/open-canvas/components/artifact/CanvasArtifactVersionNav.tsx`
+
+重点借鉴内容:
+
+- 当前 artifact 的统一入口组件结构
+- 版本导航和正文渲染如何组合
+- 文本/代码视图如何统一被包装
+
+#### `apps/web/src/components/artifacts/TextRenderer.tsx`
+
+参考价值:
+
+- 负责文本 artifact 的渲染与编辑
+- 处理 markdown 内容、更新、局部交互
+
+DeerFlow 对应落点:
+
+- `src/open-canvas/components/artifact/TextArtifactRenderer.tsx`
+- `src/open-canvas/hooks/useCanvasSelection.ts`
+
+重点借鉴内容:
+
+- 文本 artifact 的编辑态与展示态切换
+- 当前版本内容如何回写到状态
+- 局部选区的挂接点
+
+实现上的取舍建议:
+
+- DeerFlow 首版不要追求和 open-canvas 一样复杂的富文本块级编辑
+- 建议先用 `fullMarkdown` + markdown renderer + 简单编辑态完成闭环
+
+#### `apps/web/src/components/artifacts/CodeRenderer.tsx`
+
+参考价值:
+
+- 负责代码 artifact 的渲染与编辑
+- 与 CodeMirror 集成
+- 管理代码内容更新
+
+DeerFlow 对应落点:
+
+- `src/open-canvas/components/artifact/CodeArtifactRenderer.tsx`
+
+重点借鉴内容:
+
+- 代码 artifact 如何绑定语言
+- 代码编辑结果如何同步回 artifact 状态
+- 局部代码选区的接入位置
+
+#### `apps/web/src/contexts/ThreadProvider.tsx`
+
+参考价值:
+
+- 负责 thread 与模型相关状态
+- 管理 thread 切换和 thread 级配置
+
+DeerFlow 对应落点:
+
+- `src/open-canvas/contexts/CanvasThreadContext.tsx`
+- `src/open-canvas/hooks/useCanvasThread.ts`
+
+重点借鉴内容:
+
+- 当前 thread id 的管理方式
+- thread metadata 与 model state 的关系
+- 页面恢复 thread 时的上下文同步
+
+#### `apps/web/src/contexts/AssistantContext.tsx`
+
+参考价值:
+
+- 管理 assistant 选择
+- 管理与 assistant 相关的 thread 行为
+
+DeerFlow 对应落点:
+
+- DeerFlow 首版可以弱化这部分
+- 如果首版只有 `canvas_agent` 一个固定 assistant,可只保留最小 assistant 绑定能力
+
+重点借鉴内容:
+
+- thread 与 assistant 的耦合方式
+
+#### `apps/web/src/hooks/useRuns.tsx`
+
+参考价值:
+
+- 管理 run 相关行为
+
+DeerFlow 对应落点:
+
+- `src/open-canvas/api/runs.ts`
+- `src/open-canvas/hooks/useCanvasStream.ts`
+
+重点借鉴内容:
+
+- run 行为与页面状态的解耦方式
+
+#### `apps/web/src/types.ts`
+
+参考价值:
+
+- 保存了一部分 artifact 和消息类型定义
+
+DeerFlow 对应落点:
+
+- `src/open-canvas/types/artifact.ts`
+- `src/open-canvas/types/thread.ts`
+
+重点借鉴内容:
+
+- artifact 的前端表达方式
+
+注意:
+
+- 更建议以 `packages/shared/src/types.ts` 为主参考,而不是这个文件
+- 因为 `src/types.ts` 里同时包含了部分历史兼容结构
+
+#### `packages/shared/src/types.ts`
+
+参考价值:
+
+- 这是 open-canvas 中最重要的共享类型来源之一
+- 定义了 `ArtifactV3`、代码/文本内容、选择区和其他共享结构
+
+DeerFlow 对应落点:
+
+- `src/open-canvas/types/artifact.ts`
+- `src/open-canvas/types/selection.ts`
+- 可作为前后端协议设计的主要参考
+
+重点借鉴内容:
+
+- `ArtifactV3` 结构
+- 文本/代码 artifact 类型边界
+- 与版本管理有关的字段组织方式
+
+建议:
+
+- DeerFlow 可以参考其字段设计
+- 但不要机械复制所有字段,保留适合当前项目的最小集
+
+#### `packages/shared/src/models.ts`
+
+参考价值:
+
+- 展示了 open-canvas 如何组织前端模型列表和模型能力
+
+DeerFlow 对应落点:
+
+- `src/open-canvas/types/model.ts`
+- `src/open-canvas/api/models.ts`
+- `src/open-canvas/components/selectors/CanvasModelSelector.tsx`
+
+重点借鉴内容:
+
+- 模型展示结构
+- provider 概念
+- 各模型能力标签的前端呈现思路
+
+注意:
+
+- 不应作为 DeerFlow 的模型配置真源
+- DeerFlow 必须以自己后端 `/api/models` 为真源
+
+#### `packages/shared/src/utils/artifacts.ts`
+
+参考价值:
+
+- 里面有 artifact 类型判断和内容获取工具
+
+DeerFlow 对应落点:
+
+- `src/open-canvas/utils/artifact.ts`
+
+重点借鉴内容:
+
+- 获取当前版本内容
+- 判断当前 artifact 是文本还是代码
+- 为渲染器和快捷动作提供统一入口
+
+### 26.3 可以直接参考但不要直接迁移的部分
+
+以下内容可以借鉴思路,但不建议直接搬代码:
+
+- Next.js 路由和页面结构
+- `src/app/api/*` 目录中的 API Route
+- Supabase SSR 和服务端 session 相关代码
+- `next/navigation` 相关逻辑
+- `middleware.ts`
+
+原因:
+
+- DeerFlow 前端是 `React 19 + Vite + react-router-dom`
+- 这些代码依赖 Next.js 运行时
+
+### 26.4 建议的使用方式
+
+开发时推荐这样使用参考源码:
+
+1. 先按本文档实现 DeerFlow 自己的模块边界
+2. 遇到某个具体功能点时,再去查对应 open-canvas 文件
+3. 提炼实现思路,重写到 DeerFlow 的目录结构中
+4. 不要复制包含 Next.js 运行时依赖的代码
+
+### 26.5 推荐补充动作
+
+如果后面要正式进入实现阶段,建议再单独新增一份源码映射文档,例如:
+
+- `frontend-web/docs/openCanvas-source-map.md`
+
+里面可以更细地记录:
+
+- open-canvas 文件路径
+- DeerFlow 对应目标文件
+- 迁移策略
+- 是否可直接借鉴
+- 是否需要重写
diff --git a/frontend-web/docs/openCanvas.md b/frontend-web/docs/openCanvas.md
new file mode 100644
index 00000000..6ef38733
--- /dev/null
+++ b/frontend-web/docs/openCanvas.md
@@ -0,0 +1,950 @@
+# Open Canvas 模式需求拆解文档
+
+## 1. 文档目标
+
+本文档用于指导 DeerFlow 在现有架构中新增一个 `open-canvas` 风格的 Canvas 模式。
+
+目标不是直接照搬 `langchain-ai/open-canvas` 的 Next.js + LangGraph.js 实现,而是在当前项目技术栈内完成一套等价能力的实现:
+
+- 前端:基于 `React 19 + Vite + react-router-dom`
+- 后端:基于 `Python + FastAPI + LangGraph`
+- 模型层:支持云模型与本地模型自由配置
+- 状态层:支持结构化 artifact、版本历史、局部改写、快速动作、画布编辑
+
+本文档重点是把需求拆成“可实现、可排期、可验收”的阶段性任务。
+
+---
+
+## 2. 最终目标
+
+### 2.1 用户视角目标
+
+用户进入一个新的 Canvas 工作模式后,可以获得与 open-canvas 接近的体验:
+
+- 左侧是聊天区,右侧是 Canvas 编辑区
+- 可以从空白文本或代码模板快速开始
+- 可以通过聊天让 AI 生成一份结构化 artifact
+- 可以对 artifact 整体重写,也可以对选中的局部内容进行改写
+- artifact 支持版本历史切换
+- artifact 支持文本和代码两种主要类型
+- 支持快速动作,例如扩写、压缩、改风格、改语气、加注释、修 bug、换语言
+- 支持启用 Web 搜索增强
+- 支持切换模型
+- 支持使用本地模型,例如 Ollama 或 OpenAI-compatible 本地服务
+
+### 2.2 工程视角目标
+
+新增的 Canvas 模式需要满足以下工程原则:
+
+- 不破坏现有 DeerFlow 工作区
+- 不影响现有基于 `artifacts: string[]` 的文件产物功能
+- 可逐阶段上线
+- 前后端状态协议清晰
+- 可兼容现有 LangGraph 线程、消息流、认证和模型接口
+
+---
+
+## 3. 范围定义
+
+### 3.1 本次需求包含
+
+- 前端新增 `open-canvas` 专用目录
+- 在 [PageRoutes.tsx](../src/pages/PageRoutes.tsx) 中引入新的 Canvas 路由
+- 前端新增 Canvas 页面、上下文、组件、状态管理
+- 后端新增 Canvas 专用线程状态字段
+- 后端新增 Canvas Agent 图或在现有 Agent 体系中新增 Canvas 模式分支
+- 模型配置统一为 DeerFlow 后端配置驱动
+- 支持本地大模型配置与模型列表动态下发
+- 支持结构化 artifact 的保存、读取、更新、版本切换
+
+### 3.2 本次需求不包含
+
+- 一次性复刻 open-canvas 全部 UI 细节
+- 完整照搬 Supabase 鉴权体系
+- 直接复用 open-canvas 的 Next.js API Route
+- 直接运行 open-canvas 的 LangGraph.js 后端
+- 首阶段就实现所有快捷动作、所有富文本效果、所有搜索增强能力
+
+### 3.3 迁移原则
+
+- 借鉴 open-canvas 的能力模型,不直接迁移其运行时架构
+- 前端尽量复用其交互设计和数据结构
+- 后端以 Python 实现同等能力
+- 配置以 DeerFlow 为真源,不以 open-canvas 的 TS 文件为真源
+
+---
+
+## 4. 总体设计思路
+
+### 4.1 前端设计思路
+
+在现有 `frontend-web/src` 下新增一个专用目录,例如:
+
+```text
+src/
+ open-canvas/
+ pages/
+ routes/
+ components/
+ contexts/
+ hooks/
+ types/
+ api/
+ utils/
+ constants/
+```
+
+建议将 Canvas 模式作为一个独立的页面子系统接入,而不是把现有工作区页面强行改造成 Canvas。
+
+建议路由形式:
+
+- `/canvas`
+- `/canvas/:threadId`
+
+也可以挂在现有页面布局下,例如:
+
+- `/workspace/canvas`
+- `/workspace/canvas/:threadId`
+
+推荐优先采用独立一级功能路由:
+
+- 逻辑更清晰
+- 状态隔离更容易
+- 不容易污染现有 `workspace` 功能
+
+### 4.2 后端设计思路
+
+后端不建议直接改造现有通用 Agent 去同时承担全部 Canvas 行为,而是建议采用以下两种方案之一:
+
+#### 方案 A:新增独立 Canvas Assistant
+
+- 新增 `canvas_agent`
+- 使用单独的 LangGraph 状态定义
+- 前端调用时通过 `assistant_id=canvas_agent`
+
+优点:
+
+- 与现有 `lead_agent` 隔离
+- 风险更低
+- 更容易对齐 open-canvas 的图结构
+
+缺点:
+
+- 会产生一套新的 Agent 图维护成本
+
+#### 方案 B:在现有 Lead Agent 中增加 Canvas 模式分支
+
+- 在 thread metadata 或 configurable 中增加 `ui_mode=canvas`
+- Agent 根据模式进入 Canvas 路径
+
+优点:
+
+- 统一入口
+
+缺点:
+
+- 会显著增加现有 Agent 复杂度
+- 容易影响现有聊天和文件产物模式
+
+推荐先做方案 A。
+
+### 4.3 模型配置设计思路
+
+模型配置统一以 DeerFlow 后端 `config.yaml` 为真源。
+
+前端不维护固定模型常量列表,而是通过 `/api/models` 获取模型能力元数据。
+
+为了实现 open-canvas 风格体验,需要后端模型接口至少返回:
+
+- `name`
+- `display_name`
+- `provider`
+- `supports_thinking`
+- `supports_reasoning_effort`
+- `supports_vision`
+- `supports_tool_calling`
+- `supports_artifact_editing`
+- `supports_code_editing`
+- `temperature_range`
+- `max_tokens_range`
+- `base_url_source` 或 provider 标识
+- `is_local`
+
+---
+
+## 5. 与当前项目的关键差异
+
+### 5.1 当前 DeerFlow 现状
+
+当前 DeerFlow 线程状态中的 artifact 主要是文件路径列表:
+
+- `artifacts: string[]`
+
+这更接近“生成文件产物”的工作模式。
+
+前端当前 artifact 面板也主要是:
+
+- 文件列表
+- 文件详情
+- 文件下载/预览
+
+### 5.2 open-canvas 的关键能力
+
+open-canvas 的核心不是“生成文件”,而是“维护一个结构化的当前文档对象”:
+
+- 一个 conversation 对应一个主 artifact
+- artifact 具有类型、标题、内容、版本
+- 用户可以选中部分内容让 AI 改写
+- 每次改写都会生成新版本
+
+### 5.3 需要新增的核心能力
+
+为支持 Canvas 模式,需要在 DeerFlow 中新增一套结构化 artifact 状态:
+
+- 当前 artifact
+- 当前版本索引
+- 历史版本列表
+- 选区信息
+- 当前编辑模式
+- 快速动作状态
+- Web 搜索结果状态
+
+---
+
+## 6. 分阶段实施方案
+
+以下为推荐的 8 个阶段,每个阶段都可单独开发、联调和验收。
+
+---
+
+## 7. 阶段一:前端路由与目录骨架
+
+### 7.1 目标
+
+在不影响现有页面的前提下,建立 Canvas 模式的前端骨架。
+
+### 7.2 需求
+
+- 新增 `src/open-canvas/` 目录
+- 新增 Canvas 页面路由
+- 将路由接入 [PageRoutes.tsx](../src/pages/PageRoutes.tsx)
+- 提供 Canvas 首页和 Canvas Thread 页
+- 支持空状态展示
+
+### 7.3 建议目录
+
+```text
+src/open-canvas/
+ api/
+ threads.ts
+ runs.ts
+ models.ts
+ components/
+ layout/
+ chat/
+ canvas/
+ artifacts/
+ quick-actions/
+ selectors/
+ contexts/
+ CanvasThreadContext.tsx
+ CanvasGraphContext.tsx
+ CanvasUIContext.tsx
+ hooks/
+ useCanvasThread.ts
+ useCanvasStream.ts
+ useCanvasArtifact.ts
+ pages/
+ CanvasHomePage.tsx
+ CanvasThreadPage.tsx
+ routes/
+ OpenCanvasRoutes.tsx
+ types/
+ artifact.ts
+ thread.ts
+ model.ts
+ utils/
+ artifact.ts
+ selection.ts
+ stream.ts
+ constants/
+ index.ts
+```
+
+### 7.4 路由建议
+
+- 在 `PageRoutes.tsx` 中新增 `canvas/*`
+- 在 `src/open-canvas/routes/OpenCanvasRoutes.tsx` 中维护子路由
+
+建议形式:
+
+```text
+/canvas
+/canvas/:threadId
+```
+
+### 7.5 验收标准
+
+- 能访问 Canvas 首页
+- 能访问指定 thread 的 Canvas 页面
+- 不影响现有 `workspace/*` 与 `strategy/*`
+- 页面有独立布局骨架
+
+---
+
+## 8. 阶段二:前端 Canvas 布局与交互容器
+
+### 8.1 目标
+
+先做出“左聊天、右画布”的基础容器,不接真实 AI 改写逻辑。
+
+### 8.2 需求
+
+- 左侧聊天区
+- 右侧画布区
+- 支持面板拖拽或折叠
+- 初始空状态
+- 支持“快速开始”:
+ - 新建空白文本 artifact
+ - 新建代码 artifact
+
+### 8.3 组件拆分建议
+
+- `CanvasShell`
+- `CanvasSidebar`
+- `CanvasChatPanel`
+- `CanvasArtifactPanel`
+- `CanvasEmptyState`
+- `QuickStartActions`
+
+### 8.4 快速开始能力
+
+用户进入空线程时可以选择:
+
+- 开始写文章
+- 开始写代码
+- 从模板开始
+
+首版模板可只做最小集:
+
+- 空白文档
+- HTML 模板
+- React 组件模板
+- Python 脚本模板
+
+### 8.5 验收标准
+
+- 页面可稳定展示双栏布局
+- 快速开始能创建前端本地 artifact 状态
+- 代码和文本可分别进入不同渲染器
+
+---
+
+## 9. 阶段三:结构化 Artifact 数据模型
+
+### 9.1 目标
+
+定义 DeerFlow 的 Canvas Artifact 协议,作为前后端统一契约。
+
+### 9.2 核心要求
+
+需要支持以下能力:
+
+- 文本 artifact
+- 代码 artifact
+- 标题
+- 当前版本索引
+- 版本历史
+- 当前选中版本切换
+- 后续支持局部高亮编辑
+
+### 9.3 建议数据结构
+
+```ts
+type CanvasArtifact = {
+ currentIndex: number;
+ contents: Array;
+};
+
+type CanvasArtifactText = {
+ index: number;
+ type: "text";
+ title: string;
+ fullMarkdown: string;
+};
+
+type CanvasArtifactCode = {
+ index: number;
+ type: "code";
+ title: string;
+ language: string;
+ code: string;
+};
+```
+
+### 9.4 线程状态建议新增字段
+
+前端与后端需共同支持:
+
+- `artifact`
+- `highlighted_text`
+- `highlighted_code`
+- `canvas_mode`
+- `web_search_enabled`
+- `web_search_results`
+- `quick_action_id`
+
+### 9.5 与现有 `artifacts: string[]` 的关系
+
+建议保留现有 `artifacts: string[]` 不动。
+
+新增字段:
+
+- `artifact` 用于 Canvas 主文档
+- `artifacts` 继续用于文件产物
+
+这样可以兼容未来“Canvas 生成网页文件、导出文件、保存文件”的场景。
+
+### 9.6 验收标准
+
+- 前端类型定义完成
+- 后端状态字段设计完成
+- 确认与现有线程状态兼容
+
+---
+
+## 10. 阶段四:后端线程状态与 API 扩展
+
+### 10.1 目标
+
+让后端线程状态可以安全存储和返回 Canvas Artifact。
+
+### 10.2 需求
+
+- 扩展 Python `ThreadState`
+- 扩展状态序列化逻辑
+- 确保 `/api/threads/*` 返回结构化 `artifact`
+- 确保 LangGraph 流中可带上 `artifact` 更新
+
+### 10.3 后端改造点
+
+建议关注以下模块:
+
+- `packages/harness/deerflow/agents/thread_state.py`
+- 线程 state serializer
+- `app/gateway/routers/threads.py`
+- 流事件适配层
+
+### 10.4 注意事项
+
+- 旧线程没有 `artifact` 字段时必须兼容
+- 状态更新不能破坏现有消息结构
+- 必须确保 JSON 可序列化
+
+### 10.5 验收标准
+
+- 新建线程可写入 `artifact`
+- 读取线程时可返回 `artifact`
+- 不影响现有线程读取
+- 前端能从线程 state 中恢复 Canvas 内容
+
+---
+
+## 11. 阶段五:Canvas 专用 Agent 图
+
+### 11.1 目标
+
+实现与 open-canvas 类似的 AI 路由能力。
+
+### 11.2 推荐方案
+
+新增 `canvas_agent`,单独维护图逻辑。
+
+### 11.3 节点拆分建议
+
+首版建议至少拆成这些节点:
+
+- `route_user_intent`
+- `reply_general_input`
+- `generate_artifact`
+- `rewrite_artifact`
+- `update_highlighted_text`
+- `update_highlighted_code`
+- `generate_followup`
+
+二期可加:
+
+- `rewrite_artifact_theme`
+- `rewrite_code_theme`
+- `change_length`
+- `change_reading_level`
+- `translate_artifact`
+- `add_comments`
+- `add_logs`
+- `fix_bugs`
+- `port_language`
+- `web_search_enrich`
+
+### 11.4 路由逻辑要求
+
+系统需要能判断:
+
+- 用户是在闲聊
+- 用户要新生成 artifact
+- 用户要整体重写当前 artifact
+- 用户要局部修改当前 artifact
+- 用户要执行某个快捷动作
+
+### 11.5 状态输入要求
+
+节点需要读取:
+
+- 当前消息历史
+- 当前 artifact
+- 当前选区
+- 当前模型配置
+- Web 搜索开关
+
+### 11.6 输出要求
+
+节点输出必须能更新:
+
+- `messages`
+- `artifact`
+- `web_search_results`
+- `followup`
+
+### 11.7 验收标准
+
+- 能根据输入创建新 artifact
+- 能根据输入整体改写 artifact
+- 能保留版本历史
+- 能在改写后返回自然语言 followup
+
+---
+
+## 12. 阶段六:前端流式同步与版本管理
+
+### 12.1 目标
+
+让前端能像 open-canvas 一样在流式过程中更新画布与聊天。
+
+### 12.2 需求
+
+- 复用现有 LangGraph stream client
+- 在 Canvas 模式中解析 `artifact` 更新
+- 支持流式文本更新
+- 支持版本切换
+- 支持断线后恢复线程状态
+
+### 12.3 前端状态层建议
+
+- `CanvasThreadContext`:线程基础信息
+- `CanvasGraphContext`:消息、artifact、streaming 状态
+- `CanvasUIContext`:面板、编辑态、选中态
+
+### 12.4 关键能力
+
+- 当前版本切换
+- 新版本创建后自动定位到最新版本
+- 手动编辑内容后保存
+- 流结束后线程状态持久化
+
+### 12.5 验收标准
+
+- 发送消息时聊天和画布可同步更新
+- 版本数会增加
+- 切换历史版本稳定
+- 刷新页面后线程状态能恢复
+
+---
+
+## 13. 阶段七:局部选区改写
+
+### 13.1 目标
+
+实现 Canvas 模式最关键的差异化能力之一:选中局部内容进行 AI 改写。
+
+### 13.2 文本选区需求
+
+- 支持在 Markdown 文本中选择一段文本
+- 记录选区位置与原始文本
+- 用户发出修改请求后,仅重写该选区
+- 将选区结果合并为新版本 artifact
+
+### 13.3 代码选区需求
+
+- 支持在代码编辑器中选择一段代码
+- 记录 start/end index 或行列信息
+- AI 只返回替换片段
+- 前端或后端负责将新片段拼接回完整代码
+
+### 13.4 实现建议
+
+首版建议:
+
+- 文本:前端记录纯文本字符位置
+- 代码:使用 CodeMirror selection 信息
+
+不建议首版就做复杂块级富文本局部编辑。
+
+### 13.5 风险
+
+- Markdown 渲染态与源码态位置映射复杂
+- 富文本块级位置难维护
+- 流式更新中选区同步容易错位
+
+### 13.6 首版折中方案
+
+首版文本只基于 `fullMarkdown` 纯文本改写,不做 BlockNote 富文本块定位。
+
+### 13.7 验收标准
+
+- 文本局部改写成功
+- 代码局部改写成功
+- 原内容未改动部分保持不变
+- 新版本正确入历史
+
+---
+
+## 14. 阶段八:快捷动作系统
+
+### 14.1 目标
+
+实现 open-canvas 风格的快捷动作体系。
+
+### 14.2 首批推荐动作
+
+文本类:
+
+- 扩写
+- 精简
+- 改正式语气
+- 改口语语气
+- 改阅读难度
+- 翻译
+
+代码类:
+
+- 加注释
+- 加日志
+- 修复 bug
+- 优化代码
+- 转换语言
+
+### 14.3 设计方式
+
+快捷动作不要直接写死在 UI,建议配置化:
+
+- `id`
+- `label`
+- `type`
+- `applicable_to`
+- `prompt_template`
+
+### 14.4 后端设计
+
+快捷动作可通过:
+
+- 前端传 `quick_action_id`
+- 后端路由节点根据动作 id 选择 prompt
+
+### 14.5 验收标准
+
+- 文本动作可执行
+- 代码动作可执行
+- 结果进入新版本
+- 不同动作提示词可扩展
+
+---
+
+## 15. 阶段九:模型配置统一与本地模型支持
+
+### 15.1 目标
+
+让 Canvas 模式支持和主系统统一的模型选择,并且能自由配置本地大模型。
+
+### 15.2 原则
+
+- 后端 `config.yaml` 为真源
+- 前端只展示后端暴露的模型信息
+- 不维护一份脱离后端的前端常量模型表
+
+### 15.3 本地模型支持范围
+
+建议优先支持两类:
+
+- `Ollama`
+- OpenAI-compatible 本地服务
+ - LM Studio
+ - vLLM
+ - LocalAI
+ - one-api 风格代理
+
+### 15.4 后端配置建议
+
+后端模型配置应至少支持:
+
+- `name`
+- `display_name`
+- `use`
+- `model`
+- `api_key`
+- `base_url`
+- `supports_vision`
+- `supports_thinking`
+- `supports_tool_calling`
+- `is_local`
+- `canvas_capabilities`
+
+### 15.5 Canvas 模式额外要求
+
+由于不是所有模型都适合 Canvas 改写任务,建议增加能力标识:
+
+- `supports_canvas_generation`
+- `supports_canvas_rewrite`
+- `supports_canvas_code_edit`
+- `supports_streaming_text`
+- `supports_streaming_tool_calls`
+
+### 15.6 与 open-canvas 的关系
+
+可以借鉴其命名习惯和能力分层,但不建议直接依赖其 `packages/shared/src/models.ts` 作为配置源。
+
+### 15.7 验收标准
+
+- 前端模型选择器可显示后端返回模型
+- 可切换本地模型
+- Canvas 模式能用本地模型生成和改写
+
+---
+
+## 16. 阶段十:Web 搜索增强
+
+### 16.1 目标
+
+实现类似 open-canvas 的可选 Web 搜索增强。
+
+### 16.2 需求
+
+- UI 提供 Web 搜索开关
+- 后端在需要时走搜索节点
+- 搜索结果写入线程状态
+- 结果可在画布旁侧栏展示
+
+### 16.3 首版建议
+
+只做:
+
+- 开关
+- 搜索结果列表
+- 搜索结果用于生成 artifact
+
+暂不做复杂网页抓取编辑链路。
+
+### 16.4 验收标准
+
+- 打开搜索后可返回搜索结果
+- 搜索结果可参与 artifact 生成
+- 结果展示不阻塞主画布
+
+---
+
+## 17. 阶段十一:持久化、导出与文件产物联动
+
+### 17.1 目标
+
+让 Canvas 文档与 DeerFlow 原有文件能力协同。
+
+### 17.2 需求
+
+- artifact 持久化在线程 state 中
+- 可手动导出为文件
+- 可生成真实 HTML/Markdown/代码文件到现有 outputs
+- Canvas artifact 与 `artifacts: string[]` 可双向关联
+
+### 17.3 推荐能力
+
+- 导出 Markdown
+- 导出代码文件
+- 另存为 artifact file
+- 从 artifact file 回填到 Canvas
+
+### 17.4 验收标准
+
+- 当前版本可导出
+- 导出文件可在现有文件面板查看
+- 文件型 artifact 和 Canvas artifact 能共存
+
+---
+
+## 18. 推荐开发顺序
+
+建议严格按以下顺序推进:
+
+1. 路由和目录骨架
+2. Canvas 页面布局
+3. 前端 artifact 数据模型
+4. 后端线程状态扩展
+5. 新建 Canvas Agent 图
+6. 前后端流式同步
+7. 整体生成与整体改写
+8. 局部选区改写
+9. 快捷动作
+10. 本地模型支持完善
+11. Web 搜索增强
+12. 导出与文件联动
+
+不要先做局部改写和快捷动作,否则前面的状态与路由契约不稳定,返工会很多。
+
+---
+
+## 19. 里程碑定义
+
+### M1:页面可进入
+
+- 路由接通
+- 双栏布局完成
+- 本地 mock artifact 可渲染
+
+### M2:后端状态打通
+
+- 线程可保存结构化 artifact
+- 页面刷新后能恢复
+
+### M3:AI 生成可用
+
+- 可新建文本/代码 artifact
+- 可整体改写
+- 可产生版本历史
+
+### M4:核心体验可用
+
+- 选区改写可用
+- 快捷动作可用
+- 模型切换可用
+
+### M5:增强能力完整
+
+- 本地模型支持完善
+- Web 搜索增强
+- 导出和文件联动
+
+---
+
+## 20. 风险与难点
+
+### 20.1 最大难点
+
+- 结构化 artifact 状态从无到有
+- 局部选区改写的精确性
+- 流式状态与版本管理的一致性
+- 不破坏现有 DeerFlow 文件型 artifact 体系
+
+### 20.2 技术风险
+
+- 线程 state JSON 结构过大
+- 大模型对局部改写指令遵循不稳定
+- 本地模型 tool calling 与流式能力差异大
+- 文本渲染态与源码态位置映射复杂
+
+### 20.3 规避建议
+
+- 首版只支持 Markdown 源码态编辑,不做复杂富文本编辑
+- 首版只支持文本和代码两种 artifact 类型
+- 首版先做整体生成和整体改写,再做局部改写
+- 本地模型先支持“能生成、能重写”的最小能力,不强求与顶级闭源模型完全同效
+
+---
+
+## 21. 验收总清单
+
+### 21.1 前端
+
+- 有独立 Canvas 路由
+- 有专用目录和模块边界
+- 双栏布局可用
+- 文本和代码两类 artifact 可渲染
+- 历史版本可切换
+- 选区改写可交互
+- 快捷动作可触发
+- 模型可切换
+
+### 21.2 后端
+
+- 线程状态支持 `artifact`
+- 新增 `canvas_agent` 或等价模式
+- 生成、重写、局部改写可用
+- 流式返回稳定
+- 模型列表接口支持 Canvas 能力元数据
+
+### 21.3 本地模型
+
+- 可配置 Ollama
+- 可配置 OpenAI-compatible 本地服务
+- 前端可见并可切换
+- 至少能完成文本生成和整体改写
+
+---
+
+## 22. 推荐首版最小可交付范围
+
+如果要控制风险,建议首版只交付以下内容:
+
+- 新增 `canvas/*` 路由
+- 双栏布局
+- 结构化 `artifact`
+- `canvas_agent`
+- 文本/代码 artifact 新建
+- 整体生成
+- 整体改写
+- 历史版本切换
+- 后端模型动态加载
+- Ollama 或本地 OpenAI-compatible 至少一种可用
+
+先不要把以下内容放进首版强制目标:
+
+- 富文本块级精确编辑
+- 全量快捷动作
+- 复杂 Web 搜索增强
+- 多 artifact 并行管理
+
+---
+
+## 23. 后续实施建议
+
+建议下一步基于本文档继续输出两份落地文档:
+
+### 23.1 前端实施清单
+
+逐文件列出:
+
+- 要新建哪些文件
+- 哪些组件可复用
+- 哪些页面要接入路由
+- 哪些状态要从现有 hooks 抽离
+
+### 23.2 后端实施清单
+
+逐模块列出:
+
+- 要改哪些 Python 文件
+- 新增哪些状态字段
+- 新增哪些 Agent 节点
+- 哪些 API 需要扩展
+
+---
+
+## 24. 结论
+
+这个需求很大,但完全可拆。
+
+正确做法不是“先抄 UI”,而是按下面的主线推进:
+
+- 先建前端 Canvas 子系统
+- 再建结构化 artifact 状态
+- 再建 Canvas Agent 图
+- 再补局部改写和快捷动作
+- 最后统一本地模型能力
+
+只要按本文档阶段推进,这个需求是可以落地的,而且能和你现在的 DeerFlow 架构保持长期兼容。