chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:58:18 +08:00
commit 6d5d58c1a9
18293 changed files with 3502153 additions and 0 deletions
@@ -0,0 +1,533 @@
# CopilotKit v2 Public API Reference
Package imports: `@copilotkit/react-core/v2`, `@copilotkit/runtime/v2`, `@copilotkit/core`.
Note: `@copilotkit/react-core/v2` re-exports everything from `@ag-ui/client` (which itself re-exports `@ag-ui/core`), so applications typically only need `@copilotkit/react-core/v2` and `@copilotkit/runtime/v2`.
---
## Hooks (`@copilotkit/react-core/v2`)
### useFrontendTool
```ts
function useFrontendTool<T extends Record<string, unknown>>(
tool: ReactFrontendTool<T>,
deps?: ReadonlyArray<unknown>,
): void;
```
Registers a tool that the agent can invoke in the browser. The tool object has these fields:
- `name: string` -- Tool name (must be unique per agentId scope).
- `description?: string` -- Human/model-readable description.
- `parameters?: StandardSchemaV1<any, T>` -- Schema for tool arguments (Zod, Valibot, ArkType, etc.).
- `handler?: (args: T, context: FrontendToolHandlerContext) => Promise<unknown>` -- Function called when the agent invokes the tool.
- `render?: React.ComponentType<...>` -- Optional inline renderer for the tool call in chat.
- `agentId?: string` -- Constrain to a specific agent.
- `available?: boolean` -- Toggle visibility without unregistering. Defaults to `true`.
- `followUp?: boolean` -- Whether the agent should follow up after tool execution.
Re-registers when `tool.name`, `tool.available`, or any value in `deps` changes.
---
### useComponent
```ts
function useComponent<TSchema extends StandardSchemaV1 | undefined = undefined>(
config: {
name: string;
description?: string;
parameters?: TSchema;
render: ComponentType<InferRenderProps<TSchema>>;
agentId?: string;
},
deps?: ReadonlyArray<unknown>,
): void;
```
Convenience wrapper around `useFrontendTool`. Registers a React component as a visual tool in chat. The model is told to use the tool to "display the component." Render props are inferred from the `parameters` schema.
---
### useAgentContext
```ts
function useAgentContext(context: AgentContextInput): void;
interface AgentContextInput {
description: string;
value: JsonSerializable; // string | number | boolean | null | array | object
}
```
Shares application state with the agent. The `value` is serialized to JSON and registered as context. Context is removed on unmount.
---
### useAgent
```ts
function useAgent(props?: UseAgentProps): { agent: AbstractAgent };
interface UseAgentProps {
agentId?: string;
updates?: UseAgentUpdate[];
}
enum UseAgentUpdate {
OnMessagesChanged = "OnMessagesChanged",
OnStateChanged = "OnStateChanged",
OnRunStatusChanged = "OnRunStatusChanged",
}
```
Returns the `AbstractAgent` instance for the given `agentId` (defaults to `"default"`). Subscribes to the specified update categories to trigger re-renders. By default subscribes to all three.
While the runtime is connecting, returns a provisional `ProxiedCopilotRuntimeAgent` to prevent crashes.
---
### useInterrupt
```ts
function useInterrupt<
TResult = never,
TRenderInChat extends boolean | undefined = undefined,
>(
config: UseInterruptConfig<any, TResult, TRenderInChat>,
): React.ReactElement | null | void;
interface UseInterruptConfig<TValue, TResult, TRenderInChat> {
render: (
props: InterruptRenderProps<TValue, TResult | null>,
) => React.ReactElement;
handler?: (
props: InterruptHandlerProps<TValue>,
) => TResult | PromiseLike<TResult>;
enabled?: (event: InterruptEvent<TValue>) => boolean;
agentId?: string;
renderInChat?: TRenderInChat; // default: true
}
interface InterruptEvent<TValue = unknown> {
name: string;
value: TValue;
}
interface InterruptRenderProps<TValue, TResult> {
event: InterruptEvent<TValue>;
result: TResult;
resolve: (response: unknown) => void;
}
```
Handles agent `on_interrupt` events. When `renderInChat` is `true` (default), the element is published into `<CopilotChat>` and the hook returns `void`. When `false`, it returns the element for manual placement. Call `resolve()` from your render to resume the agent.
---
### useHumanInTheLoop
```ts
function useHumanInTheLoop<T extends Record<string, unknown>>(
tool: ReactHumanInTheLoop<T>,
deps?: ReadonlyArray<unknown>,
): void;
```
Registers a tool that pauses agent execution until the user responds. The `render` component receives a `respond` callback during the `"executing"` phase. Built on top of `useFrontendTool` with a promise-based handler.
```ts
type ReactHumanInTheLoop<T> = Omit<FrontendTool<T>, "handler"> & {
render: React.ComponentType<
| { status: "inProgress"; args: Partial<T>; respond: undefined }
| {
status: "executing";
args: T;
respond: (result: unknown) => Promise<void>;
}
| { status: "complete"; args: T; result: string; respond: undefined }
>;
};
```
---
### useRenderTool
```ts
// Named tool renderer with typed parameters
function useRenderTool<S extends StandardSchemaV1>(
config: {
name: string;
parameters: S;
render: (props: RenderToolProps<S>) => React.ReactElement;
agentId?: string;
},
deps?: ReadonlyArray<unknown>,
): void;
// Wildcard renderer (fallback for unregistered tools)
function useRenderTool(
config: {
name: "*";
render: (props: any) => React.ReactElement;
agentId?: string;
},
deps?: ReadonlyArray<unknown>,
): void;
type RenderToolProps<S> =
| {
name: string;
parameters: Partial<InferSchemaOutput<S>>;
status: "inProgress";
result: undefined;
}
| {
name: string;
parameters: InferSchemaOutput<S>;
status: "executing";
result: undefined;
}
| {
name: string;
parameters: InferSchemaOutput<S>;
status: "complete";
result: string;
};
```
Registers a visual renderer for tool calls in the chat. Renderers are deduplicated by `agentId:name`. The renderer is intentionally NOT removed on unmount so historical tool calls can still render.
---
### useDefaultRenderTool
```ts
function useDefaultRenderTool(
config?: { render?: (props: DefaultRenderProps) => React.ReactElement },
deps?: ReadonlyArray<unknown>,
): void;
```
Registers a wildcard `"*"` renderer via `useRenderTool`. With no arguments, uses the built-in expandable card UI showing tool name, status badge, arguments, and result.
---
### useSuggestions
```ts
function useSuggestions(options?: { agentId?: string }): UseSuggestionsResult;
interface UseSuggestionsResult {
suggestions: Suggestion[];
reloadSuggestions: () => void;
clearSuggestions: () => void;
isLoading: boolean;
}
type Suggestion = {
title: string;
message: string;
isLoading: boolean;
};
```
Reads the current suggestion list for an agent. Subscribes to real-time updates.
---
### useConfigureSuggestions
```ts
function useConfigureSuggestions(
config: SuggestionsConfigInput | null | undefined,
deps?: ReadonlyArray<unknown>,
): void;
```
Registers a suggestion configuration. Two modes:
**Dynamic** (LLM-generated):
```ts
{
instructions: "Suggest follow-up questions about the data",
minSuggestions?: number, // default 1
maxSuggestions?: number, // default 3
available?: "before-first-message" | "after-first-message" | "always" | "disabled",
providerAgentId?: string,
consumerAgentId?: string, // default "*"
}
```
**Static**:
```ts
{
suggestions: [{ title: "...", message: "..." }],
available?: SuggestionAvailability,
consumerAgentId?: string,
}
```
---
### useThreads
```ts
function useThreads(input: UseThreadsInput): UseThreadsResult;
interface UseThreadsInput {
agentId: string;
includeArchived?: boolean; // default: false
limit?: number; // enables cursor-based pagination when set
}
interface UseThreadsResult {
threads: Thread[];
isLoading: boolean;
error: Error | null;
hasMoreThreads: boolean;
isFetchingMoreThreads: boolean;
fetchMoreThreads: () => void;
renameThread: (threadId: string, name: string) => Promise<void>;
archiveThread: (threadId: string) => Promise<void>;
deleteThread: (threadId: string) => Promise<void>;
}
interface Thread {
id: string;
agentId: string;
name: string | null;
archived: boolean;
createdAt: string;
updatedAt: string;
lastRunAt?: string; // last agent run; prefer over updatedAt for "last activity"
}
```
Lists and manages Intelligence platform threads. Thread operations are scoped to the runtime-authenticated user (no `userId` input) and the given `agentId`. Uses a realtime WebSocket subscription when available.
---
### useRenderToolCall (internal)
```ts
function useRenderToolCall(): (props: {
toolCall: ToolCall;
toolMessage?: ToolMessage;
}) => React.ReactElement | null;
```
Returns a function that resolves the correct renderer for a tool call. Priority: exact name match (prefer agent-scoped) > wildcard `"*"`.
---
### useRenderActivityMessage (internal)
```ts
function useRenderActivityMessage(): {
renderActivityMessage: (
message: ActivityMessage,
) => React.ReactElement | null;
findRenderer: (activityType: string) => ReactActivityMessageRenderer | null;
};
```
Resolves and renders activity messages by type. Matches by `activityType` with agent-scoping, falls back to wildcard `"*"`.
---
### useRenderCustomMessages (internal)
Returns a function to render custom message decorators at `"before"` or `"after"` positions relative to each message.
---
## Components (`@copilotkit/react-core/v2`)
### CopilotKit (provider)
Import from `@copilotkit/react-core/v2`. The recommended root provider -- a compatibility bridge across v1 and v2 and a strict superset of the legacy `CopilotKitProvider` (all props below work on it).
```tsx
<CopilotKit
runtimeUrl?: string
headers?: Record<string, string>
credentials?: RequestCredentials
publicLicenseKey?: string // deprecated alias: publicApiKey
properties?: Record<string, unknown>
agents__unsafe_dev_only?: Record<string, AbstractAgent>
selfManagedAgents?: Record<string, AbstractAgent>
renderToolCalls?: ReactToolCallRenderer[]
renderActivityMessages?: ReactActivityMessageRenderer[]
renderCustomMessages?: ReactCustomMessageRenderer[]
frontendTools?: ReactFrontendTool[]
humanInTheLoop?: ReactHumanInTheLoop[]
showDevConsole?: boolean | "auto"
useSingleEndpoint?: boolean
onError?: (event: { error: Error; code: CopilotKitCoreErrorCode; context: Record<string, any> }) => void
a2ui?: { theme?: A2UITheme }
>
{children}
</CopilotKit>
```
Root provider. Configures the runtime connection, registers static tool renderers and tools, and provides the CopilotKit context to all descendant hooks and components.
---
### CopilotChat
```tsx
<CopilotChat
agentId?: string // default: "default"
threadId?: string // auto-generated if omitted
labels?: Partial<CopilotChatLabels>
chatView?: SlotValue<typeof CopilotChatView>
onError?: (event: { error: Error; code: CopilotKitCoreErrorCode; context: Record<string, any> }) => void
// Plus all CopilotChatViewProps (messageView, input, suggestionView, welcomeScreen, etc.)
/>
```
Full chat interface. Connects to the agent on mount, handles message submission, suggestion selection, stop, and audio transcription.
---
### CopilotPopup
```tsx
<CopilotPopup
// All CopilotChat props, plus:
header?: SlotValue
toggleButton?: SlotValue
defaultOpen?: boolean
width?: number | string
height?: number | string
clickOutsideToClose?: boolean
/>
```
Chat in a floating popup with a toggle button.
---
### CopilotSidebar
```tsx
<CopilotSidebar
// All CopilotChat props, plus:
header?: SlotValue
toggleButton?: SlotValue
defaultOpen?: boolean
width?: number | string
/>
```
Chat in a collapsible sidebar panel.
---
### CopilotChatView
Headless chat view with a slot-based architecture. Accepts slots for `messageView`, `scrollView`, `input`, `suggestionView`, and `welcomeScreen`. Also exposes sub-components: `CopilotChatView.ScrollView`, `CopilotChatView.Feather`, `CopilotChatView.WelcomeScreen`, `CopilotChatView.WelcomeMessage`, `CopilotChatView.ScrollToBottomButton`.
---
### Other Chat Sub-Components
- `CopilotChatInput` -- Textarea with send, stop, and transcription controls.
- `CopilotChatMessageView` -- Renders the message list.
- `CopilotChatAssistantMessage` -- Single assistant message bubble.
- `CopilotChatUserMessage` -- Single user message bubble.
- `CopilotChatReasoningMessage` -- Reasoning/thinking message display.
- `CopilotChatSuggestionView` -- Renders suggestion pills.
- `CopilotChatSuggestionPill` -- Individual suggestion pill.
- `CopilotChatToolCallsView` -- Renders tool call results in a message.
- `CopilotChatToggleButton` -- Open/close toggle for popup/sidebar.
- `CopilotModalHeader` -- Header bar for popup/sidebar modals.
- `CopilotPopupView` -- Popup layout wrapper.
- `CopilotSidebarView` -- Sidebar layout wrapper.
- `CopilotKitInspector` -- Dev console overlay (controlled by `showDevConsole`).
- `MCPAppsActivityRenderer` -- Built-in renderer for MCP Apps activity messages.
- `WildcardToolCallRender` -- Built-in wildcard tool call renderer component.
---
## Types (`@copilotkit/react-core/v2`)
### ReactFrontendTool
```ts
type ReactFrontendTool<T> = FrontendTool<T> & {
render?: ReactToolCallRenderer<T>["render"];
};
```
### ReactToolCallRenderer
```ts
interface ReactToolCallRenderer<T> {
name: string;
args: StandardSchemaV1<any, T>;
agentId?: string;
render: React.ComponentType<
| {
name: string;
args: Partial<T>;
status: "inProgress";
result: undefined;
}
| { name: string; args: T; status: "executing"; result: undefined }
| { name: string; args: T; status: "complete"; result: string }
>;
}
```
### ReactHumanInTheLoop
See `useHumanInTheLoop` above.
### ReactActivityMessageRenderer
```ts
interface ReactActivityMessageRenderer<TActivityContent> {
activityType: string; // or "*" for wildcard
agentId?: string;
content: StandardSchemaV1<any, TActivityContent>;
render: React.ComponentType<{
activityType: string;
content: TActivityContent;
message: ActivityMessage;
agent: AbstractAgent | undefined;
}>;
}
```
### ToolCallStatus
```ts
enum ToolCallStatus {
InProgress = "inProgress",
Executing = "executing",
Complete = "complete",
}
```
### FrontendToolHandlerContext
```ts
type FrontendToolHandlerContext = {
toolCall: ToolCall;
agent: AbstractAgent;
};
```
---
## Runtime (`@copilotkit/runtime/v2`)
See [runtime-api.md](./runtime-api.md) for full runtime reference.
@@ -0,0 +1,242 @@
# CopilotChat Customization Reference
## CopilotChat Props
`CopilotChat` is the primary chat component. It wraps `CopilotChatView` and handles agent connection, message submission, suggestions, stop, and audio transcription.
```tsx
interface CopilotChatProps {
// Agent configuration
agentId?: string; // Agent to connect to. Default: "default"
threadId?: string; // Thread ID. Auto-generated UUID if omitted.
// Labels and text customization
labels?: Partial<CopilotChatLabels>;
// Layout override
chatView?: SlotValue<typeof CopilotChatView>;
// Error handling (scoped to this chat's agent)
onError?: (event: {
error: Error;
code: CopilotKitCoreErrorCode;
context: Record<string, any>;
}) => void;
// All CopilotChatViewProps are also accepted (see below)
}
```
## CopilotChatView Props (Layout Slots)
`CopilotChatView` uses a slot-based architecture. Each slot can be:
- Omitted (uses the default component)
- A props object (merges with the default component)
- A custom React component (replaces the default)
```tsx
interface CopilotChatViewProps {
// Slot overrides
messageView?: SlotValue<typeof CopilotChatMessageView>;
scrollView?: SlotValue<typeof CopilotChatView.ScrollView>;
input?: SlotValue<typeof CopilotChatInput>;
suggestionView?: SlotValue<typeof CopilotChatSuggestionView>;
// Welcome screen: true (default), false (disabled), or custom component
welcomeScreen?: SlotValue<React.FC<WelcomeScreenProps>> | boolean;
// Data (usually provided by CopilotChat, not set directly)
messages?: Message[];
isRunning?: boolean;
suggestions?: Suggestion[];
autoScroll?: boolean; // Default: true
// Input behavior (usually provided by CopilotChat)
onSubmitMessage?: (value: string) => void;
onStop?: () => void;
inputMode?: "input" | "transcribe" | "processing";
inputValue?: string;
onInputChange?: (value: string) => void;
// Transcription handlers
onStartTranscribe?: () => void;
onCancelTranscribe?: () => void;
onFinishTranscribe?: () => void;
onFinishTranscribeWithAudio?: (audioBlob: Blob) => Promise<void>;
// Standard HTML div props
className?: string;
// ...rest HTMLAttributes<HTMLDivElement>
}
```
## Labels (Text Customization)
All user-visible text can be customized via the `labels` prop:
```tsx
const CopilotChatDefaultLabels = {
chatInputPlaceholder: "Type a message...",
chatInputToolbarStartTranscribeButtonLabel: "Transcribe",
chatInputToolbarCancelTranscribeButtonLabel: "Cancel",
chatInputToolbarFinishTranscribeButtonLabel: "Finish",
chatInputToolbarAddButtonLabel: "Add photos or files",
chatInputToolbarToolsButtonLabel: "Tools",
assistantMessageToolbarCopyCodeLabel: "Copy",
assistantMessageToolbarCopyCodeCopiedLabel: "Copied",
assistantMessageToolbarCopyMessageLabel: "Copy",
assistantMessageToolbarThumbsUpLabel: "Good response",
assistantMessageToolbarThumbsDownLabel: "Bad response",
assistantMessageToolbarReadAloudLabel: "Read aloud",
assistantMessageToolbarRegenerateLabel: "Regenerate",
userMessageToolbarCopyMessageLabel: "Copy",
userMessageToolbarEditMessageLabel: "Edit",
chatDisclaimerText:
"AI can make mistakes. Please verify important information.",
chatToggleOpenLabel: "Open chat",
chatToggleCloseLabel: "Close chat",
modalHeaderTitle: "CopilotKit Chat",
welcomeMessageText: "How can I help you today?",
};
```
Example:
```tsx
<CopilotChat
agentId="myAgent"
labels={{
chatInputPlaceholder: "Ask me anything...",
welcomeMessageText: "Welcome! How can I assist you?",
modalHeaderTitle: "AI Assistant",
}}
/>
```
## CopilotPopup Props
```tsx
interface CopilotPopupProps extends CopilotChatProps {
header?: SlotValue; // Custom header component
toggleButton?: SlotValue; // Custom toggle button
defaultOpen?: boolean; // Start open? Default: true
width?: number | string; // Popup width
height?: number | string; // Popup height
clickOutsideToClose?: boolean; // Close on outside click
}
```
## CopilotSidebar Props
```tsx
interface CopilotSidebarProps extends CopilotChatProps {
header?: SlotValue; // Custom header component
toggleButton?: SlotValue; // Custom toggle button
defaultOpen?: boolean; // Start open? Default: true
width?: number | string; // Sidebar width
}
```
## Styling
CopilotKit v2 uses Tailwind CSS with a `cpk:` prefix namespace. All internal classes use this prefix to avoid conflicts with your application's styles.
### CSS Data Attributes
The chat container exposes data attributes for CSS targeting:
- `[data-copilotkit]` -- Present on the root chat element.
- `[data-testid="copilot-chat"]` -- The main chat container.
- `[data-copilot-running="true"]` -- While the agent is running.
- `[data-testid="copilot-welcome-screen"]` -- The welcome screen container.
- `[data-sidebar-chat]` -- On sidebar layout wrapper.
- `[data-popup-chat]` -- On popup layout wrapper.
### Dark Mode
The components support dark mode through Tailwind's `dark:` variant. All internal components include `cpk:dark:` color variants. Enable dark mode by adding the `dark` class to a parent element per Tailwind convention.
### Slot-Based Customization
Every visual sub-component is a "slot" that can be replaced or extended:
```tsx
// Override the input component with custom props
<CopilotChat
input={{ className: "my-custom-input" }}
/>
// Replace the input entirely
<CopilotChat
input={MyCustomInput}
/>
// Override welcome screen
<CopilotChat
welcomeScreen={({ input, suggestionView }) => (
<div className="my-welcome">
<h1>Hello!</h1>
{input}
{suggestionView}
</div>
)}
/>
// Disable welcome screen
<CopilotChat welcomeScreen={false} />
```
### CopilotChatView Sub-Components
These can be used directly when building fully custom layouts:
- `CopilotChatView.ScrollView` -- Scroll container with auto-scroll (uses `use-stick-to-bottom`).
- `CopilotChatView.ScrollToBottomButton` -- Floating "scroll to bottom" button.
- `CopilotChatView.Feather` -- Bottom gradient overlay.
- `CopilotChatView.WelcomeScreen` -- Default welcome layout.
- `CopilotChatView.WelcomeMessage` -- Welcome heading text.
### CopilotChatInput Slots
The input component has its own slots:
- `textArea` -- The textarea element.
- `sendButton` -- Send/stop button.
- `startTranscribeButton` -- Microphone button.
- `cancelTranscribeButton` -- Cancel recording button.
- `finishTranscribeButton` -- Finish recording button.
- `addMenuButton` -- File attachment button.
- `audioRecorder` -- Audio recording component.
- `disclaimer` -- Disclaimer text below the input.
## System Prompt / Agent Context
CopilotKit v2 does not have a `systemPrompt` prop on the chat component. Instead, context is provided to agents through:
1. **`useAgentContext`** -- Share structured application data.
2. **Agent configuration** -- System prompts are configured on the agent itself (server-side), not on the React chat component.
## Error Handling
Errors can be handled at two levels:
```tsx
// Provider-level: catches all errors
<CopilotKit
runtimeUrl="/api/copilotkit"
onError={({ error, code, context }) => {
console.error("CopilotKit error:", code, error.message);
}}
>
{/* Chat-level: catches errors for this specific agent */}
<CopilotChat
agentId="myAgent"
onError={({ error, code }) => {
showToast(`Agent error: ${error.message}`);
}}
/>
</CopilotKit>
```
The chat-level `onError` fires in addition to (not instead of) the provider-level handler. It only receives errors whose `context.agentId` matches the chat's agent.
@@ -0,0 +1,370 @@
# CopilotKit v2 Runtime API Reference
Package: `@copilotkit/runtime/v2` (`createCopilotExpressHandler` from `@copilotkit/runtime/v2/express`)
---
## Runtime Classes
### CopilotRuntime
Compatibility shim that auto-detects the mode based on whether `intelligence` is provided. Delegates to `CopilotSseRuntime` or `CopilotIntelligenceRuntime`.
```ts
import { CopilotRuntime } from "@copilotkit/runtime/v2";
const runtime = new CopilotRuntime({
agents: { myAgent: new LangGraphAgent({ ... }) },
// If intelligence is provided, uses Intelligence mode; otherwise SSE mode
});
```
### CopilotSseRuntime
Explicit SSE-mode runtime. Agents run in-memory via `InMemoryAgentRunner`.
```ts
import { CopilotSseRuntime } from "@copilotkit/runtime/v2";
const runtime = new CopilotSseRuntime({
agents: { myAgent: agent },
runner?: AgentRunner, // default: InMemoryAgentRunner
});
```
### CopilotIntelligenceRuntime
Intelligence-mode runtime with durable threads, realtime events, and persistent state.
```ts
import {
CopilotIntelligenceRuntime,
CopilotKitIntelligence,
} from "@copilotkit/runtime/v2";
const runtime = new CopilotIntelligenceRuntime({
agents: { myAgent: agent },
intelligence: new CopilotKitIntelligence({ ... }),
identifyUser: async (request) => ({
id: getUserIdFromRequest(request),
name: getUserNameFromRequest(request),
}),
generateThreadNames?: boolean, // default: true
});
```
---
## Runtime Options
All runtime constructors accept these base options:
```ts
interface BaseCopilotRuntimeOptions {
// Map of available agents. Can be a promise for lazy loading.
agents: MaybePromise<Record<string, AbstractAgent>>;
// Optional transcription service for audio processing
transcriptionService?: TranscriptionService;
// Middleware hooks
beforeRequestMiddleware?: BeforeRequestMiddleware;
afterRequestMiddleware?: AfterRequestMiddleware;
// Auto-apply A2UI middleware to agents
a2ui?: {
agents?: string[]; // Limit to specific agents; omit for all
// ... A2UIMiddlewareConfig from @ag-ui/a2ui-middleware
};
// Auto-apply MCP Apps middleware
mcpApps?: {
servers: McpAppsServerConfig[];
};
}
```
### McpAppsServerConfig
```ts
type McpAppsServerConfig = MCPClientConfig & {
agentId?: string; // Bind to specific agent; omit for all agents
};
```
---
## Endpoint Factories
### createCopilotHonoHandler (Hono)
```ts
import { createCopilotHonoHandler } from "@copilotkit/runtime/v2";
const app = createCopilotHonoHandler({
runtime: CopilotRuntimeLike,
basePath: string,
mode?: "multi-route" | "single-route", // default: "multi-route"
cors?: {
origin: string | string[] | ((origin: string) => string | null);
credentials?: boolean;
},
});
```
Returns a Hono app instance with all CopilotKit routes mounted under `basePath`. Defaults to multi-route mode; pass `mode: "single-route"` to expose a single combined route.
### createCopilotExpressHandler (Express)
```ts
import { createCopilotExpressHandler } from "@copilotkit/runtime/v2/express";
const router = createCopilotExpressHandler({
runtime: CopilotRuntimeLike,
basePath: string,
mode?: "multi-route" | "single-route", // default: "multi-route"
});
// Use in Express app:
app.use(router);
```
Returns an Express `Router` with all CopilotKit routes mounted under `basePath`.
---
## HTTP Routes
Both endpoint factories create these routes under `basePath`:
| Method | Path | Description |
| -------- | -------------------------------- | ------------------------------------------------------------ |
| `GET` | `/info` | Runtime info: available agents, mode, capabilities |
| `POST` | `/agent/:agentId/run` | Run an agent (SSE stream response) |
| `POST` | `/agent/:agentId/connect` | Connect to an agent (initial handshake for existing threads) |
| `POST` | `/agent/:agentId/stop/:threadId` | Stop a running agent |
| `POST` | `/transcribe` | Transcribe audio file |
| `GET` | `/threads` | List threads (Intelligence mode) |
| `POST` | `/threads/subscribe` | Subscribe to thread updates (Intelligence mode) |
| `PATCH` | `/threads/:threadId` | Update thread metadata |
| `POST` | `/threads/:threadId/archive` | Archive a thread |
| `DELETE` | `/threads/:threadId` | Permanently delete a thread |
---
## Middleware
### BeforeRequestMiddleware
Called before each request handler. Can modify or replace the request.
```ts
type BeforeRequestMiddleware = (params: {
runtime: CopilotRuntimeLike;
request: Request;
path: string;
}) => MaybePromise<Request | void>;
```
If a `Request` is returned, it replaces the original request for the handler.
### AfterRequestMiddleware
Called after each request handler. Receives the response and parsed SSE messages.
```ts
type AfterRequestMiddleware = (params: {
runtime: CopilotRuntimeLike;
response: Response;
path: string;
messages?: Message[]; // Reconstructed from SSE stream
threadId?: string; // From RUN_STARTED event
runId?: string; // From RUN_STARTED event
}) => MaybePromise<void>;
```
### Example
```ts
const runtime = new CopilotRuntime({
agents: { myAgent: agent },
beforeRequestMiddleware: async ({ request, path }) => {
console.log(`Incoming request to ${path}`);
// Optionally return a modified Request
},
afterRequestMiddleware: async ({ response, path, threadId, messages }) => {
console.log(
`Response from ${path}, thread: ${threadId}, ${messages?.length} messages`,
);
},
});
```
---
## Intelligence Platform
### CopilotKitIntelligence
Client for the CopilotKit Intelligence platform (durable threads, realtime WebSocket).
```ts
import { CopilotKitIntelligence } from "@copilotkit/runtime/v2";
const intelligence = new CopilotKitIntelligence({
// Configuration for the Intelligence platform
// (API keys, URLs, etc.)
});
```
### identifyUser
Required for Intelligence mode. Resolves the authenticated user from the incoming request.
```ts
type IdentifyUserCallback = (
request: Request,
) => MaybePromise<{ id: string; name: string }>;
```
### Thread Management Types
```ts
interface CreateThreadRequest {
/* platform-specific */
}
interface ThreadSummary {
/* id, name, timestamps */
}
interface ListThreadsResponse {
/* thread list */
}
interface UpdateThreadRequest {
/* name updates */
}
interface SubscribeToThreadsRequest {
/* WebSocket subscription params */
}
interface SubscribeToThreadsResponse {
/* realtime thread updates */
}
```
---
## Agent Runners
### AgentRunner (abstract)
Base class for executing agents. Custom runners can be implemented for custom execution environments.
### InMemoryAgentRunner
Default runner for SSE mode. Runs agents in the Node.js process.
### IntelligenceAgentRunner
Runner for Intelligence mode. Delegates execution to the Intelligence platform via WebSocket.
---
## Transcription Service
### TranscriptionService (abstract)
```ts
interface TranscribeFileOptions {
audioFile: File;
mimeType?: string;
size?: number;
}
abstract class TranscriptionService {
abstract transcribeFile(options: TranscribeFileOptions): Promise<string>;
}
```
Implement this class to provide audio-to-text transcription. The runtime exposes it via the `/transcribe` endpoint.
---
## CORS Configuration
The Hono endpoint factory accepts explicit CORS configuration:
```ts
createCopilotHonoHandler({
runtime,
basePath: "/api/copilotkit",
cors: {
origin: "https://myapp.com", // or array, or function
credentials: true, // for HTTP-only cookies
},
});
```
When `credentials` is `true`, `origin` must be explicitly specified (cannot be `"*"`).
The Express endpoint factory uses `cors({ origin: "*" })` by default. Override by wrapping or configuring the Express cors middleware separately.
---
## Complete Example: Next.js API Route (using Hono)
```ts
// app/api/copilotkit/[[...path]]/route.ts
import {
CopilotRuntime,
createCopilotHonoHandler,
} from "@copilotkit/runtime/v2";
import { LangGraphAgent } from "@copilotkit/runtime/langgraph";
import { handle } from "hono/vercel";
const runtime = new CopilotRuntime({
agents: {
researcher: new LangGraphAgent({
graphId: "researcher",
deploymentUrl: process.env.LANGGRAPH_URL!,
}),
},
});
const app = createCopilotHonoHandler({
runtime,
basePath: "/api/copilotkit",
});
export const GET = handle(app);
export const POST = handle(app);
export const PATCH = handle(app);
export const DELETE = handle(app);
```
## Complete Example: Express
```ts
import express from "express";
import { CopilotRuntime } from "@copilotkit/runtime/v2";
import { createCopilotExpressHandler } from "@copilotkit/runtime/v2/express";
import { LangGraphAgent } from "@copilotkit/runtime/langgraph";
const app = express();
const runtime = new CopilotRuntime({
agents: {
researcher: new LangGraphAgent({
graphId: "researcher",
deploymentUrl: process.env.LANGGRAPH_URL!,
}),
},
});
app.use(
createCopilotExpressHandler({
runtime,
basePath: "/api/copilotkit",
}),
);
app.listen(3000);
```