Tool Activity
Shows the tools an agent called while it worked: what ran, what is waiting, and what needs attention. ActivityPanel frames a live run above its result.
- Searched the supplier inboxCompleted
- Reading the Q4 forecast tableIn progress
- Send the follow-up to NorthwindWaiting
Waiting for approval or another action. Review the action details below.
- Update the investor pitchPending
- Read #financeAccess denied
Access denied. Ask an administrator to review your permissions.
- Update the Northwind recordFailed
The action failed. Retry, or check the app connection.
- Post the weekly updateCancelled
- Send follow-up emails to late suppliersOutcome unknown
The outcome is unconfirmed. Check the action status before requesting it again.
Usage
import { BrandIcon } from "@tulipfarm/sprout/brand-icon";
import { ToolActivity } from "@tulipfarm/sprout/tool-activity";
<ToolActivity
active={replyIsWorking}
items={[
{
id: "call_1",
label: "Searched the supplier inbox",
status: "completed",
visual: <BrandIcon brand="gmail" size="inline" />,
},
{
id: "call_2",
label: "Update the Northwind record",
status: "failed",
visual: <BrandIcon brand="hubspot" size="inline" />,
detail: "The action failed. Retry, or check the app connection.",
details: <Button variant="outline" size="sm" onClick={retry}>Retry update</Button>,
},
]}
/>status:"queued","running","waiting","completed","blocked","failed","cancelled", or"unknown". Each has its own mark and a spoken name, such as “In progress” or “Outcome unknown”.visual: a 14px icon or an inlineBrandIconfor the tool or app.detail: one short line under the label. It turns red forfailedandblocked.details: extra content lined up with the label, such as a retry button or a “Details” toggle.active: the reply is still working even when no step is running, so the trigger shows a spinner.
Variants
"collapsible": the default. It opens while work is pending and closes once it settles. The trigger reads “Using 3 tools”, “2 tools waiting”, or “Used 3 tools · 1 needs attention”."transcript": starts closed under a chat reply. It reads “Working… Searching the web”, “Work pending”, or “Tool activity · 3 tools · Access denied”."stepper": always open, with no trigger. Items arrive newest first and show oldest first; inside anActivityPanelit scrolls to the newest step.
One tool
Request running. Tool running.
- Post to #launch-updatesIn progress
A single call, as on an agent request receipt. Pick a status to see its mark and how the summary changes.
In a chat reply
Is UK services inflation still above 5%? Check our supplier terms too.
Services inflation was 5.1% in September, down from 5.3%. Northwind’s terms allow a price review above 5%.
Following the latest message
<ToolActivity
variant="transcript"
items={tools}
active={isLatestTurn}
activityLabel="Searching the web"
sourceIcon={(url) => iconFor(new URL(url).hostname)}
onToggle={() => pauseFollowLatest()}
/>
// A web search step
{
id: "call_7",
label: "Searched the web",
status: "completed",
visual: <Globe size={14} />,
query: "UK services inflation September 2026",
urls: ["https://www.ons.gov.uk/…", "https://www.bls.gov/…"],
failedUrls: ["https://www.ft.com/…"],
sources: [{ url: "https://www.ons.gov.uk/…", title: "Consumer price inflation, UK" }],
}Web steps show their search text and up to four source chips; a “2 more” button shows the rest. A page in failedUrlsgets a warning icon. Chips without a title show the address withouthttps://www.. Only http andhttps addresses become links, which open in a new tab.
Pass sourceIcon to show page icons. It returns an image address for a page, or nothing for a globe; images that fail to load fall back to the globe. Sprõut never calls an icon service itself.
With no items, an active transcript shows “Thinking…” or the activityLabel. Other variants render nothing.
Activity panel
Supplier update
The draft appears here when the run finishes.
import { ActivityPanel, ToolActivity } from "@tulipfarm/sprout/tool-activity";
<ActivityPanel working={running} activityLabel={currentStep} hasResult collapseWhenDone>
<ToolActivity
variant="stepper"
items={steps}
hasOlder={page.hasMore}
loadingOlder={page.loading}
olderError={page.failed}
onLoadOlder={page.loadMore}
onRetryOlder={page.loadMore}
/>
</ActivityPanel>- The panel takes at most 40% of its parent’s height and scrolls inside. A soft fade covers the top once it scrolls.
hasResultdraws a line under the panel.collapseWhenDonecloses it when work stops and reopens it when work restarts.- When
hasOlderis set, scrolling within 40px of the top callsonLoadOlderonce. WhileloadingOlderit says “Loading earlier activity…”; onolderErrorit shows “Retry loading”.
Recorded activity
Recorded activity
A finished run can sit behind a ResultCard. Its details show the stepper without a panel.
Empty
Transcript, active
Transcript, active, with a label
Collapsible or stepper, no items
Nothing renders.
Accessibility
The trigger is a button named by its summary, and the summary is a live status. Steps are an ordered list named “Tool activity” (set label to rename it). Each step says its status, such as “Failed”; a running step’s status is announced outside the transcript. Source chips sit in a list named “Web sources”, and failed pages say “Page unavailable”.
ActivityPanel is a region named “Chat activity”. Its timeline is a focusable region named “Activity timeline”, so it scrolls by keyboard. Older-load errors are an alert.
Steps fade in over 180ms and the chevron turns in 120ms. With reduced motion, steps appear at once and running marks stop spinning. On touch screens the trigger and source chips grow to 44px.
Theme tokens
Rows use --sprout-text and --sprout-muted. Marks use --sprout-success (running),--sprout-primary (completed), --sprout-info(waiting), and --sprout-danger. Chips use--sprout-secondary and --sprout-hover. Set--sprout-activity-panel-fade to the panel’s background when it is not --sprout-surface.