"use client"; import { CopilotKitInspector } from "../components/CopilotKitInspector.mjs"; import { MCPAppsActivityContentSchema, MCPAppsActivityRenderer, MCPAppsActivityType } from "../components/MCPAppsActivityRenderer.mjs"; import { createA2UIMessageRenderer } from "../a2ui/A2UIMessageRenderer.mjs"; import { CopilotKitCoreReact } from "../lib/react-core.mjs"; import { createContext, useContext, useEffect, useMemo, useReducer, useRef, useState } from "react"; import { jsx, jsxs } from "react/jsx-runtime"; import { z } from "zod"; import { viewerTheme } from "@copilotkit/a2ui-renderer"; //#region src/providers/CopilotKitProvider.tsx const HEADER_NAME = "X-CopilotCloud-Public-Api-Key"; const COPILOT_CLOUD_CHAT_URL = "https://api.cloud.copilotkit.ai/copilotkit/v1"; const CopilotKitContext = createContext({ copilotkit: null, executingToolCallIds: /* @__PURE__ */ new Set() }); function useStableArrayProp(prop, warningMessage, isMeaningfulChange) { const empty = useMemo(() => [], []); const value = prop ?? empty; const initial = useRef(value); useEffect(() => { if (warningMessage && value !== initial.current && (isMeaningfulChange ? isMeaningfulChange(initial.current, value) : true)) console.error(warningMessage); }, [value, warningMessage]); return value; } const CopilotKitProvider = ({ children, runtimeUrl, headers = {}, credentials, publicApiKey, publicLicenseKey, properties = {}, agents__unsafe_dev_only: agents = {}, selfManagedAgents = {}, renderToolCalls, renderActivityMessages, renderCustomMessages, frontendTools, humanInTheLoop, showDevConsole = false, useSingleEndpoint = false, onError, a2ui }) => { const [shouldRenderInspector, setShouldRenderInspector] = useState(false); const [runtimeA2UIEnabled, setRuntimeA2UIEnabled] = useState(false); useEffect(() => { if (typeof window === "undefined") return; if (showDevConsole === true) setShouldRenderInspector(true); else if (showDevConsole === "auto") if (new Set(["localhost", "127.0.0.1"]).has(window.location.hostname)) setShouldRenderInspector(true); else setShouldRenderInspector(false); else setShouldRenderInspector(false); }, [showDevConsole]); const renderToolCallsList = useStableArrayProp(renderToolCalls, "renderToolCalls must be a stable array. If you want to dynamically add or remove tools, use `useFrontendTool` instead.", (initial, next) => { const key = (rc) => `${rc?.agentId ?? ""}:${rc?.name ?? ""}`; const setFrom = (arr) => new Set(arr.map(key)); const a = setFrom(initial); const b = setFrom(next); if (a.size !== b.size) return true; for (const k of a) if (!b.has(k)) return true; return false; }); const renderCustomMessagesList = useStableArrayProp(renderCustomMessages, "renderCustomMessages must be a stable array."); const renderActivityMessagesList = useStableArrayProp(renderActivityMessages, "renderActivityMessages must be a stable array."); const builtInActivityRenderers = useMemo(() => { const renderers = [{ activityType: MCPAppsActivityType, content: MCPAppsActivityContentSchema, render: MCPAppsActivityRenderer }]; if (runtimeA2UIEnabled) renderers.unshift(createA2UIMessageRenderer({ theme: a2ui?.theme ?? viewerTheme })); return renderers; }, [runtimeA2UIEnabled, a2ui]); const allActivityRenderers = useMemo(() => { return [...renderActivityMessagesList, ...builtInActivityRenderers]; }, [renderActivityMessagesList, builtInActivityRenderers]); const resolvedPublicKey = publicApiKey ?? publicLicenseKey; const mergedAgents = useMemo(() => ({ ...agents, ...selfManagedAgents }), [agents, selfManagedAgents]); const hasLocalAgents = mergedAgents && Object.keys(mergedAgents).length > 0; const mergedHeaders = useMemo(() => { if (!resolvedPublicKey) return headers; if (headers[HEADER_NAME]) return headers; return { ...headers, [HEADER_NAME]: resolvedPublicKey }; }, [headers, resolvedPublicKey]); if (!runtimeUrl && !resolvedPublicKey && !hasLocalAgents) { const message = "Missing required prop: 'runtimeUrl' or 'publicApiKey' or 'publicLicenseKey'"; if (process.env.NODE_ENV === "production") throw new Error(message); else console.warn(message); } const chatApiEndpoint = runtimeUrl ?? (resolvedPublicKey ? COPILOT_CLOUD_CHAT_URL : void 0); const frontendToolsList = useStableArrayProp(frontendTools, "frontendTools must be a stable array. If you want to dynamically add or remove tools, use `useFrontendTool` instead."); const humanInTheLoopList = useStableArrayProp(humanInTheLoop, "humanInTheLoop must be a stable array. If you want to dynamically add or remove human-in-the-loop tools, use `useHumanInTheLoop` instead."); const processedHumanInTheLoopTools = useMemo(() => { const processedTools = []; const processedRenderToolCalls = []; humanInTheLoopList.forEach((tool) => { const frontendTool = { name: tool.name, description: tool.description, parameters: tool.parameters, followUp: tool.followUp, ...tool.agentId && { agentId: tool.agentId }, handler: async () => { return new Promise((resolve) => { console.warn(`Human-in-the-loop tool '${tool.name}' called but no interactive handler is set up.`); resolve(void 0); }); } }; processedTools.push(frontendTool); if (tool.render) processedRenderToolCalls.push({ name: tool.name, args: tool.parameters, render: tool.render, ...tool.agentId && { agentId: tool.agentId } }); }); return { tools: processedTools, renderToolCalls: processedRenderToolCalls }; }, [humanInTheLoopList]); const allTools = useMemo(() => { const tools = []; tools.push(...frontendToolsList); tools.push(...processedHumanInTheLoopTools.tools); return tools; }, [frontendToolsList, processedHumanInTheLoopTools]); const allRenderToolCalls = useMemo(() => { const combined = [...renderToolCallsList]; frontendToolsList.forEach((tool) => { if (tool.render) { const args = tool.parameters || (tool.name === "*" ? z.any() : void 0); if (args) combined.push({ name: tool.name, args, render: tool.render }); } }); combined.push(...processedHumanInTheLoopTools.renderToolCalls); return combined; }, [ renderToolCallsList, frontendToolsList, processedHumanInTheLoopTools ]); const copilotkitRef = useRef(null); if (copilotkitRef.current === null) copilotkitRef.current = new CopilotKitCoreReact({ runtimeUrl: chatApiEndpoint, runtimeTransport: useSingleEndpoint ? "single" : "rest", headers: mergedHeaders, credentials, properties, agents__unsafe_dev_only: mergedAgents, tools: allTools, renderToolCalls: allRenderToolCalls, renderActivityMessages: allActivityRenderers, renderCustomMessages: renderCustomMessagesList }); const copilotkit = copilotkitRef.current; useEffect(() => { const subscription = copilotkit.subscribe({ onRuntimeConnectionStatusChanged: () => { setRuntimeA2UIEnabled(copilotkit.a2uiEnabled); } }); return () => { subscription.unsubscribe(); }; }, [copilotkit]); const [, forceUpdate] = useReducer((x) => x + 1, 0); useEffect(() => { const subscription = copilotkit.subscribe({ onRenderToolCallsChanged: () => { forceUpdate(); } }); return () => { subscription.unsubscribe(); }; }, [copilotkit]); const [executingToolCallIds, setExecutingToolCallIds] = useState(() => /* @__PURE__ */ new Set()); useEffect(() => { const subscription = copilotkit.subscribe({ onToolExecutionStart: ({ toolCallId }) => { setExecutingToolCallIds((prev) => { if (prev.has(toolCallId)) return prev; const next = new Set(prev); next.add(toolCallId); return next; }); }, onToolExecutionEnd: ({ toolCallId }) => { setExecutingToolCallIds((prev) => { if (!prev.has(toolCallId)) return prev; const next = new Set(prev); next.delete(toolCallId); return next; }); } }); return () => { subscription.unsubscribe(); }; }, [copilotkit]); const onErrorRef = useRef(onError); useEffect(() => { onErrorRef.current = onError; }, [onError]); useEffect(() => { if (!onErrorRef.current) return; const subscription = copilotkit.subscribe({ onError: (event) => { onErrorRef.current?.({ error: event.error, code: event.code, context: event.context }); } }); return () => { subscription.unsubscribe(); }; }, [copilotkit]); useEffect(() => { copilotkit.setRuntimeUrl(chatApiEndpoint); copilotkit.setRuntimeTransport(useSingleEndpoint ? "single" : "rest"); copilotkit.setHeaders(mergedHeaders); copilotkit.setCredentials(credentials); copilotkit.setProperties(properties); copilotkit.setAgents__unsafe_dev_only(mergedAgents); }, [ copilotkit, chatApiEndpoint, mergedHeaders, credentials, properties, mergedAgents, useSingleEndpoint ]); const didMountRef = useRef(false); useEffect(() => { if (!didMountRef.current) return; copilotkit.setTools(allTools); }, [copilotkit, allTools]); useEffect(() => { if (!didMountRef.current) return; copilotkit.setRenderToolCalls(allRenderToolCalls); }, [copilotkit, allRenderToolCalls]); useEffect(() => { if (!didMountRef.current) return; copilotkit.setRenderActivityMessages(allActivityRenderers); }, [copilotkit, allActivityRenderers]); useEffect(() => { if (!didMountRef.current) return; copilotkit.setRenderCustomMessages(renderCustomMessagesList); }, [copilotkit, renderCustomMessagesList]); useEffect(() => { didMountRef.current = true; }, []); const contextValue = useMemo(() => ({ copilotkit, executingToolCallIds }), [copilotkit, executingToolCallIds]); return /* @__PURE__ */ jsxs(CopilotKitContext.Provider, { value: contextValue, children: [children, shouldRenderInspector ? /* @__PURE__ */ jsx(CopilotKitInspector, { core: copilotkit }) : null] }); }; const useCopilotKit = () => { const context = useContext(CopilotKitContext); const [, forceUpdate] = useReducer((x) => x + 1, 0); if (!context) throw new Error("useCopilotKit must be used within CopilotKitProvider"); useEffect(() => { const subscription = context.copilotkit.subscribe({ onRuntimeConnectionStatusChanged: () => { forceUpdate(); } }); return () => { subscription.unsubscribe(); }; }, []); return context; }; //#endregion export { CopilotKitProvider, useCopilotKit }; //# sourceMappingURL=CopilotKitProvider.mjs.map