# CopilotKit — Complete Developer Guide

> This guide is written for developers who are hearing about CopilotKit for the first time. Read it top to bottom once — by the end you will understand every concept, every component, and every hook, and you will know exactly what to write and why.

---

## Table of Contents

1. [The Problem CopilotKit Solves](#1-the-problem-copilotkit-solves)
2. [What is CopilotKit?](#2-what-is-copilotkit)
3. [Core Concepts You Must Understand First](#3-core-concepts-you-must-understand-first)
4. [Two Ways to Deploy CopilotKit](#4-two-ways-to-deploy-copilotkit)
5. [Agent Backend Integration](#5-agent-backend-integration)
6. [Installation](#6-installation)
7. [Component Reference](#7-component-reference)
8. [Hook Reference](#8-hook-reference)
9. [Quick Decision Guide](#9-quick-decision-guide)
10. [What CopilotKit Does NOT Do](#10-what-copilotkit-does-not-do)

---

## 1. The Problem CopilotKit Solves

Imagine you want to add an AI chat assistant to your React app that talks to your own backend agent. Without any framework, here is what you would have to build from scratch:

**On the frontend:**

- An SSE connection to stream the response word-by-word
- A parser for each type of streaming event (text chunk, tool call start, tool call result, run complete, error)
- React state management for messages, loading state, and tool call state
- A chat UI: input box, message bubbles, markdown rendering, copy button, stop button, regenerate button, auto-scroll, mobile layout
- Thread management: generating thread IDs, storing them, switching between conversations
- Suggestion chips, image upload, human-in-the-loop confirmations

**On the backend:**

- A protocol for emitting structured streaming events so the frontend knows what each chunk means
- An agent discovery endpoint so the frontend knows which agents are available

That is easily 1,000+ lines of boilerplate before you write a single line of actual product logic.

CopilotKit is the framework that replaces all of that. You write your agent logic, CopilotKit handles everything else.

---

## 2. What is CopilotKit?

CopilotKit is a **React framework** (plus backend adapters) that connects your frontend to an AI agent and manages the entire conversation lifecycle.

It gives you:

- **Pre-built chat UI components** — drop in `<CopilotChat>` and you have a full chat interface
- **SSE streaming** — the connection to your backend is opened, parsed, and managed for you
- **Message state** — React state is kept in sync with the stream automatically
- **Tool call rendering** — when your agent calls a tool, CopilotKit shows it inline in the chat
- **Threading** — multi-conversation management with a single hook
- **Context injection** — pass app state to the agent with `useCopilotReadable`
- **Backend adapters** — for PydanticAI, LangGraph, OpenAI Agents, CrewAI, and custom frameworks

The mental model is simple: **you write the agent, CopilotKit handles the UI and the wire between them.**

---

## 3. Core Concepts You Must Understand First

Before looking at any code, understand these five concepts. Everything else in CopilotKit is built on top of them.

---

### 3.1 Agent

An **agent** is your AI backend. It receives a list of messages, runs an LLM (like GPT-4o), optionally calls tools (functions that query databases, call APIs, etc.), and produces a text response.

CopilotKit is **not** the agent. CopilotKit is the layer between your React app and the agent. You write the agent yourself using PydanticAI, LangGraph, or any other framework, and CopilotKit connects the frontend to it.

```
[React App]  <--  CopilotKit (the bridge)  -->  [Your Agent Backend]
```

An agent in CopilotKit is identified by a **name** (e.g. `enterprise_brain`). You declare this name in two places:

1. In your backend's `/info` endpoint — so the frontend knows the agent exists
2. In the `agent` prop on `<CopilotKit>` — so the frontend sends requests to the right agent

---

### 3.2 Thread

A **thread** is a conversation. Every run of the agent belongs to a thread. The thread is identified by a UUID called the `threadId`.

Why threads matter:

- The agent receives the **full message history** of the thread on every run, so it has context of what was said before
- Switching to a different `threadId` starts a new conversation with fresh context
- In Cloud mode, threads are persisted on CopilotKit's servers. In Self-Hosted mode, you manage persistence yourself.

Think of a thread the same way you think of a conversation in WhatsApp or Slack — it is a named container holding all the messages between you and the agent.

```
Thread A  (threadId: "abc-123")
  User:  "What is the Q1 revenue?"
  Agent: "Q1 revenue was $4.2M..."
  User:  "Compare to Q2"

Thread B  (threadId: "def-456")
  User:  "Show open Salesforce leads"
```

---

### 3.3 AG-UI Protocol

**AG-UI** (Agent-User Interface protocol) is the communication standard between CopilotKit's frontend and your agent backend.

It defines a set of typed events that your backend emits as a streaming response. CopilotKit's frontend listens for these events and updates the UI accordingly.

The key events in order:

| Event | When it fires |
|---|---|
| `RUN_STARTED` | Agent begins processing |
| `TOOL_CALL_START` | Agent decided to call a tool |
| `TOOL_CALL_ARGS` | Streaming the tool arguments as a JSON delta |
| `TOOL_CALL_END` | Tool arguments fully sent |
| `TOOL_CALL_RESULT` | Tool execution result returned |
| `TEXT_MESSAGE_START` | Agent begins writing its text response |
| `TEXT_MESSAGE_CONTENT` | One token streamed from the LLM |
| `TEXT_MESSAGE_END` | Text response complete |
| `RUN_FINISHED` | Agent is fully done |

This is a **standard protocol** — if your backend emits these events correctly, CopilotKit renders them correctly regardless of what framework your agent uses internally.

---

### 3.4 SSE (Server-Sent Events)

**SSE** is the transport that AG-UI events travel over. It is a browser-native mechanism for a server to push a stream of text events to a browser over a regular HTTP connection.

When your agent runs, it does not wait for the full response to be ready and then send it all at once. Instead, it streams each event as soon as it is available. This is why users see text appearing word-by-word rather than waiting several seconds for everything to appear at once.

Each SSE message is a line of text:

```
data: {"type":"TEXT_MESSAGE_CONTENT","delta":"Hello"}

data: {"type":"TEXT_MESSAGE_CONTENT","delta":" world"}
```

CopilotKit opens this connection, reads every line, parses the JSON, and updates React state. You never write SSE parsing code.

---

### 3.5 How All the Pieces Connect

Here is the full picture of what happens when a user types a message:

```mermaid
sequenceDiagram
    participant U as User
    participant FE as React App (CopilotKit)
    participant BE as Your Backend
    participant LLM as LLM (GPT-4o)
    participant Tool as Tool Function

    U->>FE: Types message and hits Enter
    FE->>BE: POST with threadId, messages, agentId
    Note over BE: Receives full conversation history
    BE->>LLM: Run LLM with messages and system prompt
    LLM->>BE: Decides to call a tool
    BE-->>FE: SSE: RUN_STARTED
    BE-->>FE: SSE: TOOL_CALL_START (tool name)
    BE-->>FE: SSE: TOOL_CALL_ARGS (arguments)
    BE-->>FE: SSE: TOOL_CALL_END
    BE->>Tool: Execute tool(args)
    Tool-->>BE: Return result
    BE-->>FE: SSE: TOOL_CALL_RESULT
    LLM->>BE: Generate final text answer
    BE-->>FE: SSE: TEXT_MESSAGE_START
    loop Token by token
        BE-->>FE: SSE: TEXT_MESSAGE_CONTENT (delta)
    end
    BE-->>FE: SSE: TEXT_MESSAGE_END
    BE-->>FE: SSE: RUN_FINISHED
    FE-->>U: Chat UI updates in real time
```

CopilotKit handles **everything on the frontend side** of this diagram — the POST request, the SSE connection, parsing every event, updating React state, and rendering the UI. You only write the backend agent logic.

---

## 4. Two Ways to Deploy CopilotKit

CopilotKit can be deployed in two modes. The choice affects where your data flows and what infrastructure you need to maintain.

---

### Mode 1 — Cloud (CopilotKit Cloud)

```mermaid
sequenceDiagram
    participant U as User
    participant FE as React Frontend
    participant Cloud as CopilotKit Cloud
    participant BE as Your Agent Backend
    participant LLM as LLM

    U->>FE: Types message
    FE->>Cloud: POST with publicApiKey, threadId, messages
    Note over Cloud: Auth, rate limiting, thread persistence, analytics
    Cloud->>BE: Forward run request via AG-UI
    BE->>LLM: Run agent
    LLM-->>BE: Tool calls and text
    BE-->>Cloud: SSE event stream
    Cloud-->>FE: Relay SSE stream
    FE-->>U: Render streamed response
```

In Cloud mode, your React app talks to **CopilotKit's servers**, which relay every message to your agent backend. You get managed infrastructure: your frontend talks to CopilotKit's URL instead of your own backend URL.

**You still run your own agent.** CopilotKit Cloud is not the LLM — it is the relay middleware.

#### What Cloud Gives You

**Thread and message persistence** — In self-hosted mode, messages live only in React component state and are lost on page refresh. With Cloud, every message is stored server-side against the `threadId`. When the user returns, their history is reloaded automatically. No database required on your end.

**Analytics dashboard** — Shows total messages, active threads per day, tool call frequency and latency, error rates per agent, and user session counts. No instrumentation code needed in your app.

**Rate limiting** — Enforces per-user and per-project rate limits. Configure in the dashboard: requests per minute per user, requests per day per project, max tokens per request.

**Authentication** — Three options:

- API key per user (scoped keys you issue from your backend)
- JWT validation (Cloud verifies a JWT you include in each request)
- CopilotKit Auth (managed user identity with email/password or SSO)

#### Setting Up Cloud — Step by Step

**Step 1: Get your API key**

Sign up at https://cloud.copilotkit.ai. Create a project and copy the `publicApiKey` (format: `ck-xxxxxxxxxxxxxxxx`).

**Step 2: Register your agent in the Cloud dashboard**

Go to **Agents → Add Agent**. Enter your agent's publicly reachable endpoint URL. Select the framework (PydanticAI, LangGraph, etc.). Give it a name — this becomes the value of the `agent` prop in your frontend code.

CopilotKit Cloud forwards every run to that endpoint. Your endpoint still follows the same AG-UI protocol as in self-hosted mode.

**Step 3: Write the frontend code**

```tsx
import { CopilotKit } from '@copilotkit/react-core'
import { CopilotChat } from '@copilotkit/react-ui'
import '@copilotkit/react-ui/styles.css'

export default function App() {
  return (
    <CopilotKit
      publicApiKey={import.meta.env.VITE_COPILOTKIT_API_KEY}
      agent="my_agent"
    >
      <CopilotChat
        labels={{
          title: 'My AI Assistant',
          initial: 'How can I help you today?',
          placeholder: 'Ask me anything...',
        }}
      />
    </CopilotKit>
  )
}
```

Store the key in your environment file — never hardcode it in source:

```
VITE_COPILOTKIT_API_KEY=ck-your-key-here
```

**Passing a user JWT for authentication:**

```tsx
<CopilotKit
  publicApiKey={import.meta.env.VITE_COPILOTKIT_API_KEY}
  agent="my_agent"
  headers={{ Authorization: `Bearer ${userJwt}` }}
>
  <CopilotChat />
</CopilotKit>
```

Your agent backend receives the verified user identity in the request context. You do not re-validate the JWT yourself.

#### Cloud vs Self-Hosted Comparison

| Feature | Cloud | Self-Hosted |
|---|---|---|
| Message history persistence | Automatic | Must build yourself |
| Analytics dashboard | Included | Must build yourself |
| Rate limiting | Configurable in dashboard | Must build in your middleware |
| Authentication | Managed | Your auth middleware |
| Data leaves your servers | Yes, via CopilotKit relay | Never |
| Agent traffic visibility | CopilotKit sees it | Fully private |
| Regulated or air-gapped environments | Not suitable | Fully supported |
| Cost | Paid, usage-based | Your infrastructure cost only |
| Setup time | Minutes | Hours, backend work required |

**Use Cloud when:** building a prototype, a SaaS product, or an internal tool where data privacy is not a hard constraint, or when your team lacks backend engineers to build the runtime.

**Do not use Cloud when:** healthcare (HIPAA), finance (PCI-DSS or SOC2), government deployments, or any environment where conversation data must never leave your own infrastructure.

---

### Mode 2 — Self-Hosted (Runtime URL)

```mermaid
flowchart LR
    User["User"] --> FE["React Frontend\nCopilotKit"]
    FE -- "POST messages" --> API["Your Backend\nFastAPI or Express"]
    API -- "Run agent" --> Agent["Your Agent\nPydanticAI or LangGraph"]
    Agent -- "Tool calls" --> Tools["Tools\nSQL, APIs, etc."]
    Tools -- "Results" --> Agent
    Agent -- "AG-UI SSE" --> API
    API -- "SSE stream" --> FE
    FE -- "Rendered response" --> User

    style FE fill:#e8f4fd,stroke:#2196f3
    style API fill:#fff3e0,stroke:#ff9800
    style Agent fill:#f3e5f5,stroke:#9c27b0
```

In self-hosted mode, your React app talks **directly to your own backend**. Nothing passes through CopilotKit's servers.

```tsx
<CopilotKit runtimeUrl="https://your-api.com/v1/copilotkit" agent="my_agent">
  <CopilotChat />
</CopilotKit>
```

#### What Your Backend Must Implement

Your backend needs exactly two endpoints:

| Method | Path | Purpose |
|---|---|---|
| GET | `/info` | Agent discovery — returns version and agents object |
| POST | `/` | Run endpoint — receives the message payload, streams AG-UI SSE back |

Example `/info` response:

```json
{
  "version": "1.54.0",
  "agents": {
    "enterprise_brain": {
      "description": "Enterprise Brain — Salesforce and Insurance data assistant"
    }
  }
}
```

CopilotKit's frontend calls `/info` on startup to discover available agents. If the agent name in `<CopilotKit agent="...">` is not found in this response, you will get an "Agent not found" error.

**Use self-hosted when:** enterprise environments, regulated industries, or any time data must not leave your infrastructure.

---

## 5. Agent Backend Integration

CopilotKit is framework-agnostic on the backend. It communicates over the AG-UI protocol (SSE events), so any agent framework that can emit those events works. The most common integrations are shown below.

---

### PydanticAI (used by Enterprise Brain)

PydanticAI has a built-in AG-UI adapter. You define your agent and tools normally, then pass the agent to `handle_ag_ui_request`. Tool call events, text streaming, and run start/finish events are all emitted automatically.

```python
from pydantic_ai import Agent
from pydantic_ai.ag_ui import handle_ag_ui_request
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse

agent = Agent("openai:gpt-4o", instructions="You are a helpful assistant.")

@agent.tool_plain()
def get_data(query: str) -> str:
    return "some data from the database"

app = FastAPI()

@app.get("/info")
async def info():
    return JSONResponse({
        "version": "1.54.0",
        "agents": {
            "my_agent": {
                "description": "My PydanticAI agent"
            }
        }
    })

@app.post("")
async def run(request: Request):
    return await handle_ag_ui_request(agent, request)
```

> **Note:** CopilotKit wraps the POST body in an envelope `{ method, params, body: <actual payload> }`. If you use `handle_ag_ui_request` directly, unwrap the `body` field first — see the Enterprise Brain copilotkit router for the implementation pattern.

---

### LangGraph

LangGraph has first-class CopilotKit integration. Define your graph as normal, then expose it through the CopilotKit LangGraph adapter. LangGraph agents have threadId-scoped memory built in, which maps directly to CopilotKit threads.

```python
from langgraph.graph import StateGraph
# define your graph as normal...
```

```tsx
// Frontend — same as any self-hosted setup
<CopilotKit runtimeUrl="/api/copilotkit" agent="my_langgraph_agent">
  <CopilotChat />
</CopilotKit>
```

---

### OpenAI Agents SDK

```python
from agents import Agent
from agents.ag_ui import handle_ag_ui_request

agent = Agent(name="my_agent", instructions="...", tools=[...])

@app.post("")
async def run(request: Request):
    return await handle_ag_ui_request(agent, request)
```

---

### Custom Framework (Manual AG-UI Events)

If your agent framework does not have an adapter, emit the AG-UI events manually. As long as your endpoint produces the correct event sequence, CopilotKit renders everything correctly regardless of what runs internally.

```python
from fastapi.responses import StreamingResponse
import json

async def event_stream(messages):
    thread_id = "thread-123"
    run_id = "run-456"

    yield f'data: {json.dumps({"type": "RUN_STARTED", "threadId": thread_id, "runId": run_id})}\n\n'

    yield f'data: {json.dumps({"type": "TOOL_CALL_START", "toolCallId": "tc1", "toolCallName": "my_tool"})}\n\n'
    yield f'data: {json.dumps({"type": "TOOL_CALL_ARGS", "toolCallId": "tc1", "delta": "{\"query\": \"Q1\"}"})}\n\n'
    yield f'data: {json.dumps({"type": "TOOL_CALL_END", "toolCallId": "tc1"})}\n\n'
    yield f'data: {json.dumps({"type": "TOOL_CALL_RESULT", "toolCallId": "tc1", "content": "result", "role": "tool"})}\n\n'

    yield f'data: {json.dumps({"type": "TEXT_MESSAGE_START", "messageId": "m1", "role": "assistant"})}\n\n'
    yield f'data: {json.dumps({"type": "TEXT_MESSAGE_CONTENT", "messageId": "m1", "delta": "Hello world"})}\n\n'
    yield f'data: {json.dumps({"type": "TEXT_MESSAGE_END", "messageId": "m1"})}\n\n'

    yield f'data: {json.dumps({"type": "RUN_FINISHED", "threadId": thread_id, "runId": run_id})}\n\n'

@app.post("")
async def run(request: Request):
    body = await request.json()
    return StreamingResponse(event_stream(body["messages"]), media_type="text/event-stream")
```

---

## 6. Installation

```bash
npm install @copilotkit/react-core @copilotkit/react-ui
```

- `react-core` — hooks, the context provider, and all business logic
- `react-ui` — pre-built UI components (chat, sidebar, popup)

Import the default styles once in your app entry point:

```tsx
import '@copilotkit/react-ui/styles.css'
```

---

## 7. Component Reference

### Component Hierarchy

```mermaid
flowchart TD
    CK["CopilotKit\nreact-core\nRoot context provider\nRequired wrapper for everything"]

    CK --> Chat["CopilotChat\nFull embedded chat UI"]
    CK --> Sidebar["CopilotSidebar\nCollapsible side panel"]
    CK --> Popup["CopilotPopup\nFloating chat button"]
    CK --> DevConsole["CopilotDevConsole\nDebug event stream"]

    Chat --> AM["AssistantMessage\nAssistant bubble"]
    Chat --> UM["UserMessage\nUser bubble"]
    Chat --> MD["Markdown\nText renderer"]
    Chat --> IR["ImageRenderer\nImage attachments"]
    Chat --> RS["RenderSuggestionsList\nSuggestion chips"]

    Sidebar -.->|same customisation slots| Chat
    Popup -.->|same customisation slots| Chat

    style CK fill:#1a73e8,color:#fff,stroke:#1a73e8
    style Chat fill:#34a853,color:#fff,stroke:#34a853
    style Sidebar fill:#34a853,color:#fff,stroke:#34a853
    style Popup fill:#34a853,color:#fff,stroke:#34a853
```

`<CopilotKit>` must always be at the root — it provides context to every component and hook inside it.

---

### `<CopilotKit>`

**Package:** `@copilotkit/react-core`

The root context provider. Must wrap every CopilotKit component and hook in your app. It sets up the runtime connection, the agent scope, the thread, and shared state.

```tsx
import { CopilotKit } from '@copilotkit/react-core'

// Self-hosted
<CopilotKit runtimeUrl="/v1/copilotkit" agent="enterprise_brain">
  {/* everything else goes here */}
</CopilotKit>

// Cloud
<CopilotKit publicApiKey={import.meta.env.VITE_COPILOTKIT_API_KEY} agent="enterprise_brain">
  {/* everything else goes here */}
</CopilotKit>
```

Without CopilotKit, you would write a custom context provider with SSE handling, retry logic, and message state — approximately 200 lines of boilerplate before any UI exists.

---

### `<CopilotChat>`

**Package:** `@copilotkit/react-ui`

A complete chat interface out of the box: input box, message list, loading indicators, suggestion chips, stop button, copy button, regenerate button, auto-scroll, markdown rendering, and mobile layout.

```tsx
import { CopilotChat } from '@copilotkit/react-ui'
import '@copilotkit/react-ui/styles.css'

<CopilotChat
  labels={{
    title: 'Enterprise Brain',
    initial: 'Ask me anything about your business data.',
    placeholder: 'Type your question...',
  }}
  onSubmitMessage={(msg) => console.log('sent:', msg)}
  onInProgress={(loading) => setIsLoading(loading)}
  instructions="Always reply in bullet points."
/>
```

**Key props:**

| Prop | Type | Purpose |
|---|---|---|
| `labels` | object | UI text: title, initial message, input placeholder |
| `instructions` | string | Extra system prompt appended to every request |
| `onSubmitMessage` | function | Called when user sends a message |
| `onInProgress` | function | Fires true when agent starts, false when done |
| `suggestions` | array | Static suggestion chips above the input |
| `makeSystemMessage` | function | Completely replace the system prompt |
| `disableSystemMessage` | boolean | Send no system prompt at all |
| `imageUploadsEnabled` | boolean | Show image upload button |
| `AssistantMessage` | component | Replace the assistant bubble component |
| `UserMessage` | component | Replace the user bubble component |
| `RenderMessage` | component | Replace the per-message renderer |
| `Messages` | component | Replace the entire message list area |

---

### `<CopilotSidebar>`

**Package:** `@copilotkit/react-ui`

Same as `<CopilotChat>` but mounted as a collapsible sidebar that slides in over your app. Your app content is always rendered; the sidebar overlays it.

```tsx
import { CopilotSidebar } from '@copilotkit/react-ui'

<CopilotSidebar defaultOpen={false} labels={{ title: 'AI Assistant' }}>
  <YourMainApp />
</CopilotSidebar>
```

---

### `<CopilotPopup>`

**Package:** `@copilotkit/react-ui`

A floating chat button in the bottom-right corner that expands into a chat window on click. Accepts all the same props as `<CopilotChat>`.

```tsx
import { CopilotPopup } from '@copilotkit/react-ui'

<CopilotPopup defaultOpen={false} labels={{ title: 'Ask AI' }} />
```

Use this when you want AI available on every page without dedicating permanent screen space to a chat panel.

---

### `<CopilotDevConsole>`

**Package:** `@copilotkit/react-ui`

A debug panel that shows the raw AG-UI event stream, tool calls, and agent state in real time. Add it inside `<CopilotKit>` during development and remove it before production.

```tsx
import { CopilotDevConsole } from '@copilotkit/react-ui'

<CopilotKit runtimeUrl="...">
  <CopilotDevConsole />
  <CopilotChat />
</CopilotKit>
```

---

### `<AssistantMessage>`

**Package:** `@copilotkit/react-ui`

The individual assistant message bubble component. Pass a wrapper via the `AssistantMessage` prop of `<CopilotChat>` to customise the bubble style while keeping everything else default.

```tsx
import { AssistantMessage } from '@copilotkit/react-ui'

function MyAssistantMessage(props) {
  return (
    <div style={{ background: '#f0f4ff', borderRadius: 8, padding: 12 }}>
      <AssistantMessage {...props} />
    </div>
  )
}

<CopilotChat AssistantMessage={MyAssistantMessage} />
```

| Prop | Type | Meaning |
|---|---|---|
| `message` | AIMessage | The full message object |
| `isLoading` | boolean | Model thinking, no output produced yet |
| `isGenerating` | boolean | Actively streaming text tokens |
| `isCurrentMessage` | boolean | This is the last message in the list |

---

### `<UserMessage>`

**Package:** `@copilotkit/react-ui`

The individual user message bubble. Customise it while keeping defaults for everything else.

```tsx
import { UserMessage } from '@copilotkit/react-ui'

function MyUserMessage(props) {
  return (
    <div style={{ textAlign: 'right', color: '#1d4ed8' }}>
      <UserMessage {...props} />
    </div>
  )
}

<CopilotChat UserMessage={MyUserMessage} />
```

---

### `<Markdown>`

**Package:** `@copilotkit/react-ui`

CopilotKit's internal markdown renderer. Use it inside a custom `RenderMessage` component so you do not need to install `react-markdown` separately.

```tsx
import { Markdown } from '@copilotkit/react-ui'

function MyMessage({ message }) {
  return <Markdown content={message.content} />
}
```

---

### `<ImageRenderer>`

**Package:** `@copilotkit/react-ui`

Renders image attachments inside messages. Required when building a custom `UserMessage` that supports image uploads.

```tsx
import { UserMessage, ImageRenderer } from '@copilotkit/react-ui'

<UserMessage message={message} ImageRenderer={ImageRenderer} rawData={message} />
```

---

### `<RenderSuggestion>` and `<RenderSuggestionsList>`

**Package:** `@copilotkit/react-ui`

Components for rendering suggestion chips. Use these when building a fully custom chat UI where you need to render CopilotKit suggestions yourself.

```tsx
import { RenderSuggestion, RenderSuggestionsList } from '@copilotkit/react-ui'

<RenderSuggestion suggestion={{ title: 'Show pipeline', message: 'show pipeline' }} />

<RenderSuggestionsList suggestions={[...]} onSelect={(s) => send(s.message)} />
```

---

## 8. Hook Reference

Hooks are functions you call inside React components to interact with CopilotKit state and behaviour. All hooks require being inside a `<CopilotKit>` context.

---

### `useThreads()`

**Package:** `@copilotkit/react-core`

Gives you the current `threadId` and a setter to switch between conversations.

```mermaid
stateDiagram-v2
    [*] --> Active: App loads, CopilotKit generates threadId
    Active --> Active: User sends messages
    Active --> Titled: First message sent (auto-title the thread)
    Titled --> Titled: More messages in same thread
    Titled --> Switching: User selects a saved thread
    Switching --> Active: CopilotChat remounts via key=threadId
    Active --> [*]: User closes tab
```

```ts
const { threadId, setThreadId } = useThreads()

// Start a new conversation
setThreadId(crypto.randomUUID())

// Switch to a previously stored thread
setThreadId('a6fb6c62-9814-4c4c-8c16-a4712394475a')
```

CopilotKit sends `threadId` with every request so the backend can scope conversation context.

**Important pattern:** When switching threads, add `key={threadId}` to `<CopilotChat>`. This forces React to fully remount the component and clear the message list:

```tsx
<CopilotChat key={threadId} labels={{ title: 'Enterprise Brain' }} />
```

Without `key={threadId}`, the UI continues showing the previous thread's messages even after calling `setThreadId`.

---

### `useDefaultTool()`

**Package:** `@copilotkit/react-core`

Registers a catch-all render function for every tool call the agent makes. When the agent calls any tool, CopilotKit renders your component inline in the chat thread at the point where the tool was called.

```tsx
import { useDefaultTool } from '@copilotkit/react-core'

function ToolCallDisplay() {
  useDefaultTool({
    render: ({ name, status }) => (
      <div style={{ color: '#6366f1', fontSize: 13, fontFamily: 'monospace' }}>
        {status === 'complete' ? '✅' : '⏳'} {name}
      </div>
    ),
  })
  return null
}
```

Render callback receives:

| Prop | Type | Value |
|---|---|---|
| `name` | string | Tool function name, e.g. `get_table_schema` |
| `status` | string | `inProgress` while running, `complete` when done |
| `args` | object | Arguments passed to the tool |
| `result` | any | Return value — only present when status is complete |

---

### `useRenderToolCall()`

**Package:** `@copilotkit/react-core`

Same as `useDefaultTool` but targets one specific named tool. Use this when a particular tool needs a rich custom UI — for example, a SQL query tool that should display the results as a formatted table.

```tsx
import { useRenderToolCall } from '@copilotkit/react-core'

useRenderToolCall({
  name: 'run_salesforce_query',
  render: ({ status, args, result }) => (
    <div>
      <code>SOQL: {args?.soql_query}</code>
      {status === 'complete' && (
        <pre>{JSON.stringify(result, null, 2)}</pre>
      )}
    </div>
  ),
})
```

Use `useDefaultTool` as a catch-all for all tools. Use `useRenderToolCall` when one specific tool needs its own display.

---

### `useCopilotAction()`

**Package:** `@copilotkit/react-core`

Registers a tool that the LLM can call **and** renders its output in the chat. The difference from `useDefaultTool` is that this hook also *defines* the tool — the LLM learns about it from the description and parameters you provide here.

Use this when you want the AI to trigger frontend actions: navigate to a page, open a modal, update a filter.

```tsx
import { useCopilotAction } from '@copilotkit/react-core'

useCopilotAction({
  name: 'navigate_to_dashboard',
  description: 'Navigate to a specific dashboard page',
  parameters: [
    { name: 'page', type: 'string', description: 'dashboard | reports | settings' }
  ],
  handler: async ({ page }) => {
    router.push(`/${page}`)
    return `Navigated to ${page}`
  },
  render: ({ status, args }) => (
    <div>Going to {args.page}...</div>
  ),
})
```

---

### `useCopilotChat()`

**Package:** `@copilotkit/react-core`

Programmatic access to the chat — read messages, send messages, clear history — without rendering any UI. Use this when you need to trigger agent runs from code rather than from user input.

```tsx
import { useCopilotChat } from '@copilotkit/react-core'

const { messages, appendMessage, setMessages, isLoading } = useCopilotChat()

// Trigger a message automatically on page load
await appendMessage({ role: 'user', content: 'Summarise the dashboard' })

// Read the current message list
console.log(messages)

// Reset the conversation
setMessages([])
```

---

### `useCopilotReadable()`

**Package:** `@copilotkit/react-core`

Injects data from your React app into the agent's system context on every request. The agent can read your current app state without you explicitly including it in every message.

```tsx
import { useCopilotReadable } from '@copilotkit/react-core'

useCopilotReadable({
  description: 'The currently selected date range in the dashboard',
  value: { from: '2025-01-01', to: '2025-12-31' },
})
```

If the user asks "show data for the selected period", the agent already knows what period is selected and does not need to ask.

---

### `useCopilotChatSuggestions()`

**Package:** `@copilotkit/react-core`

Registers AI-generated suggestion chips that appear above the chat input. The LLM generates contextually appropriate suggestions based on your instructions.

```tsx
import { useCopilotChatSuggestions } from '@copilotkit/react-core'

useCopilotChatSuggestions({
  instructions: 'Suggest questions about Salesforce pipeline data',
  maxSuggestions: 3,
  minSuggestions: 1,
})
```

For static suggestions, pass them as a prop to `<CopilotChat>`:

```tsx
<CopilotChat
  suggestions={[
    { title: 'Show pipeline', message: 'Show me the current sales pipeline' },
    { title: 'Lead count', message: 'How many leads this month?' },
  ]}
/>
```

---

### `useCoAgent()`

**Package:** `@copilotkit/react-core`

Reads and writes the agent's shared state — structured data that the backend agent publishes alongside its text response. Use this when your agent's output should drive UI outside the chat (e.g. the agent computes a chart and a chart panel in your dashboard updates in real time).

```tsx
import { useCoAgent } from '@copilotkit/react-core'

const { state, setState } = useCoAgent({
  name: 'enterprise_brain',
  initialState: { currentQuery: null, chartData: null },
})

// state.chartData updates in real time when the agent publishes it
// setState sends state back up to the agent
```

---

### `useCoAgentStateRender()`

**Package:** `@copilotkit/react-core`

Renders intermediate agent state inline in the chat thread as the agent works. Useful for progress indicators and partial results while the agent is still running.

```tsx
import { useCoAgentStateRender } from '@copilotkit/react-core'

useCoAgentStateRender({
  name: 'enterprise_brain',
  render: ({ state }) =>
    state?.currentStep ? <div>Running: {state.currentStep}</div> : null,
})
```

---

### `useHumanInTheLoop()`

**Package:** `@copilotkit/react-core`

Pauses the agent mid-run and renders a confirmation UI in the chat. The agent waits until the user responds before continuing. Use this for destructive or expensive operations.

```tsx
import { useHumanInTheLoop } from '@copilotkit/react-core'

useHumanInTheLoop({
  name: 'confirm_delete',
  render: ({ args, resolve }) => (
    <div>
      Delete record: {args.record}?
      <button onClick={() => resolve(true)}>Yes, delete</button>
      <button onClick={() => resolve(false)}>Cancel</button>
    </div>
  ),
})
```

The agent calls `confirm_delete` as a tool. The UI renders the confirmation. The agent is suspended until `resolve()` is called.

---

### `useChatContext()`

**Package:** `@copilotkit/react-ui`

Accesses internal chat state from inside a component that is a child of `<CopilotChat>`. Gives you messages, input value, and loading state without prop drilling.

```tsx
import { useChatContext } from '@copilotkit/react-ui'

function MyCustomHeader() {
  const { messages, isLoading } = useChatContext()
  return (
    <div>
      {isLoading ? 'Thinking...' : `${messages.length} messages`}
    </div>
  )
}
```

Must be used inside the `<CopilotChat>` component tree, not outside it.

---

## 9. Quick Decision Guide

| What you need | What to use |
|---|---|
| Full chat UI in a page | `<CopilotChat>` |
| Chat in a collapsible sidebar | `<CopilotSidebar>` |
| Floating AI button on every page | `<CopilotPopup>` |
| Show what tools the agent is calling | `useDefaultTool()` |
| Custom display for one specific tool | `useRenderToolCall()` |
| Let the AI trigger frontend actions | `useCopilotAction()` |
| Send messages from code, not user input | `useCopilotChat()` |
| Give the agent access to current app state | `useCopilotReadable()` |
| Multi-conversation thread list | `useThreads()` |
| Suggestion chips above the input | `useCopilotChatSuggestions()` |
| Agent state drives UI panels outside chat | `useCoAgent()` |
| Require human approval before agent continues | `useHumanInTheLoop()` |
| Debug the AG-UI event stream during development | `<CopilotDevConsole>` |

---

## 10. What CopilotKit Does NOT Do

CopilotKit handles the frontend conversation layer. The following responsibilities always remain yours:

| Responsibility | Owner |
|---|---|
| Message persistence across page refreshes in self-hosted mode | Your database or localStorage |
| User authentication and session management | Your auth middleware |
| Agent logic, tools, and LLM calls | Your backend code |
| Styling beyond the default CopilotKit theme | Your CSS or Tailwind |
| Thread metadata such as title, creation date, labels | Your code — `useThreads` gives the ID only |
| Business logic inside tools | Your code |
| Rate limiting and abuse prevention in self-hosted mode | Your middleware |

---

## Reference

- Official documentation: https://docs.copilotkit.ai/
- AG-UI protocol specification: https://docs.ag-ui.com/
