16 KiB
CopilotKit v2 Breaking Changes
Package Structure
Consolidated React packages
v1 split React functionality across three packages:
@copilotkit/react-core-- provider, hooks, types@copilotkit/react-ui-- chat components (CopilotChat, CopilotPopup, CopilotSidebar)@copilotkit/react-textarea-- CopilotTextarea component
v2 consolidates the React surface under the /v2 subpath of the same @copilotkit/react-core package (there is no @copilotkit/react package):
@copilotkit/react-core/v2-- provider, hooks, types, chat components, and AG-UI re-exports (@copilotkit/react-core/v2/styles.cssfor styles)
Same package names, new subpath
The v2 API is exposed through the same @copilotkit/* packages -- no package name changes are required when upgrading. The v2 symbols live under the /v2 subpath (@copilotkit/react-core/v2, @copilotkit/runtime/v2, @copilotkit/runtime/v2/express).
Removed packages
| Package | Status |
|---|---|
@copilotkit/react-textarea |
No v2 equivalent. The v1 package stays installable; remove it only after migrating off CopilotTextarea. |
@copilotkit/runtime-client-gql |
Replaced by @ag-ui/client (re-exported from @copilotkit/react-core/v2) |
@copilotkit/sdk-js |
Removed. BuiltInAgent and agent definitions ship from @copilotkit/runtime/v2 |
Protocol Change: GraphQL to AG-UI
The most fundamental breaking change is the protocol layer. v1 used a GraphQL-based protocol (@copilotkit/runtime-client-gql). v2 uses the AG-UI protocol (@ag-ui/client / @ag-ui/core), which is SSE-based.
Impact:
- All GraphQL message types (
TextMessage,ActionExecutionMessage,ResultMessage, etc.) are replaced by AG-UI event types (TextMessageChunkEvent,ToolCallStartEvent,ToolCallArgsEvent,ToolCallEndEvent,ToolCallResultEvent, etc.) - The
MessageRoleenum is replaced by AG-UI message roles - Custom GraphQL queries/mutations against the runtime are no longer possible
- The runtime no longer exposes a GraphQL endpoint
Provider Changes
Component import path change
The provider keeps the name CopilotKit; the import path changes from the package root (@copilotkit/react-core, legacy v1) to the /v2 subpath (@copilotkit/react-core/v2). The /v2 subpath also exports a CopilotKitProvider component -- do not migrate to it. It is a functionality subset of CopilotKit, which is the compatibility bridge across v1 and v2 (its CopilotKitProps extends Omit<CopilotKitProviderProps, "children"> with a narrowed children type, so every non-children CopilotKitProvider prop works on it).
Props changes
| v1 Prop | v2 Status | Notes |
|---|---|---|
runtimeUrl |
Kept | Same behavior |
headers |
Kept | Same behavior |
publicApiKey |
Kept (deprecated) | publicLicenseKey is the canonical name |
properties |
Kept | Same behavior |
agents |
Removed | Use selfManagedAgents or agents__unsafe_dev_only |
guardrails_c |
Kept (CopilotCloud only) | Marked @internal/defunct in source, but still wired into the legacy CopilotCloud restrictToTopic config when a cloud key (publicApiKey) is set; has no effect on the v2 AG-UI runtime path |
children |
Kept | Same behavior |
| -- | Added: credentials |
RequestCredentials for fetch (e.g., "include" for cookies) |
| -- | Added: selfManagedAgents |
Record<string, AbstractAgent> for client-side agents |
| -- | Added: renderToolCalls |
ReactToolCallRenderer[] for provider-level tool renderers |
| -- | Added: renderActivityMessages |
ReactActivityMessageRenderer[] for activity renderers |
| -- | Added: useSingleEndpoint |
Boolean to use single-route endpoint mode |
Context hook rename
useCopilotContext is replaced by useCopilotKit (imported from @copilotkit/react-core/v2/context), which returns { copilotkit: CopilotKitCoreReact, executingToolCallIds: ReadonlySet<string> }.
Hook Renames and API Changes
useCopilotAction -> useFrontendTool
Parameter definition change: v1 used a custom parameter descriptor format. v2 uses Zod schemas.
// v1 parameters
parameters: [
{ name: "city", type: "string", description: "City name", required: true },
{ name: "units", type: "string", enum: ["celsius", "fahrenheit"] },
];
// v2 parameters (Zod)
parameters: z.object({
city: z.string().describe("City name"),
units: z.enum(["celsius", "fahrenheit"]).optional(),
});
Handler signature change:
// v1
handler: ({ city, units }) => { ... }
// v2
handler: async (args) => { ... } // args is typed from the Zod schema
Render props change:
// v1 render status: the string literals "inProgress" | "executing" | "complete"
// v1 uses `respond()` callback for interactive actions
// v2 render status: the `ToolCallStatus` enum (ToolCallStatus.InProgress | .Executing | .Complete).
// Its values ARE those same strings, so `status === "inProgress"` still works;
// prefer comparing against the enum members.
// v2 render props: { name, toolCallId, args, status, result }
Availability change:
// v1
disabled: true;
// v2 — `available` is a boolean (defaults to true; set false to hide the tool)
available: false;
useCopilotReadable -> useAgentContext
Breaking: The parentId parameter for hierarchical context is removed. Flatten nested contexts.
// v1 (hierarchical)
const parentId = useCopilotReadable({ description: "Parent", value: "..." });
useCopilotReadable({ description: "Child", value: "...", parentId });
// v2 (flat)
useAgentContext({
description: "Parent - Child context",
value: { parent: "...", child: "..." },
});
useCoAgent -> useAgent
Breaking: Completely different return type.
// v1 returns
{
(name, nodeName, state, setState, running, start, stop, run);
}
// v2 returns
AbstractAgent; // AG-UI agent instance with run(), stop(), etc.
name->agentId(in props)initialState-> removed (no client-side state initialization)setState-> removed (state flows via AG-UI events)nodeName-> removedstate-> accessed through AG-UIStateSnapshotEvent/StateDeltaEvent
useLangGraphInterrupt -> useInterrupt
Breaking: Different API shape.
agentName->agentIdnodeName-> removed (useenabledpredicate to filter)renderprops change: v2 receivesInterruptRenderProps<TValue, TResult>={ event, resolve, result }(still includesevent/resolve, addsresult)- New
renderInChatprop (defaulttrue) controls whether interrupt renders inside CopilotChat - New
handlerprop for programmatic handling before rendering - New
enabledpredicate prop for filtering interrupts
useCopilotChat -> removed
Replaced by useAgent for agent interaction. The headless chat API (appendMessage, visibleMessages, etc.) is replaced by the AG-UI agent event stream.
useCopilotChatSuggestions -> useConfigureSuggestions + useSuggestions
Split into two hooks: one for configuration, one for reading state.
useCoAgentStateRender -> useRenderToolCall / useRenderActivityMessage
Split into two hooks based on the type of rendering needed.
useCopilotAdditionalInstructions -> useAgentContext
Use useAgentContext with an appropriate description to provide instructions.
useMakeCopilotDocumentReadable -> useAgentContext
Use useAgentContext to pass document content. The DocumentPointer type and category-based filtering are removed.
Runtime Breaking Changes
Service adapters removed
All service adapters are removed from the runtime:
| Removed Adapter | v2 Alternative |
|---|---|
OpenAIAdapter |
Use BuiltInAgent({ model: "openai/gpt-4o" }) |
AnthropicAdapter |
Use BuiltInAgent({ model: "anthropic/claude-sonnet-4.5" }) |
GoogleGenerativeAIAdapter |
Use BuiltInAgent({ model: "google/gemini-2.5-pro" }) |
LangChainAdapter |
Use a custom AbstractAgent implementation |
GroqAdapter |
Use a custom AbstractAgent (pass a Groq LanguageModel instance) |
UnifyAdapter |
Use a custom AbstractAgent implementation |
OpenAIAssistantAdapter |
Use a custom AbstractAgent implementation |
BedrockAdapter |
Use a custom AbstractAgent implementation |
OllamaAdapter |
Use a custom AbstractAgent implementation |
EmptyAdapter |
Not needed |
Runtime constructor changes
// v1
new CopilotRuntime({
actions: [...], // Removed
remoteEndpoints: [...], // Removed
remoteActions: [...], // Removed
onBeforeRequest: (options) => {}, // Deprecated
onAfterRequest: (options) => {}, // Deprecated
})
// v2
new CopilotRuntime({
agents: { ... }, // Required: Record<string, AbstractAgent>
transcriptionService: ..., // Optional: TranscriptionService
beforeRequestMiddleware: ..., // Optional: BeforeRequestMiddleware
afterRequestMiddleware: ..., // Optional: AfterRequestMiddleware
a2ui: { ... }, // Optional: A2UIMiddleware config
mcpApps: { servers: [...] }, // Optional: MCP Apps middleware
// Intelligence mode only:
intelligence: new CopilotKitIntelligence({ ... }),
identifyUser: (request) => ({ id: "..." }),
generateThreadNames: true,
})
Framework integrations removed
v1 had built-in integrations for Next.js (App Router, Pages Router), Express, NestJS, and Node HTTP. v2 uses Hono as the standard HTTP layer:
| v1 Integration | v2 Replacement |
|---|---|
copilotRuntimeNextJSAppRouterEndpoint |
createCopilotHonoHandler (Hono, works with Next.js) |
copilotRuntimeNextJSPagesRouterEndpoint |
createCopilotHonoHandler (Hono) |
CopilotRuntimeNodeExpressEndpoint |
createCopilotExpressHandler (@copilotkit/runtime/v2/express) |
CopilotRuntimeNestEndpoint |
Use Hono adapter or Express endpoint |
CopilotRuntimeNodeHttpEndpoint |
Use Hono or Express endpoint |
Endpoint configuration
// v1 (Next.js App Router example)
import { copilotRuntimeNextJSAppRouterEndpoint } from "@copilotkit/runtime";
export const POST = copilotRuntimeNextJSAppRouterEndpoint({
runtime,
serviceAdapter,
endpoint: "/api/copilotkit",
});
// v2 -- use createCopilotHonoHandler (createCopilotEndpoint is a deprecated alias)
import { createCopilotHonoHandler } from "@copilotkit/runtime/v2";
const app = createCopilotHonoHandler({
runtime,
basePath: "/api/copilotkit",
cors: {
origin: "https://myapp.com",
credentials: true,
},
});
// For Next.js App Router, export the Hono app's fetch handler
export const POST = app.fetch;
export const GET = app.fetch;
LangGraph agent configuration
// v1 (remote endpoint)
new CopilotRuntime({
remoteEndpoints: [
{
url: "http://localhost:8000/copilotkit",
type: "langgraph",
},
],
});
// v2 (direct agent instance)
import { LangGraphAgent } from "@copilotkit/runtime/langgraph";
new CopilotRuntime({
agents: {
myAgent: new LangGraphAgent({
deploymentUrl: "http://localhost:8000",
graphId: "my-graph",
}),
},
});
Type System Changes
Parameter types
v1 used a custom Parameter type for defining tool parameters:
type Parameter = {
name: string;
type:
| "string"
| "number"
| "boolean"
| "object"
| "string[]"
| "number[]"
| "boolean[]"
| "object[]";
description?: string;
required?: boolean;
enum?: string[];
attributes?: Parameter[]; // for object types
};
v2 uses Zod schemas (z.object(...)) or Standard Schema V1 (StandardSchemaV1).
Message types
v1 GraphQL types from @copilotkit/runtime-client-gql are replaced by AG-UI types:
| v1 Type | v2 Type |
|---|---|
TextMessage |
Message with text content |
ActionExecutionMessage |
ToolCall |
ResultMessage |
ToolMessage |
MessageRole |
AG-UI role types |
Event types
v2 introduces AG-UI event types for streaming:
RunStartedEvent,RunFinishedEvent,RunErrorEventTextMessageChunkEventToolCallStartEvent,ToolCallArgsEvent,ToolCallEndEvent,ToolCallResultEventStateSnapshotEvent,StateDeltaEventReasoningStartEvent,ReasoningMessageStartEvent,ReasoningMessageContentEvent,ReasoningMessageEndEvent,ReasoningEndEvent