@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
package/dist/v2/index.umd.js
CHANGED
|
@@ -283,6 +283,62 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
283
283
|
const useCopilotChatConfiguration = () => {
|
|
284
284
|
return (0, react.useContext)(CopilotChatConfiguration);
|
|
285
285
|
};
|
|
286
|
+
/**
|
|
287
|
+
* Reports modal open/close requests to the host, and — when `open` is
|
|
288
|
+
* supplied — makes the modal state of an already-established chat
|
|
289
|
+
* configuration **controlled** for the subtree it wraps.
|
|
290
|
+
*
|
|
291
|
+
* This is deliberately a scope component rather than another mode inside
|
|
292
|
+
* {@link CopilotChatConfigurationProvider}. The provider resolves modal state
|
|
293
|
+
* across a nested chain (own state, parent sync, drawer mutual-exclusion, the
|
|
294
|
+
* modal-closer registry); a controlled branch inside that resolution would add
|
|
295
|
+
* a fourth interacting mode. Overriding the context for the subtree instead
|
|
296
|
+
* leaves every one of those paths untouched:
|
|
297
|
+
*
|
|
298
|
+
* - `isModalOpen` is replaced with the host's `open`, so the rendered surface
|
|
299
|
+
* follows the prop from the very first frame (no open-then-close flash).
|
|
300
|
+
* - `setModalOpen` still calls the underlying setter, so the existing
|
|
301
|
+
* parent-sync and drawer mutual-exclusion side effects continue to run, and
|
|
302
|
+
* *then* reports the request through `onOpenChange`.
|
|
303
|
+
* - The wrapped setter is registered as the modal closer, so the drawer's
|
|
304
|
+
* mobile mutual-exclusion reaches the host instead of silently flipping
|
|
305
|
+
* state that nothing displays.
|
|
306
|
+
*
|
|
307
|
+
* A host that supplies `open` and ignores `onOpenChange` gets a modal pinned
|
|
308
|
+
* to `open`, which is the standard controlled-component contract. A host that
|
|
309
|
+
* supplies only `onOpenChange` is notified while the modal keeps managing
|
|
310
|
+
* itself.
|
|
311
|
+
*
|
|
312
|
+
* Renders `children` unchanged when no chat configuration is in scope.
|
|
313
|
+
*/
|
|
314
|
+
const ControlledModalOpenScope = ({ children, open, onOpenChange }) => {
|
|
315
|
+
const parentConfig = (0, react.useContext)(CopilotChatConfiguration);
|
|
316
|
+
const parentSetModalOpen = parentConfig?.setModalOpen;
|
|
317
|
+
const registerModalCloser = parentConfig?.ɵregisterModalCloser;
|
|
318
|
+
const setModalOpen = (0, react.useCallback)((next) => {
|
|
319
|
+
parentSetModalOpen?.(next);
|
|
320
|
+
onOpenChange?.(next);
|
|
321
|
+
}, [parentSetModalOpen, onOpenChange]);
|
|
322
|
+
(0, react.useEffect)(() => {
|
|
323
|
+
if (!registerModalCloser) return;
|
|
324
|
+
return registerModalCloser(setModalOpen);
|
|
325
|
+
}, [registerModalCloser, setModalOpen]);
|
|
326
|
+
const configurationValue = (0, react.useMemo)(() => parentConfig ? {
|
|
327
|
+
...parentConfig,
|
|
328
|
+
isModalOpen: open ?? parentConfig.isModalOpen,
|
|
329
|
+
setModalOpen
|
|
330
|
+
} : null, [
|
|
331
|
+
parentConfig,
|
|
332
|
+
open,
|
|
333
|
+
setModalOpen
|
|
334
|
+
]);
|
|
335
|
+
if (!configurationValue) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children });
|
|
336
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChatConfiguration.Provider, {
|
|
337
|
+
value: configurationValue,
|
|
338
|
+
children
|
|
339
|
+
});
|
|
340
|
+
};
|
|
341
|
+
ControlledModalOpenScope.displayName = "ControlledModalOpenScope";
|
|
286
342
|
|
|
287
343
|
//#endregion
|
|
288
344
|
//#region src/v2/lib/utils.ts
|
|
@@ -1604,6 +1660,29 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
1604
1660
|
if (prevProps.RenderComponent !== nextProps.RenderComponent) return false;
|
|
1605
1661
|
return true;
|
|
1606
1662
|
});
|
|
1663
|
+
const IS_DEVELOPMENT$1 = process.env.NODE_ENV !== "production";
|
|
1664
|
+
/**
|
|
1665
|
+
* Reports tool calls that resolved to no renderer.
|
|
1666
|
+
*
|
|
1667
|
+
* A tool call with no renderer paints an empty message container and says
|
|
1668
|
+
* nothing else, so the only signal a developer gets today is a blank space in
|
|
1669
|
+
* the chat. This names the call and the renderers that *are* registered, which
|
|
1670
|
+
* is the whole diagnosis when the cause is a name that does not match.
|
|
1671
|
+
*
|
|
1672
|
+
* @param toolNames - The unmatched tool names collected during render.
|
|
1673
|
+
* @param registered - The registry as it stands now, re-read at report time.
|
|
1674
|
+
* @param alreadyWarned - Names already reported, mutated to keep this once per name.
|
|
1675
|
+
*/
|
|
1676
|
+
function warnAboutUnrenderedToolCalls(toolNames, registered, alreadyWarned) {
|
|
1677
|
+
const registeredNames = Array.from(new Set(registered.map((rc) => rc.name)));
|
|
1678
|
+
const hasWildcard = registeredNames.includes("*");
|
|
1679
|
+
for (const toolName of toolNames) {
|
|
1680
|
+
if (hasWildcard || registeredNames.includes(toolName)) continue;
|
|
1681
|
+
if (alreadyWarned.has(toolName)) continue;
|
|
1682
|
+
alreadyWarned.add(toolName);
|
|
1683
|
+
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.`);
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1607
1686
|
/**
|
|
1608
1687
|
* Hook that returns a function to render tool calls based on the render functions
|
|
1609
1688
|
* defined in CopilotKitProvider.
|
|
@@ -1613,13 +1692,18 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
1613
1692
|
function useRenderToolCall() {
|
|
1614
1693
|
const { copilotkit, executingToolCallIds } = useCopilotKit();
|
|
1615
1694
|
const agentId = useCopilotChatConfiguration()?.agentId ?? _copilotkit_shared.DEFAULT_AGENT_ID;
|
|
1695
|
+
const unrenderedToolNames = (0, react.useRef)(/* @__PURE__ */ new Set());
|
|
1696
|
+
const warnedToolNames = (0, react.useRef)(/* @__PURE__ */ new Set());
|
|
1616
1697
|
const renderToolCalls = (0, react.useSyncExternalStore)((callback) => {
|
|
1617
1698
|
return copilotkit.subscribe({ onRenderToolCallsChanged: callback }).unsubscribe;
|
|
1618
1699
|
}, () => copilotkit.renderToolCalls, () => copilotkit.renderToolCalls);
|
|
1619
|
-
|
|
1700
|
+
const renderToolCall = (0, react.useCallback)(({ toolCall, toolMessage }) => {
|
|
1620
1701
|
const exactMatches = renderToolCalls.filter((rc) => rc.name === toolCall.function.name);
|
|
1621
1702
|
const renderConfig = exactMatches.find((rc) => rc.agentId === agentId) || exactMatches.find((rc) => !rc.agentId) || exactMatches[0] || renderToolCalls.find((rc) => rc.name === "*");
|
|
1622
|
-
if (!renderConfig)
|
|
1703
|
+
if (!renderConfig) {
|
|
1704
|
+
if (IS_DEVELOPMENT$1) unrenderedToolNames.current.add(toolCall.function.name);
|
|
1705
|
+
return null;
|
|
1706
|
+
}
|
|
1623
1707
|
const RenderComponent = renderConfig.render;
|
|
1624
1708
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToolCallRenderer, {
|
|
1625
1709
|
toolCall,
|
|
@@ -1632,6 +1716,17 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
|
|
|
1632
1716
|
executingToolCallIds,
|
|
1633
1717
|
agentId
|
|
1634
1718
|
]);
|
|
1719
|
+
(0, react.useEffect)(() => {
|
|
1720
|
+
if (!IS_DEVELOPMENT$1) return;
|
|
1721
|
+
if (unrenderedToolNames.current.size === 0) return;
|
|
1722
|
+
const timer = setTimeout(() => {
|
|
1723
|
+
const pending = Array.from(unrenderedToolNames.current);
|
|
1724
|
+
unrenderedToolNames.current.clear();
|
|
1725
|
+
warnAboutUnrenderedToolCalls(pending, copilotkit.renderToolCalls, warnedToolNames.current);
|
|
1726
|
+
}, 0);
|
|
1727
|
+
return () => clearTimeout(timer);
|
|
1728
|
+
});
|
|
1729
|
+
return renderToolCall;
|
|
1635
1730
|
}
|
|
1636
1731
|
|
|
1637
1732
|
//#endregion
|
|
@@ -3110,6 +3205,95 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
3110
3205
|
a2ui_operations: zod.z.array(zod.z.any()).optional(),
|
|
3111
3206
|
...A2UILifecycleFields
|
|
3112
3207
|
}).passthrough();
|
|
3208
|
+
const IS_DEVELOPMENT = process.env.NODE_ENV !== "production";
|
|
3209
|
+
/**
|
|
3210
|
+
* How long to wait for a surface to report its first paint before giving up on
|
|
3211
|
+
* the loader cross-over. Reaching it also means `onReady` never fired, which is
|
|
3212
|
+
* the signal the warning below reports.
|
|
3213
|
+
*/
|
|
3214
|
+
const PAINT_FALLBACK_MS = 8e3;
|
|
3215
|
+
/**
|
|
3216
|
+
* Names the operation kinds a surface received, for a warning that has to say
|
|
3217
|
+
* what did arrive as well as what did not.
|
|
3218
|
+
*
|
|
3219
|
+
* @param operations - The operations grouped under one surface.
|
|
3220
|
+
* @returns A comma-separated list of operation keys, or "none".
|
|
3221
|
+
*/
|
|
3222
|
+
function describeOperationKinds(operations) {
|
|
3223
|
+
const kinds = /* @__PURE__ */ new Set();
|
|
3224
|
+
for (const operation of operations) {
|
|
3225
|
+
if (!operation || typeof operation !== "object") continue;
|
|
3226
|
+
for (const key of Object.keys(operation)) if (key !== "version") kinds.add(key);
|
|
3227
|
+
}
|
|
3228
|
+
return kinds.size === 0 ? "none" : Array.from(kinds).join(", ");
|
|
3229
|
+
}
|
|
3230
|
+
/**
|
|
3231
|
+
* Reports surfaces that received operations and never painted.
|
|
3232
|
+
*
|
|
3233
|
+
* Reaching {@link PAINT_FALLBACK_MS} with no `onReady` means the operations were
|
|
3234
|
+
* accepted, were not malformed enough to raise the provider's error state, and
|
|
3235
|
+
* still put nothing on screen. Left alone that is invisible: the loader drops,
|
|
3236
|
+
* the turn finishes, and the only trace is an empty placeholder above the reply.
|
|
3237
|
+
*
|
|
3238
|
+
* `surfaceHasRenderableContent` already knows which half is missing, so the
|
|
3239
|
+
* warning says which rather than making the reader re-derive it.
|
|
3240
|
+
*
|
|
3241
|
+
* @param grouped - Operations grouped by surface id.
|
|
3242
|
+
*/
|
|
3243
|
+
function warnAboutUnpaintedSurfaces(grouped) {
|
|
3244
|
+
for (const [surfaceId, operations] of grouped) {
|
|
3245
|
+
if (surfaceHasRenderableContent(operations)) continue;
|
|
3246
|
+
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";
|
|
3247
|
+
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.`);
|
|
3248
|
+
}
|
|
3249
|
+
}
|
|
3250
|
+
/**
|
|
3251
|
+
* Names the component ids a surface was sent, for a warning about the one id
|
|
3252
|
+
* that is missing.
|
|
3253
|
+
*
|
|
3254
|
+
* @param operations - The operations grouped under one surface.
|
|
3255
|
+
* @returns A quoted, comma-separated list of ids, or "none".
|
|
3256
|
+
*/
|
|
3257
|
+
function describeComponentIds(operations) {
|
|
3258
|
+
const ids = [];
|
|
3259
|
+
for (const operation of operations) {
|
|
3260
|
+
const components = operation?.updateComponents?.components;
|
|
3261
|
+
if (!Array.isArray(components)) continue;
|
|
3262
|
+
for (const component of components) {
|
|
3263
|
+
const id = component?.id;
|
|
3264
|
+
if (typeof id === "string" && !ids.includes(id)) ids.push(id);
|
|
3265
|
+
}
|
|
3266
|
+
}
|
|
3267
|
+
return ids.length === 0 ? "none" : ids.map((id) => `"${id}"`).join(", ");
|
|
3268
|
+
}
|
|
3269
|
+
/**
|
|
3270
|
+
* Reports a surface that is still waiting for its {@link ROOT_COMPONENT_ID}
|
|
3271
|
+
* component once its operations have stopped arriving.
|
|
3272
|
+
*
|
|
3273
|
+
* Both renderers begin walking a surface at that one id, and treat an id they
|
|
3274
|
+
* cannot find as not arrived yet — an animated placeholder. That is right while
|
|
3275
|
+
* operations stream. Once they have stopped it is not waiting, it is stuck, and
|
|
3276
|
+
* every other check calls it healthy: the surface exists, `processMessages` did
|
|
3277
|
+
* not throw, the component types were never reached, and
|
|
3278
|
+
* `surfaceHasRenderableContent` says yes on the strength of components plus a
|
|
3279
|
+
* data model, so `onReady` fires and the never-painted report is suppressed.
|
|
3280
|
+
* A complete, accepted payload therefore animates a grey box forever in silence.
|
|
3281
|
+
*
|
|
3282
|
+
* Reads the live components model rather than scanning the operations for the
|
|
3283
|
+
* id, so it covers every way the root can fail to resolve — not only a payload
|
|
3284
|
+
* that never named one.
|
|
3285
|
+
*
|
|
3286
|
+
* @param surfaceId - The surface the operations were addressed to.
|
|
3287
|
+
* @param operations - The operations processed for that surface.
|
|
3288
|
+
* @param surface - The live surface model, already known to exist.
|
|
3289
|
+
*/
|
|
3290
|
+
function warnAboutUnresolvedRoot(surfaceId, operations, surface) {
|
|
3291
|
+
if (surface?.componentsModel?.get?.(_copilotkit_a2ui_renderer.ROOT_COMPONENT_ID)) return;
|
|
3292
|
+
const componentOps = operations.filter((o) => o?.updateComponents);
|
|
3293
|
+
if (componentOps.length === 0) return;
|
|
3294
|
+
const cause = componentOps.some((o) => o.updateComponents?.components?.some?.((c) => c?.id === _copilotkit_a2ui_renderer.ROOT_COMPONENT_ID)) ? `a component with id "${_copilotkit_a2ui_renderer.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 "${_copilotkit_a2ui_renderer.ROOT_COMPONENT_ID}" — rename the entry-point component to "${_copilotkit_a2ui_renderer.ROOT_COMPONENT_ID}", and make every other component reachable from it through child/children`;
|
|
3295
|
+
console.warn(`[CopilotKit] A2UI surface "${surfaceId}" has no "${_copilotkit_a2ui_renderer.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.`);
|
|
3296
|
+
}
|
|
3113
3297
|
function createA2UIMessageRenderer(options) {
|
|
3114
3298
|
const { theme, catalog, loadingComponent, recovery, onAction } = options;
|
|
3115
3299
|
const showAfterMs = recovery?.showAfterMs ?? 2e3;
|
|
@@ -3143,6 +3327,8 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
3143
3327
|
return groups;
|
|
3144
3328
|
}, [operations]);
|
|
3145
3329
|
const hasOps = groupedOperations.size > 0;
|
|
3330
|
+
const groupedOperationsRef = (0, react.useRef)(groupedOperations);
|
|
3331
|
+
groupedOperationsRef.current = groupedOperations;
|
|
3146
3332
|
const renderLifecycle = (c) => {
|
|
3147
3333
|
const status = c?.status;
|
|
3148
3334
|
const debugExposure = resolveDebugExposure(c, optionDebugExposure);
|
|
@@ -3174,7 +3360,10 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
3174
3360
|
readyRef.current = false;
|
|
3175
3361
|
return;
|
|
3176
3362
|
}
|
|
3177
|
-
const t = setTimeout(() =>
|
|
3363
|
+
const t = setTimeout(() => {
|
|
3364
|
+
setSurfaceReady(true);
|
|
3365
|
+
if (IS_DEVELOPMENT && !readyRef.current) warnAboutUnpaintedSurfaces(groupedOperationsRef.current);
|
|
3366
|
+
}, PAINT_FALLBACK_MS);
|
|
3178
3367
|
return () => clearTimeout(t);
|
|
3179
3368
|
}, [hasOps]);
|
|
3180
3369
|
if (!hasOps) return renderLifecycle(content);
|
|
@@ -3298,8 +3487,21 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
3298
3487
|
const hash = JSON.stringify(operations);
|
|
3299
3488
|
if (hash === lastHashRef.current) return;
|
|
3300
3489
|
lastHashRef.current = hash;
|
|
3301
|
-
|
|
3490
|
+
const ops = getSurface(surfaceId) ? operations.filter((op) => !op?.createSurface) : operations;
|
|
3491
|
+
processMessages(ops);
|
|
3302
3492
|
if (onReady && surfaceHasRenderableContent(operations)) onReady();
|
|
3493
|
+
if (!IS_DEVELOPMENT) return;
|
|
3494
|
+
if (!getSurface(surfaceId)) {
|
|
3495
|
+
const missingSurfaceCheck = setTimeout(() => {
|
|
3496
|
+
if (getSurface(surfaceId)) return;
|
|
3497
|
+
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.`);
|
|
3498
|
+
}, 0);
|
|
3499
|
+
return () => clearTimeout(missingSurfaceCheck);
|
|
3500
|
+
}
|
|
3501
|
+
const unresolvedRootCheck = setTimeout(() => {
|
|
3502
|
+
warnAboutUnresolvedRoot(surfaceId, operations, getSurface(surfaceId));
|
|
3503
|
+
}, PAINT_FALLBACK_MS);
|
|
3504
|
+
return () => clearTimeout(unresolvedRootCheck);
|
|
3303
3505
|
}, [
|
|
3304
3506
|
processMessages,
|
|
3305
3507
|
getSurface,
|
|
@@ -3326,10 +3528,26 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
3326
3528
|
return Object.values(v).some((x) => Array.isArray(x) ? x.length > 0 : x !== null && x !== void 0 && x !== "");
|
|
3327
3529
|
});
|
|
3328
3530
|
}
|
|
3531
|
+
/**
|
|
3532
|
+
* Resolves the surface an operation addresses.
|
|
3533
|
+
*
|
|
3534
|
+
* The nested v0.9 `surfaceId` wins, because that is the id `MessageProcessor`
|
|
3535
|
+
* creates the surface under. Grouping by a top-level `surfaceId` instead files
|
|
3536
|
+
* the operations against a surface that never exists, which paints nothing —
|
|
3537
|
+
* the silence the missing-surface report above now names. A top-level
|
|
3538
|
+
* `surfaceId` is not the v0.9 shape, so it is honoured only when no nested id is
|
|
3539
|
+
* present. `getSurfaceId` in `@copilotkit/a2ui-renderer`'s web-components path
|
|
3540
|
+
* resolves it in the same order; the two disagreeing is what OSS-1048 recorded.
|
|
3541
|
+
*
|
|
3542
|
+
* @param operation - One A2UI operation, of any shape.
|
|
3543
|
+
* @returns The surface id, or null when the operation names none.
|
|
3544
|
+
*/
|
|
3329
3545
|
function getOperationSurfaceId(operation) {
|
|
3330
3546
|
if (!operation || typeof operation !== "object") return null;
|
|
3547
|
+
const nested = operation?.createSurface?.surfaceId ?? operation?.updateComponents?.surfaceId ?? operation?.updateDataModel?.surfaceId ?? operation?.deleteSurface?.surfaceId;
|
|
3548
|
+
if (typeof nested === "string") return nested;
|
|
3331
3549
|
if (typeof operation.surfaceId === "string") return operation.surfaceId;
|
|
3332
|
-
return
|
|
3550
|
+
return null;
|
|
3333
3551
|
}
|
|
3334
3552
|
|
|
3335
3553
|
//#endregion
|
|
@@ -3447,6 +3665,9 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
3447
3665
|
const EMPTY_HEADERS = Object.freeze({});
|
|
3448
3666
|
const EMPTY_PROPERTIES = Object.freeze({});
|
|
3449
3667
|
const EMPTY_AGENTS = Object.freeze({});
|
|
3668
|
+
/** Registration name of a catch-all tool: handles any otherwise-unhandled call. */
|
|
3669
|
+
const WILDCARD_TOOL_NAME$1 = "*";
|
|
3670
|
+
const HUMAN_IN_THE_LOOP_ABORTED_MESSAGE = "Human-in-the-loop interaction aborted";
|
|
3450
3671
|
const DEFAULT_DESIGN_SKILL = `When generating UI with generateSandboxedUi, follow these design principles inspired by shadcn/ui:
|
|
3451
3672
|
|
|
3452
3673
|
- Use a minimal, flat aesthetic. Avoid drop shadows and gradients — rely on subtle borders (1px solid, light gray like #e5e7eb) to define surfaces.
|
|
@@ -3565,6 +3786,11 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
3565
3786
|
}
|
|
3566
3787
|
const chatApiEndpoint = runtimeUrl ?? (resolvedPublicKey ? COPILOT_CLOUD_CHAT_URL$1 : void 0);
|
|
3567
3788
|
const frontendToolsList = useStableArrayProp(frontendTools, "frontendTools must be a stable array. If you want to dynamically add or remove tools, use `useFrontendTool` instead.");
|
|
3789
|
+
/**
|
|
3790
|
+
* A `humanInTheLoop` prop tool call that is parked, waiting on the user.
|
|
3791
|
+
* Keyed by tool call id, so parallel calls of one tool stay independent.
|
|
3792
|
+
*/
|
|
3793
|
+
const pendingHumanInTheLoopRef = (0, react.useRef)(/* @__PURE__ */ new Map());
|
|
3568
3794
|
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.");
|
|
3569
3795
|
const sandboxFunctionsList = useStableArrayProp(openGenerativeUI?.sandboxFunctions, "openGenerativeUI.sandboxFunctions must be a stable array.");
|
|
3570
3796
|
const processedHumanInTheLoopTools = (0, react.useMemo)(() => {
|
|
@@ -3577,20 +3803,52 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
3577
3803
|
parameters: tool.parameters,
|
|
3578
3804
|
followUp: tool.followUp,
|
|
3579
3805
|
...tool.agentId && { agentId: tool.agentId },
|
|
3580
|
-
handler: async () => {
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3806
|
+
handler: async (_args, context) => {
|
|
3807
|
+
const signal = context?.signal;
|
|
3808
|
+
const key = context?.toolCall?.id ?? tool.name;
|
|
3809
|
+
return new Promise((resolve, reject) => {
|
|
3810
|
+
if (signal?.aborted) {
|
|
3811
|
+
reject(new Error(HUMAN_IN_THE_LOOP_ABORTED_MESSAGE));
|
|
3812
|
+
return;
|
|
3813
|
+
}
|
|
3814
|
+
const pending = { resolve };
|
|
3815
|
+
pendingHumanInTheLoopRef.current.set(key, pending);
|
|
3816
|
+
if (signal) {
|
|
3817
|
+
const onAbort = () => {
|
|
3818
|
+
pendingHumanInTheLoopRef.current.delete(key);
|
|
3819
|
+
reject(new Error(HUMAN_IN_THE_LOOP_ABORTED_MESSAGE));
|
|
3820
|
+
};
|
|
3821
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
3822
|
+
pending.detachAbort = () => {
|
|
3823
|
+
signal.removeEventListener("abort", onAbort);
|
|
3824
|
+
};
|
|
3825
|
+
}
|
|
3584
3826
|
});
|
|
3585
3827
|
}
|
|
3586
3828
|
};
|
|
3587
3829
|
processedTools.push(frontendTool);
|
|
3588
|
-
if (tool.render)
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3830
|
+
if (tool.render) {
|
|
3831
|
+
const ToolComponent = tool.render;
|
|
3832
|
+
const RenderComponent = (props) => (0, react.createElement)(ToolComponent, {
|
|
3833
|
+
...props,
|
|
3834
|
+
name: tool.name === WILDCARD_TOOL_NAME$1 ? props.name : tool.name,
|
|
3835
|
+
description: tool.description || "",
|
|
3836
|
+
agentId: tool.agentId,
|
|
3837
|
+
respond: props.status === _copilotkit_core.ToolCallStatus.Executing ? async (result) => {
|
|
3838
|
+
const pending = pendingHumanInTheLoopRef.current.get(props.toolCallId);
|
|
3839
|
+
if (!pending) return;
|
|
3840
|
+
pending.detachAbort?.();
|
|
3841
|
+
pendingHumanInTheLoopRef.current.delete(props.toolCallId);
|
|
3842
|
+
pending.resolve(result);
|
|
3843
|
+
} : void 0
|
|
3844
|
+
});
|
|
3845
|
+
processedRenderToolCalls.push({
|
|
3846
|
+
name: tool.name,
|
|
3847
|
+
args: tool.parameters,
|
|
3848
|
+
render: RenderComponent,
|
|
3849
|
+
...tool.agentId && { agentId: tool.agentId }
|
|
3850
|
+
});
|
|
3851
|
+
}
|
|
3594
3852
|
});
|
|
3595
3853
|
return {
|
|
3596
3854
|
tools: processedTools,
|
|
@@ -5439,7 +5697,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
5439
5697
|
* at the call site.
|
|
5440
5698
|
*/
|
|
5441
5699
|
async function recordAnnotation(args) {
|
|
5442
|
-
const { runtimeUrl, headers, type, payload, threadId, occurredAt } = args;
|
|
5700
|
+
const { runtimeUrl, headers, type, payload, threadId, occurredAt, fetch: fetchImplementation = globalThis.fetch } = args;
|
|
5443
5701
|
const body = {
|
|
5444
5702
|
type,
|
|
5445
5703
|
threadId,
|
|
@@ -5447,7 +5705,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
5447
5705
|
...payload !== void 0 ? { payload } : {},
|
|
5448
5706
|
...occurredAt !== void 0 ? { occurredAt } : {}
|
|
5449
5707
|
};
|
|
5450
|
-
const response = await
|
|
5708
|
+
const response = await fetchImplementation(`${runtimeUrl}/annotate`, {
|
|
5451
5709
|
method: "POST",
|
|
5452
5710
|
headers: {
|
|
5453
5711
|
"Content-Type": "application/json",
|
|
@@ -5516,6 +5774,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
5516
5774
|
...input.data !== void 0 ? { data: input.data } : {}
|
|
5517
5775
|
};
|
|
5518
5776
|
return recordAnnotation({
|
|
5777
|
+
fetch: copilotkit.ɵruntimeFetch,
|
|
5519
5778
|
runtimeUrl,
|
|
5520
5779
|
headers: copilotkit.headers ?? {},
|
|
5521
5780
|
type: "user_action",
|
|
@@ -5585,7 +5844,22 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
5585
5844
|
|
|
5586
5845
|
//#endregion
|
|
5587
5846
|
//#region src/v2/hooks/use-attachments.tsx
|
|
5588
|
-
|
|
5847
|
+
const DEFAULT_MAX_SIZE = 20 * 1024 * 1024;
|
|
5848
|
+
/**
|
|
5849
|
+
* How many uploads run at once when `maxConcurrentUploads` is unset. One, because
|
|
5850
|
+
* `onUpload` is a public callback an app may have written expecting the previous
|
|
5851
|
+
* file to have finished — concurrency is something the app asks for.
|
|
5852
|
+
*/
|
|
5853
|
+
const DEFAULT_MAX_CONCURRENT_UPLOADS = 1;
|
|
5854
|
+
/**
|
|
5855
|
+
* At least one upload at a time, whole files only; `NaN` or a non-number falls back to the
|
|
5856
|
+
* default, and `Infinity` means "no limit" — bounded in practice by how many files are queued.
|
|
5857
|
+
*/
|
|
5858
|
+
function resolveMaxConcurrentUploads(configured) {
|
|
5859
|
+
if (typeof configured !== "number" || Number.isNaN(configured)) return DEFAULT_MAX_CONCURRENT_UPLOADS;
|
|
5860
|
+
return Math.max(1, Math.floor(configured));
|
|
5861
|
+
}
|
|
5862
|
+
/**
|
|
5589
5863
|
* Hook that manages file attachment state — uploads, drag-and-drop, paste,
|
|
5590
5864
|
* and lifecycle. All returned callbacks are referentially stable across
|
|
5591
5865
|
* renders (via useCallback) to avoid destabilizing downstream memoization.
|
|
@@ -5600,10 +5874,62 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
5600
5874
|
configRef.current = config;
|
|
5601
5875
|
const attachmentsRef = (0, react.useRef)([]);
|
|
5602
5876
|
attachmentsRef.current = attachments;
|
|
5877
|
+
const uploadQueueRef = (0, react.useRef)([]);
|
|
5878
|
+
const activeWorkersRef = (0, react.useRef)(0);
|
|
5879
|
+
const uploadFile = (0, react.useCallback)(async (file, placeholder, cfg) => {
|
|
5880
|
+
try {
|
|
5881
|
+
let source;
|
|
5882
|
+
let uploadMetadata;
|
|
5883
|
+
if (cfg?.onUpload) {
|
|
5884
|
+
const { metadata: meta, ...uploadSource } = await cfg.onUpload(file);
|
|
5885
|
+
source = uploadSource;
|
|
5886
|
+
uploadMetadata = meta;
|
|
5887
|
+
} else source = {
|
|
5888
|
+
type: "data",
|
|
5889
|
+
value: await (0, _copilotkit_shared.readFileAsBase64)(file),
|
|
5890
|
+
mimeType: file.type
|
|
5891
|
+
};
|
|
5892
|
+
let thumbnail;
|
|
5893
|
+
if (placeholder.type === "video") thumbnail = await (0, _copilotkit_shared.generateVideoThumbnail)(file);
|
|
5894
|
+
setAttachments((prev) => prev.map((att) => att.id === placeholder.id ? {
|
|
5895
|
+
...att,
|
|
5896
|
+
source,
|
|
5897
|
+
status: "ready",
|
|
5898
|
+
thumbnail,
|
|
5899
|
+
metadata: uploadMetadata
|
|
5900
|
+
} : att));
|
|
5901
|
+
} catch (error) {
|
|
5902
|
+
setAttachments((prev) => prev.filter((att) => att.id !== placeholder.id));
|
|
5903
|
+
console.error(`[CopilotKit] Failed to upload "${file.name}":`, error);
|
|
5904
|
+
cfg?.onUploadFailed?.({
|
|
5905
|
+
reason: "upload-failed",
|
|
5906
|
+
file,
|
|
5907
|
+
message: error instanceof Error ? error.message : `Failed to upload "${file.name}"`
|
|
5908
|
+
});
|
|
5909
|
+
}
|
|
5910
|
+
}, []);
|
|
5911
|
+
const drainUploadQueue = (0, react.useCallback)(async () => {
|
|
5912
|
+
activeWorkersRef.current++;
|
|
5913
|
+
try {
|
|
5914
|
+
for (;;) {
|
|
5915
|
+
const item = uploadQueueRef.current.shift();
|
|
5916
|
+
if (!item) return;
|
|
5917
|
+
try {
|
|
5918
|
+
await uploadFile(item.file, item.placeholder, item.cfg);
|
|
5919
|
+
} catch (error) {
|
|
5920
|
+
console.error("[CopilotKit] Upload worker error:", error);
|
|
5921
|
+
} finally {
|
|
5922
|
+
item.settle();
|
|
5923
|
+
}
|
|
5924
|
+
}
|
|
5925
|
+
} finally {
|
|
5926
|
+
activeWorkersRef.current--;
|
|
5927
|
+
}
|
|
5928
|
+
}, [uploadFile]);
|
|
5603
5929
|
const processFiles = (0, react.useCallback)(async (files) => {
|
|
5604
5930
|
const cfg = configRef.current;
|
|
5605
5931
|
const accept = cfg?.accept ?? "*/*";
|
|
5606
|
-
const maxSize = cfg?.maxSize ??
|
|
5932
|
+
const maxSize = cfg?.maxSize ?? DEFAULT_MAX_SIZE;
|
|
5607
5933
|
const rejectedFiles = files.filter((file) => !(0, _copilotkit_shared.matchesAcceptFilter)(file, accept));
|
|
5608
5934
|
for (const file of rejectedFiles) cfg?.onUploadFailed?.({
|
|
5609
5935
|
reason: "invalid-type",
|
|
@@ -5611,6 +5937,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
5611
5937
|
message: `File "${file.name}" is not accepted. Supported types: ${accept}`
|
|
5612
5938
|
});
|
|
5613
5939
|
const validFiles = files.filter((file) => (0, _copilotkit_shared.matchesAcceptFilter)(file, accept));
|
|
5940
|
+
const queued = [];
|
|
5614
5941
|
for (const file of validFiles) {
|
|
5615
5942
|
if ((0, _copilotkit_shared.exceedsMaxSize)(file, maxSize)) {
|
|
5616
5943
|
cfg?.onUploadFailed?.({
|
|
@@ -5620,53 +5947,37 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
5620
5947
|
});
|
|
5621
5948
|
continue;
|
|
5622
5949
|
}
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
try {
|
|
5639
|
-
let source;
|
|
5640
|
-
let uploadMetadata;
|
|
5641
|
-
if (cfg?.onUpload) {
|
|
5642
|
-
const { metadata: meta, ...uploadSource } = await cfg.onUpload(file);
|
|
5643
|
-
source = uploadSource;
|
|
5644
|
-
uploadMetadata = meta;
|
|
5645
|
-
} else source = {
|
|
5646
|
-
type: "data",
|
|
5647
|
-
value: await (0, _copilotkit_shared.readFileAsBase64)(file),
|
|
5648
|
-
mimeType: file.type
|
|
5649
|
-
};
|
|
5650
|
-
let thumbnail;
|
|
5651
|
-
if (modality === "video") thumbnail = await (0, _copilotkit_shared.generateVideoThumbnail)(file);
|
|
5652
|
-
setAttachments((prev) => prev.map((att) => att.id === placeholderId ? {
|
|
5653
|
-
...att,
|
|
5654
|
-
source,
|
|
5655
|
-
status: "ready",
|
|
5656
|
-
thumbnail,
|
|
5657
|
-
metadata: uploadMetadata
|
|
5658
|
-
} : att));
|
|
5659
|
-
} catch (error) {
|
|
5660
|
-
setAttachments((prev) => prev.filter((att) => att.id !== placeholderId));
|
|
5661
|
-
console.error(`[CopilotKit] Failed to upload "${file.name}":`, error);
|
|
5662
|
-
cfg?.onUploadFailed?.({
|
|
5663
|
-
reason: "upload-failed",
|
|
5664
|
-
file,
|
|
5665
|
-
message: error instanceof Error ? error.message : `Failed to upload "${file.name}"`
|
|
5666
|
-
});
|
|
5667
|
-
}
|
|
5950
|
+
queued.push({
|
|
5951
|
+
file,
|
|
5952
|
+
placeholder: {
|
|
5953
|
+
id: (0, _copilotkit_shared.randomUUID)(),
|
|
5954
|
+
type: (0, _copilotkit_shared.getModalityFromMimeType)(file.type),
|
|
5955
|
+
source: {
|
|
5956
|
+
type: "data",
|
|
5957
|
+
value: "",
|
|
5958
|
+
mimeType: file.type
|
|
5959
|
+
},
|
|
5960
|
+
filename: file.name,
|
|
5961
|
+
size: file.size,
|
|
5962
|
+
status: "uploading"
|
|
5963
|
+
}
|
|
5964
|
+
});
|
|
5668
5965
|
}
|
|
5669
|
-
|
|
5966
|
+
if (queued.length === 0) return;
|
|
5967
|
+
setAttachments((prev) => [...prev, ...queued.map((q) => q.placeholder)]);
|
|
5968
|
+
const settled = queued.map(({ file, placeholder }) => new Promise((resolve) => {
|
|
5969
|
+
uploadQueueRef.current.push({
|
|
5970
|
+
file,
|
|
5971
|
+
placeholder,
|
|
5972
|
+
cfg,
|
|
5973
|
+
settle: resolve
|
|
5974
|
+
});
|
|
5975
|
+
}));
|
|
5976
|
+
const limit = resolveMaxConcurrentUploads(cfg?.maxConcurrentUploads);
|
|
5977
|
+
const toSpawn = Math.min(uploadQueueRef.current.length, Math.max(0, limit - activeWorkersRef.current));
|
|
5978
|
+
for (let i = 0; i < toSpawn; i++) drainUploadQueue();
|
|
5979
|
+
await Promise.all(settled);
|
|
5980
|
+
}, [drainUploadQueue]);
|
|
5670
5981
|
const handleFileUpload = (0, react.useCallback)(async (e) => {
|
|
5671
5982
|
if (!e.target.files?.length) return;
|
|
5672
5983
|
try {
|
|
@@ -5794,8 +6105,10 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
5794
6105
|
const warnedMissingUrlRef = (0, react.useRef)(false);
|
|
5795
6106
|
const runtimeUrlRef = (0, react.useRef)(copilotkit.runtimeUrl);
|
|
5796
6107
|
const headersRef = (0, react.useRef)(copilotkit.headers ?? {});
|
|
6108
|
+
const runtimeFetchRef = (0, react.useRef)(copilotkit.ɵruntimeFetch);
|
|
5797
6109
|
runtimeUrlRef.current = copilotkit.runtimeUrl;
|
|
5798
6110
|
headersRef.current = copilotkit.headers ?? {};
|
|
6111
|
+
runtimeFetchRef.current = copilotkit.ɵruntimeFetch;
|
|
5799
6112
|
const key = JSON.stringify(learningContainers);
|
|
5800
6113
|
const defaultKey = JSON.stringify(DEFAULT_CONTAINERS);
|
|
5801
6114
|
(0, react.useEffect)(() => {
|
|
@@ -5815,6 +6128,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
5815
6128
|
return;
|
|
5816
6129
|
}
|
|
5817
6130
|
recordAnnotation({
|
|
6131
|
+
fetch: copilotkit.ɵruntimeFetch,
|
|
5818
6132
|
runtimeUrl,
|
|
5819
6133
|
headers,
|
|
5820
6134
|
type: "set_learning_containers",
|
|
@@ -5842,6 +6156,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
5842
6156
|
const capturedRuntimeUrl = runtimeUrlRef.current;
|
|
5843
6157
|
const capturedHeaders = headersRef.current;
|
|
5844
6158
|
if (capturedRuntimeUrl) recordAnnotation({
|
|
6159
|
+
fetch: runtimeFetchRef.current,
|
|
5845
6160
|
runtimeUrl: capturedRuntimeUrl,
|
|
5846
6161
|
headers: capturedHeaders,
|
|
5847
6162
|
type: "set_learning_containers",
|
|
@@ -9104,6 +9419,41 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
9104
9419
|
});
|
|
9105
9420
|
CopilotChatToggleButton.displayName = "CopilotChatToggleButton";
|
|
9106
9421
|
|
|
9422
|
+
//#endregion
|
|
9423
|
+
//#region src/v2/components/chat/modal-open-control.tsx
|
|
9424
|
+
const ModalOpenControlContext = (0, react.createContext)({});
|
|
9425
|
+
/**
|
|
9426
|
+
* Carries `open` / `onOpenChange` from a prebuilt surface down to the view that
|
|
9427
|
+
* owns the modal state.
|
|
9428
|
+
*
|
|
9429
|
+
* A context is required rather than plain props because `<CopilotSidebar>`
|
|
9430
|
+
* hands its view to `<CopilotChat>` as a `chatView` **component**. Threading a
|
|
9431
|
+
* value that changes (like `open`) through that component's identity would mint
|
|
9432
|
+
* a new element type on every toggle, and React unmounts and remounts the whole
|
|
9433
|
+
* chat subtree when the element type changes. That is the remount class of bug
|
|
9434
|
+
* already fixed for `<CopilotPopup>` on resize. Context keeps the override
|
|
9435
|
+
* identity stable while still re-rendering the view when `open` changes.
|
|
9436
|
+
*/
|
|
9437
|
+
function ModalOpenControlProvider({ open, onOpenChange, children }) {
|
|
9438
|
+
const value = (0, react.useMemo)(() => ({
|
|
9439
|
+
open,
|
|
9440
|
+
onOpenChange
|
|
9441
|
+
}), [open, onOpenChange]);
|
|
9442
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModalOpenControlContext.Provider, {
|
|
9443
|
+
value,
|
|
9444
|
+
children
|
|
9445
|
+
});
|
|
9446
|
+
}
|
|
9447
|
+
/**
|
|
9448
|
+
* Reads the controlled open state supplied by the surrounding prebuilt
|
|
9449
|
+
* surface. Returns an empty control (uncontrolled) when there is none.
|
|
9450
|
+
*
|
|
9451
|
+
* @returns The host's `open` / `onOpenChange` pair.
|
|
9452
|
+
*/
|
|
9453
|
+
function useModalOpenControl() {
|
|
9454
|
+
return (0, react.useContext)(ModalOpenControlContext);
|
|
9455
|
+
}
|
|
9456
|
+
|
|
9107
9457
|
//#endregion
|
|
9108
9458
|
//#region src/v2/components/chat/CopilotModalHeader.tsx
|
|
9109
9459
|
/**
|
|
@@ -9213,15 +9563,22 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
9213
9563
|
const DEFAULT_SIDEBAR_WIDTH = 480;
|
|
9214
9564
|
const SIDEBAR_TRANSITION_MS = 260;
|
|
9215
9565
|
function CopilotSidebarView({ header, toggleButton, width, defaultOpen = true, position = "right", ...props }) {
|
|
9566
|
+
const { open, onOpenChange } = useModalOpenControl();
|
|
9567
|
+
const hasOpenControl = open !== void 0 || onOpenChange !== void 0;
|
|
9568
|
+
const internal = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotSidebarViewInternal, {
|
|
9569
|
+
header,
|
|
9570
|
+
toggleButton,
|
|
9571
|
+
width,
|
|
9572
|
+
position,
|
|
9573
|
+
...props
|
|
9574
|
+
});
|
|
9216
9575
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChatConfigurationProvider, {
|
|
9217
|
-
isModalDefaultOpen: defaultOpen,
|
|
9218
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
9219
|
-
|
|
9220
|
-
|
|
9221
|
-
|
|
9222
|
-
|
|
9223
|
-
...props
|
|
9224
|
-
})
|
|
9576
|
+
isModalDefaultOpen: open ?? defaultOpen,
|
|
9577
|
+
children: hasOpenControl ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ControlledModalOpenScope, {
|
|
9578
|
+
open,
|
|
9579
|
+
onOpenChange,
|
|
9580
|
+
children: internal
|
|
9581
|
+
}) : internal
|
|
9225
9582
|
});
|
|
9226
9583
|
}
|
|
9227
9584
|
function CopilotSidebarViewInternal({ header, toggleButton, width, position = "right", ...props }) {
|
|
@@ -9285,7 +9642,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
9285
9642
|
"data-position": position,
|
|
9286
9643
|
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"),
|
|
9287
9644
|
style: {
|
|
9288
|
-
|
|
9645
|
+
"--sidebar-width": widthToCss(sidebarWidth),
|
|
9289
9646
|
paddingTop: "env(safe-area-inset-top)",
|
|
9290
9647
|
paddingBottom: "env(safe-area-inset-bottom)"
|
|
9291
9648
|
},
|
|
@@ -9347,17 +9704,24 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
9347
9704
|
return `${fallback}px`;
|
|
9348
9705
|
};
|
|
9349
9706
|
function CopilotPopupView({ header, toggleButton, width, height, clickOutsideToClose, defaultOpen = true, className, ...restProps }) {
|
|
9707
|
+
const { open, onOpenChange } = useModalOpenControl();
|
|
9708
|
+
const hasOpenControl = open !== void 0 || onOpenChange !== void 0;
|
|
9709
|
+
const internal = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotPopupViewInternal, {
|
|
9710
|
+
header,
|
|
9711
|
+
toggleButton,
|
|
9712
|
+
width,
|
|
9713
|
+
height,
|
|
9714
|
+
clickOutsideToClose,
|
|
9715
|
+
className,
|
|
9716
|
+
...restProps
|
|
9717
|
+
});
|
|
9350
9718
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChatConfigurationProvider, {
|
|
9351
|
-
isModalDefaultOpen: defaultOpen,
|
|
9352
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
9353
|
-
|
|
9354
|
-
|
|
9355
|
-
|
|
9356
|
-
|
|
9357
|
-
clickOutsideToClose,
|
|
9358
|
-
className,
|
|
9359
|
-
...restProps
|
|
9360
|
-
})
|
|
9719
|
+
isModalDefaultOpen: open ?? defaultOpen,
|
|
9720
|
+
children: hasOpenControl ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ControlledModalOpenScope, {
|
|
9721
|
+
open,
|
|
9722
|
+
onOpenChange,
|
|
9723
|
+
children: internal
|
|
9724
|
+
}) : internal
|
|
9361
9725
|
});
|
|
9362
9726
|
}
|
|
9363
9727
|
function CopilotPopupViewInternal({ header, toggleButton, width, height, clickOutsideToClose, className, ...restProps }) {
|
|
@@ -9490,7 +9854,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
9490
9854
|
|
|
9491
9855
|
//#endregion
|
|
9492
9856
|
//#region src/v2/components/chat/CopilotSidebar.tsx
|
|
9493
|
-
function CopilotSidebar({ header, toggleButton, defaultOpen, width, position, ...chatProps }) {
|
|
9857
|
+
function CopilotSidebar({ header, toggleButton, defaultOpen, open, onOpenChange, width, position, ...chatProps }) {
|
|
9494
9858
|
const { checkFeature } = useLicenseContext();
|
|
9495
9859
|
const isSidebarLicensed = checkFeature("sidebar");
|
|
9496
9860
|
(0, react.useEffect)(() => {
|
|
@@ -9516,11 +9880,15 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
9516
9880
|
defaultOpen,
|
|
9517
9881
|
position
|
|
9518
9882
|
]);
|
|
9519
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [!isSidebarLicensed && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InlineFeatureWarning, { featureName: "Sidebar" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
9520
|
-
|
|
9521
|
-
|
|
9522
|
-
|
|
9523
|
-
|
|
9883
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [!isSidebarLicensed && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InlineFeatureWarning, { featureName: "Sidebar" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModalOpenControlProvider, {
|
|
9884
|
+
open,
|
|
9885
|
+
onOpenChange,
|
|
9886
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChat, {
|
|
9887
|
+
welcomeScreen: CopilotSidebarView.WelcomeScreen,
|
|
9888
|
+
...chatProps,
|
|
9889
|
+
isModalDefaultOpen: defaultOpen,
|
|
9890
|
+
chatView: SidebarViewOverride
|
|
9891
|
+
})
|
|
9524
9892
|
})] });
|
|
9525
9893
|
}
|
|
9526
9894
|
CopilotSidebar.displayName = "CopilotSidebar";
|
|
@@ -9542,7 +9910,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
9542
9910
|
});
|
|
9543
9911
|
};
|
|
9544
9912
|
const PopupViewOverrideWithStatics = Object.assign(PopupViewOverride, CopilotChatView_default);
|
|
9545
|
-
function CopilotPopup({ header, toggleButton, defaultOpen, width, height, clickOutsideToClose, ...chatProps }) {
|
|
9913
|
+
function CopilotPopup({ header, toggleButton, defaultOpen, open, onOpenChange, width, height, clickOutsideToClose, ...chatProps }) {
|
|
9546
9914
|
const { checkFeature } = useLicenseContext();
|
|
9547
9915
|
const isPopupLicensed = checkFeature("popup");
|
|
9548
9916
|
(0, react.useEffect)(() => {
|
|
@@ -9565,11 +9933,15 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
9565
9933
|
]);
|
|
9566
9934
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [!isPopupLicensed && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InlineFeatureWarning, { featureName: "Popup" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PopupShellPropsContext.Provider, {
|
|
9567
9935
|
value: shellProps,
|
|
9568
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
9569
|
-
|
|
9570
|
-
|
|
9571
|
-
|
|
9572
|
-
|
|
9936
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModalOpenControlProvider, {
|
|
9937
|
+
open,
|
|
9938
|
+
onOpenChange,
|
|
9939
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChat, {
|
|
9940
|
+
welcomeScreen: CopilotPopupView_default.WelcomeScreen,
|
|
9941
|
+
...chatProps,
|
|
9942
|
+
isModalDefaultOpen: defaultOpen,
|
|
9943
|
+
chatView: PopupViewOverrideWithStatics
|
|
9944
|
+
})
|
|
9573
9945
|
})
|
|
9574
9946
|
})] });
|
|
9575
9947
|
}
|