suiss/ui
  • Docs
  • Components
  • Patterns
  • Interactions
  • Charts
  • Blocks
  • AI
GitHubCreate
DocsComponentsPatternsInteractionsChartsBlocksAICreate
AI21
  • Overview
Conversation
  • Chat
  • Message
  • Prompt Input
  • Suggestion
  • Model Selector
  • Context
  • Checkpoint
  • Inline Citation
Agent steps
  • Chain of Thought
  • Reasoning
  • Tool
  • Confirmation
  • Task
  • Plan
  • Queue
  • Subagent
  • Sources
Output
  • Terminal
  • Stack Trace
  • Test Results
  • File Tree

suiss/ui · AI

Chain of Thought

A summary line that expands into the steps an agent took, such as reads, searches and tool calls.

import {
  ArrowUpRightIcon,
  CheckCircleIcon,
  GlobeIcon,
} from "@phosphor-icons/react"
import type * as React from "react"

import { Badge } from "@/components/ui/badge"
import { Bubble, BubbleContent } from "@/components/ui/bubble"
import { CodeBlock, CodeBlockContent } from "@/components/ui/code-block"
import { Message, MessageContent } from "@/components/ui/message"
import {
  Trace,
  TraceCollapsible,
  TraceCollapsibleContent,
  TraceCollapsibleTrigger,

Chain of Thought is a summary line that expands into the steps an agent took. The summary says what happened, such as "Researched in 3 steps", and each step inside it is a line of its own that can expand into its output.

It is built with Trace: a TraceCollapsible for the summary and a nested Trace for the steps. For a single tool call, see Tool. For steps that are known up front, see Plan.

Installation

Chain of Thought is built with Trace, Code Block and Badge.

$ pnpm dlx shadcn@latest add @esuiss/trace @esuiss/code-block @esuiss/badge

Or use the suiss/ui CLI:

$ pnpm dlx @esuiss/ui@latest add trace code-block badge

Usage

import {
  Trace,
  TraceCollapsible,
  TraceCollapsibleContent,
  TraceCollapsibleTrigger,
  TraceIcon,
  TraceLine,
  TraceTitle,
} from "@/components/ui/trace"
<Trace>
  <TraceCollapsible defaultOpen>
    <TraceCollapsibleTrigger>
      <TraceLine>
        <TraceIcon>
          <CircleCheckIcon />
        </TraceIcon>
        <TraceTitle>Researched in 3 steps</TraceTitle>
      </TraceLine>
    </TraceCollapsibleTrigger>
    <TraceCollapsibleContent keepMounted>
      <Trace>
        <TraceLine>
          <TraceIcon>
            <CircleCheckIcon />
          </TraceIcon>
          <TraceTitle>Read the build log for dpl_8Kx2</TraceTitle>
        </TraceLine>
        <TraceLine>
          <TraceIcon>
            <CircleCheckIcon />
          </TraceIcon>
          <TraceTitle>Searched the code for cacheKey</TraceTitle>
        </TraceLine>
      </Trace>
    </TraceCollapsibleContent>
  </TraceCollapsible>
</Trace>

Set keepMounted on the summary's TraceCollapsibleContent so the steps keep their open state while the summary is closed.

Use defaultExpanded instead of defaultOpen on TraceCollapsible.

Steps

Each step is a TraceLine, or a TraceCollapsible when it has output to show. Set its status and write the title in the matching tense.

StepstatusTitle
Running"running"Searching for …
DonenoneSearched for …
Failed"error"Failed to search for …

Set the summary's status and title from its steps: running while any step runs, error when one failed, and a count such as "Researched in 3 steps, 1 failed" once they are done.

Search results

When a step runs a web search, show each result as a link row, or show the hostnames as a Badge each:

<TraceCollapsibleContent className="flex flex-wrap gap-1.5">
  {results.map((result) => (
    <Badge key={result.url} variant="secondary">
      {new URL(result.url).hostname}
    </Badge>
  ))}
</TraceCollapsibleContent>

AI SDK

Render each tool part as a step. The summary is running while tool parts stream and before the reply text starts. It opens while the steps run and keeps the reader's choice once they open or close it.

const [open, setOpen] = React.useState<boolean>()
const running = streaming && !answering
const failed = steps.filter((part) => part.state === "output-error").length

<TraceCollapsible open={open ?? running} onOpenChange={setOpen}>
  <TraceCollapsibleTrigger>
    <TraceLine status={running ? "running" : failed > 0 ? "error" : undefined}>
      <TraceTitle>
        {running ? "Researching" : `Researched in ${steps.length} steps`}
      </TraceTitle>
    </TraceLine>
  </TraceCollapsibleTrigger>
  <TraceCollapsibleContent keepMounted>
    <Trace>
      {steps.map((part) => (
        <StepLine key={part.toolCallId} part={part} streaming={streaming} />
      ))}
    </Trace>
  </TraceCollapsibleContent>
</TraceCollapsible>

StepLine renders one tool part as a line, as in Tool.

API Reference

See Trace, Code Block and Badge.

Accessibility

  • The summary and each expandable step are buttons with aria-expanded.
  • Say the state in each title, such as "Searching" or "Failed to search", since status is otherwise shown with color and motion.
  • Add "(opens in a new tab)" with sr-only to links that open a new tab.
import { FileTextIcon, GlobeIcon, MagnifyingGlassIcon } from "phosphor-react-native"
import { View } from "react-native"
import { Bubble, BubbleContent } from "@/components/ui/bubble"
import { Icon } from "@/components/ui/icon"
import { Message, MessageContent } from "@/components/ui/message"
import { Text } from "@/components/ui/text"
import { Trace, TraceCollapsible, TraceCollapsibleContent, TraceCollapsibleTrigger, TraceDescription, TraceIcon, TraceLine, TraceTitle } from "@/components/ui/trace"

export function AiChainOfThoughtExample() {
  return (
    <View className="w-full gap-4">
      <Message align="end">
        <MessageContent>
          <Bubble variant="muted">
            <BubbleContent>Why is the checkout deploy so slow?</BubbleContent>
          </Bubble>
import EsuissUI
import PhosphorSwift
import SwiftUI

struct ChainOfThoughtExample: View {
  var body: some View {
    VStack(alignment: .leading, spacing: 16) {
      Message(align: .end) {
        MessageContent {
          Bubble(variant: .muted, align: .end) { BubbleContent("Why is the checkout deploy so slow?") }
        }
      }
      TraceCollapsible(initiallyExpanded: true) {
        TraceCollapsibleTrigger {
          TraceLine {
            TraceTitle(verbatim: "Researched in 3 steps")
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.adamglin.PhosphorIcons
import com.adamglin.phosphoricons.Regular
import com.adamglin.phosphoricons.regular.FileText
import com.adamglin.phosphoricons.regular.Globe
import com.adamglin.phosphoricons.regular.MagnifyingGlass
import com.esuiss.ui.components.Bubble
import com.esuiss.ui.components.BubbleContent
import com.esuiss.ui.components.BubbleVariant
import com.esuiss.ui.components.Icon
import com.esuiss.ui.components.Message

Chain of Thought on mobile is built from the same parts as on the web: Trace, Message, Bubble. The example above is a static demo; connect it to your agent by rendering the same parts from your messages.

Installation

$ pnpm dlx @esuiss/ui@latest add trace message bubble
$ pnpm dlx @esuiss/ui@latest add trace message bubble --platform swift
$ pnpm dlx @esuiss/ui@latest add trace message bubble --platform kotlin

API Reference

See Trace, Message, Bubble.

NextReasoningPreviousInline Citation

On this page

  1. 01Installation
  2. 02Usage
    • Steps
    • Search results
  3. 03AI SDK
  4. 04API Reference
  5. 05Accessibility
  6. 06Installation
  7. 07API Reference