deerflow-code/frontend-web/docs/kaifawendnag.md
2026-09-07 18:24:55 +08:00

31 KiB
Raw Permalink Blame History

DeerFlow 前端开发文档

目录

  1. 整体目录结构
  2. 路由结构
  3. 核心数据流与状态管理
  4. 主要页面组件
  5. 核心业务组件
  6. 核心 Hooks 与工具函数
  7. API 调用层
  8. 国际化机制
  9. 主题与样式体系
  10. 关键业务流程
  11. 项目配置与依赖
  12. 常见开发模式

1. 整体目录结构

frontend-web/src/
├── App.tsx                        # 应用入口,顶层路由 + Provider
├── env.ts                         # 环境变量类型定义
├── pages/                         # 路由级页面组件
│   ├── PageRoutes.tsx             # /page/* 根路由容器(含外部系统预留位)
│   ├── WorkspaceRoutes.tsx        # /page/workspace/* 工作区路由
│   ├── LoginPage.tsx              # 登录页
│   ├── LandingPage.tsx            # 营销落地页(强制 dark 主题)
│   ├── ChatsPage.tsx              # 对话列表
│   ├── ChatPage.tsx               # 单条对话(核心页面)
│   ├── AgentsPage.tsx             # 智能体库
│   ├── AgentChatPage.tsx          # 与智能体对话
│   ├── NewAgentPage.tsx           # 创建智能体(两步流程)
│   ├── ScheduledTasksPage.tsx     # 定时任务管理
│   ├── ScheduledTaskRunDetailPage.tsx  # 定时任务执行详情
│   ├── ScheduledChatPage.tsx      # 定时任务对话跳转页
│   └── NotFoundPage.tsx           # 404 页面
├── components/                    # 业务组件库
│   ├── ui/                        # shadcn/ui 基础组件(Button、Card、Dialog 等 40+)
│   ├── ai-elements/               # AI 交互可视化组件
│   │   ├── prompt-input/          # 输入框 Context + 子组件系统
│   │   ├── artifact.tsx           # 制品展示
│   │   ├── canvas.tsx
│   │   ├── conversation.tsx       # 虚拟滚动对话容器
│   │   ├── message.tsx
│   │   ├── model-selector.tsx
│   │   ├── code-block.tsx
│   │   └── shimmer.tsx
│   ├── workspace/                 # 工作区业务组件(详见第 5 节)
│   └── landing/                   # 落地页组件
├── core/                          # 核心业务逻辑层(非 UI)
│   ├── api/                       # API 客户端(LangGraph SDK + Fetch)
│   ├── auth/                      # 认证管理
│   ├── config/                    # 环境配置 & Base URL
│   ├── i18n/                      # 国际化(上下文、翻译文件、语言检测)
│   ├── threads/                   # 对话线程管理(最核心)
│   ├── agents/                    # 智能体 CRUD
│   ├── models/                    # 模型列表
│   ├── settings/                  # 本地设置(LocalStorage 发布订阅)
│   ├── uploads/                   # 文件上传
│   ├── artifacts/                 # 制品管理
│   ├── memory/                    # 用户记忆
│   ├── skills/                    # 技能管理
│   ├── scheduled-tasks/           # 定时任务
│   ├── messages/                  # 消息处理工具函数
│   ├── tasks/                     # 子任务 Context
│   ├── notification/              # 系统通知
│   └── utils/                     # 通用工具(文件下载、日期格式化等)
└── hooks/                         # 全局自定义 hooks

2. 路由结构

项目使用 HashRouter,所有路由访问形如 http://host/#/xxx

2.1 App.tsx 顶层路由

路径 组件 说明
/ Navigate 重定向到 /login
/login LoginPage 登录(自动登录,无表单)
/login/:username LoginPage 带用户名登录
/landing LandingPage 营销落地页(固定 dark 主题)
/page/* PageRoutes 应用内容根容器
* NotFoundPage 404

2.2 PageRoutes.tsx(/page/*)

/page/
├── index              → Navigate to "workspace"
├── workspace/*        → WorkspaceRoutes
└── [TODO 预留]        → 外部系统路由挂载位置

2.3 WorkspaceRoutes.tsx(/page/workspace/*)

路径 页面组件 布局包裹
index Navigate → chats/new -
chats ChatsPage WorkspaceLayout
chats/:thread_id ChatPage WorkspaceLayout + ChatRuntime
agents AgentsPage WorkspaceLayout
agents/new NewAgentPage WorkspaceLayout
agents/:agent_id/chats Navigate → /page/workspace/agents -
agents/:agent_id/chats/:thread_id AgentChatPage WorkspaceLayout + ChatRuntime
scheduled Navigate → .../scheduled/tasks -
scheduled/tasks ScheduledTasksPage WorkspaceLayout
scheduled/runs/:run_id ScheduledTaskRunDetailPage WorkspaceLayout

2.4 布局 Provider 层级结构

WorkspaceLayout
├── SidebarProvider(侧边栏展开/收起状态)
│   ├── WorkspaceSidebar
│   │   ├── WorkspaceHeader(Logo、新建按钮)
│   │   ├── WorkspaceNavChatList(Chats / Agents / Scheduled 导航)
│   │   ├── RecentChatList(最近会话列表)
│   │   └── WorkspaceNavMenu(Settings / About / GitHub)
│   ├── SidebarInset(主内容区)
│   │   └── [Page Content]
│   ├── CommandPalette(快捷命令面板)
│   └── Toaster(全局通知)

ChatRuntime(仅 ChatPage / AgentChatPage 使用)
├── SubtasksProvider(子任务执行状态)
├── ArtifactsProvider(制品选中/打开状态)
└── PromptInputProvider(输入框内容/附件状态)

3. 核心数据流与状态管理

3.1 全局 Provider 架构

App
└── HashRouter
    └── AppProviders(useLocation 驱动主题判断)
        ├── NextThemesProvider
        │   └── attribute="class",/landing 强制 forcedTheme="dark"
        ├── I18nProvider
        │   └── initialLocale = detectLocale()(从 cookie 或浏览器语言)
        └── QueryClientProvider(TanStack React Query 全局缓存)

3.2 全局 Context 列表

Context 文件 职责 消费 Hook
I18nContext core/i18n/context.tsx 当前语言 + 翻译对象 useI18n()
SubtaskContext core/tasks/context.tsx 实时子任务执行状态 useSubtaskContext()
ArtifactsContext components/workspace/artifacts/context.tsx 制品选中/面板开关 useArtifacts()
PromptInputContext components/ai-elements/prompt-input/ 输入框内容、附件列表 usePromptInputController()
ThreadContext components/workspace/messages/context.tsx 当前 thread 对象下传 直接读 context.thread

3.3 LocalStorage 数据

操作层: core/settings/store.ts(发布-订阅,useSyncExternalStore 驱动响应式)

Key 内容
deerflow.auth { access_token, token_type, user_id, email }
deerflow.local-settings { notification, context: { model_name, mode, reasoning_effort } }
deerflow.thread-model.{threadId} 每条线程的模型覆盖

3.4 SessionStorage 数据

Key 内容
deerflow.run-id.{threadId} WebSocket run_id,用于断线重连

3.5 React Query 缓存 Key

Query Key 数据
["threads"] 线程列表
["thread", threadId] 单条线程
["agents"] 智能体列表
["models"] 模型列表
["skills"] 技能列表
["memory"] 用户记忆
["scheduled-tasks"] 定时任务列表
["scheduled-runs", taskId] 任务执行记录

4. 主要页面组件

4.1 ChatPage.tsx — 单条对话页面

职责: 管理单条聊天线程的完整交互,包括消息流、输入、工具调用展示、制品等。

关键状态:

const [threadId, setThreadId] = useState(routeThreadId || uuid());
const [isNewThread, setIsNewThread] = useState(!routeThreadId || routeThreadId === "new");
const [hasStartedConversation, setHasStartedConversation] = useState(false);
const [showFollowups, setShowFollowups] = useState(false);
const [settings, setSettings] = useThreadSettings(threadId);

核心 Hook:

const [thread, sendMessage, isUploading] = useThreadStream({
  threadId: isNewThread ? undefined : threadId,
  context: settings.context,
  onStart: (createdThreadId) => {
    setThreadId(createdThreadId);
    setIsNewThread(false);
    // 不刷新页面,直接更新 URL hash
    history.replaceState(null, "", `...#/page/workspace/chats/${createdThreadId}`);
  },
  onFinish: (state) => {
    // 后台通知
    showNotification(state.title, { body: lastMessageText });
  }
});

主要子组件:

组件 职责
<MessageList> 消息渲染(含工具调用、子任务、制品)
<Welcome> 新对话欢迎屏
<InputBox> 输入框(模式选择、附件、发送)
<ThreadTitle> 线程标题(自动生成后同步更新)
<ExportTrigger> 导出对话按钮
<ArtifactTrigger> 制品面板开关
<TokenUsageIndicator> Token 用量展示(可选)
<TodoList> 任务清单
<Suggestions> 追问建议

数据流:

用户输入 (InputBox)
  ↓ handleSubmit(message: PromptInputMessage)
  ↓ sendMessage(threadId, message)
  ↓ [内部] 上传文件 → 提交到 LangGraph API
  ↓ WebSocket 流返回消息
  ↓ thread.messages 更新 → MessageList 重渲染

4.2 AgentChatPage.tsx — 与智能体对话

与 ChatPage 结构基本一致,差异点:

  • 从路由获取 agent_id,传入 useThreadStream({ assistantId: agent_id })
  • Header 展示智能体名称 Badge
  • "新建对话"跳转到 /page/workspace/agents/${agent_id}/chats/new
  • URL 更新为 #/page/workspace/agents/${agent_id}/chats/${threadId}

4.3 NewAgentPage.tsx — 创建智能体(两步流程)

Step 1:name(命名 + 选技能)

// 自动预选前 3 个启用的技能
useEffect(() => {
  if (!isSkillSelectionTouched) {
    setSelectedSkills(enabledSkills.slice(0, 3).map(s => s.name));
  }
}, [enabledSkills]);

// 提交:验证名称 → 创建智能体
await checkAgentName(name);   // 检查重名
await createAgent(request);   // 创建,返回 agent.id
setStep("chat");              // 进入 Step 2

Step 2:chat(初始化对话)

// 发送 bootstrap 消息触发智能体初始化
sendMessage(threadId, bootstrapMessage, { agent_id: agentId });

// 监听 setup_agent 工具完成事件
onToolEnd: (event) => {
  if (event.name === "setup_agent") {
    // 带重试轮询加载 agent 最新信息
    retryLoadAgent(agentId);
  }
}

4.4 ChatsPage.tsx — 对话列表

const { data: threads } = useThreads({ limit: 50, sortBy: "updated_at" });

// 客户端过滤:排除定时任务线程 + 搜索关键词
const filteredThreads = useMemo(() =>
  threads?.filter(t =>
    t.metadata?.thread_type !== "scheduler" &&
    titleOfThread(t).toLowerCase().includes(search)
  ), [threads, search]
);

4.5 LoginPage.tsx — 登录

// 自动登录,无需用户操作
useEffect(() => {
  loginByUsername(username || "guest")
    .then(auth => {
      setStoredAuth(auth);
      router.replace("/page/workspace/chats/new");
    })
    .catch(err => setStatus("error"));
}, [username]);

4.6 ScheduledTasksPage.tsx — 定时任务

功能: 创建/编辑/发布/暂停/恢复定时任务,查看执行历史。

Cron 表达式构建:

type ScheduleFreq = "hourly" | "daily" | "weekly" | "monthly";

function buildCron(config): string {
  // hourly  → "15 * * * *"
  // daily   → "0 9 * * *"
  // weekly  → "0 9 * * 1"
  // monthly → "0 9 1 * *"
}

核心操作:

const actions = useScheduledTaskActions();
actions.create.mutateAsync(payload);
actions.publish.mutateAsync(taskId);
actions.pause.mutateAsync(taskId);
actions.trigger.mutateAsync(taskId);   // 立即执行一次
actions.subscribe.mutateAsync(params); // 订阅推送

5. 核心业务组件

5.1 消息系统(components/workspace/messages/)

文件 职责
message-list.tsx 消息列表容器,调用 groupMessages 分组后渲染
message-list-item.tsx 单条消息渲染(含 role 判断)
message-group.tsx 消息组(human / assistant / processing 等)
markdown-content.tsx Markdown 渲染(rehype 系列插件)
subtask-card.tsx 子任务状态卡片
message-token-usage.tsx 单条消息 Token 用量
skeleton.tsx 流式加载骨架屏
context.tsx ThreadContext,向下传递 thread 对象

消息分组类型(groupMessages):

type MessageGroup =
  | "human"                    // 用户输入
  | "assistant:processing"     // 推理/工具调用中
  | "assistant"                // 最终响应
  | "assistant:clarification"  // 澄清请求
  | "assistant:present-files"  // 文件呈现
  | "assistant:subagent";      // 子智能体消息

5.2 输入框(components/workspace/input-box.tsx)

子组件层级:

InputBox
└── PromptInput(Context Provider)
    ├── PromptInputBody
    │   ├── PromptInputTextarea(文本输入)
    │   ├── PromptInputAttachments(附件列表)
    │   └── PromptInputTools(工具栏:附件上传、模式选择)
    ├── PromptInputFooter
    │   ├── PromptInputSubmit(发送/停止按钮)
    │   └── Suggestions(追问建议列表)
    └── ModelSelector(模型下拉选择)

四种会话模式:

Mode 说明
flash 快速模式,无推理步骤
thinking 推理模式,开启深度思考
pro 专业模式,多模态 + 规划
ultra 超级模式,启用子智能体

推理努力等级(mode ≠ flash 时可选): minimal / low / medium / high


5.3 侧边栏(components/workspace/workspace-sidebar.tsx)

WorkspaceSidebar
├── SidebarHeader → WorkspaceHeader
│   ├── Logo(可点击,跳转 /page/workspace/chats/new)
│   └── 新建对话按钮
├── SidebarContent
│   ├── WorkspaceNavChatList
│   │   ├── 新建对话(/page/workspace/chats/new)
│   │   ├── 所有对话(/page/workspace/chats)
│   │   ├── 智能体(/page/workspace/agents)
│   │   └── 任务管理(/page/workspace/scheduled/tasks)
│   └── RecentChatList(最近会话,含搜索)
└── SidebarFooter → WorkspaceNavMenu
    ├── Settings(打开设置 Dialog)
    ├── About
    └── GitHub

5.4 制品管理(components/workspace/artifacts/)

interface ArtifactsContextType {
  artifacts: string[];             // artifact ID 列表
  selectedArtifact: string | null;
  autoSelect: boolean;             // 是否自动选中最新制品
  open: boolean;                   // 面板是否展开
  autoOpen: boolean;
  select(artifact: string, autoSelect?: boolean): void;
  deselect(): void;
  setOpen(open: boolean): void;
}

文件:

文件 职责
context.tsx ArtifactsContext + Provider
artifact-trigger.tsx 面板展开/收起按钮
artifact-file-list.tsx 制品文件列表
artifact-file-detail.tsx 单个制品详情(含代码编辑器)

5.5 设置面板(components/workspace/settings/)

页面文件 内容
appearance-settings-page.tsx 主题切换(light/dark/system)、语言切换
memory-settings-page.tsx 用户记忆(事实列表、总结管理)
notification-settings-page.tsx 桌面通知开关
skill-settings-page.tsx 技能启用/禁用
tool-settings-page.tsx 工具配置
about-settings-page.tsx 版本号、仓库链接

5.6 命令面板(components/workspace/command-palette.tsx)

通过 Cmd/Ctrl + K 触发,提供快速导航和操作入口。

const handleNewChat = useCallback(() => {
  router.push("/page/workspace/chats/new");
  setOpen(false);
}, [router]);

6. 核心 Hooks 与工具函数

6.1 useThreadStream(最核心 Hook)

位置: core/threads/hooks.ts

管理 LangGraph WebSocket 连接、消息流、乐观更新。

签名:

const [thread, sendMessage, isUploading] = useThreadStream({
  threadId?: string,               // 有值则连接现有线程,无值表示新建
  context: LocalSettings["context"], // 模型、模式等
  isMock?: boolean,
  assistantId?: string,            // 默认 "lead_agent"
  onStart?: (threadId: string) => void,
  onFinish?: (state: AgentThreadState) => void,
  onToolEnd?: (event: ToolEndEvent) => void,
});

thread 对象关键属性:

thread: {
  messages: Message[],      // 含乐观消息的完整列表
  isLoading: boolean,       // 流是否进行中
  isThreadLoading: boolean, // 初始线程数据是否加载中
  values: AgentThreadState, // 线程最终状态
  error?: Error,
  stop: async () => void,   // 终止当前流
}

sendMessage 签名:

sendMessage(
  threadId: string | undefined,
  message: PromptInputMessage,
  extraContext?: Partial<AgentThreadContext>,
  options?: { isMock?: boolean }
): Promise<void>

内部机制:

  • 乐观更新: 用户发送后立即本地展示消息,不等服务端响应
  • 文件上传: 自动调用 uploadFiles() 后再提交
  • run_id 持久化: sessionStorage 保存,支持页面刷新后断线重连
  • 消息同步: 流结束后通过 queryClient.invalidateQueries(["threads"]) 刷新列表

6.2 useThreadSettings

位置: core/settings/hooks.ts

const [settings, setSettings] = useThreadSettings(threadId);

// settings 结构
{
  notification: { enabled: boolean },
  context: {
    model_name?: string,
    mode: "flash" | "thinking" | "pro" | "ultra",
    reasoning_effort?: "minimal" | "low" | "medium" | "high"
  }
}

// 修改(合并更新)
setSettings("context", { mode: "pro" });
setSettings("notification", { enabled: true });

工作原理: useSyncExternalStore 监听 localStorage 变化,跨标签页同步。


6.3 useI18n

位置: core/i18n/hooks.ts

const { t, locale, changeLocale } = useI18n();

t.sidebar.newChat          // "New Chat"
t.agents.createPageTitle   // "Create Agent"
t.toolCalls.moreSteps(3)   // "Show 3 more steps"

changeLocale("zh-CN");     // 切换语言,自动存 cookie

6.4 useScheduledTaskActions

位置: core/scheduled-tasks/hooks.ts

const actions = useScheduledTaskActions();

// 所有返回值均为 TanStack Query Mutation
actions.create           // 创建定时任务
actions.update           // 更新任务配置
actions.remove           // 删除任务
actions.removeRun        // 删除执行记录
actions.pause            // 暂停
actions.resume           // 恢复
actions.trigger          // 立即触发一次
actions.publish          // 发布(激活)
actions.unpublish        // 取消发布
actions.subscribe        // 订阅推送
actions.updateSubscription
actions.unsubscribe

6.5 工具函数

消息处理(core/messages/utils.ts):

groupMessages(messages, mapper)            // 按类型分组消息列表
extractTextFromMessage(message)            // 提取纯文本
extractContentFromMessage(message)         // 提取 Markdown/图像内容
extractReasoningContentFromMessage(msg)    // 提取推理过程
hasToolCalls(message)                      // 是否含工具调用
hasPresentFiles(message)                   // 是否包含文件呈现
extractPresentFilesFromMessage(message)    // 获取文件列表
isClarificationToolMessage(message)        // 是否为澄清请求

线程路由(core/threads/utils.ts):

pathOfThread(thread, context?)
// → "/page/workspace/agents/{agentRef}/chats/{threadId}"
// 或 "/page/workspace/chats/{threadId}"

titleOfThread(thread)
// → thread.values?.title ?? "Untitled"

textOfMessage(message)
// → 消息文本内容(string 或 content 数组中第一个 text)

其他工具:

// core/utils/files.tsx
downloadFile(blob: Blob, filename: string)

// core/utils/datetime.ts
formatTimeAgo(dateString: string)  // → "2 小时前" / "3 days ago"

7. API 调用层

7.1 API 客户端架构

两层设计:

第一层:LangGraph SDK Client(core/api/api-client.ts)

const client = new LangGraphClient({
  apiUrl: getLangGraphBaseURL(isMock),
  onRequest(url, init) {
    const headers = new Headers(init.headers ?? {});
    headers.set("Authorization", getAuthorizationHeaderValue());
    return { ...init, headers };
  }
});

export function getAPIClient(isMock?: boolean): LangGraphClient

第二层:Fetch Client(core/api/fetch-client.ts)

function apiFetch(input: RequestInfo, init?: RequestInit): Promise<Response> {
  return fetch(input, {
    ...init,
    headers: withAuthHeaders(init?.headers)
  });
}

7.2 主要 API 模块

模块 文件 关键函数
Auth core/auth/api.ts loginByUsername(username) → LoginByUsernameResponse
Agents core/agents/api.ts createAgent(), updateAgent(), listAgents(), deleteAgent(), checkAgentName()
Models core/models/api.ts loadModels() → Model[]
Threads (via LangGraph SDK) useThreadStream(), useThreads(), useDeleteThread(), useRenameThread()
Skills core/skills/api.ts loadSkills(), enableSkill(name, enabled)
Uploads core/uploads/api.ts uploadFiles(threadId, files[]), listUploadedFiles(), deleteUploadedFile()
Memory core/memory/api.ts loadMemory(), createMemoryFact(), updateMemoryFact(), deleteMemoryFact()
Scheduled Tasks core/scheduled-tasks/api.ts CRUD、publish、pause、resume、trigger、subscribe

7.3 Base URL 配置

文件: core/config/index.ts

export function getBackendBaseURL(): string {
  // env.NEXT_PUBLIC_BACKEND_BASE_URL
  // 默认:""(当前域名根路径)
}

export function getLangGraphBaseURL(isMock?: boolean): string {
  // mock 模式:${origin}/mock/api
  // 正常:${origin}/api/langgraph
  // 或读取 env.NEXT_PUBLIC_LANGGRAPH_BASE_URL
}

7.4 认证流程

LoginPage 调用 loginByUsername(username)
  ↓ POST /api/auth/login
  ↓ 返回 { access_token, token_type, user_id, email }
  ↓ setStoredAuth() 存入 localStorage["deerflow.auth"]
  ↓
后续所有 API 请求
  ↓ getAuthorizationHeaderValue()
  ↓ → "Bearer {access_token}"
  ↓ 自动添加到 Authorization header

8. 国际化机制

8.1 文件结构

core/i18n/
├── context.tsx          # I18nProvider(包裹 App)
├── hooks.ts             # useI18n()
├── locale.ts            # detectLocale(),Locale = "en-US" | "zh-CN"
├── cookies.ts           # cookie 读写(持久化语言选择)
├── translations.ts      # 翻译映射表入口
└── locales/
    ├── types.ts         # Translations 接口定义(所有翻译 key 的类型)
    ├── en-US.ts         # 英文翻译
    └── zh-CN.ts         # 简体中文翻译

8.2 Translations 接口分类

interface Translations {
  locale: { localName: string }         // 语言自身名称
  common: { ... }                       // 通用词汇(确认、取消等)
  welcome: { ... }                      // 欢迎屏
  inputBox: { ... }                     // 输入框(模式、占位符)
  sidebar: { ... }                      // 侧边栏导航
  agents: { ... }                       // 智能体相关
  chats: { ... }                        // 对话相关
  workspace: { ... }                    // 工作区通用
  settings: { ... }                     // 设置面板
  toolCalls: { ... }                    // 工具调用展示
  uploads: { ... }                      // 文件上传
  subtasks: { ... }                     // 子任务
  tokenUsage: { ... }                   // Token 用量
  shortcuts: { ... }                    // 快捷键说明
}

8.3 语言检测优先级

  1. 读取 cookie deerflow.locale
  2. 读取浏览器 navigator.language
  3. 回退到 en-US

9. 主题与样式体系

9.1 主题系统

库: next-themes

// App.tsx
<NextThemesProvider
  attribute="class"           // 通过 <html class="dark"> 应用主题
  enableSystem               // 跟随系统偏好
  disableTransitionOnChange  // 切换时禁用过渡动画
  forcedTheme={pathname === "/landing" ? "dark" : undefined}
>

可选主题值: light / dark / system

9.2 样式方案

基础: Tailwind CSS

组件库: shadcn/ui(components/ui/ 目录,40+ 基础组件)

主要 CSS 自定义属性:

--container-width-sm    /* 小容器宽度 */
--container-width-md    /* 中等容器宽度(对话主区域) */
--primary               /* 主色 */
--background            /* 页面背景 */
--foreground            /* 主文本色 */
--muted-foreground      /* 次要文本色 */
--border                /* 边框色 */
--sidebar-foreground    /* 侧边栏文本 */

9.3 样式使用规范

  • 工具类优先(Tailwind)
  • 动态样式用 cn() 工具函数合并(基于 clsx + tailwind-merge)
  • 主题感知样式使用 CSS 变量(如 text-muted-foreground)

10. 关键业务流程

10.1 新建对话流程

1. 点击"新建对话" → navigate("/page/workspace/chats/new")
2. ChatPage 挂载,threadId = uuid(),isNewThread = true
3. 用户输入消息,点击发送
4. sendMessage(undefined, message) 调用
5. useThreadStream 内部:
   a. 上传文件(若有)
   b. 创建 LangGraph 线程,后端返回 threadId
   c. onStart(threadId) 回调:
      - setIsNewThread(false)
      - history.replaceState 更新 URL hash
6. WebSocket 流开始接收 AI 消息
7. MessageList 实时渲染消息
8. 流结束,onFinish 回调,可能触发桌面通知

10.2 创建智能体流程

Step 1(name 步骤)
  ↓ 用户输入名称
  ↓ checkAgentName(name) → 验证是否重名
  ↓ createAgent({ name, skills: selectedSkills })
  ↓ 后端返回 agent.id,setStep("chat")

Step 2(chat 步骤)
  ↓ 生成临时 threadId
  ↓ useThreadStream({ assistantId: agent.id })
  ↓ 发送 bootstrap 消息(触发智能体自我设置)
  ↓ onToolEnd 监听:event.name === "setup_agent"
  ↓ 指数退避重试加载 agent 信息,确认已保存
  ↓ 显示"Agent Created"完成界面
  ↓ 用户可点击"开始对话"或"返回列表"

10.3 文件上传流程

1. 用户在 InputBox 选择/粘贴文件
2. PromptInputAttachments 展示预览列表
3. 用户点击发送
4. sendMessage 内部调用 uploadFiles(threadId, files)
5. POST /api/threads/{threadId}/upload
6. 后端返回 { files: [{ filename, size, virtual_path }] }
7. 构建 Message additional_kwargs.files
8. 完整 Message 提交到 LangGraph

11. 项目配置与依赖

11.1 主要依赖

包 版本 用途
react ^18 核心框架
react-router-dom ^6 客户端路由(HashRouter)
@tanstack/react-query - 服务端状态缓存
@langchain/langgraph-sdk - LangGraph WebSocket 连接
next-themes - 主题管理
sonner - Toast 通知
lucide-react - 图标库
tailwindcss - CSS 框架
rehype 系列 - Markdown 渲染
uuid - 生成临时 thread ID

11.2 环境变量

变量 说明 默认值
NEXT_PUBLIC_BACKEND_BASE_URL 后端接口基础 URL "" (当前域名)
NEXT_PUBLIC_LANGGRAPH_BASE_URL LangGraph API URL /api/langgraph
NEXT_PUBLIC_STATIC_WEBSITE_ONLY 纯静态演示模式 "false"

12. 常见开发模式

12.1 添加新工作区页面

1. 创建 src/pages/MyPage.tsx
2. 在 WorkspaceRoutes.tsx 中添加路由:
   <Route path="my-page" element={<WorkspaceLayout><MyPage /></WorkspaceLayout>} />
3. 在 workspace-nav-chat-list.tsx 中添加导航入口(如需要)
4. 更新相关的跳转路径

12.2 添加新 API 接口

1. 在 core/xxx/api.ts 中定义 API 函数(使用 apiFetch 或 getAPIClient())
2. 在 core/xxx/hooks.ts 中封装 useQuery / useMutation
3. 在页面或组件中调用 hook

12.3 添加新 Context

1. 创建 core/xxx/context.tsx:定义 Context + Provider + 默认值
2. 创建消费 hook(如 useXxx())
3. 在合适的组件树根部插入 Provider(WorkspaceRoutes 或 ChatRuntime)

12.4 添加国际化文本

1. 在 core/i18n/locales/types.ts 的 Translations 接口中添加字段
2. 在 core/i18n/locales/en-US.ts 添加英文内容
3. 在 core/i18n/locales/zh-CN.ts 添加中文内容
4. 组件中通过 useI18n() 访问:const { t } = useI18n(); t.xxx.yyy

12.5 引入外部系统路由

在 src/pages/PageRoutes.tsx 中找到 TODO 注释位置,填入:

import AnotherSystemRoutes from "外部系统路径";

// 在 Routes 中添加:
<Route path="other/*" element={<AnotherSystemRoutes />} />

如外部系统有独立 Provider 依赖,在此文件或 App.tsx 中包裹。


附:关键文件速查

需求 关键文件
修改路由结构 App.tsx, PageRoutes.tsx, WorkspaceRoutes.tsx
修改侧边栏导航 components/workspace/workspace-nav-chat-list.tsx
修改对话逻辑 pages/ChatPage.tsx, core/threads/hooks.ts
修改输入框 components/workspace/input-box.tsx, components/ai-elements/prompt-input/
修改消息渲染 components/workspace/messages/
添加 API 接口 core/xxx/api.ts + core/xxx/hooks.ts
修改全局设置 core/settings/store.ts, core/settings/hooks.ts
修改翻译文本 core/i18n/locales/en-US.ts, core/i18n/locales/zh-CN.ts
修改主题 App.tsx (NextThemesProvider)
修改认证逻辑 core/auth/api.ts, pages/LoginPage.tsx
定时任务 pages/ScheduledTasksPage.tsx, core/scheduled-tasks/
智能体管理 pages/NewAgentPage.tsx, core/agents/