# What Is the AG-UI Protocol? How Tambo AI Uses It for Real-Time Streaming

> Discover the AG-UI protocol for real-time conversational AI streams. Learn how Tambo AI leverages this event-based format to deliver LLM outputs and UI components instantly.

- Repository: [tambo ai/tambo](https://github.com/tambo-ai/tambo)
- Tags: deep-dive
- Published: 2026-02-16

---

**The AG-UI protocol is an open-source event-based wire format that represents conversational AI interactions as typed events, which Tambo AI uses to stream LLM outputs, tool calls, and UI components in real-time via Server-Sent Events.**

The AG-UI protocol powers the streaming architecture of the `tambo-ai/tambo` repository, enabling low-latency delivery of text deltas, tool invocations, and interactive UI components from backend LLMs to React frontends.

## What Is the AG-UI Protocol?

AG-UI (Agent-User Interface) is an open-source wire protocol defined by the `@ag-ui/core` SDK. It models conversational interactions as a stream of strongly typed events rather than monolithic JSON responses. Standard event types include `RUN_STARTED`, `TEXT_MESSAGE_CONTENT`, `TOOL_CALL_START`, and `RUN_FINISHED`, each carrying specific payloads that describe the state of an AI run.

This event-based architecture decouples the LLM generation process from the UI rendering layer, allowing clients to incrementally display content as it is produced rather than waiting for complete responses.

## How Tambo AI Implements AG-UI for Streaming

Tambo AI adopts AG-UI as the foundational wire protocol for its v1 streaming-first API. The implementation spans three architectural layers: backend event generation, SSE transport, and React SDK consumption.

### Backend Event Generation

In [`packages/backend/src/util/tambo-custom-events.ts`](https://github.com/tambo-ai/tambo/blob/main/packages/backend/src/util/tambo-custom-events.ts), Tambo extends the standard AG-UI specification with custom event types prefixed with `tambo.`. These extensions handle component streaming, property updates, and input awaiting states. The backend translates LLM token streams, tool call stages, and component generation into AG-UI events, mixing standard types like `TEXT_MESSAGE_CONTENT` with custom events like `tambo.component.start`.

### SSE Transport Layer

Events flow from the backend to the client via Server-Sent Events (SSE). The API endpoint streams `text/event-stream` content where each line contains a JSON-encoded AG-UI event. This transport method maintains a persistent connection ideal for real-time incremental updates while remaining compatible with standard HTTP infrastructure.

### React SDK Consumption

The React SDK consumes these streams through two core utilities in `react-sdk/src/v1/utils/`. The `handleEventStream` function in [`stream-handler.ts`](https://github.com/tambo-ai/tambo/blob/main/stream-handler.ts) converts the SDK's async iterable into typed `AGUIEvent` objects with optional debug logging. These events feed into `streamReducer` in [`event-accumulator.ts`](https://github.com/tambo-ai/tambo/blob/main/event-accumulator.ts), an immutable state reducer that builds the thread state by processing each event type and updating React state accordingly.

## Core Components in the Tambo AI Repository

| Responsibility | File Path | Key Function/Export |
|----------------|-----------|---------------------|
| Event source conversion | [`react-sdk/src/v1/utils/stream-handler.ts`](https://github.com/tambo-ai/tambo/blob/main/react-sdk/src/v1/utils/stream-handler.ts) | `handleEventStream` |
| State accumulation | [`react-sdk/src/v1/utils/event-accumulator.ts`](https://github.com/tambo-ai/tambo/blob/main/react-sdk/src/v1/utils/event-accumulator.ts) | `streamReducer` |
| Custom event definitions | [`packages/backend/src/util/tambo-custom-events.ts`](https://github.com/tambo-ai/tambo/blob/main/packages/backend/src/util/tambo-custom-events.ts) | `ComponentStartEvent`, `ComponentPropsDeltaEvent` |
| Hook implementation | [`react-sdk/src/v1/hooks/use-tambo-v1-send-message.ts`](https://github.com/tambo-ai/tambo/blob/main/react-sdk/src/v1/hooks/use-tambo-v1-send-message.ts) | `useTamboV1SendMessage` |
| Type definitions | [`react-sdk/src/v1/types/event.ts`](https://github.com/tambo-ai/tambo/blob/main/react-sdk/src/v1/types/event.ts) | `TamboCustomEvent` |

## Streaming Flow: From LLM to UI

The complete data flow follows these discrete stages:

1. **Run Initialization** – The client calls `POST /v1/threads/{id}/runs`, triggering the backend to emit a `RUN_STARTED` event.

2. **Content Generation** – As the LLM produces tokens, the backend emits `TEXT_MESSAGE_CONTENT` events containing text deltas. When the model invokes tools, the system emits `TOOL_CALL_START`, `TOOL_CALL_ARGS`, and `TOOL_CALL_END` events.

3. **Component Streaming** – For UI component generation, Tambo emits custom events: `tambo.component.start` initializes the component, `tambo.component.props_delta` streams JSON-Patch updates to properties, and `tambo.component.end` finalizes the state.

4. **SSE Delivery** – Each event travels via Server-Sent Events as `data: { "type": "...", ... }` JSON payloads.

5. **State Reduction** – The React SDK's `streamReducer` processes incoming events immutably, appending text deltas to messages, updating tool call states, and merging component property patches into the thread state.

6. **UI Rendering** – React hooks like `useTamboV1SendMessage` expose the accumulated state to components, enabling real-time rendering of streaming text, tool results, and interactive UI components.

## Handling Custom AG-UI Events in Tambo

Tambo extends the standard AG-UI specification with seven custom event types defined in [`packages/backend/src/util/tambo-custom-events.ts`](https://github.com/tambo-ai/tambo/blob/main/packages/backend/src/util/tambo-custom-events.ts):

| Event Name | Purpose | Payload Structure |
|------------|---------|-------------------|
| `tambo.component.start` | Signals the beginning of a component tool call | `ComponentStartEventValue` with `messageId`, `componentId`, `componentName` |
| `tambo.component.props_delta` | Streams incremental property updates via JSON-Patch | `ComponentPropsDeltaEventValue` with `operations` array and `streamingStatus` |
| `tambo.component.state_delta` | Streams incremental state updates via JSON-Patch | `ComponentStateDeltaEventValue` with `operations` array |
| `tambo.component.end` | Finalizes component streaming with complete props/state | `ComponentEndEventValue` with `finalProps` and `finalState` |
| `tambo.run.awaiting_input` | Pauses the run pending client-side tool execution | `RunAwaitingInputEventValue` with `pendingToolCalls` |
| `tambo.message.parent` | Links messages to parent messages for MCP-style threading | `MessageParentEventValue` with `messageId` and `parentMessageId` |

The `streamReducer` in [`react-sdk/src/v1/utils/event-accumulator.ts`](https://github.com/tambo-ai/tambo/blob/main/react-sdk/src/v1/utils/event-accumulator.ts) handles these via a `handleCustomEvent` function that applies JSON-Patch operations to component state and manages the component lifecycle.

## Practical Example: Consuming AG-UI Streams

The following React component demonstrates how to consume AG-UI events using Tambo's streaming utilities:

```typescript
import { useEffect, useReducer } from "react";
import { streamReducer, createInitialState } from "@tambo-ai/react/v1";
import { handleEventStream } from "@tambo-ai/react/v1/utils/stream-handler";

export function ChatThread({ threadId, apiKey }) {
  const [state, dispatch] = useReducer(streamReducer, createInitialState());

  useEffect(() => {
    // Initialise the thread locally
    dispatch({ type: "INIT_THREAD", threadId });

    async function startRun() {
      const client = await getTamboClient({ apiKey });
      const stream = await client.threads.runs.run(threadId, {
        message: { 
          role: "user", 
          content: [{ type: "text", text: "Hello" }] 
        },
      });

      // Convert the SDK async iterable into typed AG-UI events
      for await (const ev of handleEventStream(stream, { debug: false })) {
        dispatch({ type: "EVENT", event: ev, threadId });
      }
    }

    startRun().catch(console.error);
  }, [threadId, apiKey]);

  const thread = state.threadMap[threadId]?.thread ?? { messages: [] };

  return (
    <div>
      {thread.messages.map((msg) => (
        <Message key={msg.id} data={msg} />
      ))}
    </div>
  );
}

```

In this implementation, `handleEventStream` from [`react-sdk/src/v1/utils/stream-handler.ts`](https://github.com/tambo-ai/tambo/blob/main/react-sdk/src/v1/utils/stream-handler.ts) transforms the raw SDK stream into typed `AGUIEvent` objects, while `streamReducer` from [`react-sdk/src/v1/utils/event-accumulator.ts`](https://github.com/tambo-ai/tambo/blob/main/react-sdk/src/v1/utils/event-accumulator.ts) immutably updates the React state based on each event type.

## Summary

- The **AG-UI protocol** is an open-source, event-based wire format that represents AI interactions as typed events like `RUN_STARTED`, `TEXT_MESSAGE_CONTENT`, and `TOOL_CALL_START`.
- **Tambo AI** uses AG-UI as the foundation for its v1 streaming API, transmitting events via Server-Sent Events from backend to client.
- The **React SDK** consumes these streams through `handleEventStream` in [`react-sdk/src/v1/utils/stream-handler.ts`](https://github.com/tambo-ai/tambo/blob/main/react-sdk/src/v1/utils/stream-handler.ts) and accumulates state via `streamReducer` in [`react-sdk/src/v1/utils/event-accumulator.ts`](https://github.com/tambo-ai/tambo/blob/main/react-sdk/src/v1/utils/event-accumulator.ts).
- **Custom extensions** in [`packages/backend/src/util/tambo-custom-events.ts`](https://github.com/tambo-ai/tambo/blob/main/packages/backend/src/util/tambo-custom-events.ts) enable streaming UI components with events like `tambo.component.start` and `tambo.component.props_delta` using JSON-Patch operations.
- This architecture enables **real-time, incremental UI updates** where text, tool results, and interactive components stream to the user as they are generated.

## Frequently Asked Questions

### What is the AG-UI protocol?

The AG-UI protocol is an open-source event-based wire format defined by the `@ag-ui/core` SDK. It represents conversational AI interactions as a stream of strongly typed events—such as `RUN_STARTED`, `TEXT_MESSAGE_CONTENT`, and `TOOL_CALL_END`—rather than monolithic JSON responses, enabling fine-grained streaming and real-time UI updates.

### How does Tambo AI use AG-UI for streaming?

Tambo AI implements AG-UI in its v1 API by translating LLM outputs into AG-UI events on the backend, transmitting them via Server-Sent Events (SSE), and consuming them in the React SDK. The `handleEventStream` utility in [`react-sdk/src/v1/utils/stream-handler.ts`](https://github.com/tambo-ai/tambo/blob/main/react-sdk/src/v1/utils/stream-handler.ts) converts the SSE stream into typed events, while `streamReducer` in [`react-sdk/src/v1/utils/event-accumulator.ts`](https://github.com/tambo-ai/tambo/blob/main/react-sdk/src/v1/utils/event-accumulator.ts) updates React state incrementally.

### What are Tambo's custom AG-UI events?

Tambo extends the standard AG-UI specification with custom events defined in [`packages/backend/src/util/tambo-custom-events.ts`](https://github.com/tambo-ai/tambo/blob/main/packages/backend/src/util/tambo-custom-events.ts). These include `tambo.component.start` to initialize UI components, `tambo.component.props_delta` and `tambo.component.state_delta` to stream JSON-Patch updates to component properties, `tambo.component.end` to finalize rendering, and `tambo.run.awaiting_input` to pause execution for client-side tool calls.

### Where is the AG-UI stream handling implemented in Tambo?

The primary AG-UI stream handling logic resides in two key files within the React SDK: [`react-sdk/src/v1/utils/stream-handler.ts`](https://github.com/tambo-ai/tambo/blob/main/react-sdk/src/v1/utils/stream-handler.ts) contains the `handleEventStream` generator function that parses raw SSE data into `AGUIEvent` objects, and [`react-sdk/src/v1/utils/event-accumulator.ts`](https://github.com/tambo-ai/tambo/blob/main/react-sdk/src/v1/utils/event-accumulator.ts) contains the `streamReducer` that processes these events into immutable React state updates.