Reasoning
Chat UI shows the model's reasoning in a collapsible Thinking block above the answer, and can send a reasoning effort with each message.
Available from @cognipeer/chat-ui 0.6.0
Needs agent-server 0.6.0 or newer for stream.thinking frames and the reasoningEffort request field. Against an older server the block simply never appears and the effort is ignored.
The Thinking block
When the server streams stream.thinking frames, Chat UI keeps that text apart from the answer:
- Each assistant message carries
reasoning. The answer bubble and the stored answer text never contain it. - The block sits above the answer. It is open while the model is still reasoning and folds once the answer starts. The person can open and close it at any time, with the keyboard too.
- The text is plain text and follows the theme tokens.
- Stored messages that carry
metadata.reasoningormetadata.thinkingshow the block too, so a conversation reloaded from the server keeps what the server stored. - The strings are
chat.reasoning.*(English and Turkish). Override them withcustomMessageslike any other string, see Internationalization.
Reasoning is usually a summary of the model's thinking, not its raw chain of thought. Providers decide what they return, and the agent behind the server decides whether the text is shown at all.
Hiding it
<Chat baseUrl="/api/agents" agentId="support" showReasoning={false} />| Switch | Effect |
|---|---|
showReasoning prop on Chat / ChatMessageList (default true) | false never renders the block |
AgentInfo.showReasoning === false (set on the server) | The block is never shown for that agent, even with showReasoning true. A block the client already holds for that agent is hidden too |
The server-side switch is the one that matters for confidentiality: with it off the server does not send the text at all. The showReasoning prop only decides what this page renders.
Reasoning effort
Send a reasoning effort with every message the chat sends, including regenerate and edit:
<Chat baseUrl="/api/agents" agentId="support" reasoningEffort="high" />reasoningEffort is one of none, minimal, low, medium, high (type ReasoningEffort). The server answers 400 for anything else, and leaves the agent's own setting in force when the prop is absent. There is no effort picker in the UI yet: the value is whatever your page passes.
With useChat
const chat = useChat({
baseUrl: '/api/agents',
agentId: 'support',
getReasoningEffort: () => 'low', // read when each message is sent
});
chat.streamingReasoning; // the reasoning of the turn that is runningstreamingReasoningholds the reasoning of the running turn. Finished messages keep theirs inMessage.reasoning.getReasoningEffortis a function, so the effort can follow a control of yours.SendMessageOptions.reasoningEffortsets it for one send, regenerate or edit call.
Using the pieces yourself
import { ThinkingBlock } from '@cognipeer/chat-ui';
<ThinkingBlock reasoning={text} streaming={false} answering />| Prop | Meaning |
|---|---|
reasoning | The text. An empty string renders nothing |
streaming | The reasoning is still arriving: the block is open and its title reads "Thinking" |
answering | The answer has started: the block folds |
className | Extra class on the container |
A custom StreamCallbacks receives onThinking(text, fullThinking), next to onText. See Streaming.
Related
- Reasoning in Agent Server: the frames,
showReasoningand the request field - Streaming
- Agent Server

