AG-UI · Getting Started

Installation

#Prerequisites

  • Angular 20 or later
  • Node.js 22+
  • An AG-UI-compatible backend running locally or remotely (CrewAI, Mastra, Microsoft Agent Framework, AG2, Pydantic AI, AWS Strands, CopilotKit runtime, or your own subclass of AbstractAgent)

#Install packages

npm install @threadplane/chat @threadplane/ag-ui @ag-ui/client

@threadplane/chat provides the chat UI primitives. @threadplane/ag-ui provides the adapter that wires an AG-UI backend into the Agent contract those primitives consume.

#Peer Dependencies

@threadplane/ag-ui declares the following peer dependencies:

PackageVersion
@threadplane/chat*
@threadplane/licensing*
@angular/core^20.0.0 || ^21.0.0
@ag-ui/client*
rxjs~7.8.0

#Configure the provider

In your app config:

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

provideAgent accepts:

OptionTypeDescription
urlstringRequired. AG-UI backend HTTP/SSE endpoint.
agentIdstringOptional. Identifies a specific agent on the backend.
threadIdstringOptional. Resume an existing conversation thread.
headersRecord<string, string>Optional. Custom request headers (auth, tracing).
telemetryAgentRuntimeTelemetrySink | falseOptional. App-owned telemetry sink — opt-in, emits nothing unless supplied. See @threadplane/telemetry.

#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();
}

#No backend yet?

Use the FakeAgent for offline demos:

import { provideFakeAgent } from '@threadplane/ag-ui';
 
export const appConfig: ApplicationConfig = {
  providers: [
    provideFakeAgent({
      tokens: ['Hello', ' from', ' a', ' fake', ' agent.'],
      reasoningTokens: ['Thinking', ' it', ' over...'],
      delayMs: 60,
    }),
  ],
};

FakeAgent extends AbstractAgent and emits a canned RUN_STARTED -> TEXT_MESSAGE_START -> TEXT_MESSAGE_CONTENT x N -> TEXT_MESSAGE_END -> RUN_FINISHED sequence. It's a drop-in replacement for provideAgent({ url }) while you're prototyping.

provideFakeAgent accepts:

OptionTypeDescription
tokensstring[]Optional. Tokens streamed back as the assistant reply.
reasoningTokensstring[]Optional. Reasoning chunks emitted before the text reply (defaults to []).
delayMsnumberOptional. Milliseconds between successive token emissions (defaults to 60).

#Custom transport

If you have a backend that speaks AG-UI but not over HTTP, subclass AbstractAgent directly and feed it to toAgent:

import { AbstractAgent, type RunAgentInput, type BaseEvent } from '@ag-ui/client';
import { Observable } from 'rxjs';
import { toAgent } from '@threadplane/ag-ui';
 
class MyCustomAgent extends AbstractAgent {
  protected run(input: RunAgentInput): Observable<BaseEvent> {
    // Your custom transport (WebSocket, in-process worker, etc.)
    // emits BaseEvent events.
  }
}
 
const agent = toAgent(new MyCustomAgent());