Chat · Components

ChatTraceComponent

ChatTraceComponent is a primitive that renders a collapsible trace row for a single agent execution step. It shows a status indicator, label, optional metadata, and default slot content. Traces auto-expand while running and auto-collapse when done.

Selector: chat-trace

Import:

import { ChatTraceComponent } from '@threadplane/chat';

#When to Use It

Use ChatTraceComponent when you want to expose agent reasoning steps, tool calls, or subgraph transitions to the user. It pairs well with the <chat-message-list> primitive to interleave execution traces with message bubbles.

For a fully managed tool call display, see <chat-tool-call-card>.

#Basic Usage

<chat-trace state="running">
  Searching knowledge base...
</chat-trace>

#API

#Inputs

InputTypeDefaultDescription
stateTraceState'pending'Current execution state. Controls the status icon and auto-expand behavior. TraceState is exported from @threadplane/chat and is 'pending' | 'running' | 'done' | 'error'.

#Outputs

None. State transitions are driven by the state input.

#Slots

All slots are optional.

SlotSelectorDescription
Default(none)Main trace content. Shown when the trace is expanded
Label[traceLabel]Custom label text in the trace header. Defaults to the state name
Icon[traceIcon]Custom icon in the trace header. Replaces the default state icon
Meta[traceMeta]Additional metadata shown in the header (e.g., duration, token count)

#Methods

MethodDescription
toggle()Manually toggles the expanded/collapsed state

#State Behavior

StateAuto-expandStatus iconColor
pendingNoClockMuted
runningYesSpinnerWarning
doneCollapsesCheckmarkSuccess
errorYesX markError

When state transitions from any value to 'running', the trace automatically expands. When state transitions to 'done', the trace automatically collapses. When state transitions to 'error', the trace automatically expands so the error content is visible.

#Examples

#Tool call in progress

<chat-trace [state]="toolState()">
  <span traceLabel>{{ toolName }}</span>
  <span traceMeta>{{ elapsedMs }}ms</span>
 
  <pre>{{ toolArgs | json }}</pre>
</chat-trace>

#Custom icon

<chat-trace state="running">
  <svg traceIcon aria-hidden="true"><!-- search icon --></svg>
  <span traceLabel>Searching documents</span>
 
  <p>Query: "{{ searchQuery }}"</p>
</chat-trace>

#Full component example

import { Component, ChangeDetectionStrategy, computed, signal } from '@angular/core';
import { injectAgent, provideAgent } from '@threadplane/langgraph';
import { ChatTraceComponent, ChatMessageListComponent } from '@threadplane/chat';
import type { ToolCallStatus, TraceState } from '@threadplane/chat';
 
function toTraceState(status: ToolCallStatus): TraceState {
  // 'pending' | 'running' | 'error' carry over; only 'complete' is renamed.
  return status === 'complete' ? 'done' : status;
}
 
@Component({
  selector: 'app-traced-chat',
  standalone: true,
  imports: [ChatMessageListComponent, ChatTraceComponent],
  providers: [provideAgent({ assistantId: 'chat', threadId: signal(null) })],
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <div style="height: 100vh; display: flex; flex-direction: column;">
      <chat-message-list [agent]="chatAgent">
        <ng-template chatMessageTemplate="ai" let-message>
          <!-- Show tool traces before the AI message -->
          @for (trace of traces(); track trace.id) {
            <chat-trace [state]="trace.state">
              <span traceLabel>{{ trace.name }}</span>
              <pre>{{ trace.args | json }}</pre>
            </chat-trace>
          }
          <div>{{ message.content }}</div>
        </ng-template>
      </chat-message-list>
    </div>
  `,
})
export class TracedChatComponent {
  protected readonly chatAgent = injectAgent();
 
  // The agent's toolCalls() signal is the real source for trace rows.
  protected readonly traces = computed(() =>
    this.chatAgent.toolCalls().map((call) => ({
      id: call.id,
      name: call.name,
      args: call.args,
      state: toTraceState(call.status),
    })),
  );
}

#Driving traces from agent.toolCalls()

The agent's toolCalls() signal is the real source for tool-call traces. ToolCall.status and TraceState use almost the same names, but ToolCall reports 'complete' where TraceState expects 'done' — map that one explicitly:

import { ChangeDetectionStrategy, Component, computed } from '@angular/core';
import { injectAgent, provideAgent } from '@threadplane/langgraph';
import { signal } from '@angular/core';
import {
  ChatTraceComponent,
  ChatMessageListComponent,
} from '@threadplane/chat';
import type { ToolCallStatus } from '@threadplane/chat';
import type { TraceState } from '@threadplane/chat';
 
function toTraceState(status: ToolCallStatus): TraceState {
  // 'pending' | 'running' | 'error' carry over; only 'complete' is renamed.
  return status === 'complete' ? 'done' : status;
}
 
@Component({
  selector: 'app-tool-traces',
  standalone: true,
  imports: [ChatMessageListComponent, ChatTraceComponent],
  providers: [provideAgent({ assistantId: 'chat', threadId: signal(null) })],
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <chat-message-list [agent]="chatAgent">
      <ng-template chatMessageTemplate="ai" let-message>
        @for (call of traces(); track call.id) {
          <chat-trace [state]="call.state">
            <span traceLabel>{{ call.name }}</span>
            <pre>{{ call.args | json }}</pre>
          </chat-trace>
        }
        <div>{{ message.content }}</div>
      </ng-template>
    </chat-message-list>
  `,
})
export class ToolTracesComponent {
  protected readonly chatAgent = injectAgent();
 
  // Map each ToolCall to a trace-friendly view, translating status -> TraceState.
  protected readonly traces = computed(() =>
    this.chatAgent.toolCalls().map((call) => ({
      id: call.id,
      name: call.name,
      args: call.args,
      state: toTraceState(call.status),
    })),
  );
}

#Styling

The component uses the following --ngaf-chat-* tokens:

TokenApplied to
--ngaf-chat-surface-altTrace row background
--ngaf-chat-separatorRow border
--ngaf-chat-radius-cardRow border radius
--ngaf-chat-textLabel and content
--ngaf-chat-text-mutedMeta text, icon
--ngaf-chat-warning-textRunning state icon
--ngaf-chat-successDone state icon
--ngaf-chat-error-textError state icon

See Theming for the full token reference.