# Angular Setup Guide
This guide shows how to set up CopilotKit in an Angular app — from minimal to fully configured.
---
## What Talks to What
```mermaid
graph LR
subgraph Your Angular App
DI["provideCopilotKit() DI token"]
Service["CopilotKit Service Injectable"]
Store["AgentStore Signal-based state"]
Comp["Your Components"]
end
subgraph Under the Hood
Core["CopilotKitCore Orchestrator"]
Proxy["ProxiedAgent HTTP client"]
end
subgraph Your Server
Runtime["CopilotRuntime Express / Hono"]
end
DI -->|configures| Service
Service -->|wraps| Core
Comp -->|injects| Service
Service -->|creates| Store
Store -->|wraps| Proxy
Proxy -->|HTTP POST + SSE| Runtime
```
---
## Minimal Setup
### 1. Install
```bash
npm install @copilotkit/angular
```
### 2. Configure the DI token
```typescript
// app.config.ts
import { ApplicationConfig } from "@angular/core";
import { provideCopilotKit } from "@copilotkit/angular";
export const appConfig: ApplicationConfig = {
providers: [
provideCopilotKit({
runtimeUrl: "/api/copilotkit",
}),
],
};
```
### 3. Use the service in a component
```typescript
// chat.component.ts
import { Component, inject } from "@angular/core";
import { CopilotKit } from "@copilotkit/angular";
@Component({
selector: "app-chat",
template: `
{{ msg.role }}: {{ msg.content }}
`,
})
export class ChatComponent {
private copilotKit = inject(CopilotKit);
agentStore = this.copilotKit.getAgentStore(); // default agent
async send(message: string) {
this.agentStore.addMessage({
id: crypto.randomUUID(),
role: "user",
content: message,
});
await this.copilotKit.runAgent({ agent: this.agentStore.agent });
}
}
```
That's it — the DI token creates a `CopilotKit` service backed by `CopilotKitCore`, and `AgentStore` gives you signal-based reactive state.
```mermaid
sequenceDiagram
participant Config as app.config.ts
participant Service as CopilotKit Service
participant Core as CopilotKitCore
participant Runtime as Your Server
Config->>Service: provideCopilotKit({ runtimeUrl })
Service->>Core: new CopilotKitCore(config)
Core->>Runtime: GET /info
Runtime-->>Core: Available agents
Note over Service: Ready — inject anywhere
```
---
## Angular Signals for Reactive State
`AgentStore` uses Angular signals, so your templates react to changes automatically:
```typescript
@Component({
template: `
@if (agentStore.isRunning()) {
Agent is thinking...
}
@for (msg of agentStore.messages(); track msg.id) {
{{ msg.content }}
}
{{ agentStore.state() | json }}
`,
})
export class ChatComponent {
private copilotKit = inject(CopilotKit);
agentStore = this.copilotKit.getAgentStore("my-agent");
}
```
### AgentStore Signals
| Signal | Type | What it tracks |
| ------------- | ----------- | -------------------------------------- |
| `messages()` | `Message[]` | All messages in the conversation |
| `isRunning()` | `boolean` | Whether the agent is currently running |
| `state()` | `any` | Agent state (arbitrary JSON) |
```mermaid
graph TB
subgraph AgentStore
Agent["AbstractAgent Subscribed to events"]
MS["messages() Signal<Message[]>"]
IR["isRunning() Signal<boolean>"]
ST["state() Signal<any>"]
end
Agent -->|onMessagesChanged| MS
Agent -->|onRunStarted/Finished| IR
Agent -->|onStateChanged| ST
subgraph Template
T["Your template auto-updates"]
end
MS --> T
IR --> T
ST --> T
```
---
## Registering Tools
```typescript
// In your component or service
import { CopilotKit } from "@copilotkit/angular";
import { z } from "zod";
@Component({
/* ... */
})
export class ProductComponent implements OnInit, OnDestroy {
private copilotKit = inject(CopilotKit);
ngOnInit() {
// Register a tool the agent can call
this.copilotKit.addTool({
name: "addToCart",
description: "Add a product to cart",
parameters: z.object({
productId: z.string(),
quantity: z.number().default(1),
}),
handler: async ({ productId, quantity }) => {
this.cartService.add(productId, quantity);
return `Added ${quantity} item(s)`;
},
});
}
ngOnDestroy() {
// Clean up when component is destroyed
this.copilotKit.removeTool("addToCart");
}
}
```
---
## Providing Context
```typescript
@Component({
/* ... */
})
export class DashboardComponent implements OnInit, OnDestroy {
private copilotKit = inject(CopilotKit);
private contextId?: string;
ngOnInit() {
this.contextId = this.copilotKit.addContext({
description: "Current dashboard metrics",
value: JSON.stringify({
revenue: this.metricsService.revenue(),
activeUsers: this.metricsService.activeUsers(),
}),
});
}
ngOnDestroy() {
if (this.contextId) {
this.copilotKit.removeContext(this.contextId);
}
}
}
```
---
## Tool Call Rendering
Angular uses the `AngularToolCall` type for rendering tool calls:
```typescript
import { AngularToolCall } from "@copilotkit/angular";
// Configure in provideCopilotKit
provideCopilotKit({
runtimeUrl: "/api/copilotkit",
renderToolCalls: [
{
name: "searchProducts",
// The Angular component receives the AngularToolCall
},
],
});
```
### AngularToolCall Status Flow
```mermaid
graph LR
IP["in-progress Args still streaming"]
EX["executing Handler is running"]
CO["complete Result ready"]
IP --> EX --> CO
```
| Field | Type | Description |
| -------- | -------------------------------------------- | ---------------------------------------- |
| `status` | `"in-progress" \| "executing" \| "complete"` | Current lifecycle stage |
| `name` | `string` | Tool name |
| `args` | `Partial` or `T` | Tool arguments (partial while streaming) |
| `result` | `string \| undefined` | Result (only when complete) |
---
## All Configuration Options
```typescript
// app.config.ts
import { provideCopilotKit } from "@copilotkit/angular";
provideCopilotKit({
// Required
runtimeUrl: "/api/copilotkit",
// Authentication
headers: { Authorization: "Bearer token" },
// Custom properties forwarded to agents
properties: { userId: "123", plan: "pro" },
// Local agents for development
agents: { test: myTestAgent },
// Tools (can also add via service)
tools: [
{
name: "myTool",
parameters: z.object({ input: z.string() }),
handler: async ({ input }) => `Processed: ${input}`,
},
],
// Tool call rendering
renderToolCalls: [
/* ... */
],
// Frontend tools
frontendTools: [
/* ... */
],
// Human-in-the-loop
humanInTheLoop: [
/* ... */
],
});
```
```mermaid
graph TB
subgraph "provideCopilotKit() Config"
direction TB
subgraph Required
URL["runtimeUrl"]
end
subgraph "Optional: Auth"
H["headers"]
end
subgraph "Optional: Tools & Rendering"
T["tools"]
FT["frontendTools"]
RTC["renderToolCalls"]
HIL["humanInTheLoop"]
end
subgraph "Optional: Other"
P["properties"]
AG["agents"]
end
end
```
---
## Full Example: Dashboard App
```typescript
// app.config.ts
import { ApplicationConfig } from "@angular/core";
import { provideCopilotKit } from "@copilotkit/angular";
export const appConfig: ApplicationConfig = {
providers: [
provideCopilotKit({
runtimeUrl: "/api/copilotkit",
headers: { Authorization: `Bearer ${getToken()}` },
}),
],
};
```
```typescript
// dashboard.component.ts
import { Component, inject, OnInit, OnDestroy } from "@angular/core";
import { CopilotKit } from "@copilotkit/angular";
import { z } from "zod";
@Component({
selector: "app-dashboard",
template: `
@if (agentStore.isRunning()) {
Agent is thinking...
}
@for (msg of agentStore.messages(); track msg.id) {