# Agent Activity

A run as one thing: the wait while it goes, one line once it is over, and the steps it took folded behind that line for the reader who doubts the answer.

> For the complete documentation index, see [llms.txt](/llms.txt). Markdown variants are available by appending `.md` to any URL or sending an `Accept: text/markdown` header. An agent skill is available at [/.well-known/agent-skills/site-skill.md](/.well-known/agent-skills/site-skill.md).

<ComponentPreview name="agent-activity">
  <AgentActivityDemo />
</ComponentPreview>

## Installation [#installation]

```bash
npx shadcn@latest add https://motif.sweetretry.com/r/agent-activity.json
```

It is built on [Loading State](/docs/agents/loading-state), which `shadcn add` brings along. The
steps inside it are [Tool Call](/docs/agents/tool-call) and
[Thinking Block](/docs/agents/thinking-block), which you add on their own.

## Usage [#usage]

```tsx
import {
  AgentActivity,
  AgentActivityContent,
  AgentActivityHeader,
  AgentActivitySummary,
  AgentActivityTitle,
} from "@/components/ui/motif/agent-activity";

export function Run({ run }) {
  return (
    <AgentActivity
      duration={run.seconds}
      running={run.running}
      startedAt={run.startedAt}
    >
      <AgentActivityHeader>
        <AgentActivityTitle />
        <AgentActivitySummary>
          {run.calls.length} tool calls
        </AgentActivitySummary>
      </AgentActivityHeader>
      <AgentActivityContent>
        {run.steps.map((step) => (
          <Step key={step.id} step={step} />
        ))}
      </AgentActivityContent>
    </AgentActivity>
  );
}
```

| Part                   | Draws                                                        |
| ---------------------- | ------------------------------------------------------------ |
| `AgentActivity`        | The column, whether the run is going, and the fold           |
| `AgentActivityHeader`  | The row; the control that opens the timeline                 |
| `AgentActivityTitle`   | The wait while it runs, `Worked for 42s` once it has stopped |
| `AgentActivitySummary` | A line the caller writes about what the run amounted to      |
| `AgentActivityContent` | The steps, behind the header, hung from a rule on the left   |

## The header follows the run [#the-header-follows-the-run]

While `running`, the title is Loading State whole: the mark, a word and a clock, and the
timeline is open so the steps can be watched arriving. Once it stops, the title is plain text
and the timeline folds, because the reader wants the answer and the steps are a receipt for
the one who doubts it.

<ComponentPreview name="agent-activity">
  <AgentActivityLiveDemo />
</ComponentPreview>

The fold needs no effect and no timer. The root keeps what the reader picked, and while that
is empty the timeline is open exactly when `running` is. Once the reader presses the header
the choice is theirs, and a run that ends does not close what they opened.

`duration` is the caller's, in seconds, because the caller is the one who knows when the run
began. Without it the title says `Worked`. `startedAt` is the epoch ms the run began, so a
remount does not restart the clock.

## Steps are not parts [#steps-are-not-parts]

A step is a Tool Call, a Thinking Block, or anything you draw, and they stack in the order
they are given. There is no `AgentActivityStep`: wrapping each in a part that drew a dot on
the rail would put a second status beside the one the row already has. A Tool Call inside
the timeline still opens its own detail.

## Open and closed [#open-and-closed]

| Prop           | Does                                                       |
| -------------- | ---------------------------------------------------------- |
| `defaultOpen`  | Where it starts. Without it, open exactly while the run is |
| `open`         | Controlled. Passed, the root never opens or closes itself  |
| `onOpenChange` | Called when the reader presses the header                  |

A run with no steps is never open, whatever `open` says. Without a content part the header
is a plain row and draws no chevron: a chevron that pointed at nothing would be a promise
the part could not keep.

## Your own part [#your-own-part]

`useAgentActivity` hands over `running`, `duration`, `isOpen` and `toggle`, so a stop button
that only exists while the run does reads from the same state the title does.

## Accessibility [#accessibility]

The header is a real `button` with `aria-expanded` and `aria-controls` while there are steps,
and the running title is a live region, so the word is read when the run starts. The clock is
hidden from it, since a count that announced itself every tenth of a second would be the only
thing a screen reader said. The folded timeline is `inert`.

## Component source [#component-source]

<ComponentSource
  name="agent-activity"
  src="registry/new-york/agents/agent-activity.tsx"
  title="agent-activity.tsx"
/>
