@copilotkit/react-core 1.70.1 → 1.70.2

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.
@@ -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
@@ -5439,7 +5495,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
5439
5495
  * at the call site.
5440
5496
  */
5441
5497
  async function recordAnnotation(args) {
5442
- const { runtimeUrl, headers, type, payload, threadId, occurredAt } = args;
5498
+ const { runtimeUrl, headers, type, payload, threadId, occurredAt, fetch: fetchImplementation = globalThis.fetch } = args;
5443
5499
  const body = {
5444
5500
  type,
5445
5501
  threadId,
@@ -5447,7 +5503,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
5447
5503
  ...payload !== void 0 ? { payload } : {},
5448
5504
  ...occurredAt !== void 0 ? { occurredAt } : {}
5449
5505
  };
5450
- const response = await fetch(`${runtimeUrl}/annotate`, {
5506
+ const response = await fetchImplementation(`${runtimeUrl}/annotate`, {
5451
5507
  method: "POST",
5452
5508
  headers: {
5453
5509
  "Content-Type": "application/json",
@@ -5516,6 +5572,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
5516
5572
  ...input.data !== void 0 ? { data: input.data } : {}
5517
5573
  };
5518
5574
  return recordAnnotation({
5575
+ fetch: copilotkit.ɵruntimeFetch,
5519
5576
  runtimeUrl,
5520
5577
  headers: copilotkit.headers ?? {},
5521
5578
  type: "user_action",
@@ -5585,7 +5642,22 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
5585
5642
 
5586
5643
  //#endregion
5587
5644
  //#region src/v2/hooks/use-attachments.tsx
5588
- /**
5645
+ const DEFAULT_MAX_SIZE = 20 * 1024 * 1024;
5646
+ /**
5647
+ * How many uploads run at once when `maxConcurrentUploads` is unset. One, because
5648
+ * `onUpload` is a public callback an app may have written expecting the previous
5649
+ * file to have finished — concurrency is something the app asks for.
5650
+ */
5651
+ const DEFAULT_MAX_CONCURRENT_UPLOADS = 1;
5652
+ /**
5653
+ * At least one upload at a time, whole files only; `NaN` or a non-number falls back to the
5654
+ * default, and `Infinity` means "no limit" — bounded in practice by how many files are queued.
5655
+ */
5656
+ function resolveMaxConcurrentUploads(configured) {
5657
+ if (typeof configured !== "number" || Number.isNaN(configured)) return DEFAULT_MAX_CONCURRENT_UPLOADS;
5658
+ return Math.max(1, Math.floor(configured));
5659
+ }
5660
+ /**
5589
5661
  * Hook that manages file attachment state — uploads, drag-and-drop, paste,
5590
5662
  * and lifecycle. All returned callbacks are referentially stable across
5591
5663
  * renders (via useCallback) to avoid destabilizing downstream memoization.
@@ -5600,10 +5672,62 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
5600
5672
  configRef.current = config;
5601
5673
  const attachmentsRef = (0, react.useRef)([]);
5602
5674
  attachmentsRef.current = attachments;
5675
+ const uploadQueueRef = (0, react.useRef)([]);
5676
+ const activeWorkersRef = (0, react.useRef)(0);
5677
+ const uploadFile = (0, react.useCallback)(async (file, placeholder, cfg) => {
5678
+ try {
5679
+ let source;
5680
+ let uploadMetadata;
5681
+ if (cfg?.onUpload) {
5682
+ const { metadata: meta, ...uploadSource } = await cfg.onUpload(file);
5683
+ source = uploadSource;
5684
+ uploadMetadata = meta;
5685
+ } else source = {
5686
+ type: "data",
5687
+ value: await (0, _copilotkit_shared.readFileAsBase64)(file),
5688
+ mimeType: file.type
5689
+ };
5690
+ let thumbnail;
5691
+ if (placeholder.type === "video") thumbnail = await (0, _copilotkit_shared.generateVideoThumbnail)(file);
5692
+ setAttachments((prev) => prev.map((att) => att.id === placeholder.id ? {
5693
+ ...att,
5694
+ source,
5695
+ status: "ready",
5696
+ thumbnail,
5697
+ metadata: uploadMetadata
5698
+ } : att));
5699
+ } catch (error) {
5700
+ setAttachments((prev) => prev.filter((att) => att.id !== placeholder.id));
5701
+ console.error(`[CopilotKit] Failed to upload "${file.name}":`, error);
5702
+ cfg?.onUploadFailed?.({
5703
+ reason: "upload-failed",
5704
+ file,
5705
+ message: error instanceof Error ? error.message : `Failed to upload "${file.name}"`
5706
+ });
5707
+ }
5708
+ }, []);
5709
+ const drainUploadQueue = (0, react.useCallback)(async () => {
5710
+ activeWorkersRef.current++;
5711
+ try {
5712
+ for (;;) {
5713
+ const item = uploadQueueRef.current.shift();
5714
+ if (!item) return;
5715
+ try {
5716
+ await uploadFile(item.file, item.placeholder, item.cfg);
5717
+ } catch (error) {
5718
+ console.error("[CopilotKit] Upload worker error:", error);
5719
+ } finally {
5720
+ item.settle();
5721
+ }
5722
+ }
5723
+ } finally {
5724
+ activeWorkersRef.current--;
5725
+ }
5726
+ }, [uploadFile]);
5603
5727
  const processFiles = (0, react.useCallback)(async (files) => {
5604
5728
  const cfg = configRef.current;
5605
5729
  const accept = cfg?.accept ?? "*/*";
5606
- const maxSize = cfg?.maxSize ?? 20 * 1024 * 1024;
5730
+ const maxSize = cfg?.maxSize ?? DEFAULT_MAX_SIZE;
5607
5731
  const rejectedFiles = files.filter((file) => !(0, _copilotkit_shared.matchesAcceptFilter)(file, accept));
5608
5732
  for (const file of rejectedFiles) cfg?.onUploadFailed?.({
5609
5733
  reason: "invalid-type",
@@ -5611,6 +5735,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
5611
5735
  message: `File "${file.name}" is not accepted. Supported types: ${accept}`
5612
5736
  });
5613
5737
  const validFiles = files.filter((file) => (0, _copilotkit_shared.matchesAcceptFilter)(file, accept));
5738
+ const queued = [];
5614
5739
  for (const file of validFiles) {
5615
5740
  if ((0, _copilotkit_shared.exceedsMaxSize)(file, maxSize)) {
5616
5741
  cfg?.onUploadFailed?.({
@@ -5620,53 +5745,37 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
5620
5745
  });
5621
5746
  continue;
5622
5747
  }
5623
- const modality = (0, _copilotkit_shared.getModalityFromMimeType)(file.type);
5624
- const placeholderId = (0, _copilotkit_shared.randomUUID)();
5625
- const placeholder = {
5626
- id: placeholderId,
5627
- type: modality,
5628
- source: {
5629
- type: "data",
5630
- value: "",
5631
- mimeType: file.type
5632
- },
5633
- filename: file.name,
5634
- size: file.size,
5635
- status: "uploading"
5636
- };
5637
- setAttachments((prev) => [...prev, placeholder]);
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
- }
5748
+ queued.push({
5749
+ file,
5750
+ placeholder: {
5751
+ id: (0, _copilotkit_shared.randomUUID)(),
5752
+ type: (0, _copilotkit_shared.getModalityFromMimeType)(file.type),
5753
+ source: {
5754
+ type: "data",
5755
+ value: "",
5756
+ mimeType: file.type
5757
+ },
5758
+ filename: file.name,
5759
+ size: file.size,
5760
+ status: "uploading"
5761
+ }
5762
+ });
5668
5763
  }
5669
- }, []);
5764
+ if (queued.length === 0) return;
5765
+ setAttachments((prev) => [...prev, ...queued.map((q) => q.placeholder)]);
5766
+ const settled = queued.map(({ file, placeholder }) => new Promise((resolve) => {
5767
+ uploadQueueRef.current.push({
5768
+ file,
5769
+ placeholder,
5770
+ cfg,
5771
+ settle: resolve
5772
+ });
5773
+ }));
5774
+ const limit = resolveMaxConcurrentUploads(cfg?.maxConcurrentUploads);
5775
+ const toSpawn = Math.min(uploadQueueRef.current.length, Math.max(0, limit - activeWorkersRef.current));
5776
+ for (let i = 0; i < toSpawn; i++) drainUploadQueue();
5777
+ await Promise.all(settled);
5778
+ }, [drainUploadQueue]);
5670
5779
  const handleFileUpload = (0, react.useCallback)(async (e) => {
5671
5780
  if (!e.target.files?.length) return;
5672
5781
  try {
@@ -5794,8 +5903,10 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
5794
5903
  const warnedMissingUrlRef = (0, react.useRef)(false);
5795
5904
  const runtimeUrlRef = (0, react.useRef)(copilotkit.runtimeUrl);
5796
5905
  const headersRef = (0, react.useRef)(copilotkit.headers ?? {});
5906
+ const runtimeFetchRef = (0, react.useRef)(copilotkit.ɵruntimeFetch);
5797
5907
  runtimeUrlRef.current = copilotkit.runtimeUrl;
5798
5908
  headersRef.current = copilotkit.headers ?? {};
5909
+ runtimeFetchRef.current = copilotkit.ɵruntimeFetch;
5799
5910
  const key = JSON.stringify(learningContainers);
5800
5911
  const defaultKey = JSON.stringify(DEFAULT_CONTAINERS);
5801
5912
  (0, react.useEffect)(() => {
@@ -5815,6 +5926,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
5815
5926
  return;
5816
5927
  }
5817
5928
  recordAnnotation({
5929
+ fetch: copilotkit.ɵruntimeFetch,
5818
5930
  runtimeUrl,
5819
5931
  headers,
5820
5932
  type: "set_learning_containers",
@@ -5842,6 +5954,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
5842
5954
  const capturedRuntimeUrl = runtimeUrlRef.current;
5843
5955
  const capturedHeaders = headersRef.current;
5844
5956
  if (capturedRuntimeUrl) recordAnnotation({
5957
+ fetch: runtimeFetchRef.current,
5845
5958
  runtimeUrl: capturedRuntimeUrl,
5846
5959
  headers: capturedHeaders,
5847
5960
  type: "set_learning_containers",
@@ -9104,6 +9217,41 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
9104
9217
  });
9105
9218
  CopilotChatToggleButton.displayName = "CopilotChatToggleButton";
9106
9219
 
9220
+ //#endregion
9221
+ //#region src/v2/components/chat/modal-open-control.tsx
9222
+ const ModalOpenControlContext = (0, react.createContext)({});
9223
+ /**
9224
+ * Carries `open` / `onOpenChange` from a prebuilt surface down to the view that
9225
+ * owns the modal state.
9226
+ *
9227
+ * A context is required rather than plain props because `<CopilotSidebar>`
9228
+ * hands its view to `<CopilotChat>` as a `chatView` **component**. Threading a
9229
+ * value that changes (like `open`) through that component's identity would mint
9230
+ * a new element type on every toggle, and React unmounts and remounts the whole
9231
+ * chat subtree when the element type changes. That is the remount class of bug
9232
+ * already fixed for `<CopilotPopup>` on resize. Context keeps the override
9233
+ * identity stable while still re-rendering the view when `open` changes.
9234
+ */
9235
+ function ModalOpenControlProvider({ open, onOpenChange, children }) {
9236
+ const value = (0, react.useMemo)(() => ({
9237
+ open,
9238
+ onOpenChange
9239
+ }), [open, onOpenChange]);
9240
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModalOpenControlContext.Provider, {
9241
+ value,
9242
+ children
9243
+ });
9244
+ }
9245
+ /**
9246
+ * Reads the controlled open state supplied by the surrounding prebuilt
9247
+ * surface. Returns an empty control (uncontrolled) when there is none.
9248
+ *
9249
+ * @returns The host's `open` / `onOpenChange` pair.
9250
+ */
9251
+ function useModalOpenControl() {
9252
+ return (0, react.useContext)(ModalOpenControlContext);
9253
+ }
9254
+
9107
9255
  //#endregion
9108
9256
  //#region src/v2/components/chat/CopilotModalHeader.tsx
9109
9257
  /**
@@ -9213,15 +9361,22 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
9213
9361
  const DEFAULT_SIDEBAR_WIDTH = 480;
9214
9362
  const SIDEBAR_TRANSITION_MS = 260;
9215
9363
  function CopilotSidebarView({ header, toggleButton, width, defaultOpen = true, position = "right", ...props }) {
9364
+ const { open, onOpenChange } = useModalOpenControl();
9365
+ const hasOpenControl = open !== void 0 || onOpenChange !== void 0;
9366
+ const internal = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotSidebarViewInternal, {
9367
+ header,
9368
+ toggleButton,
9369
+ width,
9370
+ position,
9371
+ ...props
9372
+ });
9216
9373
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChatConfigurationProvider, {
9217
- isModalDefaultOpen: defaultOpen,
9218
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotSidebarViewInternal, {
9219
- header,
9220
- toggleButton,
9221
- width,
9222
- position,
9223
- ...props
9224
- })
9374
+ isModalDefaultOpen: open ?? defaultOpen,
9375
+ children: hasOpenControl ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ControlledModalOpenScope, {
9376
+ open,
9377
+ onOpenChange,
9378
+ children: internal
9379
+ }) : internal
9225
9380
  });
9226
9381
  }
9227
9382
  function CopilotSidebarViewInternal({ header, toggleButton, width, position = "right", ...props }) {
@@ -9285,7 +9440,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
9285
9440
  "data-position": position,
9286
9441
  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
9442
  style: {
9288
- ["--sidebar-width"]: widthToCss(sidebarWidth),
9443
+ "--sidebar-width": widthToCss(sidebarWidth),
9289
9444
  paddingTop: "env(safe-area-inset-top)",
9290
9445
  paddingBottom: "env(safe-area-inset-bottom)"
9291
9446
  },
@@ -9347,17 +9502,24 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
9347
9502
  return `${fallback}px`;
9348
9503
  };
9349
9504
  function CopilotPopupView({ header, toggleButton, width, height, clickOutsideToClose, defaultOpen = true, className, ...restProps }) {
9505
+ const { open, onOpenChange } = useModalOpenControl();
9506
+ const hasOpenControl = open !== void 0 || onOpenChange !== void 0;
9507
+ const internal = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotPopupViewInternal, {
9508
+ header,
9509
+ toggleButton,
9510
+ width,
9511
+ height,
9512
+ clickOutsideToClose,
9513
+ className,
9514
+ ...restProps
9515
+ });
9350
9516
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChatConfigurationProvider, {
9351
- isModalDefaultOpen: defaultOpen,
9352
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotPopupViewInternal, {
9353
- header,
9354
- toggleButton,
9355
- width,
9356
- height,
9357
- clickOutsideToClose,
9358
- className,
9359
- ...restProps
9360
- })
9517
+ isModalDefaultOpen: open ?? defaultOpen,
9518
+ children: hasOpenControl ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ControlledModalOpenScope, {
9519
+ open,
9520
+ onOpenChange,
9521
+ children: internal
9522
+ }) : internal
9361
9523
  });
9362
9524
  }
9363
9525
  function CopilotPopupViewInternal({ header, toggleButton, width, height, clickOutsideToClose, className, ...restProps }) {
@@ -9490,7 +9652,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
9490
9652
 
9491
9653
  //#endregion
9492
9654
  //#region src/v2/components/chat/CopilotSidebar.tsx
9493
- function CopilotSidebar({ header, toggleButton, defaultOpen, width, position, ...chatProps }) {
9655
+ function CopilotSidebar({ header, toggleButton, defaultOpen, open, onOpenChange, width, position, ...chatProps }) {
9494
9656
  const { checkFeature } = useLicenseContext();
9495
9657
  const isSidebarLicensed = checkFeature("sidebar");
9496
9658
  (0, react.useEffect)(() => {
@@ -9516,11 +9678,15 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
9516
9678
  defaultOpen,
9517
9679
  position
9518
9680
  ]);
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)(CopilotChat, {
9520
- welcomeScreen: CopilotSidebarView.WelcomeScreen,
9521
- ...chatProps,
9522
- isModalDefaultOpen: defaultOpen,
9523
- chatView: SidebarViewOverride
9681
+ 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, {
9682
+ open,
9683
+ onOpenChange,
9684
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChat, {
9685
+ welcomeScreen: CopilotSidebarView.WelcomeScreen,
9686
+ ...chatProps,
9687
+ isModalDefaultOpen: defaultOpen,
9688
+ chatView: SidebarViewOverride
9689
+ })
9524
9690
  })] });
9525
9691
  }
9526
9692
  CopilotSidebar.displayName = "CopilotSidebar";
@@ -9542,7 +9708,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
9542
9708
  });
9543
9709
  };
9544
9710
  const PopupViewOverrideWithStatics = Object.assign(PopupViewOverride, CopilotChatView_default);
9545
- function CopilotPopup({ header, toggleButton, defaultOpen, width, height, clickOutsideToClose, ...chatProps }) {
9711
+ function CopilotPopup({ header, toggleButton, defaultOpen, open, onOpenChange, width, height, clickOutsideToClose, ...chatProps }) {
9546
9712
  const { checkFeature } = useLicenseContext();
9547
9713
  const isPopupLicensed = checkFeature("popup");
9548
9714
  (0, react.useEffect)(() => {
@@ -9565,11 +9731,15 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
9565
9731
  ]);
9566
9732
  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
9733
  value: shellProps,
9568
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChat, {
9569
- welcomeScreen: CopilotPopupView_default.WelcomeScreen,
9570
- ...chatProps,
9571
- isModalDefaultOpen: defaultOpen,
9572
- chatView: PopupViewOverrideWithStatics
9734
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModalOpenControlProvider, {
9735
+ open,
9736
+ onOpenChange,
9737
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChat, {
9738
+ welcomeScreen: CopilotPopupView_default.WelcomeScreen,
9739
+ ...chatProps,
9740
+ isModalDefaultOpen: defaultOpen,
9741
+ chatView: PopupViewOverrideWithStatics
9742
+ })
9573
9743
  })
9574
9744
  })] });
9575
9745
  }