Skip to content
Component installs need the registry setup
VegaStack Design

Agent Edit Banner

The strip under a document's header after an agent changed it — who, how many changes, when — with View changes, Undo and a dismiss.

Status
stable
Since
0.25.38
Accessibility pattern
polite live region, named buttons, decorative agent look

Last updated

Edited by Claude (via Manoj) 3 changes

Install

Configure registry credentials first using the Quickstart. Before copying this item or any transitive registry dependency, verify the signed manifest and save the exact bytes for Agent Edit Banner before installation. Retain the digest printed by this command.

pnpm exec vegastack-design verify agent-edit-banner

Install with the pinned shadcn CLI. Bare shadcn does not verify VegaStack signature or integrity.

pnpm dlx shadcn@4.21.0 add @vegastack/agent-edit-banner

Run the exact offline --post-write command printed by the preflight, using its saved item path and independently retained --expected-integrity digest. Use the saved preflight for every transitive registry dependency too; stop on any mismatch before using the components.

The same command installs the registry items it composes: @vegastack/alert, @vegastack/button, @vegastack/person-avatar, @vegastack/popover, @vegastack/relative-time.

Usage

import { AgentEditBanner } from "@/components/ui/agent-edit-banner";

<AgentEditBanner
  agent={{ name: "Claude", via: "Manoj" }}
  changeCount={group.writes}
  at={group.lastWriteAt}
  status={undoing ? "undoing" : refused ? "refused" : "idle"}
  onViewChanges={group.canDiff ? () => openDiff(group) : undefined}
  onUndo={canEdit && group.canUndo ? () => undo(group) : undefined}
  onOpenVersions={() => openVersions()}
  onDismiss={() => dismiss(group.runIds)}
/>;

The banner is presentational: the host owns the agent's runs, the undo, the refusal and the dismiss memory, and passes the state back. agent is the agent as a Person reads it — name ("Claude") and via its owner ("Manoj") — so the line says "Claude (via Manoj)" and the refused sentence uses the short name. The callbacks decide which buttons show: leave out onUndo and onViewChanges when the agent's checkpoint is gone, and every callback but onDismiss for a read-only viewer. When the undo succeeds, remove the banner and show a toast.

Scope

Pin it under a document's header, above the text, and reserve its space only while it shows. Render at most two; pass the rest to the second one's moreAgents, which ends its line with "+1 more agent" and lists each in a popover with its own Undo. Every string comes in through labels (and refusedReason for the refused line), with the English defaults below.

Examples

Edited by Claude (via Manoj) 3 changes

States

undoing spins Undo and disables both buttons. refused adds the reason line and swaps Undo for Open versions; pass refusedReason for another reason ("…because the page was restored since."). Without onUndo and onViewChanges (too old), or any action (a read-only viewer), the banner is words and the ✕ — or words alone without onDismiss. kind="created" reads "Created by Claude (via Manoj) · 5m ago".

Edited by Claude (via Manoj) 3 changes

Edited by Claude (via Manoj) 3 changes

Couldn't undo only Claude's changes because people edited the page since.

Edited by Claude (via Manoj) 3 changes

Edited by Claude (via Manoj) 3 changes

Created by Claude (via Manoj)

Stacked

The second banner ends with "+N more agents"; its popover lists the rest, each with its own Undo, spinner and refused line.

Edited by Claude (via Manoj) 3 changes

Edited by Codex (via Priya) 1 change

Narrow

Under a 42rem container the buttons take their own row under the text, which wraps beside the ✕; under 24rem Undo reads "Undo changes". On a coarse pointer every button has a 44px target.

Edited by Claude (via Manoj) 3 changes

API Reference

PropTypeDefaultDescription
agent*AgentEditBannerAgent—The agent: { name: "Claude", via: "Manoj" } reads "Claude (via Manoj)".
at*string | number | Date—When the agent last changed (or created) the document.
changeCountnumber—How many changes, after the name; omit to leave the count out.
kindAgentEditBannerKind"edited"Edited the document ("· 3 changes"), or created it.
labelsPartial<AgentEditBannerLabels>—Replace any of the strings (AgentEditBannerLabels).
moreAgentsreadonly AgentEditBannerMoreAgent[][]The other agents, behind "+N more agents" at the line's end.
nownumber—Pin the relative times' clock (docs, tests).
onDismiss(() => void)—Dismiss the banner for this viewer; the ✕ shows when set.
onOpenVersions(() => void)—Open the version history; Open versions shows when set and refused.
onUndo(() => void)—Undo the agent's changes; Undo shows when set, except while refused.
onViewChanges(() => void)—Open the diff of the agent's changes; View changes shows when set.
refusedReasonReact.ReactNodelabels.refused(agent.name)The line refused shows, in place of "Couldn't undo only Claude's changes because people edited the page since." — for another reason, such as a restore.
statusAgentEditBannerStatus"idle"Where the undo stands (AgentEditBannerStatus).

Data attributes and CSS variables on AgentEditBanner

AttributeValues
data-kindmirrors a prop or state value
data-slot"agent-edit-banner" | "agent-edit-banner-actions" | "agent-edit-banner-body" | "agent-edit-banner-dismiss" | "agent-edit-banner-reason" | "agent-edit-banner-summary"
data-statusmirrors a prop or state value

AgentEditBannerMoreAgent

PropTypeDefaultDescription
agent*AgentEditBannerAgent—The agent.
at*string | number | Date—When it last changed the document.
id*string—A stable key.
changeCountnumber—How many changes it made; omit to leave the count out.
kindAgentEditBannerKind"edited"Edited or created.
onUndo(() => void)—Undo this agent's changes; the row's Undo shows when set.
refusedReasonReact.ReactNodelabels.refused(agent.name)The refused line in place of the default.
statusAgentEditBannerStatus"idle"Where its undo stands; refused shows the reason in place of Undo.

Accessibility

  • The banner is an Alert status region with aria-live="polite", so a banner that changes while on screen is announced without interrupting; the relative time inside it ticks silently.
  • The buttons are named for the agent: "View Claude (via Manoj)'s changes" and "Undo Claude (via Manoj)'s changes", so two stacked banners never offer two identical names.
  • The purple bot is decoration (hidden from assistive tech); the words say it was an agent.
  • While undoing, Undo is busy (aria-busy) and both buttons stay focusable but inert.
KeyAction
TabMove through the time, "+N more agents", the buttons and ✕.
Enter / SpaceActivate a button, or open the list of the other agents.
EscClose that list and return focus to "+N more agents".
ContractStates tested
Behaviouredited, undoing, refused, too-old, read-only, created, more-agents, labels
Accessibilitypolite-live-region, named-buttons, decorative-avatar, silent-relative-time, browser-accessibility-test
Visualedited, states, stacked, narrow

Do / Don't

Do
Show it after an agent changed the document, with Undo for people who can edit, and remember a dismiss per viewer until the next run.
Don't
Ask for confirmation before Undo (it is reversible), or use it for an agent asking permission — that is an ApprovalCard.

On this page