Message
Turno de chat atômico com layout ciente do papel, attachments, navegação por branch e uma superfície de markdown com streaming.
Visão geral
Message renderiza um único turno de chat. Ele escolhe layout, alinhamento e tratamento de superfície a partir do papel from ("user" vs "assistant"), e então deixa você compor o interior com conteúdo, attachments, uma toolbar e navegação por branch. O markdown com streaming é renderizado por MessageResponse, que é memoizado para manter turnos grandes fluidos enquanto os tokens chegam.
Use como a unidade atômica de qualquer conversa: um Message por turno, composto com irmãos como Reasoning, Sources ou InlineCitation.
Preview
Assistant com toolbar
How can I help?
I can answer questions, summarize documents, and walk through code with you. Pick a task:
- Explain a concept
- Refactor a function
- Draft an email
Just let me know what you need.
'use client';import { Message, MessageAction, MessageActions, MessageContent, MessageResponse, MessageToolbar,} from '@gremorie/rx-ai';import { Copy, RefreshCw, ThumbsDown, ThumbsUp } from 'lucide-react';const assistantMarkdown = `## How can I help?I can answer questions, summarize documents, and walk through code with you. Pick a task:- Explain a concept- Refactor a function- Draft an emailJust let me know what you need.`;export function MessageAssistantPreview() { return ( <div className="flex flex-col gap-2"> <Message from="assistant"> <MessageContent> <MessageResponse>{assistantMarkdown}</MessageResponse> </MessageContent> <MessageToolbar> <MessageActions> <MessageAction tooltip="Copy"> <Copy /> </MessageAction> <MessageAction tooltip="Regenerate"> <RefreshCw /> </MessageAction> <MessageAction tooltip="Good response"> <ThumbsUp /> </MessageAction> <MessageAction tooltip="Bad response"> <ThumbsDown /> </MessageAction> </MessageActions> </MessageToolbar> </Message> </div> );}Mensagem do usuário
'use client';import { Message, MessageContent } from '@gremorie/rx-ai';export function MessageUserPreview() { return ( <Message from="user"> <MessageContent> Can you summarize the latest Gremorie release notes in three bullet points? </MessageContent> </Message> );}Resposta em markdown rico
Here's the breakdown:
- Speed — caching layer responds in under 50ms.
- Coverage — 100 primitives shipped across 9 packages.
- DX —
npx gremorie add rx-messageis the single entry point.
The registry is now the source of truth.
'use client';import { Message, MessageContent, MessageResponse } from '@gremorie/rx-ai';const richMarkdown = `Here's the breakdown:1. **Speed** — caching layer responds in under 50ms.2. **Coverage** — 100 primitives shipped across 9 packages.3. **DX** — \`npx gremorie add rx-message\` is the single entry point.> The registry is now the source of truth.\`\`\`tsimport { Message } from "@gremorie/rx-ai";\`\`\``;export function MessageMarkdownPreview() { return ( <Message from="assistant"> <MessageContent> <MessageResponse>{richMarkdown}</MessageResponse> </MessageContent> </Message> );}Par usuário e assistant
Gremorie is an AI-native design system distributed via registry and MCP. It ships React and Angular primitives that AI agents can pull on demand.
'use client';import { Message, MessageContent, MessageResponse } from '@gremorie/rx-ai';export function MessagePairPreview() { return ( <div className="flex flex-col gap-4"> <Message from="user"> <MessageContent>What is Gremorie?</MessageContent> </Message> <Message from="assistant"> <MessageContent> <MessageResponse> Gremorie is an AI-native design system distributed via registry and MCP. It ships React and Angular primitives that AI agents can pull on demand. </MessageResponse> </MessageContent> </Message> </div> );}Anatomia
Message
├─ MessageContent
├─ MessageResponse markdown Streamdown
├─ MessageAttachments
│ └─ MessageAttachment
└─ MessageToolbar
├─ MessageActions
│ └─ MessageAction
└─ MessageBranch
├─ MessageBranchContent
└─ MessageBranchSelector
├─ MessageBranchPrevious
├─ MessageBranchPage
└─ MessageBranchNextInstalação
bash npx gremorie@latest add rx-message bash pnpm dlx gremorie@latest add rx-message bash yarn dlx gremorie@latest add rx-message bash bunx --bun gremorie@latest add rx-message Uso
import {
Message,
MessageContent,
MessageResponse,
} from "@gremorie/rx-ai";
export function Example() {
return (
<Message from="assistant">
<MessageContent>
<MessageResponse>{markdown}</MessageResponse>
</MessageContent>
</Message>
);
}import { Component } from "@angular/core";
import {
Message,
MessageContent,
MessageResponse,
} from "@gremorie/ng-ai";
@Component({
selector: "app-example",
standalone: true,
imports: [Message, MessageContent, MessageResponse],
template: ` <message from="assistant">
<message-content>
<message-response>{{ markdown }}</message-response>
</message-content>
</message>
`,
})
export class ExampleComponent {
readonly markdown = "Hello! How can I help you today?";
}
API
<Message>
| Prop | Type | Default | Description |
|---|---|---|---|
from | "user" | "assistant" | "system" | - | Papel do turno. Determina o alinhamento e o tratamento de superfície via classes de grupo is-user / is-assistant. |
className | string | - | Classes extras na div raiz. |
Estende todos os HTMLAttributes<HTMLDivElement>.
<MessageContent>
Container para o corpo do turno. Herda estilo do Message pai via seletores de grupo (por exemplo, turnos de usuário recebem uma superfície secondary arredondada).
Estende todos os HTMLAttributes<HTMLDivElement>.
<MessageResponse>
| Prop | Type | Default | Description |
|---|---|---|---|
children | string | - | Source de markdown. Re-renders são limitados por igualdade de string. |
Envolve Streamdown para renderização incremental token por token.
<MessageAttachments> / <MessageAttachment>
| Prop | Type | Default | Description |
|---|---|---|---|
data | FileUIPart | - | Payload do attachment (filename, mediaType, url). |
onRemove | () => void | - | Handler de remoção opcional. Renderiza um botão X no hover. |
<MessageToolbar> / <MessageActions> / <MessageAction>
| Prop | Type | Default | Description |
|---|---|---|---|
tooltip | string | - | Label do tooltip renderizado acima da ação. Serve também como texto sr-only. |
label | string | - | Label acessível explícito (sobrescreve o tooltip para o texto sr-only). |
variant | ButtonVariant | "ghost" | Encaminhado para o Button subjacente. |
size | ButtonSize | "icon-sm" | Encaminhado para o Button subjacente. |
<MessageBranch> (composto)
| Prop | Type | Default | Description |
|---|---|---|---|
defaultBranch | number | 0 | Índice de branch inicial. |
onBranchChange | (index: number) => void | - | Dispara quando o usuário navega entre branches. |
Provê o context para MessageBranchContent, MessageBranchSelector, MessageBranchPrevious, MessageBranchNext e MessageBranchPage.
Composição
<Message>define o alinhamento e expõe o papel via classes de grupo.<MessageContent>é a superfície que se adapta a usuário vs assistant.<MessageResponse>renderiza markdown com streaming dentro do content.<MessageAttachments>/<MessageAttachment>ficam acima do content para previews de arquivo.<MessageToolbar>+<MessageActions>+<MessageAction>aparecem sob o content para copiar, regenerar, curtir e outros affordances.<MessageBranch>envolve vários irmãos<MessageBranchContent>para que os usuários possam percorrer completions alternativos.
Variações
Resposta do assistant com streaming
Use enquanto os tokens ainda estão chegando. Combine com Reasoning para expor o pensamento.
<Message from="assistant">
<MessageContent>
<Reasoning isStreaming={status === "streaming"}>
<ReasoningTrigger />
<ReasoningContent>{thinking}</ReasoningContent>
</Reasoning>
<MessageResponse>{partialMarkdown}</MessageResponse>
</MessageContent>
</Message>Turno do usuário com attachments
Os attachments do usuário flutuam acima do balão. A linha de attachments alinha-se à borda final para combinar com o alinhamento à direita do balão.
<Message from="user">
<MessageAttachments>
{files.map((file) => (
<MessageAttachment
key={file.url}
data={file}
onRemove={() => removeFile(file.url)}
/>
))}
</MessageAttachments>
<MessageContent>{prompt}</MessageContent>
</Message>Turno do assistant com navegação por branch e toolbar
Permite que os usuários percorram alternativas regeneradas e ajam sobre a atual.
<Message from="assistant">
<MessageBranch>
<MessageBranchContent>
<MessageContent>
<MessageResponse>{variantA}</MessageResponse>
</MessageContent>
</MessageBranchContent>
<MessageBranchContent>
<MessageContent>
<MessageResponse>{variantB}</MessageResponse>
</MessageContent>
</MessageBranchContent>
</MessageBranch>
<MessageToolbar>
<MessageBranchSelector from="assistant">
<MessageBranchPrevious />
<MessageBranchPage />
<MessageBranchNext />
</MessageBranchSelector>
<MessageActions>
<MessageAction tooltip="Copy" onClick={copy}>
<CopyIcon />
</MessageAction>
<MessageAction tooltip="Regenerate" onClick={regenerate}>
<RefreshIcon />
</MessageAction>
</MessageActions>
</MessageToolbar>
</Message>Acessibilidade
- Teclado:
MessageActione os controles de branch sãoButtons de verdade, então participam da ordem normal de Tab e respondem a Enter / Space. - ARIA:
MessageActionlêtooltip(oulabel) como textosr-only, então ações apenas com ícone ainda anunciam.MessageBranchPreviouseMessageBranchNextcarregamaria-labels explícitos ("Previous branch", "Next branch"). Os botões de remoção deMessageAttachmentanunciam como "Remove attachment". - Leitores de tela: os controles de branch se desabilitam (e anunciam como desabilitados) sempre que há apenas um branch. O selector se oculta inteiramente abaixo de dois branches.
- Gestão de foco: as ações da toolbar ficam na ordem do documento para que leitores de tela narrem o turno antes de seus affordances.
Relacionados
- Conversation - container com scroll-to-bottom para um stream de mensagens
- Reasoning - bloco de pensamento recolhível para embutir dentro de um Message
- Sources - cite os documentos que um turno do assistant usou
- InlineCitation - citações inline no estilo nota de rodapé dentro de
MessageResponse