mirror of
https://github.com/CopilotKit/CopilotKit.git
synced 2026-09-14 16:26:20 +08:00
1c92a69f58
New users were still discovering cloud.copilotkit.ai through docs pages, the README, example READMEs, and in-app banners/console messages. Replace all user-facing web links with dashboard.operations.copilotkit.ai (the destination the marketing-site CTAs already use). Functional API endpoints (api.cloud.copilotkit.ai) are deliberately untouched since existing cloud customers depend on them. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
432 lines
12 KiB
Plaintext
432 lines
12 KiB
Plaintext
import { ImageAndCode } from "@/components/react/image-and-code"
|
|
import {
|
|
MessageCircleDashed,
|
|
Blocks,
|
|
LayoutList,
|
|
UserPen,
|
|
BookOpen,
|
|
} from "lucide-react"
|
|
|
|
## Overview
|
|
|
|
CopilotKit offers *fully headless UI* through the `useCopilotChatHeadless_c` hook. By using this hook, you can build your own chat interfaces
|
|
from the ground up while still utilizing CopilotKit's core features and ease-of-use.
|
|
|
|
<OpsPlatformCTA
|
|
variant="card"
|
|
title="Headless UI requires an Enterprise Intelligence Platform license key"
|
|
body="Sign up for a free account to get a publicLicenseKey and unlock the headless hooks."
|
|
ctaLabel="Create a free account"
|
|
surface="docs_premium_headless_ui"
|
|
/>
|
|
|
|
## Navigation
|
|
This page has all the information you need to get started with CopilotKit's headless UI. Select where you'd like to get started below.
|
|
|
|
<Cards className="gap-6">
|
|
<Card
|
|
icon={<MessageCircleDashed className="text-primary" />}
|
|
className="p-6 rounded-xl text-base md:col-span-2"
|
|
title="Getting started"
|
|
description="Build a fully headless chat interface from the ground up to get started."
|
|
href="#getting-started"
|
|
/>
|
|
<Card
|
|
icon={<Blocks className="text-primary" />}
|
|
className="p-6 rounded-xl text-base"
|
|
title="Generative UI"
|
|
description="Learn how to work with generative UI to render tools and other UI elements."
|
|
href="#working-with-generative-ui"
|
|
/>
|
|
<Card
|
|
icon={<LayoutList className="text-primary" />}
|
|
className="p-6 rounded-xl text-base"
|
|
title="Suggestions"
|
|
description="Learn how to work with suggestions to provide your users with a list of generated or static options to operate the chat with."
|
|
href="#working-with-suggestions"
|
|
/>
|
|
<Card
|
|
icon={<UserPen className="text-primary" />}
|
|
className="p-6 rounded-xl text-base"
|
|
title="Human-in-the-loop"
|
|
description="Learn how to work with human-in-the-loop to pause the chat and wait for a human to respond."
|
|
href="#working-with-human-in-the-loop"
|
|
/>
|
|
<Card
|
|
icon={<BookOpen className="text-primary" />}
|
|
className="p-6 rounded-xl text-base"
|
|
title="Reference"
|
|
description="Reference documentation for the `useCopilotChatHeadless_c` hook."
|
|
href="/reference/v1/hooks/useCopilotChatHeadless_c"
|
|
/>
|
|
</Cards>
|
|
|
|
## Getting started
|
|
To get started, let's walk through building a simple chat interface. From there, we'll cover
|
|
how to do more advanced things like working with suggestions and generative UI.
|
|
|
|
<video
|
|
src="https://cdn.copilotkit.ai/docs/copilotkit/videos/full-headless-chat.mp4"
|
|
className="rounded-xl shadow-lg border"
|
|
loop
|
|
playsInline
|
|
autoPlay
|
|
muted
|
|
/>
|
|
|
|
To get there, let's start by building a simple chat interface.
|
|
|
|
<Steps>
|
|
<Step>
|
|
### Create a new application
|
|
```bash
|
|
npx copilotkit@latest create
|
|
```
|
|
</Step>
|
|
|
|
<Step>
|
|
### Set up your application
|
|
First, follow the instructions in the README to set up your application, it will be a simple process.
|
|
|
|
```bash
|
|
open README.md
|
|
```
|
|
</Step>
|
|
|
|
<Step>
|
|
### Set up your CopilotKit provider
|
|
You will need to provide your public license key to the `CopilotKit` provider component. Get yours on [Copilot Cloud](https://dashboard.operations.copilotkit.ai) or read more about [premium features](/premium).
|
|
|
|
```tsx title="src/app/layout.tsx"
|
|
<CopilotKit
|
|
publicLicenseKey="your-free-public-license-key"
|
|
>
|
|
{children}
|
|
</CopilotKit>
|
|
```
|
|
</Step>
|
|
|
|
<Step>
|
|
### Create a headless chat component
|
|
Replace your main page with a simple chat interface using the headless hook.
|
|
|
|
```tsx title="src/app/page.tsx"
|
|
"use client";
|
|
import { useState } from "react";
|
|
import { useCopilotChatHeadless_c } from "@copilotkit/react-core/v2"; // [!code highlight]
|
|
|
|
export default function Home() {
|
|
const { messages, sendMessage, isLoading } = useCopilotChatHeadless_c(); // [!code highlight]
|
|
const [input, setInput] = useState("");
|
|
|
|
const handleSend = () => {
|
|
if (input.trim()) {
|
|
// [!code highlight:5]
|
|
sendMessage({
|
|
id: Date.now().toString(),
|
|
role: "user",
|
|
content: input,
|
|
});
|
|
setInput("");
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div>
|
|
<h1>My Headless Chat</h1>
|
|
|
|
{/* Messages */}
|
|
<div>
|
|
{/* [!code highlight:6] */}
|
|
{messages.map((message) => (
|
|
<div key={message.id}>
|
|
<strong>{message.role === "user" ? "You" : "Assistant"}:</strong>
|
|
<p>{message.content}</p>
|
|
</div>
|
|
))}
|
|
|
|
{/* [!code highlight:1] */}
|
|
{isLoading && <p>Assistant is typing...</p>}
|
|
</div>
|
|
|
|
{/* Input */}
|
|
<div>
|
|
<input
|
|
type="text"
|
|
value={input}
|
|
onChange={(e) => setInput(e.target.value)}
|
|
// [!code highlight:1]
|
|
onKeyDown={(e) => e.key === "Enter" && handleSend()}
|
|
placeholder="Type your message here..."
|
|
/>
|
|
{/* [!code highlight:1] */}
|
|
<button onClick={handleSend} disabled={isLoading}>
|
|
Send
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
```
|
|
</Step>
|
|
</Steps>
|
|
|
|
## Working with Generative UI
|
|
|
|
You can also render generative UI either via `useCopilotAction` or by reading tools and rendering them directly.
|
|
|
|
<video
|
|
src="https://cdn.copilotkit.ai/docs/copilotkit/videos/gen-ui.mp4"
|
|
className="rounded-xl shadow-lg border"
|
|
loop
|
|
playsInline
|
|
autoPlay
|
|
muted
|
|
/>
|
|
|
|
### With `useCopilotAction`
|
|
CopilotKit's standard components utilize `useCopilotAction` to allow tools to be both rendered and called in
|
|
the frontend. These same interfaces are available to you while using the `useCopilotChatHeadless_c` hook.
|
|
|
|
```tsx title="src/app/components/chat.tsx"
|
|
import { useFrontendTool } from "@copilotkit/react-core/v2";
|
|
|
|
export const Chat = () => {
|
|
// ...
|
|
|
|
// Define an action that will show a custom component
|
|
useFrontendTool({
|
|
name: "showCustomComponent",
|
|
// Handle the tool on the frontend
|
|
// [!code highlight:3]
|
|
handler: () => {
|
|
return "Foo, Bar, Baz";
|
|
},
|
|
// Render a custom component for the underlying data
|
|
// [!code highlight:13]
|
|
render: ({ result, args, status}) => {
|
|
return <div style={{
|
|
backgroundColor: "red",
|
|
padding: "10px",
|
|
borderRadius: "5px",
|
|
}}>
|
|
<p>Custom component</p>
|
|
<p>Result: {result}</p>
|
|
<p>Args: {JSON.stringify(args)}</p>
|
|
<p>Status: {status}</p>
|
|
</div>;
|
|
}
|
|
});
|
|
|
|
// ...
|
|
|
|
return <div>
|
|
{messages.map((message) => (
|
|
<p key={message.id}>
|
|
{message.role === "user" ? "User: " : "Assistant: "}
|
|
{message.content}
|
|
{/* Render the generative UI if it exists */}
|
|
{/* [!code highlight:1] */}
|
|
{message.role === "assistant" && message.generativeUI?.()}
|
|
</p>
|
|
))}
|
|
</div>
|
|
};
|
|
```
|
|
|
|
### With raw data
|
|
If you don't want to use `useCopilotAction`, you can also render the raw data directly.
|
|
|
|
```tsx title="src/app/components/chat.tsx"
|
|
export const Chat = () => {
|
|
// ...
|
|
|
|
return <div>
|
|
{messages.map((message) => (
|
|
<p key={message.id}>
|
|
{/* Render the tool calls if they exist */}
|
|
{/* [!code highlight:5] */}
|
|
{message.role === "assistant" && message.toolCalls?.map((toolCall) => (
|
|
<p key={toolCall.id}>
|
|
{toolCall.function.name}: {toolCall.function.arguments}
|
|
</p>
|
|
))}
|
|
</p>
|
|
))}
|
|
</div>
|
|
};
|
|
```
|
|
|
|
## Working with suggestions
|
|
|
|
CopilotKit's suggestions are a way to provide your users with a list of suggestions to operate the chat with. When utilizing
|
|
Headless UI, you have full control over the lifecycle of these suggestions.
|
|
|
|
<video
|
|
src="https://cdn.copilotkit.ai/docs/copilotkit/videos/suggestions.mp4"
|
|
className="rounded-xl shadow-lg border"
|
|
loop
|
|
playsInline
|
|
autoPlay
|
|
muted
|
|
/>
|
|
|
|
### Generating suggestions
|
|
|
|
You can generate suggestions by calling the `generateSuggestions` function.
|
|
```tsx title="src/app/components/chat.tsx"
|
|
import { useCopilotChatHeadless_c, useCopilotChatSuggestions } from "@copilotkit/react-core/v2"; // [!code highlight]
|
|
|
|
export const Chat = () => {
|
|
// Specify what suggestions should be generated
|
|
// [!code highlight:5]
|
|
useCopilotChatSuggestions({
|
|
instructions:
|
|
"Suggest 5 interesting activities for programmers to do on their next vacation",
|
|
maxSuggestions: 5,
|
|
});
|
|
|
|
// Grab relevant state from the headless hook
|
|
const { suggestions, generateSuggestions, sendMessage } = useCopilotChatHeadless_c(); // [!code highlight]
|
|
|
|
// Generate suggestions when the component mounts
|
|
useEffect(() => {
|
|
generateSuggestions(); // [!code highlight]
|
|
}, []);
|
|
|
|
// ...
|
|
|
|
// [!code word:suggestion]
|
|
return <div>
|
|
{suggestions.map((suggestion, index) => (
|
|
<button
|
|
key={index}
|
|
onClick={() => sendMessage({
|
|
id: "123",
|
|
role: "user",
|
|
content: suggestion.message
|
|
})}
|
|
>
|
|
{suggestion.title}
|
|
</button>
|
|
))}
|
|
</div>
|
|
};
|
|
```
|
|
|
|
### Programmatically setting suggestions
|
|
If you want more deterministic control over the suggestions, you can set them manually.
|
|
|
|
```tsx title="src/app/components/chat.tsx"
|
|
import { useCopilotChatHeadless_c } from "@copilotkit/react-core/v2";
|
|
|
|
export const Chat = () => {
|
|
// Grab relevant state from the headless hook
|
|
// [!code highlight:1]
|
|
const { suggestions, setSuggestions } = useCopilotChatHeadless_c();
|
|
|
|
// Set the suggestions when the component mounts
|
|
// [!code highlight:6]
|
|
useEffect(() => {
|
|
setSuggestions([
|
|
{ title: "Suggestion 1", message: "The actual message for suggestion 1" },
|
|
{ title: "Suggestion 2", message: "The actual message for suggestion 2" },
|
|
]);
|
|
}, []);
|
|
|
|
// Change the suggestions on function call
|
|
const changeSuggestions = () => {
|
|
// [!code highlight:4]
|
|
setSuggestions([
|
|
{ title: "Foo", message: "Bar" },
|
|
{ title: "Baz", message: "Bat" },
|
|
]);
|
|
};
|
|
|
|
// [!code word:suggestion]
|
|
return (
|
|
<div>
|
|
{/* Change on button click */}
|
|
<button onClick={changeSuggestions}>Change suggestions</button>
|
|
|
|
{/* Render */}
|
|
{suggestions.map((suggestion, index) => (
|
|
<button
|
|
key={index}
|
|
onClick={() => sendMessage({
|
|
id: "123",
|
|
role: "user",
|
|
content: suggestion.message
|
|
})}
|
|
>
|
|
{suggestion.title}
|
|
</button>
|
|
))}
|
|
</div>
|
|
);
|
|
};
|
|
```
|
|
|
|
## Working with Human-in-the-loop
|
|
|
|
CopilotKit's human-in-the-loop (HITL) features allows you to pause the chat and wait for a human to respond. This comes
|
|
in two flavors: **tool-based** and **interrupt-based** (for certain frameworks).
|
|
|
|
<video
|
|
src="https://cdn.copilotkit.ai/docs/copilotkit/videos/hitl.mp4"
|
|
className="rounded-xl shadow-lg border"
|
|
loop
|
|
playsInline
|
|
autoPlay
|
|
muted
|
|
/>
|
|
|
|
### Tool-based
|
|
Tool-based HITL allows for you to pause completion of a tool call and wait for a human to respond. That human's response,
|
|
becomes the result of the tool call.
|
|
|
|
|
|
```tsx title="src/app/components/chat.tsx"
|
|
import { useFrontendTool, useCopilotChatHeadless_c } from "@copilotkit/react-core/v2";
|
|
|
|
export const Chat = () => {
|
|
const { messages, sendMessage } = useCopilotChatHeadless_c();
|
|
|
|
// Define an action that will wait for the user to enter their name
|
|
useFrontendTool({
|
|
name: "getName",
|
|
renderAndWaitForResponse: ({ respond, args, status}) => {
|
|
if (status === "complete") {
|
|
return <div>
|
|
<p>Name retrieved...</p>
|
|
</div>;
|
|
}
|
|
|
|
return <div>
|
|
<input
|
|
type="text"
|
|
value={args.name || ""}
|
|
onChange={(e) => respond?.(e.target.value)}
|
|
placeholder="Enter your name"
|
|
/>
|
|
{/* Respond with the name */}
|
|
{/* [!code highlight:1] */}
|
|
<button onClick={() => respond?.(args.name)}>Submit</button>
|
|
</div>;
|
|
}
|
|
});
|
|
|
|
return (
|
|
{messages.map((message) => (
|
|
<p key={message.id}>
|
|
{message.role === "user" ? "User: " : "Assistant: "}
|
|
{message.content}
|
|
{/* [!code highlight:2] */}
|
|
{/* This will render the tool-based HITL if it exists */}
|
|
{message.role === "assistant" && message.generativeUI?.()}
|
|
</p>
|
|
))}
|
|
)
|
|
};
|
|
```
|