# AG-UI

Turns AG-UI events into Candor messages, waiting approvals and usage. Pure (given `now`), so it can run on every render; useAgUi calls it for you.

- Registry name: `ag-ui` (`@candor/ag-ui`)
- Tier: Free (MIT). No licence key needed.
- Docs: https://candor.themethodic.com/docs/ag-ui

## Install

```bash
npx candor-ui add ag-ui
```

Run `npx candor-ui@latest init` once first (https://candor.themethodic.com/get-started.md). Without the CLI: `npx shadcn@latest add @candor/ag-ui`.
It brings in: chat, safe-markdown, status.
npm packages: @ag-ui/core@^1.0.3.

## Functions

### fromAgUiEvents

```ts
fromAgUiEvents(events: AgUiEvent[], options: FromAgUiOptions)
```

Turns AG-UI events into Candor messages, waiting approvals and usage. Pure (given `now`), so it can run on every render; useAgUi calls it for you.

### applyJsonPatch

```ts
applyJsonPatch(document: unknown, patch: JsonPatch | unknown)
```

Applies an RFC 6902 JSON Patch to a JSON document, all or nothing. Pure: the document passed in is never changed, and the result shares nothing with the patch's values. A patch that fails (a path that doesn't resolve, a failed `test`, a malformed operation) returns `ok: false` with a plain reason.

## Types

### CandorAgUiEvent

Events of Candor's own, mixed into the AG-UI stream by useAgUi.

```ts
| { type: "candor_user"; id: string; text: string; references?: EntityRef[] | undefined } /** A person answered an interrupt; the next run resumes with it. */ | { type: "candor_answer"; interruptId: string; approved: boolean; reason?: string | undefined } /** The run failed outside the protocol's own events (the request, the stream). */ | { type: "candor_error"; message: string }
```

### AgUiEvent

```ts
Event | CandorAgUiEvent
```

### AgUiApproval

An interrupt waiting on a person.

```ts
{ /** The interrupt's id; answer it with `respond(id, …)`. */ id: string /** The agent's machine-readable reason, e.g. "tool_approval". */ reason: string /** The agent's own sentence for the request, when it sent one. */ message?: string | undefined /** A sentence to show: the agent's message, or a plain one naming the tool. */ title: string /** Set when the interrupt asks to run a tool call. */ t
```

### AgUiUsage

Tokens the runs reported, summed. A count no run reported stays unknown. AG-UI reports no cost.

```ts
{ inputTokens?: number | undefined; outputTokens?: number | undefined }
```

### FromAgUiOptions

```ts
{ /** Who the agent is. Candor always names the agent. */ agent: AgentIdentity /** A run is open now: the last reply is still streaming, and no interrupt can be answered yet. */ running?: boolean | undefined /** A plain-words title for a tool call: "Read notes.md". `input` is undefined until the arguments arrive. */ toolTitle?: ((tool: string, input: unknown) => string | undefined) | undefined /**
```

### AgUiPlanStep

A plan step read from an activity whose content has `steps: [{ title, status }]`. The same shape as PlanStep, so it can go straight to a plan view.

```ts
{ id: string title: string status: RunStatus /** The step's own summary, when it sent one as text. */ summary?: string | undefined /** Why it failed: the agent's words, or a plain sentence saying it didn't say. Set only when status is "failed". */ failure?: string | undefined }
```

### AgUiAgentActivityEntry

What an agent is doing, read from an activity whose content has `status` (and optionally `doing`, `since`, `agentId`). The same shape as AgentActivityEntry.

```ts
{ /** The app's own identity for the agent, never one taken from the content. */ agent: AgentIdentity doing?: string | undefined status: RunStatus since?: string | undefined }
```

### AgUiActivity

An activity the agent reported: structured progress that isn't part of a reply.

```ts
{ /** The activity message's id. */ id: string /** The agent's own kind for it, e.g. "plan" or "search". An open string. */ type: string /** Its content as the agent sent it, after any patches. Data, never markup. */ content: Record<string, unknown> /** Set when an update to it couldn't be applied: the content is the last good one, and may be behind. */ outOfDate?: string | undefined /** Its `step
```

### AgUiState

```ts
{ messages: Message[] /** Interrupts waiting on a person, oldest first. Empty while a run is open; expired ones are left out. */ approvals: AgUiApproval[] /** The thread the runs belong to. Send it back to continue the conversation. */ threadId?: string | undefined usage?: AgUiUsage | undefined /** Something the person should know that isn't part of a reply, such as an expired request. */ notice?:
```

### JsonPatchResult

What applying a JSON Patch gave: the new document, or why it didn't apply (and then nothing changed).

```ts
{ ok: true; value: unknown } | { ok: false; reason: string }
```

## Rules for using Candor UI

- Components take plain typed data. Never pass model output as HTML or render it as a link; messages are typed blocks.
- A control that can't be used says why: wrap it in `<Locked reason="…">`, don't just disable it.
- Don't show a value you don't have: leave it out (it renders as —) rather than guess. An estimate is labelled as one.
- Nothing is pre-selected in a decision a person makes, and the agent is named from your app's data, never from model output.
- Your app's words go in `LocaleProvider` (fixed strings) and `TermsProvider` (nouns); entity kinds and agent roles in `EntityKindsProvider` and `AgentRolesProvider`.
