@copilotkit/react-core 1.61.1 → 1.62.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/{copilotkit-UY-H6Kx7.mjs → copilotkit-BtRkFsNR.mjs} +1227 -599
- package/dist/copilotkit-BtRkFsNR.mjs.map +1 -0
- package/dist/{copilotkit-BCJDP8qd.cjs → copilotkit-CdpDZi3i.cjs} +1219 -585
- package/dist/copilotkit-CdpDZi3i.cjs.map +1 -0
- package/dist/{copilotkit-CEdu_aie.d.cts → copilotkit-Cga6AHO0.d.cts} +497 -209
- package/dist/copilotkit-Cga6AHO0.d.cts.map +1 -0
- package/dist/{copilotkit-M1FiciGd.d.mts → copilotkit-DnLpJ2Cl.d.mts} +497 -209
- package/dist/copilotkit-DnLpJ2Cl.d.mts.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +360 -270
- package/dist/index.umd.js.map +1 -1
- package/dist/v2/context.d.cts +5 -1
- package/dist/v2/context.d.cts.map +1 -1
- package/dist/v2/context.d.mts +5 -1
- package/dist/v2/context.d.mts.map +1 -1
- package/dist/v2/headless.cjs +323 -104
- package/dist/v2/headless.cjs.map +1 -1
- package/dist/v2/headless.d.cts +187 -69
- package/dist/v2/headless.d.cts.map +1 -1
- package/dist/v2/headless.d.mts +187 -69
- package/dist/v2/headless.d.mts.map +1 -1
- package/dist/v2/headless.mjs +325 -106
- package/dist/v2/headless.mjs.map +1 -1
- package/dist/v2/index.cjs +2 -1
- package/dist/v2/index.css +1 -1
- package/dist/v2/index.d.cts +2 -2
- package/dist/v2/index.d.mts +2 -2
- package/dist/v2/index.mjs +2 -2
- package/dist/v2/index.umd.js +1112 -484
- package/dist/v2/index.umd.js.map +1 -1
- package/package.json +8 -6
- package/dist/copilotkit-BCJDP8qd.cjs.map +0 -1
- package/dist/copilotkit-CEdu_aie.d.cts.map +0 -1
- package/dist/copilotkit-M1FiciGd.d.mts.map +0 -1
- package/dist/copilotkit-UY-H6Kx7.mjs.map +0 -1
|
@@ -48,6 +48,7 @@ let zod_to_json_schema = require("zod-to-json-schema");
|
|
|
48
48
|
let react_dom = require("react-dom");
|
|
49
49
|
let _tanstack_react_virtual = require("@tanstack/react-virtual");
|
|
50
50
|
let use_stick_to_bottom = require("use-stick-to-bottom");
|
|
51
|
+
let _copilotkit_web_components_threads_drawer = require("@copilotkit/web-components/threads-drawer");
|
|
51
52
|
let react_markdown = require("react-markdown");
|
|
52
53
|
react_markdown = __toESM(react_markdown);
|
|
53
54
|
|
|
@@ -174,6 +175,25 @@ const CopilotChatDefaultLabels = {
|
|
|
174
175
|
modalHeaderTitle: "CopilotKit Chat",
|
|
175
176
|
welcomeMessageText: "How can I help you today?"
|
|
176
177
|
};
|
|
178
|
+
/**
|
|
179
|
+
* Mobile breakpoint below which the chat modal and the thread-list drawer are
|
|
180
|
+
* mutually exclusive. At or above this width both surfaces may coexist. This
|
|
181
|
+
* mirrors the `(max-width: 767px)` / `(min-width: 768px)` split already used by
|
|
182
|
+
* CopilotChatInput and CopilotSidebarView.
|
|
183
|
+
*/
|
|
184
|
+
const MOBILE_MAX_WIDTH_PX = 767;
|
|
185
|
+
/**
|
|
186
|
+
* Reports whether the current viewport is in the mobile range (`<768px`), where
|
|
187
|
+
* the chat modal and drawer must not be open simultaneously. SSR-safe and
|
|
188
|
+
* defensive against environments without `matchMedia` (treated as desktop, so
|
|
189
|
+
* no mutual-exclusion constraint is applied).
|
|
190
|
+
*
|
|
191
|
+
* @returns `true` when the viewport is mobile-width, `false` otherwise.
|
|
192
|
+
*/
|
|
193
|
+
function isMobileViewport() {
|
|
194
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return false;
|
|
195
|
+
return window.matchMedia(`(max-width: ${MOBILE_MAX_WIDTH_PX}px)`).matches;
|
|
196
|
+
}
|
|
177
197
|
const CopilotChatConfiguration = (0, react.createContext)(null);
|
|
178
198
|
const CopilotChatConfigurationProvider = ({ children, labels, agentId, threadId, hasExplicitThreadId, isModalDefaultOpen }) => {
|
|
179
199
|
const parentConfig = (0, react.useContext)(CopilotChatConfiguration);
|
|
@@ -184,12 +204,22 @@ const CopilotChatConfigurationProvider = ({ children, labels, agentId, threadId,
|
|
|
184
204
|
...stableLabels
|
|
185
205
|
}), [stableLabels, parentConfig?.labels]);
|
|
186
206
|
const resolvedAgentId = agentId ?? parentConfig?.agentId ?? _copilotkit_shared.DEFAULT_AGENT_ID;
|
|
207
|
+
const threadIdPropIsAuthoritative = threadId !== void 0 && hasExplicitThreadId !== false;
|
|
208
|
+
const isThreadIdControlled = threadIdPropIsAuthoritative;
|
|
209
|
+
const [activeThreadOverride, setActiveThreadOverride] = (0, react.useState)(null);
|
|
187
210
|
const resolvedThreadId = (0, react.useMemo)(() => {
|
|
188
|
-
if (
|
|
211
|
+
if (threadIdPropIsAuthoritative) return threadId;
|
|
212
|
+
if (activeThreadOverride) return activeThreadOverride.threadId;
|
|
189
213
|
if (parentConfig?.threadId) return parentConfig.threadId;
|
|
214
|
+
if (threadId) return threadId;
|
|
190
215
|
return (0, _copilotkit_shared.randomUUID)();
|
|
191
|
-
}, [
|
|
192
|
-
|
|
216
|
+
}, [
|
|
217
|
+
threadIdPropIsAuthoritative,
|
|
218
|
+
threadId,
|
|
219
|
+
parentConfig?.threadId,
|
|
220
|
+
activeThreadOverride
|
|
221
|
+
]);
|
|
222
|
+
const resolvedHasExplicitThreadId = (threadIdPropIsAuthoritative ? true : activeThreadOverride?.explicit ?? hasExplicitThreadId ?? false) || !!parentConfig?.hasExplicitThreadId;
|
|
193
223
|
const [internalModalOpen, setInternalModalOpen] = (0, react.useState)(isModalDefaultOpen ?? true);
|
|
194
224
|
const hasExplicitDefault = isModalDefaultOpen !== void 0;
|
|
195
225
|
const setAndSync = (0, react.useCallback)((open) => {
|
|
@@ -208,20 +238,113 @@ const CopilotChatConfigurationProvider = ({ children, labels, agentId, threadId,
|
|
|
208
238
|
}, [parentConfig?.isModalOpen, hasExplicitDefault]);
|
|
209
239
|
const resolvedIsModalOpen = hasExplicitDefault ? internalModalOpen : parentConfig?.isModalOpen ?? internalModalOpen;
|
|
210
240
|
const resolvedSetModalOpen = hasExplicitDefault ? setAndSync : parentConfig?.setModalOpen ?? setInternalModalOpen;
|
|
241
|
+
const [ownDrawerOpen, setOwnDrawerOpen] = (0, react.useState)(false);
|
|
242
|
+
const [ownDrawerCount, setOwnDrawerCount] = (0, react.useState)(0);
|
|
243
|
+
const modalCloseRef = (0, react.useRef)(() => {});
|
|
244
|
+
modalCloseRef.current = resolvedSetModalOpen;
|
|
245
|
+
const registeredModalClosersRef = (0, react.useRef)([]);
|
|
246
|
+
const ownRegisterModalCloser = (0, react.useCallback)((closeModal) => {
|
|
247
|
+
registeredModalClosersRef.current.push(closeModal);
|
|
248
|
+
return () => {
|
|
249
|
+
registeredModalClosersRef.current = registeredModalClosersRef.current.filter((entry) => entry !== closeModal);
|
|
250
|
+
};
|
|
251
|
+
}, []);
|
|
252
|
+
const ownSetDrawerOpen = (0, react.useCallback)((open) => {
|
|
253
|
+
setOwnDrawerOpen(open);
|
|
254
|
+
if (open && isMobileViewport()) {
|
|
255
|
+
const registered = registeredModalClosersRef.current;
|
|
256
|
+
(registered.length > 0 ? registered[registered.length - 1] : modalCloseRef.current)(false);
|
|
257
|
+
}
|
|
258
|
+
}, []);
|
|
259
|
+
const ownRegisterDrawer = (0, react.useCallback)(() => {
|
|
260
|
+
setOwnDrawerCount((count) => count + 1);
|
|
261
|
+
return () => {
|
|
262
|
+
setOwnDrawerCount((count) => Math.max(0, count - 1));
|
|
263
|
+
};
|
|
264
|
+
}, []);
|
|
265
|
+
const resolvedDrawerOpen = parentConfig ? parentConfig.drawerOpen : ownDrawerOpen;
|
|
266
|
+
const resolvedSetDrawerOpen = parentConfig ? parentConfig.setDrawerOpen : ownSetDrawerOpen;
|
|
267
|
+
const resolvedDrawerRegistered = parentConfig ? parentConfig.drawerRegistered : ownDrawerCount > 0;
|
|
268
|
+
const resolvedRegisterDrawer = parentConfig ? parentConfig.registerDrawer : ownRegisterDrawer;
|
|
269
|
+
const resolvedRegisterModalCloser = parentConfig ? parentConfig.ɵregisterModalCloser : ownRegisterModalCloser;
|
|
270
|
+
(0, react.useEffect)(() => {
|
|
271
|
+
if (!hasExplicitDefault) return;
|
|
272
|
+
return resolvedRegisterModalCloser(resolvedSetModalOpen);
|
|
273
|
+
}, [
|
|
274
|
+
hasExplicitDefault,
|
|
275
|
+
resolvedRegisterModalCloser,
|
|
276
|
+
resolvedSetModalOpen
|
|
277
|
+
]);
|
|
278
|
+
const isThreadIdControlledRef = (0, react.useRef)(isThreadIdControlled);
|
|
279
|
+
isThreadIdControlledRef.current = isThreadIdControlled;
|
|
280
|
+
const ownSetActiveThreadId = (0, react.useCallback)((id, options) => {
|
|
281
|
+
setActiveThreadOverride({
|
|
282
|
+
threadId: id,
|
|
283
|
+
explicit: options?.explicit ?? true
|
|
284
|
+
});
|
|
285
|
+
}, []);
|
|
286
|
+
const ownStartNewThread = (0, react.useCallback)(() => {
|
|
287
|
+
setActiveThreadOverride({
|
|
288
|
+
threadId: (0, _copilotkit_shared.randomUUID)(),
|
|
289
|
+
explicit: false
|
|
290
|
+
});
|
|
291
|
+
}, []);
|
|
292
|
+
const parentSetActiveThreadId = parentConfig?.setActiveThreadId;
|
|
293
|
+
const parentStartNewThread = parentConfig?.startNewThread;
|
|
294
|
+
const resolvedSetActiveThreadId = (0, react.useCallback)((id, options) => {
|
|
295
|
+
if (isThreadIdControlledRef.current) {
|
|
296
|
+
console.warn("[CopilotKit] Ignoring setActiveThreadId(): threadId is controlled via the `threadId` prop on CopilotChatConfigurationProvider.");
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
if (parentSetActiveThreadId) {
|
|
300
|
+
parentSetActiveThreadId(id, options);
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
ownSetActiveThreadId(id, options);
|
|
304
|
+
}, [parentSetActiveThreadId, ownSetActiveThreadId]);
|
|
305
|
+
const resolvedStartNewThread = (0, react.useCallback)(() => {
|
|
306
|
+
if (isThreadIdControlledRef.current) {
|
|
307
|
+
console.warn("[CopilotKit] Ignoring startNewThread(): threadId is controlled via the `threadId` prop on CopilotChatConfigurationProvider.");
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
if (parentStartNewThread) {
|
|
311
|
+
parentStartNewThread();
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
ownStartNewThread();
|
|
315
|
+
}, [parentStartNewThread, ownStartNewThread]);
|
|
316
|
+
const setModalOpenWithDrawerExclusion = (0, react.useCallback)((open) => {
|
|
317
|
+
if (open && isMobileViewport()) resolvedSetDrawerOpen(false);
|
|
318
|
+
resolvedSetModalOpen(open);
|
|
319
|
+
}, [resolvedSetModalOpen, resolvedSetDrawerOpen]);
|
|
211
320
|
const configurationValue = (0, react.useMemo)(() => ({
|
|
212
321
|
labels: mergedLabels,
|
|
213
322
|
agentId: resolvedAgentId,
|
|
214
323
|
threadId: resolvedThreadId,
|
|
215
324
|
hasExplicitThreadId: resolvedHasExplicitThreadId,
|
|
216
325
|
isModalOpen: resolvedIsModalOpen,
|
|
217
|
-
setModalOpen:
|
|
326
|
+
setModalOpen: setModalOpenWithDrawerExclusion,
|
|
327
|
+
drawerOpen: resolvedDrawerOpen,
|
|
328
|
+
setDrawerOpen: resolvedSetDrawerOpen,
|
|
329
|
+
drawerRegistered: resolvedDrawerRegistered,
|
|
330
|
+
registerDrawer: resolvedRegisterDrawer,
|
|
331
|
+
ɵregisterModalCloser: resolvedRegisterModalCloser,
|
|
332
|
+
setActiveThreadId: resolvedSetActiveThreadId,
|
|
333
|
+
startNewThread: resolvedStartNewThread
|
|
218
334
|
}), [
|
|
219
335
|
mergedLabels,
|
|
220
336
|
resolvedAgentId,
|
|
221
337
|
resolvedThreadId,
|
|
222
338
|
resolvedHasExplicitThreadId,
|
|
223
339
|
resolvedIsModalOpen,
|
|
224
|
-
|
|
340
|
+
setModalOpenWithDrawerExclusion,
|
|
341
|
+
resolvedDrawerOpen,
|
|
342
|
+
resolvedSetDrawerOpen,
|
|
343
|
+
resolvedDrawerRegistered,
|
|
344
|
+
resolvedRegisterDrawer,
|
|
345
|
+
resolvedRegisterModalCloser,
|
|
346
|
+
resolvedSetActiveThreadId,
|
|
347
|
+
resolvedStartNewThread
|
|
225
348
|
]);
|
|
226
349
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChatConfiguration.Provider, {
|
|
227
350
|
value: configurationValue,
|
|
@@ -1142,7 +1265,7 @@ function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning =
|
|
|
1142
1265
|
},
|
|
1143
1266
|
...props,
|
|
1144
1267
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1145
|
-
className: "cpk:max-w-3xl cpk:mx-auto cpk:py-0 cpk:px-4 cpk:
|
|
1268
|
+
className: "cpk:max-w-3xl cpk:mx-auto cpk:py-0 cpk:px-4 cpk:@3xl:px-0 cpk:[div[data-sidebar-chat]_&]:px-8 cpk:[div[data-popup-chat]_&]:px-4 cpk:pointer-events-auto",
|
|
1146
1269
|
children: inputPill
|
|
1147
1270
|
}), shouldShowDisclaimer && BoundDisclaimer]
|
|
1148
1271
|
});
|
|
@@ -1451,353 +1574,75 @@ const LicenseContext = (0, react.createContext)({
|
|
|
1451
1574
|
const useLicenseContext = () => (0, react.useContext)(LicenseContext);
|
|
1452
1575
|
|
|
1453
1576
|
//#endregion
|
|
1454
|
-
//#region src/v2/
|
|
1455
|
-
function defineToolCallRenderer(def) {
|
|
1456
|
-
const argsSchema = def.name === "*" && !def.args ? zod.z.any() : def.args;
|
|
1457
|
-
return {
|
|
1458
|
-
name: def.name,
|
|
1459
|
-
args: argsSchema,
|
|
1460
|
-
render: def.render,
|
|
1461
|
-
...def.agentId ? { agentId: def.agentId } : {}
|
|
1462
|
-
};
|
|
1463
|
-
}
|
|
1464
|
-
|
|
1465
|
-
//#endregion
|
|
1466
|
-
//#region src/v2/hooks/use-render-tool.tsx
|
|
1467
|
-
const EMPTY_DEPS$1 = [];
|
|
1577
|
+
//#region src/v2/hooks/use-render-tool-call.tsx
|
|
1468
1578
|
/**
|
|
1469
|
-
*
|
|
1470
|
-
*
|
|
1471
|
-
*
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1579
|
+
* Memoized component that renders a single tool call.
|
|
1580
|
+
* This prevents unnecessary re-renders when parent components update
|
|
1581
|
+
* but the tool call data hasn't changed.
|
|
1582
|
+
*/
|
|
1583
|
+
const ToolCallRenderer = react.default.memo(function ToolCallRenderer({ toolCall, toolMessage, RenderComponent, isExecuting }) {
|
|
1584
|
+
const args = (0, react.useMemo)(() => (0, _copilotkit_shared.partialJSONParse)(toolCall.function.arguments), [toolCall.function.arguments]);
|
|
1585
|
+
const toolName = toolCall.function.name;
|
|
1586
|
+
if (toolMessage) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RenderComponent, {
|
|
1587
|
+
name: toolName,
|
|
1588
|
+
toolCallId: toolCall.id,
|
|
1589
|
+
args,
|
|
1590
|
+
status: _copilotkit_core.ToolCallStatus.Complete,
|
|
1591
|
+
result: toolMessage.content
|
|
1592
|
+
});
|
|
1593
|
+
else if (isExecuting) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RenderComponent, {
|
|
1594
|
+
name: toolName,
|
|
1595
|
+
toolCallId: toolCall.id,
|
|
1596
|
+
args,
|
|
1597
|
+
status: _copilotkit_core.ToolCallStatus.Executing,
|
|
1598
|
+
result: void 0
|
|
1599
|
+
});
|
|
1600
|
+
else return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RenderComponent, {
|
|
1601
|
+
name: toolName,
|
|
1602
|
+
toolCallId: toolCall.id,
|
|
1603
|
+
args,
|
|
1604
|
+
status: _copilotkit_core.ToolCallStatus.InProgress,
|
|
1605
|
+
result: void 0
|
|
1606
|
+
});
|
|
1607
|
+
}, (prevProps, nextProps) => {
|
|
1608
|
+
if (prevProps.toolCall.id !== nextProps.toolCall.id) return false;
|
|
1609
|
+
if (prevProps.toolCall.function.name !== nextProps.toolCall.function.name) return false;
|
|
1610
|
+
if (prevProps.toolCall.function.arguments !== nextProps.toolCall.function.arguments) return false;
|
|
1611
|
+
if (prevProps.toolMessage?.content !== nextProps.toolMessage?.content) return false;
|
|
1612
|
+
if (prevProps.isExecuting !== nextProps.isExecuting) return false;
|
|
1613
|
+
if (prevProps.RenderComponent !== nextProps.RenderComponent) return false;
|
|
1614
|
+
return true;
|
|
1615
|
+
});
|
|
1616
|
+
/**
|
|
1617
|
+
* Hook that returns a function to render tool calls based on the render functions
|
|
1618
|
+
* defined in CopilotKitProvider.
|
|
1495
1619
|
*
|
|
1496
|
-
* @
|
|
1497
|
-
* ```tsx
|
|
1498
|
-
* useRenderTool(
|
|
1499
|
-
* {
|
|
1500
|
-
* name: "summarize",
|
|
1501
|
-
* parameters: z.object({ text: z.string() }),
|
|
1502
|
-
* agentId: "research-agent",
|
|
1503
|
-
* render: ({ name, status }) => <div>{name}: {status}</div>,
|
|
1504
|
-
* },
|
|
1505
|
-
* [selectedAgentId],
|
|
1506
|
-
* );
|
|
1507
|
-
* ```
|
|
1620
|
+
* @returns A function that takes a tool call and optional tool message and returns the rendered component
|
|
1508
1621
|
*/
|
|
1509
|
-
function
|
|
1510
|
-
const { copilotkit } = useCopilotKit();
|
|
1511
|
-
const
|
|
1512
|
-
(0, react.
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
}),
|
|
1527
|
-
...config.agentId ? { agentId: config.agentId } : {}
|
|
1528
|
-
});
|
|
1529
|
-
copilotkit.addHookRenderToolCall(renderer);
|
|
1622
|
+
function useRenderToolCall() {
|
|
1623
|
+
const { copilotkit, executingToolCallIds } = useCopilotKit();
|
|
1624
|
+
const agentId = useCopilotChatConfiguration()?.agentId ?? _copilotkit_shared.DEFAULT_AGENT_ID;
|
|
1625
|
+
const renderToolCalls = (0, react.useSyncExternalStore)((callback) => {
|
|
1626
|
+
return copilotkit.subscribe({ onRenderToolCallsChanged: callback }).unsubscribe;
|
|
1627
|
+
}, () => copilotkit.renderToolCalls, () => copilotkit.renderToolCalls);
|
|
1628
|
+
return (0, react.useCallback)(({ toolCall, toolMessage }) => {
|
|
1629
|
+
const exactMatches = renderToolCalls.filter((rc) => rc.name === toolCall.function.name);
|
|
1630
|
+
const renderConfig = exactMatches.find((rc) => rc.agentId === agentId) || exactMatches.find((rc) => !rc.agentId) || exactMatches[0] || renderToolCalls.find((rc) => rc.name === "*");
|
|
1631
|
+
if (!renderConfig) return null;
|
|
1632
|
+
const RenderComponent = renderConfig.render;
|
|
1633
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToolCallRenderer, {
|
|
1634
|
+
toolCall,
|
|
1635
|
+
toolMessage,
|
|
1636
|
+
RenderComponent,
|
|
1637
|
+
isExecuting: executingToolCallIds.has(toolCall.id)
|
|
1638
|
+
}, toolCall.id);
|
|
1530
1639
|
}, [
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1640
|
+
renderToolCalls,
|
|
1641
|
+
executingToolCallIds,
|
|
1642
|
+
agentId
|
|
1534
1643
|
]);
|
|
1535
1644
|
}
|
|
1536
1645
|
|
|
1537
|
-
//#endregion
|
|
1538
|
-
//#region src/v2/hooks/use-default-render-tool.tsx
|
|
1539
|
-
/**
|
|
1540
|
-
* Module-level dedup set so an unknown status value only emits a console
|
|
1541
|
-
* warning the FIRST time we encounter it. Otherwise a stuck/unmapped status
|
|
1542
|
-
* would log on every re-render (potentially many per second).
|
|
1543
|
-
*/
|
|
1544
|
-
const warnedUnknownStatuses = /* @__PURE__ */ new Set();
|
|
1545
|
-
/**
|
|
1546
|
-
* Map a {@link ToolCallStatus} enum value to the documented string-union
|
|
1547
|
-
* status the {@link DefaultRenderProps} contract exposes. Unknown / future
|
|
1548
|
-
* enum members log a warning (once per distinct value) and fall back to
|
|
1549
|
-
* `"inProgress"`.
|
|
1550
|
-
*/
|
|
1551
|
-
function mapToolCallStatus(status) {
|
|
1552
|
-
switch (status) {
|
|
1553
|
-
case _copilotkit_core.ToolCallStatus.Complete: return "complete";
|
|
1554
|
-
case _copilotkit_core.ToolCallStatus.Executing: return "executing";
|
|
1555
|
-
case _copilotkit_core.ToolCallStatus.InProgress: return "inProgress";
|
|
1556
|
-
default: {
|
|
1557
|
-
const key = String(status);
|
|
1558
|
-
if (!warnedUnknownStatuses.has(key)) {
|
|
1559
|
-
warnedUnknownStatuses.add(key);
|
|
1560
|
-
console.warn(`[CopilotKit] Unknown ToolCallStatus "${key}" in default tool-call renderer; falling back to "inProgress".`);
|
|
1561
|
-
}
|
|
1562
|
-
return "inProgress";
|
|
1563
|
-
}
|
|
1564
|
-
}
|
|
1565
|
-
}
|
|
1566
|
-
/**
|
|
1567
|
-
* Convert the framework-internal renderer props (`args`, enum status) into
|
|
1568
|
-
* the documented {@link DefaultRenderProps} shape (`parameters`, string-union
|
|
1569
|
-
* status) so a user `config.render` always sees the documented contract.
|
|
1570
|
-
*/
|
|
1571
|
-
function adaptRendererProps(props) {
|
|
1572
|
-
return {
|
|
1573
|
-
name: props.name,
|
|
1574
|
-
toolCallId: props.toolCallId,
|
|
1575
|
-
parameters: props.args,
|
|
1576
|
-
status: mapToolCallStatus(props.status),
|
|
1577
|
-
result: props.result
|
|
1578
|
-
};
|
|
1579
|
-
}
|
|
1580
|
-
/**
|
|
1581
|
-
* Registers a wildcard (`"*"`) tool-call renderer via `useRenderTool`.
|
|
1582
|
-
*
|
|
1583
|
-
* - Call with no config to use CopilotKit's built-in default tool-call card.
|
|
1584
|
-
* - Pass `config.render` to replace the default UI with your own fallback renderer.
|
|
1585
|
-
*
|
|
1586
|
-
* This is useful when you want a generic renderer for tools that do not have a
|
|
1587
|
-
* dedicated `useRenderTool({ name: "..." })` registration.
|
|
1588
|
-
*
|
|
1589
|
-
* @param config - Optional custom wildcard render function.
|
|
1590
|
-
* @param deps - Optional dependencies to refresh registration.
|
|
1591
|
-
*
|
|
1592
|
-
* @example
|
|
1593
|
-
* ```tsx
|
|
1594
|
-
* useDefaultRenderTool();
|
|
1595
|
-
* ```
|
|
1596
|
-
*
|
|
1597
|
-
* @example
|
|
1598
|
-
* ```tsx
|
|
1599
|
-
* useDefaultRenderTool({
|
|
1600
|
-
* render: ({ name, status }) => <div>{name}: {status}</div>,
|
|
1601
|
-
* });
|
|
1602
|
-
* ```
|
|
1603
|
-
*
|
|
1604
|
-
* @example
|
|
1605
|
-
* ```tsx
|
|
1606
|
-
* useDefaultRenderTool(
|
|
1607
|
-
* {
|
|
1608
|
-
* render: ({ name, result }) => (
|
|
1609
|
-
* <ToolEventRow title={name} payload={result} compact={compactMode} />
|
|
1610
|
-
* ),
|
|
1611
|
-
* },
|
|
1612
|
-
* [compactMode],
|
|
1613
|
-
* );
|
|
1614
|
-
* ```
|
|
1615
|
-
*/
|
|
1616
|
-
function useDefaultRenderTool(config, deps) {
|
|
1617
|
-
const userRender = config?.render;
|
|
1618
|
-
useRenderTool({
|
|
1619
|
-
name: "*",
|
|
1620
|
-
render: userRender ? (raw) => userRender(adaptRendererProps(raw)) : (raw) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DefaultToolCallRenderer, { ...adaptRendererProps(raw) })
|
|
1621
|
-
}, deps);
|
|
1622
|
-
}
|
|
1623
|
-
/**
|
|
1624
|
-
* Guarded JSON.stringify used inside the expanded `<pre>` blocks. A circular
|
|
1625
|
-
* reference would otherwise crash the entire React tree on render.
|
|
1626
|
-
*/
|
|
1627
|
-
function safeStringifyForPre(value) {
|
|
1628
|
-
try {
|
|
1629
|
-
return JSON.stringify(value, null, 2);
|
|
1630
|
-
} catch (err) {
|
|
1631
|
-
console.warn("[CopilotKit] Failed to JSON.stringify tool-call payload for default renderer; falling back to String():", err);
|
|
1632
|
-
try {
|
|
1633
|
-
return String(value);
|
|
1634
|
-
} catch (innerErr) {
|
|
1635
|
-
console.warn("[CopilotKit] safeStringifyForPre: value could not be stringified:", innerErr);
|
|
1636
|
-
return "[unserializable]";
|
|
1637
|
-
}
|
|
1638
|
-
}
|
|
1639
|
-
}
|
|
1640
|
-
function DefaultToolCallRenderer({ name, toolCallId, parameters, status, result }) {
|
|
1641
|
-
const [isExpanded, setIsExpanded] = (0, react.useState)(false);
|
|
1642
|
-
const isActive = status === "inProgress" || status === "executing";
|
|
1643
|
-
const isComplete = status === "complete";
|
|
1644
|
-
const statusLabel = isActive ? "Running" : isComplete ? "Done" : status;
|
|
1645
|
-
const dotClassName = isActive ? "cpk:bg-amber-500" : isComplete ? "cpk:bg-emerald-500" : "cpk:bg-zinc-400";
|
|
1646
|
-
const badgeClassName = isActive ? "cpk:bg-amber-100 cpk:text-amber-800 cpk:dark:bg-amber-500/15 cpk:dark:text-amber-400" : isComplete ? "cpk:bg-emerald-100 cpk:text-emerald-800 cpk:dark:bg-emerald-500/15 cpk:dark:text-emerald-400" : "cpk:bg-zinc-100 cpk:text-zinc-800 cpk:dark:bg-zinc-700/40 cpk:dark:text-zinc-300";
|
|
1647
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1648
|
-
"data-testid": "copilot-tool-render",
|
|
1649
|
-
"data-tool-name": name,
|
|
1650
|
-
"data-tool-call-id": toolCallId,
|
|
1651
|
-
"data-status": status,
|
|
1652
|
-
"data-args": safeStringifyForAttr(parameters),
|
|
1653
|
-
"data-result": safeStringifyForAttr(result),
|
|
1654
|
-
className: "cpk:mt-2 cpk:pb-2",
|
|
1655
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1656
|
-
className: "cpk:rounded-xl cpk:border cpk:border-zinc-200/60 cpk:bg-white/70 cpk:p-4 cpk:shadow-sm cpk:backdrop-blur cpk:dark:border-zinc-800/60 cpk:dark:bg-zinc-900/50",
|
|
1657
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1658
|
-
type: "button",
|
|
1659
|
-
"aria-expanded": isExpanded,
|
|
1660
|
-
onClick: () => setIsExpanded(!isExpanded),
|
|
1661
|
-
className: "cpk:flex cpk:w-full cpk:cursor-pointer cpk:select-none cpk:items-center cpk:justify-between cpk:gap-2.5 cpk:border-none cpk:bg-transparent cpk:p-0 cpk:m-0 cpk:text-left cpk:text-inherit",
|
|
1662
|
-
style: { font: "inherit" },
|
|
1663
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1664
|
-
className: "cpk:flex cpk:min-w-0 cpk:items-center cpk:gap-2",
|
|
1665
|
-
children: [
|
|
1666
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
1667
|
-
className: `cpk:h-3.5 cpk:w-3.5 cpk:flex-shrink-0 cpk:text-zinc-500 cpk:transition-transform cpk:dark:text-zinc-400 ${isExpanded ? "cpk:rotate-90" : ""}`,
|
|
1668
|
-
fill: "none",
|
|
1669
|
-
viewBox: "0 0 24 24",
|
|
1670
|
-
strokeWidth: 2,
|
|
1671
|
-
stroke: "currentColor",
|
|
1672
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
1673
|
-
strokeLinecap: "round",
|
|
1674
|
-
strokeLinejoin: "round",
|
|
1675
|
-
d: "M8.25 4.5l7.5 7.5-7.5 7.5"
|
|
1676
|
-
})
|
|
1677
|
-
}),
|
|
1678
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: `cpk:inline-block cpk:h-2 cpk:w-2 cpk:flex-shrink-0 cpk:rounded-full ${dotClassName}` }),
|
|
1679
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1680
|
-
"data-testid": "copilot-tool-render-name",
|
|
1681
|
-
className: "cpk:truncate cpk:text-[13px] cpk:font-semibold cpk:text-zinc-900 cpk:dark:text-zinc-100",
|
|
1682
|
-
children: name
|
|
1683
|
-
})
|
|
1684
|
-
]
|
|
1685
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1686
|
-
"data-testid": "copilot-tool-render-status",
|
|
1687
|
-
className: `cpk:inline-flex cpk:flex-shrink-0 cpk:items-center cpk:rounded-full cpk:px-2 cpk:py-0.5 cpk:text-[11px] cpk:font-medium ${badgeClassName}`,
|
|
1688
|
-
children: statusLabel
|
|
1689
|
-
})]
|
|
1690
|
-
}), isExpanded && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1691
|
-
className: "cpk:mt-3 cpk:grid cpk:gap-3",
|
|
1692
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1693
|
-
className: "cpk:text-[10px] cpk:uppercase cpk:text-zinc-500 cpk:dark:text-zinc-400",
|
|
1694
|
-
children: "Arguments"
|
|
1695
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
|
|
1696
|
-
className: "cpk:mt-1.5 cpk:max-h-[200px] cpk:overflow-auto cpk:rounded-md cpk:bg-zinc-100 cpk:p-2.5 cpk:text-[11px] cpk:leading-relaxed cpk:text-zinc-800 cpk:whitespace-pre-wrap cpk:break-words cpk:dark:bg-zinc-800/60 cpk:dark:text-zinc-200",
|
|
1697
|
-
children: safeStringifyForPre(parameters ?? {})
|
|
1698
|
-
})] }), result !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1699
|
-
className: "cpk:text-[10px] cpk:uppercase cpk:text-zinc-500 cpk:dark:text-zinc-400",
|
|
1700
|
-
children: "Result"
|
|
1701
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
|
|
1702
|
-
className: "cpk:mt-1.5 cpk:max-h-[200px] cpk:overflow-auto cpk:rounded-md cpk:bg-zinc-100 cpk:p-2.5 cpk:text-[11px] cpk:leading-relaxed cpk:text-zinc-800 cpk:whitespace-pre-wrap cpk:break-words cpk:dark:bg-zinc-800/60 cpk:dark:text-zinc-200",
|
|
1703
|
-
children: typeof result === "string" ? result : safeStringifyForPre(result)
|
|
1704
|
-
})] })]
|
|
1705
|
-
})]
|
|
1706
|
-
})
|
|
1707
|
-
});
|
|
1708
|
-
}
|
|
1709
|
-
function safeStringifyForAttr(value) {
|
|
1710
|
-
if (value === void 0 || value === null) return "";
|
|
1711
|
-
if (typeof value === "string") return value;
|
|
1712
|
-
try {
|
|
1713
|
-
return JSON.stringify(value);
|
|
1714
|
-
} catch (err) {
|
|
1715
|
-
console.warn("[CopilotKit] Failed to JSON.stringify tool-call payload for data-* attribute; falling back to String():", err);
|
|
1716
|
-
try {
|
|
1717
|
-
return String(value);
|
|
1718
|
-
} catch (innerErr) {
|
|
1719
|
-
console.warn("[CopilotKit] safeStringifyForAttr: value could not be stringified:", innerErr);
|
|
1720
|
-
return "";
|
|
1721
|
-
}
|
|
1722
|
-
}
|
|
1723
|
-
}
|
|
1724
|
-
|
|
1725
|
-
//#endregion
|
|
1726
|
-
//#region src/v2/hooks/use-render-tool-call.tsx
|
|
1727
|
-
/**
|
|
1728
|
-
* Memoized component that renders a single tool call.
|
|
1729
|
-
* This prevents unnecessary re-renders when parent components update
|
|
1730
|
-
* but the tool call data hasn't changed.
|
|
1731
|
-
*/
|
|
1732
|
-
const ToolCallRenderer = react.default.memo(function ToolCallRenderer({ toolCall, toolMessage, RenderComponent, isExecuting }) {
|
|
1733
|
-
const args = (0, react.useMemo)(() => (0, _copilotkit_shared.partialJSONParse)(toolCall.function.arguments), [toolCall.function.arguments]);
|
|
1734
|
-
const toolName = toolCall.function.name;
|
|
1735
|
-
if (toolMessage) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RenderComponent, {
|
|
1736
|
-
name: toolName,
|
|
1737
|
-
toolCallId: toolCall.id,
|
|
1738
|
-
args,
|
|
1739
|
-
status: _copilotkit_core.ToolCallStatus.Complete,
|
|
1740
|
-
result: toolMessage.content
|
|
1741
|
-
});
|
|
1742
|
-
else if (isExecuting) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RenderComponent, {
|
|
1743
|
-
name: toolName,
|
|
1744
|
-
toolCallId: toolCall.id,
|
|
1745
|
-
args,
|
|
1746
|
-
status: _copilotkit_core.ToolCallStatus.Executing,
|
|
1747
|
-
result: void 0
|
|
1748
|
-
});
|
|
1749
|
-
else return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RenderComponent, {
|
|
1750
|
-
name: toolName,
|
|
1751
|
-
toolCallId: toolCall.id,
|
|
1752
|
-
args,
|
|
1753
|
-
status: _copilotkit_core.ToolCallStatus.InProgress,
|
|
1754
|
-
result: void 0
|
|
1755
|
-
});
|
|
1756
|
-
}, (prevProps, nextProps) => {
|
|
1757
|
-
if (prevProps.toolCall.id !== nextProps.toolCall.id) return false;
|
|
1758
|
-
if (prevProps.toolCall.function.name !== nextProps.toolCall.function.name) return false;
|
|
1759
|
-
if (prevProps.toolCall.function.arguments !== nextProps.toolCall.function.arguments) return false;
|
|
1760
|
-
if (prevProps.toolMessage?.content !== nextProps.toolMessage?.content) return false;
|
|
1761
|
-
if (prevProps.isExecuting !== nextProps.isExecuting) return false;
|
|
1762
|
-
if (prevProps.RenderComponent !== nextProps.RenderComponent) return false;
|
|
1763
|
-
return true;
|
|
1764
|
-
});
|
|
1765
|
-
/**
|
|
1766
|
-
* Hook that returns a function to render tool calls based on the render functions
|
|
1767
|
-
* defined in CopilotKitProvider.
|
|
1768
|
-
*
|
|
1769
|
-
* @returns A function that takes a tool call and optional tool message and returns the rendered component
|
|
1770
|
-
*/
|
|
1771
|
-
function useRenderToolCall() {
|
|
1772
|
-
const { copilotkit, executingToolCallIds } = useCopilotKit();
|
|
1773
|
-
const agentId = useCopilotChatConfiguration()?.agentId ?? _copilotkit_shared.DEFAULT_AGENT_ID;
|
|
1774
|
-
const renderToolCalls = (0, react.useSyncExternalStore)((callback) => {
|
|
1775
|
-
return copilotkit.subscribe({ onRenderToolCallsChanged: callback }).unsubscribe;
|
|
1776
|
-
}, () => copilotkit.renderToolCalls, () => copilotkit.renderToolCalls);
|
|
1777
|
-
return (0, react.useCallback)(({ toolCall, toolMessage }) => {
|
|
1778
|
-
const exactMatches = renderToolCalls.filter((rc) => rc.name === toolCall.function.name);
|
|
1779
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToolCallRenderer, {
|
|
1780
|
-
toolCall,
|
|
1781
|
-
toolMessage,
|
|
1782
|
-
RenderComponent: (exactMatches.find((rc) => rc.agentId === agentId) || exactMatches.find((rc) => !rc.agentId) || exactMatches[0] || renderToolCalls.find((rc) => rc.name === "*"))?.render ?? defaultToolCallRenderAdapter,
|
|
1783
|
-
isExecuting: executingToolCallIds.has(toolCall.id)
|
|
1784
|
-
}, toolCall.id);
|
|
1785
|
-
}, [
|
|
1786
|
-
renderToolCalls,
|
|
1787
|
-
executingToolCallIds,
|
|
1788
|
-
agentId
|
|
1789
|
-
]);
|
|
1790
|
-
}
|
|
1791
|
-
function defaultToolCallRenderAdapter(props) {
|
|
1792
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DefaultToolCallRenderer, {
|
|
1793
|
-
name: props.name,
|
|
1794
|
-
toolCallId: props.toolCallId,
|
|
1795
|
-
parameters: props.args,
|
|
1796
|
-
status: mapToolCallStatus(props.status),
|
|
1797
|
-
result: props.result
|
|
1798
|
-
});
|
|
1799
|
-
}
|
|
1800
|
-
|
|
1801
1646
|
//#endregion
|
|
1802
1647
|
//#region src/v2/components/CopilotKitInspector.tsx
|
|
1803
1648
|
const CopilotKitInspector = ({ core, ...rest }) => {
|
|
@@ -3278,7 +3123,7 @@ const A2UISurfaceContentSchema = zod.z.object({
|
|
|
3278
3123
|
...A2UILifecycleFields
|
|
3279
3124
|
}).passthrough();
|
|
3280
3125
|
function createA2UIMessageRenderer(options) {
|
|
3281
|
-
const { theme, catalog, loadingComponent, recovery } = options;
|
|
3126
|
+
const { theme, catalog, loadingComponent, recovery, onAction } = options;
|
|
3282
3127
|
const showAfterMs = recovery?.showAfterMs ?? 2e3;
|
|
3283
3128
|
const showAfterAttempts = recovery?.showAfterAttempts ?? 2;
|
|
3284
3129
|
const optionDebugExposure = recovery?.debugExposure ?? "collapsed";
|
|
@@ -3354,6 +3199,7 @@ function createA2UIMessageRenderer(options) {
|
|
|
3354
3199
|
agent,
|
|
3355
3200
|
copilotkit,
|
|
3356
3201
|
catalog,
|
|
3202
|
+
onAction,
|
|
3357
3203
|
onReady: markSurfaceReady
|
|
3358
3204
|
}, surfaceId))
|
|
3359
3205
|
});
|
|
@@ -3374,29 +3220,60 @@ function createA2UIMessageRenderer(options) {
|
|
|
3374
3220
|
};
|
|
3375
3221
|
}
|
|
3376
3222
|
/**
|
|
3223
|
+
* Orchestrates a single A2UI user action: runs the optional `onAction`
|
|
3224
|
+
* interceptor first, then forwards to the agent unless the interceptor
|
|
3225
|
+
* suppressed it (returned `null`). Exported for unit testing; the wiring lives
|
|
3226
|
+
* in {@link ReactSurfaceHost}.
|
|
3227
|
+
*/
|
|
3228
|
+
async function runA2UIAction({ message, agent, copilotkit, onAction }) {
|
|
3229
|
+
if (!agent) return;
|
|
3230
|
+
const action = message.userAction;
|
|
3231
|
+
const forward = async (forwardAction) => {
|
|
3232
|
+
const a2uiAction = forwardAction !== void 0 ? {
|
|
3233
|
+
...message,
|
|
3234
|
+
userAction: forwardAction
|
|
3235
|
+
} : message;
|
|
3236
|
+
try {
|
|
3237
|
+
copilotkit.setProperties({
|
|
3238
|
+
...copilotkit.properties,
|
|
3239
|
+
a2uiAction
|
|
3240
|
+
});
|
|
3241
|
+
await copilotkit.runAgent({ agent });
|
|
3242
|
+
} finally {
|
|
3243
|
+
if (copilotkit.properties) {
|
|
3244
|
+
const { a2uiAction: _omit, ...rest } = copilotkit.properties;
|
|
3245
|
+
copilotkit.setProperties(rest);
|
|
3246
|
+
}
|
|
3247
|
+
}
|
|
3248
|
+
};
|
|
3249
|
+
if (onAction && action) {
|
|
3250
|
+
const result = await onAction(action, forward);
|
|
3251
|
+
if (result === null) return;
|
|
3252
|
+
if (result) {
|
|
3253
|
+
await forward(result);
|
|
3254
|
+
return;
|
|
3255
|
+
}
|
|
3256
|
+
}
|
|
3257
|
+
await forward();
|
|
3258
|
+
}
|
|
3259
|
+
/**
|
|
3377
3260
|
* Renders a single A2UI surface using the React renderer.
|
|
3378
3261
|
* Wraps A2UIProvider + A2UIRenderer and bridges actions back to CopilotKit.
|
|
3379
3262
|
*/
|
|
3380
|
-
function ReactSurfaceHost({ surfaceId, operations, theme, agent, copilotkit, catalog, onReady }) {
|
|
3263
|
+
function ReactSurfaceHost({ surfaceId, operations, theme, agent, copilotkit, catalog, onAction, onReady }) {
|
|
3381
3264
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3382
3265
|
className: "cpk:flex cpk:w-full cpk:flex-none cpk:flex-col cpk:gap-4",
|
|
3383
3266
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_copilotkit_a2ui_renderer.A2UIProvider, {
|
|
3384
|
-
onAction: (0, react.useCallback)(
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
if (copilotkit.properties) {
|
|
3395
|
-
const { a2uiAction, ...rest } = copilotkit.properties;
|
|
3396
|
-
copilotkit.setProperties(rest);
|
|
3397
|
-
}
|
|
3398
|
-
}
|
|
3399
|
-
}, [agent, copilotkit]),
|
|
3267
|
+
onAction: (0, react.useCallback)((message) => runA2UIAction({
|
|
3268
|
+
message,
|
|
3269
|
+
agent,
|
|
3270
|
+
copilotkit,
|
|
3271
|
+
onAction
|
|
3272
|
+
}), [
|
|
3273
|
+
agent,
|
|
3274
|
+
copilotkit,
|
|
3275
|
+
onAction
|
|
3276
|
+
]),
|
|
3400
3277
|
theme,
|
|
3401
3278
|
catalog,
|
|
3402
3279
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SurfaceMessageProcessor, {
|
|
@@ -3467,6 +3344,18 @@ function getOperationSurfaceId(operation) {
|
|
|
3467
3344
|
return operation?.createSurface?.surfaceId ?? operation?.updateComponents?.surfaceId ?? operation?.updateDataModel?.surfaceId ?? operation?.deleteSurface?.surfaceId ?? null;
|
|
3468
3345
|
}
|
|
3469
3346
|
|
|
3347
|
+
//#endregion
|
|
3348
|
+
//#region src/v2/types/defineToolCallRenderer.ts
|
|
3349
|
+
function defineToolCallRenderer(def) {
|
|
3350
|
+
const argsSchema = def.name === "*" && !def.args ? zod.z.any() : def.args;
|
|
3351
|
+
return {
|
|
3352
|
+
name: def.name,
|
|
3353
|
+
args: argsSchema,
|
|
3354
|
+
render: def.render,
|
|
3355
|
+
...def.agentId ? { agentId: def.agentId } : {}
|
|
3356
|
+
};
|
|
3357
|
+
}
|
|
3358
|
+
|
|
3470
3359
|
//#endregion
|
|
3471
3360
|
//#region src/v2/a2ui/A2UIToolCallRenderer.tsx
|
|
3472
3361
|
/**
|
|
@@ -3561,6 +3450,10 @@ function A2UICatalogContext({ catalog, includeSchema }) {
|
|
|
3561
3450
|
|
|
3562
3451
|
//#endregion
|
|
3563
3452
|
//#region src/v2/providers/CopilotKitProvider.tsx
|
|
3453
|
+
const zodToJsonSchemaAdapter = (schema, options) => {
|
|
3454
|
+
const refStrategy = options?.$refStrategy;
|
|
3455
|
+
return (0, zod_to_json_schema.zodToJsonSchema)(schema, refStrategy === "root" || refStrategy === "relative" || refStrategy === "none" || refStrategy === "seen" ? { $refStrategy: refStrategy } : {});
|
|
3456
|
+
};
|
|
3564
3457
|
const HEADER_NAME = "X-CopilotCloud-Public-Api-Key";
|
|
3565
3458
|
const COPILOT_CLOUD_CHAT_URL$1 = "https://api.cloud.copilotkit.ai/copilotkit/v1";
|
|
3566
3459
|
const EMPTY_HEADERS = Object.freeze({});
|
|
@@ -3591,6 +3484,8 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers: headersProp = EMPTY
|
|
|
3591
3484
|
const [runtimeA2UIEnabled, setRuntimeA2UIEnabled] = (0, react.useState)(false);
|
|
3592
3485
|
const [runtimeOpenGenUIEnabled, setRuntimeOpenGenUIEnabled] = (0, react.useState)(false);
|
|
3593
3486
|
const openGenUIActive = runtimeOpenGenUIEnabled || !!openGenerativeUI;
|
|
3487
|
+
const a2uiCatalogProvided = !!a2ui?.catalog;
|
|
3488
|
+
const a2uiActive = runtimeA2UIEnabled || a2uiCatalogProvided;
|
|
3594
3489
|
const [runtimeLicenseStatus, setRuntimeLicenseStatus] = (0, react.useState)(void 0);
|
|
3595
3490
|
(0, react.useEffect)(() => {
|
|
3596
3491
|
if (typeof window === "undefined") return;
|
|
@@ -3621,7 +3516,7 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers: headersProp = EMPTY
|
|
|
3621
3516
|
content: OpenGenerativeUIContentSchema,
|
|
3622
3517
|
render: OpenGenerativeUIActivityRenderer
|
|
3623
3518
|
});
|
|
3624
|
-
if (
|
|
3519
|
+
if (a2uiActive) renderers.unshift(createA2UIMessageRenderer({
|
|
3625
3520
|
theme: a2ui?.theme ?? _copilotkit_a2ui_renderer.viewerTheme,
|
|
3626
3521
|
catalog: a2ui?.catalog,
|
|
3627
3522
|
loadingComponent: a2ui?.loadingComponent,
|
|
@@ -3629,7 +3524,7 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers: headersProp = EMPTY
|
|
|
3629
3524
|
}));
|
|
3630
3525
|
return renderers;
|
|
3631
3526
|
}, [
|
|
3632
|
-
|
|
3527
|
+
a2uiActive,
|
|
3633
3528
|
openGenUIActive,
|
|
3634
3529
|
a2ui
|
|
3635
3530
|
]);
|
|
@@ -3816,7 +3711,10 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers: headersProp = EMPTY
|
|
|
3816
3711
|
copilotkit.setRuntimeTransport(useSingleEndpoint === true ? "single" : useSingleEndpoint === false ? "rest" : "auto");
|
|
3817
3712
|
copilotkit.setHeaders(mergedHeaders);
|
|
3818
3713
|
copilotkit.setCredentials(credentials);
|
|
3819
|
-
copilotkit.setProperties(
|
|
3714
|
+
copilotkit.setProperties(a2uiCatalogProvided ? {
|
|
3715
|
+
...properties,
|
|
3716
|
+
a2uiCatalogAvailable: true
|
|
3717
|
+
} : properties);
|
|
3820
3718
|
copilotkit.setAgents__unsafe_dev_only(mergedAgents);
|
|
3821
3719
|
copilotkit.setDebug(debug);
|
|
3822
3720
|
}, [
|
|
@@ -3825,6 +3723,7 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers: headersProp = EMPTY
|
|
|
3825
3723
|
mergedHeaders,
|
|
3826
3724
|
credentials,
|
|
3827
3725
|
properties,
|
|
3726
|
+
a2uiCatalogProvided,
|
|
3828
3727
|
mergedAgents,
|
|
3829
3728
|
useSingleEndpoint,
|
|
3830
3729
|
debug
|
|
@@ -3872,7 +3771,7 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers: headersProp = EMPTY
|
|
|
3872
3771
|
return JSON.stringify(sandboxFunctionsList.map((fn) => ({
|
|
3873
3772
|
name: fn.name,
|
|
3874
3773
|
description: fn.description,
|
|
3875
|
-
parameters: (0, _copilotkit_shared.schemaToJsonSchema)(fn.parameters, { zodToJsonSchema:
|
|
3774
|
+
parameters: (0, _copilotkit_shared.schemaToJsonSchema)(fn.parameters, { zodToJsonSchema: zodToJsonSchemaAdapter })
|
|
3876
3775
|
})));
|
|
3877
3776
|
}, [sandboxFunctionsList]);
|
|
3878
3777
|
(0, react.useLayoutEffect)(() => {
|
|
@@ -3893,7 +3792,7 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers: headersProp = EMPTY
|
|
|
3893
3792
|
copilotkit,
|
|
3894
3793
|
executingToolCallIds
|
|
3895
3794
|
}), [copilotkit, executingToolCallIds]);
|
|
3896
|
-
const licenseContextValue = (0, react.useMemo)(() => (0, _copilotkit_shared.createLicenseContextValue)(
|
|
3795
|
+
const licenseContextValue = (0, react.useMemo)(() => (0, _copilotkit_shared.createLicenseContextValue)(runtimeLicenseStatus), [runtimeLicenseStatus]);
|
|
3897
3796
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SandboxFunctionsContext.Provider, {
|
|
3898
3797
|
value: sandboxFunctionsList,
|
|
3899
3798
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotKitContext.Provider, {
|
|
@@ -3901,8 +3800,8 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers: headersProp = EMPTY
|
|
|
3901
3800
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(LicenseContext.Provider, {
|
|
3902
3801
|
value: licenseContextValue,
|
|
3903
3802
|
children: [
|
|
3904
|
-
|
|
3905
|
-
|
|
3803
|
+
a2uiActive && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(A2UIBuiltInToolCallRenderer, {}),
|
|
3804
|
+
a2uiActive && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(A2UICatalogContext, {
|
|
3906
3805
|
catalog: a2ui?.catalog,
|
|
3907
3806
|
includeSchema: a2ui?.includeSchema
|
|
3908
3807
|
}),
|
|
@@ -3980,16 +3879,20 @@ function useRenderActivityMessage() {
|
|
|
3980
3879
|
const renderActivityMessage = (0, react.useCallback)((message) => {
|
|
3981
3880
|
const renderer = findRenderer(message.activityType);
|
|
3982
3881
|
if (!renderer) return null;
|
|
3983
|
-
const parseResult = renderer.content.
|
|
3984
|
-
if (
|
|
3985
|
-
console.warn(`
|
|
3882
|
+
const parseResult = renderer.content["~standard"].validate(message.content);
|
|
3883
|
+
if (parseResult instanceof Promise) {
|
|
3884
|
+
console.warn(`Async content validation is not supported for activity message '${message.activityType}'`);
|
|
3885
|
+
return null;
|
|
3886
|
+
}
|
|
3887
|
+
if (parseResult.issues) {
|
|
3888
|
+
console.warn(`Failed to parse content for activity message '${message.activityType}':`, parseResult.issues);
|
|
3986
3889
|
return null;
|
|
3987
3890
|
}
|
|
3988
3891
|
const Component = renderer.render;
|
|
3989
3892
|
const agent = copilotkit.getAgent(agentId);
|
|
3990
3893
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Component, {
|
|
3991
3894
|
activityType: message.activityType,
|
|
3992
|
-
content: parseResult.
|
|
3895
|
+
content: parseResult.value,
|
|
3993
3896
|
message,
|
|
3994
3897
|
agent
|
|
3995
3898
|
}, message.id);
|
|
@@ -4003,106 +3906,376 @@ function useRenderActivityMessage() {
|
|
|
4003
3906
|
findRenderer
|
|
4004
3907
|
}), [renderActivityMessage, findRenderer]);
|
|
4005
3908
|
}
|
|
4006
|
-
|
|
4007
|
-
//#endregion
|
|
4008
|
-
//#region src/v2/hooks/use-frontend-tool.tsx
|
|
4009
|
-
const EMPTY_DEPS = [];
|
|
4010
|
-
function useFrontendTool(tool, deps) {
|
|
4011
|
-
const { copilotkit } = useCopilotKit();
|
|
4012
|
-
const extraDeps = deps ?? EMPTY_DEPS;
|
|
4013
|
-
(0, react.useEffect)(() => {
|
|
4014
|
-
const name = tool.name;
|
|
4015
|
-
if (copilotkit.getTool({
|
|
4016
|
-
toolName: name,
|
|
4017
|
-
agentId: tool.agentId
|
|
4018
|
-
})) {
|
|
4019
|
-
console.warn(`Tool '${name}' already exists for agent '${tool.agentId || "global"}'. Overriding with latest registration.`);
|
|
4020
|
-
copilotkit.removeTool(name, tool.agentId);
|
|
3909
|
+
|
|
3910
|
+
//#endregion
|
|
3911
|
+
//#region src/v2/hooks/use-frontend-tool.tsx
|
|
3912
|
+
const EMPTY_DEPS$1 = [];
|
|
3913
|
+
function useFrontendTool(tool, deps) {
|
|
3914
|
+
const { copilotkit } = useCopilotKit();
|
|
3915
|
+
const extraDeps = deps ?? EMPTY_DEPS$1;
|
|
3916
|
+
(0, react.useEffect)(() => {
|
|
3917
|
+
const name = tool.name;
|
|
3918
|
+
if (copilotkit.getTool({
|
|
3919
|
+
toolName: name,
|
|
3920
|
+
agentId: tool.agentId
|
|
3921
|
+
})) {
|
|
3922
|
+
console.warn(`Tool '${name}' already exists for agent '${tool.agentId || "global"}'. Overriding with latest registration.`);
|
|
3923
|
+
copilotkit.removeTool(name, tool.agentId);
|
|
3924
|
+
}
|
|
3925
|
+
copilotkit.addTool(tool);
|
|
3926
|
+
if (tool.render) copilotkit.addHookRenderToolCall({
|
|
3927
|
+
name,
|
|
3928
|
+
args: tool.parameters,
|
|
3929
|
+
agentId: tool.agentId,
|
|
3930
|
+
render: tool.render
|
|
3931
|
+
});
|
|
3932
|
+
return () => {
|
|
3933
|
+
copilotkit.removeTool(name, tool.agentId);
|
|
3934
|
+
};
|
|
3935
|
+
}, [
|
|
3936
|
+
tool.name,
|
|
3937
|
+
tool.available,
|
|
3938
|
+
copilotkit,
|
|
3939
|
+
JSON.stringify(extraDeps)
|
|
3940
|
+
]);
|
|
3941
|
+
}
|
|
3942
|
+
|
|
3943
|
+
//#endregion
|
|
3944
|
+
//#region src/v2/hooks/use-component.tsx
|
|
3945
|
+
/**
|
|
3946
|
+
* Registers a React component as a frontend tool renderer in chat.
|
|
3947
|
+
*
|
|
3948
|
+
* This hook is a convenience wrapper around `useFrontendTool` that:
|
|
3949
|
+
* - builds a model-facing tool description,
|
|
3950
|
+
* - forwards optional schema parameters (any Standard Schema V1 compatible library),
|
|
3951
|
+
* - renders your component with tool call parameters.
|
|
3952
|
+
*
|
|
3953
|
+
* Use this when you want to display a typed visual component for a tool call
|
|
3954
|
+
* without manually wiring a full frontend tool object.
|
|
3955
|
+
*
|
|
3956
|
+
* When `parameters` is provided, render props are inferred from the schema.
|
|
3957
|
+
* When omitted, the render component may accept any props.
|
|
3958
|
+
*
|
|
3959
|
+
* @typeParam TSchema - Schema describing tool parameters, or `undefined` when no schema is given.
|
|
3960
|
+
* @param config - Tool registration config.
|
|
3961
|
+
* @param deps - Optional dependencies to refresh registration (same semantics as `useEffect`).
|
|
3962
|
+
*
|
|
3963
|
+
* @example
|
|
3964
|
+
* ```tsx
|
|
3965
|
+
* // Without parameters — render accepts any props
|
|
3966
|
+
* useComponent({
|
|
3967
|
+
* name: "showGreeting",
|
|
3968
|
+
* render: ({ message }: { message: string }) => <div>{message}</div>,
|
|
3969
|
+
* });
|
|
3970
|
+
* ```
|
|
3971
|
+
*
|
|
3972
|
+
* @example
|
|
3973
|
+
* ```tsx
|
|
3974
|
+
* // With parameters — render props inferred from schema
|
|
3975
|
+
* useComponent({
|
|
3976
|
+
* name: "showWeatherCard",
|
|
3977
|
+
* parameters: z.object({ city: z.string() }),
|
|
3978
|
+
* render: ({ city }) => <div>{city}</div>,
|
|
3979
|
+
* });
|
|
3980
|
+
* ```
|
|
3981
|
+
*
|
|
3982
|
+
* @example
|
|
3983
|
+
* ```tsx
|
|
3984
|
+
* useComponent(
|
|
3985
|
+
* {
|
|
3986
|
+
* name: "renderProfile",
|
|
3987
|
+
* parameters: z.object({ userId: z.string() }),
|
|
3988
|
+
* render: ProfileCard,
|
|
3989
|
+
* agentId: "support-agent",
|
|
3990
|
+
* },
|
|
3991
|
+
* [selectedAgentId],
|
|
3992
|
+
* );
|
|
3993
|
+
* ```
|
|
3994
|
+
*/
|
|
3995
|
+
function useComponent(config, deps) {
|
|
3996
|
+
const prefix = `Use this tool to display the "${config.name}" component in the chat. This tool renders a visual UI component for the user.`;
|
|
3997
|
+
const fullDescription = config.description ? `${prefix}\n\n${config.description}` : prefix;
|
|
3998
|
+
useFrontendTool({
|
|
3999
|
+
name: config.name,
|
|
4000
|
+
description: fullDescription,
|
|
4001
|
+
parameters: config.parameters,
|
|
4002
|
+
render: ({ args }) => {
|
|
4003
|
+
const Component = config.render;
|
|
4004
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Component, { ...args });
|
|
4005
|
+
},
|
|
4006
|
+
agentId: config.agentId,
|
|
4007
|
+
followUp: config.followUp
|
|
4008
|
+
}, deps);
|
|
4009
|
+
}
|
|
4010
|
+
|
|
4011
|
+
//#endregion
|
|
4012
|
+
//#region src/v2/hooks/use-render-tool.tsx
|
|
4013
|
+
const EMPTY_DEPS = [];
|
|
4014
|
+
/**
|
|
4015
|
+
* Registers a renderer entry in CopilotKit's `renderToolCalls` registry.
|
|
4016
|
+
*
|
|
4017
|
+
* Key behavior:
|
|
4018
|
+
* - deduplicates by `agentId:name` (latest registration wins),
|
|
4019
|
+
* - keeps renderer entries on cleanup so historical chat tool calls can still render,
|
|
4020
|
+
* - refreshes registration when `deps` change.
|
|
4021
|
+
*
|
|
4022
|
+
* @typeParam S - Schema type describing tool call parameters.
|
|
4023
|
+
* @param config - Renderer config for wildcard or named tools.
|
|
4024
|
+
* @param deps - Optional dependencies to refresh registration.
|
|
4025
|
+
*
|
|
4026
|
+
* @example
|
|
4027
|
+
* ```tsx
|
|
4028
|
+
* useRenderTool(
|
|
4029
|
+
* {
|
|
4030
|
+
* name: "searchDocs",
|
|
4031
|
+
* parameters: z.object({ query: z.string() }),
|
|
4032
|
+
* render: ({ status, parameters, result }) => {
|
|
4033
|
+
* if (status === "executing") return <div>Searching {parameters.query}</div>;
|
|
4034
|
+
* if (status === "complete") return <div>{result}</div>;
|
|
4035
|
+
* return <div>Preparing...</div>;
|
|
4036
|
+
* },
|
|
4037
|
+
* },
|
|
4038
|
+
* [],
|
|
4039
|
+
* );
|
|
4040
|
+
* ```
|
|
4041
|
+
*
|
|
4042
|
+
* @example
|
|
4043
|
+
* ```tsx
|
|
4044
|
+
* useRenderTool(
|
|
4045
|
+
* {
|
|
4046
|
+
* name: "summarize",
|
|
4047
|
+
* parameters: z.object({ text: z.string() }),
|
|
4048
|
+
* agentId: "research-agent",
|
|
4049
|
+
* render: ({ name, status }) => <div>{name}: {status}</div>,
|
|
4050
|
+
* },
|
|
4051
|
+
* [selectedAgentId],
|
|
4052
|
+
* );
|
|
4053
|
+
* ```
|
|
4054
|
+
*/
|
|
4055
|
+
function useRenderTool(config, deps) {
|
|
4056
|
+
const { copilotkit } = useCopilotKit();
|
|
4057
|
+
const extraDeps = deps ?? EMPTY_DEPS;
|
|
4058
|
+
(0, react.useEffect)(() => {
|
|
4059
|
+
const renderer = config.name === "*" && !config.parameters ? defineToolCallRenderer({
|
|
4060
|
+
name: "*",
|
|
4061
|
+
render: (props) => config.render({
|
|
4062
|
+
...props,
|
|
4063
|
+
parameters: props.args
|
|
4064
|
+
}),
|
|
4065
|
+
...config.agentId ? { agentId: config.agentId } : {}
|
|
4066
|
+
}) : defineToolCallRenderer({
|
|
4067
|
+
name: config.name,
|
|
4068
|
+
args: config.parameters,
|
|
4069
|
+
render: (props) => {
|
|
4070
|
+
if (props.status === _copilotkit_core.ToolCallStatus.InProgress) return config.render({
|
|
4071
|
+
...props,
|
|
4072
|
+
parameters: props.args
|
|
4073
|
+
});
|
|
4074
|
+
if (props.status === _copilotkit_core.ToolCallStatus.Executing) return config.render({
|
|
4075
|
+
...props,
|
|
4076
|
+
parameters: props.args
|
|
4077
|
+
});
|
|
4078
|
+
return config.render({
|
|
4079
|
+
...props,
|
|
4080
|
+
parameters: props.args
|
|
4081
|
+
});
|
|
4082
|
+
},
|
|
4083
|
+
...config.agentId ? { agentId: config.agentId } : {}
|
|
4084
|
+
});
|
|
4085
|
+
copilotkit.addHookRenderToolCall(renderer);
|
|
4086
|
+
}, [
|
|
4087
|
+
config.name,
|
|
4088
|
+
copilotkit,
|
|
4089
|
+
JSON.stringify(extraDeps)
|
|
4090
|
+
]);
|
|
4091
|
+
}
|
|
4092
|
+
|
|
4093
|
+
//#endregion
|
|
4094
|
+
//#region src/v2/hooks/use-default-render-tool.tsx
|
|
4095
|
+
/**
|
|
4096
|
+
* Module-level dedup set so an unknown status value only emits a console
|
|
4097
|
+
* warning the FIRST time we encounter it. Otherwise a stuck/unmapped status
|
|
4098
|
+
* would log on every re-render (potentially many per second).
|
|
4099
|
+
*/
|
|
4100
|
+
const warnedUnknownStatuses = /* @__PURE__ */ new Set();
|
|
4101
|
+
/**
|
|
4102
|
+
* Map a {@link ToolCallStatus} enum value to the documented string-union
|
|
4103
|
+
* status the {@link DefaultRenderProps} contract exposes. Unknown / future
|
|
4104
|
+
* enum members log a warning (once per distinct value) and fall back to
|
|
4105
|
+
* `"inProgress"`.
|
|
4106
|
+
*/
|
|
4107
|
+
function mapToolCallStatus(status) {
|
|
4108
|
+
switch (status) {
|
|
4109
|
+
case _copilotkit_core.ToolCallStatus.Complete: return "complete";
|
|
4110
|
+
case _copilotkit_core.ToolCallStatus.Executing: return "executing";
|
|
4111
|
+
case _copilotkit_core.ToolCallStatus.InProgress: return "inProgress";
|
|
4112
|
+
default: {
|
|
4113
|
+
const key = String(status);
|
|
4114
|
+
if (!warnedUnknownStatuses.has(key)) {
|
|
4115
|
+
warnedUnknownStatuses.add(key);
|
|
4116
|
+
console.warn(`[CopilotKit] Unknown ToolCallStatus "${key}" in default tool-call renderer; falling back to "inProgress".`);
|
|
4117
|
+
}
|
|
4118
|
+
return "inProgress";
|
|
4119
|
+
}
|
|
4120
|
+
}
|
|
4121
|
+
}
|
|
4122
|
+
/**
|
|
4123
|
+
* Convert the framework-internal renderer props (`args`, enum status) into
|
|
4124
|
+
* the documented {@link DefaultRenderProps} shape (`parameters`, string-union
|
|
4125
|
+
* status) so a user `config.render` always sees the documented contract.
|
|
4126
|
+
*/
|
|
4127
|
+
function adaptRendererProps(props) {
|
|
4128
|
+
return {
|
|
4129
|
+
name: props.name,
|
|
4130
|
+
toolCallId: props.toolCallId,
|
|
4131
|
+
parameters: props.args,
|
|
4132
|
+
status: mapToolCallStatus(props.status),
|
|
4133
|
+
result: props.result
|
|
4134
|
+
};
|
|
4135
|
+
}
|
|
4136
|
+
/**
|
|
4137
|
+
* Registers a wildcard (`"*"`) tool-call renderer via `useRenderTool`.
|
|
4138
|
+
*
|
|
4139
|
+
* - Call with no config to use CopilotKit's built-in default tool-call card.
|
|
4140
|
+
* - Pass `config.render` to replace the default UI with your own fallback renderer.
|
|
4141
|
+
*
|
|
4142
|
+
* This is useful when you want a generic renderer for tools that do not have a
|
|
4143
|
+
* dedicated `useRenderTool({ name: "..." })` registration.
|
|
4144
|
+
*
|
|
4145
|
+
* @param config - Optional custom wildcard render function.
|
|
4146
|
+
* @param deps - Optional dependencies to refresh registration.
|
|
4147
|
+
*
|
|
4148
|
+
* @example
|
|
4149
|
+
* ```tsx
|
|
4150
|
+
* useDefaultRenderTool();
|
|
4151
|
+
* ```
|
|
4152
|
+
*
|
|
4153
|
+
* @example
|
|
4154
|
+
* ```tsx
|
|
4155
|
+
* useDefaultRenderTool({
|
|
4156
|
+
* render: ({ name, status }) => <div>{name}: {status}</div>,
|
|
4157
|
+
* });
|
|
4158
|
+
* ```
|
|
4159
|
+
*
|
|
4160
|
+
* @example
|
|
4161
|
+
* ```tsx
|
|
4162
|
+
* useDefaultRenderTool(
|
|
4163
|
+
* {
|
|
4164
|
+
* render: ({ name, result }) => (
|
|
4165
|
+
* <ToolEventRow title={name} payload={result} compact={compactMode} />
|
|
4166
|
+
* ),
|
|
4167
|
+
* },
|
|
4168
|
+
* [compactMode],
|
|
4169
|
+
* );
|
|
4170
|
+
* ```
|
|
4171
|
+
*/
|
|
4172
|
+
function useDefaultRenderTool(config, deps) {
|
|
4173
|
+
const userRender = config?.render;
|
|
4174
|
+
useRenderTool({
|
|
4175
|
+
name: "*",
|
|
4176
|
+
render: userRender ? (raw) => userRender(adaptRendererProps(raw)) : (raw) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DefaultToolCallRenderer, { ...adaptRendererProps(raw) })
|
|
4177
|
+
}, deps);
|
|
4178
|
+
}
|
|
4179
|
+
/**
|
|
4180
|
+
* Guarded JSON.stringify used inside the expanded `<pre>` blocks. A circular
|
|
4181
|
+
* reference would otherwise crash the entire React tree on render.
|
|
4182
|
+
*/
|
|
4183
|
+
function safeStringifyForPre(value) {
|
|
4184
|
+
try {
|
|
4185
|
+
return JSON.stringify(value, null, 2);
|
|
4186
|
+
} catch (err) {
|
|
4187
|
+
console.warn("[CopilotKit] Failed to JSON.stringify tool-call payload for default renderer; falling back to String():", err);
|
|
4188
|
+
try {
|
|
4189
|
+
return String(value);
|
|
4190
|
+
} catch (innerErr) {
|
|
4191
|
+
console.warn("[CopilotKit] safeStringifyForPre: value could not be stringified:", innerErr);
|
|
4192
|
+
return "[unserializable]";
|
|
4193
|
+
}
|
|
4194
|
+
}
|
|
4195
|
+
}
|
|
4196
|
+
function DefaultToolCallRenderer({ name, toolCallId, parameters, status, result }) {
|
|
4197
|
+
const [isExpanded, setIsExpanded] = (0, react.useState)(false);
|
|
4198
|
+
const isActive = status === "inProgress" || status === "executing";
|
|
4199
|
+
const isComplete = status === "complete";
|
|
4200
|
+
const statusLabel = isActive ? "Running" : isComplete ? "Done" : status;
|
|
4201
|
+
const dotClassName = isActive ? "cpk:bg-amber-500" : isComplete ? "cpk:bg-emerald-500" : "cpk:bg-zinc-400";
|
|
4202
|
+
const badgeClassName = isActive ? "cpk:bg-amber-100 cpk:text-amber-800 cpk:dark:bg-amber-500/15 cpk:dark:text-amber-400" : isComplete ? "cpk:bg-emerald-100 cpk:text-emerald-800 cpk:dark:bg-emerald-500/15 cpk:dark:text-emerald-400" : "cpk:bg-zinc-100 cpk:text-zinc-800 cpk:dark:bg-zinc-700/40 cpk:dark:text-zinc-300";
|
|
4203
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4204
|
+
"data-testid": "copilot-tool-render",
|
|
4205
|
+
"data-tool-name": name,
|
|
4206
|
+
"data-tool-call-id": toolCallId,
|
|
4207
|
+
"data-status": status,
|
|
4208
|
+
"data-args": safeStringifyForAttr(parameters),
|
|
4209
|
+
"data-result": safeStringifyForAttr(result),
|
|
4210
|
+
className: "cpk:mt-2 cpk:pb-2",
|
|
4211
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4212
|
+
className: "cpk:rounded-xl cpk:border cpk:border-zinc-200/60 cpk:bg-white/70 cpk:p-4 cpk:shadow-sm cpk:backdrop-blur cpk:dark:border-zinc-800/60 cpk:dark:bg-zinc-900/50",
|
|
4213
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
4214
|
+
type: "button",
|
|
4215
|
+
"aria-expanded": isExpanded,
|
|
4216
|
+
onClick: () => setIsExpanded(!isExpanded),
|
|
4217
|
+
className: "cpk:flex cpk:w-full cpk:cursor-pointer cpk:select-none cpk:items-center cpk:justify-between cpk:gap-2.5 cpk:border-none cpk:bg-transparent cpk:p-0 cpk:m-0 cpk:text-left cpk:text-inherit",
|
|
4218
|
+
style: { font: "inherit" },
|
|
4219
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4220
|
+
className: "cpk:flex cpk:min-w-0 cpk:items-center cpk:gap-2",
|
|
4221
|
+
children: [
|
|
4222
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
4223
|
+
className: `cpk:h-3.5 cpk:w-3.5 cpk:flex-shrink-0 cpk:text-zinc-500 cpk:transition-transform cpk:dark:text-zinc-400 ${isExpanded ? "cpk:rotate-90" : ""}`,
|
|
4224
|
+
fill: "none",
|
|
4225
|
+
viewBox: "0 0 24 24",
|
|
4226
|
+
strokeWidth: 2,
|
|
4227
|
+
stroke: "currentColor",
|
|
4228
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
4229
|
+
strokeLinecap: "round",
|
|
4230
|
+
strokeLinejoin: "round",
|
|
4231
|
+
d: "M8.25 4.5l7.5 7.5-7.5 7.5"
|
|
4232
|
+
})
|
|
4233
|
+
}),
|
|
4234
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: `cpk:inline-block cpk:h-2 cpk:w-2 cpk:flex-shrink-0 cpk:rounded-full ${dotClassName}` }),
|
|
4235
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4236
|
+
"data-testid": "copilot-tool-render-name",
|
|
4237
|
+
className: "cpk:truncate cpk:text-[13px] cpk:font-semibold cpk:text-zinc-900 cpk:dark:text-zinc-100",
|
|
4238
|
+
children: name
|
|
4239
|
+
})
|
|
4240
|
+
]
|
|
4241
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4242
|
+
"data-testid": "copilot-tool-render-status",
|
|
4243
|
+
className: `cpk:inline-flex cpk:flex-shrink-0 cpk:items-center cpk:rounded-full cpk:px-2 cpk:py-0.5 cpk:text-[11px] cpk:font-medium ${badgeClassName}`,
|
|
4244
|
+
children: statusLabel
|
|
4245
|
+
})]
|
|
4246
|
+
}), isExpanded && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4247
|
+
className: "cpk:mt-3 cpk:grid cpk:gap-3",
|
|
4248
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4249
|
+
className: "cpk:text-[10px] cpk:uppercase cpk:text-zinc-500 cpk:dark:text-zinc-400",
|
|
4250
|
+
children: "Arguments"
|
|
4251
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
|
|
4252
|
+
className: "cpk:mt-1.5 cpk:max-h-[200px] cpk:overflow-auto cpk:rounded-md cpk:bg-zinc-100 cpk:p-2.5 cpk:text-[11px] cpk:leading-relaxed cpk:text-zinc-800 cpk:whitespace-pre-wrap cpk:break-words cpk:dark:bg-zinc-800/60 cpk:dark:text-zinc-200",
|
|
4253
|
+
children: safeStringifyForPre(parameters ?? {})
|
|
4254
|
+
})] }), result !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4255
|
+
className: "cpk:text-[10px] cpk:uppercase cpk:text-zinc-500 cpk:dark:text-zinc-400",
|
|
4256
|
+
children: "Result"
|
|
4257
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
|
|
4258
|
+
className: "cpk:mt-1.5 cpk:max-h-[200px] cpk:overflow-auto cpk:rounded-md cpk:bg-zinc-100 cpk:p-2.5 cpk:text-[11px] cpk:leading-relaxed cpk:text-zinc-800 cpk:whitespace-pre-wrap cpk:break-words cpk:dark:bg-zinc-800/60 cpk:dark:text-zinc-200",
|
|
4259
|
+
children: typeof result === "string" ? result : safeStringifyForPre(result)
|
|
4260
|
+
})] })]
|
|
4261
|
+
})]
|
|
4262
|
+
})
|
|
4263
|
+
});
|
|
4264
|
+
}
|
|
4265
|
+
function safeStringifyForAttr(value) {
|
|
4266
|
+
if (value === void 0 || value === null) return "";
|
|
4267
|
+
if (typeof value === "string") return value;
|
|
4268
|
+
try {
|
|
4269
|
+
return JSON.stringify(value);
|
|
4270
|
+
} catch (err) {
|
|
4271
|
+
console.warn("[CopilotKit] Failed to JSON.stringify tool-call payload for data-* attribute; falling back to String():", err);
|
|
4272
|
+
try {
|
|
4273
|
+
return String(value);
|
|
4274
|
+
} catch (innerErr) {
|
|
4275
|
+
console.warn("[CopilotKit] safeStringifyForAttr: value could not be stringified:", innerErr);
|
|
4276
|
+
return "";
|
|
4021
4277
|
}
|
|
4022
|
-
|
|
4023
|
-
if (tool.render) copilotkit.addHookRenderToolCall({
|
|
4024
|
-
name,
|
|
4025
|
-
args: tool.parameters,
|
|
4026
|
-
agentId: tool.agentId,
|
|
4027
|
-
render: tool.render
|
|
4028
|
-
});
|
|
4029
|
-
return () => {
|
|
4030
|
-
copilotkit.removeTool(name, tool.agentId);
|
|
4031
|
-
};
|
|
4032
|
-
}, [
|
|
4033
|
-
tool.name,
|
|
4034
|
-
tool.available,
|
|
4035
|
-
copilotkit,
|
|
4036
|
-
JSON.stringify(extraDeps)
|
|
4037
|
-
]);
|
|
4038
|
-
}
|
|
4039
|
-
|
|
4040
|
-
//#endregion
|
|
4041
|
-
//#region src/v2/hooks/use-component.tsx
|
|
4042
|
-
/**
|
|
4043
|
-
* Registers a React component as a frontend tool renderer in chat.
|
|
4044
|
-
*
|
|
4045
|
-
* This hook is a convenience wrapper around `useFrontendTool` that:
|
|
4046
|
-
* - builds a model-facing tool description,
|
|
4047
|
-
* - forwards optional schema parameters (any Standard Schema V1 compatible library),
|
|
4048
|
-
* - renders your component with tool call parameters.
|
|
4049
|
-
*
|
|
4050
|
-
* Use this when you want to display a typed visual component for a tool call
|
|
4051
|
-
* without manually wiring a full frontend tool object.
|
|
4052
|
-
*
|
|
4053
|
-
* When `parameters` is provided, render props are inferred from the schema.
|
|
4054
|
-
* When omitted, the render component may accept any props.
|
|
4055
|
-
*
|
|
4056
|
-
* @typeParam TSchema - Schema describing tool parameters, or `undefined` when no schema is given.
|
|
4057
|
-
* @param config - Tool registration config.
|
|
4058
|
-
* @param deps - Optional dependencies to refresh registration (same semantics as `useEffect`).
|
|
4059
|
-
*
|
|
4060
|
-
* @example
|
|
4061
|
-
* ```tsx
|
|
4062
|
-
* // Without parameters — render accepts any props
|
|
4063
|
-
* useComponent({
|
|
4064
|
-
* name: "showGreeting",
|
|
4065
|
-
* render: ({ message }: { message: string }) => <div>{message}</div>,
|
|
4066
|
-
* });
|
|
4067
|
-
* ```
|
|
4068
|
-
*
|
|
4069
|
-
* @example
|
|
4070
|
-
* ```tsx
|
|
4071
|
-
* // With parameters — render props inferred from schema
|
|
4072
|
-
* useComponent({
|
|
4073
|
-
* name: "showWeatherCard",
|
|
4074
|
-
* parameters: z.object({ city: z.string() }),
|
|
4075
|
-
* render: ({ city }) => <div>{city}</div>,
|
|
4076
|
-
* });
|
|
4077
|
-
* ```
|
|
4078
|
-
*
|
|
4079
|
-
* @example
|
|
4080
|
-
* ```tsx
|
|
4081
|
-
* useComponent(
|
|
4082
|
-
* {
|
|
4083
|
-
* name: "renderProfile",
|
|
4084
|
-
* parameters: z.object({ userId: z.string() }),
|
|
4085
|
-
* render: ProfileCard,
|
|
4086
|
-
* agentId: "support-agent",
|
|
4087
|
-
* },
|
|
4088
|
-
* [selectedAgentId],
|
|
4089
|
-
* );
|
|
4090
|
-
* ```
|
|
4091
|
-
*/
|
|
4092
|
-
function useComponent(config, deps) {
|
|
4093
|
-
const prefix = `Use this tool to display the "${config.name}" component in the chat. This tool renders a visual UI component for the user.`;
|
|
4094
|
-
const fullDescription = config.description ? `${prefix}\n\n${config.description}` : prefix;
|
|
4095
|
-
useFrontendTool({
|
|
4096
|
-
name: config.name,
|
|
4097
|
-
description: fullDescription,
|
|
4098
|
-
parameters: config.parameters,
|
|
4099
|
-
render: ({ args }) => {
|
|
4100
|
-
const Component = config.render;
|
|
4101
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Component, { ...args });
|
|
4102
|
-
},
|
|
4103
|
-
agentId: config.agentId,
|
|
4104
|
-
followUp: config.followUp
|
|
4105
|
-
}, deps);
|
|
4278
|
+
}
|
|
4106
4279
|
}
|
|
4107
4280
|
|
|
4108
4281
|
//#endregion
|
|
@@ -4225,7 +4398,7 @@ function useAgent({ agentId, updates, throttleMs } = {}) {
|
|
|
4225
4398
|
if (isRuntimeConfigured && (status === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Disconnected || status === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Connecting)) {
|
|
4226
4399
|
const cached = provisionalAgentCache.current.get(agentId);
|
|
4227
4400
|
if (cached) {
|
|
4228
|
-
|
|
4401
|
+
copilotkit.applyHeadersToAgent(cached);
|
|
4229
4402
|
return cached;
|
|
4230
4403
|
}
|
|
4231
4404
|
const provisional = new _copilotkit_core.ProxiedCopilotRuntimeAgent({
|
|
@@ -4234,14 +4407,14 @@ function useAgent({ agentId, updates, throttleMs } = {}) {
|
|
|
4234
4407
|
transport: copilotkit.runtimeTransport,
|
|
4235
4408
|
runtimeMode: "pending"
|
|
4236
4409
|
});
|
|
4237
|
-
|
|
4410
|
+
copilotkit.applyHeadersToAgent(provisional);
|
|
4238
4411
|
provisionalAgentCache.current.set(agentId, provisional);
|
|
4239
4412
|
return provisional;
|
|
4240
4413
|
}
|
|
4241
4414
|
if (isRuntimeConfigured && status === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Error) {
|
|
4242
4415
|
const cached = provisionalAgentCache.current.get(agentId);
|
|
4243
4416
|
if (cached) {
|
|
4244
|
-
|
|
4417
|
+
copilotkit.applyHeadersToAgent(cached);
|
|
4245
4418
|
return cached;
|
|
4246
4419
|
}
|
|
4247
4420
|
const provisional = new _copilotkit_core.ProxiedCopilotRuntimeAgent({
|
|
@@ -4250,7 +4423,7 @@ function useAgent({ agentId, updates, throttleMs } = {}) {
|
|
|
4250
4423
|
transport: copilotkit.runtimeTransport,
|
|
4251
4424
|
runtimeMode: "pending"
|
|
4252
4425
|
});
|
|
4253
|
-
|
|
4426
|
+
copilotkit.applyHeadersToAgent(provisional);
|
|
4254
4427
|
provisionalAgentCache.current.set(agentId, provisional);
|
|
4255
4428
|
return provisional;
|
|
4256
4429
|
}
|
|
@@ -4301,7 +4474,7 @@ function useAgent({ agentId, updates, throttleMs } = {}) {
|
|
|
4301
4474
|
updateFlags
|
|
4302
4475
|
]);
|
|
4303
4476
|
(0, react.useEffect)(() => {
|
|
4304
|
-
if (agent instanceof _ag_ui_client.HttpAgent)
|
|
4477
|
+
if (agent instanceof _ag_ui_client.HttpAgent) copilotkit.applyHeadersToAgent(agent);
|
|
4305
4478
|
}, [agent, JSON.stringify(copilotkit.headers)]);
|
|
4306
4479
|
const chatConfig = useCopilotChatConfiguration();
|
|
4307
4480
|
const configThreadId = chatConfig?.threadId;
|
|
@@ -4578,114 +4751,165 @@ const INTERRUPT_EVENT_NAME = "on_interrupt";
|
|
|
4578
4751
|
function isPromiseLike(value) {
|
|
4579
4752
|
return (typeof value === "object" || typeof value === "function") && value !== null && typeof Reflect.get(value, "then") === "function";
|
|
4580
4753
|
}
|
|
4754
|
+
/** Derive the legacy-compatible `event` for any pending interrupt. */
|
|
4755
|
+
function toLegacyEvent(pending) {
|
|
4756
|
+
if (pending.kind === "legacy") return pending.event;
|
|
4757
|
+
return {
|
|
4758
|
+
name: INTERRUPT_EVENT_NAME,
|
|
4759
|
+
value: pending.interrupts[0]
|
|
4760
|
+
};
|
|
4761
|
+
}
|
|
4581
4762
|
/**
|
|
4582
|
-
* Handles agent interrupts
|
|
4583
|
-
*
|
|
4584
|
-
* The hook listens to custom events on the active agent, stores interrupt payloads per run,
|
|
4585
|
-
* and surfaces a render callback once the run finalizes. Call `resolve` from your UI to resume
|
|
4586
|
-
* execution with user-provided data.
|
|
4587
|
-
*
|
|
4588
|
-
* - `renderInChat: true` (default): the element is published into `<CopilotChat>` and this hook returns `void`.
|
|
4589
|
-
* - `renderInChat: false`: the hook returns the interrupt element so you can place it anywhere in your component tree.
|
|
4763
|
+
* Handles agent interrupts with optional filtering, preprocessing, and resume behavior.
|
|
4590
4764
|
*
|
|
4591
|
-
*
|
|
4592
|
-
*
|
|
4765
|
+
* Supports both the AG-UI standard interrupt flow (`RUN_FINISHED` with
|
|
4766
|
+
* `outcome.type === "interrupt"`) and the legacy custom-event flow
|
|
4767
|
+
* (`on_interrupt`). For standard interrupts, `render` receives `interrupt`
|
|
4768
|
+
* (the primary one) and `interrupts` (the full open set); call `resolve(payload)`
|
|
4769
|
+
* to resume or `cancel()` to cancel. Resuming addresses the targeted interrupt
|
|
4770
|
+
* and, once every open interrupt is addressed, submits a single spec `resume`
|
|
4771
|
+
* array via `copilotkit.runAgent`.
|
|
4593
4772
|
*
|
|
4594
|
-
*
|
|
4595
|
-
*
|
|
4596
|
-
* @returns When `renderInChat` is `false`, returns the interrupt element (or `null` when idle).
|
|
4597
|
-
* Otherwise returns `void` and publishes the element into chat. In `render`, `result` is always
|
|
4598
|
-
* either the handler's resolved return value or `null` (including when no handler is provided,
|
|
4599
|
-
* when filtering skips the interrupt, or when handler execution fails).
|
|
4600
|
-
*
|
|
4601
|
-
* @example
|
|
4602
|
-
* ```tsx
|
|
4603
|
-
* import { useInterrupt } from "@copilotkit/react-core/v2";
|
|
4604
|
-
*
|
|
4605
|
-
* function InterruptUI() {
|
|
4606
|
-
* useInterrupt({
|
|
4607
|
-
* render: ({ event, resolve }) => (
|
|
4608
|
-
* <div>
|
|
4609
|
-
* <p>{event.value.question}</p>
|
|
4610
|
-
* <button onClick={() => resolve({ approved: true })}>Approve</button>
|
|
4611
|
-
* <button onClick={() => resolve({ approved: false })}>Reject</button>
|
|
4612
|
-
* </div>
|
|
4613
|
-
* ),
|
|
4614
|
-
* });
|
|
4615
|
-
*
|
|
4616
|
-
* return null;
|
|
4617
|
-
* }
|
|
4618
|
-
* ```
|
|
4773
|
+
* - `renderInChat: true` (default): the element is published into `<CopilotChat>`; returns `void`.
|
|
4774
|
+
* - `renderInChat: false`: the hook returns the interrupt element for manual placement.
|
|
4619
4775
|
*
|
|
4620
4776
|
* @example
|
|
4621
4777
|
* ```tsx
|
|
4622
|
-
*
|
|
4623
|
-
*
|
|
4624
|
-
*
|
|
4625
|
-
*
|
|
4626
|
-
*
|
|
4627
|
-
*
|
|
4628
|
-
*
|
|
4629
|
-
*
|
|
4630
|
-
*
|
|
4631
|
-
* <strong>{result?.label ?? ""}</strong>
|
|
4632
|
-
* <button onClick={() => resolve({ value: event.value })}>Continue</button>
|
|
4633
|
-
* </aside>
|
|
4634
|
-
* ),
|
|
4635
|
-
* });
|
|
4636
|
-
*
|
|
4637
|
-
* return <>{interruptElement}</>;
|
|
4638
|
-
* }
|
|
4778
|
+
* useInterrupt({
|
|
4779
|
+
* render: ({ interrupt, resolve, cancel }) => (
|
|
4780
|
+
* <div>
|
|
4781
|
+
* <p>{interrupt?.message}</p>
|
|
4782
|
+
* <button onClick={() => resolve({ approved: true })}>Approve</button>
|
|
4783
|
+
* <button onClick={() => cancel()}>Cancel</button>
|
|
4784
|
+
* </div>
|
|
4785
|
+
* ),
|
|
4786
|
+
* });
|
|
4639
4787
|
* ```
|
|
4640
4788
|
*/
|
|
4641
4789
|
function useInterrupt(config) {
|
|
4642
4790
|
const { copilotkit } = useCopilotKit();
|
|
4643
4791
|
const { agent } = useAgent({ agentId: config.agentId });
|
|
4644
|
-
const [
|
|
4645
|
-
const
|
|
4646
|
-
|
|
4792
|
+
const [pending, setPending] = (0, react.useState)(null);
|
|
4793
|
+
const pendingRef = (0, react.useRef)(pending);
|
|
4794
|
+
pendingRef.current = pending;
|
|
4647
4795
|
const [handlerResult, setHandlerResult] = (0, react.useState)(null);
|
|
4796
|
+
const responsesRef = (0, react.useRef)({});
|
|
4648
4797
|
(0, react.useEffect)(() => {
|
|
4649
|
-
let
|
|
4798
|
+
let localLegacy = null;
|
|
4799
|
+
let localStandard = null;
|
|
4650
4800
|
const subscription = agent.subscribe({
|
|
4651
4801
|
onCustomEvent: ({ event }) => {
|
|
4652
|
-
if (event.name === INTERRUPT_EVENT_NAME)
|
|
4802
|
+
if (event.name === INTERRUPT_EVENT_NAME) localLegacy = {
|
|
4653
4803
|
name: event.name,
|
|
4654
4804
|
value: event.value
|
|
4655
4805
|
};
|
|
4656
4806
|
},
|
|
4807
|
+
onRunFinishedEvent: (params) => {
|
|
4808
|
+
if (params.outcome === "interrupt") localStandard = params.interrupts;
|
|
4809
|
+
},
|
|
4657
4810
|
onRunStartedEvent: () => {
|
|
4658
|
-
|
|
4659
|
-
|
|
4811
|
+
localLegacy = null;
|
|
4812
|
+
localStandard = null;
|
|
4813
|
+
responsesRef.current = {};
|
|
4814
|
+
setPending(null);
|
|
4660
4815
|
},
|
|
4661
4816
|
onRunFinalized: () => {
|
|
4662
|
-
if (
|
|
4663
|
-
|
|
4664
|
-
|
|
4665
|
-
}
|
|
4817
|
+
if (localStandard && localStandard.length > 0) setPending({
|
|
4818
|
+
kind: "standard",
|
|
4819
|
+
interrupts: localStandard
|
|
4820
|
+
});
|
|
4821
|
+
else if (localLegacy) setPending({
|
|
4822
|
+
kind: "legacy",
|
|
4823
|
+
event: localLegacy
|
|
4824
|
+
});
|
|
4825
|
+
localLegacy = null;
|
|
4826
|
+
localStandard = null;
|
|
4666
4827
|
},
|
|
4667
4828
|
onRunFailed: () => {
|
|
4668
|
-
|
|
4669
|
-
|
|
4829
|
+
localLegacy = null;
|
|
4830
|
+
localStandard = null;
|
|
4831
|
+
responsesRef.current = {};
|
|
4832
|
+
setPending(null);
|
|
4670
4833
|
}
|
|
4671
4834
|
});
|
|
4672
4835
|
return () => subscription.unsubscribe();
|
|
4673
4836
|
}, [agent]);
|
|
4674
|
-
const
|
|
4837
|
+
const submitStandardIfComplete = (0, react.useCallback)(async (interrupts) => {
|
|
4838
|
+
if (!interrupts.every((i) => responsesRef.current[i.id])) return;
|
|
4839
|
+
const expired = interrupts.find((i) => (0, _ag_ui_client.isInterruptExpired)(i));
|
|
4840
|
+
if (expired) {
|
|
4841
|
+
console.error(`[CopilotKit] useInterrupt: interrupt ${expired.id} expired at ${expired.expiresAt}; not resuming.`);
|
|
4842
|
+
responsesRef.current = {};
|
|
4843
|
+
setPending(null);
|
|
4844
|
+
return;
|
|
4845
|
+
}
|
|
4846
|
+
const resume = (0, _ag_ui_client.buildResumeArray)(interrupts, responsesRef.current);
|
|
4847
|
+
for (const i of interrupts) {
|
|
4848
|
+
if (!i.toolCallId) continue;
|
|
4849
|
+
const response = responsesRef.current[i.id];
|
|
4850
|
+
const content = response.status === "cancelled" ? { status: "cancelled" } : response.payload ?? { status: "resolved" };
|
|
4851
|
+
agent.addMessage({
|
|
4852
|
+
id: (0, _ag_ui_client.randomUUID)(),
|
|
4853
|
+
role: "tool",
|
|
4854
|
+
toolCallId: i.toolCallId,
|
|
4855
|
+
content: JSON.stringify(content)
|
|
4856
|
+
});
|
|
4857
|
+
}
|
|
4858
|
+
responsesRef.current = {};
|
|
4675
4859
|
try {
|
|
4860
|
+
return await copilotkit.runAgent({
|
|
4861
|
+
agent,
|
|
4862
|
+
resume
|
|
4863
|
+
});
|
|
4864
|
+
} catch (err) {
|
|
4865
|
+
console.error("[CopilotKit] useInterrupt resolve: runAgent rejected; clearing pending + rethrowing", err);
|
|
4866
|
+
setPending(null);
|
|
4867
|
+
throw err;
|
|
4868
|
+
}
|
|
4869
|
+
}, [agent, copilotkit]);
|
|
4870
|
+
const resolve = (0, react.useCallback)(async (payload, interruptId) => {
|
|
4871
|
+
const current = pendingRef.current;
|
|
4872
|
+
if (!current) return;
|
|
4873
|
+
if (current.kind === "legacy") try {
|
|
4676
4874
|
return await copilotkit.runAgent({
|
|
4677
4875
|
agent,
|
|
4678
4876
|
forwardedProps: { command: {
|
|
4679
|
-
resume:
|
|
4680
|
-
interruptEvent:
|
|
4877
|
+
resume: payload,
|
|
4878
|
+
interruptEvent: current.event.value
|
|
4681
4879
|
} }
|
|
4682
4880
|
});
|
|
4683
4881
|
} catch (err) {
|
|
4684
4882
|
console.error("[CopilotKit] useInterrupt resolve: runAgent rejected; clearing pending + rethrowing", err);
|
|
4685
|
-
|
|
4883
|
+
setPending(null);
|
|
4686
4884
|
throw err;
|
|
4687
4885
|
}
|
|
4688
|
-
|
|
4886
|
+
if (current.interrupts.length > 1 && interruptId === void 0) console.warn(`[CopilotKit] useInterrupt: resolve()/cancel() called without an interruptId while ${current.interrupts.length} interrupts are open; defaulting to the first. Pass an interruptId to address a specific interrupt.`);
|
|
4887
|
+
const id = interruptId ?? current.interrupts[0]?.id;
|
|
4888
|
+
if (!id) return;
|
|
4889
|
+
responsesRef.current[id] = {
|
|
4890
|
+
status: "resolved",
|
|
4891
|
+
payload
|
|
4892
|
+
};
|
|
4893
|
+
return submitStandardIfComplete(current.interrupts);
|
|
4894
|
+
}, [
|
|
4895
|
+
agent,
|
|
4896
|
+
copilotkit,
|
|
4897
|
+
submitStandardIfComplete
|
|
4898
|
+
]);
|
|
4899
|
+
const cancel = (0, react.useCallback)(async (interruptId) => {
|
|
4900
|
+
const current = pendingRef.current;
|
|
4901
|
+
if (!current) return;
|
|
4902
|
+
if (current.kind === "legacy") {
|
|
4903
|
+
console.warn("[CopilotKit] useInterrupt: cancel() is not supported for legacy on_interrupt interrupts; dismissing.");
|
|
4904
|
+
setPending(null);
|
|
4905
|
+
return;
|
|
4906
|
+
}
|
|
4907
|
+
if (current.interrupts.length > 1 && interruptId === void 0) console.warn(`[CopilotKit] useInterrupt: resolve()/cancel() called without an interruptId while ${current.interrupts.length} interrupts are open; defaulting to the first. Pass an interruptId to address a specific interrupt.`);
|
|
4908
|
+
const id = interruptId ?? current.interrupts[0]?.id;
|
|
4909
|
+
if (!id) return;
|
|
4910
|
+
responsesRef.current[id] = { status: "cancelled" };
|
|
4911
|
+
return submitStandardIfComplete(current.interrupts);
|
|
4912
|
+
}, [submitStandardIfComplete]);
|
|
4689
4913
|
const renderRef = (0, react.useRef)(config.render);
|
|
4690
4914
|
renderRef.current = config.render;
|
|
4691
4915
|
const enabledRef = (0, react.useRef)(config.enabled);
|
|
@@ -4694,6 +4918,8 @@ function useInterrupt(config) {
|
|
|
4694
4918
|
handlerRef.current = config.handler;
|
|
4695
4919
|
const resolveRef = (0, react.useRef)(resolve);
|
|
4696
4920
|
resolveRef.current = resolve;
|
|
4921
|
+
const cancelRef = (0, react.useRef)(cancel);
|
|
4922
|
+
cancelRef.current = cancel;
|
|
4697
4923
|
const isEnabled = (event) => {
|
|
4698
4924
|
const predicate = enabledRef.current;
|
|
4699
4925
|
if (!predicate) return true;
|
|
@@ -4705,11 +4931,12 @@ function useInterrupt(config) {
|
|
|
4705
4931
|
}
|
|
4706
4932
|
};
|
|
4707
4933
|
(0, react.useEffect)(() => {
|
|
4708
|
-
if (!
|
|
4934
|
+
if (!pending) {
|
|
4709
4935
|
setHandlerResult(null);
|
|
4710
4936
|
return;
|
|
4711
4937
|
}
|
|
4712
|
-
|
|
4938
|
+
const legacyEvent = toLegacyEvent(pending);
|
|
4939
|
+
if (!isEnabled(legacyEvent)) {
|
|
4713
4940
|
setHandlerResult(null);
|
|
4714
4941
|
return;
|
|
4715
4942
|
}
|
|
@@ -4722,8 +4949,11 @@ function useInterrupt(config) {
|
|
|
4722
4949
|
let maybePromise;
|
|
4723
4950
|
try {
|
|
4724
4951
|
maybePromise = handler({
|
|
4725
|
-
event:
|
|
4726
|
-
|
|
4952
|
+
event: legacyEvent,
|
|
4953
|
+
interrupt: pending.kind === "standard" ? pending.interrupts[0] : null,
|
|
4954
|
+
interrupts: pending.kind === "standard" ? pending.interrupts : [],
|
|
4955
|
+
resolve: resolveRef.current,
|
|
4956
|
+
cancel: cancelRef.current
|
|
4727
4957
|
});
|
|
4728
4958
|
} catch (err) {
|
|
4729
4959
|
console.error("[CopilotKit] useInterrupt handler threw; result will be null:", err);
|
|
@@ -4742,19 +4972,24 @@ function useInterrupt(config) {
|
|
|
4742
4972
|
return () => {
|
|
4743
4973
|
cancelled = true;
|
|
4744
4974
|
};
|
|
4745
|
-
}, [
|
|
4975
|
+
}, [pending]);
|
|
4746
4976
|
const element = (0, react.useMemo)(() => {
|
|
4747
|
-
if (!
|
|
4748
|
-
|
|
4977
|
+
if (!pending) return null;
|
|
4978
|
+
const legacyEvent = toLegacyEvent(pending);
|
|
4979
|
+
if (!isEnabled(legacyEvent)) return null;
|
|
4749
4980
|
return renderRef.current({
|
|
4750
|
-
event:
|
|
4981
|
+
event: legacyEvent,
|
|
4982
|
+
interrupt: pending.kind === "standard" ? pending.interrupts[0] : null,
|
|
4983
|
+
interrupts: pending.kind === "standard" ? pending.interrupts : [],
|
|
4751
4984
|
result: handlerResult,
|
|
4752
|
-
resolve
|
|
4985
|
+
resolve,
|
|
4986
|
+
cancel
|
|
4753
4987
|
});
|
|
4754
4988
|
}, [
|
|
4755
|
-
|
|
4989
|
+
pending,
|
|
4756
4990
|
handlerResult,
|
|
4757
|
-
resolve
|
|
4991
|
+
resolve,
|
|
4992
|
+
cancel
|
|
4758
4993
|
]);
|
|
4759
4994
|
(0, react.useEffect)(() => {
|
|
4760
4995
|
if (config.renderInChat === false) return;
|
|
@@ -4779,7 +5014,7 @@ function useThreadStoreSelector(store, selector) {
|
|
|
4779
5014
|
return (0, react.useSyncExternalStore)((0, react.useCallback)((onStoreChange) => {
|
|
4780
5015
|
const subscription = store.select(selector).subscribe(onStoreChange);
|
|
4781
5016
|
return () => subscription.unsubscribe();
|
|
4782
|
-
}, [store, selector]), () => selector(store.getState()));
|
|
5017
|
+
}, [store, selector]), () => selector(store.getState()), () => selector(store.getServerState()));
|
|
4783
5018
|
}
|
|
4784
5019
|
/**
|
|
4785
5020
|
* React hook for listing and managing Intelligence platform threads.
|
|
@@ -4790,9 +5025,9 @@ function useThreadStoreSelector(store, selector) {
|
|
|
4790
5025
|
* current without polling — thread creates, renames, archives, and deletes
|
|
4791
5026
|
* from any client are reflected immediately.
|
|
4792
5027
|
*
|
|
4793
|
-
* Mutation methods (`renameThread`, `archiveThread`, `
|
|
4794
|
-
* promises that resolve once the platform confirms the
|
|
4795
|
-
* with an `Error` on failure.
|
|
5028
|
+
* Mutation methods (`renameThread`, `archiveThread`, `unarchiveThread`,
|
|
5029
|
+
* `deleteThread`) return promises that resolve once the platform confirms the
|
|
5030
|
+
* operation and reject with an `Error` on failure.
|
|
4796
5031
|
*
|
|
4797
5032
|
* @param input - Agent identifier and optional list controls.
|
|
4798
5033
|
* @returns Thread list state and stable mutation callbacks.
|
|
@@ -4822,7 +5057,7 @@ function useThreadStoreSelector(store, selector) {
|
|
|
4822
5057
|
* }
|
|
4823
5058
|
* ```
|
|
4824
5059
|
*/
|
|
4825
|
-
function useThreads$1({ agentId, includeArchived, limit }) {
|
|
5060
|
+
function useThreads$1({ agentId, includeArchived, limit, enabled = true }) {
|
|
4826
5061
|
const { copilotkit } = useCopilotKit();
|
|
4827
5062
|
const [store] = (0, react.useState)(() => (0, _copilotkit_core.ɵcreateThreadStore)({ fetch: globalThis.fetch }));
|
|
4828
5063
|
const coreThreads = useThreadStoreSelector(store, _copilotkit_core.ɵselectThreads);
|
|
@@ -4839,6 +5074,7 @@ function useThreads$1({ agentId, includeArchived, limit }) {
|
|
|
4839
5074
|
const storeError = useThreadStoreSelector(store, _copilotkit_core.ɵselectThreadsError);
|
|
4840
5075
|
const hasMoreThreads = useThreadStoreSelector(store, _copilotkit_core.ɵselectHasNextPage);
|
|
4841
5076
|
const isFetchingMoreThreads = useThreadStoreSelector(store, _copilotkit_core.ɵselectIsFetchingNextPage);
|
|
5077
|
+
const isMutating = useThreadStoreSelector(store, _copilotkit_core.ɵselectIsMutating);
|
|
4842
5078
|
const headersKey = (0, react.useMemo)(() => {
|
|
4843
5079
|
return JSON.stringify(Object.entries(copilotkit.headers ?? {}).sort(([left], [right]) => left.localeCompare(right)));
|
|
4844
5080
|
}, [copilotkit.headers]);
|
|
@@ -4859,9 +5095,16 @@ function useThreads$1({ agentId, includeArchived, limit }) {
|
|
|
4859
5095
|
return /* @__PURE__ */ new Error("Thread mutations are not available on this CopilotKit runtime");
|
|
4860
5096
|
}, [threadMutationsSupported]);
|
|
4861
5097
|
const [hasDispatchedContext, setHasDispatchedContext] = (0, react.useState)(false);
|
|
4862
|
-
const preConnectLoading = !!copilotkit.runtimeUrl && !threadEndpointsUnavailable && !hasDispatchedContext;
|
|
4863
|
-
const
|
|
4864
|
-
|
|
5098
|
+
const preConnectLoading = enabled && !!copilotkit.runtimeUrl && !threadEndpointsUnavailable && !hasDispatchedContext;
|
|
5099
|
+
const [configErrorDismissed, setConfigErrorDismissed] = (0, react.useState)(false);
|
|
5100
|
+
(0, react.useEffect)(() => {
|
|
5101
|
+
setConfigErrorDismissed(false);
|
|
5102
|
+
}, [runtimeError, threadEndpointsError]);
|
|
5103
|
+
const activeRuntimeError = configErrorDismissed ? null : runtimeError;
|
|
5104
|
+
const activeThreadEndpointsError = configErrorDismissed ? null : threadEndpointsError;
|
|
5105
|
+
const isLoading = activeRuntimeError || activeThreadEndpointsError ? false : preConnectLoading || storeIsLoading;
|
|
5106
|
+
const error = activeRuntimeError ?? activeThreadEndpointsError ?? storeError;
|
|
5107
|
+
const listError = storeError;
|
|
4865
5108
|
(0, react.useEffect)(() => {
|
|
4866
5109
|
store.start();
|
|
4867
5110
|
return () => {
|
|
@@ -4869,6 +5112,7 @@ function useThreads$1({ agentId, includeArchived, limit }) {
|
|
|
4869
5112
|
};
|
|
4870
5113
|
}, [store]);
|
|
4871
5114
|
(0, react.useEffect)(() => {
|
|
5115
|
+
if (!enabled) return;
|
|
4872
5116
|
copilotkit.registerThreadStore(agentId, store);
|
|
4873
5117
|
return () => {
|
|
4874
5118
|
copilotkit.unregisterThreadStore(agentId);
|
|
@@ -4876,9 +5120,15 @@ function useThreads$1({ agentId, includeArchived, limit }) {
|
|
|
4876
5120
|
}, [
|
|
4877
5121
|
copilotkit,
|
|
4878
5122
|
agentId,
|
|
4879
|
-
store
|
|
5123
|
+
store,
|
|
5124
|
+
enabled
|
|
4880
5125
|
]);
|
|
4881
5126
|
(0, react.useEffect)(() => {
|
|
5127
|
+
if (!enabled) {
|
|
5128
|
+
store.setContext(null);
|
|
5129
|
+
setHasDispatchedContext(false);
|
|
5130
|
+
return;
|
|
5131
|
+
}
|
|
4882
5132
|
if (!copilotkit.runtimeUrl) {
|
|
4883
5133
|
store.setContext(null);
|
|
4884
5134
|
setHasDispatchedContext(false);
|
|
@@ -4902,6 +5152,7 @@ function useThreads$1({ agentId, includeArchived, limit }) {
|
|
|
4902
5152
|
setHasDispatchedContext(true);
|
|
4903
5153
|
}, [
|
|
4904
5154
|
store,
|
|
5155
|
+
enabled,
|
|
4905
5156
|
copilotkit.runtimeUrl,
|
|
4906
5157
|
runtimeStatus,
|
|
4907
5158
|
headersKey,
|
|
@@ -4919,16 +5170,25 @@ function useThreads$1({ agentId, includeArchived, limit }) {
|
|
|
4919
5170
|
}, [threadMutationsError]);
|
|
4920
5171
|
const renameThread = (0, react.useMemo)(() => guardMutation((threadId, name) => store.renameThread(threadId, name)), [store, guardMutation]);
|
|
4921
5172
|
const archiveThread = (0, react.useMemo)(() => guardMutation((threadId) => store.archiveThread(threadId)), [store, guardMutation]);
|
|
5173
|
+
const unarchiveThread = (0, react.useMemo)(() => guardMutation((threadId) => store.unarchiveThread(threadId)), [store, guardMutation]);
|
|
4922
5174
|
const deleteThread = (0, react.useMemo)(() => guardMutation((threadId) => store.deleteThread(threadId)), [store, guardMutation]);
|
|
4923
5175
|
return {
|
|
4924
5176
|
threads,
|
|
4925
5177
|
isLoading,
|
|
4926
5178
|
error,
|
|
5179
|
+
listError,
|
|
4927
5180
|
hasMoreThreads,
|
|
4928
5181
|
isFetchingMoreThreads,
|
|
5182
|
+
isMutating,
|
|
4929
5183
|
fetchMoreThreads: (0, react.useCallback)(() => store.fetchNextPage(), [store]),
|
|
5184
|
+
refetchThreads: (0, react.useCallback)(() => store.refetchThreads(), [store]),
|
|
5185
|
+
startNewThread: (0, react.useCallback)(() => {
|
|
5186
|
+
setConfigErrorDismissed(true);
|
|
5187
|
+
store.startNewThread();
|
|
5188
|
+
}, [store]),
|
|
4930
5189
|
renameThread,
|
|
4931
5190
|
archiveThread,
|
|
5191
|
+
unarchiveThread,
|
|
4932
5192
|
deleteThread
|
|
4933
5193
|
};
|
|
4934
5194
|
}
|
|
@@ -6112,7 +6372,7 @@ const DefaultContainer = react.default.forwardRef(function DefaultContainer({ cl
|
|
|
6112
6372
|
ref,
|
|
6113
6373
|
"data-copilotkit": true,
|
|
6114
6374
|
"data-testid": "copilot-suggestions",
|
|
6115
|
-
className: cn("cpk:flex cpk:flex-wrap cpk:items-center cpk:gap-1.5 cpk:sm:gap-2 cpk:pl-0 cpk:pr-4 cpk:
|
|
6375
|
+
className: cn("cpk:flex cpk:flex-wrap cpk:items-center cpk:gap-1.5 cpk:sm:gap-2 cpk:pl-0 cpk:pr-4 cpk:@3xl:px-0 cpk:pointer-events-none", className),
|
|
6116
6376
|
...props
|
|
6117
6377
|
});
|
|
6118
6378
|
});
|
|
@@ -7217,7 +7477,7 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
7217
7477
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7218
7478
|
className: "cpk:max-w-3xl cpk:mx-auto",
|
|
7219
7479
|
children: [BoundMessageView, hasSuggestions ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7220
|
-
className: "cpk:pl-0 cpk:pr-4 cpk:
|
|
7480
|
+
className: "cpk:pl-0 cpk:pr-4 cpk:@3xl:px-0 cpk:mt-4",
|
|
7221
7481
|
children: BoundSuggestionView
|
|
7222
7482
|
}) : null]
|
|
7223
7483
|
})
|
|
@@ -7260,7 +7520,7 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
7260
7520
|
onDragOver,
|
|
7261
7521
|
onDragLeave,
|
|
7262
7522
|
onDrop,
|
|
7263
|
-
className: cn("copilotKitChat cpk:relative cpk:h-full cpk:flex cpk:flex-col", className),
|
|
7523
|
+
className: cn("copilotKitChat cpk:@container cpk:relative cpk:h-full cpk:flex cpk:flex-col", className),
|
|
7264
7524
|
...props,
|
|
7265
7525
|
children: [dragOver && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DropOverlay, {}), BoundWelcomeScreen]
|
|
7266
7526
|
});
|
|
@@ -7282,7 +7542,7 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
7282
7542
|
onDragOver,
|
|
7283
7543
|
onDragLeave,
|
|
7284
7544
|
onDrop,
|
|
7285
|
-
className: cn("copilotKitChat cpk:relative cpk:h-full cpk:flex cpk:flex-col", className),
|
|
7545
|
+
className: cn("copilotKitChat cpk:@container cpk:relative cpk:h-full cpk:flex cpk:flex-col", className),
|
|
7286
7546
|
...props,
|
|
7287
7547
|
children: [
|
|
7288
7548
|
dragOver && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DropOverlay, {}),
|
|
@@ -7321,7 +7581,7 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
7321
7581
|
minHeight: 0
|
|
7322
7582
|
},
|
|
7323
7583
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7324
|
-
className: "cpk:px-4 cpk:
|
|
7584
|
+
className: "cpk:px-4 cpk:@3xl:px-0 cpk:[div[data-sidebar-chat]_&]:px-8 cpk:[div[data-popup-chat]_&]:px-6",
|
|
7325
7585
|
children
|
|
7326
7586
|
})
|
|
7327
7587
|
}),
|
|
@@ -7354,7 +7614,7 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
7354
7614
|
...props,
|
|
7355
7615
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7356
7616
|
ref: contentRef,
|
|
7357
|
-
className: "cpk:px-4 cpk:
|
|
7617
|
+
className: "cpk:px-4 cpk:@3xl:px-0 cpk:[div[data-sidebar-chat]_&]:px-8 cpk:[div[data-popup-chat]_&]:px-6",
|
|
7358
7618
|
children
|
|
7359
7619
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7360
7620
|
ref: spacerRef,
|
|
@@ -7416,7 +7676,7 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
7416
7676
|
if (!hasMounted) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7417
7677
|
className: "cpk:h-full cpk:max-h-full cpk:flex cpk:flex-col cpk:min-h-0 cpk:overflow-y-auto cpk:overflow-x-hidden",
|
|
7418
7678
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7419
|
-
className: "cpk:px-4 cpk:
|
|
7679
|
+
className: "cpk:px-4 cpk:@3xl:px-0 cpk:[div[data-sidebar-chat]_&]:px-8 cpk:[div[data-popup-chat]_&]:px-6",
|
|
7420
7680
|
children
|
|
7421
7681
|
})
|
|
7422
7682
|
});
|
|
@@ -7431,7 +7691,7 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
7431
7691
|
children: [
|
|
7432
7692
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7433
7693
|
ref: contentRef,
|
|
7434
|
-
className: "cpk:px-4 cpk:
|
|
7694
|
+
className: "cpk:px-4 cpk:@3xl:px-0 cpk:[div[data-sidebar-chat]_&]:px-8 cpk:[div[data-popup-chat]_&]:px-6",
|
|
7435
7695
|
children
|
|
7436
7696
|
}),
|
|
7437
7697
|
BoundFeather,
|
|
@@ -7695,9 +7955,17 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
7695
7955
|
const { messageView: providedMessageView, suggestionView: providedSuggestionView, onStop: providedStopHandler, ...restProps } = props;
|
|
7696
7956
|
const [lastConnectedThreadId, setLastConnectedThreadId] = (0, react.useState)(null);
|
|
7697
7957
|
const isConnecting = hasExplicitThreadId && lastConnectedThreadId !== resolvedThreadId;
|
|
7958
|
+
const previousThreadIdRef = (0, react.useRef)(null);
|
|
7959
|
+
const hasExplicitThreadIdRef = (0, react.useRef)(hasExplicitThreadId);
|
|
7960
|
+
hasExplicitThreadIdRef.current = hasExplicitThreadId;
|
|
7698
7961
|
(0, react.useEffect)(() => {
|
|
7962
|
+
const threadChanged = previousThreadIdRef.current !== resolvedThreadId;
|
|
7963
|
+
previousThreadIdRef.current = resolvedThreadId;
|
|
7699
7964
|
agent.threadId = resolvedThreadId;
|
|
7700
|
-
if (!hasExplicitThreadId)
|
|
7965
|
+
if (!hasExplicitThreadId) {
|
|
7966
|
+
if (threadChanged && agent.messages.length > 0) agent.setMessages([]);
|
|
7967
|
+
return;
|
|
7968
|
+
}
|
|
7701
7969
|
let detached = false;
|
|
7702
7970
|
const connectAbortController = new AbortController();
|
|
7703
7971
|
if (agent instanceof _ag_ui_client.HttpAgent) agent.abortController = connectAbortController;
|
|
@@ -7711,6 +7979,7 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
7711
7979
|
if (!detached) (typeof requestAnimationFrame === "function" ? requestAnimationFrame : (cb) => setTimeout(cb, 16))(() => {
|
|
7712
7980
|
if (!detached) setLastConnectedThreadId(resolvedThreadId);
|
|
7713
7981
|
});
|
|
7982
|
+
else if (!hasExplicitThreadIdRef.current) agentToConnect.setMessages([]);
|
|
7714
7983
|
}
|
|
7715
7984
|
};
|
|
7716
7985
|
connect(agent);
|
|
@@ -7726,8 +7995,10 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
7726
7995
|
hasExplicitThreadId
|
|
7727
7996
|
]);
|
|
7728
7997
|
const waitForActiveRunToSettle = (0, react.useCallback)(async () => {
|
|
7729
|
-
|
|
7730
|
-
|
|
7998
|
+
const maybeAware = agent;
|
|
7999
|
+
const activeRunCompletionPromise = (0, _copilotkit_core.isRunCompletionAware)(maybeAware) ? maybeAware.activeRunCompletionPromise : void 0;
|
|
8000
|
+
if (agent.isRunning && activeRunCompletionPromise) try {
|
|
8001
|
+
await activeRunCompletionPromise;
|
|
7731
8002
|
} catch (error) {
|
|
7732
8003
|
console.error("CopilotChat: in-flight run rejected while queuing send", error);
|
|
7733
8004
|
}
|
|
@@ -8059,18 +8330,46 @@ CopilotChatToggleButton.displayName = "CopilotChatToggleButton";
|
|
|
8059
8330
|
|
|
8060
8331
|
//#endregion
|
|
8061
8332
|
//#region src/v2/components/chat/CopilotModalHeader.tsx
|
|
8062
|
-
|
|
8333
|
+
/**
|
|
8334
|
+
* Reactively tracks whether the viewport is in the mobile range (≤767px) — the
|
|
8335
|
+
* same breakpoint the drawer + chat coordination use. SSR-safe: starts `false`
|
|
8336
|
+
* (desktop) so the server render and first client render agree, then syncs on
|
|
8337
|
+
* mount and on resize.
|
|
8338
|
+
*/
|
|
8339
|
+
function useIsMobileViewport() {
|
|
8340
|
+
const [isMobile, setIsMobile] = (0, react.useState)(false);
|
|
8341
|
+
(0, react.useEffect)(() => {
|
|
8342
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
|
|
8343
|
+
const mql = window.matchMedia("(max-width: 767px)");
|
|
8344
|
+
const update = () => setIsMobile(mql.matches);
|
|
8345
|
+
update();
|
|
8346
|
+
mql.addEventListener("change", update);
|
|
8347
|
+
return () => mql.removeEventListener("change", update);
|
|
8348
|
+
}, []);
|
|
8349
|
+
return isMobile;
|
|
8350
|
+
}
|
|
8351
|
+
function CopilotModalHeader({ title, titleContent, closeButton, drawerLauncher, children, className, ...rest }) {
|
|
8063
8352
|
const configuration = useCopilotChatConfiguration();
|
|
8064
8353
|
const fallbackTitle = configuration?.labels.modalHeaderTitle ?? CopilotChatDefaultLabels.modalHeaderTitle;
|
|
8065
8354
|
const resolvedTitle = title ?? fallbackTitle;
|
|
8355
|
+
const isMobile = useIsMobileViewport();
|
|
8356
|
+
const drawerRegistered = (configuration?.drawerRegistered ?? false) && isMobile;
|
|
8066
8357
|
const handleClose = (0, react.useCallback)(() => {
|
|
8067
8358
|
configuration?.setModalOpen?.(false);
|
|
8068
8359
|
}, [configuration]);
|
|
8360
|
+
const handleToggleDrawer = (0, react.useCallback)(() => {
|
|
8361
|
+
configuration?.setDrawerOpen?.(!configuration.drawerOpen);
|
|
8362
|
+
}, [configuration]);
|
|
8069
8363
|
const BoundTitle = renderSlot(titleContent, CopilotModalHeader.Title, { children: resolvedTitle });
|
|
8070
8364
|
const BoundCloseButton = renderSlot(closeButton, CopilotModalHeader.CloseButton, { onClick: handleClose });
|
|
8365
|
+
const BoundDrawerLauncher = drawerRegistered ? renderSlot(drawerLauncher, CopilotModalHeader.DrawerLauncher, {
|
|
8366
|
+
onClick: handleToggleDrawer,
|
|
8367
|
+
"aria-expanded": configuration?.drawerOpen ?? false
|
|
8368
|
+
}) : null;
|
|
8071
8369
|
if (children) return children({
|
|
8072
8370
|
titleContent: BoundTitle,
|
|
8073
8371
|
closeButton: BoundCloseButton,
|
|
8372
|
+
drawerLauncher: BoundDrawerLauncher,
|
|
8074
8373
|
title: resolvedTitle,
|
|
8075
8374
|
...rest
|
|
8076
8375
|
});
|
|
@@ -8083,8 +8382,8 @@ function CopilotModalHeader({ title, titleContent, closeButton, children, classN
|
|
|
8083
8382
|
className: "cpk:flex cpk:w-full cpk:items-center cpk:gap-2",
|
|
8084
8383
|
children: [
|
|
8085
8384
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8086
|
-
className: "cpk:flex-1",
|
|
8087
|
-
"aria-hidden": "true"
|
|
8385
|
+
className: "cpk:flex cpk:flex-1 cpk:justify-start",
|
|
8386
|
+
children: BoundDrawerLauncher ?? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { "aria-hidden": "true" })
|
|
8088
8387
|
}),
|
|
8089
8388
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8090
8389
|
className: "cpk:flex cpk:flex-1 cpk:justify-center cpk:text-center",
|
|
@@ -8117,9 +8416,21 @@ CopilotModalHeader.displayName = "CopilotModalHeader";
|
|
|
8117
8416
|
"aria-hidden": "true"
|
|
8118
8417
|
})
|
|
8119
8418
|
});
|
|
8419
|
+
_CopilotModalHeader.DrawerLauncher = ({ className, ...props }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8420
|
+
type: "button",
|
|
8421
|
+
"data-testid": "copilot-threads-drawer-launcher",
|
|
8422
|
+
className: cn("cpk:inline-flex cpk:size-8 cpk:items-center cpk:justify-center cpk:rounded-full cpk:text-muted-foreground cpk:transition cpk:cursor-pointer", "cpk:hover:bg-muted cpk:hover:text-foreground cpk:focus-visible:outline-none cpk:focus-visible:ring-2 cpk:focus-visible:ring-ring", className),
|
|
8423
|
+
"aria-label": "Open threads",
|
|
8424
|
+
...props,
|
|
8425
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.PanelLeftOpen, {
|
|
8426
|
+
className: "cpk:h-4 cpk:w-4",
|
|
8427
|
+
"aria-hidden": "true"
|
|
8428
|
+
})
|
|
8429
|
+
});
|
|
8120
8430
|
})(CopilotModalHeader || (CopilotModalHeader = {}));
|
|
8121
8431
|
CopilotModalHeader.Title.displayName = "CopilotModalHeader.Title";
|
|
8122
8432
|
CopilotModalHeader.CloseButton.displayName = "CopilotModalHeader.CloseButton";
|
|
8433
|
+
CopilotModalHeader.DrawerLauncher.displayName = "CopilotModalHeader.DrawerLauncher";
|
|
8123
8434
|
|
|
8124
8435
|
//#endregion
|
|
8125
8436
|
//#region src/v2/components/chat/CopilotSidebarView.tsx
|
|
@@ -8477,6 +8788,322 @@ function CopilotPopup({ header, toggleButton, defaultOpen, width, height, clickO
|
|
|
8477
8788
|
}
|
|
8478
8789
|
CopilotPopup.displayName = "CopilotPopup";
|
|
8479
8790
|
|
|
8791
|
+
//#endregion
|
|
8792
|
+
//#region src/v2/components/chat/CopilotThreadsDrawer.tsx
|
|
8793
|
+
/**
|
|
8794
|
+
* Maps a {@link Thread} from {@link useThreads} to the element's
|
|
8795
|
+
* {@link DrawerThread} view shape. The shapes are structurally compatible; this
|
|
8796
|
+
* narrows to exactly the fields the element renders so the element never sees
|
|
8797
|
+
* platform-internal fields.
|
|
8798
|
+
*/
|
|
8799
|
+
function toDrawerThread(thread) {
|
|
8800
|
+
return {
|
|
8801
|
+
id: thread.id,
|
|
8802
|
+
name: thread.name,
|
|
8803
|
+
archived: thread.archived,
|
|
8804
|
+
createdAt: thread.createdAt,
|
|
8805
|
+
updatedAt: thread.updatedAt,
|
|
8806
|
+
...thread.lastRunAt !== void 0 ? { lastRunAt: thread.lastRunAt } : {}
|
|
8807
|
+
};
|
|
8808
|
+
}
|
|
8809
|
+
/** The chat input textarea's documented `data-testid`. */
|
|
8810
|
+
const CHAT_INPUT_TESTID = "copilot-chat-textarea";
|
|
8811
|
+
/** The chat view container's documented `data-testid`. */
|
|
8812
|
+
const CHAT_CONTAINER_TESTID = "copilot-chat";
|
|
8813
|
+
/**
|
|
8814
|
+
* Returns the chat input element for focus-return after a thread is selected.
|
|
8815
|
+
*
|
|
8816
|
+
* Best-effort and SCOPED: walks up from the drawer element looking for an
|
|
8817
|
+
* ancestor that contains a chat-view container (`data-testid="copilot-chat"`),
|
|
8818
|
+
* then returns the chat input within that subtree. This avoids focusing the
|
|
8819
|
+
* wrong composer on a page hosting more than one chat (multi-chat dashboards),
|
|
8820
|
+
* where a document-global lookup would grab whichever input appears first in
|
|
8821
|
+
* DOM order rather than the one this drawer drives.
|
|
8822
|
+
*
|
|
8823
|
+
* Falls back to a document-global lookup when no scoping ancestor is found
|
|
8824
|
+
* (e.g. the drawer and chat share no common container, or headless usage),
|
|
8825
|
+
* and returns `null` when there is no chat input at all.
|
|
8826
|
+
*
|
|
8827
|
+
* @param origin - The drawer element to scope the search from.
|
|
8828
|
+
*/
|
|
8829
|
+
function findChatInput(origin) {
|
|
8830
|
+
if (typeof document === "undefined") return null;
|
|
8831
|
+
const container = origin?.closest?.(`[data-testid="${CHAT_CONTAINER_TESTID}"]`);
|
|
8832
|
+
if (container) {
|
|
8833
|
+
const scoped = container.querySelector(`[data-testid="${CHAT_INPUT_TESTID}"]`);
|
|
8834
|
+
if (scoped) return scoped;
|
|
8835
|
+
}
|
|
8836
|
+
return document.querySelector(`[data-testid="${CHAT_INPUT_TESTID}"]`);
|
|
8837
|
+
}
|
|
8838
|
+
/**
|
|
8839
|
+
* React wrapper for the shadow-DOM `<copilotkit-threads-drawer>` threads drawer.
|
|
8840
|
+
*
|
|
8841
|
+
* Responsibilities:
|
|
8842
|
+
* - Registers the custom element on the client (SSR-safe; nothing renders
|
|
8843
|
+
* during prerender to avoid hydration mismatch).
|
|
8844
|
+
* - Feeds the element domain data: `threads`, `loading`, `error`,
|
|
8845
|
+
* `activeThreadId`, `licensed`, fetch-more state.
|
|
8846
|
+
* - Routes the element's nine outbound events to core thread operations
|
|
8847
|
+
* ({@link useThreads}) and chat-configuration changes.
|
|
8848
|
+
* - Registers with the surrounding chat configuration so the header
|
|
8849
|
+
* thread-list launcher appears, and binds the element `open` state to the
|
|
8850
|
+
* configuration's `drawerOpen`.
|
|
8851
|
+
*
|
|
8852
|
+
* License gating is two-pronged: the locked view shows when no license is configured
|
|
8853
|
+
* (the runtime reported no license status) OR the `threads` feature is
|
|
8854
|
+
* explicitly unlicensed. While unlicensed, the thread fetch is skipped entirely
|
|
8855
|
+
* so an unlicensed drawer issues no network requests.
|
|
8856
|
+
*
|
|
8857
|
+
* Thread switching needs no host wiring: when `onThreadSelect`/`onNewThread`
|
|
8858
|
+
* are omitted, the wrapper drives the surrounding chat configuration directly
|
|
8859
|
+
* ({@link CopilotChatConfigurationValue.setActiveThreadId} /
|
|
8860
|
+
* {@link CopilotChatConfigurationValue.startNewThread}), so a bare drawer
|
|
8861
|
+
* connects to the picked thread and shows the welcome screen on "+ New". Pass
|
|
8862
|
+
* the callbacks only to take control yourself.
|
|
8863
|
+
*
|
|
8864
|
+
* @example
|
|
8865
|
+
* ```tsx
|
|
8866
|
+
* // Callback-free: the drawer drives the chat configuration itself.
|
|
8867
|
+
* <CopilotKitProvider runtimeUrl="/api/copilotkit" publicLicenseKey="ck_pub_...">
|
|
8868
|
+
* <CopilotChat />
|
|
8869
|
+
* <CopilotThreadsDrawer />
|
|
8870
|
+
* </CopilotKitProvider>
|
|
8871
|
+
* ```
|
|
8872
|
+
*/
|
|
8873
|
+
function CopilotThreadsDrawer({ agentId, onThreadSelect, onNewThread, onLicensed, licenseUrl, renderRow, label, limit, "data-testid": dataTestId = "copilot-threads-drawer" }) {
|
|
8874
|
+
const configuration = useCopilotChatConfiguration();
|
|
8875
|
+
const { status, checkFeature } = useLicenseContext();
|
|
8876
|
+
const licensePresent = status === "valid" || status === "expiring";
|
|
8877
|
+
const featureLicensed = checkFeature("threads");
|
|
8878
|
+
const licensed = licensePresent && featureLicensed;
|
|
8879
|
+
const licensePending = status === null;
|
|
8880
|
+
const resolvedAgentId = agentId ?? configuration?.agentId ?? "default";
|
|
8881
|
+
const activeThreadId = configuration?.threadId ?? null;
|
|
8882
|
+
const { threads, isLoading, listError, hasMoreThreads, isFetchingMoreThreads, archiveThread, unarchiveThread, deleteThread, fetchMoreThreads, refetchThreads, startNewThread } = useThreads$1({
|
|
8883
|
+
agentId: resolvedAgentId,
|
|
8884
|
+
includeArchived: true,
|
|
8885
|
+
enabled: licensed,
|
|
8886
|
+
...limit !== void 0 ? { limit } : {}
|
|
8887
|
+
});
|
|
8888
|
+
const drawerThreads = (0, react.useMemo)(() => threads.map(toDrawerThread), [threads]);
|
|
8889
|
+
const elementRef = (0, react.useRef)(null);
|
|
8890
|
+
const [mounted, setMounted] = (0, react.useState)(false);
|
|
8891
|
+
(0, react.useEffect)(() => {
|
|
8892
|
+
(0, _copilotkit_web_components_threads_drawer.defineCopilotKitThreadsDrawer)();
|
|
8893
|
+
setMounted(true);
|
|
8894
|
+
}, []);
|
|
8895
|
+
const registerDrawer = configuration?.registerDrawer;
|
|
8896
|
+
(0, react.useEffect)(() => {
|
|
8897
|
+
if (!registerDrawer) return;
|
|
8898
|
+
return registerDrawer();
|
|
8899
|
+
}, [registerDrawer]);
|
|
8900
|
+
const [localDrawerOpen, setLocalDrawerOpen] = (0, react.useState)(false);
|
|
8901
|
+
const drawerOpen = configuration ? configuration.drawerOpen : localDrawerOpen;
|
|
8902
|
+
const setDrawerOpen = configuration ? configuration.setDrawerOpen : setLocalDrawerOpen;
|
|
8903
|
+
const setActiveThreadId = configuration?.setActiveThreadId;
|
|
8904
|
+
const startNewThreadConfig = configuration?.startNewThread;
|
|
8905
|
+
const handleThreadSelected = (0, react.useCallback)((threadId) => {
|
|
8906
|
+
if (onThreadSelect) onThreadSelect(threadId);
|
|
8907
|
+
else setActiveThreadId?.(threadId, { explicit: true });
|
|
8908
|
+
findChatInput(elementRef.current)?.focus();
|
|
8909
|
+
}, [onThreadSelect, setActiveThreadId]);
|
|
8910
|
+
const handleNewThread = (0, react.useCallback)(() => {
|
|
8911
|
+
startNewThread();
|
|
8912
|
+
if (onNewThread) onNewThread();
|
|
8913
|
+
else startNewThreadConfig?.();
|
|
8914
|
+
}, [
|
|
8915
|
+
startNewThread,
|
|
8916
|
+
onNewThread,
|
|
8917
|
+
startNewThreadConfig
|
|
8918
|
+
]);
|
|
8919
|
+
const handleArchive = (0, react.useCallback)((threadId) => {
|
|
8920
|
+
archiveThread(threadId).catch((err) => {
|
|
8921
|
+
console.error("CopilotThreadsDrawer: archiveThread failed", err);
|
|
8922
|
+
});
|
|
8923
|
+
}, [archiveThread]);
|
|
8924
|
+
const handleUnarchive = (0, react.useCallback)((threadId) => {
|
|
8925
|
+
unarchiveThread(threadId).catch((err) => {
|
|
8926
|
+
console.error("CopilotThreadsDrawer: unarchiveThread failed", err);
|
|
8927
|
+
});
|
|
8928
|
+
}, [unarchiveThread]);
|
|
8929
|
+
const handleDelete = (0, react.useCallback)((threadId) => {
|
|
8930
|
+
const isActive = threadId === activeThreadId;
|
|
8931
|
+
deleteThread(threadId).then(() => {
|
|
8932
|
+
if (isActive) {
|
|
8933
|
+
startNewThread();
|
|
8934
|
+
if (onNewThread) onNewThread();
|
|
8935
|
+
else startNewThreadConfig?.();
|
|
8936
|
+
}
|
|
8937
|
+
}).catch((err) => {
|
|
8938
|
+
console.error("CopilotThreadsDrawer: deleteThread failed", err);
|
|
8939
|
+
});
|
|
8940
|
+
}, [
|
|
8941
|
+
deleteThread,
|
|
8942
|
+
activeThreadId,
|
|
8943
|
+
startNewThread,
|
|
8944
|
+
onNewThread,
|
|
8945
|
+
startNewThreadConfig
|
|
8946
|
+
]);
|
|
8947
|
+
const handleFilterChange = (0, react.useCallback)(() => {
|
|
8948
|
+
refetchThreads();
|
|
8949
|
+
}, [refetchThreads]);
|
|
8950
|
+
const handleRetry = (0, react.useCallback)((scope) => {
|
|
8951
|
+
if (scope === "fetch-more") fetchMoreThreads();
|
|
8952
|
+
else refetchThreads();
|
|
8953
|
+
}, [fetchMoreThreads, refetchThreads]);
|
|
8954
|
+
const handleOpenChange = (0, react.useCallback)((open) => {
|
|
8955
|
+
setDrawerOpen(open);
|
|
8956
|
+
}, [setDrawerOpen]);
|
|
8957
|
+
const handleLicensed = (0, react.useCallback)(() => {
|
|
8958
|
+
onLicensed?.();
|
|
8959
|
+
}, [onLicensed]);
|
|
8960
|
+
const handleLoadMore = (0, react.useCallback)(() => {
|
|
8961
|
+
fetchMoreThreads();
|
|
8962
|
+
}, [fetchMoreThreads]);
|
|
8963
|
+
const handlersRef = (0, react.useRef)({
|
|
8964
|
+
handleThreadSelected,
|
|
8965
|
+
handleNewThread,
|
|
8966
|
+
handleArchive,
|
|
8967
|
+
handleUnarchive,
|
|
8968
|
+
handleDelete,
|
|
8969
|
+
handleFilterChange,
|
|
8970
|
+
handleRetry,
|
|
8971
|
+
handleOpenChange,
|
|
8972
|
+
handleLicensed,
|
|
8973
|
+
handleLoadMore
|
|
8974
|
+
});
|
|
8975
|
+
handlersRef.current = {
|
|
8976
|
+
handleThreadSelected,
|
|
8977
|
+
handleNewThread,
|
|
8978
|
+
handleArchive,
|
|
8979
|
+
handleUnarchive,
|
|
8980
|
+
handleDelete,
|
|
8981
|
+
handleFilterChange,
|
|
8982
|
+
handleRetry,
|
|
8983
|
+
handleOpenChange,
|
|
8984
|
+
handleLicensed,
|
|
8985
|
+
handleLoadMore
|
|
8986
|
+
};
|
|
8987
|
+
(0, react.useEffect)(() => {
|
|
8988
|
+
const el = elementRef.current;
|
|
8989
|
+
if (!el) return;
|
|
8990
|
+
const onThreadSelected = (event) => {
|
|
8991
|
+
const detail = event.detail;
|
|
8992
|
+
handlersRef.current.handleThreadSelected(detail.threadId);
|
|
8993
|
+
};
|
|
8994
|
+
const onNewThreadEvent = () => handlersRef.current.handleNewThread();
|
|
8995
|
+
const onArchive = (event) => {
|
|
8996
|
+
const detail = event.detail;
|
|
8997
|
+
handlersRef.current.handleArchive(detail.threadId);
|
|
8998
|
+
};
|
|
8999
|
+
const onUnarchive = (event) => {
|
|
9000
|
+
const detail = event.detail;
|
|
9001
|
+
handlersRef.current.handleUnarchive(detail.threadId);
|
|
9002
|
+
};
|
|
9003
|
+
const onDelete = (event) => {
|
|
9004
|
+
const detail = event.detail;
|
|
9005
|
+
handlersRef.current.handleDelete(detail.threadId);
|
|
9006
|
+
};
|
|
9007
|
+
const onFilterChange = (_event) => {
|
|
9008
|
+
handlersRef.current.handleFilterChange();
|
|
9009
|
+
};
|
|
9010
|
+
const onOpenChangeEvent = (event) => {
|
|
9011
|
+
const detail = event.detail;
|
|
9012
|
+
handlersRef.current.handleOpenChange(detail.open);
|
|
9013
|
+
};
|
|
9014
|
+
const onRetry = (event) => {
|
|
9015
|
+
const detail = event.detail;
|
|
9016
|
+
handlersRef.current.handleRetry(detail.scope);
|
|
9017
|
+
};
|
|
9018
|
+
const onLicensedEvent = () => handlersRef.current.handleLicensed();
|
|
9019
|
+
const onLoadMore = () => handlersRef.current.handleLoadMore();
|
|
9020
|
+
el.addEventListener("thread-selected", onThreadSelected);
|
|
9021
|
+
el.addEventListener("new-thread", onNewThreadEvent);
|
|
9022
|
+
el.addEventListener("archive", onArchive);
|
|
9023
|
+
el.addEventListener("unarchive", onUnarchive);
|
|
9024
|
+
el.addEventListener("delete", onDelete);
|
|
9025
|
+
el.addEventListener("filter-change", onFilterChange);
|
|
9026
|
+
el.addEventListener("open-change", onOpenChangeEvent);
|
|
9027
|
+
el.addEventListener("retry", onRetry);
|
|
9028
|
+
el.addEventListener("licensed", onLicensedEvent);
|
|
9029
|
+
el.addEventListener("load-more", onLoadMore);
|
|
9030
|
+
return () => {
|
|
9031
|
+
el.removeEventListener("thread-selected", onThreadSelected);
|
|
9032
|
+
el.removeEventListener("new-thread", onNewThreadEvent);
|
|
9033
|
+
el.removeEventListener("archive", onArchive);
|
|
9034
|
+
el.removeEventListener("unarchive", onUnarchive);
|
|
9035
|
+
el.removeEventListener("delete", onDelete);
|
|
9036
|
+
el.removeEventListener("filter-change", onFilterChange);
|
|
9037
|
+
el.removeEventListener("open-change", onOpenChangeEvent);
|
|
9038
|
+
el.removeEventListener("retry", onRetry);
|
|
9039
|
+
el.removeEventListener("licensed", onLicensedEvent);
|
|
9040
|
+
el.removeEventListener("load-more", onLoadMore);
|
|
9041
|
+
};
|
|
9042
|
+
}, [mounted]);
|
|
9043
|
+
(0, react.useEffect)(() => {
|
|
9044
|
+
const el = elementRef.current;
|
|
9045
|
+
if (!el) return;
|
|
9046
|
+
el.threads = drawerThreads;
|
|
9047
|
+
}, [drawerThreads, mounted]);
|
|
9048
|
+
(0, react.useEffect)(() => {
|
|
9049
|
+
const el = elementRef.current;
|
|
9050
|
+
if (!el) return;
|
|
9051
|
+
el.loading = isLoading || licensePending;
|
|
9052
|
+
el.error = listError ? listError.message : null;
|
|
9053
|
+
el.activeThreadId = activeThreadId;
|
|
9054
|
+
el.licensed = licensed || licensePending;
|
|
9055
|
+
el.hasMore = hasMoreThreads;
|
|
9056
|
+
el.fetchingMore = isFetchingMoreThreads;
|
|
9057
|
+
}, [
|
|
9058
|
+
isLoading,
|
|
9059
|
+
listError,
|
|
9060
|
+
activeThreadId,
|
|
9061
|
+
licensed,
|
|
9062
|
+
licensePending,
|
|
9063
|
+
hasMoreThreads,
|
|
9064
|
+
isFetchingMoreThreads,
|
|
9065
|
+
mounted
|
|
9066
|
+
]);
|
|
9067
|
+
(0, react.useEffect)(() => {
|
|
9068
|
+
const el = elementRef.current;
|
|
9069
|
+
if (!el) return;
|
|
9070
|
+
el.open = drawerOpen;
|
|
9071
|
+
}, [drawerOpen, mounted]);
|
|
9072
|
+
(0, react.useEffect)(() => {
|
|
9073
|
+
const el = elementRef.current;
|
|
9074
|
+
if (!el) return;
|
|
9075
|
+
if (label !== void 0) el.label = label;
|
|
9076
|
+
}, [label, mounted]);
|
|
9077
|
+
(0, react.useEffect)(() => {
|
|
9078
|
+
const el = elementRef.current;
|
|
9079
|
+
if (!el) return;
|
|
9080
|
+
if (licenseUrl !== void 0) el.licenseUrl = licenseUrl;
|
|
9081
|
+
}, [licenseUrl, mounted]);
|
|
9082
|
+
const rowChildren = (0, react.useMemo)(() => {
|
|
9083
|
+
if (!renderRow) return null;
|
|
9084
|
+
return drawerThreads.map((drawerThread) => {
|
|
9085
|
+
const fullThread = threads.find((t) => t.id === drawerThread.id);
|
|
9086
|
+
if (!fullThread) return null;
|
|
9087
|
+
const content = renderRow(fullThread);
|
|
9088
|
+
if (content === null || content === void 0) return null;
|
|
9089
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9090
|
+
slot: `row:${drawerThread.id}`,
|
|
9091
|
+
children: content
|
|
9092
|
+
}, drawerThread.id);
|
|
9093
|
+
});
|
|
9094
|
+
}, [
|
|
9095
|
+
renderRow,
|
|
9096
|
+
drawerThreads,
|
|
9097
|
+
threads
|
|
9098
|
+
]);
|
|
9099
|
+
if (!mounted) return null;
|
|
9100
|
+
return react.default.createElement(_copilotkit_web_components_threads_drawer.COPILOTKIT_THREADS_DRAWER_TAG, {
|
|
9101
|
+
ref: elementRef,
|
|
9102
|
+
"data-testid": dataTestId
|
|
9103
|
+
}, rowChildren);
|
|
9104
|
+
}
|
|
9105
|
+
CopilotThreadsDrawer.displayName = "CopilotThreadsDrawer";
|
|
9106
|
+
|
|
8480
9107
|
//#endregion
|
|
8481
9108
|
//#region src/v2/components/WildcardToolCallRender.tsx
|
|
8482
9109
|
const WildcardToolCallRender = defineToolCallRenderer({
|
|
@@ -10166,6 +10793,7 @@ function CopilotKit({ children, ...props }) {
|
|
|
10166
10793
|
const showInspector = shouldShowDevConsole(props.enableInspector);
|
|
10167
10794
|
const publicApiKey = props.publicApiKey || props.publicLicenseKey;
|
|
10168
10795
|
const renderArr = (0, react.useMemo)(() => [{ render: CoAgentStateRenderBridge }], []);
|
|
10796
|
+
const { onError: _onError, ...v2Props } = props;
|
|
10169
10797
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToastProvider, {
|
|
10170
10798
|
enabled,
|
|
10171
10799
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotErrorBoundary, {
|
|
@@ -10174,7 +10802,7 @@ function CopilotKit({ children, ...props }) {
|
|
|
10174
10802
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ThreadsProvider, {
|
|
10175
10803
|
threadId: props.threadId,
|
|
10176
10804
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotKitProvider, {
|
|
10177
|
-
...
|
|
10805
|
+
...v2Props,
|
|
10178
10806
|
showDevConsole: showInspector,
|
|
10179
10807
|
renderCustomMessages: renderArr,
|
|
10180
10808
|
useSingleEndpoint: props.useSingleEndpoint ?? true,
|
|
@@ -10838,6 +11466,12 @@ Object.defineProperty(exports, 'CopilotSidebarView', {
|
|
|
10838
11466
|
return CopilotSidebarView;
|
|
10839
11467
|
}
|
|
10840
11468
|
});
|
|
11469
|
+
Object.defineProperty(exports, 'CopilotThreadsDrawer', {
|
|
11470
|
+
enumerable: true,
|
|
11471
|
+
get: function () {
|
|
11472
|
+
return CopilotThreadsDrawer;
|
|
11473
|
+
}
|
|
11474
|
+
});
|
|
10841
11475
|
Object.defineProperty(exports, 'DefaultCloseIcon', {
|
|
10842
11476
|
enumerable: true,
|
|
10843
11477
|
get: function () {
|
|
@@ -11126,4 +11760,4 @@ Object.defineProperty(exports, 'useToast', {
|
|
|
11126
11760
|
return useToast;
|
|
11127
11761
|
}
|
|
11128
11762
|
});
|
|
11129
|
-
//# sourceMappingURL=copilotkit-
|
|
11763
|
+
//# sourceMappingURL=copilotkit-CdpDZi3i.cjs.map
|