Files
UHD_Media_Tool/docs/design/agent-ui-reference.md
T
rootandClaude Opus 5.5 8352e5e881 feat(web): W4-F rebuild agent conversation and drawer with agentui components
- Port agentui (MIT, ashish200729/agentui@b2b752b) Message/MessageBubble/MessageScroller,
  StreamingResponse, ToolResult/ToolApproval, TodoList, ApprovalCard, CodeBlock/FileDiff,
  Citations, PromptInput into components/agentui; drop motion/shiki/Next, switch colors,
  type scale, radii, durations and easing to semantic tokens, honour reduced motion
- Conversation: streaming cursor, collapsible thinking, tool cards with kind/scope/risk/
  idempotency badges and audit idempotency key, prominent server-rejection state for both
  whitelist rejections and unauthorized errors, compaction markers, budget meters with
  over-limit state, approval cards (admin session only), two-column final report
  (model said vs system verified with task/record links), follow-scroll with jump-to-bottom
- Composer: Enter send / Shift+Enter newline, stop = abort (confirmed), append,
  execute/plan_only switch, "execute this plan" from finished plan_only runs
- Session list sidebar with status filter and usage; reconnect/error banners with retry
- Drawer: route-derived context (entity/site/task), minimize to a live mini dock
- Fix stream refetch race when the run switches from loading to finished

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 23:08:17 +08:00

174 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Agent UI(agentui.pro)组件库调研 → Agent 会话页参考
调研对象:<https://www.agentui.pro/>(shadcn 目录第三方社区 registry `@agentui`)。结论先说:这是一套**纯前端交互参考**,MIT 协议、可自由复制修改;组件本身自包含(不依赖 radix-ui/ai-sdk,`registryDependencies` 为空),但视觉上大量使用 Tailwind 调色板色(`emerald-*`/`rose-*`/`amber-*`/`blue-*`)与个别十六进制硬编码,与本项目 `docs/design/README.md` 的 token 纪律正面冲突,**不能直接 `shadcn add` 落地,只能复制源码后逐组件替换视觉层**。交互设计(状态机、折叠策略、滚动跟随阈值)成熟度高于我们目前的空白,值得原样借用。
## 1. 项目身份
| 项 | 内容 |
|---|---|
| 定位 | "Copy-paste AI agent components built with Motion and Tailwind CSS." |
| 公开仓库 | <https://github.com/ashish200729/agentui>(经 shadcn-ui/ui PR #11607 确认,`ashish200729` 为提交者,LICENSE 落款人 Saurabh Chauhan,应为同一团队) |
| 许可证 | MIT(仓库根目录 `LICENSE`,标准 MIT 全文,保留版权声明即可商用/修改/私有项目使用,无需开源回馈) |
| 技术栈 | React `^19.0.0`、Next.js `16.3.5`(仅站点本身,组件不依赖 Next 特性)、Tailwind CSS `^4.0.0`、TypeScript `^5.7.3`、动效库 `motion`(Framer Motion 后继,`motion/react`)、代码高亮 `shiki`、`clsx` + `tailwind-merge` |
| shadcn style | 未取得。仓库根目录无 `components.json`,`registry.json` 也无 `style` 字段;组件不引用 shadcn 的 `Button`/`Card` 等基础原语(`registryDependencies: []`),只假设消费方项目已有 `bg-muted`/`text-foreground`/`border-border` 等 shadcn 语义 CSS 变量,style 差异对能否使用没有实质影响 |
| 依赖 radix/ai-sdk | 均不依赖。折叠/弹层是 `motion` 手写实现,不是 Radix Primitive,复制后需自查无障碍(aria)行为,不能假设 Radix 默认可访问性 |
| 安装方式 | 逐组件走 shadcn registry:`bunx --bun shadcn add https://www.agentui.pro/r/<component>`(npm/pnpm/yarn 等价);无独立可发布的 npm 包,也可直接 `git clone` 仓库复制 `components/agents/*.tsx` 源码,本项目应选后者(见第 5 节) |
| 组件规模 | 18 个组件文档页(footer 分「Primitives」「Surfaces」两组),`registry.json` 汇总 22 个 registry item(component/lib/hook 混计,如 `lib/ease.ts`、`message-context.tsx` 各自单独登记) |
| 未取得 | LICENSE 与 PR 里的作者姓名不一致但均指向同一仓库,未进一步核实组织关系;`/pricing`、`/license`、`/playground` 页面均 404 或未抓取 |
## 2. 组件清单与交互语义
统一安装命令 `bunx --bun shadcn add https://www.agentui.pro/r/<name>`,依赖均含 `clsx lucide-react motion tailwind-merge`(部分另加 `shiki`)。
### 消息列表/气泡
| 组件 | 用途 | 关键 props | 视觉要点 |
|---|---|---|---|
| `Message` | 消息行容器,按 `from` 控制左右布局与头像位 | `from: "user"\|"assistant"`、`animateIn`;子件 `MessageAvatar`/`MessageHeader`/`MessageFooter`/`MessageTyping` | 7×7 圆形头像,header 时间戳 `text-[11px]` |
| `MessageBubble` | 气泡本体 | `variant: solid\|soft\|tint\|outline\|ghost\|danger`、`align`、`MessageBubbleCollapsible.collapsedLines`(2~6 行截断) | `rounded-2xl px-3.5 py-2.5`,`max-w-[82%]`,长内容 `line-clamp` 折叠 |
| `MessageScroller` | 会话滚动容器(见"滚动跟随") | — | — |
### 流式文本(打字/光标)
`StreamingResponse`:`status: streaming\|complete\|error`,`sources`(接 Citations)、`showActions`(复制/重试/反馈)。是"内容整段替换后平滑重排"模型,**不是逐字符打字机**,也没有光标闪烁效果;富文本用 `[&_a]`/`[&_code]`/`[&_pre]` 选择器样式化。
### 推理/思考折叠块
没有专门的"可展开查看完整思考记录"组件。两个近似方案:
- `Agent Activity`:`contentType: text\|search\|mixed\|step\|tool\|trace`,时间线渐进渲染,完成后**折叠为摘要**"Thought for Ns"(`formatDuration()`),原始推理文本不保留可展开入口。
- `Loading States` 里的 `ReasoningText`:`phrases`(循环短语)+ `variant: cascade\|swap\|scramble`,纯"正在思考"提示,无历史、无折叠。
### 工具调用卡片
| 组件 | 状态 | 折叠/耗时 | 备注 |
|---|---|---|---|
| `ToolResult` | `running\|success\|error\|cancelled` | `open/defaultOpen/collapseOnComplete`(完成自动折叠),`meta` 显示耗时/状态码,`maxHeight` 默认 220 | `ToolResultOutput` 承载语法高亮的输入/输出,`kind: terminal\|request\|custom` |
| `ToolApproval` | `pending\|approving\|approved\|denied\|running\|complete\|error` | `parameters: {id,label,value}[]` 展示参数,无风险分级 | 三按钮:Allow once / Always allow / Deny |
### 计划/步骤
`TodoList`:扁平数组 `items: TodoItem[]`(**不支持嵌套子任务**),状态 `pending\|in-progress\|completed\|cancelled`,`in-progress` 可带 `progress` 百分比,`collapseOnComplete` 默认折叠,`maxHeight` 默认 248。
### 审批/确认
| 组件 | 场景 | 状态机 | 交互 |
|---|---|---|---|
| `ApprovalCard` | 通用审批 + 多步问答 | `pending\|submitting\|approved\|rejected\|changes-requested\|answered` | Approve / Reject / Request Changes,或问题流的单选/多选/自由填写 + 步骤导航 |
| `ToolApproval` | 单个工具执行权限 | 见上 | Allow once / Always allow / Deny |
两者均**没有 `riskLevel`/`scope` 字段**,风险信息属于应用层自行拼进 `title`/`description`/`parameters`。
### 代码/JSON 展示
`CodeBlock`:`shiki` 高亮,`language: text\|bash\|diff\|json\|tsx\|typescript`,`showLineNumbers`(默认 true)、`highlightLines`、`status: streaming\|complete`、`copyable`,**无折叠功能**。`FileDiff` 是它的 diff 变体:`lines: FileDiffLine[]`,新增行 `bg-emerald-500/[0.07]`、删除行 `bg-rose-500/[0.07]`,同样支持 `collapseOnComplete`。
### 引用来源
`Citations`:行内角标(`Citation` + `idPrefix` 关联)+ 底部可折叠来源列表(`Citations`,`defaultOpen` 默认 **false**),支持网站 favicon、新增项弹簧动效。
### 附件/图片
`ImageGeneration`:状态机 `queued\|generating\|refining\|complete\|error`(带 `onRetry`),`aspectRatio`/`resolution` 固定占位避免布局跳动,悬浮有跟随鼠标的抖动叠层特效;**不支持多图网格、不支持点击放大**。`PromptInput` 的 "Attach image"/"Add context" 只是 Actions 菜单里的两个按钮项,没有真正的附件预览/管理组件。
### 用量与费用
`UsageDashboard`:`records: UsageRecord[]`(`inputTokens/outputTokens/cachedInputTokens/costUsd/requests/date/provider/model`),`range: 7|30` 天切换,输出「按天令牌趋势折线图 + 按 provider/model 汇总 + 计费金额表」,**没有预算/额度、没有进度条**,图表配色是 4 组写死的十六进制 CSS 变量(`--usage-first:#0e857e` 等,深浅各一套)。
### 会话列表/分支
`AISidebar`:资源树(folders/projects/files/bookmarks),支持拖拽移动、内联重命名(F2/双击)、键盘导航,**不支持搜索,也没有"会话分支"概念**,是文件系统式的资源管理器而非对话历史列表。
### 输入框
`PromptInput`:自增高文本域 `minRows=2/maxRows=8`,Enter 发送、Shift+Enter 换行,`loading` 时按钮变"停止"(`onStop`),`models`(模型选择器)、`actions`(附加动作菜单)。
### 空态与错误态
**没有独立的 EmptyState 组件**。错误态分散在各组件里:`StreamingResponse.status="error"`、`ImageGeneration.status="error"`(带重试)、`ToolResult.status="error"`、`ToolApproval.status="error"`;会话为空时没有专门占位方案。
### 滚动跟随策略
`MessageScroller` 精确对应需求:内部按 `scrollHeight - scrollTop - clientHeight` 算与底部距离,小于 `followThreshold`(默认 56px)才判定为"跟随中";滚轮/触摸/方向键会主动 `leaveLiveEdge()` 退出跟随,直到用户手动滚回底部;`followOutput` 开关、`onFollowChange` 回调、`ResizeObserver` 监听内容增长。这是本次调研里与我们需求匹配度最高的单个组件。
## 3. 与本项目的映射
| 我们的事件/对象(`packages/contracts/src/*`) | agentui 对应组件 | 需要改造的点 |
|---|---|---|
| `run_started`(`agent-events.ts`) | 无对应"轮次开始"组件 | 需自建,可借 `Message` 起新一行 + `AgentProgress` 计时 |
| `text_delta` | `StreamingResponse` | 该组件是整段替换模型,需要自己把增量 `delta` 拼接成累积字符串再喂入;无逐字符/光标效果 |
| `thinking_delta` | `AgentActivity`(`contentType="text"`)/`ReasoningText` | 都不满足"可展开查看完整推理文本"——`AgentActivity` 完成后只留"Thought for Ns"摘要,`ReasoningText` 无历史;需要在其骨架上新增可展开的完整文本区 |
| `tool_call_start`/`tool_call_end`(字段 `capabilityId`/`toolCallId`/`inputSummary`/`outputSummary`/`isError`) | `ToolResult` | 状态映射 running→running、!isError→success、isError→error 基本可套;`inputSummary`/`outputSummary` 对应 `ToolResultOutput` 折叠内容,耗时对应 `meta` |
| `tool_call_rejected`(带 `toolName`/`reason`) | `ToolApproval.denied` | **需要改造**:库里 `denied` 只是三按钮里的弱化态,不够醒目;需要新增一个突出的"已拒绝"卡片(destructive 材质 + 拒绝原因文案),不能照抄 |
| `compaction`(`phase`/`reason`/`status`) | 无对应组件 | 该库没有"上下文压缩"概念,需全新设计系统提示卡片 |
| `run_completed`/`run_failed`(含 `AgentUsageTotals`、`budget` 超限原因) | `StreamingResponse.status="complete"/"error"` | 可复用完成态操作条,失败态需要自己接超限原因(`tool_calls/duration/tokens/cost`)文案 |
| Capability `scope`/`riskLevel`/`idempotent`(`capability.ts`)、`idempotencyKey`(`agent.ts` `CapabilityInvocation`) | `ToolApproval.parameters` | 只有 key/value 参数列表,**没有风险等级视觉(红/黄/绿)、没有幂等键/审计信息位**,需要在参数区之外加风险徽章 + 审计元数据条 |
| `Approval`(`agent.ts` ~222,`status: pending\|approved\|rejected\|revoked\|expired\|consumed`) | `ApprovalCard`/`ToolApproval` | 状态集不对齐:我们多出 `revoked/expired/consumed`,库多出 `submitting/changes-requested/answered`,需要做一层状态映射并砍掉/新增对应视觉 |
| `AgentGoalReport`(`modelText` vs `buildGoalReport()` 系统汇总)、UI `FinalReport()`(`agent-conversation.tsx`,"模型说的"/"系统核实的结果"双栏) | 无对应组件 | **该库完全没有"声明 vs 核实"双轨展示**,`StreamingResponse` 只有单一正文 + `Citations`;需要新写一张"系统核实结果"卡片,可能借 `ToolResult` 或 `Citations` 的折叠壳改造 |
| `AgentBudget`/`AgentUsage`、`BudgetBar()`+`Meter()`(`agent-conversation.tsx`,四项:工具调用/token/时长/费用) | `UsageDashboard` | 该组件是历史用量仪表盘(按天图表 + 汇总表),**没有"当前额度 vs 已用"的进度条**,量级和展示逻辑都不同,预算条要另写 |
| `AgentRunMode`(`execute`/`plan_only`) | 无对应组件 | 库里没有模式指示器,需要自建(如顶部条幅或输入框旁的模式开关) |
## 4. 设计纪律冲突
对照 `docs/design/README.md` 的硬规则(禁原色/十六进制/调色板色/字面量字号/字面量时长/裸 `rounded`):
- **调色板色(命中"禁止"规则)**:`ApprovalCard`/`ToolApproval`/`TodoList`/`CodeBlock`/`FileDiff` 大量使用 `text-emerald-600`、`text-rose-600`、`text-amber-600`、`text-blue-600`(及各自 `dark:` 变体)表示成功/失败/等待/进行中,直接对应我们要求的 `success`/`destructive`/`warning`/(进行中无专用状态色,需另议)。
- **十六进制硬编码(命中"禁止"规则)**:`UsageDashboard` 图表配色写死 `--usage-first:#0e857e` 等 4 组变量,亮暗各一套。按我们规则,图表这类"只接受颜色值的地方"允许组件内常量表 + `token-allow` 注释,但当前写法未走语义 token,需要重新登记。
- **字号**:多用 Tailwind 语义档 `text-xs`/`text-sm`,不是字面量 `text-[13px]`,和我们规则里"Tailwind 档继续用"部分相容,但两套字号阶梯(我们的 `micro/label/meta/caption/body/control...`)档位不完全对齐(如我们 `caption=13px` 在 Tailwind 默认档里没有对应),混用会出现两套字号语言,需要逐组件按角色替换成我们的 `text-*` token。
- **圆角**:`rounded-md/lg/xl/2xl/full` 与我们"控件/输入/卡片/面板/药丸"的角色划分基本对齐,迁移成本低;但我们另有 `rounded-tight`/`rounded-slab` 等角色名,复制后要重新按角色套。
- **动效时长**:`docs/motion-patterns` 文档直接写 `duration: 0.22`/`0.18`/`0.12` 等字面量秒数,命中"禁止 `duration-N`"类规则,需要批量替换成 `duration-micro/base/layout` 具名档。
- **材质体系**:agentui 全部是纯 shadcn 语义色平面卡片(`bg-muted`/`bg-background`/`border-border`),没有玻璃拟态、没有 `backdrop-blur`,与我们三层材质(`pg-surface`/`pg-slab`/`pg-float`)是完全不同的视觉语言;复制后每个容器要重新判断属于贴边/内容卡/悬浮层的哪一层并换成对应 `pg-*` 类,不能直接沿用 `bg-muted`。
改造成本估算(以复制源码后逐项替换为准):
- 调色板色 → 语义状态色:每组件 5~15 处 className,18 个组件全量约 2~3 人日。
- 十六进制清理(仅 `UsageDashboard` 4 组图表色):新增语义 token 并跑 `deno task gen:tokens`,约 0.5 人日。
- 字号/圆角对齐:圆角基本零成本,字号逐组件替换约 0.5 人日。
- 动效时长具名化:批量替换,约 0.5 人日。
- 材质分层改造(成本最大项):需要设计判断 + 重写外层 class,尤其 `ChatApp` 整合布局改动最大,预估 2~4 人日(取决于选用组件数量)。
- 全量 18 个组件改造合计约 5~8 人日;若只挑第 5 节列出的核心 6~8 个组件,约 3~4 人日。
## 5. 建议采用方案
**优先"复制源码改 token",不建议"只借鉴交互自己写"。** 理由:组件本就是自包含源码(`registryDependencies: []`,不依赖 Radix 基座),复制后完全在自己仓库维护,和门户现有 shadcn 组件的接入方式一致;MIT 协议允许修改与内部使用,仅需保留源码头部版权声明;`MessageScroller` 的跟随阈值、`ToolResult`/`TodoList` 的折叠状态机等细节比从零设计更省时间。只有个别极简组件(如 `Citations` 的行内角标)从零写可能比适配 `motion` 依赖更快,可视情况自写。
落地优先顺序(按覆盖我们 9 类事件/对象的紧迫度 + 改造成本排序):
1. `Message` + `MessageBubble` + `MessageScroller` —— 会话主干,先落地,材质改造集中在气泡外壳。
2. `StreamingResponse` —— 承载 `text_delta`,需先验证"整段替换"模型能否套我们的增量拼接。
3. `ToolResult` + `ToolApproval` —— 覆盖 `tool_call_*` 与 approval 对象;`tool_call_rejected` 需新增比 `denied` 更醒目的拒绝态。
4. `TodoList` —— `plan_only` 模式下的步骤展示。
5. `ApprovalCard` —— 覆盖非工具类通用审批。
6. `CodeBlock`/`FileDiff` —— 系统核实结果与 diff 类工具输出的展示载体。
7. `Citations` —— 改造成本最低,可较早排期。
8. `AgentActivity`/`ReasoningText` —— 只借鉴时间线骨架与"Thought for Ns"摘要交互,不直接复制状态机(缺"保留完整推理文本可展开"这一我们需要的能力)。
9. `UsageDashboard` —— 仅作历史用量图表参考;预算条(`BudgetBar`/`Meter`)在此库能力范围之外,需独立新写。
10. `AISidebar`/`ChatApp` —— 不支持会话分支、无搜索,只作整体布局排版参考,不建议直接采用其资源树数据模型。
## 6. 已采用清单(W4-F,2026-09-27)
源码取自 `ashish200729/agentui@b2b752b`(MIT),放在 `apps/web/app/components/agentui/`,每个文件头保留版权与来源,
许可证全文见同目录 `LICENSE-agentui.md`。统一改造:去掉 `motion`/`shiki`/Next.js 依赖(入场用 tw-animate 的
`animate-in`,折叠用 CSS grid-rows 过渡,全部带 `motion-reduce:` 关闭);调色板色 → `success`/`warning`/`destructive`
并配文字;字号/圆角/时长/缓动换项目 token;文案中文化。
| 上游组件 | 本项目文件 | 用在哪 | 主要改造 |
|---|---|---|---|
| `Message`(+`message-context`) | `message.tsx` | 会话流的用户/Agent/系统行 | 新增 `from="system"`;`MessageMarker` 作压缩提示;`MessageTyping` 用 animate-pulse |
| `MessageBubble` | `message-bubble.tsx` | 用户消息、失败/超预算/中止提示 | 变体换语义底色,新增 `warning`;去 layout 动画 |
| `MessageScroller` | `message-scroller.tsx` | 会话页与侧栏抽屉的滚动区 | 保留跟随阈值状态机;只有"往上翻"才离开跟随;新增"回到底部"按钮;首屏回放直接跳底;log 只播报新增行 |
| `StreamingResponse` | `streaming-response.tsx` | 流式文本、"模型说的"栏 | 新增流式光标;去点赞/点踩;来源接 `CitationList` |
| `ToolResult` | `tool-result.tsx` | 工具调用卡片 | 新增 `badges`(类别/scope/风险/幂等/恢复补记)与收起摘要;输入输出用 `CodeBlock` |
| `ToolApproval` | `tool-approval.tsx` | **拒绝态**(白名单拦截 `tool_call_rejected` 与授权校验失败的 `unauthorized`) | 新增 `rejected` 醒目态:destructive 材质 + `role=alert` + 原因 + 授权说明;去掉 "Always allow" |
| `TodoList` | `todo-list.tsx` | 只要方案模式的"调查步骤" | SVG 状态图标保留,弹簧动画换 CSS;新增 `error` 态 |
| `ApprovalCard` | `approval-card.tsx` | Approval 对象(计划、payload hash、版本、到期、风险) | 状态集对齐 `pending/approved/rejected/revoked/expired/consumed`(+`submitting`);去掉问答模式;非管理员会话按钮禁用并说明 |
| `CodeBlock`(+`agent-code`) | `code-block.tsx` | 工具输入/输出 | 不做语法高亮;JSON 自动缩进 |
| `FileDiff` | `file-diff.tsx` | 系统核实栏的"入库目标" | +/− 符号保留,底色换 success/destructive 洗层 |
| `Citations` | `citations.tsx` | 系统核实栏的下载任务/整理记录链接 | 去 favicon;站内链接走 `Link` |
| `PromptInput` | `prompt-input.tsx` | 新目标与追加消息输入框 | 保留自增高、Enter 发送/Shift+Enter 换行/组字不发送、运行中"停止";去模型选择与动作菜单,换 `toolbar` 槽 |
| `AgentDisclosure` | `disclosure.tsx` | 所有折叠区 | motion → CSS grid-rows;收起时 `inert` |
未采用:`AgentActivity`/`ReasoningText`(思考块自写,保留完整推理文本可展开)、`UsageDashboard`(预算条自写,带超限态)、
`AISidebar`/`ChatApp`(会话列表自写:状态筛选 + 目标/状态/模式/时间/用量)、`ImageGeneration`。
已知限制:幂等键来自审计事件(`/audit-events` 按 `payload.agentRunId` 过滤,最多翻 3 页、按同能力先后与工具调用配对),
较早的运行可能取不到;审批卡片的计划来自工具调用输入/输出里能解析到的 `planId`(摘要被截断时可能漏)与服务端汇报。