NashTech Blog

Understanding AG-UI Protocol: Streamlined AI Communication

Table of Contents

What is AG-UI Protocol?

AG-UI (Agent User Interface) is a standardized protocol designed to facilitate seamless communication between AI agents and user interfaces. It provides a structured, event-driven approach to building interactive AI applications with real-time streaming capabilities.

Event-Driven Architecture

AG-UI operates on a publish-subscribe model where agents emit events that UIs can listen to and react accordingly.

Streaming Communication

Instead of waiting for complete responses, AG-UI enables real-time streaming of content as it’s generated, providing immediate user feedback.

Protocol Standardization

AG-UI defines standard event types and message structures, ensuring consistency across different implementations.

AG-UI Event System

Event Types

enum EventType {
  RUN_STARTED = "RUN_STARTED",
  RUN_FINISHED = "RUN_FINISHED",
  TEXT_MESSAGE_START = "TEXT_MESSAGE_START",
  TEXT_MESSAGE_CONTENT = "TEXT_MESSAGE_CONTENT",
  TEXT_MESSAGE_END = "TEXT_MESSAGE_END",
  TOOL_CALL_START = "TOOL_CALL_START",
  TOOL_CALL_CONTENT = "TOOL_CALL_CONTENT",
  TOOL_CALL_END = "TOOL_CALL_END",
  ERROR = "ERROR",
}

Event Flow

1. RUN_STARTED → Agent begins processing

2. TEXT_MESSAGE_START → Text response begins

3. TEXT_MESSAGE_CONTENT (multiple) → Streaming content

4. TEXT_MESSAGE_END → Text response complete

5. RUN_FINISHED → Agent processing complete

Agent Interface

interface Agent {
  run(input: RunAgentInput): RunAgent;
}

interface RunAgentInput {
  prompt: string;
  context?: any;
  sessionId?: string;
}

type RunAgent = () => Observable<BaseEvent>;

Core Concepts

What is an Agent?

An Agent in the AG-UI protocol represents an AI entity that can process user inputs and generate responses through a standardized interface. Think of it as a wrapper around your AI model (like OpenAI’s GPT) that speaks the AG-UI “language”.

Key Characteristics

Standardized Interface: All agents implement the same `run` method, ensuring consistency

Event-Driven: Agents emit events (like `TEXT_MESSAGE_START`, `TEXT_MESSAGE_CONTENT`) instead of returning complete responses

Observable-Based: Uses Observables for streaming real-time responses

Stateless: Each agent run is independent, with state managed externally

Agent Example

export class ChatbotAgent extends AbstractAgent {
  private openai: OpenAI;

  constructor(openai: OpenAI, config: ChatbotConfig = {}) {
    super();
    this.openai = openai;
    // Configure your AI model settings
  }

  /**
   * The run method of the Agent is called whenever the frontend sends a user input to the backend for processing. This happens when the user submits a message in the chat interface.
   *
   * @param {RunAgentInput} input - The input data required to run the agent.
   * @returns {Observable<BaseEvent>} - An observable that emits a stream of events during the agent's execution.
   */

  run(input: RunAgentInput): Observable<BaseEvent> {
    return new Observable((observer) => {
      // 1. Emit RUN_STARTED event
      observer.next({ type: EventType.RUN_STARTED });

      // 2. Process the input and stream responses
      this.processWithOpenAI(input, observer);

      // 3. Emit RUN_FINISHED when complete
      observer.next({ type: EventType.RUN_FINISHED });
    });
  }
}

What is RunAgentInput?

RunAgentInput is the standardized data structure that contains all the information an agent needs to process a user’s request.

Full Interface Structure:

interface RunAgentInput {
  // Conversation context
  threadId: string; // Unique identifier for the conversation thread
  runId: string; // Unique identifier for this specific run
  messages: Message[]; // Complete conversation history

  // Tool and context data
  tools?: Tool[]; // Available tools the agent can use
  context?: any[]; // Additional context data
  state?: any; // Current state information
  forwardedProps?: any; // Custom properties passed through
}

Key Properties Explained:

threadId: A unique identifier for the entire conversation. All messages in the same chat session share the same threadId.

runId: A unique identifier for this specific agent execution. Each time the user sends a message, a new runId is generated.

messages: An array containing the full conversation history, including:

interface Message {
  id: string;
  role: "user" | "assistant" | "system" | "tool";
  content: string | ContentPart[];
  toolCalls?: ToolCall[]; // For function calling
  toolCallId?: string; // For tool responses
}

tools (optional): Array of available tools/functions the agent can call:

interface Tool {
  name: string;
  description: string;
  parameters: object; // JSON Schema for parameters
}

context (optional): Additional context information that might influence the agent’s behavior.

RunAgentInput Example

// When user sends "What's the weather in Paris?"
const input: RunAgentInput = {
  threadId: "thread-abc-123",
  runId: "run-def-456",
  messages: [
    {
      id: "msg-1",
      role: "system",
      content: "You are a helpful assistant.",
    },
    {
      id: "msg-2",
      role: "user",
      content: "What's the weather in Paris?",
    },
  ],
  tools: [
    {
      name: "get_weather",
      description: "Get weather information for a location",
      parameters: {
        type: "object",
        properties: {
          location: { type: "string" },
        },
      },
    },
  ],
  context: [],
  state: null,
  forwardedProps: {},
};

// Agent processes this input and streams back events
const observable = agent.run(input); 

How They Work Together

1. Frontend collects user input and conversation history

2. RunAgentInput packages this data in a standardized format

3. Agent receives the input and processes it with your AI model

4. Agent streams response events back to the frontend

5. Frontend renders the streaming response in real-time

Frontend Communication HttpAgent

What is HttpAgent?

HttpAgent is AG-UI’s specialized HTTP client designed specifically for agent communication. HttpAgent uses Server-Sent Events (SSE) over HTTP to achieve real-time streaming while maintaining the simplicity of HTTP requests.

// AG-UI HttpAgent Approach
const agent = new HttpAgent({
  url: "/agent",
  agentId: "chatbot-agent",
  threadId: randomUUID(),
});

agent.runAgent(
  { tools: [], context: [] },
  {
    onTextMessageContentEvent: ({ event }) => {
      handleEvent(event);
    },
  }
);

Key Benefits

FeatureHttpAgent
ProtocolHTTP + Server-Sent Events
ConnectionHTTP request with streaming response
Message FormatAG-UI standardized events
State ManagementBuilt-in conversation threading
Error RecoveryHTTP retry mechanisms

Demo

We built a sample for how to build a chat bot with AG-UI at https://github.com/nashtech-garage/nt-agui-starter. You follow the readme and run it with few steps.

Reference

[AG-UI Protocol Documentation](https://github.com/ag-ui-protocol/ag-ui)

Picture of Quang Truong

Quang Truong

Line Manager at NashTech, I am a curious and motivated software engineer with a passion for creating applications that make life easier and more enjoyable.

Leave a Comment

Your email address will not be published. Required fields are marked *

Suggested Article

Scroll to Top