AI 消息
消息行基元 .ai-msg:user / assistant / system / tool 四角色(avatar 语义色)+ meta 时间 · token(summary 档隐藏)+ hover / focus-within 浮出 copy · retry 操作钮。无独立 init——操作委托由 initAiChat 提供(消息须挂在 .ai-chat 容器内)。
我
把这句话翻译成英文:「潮水褪去,才知道谁在裸泳。」
AI
"Only when the tide goes out do you discover who's been swimming naked."
SYS
上下文已压缩:38k → 21k tokens
TL
grep「formatDate」命中 6 处(src/utils/date.ts 等)
悬停 assistant 消息看 copy / retry 操作钮
<div class="ai-chat" style="height:auto"> <div class="ai-msg ai-msg--user" style="margin-bottom:10px"> <span class="ai-msg-avatar">我</span> <div style="min-width:0"> <div class="ai-msg-body">把这句话翻译成英文:「潮水褪去,才知道谁在裸泳。」</div> <div class="ai-msg-meta">12:04 · 21 tok</div> </div> </div> <div class="ai-msg ai-msg--assistant" style="margin-bottom:10px"> <span class="ai-msg-avatar">AI</span> <div style="min-width:0"> <div class="ai-msg-body">"Only when the tide goes out do you discover who's been swimming naked."</div> <div class="ai-msg-meta">12:04 · 34 tok</div> </div> <div class="ai-msg-actions"> <button type="button" data-ai-msg-action="copy" aria-label="复制"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="8" y="2" width="8" height="4" rx="1"/><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/></svg></button> <button type="button" data-ai-msg-action="retry" aria-label="重试"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg></button> </div> </div> <div class="ai-msg ai-msg--system" style="margin-bottom:10px"> <span class="ai-msg-avatar">SYS</span> <div style="min-width:0"> <div class="ai-msg-body">上下文已压缩:38k → 21k tokens</div> <div class="ai-msg-meta">12:06</div> </div> </div> <div class="ai-msg ai-msg--tool"> <span class="ai-msg-avatar">TL</span> <div style="min-width:0"> <div class="ai-msg-body">grep「formatDate」命中 6 处(src/utils/date.ts 等)</div> <div class="ai-msg-meta">12:06 · 0.4s</div> </div> </div></div><p class="demo-label" id="ai-msg-log" style="margin-top:8px">悬停 assistant 消息看 copy / retry 操作钮</p> 安装
bun add @icen.ai/ui pnpm add @icen.ai/ui npm install @icen.ai/ui yarn add @icen.ai/ui 一行引入该组件(CSS 与 behavior 自动带上,无需关心内部 CSS 文件名):
import { initAiChat } from '@icen.ai/ui/kit/ai-message';initAiChat(); 也可以用脚手架直接打印引入行:
bunx --bun @icen.ai/ui add ai-message
Astro 项目注意:kit 入口里的 CSS import 在页面 <script> 里会被 Astro 的 client bundle 摇掉——请改在布局 frontmatter 里引 CSS(import '@icen.ai/ui/components/ai-chat.css';),JS 行为仍可走 kit。Vite SPA / webpack 项目无此问题。
用法
<!-- 四角色:ai-msg--user / --assistant / --system / --tool;消息须挂在 .ai-chat 容器内 --><div class="ai-chat"> <div class="ai-msg ai-msg--assistant"> <span class="ai-msg-avatar">AI</span> <div> <div class="ai-msg-body">…消费方自行渲染 markdown…</div> <div class="ai-msg-actions"> <button type="button" data-ai-msg-action="copy" aria-label="复制">…</button> <button type="button" data-ai-msg-action="retry" aria-label="重试">…</button> </div> <div class="ai-msg-meta">12:04 · 1.2k tok</div> </div> </div></div> <!-- copy / retry 委托(与 ai-chat 同一个 init,事件 icen:ai-copy / icen:ai-retry,detail {el}) -->import { initAiChat } from '@icen.ai/ui/kit/ai-message';initAiChat();