Three new primitives — every product chat / agent surface should
adopt these to make the model honest about what it is doing.
──────────────────────────────────────────────────────────────────
<CostMeter> · Wave 13.C.1
──────────────────────────────────────────────────────────────────
packages/ai-ui/src/CostMeter.tsx (new)
- Live token + (optional) USD readout
- 4 tiers: neutral (no budget) · ok (<70 %) · warn (>=70 %) ·
danger (>=95 %) — token-tinted via color-mix() so all four
palettes degrade gracefully on browsers without var() support
- NaN-safe — non-finite / negative inputs floor to 0
- role=status + aria-live=polite + aria-label assembles a
screen-reader-friendly sentence
- Mini-bar visual indicator at the end of the pill when budget
is provided
- Pure passive surface — never warns / prompts / blocks
──────────────────────────────────────────────────────────────────
<ConfidenceTag> · Wave 13.C.2
──────────────────────────────────────────────────────────────────
packages/ai-ui/src/ConfidenceTag.tsx (new)
- Accepts `number | 'high' | 'medium' | 'low' | 'unknown'`
- Default thresholds 0.8 / 0.5 — both overridable
- Out-of-range numerics map to `unknown` (no false confidence)
- Optional `showScore` renders a tabular-nums percent suffix
- 4 token-tinted palettes (success / warning / danger /
neutral) — pair naturally with <CitationChip> for the full
'show your work' story
──────────────────────────────────────────────────────────────────
<RefusalCard> · Wave 13.C.3
──────────────────────────────────────────────────────────────────
packages/ai-ui/src/RefusalCard.tsx (new)
- 6 reason archetypes — safety / policy / capability /
authorization / rate-limit / unknown — each with a typed
heading + glyph
- Calm warning palette (never red) — refusals are not errors
- Up to 3 actionable next steps (further entries silently
clipped) — one is markable `primary` to render as filled CTA
- Optional `footer` slot for policy doc links
- role=note + composite aria-label covering heading +
explanation
──────────────────────────────────────────────────────────────────
Quality gates
──────────────────────────────────────────────────────────────────
✓ pnpm -F @bytelyst/ai-ui test → 67/67 passing (was 53/53)
+14 new trust-surface tests in src/__tests__/trust.test.tsx
✓ Exports wired in src/index.ts under '0.5 surfaces' section
✓ package.json 0.4.0 → 0.5.0
──────────────────────────────────────────────────────────────────
Roadmap tracker — 5 boxes flipped (§11)
──────────────────────────────────────────────────────────────────
13.C.1 CostMeter shipped
13.C.2 ConfidenceTag shipped
13.C.3 RefusalCard shipped
13.C.7 trust-surfaces showcase (lands in paired showcase commit)
MAG.3 the trust-surfaces customer-magnet ✨
Wave 13 Futurism: 5/39 → 9/39 (23%)
Magnet demos: 1/8 → 2/8 (25%)
TOTAL: 19/202 → 24/202 (12%)
Vendored snapshot + showcase /ai-ui/* + /futurism/trust-surfaces
routes land in the paired showcase commit.
Pending in 13.C: ProvenanceDrawer (.4) · DebugOverlay (.5) ·
PrivacyBadge (.6).
|
||
|---|---|---|
| .. | ||
| src | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
| vitest.config.ts | ||
@bytelyst/ai-ui
AI-native UI primitives for ByteLyst products. The flagship deliverable
of Wave 2 in learning_ai_uxui_web/docs/ROADMAP_2026.md.
Status:
0.1.0MVP — 3 components + 1 hook + 1 utility. Subsequent 0.x bumps add<ToolCallCard>,<CitationChip>,<AgentTimeline>,<ModelPicker>,<ToolPalette>, and theuseToolCalls/usePromptHistory/useTokenCounthooks.
Quick start
import { ChatStream } from '@bytelyst/ai-ui';
export function ChatPage() {
return (
<div style={{ height: '70vh' }}>
<ChatStream
endpoint="/api/chat"
placeholder="Ask anything…"
emptyState={<EmptyHint />}
/>
</div>
);
}
Architectural decisions
Per learning_ai_common_plat/docs/ROADMAP_2026_DECISIONS.md:
- §10 hook shape —
useChat()returns the same shape as Vercel AI SDK'suseChat. Drop-in compatible for any engineer who has already written a chat UI with the AI SDK. - Transport is pluggable — products inject
endpoint,streamProtocol,fetcher, orheaders. We are not locked to Vercel's SSE wire format.
Components
<ChatStream>
Opinionated composition of useChat + <MessageBubble> +
<PromptComposer>. Auto-scrolls (sticky-bottom), shows Stop while
streaming, surfaces transport errors inline.
<MessageBubble>
Single chat message atom. Variants by role (user / assistant / system /
tool). Built-in "thinking" indicator while streaming with no content
yet. Honors --bl-* design tokens.
<PromptComposer>
Multi-line input. Enter submits, Shift+Enter newlines, Cmd/Ctrl+Enter
alternates submit. Auto-grows up to maxLines. Slot for leading
actions (slash-commands etc.).
Hooks
useChat(options?)
Vercel-AI-SDK-shaped:
const {
messages, input, setInput, handleInputChange, handleSubmit,
append, isLoading, error, stop, reload, setMessages
} = useChat({
endpoint: '/api/chat',
streamProtocol: 'text', // 'text' | 'sse' | 'data'
initialMessages: [],
onFinish: (msg) => console.log('done', msg),
onError: (err) => console.error(err),
});
streamText(response, protocol?, signal?)
Low-level async generator that yields text deltas from a streaming
HTTP response. Supports 'text', 'sse', and 'data' protocols.
Wire protocols
| Protocol | Body format | Use when |
|---|---|---|
'text' (default) |
Plain text, streamed chunk-by-chunk | Any backend that pipes an LLM stream directly |
'sse' |
Server-Sent Events with data: ... frames |
OpenAI-compatible, Anthropic, most HF inference |
'data' |
Vercel AI SDK "data stream" prefix protocol | Backends using streamText() from ai/server |
For tool calls / citations / images, use 'sse' or 'data' once the
matching components ship in 0.2.x.
Tests
pnpm --filter @bytelyst/ai-ui test
Roadmap
0.2.0—<ToolCallCard>,<CitationChip>,useToolCalls()0.3.0—<AgentTimeline>,<ModelPicker>0.4.0—<ToolPalette>with MCP discovery0.5.0—<Markdown>+<CodeDiff>(Wave 2 stretch)1.0.0— API freeze when 3+ products consume in production