19 KiB
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) |
— | AG-2 已取消运行模式;"先看方案再执行"是输入区的开关(scope.proposeFirst) |
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 个组件全量约 23 人日。 - 十六进制清理(仅
UsageDashboard4 组图表色):新增语义 token 并跑deno task gen:tokens,约 0.5 人日。 - 字号/圆角对齐:圆角基本零成本,字号逐组件替换约 0.5 人日。
- 动效时长具名化:批量替换,约 0.5 人日。
- 材质分层改造(成本最大项):需要设计判断 + 重写外层 class,尤其
ChatApp整合布局改动最大,预估 2~4 人日(取决于选用组件数量)。 - 全量 18 个组件改造合计约 5
8 人日;若只挑第 5 节列出的核心 68 个组件,约 3~4 人日。
5. 建议采用方案
优先"复制源码改 token",不建议"只借鉴交互自己写"。 理由:组件本就是自包含源码(registryDependencies: [],不依赖 Radix 基座),复制后完全在自己仓库维护,和门户现有 shadcn 组件的接入方式一致;MIT 协议允许修改与内部使用,仅需保留源码头部版权声明;MessageScroller 的跟随阈值、ToolResult/TodoList 的折叠状态机等细节比从零设计更省时间。只有个别极简组件(如 Citations 的行内角标)从零写可能比适配 motion 依赖更快,可视情况自写。
落地优先顺序(按覆盖我们 9 类事件/对象的紧迫度 + 改造成本排序):
Message+MessageBubble+MessageScroller—— 会话主干,先落地,材质改造集中在气泡外壳。StreamingResponse—— 承载text_delta,需先验证"整段替换"模型能否套我们的增量拼接。ToolResult+ToolApproval—— 覆盖tool_call_*与 approval 对象;tool_call_rejected需新增比denied更醒目的拒绝态。TodoList——agent.plan步骤清单(会话页顶部;抽屉压缩为一行进度)。ApprovalCard—— 覆盖非工具类通用审批。CodeBlock/FileDiff—— 系统核实结果与 diff 类工具输出的展示载体。Citations—— 改造成本最低,可较早排期。AgentActivity/ReasoningText—— 只借鉴时间线骨架与"Thought for Ns"摘要交互,不直接复制状态机(缺"保留完整推理文本可展开"这一我们需要的能力)。UsageDashboard—— 仅作历史用量图表参考;预算条(BudgetBar/Meter)在此库能力范围之外,需独立新写。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 |
agent.plan 步骤清单(新增 skipped 态) |
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(摘要被截断时可能漏)与服务端汇报。