@copilotkit/react-core
Version:
<img src="https://github.com/user-attachments/assets/0a6b64d9-e193-4940-a3f6-60334ac34084" alt="banner" style="border-radius: 12px; border: 2px solid #d6d4fa;" />
1,907 lines • 67 kB
JavaScript
"use client";
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const require_copilotkit = require('./copilotkit-Bocmlr37.cjs');
let react = require("react");
react = require_copilotkit.__toESM(react);
let _copilotkit_core = require("@copilotkit/core");
let _ag_ui_client = require("@ag-ui/client");
let _copilotkit_shared = require("@copilotkit/shared");
let _copilotkit_runtime_client_gql = require("@copilotkit/runtime-client-gql");
let _copilotkit_react_core_v2_context = require("@copilotkit/react-core/v2/context");
//#region src/utils/suggestions-constants.ts
/**
* Constants for suggestions retry logic
*/
const SUGGESTION_RETRY_CONFIG = {
MAX_RETRIES: 3,
COOLDOWN_MS: 5e3
};
//#endregion
//#region src/hooks/use-lazy-tool-renderer.tsx
function useLazyToolRenderer() {
const renderToolCall = require_copilotkit.useRenderToolCall();
return (0, react.useCallback)((message, messages) => {
if (!message?.toolCalls?.length) return null;
const toolCall = message.toolCalls[0];
if (!toolCall) return null;
const toolMessage = messages?.find((m) => m.role === "tool" && m.toolCallId === toolCall.id);
return () => renderToolCall({
toolCall,
toolMessage
});
}, [renderToolCall]);
}
//#endregion
//#region src/hooks/use-copilot-chat_internal.ts
function useCopilotChatInternal({ suggestions, onInProgress, onSubmitMessage, onStopGeneration, onReloadMessages } = {}) {
const { copilotkit } = (0, _copilotkit_react_core_v2_context.useCopilotKit)();
const { threadId, agentSession } = require_copilotkit.useCopilotContext();
const existingConfig = require_copilotkit.useCopilotChatConfiguration();
const [agentAvailable, setAgentAvailable] = (0, react.useState)(false);
const resolvedAgentId = existingConfig?.agentId ?? "default";
const { agent } = require_copilotkit.useAgent({ agentId: resolvedAgentId });
const lastConnectedAgentRef = (0, react.useRef)(null);
(0, react.useEffect)(() => {
let detached = false;
const connectAbortController = new AbortController();
if (agent instanceof _ag_ui_client.HttpAgent) agent.abortController = connectAbortController;
const connect = async (agent) => {
setAgentAvailable(false);
try {
await copilotkit.connectAgent({ agent });
if (!detached) setAgentAvailable(true);
} catch (error) {
if (detached) return;
if (error instanceof _ag_ui_client.AGUIConnectNotImplementedError) {} else console.error("CopilotChat: connectAgent failed", error);
}
};
if (agent && agent !== lastConnectedAgentRef.current && copilotkit.runtimeConnectionStatus === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Connected) {
lastConnectedAgentRef.current = agent;
connect(agent);
}
return () => {
lastConnectedAgentRef.current = null;
detached = true;
connectAbortController.abort();
agent?.detachActiveRun();
};
}, [
existingConfig?.threadId,
agent,
copilotkit,
copilotkit.runtimeConnectionStatus,
resolvedAgentId
]);
(0, react.useEffect)(() => {
onInProgress?.(Boolean(agent?.isRunning));
}, [agent?.isRunning, onInProgress]);
const [interrupt, setInterrupt] = (0, react.useState)(null);
(0, react.useEffect)(() => {
setInterrupt(copilotkit.interruptElement);
const subscription = copilotkit.subscribe({ onInterruptElementChanged: ({ interruptElement }) => {
setInterrupt(interruptElement);
} });
return () => subscription.unsubscribe();
}, [copilotkit]);
const reset = () => {
agent?.setMessages([]);
agent?.setState(null);
};
const latestDelete = useUpdatedRef((0, react.useCallback)((messageId) => {
const filteredMessages = (agent?.messages ?? []).filter((message) => message.id !== messageId);
agent?.setMessages(filteredMessages);
}, [agent?.setMessages, agent?.messages]));
const latestDeleteFunc = (0, react.useCallback)((messageId) => {
return latestDelete.current(messageId);
}, [latestDelete]);
const currentSuggestions = require_copilotkit.useSuggestions({ agentId: resolvedAgentId });
const reload = require_copilotkit.useAsyncCallback(async (reloadMessageId) => {
if (!agent) return;
const messages = agent?.messages ?? [];
if (agent.isRunning || messages.length === 0) return;
const reloadMessageIndex = messages.findIndex((msg) => msg.id === reloadMessageId);
if (reloadMessageIndex === -1) {
console.warn(`Message with id ${reloadMessageId} not found`);
return;
}
const reloadMessageRole = messages[reloadMessageIndex].role;
if (reloadMessageRole !== "assistant") {
console.warn(`Regenerate cannot be performed on ${reloadMessageRole} role`);
return;
}
let historyCutoff = [messages[0]];
if (messages.length > 2 && reloadMessageIndex !== 0) {
const lastUserMessageBeforeRegenerate = messages.slice(0, reloadMessageIndex).toReversed().find((msg) => msg.role === "user");
if (!lastUserMessageBeforeRegenerate) historyCutoff = [messages[0]];
else {
const indexOfLastUserMessageBeforeRegenerate = messages.findIndex((msg) => msg.id === lastUserMessageBeforeRegenerate.id);
historyCutoff = messages.slice(0, indexOfLastUserMessageBeforeRegenerate + 1);
}
} else if (messages.length > 2 && reloadMessageIndex === 0) historyCutoff = [messages[0], messages[1]];
agent?.setMessages(historyCutoff);
if (agent) try {
await copilotkit.runAgent({ agent });
} catch (error) {
console.error("CopilotChat: runAgent failed during reload", error);
}
}, [
agent?.messages.length,
agent?.isRunning,
agent?.setMessages,
copilotkit?.runAgent
]);
const latestSendMessageFunc = require_copilotkit.useAsyncCallback(async (message, options) => {
if (!agent) return;
const followUp = options?.followUp ?? true;
if (options?.clearSuggestions) copilotkit.clearSuggestions(resolvedAgentId);
if (onSubmitMessage) {
const content = typeof message.content === "string" ? message.content : message.content && "text" in message.content ? message.content.text : message.content && "filename" in message.content ? message.content.filename : "";
try {
await onSubmitMessage(content);
} catch (error) {
console.error("Error in onSubmitMessage:", error);
}
}
agent?.addMessage(message);
if (followUp) try {
await copilotkit.runAgent({ agent });
} catch (error) {
console.error("CopilotChat: runAgent failed", error);
}
}, [
agent,
copilotkit,
resolvedAgentId,
onSubmitMessage
]);
const latestAppendFunc = require_copilotkit.useAsyncCallback(async (message, options) => {
return latestSendMessageFunc((0, _copilotkit_runtime_client_gql.gqlToAGUI)([message])[0], options);
}, [latestSendMessageFunc]);
const latestSetMessagesFunc = (0, react.useCallback)((messages) => {
if (messages.every((message) => message instanceof _copilotkit_runtime_client_gql.Message)) return agent?.setMessages?.((0, _copilotkit_runtime_client_gql.gqlToAGUI)(messages));
return agent?.setMessages?.(messages);
}, [agent?.setMessages, agent]);
const latestReload = useUpdatedRef(reload);
const latestReloadFunc = require_copilotkit.useAsyncCallback(async (messageId) => {
onReloadMessages?.({
messageId,
currentAgentName: agent?.agentId,
messages: agent?.messages ?? []
});
return await latestReload.current(messageId);
}, [
latestReload,
agent,
onReloadMessages
]);
const latestStopFunc = (0, react.useCallback)(() => {
onStopGeneration?.({
currentAgentName: agent?.agentId,
messages: agent?.messages ?? []
});
return agent?.abortRun?.();
}, [onStopGeneration, agent]);
const latestReset = useUpdatedRef(reset);
const latestResetFunc = (0, react.useCallback)(() => {
return latestReset.current();
}, [latestReset]);
const lazyToolRendered = useLazyToolRenderer();
const renderCustomMessage = require_copilotkit.useRenderCustomMessages();
const legacyCustomMessageRenderer = useLegacyCoagentRenderer({
copilotkit,
agent,
agentId: resolvedAgentId,
threadId: existingConfig?.threadId ?? threadId
});
const allMessages = agent?.messages ?? [];
const resolvedMessages = (0, react.useMemo)(() => {
let processedMessages = allMessages.map((message) => {
if (message.role !== "assistant") return message;
const lazyRendered = lazyToolRendered(message, allMessages);
if (lazyRendered) {
const renderedGenUi = lazyRendered();
if (renderedGenUi) return {
...message,
generativeUI: () => renderedGenUi
};
}
const bridgeRenderer = legacyCustomMessageRenderer || renderCustomMessage ? () => {
if (legacyCustomMessageRenderer) return legacyCustomMessageRenderer({
message,
position: "before"
});
try {
return renderCustomMessage?.({
message,
position: "before"
}) ?? null;
} catch (error) {
console.warn("[CopilotKit] renderCustomMessages failed, falling back to legacy renderer", error);
return null;
}
} : null;
if (bridgeRenderer) return {
...message,
generativeUI: bridgeRenderer,
generativeUIPosition: "before"
};
return message;
});
const hasAssistantMessages = processedMessages.some((msg) => msg.role === "assistant");
const canUseCustomRenderer = Boolean(renderCustomMessage && copilotkit?.getAgent?.(resolvedAgentId));
const placeholderRenderer = legacyCustomMessageRenderer ? legacyCustomMessageRenderer : canUseCustomRenderer ? renderCustomMessage : null;
const shouldRenderPlaceholder = Boolean(agent?.isRunning) || Boolean(agent?.state && Object.keys(agent.state).length);
const effectiveThreadId = threadId ?? agent?.threadId ?? "default";
let latestUserIndex = -1;
for (let i = processedMessages.length - 1; i >= 0; i -= 1) if (processedMessages[i].role === "user") {
latestUserIndex = i;
break;
}
const latestUserMessageId = latestUserIndex >= 0 ? processedMessages[latestUserIndex].id : void 0;
const currentRunId = latestUserMessageId ? copilotkit.getRunIdForMessage(resolvedAgentId, effectiveThreadId, latestUserMessageId) || `pending:${latestUserMessageId}` : void 0;
const hasAssistantForCurrentRun = latestUserIndex >= 0 ? processedMessages.slice(latestUserIndex + 1).some((msg) => msg.role === "assistant") : hasAssistantMessages;
if (placeholderRenderer && shouldRenderPlaceholder && !hasAssistantForCurrentRun) {
const placeholderMessage = {
id: currentRunId ? `coagent-state-render-${resolvedAgentId}-${currentRunId}` : `coagent-state-render-${resolvedAgentId}`,
role: "assistant",
content: "",
name: "coagent-state-render",
runId: currentRunId
};
processedMessages = [...processedMessages, {
...placeholderMessage,
generativeUIPosition: "before",
generativeUI: () => placeholderRenderer({
message: placeholderMessage,
position: "before"
})
}];
}
return processedMessages;
}, [
agent?.messages,
lazyToolRendered,
allMessages,
renderCustomMessage,
legacyCustomMessageRenderer,
resolvedAgentId,
copilotkit,
agent?.isRunning,
agent?.state
]);
const renderedSuggestions = (0, react.useMemo)(() => {
if (Array.isArray(suggestions)) return {
suggestions: suggestions.map((s) => ({
...s,
isLoading: false
})),
isLoading: false
};
return currentSuggestions;
}, [suggestions, currentSuggestions]);
return {
messages: resolvedMessages,
sendMessage: latestSendMessageFunc,
appendMessage: latestAppendFunc,
setMessages: latestSetMessagesFunc,
reloadMessages: latestReloadFunc,
stopGeneration: latestStopFunc,
reset: latestResetFunc,
deleteMessage: latestDeleteFunc,
isAvailable: agentAvailable,
isLoading: Boolean(agent?.isRunning),
suggestions: renderedSuggestions.suggestions,
setSuggestions: (suggestions) => copilotkit.addSuggestionsConfig({ suggestions }),
generateSuggestions: async () => copilotkit.reloadSuggestions(resolvedAgentId),
resetSuggestions: () => copilotkit.clearSuggestions(resolvedAgentId),
isLoadingSuggestions: renderedSuggestions.isLoading,
interrupt,
agent,
threadId
};
}
function useUpdatedRef(value) {
const ref = (0, react.useRef)(value);
(0, react.useEffect)(() => {
ref.current = value;
}, [value]);
return ref;
}
function useLegacyCoagentRenderer({ copilotkit, agent, agentId, threadId }) {
return (0, react.useMemo)(() => {
if (!copilotkit || !agent) return null;
return ({ message, position }) => {
const effectiveThreadId = threadId ?? agent.threadId ?? "default";
const providedRunId = message.runId;
return (0, react.createElement)(require_copilotkit.CoAgentStateRenderBridge, {
message,
position,
runId: (providedRunId ? providedRunId : copilotkit.getRunIdForMessage(agentId, effectiveThreadId, message.id)) || `pending:${message.id}`,
messageIndex: Math.max(agent.messages.findIndex((msg) => msg.id === message.id), 0),
messageIndexInRun: 0,
numberOfMessagesInRun: 1,
agentId,
stateSnapshot: message.state
});
};
}, [
agent,
agentId,
copilotkit,
threadId
]);
}
//#endregion
//#region src/hooks/use-copilot-chat.ts
/**
* A lightweight React hook for headless chat interactions.
* Perfect for programmatic messaging, background operations, and custom UI implementations.
*
* **Open Source Friendly** - Works without requiring a `publicApiKey`.
*/
function useCopilotChat(options = {}) {
const { visibleMessages, appendMessage, reloadMessages, stopGeneration, reset, isLoading, isAvailable, runChatCompletion, mcpServers, setMcpServers } = useCopilotChatInternal(options);
return {
visibleMessages,
appendMessage,
reloadMessages,
stopGeneration,
reset,
isLoading,
isAvailable,
runChatCompletion,
mcpServers,
setMcpServers
};
}
//#endregion
//#region src/hooks/use-copilot-chat-headless_c.ts
/**
* `useCopilotChatHeadless_c` is for building fully custom UI (headless UI) implementations.
*
* <Callout title="This is an Enterprise Intelligence Platform feature">
* Read more about <a href="/premium/overview">the Enterprise Intelligence Platform</a>.
*
* Usage is generous and **free** to get started.
* </Callout>
*
* ## Key Features
*
* - **Fully headless**: Build your own fully custom UI's for your agentic applications.
* - **Advanced Suggestions**: Direct access to suggestions array with full control
* - **Interrupt Handling**: Support for advanced interrupt functionality
* - **MCP Server Support**: Model Context Protocol server configurations
* - **Chat Controls**: Complete set of chat management functions
* - **Loading States**: Comprehensive loading state management
*
*
* ## Usage
*
* ### Basic Setup
*
* ```tsx
* import { CopilotKit } from "@copilotkit/react-core";
* import { useCopilotChatHeadless_c } from "@copilotkit/react-core";
*
* export function App() {
* return (
* <CopilotKit runtimeUrl="/api/copilotkit">
* <YourComponent />
* </CopilotKit>
* );
* }
*
* export function YourComponent() {
* const { messages, sendMessage, isLoading } = useCopilotChatHeadless_c();
*
* const handleSendMessage = async () => {
* await sendMessage({
* id: "123",
* role: "user",
* content: "Hello World",
* });
* };
*
* return (
* <div>
* {messages.map(msg => <div key={msg.id}>{msg.content}</div>)}
* <button onClick={handleSendMessage} disabled={isLoading}>
* Send Message
* </button>
* </div>
* );
* }
* ```
*
* ### Working with Suggestions
*
* ```tsx
* import { useCopilotChatHeadless_c, useCopilotChatSuggestions } from "@copilotkit/react-core";
*
* export function SuggestionExample() {
* const {
* suggestions,
* setSuggestions,
* generateSuggestions,
* isLoadingSuggestions
* } = useCopilotChatHeadless_c();
*
* // Configure AI suggestion generation
* useCopilotChatSuggestions({
* instructions: "Suggest helpful actions based on the current context",
* maxSuggestions: 3
* });
*
* return (
* <div>
* {suggestions.map(suggestion => (
* <button key={suggestion.title}>{suggestion.title}</button>
* ))}
* <button onClick={generateSuggestions} disabled={isLoadingSuggestions}>
* Generate Suggestions
* </button>
* </div>
* );
* }
* ```
*
* ## Return Values
* The following properties are returned from the hook:
*
* <PropertyReference name="messages" type="Message[]">
* The messages currently in the chat in AG-UI format
* </PropertyReference>
*
* <PropertyReference name="sendMessage" type="(message: Message, options?) => Promise<void>">
* Send a new message to the chat and trigger AI response
* </PropertyReference>
*
* <PropertyReference name="setMessages" type="(messages: Message[] | DeprecatedGqlMessage[]) => void">
* Replace all messages in the chat with new array
* </PropertyReference>
*
* <PropertyReference name="deleteMessage" type="(messageId: string) => void">
* Remove a specific message by ID from the chat
* </PropertyReference>
*
* <PropertyReference name="reloadMessages" type="(messageId: string) => Promise<void>">
* Regenerate the response for a specific message by ID
* </PropertyReference>
*
* <PropertyReference name="stopGeneration" type="() => void">
* Stop the current message generation process
* </PropertyReference>
*
* <PropertyReference name="reset" type="() => void">
* Clear all messages and reset chat state completely
* </PropertyReference>
*
* <PropertyReference name="isLoading" type="boolean">
* Whether the chat is currently generating a response
* </PropertyReference>
*
* <PropertyReference name="runChatCompletion" type="() => Promise<Message[]>">
* Manually trigger chat completion for advanced usage
* </PropertyReference>
*
* <PropertyReference name="mcpServers" type="MCPServerConfig[]">
* Array of Model Context Protocol server configurations
* </PropertyReference>
*
* <PropertyReference name="setMcpServers" type="(servers: MCPServerConfig[]) => void">
* Update MCP server configurations for enhanced context
* </PropertyReference>
*
* <PropertyReference name="suggestions" type="SuggestionItem[]">
* Current suggestions array for reading or manual control
* </PropertyReference>
*
* <PropertyReference name="setSuggestions" type="(suggestions: SuggestionItem[]) => void">
* Manually set suggestions for custom workflows
* </PropertyReference>
*
* <PropertyReference name="generateSuggestions" type="() => Promise<void>">
* Trigger AI-powered suggestion generation using configured settings
* </PropertyReference>
*
* <PropertyReference name="resetSuggestions" type="() => void">
* Clear all current suggestions and reset generation state
* </PropertyReference>
*
* <PropertyReference name="isLoadingSuggestions" type="boolean">
* Whether suggestions are currently being generated
* </PropertyReference>
*
* <PropertyReference name="interrupt" type="string | React.ReactElement | null">
* Interrupt content for human-in-the-loop workflows
* </PropertyReference>
*/
const createNonFunctionalReturn = () => ({
visibleMessages: [],
messages: [],
sendMessage: async () => {},
appendMessage: async () => {},
setMessages: () => {},
deleteMessage: () => {},
reloadMessages: async () => {},
stopGeneration: () => {},
reset: () => {},
isLoading: false,
isAvailable: false,
runChatCompletion: async () => [],
mcpServers: [],
setMcpServers: () => {},
suggestions: [],
setSuggestions: () => {},
generateSuggestions: async () => {},
resetSuggestions: () => {},
isLoadingSuggestions: false,
interrupt: null
});
/**
* Enterprise Intelligence Platform React hook that provides complete chat functionality for fully custom UI implementations.
* Includes all advanced features like direct message access, suggestions array, interrupt handling, and MCP support.
*
* @param options - Configuration options for the chat
* @returns Complete chat interface with all Enterprise Intelligence Platform features
*
* @example
* ```tsx
* const { messages, sendMessage, suggestions, interrupt } = useCopilotChatHeadless_c();
* ```
*/
function useCopilotChatHeadless_c(options = {}) {
const { copilotApiConfig, setBannerError } = require_copilotkit.useCopilotContext();
const hasPublicApiKey = Boolean(copilotApiConfig.publicApiKey);
const internalResult = useCopilotChatInternal(options);
(0, react.useEffect)(() => {
if (!hasPublicApiKey) {
setBannerError(new _copilotkit_shared.CopilotKitError({
message: "You're using useCopilotChatHeadless_c, an Enterprise Intelligence Platform feature that offers extensive headless chat capabilities. To continue, you'll need to provide a free public license key.",
code: _copilotkit_shared.CopilotKitErrorCode.MISSING_PUBLIC_API_KEY_ERROR,
severity: _copilotkit_shared.Severity.WARNING,
visibility: _copilotkit_shared.ErrorVisibility.BANNER
}));
_copilotkit_shared.styledConsole.logCopilotKitPlatformMessage();
} else setBannerError(null);
}, [hasPublicApiKey]);
if (hasPublicApiKey) return internalResult;
return createNonFunctionalReturn();
}
//#endregion
//#region src/hooks/use-frontend-tool.ts
function useFrontendTool(tool, dependencies) {
const { name, description, parameters, render, followUp, available } = tool;
const zodParameters = (0, _copilotkit_shared.getZodParameters)(parameters);
const renderRef = (0, react.useRef)(render);
(0, react.useEffect)(() => {
renderRef.current = render;
}, [render, ...dependencies ?? []]);
const normalizedRender = (0, react.useMemo)(() => {
if (typeof render === "undefined") return;
return ((args) => {
const currentRender = renderRef.current;
if (typeof currentRender === "undefined") return null;
if (typeof currentRender === "string") return react.default.createElement(react.default.Fragment, null, currentRender);
const rendered = currentRender({
...args,
result: typeof args.result === "string" ? (0, _copilotkit_shared.parseJson)(args.result, args.result) : args.result
});
if (typeof rendered === "string") return react.default.createElement(react.default.Fragment, null, rendered);
return rendered ?? null;
});
}, []);
const handlerRef = (0, react.useRef)(tool.handler);
(0, react.useEffect)(() => {
handlerRef.current = tool.handler;
}, [tool.handler, ...dependencies ?? []]);
require_copilotkit.useFrontendTool({
name,
description,
parameters: zodParameters,
handler: tool.handler ? (args) => handlerRef.current?.(args) : void 0,
followUp,
render: normalizedRender,
available: available === void 0 ? void 0 : available !== "disabled"
});
}
//#endregion
//#region src/hooks/use-render-tool-call.ts
function useRenderToolCall(tool, dependencies) {
const { copilotkit } = (0, _copilotkit_react_core_v2_context.useCopilotKit)();
const hasAddedRef = (0, react.useRef)(false);
(0, react.useEffect)(() => {
const { name, parameters, render } = tool;
const zodParameters = (0, _copilotkit_shared.getZodParameters)(parameters);
const renderToolCall = name === "*" ? require_copilotkit.defineToolCallRenderer({
name: "*",
render: ((args) => {
return render({
...args,
result: args.result ? (0, _copilotkit_shared.parseJson)(args.result, args.result) : args.result
});
})
}) : require_copilotkit.defineToolCallRenderer({
name,
args: zodParameters,
render: ((args) => {
return render({
...args,
result: args.result ? (0, _copilotkit_shared.parseJson)(args.result, args.result) : args.result
});
})
});
const existingIndex = copilotkit.renderToolCalls.findIndex((r) => r.name === name);
if (existingIndex !== -1) copilotkit.renderToolCalls.splice(existingIndex, 1);
copilotkit.renderToolCalls.push(renderToolCall);
hasAddedRef.current = true;
return () => {
if (hasAddedRef.current) {
const index = copilotkit.renderToolCalls.findIndex((r) => r.name === name);
if (index !== -1) copilotkit.renderToolCalls.splice(index, 1);
hasAddedRef.current = false;
}
};
}, [tool, ...dependencies ?? []]);
}
//#endregion
//#region src/hooks/use-human-in-the-loop.ts
function useHumanInTheLoop(tool, dependencies) {
const { render, ...toolRest } = tool;
const { name, description, parameters, followUp } = toolRest;
const zodParameters = (0, _copilotkit_shared.getZodParameters)(parameters);
const renderRef = (0, react.useRef)(null);
(0, react.useEffect)(() => {
renderRef.current = (args) => {
if (typeof render === "string") return react.default.createElement(react.default.Fragment, null, render);
if (!render) return null;
const rendered = render((() => {
const mappedArgs = args.args;
switch (args.status) {
case _copilotkit_core.ToolCallStatus.InProgress: return {
args: mappedArgs,
respond: args.respond,
status: args.status,
handler: void 0
};
case _copilotkit_core.ToolCallStatus.Executing: return {
args: mappedArgs,
respond: args.respond,
status: args.status,
handler: () => {}
};
case _copilotkit_core.ToolCallStatus.Complete: return {
args: mappedArgs,
respond: args.respond,
status: args.status,
result: args.result ? (0, _copilotkit_shared.parseJson)(args.result, args.result) : args.result,
handler: void 0
};
default: throw new _copilotkit_shared.CopilotKitError({
code: _copilotkit_shared.CopilotKitErrorCode.UNKNOWN,
message: `Invalid tool call status: ${args.status}`
});
}
})());
if (typeof rendered === "string") return react.default.createElement(react.default.Fragment, null, rendered);
return rendered ?? null;
};
}, [render, ...dependencies ?? []]);
require_copilotkit.useHumanInTheLoop({
name,
description,
followUp,
parameters: zodParameters,
render: ((args) => renderRef.current?.(args) ?? null)
});
}
//#endregion
//#region src/hooks/use-copilot-action.ts
/**
* Example usage of useCopilotAction with complex parameters:
*
* @example
* useCopilotAction({
* name: "myAction",
* parameters: [
* { name: "arg1", type: "string", enum: ["option1", "option2", "option3"], required: false },
* { name: "arg2", type: "number" },
* {
* name: "arg3",
* type: "object",
* attributes: [
* { name: "nestedArg1", type: "boolean" },
* { name: "xyz", required: false },
* ],
* },
* { name: "arg4", type: "number[]" },
* ],
* handler: ({ arg1, arg2, arg3, arg4 }) => {
* const x = arg3.nestedArg1;
* const z = arg3.xyz;
* console.log(arg1, arg2, arg3);
* },
* });
*
* @example
* // Simple action without parameters
* useCopilotAction({
* name: "myAction",
* handler: () => {
* console.log("No parameters provided.");
* },
* });
*
* @example
* // Interactive action with UI rendering and response handling
* useCopilotAction({
* name: "handleMeeting",
* description: "Handle a meeting by booking or canceling",
* parameters: [
* {
* name: "meeting",
* type: "string",
* description: "The meeting to handle",
* required: true,
* },
* {
* name: "date",
* type: "string",
* description: "The date of the meeting",
* required: true,
* },
* {
* name: "title",
* type: "string",
* description: "The title of the meeting",
* required: true,
* },
* ],
* renderAndWaitForResponse: ({ args, respond, status }) => {
* const { meeting, date, title } = args;
* return (
* <MeetingConfirmationDialog
* meeting={meeting}
* date={date}
* title={title}
* onConfirm={() => respond('meeting confirmed')}
* onCancel={() => respond('meeting canceled')}
* />
* );
* },
* });
*
* @example
* // Catch all action allows you to render actions that are not defined in the frontend
* useCopilotAction({
* name: "*",
* render: ({ name, args, status, result, handler, respond }) => {
* return <div>Rendering action: {name}</div>;
* },
* });
*/
/**
* <img src="https://cdn.copilotkit.ai/docs/copilotkit/images/use-copilot-action/useCopilotAction.gif" width="500" />
* `useCopilotAction` is a React hook that you can use in your application to provide
* custom actions that can be called by the AI. Essentially, it allows the Copilot to
* execute these actions contextually during a chat, based on the user's interactions
* and needs.
*
* Here's how it works:
*
* Use `useCopilotAction` to set up actions that the Copilot can call. To provide
* more context to the Copilot, you can provide it with a `description` (for example to explain
* what the action does, under which conditions it can be called, etc.).
*
* Then you define the parameters of the action, which can be simple, e.g. primitives like strings or numbers,
* or complex, e.g. objects or arrays.
*
* Finally, you provide a `handler` function that receives the parameters and returns a result.
* CopilotKit takes care of automatically inferring the parameter types, so you get type safety
* and autocompletion for free.
*
* To render a custom UI for the action, you can provide a `render()` function. This function
* lets you render a custom component or return a string to display.
*
* ## Usage
*
* ### Simple Usage
*
* ```tsx
* useCopilotAction({
* name: "sayHello",
* description: "Say hello to someone.",
* parameters: [
* {
* name: "name",
* type: "string",
* description: "name of the person to say greet",
* },
* ],
* handler: async ({ name }) => {
* alert(`Hello, ${name}!`);
* },
* });
* ```
*
* ## Generative UI
*
* This hooks enables you to dynamically generate UI elements and render them in the copilot chat. For more information, check out the [Generative UI](/guides/generative-ui) page.
*/
function getActionConfig(action) {
if (action.name === "*") return {
type: "render",
action
};
if ("renderAndWaitForResponse" in action || "renderAndWait" in action) {
let render = action.render;
if (!render && "renderAndWaitForResponse" in action) render = action.renderAndWaitForResponse;
if (!render && "renderAndWait" in action) render = action.renderAndWait;
return {
type: "hitl",
action: {
...action,
render
}
};
}
if ("available" in action) {
if (action.available === "enabled" || action.available === "remote") return {
type: "frontend",
action
};
if (action.available === "frontend" || action.available === "disabled") return {
type: "render",
action
};
}
if ("handler" in action) return {
type: "frontend",
action
};
throw new Error("Invalid action configuration");
}
/**
* useCopilotAction is a legacy hook maintained for backwards compatibility.
*
* To avoid violating React's Rules of Hooks (which prohibit conditional hook calls),
* we use a registration pattern:
* 1. This hook registers the action configuration with the CopilotContext
* 2. A renderer component in CopilotKit actually renders the appropriate hook wrapper
* 3. React properly manages hook state since components are rendered, not conditionally called
*
* This allows action types to change between renders without corrupting React's hook state.
*/
function useCopilotAction(action, dependencies) {
const [initialActionConfig] = (0, react.useState)(getActionConfig(action));
const currentActionConfig = getActionConfig(action);
/**
* Calling hooks conditionally violates React's Rules of Hooks. This rule exists because
* React maintains the call stack for hooks like useEffect or useState, and conditionally
* calling a hook would result in inconsistent call stacks between renders.
*
* Unfortunately, useCopilotAction _has_ to conditionally call a hook based on the
* supplied parameters. In order to avoid breaking React's call stack tracking, while
* breaking the Rule of Hooks, we use a ref to store the initial action configuration
* and throw an error if the _configuration_ changes such that we would call a different hook.
*/
if (initialActionConfig.type !== currentActionConfig.type) throw new Error("Action configuration changed between renders");
switch (currentActionConfig.type) {
case "render": return useRenderToolCall(currentActionConfig.action, dependencies);
case "hitl": return useHumanInTheLoop(currentActionConfig.action, dependencies);
case "frontend": return useFrontendTool(currentActionConfig.action, dependencies);
default: throw new Error("Invalid action configuration");
}
}
//#endregion
//#region src/hooks/use-coagent-state-render.ts
/**
* The useCoAgentStateRender hook allows you to render UI or text based components on a Agentic Copilot's state in the chat.
* This is particularly useful for showing intermediate state or progress during Agentic Copilot operations.
*
* ## Usage
*
* ### Simple Usage
*
* ```tsx
* import { useCoAgentStateRender } from "@copilotkit/react-core";
*
* type YourAgentState = {
* agent_state_property: string;
* }
*
* useCoAgentStateRender<YourAgentState>({
* name: "basic_agent",
* nodeName: "optionally_specify_a_specific_node",
* render: ({ status, state, nodeName }) => {
* return (
* <YourComponent
* agentStateProperty={state.agent_state_property}
* status={status}
* nodeName={nodeName}
* />
* );
* },
* });
* ```
*
* This allows for you to render UI components or text based on what is happening within the agent.
*
* ### Example
* A great example of this is in our Perplexity Clone where we render the progress of an agent's internet search as it is happening.
* You can play around with it below or learn how to build it with its [demo](/coagents/videos/perplexity-clone).
*
* <Callout type="info">
* This example is hosted on Vercel and may take a few seconds to load.
* </Callout>
*
* <iframe src="https://examples-coagents-ai-researcher-ui.vercel.app/" className="w-full rounded-lg border h-[700px] my-4" />
*/
/**
* This hook is used to render agent state with custom UI components or text. This is particularly
* useful for showing intermediate state or progress during Agentic Copilot operations.
* To get started using rendering intermediate state through this hook, checkout the documentation.
*
* https://docs.copilotkit.ai/langgraph-python/shared-state/predictive-state-updates
*/
function useCoAgentStateRender(action, dependencies) {
const { chatComponentsCache, availableAgents } = (0, react.useContext)(require_copilotkit.CopilotContext);
const { setCoAgentStateRender, removeCoAgentStateRender, coAgentStateRenders } = require_copilotkit.useCoAgentStateRenders();
const idRef = (0, react.useRef)((0, _copilotkit_shared.randomId)());
const { setBannerError, addToast } = require_copilotkit.useToast();
(0, react.useEffect)(() => {
if (availableAgents?.length && !availableAgents.some((a) => a.name === action.name)) {
`${action.name}`;
setBannerError(new _copilotkit_shared.CopilotKitAgentDiscoveryError({
agentName: action.name,
availableAgents: availableAgents.map((a) => ({
name: a.name,
id: a.id
}))
}));
}
}, [availableAgents]);
const key = `${action.name}-${action.nodeName || "global"}`;
if (dependencies === void 0) {
if (coAgentStateRenders[idRef.current]) {
coAgentStateRenders[idRef.current].handler = action.handler;
if (typeof action.render === "function") {
if (chatComponentsCache.current !== null) chatComponentsCache.current.coAgentStateRenders[key] = action.render;
}
}
}
(0, react.useEffect)(() => {
const currentId = idRef.current;
if (Object.entries(coAgentStateRenders).some(([id, otherAction]) => {
if (id === currentId) return false;
if (otherAction.name !== action.name) return false;
const hasNodeName = !!action.nodeName;
const hasOtherNodeName = !!otherAction.nodeName;
if (!hasNodeName && !hasOtherNodeName) return true;
if (hasNodeName !== hasOtherNodeName) return false;
return action.nodeName === otherAction.nodeName;
})) addToast({
type: "warning",
message: action.nodeName ? `Found multiple state renders for agent ${action.name} and node ${action.nodeName}. State renders might get overridden` : `Found multiple state renders for agent ${action.name}. State renders might get overridden`,
id: `dup-action-${action.name}`
});
}, [coAgentStateRenders]);
(0, react.useEffect)(() => {
setCoAgentStateRender(idRef.current, action);
if (chatComponentsCache.current !== null && action.render !== void 0) chatComponentsCache.current.coAgentStateRenders[key] = action.render;
return () => {
removeCoAgentStateRender(idRef.current);
};
}, [
setCoAgentStateRender,
removeCoAgentStateRender,
action.name,
typeof action.render === "string" ? action.render : void 0,
...dependencies || []
]);
}
//#endregion
//#region src/hooks/use-make-copilot-document-readable.ts
/**
* Makes a document readable by Copilot.
* @param document The document to make readable.
* @param categories The categories to associate with the document.
* @param dependencies The dependencies to use for the effect.
* @returns The id of the document.
*/
function useMakeCopilotDocumentReadable(document, categories, dependencies = []) {
const { addDocumentContext, removeDocumentContext } = require_copilotkit.useCopilotContext();
const idRef = (0, react.useRef)(void 0);
(0, react.useEffect)(() => {
const id = addDocumentContext(document, categories);
idRef.current = id;
return () => {
removeDocumentContext(id);
};
}, [
addDocumentContext,
removeDocumentContext,
...dependencies
]);
return idRef.current;
}
//#endregion
//#region src/hooks/use-copilot-readable.ts
/**
* `useCopilotReadable` is a React hook that provides app-state and other information
* to the Copilot.
*
* ## Usage
*
* ### Simple Usage
*
* In its most basic usage, useCopilotReadable accepts a single string argument
* representing any piece of app state, making it available for the Copilot to use
* as context when responding to user input.
*
* ```tsx
* import { useCopilotReadable } from "@copilotkit/react-core";
*
* export function MyComponent() {
* const [employees, setEmployees] = useState([]);
*
* useCopilotReadable({
* description: "The list of employees",
* value: employees,
* });
* }
* ```
*
* ### Custom Serialization
*
* By default the value is serialized with `JSON.stringify`. Pass `convert` to
* control the string the Copilot sees. It is called with the description and the
* value, in that order:
*
* ```tsx
* useCopilotReadable({
* description: "The current user",
* value: user,
* convert: (description, value) => `${description}: ${value.firstName} ${value.lastName}`,
* });
* ```
*
* ### Conditional Usage
*
* Toggle `available` to add or remove the context as your app state changes.
* Switching to `"disabled"` removes the entry from the Copilot context; switching
* back to `"enabled"` re-adds it.
*
* ```tsx
* useCopilotReadable({
* description: "The list of employees",
* value: employees,
* available: showEmployees ? "enabled" : "disabled",
* });
* ```
*
* ### Re-running on Custom Dependencies
*
* The context is refreshed whenever `description`, `value`, `convert` or
* `available` change. Pass a second argument to add your own dependencies:
*
* ```tsx
* useCopilotReadable(
* {
* description: "The selected employee",
* value: employee,
* },
* [departmentId],
* );
* ```
*/
/**
* Adds the given information to the Copilot context to make it readable by Copilot.
*/
function useCopilotReadable({ description, value, convert, available = "enabled" }, dependencies) {
const { copilotkit } = (0, _copilotkit_react_core_v2_context.useCopilotKit)();
const ctxIdRef = (0, react.useRef)(void 0);
(0, react.useEffect)(() => {
if (!copilotkit) return;
if (available === "disabled") return;
const id = copilotkit.addContext({
description,
value: convert ? convert(description, value) : JSON.stringify(value)
});
ctxIdRef.current = id;
return () => {
copilotkit.removeContext(id);
if (ctxIdRef.current === id) ctxIdRef.current = void 0;
};
}, [
copilotkit,
description,
value,
convert,
available,
...dependencies || []
]);
return ctxIdRef.current;
}
//#endregion
//#region src/hooks/use-agent-nodename.ts
/**
* Tracks the node the agent is currently executing.
*
* Backed by state rather than a ref: mutating a ref schedules no render, so
* consumers such as `useCoAgent().nodeName` kept reporting whichever node was
* current at their last render and never updated on their own.
*/
function useAgentNodeName(agentName) {
const { agent } = require_copilotkit.useAgent({ agentId: agentName });
const [nodeName, setNodeName] = (0, react.useState)("start");
(0, react.useEffect)(() => {
if (!agent) return;
const subscription = agent.subscribe({
onStepStartedEvent: ({ event }) => {
setNodeName(event.stepName);
},
onRunStartedEvent: () => {
setNodeName("start");
},
onRunFinishedEvent: () => {
setNodeName("end");
},
onRunErrorEvent: () => {
setNodeName("end");
}
});
return () => {
subscription.unsubscribe();
};
}, [agent]);
return nodeName;
}
//#endregion
//#region src/hooks/use-coagent.ts
/**
* <Callout type="info">
* Usage of this hook assumes some additional setup in your application, for more information
* on that see the CoAgents <span className="text-blue-500">[getting started guide](/langgraph-python/quickstart)</span>.
* </Callout>
* <Frame className="my-12">
* <img
* src="https://cdn.copilotkit.ai/docs/copilotkit/images/coagents/SharedStateCoAgents.gif"
* alt="CoAgents demonstration"
* className="w-auto"
* />
* </Frame>
*
* This hook is used to integrate an agent into your application. With its use, you can
* render and update the state of an agent, allowing for a dynamic and interactive experience.
* We call these shared state experiences agentic copilots, or CoAgents for short.
*
* ## Usage
*
* ### Simple Usage
*
* ```tsx
* import { useCoAgent } from "@copilotkit/react-core";
*
* type AgentState = {
* count: number;
* }
*
* const agent = useCoAgent<AgentState>({
* name: "my-agent",
* initialState: {
* count: 0,
* },
* });
*
* ```
*
* In CopilotKit v2, `useCoAgent` is a thin compatibility wrapper over the v2
* [`useAgent`](/reference/hooks/useAgent) hook. It returns an object with the
* following properties:
*
* ```tsx
* const {
* name, // The name of the agent currently being used.
* nodeName, // The name of the current LangGraph node.
* threadId, // The ID of the thread the agent is running in.
* state, // The current state of the agent.
* setState, // A function to update the state of the agent.
* running, // A boolean indicating if the agent is currently running.
* start, // A function to start the agent.
* stop, // A function to stop the agent.
* run, // A function to (re-)run the agent. Maps to the v2 agent's `runAgent()`.
* } = agent;
* ```
*
* Finally we can leverage these properties to create reactive experiences with the agent!
*
* ```tsx
* const { state, setState } = useCoAgent<AgentState>({
* name: "my-agent",
* initialState: {
* count: 0,
* },
* });
*
* return (
* <div>
* <p>Count: {state.count}</p>
* <button onClick={() => setState({ count: state.count + 1 })}>Increment</button>
* </div>
* );
* ```
*
* This reactivity is bidirectional, meaning that changes to the state from the agent will be reflected in the UI and vice versa.
*
* ## Parameters
* <PropertyReference name="options" type="UseCoagentOptions<T>" required>
* The options to use when creating the coagent.
* <PropertyReference name="name" type="string" required>
* The name of the agent to use.
* </PropertyReference>
* <PropertyReference name="initialState" type="T | any">
* The initial state of the agent.
* </PropertyReference>
* <PropertyReference name="state" type="T | any">
* State to manage externally if you are using this hook with external state management.
* </PropertyReference>
* <PropertyReference name="setState" type="(newState: T | ((prevState: T | undefined) => T)) => void">
* A function to update the state of the agent if you are using this hook with external state management.
* </PropertyReference>
* </PropertyReference>
*/
/**
* This hook is used to integrate an agent into your application. With its use, you can
* render and update the state of the agent, allowing for a dynamic and interactive experience.
* We call these shared state experiences "agentic copilots". To get started using agentic copilots, which
* we refer to as CoAgents, checkout the documentation at https://docs.copilotkit.ai/langgraph-python/quickstart.
*/
function useCoAgent(options) {
const { agent } = require_copilotkit.useAgent({ agentId: options.name });
const { copilotkit } = (0, _copilotkit_react_core_v2_context.useCopilotKit)();
const nodeName = useAgentNodeName(options.name);
const handleStateUpdate = (0, react.useCallback)((newState) => {
if (!agent) return;
if (typeof newState === "function") {
const updater = newState;
agent.setState(updater(agent.state));
} else agent.setState({
...agent.state,
...newState
});
}, [agent?.state, agent?.setState]);
(0, react.useEffect)(() => {
if (!options.config && !options.configurable) return;
let config = options.config ?? {};
if (options.configurable) config = {
...config,
configurable: {
...options.configurable,
...config.configurable
}
};
copilotkit.setProperties(config);
}, [options.config, options.configurable]);
(0, react.useEffect)(() => {
if (agent?.state && isExternalStateManagement(options) && JSON.stringify(options.state) !== JSON.stringify(agent.state)) handleStateUpdate(options.state);
}, [
agent,
(0, react.useMemo)(() => isExternalStateManagement(options) ? JSON.stringify(options.state) : void 0, [isExternalStateManagement(options) ? JSON.stringify(options.state) : void 0]),
handleStateUpdate
]);
const hasStateValues = (0, react.useCallback)((value) => {
return Boolean(value && Object.keys(value).length);
}, []);
const initialStateRef = (0, react.useRef)(isExternalStateManagement(options) ? options.state : "initialState" in options ? options.initialState : void 0);
(0, react.useEffect)(() => {
if (isExternalStateManagement(options)) initialStateRef.current = options.state;
else if ("initialState" in options) initialStateRef.current = options.initialState;
}, [isExternalStateManagement(options) ? JSON.stringify(options.state) : "initialState" in options ? JSON.stringify(options.initialState) : void 0]);
(0, react.useEffect)(() => {
if (!agent) return;
const subscription = agent.subscribe({
onStateChanged: (args) => {
if (isExternalStateManagement(options)) options.setState(args.state);
},
onRunInitialized: (args) => {
if (hasStateValues(args.state)) {
handleStateUpdate(args.state);
return;
}
if (hasStateValues(agent.state)) return;
if (initialStateRef.current !== void 0) handleStateUpdate(initialStateRef.current);
}
});
return () => {
subscription.unsubscribe();
};
}, [
agent,
handleStateUpdate,
hasStateValues
]);
return (0, react.useMemo)(() => {
if (!agent) {
const noop = () => {};
const noopAsync = async () => {};
const initialState = ("state" in options && options.state) ?? ("initialState" in options && options.initialState) ?? {};
return {
name: options.name,
nodeName,
threadId: void 0,
running: false,
state: initialState,
setState: noop,
start: noop,
stop: noop,
run: noopAsync
};
}
return {
name: agent?.agentId ?? options.name,
nodeName,
threadId: agent.threadId,
running: agent.isRunning,
state: agent.state,
setState: handleStateUpdate,
start: agent.runAgent,
stop: agent.abortRun,
run: agent.runAgent
};
}, [
agent?.state,
agent?.runAgent,
agent?.abortRun,
agent?.runAgent,
agent?.threadId,
agent?.isRunning,
agent?.agentId,
handleStateUpdate,
options.name
]);
}
const isExternalStateManagement = (options) => {
return "state" in options && "setState" in options;
};
//#endregion
//#region src/hooks/use-copilot-runtime-client.ts
const useCopilotRuntimeClient = (options) => {
const { setBannerError } = require_copilotkit.useToast();
const { showDevConsole, onError, ...runtimeOptions } = options;
const lastStructuredErrorRef = (0, react.useRef)(null);
const traceUIError = async (error, originalError) => {
try {
await onError({
type: "error",
timestamp: Date.now(),
context: {
source: "ui",
request: {
operation: "runtimeClient",
url: runtimeOptions.url,
startTime: Date.now()
},
technical: {
environment: "browser",
userAgent: typeof navigator !== "undefined" ? navigator.userAgent : void 0,
stackTrace: originalError instanceof Error ? originalError.stack : void 0
}
},
error
});
} catch (error) {
console.error("Error in onError handler:", error);
}
};
return (0, react.useMemo)(() => {
return new _copilotkit_runtime_client_gql.CopilotRuntimeClient({
...runtimeOptions,
handleGQLErrors: (error) => {
if (error.graphQLErrors?.length) {
const graphQLErrors = error.graphQLErrors;
const routeError = (gqlError) => {
if (gqlError.extensions?.visibility === _copilotkit_shared.ErrorVisibility.SILENT) {
console.error("CopilotKit Silent Error:", gqlError.message);
return;
}
const now = Date.now();
const errorMessage = gqlError.message;
if (lastStructuredErrorRef.current && lastStructuredErrorRef.current.message === errorMessage && now - lastStructuredErrorRef.current.timestamp < 150) return;
lastStructuredErrorRef.current = {
message: errorMessage,
timestamp: now
};
const ckError = createStructuredError(gqlError);
if (ckError) {
setBannerError(ckError);
traceUIError(ckError, gqlError);
} else {
const fallbackError = new _copilotkit_shared.CopilotKitError({
message: gqlError.message,
code: _copilotkit_shared.CopilotKitErrorCode.UNKNOWN
});
setBannerError(fallbackError);
traceUIError(fallbackError, gqlError);
}
};
graphQLErrors.forEach(routeError);
} else {
const fallbackError = new _copilotkit_shared.CopilotKitError({
message: error?.message || String(error),
code: _copilotkit_shared.CopilotKitErrorCode.UNKNOWN
});
setBannerError(fallbackError);
traceUIError(fallbackError, error);
}
},
handleGQLWarning: (message) => {
console.warn(message);
setBannerError(new _copilotkit_shared.CopilotKitError({
message,
code: _copilotkit_shared.CopilotKitErrorCode.UNKNOWN
}));
}
});
}, [
runtimeOptions,
setBannerError,
onError
]);
};
function createStructuredError(gqlError) {
const extensions = gqlError.extensions;
const originalError = extensions?.originalError;
const message = originalError?.message || gqlError.message;
const code = extensions?.code;
if (code) return new _copilotkit_shared.CopilotKitError({
message,
code
});
if (originalError?.stack?.includes("CopilotApiDiscoveryError")) return new _copilotkit_shared.CopilotKitApiDiscoveryError({ message });
if (originalError?.stack?.includes("CopilotKitRemoteEndpointDiscoveryError")) return new _copilotkit_shared.CopilotKitRemoteEndpointDiscoveryError({ message });
if (originalError?.stack?.includes("CopilotKitAgentDiscoveryError")) return new _copilotkit_shared.CopilotKitAgentDiscoveryError({
agentName: "",
availableAgents: []
});
return null;
}
//#endregion
//#region src/hooks/use-copilot-authenticated-action.ts
/**
* Hook to create an authenticated action that requires user sign-in before execution.
*
* @internal Defunct — retained for backward compatibility.
*
* @param action - The frontend action to be wrapped with authentication
* @param dependencies - Optional array of dependencies that will trigger recreation of the action when changed
*/
function useCopilotAuthenticatedAction_c(action, dependencies) {
const { authConfig_c, authStates_c, setAuthStates_c } = require_copilotkit.useCopilotContext();
const pendingActionRef = (0, react.useRef)(null);
const executeAction = (0, react.useCallback)((props) => {
if (typeof action.render === "function") return action.render(props);
return action.render || react.default.createElement(react.Fragment);
}, [action]);
const wrappedRender = (0, react.useCallback)((props) => {
if (!Object.values(authStates_c || {}).some((state) => state.status === "authenticated")) {
pendingActionRef.current = props;
return authConfig_c?.SignInComponent ? react.default.createElement(authConfig_c.SignInComponent, { onSignInComplete: (authState) => {
setAuthStates_c?.((prev) => ({
...prev,
[action.name]: authState
}));
if (pendingActionRef.current) {
executeAction(pendingActionRef.current);
pendingActionRef.current = null;
}
} }) : react.default.createElement(react.Fragment);
}
return executeAction(props);
}, [
action,
authStates_c,
setAuthStates_c
]);
useCopilotAction({
...action,
render: wrappedRender
}, dependencies);
}
//#endregion
//#region src/hooks/use-langgraph-interrupt.ts
/**
* Transforms a v2 InterruptEvent into the v1 LangGraphInterruptEvent shape
* expected by existing useLangGraphInterrupt callbacks.
*/
function toV1Event(event) {
const value = typeof event.value === "string" ? (0, _copilotkit_shared.parseJson)(event.value, event.value) : event.value;
return {
name: _copilotkit_runtime_client_gql.MetaEventName.LangGraphInterruptEvent,
type: "MetaEvent",
value
};
}
function useLangGraphInterrupt(action, _dependencies) {
const actionRef = (0, react.useRef)(action);
actionRef.current = action;
const existingConfig = require_copilotkit.useCopilotChatConfiguration();
const resolvedAgentId = action.agentId ?? existingConfig?.agentId ?? "default";
const threadId = existingConfig?.threadId;
const nodeName = useAgentNodeName(resolvedAgentId);
const metadataRef = (0, react.useRef)({
agentName: resolvedAgentId,
threadId,
nodeName
});
metadataRef.current = {
agentName: resolvedAgentId,
threadId,
nodeName
};
require_copilotkit.useInterrupt({
render: (0, react.useCallback)(({ event, result, resolve }) => {
const renderFn = actionRef.current.render;
if (!renderFn) return react.default.createElement(react.default.Fragment);
const rendered = renderFn({
event: toV1Event(event),
result,
resolve: (r) => resolve(r)
});
if (typeof rendered === "string") return react.default.createElement(react.default.Fragment, null, rendered);
return rendered;
}, []),
handler: (0, react.useCallback)(({ event, resolve }) => {
return actionRef.current.handler?.({
event: toV1Event(event),
resolve: (r) => resolve(r)
});
}, []),
enabled: (0, react.useCallback)((event) => {
if (!actionRef.current.enabled) return true;
return actionRef.current.enabled({
eventValue: toV1Event(event).value,
agentMetadata: metadataRef.current
});
}, []),
agentId: resolvedAgentId
});
}
//#endregion
//#region src/hooks/use-copilot-additional-instructions.ts
/**
* `useCopilotAdditionalInstructions` is a React hook that provides additional instructions
* to the Copilot.
*
* ## Usage
*
* ### Simple Usage
*
* In its most basic usage, useCopilotAdditionalInstructions accepts a single string argument
* representing the instructions to be added to the Copilot.
*
* ```tsx
* import { useCopilotAdditionalInstructions } from "@copilotkit/react-core";
*
* export function MyComponent() {
* useCopilotAdditionalInstructions({
* instructions: "Do not answer questions about the weather.",
* });
* }
* ```
*
* ### Conditional Usage
*
* You can also conditionally add instructions based on the state of your app.
*
* ```tsx
* import { useCopilotAdditionalInstructions } from "@copilotkit/react-core";
*
* export function MyComponent() {
* const [showInstructions, setShowInstructions] = useState(false);
*
* useCopilotAdditionalInstructions({
* available: showInstructions ? "enabled" : "disabled",
* instructions: "Do not answer questions about the weather.",
* });
* }
* ```
*/
/**
* Adds the given instructions to the Copilot context.
*/
function useCopilotAdditionalInstructions({ instructions, available = "enabled" }, dependencies) {
const { setAdditionalInstructions } = require_copilotkit.useCopilotContext();
(0, react.useEffect)(() => {
if (available === "disabled") return;
setAdditionalInstructions((prevInstructions) => [...prevInstructions || [], instructions]);
return () => {
setAdditionalInstructions((prevInstructions) => prevInstructions?.filter((instruction) => instruction !== instructions) || []);
};
}, [
available,
instructions,
setAdditionalInstructions,
...dependencies || []
]);
}
//#endregion
//#region src/hooks/use-default-tool.ts
function useDefaultTool(tool, dependencies) {
useCopilotAction({
...tool,
name: "*"
}, dependencies);
}
//#endregion
//#region src/hooks/use-copilot-chat-suggestions.tsx
/**
* <Callout type="warning">
* useCopilotChatSuggestions is experimental. The interface is not final and
* can change without notice.
* </Callout>
*
* `useCopilotReadable` is a React hook that provides app-state and other information
* to the Copilot. Optionally, the hook can also handle hierarchical state within your
* application, passing these parent-child relationships to the Copilot.
*
* <br/>
* <img src="https://cdn.copilotkit.ai/docs/copilotkit/images/use-copilot-chat-suggestions/use-copilot-chat-suggestions.gif" width="500" />
*
* ## Usage
*
* ### Install Dependencies
*
* This component is part of the [@copilotkit/react-ui](https://npmjs.com/package/@copilotkit/react-ui) package.
*
* ```shell npm2yarn \"@copilotkit/react-ui"\
* npm install @copilotkit/react-core @copilotkit/react-ui
* ```
*
* ### Simple Usage
*
* ```tsx
* import { useCopilotChatSuggestions } from "@copilotkit/react-ui";
*
* export function MyComponent() {
* const [employees, setEmployees] = useState([]);
*
* useCopilotChatSuggestions({
* instructions: `The following employees are on duty: ${JSON.stringify(employees)}`,
* });
* }
* ```
*
* ### Dependency Management
*
* ```tsx
* import { useCopilotChatSuggestions } from "@copilotkit/react-ui";
*
* export function MyComponent() {
* useCopilotChatSuggestions(
* {
* instructions: "Suggest the most relevant next actions.",
* },
* [appState],
* );
* }
* ```
*
* In the example above, the suggestions are generated based on the given instructions.
* The hook monitors `appState`, and updates suggestions accordingly whenever it changes.
*
* ### Behavior and Lifecycle
*
* The hook registers the configuration with the chat context upon component mount and
* removes it on unmount, ensuring a clean and efficient lifecycle management.
*/
function useCopilotChatSuggestions(config, dependencies = []) {
const resolvedAgentId = require_copilotkit.useCopilotChatConfiguration()?.agentId ?? "default";
const available = (config.available === "enabled" ? "always" : config.available) ?? "before-first-message";
require_copilotkit.useConfigureSuggestions({
...config,
available,
consumerAgentId: resolvedAgentId
}, dependencies);
}
//#endregion
//#region src/types/frontend-action.ts
function processActionsForRuntimeRequest(actions) {
return actions.filter((action) => action.available !== _copilotkit_runtime_client_gql.ActionInputAvailability.Disabled && action.disabled !== true && action.name !== "*" && action.available != "frontend" && !action.pairedAction).map((action) => {
let available = _copilotkit_runtime_client_gql.ActionInputAvailability.Enabled;
if (action.disabled) available = _copilotkit_runtime_client_gql.ActionInputAvailability.Disabled;
else if (action.available === "disabled") available = _copilotkit_runtime_client_gql.ActionInputAvailability.Disabled;
else if (action.available === "remote") available = _copilotkit_runtime_client_gql.ActionInputAvailability.Remote;
return {
name: action.name,
description: action.description || "",
jsonSchema: JSON.stringify((0, _copilotkit_shared.actionParametersToJsonSchema)(action.parameters || [])),
available
};
});
}
//#endregion
//#region src/lib/copilot-task.ts
/**
* This class is used to execute one-off tasks, for example on button press. It can use the context available via [useCopilotReadable](/reference/v1/hooks/useCopilotReadable) and the actions provided by [useCopilotAction](/reference/v1/hooks/useCopilotAction), or you can provide your own context and actions.
*
* ## Example
* In the simplest case, use CopilotTask in the context of your app by giving it instructions on what to do.
*
* ```tsx
* import { CopilotTask, useCopilotContext } from "@copilotkit/react-core";
*
* export function MyComponent() {
* const context = useCopilotContext();
*
* const task = new CopilotTask({
* instructions: "Set a random message",
* actions: [
* {
* name: "setMessage",
* description: "Set the message.",
* argumentAnnotations: [
* {
* name: "message",
* type: "string",
* description:
* "A message to display.",
* required: true,
* },
* ],
* }
* ]
* });
*
* const executeTask = async () => {
* await task.run(context, action);
* }
*
* return (
* <>
* <button onClick={executeTask}>
* Execute task
* </button>
* </>
* )
* }
* ```
*
* Have a look at the [Presentation Example App](https://github.com/CopilotKit/CopilotKit/blob/main/examples/v1/next-openai/src/app/presentation/page.tsx) for a more complete example.
*/
var CopilotTask = class {
constructor(config) {
this.instructions = config.instructions;
this.actions = config.actions || [];
this.includeCopilotReadable = config.includeCopilotReadable !== false;
this.includeCopilotActions = config.includeCopilotActions !== false;
this.forwardedParameters = config.forwardedParameters;
}
/**
* Run the task.
* @param context The CopilotContext to use for the task. Use `useCopilotContext` to obtain the current context.
* @param data The data to use for the task.
*/
async run(context, data) {
const actions = this.includeCopilotActions ? Object.assign({}, context.actions) : {};
for (const fn of this.actions) actions[fn.name] = fn;
let contextString = "";
if (data) contextString = (typeof data === "string" ? data : JSON.stringify(data)) + "\n\n";
if (this.includeCopilotReadable) contextString += context.getContextString([], require_copilotkit.defaultCopilotContextCategories);
const messages = [new _copilotkit_runtime_client_gql.TextMessage({
content: taskSystemMessage(contextString, this.instructions),
role: _copilotkit_runtime_client_gql.Role.System
})];
const response = await new _copilotkit_runtime_client_gql.CopilotRuntimeClient({
url: context.copilotApiConfig.chatApiEndpoint,
publicApiKey: context.copilotApiConfig.publicApiKey,
headers: context.copilotApiConfig.headers,
credentials: context.copilotApiConfig.credentials
}).generateCopilotResponse({
data: {
frontend: {
actions: processActionsForRuntimeRequest(Object.values(actions)),
url: window.location.href
},
messages: (0, _copilotkit_runtime_client_gql.convertMessagesToGqlInput)((0, _copilotkit_runtime_client_gql.filterAgentStateMessages)(messages)),
metadata: { requestType: _copilotkit_runtime_client_gql.CopilotRequestType.Task },
forwardedParameters: {
toolChoice: "required",
...this.forwardedParameters
}
},
properties: context.copilotApiConfig.properties
}).toPromise();
const functionCallHandler = context.getFunctionCallHandler(actions);
const functionCalls = (0, _copilotkit_runtime_client_gql.convertGqlOutputToMessages)(response.data?.generateCopilotResponse?.messages || []).filter((m) => m.isActionExecutionMessage());
for (const functionCall of functionCalls) await functionCallHandler({
messages,
name: functionCall.name,
args: functionCall.arguments
});
}
};
function taskSystemMessage(contextString, instructions) {
return `
Please act as an efficient, competent, conscientious, and industrious professional assistant.
Help the user achieve their goals, and you do so in a way that is as efficient as possible, without unnecessary fluff, but also without sacrificing professionalism.
Always be polite and respectful, and prefer brevity over verbosity.
The user has provided you with the following context:
\`\`\`
${contextString}
\`\`\`
They have also provided you with functions you can call to initiate actions on their behalf.
Please assist them as best you can.
This is not a conversation, so please do not ask questions. Just call a function without saying anything else.
The user has given you the following task to complete:
\`\`\`
${instructions}
\`\`\`
`;
}
//#endregion
exports.CoAgentStateRendersContext = require_copilotkit.CoAgentStateRendersContext;
exports.CoAgentStateRendersProvider = require_copilotkit.CoAgentStateRendersProvider;
exports.CopilotContext = require_copilotkit.CopilotContext;
exports.CopilotKit = require_copilotkit.CopilotKit;
exports.CopilotMessagesContext = require_copilotkit.CopilotMessagesContext;
exports.CopilotTask = CopilotTask;
exports.SUGGESTION_RETRY_CONFIG = SUGGESTION_RETRY_CONFIG;
exports.ThreadsContext = require_copilotkit.ThreadsContext;
exports.ThreadsProvider = require_copilotkit.ThreadsProvider;
exports.defaultCopilotContextCategories = require_copilotkit.defaultCopilotContextCategories;
exports.shouldShowDevConsole = require_copilotkit.shouldShowDevConsole;
exports.useCoAgent = useCoAgent;
exports.useCoAgentStateRender = useCoAgentStateRender;
exports.useCoAgentStateRenders = require_copilotkit.useCoAgentStateRenders;
exports.useCopilotAction = useCopilotAction;
exports.useCopilotAdditionalInstructions = useCopilotAdditionalInstructions;
exports.useCopilotAuthenticatedAction_c = useCopilotAuthenticatedAction_c;
exports.useCopilotChat = useCopilotChat;
exports.useCopilotChatHeadless_c = useCopilotChatHeadless_c;
exports.useCopilotChatInternal = useCopilotChatInternal;
exports.useCopilotChatSuggestions = useCopilotChatSuggestions;
exports.useCopilotContext = require_copilotkit.useCopilotContext;
exports.useCopilotMessagesContext = require_copilotkit.useCopilotMessagesContext;
exports.useCopilotReadable = useCopilotReadable;
exports.useCopilotRuntimeClient = useCopilotRuntimeClient;
exports.useDefaultTool = useDefaultTool;
exports.useFrontendTool = useFrontendTool;
exports.useHumanInTheLoop = useHumanInTheLoop;
exports.useLangGraphInterrupt = useLangGraphInterrupt;
exports.useLazyToolRenderer = useLazyToolRenderer;
exports.useMakeCopilotDocumentReadable = useMakeCopilotDocumentReadable;
exports.useRenderToolCall = useRenderToolCall;
exports.useThreads = require_copilotkit.useThreads;
//# sourceMappingURL=index.cjs.map