Reasoning
Surface colapsável de "pensamento" do modelo — auto-abre durante streaming, fecha quando termina.
Overview
Reasoning mostra o chain-of-thought do modelo — o pensamento
interno que precede a resposta final. Construído sobre
Collapsible. O comportamento crítico:
quando isStreaming é true, o componente abre automaticamente —
o usuário vê tokens de raciocínio formando em tempo real. Quando
isStreaming vira false, fecha sozinho (a menos que o usuário
tenha aberto manualmente).
Use pra modelos com modos extended thinking (Claude com extended_thinking,
o1, etc) ou qualquer agente que separe planning de execution.
Anatomy
<Reasoning isStreaming={...}>
├─ <ReasoningTrigger /> ← header com chevron e label "Reasoning"
└─ <ReasoningContent> ← Streamdown (markdown live)
{tokens}
</Reasoning>Usage
"use client";
import { Reasoning, ReasoningContent, ReasoningTrigger } from "@kalvner/kds/ai/reasoning";
export function ThinkingBlock({ thoughts, isStreaming }) {
return (
<Reasoning isStreaming={isStreaming}>
<ReasoningTrigger />
<ReasoningContent>{thoughts}</ReasoningContent>
</Reasoning>
);
}Props
Reasoning (Root)
| Prop | Tipo | Default | Descrição |
|---|---|---|---|
isStreaming | boolean | false | Quando true, força open=true automaticamente. Quando muda pra false, fecha (a menos que o user tenha clicado pra abrir manualmente). |
open / defaultOpen | boolean | — | Controle externo (override do auto-behavior). |
onOpenChange | (open: boolean) => void | — | Callback quando o user clica trigger. |
duration | number | 1 | Segundos para a animação de "pensando" no trigger. |
className | string | — | Override. |
Aceita os outros props de Collapsible.
ReasoningTrigger
| Prop | Tipo | Default | Descrição |
|---|---|---|---|
title | string | 'Reasoning' (ou 'Thought for X seconds' quando isStreaming muda) | Texto do header. |
className | string | — | Override. |
Mostra BrainIcon + title + ChevronDownIcon. Durante streaming
exibe duração; ao parar, mostra "Thought for Xs".
ReasoningContent
| Prop | Tipo | Default | Descrição |
|---|---|---|---|
children | string | — | Markdown. Renderiza via Streamdown (memoizado). |
className | string | — | Override; padrão tem text-muted-foreground + animações de slide. |
Subcomponents
Reasoning— provider que gerencia o estado open/closed em resposta aoisStreaming. Sempre o root.ReasoningTrigger— header clicável com chevron + label dinâmico. UsauseReasoning()interno pra lerisStreaminge ajustar o texto.ReasoningContent— região revelada. Renderiza markdown via Streamdown — perfeito pra streams de tokens.
useReasoning()
Hook retorna { isStreaming: boolean }. Use pra montar triggers
custom (ex.: trigger que mostra avatar do modelo durante thinking):
import { useReasoning } from "@kalvner/kds/ai/reasoning";
function CustomTrigger() {
const { isStreaming } = useReasoning();
return <button>{isStreaming ? "🧠 thinking" : "Show reasoning"}</button>;
}States
| State | Comportamento |
|---|---|
isStreaming=true | Abre automaticamente, conteúdo aparece. Trigger mostra duration crescente. |
isStreaming=false (após streaming) | Fecha auto após pequeno delay; trigger mostra "Thought for Xs". |
open (controlado) | Override total — ignora isStreaming. |
| User clica trigger | onOpenChange dispara; isStreaming já não controla. |
Composition
Dentro de Message
<Message from="assistant">
<MessageContent>
<Reasoning isStreaming={status === "thinking"}>
<ReasoningTrigger />
<ReasoningContent>{thinkingTokens}</ReasoningContent>
</Reasoning>
<MessageResponse>{responseTokens}</MessageResponse>
</MessageContent>
</Message>Com botão custom (sem padrão Trigger)
<Reasoning isStreaming>
<CollapsibleTrigger asChild>
<Button variant="link">🧠 Ver pensamento</Button>
</CollapsibleTrigger>
<ReasoningContent>{tokens}</ReasoningContent>
</Reasoning>When to use
- Modelos que separam reasoning de output (Claude extended_thinking, o1).
- Agentes que querem mostrar planning antes da execução.
- Debug UI pra fluxos de IA — ver o que o modelo "pensou".
When not to use
- Mensagens regulares — use Message + MessageResponse direto.
- Tool calls — use Tool; reasoning é raciocínio interno, não execução.
- Conteúdo crítico que deve estar sempre visível — Reasoning fecha por padrão.
Best practices
- Sempre passe
isStreaming. Sem isso, o componente vira só Collapsible regular — perde o auto-open/close characteristic. - Antes do MessageResponse. Reasoning vem antes do texto final pra criar o ritmo "pensei → respondi".
- Não persista thinking entre regenerações. Quando o user clica regenerate, descarta o reasoning anterior — confunde manter.
Accessibility
| Concern | Comportamento |
|---|---|
| Roles | Trigger é <button> com aria-expanded. Content é <region>. |
| Keyboard | Space/Enter alterna o trigger. |
| Focus | Trigger herda focus-visible:ring-[3px]. |
| Live region | Content tem animação slide-in/out que respeita prefers-reduced-motion. |
| Screen reader | Anuncia "expandido"/"recolhido" no toggle. |
Related
- ChainOfThought — versão estruturada com steps numerados.
- Tool — execução visível (não pensamento).
- Message — wrapper dentro do qual Reasoning vive.