Installation
Supported Angular majors: 20, 21, and 22.
Use a Node.js version supported by the selected Angular major. Angular 22 supports Node.js ^22.22.3, ^24.15.0, or ^26.0.0. See the Angular compatibility matrix.
Prerequisites
- Angular 20, 21, or 22
- An AG-UI-compatible backend running locally or remotely (CrewAI, Mastra, Microsoft Agent Framework, AG2, Pydantic AI, AWS Strands, or your own subclass of
AbstractAgent)
Install packages
npm install @threadplane/chat @threadplane/ag-ui @ag-ui/client @ag-ui/core marked@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.
marked is the required markdown parser peer used by @threadplane/chat when assistant messages render through <chat>.
Peer Dependencies
@threadplane/ag-ui declares the following peer dependencies:
| Package | Version |
|---|---|
@threadplane/chat | 0.0.66 |
@threadplane/telemetry | ^0.0.66 |
@angular/core | ^20.0.0 || ^21.0.0 || ^22.0.0 |
@ag-ui/client | ^1.0.1 |
@ag-ui/core | ^1.0.1 |
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:
| Option | Type | Description |
|---|---|---|
url | string | Required. AG-UI backend HTTP/SSE endpoint. |
agentId | string | Optional. Identifies a specific agent on the backend. |
threadId | string | Optional. Resume an existing conversation thread. |
headers | Record<string, string> | Optional. Custom request headers (auth, tracing). |
telemetry | AgentRuntimeTelemetrySink | false | Optional. App-owned sink for runtime lifecycle events. |
Use in a component
import { Component } 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 is a drop-in replacement for the ref-less provideAgent({ url }) while you are prototyping.
provideFakeAgent accepts:
| Option | Type | Description |
|---|---|---|
tokens | string[] | Optional. Tokens streamed back as the assistant reply. |
reasoningTokens | string[] | Optional. Reasoning chunks emitted before the text reply (defaults to []). |
delayMs | number | Optional. 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 {
run(input: RunAgentInput): Observable<BaseEvent> {
// Your custom transport (WebSocket, in-process worker, etc.)
// emits BaseEvent events.
return new Observable<BaseEvent>((observer) => {
observer.complete();
});
}
}
const agent = toAgent(new MyCustomAgent());