# Frontend Multi-Agent / MCP Process UI Change

## 1. 目标

前端聊天页要从“单一消息流”升级成“可视化协作工作台”，让用户在一次聊天里同时看到：

1. 主对话区里的用户问题与最终总结回复。
2. 每个 sub-agent / A2A agent / MCP server 的独立处理框。
3. agent 之间的流式进展、状态变化、问答片段。
4. MCP 工具调用产物，例如文本结果、结构化 JSON、文件、链接、图片。
5. 一个固定的结果侧栏，用来汇总当前运行中的过程结果与最终产物。
6. 独立的 Agent 管理页和 MCP 管理页，体验上与现有 `skills` / `plugins` 页面一致。

这个需求本质上不是“把聊天页面做复杂一点”，而是要把聊天 UI 的数据模型从 `messages[]` 升级成 `messages[] + process runs[] + artifacts[] + actor registry[]`。

## 2. 当前现状

### 2.1 前端现状

当前前端的核心限制如下：

- 聊天页集中在 `/home/ivan/xuan/steven_project/nanobot-fronted/app/page.tsx`。
- 聊天状态只在 `/home/ivan/xuan/steven_project/nanobot-fronted/lib/store.ts` 里维护：
  - `messages`
  - `isLoading`
  - `isThinking`
  - `streamingContent`
- WebSocket 只在 `/home/ivan/xuan/steven_project/nanobot-fronted/lib/api.ts` 里处理非常薄的一层消息：
  - `type=status`
  - `type=message`
- 类型定义 `/home/ivan/xuan/steven_project/nanobot-fronted/types/index.ts` 没有“运行事件 / agent 卡片 / artifact / process timeline”概念。
- 顶部导航 `/home/ivan/xuan/steven_project/nanobot-fronted/components/Header.tsx` 目前没有 `Agents` / `MCP` 页入口。
- 现有 `skills` / `plugins` 页面适合复用作管理页风格参考：
  - `/home/ivan/xuan/steven_project/nanobot-fronted/app/skills/page.tsx`
  - `/home/ivan/xuan/steven_project/nanobot-fronted/app/plugins/page.tsx`

### 2.2 后端现状

后端已经具备部分多 agent 能力，但还不够支撑前端过程可视化：

- 已有统一 agent 列表接口：`GET /api/agents`
  - 位置：`/home/ivan/xuan/steven_project/nanobot-backend/nanobot/web/server.py`
- 已有 A2A / group delegation 逻辑：
  - `/home/ivan/xuan/steven_project/nanobot-backend/nanobot/agent/delegation.py`
- 已有 A2A streaming / resubscribe / cancel：
  - `/home/ivan/xuan/steven_project/nanobot-backend/nanobot/a2a/client.py`
- 但当前对前端暴露的实时消息仍然只有：
  - `status=thinking`
  - `assistant message`
- `DelegationManager` 现在对外发布的也只是普通 `_progress` 文本，例如：
  - `[AgentName] ...`
- MCP 目前只有后端连接配置和工具注册，没有独立的 Web 管理接口，也没有结构化 MCP 运行事件。

结论：

前端可以先做布局和状态层改造，但如果想真正展示“每个 agent 的框、每个 MCP 的产物、agent 间问答”，后端必须补一层结构化 process event 协议。只靠现在的纯文本 progress 不够。

## 3. 推荐的界面形态

桌面端建议改成三栏工作台，而不是继续沿用现在的单栏聊天布局。

### 3.1 桌面布局

```text
┌──────────────┬───────────────────────────────────────┬──────────────────────────┐
│ 会话侧栏     │ 主聊天 + 过程泳道                    │ 结果侧栏                 │
│ Sessions     │                                       │ Results / Artifacts      │
│              │ 用户消息                              │ 当前运行摘要             │
│              │ assistant 最终总结                    │ agent 产物列表           │
│              │ ───────────────────────────────────   │ MCP 产物列表             │
│              │ Agent A 卡片                          │ 文件/图片/JSON 预览      │
│              │ Agent B 卡片                          │ 错误/告警                │
│              │ MCP github 卡片                       │ 最终汇总结论             │
│              │ MCP browser 卡片                      │                          │
└──────────────┴───────────────────────────────────────┴──────────────────────────┘
```

### 3.2 移动端布局

移动端不要硬保留三栏：

1. 主聊天区保留为默认视图。
2. 过程泳道和结果侧栏改成底部 `Tabs` 或 `Drawer`。
3. 正在运行时，顶部显示一个 `Process (3)` 悬浮入口。

### 3.3 视觉原则

不要把过程信息混成普通 assistant markdown。

应明确区分三类对象：

1. `Chat Message`：用户问题、最终总结。
2. `Process Card`：某个 agent 或 MCP 的运行容器。
3. `Artifact`：某个步骤产出的结构化结果。

建议：

- Agent 卡片用清晰的状态边框和标题区。
- MCP 卡片强调“工具/服务器”属性，避免与 agent 混淆。
- 结果侧栏始终可见，展示当前选中卡片的详细结果。

## 4. 目标交互

### 4.1 单 Agent

用户发出问题后：

1. 主聊天区出现用户消息。
2. assistant 进入 `thinking`。
3. 若命中 `spawn` / A2A delegation，过程泳道新增一个 Agent 卡片。
4. 卡片内部流式更新：
   - 状态：queued / running / waiting / done / error / cancelled
   - 文本片段
   - agent 生成的中间消息
   - 关键参数或结果摘要
5. 如果 agent 调了 MCP，再在该卡片内部挂子步骤，或在泳道新增 MCP 卡片。
6. 右侧结果栏展示：
   - 当前 agent 的最新摘要
   - 产物列表
   - 可预览文件
7. 所有 agent 结束后，主 assistant 再给一条最终总结回复。

### 4.2 多 Agent Group

如果是 group delegation：

1. 过程泳道里要同时出现多个 Agent 卡片。
2. 每个卡片独立流式刷新，不要合并成一条文本。
3. 结果侧栏支持切换：
   - `All`
   - `Agent A`
   - `Agent B`
   - `MCP Outputs`
4. 最终 assistant 总结要包含：
   - 共识
   - 分歧
   - 失败项
   - 最终建议

### 4.3 Agent 间“一问一答”

如果未来后端能发出 agent-to-agent message event，前端直接把这些消息渲染到卡片里的 transcript 区。

建议 UI 表现：

- 卡片头：agent 名称、来源、状态、耗时
- 卡片体：
  - `Transcript`
  - `Steps`
  - `Artifacts`
- 卡片尾：最终摘要 / 错误信息

## 5. 前端改造点

## 5.1 先不要继续把逻辑堆进 `app/page.tsx`

当前 `/home/ivan/xuan/steven_project/nanobot-fronted/app/page.tsx` 已经过大。这个需求如果继续直接堆，会很快失控。

建议拆分。

### 5.2 建议新增的组件与文件

建议新增目录：

- `components/chat-workbench/ChatWorkbench.tsx`
- `components/chat-workbench/ProcessLane.tsx`
- `components/chat-workbench/ProcessRunCard.tsx`
- `components/chat-workbench/ProcessTranscript.tsx`
- `components/chat-workbench/ArtifactSidebar.tsx`
- `components/chat-workbench/RunSummaryPanel.tsx`
- `components/chat-workbench/AgentBadge.tsx`
- `components/chat-workbench/McpBadge.tsx`
- `components/chat-workbench/StatusPill.tsx`

建议职责：

- `ChatWorkbench.tsx`
  - 负责三栏布局组合。
- `ProcessLane.tsx`
  - 渲染当前 session 的所有 process run。
- `ProcessRunCard.tsx`
  - 渲染单个 agent / MCP 卡片。
- `ProcessTranscript.tsx`
  - 渲染步骤流、问答片段、进度文本。
- `ArtifactSidebar.tsx`
  - 渲染右侧产物栏。
- `RunSummaryPanel.tsx`
  - 展示当前 run 的状态概览和最终摘要。

### 5.3 对现有文件的插入建议

#### `/home/ivan/xuan/steven_project/nanobot-fronted/app/page.tsx`

保留职责：

- session 列表
- 输入框
- 顶层页面组织

减少职责：

- 不再在这里直接渲染复杂过程 UI
- 不再在这里直接解析 process 事件

建议修改为：

1. 左侧会话侧栏基本保留。
2. 中间改成 `<ChatWorkbench />`。
3. `MessageBubble` 可以保留，但只负责普通 `user/assistant` 消息。
4. 新增一个 `selectedRunId` / `selectedArtifactId` 的页面级状态，或者放进 Zustand store。

#### `/home/ivan/xuan/steven_project/nanobot-fronted/lib/store.ts`

这里需要从“聊天 store”升级成“聊天 + 过程 store”。

建议新增状态：

- `processRuns: ProcessRun[]`
- `processEvents: ProcessEvent[]`
- `artifacts: ProcessArtifact[]`
- `selectedRunId: string | null`
- `selectedArtifactId: string | null`
- `activeRunIds: string[]`
- `agentRegistry: UiAgentDescriptor[]`
- `mcpRegistry: UiMcpServerDescriptor[]`

建议新增 action：

- `resetProcessState(sessionId)`
- `upsertProcessRun(run)`
- `appendProcessEvent(event)`
- `appendProcessArtifact(artifact)`
- `finishProcessRun(runId, status)`
- `cancelProcessRun(runId)`
- `setSelectedRunId(runId)`
- `setSelectedArtifactId(artifactId)`
- `setAgentRegistry(agents)`
- `setMcpRegistry(servers)`

#### `/home/ivan/xuan/steven_project/nanobot-fronted/types/index.ts`

这里需要新增完整类型层。

建议新增：

```ts
export type ProcessActorType = 'agent' | 'mcp' | 'system';
export type ProcessRunStatus = 'queued' | 'running' | 'waiting' | 'done' | 'error' | 'cancelled';
export type ProcessEventKind =
  | 'run_started'
  | 'run_progress'
  | 'run_message'
  | 'run_artifact'
  | 'run_status'
  | 'run_finished'
  | 'run_cancelled';

export interface UiAgentDescriptor {
  id: string;
  name: string;
  description: string;
  source: 'workspace' | 'plugin' | 'skill' | 'builtin';
  kind: string;
  protocol: string | null;
  tags: string[];
  aliases: string[];
  support_group: boolean;
  support_streaming: boolean;
}

export interface UiMcpServerDescriptor {
  id: string;
  name: string;
  transport: 'stdio' | 'http';
  url?: string;
  command?: string;
  enabled: boolean;
  tool_count?: number;
  tool_names?: string[];
  status?: 'connected' | 'disconnected' | 'error';
  last_error?: string | null;
}

export interface ProcessRun {
  run_id: string;
  parent_run_id?: string | null;
  session_id: string;
  actor_type: ProcessActorType;
  actor_id: string;
  actor_name: string;
  title: string;
  status: ProcessRunStatus;
  started_at: string;
  finished_at?: string | null;
  summary?: string | null;
  source?: string | null;
}

export interface ProcessEvent {
  event_id: string;
  run_id: string;
  parent_run_id?: string | null;
  kind: ProcessEventKind;
  actor_type: ProcessActorType;
  actor_id: string;
  actor_name: string;
  text?: string;
  status?: ProcessRunStatus;
  message_role?: 'system' | 'user' | 'assistant' | 'tool';
  metadata?: Record<string, unknown>;
  created_at: string;
}

export interface ProcessArtifact {
  artifact_id: string;
  run_id: string;
  actor_type: ProcessActorType;
  actor_id: string;
  title: string;
  artifact_type: 'text' | 'json' | 'file' | 'image' | 'link' | 'markdown';
  content?: string;
  data?: Record<string, unknown> | unknown[];
  file_id?: string;
  url?: string;
  created_at: string;
}
```

#### `/home/ivan/xuan/steven_project/nanobot-fronted/lib/api.ts`

这里要扩展三类能力：

1. Agent 管理 API
2. MCP 管理 API
3. WebSocket process event 订阅

建议新增：

- `listAgents()`
- `addAgent()`
- `deleteAgent()`
- `refreshAgents()`
- `listMcpServers()`
- `addMcpServer()`
- `updateMcpServer()`
- `deleteMcpServer()`
- `testMcpServer()`

同时把 `WsMessageHandler` 从现在的宽松结构，升级成联合类型：

```ts
export type WsEvent =
  | ChatAssistantEvent
  | ChatThinkingEvent
  | ProcessRunStartedEvent
  | ProcessRunUpdatedEvent
  | ProcessArtifactEvent
  | ProcessRunFinishedEvent
  | ProcessRunCancelledEvent;
```

#### `/home/ivan/xuan/steven_project/nanobot-fronted/components/Header.tsx`

导航中建议新增：

- `/agents`
- `/mcp`

放在 `skills` / `plugins` 旁边，不要塞进聊天页内部。

### 5.4 建议新增页面

- `/home/ivan/xuan/steven_project/nanobot-fronted/app/agents/page.tsx`
- `/home/ivan/xuan/steven_project/nanobot-fronted/app/mcp/page.tsx`

Agent 页面参考 `skills + plugins` 的中间态：

- 列表视图
- 支持新增、删除、刷新
- 展示来源：workspace / plugin / skill / builtin
- 展示协议：a2a / local
- 展示标签、别名、streaming/group 支持

MCP 页面建议分两块：

1. `Configured Servers`
2. `Discovered Tools`

每个 MCP server 展示：

- 连接方式：stdio / http
- 地址或命令
- tool 数量
- 连接状态
- 最后错误
- 编辑/删除/测试按钮

## 6. 聊天页的推荐逻辑链路

这是前端应当遵守的主链路。

### 6.1 用户发消息

1. 用户在 `app/page.tsx` 输入消息。
2. 立即写入 `messages[]`。
3. 设置 `isLoading=true`。
4. 如果 WebSocket 已连接，消息通过 `wsManager.sendRaw()` 发出去。
5. 前端等待两类数据：
   - 普通 assistant reply
   - process events

### 6.2 触发 sub-agent / group / MCP

后端一旦进入 delegation / MCP tool 调用，应向前端发结构化 process event。

前端收到后：

1. `run_started` -> 创建卡片。
2. `run_progress` -> 更新卡片中的 transcript。
3. `run_artifact` -> 写入右侧侧栏。
4. `run_status` -> 更新状态 pill。
5. `run_finished` -> 收起 loading，保留结果。
6. 最终 `assistant message` -> 输出总结性回复。

### 6.3 用户点击某个 Agent / MCP 卡片

1. 设置 `selectedRunId`。
2. 右侧 `ArtifactSidebar` 切换到该 run 的 artifact 列表。
3. 中间卡片高亮。
4. 若有 transcript，则显示完整流。

### 6.4 用户取消运行

如果后端暴露 cancel 接口或 WebSocket cancel command：

1. 卡片上显示 `Cancel`。
2. 用户点击后发送 cancel 请求。
3. run 状态变为 `cancelled`。
4. 侧栏保留已有产物，但标记“未完成”。

## 7. 后端必须补的事件协议

这是这次前端能否做成的关键。

当前后端只发普通文本 `_progress`，不够。

必须新增结构化 WebSocket 事件。建议统一成 `type=process_*`。

### 7.1 建议的事件集合

#### `process_run_started`

```json
{
  "type": "process_run_started",
  "session_id": "web:default",
  "run_id": "deleg-123",
  "parent_run_id": null,
  "actor_type": "agent",
  "actor_id": "repo-reviewer",
  "actor_name": "Repo Reviewer",
  "source": "workspace",
  "title": "Review auth refactor",
  "status": "running",
  "created_at": "2026-03-06T10:00:00Z"
}
```

#### `process_run_progress`

```json
{
  "type": "process_run_progress",
  "run_id": "deleg-123",
  "actor_type": "agent",
  "actor_id": "repo-reviewer",
  "text": "Scanning auth middleware and session lifecycle",
  "created_at": "2026-03-06T10:00:03Z"
}
```

#### `process_run_message`

用于展示 agent 间问答或 agent 内部消息。

```json
{
  "type": "process_run_message",
  "run_id": "deleg-123",
  "actor_type": "agent",
  "actor_id": "repo-reviewer",
  "message_role": "assistant",
  "text": "I need the gateway config file before deciding.",
  "created_at": "2026-03-06T10:00:04Z"
}
```

#### `process_run_artifact`

```json
{
  "type": "process_run_artifact",
  "run_id": "mcp-456",
  "actor_type": "mcp",
  "actor_id": "github",
  "title": "Pull Request Diff Summary",
  "artifact_type": "markdown",
  "content": "...",
  "created_at": "2026-03-06T10:00:08Z"
}
```

#### `process_run_status`

```json
{
  "type": "process_run_status",
  "run_id": "deleg-123",
  "status": "waiting",
  "text": "Waiting for remote agent task completion",
  "created_at": "2026-03-06T10:00:10Z"
}
```

#### `process_run_finished`

```json
{
  "type": "process_run_finished",
  "run_id": "deleg-123",
  "status": "done",
  "summary": "Found 2 risks in auth token refresh flow.",
  "created_at": "2026-03-06T10:00:20Z"
}
```

#### `process_run_cancelled`

```json
{
  "type": "process_run_cancelled",
  "run_id": "deleg-123",
  "status": "cancelled",
  "created_at": "2026-03-06T10:00:12Z"
}
```

### 7.2 后端推荐插入点

如果你后面让我直接改前后端，我会从这些点切：

#### `/home/ivan/xuan/steven_project/nanobot-backend/nanobot/agent/delegation.py`

这里最适合发 agent 级 process event：

- `dispatch()` 开始时发 `process_run_started`
- `_build_progress_callback()` 中把 A2A stream 文本转成 `process_run_progress`
- `_run_group()` 中每个 descriptor 启动时发独立子 run
- `_announce_single_result()` 之前发 `process_run_finished`
- `_announce_group_result()` 之前发 group summary run finished
- `cancel()` / `_announce_cancelled()` 发 `process_run_cancelled`

#### `/home/ivan/xuan/steven_project/nanobot-backend/nanobot/a2a/client.py`

这里最适合补更细的远端 agent 消息：

- `_consume_stream_method()`
- `_resume_subscription()`

如果远端流里有 message chunk / state / artifact，就在这里归一化后向上抛给 `DelegationManager`。

#### `/home/ivan/xuan/steven_project/nanobot-backend/nanobot/agent/tools/mcp.py`

这里最适合发 MCP 级事件：

- MCP 工具调用开始 -> `process_run_started` (`actor_type=mcp`)
- 工具标准输出 / 中间结果 -> `process_run_progress`
- 工具返回文本 / JSON / 文件 -> `process_run_artifact`
- 工具调用完成 -> `process_run_finished`
- 超时 / 失败 -> `process_run_status` + `process_run_finished(status=error)`

#### `/home/ivan/xuan/steven_project/nanobot-backend/nanobot/web/server.py`

这里需要扩展 WebSocket 发送协议，而不是只发 `thinking/message`。

## 8. Agent 管理页方案

### 8.1 页面目标

让用户能像管理 `skills` 一样管理委派目标 agent。

### 8.2 数据来源

直接用现有接口：

- `GET /api/agents`
- `POST /api/agents`
- `DELETE /api/agents/{id}`
- `POST /api/agents/refresh`

### 8.3 页面布局建议

参考 `plugins` 页的卡片布局，但要比 `plugins` 更偏“资源管理”。

建议字段：

- 名称
- id
- description
- source
- protocol
- tags
- aliases
- support_group
- support_streaming
- endpoint / base_url / card_url

建议交互：

1. 顶部 `Refresh`
2. 顶部 `Add Agent`
3. 列表卡片
4. workspace agent 允许删除
5. plugin / skill / builtin agent 只读

### 8.4 Add Agent 弹窗字段

- `id`
- `name`
- `description`
- `protocol`，先只放 `a2a`
- `base_url`
- `endpoint`
- `card_url`
- `auth_env`
- `tags`
- `aliases`
- `enabled`

## 9. MCP 管理页方案

### 9.1 结论先说

这个页面前端不能单独完成，因为当前后端没有 MCP 管理 API。

所以文档给的是“前端页面方案 + 后端配套接口定义”。

### 9.2 后端建议增加的 API

建议新增：

- `GET /api/mcp/servers`
- `POST /api/mcp/servers`
- `PUT /api/mcp/servers/{id}`
- `DELETE /api/mcp/servers/{id}`
- `POST /api/mcp/servers/{id}/test`
- `GET /api/mcp/tools`

### 9.3 MCP server 返回结构建议

```json
{
  "id": "github",
  "name": "github",
  "transport": "http",
  "url": "http://localhost:3001/mcp",
  "command": "",
  "args": [],
  "enabled": true,
  "tool_timeout": 30,
  "headers": {},
  "status": "connected",
  "tool_count": 12,
  "tool_names": ["search_repos", "list_prs"],
  "last_error": null
}
```

### 9.4 页面布局建议

上半区：MCP servers

- 卡片或表格
- 编辑 / 删除 / 测试连接

下半区：Discovered tools

- 按 server 分组
- 展示工具名、说明、schema 摘要

## 10. 建议的前端实现顺序

按这个顺序做最稳。

### Phase 1: 先做前端数据结构重构

1. 扩 `types/index.ts`
2. 扩 `lib/store.ts`
3. 扩 `lib/api.ts` 的 ws event 类型
4. 把 `app/page.tsx` 拆出 `ChatWorkbench`

这一步即使后端结构化事件还没补，也可以先用 mock data 跑布局。

### Phase 2: 落三栏工作台 UI

1. 中间主聊天区保留现有 message bubble
2. 加 `ProcessLane`
3. 加 `ArtifactSidebar`
4. 支持选中某个 run

### Phase 3: 接后端 process events

1. 给 `wsManager.onMessage()` 加 process 事件分发
2. store 按 event 更新 process state
3. 卡片流式刷新

### Phase 4: 新增 Agent 管理页

1. `app/agents/page.tsx`
2. `lib/api.ts` 增 Agent API
3. `Header.tsx` 增导航

### Phase 5: 新增 MCP 管理页

1. 后端先补接口
2. 前端 `app/mcp/page.tsx`
3. 管理 + 测试连接 + 工具查看

## 11. 为什么我建议最好由同一个 Codex 连前后端一起改

如果只是做视觉壳子，另一个 Codex 在前端仓库里单独改也可以。

但如果目标是你描述的完整体验：

- 每个 agent / MCP 弹出独立框
- 展示过程中的一问一答
- 展示 MCP 产物
- 最后再统一总结

那就不是纯前端问题，而是“后端事件模型 + 前端状态模型”联动问题。

结论：

- 只写前端：可以先做静态布局和 store 重构。
- 真正做成：最好同一个人连续改 backend + frontend，避免事件协议和 UI 状态设计脱节。

## 12. 给另一个 Codex 的明确施工指令

如果你把这份文档交给另一个 Codex，建议直接给它下面这段要求：

1. 先阅读：
   - `/home/ivan/xuan/steven_project/nanobot-fronted/app/page.tsx`
   - `/home/ivan/xuan/steven_project/nanobot-fronted/lib/store.ts`
   - `/home/ivan/xuan/steven_project/nanobot-fronted/lib/api.ts`
   - `/home/ivan/xuan/steven_project/nanobot-fronted/types/index.ts`
   - `/home/ivan/xuan/steven_project/nanobot-fronted/app/plugins/page.tsx`
   - `/home/ivan/xuan/steven_project/nanobot-fronted/app/skills/page.tsx`
2. 先把聊天页拆成三栏工作台，不要继续把复杂逻辑堆在 `app/page.tsx`。
3. 先做 `processRuns / processEvents / artifacts` 的前端数据模型。
4. 先接 `/api/agents` 做 Agent 管理页。
5. MCP 管理页先按文档搭 UI 壳子，但要显式标记“依赖后端 MCP API”。
6. 如果要做真实过程可视化，不要拿普通 markdown 消息硬解析，必须等结构化 WebSocket process events。

## 13. 最小可交付版本

如果要先做一个能看的版本，建议这样收敛：

1. 聊天页先做三栏布局。
2. 用当前 `_progress` 文本先临时映射成 Agent 卡片日志。
3. 先接 `/api/agents` 做管理页。
4. MCP 页先做只读占位页，提示“等待后端 MCP API”。
5. 第二轮再补真正结构化 process events。

这条路径的好处是：

- UI 先起来
- 后端协议第二轮再精修
- 不会一开始就卡死在全链路联调上

## 14. 推荐文档结论

最合适的落地方式是：

1. 前端先重构成“聊天消息”和“过程运行”两套状态。
2. 聊天页改成三栏工作台。
3. 先接现有 `/api/agents` 做 Agent 管理页。
4. MCP 管理页需要后端先补接口。
5. 真正的过程可视化必须补结构化 WebSocket process events，核心后端插入点是：
   - `nanobot/agent/delegation.py`
   - `nanobot/a2a/client.py`
   - `nanobot/agent/tools/mcp.py`
   - `nanobot/web/server.py`

