AG-UI ยท API Reference

injectAgent()

injectAgent() retrieves the AG-UI agent from Angular's dependency injection container. Call it in an Angular injection context โ€” typically as a component field initializer. The returned object exposes Angular Signals for reactive UI state and async methods for user actions.

Configuration is supplied globally via provideAgent() โ€” injectAgent() itself takes no arguments.

import { injectAgent } from '@threadplane/ag-ui';
 
readonly chat = injectAgent();
 
await this.chat.submit({ message: 'Hello' });

In practice you rarely call submit() yourself โ€” you hand the agent to the <chat> composition from @threadplane/chat, which drives streaming, tool calls, errors, and submit for you:

import { ChangeDetectionStrategy, Component } from '@angular/core';
import { ChatComponent } from '@threadplane/chat';
import { injectAgent } from '@threadplane/ag-ui';
 
@Component({
  selector: 'app-chat',
  standalone: true,
  imports: [ChatComponent],
  template: `<chat [agent]="agent" />`,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ChatPage {
  protected readonly agent = injectAgent();
}

Pair it with provideAgent() at bootstrap to configure the agent endpoint:

import { bootstrapApplication } from '@angular/platform-browser';
import { provideAgent } from '@threadplane/ag-ui';
import { AppComponent } from './app/app.component';
 
bootstrapApplication(AppComponent, {
  providers: [
    provideAgent({ url: 'http://localhost:8000/my-agent' }),
  ],
});

#Runtime-neutral surface

These fields are stable across runtime adapters and are what chat components consume.

FieldTypeDescription
messages()Message[]Chat messages with role, content, optional toolCallIds, citations, and reasoning.
status()'idle' | 'running' | 'error'UI lifecycle status.
isLoading()booleanConvenience signal for active streaming.
error()unknownLatest runtime error, when present.
toolCalls()ToolCall[]Tool calls projected into the chat contract.
state()Record<string, unknown>Latest agent state projected as a plain object.
interrupt()AgentInterrupt | undefinedCurrent interrupt, when the backend pauses for human input.
events$Observable<AgentEvent>Runtime-neutral observable of transient events (state_update / custom). Subscribe for side-effects; not a signal.
submit(input, opts?)Promise<void>Submit a user message or resume payload.
stop()Promise<void>Abort the active run.
regenerate(index)Promise<void>Remove the assistant message at index and rerun from the preceding user message.

#AG-UI-specific surface

The AG-UI adapter extends the neutral Agent contract with AG-UI-specific protocol surfaces:

FieldTypeDescription
customEvents()CustomStreamEvent[]Custom events emitted by the backend during a run. Accumulates per run; resets on each new submit().
clientToolsClientToolsCapabilityBrowser client-tool catalog, pending calls, and result resolution used by <chat [clientTools]>.
subagents()Map<string, Subagent>ACTIVITY_* entries with activityType: 'subagent', projected to the neutral subagent contract and keyed by messageId.

injectAgent() returns the AgUiAgent type โ€” the neutral Agent contract plus these AG-UI-specific fields โ€” so they are reachable directly, no cast required:

import { injectAgent } from '@threadplane/ag-ui';
 
const chat = injectAgent();
chat.customEvents(); // CustomStreamEvent[]
chat.subagents(); // Map<string, Subagent>

The chat a2ui bridge reads customEvents to light up live generative-UI streaming when your backend emits a2ui-partial events. The consuming side is documented in chat's A2UI overview. See the Custom Events guide for backend wiring details.

Don't confuse customEvents() with the neutral events$ listed above. Each CUSTOM event is fanned out to both: events$ is the runtime-neutral Observable<AgentEvent> you subscribe to for transient side-effects (telemetry, toasts), while customEvents() is the AG-UI-specific signal that accumulates CustomStreamEvent[] as a per-run snapshot for reactive rendering. See the Event Mapping reference for the full fan-out.

#Submit and resume

Use the runtime-neutral submit shape for normal chat input:

await chat.submit({ message: 'Summarize this document' });

Resume an interrupt by passing a resume payload:

await chat.submit({ resume: { approved: true } });

#Regenerate semantics

regenerate(assistantMessageIndex) has replace semantics: it keeps the user message before the selected assistant message, removes the selected assistant message and all later messages, syncs the rollback to the AG-UI source, then reruns with no new user message appended.

await chat.regenerate(3);

The method throws when the selected index is not an assistant message, when no preceding user message exists, or while another response is already loading.

Injection context required

injectAgent() must be called during construction, inside an injection context (e.g. a component constructor, field initializer, or a function passed to runInInjectionContext). Calling it outside an injection context will throw.

#What's Next

injectAgentfunction

Injects the AG-UI agent from Angular's dependency injection container. Use this in components or services provided via `provideAgent()` (or `provideFakeAgent()`). Returns an `AgUiAgent` โ€” the runtime-neutral `Agent` contract plus the AG-UI-specific `customEvents` signal โ€” so `customEvents` is reachable directly, without casting. **Typed state via AgentRef.** Pass the same ref that was supplied to `provideAgent(ref, โ€ฆ)` to carry the state type through DI without repeating the generic at every call site. The no-arg form defaults to `AgUiAgent<Record<string, unknown>>`.

injectAgent(): AgUiAgent<>

Returns

AgUiAgent<>

Examples

const agent = injectAgent(TRIP); // AgUiAgent<TripState>