Chat · Components

ChatReasoningComponent

ChatReasoningComponent renders an assistant's reasoning content as a compact pill that expands to reveal the underlying text. The <chat> composition automatically renders this primitive above the assistant response when Message.reasoning is populated by the adapter — most consumers don't need to use it directly.

Selector: chat-reasoning

Import:

import {
  ChatReasoningComponent,
  completeDelivery,
  formatDuration,
  streamingDelivery,
  type MessageDelivery,
} from '@threadplane/chat';

#Visual states

StatePill labelBehavior
[delivery] phase is streaming"Thinking…" with pulsing dotAuto-expanded; body streams in
[delivery] phase is complete, [durationMs] set"Thought for Ns"Collapsed by default; click to expand
[delivery] phase is complete, no [durationMs]"Show reasoning"Collapsed by default; click to expand

#Inputs

InputTypeDefaultDescription
[content]string''The reasoning text to render
[delivery]MessageDeliveryRequiredAuthoritative generation, phase, and terminal outcome from the adapter
[durationMs]number | undefinedundefinedWall-clock duration of the reasoning phase
[label]string | undefinedundefinedOverride the auto-derived label
[defaultExpanded]booleanfalseOpen the panel by default when idle

#Standalone usage

<chat-reasoning
  [content]="reasoningText"
  [delivery]="reasoningDelivery"
  [durationMs]="thoughtFor"
/>

Keep the generation stable while the same response attempt moves from streaming to complete:

reasoningDelivery: MessageDelivery = streamingDelivery('turn-42');
 
finishReasoning() {
  this.reasoningDelivery = completeDelivery('turn-42', 'success');
}

#formatDuration utility

Use formatDuration(ms) to render the duration string yourself (e.g. for a sidebar):

formatDuration(0)      // "<1s"
formatDuration(4_000)  // "4s"
formatDuration(72_000) // "1m 12s"

#Behavior

  • The component hides itself entirely (display: none) when [content] is empty.
  • A streaming delivery force-expands the panel so streaming content is visible.
  • A user click on the pill toggles the panel; the user choice persists across delivery phase transitions for the lifetime of the instance.
  • When the delivery enters streaming after a completed phase, the panel resets to expanded.
  • The body re-uses <chat-streaming-md> so reasoning content gets the same markdown rendering pipeline as the response (lists, code blocks, headings render).