import { CopilotKitCoreReact, useCopilotKit } from "@copilotkit/react-core/v2/context";
import React, { createContext, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useReducer, useRef, useState, useSyncExternalStore } from "react";
import { DEFAULT_AGENT_ID, randomUUID } from "@copilotkit/shared";
import { twMerge } from "tailwind-merge";
import { jsx } from "react/jsx-runtime";
import { HttpAgent } from "@ag-ui/client";
import { CopilotKitCoreRuntimeConnectionStatus, ProxiedCopilotRuntimeAgent, ɵcreateThreadStore, ɵselectHasNextPage, ɵselectIsFetchingNextPage, ɵselectThreads, ɵselectThreadsError, ɵselectThreadsIsLoading } from "@copilotkit/core";
import { z } from "zod";

//#region src/v2/lib/slots.tsx
/**
* Shallow equality comparison for objects.
*/
function shallowEqual(obj1, obj2) {
	const keys1 = Object.keys(obj1);
	const keys2 = Object.keys(obj2);
	if (keys1.length !== keys2.length) return false;
	for (const key of keys1) if (obj1[key] !== obj2[key]) return false;
	return true;
}
/**
* Returns true only for plain JS objects (`{}`), excluding arrays, Dates,
* class instances, and other exotic objects that happen to have typeof "object".
*/
function isPlainObject(obj) {
	return obj !== null && typeof obj === "object" && Object.prototype.toString.call(obj) === "[object Object]";
}
/**
* Returns the same reference as long as the value is shallowly equal to the
* previous render's value.
*
* - Identical references bail out immediately (O(1)).
* - Plain objects ({}) are shallow-compared key-by-key.
* - Arrays, Dates, class instances, functions, and primitives are compared by
*   reference only — shallowEqual is never called on non-plain objects, which
*   avoids incorrect equality for e.g. [1,2] vs [1,2] (different arrays).
*
* Typical use: stabilize inline slot props so MemoizedSlotWrapper's shallow
* equality check isn't defeated by a new object reference on every render.
*/
function useShallowStableRef(value) {
	const ref = useRef(value);
	if (ref.current === value) return ref.current;
	if (isPlainObject(ref.current) && isPlainObject(value)) {
		if (shallowEqual(ref.current, value)) return ref.current;
	}
	ref.current = value;
	return ref.current;
}
/**
* Check if a value is a React component type (function, class, forwardRef, memo, etc.)
*/
function isReactComponentType(value) {
	if (typeof value === "function") return true;
	if (value && typeof value === "object" && "$$typeof" in value && !React.isValidElement(value)) return true;
	return false;
}
/**
* Internal function to render a slot value as a React element (non-memoized).
*/
function renderSlotElement(slot, DefaultComponent, props) {
	if (typeof slot === "string") {
		const existingClassName = props.className;
		return React.createElement(DefaultComponent, {
			...props,
			className: twMerge(existingClassName, slot)
		});
	}
	if (isReactComponentType(slot)) return React.createElement(slot, props);
	if (slot && typeof slot === "object" && !React.isValidElement(slot)) return React.createElement(DefaultComponent, {
		...props,
		...slot
	});
	return React.createElement(DefaultComponent, props);
}
/**
* Internal memoized wrapper component for renderSlot.
* Uses forwardRef to support ref forwarding.
*/
const MemoizedSlotWrapper = React.memo(React.forwardRef(function MemoizedSlotWrapper(props, ref) {
	const { $slot, $component, ...rest } = props;
	return renderSlotElement($slot, $component, ref !== null ? {
		...rest,
		ref
	} : rest);
}), (prev, next) => {
	if (prev.$slot !== next.$slot) return false;
	if (prev.$component !== next.$component) return false;
	const { $slot: _ps, $component: _pc, ...prevRest } = prev;
	const { $slot: _ns, $component: _nc, ...nextRest } = next;
	return shallowEqual(prevRest, nextRest);
});

//#endregion
//#region src/v2/providers/CopilotChatConfigurationProvider.tsx
const CopilotChatDefaultLabels = {
	chatInputPlaceholder: "Type a message...",
	chatInputToolbarStartTranscribeButtonLabel: "Transcribe",
	chatInputToolbarCancelTranscribeButtonLabel: "Cancel",
	chatInputToolbarFinishTranscribeButtonLabel: "Finish",
	chatInputToolbarAddButtonLabel: "Add attachments",
	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?"
};
const CopilotChatConfiguration = createContext(null);
const CopilotChatConfigurationProvider = ({ children, labels, agentId, threadId, hasExplicitThreadId, isModalDefaultOpen }) => {
	const parentConfig = useContext(CopilotChatConfiguration);
	const stableLabels = useShallowStableRef(labels);
	const mergedLabels = useMemo(() => ({
		...CopilotChatDefaultLabels,
		...parentConfig?.labels,
		...stableLabels
	}), [stableLabels, parentConfig?.labels]);
	const resolvedAgentId = agentId ?? parentConfig?.agentId ?? DEFAULT_AGENT_ID;
	const resolvedThreadId = useMemo(() => {
		if (threadId) return threadId;
		if (parentConfig?.threadId) return parentConfig.threadId;
		return randomUUID();
	}, [threadId, parentConfig?.threadId]);
	const resolvedHasExplicitThreadId = (hasExplicitThreadId !== void 0 ? hasExplicitThreadId : !!threadId) || !!parentConfig?.hasExplicitThreadId;
	const [internalModalOpen, setInternalModalOpen] = useState(isModalDefaultOpen ?? true);
	const hasExplicitDefault = isModalDefaultOpen !== void 0;
	const setAndSync = useCallback((open) => {
		setInternalModalOpen(open);
		parentConfig?.setModalOpen(open);
	}, [parentConfig?.setModalOpen]);
	const isMounted = useRef(false);
	useEffect(() => {
		if (!hasExplicitDefault) return;
		if (!isMounted.current) {
			isMounted.current = true;
			return;
		}
		if (parentConfig?.isModalOpen === void 0) return;
		setInternalModalOpen(parentConfig.isModalOpen);
	}, [parentConfig?.isModalOpen, hasExplicitDefault]);
	const resolvedIsModalOpen = hasExplicitDefault ? internalModalOpen : parentConfig?.isModalOpen ?? internalModalOpen;
	const resolvedSetModalOpen = hasExplicitDefault ? setAndSync : parentConfig?.setModalOpen ?? setInternalModalOpen;
	const configurationValue = useMemo(() => ({
		labels: mergedLabels,
		agentId: resolvedAgentId,
		threadId: resolvedThreadId,
		hasExplicitThreadId: resolvedHasExplicitThreadId,
		isModalOpen: resolvedIsModalOpen,
		setModalOpen: resolvedSetModalOpen
	}), [
		mergedLabels,
		resolvedAgentId,
		resolvedThreadId,
		resolvedHasExplicitThreadId,
		resolvedIsModalOpen,
		resolvedSetModalOpen
	]);
	return /* @__PURE__ */ jsx(CopilotChatConfiguration.Provider, {
		value: configurationValue,
		children
	});
};
const useCopilotChatConfiguration = () => {
	return useContext(CopilotChatConfiguration);
};

//#endregion
//#region src/v2/hooks/use-agent.tsx
let UseAgentUpdate = /* @__PURE__ */ function(UseAgentUpdate) {
	UseAgentUpdate["OnMessagesChanged"] = "OnMessagesChanged";
	UseAgentUpdate["OnStateChanged"] = "OnStateChanged";
	UseAgentUpdate["OnRunStatusChanged"] = "OnRunStatusChanged";
	return UseAgentUpdate;
}({});
const ALL_UPDATES = [
	UseAgentUpdate.OnMessagesChanged,
	UseAgentUpdate.OnStateChanged,
	UseAgentUpdate.OnRunStatusChanged
];
function useAgent({ agentId, updates, throttleMs } = {}) {
	agentId ??= DEFAULT_AGENT_ID;
	const { copilotkit } = useCopilotKit();
	const providerThrottleMs = copilotkit.defaultThrottleMs;
	const [, forceUpdate] = useReducer((x) => x + 1, 0);
	const updateFlags = useMemo(() => updates ?? ALL_UPDATES, [JSON.stringify(updates)]);
	const provisionalAgentCache = useRef(/* @__PURE__ */ new Map());
	const agent = useMemo(() => {
		const existing = copilotkit.getAgent(agentId);
		if (existing) {
			provisionalAgentCache.current.delete(agentId);
			return existing;
		}
		const isRuntimeConfigured = copilotkit.runtimeUrl !== void 0;
		const status = copilotkit.runtimeConnectionStatus;
		if (isRuntimeConfigured && (status === CopilotKitCoreRuntimeConnectionStatus.Disconnected || status === CopilotKitCoreRuntimeConnectionStatus.Connecting)) {
			const cached = provisionalAgentCache.current.get(agentId);
			if (cached) {
				cached.headers = { ...copilotkit.headers };
				return cached;
			}
			const provisional = new ProxiedCopilotRuntimeAgent({
				runtimeUrl: copilotkit.runtimeUrl,
				agentId,
				transport: copilotkit.runtimeTransport,
				runtimeMode: "pending"
			});
			provisional.headers = { ...copilotkit.headers };
			provisionalAgentCache.current.set(agentId, provisional);
			return provisional;
		}
		if (isRuntimeConfigured && status === CopilotKitCoreRuntimeConnectionStatus.Error) {
			const cached = provisionalAgentCache.current.get(agentId);
			if (cached) {
				cached.headers = { ...copilotkit.headers };
				return cached;
			}
			const provisional = new ProxiedCopilotRuntimeAgent({
				runtimeUrl: copilotkit.runtimeUrl,
				agentId,
				transport: copilotkit.runtimeTransport,
				runtimeMode: "pending"
			});
			provisional.headers = { ...copilotkit.headers };
			provisionalAgentCache.current.set(agentId, provisional);
			return provisional;
		}
		const knownAgents = Object.keys(copilotkit.agents ?? {});
		const runtimePart = isRuntimeConfigured ? `runtimeUrl=${copilotkit.runtimeUrl}` : "no runtimeUrl";
		throw new Error(`useAgent: Agent '${agentId}' not found after runtime sync (${runtimePart}). ` + (knownAgents.length ? `Known agents: [${knownAgents.join(", ")}]` : "No agents registered.") + " Verify your runtime /info and/or agents__unsafe_dev_only.");
	}, [
		agentId,
		copilotkit.agents,
		copilotkit.runtimeConnectionStatus,
		copilotkit.runtimeUrl,
		copilotkit.runtimeTransport,
		JSON.stringify(copilotkit.headers)
	]);
	useEffect(() => {
		if (updateFlags.length === 0) return;
		let active = true;
		const handlers = {};
		let batchScheduled = false;
		const batchedForceUpdate = () => {
			if (!active) return;
			if (!batchScheduled) {
				batchScheduled = true;
				queueMicrotask(() => {
					batchScheduled = false;
					if (active) forceUpdate();
				});
			}
		};
		if (updateFlags.includes(UseAgentUpdate.OnMessagesChanged)) handlers.onMessagesChanged = batchedForceUpdate;
		if (updateFlags.includes(UseAgentUpdate.OnStateChanged)) handlers.onStateChanged = batchedForceUpdate;
		if (updateFlags.includes(UseAgentUpdate.OnRunStatusChanged)) {
			handlers.onRunInitialized = batchedForceUpdate;
			handlers.onRunFinalized = batchedForceUpdate;
			handlers.onRunFailed = batchedForceUpdate;
			handlers.onRunErrorEvent = batchedForceUpdate;
		}
		const subscription = copilotkit.subscribeToAgentWithOptions(agent, handlers, { throttleMs });
		return () => {
			active = false;
			subscription.unsubscribe();
		};
	}, [
		agent,
		forceUpdate,
		throttleMs,
		providerThrottleMs,
		updateFlags
	]);
	useEffect(() => {
		if (agent instanceof HttpAgent) agent.headers = { ...copilotkit.headers };
	}, [agent, JSON.stringify(copilotkit.headers)]);
	const chatConfig = useCopilotChatConfiguration();
	const configThreadId = chatConfig?.threadId;
	const configHasExplicitThreadId = chatConfig?.hasExplicitThreadId;
	useEffect(() => {
		if (!configHasExplicitThreadId || !configThreadId) return;
		agent.threadId = configThreadId;
	}, [
		agent,
		configThreadId,
		configHasExplicitThreadId
	]);
	return { agent };
}

//#endregion
//#region src/v2/hooks/use-frontend-tool.tsx
const EMPTY_DEPS$1 = [];
function useFrontendTool(tool, deps) {
	const { copilotkit } = useCopilotKit();
	const extraDeps = deps ?? EMPTY_DEPS$1;
	useEffect(() => {
		const name = tool.name;
		if (copilotkit.getTool({
			toolName: name,
			agentId: tool.agentId
		})) {
			console.warn(`Tool '${name}' already exists for agent '${tool.agentId || "global"}'. Overriding with latest registration.`);
			copilotkit.removeTool(name, tool.agentId);
		}
		copilotkit.addTool(tool);
		if (tool.render) copilotkit.addHookRenderToolCall({
			name,
			args: tool.parameters,
			agentId: tool.agentId,
			render: tool.render
		});
		return () => {
			copilotkit.removeTool(name, tool.agentId);
		};
	}, [
		tool.name,
		tool.available,
		copilotkit,
		JSON.stringify(extraDeps)
	]);
}

//#endregion
//#region src/v2/hooks/use-component.tsx
/**
* Registers a React component as a frontend tool renderer in chat.
*
* This hook is a convenience wrapper around `useFrontendTool` that:
* - builds a model-facing tool description,
* - forwards optional schema parameters (any Standard Schema V1 compatible library),
* - renders your component with tool call parameters.
*
* Use this when you want to display a typed visual component for a tool call
* without manually wiring a full frontend tool object.
*
* When `parameters` is provided, render props are inferred from the schema.
* When omitted, the render component may accept any props.
*
* @typeParam TSchema - Schema describing tool parameters, or `undefined` when no schema is given.
* @param config - Tool registration config.
* @param deps - Optional dependencies to refresh registration (same semantics as `useEffect`).
*
* @example
* ```tsx
* // Without parameters — render accepts any props
* useComponent({
*   name: "showGreeting",
*   render: ({ message }: { message: string }) => <div>{message}</div>,
* });
* ```
*
* @example
* ```tsx
* // With parameters — render props inferred from schema
* useComponent({
*   name: "showWeatherCard",
*   parameters: z.object({ city: z.string() }),
*   render: ({ city }) => <div>{city}</div>,
* });
* ```
*
* @example
* ```tsx
* useComponent(
*   {
*     name: "renderProfile",
*     parameters: z.object({ userId: z.string() }),
*     render: ProfileCard,
*     agentId: "support-agent",
*   },
*   [selectedAgentId],
* );
* ```
*/
function useComponent(config, deps) {
	const prefix = `Use this tool to display the "${config.name}" component in the chat. This tool renders a visual UI component for the user.`;
	const fullDescription = config.description ? `${prefix}\n\n${config.description}` : prefix;
	useFrontendTool({
		name: config.name,
		description: fullDescription,
		parameters: config.parameters,
		render: ({ args }) => {
			const Component = config.render;
			return /* @__PURE__ */ jsx(Component, { ...args });
		},
		agentId: config.agentId,
		followUp: config.followUp
	}, deps);
}

//#endregion
//#region src/v2/hooks/use-human-in-the-loop.tsx
function useHumanInTheLoop(tool, deps) {
	const { copilotkit } = useCopilotKit();
	const resolvePromiseRef = useRef(null);
	const respond = useCallback(async (result) => {
		if (resolvePromiseRef.current) {
			resolvePromiseRef.current(result);
			resolvePromiseRef.current = null;
		}
	}, []);
	const handler = useCallback(async () => {
		return new Promise((resolve) => {
			resolvePromiseRef.current = resolve;
		});
	}, []);
	const RenderComponent = useCallback((props) => {
		const ToolComponent = tool.render;
		if (props.status === "inProgress") {
			const enhancedProps = {
				...props,
				name: tool.name,
				description: tool.description || "",
				respond: void 0
			};
			return React.createElement(ToolComponent, enhancedProps);
		} else if (props.status === "executing") {
			const enhancedProps = {
				...props,
				name: tool.name,
				description: tool.description || "",
				respond
			};
			return React.createElement(ToolComponent, enhancedProps);
		} else if (props.status === "complete") {
			const enhancedProps = {
				...props,
				name: tool.name,
				description: tool.description || "",
				respond: void 0
			};
			return React.createElement(ToolComponent, enhancedProps);
		}
		return React.createElement(ToolComponent, props);
	}, [
		tool.render,
		tool.name,
		tool.description,
		respond
	]);
	useFrontendTool({
		...tool,
		handler,
		render: RenderComponent
	}, deps);
	useEffect(() => {
		return () => {
			copilotkit.removeHookRenderToolCall(tool.name, tool.agentId);
		};
	}, [
		copilotkit,
		tool.name,
		tool.agentId
	]);
}

//#endregion
//#region src/v2/hooks/use-interrupt.tsx
const INTERRUPT_EVENT_NAME = "on_interrupt";
function isPromiseLike(value) {
	return (typeof value === "object" || typeof value === "function") && value !== null && typeof Reflect.get(value, "then") === "function";
}
/**
* Handles agent interrupts (`on_interrupt`) with optional filtering, preprocessing, and resume behavior.
*
* The hook listens to custom events on the active agent, stores interrupt payloads per run,
* and surfaces a render callback once the run finalizes. Call `resolve` from your UI to resume
* execution with user-provided data.
*
* - `renderInChat: true` (default): the element is published into `<CopilotChat>` and this hook returns `void`.
* - `renderInChat: false`: the hook returns the interrupt element so you can place it anywhere in your component tree.
*
* `event.value` is typed as `any` since the interrupt payload shape depends on your agent.
* Type-narrow it in your callbacks (e.g. `handler`, `enabled`, `render`) as needed.
*
* @typeParam TResult - Inferred from `handler` return type. Exposed as `result` in `render`.
* @param config - Interrupt configuration (renderer, optional handler/filter, and render mode).
* @returns When `renderInChat` is `false`, returns the interrupt element (or `null` when idle).
* Otherwise returns `void` and publishes the element into chat. In `render`, `result` is always
* either the handler's resolved return value or `null` (including when no handler is provided,
* when filtering skips the interrupt, or when handler execution fails).
*
* @example
* ```tsx
* import { useInterrupt } from "@copilotkit/react-core/v2";
*
* function InterruptUI() {
*   useInterrupt({
*     render: ({ event, resolve }) => (
*       <div>
*         <p>{event.value.question}</p>
*         <button onClick={() => resolve({ approved: true })}>Approve</button>
*         <button onClick={() => resolve({ approved: false })}>Reject</button>
*       </div>
*     ),
*   });
*
*   return null;
* }
* ```
*
* @example
* ```tsx
* import { useInterrupt } from "@copilotkit/react-core/v2";
*
* function CustomPanel() {
*   const interruptElement = useInterrupt({
*     renderInChat: false,
*     enabled: (event) => event.value.startsWith("approval:"),
*     handler: async ({ event }) => ({ label: event.value.toUpperCase() }),
*     render: ({ event, result, resolve }) => (
*       <aside>
*         <strong>{result?.label ?? ""}</strong>
*         <button onClick={() => resolve({ value: event.value })}>Continue</button>
*       </aside>
*     ),
*   });
*
*   return <>{interruptElement}</>;
* }
* ```
*/
function useInterrupt(config) {
	const { copilotkit } = useCopilotKit();
	const { agent } = useAgent({ agentId: config.agentId });
	const [pendingEvent, setPendingEvent] = useState(null);
	const pendingEventRef = useRef(pendingEvent);
	pendingEventRef.current = pendingEvent;
	const [handlerResult, setHandlerResult] = useState(null);
	useEffect(() => {
		let localInterrupt = null;
		const subscription = agent.subscribe({
			onCustomEvent: ({ event }) => {
				if (event.name === INTERRUPT_EVENT_NAME) localInterrupt = {
					name: event.name,
					value: event.value
				};
			},
			onRunStartedEvent: () => {
				localInterrupt = null;
				setPendingEvent(null);
			},
			onRunFinalized: () => {
				if (localInterrupt) {
					setPendingEvent(localInterrupt);
					localInterrupt = null;
				}
			},
			onRunFailed: () => {
				localInterrupt = null;
			}
		});
		return () => subscription.unsubscribe();
	}, [agent]);
	const resolve = useCallback((response) => {
		setPendingEvent(null);
		copilotkit.runAgent({
			agent,
			forwardedProps: { command: {
				resume: response,
				interruptEvent: pendingEventRef.current?.value
			} }
		});
	}, [agent, copilotkit]);
	useEffect(() => {
		if (!pendingEvent) {
			setHandlerResult(null);
			return;
		}
		if (config.enabled && !config.enabled(pendingEvent)) {
			setHandlerResult(null);
			return;
		}
		const handler = config.handler;
		if (!handler) {
			setHandlerResult(null);
			return;
		}
		let cancelled = false;
		const maybePromise = handler({
			event: pendingEvent,
			resolve
		});
		if (isPromiseLike(maybePromise)) Promise.resolve(maybePromise).then((resolved) => {
			if (!cancelled) setHandlerResult(resolved);
		}).catch(() => {
			if (!cancelled) setHandlerResult(null);
		});
		else setHandlerResult(maybePromise);
		return () => {
			cancelled = true;
		};
	}, [
		pendingEvent,
		config.enabled,
		config.handler,
		resolve
	]);
	const element = useMemo(() => {
		if (!pendingEvent) return null;
		if (config.enabled && !config.enabled(pendingEvent)) return null;
		return config.render({
			event: pendingEvent,
			result: handlerResult,
			resolve
		});
	}, [
		pendingEvent,
		handlerResult,
		config.enabled,
		config.render,
		resolve
	]);
	useEffect(() => {
		if (config.renderInChat === false) return;
		copilotkit.setInterruptElement(element);
		return () => copilotkit.setInterruptElement(null);
	}, [
		element,
		config.renderInChat,
		copilotkit
	]);
	if (config.renderInChat === false) return element;
}

//#endregion
//#region src/v2/hooks/use-suggestions.tsx
function useSuggestions({ agentId } = {}) {
	const { copilotkit } = useCopilotKit();
	const config = useCopilotChatConfiguration();
	const resolvedAgentId = useMemo(() => agentId ?? config?.agentId ?? DEFAULT_AGENT_ID, [agentId, config?.agentId]);
	const [suggestions, setSuggestions] = useState(() => {
		return copilotkit.getSuggestions(resolvedAgentId).suggestions;
	});
	const [isLoading, setIsLoading] = useState(() => {
		return copilotkit.getSuggestions(resolvedAgentId).isLoading;
	});
	useEffect(() => {
		const result = copilotkit.getSuggestions(resolvedAgentId);
		setSuggestions(result.suggestions);
		setIsLoading(result.isLoading);
	}, [copilotkit, resolvedAgentId]);
	useEffect(() => {
		const subscription = copilotkit.subscribe({
			onSuggestionsChanged: ({ agentId: changedAgentId, suggestions }) => {
				if (changedAgentId !== resolvedAgentId) return;
				setSuggestions(suggestions);
			},
			onSuggestionsStartedLoading: ({ agentId: changedAgentId }) => {
				if (changedAgentId !== resolvedAgentId) return;
				setIsLoading(true);
			},
			onSuggestionsFinishedLoading: ({ agentId: changedAgentId }) => {
				if (changedAgentId !== resolvedAgentId) return;
				setIsLoading(false);
			},
			onSuggestionsConfigChanged: () => {
				const result = copilotkit.getSuggestions(resolvedAgentId);
				setSuggestions(result.suggestions);
				setIsLoading(result.isLoading);
			}
		});
		return () => {
			subscription.unsubscribe();
		};
	}, [copilotkit, resolvedAgentId]);
	return {
		suggestions,
		reloadSuggestions: useCallback(() => {
			copilotkit.reloadSuggestions(resolvedAgentId);
		}, [copilotkit, resolvedAgentId]),
		clearSuggestions: useCallback(() => {
			copilotkit.clearSuggestions(resolvedAgentId);
		}, [copilotkit, resolvedAgentId]),
		isLoading
	};
}

//#endregion
//#region src/v2/hooks/use-configure-suggestions.tsx
function useConfigureSuggestions(config, deps) {
	const { copilotkit } = useCopilotKit();
	const chatConfig = useCopilotChatConfiguration();
	const extraDeps = deps ?? [];
	const resolvedConsumerAgentId = useMemo(() => chatConfig?.agentId ?? DEFAULT_AGENT_ID, [chatConfig?.agentId]);
	const rawConsumerAgentId = useMemo(() => config ? config.consumerAgentId : void 0, [config]);
	const normalizationCacheRef = useRef({
		serialized: null,
		config: null
	});
	const { normalizedConfig, serializedConfig } = useMemo(() => {
		if (!config) {
			normalizationCacheRef.current = {
				serialized: null,
				config: null
			};
			return {
				normalizedConfig: null,
				serializedConfig: null
			};
		}
		if (config.available === "disabled") {
			normalizationCacheRef.current = {
				serialized: null,
				config: null
			};
			return {
				normalizedConfig: null,
				serializedConfig: null
			};
		}
		let built;
		if (isDynamicConfig(config)) built = { ...config };
		else {
			const normalizedSuggestions = normalizeStaticSuggestions(config.suggestions);
			built = {
				...config,
				suggestions: normalizedSuggestions
			};
		}
		const serialized = JSON.stringify(built);
		const cache = normalizationCacheRef.current;
		if (cache.serialized === serialized && cache.config) return {
			normalizedConfig: cache.config,
			serializedConfig: serialized
		};
		normalizationCacheRef.current = {
			serialized,
			config: built
		};
		return {
			normalizedConfig: built,
			serializedConfig: serialized
		};
	}, [
		config,
		resolvedConsumerAgentId,
		...extraDeps
	]);
	const latestConfigRef = useRef(null);
	latestConfigRef.current = normalizedConfig;
	const previousSerializedConfigRef = useRef(null);
	const targetAgentId = useMemo(() => {
		if (!normalizedConfig) return resolvedConsumerAgentId;
		const consumer = normalizedConfig.consumerAgentId;
		if (!consumer || consumer === "*") return resolvedConsumerAgentId;
		return consumer;
	}, [normalizedConfig, resolvedConsumerAgentId]);
	const isGlobalConfig = rawConsumerAgentId === void 0 || rawConsumerAgentId === "*";
	const isDynamicConfigType = useMemo(() => !!normalizedConfig && "instructions" in normalizedConfig, [normalizedConfig]);
	const requestReload = useCallback(() => {
		if (!normalizedConfig) return;
		if (isGlobalConfig) {
			const seen = /* @__PURE__ */ new Set();
			const agents = Object.values(copilotkit.agents ?? {});
			for (const entry of agents) {
				const agentId = entry.agentId;
				if (!agentId) continue;
				seen.add(agentId);
				if (!entry.isRunning) copilotkit.reloadSuggestions(agentId);
			}
			if (targetAgentId && !seen.has(targetAgentId)) copilotkit.reloadSuggestions(targetAgentId);
			return;
		}
		if (!targetAgentId) return;
		copilotkit.reloadSuggestions(targetAgentId);
	}, [
		copilotkit,
		isGlobalConfig,
		normalizedConfig,
		targetAgentId
	]);
	useEffect(() => {
		if (!serializedConfig || !latestConfigRef.current) return;
		const id = copilotkit.addSuggestionsConfig(latestConfigRef.current);
		requestReload();
		return () => {
			copilotkit.removeSuggestionsConfig(id);
		};
	}, [
		copilotkit,
		serializedConfig,
		requestReload
	]);
	useEffect(() => {
		if (!normalizedConfig) {
			previousSerializedConfigRef.current = null;
			return;
		}
		if (serializedConfig && previousSerializedConfigRef.current === serializedConfig) return;
		if (serializedConfig) previousSerializedConfigRef.current = serializedConfig;
		requestReload();
	}, [
		normalizedConfig,
		requestReload,
		serializedConfig
	]);
	useEffect(() => {
		if (!normalizedConfig || extraDeps.length === 0) return;
		requestReload();
	}, [
		extraDeps.length,
		normalizedConfig,
		requestReload,
		...extraDeps
	]);
	useEffect(() => {
		if (!normalizedConfig || !isDynamicConfigType) return;
		if (!targetAgentId) return;
		if (!!copilotkit.getAgent(targetAgentId)) return;
		const subscription = copilotkit.subscribe({ onAgentsChanged: () => {
			if (copilotkit.getAgent(targetAgentId)) {
				requestReload();
				subscription.unsubscribe();
			}
		} });
		return () => {
			subscription.unsubscribe();
		};
	}, [
		copilotkit,
		normalizedConfig,
		isDynamicConfigType,
		targetAgentId,
		requestReload
	]);
}
function isDynamicConfig(config) {
	return "instructions" in config;
}
function normalizeStaticSuggestions(suggestions) {
	return suggestions.map((suggestion) => ({
		...suggestion,
		isLoading: suggestion.isLoading ?? false
	}));
}

//#endregion
//#region src/v2/hooks/use-agent-context.tsx
function useAgentContext(context) {
	const { description, value } = context;
	const { copilotkit } = useCopilotKit();
	const stringValue = useMemo(() => {
		if (typeof value === "string") return value;
		return JSON.stringify(value);
	}, [value]);
	useLayoutEffect(() => {
		if (!copilotkit) return;
		const id = copilotkit.addContext({
			description,
			value: stringValue
		});
		return () => {
			copilotkit.removeContext(id);
		};
	}, [
		description,
		stringValue,
		copilotkit
	]);
}

//#endregion
//#region src/v2/hooks/use-threads.tsx
function useThreadStoreSelector(store, selector) {
	return useSyncExternalStore(useCallback((onStoreChange) => {
		const subscription = store.select(selector).subscribe(onStoreChange);
		return () => subscription.unsubscribe();
	}, [store, selector]), () => selector(store.getState()));
}
/**
* React hook for listing and managing Intelligence platform threads.
*
* On mount the hook fetches the thread list for the runtime-authenticated user
* and the given `agentId`. When the Intelligence platform exposes a WebSocket
* URL, it also opens a realtime subscription so the `threads` array stays
* current without polling — thread creates, renames, archives, and deletes
* from any client are reflected immediately.
*
* Mutation methods (`renameThread`, `archiveThread`, `deleteThread`) return
* promises that resolve once the platform confirms the operation and reject
* with an `Error` on failure.
*
* @param input - Agent identifier and optional list controls.
* @returns Thread list state and stable mutation callbacks.
*
* @example
* ```tsx
* import { useThreads } from "@copilotkit/react-core";
*
* function ThreadList() {
*   const { threads, isLoading, renameThread, deleteThread } = useThreads({
*     agentId: "agent-1",
*   });
*
*   if (isLoading) return <p>Loading…</p>;
*
*   return (
*     <ul>
*       {threads.map((t) => (
*         <li key={t.id}>
*           {t.name ?? "Untitled"}
*           <button onClick={() => renameThread(t.id, "New name")}>Rename</button>
*           <button onClick={() => deleteThread(t.id)}>Delete</button>
*         </li>
*       ))}
*     </ul>
*   );
* }
* ```
*/
function useThreads({ agentId, includeArchived, limit }) {
	const { copilotkit } = useCopilotKit();
	const [store] = useState(() => ɵcreateThreadStore({ fetch: globalThis.fetch }));
	const coreThreads = useThreadStoreSelector(store, ɵselectThreads);
	const threads = useMemo(() => coreThreads.map(({ id, agentId, name, archived, createdAt, updatedAt, lastRunAt }) => ({
		id,
		agentId,
		name,
		archived,
		createdAt,
		updatedAt,
		...lastRunAt !== void 0 ? { lastRunAt } : {}
	})), [coreThreads]);
	const storeIsLoading = useThreadStoreSelector(store, ɵselectThreadsIsLoading);
	const storeError = useThreadStoreSelector(store, ɵselectThreadsError);
	const hasMoreThreads = useThreadStoreSelector(store, ɵselectHasNextPage);
	const isFetchingMoreThreads = useThreadStoreSelector(store, ɵselectIsFetchingNextPage);
	const headersKey = useMemo(() => {
		return JSON.stringify(Object.entries(copilotkit.headers ?? {}).sort(([left], [right]) => left.localeCompare(right)));
	}, [copilotkit.headers]);
	const runtimeError = useMemo(() => {
		if (copilotkit.runtimeUrl) return null;
		return /* @__PURE__ */ new Error("Runtime URL is not configured");
	}, [copilotkit.runtimeUrl]);
	const [hasDispatchedContext, setHasDispatchedContext] = useState(false);
	const preConnectLoading = !!copilotkit.runtimeUrl && !hasDispatchedContext;
	const isLoading = runtimeError ? false : preConnectLoading || storeIsLoading;
	const error = runtimeError ?? storeError;
	useEffect(() => {
		store.start();
		return () => {
			store.stop();
		};
	}, [store]);
	const runtimeStatus = copilotkit.runtimeConnectionStatus;
	useEffect(() => {
		copilotkit.registerThreadStore(agentId, store);
		return () => {
			copilotkit.unregisterThreadStore(agentId);
		};
	}, [
		copilotkit,
		agentId,
		store
	]);
	useEffect(() => {
		if (!copilotkit.runtimeUrl) {
			store.setContext(null);
			return;
		}
		if (runtimeStatus !== CopilotKitCoreRuntimeConnectionStatus.Connected) return;
		const context = {
			runtimeUrl: copilotkit.runtimeUrl,
			headers: { ...copilotkit.headers },
			wsUrl: copilotkit.intelligence?.wsUrl,
			agentId,
			includeArchived,
			limit
		};
		store.setContext(context);
		setHasDispatchedContext(true);
	}, [
		store,
		copilotkit.runtimeUrl,
		runtimeStatus,
		headersKey,
		copilotkit.intelligence?.wsUrl,
		agentId,
		includeArchived,
		limit
	]);
	const renameThread = useCallback((threadId, name) => store.renameThread(threadId, name), [store]);
	const archiveThread = useCallback((threadId) => store.archiveThread(threadId), [store]);
	const deleteThread = useCallback((threadId) => store.deleteThread(threadId), [store]);
	return {
		threads,
		isLoading,
		error,
		hasMoreThreads,
		isFetchingMoreThreads,
		fetchMoreThreads: useCallback(() => store.fetchNextPage(), [store]),
		renameThread,
		archiveThread,
		deleteThread
	};
}

//#endregion
//#region src/v2/types/defineToolCallRenderer.ts
function defineToolCallRenderer(def) {
	const argsSchema = def.name === "*" && !def.args ? z.any() : def.args;
	return {
		name: def.name,
		args: argsSchema,
		render: def.render,
		...def.agentId ? { agentId: def.agentId } : {}
	};
}

//#endregion
//#region src/v2/hooks/use-render-tool.tsx
const EMPTY_DEPS = [];
/**
* Registers a renderer entry in CopilotKit's `renderToolCalls` registry.
*
* Key behavior:
* - deduplicates by `agentId:name` (latest registration wins),
* - keeps renderer entries on cleanup so historical chat tool calls can still render,
* - refreshes registration when `deps` change.
*
* @typeParam S - Schema type describing tool call parameters.
* @param config - Renderer config for wildcard or named tools.
* @param deps - Optional dependencies to refresh registration.
*
* @example
* ```tsx
* useRenderTool(
*   {
*     name: "searchDocs",
*     parameters: z.object({ query: z.string() }),
*     render: ({ status, parameters, result }) => {
*       if (status === "executing") return <div>Searching {parameters.query}</div>;
*       if (status === "complete") return <div>{result}</div>;
*       return <div>Preparing...</div>;
*     },
*   },
*   [],
* );
* ```
*
* @example
* ```tsx
* useRenderTool(
*   {
*     name: "summarize",
*     parameters: z.object({ text: z.string() }),
*     agentId: "research-agent",
*     render: ({ name, status }) => <div>{name}: {status}</div>,
*   },
*   [selectedAgentId],
* );
* ```
*/
function useRenderTool(config, deps) {
	const { copilotkit } = useCopilotKit();
	const extraDeps = deps ?? EMPTY_DEPS;
	useEffect(() => {
		const renderer = config.name === "*" && !config.parameters ? defineToolCallRenderer({
			name: "*",
			render: (props) => config.render({
				...props,
				parameters: props.args
			}),
			...config.agentId ? { agentId: config.agentId } : {}
		}) : defineToolCallRenderer({
			name: config.name,
			args: config.parameters,
			render: (props) => config.render({
				...props,
				parameters: props.args
			}),
			...config.agentId ? { agentId: config.agentId } : {}
		});
		copilotkit.addHookRenderToolCall(renderer);
	}, [
		config.name,
		copilotkit,
		JSON.stringify(extraDeps)
	]);
}

//#endregion
//#region src/v2/hooks/use-capabilities.tsx
/**
* Returns the capabilities declared by the given agent (or the default agent).
* Capabilities are populated from the runtime `/info` response at connection
* time. The hook reads them synchronously from the agent instance — there is
* no separate loading state, but the value will be `undefined` until the
* runtime handshake completes.
*
* @param agentId - Optional agent ID. If omitted, uses the default agent.
* @returns The agent's capabilities, or `undefined` if the agent doesn't
*          declare capabilities.
*/
function useCapabilities(agentId) {
	const { agent } = useAgent({ agentId });
	if (agent && "capabilities" in agent) return agent.capabilities;
}

//#endregion
export { CopilotChatConfigurationProvider, CopilotChatDefaultLabels, CopilotKitCoreReact, defineToolCallRenderer, useAgent, useAgentContext, useCapabilities, useComponent, useConfigureSuggestions, useCopilotChatConfiguration, useFrontendTool, useHumanInTheLoop, useInterrupt, useRenderTool, useSuggestions, useThreads };
//# sourceMappingURL=headless.mjs.map