AI chat message bubble
ai-ui specs/ai-ui/chat-message-bubble.kmd
Baseline message bubble for any AI chat surface in Koder Stack: user vs assistant variants, mandatory AI disclaimer chip on assistant messages, copy/edit/regenerate/branch actions, multi-modal content hosting (text, code, image, citations, tool invocations).
Quando esta spec se aplica
Triggers primários
- Display a single AI conversation message
Todos os triggers
- Render any conversational AI exchange in a Koder product
- Build new chat surface (Kortex, Talk, Kruze, Kode, Bot)
- Audit AI UI for compliance disclaimer
Corpo da especificação
Spec — AI chat message bubble
Baseline component consumido por todo produto AI Koder. Hosts streaming text (cross-link
streaming-text.kmd), tool invocations (cross-linkmcp-tool-invocation.kmd), code blocks, citations, e disclaimer (cross-linkai-disclaimer.kmd).
Princípios
- Two-role taxonomy — user vs assistant. Sem variantes "system" ou "tool" no bubble visual (tool calls são inline content do assistant bubble, não bubbles próprios).
- Disclaimer is non-negotiable — todo assistant bubble carrega disclaimer chip per #119. Sem exceção em produto distribuído.
- Composable content — bubble é container; renderers de text/code/image/citation/tool são plug-ins.
- Actions where the user expects them — toolbar inline (hover desktop / always-visible mobile) com Copy / Edit / Regenerate / Branch.
R1 — Anatomia
R1.1 — User bubble
┌──────────────────────┐
│ "What's the weather?"│
└──────────────────────┘
14:32 · ✎
- Alignment: right (LTR) / left (RTL per
i18n/contract.kmd). - Tint:
primary-container(perthemes/color-roles.kmd). - Shape:
shape-corner-largeexceto trailing-bottom corner (shape-corner-small) — tail. - Avatar: opcional (off by default; product configurável).
- Footer chips: timestamp · edit pencil (R3.2).
R1.2 — Assistant bubble
[avatar] ┌──────────────────────────────────────────┐
│ "It's 22°C in São Paulo right now." │
│ │
│ [mcp-tool-card if any] │
│ [code-block if any] │
│ [citation[1]] inline │
│ │
│ — Sources │
│ [1] weather.com/sp │
└──────────────────────────────────────────┘
🤖 Generated by AI — verify · 14:32 · ⎘ ✎ ↻ ⑂
- Alignment: left (LTR) / right (RTL).
- Tint:
surface(perthemes/color-roles.kmd). - Shape:
shape-corner-largeexceto leading-bottom corner. - Avatar: assistant icon (configurável: model logo OR product logo OR generic ✨).
- Disclaimer chip: SEMPRE presente (cross-link
ai-disclaimer.kmdper tier). - Footer chips: timestamp · Copy ⎘ · Edit ✎ · Regenerate ↻ · Branch ⑂.
R2 — Mandatory disclaimer chip
ai-disclaimer.kmd R1 define 3 tiers (label / label+modal / label+banner+confirmation). Bubble hosts o label form:
| Risk tier | Chip placement | Copy key |
|---|---|---|
| low (default) | Footer chip; subtle (text-muted) | ai.disclaimer.label.low |
| medium | Footer chip; emphasized (warning) | ai.disclaimer.label.medium |
| high | Banner ACIMA do bubble (não chip footer) | ai.disclaimer.label.high |
Chip clickable → expand modal explicativo (#119 R1 tier 2 behavior; tier 1 = chip-only).
Per feedback_kds_owner_curated_content: copy editorial não editável por IA autonomamente.
R3 — Actions
R3.1 — User actions
| Action | Behavior |
|---|---|
| Edit ✎ | Re-opens composer pré-preenchido com prompt original; submit substitui esta mensagem + invalida cascata downstream (assistant responses subsequentes). |
R3.2 — Assistant actions
| Action | Behavior |
|---|---|
| Copy ⎘ | Copia content como markdown (preservando code blocks, citations footnotes per citations.kmd R4). |
| Edit ✎ | Permite override do assistant message (rare; admin/debug surfaces only — default OFF). |
| Regenerate ↻ | Re-invoke gateway com same context; nova resposta substitui esta. |
| Branch ⑂ | Forka conversa daqui; cria nova conversation history entry com same prefix (cross-link conversation-history.kmd #115). |
Hover surface: actions reveal on desktop hover; mobile: actions always visible (touch).
R4 — States
| State | Visual |
|---|---|
| streaming | Cursor visible (streaming-text.kmd R2); footer disabled exceto Stop button |
| complete | Footer actions enabled; disclaimer rendered |
| error | Red border + error icon + "Retry" button (replaces Regenerate); error message in body |
| edited | "✎ Edited" badge no footer + edit history accessible via long-press/right-click |
R5 — Multi-modal content hosting
Bubble body é container que renderiza array de content items (mesma estrutura do MCP tools/call content). Renderers:
| Content type | Renderer | Spec |
|---|---|---|
text | Markdown incremental + citation inline | streaming-text.kmd, citations.kmd |
code | Syntax highlight + actions | code-block.kmd |
image | KoderImage (tap-fullscreen) | media/image.kmd |
mcp_tool_call | Tool card collapsible | mcp-tool-invocation.kmd |
citation_list | Sidebar/footer footnotes | citations.kmd |
kvg | Koder Vector Graphics (declarative) | kvg/ spec (existente) |
Render order = array order from gateway response. Streaming: content items appear progressivamente.
R6 — Surface bindings
| Surface | API |
|---|---|
| Flutter | KoderAIMessageBubble({required role, required content, onAction}) em koder_kit/lib/src/ai/ai_message_bubble.dart |
| Web | <koder-ai-message-bubble role="..." content="..."> em koder_web_kit |
| Compose Android | KoderAIMessageBubble em koder-design-compose (futuro) |
| SwiftUI iOS | KoderAIMessageBubble em koder-design-swift (futuro) |
| CLI / TUI | Texto plain: prefix > user, < assistant; disclaimer linha separada |
API consistent: role: "user" | "assistant", content: List<ContentItem>, state: streaming|complete|error, onAction: callback(action_id).
R7 — Acessibilidade
- Bubble é
<article role="region" aria-label="Message from {role}">. - Avatar tem
aria-hidden="true"(role já anunciado). - Disclaimer chip lido por screen reader como part of bubble: aria-describedby.
- Actions: keyboard-accessible via Tab; aria-label per action.
- Streaming state: aria-live="polite" announces "Generating…" → silent during stream → "Done" at end.
- Edited state: aria-label includes "edited".
- Reduced-motion: no entrance animation.
- Touch targets ≥48dp.
R8 — i18n
| Key | en-US | pt-BR |
|---|---|---|
ai.bubble.role.user | "You" | "Você" |
ai.bubble.role.assistant | "Assistant" | "Assistente" |
ai.bubble.action.copy | "Copy" | "Copiar" |
ai.bubble.action.edit | "Edit" | "Editar" |
ai.bubble.action.regenerate | "Regenerate" | "Gerar de novo" |
ai.bubble.action.branch | "Branch" | "Ramificar" |
ai.bubble.action.retry | "Retry" | "Tentar novamente" |
ai.bubble.state.streaming | "Generating…" | "Gerando…" |
ai.bubble.state.edited | "Edited" | "Editado" |
ai.bubble.action.copy.confirm | "Copied to clipboard" | "Copiado" |
(Disclaimer copy lives em ai-disclaimer.kmd R7.)
R9 — Multi-tenant + persistência
Message stored per policies/multi-tenant-by-default.kmd:
- Key:
(koder_user_id, workspace_id, conversation_id, message_id). - Edit history mantém versions (linear); rollback via long-press menu.
- Cross-tenant lookup 404 per multi-tenancy contract.
- Delete: cascata per
policies/identity-data-retention.kmdR5 (24h grace + cascade).
R10 — Per-preset variation
| Preset | Bubble style |
|---|---|
material3 / material_expressive | Defaults; shape-corner-large; spring entrance |
material2 | shape-corner-medium |
terminal_classic | No bubbles — > prompt / < response prefix; monospace |
brutalist | Sharp corners; 2px border; no shadow |
cyberpunk_neon | Glow outline; gradient backdrop |
glassmorphism | Backdrop blur 20%; transparent tint |
minimalist_mono | Mono font; horizontal divider entre roles em vez de bubbles |
T-suite
- T1 Mount user: render user bubble com text content; alignment right (LTR).
- T2 Mount assistant: render assistant bubble com text + disclaimer chip visible.
- T3 Multi-modal: render assistant com text + code-block + tool-call + citation; ordem preserved.
- T4 Action Copy: tap copy → clipboard content includes citations as markdown footnotes.
- T5 Action Regenerate: tap → bubble enters streaming state; new content replaces.
- T6 Action Branch: tap → new conversation created with prefix up to this message.
- T7 Action Edit (user): tap → composer pre-filled; submit invalidates downstream cascade.
- T8 Error state: simulate gateway error → red border + Retry button visible.
- T9 RTL: render em locale rtl-* → alignment flips.
- T10 A11y: screen reader announces role + content + disclaimer + actions list.
- T11 Disclaimer always present: render assistant bubble without disclaimer prop → spec validation FAILS (compile-time or runtime error).
- N1 Cross-tenant access: try to load message from another workspace → 404.
Cross-link
- Companion:
streaming-text.kmd,ai-disclaimer.kmd,mcp-tool-invocation.kmd,citations.kmd,code-block.kmd - Policies:
multi-tenant-by-default.kmd,identity-data-retention.kmd - Tokens:
themes/color-roles.kmd,themes/typography.kmd,themes/shape.kmd - i18n:
specs/i18n/contract.kmd - Backend:
services/ai/chat-adapter/(wire protocol)
Referências
meta/docs/stack/specs/ai-ui/streaming-text.kmdmeta/docs/stack/specs/ai-ui/ai-disclaimer.kmdmeta/docs/stack/specs/ai-ui/mcp-tool-invocation.kmdmeta/docs/stack/specs/ai-ui/code-block.kmdmeta/docs/stack/specs/ai-ui/citations.kmdmeta/docs/stack/policies/multi-tenant-by-default.kmdmeta/docs/stack/specs/i18n/contract.kmd