2025-12-18 19:09:14 +01:00
# CopilotKit for Angular
2026-07-22 11:05:49 -07:00
First-party Angular bindings for CopilotKit core and AG-UI agents. The package
ships standalone chat, popup, and sidebar components as well as signal-based
headless APIs, tool and activity renderers, threads, memories, interrupts,
attachments, A2UI, Open Generative UI, and opt-in MCP Apps support.
2025-12-18 19:09:14 +01:00
## Installation
``` bash
# npm
2026-06-18 13:49:35 -07:00
npm install @copilotkit/angular
2025-12-18 19:09:14 +01:00
```
2026-06-09 09:46:25 -05:00
Peer dependencies you provide in your app:
2026-07-22 11:05:49 -07:00
- `@angular/core` and `@angular/common` (20, 21, or 22)
2026-01-21 07:04:53 -08:00
- `@angular/cdk` (match your Angular major)
2026-07-22 11:05:49 -07:00
- `rxjs` 7.8 or newer
The exact versions exercised by the packed-consumer release matrix are stored
in `package.json` under `copilotkit.angularSupport` . The library is compiled at
the Angular 20 support floor and installed with strict peer checking against
all three supported majors.
2025-12-18 19:09:14 +01:00
2026-02-26 07:25:00 -08:00
## Quick start
2025-12-18 19:09:14 +01:00
2026-01-21 07:04:53 -08:00
### 1) Provide CopilotKit
Configure runtime and tools in your app config:
2025-12-18 19:09:14 +01:00
2026-02-24 09:52:45 -08:00
``` ts
2026-02-26 07:25:00 -08:00
import { ApplicationConfig } from "@angular/core" ;
2026-06-18 13:49:35 -07:00
import { provideCopilotKit } from "@copilotkit/angular" ;
2025-12-18 19:09:14 +01:00
export const appConfig : ApplicationConfig = {
providers : [
2026-02-24 09:52:45 -08:00
provideCopilotKit ( {
runtimeUrl : "http://localhost:3001/api/copilotkit" ,
2026-01-21 07:04:53 -08:00
headers : { Authorization : "Bearer ..." } ,
properties : { app : "demo" } ,
2025-12-18 19:09:14 +01:00
} ) ,
] ,
} ;
```
2026-01-21 07:04:53 -08:00
### 2) Build a custom UI with `injectAgentStore`
2025-12-18 19:09:14 +01:00
2026-01-21 07:04:53 -08:00
``` ts
2026-02-26 07:25:00 -08:00
import { Component , inject , signal } from "@angular/core" ;
import { Message } from "@ag-ui/client" ;
2026-06-18 13:49:35 -07:00
import { CopilotKit , injectAgentStore } from "@copilotkit/angular" ;
2026-03-28 23:07:35 +00:00
import { randomUUID } from "@copilotkit/shared" ;
2026-01-21 07:04:53 -08:00
@Component ( {
template : `
2026-02-26 07:25:00 -08:00
@for (let message of messages(); track message.id) {
<div>
<em>{{ message.role }}</em>
<p>{{ message.content }}</p>
2026-01-21 07:04:53 -08:00
</div>
2026-02-26 07:25:00 -08:00
}
<input
[value]="input()"
(input)="input.set( $ any( $ event.target).value)"
(keyup.enter)="send()"
/>
<button (click)="send()" [disabled]="store().isRunning()">Send</button>
2026-01-21 07:04:53 -08:00
` ,
} )
export class HeadlessChatComponent {
2026-02-26 07:25:00 -08:00
readonly copilotKit = inject ( CopilotKit ) ;
readonly store = injectAgentStore ( "default" ) ;
readonly messages = this . store ( ) . messages ;
readonly input = signal ( "" ) ;
2026-01-21 07:04:53 -08:00
async send() {
const content = this . input ( ) . trim ( ) ;
if ( ! content ) return ;
const agent = this . store ( ) . agent ;
2026-02-26 07:25:00 -08:00
agent . addMessage ( {
id : randomUUID ( ) ,
role : "user" ,
content ,
} ) ;
2026-01-21 07:04:53 -08:00
this . input . set ( "" ) ;
2026-02-26 07:25:00 -08:00
await this . copilotKit . core . runAgent ( { agent } ) ;
2026-01-21 07:04:53 -08:00
}
}
2025-12-18 19:09:14 +01:00
```
2026-01-21 07:04:53 -08:00
The `agent` is an AG-UI `AbstractAgent` . Refer to your AG-UI agent implementation for available methods and message formats.
## Core configuration
### `CopilotKitConfig`
2025-12-18 19:09:14 +01:00
2026-01-21 07:04:53 -08:00
`provideCopilotKit` accepts a `CopilotKitConfig` object:
2025-12-18 19:09:14 +01:00
2026-01-21 07:04:53 -08:00
``` ts
export interface CopilotKitConfig {
runtimeUrl? : string ;
headers? : Record < string , string > ;
2026-01-14 09:06:54 -08:00
licenseKey? : string ;
2026-01-21 07:04:53 -08:00
properties? : Record < string , unknown > ;
agents? : Record < string , AbstractAgent > ;
2026-07-22 11:05:49 -07:00
selfManagedAgents? : Record < string , AbstractAgent > ;
2026-01-21 07:04:53 -08:00
tools? : ClientTool [ ] ;
renderToolCalls? : RenderToolCallConfig [ ] ;
2026-07-22 11:05:49 -07:00
renderActivityMessages? : RenderActivityMessageConfig [ ] ;
suggestionsConfig? : SuggestionsConfig [ ] ;
2026-01-21 07:04:53 -08:00
frontendTools? : FrontendToolConfig [ ] ;
humanInTheLoop? : HumanInTheLoopConfig [ ] ;
2026-07-22 11:05:49 -07:00
defaultToolRendering? : boolean ;
a2ui? : A2UIConfig ;
openGenerativeUI? : OpenGenerativeUIConfig ;
2026-01-21 07:04:53 -08:00
}
```
2025-12-18 19:09:14 +01:00
2026-01-21 07:04:53 -08:00
- `runtimeUrl` : URL to your CopilotKit runtime.
- `headers` : Default headers sent to the runtime.
- `properties` : Arbitrary props forwarded to agent runs.
- `agents` : Local, in-browser agents keyed by `agentId` .
2026-07-22 11:05:49 -07:00
- `selfManagedAgents` : AG-UI agents managed directly by the application.
2026-01-21 07:04:53 -08:00
- `tools` : Tool definitions advertised to the runtime (no handler).
- `renderToolCalls` : Components to render tool calls in the UI.
2026-07-22 11:05:49 -07:00
- `renderActivityMessages` : Components to render AG-UI activity messages.
- `suggestionsConfig` : Static or runtime-generated chat suggestions.
2026-01-21 07:04:53 -08:00
- `frontendTools` : Client-side tools with handlers.
- `humanInTheLoop` : Tools that pause for user input.
2026-07-22 11:05:49 -07:00
- `defaultToolRendering` : Opt in to the text-only renderer for unknown tools.
It is disabled by default so missing renderers remain visible integration
errors rather than silently changing the experience.
- `a2ui` : Theme, catalog, schema, loading UI, and recovery policy for A2UI.
- `openGenerativeUI` : Sandboxed UI functions and optional design guidance.
2025-12-18 19:09:14 +01:00
2026-01-21 07:04:53 -08:00
### Injection helpers
2025-12-18 19:09:14 +01:00
2026-01-21 07:04:53 -08:00
- `provideCopilotKit(config)` : Provider for `CopilotKitConfig` .
2025-12-18 19:09:14 +01:00
2026-01-21 07:04:53 -08:00
## `CopilotKit` service
2025-12-18 19:09:14 +01:00
2026-01-21 07:04:53 -08:00
### Readonly signals
2025-12-18 19:09:14 +01:00
2026-01-21 07:04:53 -08:00
- `agents` : `Signal<Record<string, AbstractAgent>>`
- `runtimeConnectionStatus` : `Signal<CopilotKitCoreRuntimeConnectionStatus>`
- `runtimeUrl` : `Signal<string | undefined>`
- `runtimeTransport` : `Signal<CopilotRuntimeTransport>` (`"rest" | "single"` )
- `headers` : `Signal<Record<string, string>>`
- `toolCallRenderConfigs` : `Signal<RenderToolCallConfig[]>`
- `clientToolCallRenderConfigs` : `Signal<FrontendToolConfig[]>`
- `humanInTheLoopToolRenderConfigs` : `Signal<HumanInTheLoopConfig[]>`
2025-12-18 19:09:14 +01:00
2026-01-21 07:04:53 -08:00
### Methods
2025-12-18 19:09:14 +01:00
2026-01-21 07:04:53 -08:00
- `getAgent(agentId: string): AbstractAgent | undefined`
- `addFrontendTool(config: FrontendToolConfig & { injector: Injector }): void`
- `addRenderToolCall(config: RenderToolCallConfig): void`
- `addHumanInTheLoop(config: HumanInTheLoopConfig): void`
- `removeTool(toolName: string, agentId?: string): void`
- `updateRuntime(options: { runtimeUrl?: string; runtimeTransport?: CopilotRuntimeTransport; headers?: Record<string,string>; properties?: Record<string, unknown>; agents?: Record<string, AbstractAgent>; }): void`
### Advanced
- `core` : The underlying `CopilotKitCore` instance.
## Agents
### `injectAgentStore`
``` ts
const store = injectAgentStore ( "default" ) ;
// or: injectAgentStore(signal(agentId))
2026-02-24 09:52:45 -08:00
```
2025-12-18 19:09:14 +01:00
2026-01-21 07:04:53 -08:00
Returns a `Signal<AgentStore>` . The store exposes:
- `agent` : `AbstractAgent`
- `messages` : `Signal<Message[]>`
- `state` : `Signal<any>`
- `isRunning` : `Signal<boolean>`
- `teardown()` : Clean up subscriptions
If the agent is not available locally but a `runtimeUrl` is configured, a proxy agent is created while the runtime connects. If the agent still cannot be resolved, an error is thrown that includes the configured runtime and known agent IDs.
### `CopilotkitAgentFactory`
2026-02-24 09:52:45 -08:00
2026-01-21 07:04:53 -08:00
Advanced factory for creating `AgentStore` signals. Most apps should use `injectAgentStore` instead.
2026-02-24 09:52:45 -08:00
2026-01-21 07:04:53 -08:00
## Agent context
### `connectAgentContext`
Connect AG-UI context to the runtime (auto-cleanup when the effect is destroyed):
2026-02-24 09:52:45 -08:00
``` ts
2026-06-18 13:49:35 -07:00
import { connectAgentContext } from "@copilotkit/angular" ;
2025-12-18 19:09:14 +01:00
2026-01-21 07:04:53 -08:00
connectAgentContext ( {
description : "User preferences" ,
value : { theme : "dark" } ,
} ) ;
```
2026-02-24 09:52:45 -08:00
2026-01-21 07:04:53 -08:00
You must call it within an injection context (e.g., inside a component constructor or `runInInjectionContext` ), or pass an explicit `Injector` :
``` ts
connectAgentContext ( contextSignal , { injector } ) ;
2025-12-18 19:09:14 +01:00
```
2026-01-21 07:04:53 -08:00
## Tools and tool rendering
2026-02-24 09:52:45 -08:00
2026-01-21 07:04:53 -08:00
### Types
2026-02-24 09:52:45 -08:00
``` ts
2026-01-21 07:04:53 -08:00
export interface RenderToolCallConfig < Args > {
name : string ; // tool name, or "*" for wildcard
args : z.ZodType < Args > ; // Zod schema for args
component : Type < ToolRenderer < Args > > ;
agentId? : string ; // optional agent scope
}
2025-12-18 19:09:14 +01:00
2026-01-21 07:04:53 -08:00
export interface FrontendToolConfig < Args > {
name : string ;
description : string ;
parameters : z.ZodType < Args > ;
component? : Type < ToolRenderer < Args > > ; // optional UI renderer
2026-02-26 07:25:00 -08:00
handler : ( args : Args , context : FrontendToolHandlerContext ) = > Promise < unknown > ;
2026-01-21 07:04:53 -08:00
agentId? : string ;
}
2026-02-24 09:52:45 -08:00
2026-01-21 07:04:53 -08:00
export interface HumanInTheLoopConfig < Args > {
name : string ;
description : string ;
parameters : z.ZodType < Args > ;
component : Type < HumanInTheLoopToolRenderer < Args > > ;
agentId? : string ;
2025-12-18 19:09:14 +01:00
}
2026-01-21 07:04:53 -08:00
export type ClientTool < Args > = Omit < FrontendTool < Args > , \ "handler\" > & {
renderer? : Type < ToolRenderer < Args > > ;
} ;
2025-12-18 19:09:14 +01:00
```
2026-01-21 07:04:53 -08:00
Renderer components receive a signal:
2025-12-18 19:09:14 +01:00
2026-01-21 07:04:53 -08:00
``` ts
export interface ToolRenderer < Args > {
toolCall : Signal < AngularToolCall < Args > > ;
}
2025-12-18 19:09:14 +01:00
2026-01-21 07:04:53 -08:00
export interface HumanInTheLoopToolRenderer < Args > {
toolCall : Signal < HumanInTheLoopToolCall < Args > > ; // includes respond(result)
}
```
2025-12-18 19:09:14 +01:00
2026-01-21 07:04:53 -08:00
`AngularToolCall` / `HumanInTheLoopToolCall` expose `args` , `status` (`"in-progress" | "executing" | "complete"` ), and `result` .
2025-12-18 19:09:14 +01:00
2026-01-21 07:04:53 -08:00
### Register tools with DI
These helpers auto-remove tools when the current injection context is destroyed:
Call them from an injection context (e.g., a component constructor, directive, or `runInInjectionContext` ).
2025-12-18 19:09:14 +01:00
2026-02-24 09:52:45 -08:00
``` ts
2026-02-26 07:25:00 -08:00
import {
registerFrontendTool ,
registerRenderToolCall ,
registerHumanInTheLoop ,
2026-06-18 13:49:35 -07:00
} from "@copilotkit/angular" ;
2026-02-24 09:52:45 -08:00
import { z } from "zod" ;
2025-12-18 19:09:14 +01:00
2026-01-21 07:04:53 -08:00
registerFrontendTool ( {
name : "lookup" ,
description : "Fetch a record" ,
parameters : z.object ( { id : z.string ( ) } ) ,
handler : async ( { id } ) = > ( { id , ok : true } ) ,
} ) ;
registerRenderToolCall ( {
name : "*" , // wildcard renderer
args : z.any ( ) ,
component : MyToolCallRenderer ,
} ) ;
registerHumanInTheLoop ( {
name : "approval" ,
description : "Request approval" ,
parameters : z.object ( { reason : z.string ( ) } ) ,
component : ApprovalRenderer ,
} ) ;
```
2025-12-18 19:09:14 +01:00
2026-01-21 07:04:53 -08:00
### Configure tools in `provideCopilotKit`
``` ts
2026-02-24 09:52:45 -08:00
provideCopilotKit ( {
2026-02-26 07:25:00 -08:00
frontendTools : [
/* FrontendToolConfig[] */
] ,
renderToolCalls : [
/* RenderToolCallConfig[] */
] ,
humanInTheLoop : [
/* HumanInTheLoopConfig[] */
] ,
tools : [
/* ClientTool[] */
] ,
2025-12-18 19:09:14 +01:00
} ) ;
```
2026-01-21 07:04:53 -08:00
`tools` are advertised to the runtime. If you include `renderer` + `parameters` on a `ClientTool` , CopilotKit will also register a renderer for tool calls.
2026-07-22 11:05:49 -07:00
## Prebuilt UI
All UI exports are standalone Angular components. Import the component classes
directly and import `@copilotkit/angular/styles.css` once in the application's
global stylesheet.
### Full-page chat
``` ts
import { Component } from "@angular/core" ;
import { CopilotChat } from "@copilotkit/angular" ;
@Component ( {
selector : "app-assistant" ,
imports : [ CopilotChat ] ,
template : ` <copilot-chat [agentId]="'default'" /> ` ,
} )
export class AssistantComponent { }
```
Use `CopilotPopup` for a floating dialog and `CopilotSidebar` for responsive
overlay or docked presentation. Their `open` inputs are model signals, so
`[(open)]` supports controlled application state. Both include focus trapping,
Escape handling, focus restoration, accessible dialog naming, reduced-motion
behavior, and safe-area-aware mobile layouts.
``` ts
import { Component , signal } from "@angular/core" ;
import { CopilotPopup , CopilotSidebar } from "@copilotkit/angular" ;
@Component ( {
imports : [ CopilotPopup , CopilotSidebar ] ,
template : `
<copilot-popup [(open)]="popupOpen" title="Support assistant" />
<copilot-sidebar
[(open)]="sidebarOpen"
mode="docked"
position="right"
title="Workspace assistant"
/>
` ,
} )
export class AssistantSurfacesComponent {
readonly popupOpen = signal ( false ) ;
readonly sidebarOpen = signal ( false ) ;
}
```
`CopilotChatView` , message, input, toolbar, button, attachment, and slot
components are supported public customization primitives. See
[`API.md` ](./API.md ) for the exhaustive export inventory; use the higher-level
components unless you are replacing part of the default composition.
2026-01-21 07:04:53 -08:00
## `RenderToolCalls` component
`RenderToolCalls` renders tool call components under an assistant message based on registered render configs.
``` html
< copilot-render-tool-calls
[ message ] = " assistantMessage "
[ messages ] = " messages "
[ isLoading ] = " isRunning "
> < / copilot-render-tool-calls >
```
Inputs:
2025-12-18 19:09:14 +01:00
2026-01-21 07:04:53 -08:00
- `message` : `AssistantMessage` (must include `toolCalls` )
- `messages` : full `Message[]` list (used to find tool results)
- `isLoading` : whether the agent is currently running
2025-12-18 19:09:14 +01:00
2026-01-21 07:04:53 -08:00
Tool arguments are parsed with `partialJSONParse` , so incomplete JSON during streaming still renders.
## Runtime notes
- Set `runtimeUrl` to your CopilotKit runtime endpoint.
- If you need to change runtime settings at runtime, call `CopilotKit.updateRuntime(...)` .
- `runtimeTransport` supports `"rest"` or `"single"` (SSE single-stream transport).
2026-07-22 11:05:49 -07:00
## Activity renderers and generative UI
Register application activity renderers with `registerRenderActivityMessage`
or the `renderActivityMessages` provider option. Application registrations
take precedence over optional built-ins.
- A2UI is enabled when the runtime advertises the capability or when
`a2ui.catalog` is supplied. An explicit catalog enables its renderers and
agent context even when runtime `/info` does not advertise A2UI, matching the
React provider contract. Configure recovery exposure independently of
server-provided lifecycle content.
- Open Generative UI is enabled with `openGenerativeUI: { ... }` . Generated UI
runs in an isolated WebSandbox; expose only narrowly scoped
`sandboxFunctions` and never place credentials in browser configuration.
- MCP Apps is intentionally a secondary entry point. Add
`provideMCPApps()` to application providers and import advanced host APIs
from `@copilotkit/angular/mcp-apps` . MCP resource and tool requests travel
through the selected AG-UI agent; the browser provider does not accept a
2026-07-23 08:51:34 -07:00
server URL. The renderer uses the same inline `srcdoc` sandbox, sandbox
permissions, and resource-domain CSP as the React SDK.
2026-07-22 11:05:49 -07:00
## Lifecycle and cleanup
Call `injectAgentStore` , `connectAgentContext` , `registerFrontendTool` ,
`registerRenderToolCall` , `registerRenderActivityMessage` , `injectInterrupt` ,
`injectThreads` , and `injectMemories` from an Angular injection context. The
helpers bind subscriptions, effects, timers, runtime registrations, and
observers to the owning `DestroyRef` . Changing a signal-based agent ID tears
down the previous agent subscription before connecting the replacement.
Do not create these helpers in module-level code or cache an injected
controller beyond the lifetime of its injector. `AgentStore.teardown()` is
public for advanced manually constructed stores; stores returned by
`injectAgentStore` are cleaned up automatically and should not need a manual
call.
Application-owned asynchronous work remains application-owned. Cancel fetches
or other side effects started by a frontend-tool handler when its host is
destroyed, and do not resolve an interrupt after its controller has left the
view.
## SSR, hydration, and zoneless Angular
The package is designed for standalone, OnPush, signal-based applications and
is tested with `provideZonelessChangeDetection()` . No Zone.js dependency is
required. Keep application state in signals or Angular outputs so zoneless
change detection can observe updates.
Browser-only DOM setup is deferred to render lifecycle hooks or guarded by the
platform where the package owns it. For SSR and hydration:
- provide the same CopilotKit configuration and initial `open` /`agentId`
values on the server and first client render;
- do not access returned agents or run tools during server rendering;
- make runtime URLs absolute when the server and browser use different
origins, or proxy a same-origin `/api/copilotkit` endpoint;
- enable A2UI, Open Generative UI, audio recording, and MCP Apps in the browser;
their interactive sandboxes, custom elements, media APIs, and iframes become
active after hydration;
- avoid branching the component tree on `window` before hydration. Use Angular
platform guards and `afterNextRender` for application-owned browser work.
## Public API contract
[`API.md` ](./API.md ) lists every supported export from the root and MCP Apps
entry points and identifies the single internal extension token. A package test
compares that inventory to TypeScript's resolved entry-point exports so a new
public symbol cannot be introduced without documentation.