@copilotkitnext/core) is a framework-agnostic JavaScript library that powers the React and Angular integrations. You can use it directly in vanilla JavaScript applications, Node.js scripts, or any JavaScript environment.
Installation
npm install @copilotkitnext/core @ag-ui/client zod
# or
pnpm add @copilotkitnext/core @ag-ui/client zod
# or
yarn add @copilotkitnext/core @ag-ui/client zod
Core Concepts
CopilotKitCore
TheCopilotKitCore class is the main entry point. It manages agents, tools, context, and communication with your CopilotKit runtime.
import { CopilotKitCore } from "@copilotkitnext/core";
const copilotkit = new CopilotKitCore({
runtimeUrl: "http://localhost:3001/api/copilotkit",
headers: {
"Authorization": "Bearer your-token",
},
credentials: "include",
properties: {
userId: "user-123",
},
});
Configuration Options
interface CopilotKitCoreConfig {
// Runtime configuration
runtimeUrl?: string;
runtimeTransport?: "rest" | "single";
// Authentication & headers
headers?: Record<string, string>;
credentials?: RequestCredentials;
// Context & properties
properties?: Record<string, unknown>;
// Local agents (development only)
agents__unsafe_dev_only?: Record<string, AbstractAgent>;
// Tools
tools?: FrontendTool[];
// Suggestions
suggestionsConfig?: SuggestionsConfig[];
}
Working with Agents
Connecting to an Agent
import { CopilotKitCore } from "@copilotkitnext/core";
const core = new CopilotKitCore({
runtimeUrl: "http://localhost:3001/api/copilotkit",
});
// Get or create agent
const agent = core.getAgent("my-agent");
if (!agent) {
console.error("Agent not found");
}
// Subscribe to agent events
const subscription = agent.subscribe({
onMessagesChanged: (messages) => {
console.log("Messages updated:", messages);
renderMessages(messages);
},
onStateChanged: (state) => {
console.log("State changed:", state);
},
onRunInitialized: () => {
console.log("Agent started running");
},
onRunFinalized: () => {
console.log("Agent finished running");
},
onRunFailed: (error) => {
console.error("Agent run failed:", error);
},
});
// Don't forget to unsubscribe when done
// subscription.unsubscribe();
Running an Agent
async function sendMessage(content) {
const agent = core.getAgent("my-agent");
try {
await agent.run({
messages: [
{ role: "user", content }
],
});
} catch (error) {
console.error("Failed to run agent:", error);
}
}
// Usage
sendMessage("Hello, how can you help me?");
Connecting to a Thread
async function connectToThread(threadId) {
const agent = core.getAgent("my-agent");
try {
await agent.connect({
threadId,
// Optionally start with initial messages
messages: [],
});
console.log("Connected to thread:", threadId);
} catch (error) {
console.error("Failed to connect:", error);
}
}
// Usage
connectToThread("thread-123");
Frontend Tools
Frontend tools execute in the browser and can interact with your UI, local storage, or any browser API.Registering Tools
import { z } from "zod";
// Simple tool
core.addTool({
name: "getCurrentTime",
description: "Get the current time",
parameters: z.object({}),
handler: async () => {
return new Date().toLocaleTimeString();
},
});
// Tool with parameters
core.addTool({
name: "showNotification",
description: "Show a browser notification to the user",
parameters: z.object({
title: z.string().describe("Notification title"),
message: z.string().describe("Notification message"),
}),
handler: async ({ title, message }) => {
if (!("Notification" in window)) {
throw new Error("Notifications not supported");
}
const permission = await Notification.requestPermission();
if (permission === "granted") {
new Notification(title, { body: message });
return `Notification shown: ${title}`;
} else {
throw new Error("Notification permission denied");
}
},
});
// Tool with state access
core.addTool({
name: "updateCounter",
description: "Update the counter value",
parameters: z.object({
increment: z.number().describe("Amount to increment by"),
}),
handler: async ({ increment }) => {
const currentValue = parseInt(
document.getElementById("counter").textContent
);
const newValue = currentValue + increment;
document.getElementById("counter").textContent = newValue;
return `Counter updated to ${newValue}`;
},
});
Removing Tools
// Remove a specific tool
core.removeTool("showNotification");
// Remove tool for specific agent
core.removeTool("showNotification", "my-agent");
Context Management
Provide dynamic context to your agents:// Add context
core.addContext("user-profile", {
description: "Current user profile information",
value: {
id: "user-123",
name: "John Doe",
preferences: {
theme: "dark",
language: "en",
},
},
});
// Update context
core.updateContext("user-profile", {
description: "Current user profile information",
value: {
id: "user-123",
name: "John Doe",
preferences: {
theme: "light", // Changed
language: "en",
},
},
});
// Remove context
core.removeContext("user-profile");
Event Subscription
Subscribe to core events for reactive updates:const subscription = core.subscribe({
// Runtime connection status
onRuntimeConnectionStatusChanged: ({ status }) => {
console.log("Runtime status:", status);
updateConnectionIndicator(status);
},
// Tool execution events
onToolExecutionStart: ({ toolName, args }) => {
console.log(`Tool ${toolName} started with:`, args);
showToolExecutionUI(toolName, "running");
},
onToolExecutionEnd: ({ toolName, result, error }) => {
if (error) {
console.error(`Tool ${toolName} failed:`, error);
showToolExecutionUI(toolName, "error");
} else {
console.log(`Tool ${toolName} completed:`, result);
showToolExecutionUI(toolName, "completed");
}
},
// Agent changes
onAgentsChanged: ({ agents }) => {
console.log("Available agents:", Object.keys(agents));
updateAgentsList(agents);
},
// Context changes
onContextChanged: ({ context }) => {
console.log("Context updated:", context);
},
// Errors
onError: ({ error, code, context }) => {
console.error(`Error [${code}]:`, error);
console.error("Context:", context);
showErrorNotification(error.message);
},
});
// Clean up subscription when done
subscription.unsubscribe();
Suggestions
Configure AI-generated suggestions:// Add suggestions config
core.addSuggestionsConfig("my-suggestions", {
instructions: "Suggest helpful next actions based on the current context",
available: "always",
agentId: "my-agent",
});
// Get suggestions
const { suggestions, isLoading } = core.getSuggestions("my-agent");
console.log("Current suggestions:", suggestions);
console.log("Loading:", isLoading);
// Subscribe to suggestion changes
core.subscribe({
onSuggestionsChanged: ({ agentId, suggestions }) => {
console.log(`Suggestions for ${agentId}:`, suggestions);
renderSuggestions(suggestions);
},
onSuggestionsStartedLoading: ({ agentId }) => {
console.log(`Loading suggestions for ${agentId}`);
showSuggestionsLoader();
},
onSuggestionsFinishedLoading: ({ agentId }) => {
console.log(`Finished loading suggestions for ${agentId}`);
hideSuggestionsLoader();
},
});
Complete Example: Chat Application
Here’s a complete example of a vanilla JavaScript chat application:<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CopilotKit Chat</title>
<style>
body {
font-family: system-ui, -apple-system, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
#messages {
border: 1px solid #ddd;
border-radius: 8px;
padding: 20px;
min-height: 400px;
max-height: 400px;
overflow-y: auto;
margin-bottom: 20px;
}
.message {
margin-bottom: 15px;
padding: 10px;
border-radius: 6px;
}
.user {
background-color: #e3f2fd;
text-align: right;
}
.assistant {
background-color: #f5f5f5;
}
#input-container {
display: flex;
gap: 10px;
}
#message-input {
flex: 1;
padding: 10px;
border: 1px solid #ddd;
border-radius: 6px;
font-size: 16px;
}
#send-button {
padding: 10px 20px;
background-color: #2196f3;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 16px;
}
#send-button:hover {
background-color: #1976d2;
}
#send-button:disabled {
background-color: #ccc;
cursor: not-allowed;
}
#status {
margin-bottom: 10px;
padding: 10px;
border-radius: 6px;
font-size: 14px;
}
.status-connected {
background-color: #c8e6c9;
color: #2e7d32;
}
.status-connecting {
background-color: #fff9c4;
color: #f57f17;
}
.status-error {
background-color: #ffcdd2;
color: #c62828;
}
</style>
</head>
<body>
<h1>CopilotKit Chat Demo</h1>
<div id="status" class="status-connecting">Connecting...</div>
<div id="messages"></div>
<div id="input-container">
<input
type="text"
id="message-input"
placeholder="Type a message..."
disabled
/>
<button id="send-button" disabled>Send</button>
</div>
<script type="module">
import { CopilotKitCore } from "@copilotkitnext/core";
import { z } from "zod";
const messagesEl = document.getElementById("messages");
const inputEl = document.getElementById("message-input");
const sendButtonEl = document.getElementById("send-button");
const statusEl = document.getElementById("status");
// Initialize CopilotKit
const core = new CopilotKitCore({
runtimeUrl: "http://localhost:3001/api/copilotkit",
});
let agent = null;
let isRunning = false;
// Subscribe to runtime status
core.subscribe({
onRuntimeConnectionStatusChanged: ({ status }) => {
updateStatus(status);
},
onError: ({ error, code }) => {
console.error(`Error [${code}]:`, error);
statusEl.textContent = `Error: ${error.message}`;
statusEl.className = "status-error";
},
});
// Register frontend tools
core.addTool({
name: "getCurrentTime",
description: "Get the current time",
parameters: z.object({}),
handler: async () => {
return new Date().toLocaleString();
},
});
core.addTool({
name: "alertUser",
description: "Show an alert to the user",
parameters: z.object({
message: z.string().describe("The message to show"),
}),
handler: async ({ message }) => {
alert(message);
return "Alert shown";
},
});
// Initialize agent
async function initializeAgent() {
agent = core.getAgent("default");
if (!agent) {
console.error("Agent not found");
return;
}
// Subscribe to agent updates
agent.subscribe({
onMessagesChanged: (messages) => {
renderMessages(messages);
},
onRunInitialized: () => {
isRunning = true;
sendButtonEl.disabled = true;
sendButtonEl.textContent = "Sending...";
},
onRunFinalized: () => {
isRunning = false;
sendButtonEl.disabled = false;
sendButtonEl.textContent = "Send";
},
onRunFailed: (error) => {
isRunning = false;
sendButtonEl.disabled = false;
sendButtonEl.textContent = "Send";
console.error("Run failed:", error);
},
});
// Connect to thread
await agent.connect({
threadId: "demo-thread",
});
}
// Render messages
function renderMessages(messages) {
messagesEl.innerHTML = "";
messages.forEach((msg) => {
const msgDiv = document.createElement("div");
msgDiv.className = `message ${msg.role}`;
msgDiv.textContent = msg.content;
messagesEl.appendChild(msgDiv);
});
// Scroll to bottom
messagesEl.scrollTop = messagesEl.scrollHeight;
}
// Update status indicator
function updateStatus(status) {
const statusMap = {
connected: { text: "Connected", class: "status-connected" },
connecting: { text: "Connecting...", class: "status-connecting" },
disconnected: { text: "Disconnected", class: "status-connecting" },
error: { text: "Connection Error", class: "status-error" },
};
const { text, class: className } = statusMap[status] || statusMap.error;
statusEl.textContent = text;
statusEl.className = className;
if (status === "connected") {
inputEl.disabled = false;
sendButtonEl.disabled = false;
}
}
// Send message
async function sendMessage() {
const content = inputEl.value.trim();
if (!content || !agent || isRunning) return;
inputEl.value = "";
try {
await agent.run({
messages: [
{ role: "user", content }
],
});
} catch (error) {
console.error("Failed to send message:", error);
alert("Failed to send message: " + error.message);
}
}
// Event listeners
sendButtonEl.addEventListener("click", sendMessage);
inputEl.addEventListener("keypress", (e) => {
if (e.key === "Enter") {
sendMessage();
}
});
// Initialize
initializeAgent();
</script>
</body>
</html>
TypeScript Support
CopilotKit Core is fully typed. Import types for better developer experience:import type {
CopilotKitCore,
CopilotKitCoreConfig,
CopilotKitCoreSubscriber,
CopilotKitCoreRuntimeConnectionStatus,
CopilotKitCoreErrorCode,
FrontendTool,
SuggestionsConfig,
} from "@copilotkitnext/core";
import type {
AbstractAgent,
Context,
State,
Message,
} from "@ag-ui/client";
Next Steps
React Integration
Use CopilotKit with React hooks and components
Angular Integration
Use CopilotKit with Angular services and directives
Tool Development
Build custom tools for your agents
