Skip to content

Agent Activity

A short summary of what the assistant is doing or did, such as "Used 3 tools", that opens into each step. It stays open while a step needs approval.

AIv0.1.0experimentalWCAG 2.2 AAView spec

Bring your own model.

These components only show what you give them, in one message shape, and report what the person does. They never call a model or a server, so they work with any backend. They are built for how assistive technology handles streaming text, tool steps and approvals.

import { AgentActivity } from "@rdloom/react";

export default function AgentActivityWorkingExample() {
  return (
    <div className="w-[30rem] max-w-full">
      <AgentActivity
        defaultOpen
        tools={[
          { type: "tool", id: "1", name: "search", title: "Searching the knowledge base", state: "done", startedAt: "2026-03-01T10:00:00Z", endedAt: "2026-03-01T10:00:01.200Z" },
          { type: "tool", id: "2", name: "read", title: "Reading 3 documents", state: "running" },
          { type: "tool", id: "3", name: "write", title: "Writing the summary", state: "pending" },
        ]}
      />
    </div>
  );
}

Installation

npx rdloom add agent-activity

Copies the source into src/components/rdloom. Edit it freely: rdloom upgrade merges later versions into your changes. It needs react-aria-components; add --install to install them.

Use another registry client
npx shadcn@latest add https://rdloom.vimalbhatt.com/r/agent-activity.json

Works, but without upgrade tracking.

Usage

import { AgentActivity } from "@rdloom/react";

<div className="w-[30rem] max-w-full">
  <AgentActivity
    defaultOpen
    tools={[
      { type: "tool", id: "1", name: "search", title: "Searching the knowledge base", state: "done", startedAt: "2026-03-01T10:00:00Z", endedAt: "2026-03-01T10:00:01.200Z" },
      { type: "tool", id: "2", name: "read", title: "Reading 3 documents", state: "running" },
      { type: "tool", id: "3", name: "write", title: "Writing the summary", state: "pending" },
    ]}
  />
</div>

Finished

import { AgentActivity } from "@rdloom/react";

// Collapsed once it is done: "Used 3 tools (1 failed)". Open it to see each step.
export default function AgentActivityFinishedExample() {
  return (
    <div className="w-[30rem] max-w-full">
      <AgentActivity
        tools={[
          { type: "tool", id: "1", name: "search", title: "Searching the knowledge base", state: "done", startedAt: "2026-03-01T10:00:00Z", endedAt: "2026-03-01T10:00:01Z" },
          { type: "tool", id: "2", name: "fetch", title: "Fetching the pricing page", state: "failed", error: "The page returned 404." },
          { type: "tool", id: "3", name: "calc", title: "Calculating totals", state: "done", startedAt: "2026-03-01T10:00:02Z", endedAt: "2026-03-01T10:00:02.100Z" },
        ]}
      />
    </div>
  );
}

Needs approval

  • Send a reminder to 8 customers

    Medium risk · Can't be undone

import { useState } from "react";
import { AgentActivity, updateTool, type ChatMessage, type ToolPart } from "@rdloom/react";

// While a step waits for an answer the list stays open: a question can't be hidden.
export default function AgentActivityNeedsApprovalExample() {
  const [message, setMessage] = useState<ChatMessage>({
    id: "m",
    role: "assistant",
    parts: [
      { type: "tool", id: "1", name: "lookup", title: "Finding overdue invoices", state: "done" },
      { type: "tool", id: "2", name: "email", title: "Email the customers", state: "awaiting-approval", approval: { summary: "Send a reminder to 8 customers", risk: "medium", reversible: false } },
    ],
  });
  const tools = message.parts.filter((p): p is ToolPart => p.type === "tool");
  return (
    <div className="w-[30rem] max-w-full">
      <AgentActivity
        tools={tools}
        onApprove={(id) => setMessage((m) => updateTool(m, id, { state: "approved" }))}
        onDeny={(id) => setMessage((m) => updateTool(m, id, { state: "denied" }))}
      />
    </div>
  );
}

API Reference

Defined by the spec. Components also accept the props of the React Aria component they wrap.

PropTypeDefault
toolsrequired

The tool parts, in order.

ToolPart[]none
onApprove

Called with a tool's id when the person approves it.

(toolId: string) => voidnone
onDeny

Called with a tool's id when the person declines it.

(toolId: string) => voidnone
defaultOpen

Show the steps at first.

booleanfalse
focusApproval

Move focus to an approval box when one appears.

booleanfalse

Accessibility

Role group, WCAG 2.2 AA. Tested with axe and keyboard tests; screen reader checks are in the audit checklist.

Keyboard

  • Enter / Space on the summary: shows or hides the steps

Screen readers announce

  • "Used 3 tools (1 failed), button, collapsed"
  • While working: "Working: 1 of 3 steps done, button, collapsed"

What your code must do

  • The summary is a button with aria-expanded that controls the list of steps
  • While any step is waiting for approval the list is forced open and the button is disabled: a question can't be hidden
  • Progress reads in words ("Working: 1 of 3 steps done"), failures and declines are counted
  • Each step is a ToolCall, so it announces its own changes

Guidelines

Use it when

  • Grouping the tool calls inside one reply

Avoid it when

  • A single tool call: use ToolCall directly

Don't

  • Collapsing the list while an approval is pending

Design tokens

The semantic tokens this component uses. Change them once and every component follows; see Design tokens.

  • --rd-color-text-default
  • --rd-color-text-muted
  • --rd-color-action-primary
  • --rd-color-surface-subtle
  • --rd-color-focus-ring
  • --rd-radius-control