# Subagent

A subagent run, with the tool calls it made and what it found.

Source: https://suiss.app/ui/docs/ai/subagent

**React**

**Example**

```tsx
import { CheckCircleIcon } from "@phosphor-icons/react"
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,
  TraceIcon,
  TraceLine,
  TraceTitle,
} from "@/components/ui/trace"

const steps = [
  {
    command: "grep -rn cacheKey scripts",
    stdout:
      "scripts/optimize-images.ts:14:  const cacheKey = process.env.COMMIT_SHA",
  },
  {
    command: "sed -n 13,15p scripts/optimize-images.ts",
    stdout:
      'const cacheDir = ".next/cache/images"\nconst cacheKey = process.env.COMMIT_SHA\nconst cached = await restoreCache(cacheDir, cacheKey)',
  },
  {
    command: "ls public/images | wc -l",
    stdout: "1240",
  },
]

export default function SubagentDemo() {
  return (
    <div className="flex w-full max-w-sm flex-col gap-4 py-6 text-sm">
      <Message align="end">
        <MessageContent>
          <Bubble align="end" variant="muted">
            <BubbleContent>
              Why does image optimization rerun on every deploy?
            </BubbleContent>
          </Bubble>
        </MessageContent>
      </Message>
      <Message>
        <MessageContent className="gap-4">
          <Trace>
            <TraceCollapsible defaultOpen>
              <TraceCollapsibleTrigger>
                <TraceLine>
                  <TraceIcon>
                    <CheckCircleIcon />
                  </TraceIcon>
                  <TraceTitle>Ran the research subagent</TraceTitle>
                </TraceLine>
              </TraceCollapsibleTrigger>
              <TraceCollapsibleContent className="flex flex-col gap-3">
                <Trace>
                  {steps.map((step) => (
                    <TraceCollapsible key={step.command}>
                      <TraceCollapsibleTrigger>
                        <TraceLine>
                          <TraceIcon>
                            <CheckCircleIcon />
                          </TraceIcon>
                          <TraceTitle>Ran {step.command}</TraceTitle>
                        </TraceLine>
                      </TraceCollapsibleTrigger>
                      <TraceCollapsibleContent>
                        <CodeBlock size="sm">
                          <CodeBlockContent wrap className="max-h-64">
                            {step.stdout}
                          </CodeBlockContent>
                        </CodeBlock>
                      </TraceCollapsibleContent>
                    </TraceCollapsible>
                  ))}
                </Trace>
                <p>
                  The cache is keyed on the commit SHA, so every deploy misses
                  it and optimizes all 1,240 images again.
                </p>
              </TraceCollapsibleContent>
            </TraceCollapsible>
          </Trace>
          <p>
            Image optimization reruns because its cache is keyed on the commit
            SHA, which changes on every deploy. Key the cache on a hash of
            public/images instead, and unchanged images will be skipped.
          </p>
        </MessageContent>
      </Message>
    </div>
  )
}
```

Subagent is a row for work the agent hands to a subagent. The run is the title, such as "Ran the research agent". Open it for the tool calls the subagent made and what it found.

The run is a `TraceCollapsible`, and its tool calls are a nested `Trace`. Each tool call follows the same shape as [Tool](https://suiss.app/ui/docs/ai/tool).

## Installation

Subagent is built with the [Trace](https://suiss.app/ui/docs/components/trace), [Code Block](https://suiss.app/ui/docs/components/code-block) and [Badge](https://suiss.app/ui/docs/components/badge) components.

```bash title="Terminal"
npx shadcn@latest add @esuiss/trace @esuiss/code-block @esuiss/badge
```

Works in any project with a `components.json`. See [Installation](https://suiss.app/ui/docs/installation#add-components) for the one-line registry setup. Or use the [suiss/ui CLI](https://suiss.app/ui/docs/cli):

```bash title="Terminal"
npx @esuiss/ui@latest add trace code-block badge
```

## Usage

```tsx
import {
  Trace,
  TraceCollapsible,
  TraceCollapsibleContent,
  TraceCollapsibleTrigger,
  TraceIcon,
  TraceLine,
  TraceTitle,
} from "@/components/ui/trace"
```

```tsx
<Trace>
  <TraceCollapsible>
    <TraceCollapsibleTrigger>
      <TraceLine>
        <TraceIcon>
          <CircleCheckIcon />
        </TraceIcon>
        <TraceTitle>Ran the research agent</TraceTitle>
      </TraceLine>
    </TraceCollapsibleTrigger>
    <TraceCollapsibleContent className="flex flex-col gap-3">
      <Trace>
        <TraceLine>
          <TraceIcon>
            <CircleCheckIcon />
          </TraceIcon>
          <TraceTitle>Ran grep -rn cacheKey scripts</TraceTitle>
        </TraceLine>
      </Trace>
      <p>The cache is keyed on the commit SHA.</p>
    </TraceCollapsibleContent>
  </TraceCollapsible>
</Trace>
```

## Examples

### Running

While the subagent runs, the row has `status="running"` and its content shows the tool calls so far. Add the result when the subagent finishes.

**Example**

```tsx
import { CheckCircleIcon, CircleNotchIcon } from "@phosphor-icons/react"
import {
  Trace,
  TraceCollapsible,
  TraceCollapsibleContent,
  TraceCollapsibleTrigger,
  TraceIcon,
  TraceLine,
  TraceTitle,
} from "@/components/ui/trace"

export default function SubagentRunning() {
  return (
    <Trace className="max-w-sm">
      <TraceCollapsible defaultOpen>
        <TraceCollapsibleTrigger>
          <TraceLine status="running">
            <TraceIcon>
              <CircleNotchIcon className="animate-spin" />
            </TraceIcon>
            <TraceTitle>Running the research agent</TraceTitle>
          </TraceLine>
        </TraceCollapsibleTrigger>
        <TraceCollapsibleContent keepMounted>
          <Trace>
            <TraceLine>
              <TraceIcon>
                <CheckCircleIcon />
              </TraceIcon>
              <TraceTitle>Ran grep -rn cacheKey scripts</TraceTitle>
            </TraceLine>
            <TraceLine status="running">
              <TraceIcon>
                <CircleNotchIcon className="animate-spin" />
              </TraceIcon>
              <TraceTitle>
                Running sed -n 13,15p scripts/optimize-images.ts
              </TraceTitle>
            </TraceLine>
          </Trace>
        </TraceCollapsibleContent>
      </TraceCollapsible>
    </Trace>
  )
}
```

### Details

Puts the task the subagent was given at the top of the content, with its model and tools as [Badge](https://suiss.app/ui/docs/components/badge) items, and how long it ran in a `TraceDescription` after the title.

**Example**

```tsx
import { CheckCircleIcon } from "@phosphor-icons/react"
import { Badge } from "@/components/ui/badge"
import {
  Trace,
  TraceCollapsible,
  TraceCollapsibleContent,
  TraceCollapsibleTrigger,
  TraceDescription,
  TraceIcon,
  TraceLine,
  TraceTitle,
} from "@/components/ui/trace"

export default function SubagentDetails() {
  return (
    <Trace className="max-w-sm">
      <TraceCollapsible defaultOpen>
        <TraceCollapsibleTrigger>
          <TraceLine>
            <TraceIcon>
              <CheckCircleIcon />
            </TraceIcon>
            <TraceTitle>Ran the research agent</TraceTitle>
            <TraceDescription>48s</TraceDescription>
          </TraceLine>
        </TraceCollapsibleTrigger>
        <TraceCollapsibleContent keepMounted className="flex flex-col gap-3">
          <div className="flex flex-wrap gap-1.5">
            <Badge variant="secondary">claude-sonnet-5-5</Badge>
            <Badge variant="outline" className="font-mono">
              runCommand
            </Badge>
          </div>
          <p>Find out why image optimization reruns on every deploy.</p>
          <Trace>
            <TraceLine>
              <TraceIcon>
                <CheckCircleIcon />
              </TraceIcon>
              <TraceTitle>Ran grep -rn cacheKey scripts</TraceTitle>
            </TraceLine>
            <TraceLine>
              <TraceIcon>
                <CheckCircleIcon />
              </TraceIcon>
              <TraceTitle>
                Ran sed -n 13,15p scripts/optimize-images.ts
              </TraceTitle>
            </TraceLine>
          </Trace>
          <p>The cache is keyed on the commit SHA.</p>
        </TraceCollapsibleContent>
      </TraceCollapsible>
    </Trace>
  )
}
```

## AI SDK

With the AI SDK, a subagent is a tool whose `execute` yields the subagent's `UIMessage` as it streams. Render the tool part as the row and `part.output.parts` as the nested `Trace`.

Each yield is a preliminary output: the part is `output-available` with `preliminary: true`. The final output replaces it, so check `preliminary` before you show "Ran".

| Tool part state | `TraceLine` status | Title |
| --- | --- | --- |
| `input-streaming`, `input-available` | `running` while the chat streams | Running … |
| `output-available` with `preliminary: true` | `running` while the chat streams | Running … |
| `output-available` | — | Ran … |
| `output-error`, or a running state after the chat stops | `error` | Failed to run … |

## API Reference

See [Trace](https://suiss.app/ui/docs/components/trace), [Code Block](https://suiss.app/ui/docs/components/code-block) and [Badge](https://suiss.app/ui/docs/components/badge).

**React Native, SwiftUI, Jetpack Compose**

```tsx
import { RobotIcon, TerminalIcon } 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 AiSubagentExample() {
  return (
    <View className="w-full gap-4">
      <Message align="end">
        <MessageContent>
          <Bubble variant="muted">
            <BubbleContent>
              Find out why the images rebuild on every deploy.
            </BubbleContent>
          </Bubble>
        </MessageContent>
      </Message>
      <TraceCollapsible defaultOpen>
        <TraceCollapsibleTrigger>
          <TraceLine>
            <TraceIcon>
              <Icon as={RobotIcon} />
            </TraceIcon>
            <TraceTitle>Ran the research subagent</TraceTitle>
            <TraceDescription>3 commands</TraceDescription>
          </TraceLine>
        </TraceCollapsibleTrigger>
        <TraceCollapsibleContent>
          <Trace>
            <TraceLine>
              <TraceIcon>
                <Icon as={TerminalIcon} />
              </TraceIcon>
              <TraceTitle>Ran grep -rn cacheKey scripts</TraceTitle>
            </TraceLine>
            <TraceLine>
              <TraceIcon>
                <Icon as={TerminalIcon} />
              </TraceIcon>
              <TraceTitle>
                Ran sed -n 13,15p scripts/optimize-images.ts
              </TraceTitle>
            </TraceLine>
            <TraceLine>
              <TraceIcon>
                <Icon as={TerminalIcon} />
              </TraceIcon>
              <TraceTitle>Ran ls public/images | wc -l</TraceTitle>
            </TraceLine>
          </Trace>
          <Text className="text-foreground">
            The cache key in scripts/optimize-images.ts includes the commit
            hash, so all 1,284 images rebuild.
          </Text>
        </TraceCollapsibleContent>
      </TraceCollapsible>
    </View>
  )
}
```

```swift
import EsuissUI
import PhosphorSwift
import SwiftUI

struct SubagentExample: View {
  var body: some View {
    VStack(alignment: .leading, spacing: 16) {
      Message(align: .end) {
        MessageContent {
          Bubble(variant: .muted, align: .end) { BubbleContent("Find out why the images rebuild on every deploy.") }
        }
      }
      TraceCollapsible(initiallyExpanded: true) {
        TraceCollapsibleTrigger {
          TraceLine {
            TraceIcon { Ph.robot.regular }
            TraceTitle(verbatim: "Ran the research subagent")
            TraceDescription(verbatim: "3 commands")
          }
        }
        TraceCollapsibleContent {
          Trace {
            TraceLine {
              TraceIcon { Ph.terminal.regular }
              TraceTitle(verbatim: "Ran grep -rn cacheKey scripts")
            }
            TraceLine {
              TraceIcon { Ph.terminal.regular }
              TraceTitle(verbatim: "Ran sed -n 13,15p scripts/optimize-images.ts")
            }
            TraceLine {
              TraceIcon { Ph.terminal.regular }
              TraceTitle(verbatim: "Ran ls public/images | wc -l")
            }
          }
          Text("The cache key in scripts/optimize-images.ts includes the commit hash, so all 1,284 images rebuild.").foregroundStyle(EsuissColor.foreground)
        }
      }
    }
  }
}
```

```kotlin
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.Robot
import com.adamglin.phosphoricons.regular.Terminal
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
import com.esuiss.ui.components.MessageAlign
import com.esuiss.ui.components.MessageContent
import com.esuiss.ui.components.Text
import com.esuiss.ui.components.Trace
import com.esuiss.ui.components.TraceCollapsible
import com.esuiss.ui.components.TraceCollapsibleContent
import com.esuiss.ui.components.TraceCollapsibleTrigger
import com.esuiss.ui.components.TraceDescription
import com.esuiss.ui.components.TraceIcon
import com.esuiss.ui.components.TraceLine
import com.esuiss.ui.components.TraceTitle
import com.esuiss.ui.theme.EsuissTheme

@Composable
fun SubagentAIDefault() {
    Column(Modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(16.dp)) {
        Message(Modifier.fillMaxWidth(), align = MessageAlign.End) {
            MessageContent {
                Bubble(variant = BubbleVariant.Muted) { BubbleContent("Find out why the images rebuild on every deploy.") }
            }
        }
        TraceCollapsible(initiallyExpanded = true) {
            TraceCollapsibleTrigger {
                TraceLine {
                    TraceIcon { Icon(PhosphorIcons.Regular.Robot, contentDescription = null) }
                    TraceTitle("Ran the research subagent")
                    TraceDescription("3 commands")
                }
            }
            TraceCollapsibleContent {
                Trace {
                    TraceLine {
                        TraceIcon { Icon(PhosphorIcons.Regular.Terminal, contentDescription = null) }
                        TraceTitle("Ran grep -rn cacheKey scripts")
                    }
                    TraceLine {
                        TraceIcon { Icon(PhosphorIcons.Regular.Terminal, contentDescription = null) }
                        TraceTitle("Ran sed -n 13,15p scripts/optimize-images.ts")
                    }
                    TraceLine {
                        TraceIcon { Icon(PhosphorIcons.Regular.Terminal, contentDescription = null) }
                        TraceTitle("Ran ls public/images | wc -l")
                    }
                }
                Text("The cache key in scripts/optimize-images.ts includes the commit hash, so all 1,284 images rebuild.", color = EsuissTheme.colors.foreground)
            }
        }
    }
}
```

Subagent on mobile is built from the same parts as on the web: [Trace](https://suiss.app/ui/docs/components/trace), [Message](https://suiss.app/ui/docs/components/message), [Bubble](https://suiss.app/ui/docs/components/bubble). The example above is a static demo; connect it to your agent by rendering the same parts from your messages.

## Installation

**React Native**

```bash title="Terminal"
npx @esuiss/ui@latest add trace message bubble
```

**SwiftUI**

```bash title="Terminal"
npx @esuiss/ui@latest add trace message bubble --platform swift
```

**Jetpack Compose**

```bash title="Terminal"
npx @esuiss/ui@latest add trace message bubble --platform kotlin
```

## API Reference

See [Trace](https://suiss.app/ui/docs/components/trace), [Message](https://suiss.app/ui/docs/components/message), [Bubble](https://suiss.app/ui/docs/components/bubble).

