onAgentEvent
Subscribes to everything the visual layer observes, in order: tool starts, field fills, parks, results, errors, cancels, and the cursor yielding to or resuming after the person.
Subscribes to everything the visual layer observes, in order: tool starts, field fills, parks, results, errors, cancels, and the cursor yielding to or resuming after the person. Reach for it to build your own status UI, logging or tests; the devtools and the chat do the same instead of reading internals.
Import
import { onAgentEvent } from "@webmcp-agents/core";
import type { AgentEvent } from "@webmcp-agents/core";
Example
A banner that shows what the agent is waiting for and hides when the call ends.
import { onAgentEvent } from "@webmcp-agents/core";
// A banner that says what the agent is waiting for.
const banner = document.createElement("p");
banner.hidden = true;
document.body.append(banner);
export const stopBanner = onAgentEvent((e) => {
switch (e.type) {
case "park": // e.g. Click "Place order" to confirm
banner.textContent = e.prompt;
banner.hidden = false;
break;
case "result":
case "error":
case "cancel":
banner.hidden = true;
break;
}
});
// Later: stopBanner();
Options
onAgentEvent(listener) takes one argument.
| Name | Type | Default | Description |
|---|---|---|---|
listener |
(e: AgentEvent) => void |
required | Called for every event, in order, as it happens. Switch on e.type; the variants are listed below. |
AgentEvent
One object per event, discriminated by type.
type |
Other fields | When |
|---|---|---|
start |
tool: string, at: number, args?: unknown |
A tool run started (the first lifecycle signal seen). at is performance.now(). args is what the agent passed, when known (tools from defineWebTool and useWebTool; declarative forms only show fills). A call whose input fails its schema still starts and answers with the error, without the cursor moving. |
fill |
tool: string, field: string, value: string | boolean |
The agent’s value went into a field, once the cursor has typed it. field is the parameter’s name for a tool (the control’s name for a declarative form); the value is a boolean for a checkbox. A custom widget the cursor only visited emits none. |
park |
tool: string, prompt: string |
The tool is waiting for the person: the browser paused on a submit button, a tool is waiting for their click on its control, or the page asked them something (see waitingForUser). prompt says what to do. |
result |
tool: string, result: unknown, ms: number |
The tool answered the agent. ms is measured from the run’s start. |
error |
tool: string, error: string, ms: number |
The tool failed; error is the text the agent got. |
cancel |
tool: string |
The call was cancelled. |
yield |
reason: "pointer" | "keyboard" | "wheel" | "touch" |
The person started interacting and the cursor got out of the way. |
resume |
none | The person has been quiet long enough for the cursor to show again. |
Returns
An unsubscribe function: () => void. Call it to stop listening.
Notes
- A listener that throws never breaks a tool run: the error is caught and logged with
console.error. - The
logoption ofinstallAgentVisualsreceives the same entries. - Listeners are module-level: subscribing works whether or not the visuals are installed, but most events come from the visual layer.
parkis also emitted bywaitingForUserand by confirm-gated tools. - There is no replay: a listener sees only events after it subscribed.
See also
- The agent cursor, what the events describe
installAgentVisuals, the layer that emits themwaitingForUser, a tool saying it waits for the personuseAgentEvents, the same events in a React component