AG-UI · Getting Started

Quick Start

Let's bind <chat> from @threadplane/chat to an AG-UI backend in 5 minutes.

Prerequisites

Angular 20+ project with Node.js 22+. If you need setup help, see the Installation guide.

Try it first

Want to see the finished result before you build? Open the live AG-UI demo.

1
Install the packages
npm install @threadplane/chat @threadplane/ag-ui @ag-ui/client
2
Configure the provider

Add provideAgent() to your application config with your AG-UI backend URL.

// app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideAgent } from '@threadplane/ag-ui';
 
export const appConfig: ApplicationConfig = {
  providers: [
    provideAgent({ url: 'http://localhost:3000/agent' }),
  ],
};

No backend yet? Swap to provideFakeAgent({}) - it serves canned streaming responses so you can build UI offline.

3
Use in a component
import { Component, inject } from '@angular/core';
import { ChatComponent } from '@threadplane/chat';
import { injectAgent } from '@threadplane/ag-ui';
 
@Component({
  selector: 'app-streaming',
  standalone: true,
  imports: [ChatComponent],
  template: `<chat [agent]="agent" />`,
})
export class StreamingComponent {
  protected readonly agent = injectAgent();
}

That's it. The <chat> composition handles streaming messages, tool calls, errors, and submit - all bound to the AG-UI backend through the Agent contract.

  • Architecture explains how toAgent(), provideAgent(), and injectAgent() fit together.
  • Event Mapping is the backend compatibility checklist for emitted AG-UI events.
  • Fake Agent covers offline demos and frontend tests.
  • Troubleshooting is the fastest place to start when a stream does not render.
  • The @threadplane/chat Components reference covers the primitives the <chat> composition uses internally - handy if you want to compose your own layout.
  • Looking for LangGraph instead of AG-UI? See @threadplane/langgraph.

#Switching backends without changing UI

For me, the runtime-neutral Agent contract is the whole payoff: your component never learns which protocol it's talking to. The cost is a thin translation layer per adapter, but you pay it once and your UI code stops caring.

So swapping backends is a one-line change in app.config.ts, and the component code stays the same:

- import { provideAgent } from '@threadplane/langgraph';
- providers: [provideAgent({ apiUrl: '...' })],   // LangGraph
+ import { provideAgent } from '@threadplane/ag-ui';
+ providers: [provideAgent({ url: '...' })],  // AG-UI

These are two different provideAgent functions from two different packages — the import source changes along with the config key (apiUrl for LangGraph, url for AG-UI). It's not one symbol that accepts both.