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.
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-activityCopies 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.jsonWorks, 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
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.
| Prop | Type | Default |
|---|---|---|
toolsrequiredThe tool parts, in order. | ToolPart[] | none |
onApproveCalled with a tool's id when the person approves it. | (toolId: string) => void | none |
onDenyCalled with a tool's id when the person declines it. | (toolId: string) => void | none |
defaultOpenShow the steps at first. | boolean | false |
focusApprovalMove focus to an approval box when one appears. | boolean | false |
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