# The AG-UI Channel

Course: [AI UX & Generative UI](https://www.devtutorials.ai/learn/ai-ux) · Section: Generative UI
Source: https://www.devtutorials.ai/learn/ai-ux/generative-ui/ag-ui-channel

> Wire the agent and the UI over an AG-UI-style event stream: text, tool calls, state deltas, interrupts and human-in-the-loop, without losing what the user typed.

## What the AG-UI Channel Is

**AG-UI** = an open, event-based protocol for the live connection between an agent and your app's interface.

In this lesson, you will wire the order panel to the agent over one event stream, so the panel shows the agent's work as it happens, keeps what the user typed, stops cleanly, and asks the user when the agent needs a yes.

Every lesson so far used events: tokens, tool calls, a proposed action, an A2UI payload. AG-UI is the standard shape for that stream.

When the client handles the events badly, the user loses work. Here, the user is typing a note while the agent updates the order:

Press **Play**, or use **Next** to go one step at a time.

- **Frame 1:** the user types "Call after 5 pm" into the note.
- **Frame 2:** a state update from the agent replaces the whole note. The user's words are gone.
- **Frame 3:** with merge, the new delivery date applies and the user's note stays.

**Simple lesson:** the agent and the user share the same screen. Neither should wipe out the other.

### A Real-World Example

Think about a shared online document.

- Two people type at once. Each sees the other's changes appear.
- Your words don't disappear when someone else edits another line.
- If someone needs your approval, a comment asks you, and they wait.

The AG-UI channel works the same way:

- **Seeing the other's changes** = events streaming to the UI.
- **Your words stay** = state deltas that keep the user's edits.
- **Asking and waiting** = human-in-the-loop.

Click the button. The Build tab plays the state update through the naive client.

- **Shared state:** watch the note before and after STATE_DELTA.
- **Events from the agent:** RUN_STARTED, the user's typing, STATE_DELTA, RUN_FINISHED.
- **The check:** the delta must not lose user edits.

**Simple lesson:** the client decides how each event changes the screen.

## What You Will Learn

In this lesson, you will learn:

1. How MCP, AG-UI and A2UI fit together.
2. The main AG-UI event types.
3. How to apply state deltas without losing user edits.
4. How to interrupt an agent in the middle of a tool call.
5. How human-in-the-loop requests work.

**About AG-UI in this lab**

- AG-UI is an open spec. This course teaches a **compatible subset**, so the checks stay stable while the spec grows.
- Real AG-UI sends state changes as JSON Patch operations. The lab shows the changed fields directly, so the idea is easier to see.
- The human-in-the-loop event here is labelled "custom": check how your framework names it.

## Three Protocols, Three Jobs

Step through all three frames.

- **Frame 1: MCP** connects the agent to its tools: the order database, the courier.
- **Frame 2: AG-UI** connects the agent to your app: the stream of events.
- **Frame 3: A2UI or MCP Apps** describe what to draw. They travel inside AG-UI events.

| Layer | Job | In this course |
|---|---|---|
| MCP | Agent ↔ tools | The MCP course |
| AG-UI | Agent ↔ your app | This lesson |
| A2UI / MCP Apps | What to render | Lessons 8 and 9 |

**Simple lesson:** MCP is for tools, AG-UI is the channel, A2UI and MCP Apps are the payload.

## The Event Stream

An AG-UI run is a stream of small events. The main ones:

| Event | What it says |
|---|---|
| `RUN_STARTED` | The agent started working |
| `TEXT_MESSAGE_CONTENT` | A few more words of the answer |
| `TOOL_CALL_START` / `TOOL_CALL_END` | A tool call began or finished |
| `STATE_DELTA` | Some fields of the shared state changed |
| `RUN_FINISHED` | The agent is done |

The client reads each event and updates the screen. You already built most of this: streaming (Lesson 2), tool steps (Lesson 2), and payloads (Lesson 8).

### State Deltas

**Shared state** = data both the agent and the UI can see and change, such as the order's ETA and the ticket note.

**State delta** = an event with only the fields that changed.

The client must merge the delta, but keep any field the user is editing:

```tsx
function onStateDelta(patch: Record<string, string>) {
  setState((s) => {
    const next = { ...s };
    for (const [k, v] of Object.entries(patch)) if (!dirty.current.has(k)) next[k] = v;
    return next;
  });
}
```

`dirty` is the set of fields the user has typed in. Tell the agent about the user's edit in the next message, so it can adjust.

**Simple lesson:** apply the agent's changes, except where the user is typing.

## Interrupts and Human-in-the-Loop

Step through both frames.

- **Frame 1:** the user presses Stop while the agent is changing the address. Ignored on the left; the address still changes. On the right, the run is cancelled and nothing changes.
- **Frame 2:** the agent pauses to ask "Change the delivery address?". On the left, the question never reaches the screen. On the right, the user approves and the run resumes.

### Interrupt

**Interrupt** = the user stops the run while it is working.

Abort the run, as with Stop in Lesson 2. The agent's server should roll back half-done tool work and end with `RUN_CANCELLED`.

### Human-in-the-Loop

**Human-in-the-loop** = the agent pauses and waits for a person to decide.

Show the request where the user is working, with the exact details (as in Lesson 5). Send the answer back, so the run continues.

**A request nobody sees is a stuck run.**

- If the client ignores the agent's question, the agent waits forever.
- Show every human-in-the-loop request, even when the panel is closed (for example with a badge).
- Time out politely, and say what happened.

**Easy way to remember:** **Merge, abort, ask.** Merge deltas around the user's edits, abort cleanly on Stop, and show the agent's questions.

**Simple lesson:** the user can stop the agent, and the agent can ask the user.

### Lab Exercise: Wire the AG-UI Client

Your task: change the Lesson 10 settings in the Build tab so all three scenarios pass. Then press **Check all scenarios**.

Click the button and open the **Build** tab.

- **The three scenarios:** a delta while typing, an interrupt during a tool call, and a request for approval.
- **Shared state:** shows whose edit won.
- **Side effects:** show whether the address really changed.

**Simple lesson:** merge, abort and ask, all three.

### What Changes per Framework

| Option | AG-UI client |
|---|---|
| Hand-built React | Read the event stream and handle each type, as above |
| CopilotKit | A reference AG-UI client with shared state and human-in-the-loop |
| AG-UI SDKs | Client and server SDKs for several languages, including .NET |
| Your agent framework | Many agent frameworks can emit AG-UI events; check yours |

## Build It in React

In the **Code** tab, your component is the AG-UI client. It gets `run-start`, `tool-call-start`, `state-delta` and `hitl-request` events, and the lab types in the Note box like a real user.

The rule for deltas fits in one loop. Skip any field the user has edited:

```tsx
for (const [k, v] of Object.entries(e.patch)) if (!edited.current.has(k)) next[k] = v;
```

Show Stop while a run is going, and call `agent.cancel()` when it is pressed. When the agent asks a person, show the question and send the answer back with `agent.respond(true)`.

## TL;DR

1. **AG-UI** = the event channel between agent and app.
2. **Layers** = MCP for tools, AG-UI for the channel, A2UI or MCP Apps for the payload.
3. **Events** = RUN_STARTED, TEXT_MESSAGE_CONTENT, TOOL_CALL_START/END, STATE_DELTA, RUN_FINISHED.
4. **State delta** = merge, but keep fields the user is editing.
5. **Interrupt** = abort and roll back, ending with RUN_CANCELLED.
6. **Human-in-the-loop** = show the agent's question, send the answer back.

## Common mistakes

| Mistake | Wrong idea | Correct idea | What goes wrong |
|---|---|---|---|
| Replacing state | "The agent's state is the truth." | Merge, keeping the user's edits. | The user's note disappears. |
| Ignoring interrupts | "The tool will finish soon anyway." | Abort and roll back. | The address changes after Stop. |
| Hiding HITL requests | "The panel is closed, it can wait." | Show the request where the user is. | The run is stuck forever. |
| Mixing up the layers | "AG-UI is a UI format." | AG-UI is the transport; A2UI is the format. | The team builds the wrong thing. |
| Tracking the full spec blindly | "Use every new event type." | Pin the subset you test. | A spec change breaks the UI. |

## Check Your Understanding

## Exercises

## What to Remember

- AG-UI is the channel; MCP is for tools; A2UI and MCP Apps are the payload.
- The client turns each event into a screen change.
- Merge state deltas, but keep what the user is typing.
- Stop during a tool call must abort and roll back.
- Show every human-in-the-loop request, and send the answer back.

## Further Reading

- [AG-UI core concepts, by the AG-UI project](https://docs.ag-ui.com/concepts): events, architecture and the protocol layers.
- [State management in AG-UI](https://docs.ag-ui.com/concepts/state): snapshots and deltas.

Next: **Feedback That Improves the Product**, where thumbs, corrections and regenerate clicks become events your evals can learn from.
