mirror of
https://github.com/CopilotKit/CopilotKit.git
synced 2026-09-14 16:26:20 +08:00
b039983f59
Moves the streaming performance tip into a reusable snippet and imports it on both the root headless page and the v2 basics headless-ui snippet (used by built-in-agent and a2a framework pages). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
144 lines
4.2 KiB
Plaintext
144 lines
4.2 KiB
Plaintext
## What is this?
|
|
|
|
A headless UI gives you full control over the chat experience — you bring your own components, layout, and styling while CopilotKit handles agent communication, message management, and streaming. This is built on top of the same primitives (`useAgent` and `useCopilotKit`) covered in Programmatic Control.
|
|
|
|
## When should I use this?
|
|
|
|
Use headless UI when the slot system isn't enough — for example, when you need a completely different layout, want to embed the chat into an existing UI, or are building a non-chat interface that still communicates with an agent.
|
|
|
|
## Implementation
|
|
|
|
<Steps>
|
|
<Step>
|
|
### Access the agent and CopilotKit
|
|
|
|
Use `useAgent` to get the agent instance (messages, state, execution status) and `useCopilotKit` to run the agent.
|
|
|
|
```tsx title="components/custom-chat.tsx"
|
|
import { useAgent } from "@copilotkit/react-core/v2";
|
|
import { useCopilotKit } from "@copilotkit/react-core/v2";
|
|
import { randomUUID } from "@copilotkit/shared/v2";
|
|
|
|
export function CustomChat() {
|
|
// [!code highlight:2]
|
|
const { agent } = useAgent();
|
|
const { copilotkit } = useCopilotKit();
|
|
|
|
return <div>{/* Your custom UI */}</div>;
|
|
}
|
|
```
|
|
</Step>
|
|
|
|
<Step>
|
|
### Display messages
|
|
|
|
The agent's messages are available via `agent.messages`. Each message has an `id`, `role` (`"user"` or `"assistant"`), and `content`.
|
|
|
|
```tsx title="components/custom-chat.tsx"
|
|
export function CustomChat() {
|
|
const { agent } = useAgent();
|
|
const { copilotkit } = useCopilotKit();
|
|
|
|
return (
|
|
<div className="flex flex-col h-full">
|
|
{/* [!code highlight:12] */}
|
|
<div className="flex-1 overflow-y-auto p-4 space-y-4">
|
|
{agent.messages.map((msg) => (
|
|
<div
|
|
key={msg.id}
|
|
className={msg.role === "user" ? "ml-auto bg-blue-100 rounded-lg p-3 max-w-md" : "bg-gray-100 rounded-lg p-3 max-w-md"}
|
|
>
|
|
<p className="text-sm font-medium">{msg.role}</p>
|
|
<p>{msg.content}</p>
|
|
</div>
|
|
))}
|
|
{agent.isRunning && <div className="text-gray-400">Thinking...</div>}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
```
|
|
</Step>
|
|
|
|
<Step>
|
|
### Send messages and run the agent
|
|
|
|
Add a message to the agent's conversation, then call `copilotkit.runAgent()` to trigger execution. This is the same method CopilotKit's built-in `<CopilotChat />` uses internally.
|
|
|
|
```tsx title="components/custom-chat.tsx"
|
|
import { useState, useCallback } from "react";
|
|
|
|
export function CustomChat() {
|
|
const { agent } = useAgent();
|
|
const { copilotkit } = useCopilotKit();
|
|
const [input, setInput] = useState("");
|
|
|
|
// [!code highlight:14]
|
|
const sendMessage = useCallback(async () => {
|
|
if (!input.trim()) return;
|
|
|
|
agent.addMessage({
|
|
id: randomUUID(),
|
|
role: "user",
|
|
content: input,
|
|
});
|
|
|
|
setInput("");
|
|
|
|
await copilotkit.runAgent({ agent });
|
|
}, [input, agent, copilotkit]);
|
|
|
|
return (
|
|
<div className="flex flex-col h-full">
|
|
<div className="flex-1 overflow-y-auto p-4 space-y-4">
|
|
{agent.messages.map((msg) => (
|
|
<div key={msg.id} className={msg.role === "user" ? "ml-auto bg-blue-100 rounded-lg p-3 max-w-md" : "bg-gray-100 rounded-lg p-3 max-w-md"}>
|
|
<p>{msg.content}</p>
|
|
</div>
|
|
))}
|
|
{agent.isRunning && <div className="text-gray-400">Thinking...</div>}
|
|
</div>
|
|
|
|
{/* [!code highlight:12] */}
|
|
<form
|
|
className="border-t p-4 flex gap-2"
|
|
onSubmit={(e) => { e.preventDefault(); sendMessage(); }}
|
|
>
|
|
<input
|
|
value={input}
|
|
onChange={(e) => setInput(e.target.value)}
|
|
placeholder="Type a message..."
|
|
className="flex-1 border rounded-lg px-3 py-2"
|
|
/>
|
|
<button type="submit" disabled={agent.isRunning}>Send</button>
|
|
</form>
|
|
</div>
|
|
);
|
|
}
|
|
```
|
|
</Step>
|
|
|
|
<Step>
|
|
### Stop the agent
|
|
|
|
Use `copilotkit.stopAgent()` to cancel a running agent:
|
|
|
|
```tsx title="components/custom-chat.tsx"
|
|
const stopAgent = useCallback(() => {
|
|
// [!code highlight:1]
|
|
copilotkit.stopAgent({ agent });
|
|
}, [agent, copilotkit]);
|
|
|
|
// In your JSX:
|
|
{agent.isRunning && (
|
|
<button onClick={stopAgent} className="text-red-500">
|
|
Stop
|
|
</button>
|
|
)}
|
|
```
|
|
</Step>
|
|
</Steps>
|
|
|
|
import PerformanceTip from "@/snippets/shared/performance-tip.mdx";
|
|
|
|
<PerformanceTip components={props.components} /> |