808 lines
35 KiB
Markdown
808 lines
35 KiB
Markdown
---
|
||
title: "feat: AgentKit Platform Experience Upgrade"
|
||
status: active
|
||
created: 2026-06-13
|
||
plan-type: feat
|
||
depth: deep
|
||
origin: docs/brainstorms/2026-06-13-agentkit-platform-experience-upgrade-requirements.md
|
||
---
|
||
|
||
# feat: AgentKit Platform Experience Upgrade
|
||
|
||
## Summary
|
||
|
||
对 Fischer AgentKit 进行平台级体验升级,四线并行推进:布局重构为左对话+右双栏、对话体验深化(首 Token 即渲染+消息格式增强+@-mention 四类引用)、响应速度核心优化、暗色主题与交互增强、Computer Use MVP——分三个冲击波迭代交付。
|
||
|
||
## Problem Frame
|
||
|
||
AgentKit 后端能力丰富(ReAct、Skill、Pipeline、记忆、自进化、多 Agent 市场),但 GUI 仍处于"功能可用但体验粗糙"状态。核心痛点:对话空间被压缩到 1/4 屏幕、消息纯文本无高亮、首 Token 延迟 5-10 秒、无暗色主题、无交互反馈、Computer Use 为占位。需求文档(见 origin)定义了 25 个需求(R1-R25),本计划定义如何实现。
|
||
|
||
---
|
||
|
||
## Key Technical Decisions
|
||
|
||
**KTD-1: 布局重构通过调整 SplitPane 嵌套实现,子视图零修改。** 当前 AgentLayout 使用三层 SplitPane(水平→左垂直+右垂直),重构为两层(水平→右垂直),ChatView 直接作为水平 SplitPane 的 first slot。QuadrantPanel 和 SplitPane 组件不变,只改 AgentLayout 的嵌套结构和路由映射。(see origin: R1)
|
||
|
||
**KTD-2: 消息格式增强基于 MarkdownIt 插件扩展 + DOMPurify 白名单扩展。** 当前 ChatMessage 已使用 MarkdownIt 渲染,添加 `markdown-it-highlightjs` 插件实现代码高亮,自定义 `tool_call` 和 `file_preview` 块级渲染器实现工具调用卡片和文件预览。关键:当前 DOMPurify 的 `ALLOWED_TAGS` 白名单不包含 `div`、`img`、`button`,自定义渲染器输出的 HTML 元素会被过滤,必须扩展白名单。不引入新的 Markdown 渲染引擎。(see origin: R8, R9, R10)
|
||
|
||
**KTD-3: @-mention 通过扩展 WebSocket 消息协议实现。** 在现有 `WsClientMessage` 的 `sources` 字段基础上扩展,引用项编码为 `{type: "mention", mention_type: "file"|"skill"|"workflow"|"agent", id: string, label: string}`,后端解析后注入 Agent 上下文。新增 `/api/v1/portal/mention-suggest` REST 端点提供 autocomplete 数据。(see origin: R13, R14)
|
||
|
||
**KTD-4: Computer Use MVP 使用 pyautogui + screencapture 实现截屏和点击。** 替换 `DockerComputerUseSession` 的 stub 为 `LocalComputerUseSession`,macOS 使用 `screencapture` 截屏 + `pyautogui` 执行点击/输入操作,Linux 使用 `xdotool` + `scrot`。不依赖 Docker 容器化。前端新增 ComputerUseView 实际界面替代占位页。(see origin: R19, R20)
|
||
|
||
**KTD-5: 暗色主题通过 `[data-theme="dark"]` CSS 选择器覆盖 + 响应式 Ant Design token。** 在现有 `tokens.css` 中添加 `[data-theme="dark"]` 块覆盖同名 CSS 变量,新增 `stores/theme.ts` 管理主题状态和 localStorage 持久化。关键:`styles/theme.ts` 的 `readToken()` 是模块加载时一次性执行的,切换主题后需重新调用生成新的 `themeConfig` 并传给 ConfigProvider,否则 Ant Design 组件不跟随暗色主题。(see origin: R11)
|
||
|
||
**KTD-6: 响应速度优化 U1-U4 已实现,仅补充 portal.py 的 ReActEngine 复用。** `HeuristicClassifier`、`_classify_merged`、`parallel_tools`、`AsyncWriteQueue` 均已在代码中。`chat.py` 已有 ReActEngine 复用逻辑,但 `portal.py` 每次创建新实例,需对齐。(see origin: R5, R6, R7)
|
||
|
||
---
|
||
|
||
## High-Level Technical Design
|
||
|
||
### 迭代 1 架构:对话体验质变
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
subgraph Frontend
|
||
AL[AgentLayout] --> SP_H[SplitPane horizontal 55:45]
|
||
SP_H --> CV[ChatView 全高]
|
||
SP_H --> SP_V[SplitPane vertical 60:40]
|
||
SP_V --> QP_TR[QuadrantPanel 右上]
|
||
SP_V --> QP_BR[QuadrantPanel 右下]
|
||
|
||
CV --> CI[ChatInput]
|
||
CV --> CM[ChatMessage]
|
||
CM --> MD[MarkdownIt + highlightjs]
|
||
CM --> TC[ToolCallCard 渲染器]
|
||
CM --> FP[FilePreview 渲染器]
|
||
|
||
CI --> WS[WebSocket]
|
||
end
|
||
|
||
subgraph Backend
|
||
WS --> PORTAL[portal.py]
|
||
PORTAL --> HC[HeuristicClassifier 已实现]
|
||
PORTAL --> MERGE[_classify_merged 已实现]
|
||
PORTAL --> RE[ReActEngine 复用]
|
||
RE --> STREAM[execute_stream]
|
||
STREAM --> |token 事件| WS
|
||
end
|
||
```
|
||
|
||
### @-mention 数据流(迭代 2)
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant U as User
|
||
participant CI as ChatInput
|
||
participant API as /mention-suggest
|
||
participant WS as WebSocket
|
||
participant PORTAL as portal.py
|
||
participant AGENT as Agent
|
||
|
||
U->>CI: 输入 @
|
||
CI->>API: GET /mention-suggest?q=keyword
|
||
API-->>CI: [{type, id, label, icon}]
|
||
U->>CI: 选择引用项
|
||
CI->>CI: 添加 ContextPill
|
||
U->>CI: 发送消息
|
||
CI->>WS: {type:chat, message, mentions:[...]}
|
||
WS->>PORTAL: 解析 mentions
|
||
PORTAL->>PORTAL: 查询引用内容
|
||
PORTAL->>AGENT: 注入上下文
|
||
AGENT-->>WS: 流式响应
|
||
WS-->>CI: 渲染响应
|
||
```
|
||
|
||
---
|
||
|
||
## Requirements Traceability
|
||
|
||
| Requirement | Iteration | Implementation Unit(s) |
|
||
|-------------|-----------|----------------------|
|
||
| R1. 左对话+右双栏 | 1 | U1 |
|
||
| R2. 面板折叠 | 1 | U1 |
|
||
| R3. 侧边导航图标 | 1 | U2 |
|
||
| R4. 小屏幕适配 | 1 | U1 |
|
||
| R5. 启发式分类器 | 1 | 已实现 |
|
||
| R6. 合并路由调用 | 1 | 已实现 |
|
||
| R7. 首 Token 即渲染 | 1 | U3 |
|
||
| R8. 代码块高亮 | 1 | U4 |
|
||
| R9. 工具调用可视化 | 1 | U5 |
|
||
| R10. 图片/文件预览 | 1 | U6 |
|
||
| R11. 暗色主题 | 2 | U7 |
|
||
| R12. 组件样式统一 | 2 | U8 |
|
||
| R13. @-mention Autocomplete | 2 | U9 |
|
||
| R14. @-mention 上下文注入 | 2 | U10 |
|
||
| R15. @-mention 引用标签 | 2 | U9 |
|
||
| R16. 过渡动画 | 2 | U11 |
|
||
| R17. 操作反馈 | 2 | U12 |
|
||
| R18. 空状态设计 | 2 | U13 |
|
||
| R19. 截屏查看 | 3 | U14 |
|
||
| R20. 简单点击操作 | 3 | U14 |
|
||
| R21. Computer Use 面板 | 3 | U15 |
|
||
| R22. 并行工具执行 | 3 | 已实现 |
|
||
| R23. 异步会话写入 | 3 | 已实现 |
|
||
| R24. 分割线拖拽增强 | 3 | U16 |
|
||
| R25. 面板折叠缩略预览 | 3 | U17 |
|
||
|
||
---
|
||
|
||
## Implementation Units
|
||
|
||
### 迭代 1:对话体验质变
|
||
|
||
---
|
||
|
||
### U1. AgentLayout 布局重构
|
||
|
||
**Goal:** 将四象限等分布局重构为左对话+右双栏布局,对话面板占满左半屏。
|
||
|
||
**Requirements:** R1, R2, R4
|
||
|
||
**Dependencies:** None
|
||
|
||
**Files:**
|
||
- `src/agentkit/server/frontend/src/components/layout/AgentLayout.vue` — 重构 SplitPane 嵌套
|
||
- `src/agentkit/server/frontend/src/router/index.ts` — 移除 terminal 路由,调整 quadrant 元数据
|
||
- `src/agentkit/server/frontend/src/styles/responsive.css` — 调整断点
|
||
|
||
**Approach:**
|
||
|
||
1. 移除左侧垂直 SplitPane,ChatView 直接作为水平 SplitPane 的 `#first` slot
|
||
2. 保留右侧垂直 SplitPane(右上:代码/工作流/知识库,右下:监控/技能/设置)
|
||
3. 水平 SplitPane 默认比例改为 0.55(55:45)
|
||
4. 移除 `agent-terminal` 路由定义
|
||
5. 调整 responsive.css:≥1280px 完整展示,1024-1280px 右下面板默认折叠,<1024px 提示。**注意:** 当前 responsive.css 的选择器基于四象限布局结构(如 `.split-pane--horizontal > .split-pane__second .split-pane--vertical > .split-pane__second .quadrant-panel`),重构后这些选择器完全失效,必须根据新的两层 SplitPane 结构重写所有象限相关选择器
|
||
|
||
**Patterns to follow:** 现有 SplitPane 嵌套模式;QuadrantPanel 的 Tab 配置模式;localStorage 持久化 key 命名 `agent-*`
|
||
|
||
**Test scenarios:**
|
||
- 布局渲染为左对话+右双栏,ChatView 占满左半屏高度
|
||
- 左右分割线可拖拽,默认 55:45,范围 20%-80%
|
||
- 右侧上下分割线可拖拽,默认 60:40
|
||
- 分割比例保存到 localStorage,刷新后恢复
|
||
- 右上面板折叠后仅显示 Tab 栏(约 38px)
|
||
- 右下面板折叠后仅显示 Tab 栏
|
||
- 两个面板可同时折叠
|
||
- 折叠/展开有 200ms ease 过渡动画
|
||
- 屏幕宽度 <1024px 显示提示
|
||
- 屏幕宽度 1024-1280px 右下面板默认折叠
|
||
- terminal 路由不再存在
|
||
|
||
**Verification:** 手动测试布局在不同屏幕宽度下的表现;折叠/展开动画流畅;localStorage 持久化正常。
|
||
|
||
---
|
||
|
||
### U2. 侧边导航精简为图标模式
|
||
|
||
**Goal:** 将侧边导航精简为 32px 宽图标导航栏,点击图标切换右侧面板 Tab 并展开。
|
||
|
||
**Requirements:** R3
|
||
|
||
**Dependencies:** U1
|
||
|
||
**Files:**
|
||
- `src/agentkit/server/frontend/src/components/layout/TopNav.vue` — 添加侧边导航切换按钮
|
||
- `src/agentkit/server/frontend/src/components/layout/IconNav.vue` — 新建 32px 图标导航组件
|
||
- `src/agentkit/server/frontend/src/components/layout/AgentLayout.vue` — 集成 IconNav
|
||
|
||
**Approach:**
|
||
|
||
1. 新建 `IconNav.vue`:32px 宽图标导航栏,只显示图标(对话、工作流、知识库、技能、监控、设置)。注意:现有 `SideNav.vue` 是遗留的 AppLayout 组件(240px 宽暗色侧边栏),不在 AgentLayout 中使用,不需要修改。
|
||
2. 点击图标:调用对应 QuadrantPanel 的 `setActiveTab()` 并展开面板
|
||
3. 当前激活图标高亮(使用 `--color-primary` Token)
|
||
4. TopNav 添加折叠/展开 SideNav 的按钮
|
||
5. SideNav 状态保存到 localStorage
|
||
|
||
**Patterns to follow:** QuadrantPanel 的 `setActiveTab()` 暴露方法;现有 SideNav 的导航项定义模式
|
||
|
||
**Test scenarios:**
|
||
- SideNav 宽度为 32px,只显示图标
|
||
- 点击对话图标,ChatView 获得焦点
|
||
- 点击工作流图标,右上面板切换到 workflow Tab 并展开
|
||
- 点击监控图标,右下面板切换到 monitor Tab 并展开
|
||
- 当前激活图标高亮
|
||
- TopNav 按钮可折叠/展开 SideNav
|
||
- 折叠状态保存到 localStorage
|
||
|
||
**Verification:** 手动测试图标导航与面板联动;折叠/展开正常。
|
||
|
||
---
|
||
|
||
### U3. 首步骤即渲染 + portal.py ReActEngine 复用
|
||
|
||
**Goal:** 前端接收到首个流式步骤即开始渲染;后端 portal.py 复用 ReActEngine 实例。
|
||
|
||
**Requirements:** R7
|
||
|
||
**Dependencies:** None
|
||
|
||
**Files:**
|
||
- `src/agentkit/server/frontend/src/stores/chat.ts` — 确认流式渲染逻辑正确处理首个步骤
|
||
- `src/agentkit/server/frontend/src/components/chat/ChatMessage.vue` — 确认流式内容渲染无闪烁
|
||
- `src/agentkit/server/routes/portal.py` — ReActEngine 复用(对齐 chat.py 模式,覆盖 SSE + WS 两个路径)
|
||
|
||
**Approach:**
|
||
|
||
1. 前端:当前 `handleWsMessage` 的 `step` 事件在 `event_type === 'final_answer'` 时逐块累加 content,确认首个步骤到达即渲染。注意:后端当前按"步骤"粒度推送(thinking/tool_call/tool_result/final_answer),不是逐 Token 推送。"首 Token 即渲染"在此架构下实际含义是"首步骤即渲染"——`final_answer` 事件的 `data.output` 是文本块,到达即显示。
|
||
2. 后端:portal.py 有两处创建 ReActEngine(SSE 路径约第 342 行,WS 路径约第 661 行),均需改为复用 agent 上已绑定的 `_react_engine`(对齐 chat.py 第 197 行的 `getattr(agent, "_react_engine", None)` 模式)。复用时调用 `react_engine.reset()` 重置内部状态。
|
||
3. 注意 `agent_pool.py` 的 `create_agent_from_skill()` 已在 agent 上绑定 `agent._react_engine`,portal.py 应优先使用该实例。
|
||
|
||
**Patterns to follow:** chat.py 的 `getattr(agent, "_react_engine", None)` 复用模式
|
||
|
||
**Test scenarios:**
|
||
- 发送简单问候,首 Token 在 1 秒内渲染
|
||
- 流式输出逐字显示,无整体延迟
|
||
- ReActEngine 在同一会话中复用,不创建新实例
|
||
- 会话结束后 ReActEngine 正确重置
|
||
- token 事件和 final_answer 事件均触发前端渲染更新
|
||
|
||
**Verification:** 手动测试对话首 Token 延迟;检查 portal.py 日志确认 ReActEngine 复用。
|
||
|
||
---
|
||
|
||
### U4. 代码块语法高亮
|
||
|
||
**Goal:** 消息中的代码块自动识别语言并语法高亮,支持复制按钮。
|
||
|
||
**Requirements:** R8
|
||
|
||
**Dependencies:** None
|
||
|
||
**Files:**
|
||
- `src/agentkit/server/frontend/src/components/chat/ChatMessage.vue` — 添加 highlight.js 插件 + 扩展 DOMPurify 白名单
|
||
- `src/agentkit/server/frontend/src/styles/` — 代码高亮主题样式
|
||
- `src/agentkit/server/frontend/package.json` — 添加 `highlight.js` 依赖
|
||
|
||
**Approach:**
|
||
|
||
1. 安装 `highlight.js` 和 `markdown-it-highlightjs`(或手动配置 MarkdownIt 的 highlight 选项)
|
||
2. 在 ChatMessage 的 MarkdownIt 实例中配置 highlight 函数使用 highlight.js
|
||
3. 代码高亮主题使用 Catppuccin Mocha(与 tokens.css 中的代码主题一致)
|
||
4. 添加代码块复制按钮(点击复制代码内容到剪贴板,显示 Toast 反馈)
|
||
5. 代码块语言标签显示在右上角
|
||
6. **扩展 DOMPurify 白名单**:当前 `ALLOWED_TAGS` 不包含 `code`、`pre`、`span`(highlight.js 生成的标签),需添加这些标签及 `class`、`data-language` 属性
|
||
|
||
**Patterns to follow:** 现有 MarkdownIt 配置模式;tokens.css 中的代码主题色(`--color-code-*`)
|
||
|
||
**Test scenarios:**
|
||
- Python 代码块正确高亮(关键字、字符串、注释、函数名)
|
||
- JavaScript 代码块正确高亮
|
||
- 未指定语言的代码块使用自动检测
|
||
- 复制按钮点击后内容复制到剪贴板,显示 Toast
|
||
- 代码块语言标签正确显示
|
||
- 流式输出时代码块逐步高亮(不闪烁)
|
||
|
||
**Verification:** 手动测试不同语言代码块的渲染效果。
|
||
|
||
---
|
||
|
||
### U5. 工具调用可视化
|
||
|
||
**Goal:** 工具调用显示为可折叠的步骤卡片,展示工具名称、参数摘要、执行状态、结果预览。
|
||
|
||
**Requirements:** R9
|
||
|
||
**Dependencies:** U3
|
||
|
||
**Files:**
|
||
- `src/agentkit/server/frontend/src/components/chat/ChatMessage.vue` — 添加工具调用渲染逻辑 + 扩展 DOMPurify 白名单
|
||
- `src/agentkit/server/frontend/src/components/chat/ToolCallCard.vue` — 新建工具调用卡片组件
|
||
|
||
**Approach:**
|
||
|
||
1. 创建 `ToolCallCard.vue` 组件:可折叠卡片,显示工具名称(图标+名称)、参数摘要(截断显示)、执行状态(pending/running/completed/error)、结果预览(折叠时显示前 2 行)
|
||
2. 在 ChatMessage 中,检测 `step` 事件中的 `tool_call` 和 `tool_result` 事件类型,将配对的工具调用渲染为 ToolCallCard
|
||
3. 利用 chat store 中 `streamingSteps` 的数据,匹配工具调用和结果
|
||
4. 折叠/展开动画使用现有 `transitions.css` 的 `collapse` 类
|
||
5. **扩展 DOMPurify 白名单**:添加 `div`、`button`、`data-tool-call`、`data-tool-result` 等标签和属性,确保 ToolCallCard 的 HTML 不被过滤
|
||
|
||
**Patterns to follow:** 现有 `streamingSteps` 数据结构;transitions.css 的 collapse 动画;QuadrantPanel 的折叠模式
|
||
|
||
**Test scenarios:**
|
||
- 工具调用显示为卡片,包含工具名称和参数摘要
|
||
- 执行中状态显示 loading 指示器
|
||
- 完成后显示结果预览(前 2 行)
|
||
- 点击卡片展开查看完整参数和结果
|
||
- 多个工具调用按顺序显示
|
||
- 折叠/展开有平滑过渡动画
|
||
- 错误状态的工具调用显示错误信息
|
||
|
||
**Verification:** 手动测试触发工具调用的对话,验证卡片渲染和交互。
|
||
|
||
---
|
||
|
||
### U6. 图片和文件预览
|
||
|
||
**Goal:** 消息中的图片内联显示缩略图,文件显示为可下载卡片。
|
||
|
||
**Requirements:** R10
|
||
|
||
**Dependencies:** U4
|
||
|
||
**Files:**
|
||
- `src/agentkit/server/frontend/src/components/chat/ChatMessage.vue` — 添加图片/文件渲染逻辑 + 扩展 DOMPurify 白名单
|
||
- `src/agentkit/server/frontend/src/components/chat/FilePreview.vue` — 新建文件预览卡片组件
|
||
|
||
**Approach:**
|
||
|
||
1. 创建 `FilePreview.vue` 组件:文件名+大小+类型图标+下载按钮
|
||
2. 在 ChatMessage 的 MarkdownIt 渲染中,自定义 `image` 渲染规则:内联缩略图,点击放大
|
||
3. 检测消息中的文件链接(URL 以常见文件扩展名结尾),渲染为 FilePreview 卡片
|
||
4. 图片缩略图使用 CSS `object-fit: contain`,最大高度 200px
|
||
5. **扩展 DOMPurify 白名单**:添加 `img` 标签及 `src`、`alt`、`loading` 属性
|
||
|
||
**Patterns to follow:** 现有 MarkdownIt 自定义渲染器模式;tokens.css 的间距和圆角 Token
|
||
|
||
**Test scenarios:**
|
||
- 消息中的图片 URL 显示为内联缩略图
|
||
- 点击缩略图放大查看
|
||
- 文件链接显示为卡片(文件名+大小+类型图标)
|
||
- 下载按钮点击触发文件下载
|
||
- 非图片/文件链接正常渲染为超链接
|
||
|
||
**Verification:** 手动测试包含图片和文件链接的消息渲染。
|
||
|
||
---
|
||
|
||
### 迭代 2:专业感 + 精准度
|
||
|
||
---
|
||
|
||
### U7. 暗色主题 Token 定义与切换
|
||
|
||
**Goal:** 在浅色 Token 基础上新增暗色主题 Token 变体,支持一键切换。
|
||
|
||
**Requirements:** R11
|
||
|
||
**Dependencies:** U1
|
||
|
||
**Files:**
|
||
- `src/agentkit/server/frontend/src/styles/tokens.css` — 添加 `[data-theme="dark"]` 块
|
||
- `src/agentkit/server/frontend/src/stores/theme.ts` — 新建主题 store
|
||
- `src/agentkit/server/frontend/src/styles/theme.ts` — 改造 `readToken()` 为可重复调用的函数,支持主题切换时重新生成 `themeConfig`
|
||
- `src/agentkit/server/frontend/src/components/layout/TopNav.vue` — 添加主题切换按钮
|
||
- `src/agentkit/server/frontend/src/App.vue` — 监听主题变化,更新 `data-theme` 属性和 ConfigProvider
|
||
|
||
**Approach:**
|
||
|
||
1. 在 tokens.css 末尾添加 `[data-theme="dark"]` 选择器块,覆盖所有颜色变量(背景、前景、边框、品牌色、语义色、代码主题色)
|
||
2. 暗色配色方案:深色背景 `#1a1a2e` 系列、荧光强调色、终端原生感
|
||
3. 创建 `stores/theme.ts`:`currentTheme` ref('light'|'dark'),`toggleTheme()` 方法,localStorage 持久化
|
||
4. **改造 `styles/theme.ts`**:当前 `readToken()` 在模块加载时一次性执行,生成静态 `themeConfig`。切换暗色主题后 CSS 变量值变了,但 `themeConfig` 不会重新计算。需将 `themeConfig` 改为响应式:导出 `getThemeConfig()` 函数,App.vue 监听 `currentTheme` 变化时重新调用生成新 config 并传给 ConfigProvider
|
||
5. App.vue 监听 `currentTheme` 变化,更新 `document.documentElement.dataset.theme` 和 ConfigProvider 的 `theme` prop
|
||
6. TopNav 添加太阳/月亮图标切换按钮
|
||
|
||
**Patterns to follow:** 现有 tokens.css 的变量命名模式;theme.ts 的 `readToken()` 运行时映射
|
||
|
||
**Test scenarios:**
|
||
- 点击切换按钮,界面从浅色切换到暗色
|
||
- 所有组件在暗色主题下正常显示(文字可读、对比度足够)
|
||
- 代码块在暗色主题下使用 Catppuccin Mocha 配色
|
||
- 主题偏好保存到 localStorage,刷新后恢复
|
||
- 切换过渡平滑(CSS transition on color variables)
|
||
|
||
**Verification:** 手动测试暗色主题下所有页面的显示效果。
|
||
|
||
---
|
||
|
||
### U8. 组件样式统一
|
||
|
||
**Goal:** 所有组件统一引用 Design Token,消除硬编码值。
|
||
|
||
**Requirements:** R12
|
||
|
||
**Dependencies:** U7
|
||
|
||
**Files:**
|
||
- `src/agentkit/server/frontend/src/components/layout/SideNav.vue` — 替换硬编码颜色
|
||
- `src/agentkit/server/frontend/src/App.vue` — 替换 `!important` 全局覆盖为 Token 驱动
|
||
- 各组件 scoped 样式中的硬编码值逐一替换
|
||
|
||
**Approach:**
|
||
|
||
1. 全局搜索 `rgba(`、`#` 开头的硬编码颜色值(排除 tokens.css 本身)
|
||
2. 逐一替换为对应的 CSS 变量引用
|
||
3. App.vue 中的 Ant Design 全局覆盖从 `!important` 改为通过 ConfigProvider token 注入
|
||
4. 确保暗色主题下替换后的变量值正确
|
||
|
||
**Patterns to follow:** tokens.css 的变量命名;theme.ts 的 readToken() 映射
|
||
|
||
**Test scenarios:**
|
||
- 零硬编码颜色值(tokens.css 除外)
|
||
- 浅色和暗色主题下所有组件样式一致
|
||
- Ant Design 组件通过 ConfigProvider token 驱动样式
|
||
- 无 `!important` 覆盖(特殊情况除外)
|
||
|
||
**Verification:** 代码搜索确认无硬编码颜色值;双主题视觉验证。
|
||
|
||
---
|
||
|
||
### U9. @-mention Autocomplete 前端
|
||
|
||
**Goal:** 对话输入框中输入 `@` 触发下拉选择器,支持四类引用,选中后显示为 ContextPill。
|
||
|
||
**Requirements:** R13, R15
|
||
|
||
**Dependencies:** U1
|
||
|
||
**Files:**
|
||
- `src/agentkit/server/frontend/src/components/chat/ChatInput.vue` — 添加 @-mention 触发和选择逻辑
|
||
- `src/agentkit/server/frontend/src/components/chat/MentionDropdown.vue` — 新建下拉选择器组件
|
||
- `src/agentkit/server/frontend/src/api/client.ts` — 添加 mention-suggest API 调用
|
||
- `src/agentkit/server/frontend/src/api/types.ts` — 添加 MentionItem 类型定义 + 扩展 WsClientMessage 添加 `mentions` 字段
|
||
|
||
**Approach:**
|
||
|
||
1. 定义 `MentionItem` 类型:`{type: 'file'|'skill'|'workflow'|'agent', id: string, label: string, icon?: string, description?: string}`
|
||
2. ChatInput 监听输入,检测 `@` 字符触发 MentionDropdown
|
||
3. MentionDropdown 调用 `/api/v1/portal/mention-suggest?q=keyword` 获取建议列表
|
||
4. 选中后生成 ContextPill 添加到 `contextPills` 数组(复用现有 ContextPillData 接口,扩展 type/id 字段)
|
||
5. 发送消息时,将 mentions 数组附加到 WebSocket 消息
|
||
6. **R15 覆盖**:ChatMessage 渲染时检测消息的 mentions 元数据,将 @引用渲染为可点击的标签/链接(点击跳转到对应面板或打开详情)
|
||
|
||
**⚠ 前后端协议耦合**:U9 和 U10 必须在同一迭代内同步交付,否则 WebSocket 协议不兼容。
|
||
|
||
**Patterns to follow:** 现有 ContextPill 数据结构;Ant Design Vue 的 AutoComplete/Select 组件模式
|
||
|
||
**Test scenarios:**
|
||
- 输入 `@` 触发下拉选择器
|
||
- 输入 `@文件名` 过滤显示匹配的知识库文档
|
||
- 输入 `@技能名` 过滤显示匹配的技能
|
||
- 输入 `@工作流名` 过滤显示匹配的工作流
|
||
- 输入 `@Agent名` 过滤显示匹配的 Agent
|
||
- 选中引用项后显示为 ContextPill
|
||
- ContextPill 可点击删除
|
||
- 发送消息时 mentions 数组正确附加
|
||
|
||
**Verification:** 手动测试四类 @-mention 的 autocomplete 和选择流程。
|
||
|
||
---
|
||
|
||
### U10. @-mention 后端上下文注入
|
||
|
||
**Goal:** 后端解析 @-mention 引用,将对应内容注入 Agent 推理上下文。
|
||
|
||
**Requirements:** R14
|
||
|
||
**Dependencies:** U9
|
||
|
||
**Files:**
|
||
- `src/agentkit/server/routes/portal.py` — 解析 mentions,注入上下文
|
||
- `src/agentkit/server/routes/portal.py` — 新增 `/portal/mention-suggest` 端点
|
||
|
||
**Approach:**
|
||
|
||
1. 新增 `GET /api/v1/portal/mention-suggest?q=keyword` 端点,聚合查询知识库文档、技能、工作流、Agent,返回 `MentionItem[]`
|
||
2. WebSocket 消息中解析 `mentions` 字段
|
||
3. 根据 mention_type 和 id 查询对应内容:
|
||
- `file` → 从 KnowledgeBase 检索文档片段
|
||
- `skill` → 从 SkillRegistry 获取技能描述和工具定义
|
||
- `workflow` → 从 WorkflowStore 获取工作流定义
|
||
- `agent` → 从 AgentPool 获取 Agent 配置
|
||
4. 将引用内容作为结构化上下文注入 system_prompt 或 messages
|
||
|
||
**Patterns to follow:** 现有 portal.py 的路由和 CostAwareRouter 模式;各 Registry 的查询 API
|
||
|
||
**Test scenarios:**
|
||
- `/mention-suggest?q=test` 返回匹配的文件、技能、工作流、Agent
|
||
- @文件引用后,Agent 回复中引用了文档内容
|
||
- @技能引用后,Agent 使用了指定技能
|
||
- @工作流引用后,Agent 了解工作流定义
|
||
- @Agent 引用后,Agent 了解目标 Agent 的能力
|
||
- 多个 @-mention 同时使用,所有引用内容均注入
|
||
- 无效引用(ID 不存在)优雅降级,不阻塞对话
|
||
|
||
**Verification:** 手动测试各类 @-mention 的上下文注入效果。
|
||
|
||
---
|
||
|
||
### U11. 过渡动画
|
||
|
||
**Goal:** 为所有交互添加过渡动画。
|
||
|
||
**Requirements:** R16
|
||
|
||
**Dependencies:** U1
|
||
|
||
**Files:**
|
||
- `src/agentkit/server/frontend/src/styles/transitions.css` — 确认/补充动画类
|
||
- `src/agentkit/server/frontend/src/components/layout/QuadrantPanel.vue` — Tab 切换淡入淡出
|
||
- `src/agentkit/server/frontend/src/components/layout/AgentLayout.vue` — 路由切换动画
|
||
- 各列表渲染组件 — 交错渐入
|
||
|
||
**Approach:**
|
||
|
||
1. 确认 transitions.css 中已有 fade、collapse、scale、stagger-list 类
|
||
2. QuadrantPanel Tab 切换添加 `<Transition name="fade">` 包裹
|
||
3. AgentLayout 路由切换添加 `<Transition name="fade">`
|
||
4. 列表项使用 `<TransitionGroup name="stagger-list">`
|
||
5. 所有时长引用 Design Token:`--transition-fast: 150ms`、`--transition-normal: 200ms`
|
||
|
||
**Patterns to follow:** 现有 transitions.css 的动画类定义模式
|
||
|
||
**Test scenarios:**
|
||
- 面板折叠/展开有 200ms ease 过渡
|
||
- Tab 切换有 150ms 淡入淡出
|
||
- 列表项交错渐入(stagger 50ms)
|
||
- 路由切换有 200ms 淡入淡出
|
||
- 动画不阻塞交互(使用 CSS transition 而非 JS 动画)
|
||
|
||
**Verification:** 手动测试各交互动画效果。
|
||
|
||
---
|
||
|
||
### U12. 操作反馈
|
||
|
||
**Goal:** 为用户操作提供即时反馈。
|
||
|
||
**Requirements:** R17
|
||
|
||
**Dependencies:** U7
|
||
|
||
**Files:**
|
||
- `src/agentkit/server/frontend/src/components/common/ToastService.ts` — 新建 Toast 服务
|
||
- `src/agentkit/server/frontend/src/components/chat/ChatInput.vue` — 按钮点击反馈
|
||
- `src/agentkit/server/frontend/src/components/layout/TopNav.vue` — WebSocket 断连横幅
|
||
- 各加载状态组件 — 骨架屏替代 a-spin
|
||
|
||
**Approach:**
|
||
|
||
1. 创建 ToastService:基于 Ant Design Vue 的 `message` 组件,封装 success/error/warning/info 方法
|
||
2. 按钮点击添加 `:active` 缩放反馈(CSS `transform: scale(0.97)`)
|
||
3. 加载状态:关键区域使用骨架屏(复用 transitions.css 的 `skeleton-pulse` 动画)
|
||
4. WebSocket 断连:TopNav 下方显示红色横幅提示,重连后自动消失
|
||
|
||
**Patterns to follow:** Ant Design Vue message 组件;transitions.css 的 skeleton-pulse 动画
|
||
|
||
**Test scenarios:**
|
||
- 操作成功显示绿色 Toast
|
||
- 操作失败显示红色 Toast
|
||
- 按钮点击有缩放反馈
|
||
- 加载状态显示骨架屏而非 Spin
|
||
- WebSocket 断连时顶部显示红色横幅
|
||
- 重连后横幅自动消失
|
||
|
||
**Verification:** 手动测试各类操作反馈。
|
||
|
||
---
|
||
|
||
### U13. 空状态设计
|
||
|
||
**Goal:** 为所有空状态提供品牌化插图和引导文案。
|
||
|
||
**Requirements:** R18
|
||
|
||
**Dependencies:** U7
|
||
|
||
**Files:**
|
||
- `src/agentkit/server/frontend/src/components/common/EmptyState.vue` — 新建空状态组件
|
||
- `src/agentkit/server/frontend/src/views/ChatView.vue` — 对话空状态
|
||
- `src/agentkit/server/frontend/src/views/WorkflowView.vue` — 工作流空状态
|
||
- `src/agentkit/server/frontend/src/views/EvolutionView.vue` — 监控空状态
|
||
- `src/agentkit/server/frontend/src/views/KnowledgeBaseView.vue` — 知识库空状态
|
||
- `src/agentkit/server/frontend/src/views/SkillsView.vue` — 技能空状态
|
||
|
||
**Approach:**
|
||
|
||
1. 创建 EmptyState.vue 通用组件:接受 `title`、`description`、`icon`、`action` props
|
||
2. 各视图在数据为空时渲染 EmptyState,提供引导文案和操作按钮
|
||
3. 图标使用 Ant Design Vue 的内置图标,配合品牌色
|
||
|
||
**Patterns to follow:** Ant Design Vue 的 `a-empty` 组件模式
|
||
|
||
**Test scenarios:**
|
||
- 对话空状态显示"开始你的第一次对话"引导
|
||
- 工作流空状态显示"创建第一个工作流"引导
|
||
- 监控空状态显示数据来源说明
|
||
- 知识库空状态显示"上传文档或配置信息源"引导
|
||
- 技能空状态显示"注册技能"引导
|
||
- 空状态组件在暗色主题下正常显示
|
||
|
||
**Verification:** 手动测试各视图的空状态显示。
|
||
|
||
---
|
||
|
||
### 迭代 3:能力扩展
|
||
|
||
---
|
||
|
||
### U14. Computer Use MVP 后端(pyautogui + screencapture)
|
||
|
||
**Goal:** 实现本地截屏和点击操作的后端闭环。
|
||
|
||
**Requirements:** R19, R20
|
||
|
||
**Dependencies:** None
|
||
|
||
**Files:**
|
||
- `src/agentkit/tools/computer_use_session.py` — 新增 `LocalComputerUseSession` 类
|
||
- `src/agentkit/tools/computer_use.py` — 确保工具注册和降级链正确
|
||
|
||
**Approach:**
|
||
|
||
1. 创建 `LocalComputerUseSession` 类,实现 `start()`、`stop()`、`screenshot()`、`execute_action()` 方法
|
||
2. `screenshot()` 实现:macOS 使用 `screencapture -x -t png <path>` 命令截屏,读取文件返回 base64;Linux 使用 `scrot` 或 `xdg-screenshot`
|
||
3. `execute_action()` 实现:使用 `pyautogui` 库执行点击(`pyautogui.click(x, y)`)、输入(`pyautogui.typewrite()`)、滚动等操作
|
||
4. 注册到 `ComputerUseSessionManager`,作为默认会话类型(替代 Docker stub)
|
||
5. 确保降级链正确:Anthropic API → LocalComputerUseSession → Shell 替代建议
|
||
6. 添加 `pyautogui` 到项目依赖(`pyproject.toml`)
|
||
|
||
**Patterns to follow:** 现有 `InMemoryComputerUseSession` 的接口模式;ToolRegistry 注册模式
|
||
|
||
**Test scenarios:**
|
||
- OpenCLI 会话创建和销毁正常
|
||
- 截屏返回有效的 base64 PNG 数据
|
||
- 点击操作执行并返回结果
|
||
- ComputerUseTool 的降级链正确工作
|
||
- 会话管理器正确管理 OpenCLI 会话生命周期
|
||
|
||
**Verification:** 手动测试通过对话触发截屏和点击操作。
|
||
|
||
---
|
||
|
||
### U15. Computer Use 前端面板
|
||
|
||
**Goal:** 右上面板新增 Computer Use Tab,展示截屏画面和操作历史。
|
||
|
||
**Requirements:** R21
|
||
|
||
**Dependencies:** U14
|
||
|
||
**Files:**
|
||
- `src/agentkit/server/frontend/src/views/ComputerUseView.vue` — 替换占位页为实际界面
|
||
- `src/agentkit/server/frontend/src/components/layout/AgentLayout.vue` — 右上面板添加 Computer Use Tab
|
||
- `src/agentkit/server/frontend/src/router/index.ts` — 添加 Computer Use 路由
|
||
|
||
**Approach:**
|
||
|
||
1. 重写 ComputerUseView.vue:截屏画面显示区域(支持缩放和滚动)、操作历史列表、手动截屏按钮
|
||
2. 截屏画面通过 WebSocket 接收 base64 图片数据,渲染为 `<img>` 标签
|
||
3. 操作历史显示时间戳、操作类型、坐标/参数、结果摘要
|
||
4. 手动截屏按钮触发后端截屏命令
|
||
5. 右上面板 QuadrantPanel 添加 Computer Use Tab
|
||
|
||
**Patterns to follow:** 现有 QuadrantPanel Tab 配置模式;WebSocket 消息处理模式
|
||
|
||
**Test scenarios:**
|
||
- Computer Use Tab 在右上面板显示
|
||
- 截屏画面正确渲染
|
||
- 截屏画面支持缩放和滚动
|
||
- 操作历史按时间倒序显示
|
||
- 手动截屏按钮触发截屏
|
||
- 暗色主题下正常显示
|
||
|
||
**Verification:** 手动测试 Computer Use 面板的截屏显示和操作历史。
|
||
|
||
---
|
||
|
||
### U16. 分割线拖拽增强
|
||
|
||
**Goal:** 拖拽分割线时高亮显示,显示当前比例百分比。
|
||
|
||
**Requirements:** R24
|
||
|
||
**Dependencies:** U1
|
||
|
||
**Files:**
|
||
- `src/agentkit/server/frontend/src/components/layout/SplitPane.vue` — 添加拖拽高亮和比例显示
|
||
|
||
**Approach:**
|
||
|
||
1. 拖拽时 handle 元素添加高亮样式(加宽 + 品牌色背景)
|
||
2. 拖拽时显示比例百分比标签(如 "55%"),定位在 handle 旁边
|
||
3. 使用 CSS transition 确保高亮和标签的显示/隐藏平滑
|
||
|
||
**Patterns to follow:** 现有 SplitPane 的拖拽逻辑和 handle 样式
|
||
|
||
**Test scenarios:**
|
||
- 拖拽时分割线高亮
|
||
- 拖拽时显示当前比例百分比
|
||
- 百分比标签定位正确不遮挡内容
|
||
- 拖拽结束后高亮和标签消失
|
||
|
||
**Verification:** 手动测试拖拽交互。
|
||
|
||
---
|
||
|
||
### U17. 面板折叠缩略预览
|
||
|
||
**Goal:** 面板折叠时显示缩略内容预览。
|
||
|
||
**Requirements:** R25
|
||
|
||
**Dependencies:** U1
|
||
|
||
**Files:**
|
||
- `src/agentkit/server/frontend/src/components/layout/QuadrantPanel.vue` — 折叠时显示缩略预览
|
||
|
||
**Approach:**
|
||
|
||
1. 折叠状态下,在 Tab 栏下方显示约 60px 高的缩略预览区域
|
||
2. 预览内容根据当前活跃 Tab 类型显示:监控显示关键指标数字、技能显示技能数量、工作流显示节点缩略图
|
||
3. 预览区域使用半透明背景,不占用过多空间
|
||
|
||
**Patterns to follow:** QuadrantPanel 的折叠模式;Design Token 的间距和圆角
|
||
|
||
**Test scenarios:**
|
||
- 右上面板折叠后显示缩略预览
|
||
- 右下面板折叠后显示缩略预览
|
||
- 预览内容根据活跃 Tab 更新
|
||
- 预览区域不遮挡 Tab 栏
|
||
- 暗色主题下预览区域正常显示
|
||
|
||
**Verification:** 手动测试折叠预览效果。
|
||
|
||
---
|
||
|
||
## Scope Boundaries
|
||
|
||
**在范围内:** 见需求文档的 Scope Boundaries。
|
||
|
||
**延迟到后续迭代:**
|
||
- Cmd+K 内联编辑
|
||
- Computer Use Docker 容器化隔离
|
||
- 代码 Diff 查看器实现
|
||
- 代码 Diff Accept/Reject 回滚
|
||
- 响应式移动端适配
|
||
- httpx 连接池配置优化(U5 已实现,无需额外工作)
|
||
- A/B 测试框架和性能基准 CI
|
||
- Ant Design Vue 按需引入(unplugin-vue-components)
|
||
- ECharts 按需引入
|
||
|
||
**不在本产品身份内:**
|
||
- 多用户协作/实时协同编辑
|
||
- 插件市场
|
||
- 代码编辑器
|
||
|
||
---
|
||
|
||
## Risks & Mitigations
|
||
|
||
| Risk | Likelihood | Impact | Mitigation |
|
||
|------|-----------|--------|------------|
|
||
| @-mention 后端查询聚合性能差 | Medium | Medium — 慢速 autocomplete 影响体验 | mention-suggest 端点添加缓存(TTL 30s),结果集限制 20 条 |
|
||
| 本地截屏兼容性问题 | Medium | High — 不同 OS 环境截屏命令不同 | 检测 OS 类型选择对应命令,添加 fallback 到 InMemory 模式 |
|
||
| 暗色主题对比度不足 | Low | Medium — 部分组件在暗色下不可读 | 使用 WCAG AA 标准验证对比度,添加自动化对比度检查 |
|
||
| 消息格式增强破坏现有渲染 | Low | High — 已有消息显示异常 | MarkdownIt 插件添加 fallback,解析失败时回退到纯文本;DOMPurify 白名单扩展需谨慎测试 |
|
||
| 布局重构影响现有路由和状态 | Medium | Medium — localStorage 旧 key 导致异常 | 添加 key 版本化,旧 key 自动迁移或清理 |
|
||
| DOMPurify 白名单扩展引入 XSS | Low | High — 恶意内容可能注入 | 仅添加必要的标签和属性,不开放 `on*` 事件属性,`img` 的 `src` 限制为相对路径和已知域名 |
|
||
| Ant Design token 不跟随暗色切换 | Medium | Medium — 组件颜色不一致 | 改造 theme.ts 为响应式,切换时重新生成 themeConfig |
|
||
| 与 001 计划的 U-unit 重叠 | High | High — 并行执行产生合并冲突 | 003 吸收 001 的重叠 U-unit,001 标注为"由 003 覆盖",不并行执行 |
|
||
|
||
---
|
||
|
||
## System-Wide Impact
|
||
|
||
- **前端布局:** AgentLayout 从三层 SplitPane 改为两层,所有依赖象限位置的路由和状态需调整
|
||
- **前端样式:** 暗色主题影响所有组件,需全面测试
|
||
- **WebSocket 协议:** @-mention 扩展了 `WsClientMessage` 的 `mentions` 字段,需前后端同步升级
|
||
- **后端路由:** 新增 `/portal/mention-suggest` 端点,portal.py 需解析 mentions
|
||
- **工具系统:** 新增 OpenCLIComputerUseSession,ComputerUseTool 降级链调整
|
||
- **响应速度:** portal.py 的 ReActEngine 复用减少实例创建开销
|
||
|
||
---
|
||
|
||
## Outstanding Questions
|
||
|
||
**Deferred to Implementation:**
|
||
- @-mention 后端解析的具体协议细节:mentions 字段在 WebSocket 消息中的 JSON 结构
|
||
- 工具调用步骤卡片的折叠/展开交互细节:默认折叠还是展开
|
||
- 骨架屏的具体形状和占位内容
|
||
- 暗色主题的具体色值需要视觉调优
|
||
- R22/R23 对 portal.py 路径无效的决策:portal.py 使用自己的 ConversationStore(内存 dict),不使用 SessionManager,异步写入和并行工具执行对 portal 路径无影响。是否需要迁移 portal.py 到 SessionManager?
|
||
|
||
**Plan Relationship:**
|
||
- 本计划(003)吸收了 001 计划(GUI 产品化)的所有重叠 U-unit(布局重构、暗色主题、交互增强),001 计划应标注为"由 003 覆盖",避免并行执行产生合并冲突
|
||
|
||
---
|
||
|
||
## Sources & Research
|
||
|
||
- 需求文档:`docs/brainstorms/2026-06-13-agentkit-platform-experience-upgrade-requirements.md`
|
||
- 响应速度优化计划(U1-U4 已实现):`docs/plans/2026-06-12-021-feat-chat-response-speed-optimization-plan.md`
|
||
- GUI 产品化计划(前一轮):`docs/plans/2026-06-13-001-feat-gui-productization-plan.md`
|
||
- 前端产品化计划:`docs/plans/2026-06-12-023-feat-frontend-productization-plan.md`
|
||
- 现有 Design Token 体系:`src/agentkit/server/frontend/src/styles/tokens.css`
|
||
- 现有 WebSocket 协议:`src/agentkit/server/frontend/src/api/types.ts`
|
||
- 现有 Computer Use 工具:`src/agentkit/tools/computer_use.py`、`src/agentkit/tools/computer_use_session.py`
|