@copilotkit/react-core 1.53.0-next.6 → 1.53.1-next.0

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.
package/dist/index.mjs CHANGED
@@ -1,859 +1,13 @@
1
1
  "use client";
2
2
 
3
- import React, { Fragment, createContext, createElement, useCallback, useContext, useEffect, useMemo, useReducer, useRef, useState } from "react";
4
- import { CopilotChatConfigurationProvider, CopilotKitProvider, defineToolCallRenderer, useAgent, useConfigureSuggestions, useCopilotChatConfiguration, useCopilotKit, useFrontendTool as useFrontendTool$1, useHumanInTheLoop as useHumanInTheLoop$1, useInterrupt, useRenderCustomMessages, useRenderToolCall as useRenderToolCall$1, useSuggestions } from "@copilotkitnext/react";
5
- import { COPILOT_CLOUD_API_URL, COPILOT_CLOUD_CHAT_URL, COPILOT_CLOUD_PUBLIC_API_KEY_HEADER, ConfigurationError, CopilotKitAgentDiscoveryError, CopilotKitApiDiscoveryError, CopilotKitError, CopilotKitErrorCode, CopilotKitLowLevelError, CopilotKitRemoteEndpointDiscoveryError, ErrorVisibility, MissingPublicApiKeyError, Severity, actionParametersToJsonSchema, dataToUUID, getZodParameters, parseJson, randomId, randomUUID, styledConsole } from "@copilotkit/shared";
6
- import { flushSync } from "react-dom";
7
- import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
- import ReactMarkdown from "react-markdown";
3
+ import { a as ThreadsProvider, c as CoAgentStateRendersProvider, d as shouldShowDevConsole, f as useToast, g as useCopilotContext, h as CopilotContext, i as ThreadsContext, l as useCoAgentStateRenders, m as useCopilotMessagesContext, n as defaultCopilotContextCategories, o as useThreads, p as CopilotMessagesContext, r as CoAgentStateRenderBridge, s as CoAgentStateRendersContext, t as CopilotKit, u as useAsyncCallback } from "./copilotkit-Yh_Ld_FX.mjs";
4
+ import React, { Fragment, createElement, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
5
+ import { defineToolCallRenderer, useAgent, useConfigureSuggestions, useCopilotChatConfiguration, useCopilotKit, useFrontendTool as useFrontendTool$1, useHumanInTheLoop as useHumanInTheLoop$1, useInterrupt, useRenderCustomMessages, useRenderToolCall as useRenderToolCall$1, useSuggestions } from "@copilotkitnext/react";
6
+ import { CopilotKitAgentDiscoveryError, CopilotKitApiDiscoveryError, CopilotKitError, CopilotKitErrorCode, CopilotKitRemoteEndpointDiscoveryError, ErrorVisibility, Severity, actionParametersToJsonSchema, getZodParameters, parseJson, randomId, styledConsole } from "@copilotkit/shared";
9
7
  import { ActionInputAvailability, CopilotRequestType, CopilotRuntimeClient, Message as Message$1, MetaEventName, Role, TextMessage, convertGqlOutputToMessages, convertMessagesToGqlInput, filterAgentStateMessages, gqlToAGUI } from "@copilotkit/runtime-client-gql";
10
8
  import { CopilotKitCoreRuntimeConnectionStatus, ToolCallStatus } from "@copilotkitnext/core";
11
9
  import { AGUIConnectNotImplementedError } from "@ag-ui/client";
12
10
 
13
- //#region src/context/copilot-context.tsx
14
- const emptyCopilotContext$1 = {
15
- actions: {},
16
- setAction: () => {},
17
- removeAction: () => {},
18
- setRegisteredActions: () => "",
19
- removeRegisteredAction: () => {},
20
- chatComponentsCache: { current: {
21
- actions: {},
22
- coAgentStateRenders: {}
23
- } },
24
- getContextString: (documents, categories) => returnAndThrowInDebug(""),
25
- addContext: () => "",
26
- removeContext: () => {},
27
- getAllContext: () => [],
28
- getFunctionCallHandler: () => returnAndThrowInDebug(async () => {}),
29
- isLoading: false,
30
- setIsLoading: () => returnAndThrowInDebug(false),
31
- chatInstructions: "",
32
- setChatInstructions: () => returnAndThrowInDebug(""),
33
- additionalInstructions: [],
34
- setAdditionalInstructions: () => returnAndThrowInDebug([]),
35
- getDocumentsContext: (categories) => returnAndThrowInDebug([]),
36
- addDocumentContext: () => returnAndThrowInDebug(""),
37
- removeDocumentContext: () => {},
38
- copilotApiConfig: new class {
39
- get chatApiEndpoint() {
40
- throw new Error("Remember to wrap your app in a `<CopilotKit> {...} </CopilotKit>` !!!");
41
- }
42
- get headers() {
43
- return {};
44
- }
45
- get body() {
46
- return {};
47
- }
48
- }(),
49
- chatSuggestionConfiguration: {},
50
- addChatSuggestionConfiguration: () => {},
51
- removeChatSuggestionConfiguration: () => {},
52
- showDevConsole: false,
53
- coagentStates: {},
54
- setCoagentStates: () => {},
55
- coagentStatesRef: { current: {} },
56
- setCoagentStatesWithRef: () => {},
57
- agentSession: null,
58
- setAgentSession: () => {},
59
- forwardedParameters: {},
60
- agentLock: null,
61
- threadId: "",
62
- setThreadId: () => {},
63
- runId: null,
64
- setRunId: () => {},
65
- chatAbortControllerRef: { current: null },
66
- availableAgents: [],
67
- extensions: {},
68
- setExtensions: () => {},
69
- interruptActions: {},
70
- setInterruptAction: () => {},
71
- removeInterruptAction: () => {},
72
- interruptEventQueue: {},
73
- addInterruptEvent: () => {},
74
- resolveInterruptEvent: () => {},
75
- onError: () => {},
76
- bannerError: null,
77
- setBannerError: () => {},
78
- internalErrorHandlers: {},
79
- setInternalErrorHandler: () => {},
80
- removeInternalErrorHandler: () => {}
81
- };
82
- const CopilotContext = React.createContext(emptyCopilotContext$1);
83
- function useCopilotContext() {
84
- const context = React.useContext(CopilotContext);
85
- if (context === emptyCopilotContext$1) throw new Error("Remember to wrap your app in a `<CopilotKit> {...} </CopilotKit>` !!!");
86
- return context;
87
- }
88
- function returnAndThrowInDebug(_value) {
89
- throw new Error("Remember to wrap your app in a `<CopilotKit> {...} </CopilotKit>` !!!");
90
- }
91
-
92
- //#endregion
93
- //#region src/hooks/use-tree.ts
94
- const removeNode = (nodes, id) => {
95
- return nodes.reduce((result, node) => {
96
- if (node.id !== id) {
97
- const newNode = {
98
- ...node,
99
- children: removeNode(node.children, id)
100
- };
101
- result.push(newNode);
102
- }
103
- return result;
104
- }, []);
105
- };
106
- const addNode = (nodes, newNode, parentId) => {
107
- if (!parentId) return [...nodes, newNode];
108
- return nodes.map((node) => {
109
- if (node.id === parentId) return {
110
- ...node,
111
- children: [...node.children, newNode]
112
- };
113
- else if (node.children.length) return {
114
- ...node,
115
- children: addNode(node.children, newNode, parentId)
116
- };
117
- return node;
118
- });
119
- };
120
- const treeIndentationRepresentation = (index, indentLevel) => {
121
- if (indentLevel === 0) return (index + 1).toString();
122
- else if (indentLevel === 1) return String.fromCharCode(65 + index);
123
- else if (indentLevel === 2) return String.fromCharCode(97 + index);
124
- else return "-";
125
- };
126
- const printNode = (node, prefix = "", indentLevel = 0) => {
127
- const indent = " ".repeat(3).repeat(indentLevel);
128
- const prefixPlusIndentLength = prefix.length + indent.length;
129
- const subsequentLinesPrefix = " ".repeat(prefixPlusIndentLength);
130
- const valueLines = node.value.split("\n");
131
- const outputFirstLine = `${indent}${prefix}${valueLines[0]}`;
132
- const outputSubsequentLines = valueLines.slice(1).map((line) => `${subsequentLinesPrefix}${line}`).join("\n");
133
- let output = `${outputFirstLine}\n`;
134
- if (outputSubsequentLines) output += `${outputSubsequentLines}\n`;
135
- const childPrePrefix = " ".repeat(prefix.length);
136
- node.children.forEach((child, index) => output += printNode(child, `${childPrePrefix}${treeIndentationRepresentation(index, indentLevel + 1)}. `, indentLevel + 1));
137
- return output;
138
- };
139
- function treeReducer(state, action) {
140
- switch (action.type) {
141
- case "ADD_NODE": {
142
- const { value, parentId, id: newNodeId } = action;
143
- const newNode = {
144
- id: newNodeId,
145
- value,
146
- children: [],
147
- categories: new Set(action.categories)
148
- };
149
- try {
150
- return addNode(state, newNode, parentId);
151
- } catch (error) {
152
- console.error(`Error while adding node with id ${newNodeId}: ${error}`);
153
- return state;
154
- }
155
- }
156
- case "REMOVE_NODE": return removeNode(state, action.id);
157
- default: return state;
158
- }
159
- }
160
- const useTree = () => {
161
- const [tree, dispatch] = useReducer(treeReducer, []);
162
- const addElement = useCallback((value, categories, parentId) => {
163
- const newNodeId = randomId();
164
- dispatch({
165
- type: "ADD_NODE",
166
- value,
167
- parentId,
168
- id: newNodeId,
169
- categories
170
- });
171
- return newNodeId;
172
- }, []);
173
- const removeElement = useCallback((id) => {
174
- dispatch({
175
- type: "REMOVE_NODE",
176
- id
177
- });
178
- }, []);
179
- const getAllElements = useCallback(() => {
180
- return tree;
181
- }, [tree]);
182
- return {
183
- tree,
184
- addElement,
185
- printTree: useCallback((categories) => {
186
- const categoriesSet = new Set(categories);
187
- let output = "";
188
- tree.forEach((node, index) => {
189
- if (!setsHaveIntersection$1(categoriesSet, node.categories)) return;
190
- if (index !== 0) output += "\n";
191
- output += printNode(node, `${treeIndentationRepresentation(index, 0)}. `);
192
- });
193
- return output;
194
- }, [tree]),
195
- removeElement,
196
- getAllElements
197
- };
198
- };
199
- function setsHaveIntersection$1(setA, setB) {
200
- const [smallerSet, largerSet] = setA.size <= setB.size ? [setA, setB] : [setB, setA];
201
- for (let item of smallerSet) if (largerSet.has(item)) return true;
202
- return false;
203
- }
204
-
205
- //#endregion
206
- //#region src/hooks/use-flat-category-store.ts
207
- const useFlatCategoryStore = () => {
208
- const [elements, dispatch] = useReducer(flatCategoryStoreReducer, /* @__PURE__ */ new Map());
209
- return {
210
- addElement: useCallback((value, categories) => {
211
- const newId = randomId();
212
- dispatch({
213
- type: "ADD_ELEMENT",
214
- value,
215
- id: newId,
216
- categories
217
- });
218
- return newId;
219
- }, []),
220
- removeElement: useCallback((id) => {
221
- dispatch({
222
- type: "REMOVE_ELEMENT",
223
- id
224
- });
225
- }, []),
226
- allElements: useCallback((categories) => {
227
- const categoriesSet = new Set(categories);
228
- const result = [];
229
- elements.forEach((element) => {
230
- if (setsHaveIntersection(categoriesSet, element.categories)) result.push(element.value);
231
- });
232
- return result;
233
- }, [elements])
234
- };
235
- };
236
- function flatCategoryStoreReducer(state, action) {
237
- switch (action.type) {
238
- case "ADD_ELEMENT": {
239
- const { value, id, categories } = action;
240
- const newElement = {
241
- id,
242
- value,
243
- categories: new Set(categories)
244
- };
245
- const newState = new Map(state);
246
- newState.set(id, newElement);
247
- return newState;
248
- }
249
- case "REMOVE_ELEMENT": {
250
- const newState = new Map(state);
251
- newState.delete(action.id);
252
- return newState;
253
- }
254
- default: return state;
255
- }
256
- }
257
- function setsHaveIntersection(setA, setB) {
258
- const [smallerSet, largerSet] = setA.size <= setB.size ? [setA, setB] : [setB, setA];
259
- for (let item of smallerSet) if (largerSet.has(item)) return true;
260
- return false;
261
- }
262
-
263
- //#endregion
264
- //#region src/context/copilot-messages-context.tsx
265
- const emptyCopilotContext = {
266
- messages: [],
267
- setMessages: () => [],
268
- suggestions: [],
269
- setSuggestions: () => []
270
- };
271
- const CopilotMessagesContext = React.createContext(emptyCopilotContext);
272
- function useCopilotMessagesContext() {
273
- const context = React.useContext(CopilotMessagesContext);
274
- if (context === emptyCopilotContext) throw new Error("A messages consuming component was not wrapped with `<CopilotMessages> {...} </CopilotMessages>`");
275
- return context;
276
- }
277
-
278
- //#endregion
279
- //#region src/components/toast/toast-provider.tsx
280
- const ToastContext = createContext(void 0);
281
- function getErrorSeverity(error) {
282
- if (error.severity) switch (error.severity) {
283
- case Severity.CRITICAL: return "critical";
284
- case Severity.WARNING: return "warning";
285
- case Severity.INFO: return "info";
286
- default: return "info";
287
- }
288
- const message = error.message.toLowerCase();
289
- if (message.includes("api key") || message.includes("401") || message.includes("unauthorized") || message.includes("authentication") || message.includes("incorrect api key")) return "critical";
290
- return "info";
291
- }
292
- function getErrorColors(severity) {
293
- switch (severity) {
294
- case "critical": return {
295
- background: "#fee2e2",
296
- border: "#dc2626",
297
- text: "#7f1d1d",
298
- icon: "#dc2626"
299
- };
300
- case "warning": return {
301
- background: "#fef3c7",
302
- border: "#d97706",
303
- text: "#78350f",
304
- icon: "#d97706"
305
- };
306
- case "info": return {
307
- background: "#dbeafe",
308
- border: "#2563eb",
309
- text: "#1e3a8a",
310
- icon: "#2563eb"
311
- };
312
- }
313
- }
314
- function useToast() {
315
- const context = useContext(ToastContext);
316
- if (!context) throw new Error("useToast must be used within a ToastProvider");
317
- return context;
318
- }
319
- function ToastProvider({ enabled, children }) {
320
- const [toasts, setToasts] = useState([]);
321
- const [bannerError, setBannerErrorState] = useState(null);
322
- const removeToast = useCallback((id) => {
323
- setToasts((prev) => prev.filter((toast) => toast.id !== id));
324
- }, []);
325
- const addToast = useCallback((toast) => {
326
- if (!enabled) return;
327
- const id = toast.id ?? Math.random().toString(36).substring(2, 9);
328
- setToasts((currentToasts) => {
329
- if (currentToasts.find((toast) => toast.id === id)) return currentToasts;
330
- return [...currentToasts, {
331
- ...toast,
332
- id
333
- }];
334
- });
335
- if (toast.duration) setTimeout(() => {
336
- removeToast(id);
337
- }, toast.duration);
338
- }, [enabled, removeToast]);
339
- const setBannerError = useCallback((error) => {
340
- if (!enabled && error !== null) return;
341
- setBannerErrorState(error);
342
- }, [enabled]);
343
- const value = {
344
- toasts,
345
- addToast,
346
- addGraphQLErrorsToast: useCallback((errors) => {
347
- console.warn("addGraphQLErrorsToast is deprecated. All errors now show as banners.");
348
- }, []),
349
- removeToast,
350
- enabled,
351
- bannerError,
352
- setBannerError
353
- };
354
- return /* @__PURE__ */ jsxs(ToastContext.Provider, {
355
- value,
356
- children: [bannerError && (() => {
357
- const colors = getErrorColors(getErrorSeverity(bannerError));
358
- return /* @__PURE__ */ jsx("div", {
359
- style: {
360
- position: "fixed",
361
- bottom: "20px",
362
- left: "50%",
363
- transform: "translateX(-50%)",
364
- zIndex: 9999,
365
- backgroundColor: colors.background,
366
- border: `1px solid ${colors.border}`,
367
- borderLeft: `4px solid ${colors.border}`,
368
- borderRadius: "8px",
369
- padding: "12px 16px",
370
- fontSize: "13px",
371
- boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
372
- backdropFilter: "blur(8px)",
373
- maxWidth: "min(90vw, 700px)",
374
- width: "100%",
375
- boxSizing: "border-box",
376
- overflow: "hidden"
377
- },
378
- children: /* @__PURE__ */ jsxs("div", {
379
- style: {
380
- display: "flex",
381
- justifyContent: "space-between",
382
- alignItems: "center",
383
- gap: "10px"
384
- },
385
- children: [/* @__PURE__ */ jsxs("div", {
386
- style: {
387
- display: "flex",
388
- alignItems: "center",
389
- gap: "8px",
390
- flex: 1,
391
- minWidth: 0
392
- },
393
- children: [/* @__PURE__ */ jsx("div", { style: {
394
- width: "12px",
395
- height: "12px",
396
- borderRadius: "50%",
397
- backgroundColor: colors.border,
398
- flexShrink: 0
399
- } }), /* @__PURE__ */ jsxs("div", {
400
- style: {
401
- display: "flex",
402
- alignItems: "center",
403
- gap: "10px",
404
- flex: 1,
405
- minWidth: 0
406
- },
407
- children: [/* @__PURE__ */ jsx("div", {
408
- style: {
409
- color: colors.text,
410
- lineHeight: "1.4",
411
- fontWeight: "400",
412
- fontSize: "13px",
413
- flex: 1,
414
- wordBreak: "break-all",
415
- overflowWrap: "break-word",
416
- maxWidth: "550px",
417
- overflow: "hidden",
418
- display: "-webkit-box",
419
- WebkitLineClamp: 10,
420
- WebkitBoxOrient: "vertical"
421
- },
422
- children: (() => {
423
- let message = bannerError.message;
424
- const jsonMatch = message.match(/'message':\s*'([^']+)'/);
425
- if (jsonMatch) return jsonMatch[1];
426
- message = message.split(" - ")[0];
427
- message = message.split(": Error code")[0];
428
- message = message.replace(/:\s*\d{3}$/, "");
429
- message = message.replace(/See more:.*$/g, "");
430
- message = message.trim();
431
- return message || "Configuration error occurred.";
432
- })()
433
- }), (() => {
434
- const message = bannerError.message;
435
- const markdownLinkRegex = /\[([^\]]+)\]\(([^)]+)\)/g;
436
- const plainUrlRegex = /(https?:\/\/[^\s)]+)/g;
437
- let url = null;
438
- let buttonText = "See More";
439
- const markdownMatch = markdownLinkRegex.exec(message);
440
- if (markdownMatch) {
441
- url = markdownMatch[2];
442
- buttonText = "See More";
443
- } else {
444
- const urlMatch = plainUrlRegex.exec(message);
445
- if (urlMatch) {
446
- url = urlMatch[0].replace(/[.,;:'"]*$/, "");
447
- buttonText = "See More";
448
- }
449
- }
450
- if (!url) return null;
451
- return /* @__PURE__ */ jsx("button", {
452
- onClick: () => window.open(url, "_blank", "noopener,noreferrer"),
453
- style: {
454
- background: colors.border,
455
- color: "white",
456
- border: "none",
457
- borderRadius: "5px",
458
- padding: "4px 10px",
459
- fontSize: "11px",
460
- fontWeight: "500",
461
- cursor: "pointer",
462
- transition: "all 0.2s ease",
463
- flexShrink: 0
464
- },
465
- onMouseEnter: (e) => {
466
- e.currentTarget.style.opacity = "0.9";
467
- e.currentTarget.style.transform = "translateY(-1px)";
468
- },
469
- onMouseLeave: (e) => {
470
- e.currentTarget.style.opacity = "1";
471
- e.currentTarget.style.transform = "translateY(0)";
472
- },
473
- children: buttonText
474
- });
475
- })()]
476
- })]
477
- }), /* @__PURE__ */ jsx("button", {
478
- onClick: () => setBannerError(null),
479
- style: {
480
- background: "transparent",
481
- border: "none",
482
- color: colors.text,
483
- cursor: "pointer",
484
- padding: "2px",
485
- borderRadius: "3px",
486
- fontSize: "14px",
487
- lineHeight: "1",
488
- opacity: .6,
489
- transition: "all 0.2s ease",
490
- flexShrink: 0
491
- },
492
- title: "Dismiss",
493
- onMouseEnter: (e) => {
494
- e.currentTarget.style.opacity = "1";
495
- e.currentTarget.style.background = "rgba(0, 0, 0, 0.05)";
496
- },
497
- onMouseLeave: (e) => {
498
- e.currentTarget.style.opacity = "0.6";
499
- e.currentTarget.style.background = "transparent";
500
- },
501
- children: "×"
502
- })]
503
- })
504
- });
505
- })(), children]
506
- });
507
- }
508
-
509
- //#endregion
510
- //#region src/utils/dev-console.ts
511
- function isLocalhost() {
512
- if (typeof window === "undefined") return false;
513
- return window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1" || window.location.hostname === "0.0.0.0";
514
- }
515
- function shouldShowDevConsole(showDevConsole) {
516
- if (showDevConsole !== void 0) return showDevConsole;
517
- return isLocalhost();
518
- }
519
-
520
- //#endregion
521
- //#region src/components/copilot-provider/copilot-messages.tsx
522
- /**
523
- * An internal context to separate the messages state (which is constantly changing) from the rest of CopilotKit context
524
- */
525
- const MessagesTapContext = createContext(null);
526
- function useMessagesTap() {
527
- const tap = useContext(MessagesTapContext);
528
- if (!tap) throw new Error("useMessagesTap must be used inside <MessagesTapProvider>");
529
- return tap;
530
- }
531
- function MessagesTapProvider({ children }) {
532
- const messagesRef = useRef([]);
533
- const tapRef = useRef({
534
- getMessagesFromTap: () => messagesRef.current,
535
- updateTapMessages: (messages) => {
536
- messagesRef.current = messages;
537
- }
538
- });
539
- return /* @__PURE__ */ jsx(MessagesTapContext.Provider, {
540
- value: tapRef.current,
541
- children
542
- });
543
- }
544
- /**
545
- * CopilotKit messages context.
546
- */
547
- function CopilotMessages({ children }) {
548
- const [messages, setMessages] = useState([]);
549
- useRef(void 0);
550
- useRef(void 0);
551
- useRef(void 0);
552
- const { updateTapMessages } = useMessagesTap();
553
- const { threadId, agentSession, showDevConsole, onError, copilotApiConfig } = useCopilotContext();
554
- const { setBannerError } = useToast();
555
- const traceUIError = useCallback(async (error, originalError) => {
556
- if (!onError || !copilotApiConfig.publicApiKey) return;
557
- try {
558
- await onError({
559
- type: "error",
560
- timestamp: Date.now(),
561
- context: {
562
- source: "ui",
563
- request: {
564
- operation: "loadAgentState",
565
- url: copilotApiConfig.chatApiEndpoint,
566
- startTime: Date.now()
567
- },
568
- technical: {
569
- environment: "browser",
570
- userAgent: typeof navigator !== "undefined" ? navigator.userAgent : void 0,
571
- stackTrace: originalError instanceof Error ? originalError.stack : void 0
572
- }
573
- },
574
- error
575
- });
576
- } catch (traceError) {
577
- console.error("Error in CopilotMessages onError handler:", traceError);
578
- }
579
- }, [
580
- onError,
581
- copilotApiConfig.publicApiKey,
582
- copilotApiConfig.chatApiEndpoint
583
- ]);
584
- const createStructuredError = (gqlError) => {
585
- const extensions = gqlError.extensions;
586
- const originalError = extensions?.originalError;
587
- if (originalError?.stack) {
588
- if (originalError.stack.includes("CopilotApiDiscoveryError")) return new CopilotKitApiDiscoveryError({ message: originalError.message });
589
- if (originalError.stack.includes("CopilotKitRemoteEndpointDiscoveryError")) return new CopilotKitRemoteEndpointDiscoveryError({ message: originalError.message });
590
- if (originalError.stack.includes("CopilotKitAgentDiscoveryError")) return new CopilotKitAgentDiscoveryError({
591
- agentName: "",
592
- availableAgents: []
593
- });
594
- }
595
- const message = originalError?.message || gqlError.message;
596
- const code = extensions?.code;
597
- if (code) return new CopilotKitError({
598
- message,
599
- code
600
- });
601
- return null;
602
- };
603
- useCallback((error) => {
604
- if (error.graphQLErrors?.length) {
605
- const graphQLErrors = error.graphQLErrors;
606
- const routeError = (gqlError) => {
607
- const visibility = gqlError.extensions?.visibility;
608
- if (!shouldShowDevConsole(showDevConsole)) {
609
- console.error("CopilotKit Error (hidden in production):", gqlError.message);
610
- return;
611
- }
612
- if (visibility === ErrorVisibility.SILENT) {
613
- console.error("CopilotKit Silent Error:", gqlError.message);
614
- return;
615
- }
616
- const ckError = createStructuredError(gqlError);
617
- if (ckError) {
618
- setBannerError(ckError);
619
- traceUIError(ckError, gqlError);
620
- } else {
621
- const fallbackError = new CopilotKitError({
622
- message: gqlError.message,
623
- code: CopilotKitErrorCode.UNKNOWN
624
- });
625
- setBannerError(fallbackError);
626
- traceUIError(fallbackError, gqlError);
627
- }
628
- };
629
- graphQLErrors.forEach(routeError);
630
- } else if (!shouldShowDevConsole(showDevConsole)) console.error("CopilotKit Error (hidden in production):", error);
631
- else {
632
- const fallbackError = new CopilotKitError({
633
- message: error?.message || String(error),
634
- code: CopilotKitErrorCode.UNKNOWN
635
- });
636
- setBannerError(fallbackError);
637
- traceUIError(fallbackError, error);
638
- }
639
- }, [
640
- setBannerError,
641
- showDevConsole,
642
- traceUIError
643
- ]);
644
- useEffect(() => {
645
- updateTapMessages(messages);
646
- }, [messages, updateTapMessages]);
647
- const memoizedChildren = useMemo(() => children, [children]);
648
- const [suggestions, setSuggestions] = useState([]);
649
- return /* @__PURE__ */ jsx(CopilotMessagesContext.Provider, {
650
- value: {
651
- messages,
652
- setMessages,
653
- suggestions,
654
- setSuggestions
655
- },
656
- children: memoizedChildren
657
- });
658
- }
659
-
660
- //#endregion
661
- //#region src/components/usage-banner.tsx
662
- function UsageBanner({ severity = Severity.CRITICAL, message = "", onClose, actions }) {
663
- if (!message || !severity) return null;
664
- const theme = {
665
- [Severity.INFO]: {
666
- bg: "#f8fafc",
667
- border: "#e2e8f0",
668
- text: "#475569",
669
- accent: "#3b82f6"
670
- },
671
- [Severity.WARNING]: {
672
- bg: "#fffbeb",
673
- border: "#fbbf24",
674
- text: "#92400e",
675
- accent: "#f59e0b"
676
- },
677
- [Severity.CRITICAL]: {
678
- bg: "#fef2f2",
679
- border: "#fecaca",
680
- text: "#dc2626",
681
- accent: "#ef4444"
682
- }
683
- }[severity];
684
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("style", { children: `
685
- @keyframes slideUp {
686
- from { opacity: 0; transform: translateX(-50%) translateY(8px); }
687
- to { opacity: 1; transform: translateX(-50%) translateY(0); }
688
- }
689
-
690
- .usage-banner {
691
- position: fixed;
692
- bottom: 24px;
693
- left: 50%;
694
- transform: translateX(-50%);
695
- width: min(600px, calc(100vw - 32px));
696
- z-index: 10000;
697
- animation: slideUp 0.2s cubic-bezier(0.16, 1, 0.3, 1);
698
- }
699
-
700
- .banner-content {
701
- background: linear-gradient(135deg, ${theme.bg} 0%, ${theme.bg}f5 100%);
702
- border: 1px solid ${theme.border};
703
- border-radius: 12px;
704
- padding: 18px 20px;
705
- box-shadow:
706
- 0 4px 24px rgba(0, 0, 0, 0.08),
707
- 0 2px 8px rgba(0, 0, 0, 0.04),
708
- inset 0 1px 0 rgba(255, 255, 255, 0.7);
709
- display: flex;
710
- align-items: center;
711
- gap: 16px;
712
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
713
- backdrop-filter: blur(12px);
714
- position: relative;
715
- overflow: hidden;
716
- }
717
-
718
- .banner-content::before {
719
- content: '';
720
- position: absolute;
721
- top: 0;
722
- left: 0;
723
- right: 0;
724
- height: 1px;
725
- background: linear-gradient(90deg, transparent, ${theme.accent}40, transparent);
726
- }
727
-
728
- .banner-message {
729
- color: ${theme.text};
730
- font-size: 14px;
731
- line-height: 1.5;
732
- font-weight: 500;
733
- flex: 1;
734
- letter-spacing: -0.01em;
735
- }
736
-
737
- .close-btn {
738
- background: rgba(0, 0, 0, 0.05);
739
- border: none;
740
- color: ${theme.text};
741
- cursor: pointer;
742
- padding: 0;
743
- border-radius: 6px;
744
- opacity: 0.6;
745
- transition: all 0.15s cubic-bezier(0.16, 1, 0.3, 1);
746
- font-size: 14px;
747
- line-height: 1;
748
- flex-shrink: 0;
749
- width: 24px;
750
- height: 24px;
751
- display: flex;
752
- align-items: center;
753
- justify-content: center;
754
- }
755
-
756
- .close-btn:hover {
757
- opacity: 1;
758
- background: rgba(0, 0, 0, 0.08);
759
- transform: scale(1.05);
760
- }
761
-
762
- .btn-primary {
763
- background: linear-gradient(135deg, ${theme.accent} 0%, ${theme.accent}e6 100%);
764
- color: white;
765
- border: none;
766
- border-radius: 8px;
767
- padding: 10px 18px;
768
- font-size: 13px;
769
- font-weight: 600;
770
- cursor: pointer;
771
- transition: all 0.15s cubic-bezier(0.16, 1, 0.3, 1);
772
- font-family: inherit;
773
- flex-shrink: 0;
774
- box-shadow:
775
- 0 2px 8px ${theme.accent}30,
776
- inset 0 1px 0 rgba(255, 255, 255, 0.2);
777
- letter-spacing: -0.01em;
778
- }
779
-
780
- .btn-primary:hover {
781
- transform: translateY(-1px) scale(1.02);
782
- box-shadow:
783
- 0 4px 12px ${theme.accent}40,
784
- inset 0 1px 0 rgba(255, 255, 255, 0.25);
785
- }
786
-
787
- .btn-primary:active {
788
- transform: translateY(0) scale(0.98);
789
- transition: all 0.08s cubic-bezier(0.16, 1, 0.3, 1);
790
- }
791
-
792
- @media (max-width: 640px) {
793
- .usage-banner {
794
- width: calc(100vw - 24px);
795
- }
796
-
797
- .banner-content {
798
- padding: 16px;
799
- gap: 12px;
800
- }
801
-
802
- .banner-message {
803
- font-size: 13px;
804
- line-height: 1.45;
805
- }
806
-
807
- .btn-primary {
808
- padding: 8px 14px;
809
- font-size: 12px;
810
- }
811
-
812
- .close-btn {
813
- width: 22px;
814
- height: 22px;
815
- font-size: 12px;
816
- }
817
- }
818
- ` }), /* @__PURE__ */ jsx("div", {
819
- className: "usage-banner",
820
- children: /* @__PURE__ */ jsxs("div", {
821
- className: "banner-content",
822
- children: [
823
- /* @__PURE__ */ jsx("div", {
824
- className: "banner-message",
825
- children: message
826
- }),
827
- actions?.primary && /* @__PURE__ */ jsx("button", {
828
- className: "btn-primary",
829
- onClick: actions.primary.onClick,
830
- children: actions.primary.label
831
- }),
832
- onClose && /* @__PURE__ */ jsx("button", {
833
- className: "close-btn",
834
- onClick: onClose,
835
- title: "Close",
836
- children: "×"
837
- })
838
- ]
839
- })
840
- })] });
841
- }
842
- const getErrorActions = (error) => {
843
- switch (error.code) {
844
- case CopilotKitErrorCode.MISSING_PUBLIC_API_KEY_ERROR: return { primary: {
845
- label: "Show me how",
846
- onClick: () => window.open("https://docs.copilotkit.ai/premium#how-do-i-get-access-to-premium-features", "_blank", "noopener,noreferrer")
847
- } };
848
- case CopilotKitErrorCode.UPGRADE_REQUIRED_ERROR: return { primary: {
849
- label: "Upgrade",
850
- onClick: () => window.open("https://cloud.copilotkit.ai", "_blank", "noopener,noreferrer")
851
- } };
852
- default: return;
853
- }
854
- };
855
-
856
- //#endregion
857
11
  //#region src/utils/suggestions-constants.ts
858
12
  /**
859
13
  * Constants for suggestions retry logic
@@ -863,1184 +17,6 @@ const SUGGESTION_RETRY_CONFIG = {
863
17
  COOLDOWN_MS: 5e3
864
18
  };
865
19
 
866
- //#endregion
867
- //#region src/lib/status-checker.ts
868
- const STATUS_CHECK_INTERVAL = 1e3 * 60 * 5;
869
- var StatusChecker = class {
870
- constructor() {
871
- this.activeKey = null;
872
- this.intervalId = null;
873
- this.instanceCount = 0;
874
- this.lastResponse = null;
875
- }
876
- async start(publicApiKey, onUpdate) {
877
- this.instanceCount++;
878
- if (this.activeKey === publicApiKey) return;
879
- if (this.intervalId) clearInterval(this.intervalId);
880
- const checkStatus = async () => {
881
- try {
882
- const response = await fetch(`${COPILOT_CLOUD_API_URL}/ciu`, {
883
- method: "GET",
884
- headers: { [COPILOT_CLOUD_PUBLIC_API_KEY_HEADER]: publicApiKey }
885
- }).then((response) => response.json());
886
- this.lastResponse = response;
887
- onUpdate?.(response);
888
- return response;
889
- } catch (error) {
890
- return null;
891
- }
892
- };
893
- const initialResponse = await checkStatus();
894
- this.intervalId = setInterval(checkStatus, STATUS_CHECK_INTERVAL);
895
- this.activeKey = publicApiKey;
896
- return initialResponse;
897
- }
898
- getLastResponse() {
899
- return this.lastResponse;
900
- }
901
- stop() {
902
- this.instanceCount--;
903
- if (this.instanceCount === 0) {
904
- if (this.intervalId) {
905
- clearInterval(this.intervalId);
906
- this.intervalId = null;
907
- this.activeKey = null;
908
- this.lastResponse = null;
909
- }
910
- }
911
- }
912
- };
913
-
914
- //#endregion
915
- //#region src/components/toast/exclamation-mark-icon.tsx
916
- const ExclamationMarkIcon = ({ className, style }) => /* @__PURE__ */ jsxs("svg", {
917
- xmlns: "http://www.w3.org/2000/svg",
918
- width: "24",
919
- height: "24",
920
- viewBox: "0 0 24 24",
921
- fill: "none",
922
- stroke: "currentColor",
923
- strokeWidth: "2",
924
- strokeLinecap: "round",
925
- strokeLinejoin: "round",
926
- className: `lucide lucide-circle-alert ${className ? className : ""}`,
927
- style,
928
- children: [
929
- /* @__PURE__ */ jsx("circle", {
930
- cx: "12",
931
- cy: "12",
932
- r: "10"
933
- }),
934
- /* @__PURE__ */ jsx("line", {
935
- x1: "12",
936
- x2: "12",
937
- y1: "8",
938
- y2: "12"
939
- }),
940
- /* @__PURE__ */ jsx("line", {
941
- x1: "12",
942
- x2: "12.01",
943
- y1: "16",
944
- y2: "16"
945
- })
946
- ]
947
- });
948
-
949
- //#endregion
950
- //#region src/components/error-boundary/error-utils.tsx
951
- function ErrorToast({ errors }) {
952
- return /* @__PURE__ */ jsxs("div", {
953
- style: {
954
- fontSize: "13px",
955
- maxWidth: "600px"
956
- },
957
- children: [errors.map((error, idx) => {
958
- const message = ("extensions" in error ? error.extensions?.originalError : {})?.message ?? error.message;
959
- const code = "extensions" in error ? error.extensions?.code : null;
960
- return /* @__PURE__ */ jsxs("div", {
961
- style: {
962
- marginTop: idx === 0 ? 0 : 10,
963
- marginBottom: 14
964
- },
965
- children: [
966
- /* @__PURE__ */ jsx(ExclamationMarkIcon, { style: { marginBottom: 4 } }),
967
- code && /* @__PURE__ */ jsxs("div", {
968
- style: {
969
- fontWeight: "600",
970
- marginBottom: 4
971
- },
972
- children: [
973
- "Copilot Runtime Error:",
974
- " ",
975
- /* @__PURE__ */ jsx("span", {
976
- style: {
977
- fontFamily: "monospace",
978
- fontWeight: "normal"
979
- },
980
- children: code
981
- })
982
- ]
983
- }),
984
- /* @__PURE__ */ jsx(ReactMarkdown, { children: message })
985
- ]
986
- }, idx);
987
- }), /* @__PURE__ */ jsx("div", {
988
- style: {
989
- fontSize: "11px",
990
- opacity: .75
991
- },
992
- children: "NOTE: This error only displays during local development."
993
- })]
994
- });
995
- }
996
- function useErrorToast() {
997
- const { addToast } = useToast();
998
- return useCallback((errors) => {
999
- addToast({
1000
- type: "error",
1001
- id: errors.map((err) => {
1002
- const message = "extensions" in err ? (err.extensions?.originalError)?.message || err.message : err.message;
1003
- const stack = err.stack || "";
1004
- return btoa(message + stack).slice(0, 32);
1005
- }).join("|"),
1006
- message: /* @__PURE__ */ jsx(ErrorToast, { errors })
1007
- });
1008
- }, [addToast]);
1009
- }
1010
- function useAsyncCallback(callback, deps) {
1011
- const addErrorToast = useErrorToast();
1012
- return useCallback(async (...args) => {
1013
- try {
1014
- return await callback(...args);
1015
- } catch (error) {
1016
- console.error("Error in async callback:", error);
1017
- addErrorToast([error]);
1018
- throw error;
1019
- }
1020
- }, deps);
1021
- }
1022
-
1023
- //#endregion
1024
- //#region src/components/error-boundary/error-boundary.tsx
1025
- const statusChecker = new StatusChecker();
1026
- var CopilotErrorBoundary = class extends React.Component {
1027
- constructor(props) {
1028
- super(props);
1029
- this.state = { hasError: false };
1030
- }
1031
- static getDerivedStateFromError(error) {
1032
- return {
1033
- hasError: true,
1034
- error
1035
- };
1036
- }
1037
- componentDidMount() {
1038
- if (this.props.publicApiKey) statusChecker.start(this.props.publicApiKey, (newStatus) => {
1039
- this.setState((prevState) => {
1040
- if (newStatus?.severity !== prevState.status?.severity) return { status: newStatus ?? void 0 };
1041
- return null;
1042
- });
1043
- });
1044
- }
1045
- componentWillUnmount() {
1046
- statusChecker.stop();
1047
- }
1048
- componentDidCatch(error, errorInfo) {
1049
- console.error("CopilotKit Error:", error, errorInfo);
1050
- }
1051
- render() {
1052
- if (this.state.hasError) {
1053
- if (this.state.error instanceof CopilotKitError) return /* @__PURE__ */ jsxs(Fragment$1, { children: [this.props.children, this.props.showUsageBanner && /* @__PURE__ */ jsx(UsageBanner, {
1054
- severity: this.state.status?.severity ?? this.state.error.severity,
1055
- message: this.state.status?.message ?? this.state.error.message,
1056
- actions: getErrorActions(this.state.error)
1057
- })] });
1058
- throw this.state.error;
1059
- }
1060
- return this.props.children;
1061
- }
1062
- };
1063
-
1064
- //#endregion
1065
- //#region src/context/coagent-state-renders-context.tsx
1066
- const CoAgentStateRendersContext = createContext(void 0);
1067
- function CoAgentStateRendersProvider({ children }) {
1068
- const [coAgentStateRenders, setCoAgentStateRenders] = useState({});
1069
- const setCoAgentStateRender = useCallback((id, stateRender) => {
1070
- setCoAgentStateRenders((prevPoints) => ({
1071
- ...prevPoints,
1072
- [id]: stateRender
1073
- }));
1074
- }, []);
1075
- const removeCoAgentStateRender = useCallback((id) => {
1076
- setCoAgentStateRenders((prevPoints) => {
1077
- const newPoints = { ...prevPoints };
1078
- delete newPoints[id];
1079
- return newPoints;
1080
- });
1081
- }, []);
1082
- const claimsRef = useRef({});
1083
- return /* @__PURE__ */ jsx(CoAgentStateRendersContext.Provider, {
1084
- value: {
1085
- coAgentStateRenders,
1086
- setCoAgentStateRender,
1087
- removeCoAgentStateRender,
1088
- claimsRef
1089
- },
1090
- children
1091
- });
1092
- }
1093
- function useCoAgentStateRenders() {
1094
- const context = useContext(CoAgentStateRendersContext);
1095
- if (!context) throw new Error("useCoAgentStateRenders must be used within CoAgentStateRendersProvider");
1096
- return context;
1097
- }
1098
-
1099
- //#endregion
1100
- //#region src/context/threads-context.tsx
1101
- const ThreadsContext = createContext(void 0);
1102
- function ThreadsProvider({ children, threadId: explicitThreadId }) {
1103
- const [internalThreadId, setThreadId] = useState(() => randomUUID());
1104
- const threadId = explicitThreadId ?? internalThreadId;
1105
- return /* @__PURE__ */ jsx(ThreadsContext.Provider, {
1106
- value: {
1107
- threadId,
1108
- setThreadId
1109
- },
1110
- children
1111
- });
1112
- }
1113
- function useThreads() {
1114
- const context = useContext(ThreadsContext);
1115
- if (!context) throw new Error("useThreads must be used within ThreadsProvider");
1116
- return context;
1117
- }
1118
-
1119
- //#endregion
1120
- //#region src/hooks/use-coagent-state-render-bridge.helpers.ts
1121
- let RenderStatus = /* @__PURE__ */ function(RenderStatus) {
1122
- RenderStatus["InProgress"] = "inProgress";
1123
- RenderStatus["Complete"] = "complete";
1124
- return RenderStatus;
1125
- }({});
1126
- let ClaimAction = /* @__PURE__ */ function(ClaimAction) {
1127
- ClaimAction["Create"] = "create";
1128
- ClaimAction["Override"] = "override";
1129
- ClaimAction["Existing"] = "existing";
1130
- ClaimAction["Block"] = "block";
1131
- return ClaimAction;
1132
- }({});
1133
- function getStateWithoutConstantKeys(state) {
1134
- if (!state) return {};
1135
- const { messages, tools, copilotkit, ...stateWithoutConstantKeys } = state;
1136
- return stateWithoutConstantKeys;
1137
- }
1138
- function areStatesEquals(a, b) {
1139
- if (a && !b || !a && b) return false;
1140
- const { messages, tools, copilotkit, ...aWithoutConstantKeys } = a;
1141
- const { messages: bMessages, tools: bTools, copilotkit: bCopilotkit, ...bWithoutConstantKeys } = b;
1142
- return JSON.stringify(aWithoutConstantKeys) === JSON.stringify(bWithoutConstantKeys);
1143
- }
1144
- function isPlaceholderMessageId(messageId) {
1145
- return !!messageId && messageId.startsWith("coagent-state-render-");
1146
- }
1147
- function isPlaceholderMessageName(messageName) {
1148
- return messageName === "coagent-state-render";
1149
- }
1150
- function readCachedMessageEntry(entry) {
1151
- if (!entry || typeof entry !== "object") return {
1152
- snapshot: entry,
1153
- runId: void 0
1154
- };
1155
- return {
1156
- snapshot: "snapshot" in entry ? entry.snapshot : entry,
1157
- runId: "runId" in entry ? entry.runId : void 0
1158
- };
1159
- }
1160
- function getEffectiveRunId({ existingClaimRunId, cachedMessageRunId, runId }) {
1161
- return existingClaimRunId || cachedMessageRunId || runId || "pending";
1162
- }
1163
- /**
1164
- * Resolve whether a message can claim a render slot.
1165
- * This is a pure decision function; the caller applies claim mutations.
1166
- */
1167
- function resolveClaim({ claims, context, stateSnapshot }) {
1168
- const { messageId, stateRenderId, runId, messageIndex } = context;
1169
- const existing = claims[messageId];
1170
- if (existing) {
1171
- const canRender = existing.stateRenderId === stateRenderId;
1172
- const shouldUpdateRunId = canRender && runId && (!existing.runId || existing.runId === "pending");
1173
- return {
1174
- canRender,
1175
- action: canRender ? ClaimAction.Existing : ClaimAction.Block,
1176
- updateRunId: shouldUpdateRunId ? runId : void 0
1177
- };
1178
- }
1179
- const normalizedRunId = runId ?? "pending";
1180
- const renderClaimedByOtherMessageEntry = Object.entries(claims).find(([, claim]) => claim.stateRenderId === stateRenderId && (claim.runId ?? "pending") === normalizedRunId && dataToUUID(getStateWithoutConstantKeys(claim.stateSnapshot)) === dataToUUID(getStateWithoutConstantKeys(stateSnapshot)));
1181
- const renderClaimedByOtherMessage = renderClaimedByOtherMessageEntry?.[1];
1182
- const claimedMessageId = renderClaimedByOtherMessageEntry?.[0];
1183
- if (renderClaimedByOtherMessage) {
1184
- if (messageIndex !== void 0 && renderClaimedByOtherMessage.messageIndex !== void 0 && messageIndex > renderClaimedByOtherMessage.messageIndex) return {
1185
- canRender: true,
1186
- action: ClaimAction.Override,
1187
- nextClaim: {
1188
- stateRenderId,
1189
- runId,
1190
- messageIndex
1191
- },
1192
- lockOthers: runId === renderClaimedByOtherMessage.runId || isPlaceholderMessageId(claimedMessageId)
1193
- };
1194
- if (runId && renderClaimedByOtherMessage.runId && runId !== renderClaimedByOtherMessage.runId) return {
1195
- canRender: true,
1196
- action: ClaimAction.Override,
1197
- nextClaim: {
1198
- stateRenderId,
1199
- runId,
1200
- messageIndex
1201
- },
1202
- lockOthers: isPlaceholderMessageId(claimedMessageId)
1203
- };
1204
- if (isPlaceholderMessageId(claimedMessageId)) return {
1205
- canRender: true,
1206
- action: ClaimAction.Override,
1207
- nextClaim: {
1208
- stateRenderId,
1209
- runId,
1210
- messageIndex
1211
- },
1212
- lockOthers: true
1213
- };
1214
- if (stateSnapshot && renderClaimedByOtherMessage.stateSnapshot && !areStatesEquals(renderClaimedByOtherMessage.stateSnapshot, stateSnapshot)) return {
1215
- canRender: true,
1216
- action: ClaimAction.Override,
1217
- nextClaim: {
1218
- stateRenderId,
1219
- runId
1220
- }
1221
- };
1222
- return {
1223
- canRender: false,
1224
- action: ClaimAction.Block
1225
- };
1226
- }
1227
- if (!runId) return {
1228
- canRender: false,
1229
- action: ClaimAction.Block
1230
- };
1231
- return {
1232
- canRender: true,
1233
- action: ClaimAction.Create,
1234
- nextClaim: {
1235
- stateRenderId,
1236
- runId,
1237
- messageIndex
1238
- }
1239
- };
1240
- }
1241
- /**
1242
- * Select the best snapshot to render for this message.
1243
- * Priority order is:
1244
- * 1) explicit message snapshot
1245
- * 2) live agent state (latest assistant only)
1246
- * 3) cached snapshot for message
1247
- * 4) cached snapshot for stateRenderId+runId
1248
- * 5) last cached snapshot for stateRenderId
1249
- */
1250
- function selectSnapshot({ messageId, messageName, allowLiveState, skipLatestCache, stateRenderId, effectiveRunId, stateSnapshotProp, agentState, agentMessages, existingClaim, caches }) {
1251
- const lastAssistantId = agentMessages ? [...agentMessages].reverse().find((msg) => msg.role === "assistant")?.id : void 0;
1252
- const latestSnapshot = stateRenderId !== void 0 ? caches.byStateRenderAndRun[`${stateRenderId}::latest`] : void 0;
1253
- const messageIndex = agentMessages ? agentMessages.findIndex((msg) => msg.id === messageId) : -1;
1254
- const messageRole = messageIndex >= 0 && agentMessages ? agentMessages[messageIndex]?.role : void 0;
1255
- let previousUserMessageId;
1256
- if (messageIndex > 0 && agentMessages) {
1257
- for (let i = messageIndex - 1; i >= 0; i -= 1) if (agentMessages[i]?.role === "user") {
1258
- previousUserMessageId = agentMessages[i]?.id;
1259
- break;
1260
- }
1261
- }
1262
- const liveStateIsStale = stateSnapshotProp === void 0 && latestSnapshot !== void 0 && agentState !== void 0 && areStatesEquals(latestSnapshot, agentState);
1263
- const shouldUseLiveState = (Boolean(allowLiveState) || !lastAssistantId || messageId === lastAssistantId) && !liveStateIsStale;
1264
- const snapshot = stateSnapshotProp ? parseJson(stateSnapshotProp, stateSnapshotProp) : shouldUseLiveState ? agentState : void 0;
1265
- const hasSnapshotKeys = !!(snapshot && Object.keys(snapshot).length > 0);
1266
- const allowEmptySnapshot = snapshot !== void 0 && !hasSnapshotKeys && (stateSnapshotProp !== void 0 || shouldUseLiveState);
1267
- const messageCacheEntry = caches.byMessageId[messageId];
1268
- const cachedMessageSnapshot = readCachedMessageEntry(messageCacheEntry).snapshot;
1269
- const cacheKey = stateRenderId !== void 0 ? `${stateRenderId}::${effectiveRunId}` : void 0;
1270
- let cachedSnapshot = cachedMessageSnapshot ?? caches.byMessageId[messageId];
1271
- if (cachedSnapshot === void 0 && cacheKey && caches.byStateRenderAndRun[cacheKey] !== void 0) cachedSnapshot = caches.byStateRenderAndRun[cacheKey];
1272
- if (cachedSnapshot === void 0 && stateRenderId && previousUserMessageId && caches.byStateRenderAndRun[`${stateRenderId}::pending:${previousUserMessageId}`] !== void 0) cachedSnapshot = caches.byStateRenderAndRun[`${stateRenderId}::pending:${previousUserMessageId}`];
1273
- if (cachedSnapshot === void 0 && !skipLatestCache && stateRenderId && messageRole !== "assistant" && (stateSnapshotProp !== void 0 || agentState && Object.keys(agentState).length > 0)) cachedSnapshot = caches.byStateRenderAndRun[`${stateRenderId}::latest`];
1274
- const snapshotForClaim = existingClaim?.locked ? existingClaim.stateSnapshot ?? cachedSnapshot : hasSnapshotKeys ? snapshot : existingClaim?.stateSnapshot ?? cachedSnapshot;
1275
- return {
1276
- snapshot,
1277
- hasSnapshotKeys,
1278
- cachedSnapshot,
1279
- allowEmptySnapshot,
1280
- snapshotForClaim
1281
- };
1282
- }
1283
-
1284
- //#endregion
1285
- //#region src/hooks/use-coagent-state-render-registry.ts
1286
- const LAST_SNAPSHOTS_BY_RENDER_AND_RUN = "__lastSnapshotsByStateRenderIdAndRun";
1287
- const LAST_SNAPSHOTS_BY_MESSAGE = "__lastSnapshotsByMessageId";
1288
- function getClaimsStore(claimsRef) {
1289
- return claimsRef.current;
1290
- }
1291
- function getSnapshotCaches(claimsRef) {
1292
- const store = getClaimsStore(claimsRef);
1293
- return {
1294
- byStateRenderAndRun: store[LAST_SNAPSHOTS_BY_RENDER_AND_RUN] ?? {},
1295
- byMessageId: store[LAST_SNAPSHOTS_BY_MESSAGE] ?? {}
1296
- };
1297
- }
1298
- function useStateRenderRegistry({ agentId, stateRenderId, message, messageIndex, stateSnapshot, agentState, agentMessages, claimsRef }) {
1299
- const store = getClaimsStore(claimsRef);
1300
- const runId = message.runId;
1301
- const cachedMessageEntry = store[LAST_SNAPSHOTS_BY_MESSAGE]?.[message.id];
1302
- const { runId: cachedMessageRunId } = readCachedMessageEntry(cachedMessageEntry);
1303
- const existingClaimRunId = claimsRef.current[message.id]?.runId;
1304
- const effectiveRunId = getEffectiveRunId({
1305
- existingClaimRunId,
1306
- cachedMessageRunId,
1307
- runId
1308
- });
1309
- useEffect(() => {
1310
- return () => {
1311
- const existingClaim = claimsRef.current[message.id];
1312
- if (existingClaim?.stateSnapshot && Object.keys(existingClaim.stateSnapshot).length > 0) {
1313
- const snapshotCache = { ...store[LAST_SNAPSHOTS_BY_RENDER_AND_RUN] ?? {} };
1314
- const cacheKey = `${existingClaim.stateRenderId}::${existingClaim.runId ?? "pending"}`;
1315
- snapshotCache[cacheKey] = existingClaim.stateSnapshot;
1316
- snapshotCache[`${existingClaim.stateRenderId}::latest`] = existingClaim.stateSnapshot;
1317
- store[LAST_SNAPSHOTS_BY_RENDER_AND_RUN] = snapshotCache;
1318
- const messageCache = { ...store[LAST_SNAPSHOTS_BY_MESSAGE] ?? {} };
1319
- messageCache[message.id] = {
1320
- snapshot: existingClaim.stateSnapshot,
1321
- runId: existingClaim.runId ?? effectiveRunId
1322
- };
1323
- store[LAST_SNAPSHOTS_BY_MESSAGE] = messageCache;
1324
- }
1325
- delete claimsRef.current[message.id];
1326
- };
1327
- }, [
1328
- claimsRef,
1329
- effectiveRunId,
1330
- message.id
1331
- ]);
1332
- if (!stateRenderId) return { canRender: false };
1333
- const caches = getSnapshotCaches(claimsRef);
1334
- const existingClaim = claimsRef.current[message.id];
1335
- const { snapshot, hasSnapshotKeys, allowEmptySnapshot, snapshotForClaim } = selectSnapshot({
1336
- messageId: message.id,
1337
- messageName: message.name,
1338
- allowLiveState: isPlaceholderMessageName(message.name) || isPlaceholderMessageId(message.id),
1339
- skipLatestCache: isPlaceholderMessageName(message.name) || isPlaceholderMessageId(message.id),
1340
- stateRenderId,
1341
- effectiveRunId,
1342
- stateSnapshotProp: stateSnapshot,
1343
- agentState,
1344
- agentMessages,
1345
- existingClaim,
1346
- caches
1347
- });
1348
- const resolution = resolveClaim({
1349
- claims: claimsRef.current,
1350
- context: {
1351
- agentId,
1352
- messageId: message.id,
1353
- stateRenderId,
1354
- runId: effectiveRunId,
1355
- messageIndex
1356
- },
1357
- stateSnapshot: snapshotForClaim
1358
- });
1359
- if (resolution.action === ClaimAction.Block) return { canRender: false };
1360
- if (resolution.updateRunId && claimsRef.current[message.id]) claimsRef.current[message.id].runId = resolution.updateRunId;
1361
- if (resolution.nextClaim) claimsRef.current[message.id] = resolution.nextClaim;
1362
- if (resolution.lockOthers) Object.entries(claimsRef.current).forEach(([id, claim]) => {
1363
- if (id !== message.id && claim.stateRenderId === stateRenderId) claim.locked = true;
1364
- });
1365
- if (existingClaim && !existingClaim.locked && agentMessages?.length) {
1366
- const indexInAgentMessages = agentMessages.findIndex((msg) => msg.id === message.id);
1367
- if (indexInAgentMessages >= 0 && indexInAgentMessages < agentMessages.length - 1) existingClaim.locked = true;
1368
- }
1369
- const existingSnapshot = claimsRef.current[message.id].stateSnapshot;
1370
- const snapshotChanged = stateSnapshot && existingSnapshot !== void 0 && !areStatesEquals(existingSnapshot, snapshot);
1371
- if (snapshot && (stateSnapshot || hasSnapshotKeys || allowEmptySnapshot) && (!claimsRef.current[message.id].locked || snapshotChanged)) {
1372
- if (!claimsRef.current[message.id].locked || snapshotChanged) {
1373
- claimsRef.current[message.id].stateSnapshot = snapshot;
1374
- const snapshotCache = { ...store[LAST_SNAPSHOTS_BY_RENDER_AND_RUN] ?? {} };
1375
- const cacheKey = `${stateRenderId}::${effectiveRunId}`;
1376
- snapshotCache[cacheKey] = snapshot;
1377
- snapshotCache[`${stateRenderId}::latest`] = snapshot;
1378
- store[LAST_SNAPSHOTS_BY_RENDER_AND_RUN] = snapshotCache;
1379
- const messageCache = { ...store[LAST_SNAPSHOTS_BY_MESSAGE] ?? {} };
1380
- messageCache[message.id] = {
1381
- snapshot,
1382
- runId: effectiveRunId
1383
- };
1384
- store[LAST_SNAPSHOTS_BY_MESSAGE] = messageCache;
1385
- if (stateSnapshot) claimsRef.current[message.id].locked = true;
1386
- }
1387
- } else if (snapshotForClaim) {
1388
- if (!claimsRef.current[message.id].stateSnapshot) {
1389
- claimsRef.current[message.id].stateSnapshot = snapshotForClaim;
1390
- const snapshotCache = { ...store[LAST_SNAPSHOTS_BY_RENDER_AND_RUN] ?? {} };
1391
- const cacheKey = `${stateRenderId}::${effectiveRunId}`;
1392
- snapshotCache[cacheKey] = snapshotForClaim;
1393
- snapshotCache[`${stateRenderId}::latest`] = snapshotForClaim;
1394
- store[LAST_SNAPSHOTS_BY_RENDER_AND_RUN] = snapshotCache;
1395
- const messageCache = { ...store[LAST_SNAPSHOTS_BY_MESSAGE] ?? {} };
1396
- messageCache[message.id] = {
1397
- snapshot: snapshotForClaim,
1398
- runId: effectiveRunId
1399
- };
1400
- store[LAST_SNAPSHOTS_BY_MESSAGE] = messageCache;
1401
- }
1402
- }
1403
- return { canRender: true };
1404
- }
1405
-
1406
- //#endregion
1407
- //#region src/hooks/use-coagent-state-render-bridge.tsx
1408
- function useCoagentStateRenderBridge(agentId, props) {
1409
- const { stateSnapshot, message } = props;
1410
- const { coAgentStateRenders, claimsRef } = useCoAgentStateRenders();
1411
- const { agent } = useAgent({ agentId });
1412
- const [nodeName, setNodeName] = useState(void 0);
1413
- const [, forceUpdate] = useState(0);
1414
- useEffect(() => {
1415
- if (!agent) return;
1416
- const { unsubscribe } = agent.subscribe({
1417
- onStateChanged: () => {
1418
- forceUpdate((value) => value + 1);
1419
- },
1420
- onStepStartedEvent: ({ event }) => {
1421
- if (event.stepName !== nodeName) setNodeName(event.stepName);
1422
- },
1423
- onStepFinishedEvent: ({ event }) => {
1424
- if (event.stepName === nodeName) setNodeName(void 0);
1425
- }
1426
- });
1427
- return () => {
1428
- unsubscribe();
1429
- };
1430
- }, [agentId, nodeName]);
1431
- const getStateRender = useCallback((messageId) => {
1432
- return Object.entries(coAgentStateRenders).find(([stateRenderId, stateRender]) => {
1433
- if (claimsRef.current[messageId]) return stateRenderId === claimsRef.current[messageId].stateRenderId;
1434
- const matchingAgentName = stateRender.name === agentId;
1435
- const matchesNodeContext = stateRender.nodeName ? stateRender.nodeName === nodeName : true;
1436
- return matchingAgentName && matchesNodeContext;
1437
- });
1438
- }, [
1439
- coAgentStateRenders,
1440
- nodeName,
1441
- agentId
1442
- ]);
1443
- const stateRenderEntry = useMemo(() => getStateRender(message.id), [getStateRender, message.id]);
1444
- const stateRenderId = stateRenderEntry?.[0];
1445
- const stateRender = stateRenderEntry?.[1];
1446
- const { canRender } = useStateRenderRegistry({
1447
- agentId,
1448
- stateRenderId,
1449
- message: {
1450
- ...message,
1451
- runId: props.runId ?? message.runId
1452
- },
1453
- messageIndex: props.messageIndex,
1454
- stateSnapshot,
1455
- agentState: agent?.state,
1456
- agentMessages: agent?.messages,
1457
- claimsRef
1458
- });
1459
- return useMemo(() => {
1460
- if (!stateRender || !stateRenderId) return null;
1461
- if (!canRender) return null;
1462
- if (stateRender.handler) stateRender.handler({
1463
- state: stateSnapshot ? parseJson(stateSnapshot, stateSnapshot) : agent?.state ?? {},
1464
- nodeName: nodeName ?? ""
1465
- });
1466
- if (stateRender.render) {
1467
- const status = agent?.isRunning ? RenderStatus.InProgress : RenderStatus.Complete;
1468
- if (typeof stateRender.render === "string") return stateRender.render;
1469
- return stateRender.render({
1470
- status,
1471
- state: claimsRef.current[message.id].stateSnapshot ?? {},
1472
- nodeName: nodeName ?? ""
1473
- });
1474
- }
1475
- }, [
1476
- stateRender,
1477
- stateRenderId,
1478
- agent?.state,
1479
- agent?.isRunning,
1480
- nodeName,
1481
- message.id,
1482
- stateSnapshot,
1483
- canRender
1484
- ]);
1485
- }
1486
- function CoAgentStateRenderBridge(props) {
1487
- return useCoagentStateRenderBridge(props.agentId, props);
1488
- }
1489
-
1490
- //#endregion
1491
- //#region src/components/CopilotListeners.tsx
1492
- const usePredictStateSubscription = (agent) => {
1493
- const predictStateToolsRef = useRef([]);
1494
- const getSubscriber = useCallback((agent) => ({
1495
- onCustomEvent: ({ event }) => {
1496
- if (event.name === "PredictState") predictStateToolsRef.current = event.value;
1497
- },
1498
- onToolCallArgsEvent: ({ partialToolCallArgs, toolCallName }) => {
1499
- predictStateToolsRef.current.forEach((t) => {
1500
- if (t?.tool !== toolCallName) return;
1501
- const emittedState = typeof partialToolCallArgs === "string" ? parseJson(partialToolCallArgs, partialToolCallArgs) : partialToolCallArgs;
1502
- agent.setState({ [t.state_key]: emittedState[t.state_key] });
1503
- });
1504
- }
1505
- }), []);
1506
- useEffect(() => {
1507
- if (!agent) return;
1508
- const subscriber = getSubscriber(agent);
1509
- const { unsubscribe } = agent.subscribe(subscriber);
1510
- return () => {
1511
- unsubscribe();
1512
- };
1513
- }, [agent, getSubscriber]);
1514
- };
1515
- function CopilotListeners() {
1516
- const { copilotkit } = useCopilotKit();
1517
- const resolvedAgentId = useCopilotChatConfiguration()?.agentId;
1518
- const { setBannerError } = useToast();
1519
- const { agent } = useAgent({ agentId: resolvedAgentId });
1520
- usePredictStateSubscription(agent);
1521
- useEffect(() => {
1522
- const subscription = copilotkit.subscribe({ onError: ({ error }) => {
1523
- setBannerError(new CopilotKitLowLevelError({
1524
- error,
1525
- message: error.message,
1526
- url: typeof window !== "undefined" ? window.location.href : ""
1527
- }));
1528
- } });
1529
- return () => {
1530
- subscription.unsubscribe();
1531
- };
1532
- }, [copilotkit?.subscribe]);
1533
- return null;
1534
- }
1535
-
1536
- //#endregion
1537
- //#region src/components/copilot-provider/copilotkit.tsx
1538
- /**
1539
- * This component will typically wrap your entire application (or a sub-tree of your application where you want to have a copilot). It provides the copilot context to all other components and hooks.
1540
- *
1541
- * ## Example
1542
- *
1543
- * You can find more information about self-hosting CopilotKit [here](/guides/self-hosting).
1544
- *
1545
- * ```tsx
1546
- * import { CopilotKit } from "@copilotkit/react-core";
1547
- *
1548
- * <CopilotKit runtimeUrl="<your-runtime-url>">
1549
- * // ... your app ...
1550
- * </CopilotKit>
1551
- * ```
1552
- */
1553
- function CopilotKit({ children, ...props }) {
1554
- const enabled = shouldShowDevConsole(props.showDevConsole);
1555
- const showInspector = shouldShowDevConsole(props.enableInspector);
1556
- const publicApiKey = props.publicApiKey || props.publicLicenseKey;
1557
- const renderArr = useMemo(() => [{ render: CoAgentStateRenderBridge }], []);
1558
- return /* @__PURE__ */ jsx(ToastProvider, {
1559
- enabled,
1560
- children: /* @__PURE__ */ jsx(CopilotErrorBoundary, {
1561
- publicApiKey,
1562
- showUsageBanner: enabled,
1563
- children: /* @__PURE__ */ jsx(ThreadsProvider, {
1564
- threadId: props.threadId,
1565
- children: /* @__PURE__ */ jsx(CopilotKitProvider, {
1566
- ...props,
1567
- showDevConsole: showInspector,
1568
- renderCustomMessages: renderArr,
1569
- useSingleEndpoint: props.useSingleEndpoint ?? true,
1570
- children: /* @__PURE__ */ jsx(CopilotKitInternal, {
1571
- ...props,
1572
- children
1573
- })
1574
- })
1575
- })
1576
- })
1577
- });
1578
- }
1579
- /**
1580
- * Bridge component that subscribes to v2.x copilotkit core error events
1581
- * and forwards them to v1.x error handling system.
1582
- * This ensures only ONE subscription exists regardless of how many times
1583
- * Chat components are rendered.
1584
- */
1585
- function CopilotKitErrorBridge() {
1586
- const { copilotkit } = useCopilotKit();
1587
- const { onError, copilotApiConfig } = useCopilotContext();
1588
- useEffect(() => {
1589
- if (!copilotkit) return;
1590
- const subscription = copilotkit.subscribe({ onError: async (event) => {
1591
- const errorEvent = {
1592
- type: "error",
1593
- timestamp: Date.now(),
1594
- context: {
1595
- source: "agent",
1596
- request: {
1597
- operation: event.code || "unknown",
1598
- url: copilotApiConfig?.chatApiEndpoint,
1599
- startTime: Date.now()
1600
- },
1601
- technical: {
1602
- environment: "browser",
1603
- userAgent: typeof navigator !== "undefined" ? navigator.userAgent : void 0,
1604
- stackTrace: event.error.stack
1605
- },
1606
- ...event.context
1607
- },
1608
- error: event.error
1609
- };
1610
- try {
1611
- await onError(errorEvent);
1612
- } catch (handlerError) {
1613
- console.error("Error in onError handler:", handlerError);
1614
- }
1615
- } });
1616
- return () => {
1617
- subscription.unsubscribe();
1618
- };
1619
- }, [
1620
- copilotkit,
1621
- onError,
1622
- copilotApiConfig
1623
- ]);
1624
- return null;
1625
- }
1626
- function CopilotKitInternal(cpkProps) {
1627
- const { children, ...props } = cpkProps;
1628
- /**
1629
- * This will throw an error if the props are invalid.
1630
- */
1631
- validateProps(cpkProps);
1632
- const publicApiKey = props.publicLicenseKey || props.publicApiKey;
1633
- const chatApiEndpoint = props.runtimeUrl || COPILOT_CLOUD_CHAT_URL;
1634
- const [actions, setActions] = useState({});
1635
- const [registeredActionConfigs, setRegisteredActionConfigs] = useState(/* @__PURE__ */ new Map());
1636
- const chatComponentsCache = useRef({
1637
- actions: {},
1638
- coAgentStateRenders: {}
1639
- });
1640
- const { addElement, removeElement, printTree, getAllElements } = useTree();
1641
- const [isLoading, setIsLoading] = useState(false);
1642
- const [chatInstructions, setChatInstructions] = useState("");
1643
- const [authStates, setAuthStates] = useState({});
1644
- const [extensions, setExtensions] = useState({});
1645
- const [additionalInstructions, setAdditionalInstructions] = useState([]);
1646
- const { addElement: addDocument, removeElement: removeDocument, allElements: allDocuments } = useFlatCategoryStore();
1647
- const setAction = useCallback((id, action) => {
1648
- setActions((prevPoints) => {
1649
- return {
1650
- ...prevPoints,
1651
- [id]: action
1652
- };
1653
- });
1654
- }, []);
1655
- const removeAction = useCallback((id) => {
1656
- setActions((prevPoints) => {
1657
- const newPoints = { ...prevPoints };
1658
- delete newPoints[id];
1659
- return newPoints;
1660
- });
1661
- }, []);
1662
- const getContextString = useCallback((documents, categories) => {
1663
- return `${documents.map((document) => {
1664
- return `${document.name} (${document.sourceApplication}):\n${document.getContents()}`;
1665
- }).join("\n\n")}\n\n${printTree(categories)}`;
1666
- }, [printTree]);
1667
- const addContext = useCallback((context, parentId, categories = defaultCopilotContextCategories) => {
1668
- return addElement(context, categories, parentId);
1669
- }, [addElement]);
1670
- const removeContext = useCallback((id) => {
1671
- removeElement(id);
1672
- }, [removeElement]);
1673
- const getAllContext = useCallback(() => {
1674
- return getAllElements();
1675
- }, [getAllElements]);
1676
- const getFunctionCallHandler = useCallback((customEntryPoints) => {
1677
- return entryPointsToFunctionCallHandler(Object.values(customEntryPoints || actions));
1678
- }, [actions]);
1679
- const getDocumentsContext = useCallback((categories) => {
1680
- return allDocuments(categories);
1681
- }, [allDocuments]);
1682
- const addDocumentContext = useCallback((documentPointer, categories = defaultCopilotContextCategories) => {
1683
- return addDocument(documentPointer, categories);
1684
- }, [addDocument]);
1685
- const removeDocumentContext = useCallback((documentId) => {
1686
- removeDocument(documentId);
1687
- }, [removeDocument]);
1688
- const copilotApiConfig = useMemo(() => {
1689
- let cloud = void 0;
1690
- if (publicApiKey) cloud = { guardrails: { input: { restrictToTopic: {
1691
- enabled: Boolean(props.guardrails_c),
1692
- validTopics: props.guardrails_c?.validTopics || [],
1693
- invalidTopics: props.guardrails_c?.invalidTopics || []
1694
- } } } };
1695
- return {
1696
- publicApiKey,
1697
- ...cloud ? { cloud } : {},
1698
- chatApiEndpoint,
1699
- headers: props.headers || {},
1700
- properties: props.properties || {},
1701
- transcribeAudioUrl: props.transcribeAudioUrl,
1702
- textToSpeechUrl: props.textToSpeechUrl,
1703
- credentials: props.credentials
1704
- };
1705
- }, [
1706
- publicApiKey,
1707
- props.headers,
1708
- props.properties,
1709
- props.transcribeAudioUrl,
1710
- props.textToSpeechUrl,
1711
- props.credentials,
1712
- props.cloudRestrictToTopic,
1713
- props.guardrails_c
1714
- ]);
1715
- useMemo(() => {
1716
- const authHeaders = Object.values(authStates || {}).reduce((acc, state) => {
1717
- if (state.status === "authenticated" && state.authHeaders) return {
1718
- ...acc,
1719
- ...Object.entries(state.authHeaders).reduce((headers, [key, value]) => ({
1720
- ...headers,
1721
- [key.startsWith("X-Custom-") ? key : `X-Custom-${key}`]: value
1722
- }), {})
1723
- };
1724
- return acc;
1725
- }, {});
1726
- return {
1727
- ...copilotApiConfig.headers || {},
1728
- ...copilotApiConfig.publicApiKey ? { [COPILOT_CLOUD_PUBLIC_API_KEY_HEADER]: copilotApiConfig.publicApiKey } : {},
1729
- ...authHeaders
1730
- };
1731
- }, [
1732
- copilotApiConfig.headers,
1733
- copilotApiConfig.publicApiKey,
1734
- authStates
1735
- ]);
1736
- const [internalErrorHandlers, _setInternalErrorHandler] = useState({});
1737
- const setInternalErrorHandler = useCallback((handler) => {
1738
- _setInternalErrorHandler((prev) => ({
1739
- ...prev,
1740
- ...handler
1741
- }));
1742
- }, []);
1743
- const removeInternalErrorHandler = useCallback((key) => {
1744
- _setInternalErrorHandler((prev) => {
1745
- const { [key]: _removed, ...rest } = prev;
1746
- return rest;
1747
- });
1748
- }, []);
1749
- const onErrorRef = useRef(props.onError);
1750
- useEffect(() => {
1751
- onErrorRef.current = props.onError;
1752
- }, [props.onError]);
1753
- const internalHandlersRef = useRef({});
1754
- useEffect(() => {
1755
- internalHandlersRef.current = internalErrorHandlers;
1756
- }, [internalErrorHandlers]);
1757
- const handleErrors = useCallback(async (error) => {
1758
- if (copilotApiConfig.publicApiKey && onErrorRef.current) try {
1759
- await onErrorRef.current(error);
1760
- } catch (e) {
1761
- console.error("Error in public onError handler:", e);
1762
- }
1763
- const handlers = Object.values(internalHandlersRef.current);
1764
- await Promise.all(handlers.map((h) => Promise.resolve(h(error)).catch((e) => console.error("Error in internal error handler:", e))));
1765
- }, [copilotApiConfig.publicApiKey]);
1766
- const [chatSuggestionConfiguration, setChatSuggestionConfiguration] = useState({});
1767
- const addChatSuggestionConfiguration = useCallback((id, suggestion) => {
1768
- setChatSuggestionConfiguration((prev) => ({
1769
- ...prev,
1770
- [id]: suggestion
1771
- }));
1772
- }, [setChatSuggestionConfiguration]);
1773
- const removeChatSuggestionConfiguration = useCallback((id) => {
1774
- setChatSuggestionConfiguration((prev) => {
1775
- const { [id]: _, ...rest } = prev;
1776
- return rest;
1777
- });
1778
- }, [setChatSuggestionConfiguration]);
1779
- const [availableAgents, setAvailableAgents] = useState([]);
1780
- const [coagentStates, setCoagentStates] = useState({});
1781
- const coagentStatesRef = useRef({});
1782
- const setCoagentStatesWithRef = useCallback((value) => {
1783
- const newValue = typeof value === "function" ? value(coagentStatesRef.current) : value;
1784
- coagentStatesRef.current = newValue;
1785
- setCoagentStates((prev) => {
1786
- return newValue;
1787
- });
1788
- }, []);
1789
- let initialAgentSession = null;
1790
- if (props.agent) initialAgentSession = { agentName: props.agent };
1791
- const [agentSession, setAgentSession] = useState(initialAgentSession);
1792
- useEffect(() => {
1793
- if (props.agent) setAgentSession({ agentName: props.agent });
1794
- else setAgentSession(null);
1795
- }, [props.agent]);
1796
- const { threadId, setThreadId: setInternalThreadId } = useThreads();
1797
- const setThreadId = useCallback((value) => {
1798
- if (props.threadId) throw new Error("Cannot call setThreadId() when threadId is provided via props.");
1799
- setInternalThreadId(value);
1800
- }, [props.threadId]);
1801
- const [runId, setRunId] = useState(null);
1802
- const chatAbortControllerRef = useRef(null);
1803
- const showDevConsole = shouldShowDevConsole(props.showDevConsole);
1804
- const [interruptActions, _setInterruptActions] = useState({});
1805
- const setInterruptAction = useCallback((action) => {
1806
- _setInterruptActions((prev) => {
1807
- if (action == null || !action.id) return prev;
1808
- return {
1809
- ...prev,
1810
- [action.id]: {
1811
- ...prev[action.id] ?? {},
1812
- ...action
1813
- }
1814
- };
1815
- });
1816
- }, []);
1817
- const removeInterruptAction = useCallback((actionId) => {
1818
- _setInterruptActions((prev) => {
1819
- const { [actionId]: _, ...rest } = prev;
1820
- return rest;
1821
- });
1822
- }, []);
1823
- const [interruptEventQueue, setInterruptEventQueue] = useState({});
1824
- const addInterruptEvent = useCallback((queuedEvent) => {
1825
- setInterruptEventQueue((prev) => {
1826
- const threadQueue = prev[queuedEvent.threadId] || [];
1827
- return {
1828
- ...prev,
1829
- [queuedEvent.threadId]: [...threadQueue, queuedEvent]
1830
- };
1831
- });
1832
- }, []);
1833
- const resolveInterruptEvent = useCallback((threadId, eventId, response) => {
1834
- setInterruptEventQueue((prev) => {
1835
- const threadQueue = prev[threadId] || [];
1836
- return {
1837
- ...prev,
1838
- [threadId]: threadQueue.map((queuedEvent) => queuedEvent.eventId === eventId ? {
1839
- ...queuedEvent,
1840
- event: {
1841
- ...queuedEvent.event,
1842
- response
1843
- }
1844
- } : queuedEvent)
1845
- };
1846
- });
1847
- }, []);
1848
- const memoizedChildren = useMemo(() => children, [children]);
1849
- const [bannerError, setBannerError] = useState(null);
1850
- const agentLock = useMemo(() => props.agent ?? null, [props.agent]);
1851
- const forwardedParameters = useMemo(() => props.forwardedParameters ?? {}, [props.forwardedParameters]);
1852
- const updateExtensions = useCallback((newExtensions) => {
1853
- setExtensions((prev) => {
1854
- const resolved = typeof newExtensions === "function" ? newExtensions(prev) : newExtensions;
1855
- return Object.keys(resolved).length === Object.keys(prev).length && Object.entries(resolved).every(([key, value]) => prev[key] === value) ? prev : resolved;
1856
- });
1857
- }, [setExtensions]);
1858
- const updateAuthStates = useCallback((newAuthStates) => {
1859
- setAuthStates((prev) => {
1860
- const resolved = typeof newAuthStates === "function" ? newAuthStates(prev) : newAuthStates;
1861
- return Object.keys(resolved).length === Object.keys(prev).length && Object.entries(resolved).every(([key, value]) => prev[key] === value) ? prev : resolved;
1862
- });
1863
- }, [setAuthStates]);
1864
- const handleSetRegisteredActions = useCallback((actionConfig) => {
1865
- const key = actionConfig.action.name || randomUUID();
1866
- setRegisteredActionConfigs((prev) => {
1867
- const newMap = new Map(prev);
1868
- newMap.set(key, actionConfig);
1869
- return newMap;
1870
- });
1871
- return key;
1872
- }, []);
1873
- const handleRemoveRegisteredAction = useCallback((actionKey) => {
1874
- setRegisteredActionConfigs((prev) => {
1875
- const newMap = new Map(prev);
1876
- newMap.delete(actionKey);
1877
- return newMap;
1878
- });
1879
- }, []);
1880
- const RegisteredActionsRenderer = useMemo(() => {
1881
- return () => /* @__PURE__ */ jsx(Fragment$1, { children: Array.from(registeredActionConfigs.entries()).map(([key, config]) => {
1882
- const Component = config.component;
1883
- return /* @__PURE__ */ jsx(Component, { action: config.action }, key);
1884
- }) });
1885
- }, [registeredActionConfigs]);
1886
- const copilotContextValue = useMemo(() => ({
1887
- actions,
1888
- chatComponentsCache,
1889
- getFunctionCallHandler,
1890
- setAction,
1891
- removeAction,
1892
- setRegisteredActions: handleSetRegisteredActions,
1893
- removeRegisteredAction: handleRemoveRegisteredAction,
1894
- getContextString,
1895
- addContext,
1896
- removeContext,
1897
- getAllContext,
1898
- getDocumentsContext,
1899
- addDocumentContext,
1900
- removeDocumentContext,
1901
- copilotApiConfig,
1902
- isLoading,
1903
- setIsLoading,
1904
- chatSuggestionConfiguration,
1905
- addChatSuggestionConfiguration,
1906
- removeChatSuggestionConfiguration,
1907
- chatInstructions,
1908
- setChatInstructions,
1909
- additionalInstructions,
1910
- setAdditionalInstructions,
1911
- showDevConsole,
1912
- coagentStates,
1913
- setCoagentStates,
1914
- coagentStatesRef,
1915
- setCoagentStatesWithRef,
1916
- agentSession,
1917
- setAgentSession,
1918
- forwardedParameters,
1919
- agentLock,
1920
- threadId,
1921
- setThreadId,
1922
- runId,
1923
- setRunId,
1924
- chatAbortControllerRef,
1925
- availableAgents,
1926
- authConfig_c: props.authConfig_c,
1927
- authStates_c: authStates,
1928
- setAuthStates_c: updateAuthStates,
1929
- extensions,
1930
- setExtensions: updateExtensions,
1931
- interruptActions,
1932
- setInterruptAction,
1933
- removeInterruptAction,
1934
- interruptEventQueue,
1935
- addInterruptEvent,
1936
- resolveInterruptEvent,
1937
- bannerError,
1938
- setBannerError,
1939
- onError: handleErrors,
1940
- internalErrorHandlers,
1941
- setInternalErrorHandler,
1942
- removeInternalErrorHandler
1943
- }), [
1944
- actions,
1945
- chatComponentsCache,
1946
- getFunctionCallHandler,
1947
- setAction,
1948
- removeAction,
1949
- handleSetRegisteredActions,
1950
- handleRemoveRegisteredAction,
1951
- getContextString,
1952
- addContext,
1953
- removeContext,
1954
- getAllContext,
1955
- getDocumentsContext,
1956
- addDocumentContext,
1957
- removeDocumentContext,
1958
- copilotApiConfig,
1959
- isLoading,
1960
- chatSuggestionConfiguration,
1961
- addChatSuggestionConfiguration,
1962
- removeChatSuggestionConfiguration,
1963
- chatInstructions,
1964
- additionalInstructions,
1965
- showDevConsole,
1966
- coagentStates,
1967
- setCoagentStatesWithRef,
1968
- agentSession,
1969
- setAgentSession,
1970
- forwardedParameters,
1971
- agentLock,
1972
- threadId,
1973
- setThreadId,
1974
- runId,
1975
- availableAgents,
1976
- props.authConfig_c,
1977
- authStates,
1978
- updateAuthStates,
1979
- extensions,
1980
- updateExtensions,
1981
- interruptActions,
1982
- setInterruptAction,
1983
- removeInterruptAction,
1984
- interruptEventQueue,
1985
- addInterruptEvent,
1986
- resolveInterruptEvent,
1987
- bannerError,
1988
- handleErrors,
1989
- internalErrorHandlers,
1990
- setInternalErrorHandler,
1991
- removeInternalErrorHandler
1992
- ]);
1993
- return /* @__PURE__ */ jsx(CopilotChatConfigurationProvider, {
1994
- agentId: props.agent ?? "default",
1995
- threadId,
1996
- children: /* @__PURE__ */ jsxs(CopilotContext.Provider, {
1997
- value: copilotContextValue,
1998
- children: [
1999
- /* @__PURE__ */ jsx(CopilotListeners, {}),
2000
- /* @__PURE__ */ jsx(CopilotKitErrorBridge, {}),
2001
- /* @__PURE__ */ jsxs(CoAgentStateRendersProvider, { children: [/* @__PURE__ */ jsx(MessagesTapProvider, { children: /* @__PURE__ */ jsxs(CopilotMessages, { children: [memoizedChildren, /* @__PURE__ */ jsx(RegisteredActionsRenderer, {})] }) }), bannerError && showDevConsole && /* @__PURE__ */ jsx(UsageBanner, {
2002
- severity: bannerError.severity,
2003
- message: bannerError.message,
2004
- onClose: () => setBannerError(null),
2005
- actions: getErrorActions(bannerError)
2006
- })] })
2007
- ]
2008
- })
2009
- });
2010
- }
2011
- const defaultCopilotContextCategories = ["global"];
2012
- function entryPointsToFunctionCallHandler(actions) {
2013
- return async ({ name, args }) => {
2014
- let actionsByFunctionName = {};
2015
- for (let action of actions) actionsByFunctionName[action.name] = action;
2016
- const action = actionsByFunctionName[name];
2017
- let result = void 0;
2018
- if (action) {
2019
- await new Promise((resolve, reject) => {
2020
- flushSync(async () => {
2021
- try {
2022
- result = await action.handler?.(args);
2023
- resolve();
2024
- } catch (error) {
2025
- reject(error);
2026
- }
2027
- });
2028
- });
2029
- await new Promise((resolve) => setTimeout(resolve, 20));
2030
- }
2031
- return result;
2032
- };
2033
- }
2034
- function formatFeatureName(featureName) {
2035
- return featureName.replace(/_c$/, "").split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
2036
- }
2037
- function validateProps(props) {
2038
- const cloudFeatures = Object.keys(props).filter((key) => key.endsWith("_c"));
2039
- const hasApiKey = props.publicApiKey || props.publicLicenseKey;
2040
- if (!props.runtimeUrl && !hasApiKey) throw new ConfigurationError("Missing required prop: 'runtimeUrl' or 'publicApiKey' or 'publicLicenseKey'");
2041
- if (cloudFeatures.length > 0 && !hasApiKey) throw new MissingPublicApiKeyError(`Missing required prop: 'publicApiKey' or 'publicLicenseKey' to use cloud features: ${cloudFeatures.map(formatFeatureName).join(", ")}`);
2042
- }
2043
-
2044
20
  //#endregion
2045
21
  //#region src/hooks/use-lazy-tool-renderer.tsx
2046
22
  function useLazyToolRenderer() {