@copilotkit/react-core 1.70.1 → 1.70.3
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-DiUK2Bhq.mjs → copilotkit-Ap_yisA5.mjs} +470 -98
- package/dist/copilotkit-Ap_yisA5.mjs.map +1 -0
- package/dist/{copilotkit-CxLT6zFx.cjs → copilotkit-BU3OvveB.cjs} +468 -96
- package/dist/copilotkit-BU3OvveB.cjs.map +1 -0
- package/dist/{copilotkit-DsWuxPUQ.d.mts → copilotkit-Bs98akp9.d.mts} +32 -2
- package/dist/{copilotkit-DsWuxPUQ.d.mts.map → copilotkit-Bs98akp9.d.mts.map} +1 -1
- package/dist/{copilotkit-CtF2clxZ.d.cts → copilotkit-X2eGbOwf.d.cts} +32 -2
- package/dist/{copilotkit-CtF2clxZ.d.cts.map → copilotkit-X2eGbOwf.d.cts.map} +1 -1
- 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 +273 -15
- package/dist/index.umd.js.map +1 -1
- package/dist/v2/headless.cjs +97 -2
- package/dist/v2/headless.cjs.map +1 -1
- package/dist/v2/headless.d.cts.map +1 -1
- package/dist/v2/headless.d.mts.map +1 -1
- package/dist/v2/headless.mjs +98 -3
- package/dist/v2/headless.mjs.map +1 -1
- package/dist/v2/index.cjs +1 -1
- package/dist/v2/index.css +1 -1
- package/dist/v2/index.d.cts +1 -1
- package/dist/v2/index.d.mts +1 -1
- package/dist/v2/index.mjs +1 -1
- package/dist/v2/index.umd.js +468 -96
- package/dist/v2/index.umd.js.map +1 -1
- package/package.json +7 -7
- package/skills/react-core/SKILL.md +1 -1
- package/skills/react-core/references/attachments.md +20 -0
- package/dist/copilotkit-CxLT6zFx.cjs.map +0 -1
- package/dist/copilotkit-DiUK2Bhq.mjs.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React$1 from "react";
|
|
2
|
-
import React, { createContext, forwardRef, memo, useCallback, useContext, useEffect, useId, useImperativeHandle, useLayoutEffect, useMemo, useReducer, useRef, useState, useSyncExternalStore } from "react";
|
|
2
|
+
import React, { createContext, createElement, forwardRef, memo, useCallback, useContext, useEffect, useId, useImperativeHandle, useLayoutEffect, useMemo, useReducer, useRef, useState, useSyncExternalStore } from "react";
|
|
3
3
|
import { CopilotKitCore, CopilotKitCoreErrorCode, CopilotKitCoreRuntimeConnectionStatus, ProxiedCopilotRuntimeAgent, ToolCallStatus, emitInspectorActiveThread, emitInspectorViewThreadResult, isInspectorThreadBridgeEnabled, isRunCompletionAware, onInspectorStopViewing, onInspectorViewThread, ɵInterruptState, ɵcreateThreadStore, ɵselectFetchMoreError, ɵselectHasNextPage, ɵselectIsFetchingNextPage, ɵselectIsMutating, ɵselectMemories, ɵselectMemoriesAvailable, ɵselectMemoriesError, ɵselectMemoriesIsLoading, ɵselectMemoriesRealtimeStatus, ɵselectThreads, ɵselectThreadsError, ɵselectThreadsIsLoading } from "@copilotkit/core";
|
|
4
4
|
import { HttpAgent, randomUUID } from "@ag-ui/client";
|
|
5
5
|
import { extendTailwindMerge, twMerge } from "tailwind-merge";
|
|
@@ -14,7 +14,7 @@ import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
|
|
14
14
|
import { Streamdown } from "streamdown";
|
|
15
15
|
import { CopilotKitContext, LicenseContext, useCopilotKit, useCopilotKit as useCopilotKit$1, useLicenseContext, useLicenseContext as useLicenseContext$1 } from "@copilotkit/react-core/v2/context";
|
|
16
16
|
import { z } from "zod";
|
|
17
|
-
import { A2UIProvider, A2UIRenderer, A2UI_SCHEMA_CONTEXT_DESCRIPTION, Catalog, DEFAULT_SURFACE_ID, buildCatalogContextValue, extractCatalogComponentSchemas, filterCatalog, initializeDefaultCatalog, injectStyles, useA2UIActions, useA2UIError, viewerTheme } from "@copilotkit/a2ui-renderer";
|
|
17
|
+
import { A2UIProvider, A2UIRenderer, A2UI_SCHEMA_CONTEXT_DESCRIPTION, Catalog, DEFAULT_SURFACE_ID, ROOT_COMPONENT_ID, buildCatalogContextValue, extractCatalogComponentSchemas, filterCatalog, initializeDefaultCatalog, injectStyles, useA2UIActions, useA2UIError, viewerTheme } from "@copilotkit/a2ui-renderer";
|
|
18
18
|
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
19
19
|
import { createPortal, flushSync } from "react-dom";
|
|
20
20
|
import { useVirtualizer } from "@tanstack/react-virtual";
|
|
@@ -268,6 +268,62 @@ const CopilotChatConfigurationProvider = ({ children, labels, agentId, threadId,
|
|
|
268
268
|
const useCopilotChatConfiguration = () => {
|
|
269
269
|
return useContext(CopilotChatConfiguration);
|
|
270
270
|
};
|
|
271
|
+
/**
|
|
272
|
+
* Reports modal open/close requests to the host, and — when `open` is
|
|
273
|
+
* supplied — makes the modal state of an already-established chat
|
|
274
|
+
* configuration **controlled** for the subtree it wraps.
|
|
275
|
+
*
|
|
276
|
+
* This is deliberately a scope component rather than another mode inside
|
|
277
|
+
* {@link CopilotChatConfigurationProvider}. The provider resolves modal state
|
|
278
|
+
* across a nested chain (own state, parent sync, drawer mutual-exclusion, the
|
|
279
|
+
* modal-closer registry); a controlled branch inside that resolution would add
|
|
280
|
+
* a fourth interacting mode. Overriding the context for the subtree instead
|
|
281
|
+
* leaves every one of those paths untouched:
|
|
282
|
+
*
|
|
283
|
+
* - `isModalOpen` is replaced with the host's `open`, so the rendered surface
|
|
284
|
+
* follows the prop from the very first frame (no open-then-close flash).
|
|
285
|
+
* - `setModalOpen` still calls the underlying setter, so the existing
|
|
286
|
+
* parent-sync and drawer mutual-exclusion side effects continue to run, and
|
|
287
|
+
* *then* reports the request through `onOpenChange`.
|
|
288
|
+
* - The wrapped setter is registered as the modal closer, so the drawer's
|
|
289
|
+
* mobile mutual-exclusion reaches the host instead of silently flipping
|
|
290
|
+
* state that nothing displays.
|
|
291
|
+
*
|
|
292
|
+
* A host that supplies `open` and ignores `onOpenChange` gets a modal pinned
|
|
293
|
+
* to `open`, which is the standard controlled-component contract. A host that
|
|
294
|
+
* supplies only `onOpenChange` is notified while the modal keeps managing
|
|
295
|
+
* itself.
|
|
296
|
+
*
|
|
297
|
+
* Renders `children` unchanged when no chat configuration is in scope.
|
|
298
|
+
*/
|
|
299
|
+
const ControlledModalOpenScope = ({ children, open, onOpenChange }) => {
|
|
300
|
+
const parentConfig = useContext(CopilotChatConfiguration);
|
|
301
|
+
const parentSetModalOpen = parentConfig?.setModalOpen;
|
|
302
|
+
const registerModalCloser = parentConfig?.ɵregisterModalCloser;
|
|
303
|
+
const setModalOpen = useCallback((next) => {
|
|
304
|
+
parentSetModalOpen?.(next);
|
|
305
|
+
onOpenChange?.(next);
|
|
306
|
+
}, [parentSetModalOpen, onOpenChange]);
|
|
307
|
+
useEffect(() => {
|
|
308
|
+
if (!registerModalCloser) return;
|
|
309
|
+
return registerModalCloser(setModalOpen);
|
|
310
|
+
}, [registerModalCloser, setModalOpen]);
|
|
311
|
+
const configurationValue = useMemo(() => parentConfig ? {
|
|
312
|
+
...parentConfig,
|
|
313
|
+
isModalOpen: open ?? parentConfig.isModalOpen,
|
|
314
|
+
setModalOpen
|
|
315
|
+
} : null, [
|
|
316
|
+
parentConfig,
|
|
317
|
+
open,
|
|
318
|
+
setModalOpen
|
|
319
|
+
]);
|
|
320
|
+
if (!configurationValue) return /* @__PURE__ */ jsx(Fragment$1, { children });
|
|
321
|
+
return /* @__PURE__ */ jsx(CopilotChatConfiguration.Provider, {
|
|
322
|
+
value: configurationValue,
|
|
323
|
+
children
|
|
324
|
+
});
|
|
325
|
+
};
|
|
326
|
+
ControlledModalOpenScope.displayName = "ControlledModalOpenScope";
|
|
271
327
|
|
|
272
328
|
//#endregion
|
|
273
329
|
//#region src/v2/lib/utils.ts
|
|
@@ -1463,6 +1519,29 @@ const ToolCallRenderer = React.memo(function ToolCallRenderer({ toolCall, toolMe
|
|
|
1463
1519
|
if (prevProps.RenderComponent !== nextProps.RenderComponent) return false;
|
|
1464
1520
|
return true;
|
|
1465
1521
|
});
|
|
1522
|
+
const IS_DEVELOPMENT$1 = process.env.NODE_ENV !== "production";
|
|
1523
|
+
/**
|
|
1524
|
+
* Reports tool calls that resolved to no renderer.
|
|
1525
|
+
*
|
|
1526
|
+
* A tool call with no renderer paints an empty message container and says
|
|
1527
|
+
* nothing else, so the only signal a developer gets today is a blank space in
|
|
1528
|
+
* the chat. This names the call and the renderers that *are* registered, which
|
|
1529
|
+
* is the whole diagnosis when the cause is a name that does not match.
|
|
1530
|
+
*
|
|
1531
|
+
* @param toolNames - The unmatched tool names collected during render.
|
|
1532
|
+
* @param registered - The registry as it stands now, re-read at report time.
|
|
1533
|
+
* @param alreadyWarned - Names already reported, mutated to keep this once per name.
|
|
1534
|
+
*/
|
|
1535
|
+
function warnAboutUnrenderedToolCalls(toolNames, registered, alreadyWarned) {
|
|
1536
|
+
const registeredNames = Array.from(new Set(registered.map((rc) => rc.name)));
|
|
1537
|
+
const hasWildcard = registeredNames.includes("*");
|
|
1538
|
+
for (const toolName of toolNames) {
|
|
1539
|
+
if (hasWildcard || registeredNames.includes(toolName)) continue;
|
|
1540
|
+
if (alreadyWarned.has(toolName)) continue;
|
|
1541
|
+
alreadyWarned.add(toolName);
|
|
1542
|
+
console.warn(`[CopilotKit] The agent called the tool "${toolName}", and no renderer is registered for it, so that message rendered nothing. ` + (registeredNames.length === 0 ? "No tool-call renderers are registered. " : `Registered renderers: ${registeredNames.map((name) => `"${name}"`).join(", ")}. `) + `Register one with useRenderTool({ name: "${toolName}", ... }), or call useDefaultRenderTool() for a built-in card that covers every tool the agent calls. This warning is development-only.`);
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1466
1545
|
/**
|
|
1467
1546
|
* Hook that returns a function to render tool calls based on the render functions
|
|
1468
1547
|
* defined in CopilotKitProvider.
|
|
@@ -1472,13 +1551,18 @@ const ToolCallRenderer = React.memo(function ToolCallRenderer({ toolCall, toolMe
|
|
|
1472
1551
|
function useRenderToolCall() {
|
|
1473
1552
|
const { copilotkit, executingToolCallIds } = useCopilotKit();
|
|
1474
1553
|
const agentId = useCopilotChatConfiguration()?.agentId ?? DEFAULT_AGENT_ID;
|
|
1554
|
+
const unrenderedToolNames = useRef(/* @__PURE__ */ new Set());
|
|
1555
|
+
const warnedToolNames = useRef(/* @__PURE__ */ new Set());
|
|
1475
1556
|
const renderToolCalls = useSyncExternalStore((callback) => {
|
|
1476
1557
|
return copilotkit.subscribe({ onRenderToolCallsChanged: callback }).unsubscribe;
|
|
1477
1558
|
}, () => copilotkit.renderToolCalls, () => copilotkit.renderToolCalls);
|
|
1478
|
-
|
|
1559
|
+
const renderToolCall = useCallback(({ toolCall, toolMessage }) => {
|
|
1479
1560
|
const exactMatches = renderToolCalls.filter((rc) => rc.name === toolCall.function.name);
|
|
1480
1561
|
const renderConfig = exactMatches.find((rc) => rc.agentId === agentId) || exactMatches.find((rc) => !rc.agentId) || exactMatches[0] || renderToolCalls.find((rc) => rc.name === "*");
|
|
1481
|
-
if (!renderConfig)
|
|
1562
|
+
if (!renderConfig) {
|
|
1563
|
+
if (IS_DEVELOPMENT$1) unrenderedToolNames.current.add(toolCall.function.name);
|
|
1564
|
+
return null;
|
|
1565
|
+
}
|
|
1482
1566
|
const RenderComponent = renderConfig.render;
|
|
1483
1567
|
return /* @__PURE__ */ jsx(ToolCallRenderer, {
|
|
1484
1568
|
toolCall,
|
|
@@ -1491,6 +1575,17 @@ function useRenderToolCall() {
|
|
|
1491
1575
|
executingToolCallIds,
|
|
1492
1576
|
agentId
|
|
1493
1577
|
]);
|
|
1578
|
+
useEffect(() => {
|
|
1579
|
+
if (!IS_DEVELOPMENT$1) return;
|
|
1580
|
+
if (unrenderedToolNames.current.size === 0) return;
|
|
1581
|
+
const timer = setTimeout(() => {
|
|
1582
|
+
const pending = Array.from(unrenderedToolNames.current);
|
|
1583
|
+
unrenderedToolNames.current.clear();
|
|
1584
|
+
warnAboutUnrenderedToolCalls(pending, copilotkit.renderToolCalls, warnedToolNames.current);
|
|
1585
|
+
}, 0);
|
|
1586
|
+
return () => clearTimeout(timer);
|
|
1587
|
+
});
|
|
1588
|
+
return renderToolCall;
|
|
1494
1589
|
}
|
|
1495
1590
|
|
|
1496
1591
|
//#endregion
|
|
@@ -2969,6 +3064,95 @@ const A2UISurfaceContentSchema = z.object({
|
|
|
2969
3064
|
a2ui_operations: z.array(z.any()).optional(),
|
|
2970
3065
|
...A2UILifecycleFields
|
|
2971
3066
|
}).passthrough();
|
|
3067
|
+
const IS_DEVELOPMENT = process.env.NODE_ENV !== "production";
|
|
3068
|
+
/**
|
|
3069
|
+
* How long to wait for a surface to report its first paint before giving up on
|
|
3070
|
+
* the loader cross-over. Reaching it also means `onReady` never fired, which is
|
|
3071
|
+
* the signal the warning below reports.
|
|
3072
|
+
*/
|
|
3073
|
+
const PAINT_FALLBACK_MS = 8e3;
|
|
3074
|
+
/**
|
|
3075
|
+
* Names the operation kinds a surface received, for a warning that has to say
|
|
3076
|
+
* what did arrive as well as what did not.
|
|
3077
|
+
*
|
|
3078
|
+
* @param operations - The operations grouped under one surface.
|
|
3079
|
+
* @returns A comma-separated list of operation keys, or "none".
|
|
3080
|
+
*/
|
|
3081
|
+
function describeOperationKinds(operations) {
|
|
3082
|
+
const kinds = /* @__PURE__ */ new Set();
|
|
3083
|
+
for (const operation of operations) {
|
|
3084
|
+
if (!operation || typeof operation !== "object") continue;
|
|
3085
|
+
for (const key of Object.keys(operation)) if (key !== "version") kinds.add(key);
|
|
3086
|
+
}
|
|
3087
|
+
return kinds.size === 0 ? "none" : Array.from(kinds).join(", ");
|
|
3088
|
+
}
|
|
3089
|
+
/**
|
|
3090
|
+
* Reports surfaces that received operations and never painted.
|
|
3091
|
+
*
|
|
3092
|
+
* Reaching {@link PAINT_FALLBACK_MS} with no `onReady` means the operations were
|
|
3093
|
+
* accepted, were not malformed enough to raise the provider's error state, and
|
|
3094
|
+
* still put nothing on screen. Left alone that is invisible: the loader drops,
|
|
3095
|
+
* the turn finishes, and the only trace is an empty placeholder above the reply.
|
|
3096
|
+
*
|
|
3097
|
+
* `surfaceHasRenderableContent` already knows which half is missing, so the
|
|
3098
|
+
* warning says which rather than making the reader re-derive it.
|
|
3099
|
+
*
|
|
3100
|
+
* @param grouped - Operations grouped by surface id.
|
|
3101
|
+
*/
|
|
3102
|
+
function warnAboutUnpaintedSurfaces(grouped) {
|
|
3103
|
+
for (const [surfaceId, operations] of grouped) {
|
|
3104
|
+
if (surfaceHasRenderableContent(operations)) continue;
|
|
3105
|
+
const cause = operations.filter((o) => o?.updateComponents).length === 0 ? "no updateComponents operation arrived, so the surface was never given anything to draw" : "its components address their values by \"path\" and no updateDataModel carried a non-empty value, so every bound component drew empty";
|
|
3106
|
+
console.warn(`[CopilotKit] A2UI surface "${surfaceId}" received operations and never painted after ${String(PAINT_FALLBACK_MS)}ms: ${cause}. Operations received: ${describeOperationKinds(operations)}. The payload was accepted, so check what the agent sent rather than the client wiring. This warning is development-only.`);
|
|
3107
|
+
}
|
|
3108
|
+
}
|
|
3109
|
+
/**
|
|
3110
|
+
* Names the component ids a surface was sent, for a warning about the one id
|
|
3111
|
+
* that is missing.
|
|
3112
|
+
*
|
|
3113
|
+
* @param operations - The operations grouped under one surface.
|
|
3114
|
+
* @returns A quoted, comma-separated list of ids, or "none".
|
|
3115
|
+
*/
|
|
3116
|
+
function describeComponentIds(operations) {
|
|
3117
|
+
const ids = [];
|
|
3118
|
+
for (const operation of operations) {
|
|
3119
|
+
const components = operation?.updateComponents?.components;
|
|
3120
|
+
if (!Array.isArray(components)) continue;
|
|
3121
|
+
for (const component of components) {
|
|
3122
|
+
const id = component?.id;
|
|
3123
|
+
if (typeof id === "string" && !ids.includes(id)) ids.push(id);
|
|
3124
|
+
}
|
|
3125
|
+
}
|
|
3126
|
+
return ids.length === 0 ? "none" : ids.map((id) => `"${id}"`).join(", ");
|
|
3127
|
+
}
|
|
3128
|
+
/**
|
|
3129
|
+
* Reports a surface that is still waiting for its {@link ROOT_COMPONENT_ID}
|
|
3130
|
+
* component once its operations have stopped arriving.
|
|
3131
|
+
*
|
|
3132
|
+
* Both renderers begin walking a surface at that one id, and treat an id they
|
|
3133
|
+
* cannot find as not arrived yet — an animated placeholder. That is right while
|
|
3134
|
+
* operations stream. Once they have stopped it is not waiting, it is stuck, and
|
|
3135
|
+
* every other check calls it healthy: the surface exists, `processMessages` did
|
|
3136
|
+
* not throw, the component types were never reached, and
|
|
3137
|
+
* `surfaceHasRenderableContent` says yes on the strength of components plus a
|
|
3138
|
+
* data model, so `onReady` fires and the never-painted report is suppressed.
|
|
3139
|
+
* A complete, accepted payload therefore animates a grey box forever in silence.
|
|
3140
|
+
*
|
|
3141
|
+
* Reads the live components model rather than scanning the operations for the
|
|
3142
|
+
* id, so it covers every way the root can fail to resolve — not only a payload
|
|
3143
|
+
* that never named one.
|
|
3144
|
+
*
|
|
3145
|
+
* @param surfaceId - The surface the operations were addressed to.
|
|
3146
|
+
* @param operations - The operations processed for that surface.
|
|
3147
|
+
* @param surface - The live surface model, already known to exist.
|
|
3148
|
+
*/
|
|
3149
|
+
function warnAboutUnresolvedRoot(surfaceId, operations, surface) {
|
|
3150
|
+
if (surface?.componentsModel?.get?.(ROOT_COMPONENT_ID)) return;
|
|
3151
|
+
const componentOps = operations.filter((o) => o?.updateComponents);
|
|
3152
|
+
if (componentOps.length === 0) return;
|
|
3153
|
+
const cause = componentOps.some((o) => o.updateComponents?.components?.some?.((c) => c?.id === ROOT_COMPONENT_ID)) ? `a component with id "${ROOT_COMPONENT_ID}" WAS sent, so the components did not reach the surface's model — check for an A2UI render error above, or a catalog that took none of them` : `the components it received are named ${describeComponentIds(operations)}, and none of them is "${ROOT_COMPONENT_ID}" — rename the entry-point component to "${ROOT_COMPONENT_ID}", and make every other component reachable from it through child/children`;
|
|
3154
|
+
console.warn(`[CopilotKit] A2UI surface "${surfaceId}" has no "${ROOT_COMPONENT_ID}" component ${String(PAINT_FALLBACK_MS)}ms after its last operations were processed, so it is showing the placeholder for a component that has not arrived yet and will keep showing it: ${cause}. Operations received: ${describeOperationKinds(operations)}. This warning is development-only.`);
|
|
3155
|
+
}
|
|
2972
3156
|
function createA2UIMessageRenderer(options) {
|
|
2973
3157
|
const { theme, catalog, loadingComponent, recovery, onAction } = options;
|
|
2974
3158
|
const showAfterMs = recovery?.showAfterMs ?? 2e3;
|
|
@@ -3002,6 +3186,8 @@ function createA2UIMessageRenderer(options) {
|
|
|
3002
3186
|
return groups;
|
|
3003
3187
|
}, [operations]);
|
|
3004
3188
|
const hasOps = groupedOperations.size > 0;
|
|
3189
|
+
const groupedOperationsRef = useRef(groupedOperations);
|
|
3190
|
+
groupedOperationsRef.current = groupedOperations;
|
|
3005
3191
|
const renderLifecycle = (c) => {
|
|
3006
3192
|
const status = c?.status;
|
|
3007
3193
|
const debugExposure = resolveDebugExposure(c, optionDebugExposure);
|
|
@@ -3033,7 +3219,10 @@ function createA2UIMessageRenderer(options) {
|
|
|
3033
3219
|
readyRef.current = false;
|
|
3034
3220
|
return;
|
|
3035
3221
|
}
|
|
3036
|
-
const t = setTimeout(() =>
|
|
3222
|
+
const t = setTimeout(() => {
|
|
3223
|
+
setSurfaceReady(true);
|
|
3224
|
+
if (IS_DEVELOPMENT && !readyRef.current) warnAboutUnpaintedSurfaces(groupedOperationsRef.current);
|
|
3225
|
+
}, PAINT_FALLBACK_MS);
|
|
3037
3226
|
return () => clearTimeout(t);
|
|
3038
3227
|
}, [hasOps]);
|
|
3039
3228
|
if (!hasOps) return renderLifecycle(content);
|
|
@@ -3157,8 +3346,21 @@ function SurfaceMessageProcessor({ surfaceId, operations, onReady }) {
|
|
|
3157
3346
|
const hash = JSON.stringify(operations);
|
|
3158
3347
|
if (hash === lastHashRef.current) return;
|
|
3159
3348
|
lastHashRef.current = hash;
|
|
3160
|
-
|
|
3349
|
+
const ops = getSurface(surfaceId) ? operations.filter((op) => !op?.createSurface) : operations;
|
|
3350
|
+
processMessages(ops);
|
|
3161
3351
|
if (onReady && surfaceHasRenderableContent(operations)) onReady();
|
|
3352
|
+
if (!IS_DEVELOPMENT) return;
|
|
3353
|
+
if (!getSurface(surfaceId)) {
|
|
3354
|
+
const missingSurfaceCheck = setTimeout(() => {
|
|
3355
|
+
if (getSurface(surfaceId)) return;
|
|
3356
|
+
console.warn(`[CopilotKit] A2UI processed ${String(ops.length)} operation(s) addressed to surface "${surfaceId}" and no surface by that id exists, so this card rendered nothing. Operations received: ${describeOperationKinds(ops)}. A createSurface for "${surfaceId}" has to arrive before, or with, the operations that target it. This warning is development-only.`);
|
|
3357
|
+
}, 0);
|
|
3358
|
+
return () => clearTimeout(missingSurfaceCheck);
|
|
3359
|
+
}
|
|
3360
|
+
const unresolvedRootCheck = setTimeout(() => {
|
|
3361
|
+
warnAboutUnresolvedRoot(surfaceId, operations, getSurface(surfaceId));
|
|
3362
|
+
}, PAINT_FALLBACK_MS);
|
|
3363
|
+
return () => clearTimeout(unresolvedRootCheck);
|
|
3162
3364
|
}, [
|
|
3163
3365
|
processMessages,
|
|
3164
3366
|
getSurface,
|
|
@@ -3185,10 +3387,26 @@ function surfaceHasRenderableContent(operations) {
|
|
|
3185
3387
|
return Object.values(v).some((x) => Array.isArray(x) ? x.length > 0 : x !== null && x !== void 0 && x !== "");
|
|
3186
3388
|
});
|
|
3187
3389
|
}
|
|
3390
|
+
/**
|
|
3391
|
+
* Resolves the surface an operation addresses.
|
|
3392
|
+
*
|
|
3393
|
+
* The nested v0.9 `surfaceId` wins, because that is the id `MessageProcessor`
|
|
3394
|
+
* creates the surface under. Grouping by a top-level `surfaceId` instead files
|
|
3395
|
+
* the operations against a surface that never exists, which paints nothing —
|
|
3396
|
+
* the silence the missing-surface report above now names. A top-level
|
|
3397
|
+
* `surfaceId` is not the v0.9 shape, so it is honoured only when no nested id is
|
|
3398
|
+
* present. `getSurfaceId` in `@copilotkit/a2ui-renderer`'s web-components path
|
|
3399
|
+
* resolves it in the same order; the two disagreeing is what OSS-1048 recorded.
|
|
3400
|
+
*
|
|
3401
|
+
* @param operation - One A2UI operation, of any shape.
|
|
3402
|
+
* @returns The surface id, or null when the operation names none.
|
|
3403
|
+
*/
|
|
3188
3404
|
function getOperationSurfaceId(operation) {
|
|
3189
3405
|
if (!operation || typeof operation !== "object") return null;
|
|
3406
|
+
const nested = operation?.createSurface?.surfaceId ?? operation?.updateComponents?.surfaceId ?? operation?.updateDataModel?.surfaceId ?? operation?.deleteSurface?.surfaceId;
|
|
3407
|
+
if (typeof nested === "string") return nested;
|
|
3190
3408
|
if (typeof operation.surfaceId === "string") return operation.surfaceId;
|
|
3191
|
-
return
|
|
3409
|
+
return null;
|
|
3192
3410
|
}
|
|
3193
3411
|
|
|
3194
3412
|
//#endregion
|
|
@@ -3402,6 +3620,9 @@ const COPILOT_CLOUD_CHAT_URL$1 = "https://api.cloud.copilotkit.ai/copilotkit/v1"
|
|
|
3402
3620
|
const EMPTY_HEADERS = Object.freeze({});
|
|
3403
3621
|
const EMPTY_PROPERTIES = Object.freeze({});
|
|
3404
3622
|
const EMPTY_AGENTS = Object.freeze({});
|
|
3623
|
+
/** Registration name of a catch-all tool: handles any otherwise-unhandled call. */
|
|
3624
|
+
const WILDCARD_TOOL_NAME$1 = "*";
|
|
3625
|
+
const HUMAN_IN_THE_LOOP_ABORTED_MESSAGE = "Human-in-the-loop interaction aborted";
|
|
3405
3626
|
const DEFAULT_DESIGN_SKILL = `When generating UI with generateSandboxedUi, follow these design principles inspired by shadcn/ui:
|
|
3406
3627
|
|
|
3407
3628
|
- Use a minimal, flat aesthetic. Avoid drop shadows and gradients — rely on subtle borders (1px solid, light gray like #e5e7eb) to define surfaces.
|
|
@@ -3520,6 +3741,11 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers: headersProp = EMPTY
|
|
|
3520
3741
|
}
|
|
3521
3742
|
const chatApiEndpoint = runtimeUrl ?? (resolvedPublicKey ? COPILOT_CLOUD_CHAT_URL$1 : void 0);
|
|
3522
3743
|
const frontendToolsList = useStableArrayProp(frontendTools, "frontendTools must be a stable array. If you want to dynamically add or remove tools, use `useFrontendTool` instead.");
|
|
3744
|
+
/**
|
|
3745
|
+
* A `humanInTheLoop` prop tool call that is parked, waiting on the user.
|
|
3746
|
+
* Keyed by tool call id, so parallel calls of one tool stay independent.
|
|
3747
|
+
*/
|
|
3748
|
+
const pendingHumanInTheLoopRef = useRef(/* @__PURE__ */ new Map());
|
|
3523
3749
|
const humanInTheLoopList = useStableArrayProp(humanInTheLoop, "humanInTheLoop must be a stable array. If you want to dynamically add or remove human-in-the-loop tools, use `useHumanInTheLoop` instead.");
|
|
3524
3750
|
const sandboxFunctionsList = useStableArrayProp(openGenerativeUI?.sandboxFunctions, "openGenerativeUI.sandboxFunctions must be a stable array.");
|
|
3525
3751
|
const processedHumanInTheLoopTools = useMemo(() => {
|
|
@@ -3532,20 +3758,52 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers: headersProp = EMPTY
|
|
|
3532
3758
|
parameters: tool.parameters,
|
|
3533
3759
|
followUp: tool.followUp,
|
|
3534
3760
|
...tool.agentId && { agentId: tool.agentId },
|
|
3535
|
-
handler: async () => {
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
|
|
3761
|
+
handler: async (_args, context) => {
|
|
3762
|
+
const signal = context?.signal;
|
|
3763
|
+
const key = context?.toolCall?.id ?? tool.name;
|
|
3764
|
+
return new Promise((resolve, reject) => {
|
|
3765
|
+
if (signal?.aborted) {
|
|
3766
|
+
reject(new Error(HUMAN_IN_THE_LOOP_ABORTED_MESSAGE));
|
|
3767
|
+
return;
|
|
3768
|
+
}
|
|
3769
|
+
const pending = { resolve };
|
|
3770
|
+
pendingHumanInTheLoopRef.current.set(key, pending);
|
|
3771
|
+
if (signal) {
|
|
3772
|
+
const onAbort = () => {
|
|
3773
|
+
pendingHumanInTheLoopRef.current.delete(key);
|
|
3774
|
+
reject(new Error(HUMAN_IN_THE_LOOP_ABORTED_MESSAGE));
|
|
3775
|
+
};
|
|
3776
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
3777
|
+
pending.detachAbort = () => {
|
|
3778
|
+
signal.removeEventListener("abort", onAbort);
|
|
3779
|
+
};
|
|
3780
|
+
}
|
|
3539
3781
|
});
|
|
3540
3782
|
}
|
|
3541
3783
|
};
|
|
3542
3784
|
processedTools.push(frontendTool);
|
|
3543
|
-
if (tool.render)
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3785
|
+
if (tool.render) {
|
|
3786
|
+
const ToolComponent = tool.render;
|
|
3787
|
+
const RenderComponent = (props) => createElement(ToolComponent, {
|
|
3788
|
+
...props,
|
|
3789
|
+
name: tool.name === WILDCARD_TOOL_NAME$1 ? props.name : tool.name,
|
|
3790
|
+
description: tool.description || "",
|
|
3791
|
+
agentId: tool.agentId,
|
|
3792
|
+
respond: props.status === ToolCallStatus.Executing ? async (result) => {
|
|
3793
|
+
const pending = pendingHumanInTheLoopRef.current.get(props.toolCallId);
|
|
3794
|
+
if (!pending) return;
|
|
3795
|
+
pending.detachAbort?.();
|
|
3796
|
+
pendingHumanInTheLoopRef.current.delete(props.toolCallId);
|
|
3797
|
+
pending.resolve(result);
|
|
3798
|
+
} : void 0
|
|
3799
|
+
});
|
|
3800
|
+
processedRenderToolCalls.push({
|
|
3801
|
+
name: tool.name,
|
|
3802
|
+
args: tool.parameters,
|
|
3803
|
+
render: RenderComponent,
|
|
3804
|
+
...tool.agentId && { agentId: tool.agentId }
|
|
3805
|
+
});
|
|
3806
|
+
}
|
|
3549
3807
|
});
|
|
3550
3808
|
return {
|
|
3551
3809
|
tools: processedTools,
|
|
@@ -5394,7 +5652,7 @@ function useMemories() {
|
|
|
5394
5652
|
* at the call site.
|
|
5395
5653
|
*/
|
|
5396
5654
|
async function recordAnnotation(args) {
|
|
5397
|
-
const { runtimeUrl, headers, type, payload, threadId, occurredAt } = args;
|
|
5655
|
+
const { runtimeUrl, headers, type, payload, threadId, occurredAt, fetch: fetchImplementation = globalThis.fetch } = args;
|
|
5398
5656
|
const body = {
|
|
5399
5657
|
type,
|
|
5400
5658
|
threadId,
|
|
@@ -5402,7 +5660,7 @@ async function recordAnnotation(args) {
|
|
|
5402
5660
|
...payload !== void 0 ? { payload } : {},
|
|
5403
5661
|
...occurredAt !== void 0 ? { occurredAt } : {}
|
|
5404
5662
|
};
|
|
5405
|
-
const response = await
|
|
5663
|
+
const response = await fetchImplementation(`${runtimeUrl}/annotate`, {
|
|
5406
5664
|
method: "POST",
|
|
5407
5665
|
headers: {
|
|
5408
5666
|
"Content-Type": "application/json",
|
|
@@ -5471,6 +5729,7 @@ function useLearnFromUserAction() {
|
|
|
5471
5729
|
...input.data !== void 0 ? { data: input.data } : {}
|
|
5472
5730
|
};
|
|
5473
5731
|
return recordAnnotation({
|
|
5732
|
+
fetch: copilotkit.ɵruntimeFetch,
|
|
5474
5733
|
runtimeUrl,
|
|
5475
5734
|
headers: copilotkit.headers ?? {},
|
|
5476
5735
|
type: "user_action",
|
|
@@ -5540,6 +5799,21 @@ function useLearnFromUserActionInCurrentThread() {
|
|
|
5540
5799
|
|
|
5541
5800
|
//#endregion
|
|
5542
5801
|
//#region src/v2/hooks/use-attachments.tsx
|
|
5802
|
+
const DEFAULT_MAX_SIZE = 20 * 1024 * 1024;
|
|
5803
|
+
/**
|
|
5804
|
+
* How many uploads run at once when `maxConcurrentUploads` is unset. One, because
|
|
5805
|
+
* `onUpload` is a public callback an app may have written expecting the previous
|
|
5806
|
+
* file to have finished — concurrency is something the app asks for.
|
|
5807
|
+
*/
|
|
5808
|
+
const DEFAULT_MAX_CONCURRENT_UPLOADS = 1;
|
|
5809
|
+
/**
|
|
5810
|
+
* At least one upload at a time, whole files only; `NaN` or a non-number falls back to the
|
|
5811
|
+
* default, and `Infinity` means "no limit" — bounded in practice by how many files are queued.
|
|
5812
|
+
*/
|
|
5813
|
+
function resolveMaxConcurrentUploads(configured) {
|
|
5814
|
+
if (typeof configured !== "number" || Number.isNaN(configured)) return DEFAULT_MAX_CONCURRENT_UPLOADS;
|
|
5815
|
+
return Math.max(1, Math.floor(configured));
|
|
5816
|
+
}
|
|
5543
5817
|
/**
|
|
5544
5818
|
* Hook that manages file attachment state — uploads, drag-and-drop, paste,
|
|
5545
5819
|
* and lifecycle. All returned callbacks are referentially stable across
|
|
@@ -5555,10 +5829,62 @@ function useAttachments({ config }) {
|
|
|
5555
5829
|
configRef.current = config;
|
|
5556
5830
|
const attachmentsRef = useRef([]);
|
|
5557
5831
|
attachmentsRef.current = attachments;
|
|
5832
|
+
const uploadQueueRef = useRef([]);
|
|
5833
|
+
const activeWorkersRef = useRef(0);
|
|
5834
|
+
const uploadFile = useCallback(async (file, placeholder, cfg) => {
|
|
5835
|
+
try {
|
|
5836
|
+
let source;
|
|
5837
|
+
let uploadMetadata;
|
|
5838
|
+
if (cfg?.onUpload) {
|
|
5839
|
+
const { metadata: meta, ...uploadSource } = await cfg.onUpload(file);
|
|
5840
|
+
source = uploadSource;
|
|
5841
|
+
uploadMetadata = meta;
|
|
5842
|
+
} else source = {
|
|
5843
|
+
type: "data",
|
|
5844
|
+
value: await readFileAsBase64(file),
|
|
5845
|
+
mimeType: file.type
|
|
5846
|
+
};
|
|
5847
|
+
let thumbnail;
|
|
5848
|
+
if (placeholder.type === "video") thumbnail = await generateVideoThumbnail(file);
|
|
5849
|
+
setAttachments((prev) => prev.map((att) => att.id === placeholder.id ? {
|
|
5850
|
+
...att,
|
|
5851
|
+
source,
|
|
5852
|
+
status: "ready",
|
|
5853
|
+
thumbnail,
|
|
5854
|
+
metadata: uploadMetadata
|
|
5855
|
+
} : att));
|
|
5856
|
+
} catch (error) {
|
|
5857
|
+
setAttachments((prev) => prev.filter((att) => att.id !== placeholder.id));
|
|
5858
|
+
console.error(`[CopilotKit] Failed to upload "${file.name}":`, error);
|
|
5859
|
+
cfg?.onUploadFailed?.({
|
|
5860
|
+
reason: "upload-failed",
|
|
5861
|
+
file,
|
|
5862
|
+
message: error instanceof Error ? error.message : `Failed to upload "${file.name}"`
|
|
5863
|
+
});
|
|
5864
|
+
}
|
|
5865
|
+
}, []);
|
|
5866
|
+
const drainUploadQueue = useCallback(async () => {
|
|
5867
|
+
activeWorkersRef.current++;
|
|
5868
|
+
try {
|
|
5869
|
+
for (;;) {
|
|
5870
|
+
const item = uploadQueueRef.current.shift();
|
|
5871
|
+
if (!item) return;
|
|
5872
|
+
try {
|
|
5873
|
+
await uploadFile(item.file, item.placeholder, item.cfg);
|
|
5874
|
+
} catch (error) {
|
|
5875
|
+
console.error("[CopilotKit] Upload worker error:", error);
|
|
5876
|
+
} finally {
|
|
5877
|
+
item.settle();
|
|
5878
|
+
}
|
|
5879
|
+
}
|
|
5880
|
+
} finally {
|
|
5881
|
+
activeWorkersRef.current--;
|
|
5882
|
+
}
|
|
5883
|
+
}, [uploadFile]);
|
|
5558
5884
|
const processFiles = useCallback(async (files) => {
|
|
5559
5885
|
const cfg = configRef.current;
|
|
5560
5886
|
const accept = cfg?.accept ?? "*/*";
|
|
5561
|
-
const maxSize = cfg?.maxSize ??
|
|
5887
|
+
const maxSize = cfg?.maxSize ?? DEFAULT_MAX_SIZE;
|
|
5562
5888
|
const rejectedFiles = files.filter((file) => !matchesAcceptFilter(file, accept));
|
|
5563
5889
|
for (const file of rejectedFiles) cfg?.onUploadFailed?.({
|
|
5564
5890
|
reason: "invalid-type",
|
|
@@ -5566,6 +5892,7 @@ function useAttachments({ config }) {
|
|
|
5566
5892
|
message: `File "${file.name}" is not accepted. Supported types: ${accept}`
|
|
5567
5893
|
});
|
|
5568
5894
|
const validFiles = files.filter((file) => matchesAcceptFilter(file, accept));
|
|
5895
|
+
const queued = [];
|
|
5569
5896
|
for (const file of validFiles) {
|
|
5570
5897
|
if (exceedsMaxSize(file, maxSize)) {
|
|
5571
5898
|
cfg?.onUploadFailed?.({
|
|
@@ -5575,53 +5902,37 @@ function useAttachments({ config }) {
|
|
|
5575
5902
|
});
|
|
5576
5903
|
continue;
|
|
5577
5904
|
}
|
|
5578
|
-
|
|
5579
|
-
|
|
5580
|
-
|
|
5581
|
-
|
|
5582
|
-
|
|
5583
|
-
|
|
5584
|
-
|
|
5585
|
-
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
5593
|
-
try {
|
|
5594
|
-
let source;
|
|
5595
|
-
let uploadMetadata;
|
|
5596
|
-
if (cfg?.onUpload) {
|
|
5597
|
-
const { metadata: meta, ...uploadSource } = await cfg.onUpload(file);
|
|
5598
|
-
source = uploadSource;
|
|
5599
|
-
uploadMetadata = meta;
|
|
5600
|
-
} else source = {
|
|
5601
|
-
type: "data",
|
|
5602
|
-
value: await readFileAsBase64(file),
|
|
5603
|
-
mimeType: file.type
|
|
5604
|
-
};
|
|
5605
|
-
let thumbnail;
|
|
5606
|
-
if (modality === "video") thumbnail = await generateVideoThumbnail(file);
|
|
5607
|
-
setAttachments((prev) => prev.map((att) => att.id === placeholderId ? {
|
|
5608
|
-
...att,
|
|
5609
|
-
source,
|
|
5610
|
-
status: "ready",
|
|
5611
|
-
thumbnail,
|
|
5612
|
-
metadata: uploadMetadata
|
|
5613
|
-
} : att));
|
|
5614
|
-
} catch (error) {
|
|
5615
|
-
setAttachments((prev) => prev.filter((att) => att.id !== placeholderId));
|
|
5616
|
-
console.error(`[CopilotKit] Failed to upload "${file.name}":`, error);
|
|
5617
|
-
cfg?.onUploadFailed?.({
|
|
5618
|
-
reason: "upload-failed",
|
|
5619
|
-
file,
|
|
5620
|
-
message: error instanceof Error ? error.message : `Failed to upload "${file.name}"`
|
|
5621
|
-
});
|
|
5622
|
-
}
|
|
5905
|
+
queued.push({
|
|
5906
|
+
file,
|
|
5907
|
+
placeholder: {
|
|
5908
|
+
id: randomUUID$1(),
|
|
5909
|
+
type: getModalityFromMimeType(file.type),
|
|
5910
|
+
source: {
|
|
5911
|
+
type: "data",
|
|
5912
|
+
value: "",
|
|
5913
|
+
mimeType: file.type
|
|
5914
|
+
},
|
|
5915
|
+
filename: file.name,
|
|
5916
|
+
size: file.size,
|
|
5917
|
+
status: "uploading"
|
|
5918
|
+
}
|
|
5919
|
+
});
|
|
5623
5920
|
}
|
|
5624
|
-
|
|
5921
|
+
if (queued.length === 0) return;
|
|
5922
|
+
setAttachments((prev) => [...prev, ...queued.map((q) => q.placeholder)]);
|
|
5923
|
+
const settled = queued.map(({ file, placeholder }) => new Promise((resolve) => {
|
|
5924
|
+
uploadQueueRef.current.push({
|
|
5925
|
+
file,
|
|
5926
|
+
placeholder,
|
|
5927
|
+
cfg,
|
|
5928
|
+
settle: resolve
|
|
5929
|
+
});
|
|
5930
|
+
}));
|
|
5931
|
+
const limit = resolveMaxConcurrentUploads(cfg?.maxConcurrentUploads);
|
|
5932
|
+
const toSpawn = Math.min(uploadQueueRef.current.length, Math.max(0, limit - activeWorkersRef.current));
|
|
5933
|
+
for (let i = 0; i < toSpawn; i++) drainUploadQueue();
|
|
5934
|
+
await Promise.all(settled);
|
|
5935
|
+
}, [drainUploadQueue]);
|
|
5625
5936
|
const handleFileUpload = useCallback(async (e) => {
|
|
5626
5937
|
if (!e.target.files?.length) return;
|
|
5627
5938
|
try {
|
|
@@ -5749,8 +6060,10 @@ function useLearningContainers({ threadId, learningContainers }) {
|
|
|
5749
6060
|
const warnedMissingUrlRef = useRef(false);
|
|
5750
6061
|
const runtimeUrlRef = useRef(copilotkit.runtimeUrl);
|
|
5751
6062
|
const headersRef = useRef(copilotkit.headers ?? {});
|
|
6063
|
+
const runtimeFetchRef = useRef(copilotkit.ɵruntimeFetch);
|
|
5752
6064
|
runtimeUrlRef.current = copilotkit.runtimeUrl;
|
|
5753
6065
|
headersRef.current = copilotkit.headers ?? {};
|
|
6066
|
+
runtimeFetchRef.current = copilotkit.ɵruntimeFetch;
|
|
5754
6067
|
const key = JSON.stringify(learningContainers);
|
|
5755
6068
|
const defaultKey = JSON.stringify(DEFAULT_CONTAINERS);
|
|
5756
6069
|
useEffect(() => {
|
|
@@ -5770,6 +6083,7 @@ function useLearningContainers({ threadId, learningContainers }) {
|
|
|
5770
6083
|
return;
|
|
5771
6084
|
}
|
|
5772
6085
|
recordAnnotation({
|
|
6086
|
+
fetch: copilotkit.ɵruntimeFetch,
|
|
5773
6087
|
runtimeUrl,
|
|
5774
6088
|
headers,
|
|
5775
6089
|
type: "set_learning_containers",
|
|
@@ -5797,6 +6111,7 @@ function useLearningContainers({ threadId, learningContainers }) {
|
|
|
5797
6111
|
const capturedRuntimeUrl = runtimeUrlRef.current;
|
|
5798
6112
|
const capturedHeaders = headersRef.current;
|
|
5799
6113
|
if (capturedRuntimeUrl) recordAnnotation({
|
|
6114
|
+
fetch: runtimeFetchRef.current,
|
|
5800
6115
|
runtimeUrl: capturedRuntimeUrl,
|
|
5801
6116
|
headers: capturedHeaders,
|
|
5802
6117
|
type: "set_learning_containers",
|
|
@@ -9059,6 +9374,41 @@ const CopilotChatToggleButton = React.forwardRef(function CopilotChatToggleButto
|
|
|
9059
9374
|
});
|
|
9060
9375
|
CopilotChatToggleButton.displayName = "CopilotChatToggleButton";
|
|
9061
9376
|
|
|
9377
|
+
//#endregion
|
|
9378
|
+
//#region src/v2/components/chat/modal-open-control.tsx
|
|
9379
|
+
const ModalOpenControlContext = createContext({});
|
|
9380
|
+
/**
|
|
9381
|
+
* Carries `open` / `onOpenChange` from a prebuilt surface down to the view that
|
|
9382
|
+
* owns the modal state.
|
|
9383
|
+
*
|
|
9384
|
+
* A context is required rather than plain props because `<CopilotSidebar>`
|
|
9385
|
+
* hands its view to `<CopilotChat>` as a `chatView` **component**. Threading a
|
|
9386
|
+
* value that changes (like `open`) through that component's identity would mint
|
|
9387
|
+
* a new element type on every toggle, and React unmounts and remounts the whole
|
|
9388
|
+
* chat subtree when the element type changes. That is the remount class of bug
|
|
9389
|
+
* already fixed for `<CopilotPopup>` on resize. Context keeps the override
|
|
9390
|
+
* identity stable while still re-rendering the view when `open` changes.
|
|
9391
|
+
*/
|
|
9392
|
+
function ModalOpenControlProvider({ open, onOpenChange, children }) {
|
|
9393
|
+
const value = useMemo(() => ({
|
|
9394
|
+
open,
|
|
9395
|
+
onOpenChange
|
|
9396
|
+
}), [open, onOpenChange]);
|
|
9397
|
+
return /* @__PURE__ */ jsx(ModalOpenControlContext.Provider, {
|
|
9398
|
+
value,
|
|
9399
|
+
children
|
|
9400
|
+
});
|
|
9401
|
+
}
|
|
9402
|
+
/**
|
|
9403
|
+
* Reads the controlled open state supplied by the surrounding prebuilt
|
|
9404
|
+
* surface. Returns an empty control (uncontrolled) when there is none.
|
|
9405
|
+
*
|
|
9406
|
+
* @returns The host's `open` / `onOpenChange` pair.
|
|
9407
|
+
*/
|
|
9408
|
+
function useModalOpenControl() {
|
|
9409
|
+
return useContext(ModalOpenControlContext);
|
|
9410
|
+
}
|
|
9411
|
+
|
|
9062
9412
|
//#endregion
|
|
9063
9413
|
//#region src/v2/components/chat/CopilotModalHeader.tsx
|
|
9064
9414
|
/**
|
|
@@ -9168,15 +9518,22 @@ CopilotModalHeader.DrawerLauncher.displayName = "CopilotModalHeader.DrawerLaunch
|
|
|
9168
9518
|
const DEFAULT_SIDEBAR_WIDTH = 480;
|
|
9169
9519
|
const SIDEBAR_TRANSITION_MS = 260;
|
|
9170
9520
|
function CopilotSidebarView({ header, toggleButton, width, defaultOpen = true, position = "right", ...props }) {
|
|
9521
|
+
const { open, onOpenChange } = useModalOpenControl();
|
|
9522
|
+
const hasOpenControl = open !== void 0 || onOpenChange !== void 0;
|
|
9523
|
+
const internal = /* @__PURE__ */ jsx(CopilotSidebarViewInternal, {
|
|
9524
|
+
header,
|
|
9525
|
+
toggleButton,
|
|
9526
|
+
width,
|
|
9527
|
+
position,
|
|
9528
|
+
...props
|
|
9529
|
+
});
|
|
9171
9530
|
return /* @__PURE__ */ jsx(CopilotChatConfigurationProvider, {
|
|
9172
|
-
isModalDefaultOpen: defaultOpen,
|
|
9173
|
-
children: /* @__PURE__ */ jsx(
|
|
9174
|
-
|
|
9175
|
-
|
|
9176
|
-
|
|
9177
|
-
|
|
9178
|
-
...props
|
|
9179
|
-
})
|
|
9531
|
+
isModalDefaultOpen: open ?? defaultOpen,
|
|
9532
|
+
children: hasOpenControl ? /* @__PURE__ */ jsx(ControlledModalOpenScope, {
|
|
9533
|
+
open,
|
|
9534
|
+
onOpenChange,
|
|
9535
|
+
children: internal
|
|
9536
|
+
}) : internal
|
|
9180
9537
|
});
|
|
9181
9538
|
}
|
|
9182
9539
|
function CopilotSidebarViewInternal({ header, toggleButton, width, position = "right", ...props }) {
|
|
@@ -9240,7 +9597,7 @@ function CopilotSidebarViewInternal({ header, toggleButton, width, position = "r
|
|
|
9240
9597
|
"data-position": position,
|
|
9241
9598
|
className: cn("copilotKitSidebar copilotKitWindow", "cpk:fixed cpk:top-0 cpk:z-[1200] cpk:flex", position === "left" ? "cpk:left-0" : "cpk:right-0", "cpk:h-[100vh] cpk:h-[100dvh] cpk:max-h-screen", "cpk:w-full", position === "left" ? "cpk:border-r" : "cpk:border-l", "cpk:border-border cpk:bg-background cpk:text-foreground cpk:shadow-xl", "cpk:transition-transform cpk:duration-300 cpk:ease-out", isSidebarOpen ? "cpk:translate-x-0" : position === "left" ? "cpk:-translate-x-full cpk:pointer-events-none" : "cpk:translate-x-full cpk:pointer-events-none"),
|
|
9242
9599
|
style: {
|
|
9243
|
-
|
|
9600
|
+
"--sidebar-width": widthToCss(sidebarWidth),
|
|
9244
9601
|
paddingTop: "env(safe-area-inset-top)",
|
|
9245
9602
|
paddingBottom: "env(safe-area-inset-bottom)"
|
|
9246
9603
|
},
|
|
@@ -9302,17 +9659,24 @@ const dimensionToCss = (value, fallback) => {
|
|
|
9302
9659
|
return `${fallback}px`;
|
|
9303
9660
|
};
|
|
9304
9661
|
function CopilotPopupView({ header, toggleButton, width, height, clickOutsideToClose, defaultOpen = true, className, ...restProps }) {
|
|
9662
|
+
const { open, onOpenChange } = useModalOpenControl();
|
|
9663
|
+
const hasOpenControl = open !== void 0 || onOpenChange !== void 0;
|
|
9664
|
+
const internal = /* @__PURE__ */ jsx(CopilotPopupViewInternal, {
|
|
9665
|
+
header,
|
|
9666
|
+
toggleButton,
|
|
9667
|
+
width,
|
|
9668
|
+
height,
|
|
9669
|
+
clickOutsideToClose,
|
|
9670
|
+
className,
|
|
9671
|
+
...restProps
|
|
9672
|
+
});
|
|
9305
9673
|
return /* @__PURE__ */ jsx(CopilotChatConfigurationProvider, {
|
|
9306
|
-
isModalDefaultOpen: defaultOpen,
|
|
9307
|
-
children: /* @__PURE__ */ jsx(
|
|
9308
|
-
|
|
9309
|
-
|
|
9310
|
-
|
|
9311
|
-
|
|
9312
|
-
clickOutsideToClose,
|
|
9313
|
-
className,
|
|
9314
|
-
...restProps
|
|
9315
|
-
})
|
|
9674
|
+
isModalDefaultOpen: open ?? defaultOpen,
|
|
9675
|
+
children: hasOpenControl ? /* @__PURE__ */ jsx(ControlledModalOpenScope, {
|
|
9676
|
+
open,
|
|
9677
|
+
onOpenChange,
|
|
9678
|
+
children: internal
|
|
9679
|
+
}) : internal
|
|
9316
9680
|
});
|
|
9317
9681
|
}
|
|
9318
9682
|
function CopilotPopupViewInternal({ header, toggleButton, width, height, clickOutsideToClose, className, ...restProps }) {
|
|
@@ -9445,7 +9809,7 @@ var CopilotPopupView_default = CopilotPopupView;
|
|
|
9445
9809
|
|
|
9446
9810
|
//#endregion
|
|
9447
9811
|
//#region src/v2/components/chat/CopilotSidebar.tsx
|
|
9448
|
-
function CopilotSidebar({ header, toggleButton, defaultOpen, width, position, ...chatProps }) {
|
|
9812
|
+
function CopilotSidebar({ header, toggleButton, defaultOpen, open, onOpenChange, width, position, ...chatProps }) {
|
|
9449
9813
|
const { checkFeature } = useLicenseContext$1();
|
|
9450
9814
|
const isSidebarLicensed = checkFeature("sidebar");
|
|
9451
9815
|
useEffect(() => {
|
|
@@ -9471,11 +9835,15 @@ function CopilotSidebar({ header, toggleButton, defaultOpen, width, position, ..
|
|
|
9471
9835
|
defaultOpen,
|
|
9472
9836
|
position
|
|
9473
9837
|
]);
|
|
9474
|
-
return /* @__PURE__ */ jsxs(Fragment$1, { children: [!isSidebarLicensed && /* @__PURE__ */ jsx(InlineFeatureWarning, { featureName: "Sidebar" }), /* @__PURE__ */ jsx(
|
|
9475
|
-
|
|
9476
|
-
|
|
9477
|
-
|
|
9478
|
-
|
|
9838
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [!isSidebarLicensed && /* @__PURE__ */ jsx(InlineFeatureWarning, { featureName: "Sidebar" }), /* @__PURE__ */ jsx(ModalOpenControlProvider, {
|
|
9839
|
+
open,
|
|
9840
|
+
onOpenChange,
|
|
9841
|
+
children: /* @__PURE__ */ jsx(CopilotChat, {
|
|
9842
|
+
welcomeScreen: CopilotSidebarView.WelcomeScreen,
|
|
9843
|
+
...chatProps,
|
|
9844
|
+
isModalDefaultOpen: defaultOpen,
|
|
9845
|
+
chatView: SidebarViewOverride
|
|
9846
|
+
})
|
|
9479
9847
|
})] });
|
|
9480
9848
|
}
|
|
9481
9849
|
CopilotSidebar.displayName = "CopilotSidebar";
|
|
@@ -9497,7 +9865,7 @@ const PopupViewOverride = (viewProps) => {
|
|
|
9497
9865
|
});
|
|
9498
9866
|
};
|
|
9499
9867
|
const PopupViewOverrideWithStatics = Object.assign(PopupViewOverride, CopilotChatView_default);
|
|
9500
|
-
function CopilotPopup({ header, toggleButton, defaultOpen, width, height, clickOutsideToClose, ...chatProps }) {
|
|
9868
|
+
function CopilotPopup({ header, toggleButton, defaultOpen, open, onOpenChange, width, height, clickOutsideToClose, ...chatProps }) {
|
|
9501
9869
|
const { checkFeature } = useLicenseContext$1();
|
|
9502
9870
|
const isPopupLicensed = checkFeature("popup");
|
|
9503
9871
|
useEffect(() => {
|
|
@@ -9520,11 +9888,15 @@ function CopilotPopup({ header, toggleButton, defaultOpen, width, height, clickO
|
|
|
9520
9888
|
]);
|
|
9521
9889
|
return /* @__PURE__ */ jsxs(Fragment$1, { children: [!isPopupLicensed && /* @__PURE__ */ jsx(InlineFeatureWarning, { featureName: "Popup" }), /* @__PURE__ */ jsx(PopupShellPropsContext.Provider, {
|
|
9522
9890
|
value: shellProps,
|
|
9523
|
-
children: /* @__PURE__ */ jsx(
|
|
9524
|
-
|
|
9525
|
-
|
|
9526
|
-
|
|
9527
|
-
|
|
9891
|
+
children: /* @__PURE__ */ jsx(ModalOpenControlProvider, {
|
|
9892
|
+
open,
|
|
9893
|
+
onOpenChange,
|
|
9894
|
+
children: /* @__PURE__ */ jsx(CopilotChat, {
|
|
9895
|
+
welcomeScreen: CopilotPopupView_default.WelcomeScreen,
|
|
9896
|
+
...chatProps,
|
|
9897
|
+
isModalDefaultOpen: defaultOpen,
|
|
9898
|
+
chatView: PopupViewOverrideWithStatics
|
|
9899
|
+
})
|
|
9528
9900
|
})
|
|
9529
9901
|
})] });
|
|
9530
9902
|
}
|
|
@@ -12078,4 +12450,4 @@ function validateProps(props) {
|
|
|
12078
12450
|
|
|
12079
12451
|
//#endregion
|
|
12080
12452
|
export { useAgentContext as $, CopilotChatMessageView as A, AudioRecorderError as At, CopilotChatAssistantMessage_default as B, CopilotModalHeader as C, MCPAppsActivityContentSchema as Ct, CopilotChat as D, CopilotKitInspector as Dt, DefaultOpenIcon as E, ɵrunMcpFollowUp as Et, CopilotChatSuggestionView as F, useLearnFromUserActionInCurrentThread as G, useLearningContainersInCurrentThread as H, CopilotChatSuggestionPill as I, useThreads$1 as J, useLearnFromUserAction as K, CopilotChatReasoningMessage_default as L, IntelligenceIndicator as M, CopilotChatConfigurationProvider as Mt, getIntelligenceTurnAnchors as N, useCopilotChatConfiguration as Nt, CopilotChatView_default as O, useRenderToolCall as Ot, IntelligenceIndicatorView as P, useSuggestions as Q, CopilotChatUserMessage_default as R, CopilotSidebarView as S, useSandboxFunctions as St, DefaultCloseIcon as T, MCPAppsActivityType as Tt, useLearningContainers as U, CopilotChatToolCallsView as V, useAttachments as W, INTERRUPT_EVENT_NAME as X, useInterrupt as Y, useConfigureSuggestions as Z, WildcardToolCallRender as _, OpenGenerativeUIActivityRenderer as _t, ThreadsProvider as a, useRenderTool as at, CopilotSidebar as b, OpenGenerativeUIToolRenderer as bt, CoAgentStateRendersProvider as c, useRenderActivityMessage as ct, shouldShowDevConsole as d, useCopilotKit$1 as dt, useCapabilities as et, useToast as f, useLicenseContext$1 as ft, useCopilotContext as g, GenerateSandboxedUiArgsSchema as gt, CopilotContext as h, createA2UIMessageRenderer as ht, ThreadsContext as i, useDefaultRenderTool as it, INTELLIGENCE_TURN_HEAD as j, CopilotChatAudioRecorder as jt, CopilotChatAttachmentQueue as k, CopilotChatInput_default as kt, useCoAgentStateRenders as l, useRenderCustomMessages as lt, useCopilotMessagesContext as m, defineToolCallRenderer as mt, defaultCopilotContextCategories as n, useAgent as nt, useThreads as o, useComponent as ot, CopilotMessagesContext as p, CopilotKitCoreReact as pt, useMemories as q, CoAgentStateRenderBridge as r, useHumanInTheLoop as rt, CoAgentStateRendersContext as s, useFrontendTool as st, CopilotKit as t, UseAgentUpdate as tt, useAsyncCallback as u, CopilotKitProvider as ut, CopilotThreadsDrawer as v, OpenGenerativeUIActivityType as vt, CopilotChatToggleButton as w, MCPAppsActivityRenderer as wt, CopilotPopupView as x, SandboxFunctionsContext as xt, CopilotPopup as y, OpenGenerativeUIContentSchema as yt, CopilotChatAttachmentRenderer as z };
|
|
12081
|
-
//# sourceMappingURL=copilotkit-
|
|
12453
|
+
//# sourceMappingURL=copilotkit-Ap_yisA5.mjs.map
|