@copilotkitnext/react 1.52.2-next.3 → 1.52.2-next.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13,13 +13,30 @@ let react_jsx_runtime = require("react/jsx-runtime");
13
13
  let ts_deepmerge = require("ts-deepmerge");
14
14
 
15
15
  //#region src/components/chat/CopilotChat.tsx
16
- function CopilotChat({ agentId, threadId, labels, chatView, ...props }) {
16
+ function CopilotChat({ agentId, threadId, labels, chatView, onError, ...props }) {
17
17
  const existingConfig = require_CopilotChatConfigurationProvider.useCopilotChatConfiguration();
18
18
  const resolvedAgentId = agentId ?? existingConfig?.agentId ?? _copilotkitnext_shared.DEFAULT_AGENT_ID;
19
19
  const resolvedThreadId = (0, react.useMemo)(() => threadId ?? existingConfig?.threadId ?? (0, _copilotkitnext_shared.randomUUID)(), [threadId, existingConfig?.threadId]);
20
20
  const { agent } = require_use_agent.useAgent({ agentId: resolvedAgentId });
21
21
  const { copilotkit } = require_CopilotKitProvider.useCopilotKit();
22
22
  const { suggestions: autoSuggestions } = require_use_suggestions.useSuggestions({ agentId: resolvedAgentId });
23
+ const onErrorRef = (0, react.useRef)(onError);
24
+ (0, react.useEffect)(() => {
25
+ onErrorRef.current = onError;
26
+ }, [onError]);
27
+ (0, react.useEffect)(() => {
28
+ if (!onErrorRef.current) return;
29
+ const subscription = copilotkit.subscribe({ onError: (event) => {
30
+ if (event.context?.agentId === resolvedAgentId || !event.context?.agentId) onErrorRef.current?.({
31
+ error: event.error,
32
+ code: event.code,
33
+ context: event.context
34
+ });
35
+ } });
36
+ return () => {
37
+ subscription.unsubscribe();
38
+ };
39
+ }, [copilotkit, resolvedAgentId]);
23
40
  const [transcribeMode, setTranscribeMode] = (0, react.useState)("input");
24
41
  const [inputValue, setInputValue] = (0, react.useState)("");
25
42
  const [transcriptionError, setTranscriptionError] = (0, react.useState)(null);
@@ -36,7 +53,7 @@ function CopilotChat({ agentId, threadId, labels, chatView, ...props }) {
36
53
  await copilotkit.connectAgent({ agent });
37
54
  } catch (error) {
38
55
  if (detached) return;
39
- if (error instanceof _ag_ui_client.AGUIConnectNotImplementedError) {} else throw error;
56
+ console.error("CopilotChat: connectAgent failed", error);
40
57
  }
41
58
  };
42
59
  agent.threadId = resolvedThreadId;
@@ -1 +1 @@
1
- {"version":3,"file":"CopilotChat.cjs","names":["useCopilotChatConfiguration","DEFAULT_AGENT_ID","useAgent","useCopilotKit","useSuggestions","HttpAgent","AGUIConnectNotImplementedError","transcribeAudio","TranscriptionError","TranscriptionErrorCode","renderSlot","CopilotChatView","CopilotChatConfigurationProvider"],"sources":["../../../src/components/chat/CopilotChat.tsx"],"sourcesContent":["import { useAgent } from \"@/hooks/use-agent\";\nimport { useSuggestions } from \"@/hooks/use-suggestions\";\nimport { CopilotChatView, CopilotChatViewProps } from \"./CopilotChatView\";\nimport { CopilotChatInputMode } from \"./CopilotChatInput\";\nimport {\n CopilotChatConfigurationProvider,\n CopilotChatLabels,\n useCopilotChatConfiguration,\n} from \"@/providers/CopilotChatConfigurationProvider\";\nimport {\n DEFAULT_AGENT_ID,\n randomUUID,\n TranscriptionErrorCode,\n} from \"@copilotkitnext/shared\";\nimport { Suggestion, CopilotKitCoreErrorCode } from \"@copilotkitnext/core\";\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\nimport { merge } from \"ts-deepmerge\";\nimport { useCopilotKit } from \"@/providers/CopilotKitProvider\";\nimport {\n AbstractAgent,\n AGUIConnectNotImplementedError,\n HttpAgent,\n} from \"@ag-ui/client\";\nimport { renderSlot, SlotValue } from \"@/lib/slots\";\nimport {\n transcribeAudio,\n TranscriptionError,\n} from \"@/lib/transcription-client\";\n\nexport type CopilotChatProps = Omit<\n CopilotChatViewProps,\n | \"messages\"\n | \"isRunning\"\n | \"suggestions\"\n | \"suggestionLoadingIndexes\"\n | \"onSelectSuggestion\"\n> & {\n agentId?: string;\n threadId?: string;\n labels?: Partial<CopilotChatLabels>;\n chatView?: SlotValue<typeof CopilotChatView>;\n};\nexport function CopilotChat({\n agentId,\n threadId,\n labels,\n chatView,\n ...props\n}: CopilotChatProps) {\n // Check for existing configuration provider\n const existingConfig = useCopilotChatConfiguration();\n\n // Apply priority: props > existing config > defaults\n const resolvedAgentId =\n agentId ?? existingConfig?.agentId ?? DEFAULT_AGENT_ID;\n const resolvedThreadId = useMemo(\n () => threadId ?? existingConfig?.threadId ?? randomUUID(),\n [threadId, existingConfig?.threadId],\n );\n\n const { agent } = useAgent({ agentId: resolvedAgentId });\n const { copilotkit } = useCopilotKit();\n const { suggestions: autoSuggestions } = useSuggestions({\n agentId: resolvedAgentId,\n });\n\n // Transcription state\n const [transcribeMode, setTranscribeMode] =\n useState<CopilotChatInputMode>(\"input\");\n const [inputValue, setInputValue] = useState(\"\");\n const [transcriptionError, setTranscriptionError] = useState<string | null>(\n null,\n );\n const [isTranscribing, setIsTranscribing] = useState(false);\n\n // Check if transcription is enabled\n const isTranscriptionEnabled = copilotkit.audioFileTranscriptionEnabled;\n\n // Check if browser supports MediaRecorder\n const isMediaRecorderSupported =\n typeof window !== \"undefined\" && typeof MediaRecorder !== \"undefined\";\n\n const {\n messageView: providedMessageView,\n suggestionView: providedSuggestionView,\n onStop: providedStopHandler,\n ...restProps\n } = props;\n\n useEffect(() => {\n let detached = false;\n\n // Create a fresh AbortController so we can cancel the HTTP request on cleanup.\n // HttpAgent (parent of ProxiedCopilotRuntimeAgent) uses this.abortController.signal\n // in its fetch config. Unlike runAgent(), connectAgent() does NOT create a new\n // AbortController automatically, so we must set one before connecting.\n const connectAbortController = new AbortController();\n if (agent instanceof HttpAgent) {\n agent.abortController = connectAbortController;\n }\n\n const connect = async (agent: AbstractAgent) => {\n try {\n await copilotkit.connectAgent({ agent });\n } catch (error) {\n // Ignore errors from aborted connections (e.g., React StrictMode cleanup)\n if (detached) return;\n if (error instanceof AGUIConnectNotImplementedError) {\n // connect not implemented, ignore\n } else {\n throw error;\n }\n }\n };\n agent.threadId = resolvedThreadId;\n connect(agent);\n return () => {\n // Abort the HTTP request and detach the active run.\n // This is critical for React StrictMode which unmounts+remounts in dev,\n // preventing duplicate /connect requests from reaching the server.\n detached = true;\n connectAbortController.abort();\n agent.detachActiveRun();\n };\n // copilotkit is intentionally excluded — it is a stable ref that never changes.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [resolvedThreadId, agent, resolvedAgentId]);\n\n const onSubmitInput = useCallback(\n async (value: string) => {\n agent.addMessage({\n id: randomUUID(),\n role: \"user\",\n content: value,\n });\n // Clear input after submitting\n setInputValue(\"\");\n try {\n await copilotkit.runAgent({ agent });\n } catch (error) {\n console.error(\"CopilotChat: runAgent failed\", error);\n }\n },\n // copilotkit is intentionally excluded — it is a stable ref that never changes.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [agent],\n );\n\n const handleSelectSuggestion = useCallback(\n async (suggestion: Suggestion) => {\n agent.addMessage({\n id: randomUUID(),\n role: \"user\",\n content: suggestion.message,\n });\n\n try {\n await copilotkit.runAgent({ agent });\n } catch (error) {\n console.error(\n \"CopilotChat: runAgent failed after selecting suggestion\",\n error,\n );\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [agent],\n );\n\n const stopCurrentRun = useCallback(() => {\n try {\n copilotkit.stopAgent({ agent });\n } catch (error) {\n console.error(\"CopilotChat: stopAgent failed\", error);\n try {\n agent.abortRun();\n } catch (abortError) {\n console.error(\"CopilotChat: abortRun fallback failed\", abortError);\n }\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [agent]);\n\n // Transcription handlers\n const handleStartTranscribe = useCallback(() => {\n setTranscriptionError(null);\n setTranscribeMode(\"transcribe\");\n }, []);\n\n const handleCancelTranscribe = useCallback(() => {\n setTranscriptionError(null);\n setTranscribeMode(\"input\");\n }, []);\n\n const handleFinishTranscribe = useCallback(() => {\n setTranscribeMode(\"input\");\n }, []);\n\n // Handle audio blob from CopilotChatInput and transcribe it\n const handleFinishTranscribeWithAudio = useCallback(\n async (audioBlob: Blob) => {\n setIsTranscribing(true);\n try {\n setTranscriptionError(null);\n\n // Send to transcription endpoint\n const result = await transcribeAudio(copilotkit, audioBlob);\n\n // Insert transcribed text into input\n setInputValue((prev) => {\n const trimmedPrev = prev.trim();\n if (trimmedPrev) {\n return `${trimmedPrev} ${result.text}`;\n }\n return result.text;\n });\n } catch (error) {\n console.error(\"CopilotChat: Transcription failed\", error);\n\n // Show contextual error message based on error type\n if (error instanceof TranscriptionError) {\n const { code, retryable, message } = error.info;\n switch (code) {\n case TranscriptionErrorCode.RATE_LIMITED:\n setTranscriptionError(\"Too many requests. Please wait a moment.\");\n break;\n case TranscriptionErrorCode.AUTH_FAILED:\n setTranscriptionError(\n \"Authentication error. Please check your configuration.\",\n );\n break;\n case TranscriptionErrorCode.AUDIO_TOO_LONG:\n setTranscriptionError(\n \"Recording is too long. Please try a shorter recording.\",\n );\n break;\n case TranscriptionErrorCode.AUDIO_TOO_SHORT:\n setTranscriptionError(\n \"Recording is too short. Please try again.\",\n );\n break;\n case TranscriptionErrorCode.INVALID_AUDIO_FORMAT:\n setTranscriptionError(\"Audio format not supported.\");\n break;\n case TranscriptionErrorCode.SERVICE_NOT_CONFIGURED:\n setTranscriptionError(\"Transcription service is not available.\");\n break;\n case TranscriptionErrorCode.NETWORK_ERROR:\n setTranscriptionError(\n \"Network error. Please check your connection.\",\n );\n break;\n default:\n // For retryable errors, show more helpful message\n setTranscriptionError(\n retryable ? \"Transcription failed. Please try again.\" : message,\n );\n }\n } else {\n // Fallback for unexpected errors\n setTranscriptionError(\"Transcription failed. Please try again.\");\n }\n } finally {\n setIsTranscribing(false);\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [],\n );\n\n // Clear transcription error after a delay\n useEffect(() => {\n if (transcriptionError) {\n const timer = setTimeout(() => {\n setTranscriptionError(null);\n }, 5000);\n return () => clearTimeout(timer);\n }\n }, [transcriptionError]);\n\n const mergedProps = merge(\n {\n isRunning: agent.isRunning,\n suggestions: autoSuggestions,\n onSelectSuggestion: handleSelectSuggestion,\n suggestionView: providedSuggestionView,\n },\n {\n ...restProps,\n ...(typeof providedMessageView === \"string\"\n ? { messageView: { className: providedMessageView } }\n : providedMessageView !== undefined\n ? { messageView: providedMessageView }\n : {}),\n },\n );\n\n const hasMessages = agent.messages.length > 0;\n const shouldAllowStop = agent.isRunning && hasMessages;\n const effectiveStopHandler = shouldAllowStop\n ? (providedStopHandler ?? stopCurrentRun)\n : providedStopHandler;\n\n // Determine if transcription feature should be available\n const showTranscription = isTranscriptionEnabled && isMediaRecorderSupported;\n\n // Determine mode: transcribing takes priority, then transcribe mode, then default to input\n const effectiveMode: CopilotChatInputMode = isTranscribing\n ? \"processing\"\n : transcribeMode;\n\n // Memoize messages array - only create new reference when content actually changes\n // (agent.messages is mutated in place, so we need a new reference for React to detect changes)\n\n const messages = useMemo(\n () => [...agent.messages],\n [JSON.stringify(agent.messages)],\n );\n\n const finalProps = merge(mergedProps, {\n messages,\n // Input behavior props\n onSubmitMessage: onSubmitInput,\n onStop: effectiveStopHandler,\n inputMode: effectiveMode,\n inputValue,\n onInputChange: setInputValue,\n // Only provide transcription handlers if feature is available\n onStartTranscribe: showTranscription ? handleStartTranscribe : undefined,\n onCancelTranscribe: showTranscription ? handleCancelTranscribe : undefined,\n onFinishTranscribe: showTranscription ? handleFinishTranscribe : undefined,\n onFinishTranscribeWithAudio: showTranscription\n ? handleFinishTranscribeWithAudio\n : undefined,\n }) as CopilotChatViewProps;\n\n // Always create a provider with merged values\n // This ensures priority: props > existing config > defaults\n const RenderedChatView = renderSlot(chatView, CopilotChatView, finalProps);\n\n return (\n <CopilotChatConfigurationProvider\n agentId={resolvedAgentId}\n threadId={resolvedThreadId}\n labels={labels}\n >\n {transcriptionError && (\n <div\n style={{\n position: \"absolute\",\n bottom: \"100px\",\n left: \"50%\",\n transform: \"translateX(-50%)\",\n backgroundColor: \"#ef4444\",\n color: \"white\",\n padding: \"8px 16px\",\n borderRadius: \"8px\",\n fontSize: \"14px\",\n zIndex: 50,\n }}\n >\n {transcriptionError}\n </div>\n )}\n {RenderedChatView}\n </CopilotChatConfigurationProvider>\n );\n}\n\n// eslint-disable-next-line @typescript-eslint/no-namespace\nexport namespace CopilotChat {\n export const View = CopilotChatView;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"CopilotChat.cjs","names":["useCopilotChatConfiguration","DEFAULT_AGENT_ID","useAgent","useCopilotKit","useSuggestions","HttpAgent","transcribeAudio","TranscriptionError","TranscriptionErrorCode","renderSlot","CopilotChatView","CopilotChatConfigurationProvider"],"sources":["../../../src/components/chat/CopilotChat.tsx"],"sourcesContent":["import { useAgent } from \"@/hooks/use-agent\";\nimport { useSuggestions } from \"@/hooks/use-suggestions\";\nimport { CopilotChatView, CopilotChatViewProps } from \"./CopilotChatView\";\nimport { CopilotChatInputMode } from \"./CopilotChatInput\";\nimport {\n CopilotChatConfigurationProvider,\n CopilotChatLabels,\n useCopilotChatConfiguration,\n} from \"@/providers/CopilotChatConfigurationProvider\";\nimport {\n DEFAULT_AGENT_ID,\n randomUUID,\n TranscriptionErrorCode,\n} from \"@copilotkitnext/shared\";\nimport { Suggestion, CopilotKitCoreErrorCode } from \"@copilotkitnext/core\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { merge } from \"ts-deepmerge\";\nimport { useCopilotKit } from \"@/providers/CopilotKitProvider\";\nimport { AbstractAgent, HttpAgent } from \"@ag-ui/client\";\nimport { renderSlot, SlotValue } from \"@/lib/slots\";\nimport {\n transcribeAudio,\n TranscriptionError,\n} from \"@/lib/transcription-client\";\n\nexport type CopilotChatProps = Omit<\n CopilotChatViewProps,\n | \"messages\"\n | \"isRunning\"\n | \"suggestions\"\n | \"suggestionLoadingIndexes\"\n | \"onSelectSuggestion\"\n> & {\n agentId?: string;\n threadId?: string;\n labels?: Partial<CopilotChatLabels>;\n chatView?: SlotValue<typeof CopilotChatView>;\n /**\n * Error handler scoped to this chat's agent. Fires in addition to the\n * provider-level onError (does not suppress it). Receives only errors\n * whose context.agentId matches this chat's agent.\n */\n onError?: (event: {\n error: Error;\n code: CopilotKitCoreErrorCode;\n context: Record<string, any>;\n }) => void | Promise<void>;\n};\nexport function CopilotChat({\n agentId,\n threadId,\n labels,\n chatView,\n onError,\n ...props\n}: CopilotChatProps) {\n // Check for existing configuration provider\n const existingConfig = useCopilotChatConfiguration();\n\n // Apply priority: props > existing config > defaults\n const resolvedAgentId =\n agentId ?? existingConfig?.agentId ?? DEFAULT_AGENT_ID;\n const resolvedThreadId = useMemo(\n () => threadId ?? existingConfig?.threadId ?? randomUUID(),\n [threadId, existingConfig?.threadId],\n );\n\n const { agent } = useAgent({ agentId: resolvedAgentId });\n const { copilotkit } = useCopilotKit();\n const { suggestions: autoSuggestions } = useSuggestions({\n agentId: resolvedAgentId,\n });\n\n // onError subscription — forward core errors scoped to this chat's agent\n const onErrorRef = useRef(onError);\n useEffect(() => {\n onErrorRef.current = onError;\n }, [onError]);\n\n useEffect(() => {\n if (!onErrorRef.current) return;\n\n const subscription = copilotkit.subscribe({\n onError: (event) => {\n // Only forward errors that match this chat's agent\n if (\n event.context?.agentId === resolvedAgentId ||\n !event.context?.agentId\n ) {\n onErrorRef.current?.({\n error: event.error,\n code: event.code,\n context: event.context,\n });\n }\n },\n });\n\n return () => {\n subscription.unsubscribe();\n };\n }, [copilotkit, resolvedAgentId]);\n\n // Transcription state\n const [transcribeMode, setTranscribeMode] =\n useState<CopilotChatInputMode>(\"input\");\n const [inputValue, setInputValue] = useState(\"\");\n const [transcriptionError, setTranscriptionError] = useState<string | null>(\n null,\n );\n const [isTranscribing, setIsTranscribing] = useState(false);\n\n // Check if transcription is enabled\n const isTranscriptionEnabled = copilotkit.audioFileTranscriptionEnabled;\n\n // Check if browser supports MediaRecorder\n const isMediaRecorderSupported =\n typeof window !== \"undefined\" && typeof MediaRecorder !== \"undefined\";\n\n const {\n messageView: providedMessageView,\n suggestionView: providedSuggestionView,\n onStop: providedStopHandler,\n ...restProps\n } = props;\n\n useEffect(() => {\n let detached = false;\n\n // Create a fresh AbortController so we can cancel the HTTP request on cleanup.\n // HttpAgent (parent of ProxiedCopilotRuntimeAgent) uses this.abortController.signal\n // in its fetch config. Unlike runAgent(), connectAgent() does NOT create a new\n // AbortController automatically, so we must set one before connecting.\n const connectAbortController = new AbortController();\n if (agent instanceof HttpAgent) {\n agent.abortController = connectAbortController;\n }\n\n const connect = async (agent: AbstractAgent) => {\n try {\n await copilotkit.connectAgent({ agent });\n } catch (error) {\n // Ignore errors from aborted connections (e.g., React StrictMode cleanup)\n if (detached) return;\n // connectAgent already emits via the subscriber system, but catch\n // here to prevent unhandled rejections from unexpected errors.\n console.error(\"CopilotChat: connectAgent failed\", error);\n }\n };\n agent.threadId = resolvedThreadId;\n connect(agent);\n return () => {\n // Abort the HTTP request and detach the active run.\n // This is critical for React StrictMode which unmounts+remounts in dev,\n // preventing duplicate /connect requests from reaching the server.\n detached = true;\n connectAbortController.abort();\n agent.detachActiveRun();\n };\n // copilotkit is intentionally excluded — it is a stable ref that never changes.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [resolvedThreadId, agent, resolvedAgentId]);\n\n const onSubmitInput = useCallback(\n async (value: string) => {\n agent.addMessage({\n id: randomUUID(),\n role: \"user\",\n content: value,\n });\n // Clear input after submitting\n setInputValue(\"\");\n try {\n await copilotkit.runAgent({ agent });\n } catch (error) {\n console.error(\"CopilotChat: runAgent failed\", error);\n }\n },\n // copilotkit is intentionally excluded — it is a stable ref that never changes.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [agent],\n );\n\n const handleSelectSuggestion = useCallback(\n async (suggestion: Suggestion) => {\n agent.addMessage({\n id: randomUUID(),\n role: \"user\",\n content: suggestion.message,\n });\n\n try {\n await copilotkit.runAgent({ agent });\n } catch (error) {\n console.error(\n \"CopilotChat: runAgent failed after selecting suggestion\",\n error,\n );\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [agent],\n );\n\n const stopCurrentRun = useCallback(() => {\n try {\n copilotkit.stopAgent({ agent });\n } catch (error) {\n console.error(\"CopilotChat: stopAgent failed\", error);\n try {\n agent.abortRun();\n } catch (abortError) {\n console.error(\"CopilotChat: abortRun fallback failed\", abortError);\n }\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [agent]);\n\n // Transcription handlers\n const handleStartTranscribe = useCallback(() => {\n setTranscriptionError(null);\n setTranscribeMode(\"transcribe\");\n }, []);\n\n const handleCancelTranscribe = useCallback(() => {\n setTranscriptionError(null);\n setTranscribeMode(\"input\");\n }, []);\n\n const handleFinishTranscribe = useCallback(() => {\n setTranscribeMode(\"input\");\n }, []);\n\n // Handle audio blob from CopilotChatInput and transcribe it\n const handleFinishTranscribeWithAudio = useCallback(\n async (audioBlob: Blob) => {\n setIsTranscribing(true);\n try {\n setTranscriptionError(null);\n\n // Send to transcription endpoint\n const result = await transcribeAudio(copilotkit, audioBlob);\n\n // Insert transcribed text into input\n setInputValue((prev) => {\n const trimmedPrev = prev.trim();\n if (trimmedPrev) {\n return `${trimmedPrev} ${result.text}`;\n }\n return result.text;\n });\n } catch (error) {\n console.error(\"CopilotChat: Transcription failed\", error);\n\n // Show contextual error message based on error type\n if (error instanceof TranscriptionError) {\n const { code, retryable, message } = error.info;\n switch (code) {\n case TranscriptionErrorCode.RATE_LIMITED:\n setTranscriptionError(\"Too many requests. Please wait a moment.\");\n break;\n case TranscriptionErrorCode.AUTH_FAILED:\n setTranscriptionError(\n \"Authentication error. Please check your configuration.\",\n );\n break;\n case TranscriptionErrorCode.AUDIO_TOO_LONG:\n setTranscriptionError(\n \"Recording is too long. Please try a shorter recording.\",\n );\n break;\n case TranscriptionErrorCode.AUDIO_TOO_SHORT:\n setTranscriptionError(\n \"Recording is too short. Please try again.\",\n );\n break;\n case TranscriptionErrorCode.INVALID_AUDIO_FORMAT:\n setTranscriptionError(\"Audio format not supported.\");\n break;\n case TranscriptionErrorCode.SERVICE_NOT_CONFIGURED:\n setTranscriptionError(\"Transcription service is not available.\");\n break;\n case TranscriptionErrorCode.NETWORK_ERROR:\n setTranscriptionError(\n \"Network error. Please check your connection.\",\n );\n break;\n default:\n // For retryable errors, show more helpful message\n setTranscriptionError(\n retryable ? \"Transcription failed. Please try again.\" : message,\n );\n }\n } else {\n // Fallback for unexpected errors\n setTranscriptionError(\"Transcription failed. Please try again.\");\n }\n } finally {\n setIsTranscribing(false);\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [],\n );\n\n // Clear transcription error after a delay\n useEffect(() => {\n if (transcriptionError) {\n const timer = setTimeout(() => {\n setTranscriptionError(null);\n }, 5000);\n return () => clearTimeout(timer);\n }\n }, [transcriptionError]);\n\n const mergedProps = merge(\n {\n isRunning: agent.isRunning,\n suggestions: autoSuggestions,\n onSelectSuggestion: handleSelectSuggestion,\n suggestionView: providedSuggestionView,\n },\n {\n ...restProps,\n ...(typeof providedMessageView === \"string\"\n ? { messageView: { className: providedMessageView } }\n : providedMessageView !== undefined\n ? { messageView: providedMessageView }\n : {}),\n },\n );\n\n const hasMessages = agent.messages.length > 0;\n const shouldAllowStop = agent.isRunning && hasMessages;\n const effectiveStopHandler = shouldAllowStop\n ? (providedStopHandler ?? stopCurrentRun)\n : providedStopHandler;\n\n // Determine if transcription feature should be available\n const showTranscription = isTranscriptionEnabled && isMediaRecorderSupported;\n\n // Determine mode: transcribing takes priority, then transcribe mode, then default to input\n const effectiveMode: CopilotChatInputMode = isTranscribing\n ? \"processing\"\n : transcribeMode;\n\n // Memoize messages array - only create new reference when content actually changes\n // (agent.messages is mutated in place, so we need a new reference for React to detect changes)\n\n const messages = useMemo(\n () => [...agent.messages],\n [JSON.stringify(agent.messages)],\n );\n\n const finalProps = merge(mergedProps, {\n messages,\n // Input behavior props\n onSubmitMessage: onSubmitInput,\n onStop: effectiveStopHandler,\n inputMode: effectiveMode,\n inputValue,\n onInputChange: setInputValue,\n // Only provide transcription handlers if feature is available\n onStartTranscribe: showTranscription ? handleStartTranscribe : undefined,\n onCancelTranscribe: showTranscription ? handleCancelTranscribe : undefined,\n onFinishTranscribe: showTranscription ? handleFinishTranscribe : undefined,\n onFinishTranscribeWithAudio: showTranscription\n ? handleFinishTranscribeWithAudio\n : undefined,\n }) as CopilotChatViewProps;\n\n // Always create a provider with merged values\n // This ensures priority: props > existing config > defaults\n const RenderedChatView = renderSlot(chatView, CopilotChatView, finalProps);\n\n return (\n <CopilotChatConfigurationProvider\n agentId={resolvedAgentId}\n threadId={resolvedThreadId}\n labels={labels}\n >\n {transcriptionError && (\n <div\n style={{\n position: \"absolute\",\n bottom: \"100px\",\n left: \"50%\",\n transform: \"translateX(-50%)\",\n backgroundColor: \"#ef4444\",\n color: \"white\",\n padding: \"8px 16px\",\n borderRadius: \"8px\",\n fontSize: \"14px\",\n zIndex: 50,\n }}\n >\n {transcriptionError}\n </div>\n )}\n {RenderedChatView}\n </CopilotChatConfigurationProvider>\n );\n}\n\n// eslint-disable-next-line @typescript-eslint/no-namespace\nexport namespace CopilotChat {\n export const View = CopilotChatView;\n}\n"],"mappings":"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"}
@@ -2,6 +2,7 @@ import { CopilotChatLabels } from "../../providers/CopilotChatConfigurationProvi
2
2
  import { SlotValue } from "../../lib/slots.cjs";
3
3
  import { CopilotChatView, CopilotChatViewProps } from "./CopilotChatView.cjs";
4
4
  import * as react_jsx_runtime0 from "react/jsx-runtime";
5
+ import { CopilotKitCoreErrorCode } from "@copilotkitnext/core";
5
6
 
6
7
  //#region src/components/chat/CopilotChat.d.ts
7
8
  type CopilotChatProps = Omit<CopilotChatViewProps, "messages" | "isRunning" | "suggestions" | "suggestionLoadingIndexes" | "onSelectSuggestion"> & {
@@ -9,12 +10,23 @@ type CopilotChatProps = Omit<CopilotChatViewProps, "messages" | "isRunning" | "s
9
10
  threadId?: string;
10
11
  labels?: Partial<CopilotChatLabels>;
11
12
  chatView?: SlotValue<typeof CopilotChatView>;
13
+ /**
14
+ * Error handler scoped to this chat's agent. Fires in addition to the
15
+ * provider-level onError (does not suppress it). Receives only errors
16
+ * whose context.agentId matches this chat's agent.
17
+ */
18
+ onError?: (event: {
19
+ error: Error;
20
+ code: CopilotKitCoreErrorCode;
21
+ context: Record<string, any>;
22
+ }) => void | Promise<void>;
12
23
  };
13
24
  declare function CopilotChat({
14
25
  agentId,
15
26
  threadId,
16
27
  labels,
17
28
  chatView,
29
+ onError,
18
30
  ...props
19
31
  }: CopilotChatProps): react_jsx_runtime0.JSX.Element;
20
32
  declare namespace CopilotChat {
@@ -1 +1 @@
1
- {"version":3,"file":"CopilotChat.d.cts","names":[],"sources":["../../../src/components/chat/CopilotChat.tsx"],"mappings":";;;;;;KA6BY,gBAAA,GAAmB,IAAA,CAC7B,oBAAA;EAOA,OAAA;EACA,QAAA;EACA,MAAA,GAAS,OAAA,CAAQ,iBAAA;EACjB,QAAA,GAAW,SAAA,QAAiB,eAAA;AAAA;AAAA,iBAEd,WAAA,CAAA;EACd,OAAA;EACA,QAAA;EACA,MAAA;EACA,QAAA;EAAA,GACG;AAAA,GACF,gBAAA,GAAgB,kBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,kBAkUF,WAAA;EAAA,MACF,IAAA,SAAI,eAAA;AAAA"}
1
+ {"version":3,"file":"CopilotChat.d.cts","names":[],"sources":["../../../src/components/chat/CopilotChat.tsx"],"mappings":";;;;;;;KAyBY,gBAAA,GAAmB,IAAA,CAC7B,oBAAA;EAOA,OAAA;EACA,QAAA;EACA,MAAA,GAAS,OAAA,CAAQ,iBAAA;EACjB,QAAA,GAAW,SAAA,QAAiB,eAAA;;;;;;EAM5B,OAAA,IAAW,KAAA;IACT,KAAA,EAAO,KAAA;IACP,IAAA,EAAM,uBAAA;IACN,OAAA,EAAS,MAAA;EAAA,aACE,OAAA;AAAA;AAAA,iBAEC,WAAA,CAAA;EACd,OAAA;EACA,QAAA;EACA,MAAA;EACA,QAAA;EACA,OAAA;EAAA,GACG;AAAA,GACF,gBAAA,GAAgB,kBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,kBA8VF,WAAA;EAAA,MACF,IAAA,SAAI,eAAA;AAAA"}
@@ -2,6 +2,7 @@ import { CopilotChatLabels } from "../../providers/CopilotChatConfigurationProvi
2
2
  import { SlotValue } from "../../lib/slots.mjs";
3
3
  import { CopilotChatView, CopilotChatViewProps } from "./CopilotChatView.mjs";
4
4
  import * as react_jsx_runtime0 from "react/jsx-runtime";
5
+ import { CopilotKitCoreErrorCode } from "@copilotkitnext/core";
5
6
 
6
7
  //#region src/components/chat/CopilotChat.d.ts
7
8
  type CopilotChatProps = Omit<CopilotChatViewProps, "messages" | "isRunning" | "suggestions" | "suggestionLoadingIndexes" | "onSelectSuggestion"> & {
@@ -9,12 +10,23 @@ type CopilotChatProps = Omit<CopilotChatViewProps, "messages" | "isRunning" | "s
9
10
  threadId?: string;
10
11
  labels?: Partial<CopilotChatLabels>;
11
12
  chatView?: SlotValue<typeof CopilotChatView>;
13
+ /**
14
+ * Error handler scoped to this chat's agent. Fires in addition to the
15
+ * provider-level onError (does not suppress it). Receives only errors
16
+ * whose context.agentId matches this chat's agent.
17
+ */
18
+ onError?: (event: {
19
+ error: Error;
20
+ code: CopilotKitCoreErrorCode;
21
+ context: Record<string, any>;
22
+ }) => void | Promise<void>;
12
23
  };
13
24
  declare function CopilotChat({
14
25
  agentId,
15
26
  threadId,
16
27
  labels,
17
28
  chatView,
29
+ onError,
18
30
  ...props
19
31
  }: CopilotChatProps): react_jsx_runtime0.JSX.Element;
20
32
  declare namespace CopilotChat {
@@ -1 +1 @@
1
- {"version":3,"file":"CopilotChat.d.mts","names":[],"sources":["../../../src/components/chat/CopilotChat.tsx"],"mappings":";;;;;;KA6BY,gBAAA,GAAmB,IAAA,CAC7B,oBAAA;EAOA,OAAA;EACA,QAAA;EACA,MAAA,GAAS,OAAA,CAAQ,iBAAA;EACjB,QAAA,GAAW,SAAA,QAAiB,eAAA;AAAA;AAAA,iBAEd,WAAA,CAAA;EACd,OAAA;EACA,QAAA;EACA,MAAA;EACA,QAAA;EAAA,GACG;AAAA,GACF,gBAAA,GAAgB,kBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,kBAkUF,WAAA;EAAA,MACF,IAAA,SAAI,eAAA;AAAA"}
1
+ {"version":3,"file":"CopilotChat.d.mts","names":[],"sources":["../../../src/components/chat/CopilotChat.tsx"],"mappings":";;;;;;;KAyBY,gBAAA,GAAmB,IAAA,CAC7B,oBAAA;EAOA,OAAA;EACA,QAAA;EACA,MAAA,GAAS,OAAA,CAAQ,iBAAA;EACjB,QAAA,GAAW,SAAA,QAAiB,eAAA;;;;;;EAM5B,OAAA,IAAW,KAAA;IACT,KAAA,EAAO,KAAA;IACP,IAAA,EAAM,uBAAA;IACN,OAAA,EAAS,MAAA;EAAA,aACE,OAAA;AAAA;AAAA,iBAEC,WAAA,CAAA;EACd,OAAA;EACA,QAAA;EACA,MAAA;EACA,QAAA;EACA,OAAA;EAAA,GACG;AAAA,GACF,gBAAA,GAAgB,kBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,kBA8VF,WAAA;EAAA,MACF,IAAA,SAAI,eAAA;AAAA"}
@@ -5,20 +5,37 @@ import { useAgent } from "../../hooks/use-agent.mjs";
5
5
  import { useSuggestions } from "../../hooks/use-suggestions.mjs";
6
6
  import { CopilotChatView } from "./CopilotChatView.mjs";
7
7
  import { TranscriptionError, transcribeAudio } from "../../lib/transcription-client.mjs";
8
- import { AGUIConnectNotImplementedError, HttpAgent } from "@ag-ui/client";
9
- import { useCallback, useEffect, useMemo, useState } from "react";
8
+ import { HttpAgent } from "@ag-ui/client";
9
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
10
10
  import { DEFAULT_AGENT_ID, TranscriptionErrorCode, randomUUID } from "@copilotkitnext/shared";
11
11
  import { jsx, jsxs } from "react/jsx-runtime";
12
12
  import { merge } from "ts-deepmerge";
13
13
 
14
14
  //#region src/components/chat/CopilotChat.tsx
15
- function CopilotChat({ agentId, threadId, labels, chatView, ...props }) {
15
+ function CopilotChat({ agentId, threadId, labels, chatView, onError, ...props }) {
16
16
  const existingConfig = useCopilotChatConfiguration();
17
17
  const resolvedAgentId = agentId ?? existingConfig?.agentId ?? DEFAULT_AGENT_ID;
18
18
  const resolvedThreadId = useMemo(() => threadId ?? existingConfig?.threadId ?? randomUUID(), [threadId, existingConfig?.threadId]);
19
19
  const { agent } = useAgent({ agentId: resolvedAgentId });
20
20
  const { copilotkit } = useCopilotKit();
21
21
  const { suggestions: autoSuggestions } = useSuggestions({ agentId: resolvedAgentId });
22
+ const onErrorRef = useRef(onError);
23
+ useEffect(() => {
24
+ onErrorRef.current = onError;
25
+ }, [onError]);
26
+ useEffect(() => {
27
+ if (!onErrorRef.current) return;
28
+ const subscription = copilotkit.subscribe({ onError: (event) => {
29
+ if (event.context?.agentId === resolvedAgentId || !event.context?.agentId) onErrorRef.current?.({
30
+ error: event.error,
31
+ code: event.code,
32
+ context: event.context
33
+ });
34
+ } });
35
+ return () => {
36
+ subscription.unsubscribe();
37
+ };
38
+ }, [copilotkit, resolvedAgentId]);
22
39
  const [transcribeMode, setTranscribeMode] = useState("input");
23
40
  const [inputValue, setInputValue] = useState("");
24
41
  const [transcriptionError, setTranscriptionError] = useState(null);
@@ -35,7 +52,7 @@ function CopilotChat({ agentId, threadId, labels, chatView, ...props }) {
35
52
  await copilotkit.connectAgent({ agent });
36
53
  } catch (error) {
37
54
  if (detached) return;
38
- if (error instanceof AGUIConnectNotImplementedError) {} else throw error;
55
+ console.error("CopilotChat: connectAgent failed", error);
39
56
  }
40
57
  };
41
58
  agent.threadId = resolvedThreadId;
@@ -1 +1 @@
1
- {"version":3,"file":"CopilotChat.mjs","names":[],"sources":["../../../src/components/chat/CopilotChat.tsx"],"sourcesContent":["import { useAgent } from \"@/hooks/use-agent\";\nimport { useSuggestions } from \"@/hooks/use-suggestions\";\nimport { CopilotChatView, CopilotChatViewProps } from \"./CopilotChatView\";\nimport { CopilotChatInputMode } from \"./CopilotChatInput\";\nimport {\n CopilotChatConfigurationProvider,\n CopilotChatLabels,\n useCopilotChatConfiguration,\n} from \"@/providers/CopilotChatConfigurationProvider\";\nimport {\n DEFAULT_AGENT_ID,\n randomUUID,\n TranscriptionErrorCode,\n} from \"@copilotkitnext/shared\";\nimport { Suggestion, CopilotKitCoreErrorCode } from \"@copilotkitnext/core\";\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\nimport { merge } from \"ts-deepmerge\";\nimport { useCopilotKit } from \"@/providers/CopilotKitProvider\";\nimport {\n AbstractAgent,\n AGUIConnectNotImplementedError,\n HttpAgent,\n} from \"@ag-ui/client\";\nimport { renderSlot, SlotValue } from \"@/lib/slots\";\nimport {\n transcribeAudio,\n TranscriptionError,\n} from \"@/lib/transcription-client\";\n\nexport type CopilotChatProps = Omit<\n CopilotChatViewProps,\n | \"messages\"\n | \"isRunning\"\n | \"suggestions\"\n | \"suggestionLoadingIndexes\"\n | \"onSelectSuggestion\"\n> & {\n agentId?: string;\n threadId?: string;\n labels?: Partial<CopilotChatLabels>;\n chatView?: SlotValue<typeof CopilotChatView>;\n};\nexport function CopilotChat({\n agentId,\n threadId,\n labels,\n chatView,\n ...props\n}: CopilotChatProps) {\n // Check for existing configuration provider\n const existingConfig = useCopilotChatConfiguration();\n\n // Apply priority: props > existing config > defaults\n const resolvedAgentId =\n agentId ?? existingConfig?.agentId ?? DEFAULT_AGENT_ID;\n const resolvedThreadId = useMemo(\n () => threadId ?? existingConfig?.threadId ?? randomUUID(),\n [threadId, existingConfig?.threadId],\n );\n\n const { agent } = useAgent({ agentId: resolvedAgentId });\n const { copilotkit } = useCopilotKit();\n const { suggestions: autoSuggestions } = useSuggestions({\n agentId: resolvedAgentId,\n });\n\n // Transcription state\n const [transcribeMode, setTranscribeMode] =\n useState<CopilotChatInputMode>(\"input\");\n const [inputValue, setInputValue] = useState(\"\");\n const [transcriptionError, setTranscriptionError] = useState<string | null>(\n null,\n );\n const [isTranscribing, setIsTranscribing] = useState(false);\n\n // Check if transcription is enabled\n const isTranscriptionEnabled = copilotkit.audioFileTranscriptionEnabled;\n\n // Check if browser supports MediaRecorder\n const isMediaRecorderSupported =\n typeof window !== \"undefined\" && typeof MediaRecorder !== \"undefined\";\n\n const {\n messageView: providedMessageView,\n suggestionView: providedSuggestionView,\n onStop: providedStopHandler,\n ...restProps\n } = props;\n\n useEffect(() => {\n let detached = false;\n\n // Create a fresh AbortController so we can cancel the HTTP request on cleanup.\n // HttpAgent (parent of ProxiedCopilotRuntimeAgent) uses this.abortController.signal\n // in its fetch config. Unlike runAgent(), connectAgent() does NOT create a new\n // AbortController automatically, so we must set one before connecting.\n const connectAbortController = new AbortController();\n if (agent instanceof HttpAgent) {\n agent.abortController = connectAbortController;\n }\n\n const connect = async (agent: AbstractAgent) => {\n try {\n await copilotkit.connectAgent({ agent });\n } catch (error) {\n // Ignore errors from aborted connections (e.g., React StrictMode cleanup)\n if (detached) return;\n if (error instanceof AGUIConnectNotImplementedError) {\n // connect not implemented, ignore\n } else {\n throw error;\n }\n }\n };\n agent.threadId = resolvedThreadId;\n connect(agent);\n return () => {\n // Abort the HTTP request and detach the active run.\n // This is critical for React StrictMode which unmounts+remounts in dev,\n // preventing duplicate /connect requests from reaching the server.\n detached = true;\n connectAbortController.abort();\n agent.detachActiveRun();\n };\n // copilotkit is intentionally excluded — it is a stable ref that never changes.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [resolvedThreadId, agent, resolvedAgentId]);\n\n const onSubmitInput = useCallback(\n async (value: string) => {\n agent.addMessage({\n id: randomUUID(),\n role: \"user\",\n content: value,\n });\n // Clear input after submitting\n setInputValue(\"\");\n try {\n await copilotkit.runAgent({ agent });\n } catch (error) {\n console.error(\"CopilotChat: runAgent failed\", error);\n }\n },\n // copilotkit is intentionally excluded — it is a stable ref that never changes.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [agent],\n );\n\n const handleSelectSuggestion = useCallback(\n async (suggestion: Suggestion) => {\n agent.addMessage({\n id: randomUUID(),\n role: \"user\",\n content: suggestion.message,\n });\n\n try {\n await copilotkit.runAgent({ agent });\n } catch (error) {\n console.error(\n \"CopilotChat: runAgent failed after selecting suggestion\",\n error,\n );\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [agent],\n );\n\n const stopCurrentRun = useCallback(() => {\n try {\n copilotkit.stopAgent({ agent });\n } catch (error) {\n console.error(\"CopilotChat: stopAgent failed\", error);\n try {\n agent.abortRun();\n } catch (abortError) {\n console.error(\"CopilotChat: abortRun fallback failed\", abortError);\n }\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [agent]);\n\n // Transcription handlers\n const handleStartTranscribe = useCallback(() => {\n setTranscriptionError(null);\n setTranscribeMode(\"transcribe\");\n }, []);\n\n const handleCancelTranscribe = useCallback(() => {\n setTranscriptionError(null);\n setTranscribeMode(\"input\");\n }, []);\n\n const handleFinishTranscribe = useCallback(() => {\n setTranscribeMode(\"input\");\n }, []);\n\n // Handle audio blob from CopilotChatInput and transcribe it\n const handleFinishTranscribeWithAudio = useCallback(\n async (audioBlob: Blob) => {\n setIsTranscribing(true);\n try {\n setTranscriptionError(null);\n\n // Send to transcription endpoint\n const result = await transcribeAudio(copilotkit, audioBlob);\n\n // Insert transcribed text into input\n setInputValue((prev) => {\n const trimmedPrev = prev.trim();\n if (trimmedPrev) {\n return `${trimmedPrev} ${result.text}`;\n }\n return result.text;\n });\n } catch (error) {\n console.error(\"CopilotChat: Transcription failed\", error);\n\n // Show contextual error message based on error type\n if (error instanceof TranscriptionError) {\n const { code, retryable, message } = error.info;\n switch (code) {\n case TranscriptionErrorCode.RATE_LIMITED:\n setTranscriptionError(\"Too many requests. Please wait a moment.\");\n break;\n case TranscriptionErrorCode.AUTH_FAILED:\n setTranscriptionError(\n \"Authentication error. Please check your configuration.\",\n );\n break;\n case TranscriptionErrorCode.AUDIO_TOO_LONG:\n setTranscriptionError(\n \"Recording is too long. Please try a shorter recording.\",\n );\n break;\n case TranscriptionErrorCode.AUDIO_TOO_SHORT:\n setTranscriptionError(\n \"Recording is too short. Please try again.\",\n );\n break;\n case TranscriptionErrorCode.INVALID_AUDIO_FORMAT:\n setTranscriptionError(\"Audio format not supported.\");\n break;\n case TranscriptionErrorCode.SERVICE_NOT_CONFIGURED:\n setTranscriptionError(\"Transcription service is not available.\");\n break;\n case TranscriptionErrorCode.NETWORK_ERROR:\n setTranscriptionError(\n \"Network error. Please check your connection.\",\n );\n break;\n default:\n // For retryable errors, show more helpful message\n setTranscriptionError(\n retryable ? \"Transcription failed. Please try again.\" : message,\n );\n }\n } else {\n // Fallback for unexpected errors\n setTranscriptionError(\"Transcription failed. Please try again.\");\n }\n } finally {\n setIsTranscribing(false);\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [],\n );\n\n // Clear transcription error after a delay\n useEffect(() => {\n if (transcriptionError) {\n const timer = setTimeout(() => {\n setTranscriptionError(null);\n }, 5000);\n return () => clearTimeout(timer);\n }\n }, [transcriptionError]);\n\n const mergedProps = merge(\n {\n isRunning: agent.isRunning,\n suggestions: autoSuggestions,\n onSelectSuggestion: handleSelectSuggestion,\n suggestionView: providedSuggestionView,\n },\n {\n ...restProps,\n ...(typeof providedMessageView === \"string\"\n ? { messageView: { className: providedMessageView } }\n : providedMessageView !== undefined\n ? { messageView: providedMessageView }\n : {}),\n },\n );\n\n const hasMessages = agent.messages.length > 0;\n const shouldAllowStop = agent.isRunning && hasMessages;\n const effectiveStopHandler = shouldAllowStop\n ? (providedStopHandler ?? stopCurrentRun)\n : providedStopHandler;\n\n // Determine if transcription feature should be available\n const showTranscription = isTranscriptionEnabled && isMediaRecorderSupported;\n\n // Determine mode: transcribing takes priority, then transcribe mode, then default to input\n const effectiveMode: CopilotChatInputMode = isTranscribing\n ? \"processing\"\n : transcribeMode;\n\n // Memoize messages array - only create new reference when content actually changes\n // (agent.messages is mutated in place, so we need a new reference for React to detect changes)\n\n const messages = useMemo(\n () => [...agent.messages],\n [JSON.stringify(agent.messages)],\n );\n\n const finalProps = merge(mergedProps, {\n messages,\n // Input behavior props\n onSubmitMessage: onSubmitInput,\n onStop: effectiveStopHandler,\n inputMode: effectiveMode,\n inputValue,\n onInputChange: setInputValue,\n // Only provide transcription handlers if feature is available\n onStartTranscribe: showTranscription ? handleStartTranscribe : undefined,\n onCancelTranscribe: showTranscription ? handleCancelTranscribe : undefined,\n onFinishTranscribe: showTranscription ? handleFinishTranscribe : undefined,\n onFinishTranscribeWithAudio: showTranscription\n ? handleFinishTranscribeWithAudio\n : undefined,\n }) as CopilotChatViewProps;\n\n // Always create a provider with merged values\n // This ensures priority: props > existing config > defaults\n const RenderedChatView = renderSlot(chatView, CopilotChatView, finalProps);\n\n return (\n <CopilotChatConfigurationProvider\n agentId={resolvedAgentId}\n threadId={resolvedThreadId}\n labels={labels}\n >\n {transcriptionError && (\n <div\n style={{\n position: \"absolute\",\n bottom: \"100px\",\n left: \"50%\",\n transform: \"translateX(-50%)\",\n backgroundColor: \"#ef4444\",\n color: \"white\",\n padding: \"8px 16px\",\n borderRadius: \"8px\",\n fontSize: \"14px\",\n zIndex: 50,\n }}\n >\n {transcriptionError}\n </div>\n )}\n {RenderedChatView}\n </CopilotChatConfigurationProvider>\n );\n}\n\n// eslint-disable-next-line @typescript-eslint/no-namespace\nexport namespace CopilotChat {\n export const View = CopilotChatView;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"CopilotChat.mjs","names":[],"sources":["../../../src/components/chat/CopilotChat.tsx"],"sourcesContent":["import { useAgent } from \"@/hooks/use-agent\";\nimport { useSuggestions } from \"@/hooks/use-suggestions\";\nimport { CopilotChatView, CopilotChatViewProps } from \"./CopilotChatView\";\nimport { CopilotChatInputMode } from \"./CopilotChatInput\";\nimport {\n CopilotChatConfigurationProvider,\n CopilotChatLabels,\n useCopilotChatConfiguration,\n} from \"@/providers/CopilotChatConfigurationProvider\";\nimport {\n DEFAULT_AGENT_ID,\n randomUUID,\n TranscriptionErrorCode,\n} from \"@copilotkitnext/shared\";\nimport { Suggestion, CopilotKitCoreErrorCode } from \"@copilotkitnext/core\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { merge } from \"ts-deepmerge\";\nimport { useCopilotKit } from \"@/providers/CopilotKitProvider\";\nimport { AbstractAgent, HttpAgent } from \"@ag-ui/client\";\nimport { renderSlot, SlotValue } from \"@/lib/slots\";\nimport {\n transcribeAudio,\n TranscriptionError,\n} from \"@/lib/transcription-client\";\n\nexport type CopilotChatProps = Omit<\n CopilotChatViewProps,\n | \"messages\"\n | \"isRunning\"\n | \"suggestions\"\n | \"suggestionLoadingIndexes\"\n | \"onSelectSuggestion\"\n> & {\n agentId?: string;\n threadId?: string;\n labels?: Partial<CopilotChatLabels>;\n chatView?: SlotValue<typeof CopilotChatView>;\n /**\n * Error handler scoped to this chat's agent. Fires in addition to the\n * provider-level onError (does not suppress it). Receives only errors\n * whose context.agentId matches this chat's agent.\n */\n onError?: (event: {\n error: Error;\n code: CopilotKitCoreErrorCode;\n context: Record<string, any>;\n }) => void | Promise<void>;\n};\nexport function CopilotChat({\n agentId,\n threadId,\n labels,\n chatView,\n onError,\n ...props\n}: CopilotChatProps) {\n // Check for existing configuration provider\n const existingConfig = useCopilotChatConfiguration();\n\n // Apply priority: props > existing config > defaults\n const resolvedAgentId =\n agentId ?? existingConfig?.agentId ?? DEFAULT_AGENT_ID;\n const resolvedThreadId = useMemo(\n () => threadId ?? existingConfig?.threadId ?? randomUUID(),\n [threadId, existingConfig?.threadId],\n );\n\n const { agent } = useAgent({ agentId: resolvedAgentId });\n const { copilotkit } = useCopilotKit();\n const { suggestions: autoSuggestions } = useSuggestions({\n agentId: resolvedAgentId,\n });\n\n // onError subscription — forward core errors scoped to this chat's agent\n const onErrorRef = useRef(onError);\n useEffect(() => {\n onErrorRef.current = onError;\n }, [onError]);\n\n useEffect(() => {\n if (!onErrorRef.current) return;\n\n const subscription = copilotkit.subscribe({\n onError: (event) => {\n // Only forward errors that match this chat's agent\n if (\n event.context?.agentId === resolvedAgentId ||\n !event.context?.agentId\n ) {\n onErrorRef.current?.({\n error: event.error,\n code: event.code,\n context: event.context,\n });\n }\n },\n });\n\n return () => {\n subscription.unsubscribe();\n };\n }, [copilotkit, resolvedAgentId]);\n\n // Transcription state\n const [transcribeMode, setTranscribeMode] =\n useState<CopilotChatInputMode>(\"input\");\n const [inputValue, setInputValue] = useState(\"\");\n const [transcriptionError, setTranscriptionError] = useState<string | null>(\n null,\n );\n const [isTranscribing, setIsTranscribing] = useState(false);\n\n // Check if transcription is enabled\n const isTranscriptionEnabled = copilotkit.audioFileTranscriptionEnabled;\n\n // Check if browser supports MediaRecorder\n const isMediaRecorderSupported =\n typeof window !== \"undefined\" && typeof MediaRecorder !== \"undefined\";\n\n const {\n messageView: providedMessageView,\n suggestionView: providedSuggestionView,\n onStop: providedStopHandler,\n ...restProps\n } = props;\n\n useEffect(() => {\n let detached = false;\n\n // Create a fresh AbortController so we can cancel the HTTP request on cleanup.\n // HttpAgent (parent of ProxiedCopilotRuntimeAgent) uses this.abortController.signal\n // in its fetch config. Unlike runAgent(), connectAgent() does NOT create a new\n // AbortController automatically, so we must set one before connecting.\n const connectAbortController = new AbortController();\n if (agent instanceof HttpAgent) {\n agent.abortController = connectAbortController;\n }\n\n const connect = async (agent: AbstractAgent) => {\n try {\n await copilotkit.connectAgent({ agent });\n } catch (error) {\n // Ignore errors from aborted connections (e.g., React StrictMode cleanup)\n if (detached) return;\n // connectAgent already emits via the subscriber system, but catch\n // here to prevent unhandled rejections from unexpected errors.\n console.error(\"CopilotChat: connectAgent failed\", error);\n }\n };\n agent.threadId = resolvedThreadId;\n connect(agent);\n return () => {\n // Abort the HTTP request and detach the active run.\n // This is critical for React StrictMode which unmounts+remounts in dev,\n // preventing duplicate /connect requests from reaching the server.\n detached = true;\n connectAbortController.abort();\n agent.detachActiveRun();\n };\n // copilotkit is intentionally excluded — it is a stable ref that never changes.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [resolvedThreadId, agent, resolvedAgentId]);\n\n const onSubmitInput = useCallback(\n async (value: string) => {\n agent.addMessage({\n id: randomUUID(),\n role: \"user\",\n content: value,\n });\n // Clear input after submitting\n setInputValue(\"\");\n try {\n await copilotkit.runAgent({ agent });\n } catch (error) {\n console.error(\"CopilotChat: runAgent failed\", error);\n }\n },\n // copilotkit is intentionally excluded — it is a stable ref that never changes.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [agent],\n );\n\n const handleSelectSuggestion = useCallback(\n async (suggestion: Suggestion) => {\n agent.addMessage({\n id: randomUUID(),\n role: \"user\",\n content: suggestion.message,\n });\n\n try {\n await copilotkit.runAgent({ agent });\n } catch (error) {\n console.error(\n \"CopilotChat: runAgent failed after selecting suggestion\",\n error,\n );\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [agent],\n );\n\n const stopCurrentRun = useCallback(() => {\n try {\n copilotkit.stopAgent({ agent });\n } catch (error) {\n console.error(\"CopilotChat: stopAgent failed\", error);\n try {\n agent.abortRun();\n } catch (abortError) {\n console.error(\"CopilotChat: abortRun fallback failed\", abortError);\n }\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [agent]);\n\n // Transcription handlers\n const handleStartTranscribe = useCallback(() => {\n setTranscriptionError(null);\n setTranscribeMode(\"transcribe\");\n }, []);\n\n const handleCancelTranscribe = useCallback(() => {\n setTranscriptionError(null);\n setTranscribeMode(\"input\");\n }, []);\n\n const handleFinishTranscribe = useCallback(() => {\n setTranscribeMode(\"input\");\n }, []);\n\n // Handle audio blob from CopilotChatInput and transcribe it\n const handleFinishTranscribeWithAudio = useCallback(\n async (audioBlob: Blob) => {\n setIsTranscribing(true);\n try {\n setTranscriptionError(null);\n\n // Send to transcription endpoint\n const result = await transcribeAudio(copilotkit, audioBlob);\n\n // Insert transcribed text into input\n setInputValue((prev) => {\n const trimmedPrev = prev.trim();\n if (trimmedPrev) {\n return `${trimmedPrev} ${result.text}`;\n }\n return result.text;\n });\n } catch (error) {\n console.error(\"CopilotChat: Transcription failed\", error);\n\n // Show contextual error message based on error type\n if (error instanceof TranscriptionError) {\n const { code, retryable, message } = error.info;\n switch (code) {\n case TranscriptionErrorCode.RATE_LIMITED:\n setTranscriptionError(\"Too many requests. Please wait a moment.\");\n break;\n case TranscriptionErrorCode.AUTH_FAILED:\n setTranscriptionError(\n \"Authentication error. Please check your configuration.\",\n );\n break;\n case TranscriptionErrorCode.AUDIO_TOO_LONG:\n setTranscriptionError(\n \"Recording is too long. Please try a shorter recording.\",\n );\n break;\n case TranscriptionErrorCode.AUDIO_TOO_SHORT:\n setTranscriptionError(\n \"Recording is too short. Please try again.\",\n );\n break;\n case TranscriptionErrorCode.INVALID_AUDIO_FORMAT:\n setTranscriptionError(\"Audio format not supported.\");\n break;\n case TranscriptionErrorCode.SERVICE_NOT_CONFIGURED:\n setTranscriptionError(\"Transcription service is not available.\");\n break;\n case TranscriptionErrorCode.NETWORK_ERROR:\n setTranscriptionError(\n \"Network error. Please check your connection.\",\n );\n break;\n default:\n // For retryable errors, show more helpful message\n setTranscriptionError(\n retryable ? \"Transcription failed. Please try again.\" : message,\n );\n }\n } else {\n // Fallback for unexpected errors\n setTranscriptionError(\"Transcription failed. Please try again.\");\n }\n } finally {\n setIsTranscribing(false);\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [],\n );\n\n // Clear transcription error after a delay\n useEffect(() => {\n if (transcriptionError) {\n const timer = setTimeout(() => {\n setTranscriptionError(null);\n }, 5000);\n return () => clearTimeout(timer);\n }\n }, [transcriptionError]);\n\n const mergedProps = merge(\n {\n isRunning: agent.isRunning,\n suggestions: autoSuggestions,\n onSelectSuggestion: handleSelectSuggestion,\n suggestionView: providedSuggestionView,\n },\n {\n ...restProps,\n ...(typeof providedMessageView === \"string\"\n ? { messageView: { className: providedMessageView } }\n : providedMessageView !== undefined\n ? { messageView: providedMessageView }\n : {}),\n },\n );\n\n const hasMessages = agent.messages.length > 0;\n const shouldAllowStop = agent.isRunning && hasMessages;\n const effectiveStopHandler = shouldAllowStop\n ? (providedStopHandler ?? stopCurrentRun)\n : providedStopHandler;\n\n // Determine if transcription feature should be available\n const showTranscription = isTranscriptionEnabled && isMediaRecorderSupported;\n\n // Determine mode: transcribing takes priority, then transcribe mode, then default to input\n const effectiveMode: CopilotChatInputMode = isTranscribing\n ? \"processing\"\n : transcribeMode;\n\n // Memoize messages array - only create new reference when content actually changes\n // (agent.messages is mutated in place, so we need a new reference for React to detect changes)\n\n const messages = useMemo(\n () => [...agent.messages],\n [JSON.stringify(agent.messages)],\n );\n\n const finalProps = merge(mergedProps, {\n messages,\n // Input behavior props\n onSubmitMessage: onSubmitInput,\n onStop: effectiveStopHandler,\n inputMode: effectiveMode,\n inputValue,\n onInputChange: setInputValue,\n // Only provide transcription handlers if feature is available\n onStartTranscribe: showTranscription ? handleStartTranscribe : undefined,\n onCancelTranscribe: showTranscription ? handleCancelTranscribe : undefined,\n onFinishTranscribe: showTranscription ? handleFinishTranscribe : undefined,\n onFinishTranscribeWithAudio: showTranscription\n ? handleFinishTranscribeWithAudio\n : undefined,\n }) as CopilotChatViewProps;\n\n // Always create a provider with merged values\n // This ensures priority: props > existing config > defaults\n const RenderedChatView = renderSlot(chatView, CopilotChatView, finalProps);\n\n return (\n <CopilotChatConfigurationProvider\n agentId={resolvedAgentId}\n threadId={resolvedThreadId}\n labels={labels}\n >\n {transcriptionError && (\n <div\n style={{\n position: \"absolute\",\n bottom: \"100px\",\n left: \"50%\",\n transform: \"translateX(-50%)\",\n backgroundColor: \"#ef4444\",\n color: \"white\",\n padding: \"8px 16px\",\n borderRadius: \"8px\",\n fontSize: \"14px\",\n zIndex: 50,\n }}\n >\n {transcriptionError}\n </div>\n )}\n {RenderedChatView}\n </CopilotChatConfigurationProvider>\n );\n}\n\n// eslint-disable-next-line @typescript-eslint/no-namespace\nexport namespace CopilotChat {\n export const View = CopilotChatView;\n}\n"],"mappings":"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"}
@@ -45,6 +45,15 @@ function useAgent({ agentId, updates } = {}) {
45
45
  provisionalAgentCache.current.set(agentId, provisional);
46
46
  return provisional;
47
47
  }
48
+ if (isRuntimeConfigured && status === _copilotkitnext_core.CopilotKitCoreRuntimeConnectionStatus.Error) {
49
+ const provisional = new _copilotkitnext_core.ProxiedCopilotRuntimeAgent({
50
+ runtimeUrl: copilotkit.runtimeUrl,
51
+ agentId,
52
+ transport: copilotkit.runtimeTransport
53
+ });
54
+ provisional.headers = { ...copilotkit.headers };
55
+ return provisional;
56
+ }
48
57
  const knownAgents = Object.keys(copilotkit.agents ?? {});
49
58
  const runtimePart = isRuntimeConfigured ? `runtimeUrl=${copilotkit.runtimeUrl}` : "no runtimeUrl";
50
59
  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.");
@@ -1 +1 @@
1
- {"version":3,"file":"use-agent.cjs","names":["DEFAULT_AGENT_ID","useCopilotKit","CopilotKitCoreRuntimeConnectionStatus","ProxiedCopilotRuntimeAgent"],"sources":["../../src/hooks/use-agent.tsx"],"sourcesContent":["import { useCopilotKit } from \"@/providers/CopilotKitProvider\";\nimport { useMemo, useEffect, useReducer, useRef } from \"react\";\nimport { DEFAULT_AGENT_ID } from \"@copilotkitnext/shared\";\nimport { AbstractAgent } from \"@ag-ui/client\";\nimport {\n ProxiedCopilotRuntimeAgent,\n CopilotKitCoreRuntimeConnectionStatus,\n} from \"@copilotkitnext/core\";\n\nexport enum UseAgentUpdate {\n OnMessagesChanged = \"OnMessagesChanged\",\n OnStateChanged = \"OnStateChanged\",\n OnRunStatusChanged = \"OnRunStatusChanged\",\n}\n\nconst ALL_UPDATES: UseAgentUpdate[] = [\n UseAgentUpdate.OnMessagesChanged,\n UseAgentUpdate.OnStateChanged,\n UseAgentUpdate.OnRunStatusChanged,\n];\n\nexport interface UseAgentProps {\n agentId?: string;\n updates?: UseAgentUpdate[];\n}\n\nexport function useAgent({ agentId, updates }: UseAgentProps = {}) {\n agentId ??= DEFAULT_AGENT_ID;\n\n const { copilotkit } = useCopilotKit();\n const [, forceUpdate] = useReducer((x) => x + 1, 0);\n\n const updateFlags = useMemo(\n () => updates ?? ALL_UPDATES,\n [JSON.stringify(updates)],\n );\n\n // Cache provisional agents to avoid creating new references on every render\n // while the runtime is still connecting. A new reference would cascade into\n // CopilotChat's connectAgent effect, causing unnecessary HTTP calls.\n const provisionalAgentCache = useRef<Map<string, ProxiedCopilotRuntimeAgent>>(\n new Map(),\n );\n\n const agent: AbstractAgent = useMemo(() => {\n const existing = copilotkit.getAgent(agentId);\n if (existing) {\n // Real agent found — clear any cached provisional for this ID\n provisionalAgentCache.current.delete(agentId);\n return existing;\n }\n\n const isRuntimeConfigured = copilotkit.runtimeUrl !== undefined;\n const status = copilotkit.runtimeConnectionStatus;\n\n // While runtime is not yet synced, return a provisional runtime agent\n if (\n isRuntimeConfigured &&\n (status === CopilotKitCoreRuntimeConnectionStatus.Disconnected ||\n status === CopilotKitCoreRuntimeConnectionStatus.Connecting)\n ) {\n // Return cached provisional if available (keeps reference stable)\n const cached = provisionalAgentCache.current.get(agentId);\n if (cached) {\n // Update headers on the cached agent in case they changed\n cached.headers = { ...copilotkit.headers };\n return cached;\n }\n\n const provisional = new ProxiedCopilotRuntimeAgent({\n runtimeUrl: copilotkit.runtimeUrl,\n agentId,\n transport: copilotkit.runtimeTransport,\n });\n // Apply current headers so runs/connects inherit them\n provisional.headers = { ...copilotkit.headers };\n provisionalAgentCache.current.set(agentId, provisional);\n return provisional;\n }\n\n // After runtime has synced (Connected or Error) or no runtime configured and the agent doesn't exist, throw a descriptive error\n const knownAgents = Object.keys(copilotkit.agents ?? {});\n const runtimePart = isRuntimeConfigured\n ? `runtimeUrl=${copilotkit.runtimeUrl}`\n : \"no runtimeUrl\";\n throw new Error(\n `useAgent: Agent '${agentId}' not found after runtime sync (${runtimePart}). ` +\n (knownAgents.length\n ? `Known agents: [${knownAgents.join(\", \")}]`\n : \"No agents registered.\") +\n \" Verify your runtime /info and/or agents__unsafe_dev_only.\",\n );\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n agentId,\n copilotkit.agents,\n copilotkit.runtimeConnectionStatus,\n copilotkit.runtimeUrl,\n copilotkit.runtimeTransport,\n JSON.stringify(copilotkit.headers),\n ]);\n\n useEffect(() => {\n if (updateFlags.length === 0) {\n return;\n }\n\n const handlers: Parameters<AbstractAgent[\"subscribe\"]>[0] = {};\n\n if (updateFlags.includes(UseAgentUpdate.OnMessagesChanged)) {\n // Content stripping for immutableContent renderers is handled by CopilotKitCoreReact\n handlers.onMessagesChanged = () => {\n forceUpdate();\n };\n }\n\n if (updateFlags.includes(UseAgentUpdate.OnStateChanged)) {\n handlers.onStateChanged = forceUpdate;\n }\n\n if (updateFlags.includes(UseAgentUpdate.OnRunStatusChanged)) {\n handlers.onRunInitialized = forceUpdate;\n handlers.onRunFinalized = forceUpdate;\n handlers.onRunFailed = forceUpdate;\n }\n\n const subscription = agent.subscribe(handlers);\n return () => subscription.unsubscribe();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [agent, forceUpdate, JSON.stringify(updateFlags)]);\n\n return {\n agent,\n };\n}\n"],"mappings":";;;;;;;AASA,IAAY,0DAAL;AACL;AACA;AACA;;;AAGF,MAAM,cAAgC;CACpC,eAAe;CACf,eAAe;CACf,eAAe;CAChB;AAOD,SAAgB,SAAS,EAAE,SAAS,YAA2B,EAAE,EAAE;AACjE,aAAYA;CAEZ,MAAM,EAAE,eAAeC,0CAAe;CACtC,MAAM,GAAG,sCAA2B,MAAM,IAAI,GAAG,EAAE;CAEnD,MAAM,uCACE,WAAW,aACjB,CAAC,KAAK,UAAU,QAAQ,CAAC,CAC1B;CAKD,MAAM,0DACJ,IAAI,KAAK,CACV;CAED,MAAM,iCAAqC;EACzC,MAAM,WAAW,WAAW,SAAS,QAAQ;AAC7C,MAAI,UAAU;AAEZ,yBAAsB,QAAQ,OAAO,QAAQ;AAC7C,UAAO;;EAGT,MAAM,sBAAsB,WAAW,eAAe;EACtD,MAAM,SAAS,WAAW;AAG1B,MACE,wBACC,WAAWC,2DAAsC,gBAChD,WAAWA,2DAAsC,aACnD;GAEA,MAAM,SAAS,sBAAsB,QAAQ,IAAI,QAAQ;AACzD,OAAI,QAAQ;AAEV,WAAO,UAAU,EAAE,GAAG,WAAW,SAAS;AAC1C,WAAO;;GAGT,MAAM,cAAc,IAAIC,gDAA2B;IACjD,YAAY,WAAW;IACvB;IACA,WAAW,WAAW;IACvB,CAAC;AAEF,eAAY,UAAU,EAAE,GAAG,WAAW,SAAS;AAC/C,yBAAsB,QAAQ,IAAI,SAAS,YAAY;AACvD,UAAO;;EAIT,MAAM,cAAc,OAAO,KAAK,WAAW,UAAU,EAAE,CAAC;EACxD,MAAM,cAAc,sBAChB,cAAc,WAAW,eACzB;AACJ,QAAM,IAAI,MACR,oBAAoB,QAAQ,kCAAkC,YAAY,QACvE,YAAY,SACT,kBAAkB,YAAY,KAAK,KAAK,CAAC,KACzC,2BACJ,6DACH;IAEA;EACD;EACA,WAAW;EACX,WAAW;EACX,WAAW;EACX,WAAW;EACX,KAAK,UAAU,WAAW,QAAQ;EACnC,CAAC;AAEF,4BAAgB;AACd,MAAI,YAAY,WAAW,EACzB;EAGF,MAAM,WAAsD,EAAE;AAE9D,MAAI,YAAY,SAAS,eAAe,kBAAkB,CAExD,UAAS,0BAA0B;AACjC,gBAAa;;AAIjB,MAAI,YAAY,SAAS,eAAe,eAAe,CACrD,UAAS,iBAAiB;AAG5B,MAAI,YAAY,SAAS,eAAe,mBAAmB,EAAE;AAC3D,YAAS,mBAAmB;AAC5B,YAAS,iBAAiB;AAC1B,YAAS,cAAc;;EAGzB,MAAM,eAAe,MAAM,UAAU,SAAS;AAC9C,eAAa,aAAa,aAAa;IAEtC;EAAC;EAAO;EAAa,KAAK,UAAU,YAAY;EAAC,CAAC;AAErD,QAAO,EACL,OACD"}
1
+ {"version":3,"file":"use-agent.cjs","names":["DEFAULT_AGENT_ID","useCopilotKit","CopilotKitCoreRuntimeConnectionStatus","ProxiedCopilotRuntimeAgent"],"sources":["../../src/hooks/use-agent.tsx"],"sourcesContent":["import { useCopilotKit } from \"@/providers/CopilotKitProvider\";\nimport { useMemo, useEffect, useReducer, useRef } from \"react\";\nimport { DEFAULT_AGENT_ID } from \"@copilotkitnext/shared\";\nimport { AbstractAgent } from \"@ag-ui/client\";\nimport {\n ProxiedCopilotRuntimeAgent,\n CopilotKitCoreRuntimeConnectionStatus,\n} from \"@copilotkitnext/core\";\n\nexport enum UseAgentUpdate {\n OnMessagesChanged = \"OnMessagesChanged\",\n OnStateChanged = \"OnStateChanged\",\n OnRunStatusChanged = \"OnRunStatusChanged\",\n}\n\nconst ALL_UPDATES: UseAgentUpdate[] = [\n UseAgentUpdate.OnMessagesChanged,\n UseAgentUpdate.OnStateChanged,\n UseAgentUpdate.OnRunStatusChanged,\n];\n\nexport interface UseAgentProps {\n agentId?: string;\n updates?: UseAgentUpdate[];\n}\n\nexport function useAgent({ agentId, updates }: UseAgentProps = {}) {\n agentId ??= DEFAULT_AGENT_ID;\n\n const { copilotkit } = useCopilotKit();\n const [, forceUpdate] = useReducer((x) => x + 1, 0);\n\n const updateFlags = useMemo(\n () => updates ?? ALL_UPDATES,\n [JSON.stringify(updates)],\n );\n\n // Cache provisional agents to avoid creating new references on every render\n // while the runtime is still connecting. A new reference would cascade into\n // CopilotChat's connectAgent effect, causing unnecessary HTTP calls.\n const provisionalAgentCache = useRef<Map<string, ProxiedCopilotRuntimeAgent>>(\n new Map(),\n );\n\n const agent: AbstractAgent = useMemo(() => {\n const existing = copilotkit.getAgent(agentId);\n if (existing) {\n // Real agent found — clear any cached provisional for this ID\n provisionalAgentCache.current.delete(agentId);\n return existing;\n }\n\n const isRuntimeConfigured = copilotkit.runtimeUrl !== undefined;\n const status = copilotkit.runtimeConnectionStatus;\n\n // While runtime is not yet synced, return a provisional runtime agent\n if (\n isRuntimeConfigured &&\n (status === CopilotKitCoreRuntimeConnectionStatus.Disconnected ||\n status === CopilotKitCoreRuntimeConnectionStatus.Connecting)\n ) {\n // Return cached provisional if available (keeps reference stable)\n const cached = provisionalAgentCache.current.get(agentId);\n if (cached) {\n // Update headers on the cached agent in case they changed\n cached.headers = { ...copilotkit.headers };\n return cached;\n }\n\n const provisional = new ProxiedCopilotRuntimeAgent({\n runtimeUrl: copilotkit.runtimeUrl,\n agentId,\n transport: copilotkit.runtimeTransport,\n });\n // Apply current headers so runs/connects inherit them\n provisional.headers = { ...copilotkit.headers };\n provisionalAgentCache.current.set(agentId, provisional);\n return provisional;\n }\n\n // Runtime is in Error state — return a provisional agent instead of throwing.\n // The error has already been emitted through the subscriber system\n // (RUNTIME_INFO_FETCH_FAILED). Throwing here would crash the React tree;\n // returning a provisional agent lets onError handlers fire while keeping\n // the app alive.\n if (\n isRuntimeConfigured &&\n status === CopilotKitCoreRuntimeConnectionStatus.Error\n ) {\n const provisional = new ProxiedCopilotRuntimeAgent({\n runtimeUrl: copilotkit.runtimeUrl,\n agentId,\n transport: copilotkit.runtimeTransport,\n });\n provisional.headers = { ...copilotkit.headers };\n return provisional;\n }\n\n // No runtime configured and agent doesn't exist this is a configuration error.\n const knownAgents = Object.keys(copilotkit.agents ?? {});\n const runtimePart = isRuntimeConfigured\n ? `runtimeUrl=${copilotkit.runtimeUrl}`\n : \"no runtimeUrl\";\n throw new Error(\n `useAgent: Agent '${agentId}' not found after runtime sync (${runtimePart}). ` +\n (knownAgents.length\n ? `Known agents: [${knownAgents.join(\", \")}]`\n : \"No agents registered.\") +\n \" Verify your runtime /info and/or agents__unsafe_dev_only.\",\n );\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n agentId,\n copilotkit.agents,\n copilotkit.runtimeConnectionStatus,\n copilotkit.runtimeUrl,\n copilotkit.runtimeTransport,\n JSON.stringify(copilotkit.headers),\n ]);\n\n useEffect(() => {\n if (updateFlags.length === 0) {\n return;\n }\n\n const handlers: Parameters<AbstractAgent[\"subscribe\"]>[0] = {};\n\n if (updateFlags.includes(UseAgentUpdate.OnMessagesChanged)) {\n // Content stripping for immutableContent renderers is handled by CopilotKitCoreReact\n handlers.onMessagesChanged = () => {\n forceUpdate();\n };\n }\n\n if (updateFlags.includes(UseAgentUpdate.OnStateChanged)) {\n handlers.onStateChanged = forceUpdate;\n }\n\n if (updateFlags.includes(UseAgentUpdate.OnRunStatusChanged)) {\n handlers.onRunInitialized = forceUpdate;\n handlers.onRunFinalized = forceUpdate;\n handlers.onRunFailed = forceUpdate;\n }\n\n const subscription = agent.subscribe(handlers);\n return () => subscription.unsubscribe();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [agent, forceUpdate, JSON.stringify(updateFlags)]);\n\n return {\n agent,\n };\n}\n"],"mappings":";;;;;;;AASA,IAAY,0DAAL;AACL;AACA;AACA;;;AAGF,MAAM,cAAgC;CACpC,eAAe;CACf,eAAe;CACf,eAAe;CAChB;AAOD,SAAgB,SAAS,EAAE,SAAS,YAA2B,EAAE,EAAE;AACjE,aAAYA;CAEZ,MAAM,EAAE,eAAeC,0CAAe;CACtC,MAAM,GAAG,sCAA2B,MAAM,IAAI,GAAG,EAAE;CAEnD,MAAM,uCACE,WAAW,aACjB,CAAC,KAAK,UAAU,QAAQ,CAAC,CAC1B;CAKD,MAAM,0DACJ,IAAI,KAAK,CACV;CAED,MAAM,iCAAqC;EACzC,MAAM,WAAW,WAAW,SAAS,QAAQ;AAC7C,MAAI,UAAU;AAEZ,yBAAsB,QAAQ,OAAO,QAAQ;AAC7C,UAAO;;EAGT,MAAM,sBAAsB,WAAW,eAAe;EACtD,MAAM,SAAS,WAAW;AAG1B,MACE,wBACC,WAAWC,2DAAsC,gBAChD,WAAWA,2DAAsC,aACnD;GAEA,MAAM,SAAS,sBAAsB,QAAQ,IAAI,QAAQ;AACzD,OAAI,QAAQ;AAEV,WAAO,UAAU,EAAE,GAAG,WAAW,SAAS;AAC1C,WAAO;;GAGT,MAAM,cAAc,IAAIC,gDAA2B;IACjD,YAAY,WAAW;IACvB;IACA,WAAW,WAAW;IACvB,CAAC;AAEF,eAAY,UAAU,EAAE,GAAG,WAAW,SAAS;AAC/C,yBAAsB,QAAQ,IAAI,SAAS,YAAY;AACvD,UAAO;;AAQT,MACE,uBACA,WAAWD,2DAAsC,OACjD;GACA,MAAM,cAAc,IAAIC,gDAA2B;IACjD,YAAY,WAAW;IACvB;IACA,WAAW,WAAW;IACvB,CAAC;AACF,eAAY,UAAU,EAAE,GAAG,WAAW,SAAS;AAC/C,UAAO;;EAIT,MAAM,cAAc,OAAO,KAAK,WAAW,UAAU,EAAE,CAAC;EACxD,MAAM,cAAc,sBAChB,cAAc,WAAW,eACzB;AACJ,QAAM,IAAI,MACR,oBAAoB,QAAQ,kCAAkC,YAAY,QACvE,YAAY,SACT,kBAAkB,YAAY,KAAK,KAAK,CAAC,KACzC,2BACJ,6DACH;IAEA;EACD;EACA,WAAW;EACX,WAAW;EACX,WAAW;EACX,WAAW;EACX,KAAK,UAAU,WAAW,QAAQ;EACnC,CAAC;AAEF,4BAAgB;AACd,MAAI,YAAY,WAAW,EACzB;EAGF,MAAM,WAAsD,EAAE;AAE9D,MAAI,YAAY,SAAS,eAAe,kBAAkB,CAExD,UAAS,0BAA0B;AACjC,gBAAa;;AAIjB,MAAI,YAAY,SAAS,eAAe,eAAe,CACrD,UAAS,iBAAiB;AAG5B,MAAI,YAAY,SAAS,eAAe,mBAAmB,EAAE;AAC3D,YAAS,mBAAmB;AAC5B,YAAS,iBAAiB;AAC1B,YAAS,cAAc;;EAGzB,MAAM,eAAe,MAAM,UAAU,SAAS;AAC9C,eAAa,aAAa,aAAa;IAEtC;EAAC;EAAO;EAAa,KAAK,UAAU,YAAY;EAAC,CAAC;AAErD,QAAO,EACL,OACD"}
@@ -44,6 +44,15 @@ function useAgent({ agentId, updates } = {}) {
44
44
  provisionalAgentCache.current.set(agentId, provisional);
45
45
  return provisional;
46
46
  }
47
+ if (isRuntimeConfigured && status === CopilotKitCoreRuntimeConnectionStatus.Error) {
48
+ const provisional = new ProxiedCopilotRuntimeAgent({
49
+ runtimeUrl: copilotkit.runtimeUrl,
50
+ agentId,
51
+ transport: copilotkit.runtimeTransport
52
+ });
53
+ provisional.headers = { ...copilotkit.headers };
54
+ return provisional;
55
+ }
47
56
  const knownAgents = Object.keys(copilotkit.agents ?? {});
48
57
  const runtimePart = isRuntimeConfigured ? `runtimeUrl=${copilotkit.runtimeUrl}` : "no runtimeUrl";
49
58
  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.");
@@ -1 +1 @@
1
- {"version":3,"file":"use-agent.mjs","names":[],"sources":["../../src/hooks/use-agent.tsx"],"sourcesContent":["import { useCopilotKit } from \"@/providers/CopilotKitProvider\";\nimport { useMemo, useEffect, useReducer, useRef } from \"react\";\nimport { DEFAULT_AGENT_ID } from \"@copilotkitnext/shared\";\nimport { AbstractAgent } from \"@ag-ui/client\";\nimport {\n ProxiedCopilotRuntimeAgent,\n CopilotKitCoreRuntimeConnectionStatus,\n} from \"@copilotkitnext/core\";\n\nexport enum UseAgentUpdate {\n OnMessagesChanged = \"OnMessagesChanged\",\n OnStateChanged = \"OnStateChanged\",\n OnRunStatusChanged = \"OnRunStatusChanged\",\n}\n\nconst ALL_UPDATES: UseAgentUpdate[] = [\n UseAgentUpdate.OnMessagesChanged,\n UseAgentUpdate.OnStateChanged,\n UseAgentUpdate.OnRunStatusChanged,\n];\n\nexport interface UseAgentProps {\n agentId?: string;\n updates?: UseAgentUpdate[];\n}\n\nexport function useAgent({ agentId, updates }: UseAgentProps = {}) {\n agentId ??= DEFAULT_AGENT_ID;\n\n const { copilotkit } = useCopilotKit();\n const [, forceUpdate] = useReducer((x) => x + 1, 0);\n\n const updateFlags = useMemo(\n () => updates ?? ALL_UPDATES,\n [JSON.stringify(updates)],\n );\n\n // Cache provisional agents to avoid creating new references on every render\n // while the runtime is still connecting. A new reference would cascade into\n // CopilotChat's connectAgent effect, causing unnecessary HTTP calls.\n const provisionalAgentCache = useRef<Map<string, ProxiedCopilotRuntimeAgent>>(\n new Map(),\n );\n\n const agent: AbstractAgent = useMemo(() => {\n const existing = copilotkit.getAgent(agentId);\n if (existing) {\n // Real agent found — clear any cached provisional for this ID\n provisionalAgentCache.current.delete(agentId);\n return existing;\n }\n\n const isRuntimeConfigured = copilotkit.runtimeUrl !== undefined;\n const status = copilotkit.runtimeConnectionStatus;\n\n // While runtime is not yet synced, return a provisional runtime agent\n if (\n isRuntimeConfigured &&\n (status === CopilotKitCoreRuntimeConnectionStatus.Disconnected ||\n status === CopilotKitCoreRuntimeConnectionStatus.Connecting)\n ) {\n // Return cached provisional if available (keeps reference stable)\n const cached = provisionalAgentCache.current.get(agentId);\n if (cached) {\n // Update headers on the cached agent in case they changed\n cached.headers = { ...copilotkit.headers };\n return cached;\n }\n\n const provisional = new ProxiedCopilotRuntimeAgent({\n runtimeUrl: copilotkit.runtimeUrl,\n agentId,\n transport: copilotkit.runtimeTransport,\n });\n // Apply current headers so runs/connects inherit them\n provisional.headers = { ...copilotkit.headers };\n provisionalAgentCache.current.set(agentId, provisional);\n return provisional;\n }\n\n // After runtime has synced (Connected or Error) or no runtime configured and the agent doesn't exist, throw a descriptive error\n const knownAgents = Object.keys(copilotkit.agents ?? {});\n const runtimePart = isRuntimeConfigured\n ? `runtimeUrl=${copilotkit.runtimeUrl}`\n : \"no runtimeUrl\";\n throw new Error(\n `useAgent: Agent '${agentId}' not found after runtime sync (${runtimePart}). ` +\n (knownAgents.length\n ? `Known agents: [${knownAgents.join(\", \")}]`\n : \"No agents registered.\") +\n \" Verify your runtime /info and/or agents__unsafe_dev_only.\",\n );\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n agentId,\n copilotkit.agents,\n copilotkit.runtimeConnectionStatus,\n copilotkit.runtimeUrl,\n copilotkit.runtimeTransport,\n JSON.stringify(copilotkit.headers),\n ]);\n\n useEffect(() => {\n if (updateFlags.length === 0) {\n return;\n }\n\n const handlers: Parameters<AbstractAgent[\"subscribe\"]>[0] = {};\n\n if (updateFlags.includes(UseAgentUpdate.OnMessagesChanged)) {\n // Content stripping for immutableContent renderers is handled by CopilotKitCoreReact\n handlers.onMessagesChanged = () => {\n forceUpdate();\n };\n }\n\n if (updateFlags.includes(UseAgentUpdate.OnStateChanged)) {\n handlers.onStateChanged = forceUpdate;\n }\n\n if (updateFlags.includes(UseAgentUpdate.OnRunStatusChanged)) {\n handlers.onRunInitialized = forceUpdate;\n handlers.onRunFinalized = forceUpdate;\n handlers.onRunFailed = forceUpdate;\n }\n\n const subscription = agent.subscribe(handlers);\n return () => subscription.unsubscribe();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [agent, forceUpdate, JSON.stringify(updateFlags)]);\n\n return {\n agent,\n };\n}\n"],"mappings":";;;;;;AASA,IAAY,0DAAL;AACL;AACA;AACA;;;AAGF,MAAM,cAAgC;CACpC,eAAe;CACf,eAAe;CACf,eAAe;CAChB;AAOD,SAAgB,SAAS,EAAE,SAAS,YAA2B,EAAE,EAAE;AACjE,aAAY;CAEZ,MAAM,EAAE,eAAe,eAAe;CACtC,MAAM,GAAG,eAAe,YAAY,MAAM,IAAI,GAAG,EAAE;CAEnD,MAAM,cAAc,cACZ,WAAW,aACjB,CAAC,KAAK,UAAU,QAAQ,CAAC,CAC1B;CAKD,MAAM,wBAAwB,uBAC5B,IAAI,KAAK,CACV;CAED,MAAM,QAAuB,cAAc;EACzC,MAAM,WAAW,WAAW,SAAS,QAAQ;AAC7C,MAAI,UAAU;AAEZ,yBAAsB,QAAQ,OAAO,QAAQ;AAC7C,UAAO;;EAGT,MAAM,sBAAsB,WAAW,eAAe;EACtD,MAAM,SAAS,WAAW;AAG1B,MACE,wBACC,WAAW,sCAAsC,gBAChD,WAAW,sCAAsC,aACnD;GAEA,MAAM,SAAS,sBAAsB,QAAQ,IAAI,QAAQ;AACzD,OAAI,QAAQ;AAEV,WAAO,UAAU,EAAE,GAAG,WAAW,SAAS;AAC1C,WAAO;;GAGT,MAAM,cAAc,IAAI,2BAA2B;IACjD,YAAY,WAAW;IACvB;IACA,WAAW,WAAW;IACvB,CAAC;AAEF,eAAY,UAAU,EAAE,GAAG,WAAW,SAAS;AAC/C,yBAAsB,QAAQ,IAAI,SAAS,YAAY;AACvD,UAAO;;EAIT,MAAM,cAAc,OAAO,KAAK,WAAW,UAAU,EAAE,CAAC;EACxD,MAAM,cAAc,sBAChB,cAAc,WAAW,eACzB;AACJ,QAAM,IAAI,MACR,oBAAoB,QAAQ,kCAAkC,YAAY,QACvE,YAAY,SACT,kBAAkB,YAAY,KAAK,KAAK,CAAC,KACzC,2BACJ,6DACH;IAEA;EACD;EACA,WAAW;EACX,WAAW;EACX,WAAW;EACX,WAAW;EACX,KAAK,UAAU,WAAW,QAAQ;EACnC,CAAC;AAEF,iBAAgB;AACd,MAAI,YAAY,WAAW,EACzB;EAGF,MAAM,WAAsD,EAAE;AAE9D,MAAI,YAAY,SAAS,eAAe,kBAAkB,CAExD,UAAS,0BAA0B;AACjC,gBAAa;;AAIjB,MAAI,YAAY,SAAS,eAAe,eAAe,CACrD,UAAS,iBAAiB;AAG5B,MAAI,YAAY,SAAS,eAAe,mBAAmB,EAAE;AAC3D,YAAS,mBAAmB;AAC5B,YAAS,iBAAiB;AAC1B,YAAS,cAAc;;EAGzB,MAAM,eAAe,MAAM,UAAU,SAAS;AAC9C,eAAa,aAAa,aAAa;IAEtC;EAAC;EAAO;EAAa,KAAK,UAAU,YAAY;EAAC,CAAC;AAErD,QAAO,EACL,OACD"}
1
+ {"version":3,"file":"use-agent.mjs","names":[],"sources":["../../src/hooks/use-agent.tsx"],"sourcesContent":["import { useCopilotKit } from \"@/providers/CopilotKitProvider\";\nimport { useMemo, useEffect, useReducer, useRef } from \"react\";\nimport { DEFAULT_AGENT_ID } from \"@copilotkitnext/shared\";\nimport { AbstractAgent } from \"@ag-ui/client\";\nimport {\n ProxiedCopilotRuntimeAgent,\n CopilotKitCoreRuntimeConnectionStatus,\n} from \"@copilotkitnext/core\";\n\nexport enum UseAgentUpdate {\n OnMessagesChanged = \"OnMessagesChanged\",\n OnStateChanged = \"OnStateChanged\",\n OnRunStatusChanged = \"OnRunStatusChanged\",\n}\n\nconst ALL_UPDATES: UseAgentUpdate[] = [\n UseAgentUpdate.OnMessagesChanged,\n UseAgentUpdate.OnStateChanged,\n UseAgentUpdate.OnRunStatusChanged,\n];\n\nexport interface UseAgentProps {\n agentId?: string;\n updates?: UseAgentUpdate[];\n}\n\nexport function useAgent({ agentId, updates }: UseAgentProps = {}) {\n agentId ??= DEFAULT_AGENT_ID;\n\n const { copilotkit } = useCopilotKit();\n const [, forceUpdate] = useReducer((x) => x + 1, 0);\n\n const updateFlags = useMemo(\n () => updates ?? ALL_UPDATES,\n [JSON.stringify(updates)],\n );\n\n // Cache provisional agents to avoid creating new references on every render\n // while the runtime is still connecting. A new reference would cascade into\n // CopilotChat's connectAgent effect, causing unnecessary HTTP calls.\n const provisionalAgentCache = useRef<Map<string, ProxiedCopilotRuntimeAgent>>(\n new Map(),\n );\n\n const agent: AbstractAgent = useMemo(() => {\n const existing = copilotkit.getAgent(agentId);\n if (existing) {\n // Real agent found — clear any cached provisional for this ID\n provisionalAgentCache.current.delete(agentId);\n return existing;\n }\n\n const isRuntimeConfigured = copilotkit.runtimeUrl !== undefined;\n const status = copilotkit.runtimeConnectionStatus;\n\n // While runtime is not yet synced, return a provisional runtime agent\n if (\n isRuntimeConfigured &&\n (status === CopilotKitCoreRuntimeConnectionStatus.Disconnected ||\n status === CopilotKitCoreRuntimeConnectionStatus.Connecting)\n ) {\n // Return cached provisional if available (keeps reference stable)\n const cached = provisionalAgentCache.current.get(agentId);\n if (cached) {\n // Update headers on the cached agent in case they changed\n cached.headers = { ...copilotkit.headers };\n return cached;\n }\n\n const provisional = new ProxiedCopilotRuntimeAgent({\n runtimeUrl: copilotkit.runtimeUrl,\n agentId,\n transport: copilotkit.runtimeTransport,\n });\n // Apply current headers so runs/connects inherit them\n provisional.headers = { ...copilotkit.headers };\n provisionalAgentCache.current.set(agentId, provisional);\n return provisional;\n }\n\n // Runtime is in Error state — return a provisional agent instead of throwing.\n // The error has already been emitted through the subscriber system\n // (RUNTIME_INFO_FETCH_FAILED). Throwing here would crash the React tree;\n // returning a provisional agent lets onError handlers fire while keeping\n // the app alive.\n if (\n isRuntimeConfigured &&\n status === CopilotKitCoreRuntimeConnectionStatus.Error\n ) {\n const provisional = new ProxiedCopilotRuntimeAgent({\n runtimeUrl: copilotkit.runtimeUrl,\n agentId,\n transport: copilotkit.runtimeTransport,\n });\n provisional.headers = { ...copilotkit.headers };\n return provisional;\n }\n\n // No runtime configured and agent doesn't exist this is a configuration error.\n const knownAgents = Object.keys(copilotkit.agents ?? {});\n const runtimePart = isRuntimeConfigured\n ? `runtimeUrl=${copilotkit.runtimeUrl}`\n : \"no runtimeUrl\";\n throw new Error(\n `useAgent: Agent '${agentId}' not found after runtime sync (${runtimePart}). ` +\n (knownAgents.length\n ? `Known agents: [${knownAgents.join(\", \")}]`\n : \"No agents registered.\") +\n \" Verify your runtime /info and/or agents__unsafe_dev_only.\",\n );\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n agentId,\n copilotkit.agents,\n copilotkit.runtimeConnectionStatus,\n copilotkit.runtimeUrl,\n copilotkit.runtimeTransport,\n JSON.stringify(copilotkit.headers),\n ]);\n\n useEffect(() => {\n if (updateFlags.length === 0) {\n return;\n }\n\n const handlers: Parameters<AbstractAgent[\"subscribe\"]>[0] = {};\n\n if (updateFlags.includes(UseAgentUpdate.OnMessagesChanged)) {\n // Content stripping for immutableContent renderers is handled by CopilotKitCoreReact\n handlers.onMessagesChanged = () => {\n forceUpdate();\n };\n }\n\n if (updateFlags.includes(UseAgentUpdate.OnStateChanged)) {\n handlers.onStateChanged = forceUpdate;\n }\n\n if (updateFlags.includes(UseAgentUpdate.OnRunStatusChanged)) {\n handlers.onRunInitialized = forceUpdate;\n handlers.onRunFinalized = forceUpdate;\n handlers.onRunFailed = forceUpdate;\n }\n\n const subscription = agent.subscribe(handlers);\n return () => subscription.unsubscribe();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [agent, forceUpdate, JSON.stringify(updateFlags)]);\n\n return {\n agent,\n };\n}\n"],"mappings":";;;;;;AASA,IAAY,0DAAL;AACL;AACA;AACA;;;AAGF,MAAM,cAAgC;CACpC,eAAe;CACf,eAAe;CACf,eAAe;CAChB;AAOD,SAAgB,SAAS,EAAE,SAAS,YAA2B,EAAE,EAAE;AACjE,aAAY;CAEZ,MAAM,EAAE,eAAe,eAAe;CACtC,MAAM,GAAG,eAAe,YAAY,MAAM,IAAI,GAAG,EAAE;CAEnD,MAAM,cAAc,cACZ,WAAW,aACjB,CAAC,KAAK,UAAU,QAAQ,CAAC,CAC1B;CAKD,MAAM,wBAAwB,uBAC5B,IAAI,KAAK,CACV;CAED,MAAM,QAAuB,cAAc;EACzC,MAAM,WAAW,WAAW,SAAS,QAAQ;AAC7C,MAAI,UAAU;AAEZ,yBAAsB,QAAQ,OAAO,QAAQ;AAC7C,UAAO;;EAGT,MAAM,sBAAsB,WAAW,eAAe;EACtD,MAAM,SAAS,WAAW;AAG1B,MACE,wBACC,WAAW,sCAAsC,gBAChD,WAAW,sCAAsC,aACnD;GAEA,MAAM,SAAS,sBAAsB,QAAQ,IAAI,QAAQ;AACzD,OAAI,QAAQ;AAEV,WAAO,UAAU,EAAE,GAAG,WAAW,SAAS;AAC1C,WAAO;;GAGT,MAAM,cAAc,IAAI,2BAA2B;IACjD,YAAY,WAAW;IACvB;IACA,WAAW,WAAW;IACvB,CAAC;AAEF,eAAY,UAAU,EAAE,GAAG,WAAW,SAAS;AAC/C,yBAAsB,QAAQ,IAAI,SAAS,YAAY;AACvD,UAAO;;AAQT,MACE,uBACA,WAAW,sCAAsC,OACjD;GACA,MAAM,cAAc,IAAI,2BAA2B;IACjD,YAAY,WAAW;IACvB;IACA,WAAW,WAAW;IACvB,CAAC;AACF,eAAY,UAAU,EAAE,GAAG,WAAW,SAAS;AAC/C,UAAO;;EAIT,MAAM,cAAc,OAAO,KAAK,WAAW,UAAU,EAAE,CAAC;EACxD,MAAM,cAAc,sBAChB,cAAc,WAAW,eACzB;AACJ,QAAM,IAAI,MACR,oBAAoB,QAAQ,kCAAkC,YAAY,QACvE,YAAY,SACT,kBAAkB,YAAY,KAAK,KAAK,CAAC,KACzC,2BACJ,6DACH;IAEA;EACD;EACA,WAAW;EACX,WAAW;EACX,WAAW;EACX,WAAW;EACX,KAAK,UAAU,WAAW,QAAQ;EACnC,CAAC;AAEF,iBAAgB;AACd,MAAI,YAAY,WAAW,EACzB;EAGF,MAAM,WAAsD,EAAE;AAE9D,MAAI,YAAY,SAAS,eAAe,kBAAkB,CAExD,UAAS,0BAA0B;AACjC,gBAAa;;AAIjB,MAAI,YAAY,SAAS,eAAe,eAAe,CACrD,UAAS,iBAAiB;AAG5B,MAAI,YAAY,SAAS,eAAe,mBAAmB,EAAE;AAC3D,YAAS,mBAAmB;AAC5B,YAAS,iBAAiB;AAC1B,YAAS,cAAc;;EAGzB,MAAM,eAAe,MAAM,UAAU,SAAS;AAC9C,eAAa,aAAa,aAAa;IAEtC;EAAC;EAAO;EAAa,KAAK,UAAU,YAAY;EAAC,CAAC;AAErD,QAAO,EACL,OACD"}
package/dist/index.umd.js CHANGED
@@ -1869,7 +1869,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
1869
1869
  }, [value, warningMessage]);
1870
1870
  return value;
1871
1871
  }
1872
- const CopilotKitProvider = ({ children, runtimeUrl, headers = {}, credentials, publicApiKey, publicLicenseKey, properties = {}, agents__unsafe_dev_only: agents = {}, selfManagedAgents = {}, renderToolCalls, renderActivityMessages, renderCustomMessages, frontendTools, humanInTheLoop, showDevConsole = false, useSingleEndpoint = false }) => {
1872
+ 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 }) => {
1873
1873
  const [shouldRenderInspector, setShouldRenderInspector] = (0, react.useState)(false);
1874
1874
  (0, react.useEffect)(() => {
1875
1875
  if (typeof window === "undefined") return;
@@ -2024,6 +2024,24 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
2024
2024
  subscription.unsubscribe();
2025
2025
  };
2026
2026
  }, [copilotkit]);
2027
+ const onErrorRef = (0, react.useRef)(onError);
2028
+ (0, react.useEffect)(() => {
2029
+ onErrorRef.current = onError;
2030
+ }, [onError]);
2031
+ (0, react.useEffect)(() => {
2032
+ if (!onErrorRef.current) return;
2033
+ const subscription = copilotkit.subscribe({ onError: (event) => {
2034
+ var _onErrorRef$current;
2035
+ (_onErrorRef$current = onErrorRef.current) === null || _onErrorRef$current === void 0 || _onErrorRef$current.call(onErrorRef, {
2036
+ error: event.error,
2037
+ code: event.code,
2038
+ context: event.context
2039
+ });
2040
+ } });
2041
+ return () => {
2042
+ subscription.unsubscribe();
2043
+ };
2044
+ }, [copilotkit]);
2027
2045
  (0, react.useEffect)(() => {
2028
2046
  copilotkit.setRuntimeUrl(chatApiEndpoint);
2029
2047
  copilotkit.setRuntimeTransport(useSingleEndpoint ? "single" : "rest");
@@ -2755,6 +2773,15 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
2755
2773
  provisionalAgentCache.current.set(agentId, provisional);
2756
2774
  return provisional;
2757
2775
  }
2776
+ if (isRuntimeConfigured && status === _copilotkitnext_core.CopilotKitCoreRuntimeConnectionStatus.Error) {
2777
+ const provisional = new _copilotkitnext_core.ProxiedCopilotRuntimeAgent({
2778
+ runtimeUrl: copilotkit.runtimeUrl,
2779
+ agentId,
2780
+ transport: copilotkit.runtimeTransport
2781
+ });
2782
+ provisional.headers = { ...copilotkit.headers };
2783
+ return provisional;
2784
+ }
2758
2785
  const knownAgents = Object.keys((_copilotkit$agents = copilotkit.agents) !== null && _copilotkit$agents !== void 0 ? _copilotkit$agents : {});
2759
2786
  const runtimePart = isRuntimeConfigured ? `runtimeUrl=${copilotkit.runtimeUrl}` : "no runtimeUrl";
2760
2787
  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.");
@@ -4426,7 +4453,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4426
4453
 
4427
4454
  //#endregion
4428
4455
  //#region src/components/chat/CopilotChat.tsx
4429
- function CopilotChat({ agentId, threadId, labels, chatView, ...props }) {
4456
+ function CopilotChat({ agentId, threadId, labels, chatView, onError, ...props }) {
4430
4457
  var _ref;
4431
4458
  const existingConfig = useCopilotChatConfiguration();
4432
4459
  const resolvedAgentId = (_ref = agentId !== null && agentId !== void 0 ? agentId : existingConfig === null || existingConfig === void 0 ? void 0 : existingConfig.agentId) !== null && _ref !== void 0 ? _ref : _copilotkitnext_shared.DEFAULT_AGENT_ID;
@@ -4437,6 +4464,27 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4437
4464
  const { agent } = useAgent({ agentId: resolvedAgentId });
4438
4465
  const { copilotkit } = useCopilotKit();
4439
4466
  const { suggestions: autoSuggestions } = useSuggestions({ agentId: resolvedAgentId });
4467
+ const onErrorRef = (0, react.useRef)(onError);
4468
+ (0, react.useEffect)(() => {
4469
+ onErrorRef.current = onError;
4470
+ }, [onError]);
4471
+ (0, react.useEffect)(() => {
4472
+ if (!onErrorRef.current) return;
4473
+ const subscription = copilotkit.subscribe({ onError: (event) => {
4474
+ var _event$context, _event$context2;
4475
+ if (((_event$context = event.context) === null || _event$context === void 0 ? void 0 : _event$context.agentId) === resolvedAgentId || !((_event$context2 = event.context) === null || _event$context2 === void 0 ? void 0 : _event$context2.agentId)) {
4476
+ var _onErrorRef$current;
4477
+ (_onErrorRef$current = onErrorRef.current) === null || _onErrorRef$current === void 0 || _onErrorRef$current.call(onErrorRef, {
4478
+ error: event.error,
4479
+ code: event.code,
4480
+ context: event.context
4481
+ });
4482
+ }
4483
+ } });
4484
+ return () => {
4485
+ subscription.unsubscribe();
4486
+ };
4487
+ }, [copilotkit, resolvedAgentId]);
4440
4488
  const [transcribeMode, setTranscribeMode] = (0, react.useState)("input");
4441
4489
  const [inputValue, setInputValue] = (0, react.useState)("");
4442
4490
  const [transcriptionError, setTranscriptionError] = (0, react.useState)(null);
@@ -4453,7 +4501,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4453
4501
  await copilotkit.connectAgent({ agent });
4454
4502
  } catch (error) {
4455
4503
  if (detached) return;
4456
- if (error instanceof _ag_ui_client.AGUIConnectNotImplementedError) {} else throw error;
4504
+ console.error("CopilotChat: connectAgent failed", error);
4457
4505
  }
4458
4506
  };
4459
4507
  agent.threadId = resolvedThreadId;