@assistant-ui/react 0.1.11 → 0.1.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -31,6 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var src_exports = {};
32
32
  __export(src_exports, {
33
33
  ActionBarPrimitive: () => actionBar_exports,
34
+ AssistantModalPrimitive: () => assistantModal_exports,
34
35
  AssistantRuntimeProvider: () => AssistantRuntimeProvider,
35
36
  BranchPickerPrimitive: () => branchPicker_exports,
36
37
  ComposerPrimitive: () => composer_exports,
@@ -167,7 +168,7 @@ var useThreadContext = () => {
167
168
 
168
169
  // src/primitive-hooks/actionBar/useActionBarReload.tsx
169
170
  var useActionBarReload = () => {
170
- const { useThread, useThreadActions, useViewport } = useThreadContext();
171
+ const { useThread, useThreadActions, useComposer, useViewport } = useThreadContext();
171
172
  const { useMessage } = useMessageContext();
172
173
  const disabled = useCombinedStore(
173
174
  [useThread, useMessage],
@@ -177,7 +178,8 @@ var useActionBarReload = () => {
177
178
  const { parentId } = useMessage.getState();
178
179
  useThreadActions.getState().startRun(parentId);
179
180
  useViewport.getState().scrollToBottom();
180
- }, [useThreadActions, useMessage, useViewport]);
181
+ useComposer.getState().focus();
182
+ }, [useThreadActions, useComposer, useViewport, useMessage]);
181
183
  if (disabled) return null;
182
184
  return callback;
183
185
  };
@@ -300,7 +302,7 @@ var useComposerIf = (props) => {
300
302
  // src/primitive-hooks/composer/useComposerSend.tsx
301
303
  var import_react14 = require("react");
302
304
  var useComposerSend = () => {
303
- const { useViewport } = useThreadContext();
305
+ const { useViewport, useComposer: useNewComposer } = useThreadContext();
304
306
  const { useComposer } = useComposerContext();
305
307
  const disabled = useComposer((c) => !c.isEditing || c.value.length === 0);
306
308
  const callback = (0, import_react14.useCallback)(() => {
@@ -308,7 +310,8 @@ var useComposerSend = () => {
308
310
  if (!composerState.isEditing) return;
309
311
  composerState.send();
310
312
  useViewport.getState().scrollToBottom();
311
- }, [useComposer, useViewport]);
313
+ useNewComposer.getState().focus();
314
+ }, [useNewComposer, useComposer, useViewport]);
312
315
  if (disabled) return null;
313
316
  return callback;
314
317
  };
@@ -400,12 +403,12 @@ var useThreadEmpty = () => {
400
403
  // src/primitive-hooks/thread/useThreadScrollToBottom.tsx
401
404
  var import_react15 = require("react");
402
405
  var useThreadScrollToBottom = () => {
403
- const { useViewport } = useThreadContext();
406
+ const { useComposer, useViewport } = useThreadContext();
404
407
  const isAtBottom = useViewport((s) => s.isAtBottom);
405
408
  const handleScrollToBottom = (0, import_react15.useCallback)(() => {
406
- const { scrollToBottom } = useViewport.getState();
407
- scrollToBottom();
408
- }, [useViewport]);
409
+ useViewport.getState().scrollToBottom();
410
+ useComposer.getState().focus();
411
+ }, [useViewport, useComposer]);
409
412
  if (isAtBottom) return null;
410
413
  return handleScrollToBottom;
411
414
  };
@@ -430,330 +433,279 @@ var useThreadSuggestion = ({
430
433
  return callback;
431
434
  };
432
435
 
433
- // src/primitives/thread/index.ts
434
- var thread_exports = {};
435
- __export(thread_exports, {
436
- Empty: () => ThreadEmpty,
437
- If: () => ThreadIf,
438
- Messages: () => ThreadMessages,
439
- Root: () => ThreadRoot,
440
- ScrollToBottom: () => ThreadScrollToBottom,
441
- Suggestion: () => ThreadSuggestion,
442
- Viewport: () => ThreadViewport
436
+ // src/primitives/actionBar/index.ts
437
+ var actionBar_exports = {};
438
+ __export(actionBar_exports, {
439
+ Copy: () => ActionBarCopy,
440
+ Edit: () => ActionBarEdit,
441
+ Reload: () => ActionBarReload,
442
+ Root: () => ActionBarRoot
443
443
  });
444
444
 
445
- // src/primitives/thread/ThreadRoot.tsx
445
+ // src/primitives/actionBar/ActionBarRoot.tsx
446
446
  var import_react_primitive = require("@radix-ui/react-primitive");
447
447
  var import_react17 = require("react");
448
448
  var import_jsx_runtime = require("react/jsx-runtime");
449
- var ThreadRoot = (0, import_react17.forwardRef)(
450
- (props, ref) => {
451
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_primitive.Primitive.div, { ...props, ref });
452
- }
453
- );
454
- ThreadRoot.displayName = "ThreadRoot";
455
-
456
- // src/primitives/thread/ThreadEmpty.tsx
457
- var ThreadEmpty = ({ children }) => {
458
- const empty = useThreadEmpty();
459
- return empty ? children : null;
460
- };
461
-
462
- // src/primitives/thread/ThreadIf.tsx
463
- var ThreadIf = ({ children, ...query }) => {
464
- const result = useThreadIf(query);
465
- return result ? children : null;
449
+ var useActionBarFloatStatus = ({
450
+ hideWhenRunning,
451
+ autohide,
452
+ autohideFloat
453
+ }) => {
454
+ const { useThread } = useThreadContext();
455
+ const { useMessage, useMessageUtils } = useMessageContext();
456
+ return useCombinedStore(
457
+ [useThread, useMessage, useMessageUtils],
458
+ (t, m, mu) => {
459
+ if (hideWhenRunning && t.isRunning) return "hidden" /* Hidden */;
460
+ const autohideEnabled = autohide === "always" || autohide === "not-last" && !m.isLast;
461
+ if (!autohideEnabled) return "normal" /* Normal */;
462
+ if (!mu.isHovering) return "hidden" /* Hidden */;
463
+ if (autohideFloat === "always" || autohideFloat === "single-branch" && m.branches.length <= 1)
464
+ return "floating" /* Floating */;
465
+ return "normal" /* Normal */;
466
+ }
467
+ );
466
468
  };
469
+ var ActionBarRoot = (0, import_react17.forwardRef)(({ hideWhenRunning, autohide, autohideFloat, ...rest }, ref) => {
470
+ const hideAndfloatStatus = useActionBarFloatStatus({
471
+ hideWhenRunning,
472
+ autohide,
473
+ autohideFloat
474
+ });
475
+ if (hideAndfloatStatus === "hidden" /* Hidden */) return null;
476
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
477
+ import_react_primitive.Primitive.div,
478
+ {
479
+ ...hideAndfloatStatus === "floating" /* Floating */ ? { "data-floating": "true" } : null,
480
+ ...rest,
481
+ ref
482
+ }
483
+ );
484
+ });
485
+ ActionBarRoot.displayName = "ActionBarRoot";
467
486
 
468
- // src/primitives/thread/ThreadViewport.tsx
469
- var import_react_compose_refs2 = require("@radix-ui/react-compose-refs");
487
+ // src/utils/createActionButton.tsx
488
+ var import_primitive = require("@radix-ui/primitive");
470
489
  var import_react_primitive2 = require("@radix-ui/react-primitive");
471
- var import_react22 = require("react");
472
-
473
- // src/primitive-hooks/thread/useThreadViewportAutoScroll.tsx
474
- var import_react_compose_refs = require("@radix-ui/react-compose-refs");
475
- var import_react21 = require("react");
476
-
477
- // src/utils/hooks/useOnResizeContent.tsx
478
- var import_react_use_callback_ref = require("@radix-ui/react-use-callback-ref");
479
- var import_react19 = require("react");
480
-
481
- // src/utils/hooks/useManagedRef.ts
482
490
  var import_react18 = require("react");
483
- var useManagedRef = (callback) => {
484
- const cleanupRef = (0, import_react18.useRef)();
485
- const ref = (0, import_react18.useCallback)(
486
- (el) => {
487
- if (cleanupRef.current) {
488
- cleanupRef.current();
489
- }
490
- if (el) {
491
- cleanupRef.current = callback(el);
491
+ var import_jsx_runtime2 = require("react/jsx-runtime");
492
+ var createActionButton = (displayName, useActionButton) => {
493
+ const ActionButton = (0, import_react18.forwardRef)((props, forwardedRef) => {
494
+ const callback = useActionButton(props);
495
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
496
+ import_react_primitive2.Primitive.button,
497
+ {
498
+ type: "button",
499
+ disabled: !callback,
500
+ ...props,
501
+ ref: forwardedRef,
502
+ onClick: (0, import_primitive.composeEventHandlers)(props.onClick, () => {
503
+ callback?.();
504
+ })
492
505
  }
493
- },
494
- [callback]
495
- );
496
- return ref;
506
+ );
507
+ });
508
+ ActionButton.displayName = displayName;
509
+ return ActionButton;
497
510
  };
498
511
 
499
- // src/utils/hooks/useOnResizeContent.tsx
500
- var useOnResizeContent = (callback) => {
501
- const callbackRef = (0, import_react_use_callback_ref.useCallbackRef)(callback);
502
- const refCallback = (0, import_react19.useCallback)(
503
- (el) => {
504
- const resizeObserver = new ResizeObserver(() => {
505
- callbackRef();
506
- });
507
- const mutationObserver = new MutationObserver((mutations) => {
508
- for (const mutation of mutations) {
509
- for (const node of mutation.addedNodes) {
510
- if (node instanceof Element) {
511
- resizeObserver.observe(node);
512
- }
513
- }
514
- for (const node of mutation.removedNodes) {
515
- if (node instanceof Element) {
516
- resizeObserver.unobserve(node);
517
- }
518
- }
519
- }
520
- callbackRef();
521
- });
522
- resizeObserver.observe(el);
523
- mutationObserver.observe(el, { childList: true });
524
- for (const child of el.children) {
525
- resizeObserver.observe(child);
526
- }
527
- return () => {
528
- resizeObserver.disconnect();
529
- mutationObserver.disconnect();
530
- };
531
- },
532
- [callbackRef]
533
- );
534
- return useManagedRef(refCallback);
535
- };
512
+ // src/primitives/actionBar/ActionBarCopy.tsx
513
+ var ActionBarCopy = createActionButton(
514
+ "ActionBarCopy",
515
+ useActionBarCopy
516
+ );
536
517
 
537
- // src/utils/hooks/useOnScrollToBottom.tsx
538
- var import_react_use_callback_ref2 = require("@radix-ui/react-use-callback-ref");
518
+ // src/primitives/actionBar/ActionBarReload.tsx
519
+ var ActionBarReload = createActionButton(
520
+ "ActionBarReload",
521
+ useActionBarReload
522
+ );
523
+
524
+ // src/primitives/actionBar/ActionBarEdit.tsx
525
+ var ActionBarEdit = createActionButton(
526
+ "ActionBarEdit",
527
+ useActionBarEdit
528
+ );
529
+
530
+ // src/primitives/assistantModal/index.ts
531
+ var assistantModal_exports = {};
532
+ __export(assistantModal_exports, {
533
+ Content: () => AssistantModalContent,
534
+ Root: () => AssistantModalRoot,
535
+ Trigger: () => AssistantModalTrigger
536
+ });
537
+
538
+ // src/primitives/assistantModal/AssistantModalRoot.tsx
539
539
  var import_react20 = require("react");
540
- var useOnScrollToBottom = (callback) => {
541
- const callbackRef = (0, import_react_use_callback_ref2.useCallbackRef)(callback);
542
- const { useViewport } = useThreadContext();
543
- (0, import_react20.useEffect)(() => {
544
- return useViewport.getState().onScrollToBottom(() => {
540
+ var PopoverPrimitive = __toESM(require("@radix-ui/react-popover"));
541
+ var import_primitive2 = require("@radix-ui/primitive");
542
+
543
+ // src/utils/hooks/useOnComposerFocus.tsx
544
+ var import_react_use_callback_ref = require("@radix-ui/react-use-callback-ref");
545
+ var import_react19 = require("react");
546
+ var useOnComposerFocus = (callback) => {
547
+ const callbackRef = (0, import_react_use_callback_ref.useCallbackRef)(callback);
548
+ const { useComposer } = useThreadContext();
549
+ (0, import_react19.useEffect)(() => {
550
+ return useComposer.getState().onFocus(() => {
545
551
  callbackRef();
546
552
  });
547
- }, [useViewport, callbackRef]);
553
+ }, [useComposer, callbackRef]);
548
554
  };
549
555
 
550
- // src/primitive-hooks/thread/useThreadViewportAutoScroll.tsx
551
- var useThreadViewportAutoScroll = ({
552
- autoScroll = true
556
+ // src/primitives/assistantModal/AssistantModalRoot.tsx
557
+ var import_jsx_runtime3 = require("react/jsx-runtime");
558
+ var usePopoverScope = PopoverPrimitive.createPopoverScope();
559
+ var useAssistantModalOpenState = (defaultOpen = false) => {
560
+ const state = (0, import_react20.useState)(defaultOpen);
561
+ const [, setOpen] = state;
562
+ useOnComposerFocus(() => {
563
+ setOpen(true);
564
+ });
565
+ return state;
566
+ };
567
+ var AssistantModalRoot = ({
568
+ __scopeAssistantModal,
569
+ defaultOpen,
570
+ open,
571
+ onOpenChange,
572
+ ...rest
553
573
  }) => {
554
- const divRef = (0, import_react21.useRef)(null);
555
- const { useViewport } = useThreadContext();
556
- const firstRenderRef = (0, import_react21.useRef)(true);
557
- const lastScrollTop = (0, import_react21.useRef)(0);
558
- const isScrollingToBottomRef = (0, import_react21.useRef)(false);
559
- const scrollToBottom = () => {
560
- const div = divRef.current;
561
- if (!div || !autoScroll) return;
562
- const behavior = firstRenderRef.current ? "instant" : "auto";
563
- firstRenderRef.current = false;
564
- isScrollingToBottomRef.current = true;
565
- div.scrollTo({ top: div.scrollHeight, behavior });
566
- };
567
- const handleScroll = () => {
568
- const div = divRef.current;
569
- if (!div) return;
570
- const isAtBottom = useViewport.getState().isAtBottom;
571
- const newIsAtBottom = div.scrollHeight - div.scrollTop <= div.clientHeight;
572
- if (!newIsAtBottom && lastScrollTop.current < div.scrollTop) {
573
- } else {
574
- isScrollingToBottomRef.current = newIsAtBottom;
575
- if (newIsAtBottom !== isAtBottom) {
576
- useViewport.setState({
577
- isAtBottom: newIsAtBottom
578
- });
579
- }
580
- }
581
- lastScrollTop.current = div.scrollTop;
582
- };
583
- const resizeRef = useOnResizeContent(() => {
584
- if (!isScrollingToBottomRef.current && !useViewport.getState().isAtBottom && !firstRenderRef.current) {
585
- handleScroll();
586
- } else {
587
- scrollToBottom();
574
+ const scope = usePopoverScope(__scopeAssistantModal);
575
+ const [modalOpen, setOpen] = useAssistantModalOpenState(defaultOpen);
576
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
577
+ PopoverPrimitive.Root,
578
+ {
579
+ ...scope,
580
+ open: open === void 0 ? modalOpen : open,
581
+ onOpenChange: (0, import_primitive2.composeEventHandlers)(onOpenChange, setOpen),
582
+ ...rest
588
583
  }
589
- });
590
- const scrollRef = useManagedRef((el) => {
591
- el.addEventListener("scroll", handleScroll);
592
- return () => {
593
- el.removeEventListener("scroll", handleScroll);
594
- };
595
- });
596
- const autoScrollRef = (0, import_react_compose_refs.useComposedRefs)(resizeRef, scrollRef, divRef);
597
- useOnScrollToBottom(() => {
598
- scrollToBottom();
599
- });
600
- return autoScrollRef;
584
+ );
601
585
  };
586
+ AssistantModalRoot.displayName = "AssistantModalRoot";
602
587
 
603
- // src/primitives/thread/ThreadViewport.tsx
604
- var import_jsx_runtime2 = require("react/jsx-runtime");
605
- var ThreadViewport = (0, import_react22.forwardRef)(({ autoScroll, onScroll, children, ...rest }, forwardedRef) => {
606
- const autoScrollRef = useThreadViewportAutoScroll({
607
- autoScroll
608
- });
609
- const ref = (0, import_react_compose_refs2.useComposedRefs)(forwardedRef, autoScrollRef);
610
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_primitive2.Primitive.div, { ...rest, ref, children });
611
- });
612
- ThreadViewport.displayName = "ThreadViewport";
613
-
614
- // src/primitives/thread/ThreadMessages.tsx
615
- var import_react24 = require("react");
616
-
617
- // src/context/providers/MessageProvider.tsx
618
- var import_react23 = require("react");
619
- var import_zustand3 = require("zustand");
620
-
621
- // src/context/stores/EditComposer.ts
622
- var import_zustand = require("zustand");
623
-
624
- // src/context/stores/BaseComposer.ts
625
- var makeBaseComposer = (set) => ({
626
- value: "",
627
- setValue: (value) => {
628
- set({ value });
588
+ // src/primitives/assistantModal/AssistantModalTrigger.tsx
589
+ var import_react21 = require("react");
590
+ var PopoverPrimitive2 = __toESM(require("@radix-ui/react-popover"));
591
+ var import_jsx_runtime4 = require("react/jsx-runtime");
592
+ var AssistantModalTrigger = (0, import_react21.forwardRef)(
593
+ ({ __scopeAssistantModal, ...rest }, ref) => {
594
+ const scope = usePopoverScope(__scopeAssistantModal);
595
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PopoverPrimitive2.Trigger, { ...scope, ...rest, ref });
629
596
  }
630
- });
597
+ );
598
+ AssistantModalTrigger.displayName = "AssistantModalTrigger";
631
599
 
632
- // src/context/stores/EditComposer.ts
633
- var makeEditComposerStore = ({
634
- onEdit,
635
- onSend
636
- }) => (0, import_zustand.create)()((set, get, store) => ({
637
- ...makeBaseComposer(set, get, store),
638
- isEditing: false,
639
- edit: () => {
640
- const value = onEdit();
641
- set({ isEditing: true, value });
642
- },
643
- send: () => {
644
- const value = get().value;
645
- set({ isEditing: false });
646
- onSend(value);
647
- },
648
- cancel: () => {
649
- if (!get().isEditing) return false;
650
- set({ isEditing: false });
651
- return true;
600
+ // src/primitives/assistantModal/AssistantModalContent.tsx
601
+ var import_react22 = require("react");
602
+ var PopoverPrimitive3 = __toESM(require("@radix-ui/react-popover"));
603
+ var import_primitive3 = require("@radix-ui/primitive");
604
+ var import_jsx_runtime5 = require("react/jsx-runtime");
605
+ var AssistantModalContent = (0, import_react22.forwardRef)(
606
+ ({
607
+ __scopeAssistantModal,
608
+ side,
609
+ align,
610
+ onInteractOutside,
611
+ dissmissOnInteractOutside = false,
612
+ ...props
613
+ }, forwardedRef) => {
614
+ const scope = usePopoverScope(__scopeAssistantModal);
615
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PopoverPrimitive3.Portal, { ...scope, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
616
+ PopoverPrimitive3.Content,
617
+ {
618
+ ...scope,
619
+ ...props,
620
+ ref: forwardedRef,
621
+ side: side ?? "top",
622
+ align: align ?? "end",
623
+ onInteractOutside: (0, import_primitive3.composeEventHandlers)(
624
+ onInteractOutside,
625
+ dissmissOnInteractOutside ? void 0 : (e) => e.preventDefault()
626
+ )
627
+ }
628
+ ) });
652
629
  }
653
- }));
630
+ );
631
+ AssistantModalContent.displayName = "AssistantModalContent";
654
632
 
655
- // src/context/stores/MessageUtils.ts
656
- var import_zustand2 = require("zustand");
657
- var makeMessageUtilsStore = () => (0, import_zustand2.create)((set) => ({
658
- inProgressIndicator: null,
659
- setInProgressIndicator: (value) => {
660
- set({ inProgressIndicator: value });
661
- },
662
- isCopied: false,
663
- setIsCopied: (value) => {
664
- set({ isCopied: value });
665
- },
666
- isHovering: false,
667
- setIsHovering: (value) => {
668
- set({ isHovering: value });
669
- }
670
- }));
633
+ // src/primitives/branchPicker/index.ts
634
+ var branchPicker_exports = {};
635
+ __export(branchPicker_exports, {
636
+ Count: () => BranchPickerCount,
637
+ Next: () => BranchPickerNext,
638
+ Number: () => BranchPickerNumber,
639
+ Previous: () => BranchPickerPrevious,
640
+ Root: () => BranchPickerRoot
641
+ });
671
642
 
672
- // src/context/providers/MessageProvider.tsx
673
- var import_jsx_runtime3 = require("react/jsx-runtime");
674
- var getIsLast = (thread, message) => {
675
- return thread.messages[thread.messages.length - 1]?.id === message.id;
643
+ // src/primitives/branchPicker/BranchPickerNext.tsx
644
+ var BranchPickerNext = createActionButton(
645
+ "BranchPickerNext",
646
+ useBranchPickerNext
647
+ );
648
+
649
+ // src/primitives/branchPicker/BranchPickerPrevious.tsx
650
+ var BranchPickerPrevious = createActionButton(
651
+ "BranchPickerPrevious",
652
+ useBranchPickerPrevious
653
+ );
654
+
655
+ // src/primitives/branchPicker/BranchPickerCount.tsx
656
+ var import_jsx_runtime6 = require("react/jsx-runtime");
657
+ var BranchPickerCount = () => {
658
+ const branchCount = useBranchPickerCount();
659
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children: branchCount });
676
660
  };
677
- var syncMessage = (thread, getBranches, useMessage, messageIndex) => {
678
- const parentId = thread.messages[messageIndex - 1]?.id ?? null;
679
- const message = thread.messages[messageIndex];
680
- if (!message) return;
681
- const isLast = getIsLast(thread, message);
682
- const branches = getBranches(message.id);
683
- const currentState = useMessage.getState();
684
- if (currentState.message === message && currentState.parentId === parentId && currentState.branches === branches && currentState.isLast === isLast)
685
- return;
686
- useMessage.setState({
687
- message,
688
- parentId,
689
- branches,
690
- isLast
691
- });
661
+
662
+ // src/primitives/branchPicker/BranchPickerNumber.tsx
663
+ var import_jsx_runtime7 = require("react/jsx-runtime");
664
+ var BranchPickerNumber = () => {
665
+ const branchNumber = useBranchPickerNumber();
666
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children: branchNumber });
692
667
  };
693
- var useMessageContext2 = (messageIndex) => {
694
- const { useThread, useThreadActions } = useThreadContext();
695
- const [context] = (0, import_react23.useState)(() => {
696
- const useMessage = (0, import_zustand3.create)(() => ({}));
697
- const useMessageUtils = makeMessageUtilsStore();
698
- const useEditComposer = makeEditComposerStore({
699
- onEdit: () => {
700
- const message = useMessage.getState().message;
701
- if (message.role !== "user")
702
- throw new Error(
703
- "Tried to edit a non-user message. Editing is only supported for user messages. This is likely an internal bug in assistant-ui."
704
- );
705
- const text = getMessageText(message);
706
- return text;
707
- },
708
- onSend: (text) => {
709
- const { message, parentId } = useMessage.getState();
710
- if (message.role !== "user")
711
- throw new Error(
712
- "Tried to edit a non-user message. Editing is only supported for user messages. This is likely an internal bug in assistant-ui."
713
- );
714
- const nonTextParts = message.content.filter(
715
- (part) => part.type !== "text" && part.type !== "ui"
716
- );
717
- useThreadActions.getState().append({
718
- parentId,
719
- role: "user",
720
- content: [{ type: "text", text }, ...nonTextParts]
721
- });
668
+
669
+ // src/primitives/branchPicker/BranchPickerRoot.tsx
670
+ var import_react_primitive6 = require("@radix-ui/react-primitive");
671
+ var import_react28 = require("react");
672
+
673
+ // src/primitives/message/index.ts
674
+ var message_exports = {};
675
+ __export(message_exports, {
676
+ Content: () => MessageContent,
677
+ If: () => MessageIf,
678
+ InProgress: () => MessageInProgress,
679
+ Root: () => MessageRoot
680
+ });
681
+
682
+ // src/primitives/message/MessageRoot.tsx
683
+ var import_primitive4 = require("@radix-ui/primitive");
684
+ var import_react_primitive3 = require("@radix-ui/react-primitive");
685
+ var import_react23 = require("react");
686
+ var import_jsx_runtime8 = require("react/jsx-runtime");
687
+ var MessageRoot = (0, import_react23.forwardRef)(
688
+ ({ onMouseEnter, onMouseLeave, ...rest }, ref) => {
689
+ const { useMessageUtils } = useMessageContext();
690
+ const setIsHovering = useMessageUtils((s) => s.setIsHovering);
691
+ const handleMouseEnter = () => {
692
+ setIsHovering(true);
693
+ };
694
+ const handleMouseLeave = () => {
695
+ setIsHovering(false);
696
+ };
697
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
698
+ import_react_primitive3.Primitive.div,
699
+ {
700
+ ...rest,
701
+ ref,
702
+ onMouseEnter: (0, import_primitive4.composeEventHandlers)(onMouseEnter, handleMouseEnter),
703
+ onMouseLeave: (0, import_primitive4.composeEventHandlers)(onMouseLeave, handleMouseLeave)
722
704
  }
723
- });
724
- syncMessage(
725
- useThread.getState(),
726
- useThreadActions.getState().getBranches,
727
- useMessage,
728
- messageIndex
729
705
  );
730
- return { useMessage, useMessageUtils, useEditComposer };
731
- });
732
- (0, import_react23.useEffect)(() => {
733
- return useThread.subscribe((thread) => {
734
- syncMessage(
735
- thread,
736
- useThreadActions.getState().getBranches,
737
- context.useMessage,
738
- messageIndex
739
- );
740
- });
741
- }, [useThread, useThreadActions, context, messageIndex]);
742
- return context;
743
- };
744
- var MessageProvider = ({
745
- messageIndex,
746
- children
747
- }) => {
748
- const context = useMessageContext2(messageIndex);
749
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MessageContext.Provider, { value: context, children });
750
- };
751
-
752
- // src/primitives/composer/ComposerIf.tsx
753
- var ComposerIf = ({ children, ...query }) => {
754
- const result = useComposerIf(query);
755
- return result ? children : null;
756
- };
706
+ }
707
+ );
708
+ MessageRoot.displayName = "MessageRoot";
757
709
 
758
710
  // src/primitives/message/MessageIf.tsx
759
711
  var MessageIf = ({ children, ...query }) => {
@@ -761,85 +713,166 @@ var MessageIf = ({ children, ...query }) => {
761
713
  return result ? children : null;
762
714
  };
763
715
 
764
- // src/primitives/thread/ThreadMessages.tsx
765
- var import_jsx_runtime4 = require("react/jsx-runtime");
766
- var getComponents = (components) => {
767
- return {
768
- EditComposer: components.EditComposer ?? components.UserMessage ?? components.Message,
769
- UserMessage: components.UserMessage ?? components.Message,
770
- AssistantMessage: components.AssistantMessage ?? components.Message
771
- };
772
- };
773
- var ThreadMessageImpl = ({
774
- messageIndex,
775
- components
776
- }) => {
777
- const { UserMessage, EditComposer, AssistantMessage } = getComponents(components);
778
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(MessageProvider, { messageIndex, children: [
779
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(MessageIf, { user: true, children: [
780
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ComposerIf, { editing: false, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(UserMessage, {}) }),
781
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ComposerIf, { editing: true, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(EditComposer, {}) })
782
- ] }),
783
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MessageIf, { assistant: true, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(AssistantMessage, {}) })
784
- ] });
716
+ // src/primitives/message/MessageContent.tsx
717
+ var import_react26 = require("react");
718
+
719
+ // src/context/providers/ContentPartProvider.tsx
720
+ var import_react24 = require("react");
721
+ var import_zustand = require("zustand");
722
+ var import_jsx_runtime9 = require("react/jsx-runtime");
723
+ var syncContentPart = ({ message }, useContentPart, partIndex) => {
724
+ const part = message.content[partIndex];
725
+ if (!part) return;
726
+ const messageStatus = message.role === "assistant" ? message.status : "done";
727
+ const status = partIndex === message.content.length - 1 ? messageStatus : "done";
728
+ const currentState = useContentPart.getState();
729
+ if (currentState.part === part && currentState.status === status) return;
730
+ useContentPart.setState(
731
+ Object.freeze({
732
+ part,
733
+ status
734
+ })
735
+ );
785
736
  };
786
- var ThreadMessage = (0, import_react24.memo)(
787
- ThreadMessageImpl,
788
- (prev, next) => prev.messageIndex === next.messageIndex && prev.components.UserMessage === next.components.UserMessage && prev.components.EditComposer === next.components.EditComposer && prev.components.AssistantMessage === next.components.AssistantMessage
789
- );
790
- var ThreadMessages = ({ components }) => {
791
- const { useThread } = useThreadContext();
792
- const messagesLength = useThread((t) => t.messages.length);
793
- if (messagesLength === 0) return null;
794
- return new Array(messagesLength).fill(null).map((_, idx) => {
795
- const messageIndex = idx;
796
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
797
- ThreadMessage,
798
- {
799
- messageIndex,
800
- components
801
- },
802
- messageIndex
737
+ var useContentPartContext2 = (partIndex) => {
738
+ const { useMessage } = useMessageContext();
739
+ const [context] = (0, import_react24.useState)(() => {
740
+ const useContentPart = (0, import_zustand.create)(
741
+ () => ({})
803
742
  );
743
+ syncContentPart(useMessage.getState(), useContentPart, partIndex);
744
+ return { useContentPart };
804
745
  });
746
+ (0, import_react24.useEffect)(() => {
747
+ syncContentPart(useMessage.getState(), context.useContentPart, partIndex);
748
+ return useMessage.subscribe((message) => {
749
+ syncContentPart(message, context.useContentPart, partIndex);
750
+ });
751
+ }, [context, useMessage, partIndex]);
752
+ return context;
753
+ };
754
+ var ContentPartProvider = ({
755
+ partIndex,
756
+ children
757
+ }) => {
758
+ const context = useContentPartContext2(partIndex);
759
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ContentPartContext.Provider, { value: context, children });
805
760
  };
806
761
 
807
- // src/utils/createActionButton.tsx
808
- var import_primitive = require("@radix-ui/primitive");
809
- var import_react_primitive3 = require("@radix-ui/react-primitive");
762
+ // src/primitives/contentPart/ContentPartDisplay.tsx
763
+ var ContentPartDisplay = () => {
764
+ const display = useContentPartDisplay();
765
+ return display ?? null;
766
+ };
767
+
768
+ // src/primitives/contentPart/ContentPartInProgressIndicator.tsx
769
+ var ContentPartInProgressIndicator = () => {
770
+ const indicator = useContentPartInProgressIndicator();
771
+ return indicator;
772
+ };
773
+
774
+ // src/primitives/contentPart/ContentPartText.tsx
775
+ var import_react_primitive4 = require("@radix-ui/react-primitive");
810
776
  var import_react25 = require("react");
811
- var import_jsx_runtime5 = require("react/jsx-runtime");
812
- var createActionButton = (displayName, useActionButton) => {
813
- const ActionButton = (0, import_react25.forwardRef)((props, forwardedRef) => {
814
- const callback = useActionButton(props);
815
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
816
- import_react_primitive3.Primitive.button,
777
+ var import_jsx_runtime10 = require("react/jsx-runtime");
778
+ var ContentPartText = (0, import_react25.forwardRef)((props, forwardedRef) => {
779
+ const text = useContentPartText();
780
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_primitive4.Primitive.span, { ...props, ref: forwardedRef, children: text });
781
+ });
782
+ ContentPartText.displayName = "ContentPartText";
783
+
784
+ // src/primitives/message/MessageContent.tsx
785
+ var import_jsx_runtime11 = require("react/jsx-runtime");
786
+ var defaultComponents = {
787
+ Text: () => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
788
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ContentPartText, {}),
789
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ContentPartInProgressIndicator, {})
790
+ ] }),
791
+ Image: () => null,
792
+ UI: () => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ContentPartDisplay, {}),
793
+ tools: {
794
+ Fallback: (props) => {
795
+ const { useToolUIs } = useAssistantContext();
796
+ const Render = useToolUIs((s) => s.getToolUI(props.part.toolName));
797
+ if (!Render) return null;
798
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Render, { ...props });
799
+ }
800
+ }
801
+ };
802
+ var MessageContentPartComponent = ({
803
+ components: {
804
+ Text = defaultComponents.Text,
805
+ Image = defaultComponents.Image,
806
+ UI = defaultComponents.UI,
807
+ tools: { by_name = {}, Fallback = defaultComponents.tools.Fallback } = {}
808
+ } = {}
809
+ }) => {
810
+ const { useThreadActions } = useThreadContext();
811
+ const addToolResult = useThreadActions((t) => t.addToolResult);
812
+ const { useContentPart } = useContentPartContext();
813
+ const { part, status } = useContentPart();
814
+ const type = part.type;
815
+ switch (type) {
816
+ case "text":
817
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { part, status });
818
+ case "image":
819
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Image, { part, status });
820
+ case "ui":
821
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(UI, { part, status });
822
+ case "tool-call": {
823
+ const Tool = by_name[part.toolName] || Fallback;
824
+ const addResult = (result) => addToolResult(part.toolCallId, result);
825
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Tool, { part, status, addResult });
826
+ }
827
+ default:
828
+ throw new Error(`Unknown content part type: ${type}`);
829
+ }
830
+ };
831
+ var MessageContentPartImpl = ({
832
+ partIndex,
833
+ components
834
+ }) => {
835
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ContentPartProvider, { partIndex, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(MessageContentPartComponent, { components }) });
836
+ };
837
+ var MessageContentPart = (0, import_react26.memo)(
838
+ MessageContentPartImpl,
839
+ (prev, next) => prev.partIndex === next.partIndex && prev.components?.Text === next.components?.Text && prev.components?.Image === next.components?.Image && prev.components?.UI === next.components?.UI && prev.components?.tools === next.components?.tools
840
+ );
841
+ var MessageContent = ({ components }) => {
842
+ const { useMessage } = useMessageContext();
843
+ const contentLength = useMessage((s) => s.message.content.length);
844
+ return new Array(contentLength).fill(null).map((_, idx) => {
845
+ const partIndex = idx;
846
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
847
+ MessageContentPart,
817
848
  {
818
- type: "button",
819
- disabled: !callback,
820
- ...props,
821
- ref: forwardedRef,
822
- onClick: (0, import_primitive.composeEventHandlers)(props.onClick, () => {
823
- callback?.();
824
- })
825
- }
849
+ partIndex,
850
+ components
851
+ },
852
+ partIndex
826
853
  );
827
854
  });
828
- ActionButton.displayName = displayName;
829
- return ActionButton;
830
855
  };
831
856
 
832
- // src/primitives/thread/ThreadScrollToBottom.tsx
833
- var ThreadScrollToBottom = createActionButton(
834
- "ThreadScrollToBottom",
835
- useThreadScrollToBottom
836
- );
857
+ // src/primitives/message/MessageInProgress.tsx
858
+ var import_react_primitive5 = require("@radix-ui/react-primitive");
859
+ var import_react27 = require("react");
860
+ var import_jsx_runtime12 = require("react/jsx-runtime");
861
+ var MessageInProgress = (0, import_react27.forwardRef)((props, ref) => {
862
+ const { useMessageUtils } = useMessageContext();
863
+ (0, import_react27.useMemo)(() => {
864
+ useMessageUtils.getState().setInProgressIndicator(/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_primitive5.Primitive.span, { ...props, ref }));
865
+ }, [useMessageUtils, props, ref]);
866
+ return null;
867
+ });
868
+ MessageInProgress.displayName = "MessageInProgress";
837
869
 
838
- // src/primitives/thread/ThreadSuggestion.tsx
839
- var ThreadSuggestion = createActionButton(
840
- "ThreadSuggestion",
841
- useThreadSuggestion
842
- );
870
+ // src/primitives/branchPicker/BranchPickerRoot.tsx
871
+ var import_jsx_runtime13 = require("react/jsx-runtime");
872
+ var BranchPickerRoot = (0, import_react28.forwardRef)(({ hideWhenSingleBranch, ...rest }, ref) => {
873
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(MessageIf, { hasBranches: hideWhenSingleBranch ? true : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_primitive6.Primitive.div, { ...rest, ref }) });
874
+ });
875
+ BranchPickerRoot.displayName = "BranchPickerRoot";
843
876
 
844
877
  // src/primitives/composer/index.ts
845
878
  var composer_exports = {};
@@ -852,11 +885,11 @@ __export(composer_exports, {
852
885
  });
853
886
 
854
887
  // src/primitives/composer/ComposerRoot.tsx
855
- var import_primitive2 = require("@radix-ui/primitive");
856
- var import_react_primitive4 = require("@radix-ui/react-primitive");
857
- var import_react26 = require("react");
858
- var import_jsx_runtime6 = require("react/jsx-runtime");
859
- var ComposerRoot = (0, import_react26.forwardRef)(
888
+ var import_primitive5 = require("@radix-ui/primitive");
889
+ var import_react_primitive7 = require("@radix-ui/react-primitive");
890
+ var import_react29 = require("react");
891
+ var import_jsx_runtime14 = require("react/jsx-runtime");
892
+ var ComposerRoot = (0, import_react29.forwardRef)(
860
893
  ({ onSubmit, ...rest }, forwardedRef) => {
861
894
  const send = useComposerSend();
862
895
  const handleSubmit = (e) => {
@@ -864,12 +897,12 @@ var ComposerRoot = (0, import_react26.forwardRef)(
864
897
  e.preventDefault();
865
898
  send();
866
899
  };
867
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
868
- import_react_primitive4.Primitive.form,
900
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
901
+ import_react_primitive7.Primitive.form,
869
902
  {
870
903
  ...rest,
871
904
  ref: forwardedRef,
872
- onSubmit: (0, import_primitive2.composeEventHandlers)(onSubmit, handleSubmit)
905
+ onSubmit: (0, import_primitive5.composeEventHandlers)(onSubmit, handleSubmit)
873
906
  }
874
907
  );
875
908
  }
@@ -877,14 +910,14 @@ var ComposerRoot = (0, import_react26.forwardRef)(
877
910
  ComposerRoot.displayName = "ComposerRoot";
878
911
 
879
912
  // src/primitives/composer/ComposerInput.tsx
880
- var import_primitive3 = require("@radix-ui/primitive");
881
- var import_react_compose_refs3 = require("@radix-ui/react-compose-refs");
913
+ var import_primitive6 = require("@radix-ui/primitive");
914
+ var import_react_compose_refs = require("@radix-ui/react-compose-refs");
882
915
  var import_react_slot = require("@radix-ui/react-slot");
883
- var import_react27 = require("react");
916
+ var import_react30 = require("react");
884
917
  var import_react_textarea_autosize = __toESM(require("react-textarea-autosize"));
885
918
  var import_react_use_escape_keydown = require("@radix-ui/react-use-escape-keydown");
886
- var import_jsx_runtime7 = require("react/jsx-runtime");
887
- var ComposerInput = (0, import_react27.forwardRef)(
919
+ var import_jsx_runtime15 = require("react/jsx-runtime");
920
+ var ComposerInput = (0, import_react30.forwardRef)(
888
921
  ({ autoFocus = false, asChild, disabled, onChange, onKeyDown, ...rest }, forwardedRef) => {
889
922
  const { useThread } = useThreadContext();
890
923
  const { useComposer, type } = useComposerContext();
@@ -893,8 +926,8 @@ var ComposerInput = (0, import_react27.forwardRef)(
893
926
  return c.value;
894
927
  });
895
928
  const Component = asChild ? import_react_slot.Slot : import_react_textarea_autosize.default;
896
- const textareaRef = (0, import_react27.useRef)(null);
897
- const ref = (0, import_react_compose_refs3.useComposedRefs)(forwardedRef, textareaRef);
929
+ const textareaRef = (0, import_react30.useRef)(null);
930
+ const ref = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, textareaRef);
898
931
  (0, import_react_use_escape_keydown.useEscapeKeydown)((e) => {
899
932
  const composer = useComposer.getState();
900
933
  if (composer.cancel()) {
@@ -912,35 +945,34 @@ var ComposerInput = (0, import_react27.forwardRef)(
912
945
  }
913
946
  };
914
947
  const autoFocusEnabled = autoFocus && !disabled;
915
- const focus = (0, import_react27.useCallback)(() => {
948
+ const focus = (0, import_react30.useCallback)(() => {
916
949
  const textarea = textareaRef.current;
917
950
  if (!textarea || !autoFocusEnabled) return;
918
- textarea.focus();
951
+ textarea.focus({ preventScroll: true });
919
952
  textarea.setSelectionRange(
920
953
  textareaRef.current.value.length,
921
954
  textareaRef.current.value.length
922
955
  );
923
956
  }, [autoFocusEnabled]);
924
- (0, import_react27.useEffect)(() => focus(), [focus]);
925
- useOnScrollToBottom(() => {
957
+ (0, import_react30.useEffect)(() => focus(), [focus]);
958
+ useOnComposerFocus(() => {
926
959
  if (type === "new") {
927
960
  focus();
928
961
  }
929
962
  });
930
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
963
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
931
964
  Component,
932
965
  {
933
966
  value,
934
967
  ...rest,
935
968
  ref,
936
- autoFocus,
937
969
  disabled,
938
- onChange: (0, import_primitive3.composeEventHandlers)(onChange, (e) => {
970
+ onChange: (0, import_primitive6.composeEventHandlers)(onChange, (e) => {
939
971
  const composerState = useComposer.getState();
940
972
  if (!composerState.isEditing) return;
941
973
  return composerState.setValue(e.target.value);
942
974
  }),
943
- onKeyDown: (0, import_primitive3.composeEventHandlers)(onKeyDown, handleKeyPress)
975
+ onKeyDown: (0, import_primitive6.composeEventHandlers)(onKeyDown, handleKeyPress)
944
976
  }
945
977
  );
946
978
  }
@@ -948,15 +980,15 @@ var ComposerInput = (0, import_react27.forwardRef)(
948
980
  ComposerInput.displayName = "ComposerInput";
949
981
 
950
982
  // src/primitives/composer/ComposerSend.tsx
951
- var import_react28 = require("react");
952
- var import_react_primitive5 = require("@radix-ui/react-primitive");
953
- var import_jsx_runtime8 = require("react/jsx-runtime");
954
- var ComposerSend = (0, import_react28.forwardRef)(
983
+ var import_react31 = require("react");
984
+ var import_react_primitive8 = require("@radix-ui/react-primitive");
985
+ var import_jsx_runtime16 = require("react/jsx-runtime");
986
+ var ComposerSend = (0, import_react31.forwardRef)(
955
987
  ({ disabled, ...rest }, ref) => {
956
988
  const { useComposer } = useComposerContext();
957
989
  const hasValue = useComposer((c) => c.isEditing && c.value.length > 0);
958
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
959
- import_react_primitive5.Primitive.button,
990
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
991
+ import_react_primitive8.Primitive.button,
960
992
  {
961
993
  type: "submit",
962
994
  ...rest,
@@ -974,332 +1006,407 @@ var ComposerCancel = createActionButton(
974
1006
  useComposerCancel
975
1007
  );
976
1008
 
977
- // src/primitives/message/index.ts
978
- var message_exports = {};
979
- __export(message_exports, {
980
- Content: () => MessageContent,
981
- If: () => MessageIf,
982
- InProgress: () => MessageInProgress,
983
- Root: () => MessageRoot
1009
+ // src/primitives/composer/ComposerIf.tsx
1010
+ var ComposerIf = ({ children, ...query }) => {
1011
+ const result = useComposerIf(query);
1012
+ return result ? children : null;
1013
+ };
1014
+
1015
+ // src/primitives/contentPart/index.ts
1016
+ var contentPart_exports = {};
1017
+ __export(contentPart_exports, {
1018
+ Display: () => ContentPartDisplay,
1019
+ Image: () => ContentPartImage,
1020
+ InProgressIndicator: () => ContentPartInProgressIndicator,
1021
+ Text: () => ContentPartText
984
1022
  });
985
1023
 
986
- // src/primitives/message/MessageRoot.tsx
987
- var import_primitive4 = require("@radix-ui/primitive");
988
- var import_react_primitive6 = require("@radix-ui/react-primitive");
989
- var import_react29 = require("react");
990
- var import_jsx_runtime9 = require("react/jsx-runtime");
991
- var MessageRoot = (0, import_react29.forwardRef)(
992
- ({ onMouseEnter, onMouseLeave, ...rest }, ref) => {
993
- const { useMessageUtils } = useMessageContext();
994
- const setIsHovering = useMessageUtils((s) => s.setIsHovering);
995
- const handleMouseEnter = () => {
996
- setIsHovering(true);
997
- };
998
- const handleMouseLeave = () => {
999
- setIsHovering(false);
1000
- };
1001
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1002
- import_react_primitive6.Primitive.div,
1003
- {
1004
- ...rest,
1005
- ref,
1006
- onMouseEnter: (0, import_primitive4.composeEventHandlers)(onMouseEnter, handleMouseEnter),
1007
- onMouseLeave: (0, import_primitive4.composeEventHandlers)(onMouseLeave, handleMouseLeave)
1008
- }
1009
- );
1024
+ // src/primitives/contentPart/ContentPartImage.tsx
1025
+ var import_react_primitive9 = require("@radix-ui/react-primitive");
1026
+ var import_react32 = require("react");
1027
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1028
+ var ContentPartImage = (0, import_react32.forwardRef)((props, forwardedRef) => {
1029
+ const image = useContentPartImage();
1030
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_primitive9.Primitive.img, { src: image, ...props, ref: forwardedRef });
1031
+ });
1032
+ ContentPartImage.displayName = "ContentPartImage";
1033
+
1034
+ // src/primitives/thread/index.ts
1035
+ var thread_exports = {};
1036
+ __export(thread_exports, {
1037
+ Empty: () => ThreadEmpty,
1038
+ If: () => ThreadIf,
1039
+ Messages: () => ThreadMessages,
1040
+ Root: () => ThreadRoot,
1041
+ ScrollToBottom: () => ThreadScrollToBottom,
1042
+ Suggestion: () => ThreadSuggestion,
1043
+ Viewport: () => ThreadViewport
1044
+ });
1045
+
1046
+ // src/primitives/thread/ThreadRoot.tsx
1047
+ var import_react_primitive10 = require("@radix-ui/react-primitive");
1048
+ var import_react33 = require("react");
1049
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1050
+ var ThreadRoot = (0, import_react33.forwardRef)(
1051
+ (props, ref) => {
1052
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_primitive10.Primitive.div, { ...props, ref });
1010
1053
  }
1011
1054
  );
1012
- MessageRoot.displayName = "MessageRoot";
1055
+ ThreadRoot.displayName = "ThreadRoot";
1013
1056
 
1014
- // src/primitives/message/MessageContent.tsx
1015
- var import_react32 = require("react");
1057
+ // src/primitives/thread/ThreadEmpty.tsx
1058
+ var ThreadEmpty = ({ children }) => {
1059
+ const empty = useThreadEmpty();
1060
+ return empty ? children : null;
1061
+ };
1016
1062
 
1017
- // src/context/providers/ContentPartProvider.tsx
1018
- var import_react30 = require("react");
1019
- var import_zustand4 = require("zustand");
1020
- var import_jsx_runtime10 = require("react/jsx-runtime");
1021
- var syncContentPart = ({ message }, useContentPart, partIndex) => {
1022
- const part = message.content[partIndex];
1023
- if (!part) return;
1024
- const messageStatus = message.role === "assistant" ? message.status : "done";
1025
- const status = partIndex === message.content.length - 1 ? messageStatus : "done";
1026
- const currentState = useContentPart.getState();
1027
- if (currentState.part === part && currentState.status === status) return;
1028
- useContentPart.setState(
1029
- Object.freeze({
1030
- part,
1031
- status
1032
- })
1063
+ // src/primitives/thread/ThreadIf.tsx
1064
+ var ThreadIf = ({ children, ...query }) => {
1065
+ const result = useThreadIf(query);
1066
+ return result ? children : null;
1067
+ };
1068
+
1069
+ // src/primitives/thread/ThreadViewport.tsx
1070
+ var import_react_compose_refs3 = require("@radix-ui/react-compose-refs");
1071
+ var import_react_primitive11 = require("@radix-ui/react-primitive");
1072
+ var import_react38 = require("react");
1073
+
1074
+ // src/primitive-hooks/thread/useThreadViewportAutoScroll.tsx
1075
+ var import_react_compose_refs2 = require("@radix-ui/react-compose-refs");
1076
+ var import_react37 = require("react");
1077
+
1078
+ // src/utils/hooks/useOnResizeContent.tsx
1079
+ var import_react_use_callback_ref2 = require("@radix-ui/react-use-callback-ref");
1080
+ var import_react35 = require("react");
1081
+
1082
+ // src/utils/hooks/useManagedRef.ts
1083
+ var import_react34 = require("react");
1084
+ var useManagedRef = (callback) => {
1085
+ const cleanupRef = (0, import_react34.useRef)();
1086
+ const ref = (0, import_react34.useCallback)(
1087
+ (el) => {
1088
+ if (cleanupRef.current) {
1089
+ cleanupRef.current();
1090
+ }
1091
+ if (el) {
1092
+ cleanupRef.current = callback(el);
1093
+ }
1094
+ },
1095
+ [callback]
1033
1096
  );
1097
+ return ref;
1034
1098
  };
1035
- var useContentPartContext2 = (partIndex) => {
1036
- const { useMessage } = useMessageContext();
1037
- const [context] = (0, import_react30.useState)(() => {
1038
- const useContentPart = (0, import_zustand4.create)(
1039
- () => ({})
1040
- );
1041
- syncContentPart(useMessage.getState(), useContentPart, partIndex);
1042
- return { useContentPart };
1043
- });
1044
- (0, import_react30.useEffect)(() => {
1045
- syncContentPart(useMessage.getState(), context.useContentPart, partIndex);
1046
- return useMessage.subscribe((message) => {
1047
- syncContentPart(message, context.useContentPart, partIndex);
1099
+
1100
+ // src/utils/hooks/useOnResizeContent.tsx
1101
+ var useOnResizeContent = (callback) => {
1102
+ const callbackRef = (0, import_react_use_callback_ref2.useCallbackRef)(callback);
1103
+ const refCallback = (0, import_react35.useCallback)(
1104
+ (el) => {
1105
+ const resizeObserver = new ResizeObserver(() => {
1106
+ callbackRef();
1107
+ });
1108
+ const mutationObserver = new MutationObserver((mutations) => {
1109
+ for (const mutation of mutations) {
1110
+ for (const node of mutation.addedNodes) {
1111
+ if (node instanceof Element) {
1112
+ resizeObserver.observe(node);
1113
+ }
1114
+ }
1115
+ for (const node of mutation.removedNodes) {
1116
+ if (node instanceof Element) {
1117
+ resizeObserver.unobserve(node);
1118
+ }
1119
+ }
1120
+ }
1121
+ callbackRef();
1122
+ });
1123
+ resizeObserver.observe(el);
1124
+ mutationObserver.observe(el, { childList: true });
1125
+ for (const child of el.children) {
1126
+ resizeObserver.observe(child);
1127
+ }
1128
+ return () => {
1129
+ resizeObserver.disconnect();
1130
+ mutationObserver.disconnect();
1131
+ };
1132
+ },
1133
+ [callbackRef]
1134
+ );
1135
+ return useManagedRef(refCallback);
1136
+ };
1137
+
1138
+ // src/utils/hooks/useOnScrollToBottom.tsx
1139
+ var import_react_use_callback_ref3 = require("@radix-ui/react-use-callback-ref");
1140
+ var import_react36 = require("react");
1141
+ var useOnScrollToBottom = (callback) => {
1142
+ const callbackRef = (0, import_react_use_callback_ref3.useCallbackRef)(callback);
1143
+ const { useViewport } = useThreadContext();
1144
+ (0, import_react36.useEffect)(() => {
1145
+ return useViewport.getState().onScrollToBottom(() => {
1146
+ callbackRef();
1048
1147
  });
1049
- }, [context, useMessage, partIndex]);
1050
- return context;
1148
+ }, [useViewport, callbackRef]);
1051
1149
  };
1052
- var ContentPartProvider = ({
1053
- partIndex,
1054
- children
1150
+
1151
+ // src/primitive-hooks/thread/useThreadViewportAutoScroll.tsx
1152
+ var useThreadViewportAutoScroll = ({
1153
+ autoScroll = true
1055
1154
  }) => {
1056
- const context = useContentPartContext2(partIndex);
1057
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ContentPartContext.Provider, { value: context, children });
1155
+ const divRef = (0, import_react37.useRef)(null);
1156
+ const { useViewport } = useThreadContext();
1157
+ const firstRenderRef = (0, import_react37.useRef)(true);
1158
+ const lastScrollTop = (0, import_react37.useRef)(0);
1159
+ const isScrollingToBottomRef = (0, import_react37.useRef)(false);
1160
+ const scrollToBottom = () => {
1161
+ const div = divRef.current;
1162
+ if (!div || !autoScroll) return;
1163
+ const behavior = firstRenderRef.current ? "instant" : "auto";
1164
+ firstRenderRef.current = false;
1165
+ isScrollingToBottomRef.current = true;
1166
+ div.scrollTo({ top: div.scrollHeight, behavior });
1167
+ };
1168
+ const handleScroll = () => {
1169
+ const div = divRef.current;
1170
+ if (!div) return;
1171
+ const isAtBottom = useViewport.getState().isAtBottom;
1172
+ const newIsAtBottom = div.scrollHeight - div.scrollTop <= div.clientHeight;
1173
+ if (!newIsAtBottom && lastScrollTop.current < div.scrollTop) {
1174
+ } else {
1175
+ isScrollingToBottomRef.current = newIsAtBottom;
1176
+ if (newIsAtBottom !== isAtBottom) {
1177
+ useViewport.setState({
1178
+ isAtBottom: newIsAtBottom
1179
+ });
1180
+ }
1181
+ }
1182
+ lastScrollTop.current = div.scrollTop;
1183
+ };
1184
+ const resizeRef = useOnResizeContent(() => {
1185
+ if (!isScrollingToBottomRef.current && !useViewport.getState().isAtBottom && !firstRenderRef.current) {
1186
+ handleScroll();
1187
+ } else {
1188
+ scrollToBottom();
1189
+ }
1190
+ });
1191
+ const scrollRef = useManagedRef((el) => {
1192
+ el.addEventListener("scroll", handleScroll);
1193
+ return () => {
1194
+ el.removeEventListener("scroll", handleScroll);
1195
+ };
1196
+ });
1197
+ const autoScrollRef = (0, import_react_compose_refs2.useComposedRefs)(resizeRef, scrollRef, divRef);
1198
+ useOnScrollToBottom(() => {
1199
+ scrollToBottom();
1200
+ });
1201
+ return autoScrollRef;
1058
1202
  };
1059
1203
 
1060
- // src/primitives/contentPart/ContentPartDisplay.tsx
1061
- var ContentPartDisplay = () => {
1062
- const display = useContentPartDisplay();
1063
- return display ?? null;
1064
- };
1204
+ // src/primitives/thread/ThreadViewport.tsx
1205
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1206
+ var ThreadViewport = (0, import_react38.forwardRef)(({ autoScroll, onScroll, children, ...rest }, forwardedRef) => {
1207
+ const autoScrollRef = useThreadViewportAutoScroll({
1208
+ autoScroll
1209
+ });
1210
+ const ref = (0, import_react_compose_refs3.useComposedRefs)(forwardedRef, autoScrollRef);
1211
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_primitive11.Primitive.div, { ...rest, ref, children });
1212
+ });
1213
+ ThreadViewport.displayName = "ThreadViewport";
1065
1214
 
1066
- // src/primitives/contentPart/ContentPartInProgressIndicator.tsx
1067
- var ContentPartInProgressIndicator = () => {
1068
- const indicator = useContentPartInProgressIndicator();
1069
- return indicator;
1070
- };
1215
+ // src/primitives/thread/ThreadMessages.tsx
1216
+ var import_react40 = require("react");
1071
1217
 
1072
- // src/primitives/contentPart/ContentPartText.tsx
1073
- var import_react_primitive7 = require("@radix-ui/react-primitive");
1074
- var import_react31 = require("react");
1075
- var import_jsx_runtime11 = require("react/jsx-runtime");
1076
- var ContentPartText = (0, import_react31.forwardRef)((props, forwardedRef) => {
1077
- const text = useContentPartText();
1078
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_primitive7.Primitive.span, { ...props, ref: forwardedRef, children: text });
1218
+ // src/context/providers/MessageProvider.tsx
1219
+ var import_react39 = require("react");
1220
+ var import_zustand4 = require("zustand");
1221
+
1222
+ // src/context/stores/EditComposer.ts
1223
+ var import_zustand2 = require("zustand");
1224
+
1225
+ // src/context/stores/BaseComposer.ts
1226
+ var makeBaseComposer = (set) => ({
1227
+ value: "",
1228
+ setValue: (value) => {
1229
+ set({ value });
1230
+ }
1079
1231
  });
1080
- ContentPartText.displayName = "ContentPartText";
1081
1232
 
1082
- // src/primitives/message/MessageContent.tsx
1083
- var import_jsx_runtime12 = require("react/jsx-runtime");
1084
- var defaultComponents = {
1085
- Text: () => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
1086
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ContentPartText, {}),
1087
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ContentPartInProgressIndicator, {})
1088
- ] }),
1089
- Image: () => null,
1090
- UI: () => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ContentPartDisplay, {}),
1091
- tools: {
1092
- Fallback: (props) => {
1093
- const { useToolUIs } = useAssistantContext();
1094
- const Render = useToolUIs((s) => s.getToolUI(props.part.toolName));
1095
- if (!Render) return null;
1096
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Render, { ...props });
1097
- }
1233
+ // src/context/stores/EditComposer.ts
1234
+ var makeEditComposerStore = ({
1235
+ onEdit,
1236
+ onSend
1237
+ }) => (0, import_zustand2.create)()((set, get, store) => ({
1238
+ ...makeBaseComposer(set, get, store),
1239
+ isEditing: false,
1240
+ edit: () => {
1241
+ const value = onEdit();
1242
+ set({ isEditing: true, value });
1243
+ },
1244
+ send: () => {
1245
+ const value = get().value;
1246
+ set({ isEditing: false });
1247
+ onSend(value);
1248
+ },
1249
+ cancel: () => {
1250
+ if (!get().isEditing) return false;
1251
+ set({ isEditing: false });
1252
+ return true;
1098
1253
  }
1254
+ }));
1255
+
1256
+ // src/context/stores/MessageUtils.ts
1257
+ var import_zustand3 = require("zustand");
1258
+ var makeMessageUtilsStore = () => (0, import_zustand3.create)((set) => ({
1259
+ inProgressIndicator: null,
1260
+ setInProgressIndicator: (value) => {
1261
+ set({ inProgressIndicator: value });
1262
+ },
1263
+ isCopied: false,
1264
+ setIsCopied: (value) => {
1265
+ set({ isCopied: value });
1266
+ },
1267
+ isHovering: false,
1268
+ setIsHovering: (value) => {
1269
+ set({ isHovering: value });
1270
+ }
1271
+ }));
1272
+
1273
+ // src/context/providers/MessageProvider.tsx
1274
+ var import_jsx_runtime20 = require("react/jsx-runtime");
1275
+ var getIsLast = (thread, message) => {
1276
+ return thread.messages[thread.messages.length - 1]?.id === message.id;
1277
+ };
1278
+ var syncMessage = (thread, getBranches, useMessage, messageIndex) => {
1279
+ const parentId = thread.messages[messageIndex - 1]?.id ?? null;
1280
+ const message = thread.messages[messageIndex];
1281
+ if (!message) return;
1282
+ const isLast = getIsLast(thread, message);
1283
+ const branches = getBranches(message.id);
1284
+ const currentState = useMessage.getState();
1285
+ if (currentState.message === message && currentState.parentId === parentId && currentState.branches === branches && currentState.isLast === isLast)
1286
+ return;
1287
+ useMessage.setState({
1288
+ message,
1289
+ parentId,
1290
+ branches,
1291
+ isLast
1292
+ });
1293
+ };
1294
+ var useMessageContext2 = (messageIndex) => {
1295
+ const { useThread, useThreadActions } = useThreadContext();
1296
+ const [context] = (0, import_react39.useState)(() => {
1297
+ const useMessage = (0, import_zustand4.create)(() => ({}));
1298
+ const useMessageUtils = makeMessageUtilsStore();
1299
+ const useEditComposer = makeEditComposerStore({
1300
+ onEdit: () => {
1301
+ const message = useMessage.getState().message;
1302
+ if (message.role !== "user")
1303
+ throw new Error(
1304
+ "Tried to edit a non-user message. Editing is only supported for user messages. This is likely an internal bug in assistant-ui."
1305
+ );
1306
+ const text = getMessageText(message);
1307
+ return text;
1308
+ },
1309
+ onSend: (text) => {
1310
+ const { message, parentId } = useMessage.getState();
1311
+ if (message.role !== "user")
1312
+ throw new Error(
1313
+ "Tried to edit a non-user message. Editing is only supported for user messages. This is likely an internal bug in assistant-ui."
1314
+ );
1315
+ const nonTextParts = message.content.filter(
1316
+ (part) => part.type !== "text" && part.type !== "ui"
1317
+ );
1318
+ useThreadActions.getState().append({
1319
+ parentId,
1320
+ role: "user",
1321
+ content: [{ type: "text", text }, ...nonTextParts]
1322
+ });
1323
+ }
1324
+ });
1325
+ syncMessage(
1326
+ useThread.getState(),
1327
+ useThreadActions.getState().getBranches,
1328
+ useMessage,
1329
+ messageIndex
1330
+ );
1331
+ return { useMessage, useMessageUtils, useEditComposer };
1332
+ });
1333
+ (0, import_react39.useEffect)(() => {
1334
+ return useThread.subscribe((thread) => {
1335
+ syncMessage(
1336
+ thread,
1337
+ useThreadActions.getState().getBranches,
1338
+ context.useMessage,
1339
+ messageIndex
1340
+ );
1341
+ });
1342
+ }, [useThread, useThreadActions, context, messageIndex]);
1343
+ return context;
1099
1344
  };
1100
- var MessageContentPartComponent = ({
1101
- components: {
1102
- Text = defaultComponents.Text,
1103
- Image = defaultComponents.Image,
1104
- UI = defaultComponents.UI,
1105
- tools: { by_name = {}, Fallback = defaultComponents.tools.Fallback } = {}
1106
- } = {}
1345
+ var MessageProvider = ({
1346
+ messageIndex,
1347
+ children
1107
1348
  }) => {
1108
- const { useThreadActions } = useThreadContext();
1109
- const addToolResult = useThreadActions((t) => t.addToolResult);
1110
- const { useContentPart } = useContentPartContext();
1111
- const { part, status } = useContentPart();
1112
- const type = part.type;
1113
- switch (type) {
1114
- case "text":
1115
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Text, { part, status });
1116
- case "image":
1117
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Image, { part, status });
1118
- case "ui":
1119
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(UI, { part, status });
1120
- case "tool-call": {
1121
- const Tool = by_name[part.toolName] || Fallback;
1122
- const addResult = (result) => addToolResult(part.toolCallId, result);
1123
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Tool, { part, status, addResult });
1124
- }
1125
- default:
1126
- throw new Error(`Unknown content part type: ${type}`);
1127
- }
1349
+ const context = useMessageContext2(messageIndex);
1350
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(MessageContext.Provider, { value: context, children });
1128
1351
  };
1129
- var MessageContentPartImpl = ({
1130
- partIndex,
1352
+
1353
+ // src/primitives/thread/ThreadMessages.tsx
1354
+ var import_jsx_runtime21 = require("react/jsx-runtime");
1355
+ var getComponents = (components) => {
1356
+ return {
1357
+ EditComposer: components.EditComposer ?? components.UserMessage ?? components.Message,
1358
+ UserMessage: components.UserMessage ?? components.Message,
1359
+ AssistantMessage: components.AssistantMessage ?? components.Message
1360
+ };
1361
+ };
1362
+ var ThreadMessageImpl = ({
1363
+ messageIndex,
1131
1364
  components
1132
1365
  }) => {
1133
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ContentPartProvider, { partIndex, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(MessageContentPartComponent, { components }) });
1366
+ const { UserMessage, EditComposer, AssistantMessage } = getComponents(components);
1367
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(MessageProvider, { messageIndex, children: [
1368
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(MessageIf, { user: true, children: [
1369
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ComposerIf, { editing: false, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(UserMessage, {}) }),
1370
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ComposerIf, { editing: true, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(EditComposer, {}) })
1371
+ ] }),
1372
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(MessageIf, { assistant: true, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(AssistantMessage, {}) })
1373
+ ] });
1134
1374
  };
1135
- var MessageContentPart = (0, import_react32.memo)(
1136
- MessageContentPartImpl,
1137
- (prev, next) => prev.partIndex === next.partIndex && prev.components?.Text === next.components?.Text && prev.components?.Image === next.components?.Image && prev.components?.UI === next.components?.UI && prev.components?.tools === next.components?.tools
1375
+ var ThreadMessage = (0, import_react40.memo)(
1376
+ ThreadMessageImpl,
1377
+ (prev, next) => prev.messageIndex === next.messageIndex && prev.components.UserMessage === next.components.UserMessage && prev.components.EditComposer === next.components.EditComposer && prev.components.AssistantMessage === next.components.AssistantMessage
1138
1378
  );
1139
- var MessageContent = ({ components }) => {
1140
- const { useMessage } = useMessageContext();
1141
- const contentLength = useMessage((s) => s.message.content.length);
1142
- return new Array(contentLength).fill(null).map((_, idx) => {
1143
- const partIndex = idx;
1144
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1145
- MessageContentPart,
1379
+ var ThreadMessages = ({ components }) => {
1380
+ const { useThread } = useThreadContext();
1381
+ const messagesLength = useThread((t) => t.messages.length);
1382
+ if (messagesLength === 0) return null;
1383
+ return new Array(messagesLength).fill(null).map((_, idx) => {
1384
+ const messageIndex = idx;
1385
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1386
+ ThreadMessage,
1146
1387
  {
1147
- partIndex,
1388
+ messageIndex,
1148
1389
  components
1149
1390
  },
1150
- partIndex
1391
+ messageIndex
1151
1392
  );
1152
1393
  });
1153
1394
  };
1154
1395
 
1155
- // src/primitives/message/MessageInProgress.tsx
1156
- var import_react_primitive8 = require("@radix-ui/react-primitive");
1157
- var import_react33 = require("react");
1158
- var import_jsx_runtime13 = require("react/jsx-runtime");
1159
- var MessageInProgress = (0, import_react33.forwardRef)((props, ref) => {
1160
- const { useMessageUtils } = useMessageContext();
1161
- (0, import_react33.useMemo)(() => {
1162
- useMessageUtils.getState().setInProgressIndicator(/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_primitive8.Primitive.span, { ...props, ref }));
1163
- }, [useMessageUtils, props, ref]);
1164
- return null;
1165
- });
1166
- MessageInProgress.displayName = "MessageInProgress";
1167
-
1168
- // src/primitives/branchPicker/index.ts
1169
- var branchPicker_exports = {};
1170
- __export(branchPicker_exports, {
1171
- Count: () => BranchPickerCount,
1172
- Next: () => BranchPickerNext,
1173
- Number: () => BranchPickerNumber,
1174
- Previous: () => BranchPickerPrevious,
1175
- Root: () => BranchPickerRoot
1176
- });
1177
-
1178
- // src/primitives/branchPicker/BranchPickerNext.tsx
1179
- var BranchPickerNext = createActionButton(
1180
- "BranchPickerNext",
1181
- useBranchPickerNext
1182
- );
1183
-
1184
- // src/primitives/branchPicker/BranchPickerPrevious.tsx
1185
- var BranchPickerPrevious = createActionButton(
1186
- "BranchPickerPrevious",
1187
- useBranchPickerPrevious
1188
- );
1189
-
1190
- // src/primitives/branchPicker/BranchPickerCount.tsx
1191
- var import_jsx_runtime14 = require("react/jsx-runtime");
1192
- var BranchPickerCount = () => {
1193
- const branchCount = useBranchPickerCount();
1194
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_jsx_runtime14.Fragment, { children: branchCount });
1195
- };
1196
-
1197
- // src/primitives/branchPicker/BranchPickerNumber.tsx
1198
- var import_jsx_runtime15 = require("react/jsx-runtime");
1199
- var BranchPickerNumber = () => {
1200
- const branchNumber = useBranchPickerNumber();
1201
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children: branchNumber });
1202
- };
1203
-
1204
- // src/primitives/branchPicker/BranchPickerRoot.tsx
1205
- var import_react_primitive9 = require("@radix-ui/react-primitive");
1206
- var import_react34 = require("react");
1207
- var import_jsx_runtime16 = require("react/jsx-runtime");
1208
- var BranchPickerRoot = (0, import_react34.forwardRef)(({ hideWhenSingleBranch, ...rest }, ref) => {
1209
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(MessageIf, { hasBranches: hideWhenSingleBranch ? true : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_primitive9.Primitive.div, { ...rest, ref }) });
1210
- });
1211
- BranchPickerRoot.displayName = "BranchPickerRoot";
1212
-
1213
- // src/primitives/actionBar/index.ts
1214
- var actionBar_exports = {};
1215
- __export(actionBar_exports, {
1216
- Copy: () => ActionBarCopy,
1217
- Edit: () => ActionBarEdit,
1218
- Reload: () => ActionBarReload,
1219
- Root: () => ActionBarRoot
1220
- });
1221
-
1222
- // src/primitives/actionBar/ActionBarRoot.tsx
1223
- var import_react_primitive10 = require("@radix-ui/react-primitive");
1224
- var import_react35 = require("react");
1225
- var import_jsx_runtime17 = require("react/jsx-runtime");
1226
- var useActionBarFloatStatus = ({
1227
- hideWhenRunning,
1228
- autohide,
1229
- autohideFloat
1230
- }) => {
1231
- const { useThread } = useThreadContext();
1232
- const { useMessage, useMessageUtils } = useMessageContext();
1233
- return useCombinedStore(
1234
- [useThread, useMessage, useMessageUtils],
1235
- (t, m, mu) => {
1236
- if (hideWhenRunning && t.isRunning) return "hidden" /* Hidden */;
1237
- const autohideEnabled = autohide === "always" || autohide === "not-last" && !m.isLast;
1238
- if (!autohideEnabled) return "normal" /* Normal */;
1239
- if (!mu.isHovering) return "hidden" /* Hidden */;
1240
- if (autohideFloat === "always" || autohideFloat === "single-branch" && m.branches.length <= 1)
1241
- return "floating" /* Floating */;
1242
- return "normal" /* Normal */;
1243
- }
1244
- );
1245
- };
1246
- var ActionBarRoot = (0, import_react35.forwardRef)(({ hideWhenRunning, autohide, autohideFloat, ...rest }, ref) => {
1247
- const hideAndfloatStatus = useActionBarFloatStatus({
1248
- hideWhenRunning,
1249
- autohide,
1250
- autohideFloat
1251
- });
1252
- if (hideAndfloatStatus === "hidden" /* Hidden */) return null;
1253
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1254
- import_react_primitive10.Primitive.div,
1255
- {
1256
- ...hideAndfloatStatus === "floating" /* Floating */ ? { "data-floating": "true" } : null,
1257
- ...rest,
1258
- ref
1259
- }
1260
- );
1261
- });
1262
- ActionBarRoot.displayName = "ActionBarRoot";
1263
-
1264
- // src/primitives/actionBar/ActionBarCopy.tsx
1265
- var ActionBarCopy = createActionButton(
1266
- "ActionBarCopy",
1267
- useActionBarCopy
1268
- );
1269
-
1270
- // src/primitives/actionBar/ActionBarReload.tsx
1271
- var ActionBarReload = createActionButton(
1272
- "ActionBarReload",
1273
- useActionBarReload
1396
+ // src/primitives/thread/ThreadScrollToBottom.tsx
1397
+ var ThreadScrollToBottom = createActionButton(
1398
+ "ThreadScrollToBottom",
1399
+ useThreadScrollToBottom
1274
1400
  );
1275
1401
 
1276
- // src/primitives/actionBar/ActionBarEdit.tsx
1277
- var ActionBarEdit = createActionButton(
1278
- "ActionBarEdit",
1279
- useActionBarEdit
1402
+ // src/primitives/thread/ThreadSuggestion.tsx
1403
+ var ThreadSuggestion = createActionButton(
1404
+ "ThreadSuggestion",
1405
+ useThreadSuggestion
1280
1406
  );
1281
1407
 
1282
- // src/primitives/contentPart/index.ts
1283
- var contentPart_exports = {};
1284
- __export(contentPart_exports, {
1285
- Display: () => ContentPartDisplay,
1286
- Image: () => ContentPartImage,
1287
- InProgressIndicator: () => ContentPartInProgressIndicator,
1288
- Text: () => ContentPartText
1289
- });
1290
-
1291
- // src/primitives/contentPart/ContentPartImage.tsx
1292
- var import_react_primitive11 = require("@radix-ui/react-primitive");
1293
- var import_react36 = require("react");
1294
- var import_jsx_runtime18 = require("react/jsx-runtime");
1295
- var ContentPartImage = (0, import_react36.forwardRef)((props, forwardedRef) => {
1296
- const image = useContentPartImage();
1297
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_primitive11.Primitive.img, { src: image, ...props, ref: forwardedRef });
1298
- });
1299
- ContentPartImage.displayName = "ContentPartImage";
1300
-
1301
1408
  // src/runtime/local/useLocalRuntime.tsx
1302
- var import_react37 = require("react");
1409
+ var import_react41 = require("react");
1303
1410
 
1304
1411
  // src/utils/ModelConfigTypes.ts
1305
1412
  var mergeModelConfigs = (configSet) => {
@@ -1585,18 +1692,18 @@ var LocalRuntime = class {
1585
1692
 
1586
1693
  // src/runtime/local/useLocalRuntime.tsx
1587
1694
  var useLocalRuntime = (adapter) => {
1588
- const [runtime] = (0, import_react37.useState)(() => new LocalRuntime(adapter));
1589
- (0, import_react37.useInsertionEffect)(() => {
1695
+ const [runtime] = (0, import_react41.useState)(() => new LocalRuntime(adapter));
1696
+ (0, import_react41.useInsertionEffect)(() => {
1590
1697
  runtime.adapter = adapter;
1591
1698
  });
1592
1699
  return runtime;
1593
1700
  };
1594
1701
 
1595
1702
  // src/context/providers/AssistantRuntimeProvider.tsx
1596
- var import_react40 = require("react");
1703
+ var import_react44 = require("react");
1597
1704
 
1598
1705
  // src/context/providers/AssistantProvider.tsx
1599
- var import_react39 = require("react");
1706
+ var import_react43 = require("react");
1600
1707
 
1601
1708
  // src/context/stores/AssistantModelConfig.ts
1602
1709
  var import_zustand5 = require("zustand");
@@ -1661,31 +1768,45 @@ var makeAssistantToolUIsStore = () => (0, import_zustand6.create)((set) => {
1661
1768
  });
1662
1769
 
1663
1770
  // src/context/providers/ThreadProvider.tsx
1664
- var import_react38 = require("react");
1771
+ var import_react42 = require("react");
1665
1772
 
1666
1773
  // src/context/stores/Composer.ts
1667
1774
  var import_zustand7 = require("zustand");
1668
- var makeComposerStore = (useThread, useThreadActions) => (0, import_zustand7.create)()((set, get, store) => {
1669
- return {
1670
- ...makeBaseComposer(set, get, store),
1671
- isEditing: true,
1672
- send: () => {
1673
- const { setValue, value } = get();
1674
- setValue("");
1675
- useThreadActions.getState().append({
1676
- parentId: useThread.getState().messages.at(-1)?.id ?? null,
1677
- role: "user",
1678
- content: [{ type: "text", text: value }]
1679
- });
1680
- },
1681
- cancel: () => {
1682
- const thread = useThread.getState();
1683
- if (!thread.isRunning) return false;
1684
- useThreadActions.getState().cancelRun();
1685
- return true;
1686
- }
1687
- };
1688
- });
1775
+ var makeComposerStore = (useThread, useThreadActions) => {
1776
+ const focusListeners = /* @__PURE__ */ new Set();
1777
+ return (0, import_zustand7.create)()((set, get, store) => {
1778
+ return {
1779
+ ...makeBaseComposer(set, get, store),
1780
+ isEditing: true,
1781
+ send: () => {
1782
+ const { setValue, value } = get();
1783
+ setValue("");
1784
+ useThreadActions.getState().append({
1785
+ parentId: useThread.getState().messages.at(-1)?.id ?? null,
1786
+ role: "user",
1787
+ content: [{ type: "text", text: value }]
1788
+ });
1789
+ },
1790
+ cancel: () => {
1791
+ const thread = useThread.getState();
1792
+ if (!thread.isRunning) return false;
1793
+ useThreadActions.getState().cancelRun();
1794
+ return true;
1795
+ },
1796
+ focus: () => {
1797
+ for (const listener of focusListeners) {
1798
+ listener();
1799
+ }
1800
+ },
1801
+ onFocus: (listener) => {
1802
+ focusListeners.add(listener);
1803
+ return () => {
1804
+ focusListeners.delete(listener);
1805
+ };
1806
+ }
1807
+ };
1808
+ });
1809
+ };
1689
1810
 
1690
1811
  // src/context/stores/Thread.ts
1691
1812
  var import_zustand8 = require("zustand");
@@ -1732,16 +1853,16 @@ var makeThreadActionStore = (runtimeRef) => {
1732
1853
  };
1733
1854
 
1734
1855
  // src/context/providers/ThreadProvider.tsx
1735
- var import_jsx_runtime19 = require("react/jsx-runtime");
1856
+ var import_jsx_runtime22 = require("react/jsx-runtime");
1736
1857
  var ThreadProvider = ({
1737
1858
  children,
1738
1859
  runtime
1739
1860
  }) => {
1740
- const runtimeRef = (0, import_react38.useRef)(runtime);
1741
- (0, import_react38.useInsertionEffect)(() => {
1861
+ const runtimeRef = (0, import_react42.useRef)(runtime);
1862
+ (0, import_react42.useInsertionEffect)(() => {
1742
1863
  runtimeRef.current = runtime;
1743
1864
  });
1744
- const [context] = (0, import_react38.useState)(() => {
1865
+ const [context] = (0, import_react42.useState)(() => {
1745
1866
  const useThread = makeThreadStore(runtimeRef);
1746
1867
  const useThreadActions = makeThreadActionStore(runtimeRef);
1747
1868
  const useViewport = makeThreadViewportStore();
@@ -1753,7 +1874,7 @@ var ThreadProvider = ({
1753
1874
  useViewport
1754
1875
  };
1755
1876
  });
1756
- (0, import_react38.useEffect)(() => {
1877
+ (0, import_react42.useEffect)(() => {
1757
1878
  const onRuntimeUpdate = () => {
1758
1879
  context.useThread.setState(
1759
1880
  Object.freeze({
@@ -1767,37 +1888,37 @@ var ThreadProvider = ({
1767
1888
  return runtime.subscribe(onRuntimeUpdate);
1768
1889
  }, [context, runtime]);
1769
1890
  const RuntimeSynchronizer = runtime.unstable_synchronizer;
1770
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(ThreadContext.Provider, { value: context, children: [
1771
- RuntimeSynchronizer && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(RuntimeSynchronizer, {}),
1891
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(ThreadContext.Provider, { value: context, children: [
1892
+ RuntimeSynchronizer && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(RuntimeSynchronizer, {}),
1772
1893
  children
1773
1894
  ] });
1774
1895
  };
1775
1896
 
1776
1897
  // src/context/providers/AssistantProvider.tsx
1777
- var import_jsx_runtime20 = require("react/jsx-runtime");
1898
+ var import_jsx_runtime23 = require("react/jsx-runtime");
1778
1899
  var AssistantProvider = ({ children, runtime }) => {
1779
- const runtimeRef = (0, import_react39.useRef)(runtime);
1780
- (0, import_react39.useInsertionEffect)(() => {
1900
+ const runtimeRef = (0, import_react43.useRef)(runtime);
1901
+ (0, import_react43.useInsertionEffect)(() => {
1781
1902
  runtimeRef.current = runtime;
1782
1903
  });
1783
- const [context] = (0, import_react39.useState)(() => {
1904
+ const [context] = (0, import_react43.useState)(() => {
1784
1905
  const useModelConfig = makeAssistantModelConfigStore();
1785
1906
  const useToolUIs = makeAssistantToolUIsStore();
1786
1907
  return { useModelConfig, useToolUIs };
1787
1908
  });
1788
1909
  const getModelCOnfig = context.useModelConfig((c) => c.getModelConfig);
1789
- (0, import_react39.useEffect)(() => {
1910
+ (0, import_react43.useEffect)(() => {
1790
1911
  return runtime.registerModelConfigProvider(getModelCOnfig);
1791
1912
  }, [runtime, getModelCOnfig]);
1792
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(AssistantContext.Provider, { value: context, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ThreadProvider, { runtime, children }) });
1913
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(AssistantContext.Provider, { value: context, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ThreadProvider, { runtime, children }) });
1793
1914
  };
1794
1915
 
1795
1916
  // src/context/providers/AssistantRuntimeProvider.tsx
1796
- var import_jsx_runtime21 = require("react/jsx-runtime");
1917
+ var import_jsx_runtime24 = require("react/jsx-runtime");
1797
1918
  var AssistantRuntimeProviderImpl = ({ children, runtime }) => {
1798
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(AssistantProvider, { runtime, children });
1919
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(AssistantProvider, { runtime, children });
1799
1920
  };
1800
- var AssistantRuntimeProvider = (0, import_react40.memo)(AssistantRuntimeProviderImpl);
1921
+ var AssistantRuntimeProvider = (0, import_react44.memo)(AssistantRuntimeProviderImpl);
1801
1922
 
1802
1923
  // src/internal.ts
1803
1924
  var internal_exports = {};
@@ -1808,6 +1929,7 @@ __export(internal_exports, {
1808
1929
  // Annotate the CommonJS export names for ESM import in node:
1809
1930
  0 && (module.exports = {
1810
1931
  ActionBarPrimitive,
1932
+ AssistantModalPrimitive,
1811
1933
  AssistantRuntimeProvider,
1812
1934
  BranchPickerPrimitive,
1813
1935
  ComposerPrimitive,