Files
deerflow-code/web-code/components/agent/doc.md
T
2026-05-28 18:29:37 +08:00

25 KiB
Raw Blame History

Agent 组件开发问答(Q&A)

目录范围:src/components/agent

涵盖文件:

  • AgentExpertCenterPage.tsx
  • AgentExpertEditPage.tsx
  • AgentChatPage.tsx
  • SkillCreatorPage.tsx
  • SkillsWorkshop.tsx
  • SkillCreatorThreadSidebar.tsx
  • AgentConversationList.tsx
  • SkillCreatorConversationItem.tsx
  • ChatInputComposer.tsx
  • AgentChatPage.css

Q1:这个目录整体是干什么的?

A:这是“专家 Agent + 技能工坊 + 技能创建对话”的前端 UI 组件集合。

  • AgentExpertCenterPage:专家列表入口(我的专家/发布专家)。
  • AgentExpertEditPage:专家配置编辑页(左侧对话预览 + 右侧配置)。
  • AgentChatPage:某个专家的真实聊天页(含线程、文件上传、流式回答)。
  • SkillsWorkshop:技能资产中心(搜索/筛选/接入/发布/删除/编辑)。
  • SkillCreatorPage:技能创建/改写专用对话页(支持文件树预览和保存弹窗)。
  • SkillCreatorThreadSidebar:复用的会话侧边栏(获取线程、新建、删除、切换)。
  • AgentConversationList + SkillCreatorConversationItem:统一消息列表与消息卡片渲染。
  • ChatInputComposer:统一输入框(发送/停止/上传)。
  • AgentChatPage.css:AgentChatPage 专用动画和滚动条样式。

Q2:核心共享数据模型有哪些?

A:对话层主要围绕 ConversationMessage。

  • 定义位置:AgentConversationList.tsx
  • 字段:
    • id: 消息唯一标识。
    • role: 'user' | 'assistant'
    • content: 文本内容(markdown 渲染)。
    • steps: 思考步骤列表(数据来自 data-thinking-step)。
    • thinkings: 推理内容列表(来自 reasoning-* 事件)。
    • toolCalls: 工具调用(输入输出)列表。

A:文件树使用 FileNode。

  • 在 AgentChatPage、SkillCreatorPage 内部定义并使用。
  • 字段:name/path/type/size/extension/children。

A:线程侧边栏使用 SkillCreatorThread。

  • 定义位置:SkillCreatorThreadSidebar.tsx
  • 字段:id/title/archived/expert_agent_id/created_at/updated_at。

Q3:整个目录的“数据流主干”怎么走?

A:可以看成 3 条主链路。

1) 专家链路(Center -> Edit -> Chat)

  1. AgentExpertCenterPage 拉专家列表(我的/发布)。
  2. 点击“编辑”跳 AgentExpertEditPage,加载专家详情 + 工具 + 技能绑定状态。
  3. 点击“进行对话”跳 AgentChatPage,加载该专家详情和对应会话消息。

2) 技能链路(Workshop -> SkillCreator)

  1. SkillsWorkshop 拉技能列表(official/mine),本地映射成 UI Skill。
  2. 新建技能:创建会话后跳 SkillCreatorPage?id=threadId。
  3. AI 辅助编辑已有技能:先创建线程,再 copy skill 到线程,再跳转 SkillCreatorPage。

3) 对话链路(输入 -> SSE -> UI -> 持久化)

  1. ChatInputComposer 触发 onSend。
  2. 页面组件(AgentChatPage 或 SkillCreatorPage)执行 handleSendMessage。
  3. 先写入用户消息 + assistant 占位消息。
  4. 调流式接口读取 SSE:
    • data-thinking-step -> 更新 steps
    • reasoning-start/delta/end -> 更新 thinkings
    • tool-input-available/tool-output-available -> 更新 toolCalls
    • text-delta -> 追加 content
  5. 完成后将 assistant 结果再次 POST 到消息接口持久化。

Q4:AgentExpertCenterPage 组件是干什么的?

A:专家资产“总览入口”,负责展示列表和基础操作入口。

组件职责

  • 展示“我的专家”和“发布专家”两种视图。
  • 打开专家详情弹窗(支持发布状态切换)。
  • 提供“编辑”和“进行对话”跳转入口。

数据来源与接口

  • 列表查询:
    • POST /api/v1/expert-agents/list(按 is_draft)
    • 我的专家场景还会额外 GET /api/v1/expert-agents 做合并去重。
  • 状态切换:
    • PATCH /api/v1/expert-agents/{id}(更新 is_draft)

数据流

  • activeTab 改变 -> fetchExpertList 触发 -> 更新 agentList。
  • agentList -> cards(useMemo) -> 渲染卡片。
  • 卡片按钮:
    • 编辑 -> navigate('/qa-center/agent-expert-edit?id=...')
    • 对话 -> navigate('/qa-center/agent-chat?id=...')

维护注意

  • “创建专家”按钮目前是 UI 壳子,未接创建接口。
  • “删除”按钮当前仅 console.log,未接真实删除逻辑。

Q5:AgentExpertEditPage 组件是干什么的?

A:专家配置编辑工作台,同时内置一个“测试对话区”。

组件职责

  • 左侧:和该专家进行流式对话(非真实聊天线程,使用 no_real 线程)。
  • 右侧:编辑专家基础配置(名称、模型、描述、系统提示词)。
  • 管理工具绑定、技能绑定(弹窗操作)。

关键状态

  • 对话相关:messages/inputValue/threadId/isStreaming
  • 配置相关:formValues
  • 工具相关:toolOptions/selectedTools/pendingTools/boundToolIdMap
  • 技能相关:skillOptions/selectedSkills/boundSkillMap/skillKeyword

主要接口

  • 专家详情:GET /api/v1/expert-agents/{agentId}
  • 保存专家:PUT /api/v1/expert-agents/{agentId}
  • 绑定工具:
    • 查询:GET /api/v1/expert-agents/{agentId}/tools
    • 添加:POST /api/v1/expert-agents/{agentId}/tools
    • 删除:DELETE /api/v1/expert-agents/{agentId}/tools/{toolId}
  • 绑定技能:
    • 查询:GET /api/v1/expert-agents/{agentId}/skills
    • 添加:POST /api/v1/expert-agents/{agentId}/skills
    • 删除:DELETE /api/v1/expert-agents/{agentId}/skills/{skillId}
  • 测试对话:
    • 线程:GET /api/v1/expert-agent-chat/threads/no_real/{agentId}
    • 用户消息:POST /api/v1/expert-agent-chat/messages
    • SSE:POST /api/v1/expert-agent-chat/run/stream/help_expert

数据流(对话)

  • 用户发送 -> append user msg -> 保证 threadId -> 保存用户消息 -> append assistant 占位 -> SSE 增量更新。

维护注意

  • 右侧 preview 区底部 ChatInputComposer 是只读展示,不参与真实请求。
  • 工具与技能弹窗是“前端状态 + 后端同步”双层状态,调试时优先检查 refresh 查询是否成功。

Q6:AgentChatPage 组件是干什么的?

A:专家“真实聊天页”,并带线程管理、文件上传和文件预览。

组件职责

  • 根据 URL id 读取专家详情。
  • 管理当前线程(localStorage 持久化)。
  • 获取历史消息并转换为统一消息结构。
  • 流式发送消息并渲染思考过程。
  • 管理会话文件(上传、树形结构、预览、侧栏缩放)。

关键状态

  • 会话:currentThreadId/messages/inputValue/isStreaming/isLoading
  • UI:isThreadSidebarOpen/autoScrollEnabled/showScrollButton
  • 文件:fileList/fileListThreadId/isFileSidebarOpen/expandedPaths/selectedFile/filePreview*

主要接口

  • 专家详情:GET /api/v1/expert-agents/{agentId}
  • 会话消息:
    • 历史:GET /api/v1/expert-agent-chat/threads/{id}/messages
    • 保存用户:POST /api/v1/expert-agent-chat/messages
    • SSE:POST /api/v1/expert-agent-chat/run/stream
    • 保存助手:POST /api/v1/expert-agent-chat/messages
  • 文件:
    • 列表:GET /api/v1/expert-agent-chat/threads/{id}/files/all
    • 上传:POST /api/v1/expert-agent-chat/threads/{id}/files/upload
    • 预览:GET /api/v1/expert-agent-chat/threads/{id}/files/preview?path=...

关键行为细节

  • 发送即出现 assistant 占位:点击发送后立即插入 assistant 空消息,保证用户立刻看到“连接中”态。
  • 连接中显示规则:由 AgentConversationList 判断“最后一条 assistant 且还没有任何生成内容”才显示连接状态。
  • 失败回滚:发送或流式失败时移除该 assistant 占位,避免残留空卡片。
  • 停止流式:AbortController 中断请求,并清理 loading 态字段。

维护注意

  • threadStorageKey 与 agentId 强绑定,切换专家会切换独立 thread 记忆。
  • normalizeHistoryContent 是历史消息兼容核心,后端 content 结构变更时先改这里。

Q7:SkillCreatorPage 组件是干什么的?

A:技能创建/重构专用对话页,结构上是 AgentChatPage 的“技能场景定制版”。

组件职责

  • 从 query/localStorage 同步当前线程 ID。
  • 加载技能会话历史与会话文件。
  • 走技能专属流式接口输出思考步骤/推理/tool call/文本。
  • 提供“保存技能”弹窗(当前主要是 UI + 本地状态)。

与 AgentChatPage 的主要差异

  • 线程 ID 同步到 URL(useSearchParams)。
  • 有独立 isConnecting 状态,用于连接中阶段展示。
  • 流式接口是:POST /api/v1/expert-agent-chat/skills-agent
  • 页面内注入了 dot/shimmer 动画样式(供消息连接中态使用)。

主要接口

  • 会话消息:GET /threads/{id}/messages
  • 流式:POST /skills-agent
  • 保存 assistant:POST /messages
  • 文件:GET all / POST upload / GET preview

数据流

  • 发消息 -> append 用户 + assistant 占位 -> isConnecting=true -> 收到首个流块后 isConnecting=false -> 增量刷新 assistant -> 持久化。

维护注意

  • 保存技能按钮目前仅 console.log 输出技能名和描述,未接正式后端保存接口。

Q8:SkillsWorkshop 组件是干什么的?

A:技能资产管理页(发现、筛选、接入、发布、删除、进入编辑)。

组件职责

  • 拉取 official 与 mine 技能,映射成统一 UI 结构。
  • 支持搜索、类型筛选、分类筛选。
  • 支持官方技能接入到“我的技能”。
  • 支持发布、删除、编辑(编辑弹窗支持 AI 编辑和上传覆盖)。
  • 支持“新建技能体”:Agent 对话创建 / 上传文件创建。

主要接口

  • 列表:GET /api/v1/skills?type=official|mine
  • 发布:POST /api/v1/expert-agents/skills/publish
  • 删除我的技能:DELETE /api/v1/skills/mine/{skillId}
  • 上传覆盖:PUT /api/v1/skills/{skillId}/upload
  • 接入官方技能:POST /api/v1/skills/mine/add
  • 上传创建:POST /api/v1/skills/upload
  • Agent 创建线程:POST /api/v1/expert-agent-chat/threads
  • AI 编辑复制技能:POST /threads/{threadId}/copy-skill/{skillId}

数据流

  • filter/search 改变 -> useEffect 重新拉取技能 -> 本地去重并缓存到 skills。
  • 卡片编辑 -> editingSkill 打开弹窗 -> 选择 AI 编辑时创建线程后跳 SkillCreatorPage。

维护注意

  • inferCategory 是关键词规则映射,新增技能类型时可优先扩展该规则。
  • “进入”按钮目前使用 skill.id 跳 skill-creator,若后端语义改成 threadId 需调整。

Q9:SkillCreatorThreadSidebar 组件是干什么的?

A:会话线程管理的复用侧边栏。

组件职责

  • 打开时加载会话列表。
  • 新建会话并自动选中。
  • 删除会话并在当前会话被删时自动回退到其它会话。
  • 支持线程过滤(如仅展示当前专家线程)。

输入输出(Props 视角)

  • 输入:authedFetch/currentThreadId/isOpen/isBusy/threadFilter/createThreadPayload...
  • 输出:
    • onThreadSelect(threadId)
    • onClose()

数据流

  • isOpen 从 false -> true:触发 refreshThreads。
  • 新建成功:更新本地列表并触发 onThreadSelect。
  • 删除成功:本地移除;若删的是当前线程,自动选择 fallback。

维护注意

  • createThreadPayload 是高复用扩展点,场景页可注入 expert_agent_id/title 等字段。

Q10:AgentConversationList 组件是干什么的?

A:统一遍历消息并决定“连接中状态”是否显示。

核心逻辑

  • 逐条渲染 SkillCreatorConversationItem。
  • 只在以下条件满足时给最后一条 assistant 传 isConnecting=true:
    • 页面处于连接/流式阶段;
    • 当前消息是最后一条 assistant;
    • 且还没有任何实际生成内容(content/steps/thinkings/toolCalls 都为空)。

价值

  • 将“连接中占位显示时机”从页面组件抽离,统一控制,减少重复判断代码。

Q11:SkillCreatorConversationItem 组件是干什么的?

A:单条消息卡片渲染器(用户消息 + 助手多面板消息)。

渲染结构

  • 用户消息:右侧气泡 + user avatar。
  • 助手消息:左侧 avatar + 多段内容:
    • StepsSummary
    • ThinkingPanel[]
    • ToolCallPanel[]
    • 连接中动画文案(正在连接技能服务...)
    • Markdown 正文

数据来源

  • 完全由父级传入 message 和 isConnecting 控制,不直接请求后端。

维护注意

  • 此组件是所有对话页的统一呈现层;若改动 message schema,要同步更新这里的各面板。

Q12:ChatInputComposer 组件是干什么的?

A:通用输入组件,封装输入、发送/停止、上传文件。

输入输出(Props)

  • 输入:value/disabled/readOnly/isSending/isDarkMode/showUpload/placeholder...
  • 回调:
    • onChange(value)
    • onSend()
    • onStop()
    • onUploadFile(file)

关键交互

  • Enter(非 Shift)触发发送(前提:submitEnabled 且非 isSending)。
  • 发送按钮在发送中切换为停止按钮(onClick={isSending ? onStop : onSend})。
  • 文件上传通过隐藏 input[type=file] + 按钮触发。

维护注意

  • 当前实现里文本框只受 disabled 控制,不再因为 isSending 禁止输入。
  • 上传按钮仍受 disabled || !onUploadFile 控制。

Q13:AgentChatPage.css 主要做了什么?

A:提供 AgentChatPage 的辅助样式。

  • .agent-resizing:拖拽文件侧栏时全局 cursor/user-select 控制。
  • .agent-file-tree-scroll / .agent-file-preview-scroll:滚动条样式统一。
  • .agent-file-markdown-preview:markdown 首尾边距和图片样式收敛。
  • .animate-breathing 等动画类:预留呼吸动效。

Q14:典型业务流程:发送一条消息时,数据如何传输?

A:以 AgentChatPage 为例。

  1. 用户在 ChatInputComposer 输入后点击发送。
  2. handleSendMessage 校验 text/threadId/isStreaming。
  3. 立即写入:
    • user message
    • assistant 占位 message(空内容)
  4. 调 POST /messages 落用户消息。
  5. 调 POST /run/stream 开始 SSE。
  6. 每个 SSE event 增量更新 assistant message:
    • step -> steps
    • reasoning -> thinkings
    • tool -> toolCalls
    • text -> content
  7. 流结束后将聚合结果组装成 persistedContent,再 POST /messages 落库。
  8. 刷新文件列表(对可能新增输出文件做同步)。

Q15:典型业务流程:从技能工坊进入技能创建页,数据如何传输?

A:两种入口。

入口 A:新建技能(Agent 构建)

  1. SkillsWorkshop.handleCreateSkillByAgent 创建线程。
  2. 将 threadId 写入 localStorage。
  3. 跳转 navigate('/qa-center/skill-creator?id=threadId')。
  4. SkillCreatorPage 用 query/localStorage 同步 currentThreadId,然后拉消息和文件。

入口 B:AI 辅助编辑已有技能

  1. 创建线程。
  2. POST /threads/{threadId}/copy-skill/{skillId} 把技能内容复制到线程工作区。
  3. 跳转 SkillCreator 页面,后续在线程中对话编辑。

Q16:如果要新增一个“对话页”,建议复用哪些组件?

A:建议最小复用组合如下。

  • 消息列表:AgentConversationList
  • 单消息卡片:SkillCreatorConversationItem(自动包含 steps/thinking/tool 等面板)
  • 输入框:ChatInputComposer
  • 线程侧边栏:SkillCreatorThreadSidebar

页面层只负责:

  • 状态管理(messages/input/isStreaming/currentThreadId)
  • 接口请求(历史 + SSE + 持久化)
  • 事件映射(把后端事件转为 ConversationMessage 结构)

Q17:维护时最容易踩坑的点有哪些?

A:建议优先关注这 8 个点。

  1. SSE 事件兼容性:后端 event type 或字段名变化会直接导致 UI 不更新。
  2. 历史内容兼容:normalizeHistoryContent 没跟上 content schema 会出现历史消息空白。
  3. 线程切换中断:切换线程时要记得 abort 流并清状态,避免串流到新线程。
  4. 占位消息回收:发送失败/流失败需移除 assistant 占位,避免残留空卡片。
  5. threadId 语义一致性:某些页面参数传 skillId/agentId,需避免误当 threadId 使用。
  6. 工具/技能绑定状态双源:本地状态和后端状态不同步时,优先以 refresh 查询结果为准。
  7. 上传入口 accept 限制:上传文件类型修改时要同步后端校验和 UI 提示。
  8. 深色主题样式:该目录深色/浅色分支很多,改样式需双主题回归。

Q18:后续文档扩展建议

A:当前文档适合开发入门,下一步可补充“接口契约版”。

  • 补完整 SSE event JSON 示例(每种事件一例)。
  • 增加错误码到 UI 提示映射表。
  • 补一份“页面状态机图”(Idle / Connecting / Streaming / Stopped / Error)。
  • 给每个页面补“可测点清单”(单测/联调/回归)。

Q19:能否给一份可联调的“接口契约附录”?

A:可以,以下按模块整理。

1) 专家模块(Expert)

  • 查询专家列表

    • POST /api/v1/expert-agents/list
    • 请求体:
      • is_draft: boolean
    • 响应(数组项):
      • id/name/avatar_url/description/model_name/is_draft/user_id/created_at
  • 查询专家详情

    • GET /api/v1/expert-agents/{agentId}
    • 响应关键字段:
      • id/name/description/system_prompt/model_name
  • 更新专家配置

    • PUT /api/v1/expert-agents/{agentId}
    • 请求体关键字段:
      • name
      • description
      • system_prompt
      • model_name
      • avatar_url(当前传 null)
  • 切换草稿/发布状态

    • PATCH /api/v1/expert-agents/{agentId}
    • 请求体:
      • is_draft: boolean

2) 线程与消息模块(Chat Thread + Message)

  • 查询线程列表

    • GET /api/v1/expert-agent-chat/threads
    • 响应:
      • threads: SkillCreatorThread[]
      • archived_threads: SkillCreatorThread[]
  • 新建线程

    • POST /api/v1/expert-agent-chat/threads
    • 请求体常见字段:
      • title
      • archived
      • is_real_chat
      • expert_agent_id(专家聊天场景)
  • 删除线程

    • DELETE /api/v1/expert-agent-chat/threads/{threadId}
  • 查询线程消息历史

    • GET /api/v1/expert-agent-chat/threads/{threadId}/messages
    • 响应消息项关键字段:
      • id/thread_id/role/content/created_at
  • 保存消息(用户或助手)

    • POST /api/v1/expert-agent-chat/messages
    • 请求体(用户消息):
      • thread_id
      • role: "user"
      • content: { type: "text", text: string }
    • 请求体(助手消息):
      • thread_id
      • role: "assistant"
      • content: persistedContent[]

3) 流式回复模块(SSE)

  • 专家聊天流式

    • POST /api/v1/expert-agent-chat/run/stream
    • 请求体关键字段:
      • chat_id
      • expert_agent_id
      • user_query
      • messages
  • 专家编辑页测试流式

    • POST /api/v1/expert-agent-chat/run/stream/help_expert
  • 技能创建流式

    • POST /api/v1/expert-agent-chat/skills-agent
    • 请求体关键字段:
      • chat_id
      • user_query

4) 文件模块(线程文件)

  • 查询线程文件树

    • GET /api/v1/expert-agent-chat/threads/{threadId}/files/all
  • 上传文件

    • POST /api/v1/expert-agent-chat/threads/{threadId}/files/upload
    • form-data:
      • file
  • 文件预览

    • GET /api/v1/expert-agent-chat/threads/{threadId}/files/preview?path=...
    • 兼容响应:
      • 文本
      • JSON 字符串
      • JSON 对象中的 content

5) 技能模块(Skills)

  • 查询技能列表

    • GET /api/v1/skills?type=official|mine|all&keyword=&page=1&page_size=100
  • 发布技能

    • POST /api/v1/expert-agents/skills/publish
    • 请求体:
      • skill_id
  • 添加官方技能到我的技能

    • POST /api/v1/skills/mine/add
    • 请求体:
      • official_skill_id
  • 删除我的技能

    • DELETE /api/v1/skills/mine/{skillId}
  • 上传技能文件创建

    • POST /api/v1/skills/upload
  • 上传覆盖已有技能

    • PUT /api/v1/skills/{skillId}/upload

6) 专家绑定工具/技能

  • 工具

    • 查询:GET /api/v1/expert-agents/{agentId}/tools
    • 绑定:POST /api/v1/expert-agents/{agentId}/tools(tool_name)
    • 解绑:DELETE /api/v1/expert-agents/{agentId}/tools/{toolId}
  • 技能

    • 查询:GET /api/v1/expert-agents/{agentId}/skills
    • 绑定:POST /api/v1/expert-agents/{agentId}/skills(skill_id)
    • 解绑:DELETE /api/v1/expert-agents/{agentId}/skills/{skillId}

Q20:SSE 事件规范可以补全吗?

A:可以,以下是前端当前实现依赖的事件集合。

1) 事件封包格式

  • 每行以 data: 开头
  • 正文为 JSON 字符串
  • 结束标记:data: [DONE]

2) 前端识别的事件类型

  • data-thinking-step

    • 用途:更新执行步骤面板
    • 关键字段:
      • data.id
      • data.title
      • data.status(completed 或其它)
      • data.items[]
  • reasoning-start

    • 用途:开始一段思考
    • 行为:创建新的 thinking 段,记录开始时间
  • reasoning-delta

    • 用途:思考内容增量
    • 关键字段:
      • delta
  • reasoning-end

    • 用途:结束当前思考段
    • 行为:计算该段耗时并写入 duration
  • tool-input-available

    • 用途:记录工具调用入参
    • 关键字段:
      • toolCallId
      • toolName
      • input
  • tool-output-available

    • 用途:记录工具调用输出
    • 关键字段:
      • toolCallId
      • output
  • text-delta

    • 用途:助手正文 token 增量
    • 关键字段:
      • delta

3) 推荐后端保证

  • 同一次回复里的 toolCallId 全局唯一。
  • reasoning-start 与 reasoning-end 成对(允许无 delta)。
  • data-thinking-step 同一个 id 可重复更新状态。
  • text-delta 在结束前允许为空片段,但尽量减少空片段。

4) 前端容错策略(已实现)

  • JSON parse 失败:跳过该行,不中断整流。
  • 未识别 event.type:忽略。
  • output 非字符串:尝试 result 字段,否则 JSON.stringify。
  • AbortError:按“用户主动停止”处理,不弹致命错误。

Q21:可以给一份页面级测试清单吗?

A:可以,以下清单按页面拆分,适合联调和回归。

A. AgentChatPage 测试清单

  • 打开页面后,能加载专家信息(名称、描述)。
  • 未选线程时,空态正确显示;选中线程后历史消息正确渲染。
  • 点击发送后立即出现 assistant 占位卡片,显示连接中状态。
  • 首个有效流式事件到达后,连接中占位消失,转为正常内容增量渲染。
  • 发送失败/流失败时,assistant 占位会被回收,不留空白卡片。
  • 点击停止后,流式中断,按钮状态恢复,后续不再追加内容。
  • 上传文件后文件树刷新;文件预览支持 text/json 两类返回。
  • 切换线程时会中断当前流,且不会把旧线程流内容写到新线程。

B. SkillCreatorPage 测试清单

  • URL id 与 localStorage 线程 ID 同步正确。
  • 新线程空态和快捷提示按钮显示正常。
  • 发送后 isConnecting=true,收到首包后 isConnecting=false。
  • steps/thinking/tool/text 四类流式内容都能正确出现。
  • 线程切换、停止流、文件上传/预览路径行为与 AgentChatPage 一致。
  • 保存技能弹窗开关正常(当前为 UI 行为)。

C. AgentExpertEditPage 测试清单

  • 进入页面后基础信息(name/model/description/system_prompt)能回填。
  • 保存专家配置后接口成功,按钮 loading 状态恢复。
  • 工具弹窗:勾选新增 -> 确认添加 -> 列表刷新一致。
  • 技能弹窗:绑定/解绑/一键绑定后状态与后端一致。
  • 左侧测试对话能正常流式返回,滚动与发送状态正确。

D. SkillsWorkshop 测试清单

  • all/mine 切换结果正确,搜索词可生效。
  • 分类筛选(writing/analysis/decision/validation/workflow)正确过滤。
  • 官方技能“+”接入后卡片状态转“已接入”。
  • 我的技能菜单中的发布/删除操作正确执行。
  • 编辑弹窗中 AI 编辑路径可成功创建线程并跳转 SkillCreator。
  • 上传创建、上传覆盖两条路径成功后状态正确恢复(含 input 清空)。

E. AgentExpertCenterPage 测试清单

  • mine/published 标签切换后列表正确变化。
  • mine 模式会按当前用户过滤,且与全量接口合并去重后正确展示。
  • 详情弹窗中的发布开关可切换并刷新列表。
  • 编辑、对话跳转路径参数正确。

F. 主题与可用性回归

  • 深色/浅色主题下对话气泡、按钮、边框、hover 都可读。
  • 长会话场景滚动性能可接受,自动滚动按钮行为符合预期。
  • 键盘发送(Enter)与换行(Shift+Enter)行为正确。