AI Agent Activity Log

Pro

4 variants: `feed` (filterable event feed with opt-in step replay), `timeline`, `compact` (dense table with expandable rows) and `trace` (span waterfall with a step-detail panel). Tracks agent runs, tool calls, LLM steps and retrieval operations. Events are shown in arrival order, clock skew is reported rather than re-sorted, and every variant caps its rows and says when it has.

</>sv-ai-agent-activity-log aiagentlogsreplay
import { SvAiAgentActivityLogComponent } from '@styloviz-pro/ai-agent-activity-log';

Demo & usage

Basic usage

Pro

Usage example — open the gallery for the full interactive demo.

Pro

An interactive demo for this component lives in the gallery.

Open live demo

More examples

Dense table & span waterfall

Pro

Step-replay the run

Pro

When to use

  • Tracing an AI agent's execution: tool calls, LLM steps, retrieval and timing.
  • Debugging multi-step agents or showing users what the agent did.
  • For non-agent activity history, use the Timeline.

Async states

  • loading
  • error
  • retry
  • offline

Item identity & owned state

Restorable state
  • expandedIds

Bind these to put a saved view back — the open sections, the hidden columns, the selected rows — and read their Change events to store what the user does.

Inputs

NameTypeDefaultDescription
loadingbooleanfalseTrue while the data is being fetched.
errorSvDataError | string | nullnullLoad failure. Use `toSvDataError()` from `@styloviz/core` to normalize an `HttpErrorResponse`.
variantActivityLogVariant'feed'Which view: `feed`, `timeline`, `compact` or `trace`.
runAgentRun | nullnullThe agent run to visualize (steps, tool calls, timings). EVENTS ARE SHOWN IN THE ORDER THEY ARRIVED, NEVER RE-SORTED BY TIME. Two agents on two machines produce timestamps that disagree, and sorting by a skewed clock would put a tool result before the call that produced it. When an event's `elapsedMs` is earlier than the one before it, `feed`, `timeline` and `compact` say so in a notice instead — each event compared with its predecessor, so one skewed event flags itself rather than everything after it. A LATE EVENT is appended where it arrives, whether through a new `run` or `appendEvent()`; re-delivering an id patches that event in place. What a late event does to a replay in progress is `replayOnChange`.
tracereadonly ActivityEvent[] | nullnullThe tree shown by the `trace` variant. Leave `null` to walk `run.events` (they already nest through `children`); supply a tree when your trace endpoint returns a different shape from the flat feed.
connectionSvConnectionState'idle'State of your `EventSource` / WebSocket. A run that stops growing looks the same whether the agent is thinking or the socket died, so the component cannot infer this — only you know.
reconnectablebooleanfalseOffer a manual reconnect while the feed is down.
replayablebooleanfalseEnables step-replay controls in the feed view: play/pause, step and restart to walk the run one event at a time.
replaySpeednumber8Playback speed multiplier applied to the run's inter-step timings.
replayOnChangeSvReplayOnChange'hold'What an incoming event does to a replay already running. NOTHING USED TO SAY. The feed re-sliced against whatever had arrived, so "step 4 of 20" quietly became step 4 of a different list — the same index over different events, mid-sentence, with no signal at all. `'hold'` (the default) keeps walking the events the replay started with and counts the ones waiting, which join the feed when the reader leaves the replay; `'cancel'` leaves the replay as soon as a new event arrives and returns to the live feed, which is right for a monitoring wall; `'extend'` appends, which is only honest for a run still in progress.
expandedIdsReadonlySet<string> (two-way)new Set()IDs of events whose detail panel is expanded (two-way). A `model` so a host can open the event a deep link names — the case this log exists for, since an agent trace is usually shared by pointing at one step — and so the open set survives a route change. It was a plain signal, readable only from inside the template.
maxEventsnumber500How many events (or, in `trace`, spans) a variant renders at once. `0` = no ceiling. Applies to every variant, each with its own notice. AN AGENT RUN IS THE LIST-SHAPED SURFACE THAT GROWS WHILE YOU WATCH IT. A retry loop emits thousands of events in minutes, and a feed that renders every one of them gets slower exactly as the run gets more interesting — the operator is watching an incident through a page that is failing for a second, unrelated reason. THE WINDOW KEEPS THE NEWEST. A run's latest events are the ones being read; the beginning is history, and history is what a filter and a search are for. Replay is exempt, and that is deliberate — see visibleEvents. `trace` keeps the FIRST spans instead — see spanWindow.

Outputs

EventPayload typeDescription
retryvoidThe host should re-run the failed load.
reconnectvoidThe user asked to re-open the feed.
stepChange{ index: number; event: ActivityEvent }Emitted on each replay step with the revealed event and its index.
traceSelectstringEmitted with the id of the trace/run the user clicks.
expandedIdsChangeReadonlySet<string>Emits the new `expandedIds` whenever it changes — the output half of `[(expandedIds)]`.

Wire it to your API

This component is headless about transport: it renders what you give it and reports what the user asks for. Nothing below requires @styloviz/data — drive it from whatever you already use.

Template

Pro

Bound to the names this component actually exposes.

Host class

Pro

Drive the three async inputs from your own fetch.

  • This component does not emit a query, so it renders what you give it. Fetch on your own trigger and bind `trace`, `loading` and `error`.
  • `connection` reports the state of your `EventSource` or WebSocket. The component cannot infer it: a list that stops growing looks identical whether the feed is quiet or the socket died.
  • Normalize failures with `toSvDataError()` from `@styloviz/core`. It derives `retryable` from the status, so a 404 does not get a "Try again" button that can only fail again.

Full walkthrough: Connecting to a backend.

Customization & theming

  • Feed, timeline, compact and trace views.
  • Per-step status, duration and tokens.
  • Expandable step details.
  • Set `replayable` (feed view) to play the run back step-by-step — play/pause, step, restart, tunable `replaySpeed`, with a `stepChange` output.
  • Emits `traceSelect` with the clicked run/trace id.
  • A scale ceiling in every variant: `[maxEvents]` (500) is how many rows a view renders at once — `timeline` and `compact` keep the newest events, `trace` keeps the first spans (cutting a flattened tree from the top would orphan child spans), and each says what it left out. In the feed it is windowed over what the FILTER left rather than the raw run, and keeping the newest — a retry loop emits thousands of events in minutes, and the feed would get slower exactly as the run got more interesting. What is missing is disclosed at the top, the counters keep reporting the whole run, and step replay is exempt: replay walks the run from its first event forward, so a window keeping the newest would show an empty feed at step one. Set `0` if you virtualize the feed yourself.
  • `[replayOnChange]` decides what an arriving event does to a replay already running: `hold` (the default — keep walking the events it started with, and **count** the ones waiting, which join the feed when the reader leaves the replay), `cancel` (leave the replay the moment an event it did not start with arrives, stop the auto-play timer and return to the live feed — right for a monitoring wall) or `extend` (append, which is only honest for a run still in progress). Nothing used to say: the feed re-sliced against whatever had arrived, so 'step 4 of 20' quietly became step 4 of a different list, mid-sentence, with no signal at all.
  • A **filter change is the reader’s own action**, not the run moving under them, so it takes effect immediately whatever `replayOnChange` says. The snapshot is of the *filtered* list — taking it earlier would let a filter change mid-replay reveal events the reader had deliberately hidden.
  • Events are rendered in the order they arrived and **never re-sorted by timestamp**. Two agents on two machines produce clocks that disagree, and sorting by them would put a tool result before the call that produced it. An event whose time runs backwards against the one before it is flagged instead, compared against its predecessor rather than the maximum so far — otherwise one machine an hour ahead would report the entire remainder of the run as out of order and tell the reader nothing.

Best practices

  • Do: Expose per-step status, duration and token cost so slow/expensive steps stand out.
  • Do: Let users expand a step to see its inputs and outputs.
  • Tip: Use the `trace` view when steps run concurrently — it lays spans out against time.

Accessibility

  • Steps expose status and timing as text.
  • Type filter reports aria-pressed; expandable rows expose aria-expanded.
  • Replay transport buttons are labelled and keyboard-operable.
  • Keyboard expand/collapse of details.

Feedback on AI Agent Activity Log

Spotted a gap in this page, or something that didn't work as described? Comments are GitHub Discussions in the public styloviz/community repo, so posting needs a GitHub account.

Loads giscus.app and GitHub — nothing is fetched until you click.