Agent Status
What the AI is doing right now, while the person waits: a single thinking line, or the stages of a longer run, each done, failed, in progress or still to come.
When to Use
size sm sits inline beside the control that started the work, such as "Drafting" next to a Generate button.
Variants
Stages
An ordered list of the run's stages. Each is done, failed, now or todo, with an optional detail line. A failed stage takes a recovery sentence and one action, so the person always knows what to do next.
Building your agenda
-
Done: Read the brief
12 product leaders, 2 hours, one decision to make.
-
Failed: Transcribe the kickoff recording
The file stopped at 12 minutes. Upload it again, or carry on without it.
-
In progress: Choose activities from the library
-
Not started: Check the timings and the breaks
<?= ws_agent_status([
'id' => 'generator-status',
'label' => 'Building your agenda',
'stages' => [
['key' => 'brief', 'label' => 'Read the brief', 'state' => 'done', 'detail' => '12 product leaders, 2 hours.'],
['key' => 'recording', 'label' => 'Transcribe the kickoff recording', 'state' => 'failed',
'recovery' => 'The file stopped at 12 minutes. Upload it again, or carry on without it.',
'action' => ['label' => 'Try again']],
['key' => 'pick', 'label' => 'Choose activities from the library', 'state' => 'now'],
['key' => 'check', 'label' => 'Check the timings and the breaks', 'state' => 'todo'],
],
]) ?>Thinking
One line: the AI mark, a sentence, three dots. The sentence says what it is doing when you know ("Reading your notes"); "Working on it" is the default. A quieter detail can follow.
<?= ws_agent_status() ?> <?= ws_agent_status(['label' => 'Reading your notes', 'detail' => '14 notes and 2 recordings']) ?>
Inline (size sm)
The thinking line at button size, with no fill, border or padding, so it sits in a button row or beside a field. Put it right after the control that started the work and give it the verb of what is happening ("Drafting", "Checking"). Stages have no inline form.
<?= ws_button('Generate', ['variant' => 'primary', 'size' => 'sm', 'disabled' => true]) ?>
<?= ws_agent_status(['label' => 'Drafting', 'size' => 'sm']) ?>
// The same from JavaScript
row.insertAdjacentHTML('beforeend', WsAgent.status({ label: 'Drafting', size: 'sm' }));From JavaScript
Most AI waits start in the browser. WsAgent.status(options) prints the same markup, and WsAgent.setStage(root, key, patch) redraws one stage as the run moves on; the list's live region reads that stage out. Press the button to move this run forward.
<script src="/js/ws-agent.js?v=<?= filemtime(WS_ROOT . '/js/ws-agent.js') ?>"></script>
panel.innerHTML = WsAgent.status({ id: 'gen', label: 'Building your agenda', stages: [
{ key: 'brief', label: 'Read the brief', state: 'now' },
{ key: 'pick', label: 'Choose activities', state: 'todo' },
] });
WsAgent.setStage('gen', 'brief', { state: 'done', detail: '12 people, 2 hours.' });
WsAgent.setStage('gen', 'pick', { state: 'failed', recovery: 'The library did not answer.', action: { label: 'Try again' } });
document.addEventListener('ws:agent-retry', e => restart(e.detail.stage));States
| Stage | Looks | Says |
|---|---|---|
done | A tick in a stone circle; the name in ink | "Done:" |
failed | An exclamation in an amber circle, the recovery sentence in amber ink, and the action | "Failed:" |
now | A turning ring in a filled red circle; still under reduced motion | "In progress:", and aria-current="step" |
todo | An empty circle; the name muted | "Not started:" |
| Thinking | Three dots that pulse, and hold still under reduced motion | Its sentence, as a status |
Thinking, sm | The same line at button text size, with no fill or border | Its sentence, as a status |
Real-World Usage
It replaces the Planner generator's loading view and Synthesize's hand-built progress screen, and the six thinking indicators around the chat surfaces. The failed stage is the part those screens never had: say which step broke, what the person can do, and give them the one button that does it.
Options
| Option | Type | Default | Purpose |
|---|---|---|---|
mode | string | 'stages' when stages are passed, else 'thinking' | thinking | stages |
size | string | 'md' | sm | md. Thinking only: sm is the inline, button-sized form |
label | string | '' | Thinking: the sentence ("Working on it" when empty). Stages: the list's title. |
detail | string | '' | Thinking only: a second, quieter sentence |
stages | array | [] | Each: label, state (done | failed | now | todo), detail, key (default: its position from 1), recovery and action (failed only; the action takes ws_button options plus label) |
id | string | '' | Element id. With a label in stages mode the list is named by {id}-title; WsAgent.setStage() takes it. |
class / attrs | string / array | Additional classes and attributes |
Events: a failed stage's action dispatches ws:agent-retry with detail.stage (its key) and detail.status (the root). Load /js/ws-agent.js for it.
Accessibility
| Concern | Behavior |
|---|---|
| Thinking | The line is role="status", so its sentence is read when it appears. The dots are aria-hidden and stop under prefers-reduced-motion. The sm form keeps both, and its words, never the dots alone, say what is happening. |
| Stage changes | The stage list is a polite live region. When WsAgent.setStage() redraws a stage, a screen reader hears that stage whole: its state, its name, its detail. |
| State in words | Every stage starts with visually hidden words for its state ("Done:", "Failed:", "In progress:", "Not started:"), and each state has its own glyph, so nothing rests on colour. The stage in progress carries aria-current="step". |
| Recovery | A failed stage's action is a real button in reading order, right after the sentence that says what went wrong. |
| Motion | The turning ring and the dots stop under reduced motion; the red circle and the words still say the run is going. |
Tokens
| Token | Used for |
|---|---|
--brand / --brand-tint / --brand-line | The dots, the stage in progress, and the thinking line's fill and border |
--color-warning / --color-warning-surface / --color-warning-surface-ink | A failed stage and its recovery sentence |
--gray-100 / --gray-300 | Done and still-to-come circles |
--text-dark / --text-default / --text-muted | Names, details, stages not started |
--font-heading / --text-h4 | The stages title |
--space-* / --radius-lg / --radius-full | Spacing and shape |
--ease-in-out | The dots' pulse |
CSS Classes
| Class | Purpose |
|---|---|
.ws-agent-status | Root; --thinking or --stages, and --sm for the inline thinking line |
.ws-agent-status__text / __label / __detail / __dots | The thinking line |
.ws-agent-status__title | The stages title, with the AI mark |
.ws-agent-status__stages | The live list |
.ws-agent-status__stage | One stage, --done / --failed / --now / --todo; carries data-ws-stage |
.ws-agent-status__icon / __glyph | The state circle and its glyph |
.ws-agent-status__name / __recovery / __action | A stage's name, recovery sentence and action |
Files
| File | Purpose |
|---|---|
includes/components/helpers.php | ws_agent_status() helper |
includes/components/agent-status.php | Template |
includes/components/components.css | Styles, in the agent components section |
js/ws-agent.js | WsAgent.status(), WsAgent.setStage() and ws:agent-retry |