AI 会话

AI 会话容器(AI 族门面条目):滚动钉底跟随、上滚暂停跟随并浮出「回到底部 · N 条」浮动钮(缺失自动补建);消息 copy / retry 操作委托(icen:ai-copy / icen:ai-retry);reasoning 折叠委托。配套 createAiStream 做 textContent 级流式追加;data-density 三档(verbose / normal / summary)控制信息密度。下方 demo 是全链路实况:composer v2(模型切换//命令/@引用/上下文环)→ createAiClient(mock provider,SSE 流式)→ createAiStream 渲染 → 审计聚合 → 用量环累计。

密度 发消息试试:全链路 demo(mock provider 流式回包 + 用量环累计)
我
帮我梳理这次发布前的检查清单,重点是构建验证和回滚路径。
12:04 · 28 tok
AI
好,先跑一下构建确认基线。
<div class="toolbar" style="margin-bottom:10px">  <span class="toolbar-label">密度</span>  <button class="btn btn-sm" type="button" data-ai-density="verbose">verbose</button>  <button class="btn btn-sm btn-primary" type="button" data-ai-density="normal">normal</button>  <button class="btn btn-sm" type="button" data-ai-density="summary">summary</button>  <span class="toolbar-spacer"></span>  <span class="toolbar-label">发消息试试:全链路 demo(mock provider 流式回包 + 用量环累计)</span></div><div class="ai-chat" id="ai-chat-demo" data-density="normal" style="height:380px;border:1px solid var(--token-line-soft);border-radius:var(--radius-md);padding:10px">  <div class="ai-chat-scroll">    <div class="ai-msg ai-msg--user">      <span class="ai-msg-avatar">我</span>      <div style="min-width:0">        <div class="ai-msg-body">帮我梳理这次发布前的检查清单,重点是构建验证和回滚路径。</div>        <div class="ai-msg-meta">12:04 · 28 tok</div>      </div>    </div>    <div class="ai-msg ai-msg--assistant">      <span class="ai-msg-avatar">AI</span>      <div style="min-width:0">        <div class="ai-msg-body">好,先跑一下构建确认基线。</div>      </div>    </div>    <div class="ai-reasoning is-done">      <button class="ai-reasoning-head" type="button" aria-expanded="false">        <span class="ai-reasoning-label">思考过程</span><span class="ai-reasoning-time">2.1s</span>      </button>      <div class="ai-reasoning-body" hidden>用户关注发布风险,清单需要覆盖:构建是否全绿、类型检查、关键页面冒烟、回滚路径。本次发布有 tag,回滚安全,可以先给结论。</div>    </div>    <div class="ai-tool ai-tool--shell is-done" data-ai-id="demo-chat-shell" data-ai-kind="shell">      <button class="ai-tool-head" type="button" aria-expanded="false">        <span class="ai-item-icon" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m4 17 6-6-6-6"/><path d="M12 19h8"/></svg></span>        <span class="ai-item-main">          <span class="ai-item-title">Shell</span>          <span class="ai-item-sub">bun run build</span>        </span>        <span class="ai-item-status" role="img" aria-label="完成"></span>        <span class="ai-item-meta">3.2s</span>      </button>      <div class="ai-tool-body" hidden>        <div class="ai-tool-io"><div class="ai-tool-io-label">输入</div><pre class="ai-tool-io-content">bun run build</pre></div>        <div class="ai-tool-io"><div class="ai-tool-io-label">输出</div><pre class="ai-tool-io-content">tsup ✓ · build-css: 55 components + 75 kit 入口 → dist/</pre></div>      </div>    </div>    <div class="ai-msg ai-msg--assistant" id="ai-chat-last" hidden>      <span class="ai-msg-avatar">AI</span>      <div style="min-width:0">        <div class="ai-msg-body" id="ai-chat-stream"></div>        <div class="ai-msg-meta" id="ai-chat-meta" hidden></div>      </div>    </div>  </div></div><div class="ai-composer" data-ai-composer id="ai-chat-composer" style="margin-top:10px">  <div class="ai-composer-queue" hidden></div>  <div class="ai-composer-attach" hidden></div>  <div class="ai-composer-box control">    <textarea class="ai-composer-input" rows="1" placeholder="输入消息,/ 命令 · @ 引用 · Enter 发送"></textarea>    <div class="ai-composer-actions">      <button class="ai-composer-btn" data-ai-attach type="button" aria-label="附件"></button>      <button class="ai-composer-send" data-ai-send type="button" aria-label="发送"></button>    </div>  </div></div>

安装

bun add @icen.ai/ui

一行引入该组件(CSS 与 behavior 自动带上,无需关心内部 CSS 文件名):

import { initAiChat } from '@icen.ai/ui/kit/ai-chat';initAiChat();

也可以用脚手架直接打印引入行:

bunx --bun @icen.ai/ui add ai-chat

Astro 项目注意:kit 入口里的 CSS import 在页面 <script> 里会被 Astro 的 client bundle 摇掉——请改在布局 frontmatter 里引 CSS(import '@icen.ai/ui/components/ai-chat.css';),JS 行为仍可走 kit。Vite SPA / webpack 项目无此问题。

用法

import { initAiChat, createAiStream } from '@icen.ai/ui/kit/ai-chat';initAiChat();   // 钉底跟随 / 上滚暂停 / .ai-chat-jump 缺失自动补建 / copy·retry / reasoning 折叠 <!-- DOM 契约 --><div class="ai-chat" data-density="normal">  <div class="ai-chat-scroll">    <div class="ai-msg ai-msg--user">      <span class="ai-msg-avatar">我</span>      <div>        <div class="ai-msg-body">…消费方自行渲染 markdown…</div>        <div class="ai-msg-meta">12:04 · 1.2k tok</div>      </div>    </div>  </div>  <button class="ai-chat-jump" hidden>回到底部 · 3 条新消息</button></div> // 流式回复:textContent 级追加(不解析 HTML;markdown 重渲染是消费方职责)const s = createAiStream(document.querySelector('.ai-msg-body'));s.append('…');s.done();   // 或 s.cancel()