AI Elements

Chain of Thought

Displays a summary that expands into the steps an agent took.

Why is the checkout deploy so slow?

Image optimization takes almost four minutes because its cache key includes the commit hash. Key it on the image directory instead.

Chain of Thought is a summary line that expands into the steps an agent took. The summary says what happened, like "Researched in 3 steps". The steps sit inside it, each one a line of its own.

Chain of Thought is built with UiTrace with a UiTraceCollapsible for the summary.

Installation

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

Usage

<template>
  <UiTrace>
    <UiTraceCollapsible default-open :unmount-on-hide="false">
      <UiTraceCollapsibleTrigger>
        <UiTraceLine>
          <UiTraceIcon>
            <UiIcon name="lucide:circle-check" />
          </UiTraceIcon>
          <UiTraceTitle>Researched in 3 steps</UiTraceTitle>
        </UiTraceLine>
      </UiTraceCollapsibleTrigger>
      <UiTraceCollapsibleContent>
        <UiTrace>
          <UiTraceLine>
            <UiTraceIcon>
              <UiIcon name="lucide:circle-check" />
            </UiTraceIcon>
            <UiTraceTitle>Read the build log for dpl_8Kx2</UiTraceTitle>
          </UiTraceLine>
          <UiTraceLine>
            <UiTraceIcon>
              <UiIcon name="lucide:circle-check" />
            </UiTraceIcon>
            <UiTraceTitle>Searched the web for next.js image cache key</UiTraceTitle>
          </UiTraceLine>
          <UiTraceLine>
            <UiTraceIcon>
              <UiIcon name="lucide:circle-check" />
            </UiTraceIcon>
            <UiTraceTitle>Searched the code for cacheKey</UiTraceTitle>
          </UiTraceLine>
        </UiTrace>
      </UiTraceCollapsibleContent>
    </UiTraceCollapsible>
  </UiTrace>
</template>

Steps

Each step is a UiTraceLine. Set its status and write the title in the matching tense.

StepstatusTitle
Running"running"Searching for …
Done, with detailnoneSearched for …
Done, links outnoneRead the Image component docs
Failed"error"Failed to search for …

Set :unmount-on-hide="false" on the summary's UiTraceCollapsible. Steps keep their open state when the summary closes.

Search Results

When a step runs a web search, show the results as a UiBadge for each hostname in the step's content.

<template>
  <UiTraceCollapsibleContent class="flex flex-wrap gap-1.5">
    <UiBadge v-for="result in results" :key="result.url" variant="secondary">
      {{ getHostname(result.url) }}
    </UiBadge>
  </UiTraceCollapsibleContent>
</template>

<script lang="ts" setup>
  function getHostname(url: string) {
    return new URL(url).hostname;
  }
</script>

AI SDK

Render each tool part as a step. running is true while tool parts stream and before the reply starts. Set the summary's status and title from the steps. The summary opens while the steps run, as in Trace.

<template>
  <UiTraceCollapsible :open="open ?? running" :unmount-on-hide="false" @update:open="open = $event">
    <UiTraceCollapsibleTrigger>
      <UiTraceLine :status="running ? 'running' : failed > 0 ? 'error' : undefined">
        <UiTraceTitle>
          {{ running ? "Researching" : `Researched in ${steps.length} steps` }}
        </UiTraceTitle>
      </UiTraceLine>
    </UiTraceCollapsibleTrigger>
    <UiTraceCollapsibleContent>
      <UiTrace>
        <StepLine
          v-for="part in steps"
          :key="part.toolCallId"
          :part="part"
          :streaming="streaming"
        />
      </UiTrace>
    </UiTraceCollapsibleContent>
  </UiTraceCollapsible>
</template>

<script lang="ts" setup>
  const props = defineProps<{
    steps: StepPart[];
    streaming: boolean;
    answering: boolean;
  }>();

  const open = ref<boolean>();
  const running = computed(() => props.streaming && !props.answering);
  const failed = computed(() => props.steps.filter((part) => part.state === "output-error").length);
</script>

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

API Reference

See Trace.