@assistant-ui/react 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.js CHANGED
@@ -33,18 +33,15 @@ __export(src_exports, {
33
33
  ActionBarPrimitive: () => actionBar_exports,
34
34
  BranchPickerPrimitive: () => branchPicker_exports,
35
35
  ComposerPrimitive: () => composer_exports,
36
- EditBarPrimitive: () => editBar_exports,
37
36
  MessagePrimitive: () => message_exports,
38
37
  ThreadPrimitive: () => thread_exports,
39
- VercelAIThreadProvider: () => VercelAIThreadProvider,
38
+ VercelAIThreadProvider: () => VercelAIAssistantProvider,
40
39
  unstable_useMessageContext: () => useMessageContext,
41
40
  useBeginMessageEdit: () => useBeginMessageEdit,
42
- useCancelMessageEdit: () => useCancelMessageEdit,
43
41
  useCopyMessage: () => useCopyMessage,
44
42
  useGoToNextBranch: () => useGoToNextBranch,
45
43
  useGoToPreviousBranch: () => useGoToPreviousBranch,
46
- useReloadMessage: () => useReloadMessage,
47
- useSaveMessageEdit: () => useSaveMessageEdit
44
+ useReloadMessage: () => useReloadMessage
48
45
  });
49
46
  module.exports = __toCommonJS(src_exports);
50
47
 
@@ -67,87 +64,22 @@ var ThreadRoot = (0, import_react.forwardRef)(
67
64
  }
68
65
  );
69
66
 
70
- // src/utils/context/createStoreContext.tsx
67
+ // src/utils/context/AssistantContext.ts
71
68
  var import_react2 = require("react");
72
- var import_with_selector = require("use-sync-external-store/with-selector");
73
-
74
- // src/utils/context/shallow.ts
75
- function shallow(objA, objB) {
76
- if (Object.is(objA, objB)) {
77
- return true;
78
- }
79
- if (typeof objA !== "object" || objA === null || typeof objB !== "object" || objB === null) {
80
- return false;
81
- }
82
- const keysA = Object.keys(objA);
83
- if (keysA.length !== Object.keys(objB).length) {
84
- return false;
85
- }
86
- for (const keyA of keysA) {
87
- if (!Object.prototype.hasOwnProperty.call(objB, keyA) || !Object.is(objA[keyA], objB[keyA])) {
88
- return false;
89
- }
90
- }
91
- return true;
92
- }
93
-
94
- // src/utils/context/createStoreContext.tsx
95
- var createStoreContext = (providerName) => {
96
- const context = (0, import_react2.createContext)(null);
97
- const StoreProvider = ({ children, ...rest }) => {
98
- const unstableContext = rest;
99
- const [store] = (0, import_react2.useState)(() => {
100
- let state = unstableContext;
101
- const listeners = /* @__PURE__ */ new Set();
102
- return {
103
- subscribe: (cb) => {
104
- listeners.add(cb);
105
- return () => listeners.delete(cb);
106
- },
107
- emit: () => {
108
- for (const listener of listeners) {
109
- listener();
110
- }
111
- },
112
- snapshot: () => {
113
- return state;
114
- },
115
- setState: (value) => {
116
- state = value;
117
- store.emit();
118
- }
119
- };
120
- });
121
- (0, import_react2.useMemo)(
122
- () => store.setState(unstableContext),
123
- Object.values(unstableContext)
124
- );
125
- return /* @__PURE__ */ React.createElement(context.Provider, { value: store }, children);
126
- };
127
- const useStoreContext = (consumerName, selector) => {
128
- const store = (0, import_react2.useContext)(context);
129
- if (!store)
130
- throw new Error(
131
- `${consumerName} can only be used inside ${providerName}.`
132
- );
133
- return (0, import_with_selector.useSyncExternalStoreWithSelector)(
134
- store.subscribe,
135
- store.snapshot,
136
- store.snapshot,
137
- selector,
138
- shallow
69
+ var AssistantContext = (0, import_react2.createContext)(null);
70
+ var useAssistantContext = () => {
71
+ const context = (0, import_react2.useContext)(AssistantContext);
72
+ if (!context)
73
+ throw new Error(
74
+ "useAssistantContext must be used within a AssistantProvider"
139
75
  );
140
- };
141
- return [StoreProvider, useStoreContext];
76
+ return context;
142
77
  };
143
78
 
144
- // src/utils/context/ThreadContext.ts
145
- var [ThreadContextProvider, useThreadContext] = createStoreContext("Thread.Provider");
146
-
147
79
  // src/primitives/thread/ThreadIf.tsx
148
80
  var useThreadIf = (props) => {
149
- return useThreadContext("Thread.If", (s) => {
150
- const thread = s.chat;
81
+ const { useThread } = useAssistantContext();
82
+ return useThread((thread) => {
151
83
  if (props.empty === true && thread.messages.length !== 0)
152
84
  return false;
153
85
  if (props.empty === false && thread.messages.length === 0)
@@ -356,79 +288,150 @@ var useChatWithBranches = (chat) => {
356
288
  );
357
289
  return (0, import_react5.useMemo)(
358
290
  () => ({
359
- ...chat,
360
291
  getBranchState,
361
292
  switchToBranch,
362
293
  editAt,
363
294
  reloadAt
364
295
  }),
365
- [chat, getBranchState, switchToBranch, editAt, reloadAt]
296
+ [getBranchState, switchToBranch, editAt, reloadAt]
366
297
  );
367
298
  };
368
299
  var hasUpcomingMessage = (thread) => {
369
300
  return thread.isLoading && thread.messages[thread.messages.length - 1]?.role !== "assistant";
370
301
  };
371
302
 
303
+ // src/utils/context/ComposerState.ts
304
+ var import_react7 = require("react");
305
+
306
+ // src/utils/context/MessageContext.ts
307
+ var import_react6 = require("react");
308
+ var MessageContext = (0, import_react6.createContext)(null);
309
+ var useMessageContext = () => {
310
+ const context = (0, import_react6.useContext)(MessageContext);
311
+ if (!context)
312
+ throw new Error("useMessageContext must be used within a MessageProvider");
313
+ return context;
314
+ };
315
+
316
+ // src/utils/context/ComposerState.ts
317
+ var useComposerContext = () => {
318
+ const { useComposer: useAssisstantComposer } = useAssistantContext();
319
+ const { useComposer: useMessageComposer } = (0, import_react7.useContext)(MessageContext) ?? {};
320
+ return { useComposer: useMessageComposer ?? useAssisstantComposer };
321
+ };
322
+
323
+ // src/primitives/composer/ComposerIf.tsx
324
+ var useComposerIf = (props) => {
325
+ const { useComposer } = useComposerContext();
326
+ return useComposer((composer) => {
327
+ if (props.editing === true && !composer.isEditing)
328
+ return false;
329
+ if (props.editing === false && composer.isEditing)
330
+ return false;
331
+ return true;
332
+ });
333
+ };
334
+ var ComposerIf = ({ children, ...query }) => {
335
+ const result = useComposerIf(query);
336
+ return result ? children : null;
337
+ };
338
+
372
339
  // src/primitives/message/index.ts
373
340
  var message_exports = {};
374
341
  __export(message_exports, {
375
342
  Content: () => MessageContent,
376
- EditableContent: () => MessageEditableContent,
377
343
  If: () => MessageIf,
378
344
  Provider: () => MessageProvider,
379
345
  Root: () => MessageRoot
380
346
  });
381
347
 
382
348
  // src/primitives/message/MessageProvider.tsx
383
- var import_react6 = require("react");
384
-
385
- // src/utils/context/MessageContext.ts
386
- var [MessageContextProvider, useMessageContext] = createStoreContext("Thread.Provider");
387
-
388
- // src/primitives/message/MessageProvider.tsx
349
+ var import_react8 = require("react");
350
+ var import_zustand = require("zustand");
351
+ var import_shallow = require("zustand/react/shallow");
352
+ var getIsLast = (thread, message) => {
353
+ const hasUpcoming = hasUpcomingMessage(thread);
354
+ return hasUpcoming ? message.id === UPCOMING_MESSAGE_ID : thread.messages[thread.messages.length - 1]?.id === message.id;
355
+ };
356
+ var useMessageContext2 = () => {
357
+ const { useBranchObserver } = useAssistantContext();
358
+ const [context] = (0, import_react8.useState)(() => {
359
+ const useMessage = (0, import_zustand.create)(() => ({
360
+ message: null,
361
+ isLast: false,
362
+ isCopied: false,
363
+ isHovering: false,
364
+ setIsCopied: () => {
365
+ },
366
+ setIsHovering: () => {
367
+ },
368
+ branchState: {
369
+ branchId: 0,
370
+ branchCount: 0
371
+ }
372
+ }));
373
+ const useComposer = (0, import_zustand.create)((set, get) => ({
374
+ isEditing: false,
375
+ canCancel: true,
376
+ edit: () => set({
377
+ isEditing: true,
378
+ value: useMessage.getState().message.content
379
+ }),
380
+ cancel: () => set({ isEditing: false }),
381
+ send: () => {
382
+ const message = useMessage.getState().message;
383
+ useBranchObserver.getState().editAt(message, {
384
+ ...message,
385
+ id: void 0,
386
+ // remove id to create a new message
387
+ content: get().value
388
+ });
389
+ set({ isEditing: false });
390
+ },
391
+ value: "",
392
+ setValue: (value) => set({ value })
393
+ }));
394
+ return { useMessage, useComposer };
395
+ });
396
+ return context;
397
+ };
389
398
  var MessageProvider = ({
390
399
  message,
391
400
  children
392
401
  }) => {
393
- const getBranchState = useThreadContext(
394
- "Message.Provider",
395
- (s) => s.chat.getBranchState
396
- );
397
- const [editState, setEditState] = (0, import_react6.useState)({
398
- isEditing: false
399
- });
400
- const [isCopied, setIsCopied] = (0, import_react6.useState)(false);
401
- const [isHovering, setIsHovering] = (0, import_react6.useState)(false);
402
- const branchState = (0, import_react6.useMemo)(
403
- () => getBranchState(message),
404
- [getBranchState, message]
405
- );
406
- return /* @__PURE__ */ React.createElement(
407
- MessageContextProvider,
408
- {
409
- message,
410
- editState,
411
- setEditState,
412
- branchState,
413
- isCopied,
414
- setIsCopied,
415
- isHovering,
416
- setIsHovering
417
- },
418
- children
402
+ const { useThread, useBranchObserver } = useAssistantContext();
403
+ const context = useMessageContext2();
404
+ const branchState = useBranchObserver(
405
+ (0, import_shallow.useShallow)((b) => b.getBranchState(message))
419
406
  );
407
+ const isLast = useThread((thread) => getIsLast(thread, message));
408
+ const [isCopied, setIsCopied] = (0, import_react8.useState)(false);
409
+ const [isHovering, setIsHovering] = (0, import_react8.useState)(false);
410
+ (0, import_react8.useMemo)(() => {
411
+ context.useMessage.setState(
412
+ {
413
+ message,
414
+ isLast,
415
+ isCopied,
416
+ isHovering,
417
+ setIsCopied,
418
+ setIsHovering,
419
+ branchState
420
+ },
421
+ true
422
+ );
423
+ }, [context, message, isLast, isCopied, isHovering, branchState]);
424
+ return /* @__PURE__ */ React.createElement(MessageContext.Provider, { value: context }, children);
420
425
  };
421
426
 
422
427
  // src/primitives/message/MessageRoot.tsx
423
- var import_react7 = require("react");
424
- var import_react_primitive3 = require("@radix-ui/react-primitive");
425
428
  var import_primitive2 = require("@radix-ui/primitive");
426
- var MessageRoot = (0, import_react7.forwardRef)(
429
+ var import_react_primitive3 = require("@radix-ui/react-primitive");
430
+ var import_react9 = require("react");
431
+ var MessageRoot = (0, import_react9.forwardRef)(
427
432
  ({ onMouseEnter, onMouseLeave, ...rest }, ref) => {
428
- const setIsHovering = useMessageContext(
429
- "Message.Root",
430
- (s) => s.setIsHovering
431
- );
433
+ const { useMessage } = useMessageContext();
434
+ const setIsHovering = useMessage((s) => s.setIsHovering);
432
435
  const handleMouseEnter = () => {
433
436
  setIsHovering(true);
434
437
  };
@@ -448,27 +451,23 @@ var MessageRoot = (0, import_react7.forwardRef)(
448
451
  );
449
452
 
450
453
  // src/primitives/message/MessageIf.tsx
451
- var isLast = (thread, message) => {
452
- const hasUpcoming = hasUpcomingMessage(thread);
453
- return hasUpcoming ? message.id === UPCOMING_MESSAGE_ID : thread.messages[thread.messages.length - 1]?.id === message.id;
454
- };
455
454
  var useMessageIf = (props) => {
456
- const thread = useThreadContext("Message.If", (s) => s.chat);
457
- return useMessageContext(
458
- "Message.If",
459
- ({ message, editState: { isEditing }, isCopied, isHovering }) => {
460
- const { branchCount } = thread.getBranchState(message);
455
+ const { useMessage } = useMessageContext();
456
+ return useMessage(
457
+ ({
458
+ message,
459
+ isLast,
460
+ isCopied,
461
+ isHovering,
462
+ branchState: { branchCount }
463
+ }) => {
461
464
  if (props.hasBranches === true && branchCount < 2)
462
465
  return false;
463
466
  if (props.user && message.role !== "user")
464
467
  return false;
465
468
  if (props.assistant && message.role !== "assistant")
466
469
  return false;
467
- if (props.editing === true && !isEditing)
468
- return false;
469
- if (props.editing === false && isEditing)
470
- return false;
471
- if (props.lastOrHover === true && !isHovering && !isLast(thread, message))
470
+ if (props.lastOrHover === true && !isHovering && !isLast)
472
471
  return false;
473
472
  if (props.copied === true && !isCopied)
474
473
  return false;
@@ -485,60 +484,32 @@ var MessageIf = ({ children, ...query }) => {
485
484
 
486
485
  // src/primitives/message/MessageContent.tsx
487
486
  var MessageContent = () => {
488
- const content = useMessageContext(
489
- "Message.Content",
490
- (s) => s.message.content
491
- );
487
+ const { useMessage } = useMessageContext();
488
+ const content = useMessage((s) => s.message.content);
492
489
  return /* @__PURE__ */ React.createElement(React.Fragment, null, content);
493
490
  };
494
491
 
495
- // src/primitives/message/MessageEditableContent.tsx
496
- var import_react8 = require("react");
497
- var import_primitive3 = require("@radix-ui/primitive");
498
- var import_react_textarea_autosize = __toESM(require("react-textarea-autosize"));
499
- var MessageEditableContent = (0, import_react8.forwardRef)(({ onChange, value, ...rest }, forwardedRef) => {
500
- const [editState, setEditState] = useMessageContext(
501
- "Message.EditableContent",
502
- (s) => [s.editState, s.setEditState]
503
- );
504
- const handleChange = (e) => {
505
- setEditState({ isEditing: true, value: e.target.value });
506
- };
507
- if (!editState.isEditing)
508
- throw new Error(
509
- "Message.EditableContent may only be rendered when edit mode is enabled. Consider wrapping the component in <Message.If editing>."
510
- );
511
- return /* @__PURE__ */ React.createElement(
512
- import_react_textarea_autosize.default,
513
- {
514
- ...rest,
515
- ref: forwardedRef,
516
- onChange: (0, import_primitive3.composeEventHandlers)(onChange, handleChange),
517
- value: editState.value || value
518
- }
519
- );
520
- });
521
-
522
492
  // src/primitives/thread/ThreadMessages.tsx
523
493
  var getComponents = (components) => {
524
494
  return {
525
- EditingUserMessage: components.EditingUserMessage ?? components.UserMessage ?? components.Message,
495
+ EditComposer: components.EditComposer ?? components.UserMessage ?? components.Message,
526
496
  UserMessage: components.UserMessage ?? components.Message,
527
497
  AssistantMessage: components.AssistantMessage ?? components.Message
528
498
  };
529
499
  };
530
500
  var ThreadMessages = ({ components }) => {
531
- const chat = useThreadContext("Thread.Messages", (s) => s.chat);
532
- const messages = chat.messages;
533
- const { UserMessage, EditingUserMessage, AssistantMessage } = getComponents(components);
501
+ const { useThread } = useAssistantContext();
502
+ const thread = useThread();
503
+ const messages = thread.messages;
504
+ const { UserMessage, EditComposer, AssistantMessage } = getComponents(components);
534
505
  if (messages.length === 0)
535
506
  return null;
536
507
  return /* @__PURE__ */ React.createElement(React.Fragment, null, messages.map((message, idx) => {
537
508
  return (
538
509
  // biome-ignore lint/suspicious/noArrayIndexKey: fixes a11y issues with branch navigation
539
- /* @__PURE__ */ React.createElement(MessageProvider, { key: idx, message }, /* @__PURE__ */ React.createElement(MessageIf, { user: true, editing: false }, /* @__PURE__ */ React.createElement(UserMessage, null)), /* @__PURE__ */ React.createElement(MessageIf, { user: true, editing: true }, /* @__PURE__ */ React.createElement(EditingUserMessage, null)), /* @__PURE__ */ React.createElement(MessageIf, { assistant: true }, /* @__PURE__ */ React.createElement(AssistantMessage, null)))
510
+ /* @__PURE__ */ React.createElement(MessageProvider, { key: idx, message }, /* @__PURE__ */ React.createElement(MessageIf, { user: true }, /* @__PURE__ */ React.createElement(ComposerIf, { editing: false }, /* @__PURE__ */ React.createElement(UserMessage, null)), /* @__PURE__ */ React.createElement(ComposerIf, { editing: true }, /* @__PURE__ */ React.createElement(EditComposer, null))), /* @__PURE__ */ React.createElement(MessageIf, { assistant: true }, /* @__PURE__ */ React.createElement(AssistantMessage, null)))
540
511
  );
541
- }), hasUpcomingMessage(chat) && /* @__PURE__ */ React.createElement(
512
+ }), hasUpcomingMessage(thread) && /* @__PURE__ */ React.createElement(
542
513
  MessageProvider,
543
514
  {
544
515
  message: {
@@ -554,20 +525,21 @@ var ThreadMessages = ({ components }) => {
554
525
  // src/primitives/composer/index.ts
555
526
  var composer_exports = {};
556
527
  __export(composer_exports, {
528
+ Cancel: () => ComposerCancel,
529
+ If: () => ComposerIf,
557
530
  Input: () => ComposerInput,
558
531
  Root: () => ComposerRoot,
559
- Send: () => ComposerSend,
560
- Stop: () => ComposerStop
532
+ Send: () => ComposerSend
561
533
  });
562
534
 
563
535
  // src/primitives/composer/ComposerRoot.tsx
564
- var import_react9 = require("react");
565
- var import_react_primitive4 = require("@radix-ui/react-primitive");
566
- var import_primitive4 = require("@radix-ui/primitive");
536
+ var import_primitive3 = require("@radix-ui/primitive");
567
537
  var import_react_compose_refs2 = require("@radix-ui/react-compose-refs");
568
- var ComposerContext = (0, import_react9.createContext)(null);
569
- var useComposerContext = () => {
570
- const context = (0, import_react9.useContext)(ComposerContext);
538
+ var import_react_primitive4 = require("@radix-ui/react-primitive");
539
+ var import_react10 = require("react");
540
+ var ComposerFormContext = (0, import_react10.createContext)(null);
541
+ var useComposerFormContext = () => {
542
+ const context = (0, import_react10.useContext)(ComposerFormContext);
571
543
  if (!context) {
572
544
  throw new Error(
573
545
  "Composer compound components cannot be rendered outside the Composer component"
@@ -575,15 +547,12 @@ var useComposerContext = () => {
575
547
  }
576
548
  return context;
577
549
  };
578
- var ComposerRoot = (0, import_react9.forwardRef)(
550
+ var ComposerRoot = (0, import_react10.forwardRef)(
579
551
  ({ onSubmit, ...rest }, forwardedRef) => {
580
- const handleSubmit = useThreadContext(
581
- "Composer.Root",
582
- (s) => s.chat.handleSubmit
583
- );
584
- const formRef = (0, import_react9.useRef)(null);
552
+ const { useComposer } = useComposerContext();
553
+ const formRef = (0, import_react10.useRef)(null);
585
554
  const ref = (0, import_react_compose_refs2.useComposedRefs)(forwardedRef, formRef);
586
- const composerContextValue = (0, import_react9.useMemo)(
555
+ const composerContextValue = (0, import_react10.useMemo)(
587
556
  () => ({
588
557
  submit: () => formRef.current?.dispatchEvent(
589
558
  new Event("submit", { cancelable: true, bubbles: true })
@@ -591,104 +560,111 @@ var ComposerRoot = (0, import_react9.forwardRef)(
591
560
  }),
592
561
  []
593
562
  );
594
- return /* @__PURE__ */ React.createElement(ComposerContext.Provider, { value: composerContextValue }, /* @__PURE__ */ React.createElement(
563
+ const handleSubmit = (e) => {
564
+ const composerState = useComposer.getState();
565
+ if (!composerState.isEditing)
566
+ return;
567
+ e.preventDefault();
568
+ composerState.send();
569
+ };
570
+ return /* @__PURE__ */ React.createElement(ComposerFormContext.Provider, { value: composerContextValue }, /* @__PURE__ */ React.createElement(
595
571
  import_react_primitive4.Primitive.form,
596
572
  {
597
573
  ...rest,
598
574
  ref,
599
- onSubmit: (0, import_primitive4.composeEventHandlers)(onSubmit, handleSubmit)
575
+ onSubmit: (0, import_primitive3.composeEventHandlers)(onSubmit, handleSubmit)
600
576
  }
601
577
  ));
602
578
  }
603
579
  );
604
580
 
605
581
  // src/primitives/composer/ComposerInput.tsx
606
- var import_react10 = require("react");
582
+ var import_primitive4 = require("@radix-ui/primitive");
607
583
  var import_react_slot = require("@radix-ui/react-slot");
608
- var import_primitive5 = require("@radix-ui/primitive");
609
- var import_react_textarea_autosize2 = __toESM(require("react-textarea-autosize"));
610
- var ComposerInput = (0, import_react10.forwardRef)(({ asChild, onChange, onKeyDown, ...rest }, forwardedRef) => {
611
- const chat = useThreadContext(
612
- "Composer.Input",
613
- ({ chat: { input, handleInputChange, isLoading } }) => ({
614
- input,
615
- handleInputChange,
616
- isLoading
617
- })
618
- );
619
- const Component = asChild ? import_react_slot.Slot : import_react_textarea_autosize2.default;
620
- const composer = useComposerContext();
584
+ var import_react11 = require("react");
585
+ var import_react_textarea_autosize = __toESM(require("react-textarea-autosize"));
586
+ var ComposerInput = (0, import_react11.forwardRef)(({ asChild, disabled, onChange, onKeyDown, ...rest }, forwardedRef) => {
587
+ const { useThread } = useAssistantContext();
588
+ const isLoading = useThread((t) => t.isLoading);
589
+ const { useComposer } = useComposerContext();
590
+ const value = useComposer((c) => {
591
+ if (!c.isEditing)
592
+ return "";
593
+ return c.value;
594
+ });
595
+ const Component = asChild ? import_react_slot.Slot : import_react_textarea_autosize.default;
596
+ const composerForm = useComposerFormContext();
621
597
  const handleKeyPress = (e) => {
622
- if (chat.isLoading || rest.disabled)
598
+ if (disabled)
599
+ return;
600
+ if (e.key === "Escape") {
601
+ useComposer.getState().cancel();
602
+ }
603
+ if (isLoading)
623
604
  return;
624
605
  if (e.key === "Enter" && e.shiftKey === false) {
625
606
  e.preventDefault();
626
- composer.submit();
607
+ composerForm.submit();
627
608
  }
628
609
  };
629
610
  return /* @__PURE__ */ React.createElement(
630
611
  Component,
631
612
  {
632
- value: chat.input,
613
+ value,
633
614
  ...rest,
634
615
  ref: forwardedRef,
635
- onChange: (0, import_primitive5.composeEventHandlers)(onChange, chat.handleInputChange),
636
- onKeyDown: (0, import_primitive5.composeEventHandlers)(onKeyDown, handleKeyPress)
616
+ disabled,
617
+ onChange: (0, import_primitive4.composeEventHandlers)(onChange, (e) => {
618
+ const composerState = useComposer.getState();
619
+ if (!composerState.isEditing)
620
+ return;
621
+ return composerState.setValue(e.target.value);
622
+ }),
623
+ onKeyDown: (0, import_primitive4.composeEventHandlers)(onKeyDown, handleKeyPress)
637
624
  }
638
625
  );
639
626
  });
640
627
 
641
628
  // src/primitives/composer/ComposerSend.tsx
642
- var import_react11 = require("react");
643
629
  var import_react_primitive5 = require("@radix-ui/react-primitive");
644
- var ComposerSend = (0, import_react11.forwardRef)(
630
+ var import_react12 = require("react");
631
+ var ComposerSend = (0, import_react12.forwardRef)(
645
632
  ({ disabled, ...rest }, ref) => {
646
- const input = useThreadContext("Composer.Send", (s) => s.chat.input);
633
+ const { useComposer } = useComposerContext();
634
+ const hasValue = useComposer((c) => c.isEditing && c.value.length > 0);
647
635
  return /* @__PURE__ */ React.createElement(
648
636
  import_react_primitive5.Primitive.button,
649
637
  {
650
638
  type: "submit",
651
639
  ...rest,
652
640
  ref,
653
- disabled: disabled || input.length === 0
641
+ disabled: disabled || !hasValue
654
642
  }
655
643
  );
656
644
  }
657
645
  );
658
646
 
659
- // src/utils/createActionButton.tsx
660
- var import_react12 = require("react");
647
+ // src/primitives/composer/ComposerCancel.tsx
648
+ var import_primitive5 = require("@radix-ui/primitive");
661
649
  var import_react_primitive6 = require("@radix-ui/react-primitive");
662
- var import_primitive6 = require("@radix-ui/primitive");
663
- var createActionButton = (useActionButton) => {
664
- return (0, import_react12.forwardRef)(
665
- (props, forwardedRef) => {
666
- const onClick = useActionButton(props);
667
- return /* @__PURE__ */ React.createElement(
668
- import_react_primitive6.Primitive.button,
669
- {
670
- type: "button",
671
- disabled: !onClick,
672
- ...props,
673
- ref: forwardedRef,
674
- onClick: (0, import_primitive6.composeEventHandlers)(props.onClick, onClick ?? void 0)
675
- }
676
- );
650
+ var import_react13 = require("react");
651
+ var ComposerCancel = (0, import_react13.forwardRef)(({ disabled, onClick, ...rest }, ref) => {
652
+ const { useComposer } = useComposerContext();
653
+ const hasValue = useComposer((c) => c.canCancel);
654
+ const handleClose = () => {
655
+ useComposer.getState().cancel();
656
+ };
657
+ return /* @__PURE__ */ React.createElement(
658
+ import_react_primitive6.Primitive.button,
659
+ {
660
+ type: "button",
661
+ ...rest,
662
+ ref,
663
+ onClick: (0, import_primitive5.composeEventHandlers)(onClick, handleClose),
664
+ disabled: disabled || !hasValue
677
665
  }
678
666
  );
679
- };
680
-
681
- // src/primitives/composer/ComposerStop.tsx
682
- var useComposerStop = () => {
683
- const [isLoading, stop] = useThreadContext("Composer.Stop", (s) => [
684
- s.chat.isLoading,
685
- s.chat.stop
686
- ]);
687
- if (!isLoading)
688
- return null;
689
- return stop;
690
- };
691
- var ComposerStop = createActionButton(useComposerStop);
667
+ });
692
668
 
693
669
  // src/primitives/branchPicker/index.ts
694
670
  var branchPicker_exports = {};
@@ -702,52 +678,64 @@ __export(branchPicker_exports, {
702
678
 
703
679
  // src/actions/useGoToNextBranch.tsx
704
680
  var useGoToNextBranch = () => {
705
- const switchToBranch = useThreadContext(
706
- "BranchPicker.Next",
707
- (s) => s.chat.switchToBranch
681
+ const { useThread, useBranchObserver } = useAssistantContext();
682
+ const { useComposer, useMessage } = useMessageContext();
683
+ const isLoading = useThread((s) => s.isLoading);
684
+ const isEditing = useComposer((s) => s.isEditing);
685
+ const hasNext = useMessage(
686
+ ({ branchState: { branchId, branchCount } }) => branchId + 1 < branchCount
708
687
  );
709
- const context = useMessageContext("BranchPicker.Next", (s) => {
710
- const {
711
- message: message2,
712
- editState: { isEditing },
713
- branchState: { branchId: branchId2, branchCount }
714
- } = s;
715
- if (isEditing || branchCount <= 1 || branchId2 + 1 >= branchCount)
716
- return null;
717
- return { message: message2, branchId: branchId2 };
718
- });
719
- if (!context)
688
+ if (isLoading || isEditing || !hasNext)
720
689
  return null;
721
- const { message, branchId } = context;
722
690
  return () => {
723
- switchToBranch(message, branchId + 1);
691
+ const {
692
+ message,
693
+ branchState: { branchId }
694
+ } = useMessage.getState();
695
+ useBranchObserver.getState().switchToBranch(message, branchId + 1);
724
696
  };
725
697
  };
726
698
 
699
+ // src/utils/createActionButton.tsx
700
+ var import_react14 = require("react");
701
+ var import_react_primitive7 = require("@radix-ui/react-primitive");
702
+ var import_primitive6 = require("@radix-ui/primitive");
703
+ var createActionButton = (useActionButton) => {
704
+ return (0, import_react14.forwardRef)(
705
+ (props, forwardedRef) => {
706
+ const onClick = useActionButton(props);
707
+ return /* @__PURE__ */ React.createElement(
708
+ import_react_primitive7.Primitive.button,
709
+ {
710
+ type: "button",
711
+ disabled: !onClick,
712
+ ...props,
713
+ ref: forwardedRef,
714
+ onClick: (0, import_primitive6.composeEventHandlers)(props.onClick, onClick ?? void 0)
715
+ }
716
+ );
717
+ }
718
+ );
719
+ };
720
+
727
721
  // src/primitives/branchPicker/BranchPickerNext.tsx
728
722
  var BranchPickerNext = createActionButton(useGoToNextBranch);
729
723
 
730
724
  // src/actions/useGoToPreviousBranch.tsx
731
725
  var useGoToPreviousBranch = () => {
732
- const switchToBranch = useThreadContext(
733
- "BranchPicker.Previous",
734
- (s) => s.chat.switchToBranch
735
- );
736
- const context = useMessageContext("BranchPicker.Previous", (s) => {
737
- const {
738
- message: message2,
739
- editState: { isEditing },
740
- branchState: { branchId: branchId2, branchCount }
741
- } = s;
742
- if (isEditing || branchCount <= 1 || branchId2 <= 0)
743
- return null;
744
- return { message: message2, branchId: branchId2 };
745
- });
746
- if (!context)
726
+ const { useThread, useBranchObserver } = useAssistantContext();
727
+ const { useComposer, useMessage } = useMessageContext();
728
+ const isLoading = useThread((s) => s.isLoading);
729
+ const isEditing = useComposer((s) => s.isEditing);
730
+ const hasNext = useMessage(({ branchState: { branchId } }) => branchId > 0);
731
+ if (isLoading || isEditing || !hasNext)
747
732
  return null;
748
- const { message, branchId } = context;
749
733
  return () => {
750
- switchToBranch(message, branchId - 1);
734
+ const {
735
+ message,
736
+ branchState: { branchId }
737
+ } = useMessage.getState();
738
+ useBranchObserver.getState().switchToBranch(message, branchId - 1);
751
739
  };
752
740
  };
753
741
 
@@ -756,27 +744,23 @@ var BranchPickerPrevious = createActionButton(useGoToPreviousBranch);
756
744
 
757
745
  // src/primitives/branchPicker/BranchPickerCount.tsx
758
746
  var BranchPickerCount = () => {
759
- const branchCount = useMessageContext(
760
- "BranchPicker.Count",
761
- (s) => s.branchState.branchCount
762
- );
747
+ const { useMessage } = useMessageContext();
748
+ const branchCount = useMessage((s) => s.branchState.branchCount);
763
749
  return /* @__PURE__ */ React.createElement(React.Fragment, null, branchCount);
764
750
  };
765
751
 
766
752
  // src/primitives/branchPicker/BranchPickerNumber.tsx
767
753
  var BranchPickerNumber = () => {
768
- const branchId = useMessageContext(
769
- "BranchPicker.Number",
770
- (s) => s.branchState.branchId
771
- );
754
+ const { useMessage } = useMessageContext();
755
+ const branchId = useMessage((s) => s.branchState.branchId);
772
756
  return /* @__PURE__ */ React.createElement(React.Fragment, null, branchId + 1);
773
757
  };
774
758
 
775
759
  // src/primitives/branchPicker/BranchPickerRoot.tsx
776
- var import_react_primitive7 = require("@radix-ui/react-primitive");
777
- var import_react13 = require("react");
778
- var BranchPickerRoot = (0, import_react13.forwardRef)(({ hideWhenSingleBranch, ...rest }, ref) => {
779
- return /* @__PURE__ */ React.createElement(MessageIf, { hasBranches: hideWhenSingleBranch ? true : void 0 }, /* @__PURE__ */ React.createElement(import_react_primitive7.Primitive.div, { ...rest, ref }));
760
+ var import_react_primitive8 = require("@radix-ui/react-primitive");
761
+ var import_react15 = require("react");
762
+ var BranchPickerRoot = (0, import_react15.forwardRef)(({ hideWhenSingleBranch, ...rest }, ref) => {
763
+ return /* @__PURE__ */ React.createElement(MessageIf, { hasBranches: hideWhenSingleBranch ? true : void 0 }, /* @__PURE__ */ React.createElement(import_react_primitive8.Primitive.div, { ...rest, ref }));
780
764
  });
781
765
 
782
766
  // src/primitives/actionBar/index.ts
@@ -789,28 +773,47 @@ __export(actionBar_exports, {
789
773
  });
790
774
 
791
775
  // src/primitives/actionBar/ActionBarRoot.tsx
792
- var import_react_primitive8 = require("@radix-ui/react-primitive");
793
- var import_react14 = require("react");
794
- var ActionBarRoot = (0, import_react14.forwardRef)(({ hideWhenBusy, hideWhenNotLastOrHover, ...rest }, ref) => {
795
- return /* @__PURE__ */ React.createElement(ThreadIf, { busy: hideWhenBusy ? false : void 0 }, /* @__PURE__ */ React.createElement(MessageIf, { lastOrHover: hideWhenNotLastOrHover ? true : void 0 }, /* @__PURE__ */ React.createElement(import_react_primitive8.Primitive.div, { ...rest, ref })));
776
+ var import_react_primitive9 = require("@radix-ui/react-primitive");
777
+ var import_react16 = require("react");
778
+ var ActionBarRoot = (0, import_react16.forwardRef)(({ hideWhenBusy, autohide, autohideFloat, ...rest }, ref) => {
779
+ const { useThread } = useAssistantContext();
780
+ const { useMessage } = useMessageContext();
781
+ const hideAndfloatStatus = useMessage((m) => {
782
+ const autohideEnabled = autohide === "always" || autohide === "not-last" && !m.isLast;
783
+ if (!autohideEnabled)
784
+ return "normal" /* Normal */;
785
+ if (!m.isHovering)
786
+ return "hidden" /* Hidden */;
787
+ if (autohideFloat === "always" || autohideFloat === "single-branch" && m.branchState.branchCount <= 1)
788
+ return "floating" /* Floating */;
789
+ return "normal" /* Normal */;
790
+ });
791
+ const busy = useThread((t) => t.isLoading);
792
+ if (hideWhenBusy && busy)
793
+ return null;
794
+ if (hideAndfloatStatus === "hidden" /* Hidden */)
795
+ return null;
796
+ return /* @__PURE__ */ React.createElement(
797
+ import_react_primitive9.Primitive.div,
798
+ {
799
+ "data-floating": hideAndfloatStatus === "floating" /* Floating */,
800
+ ...rest,
801
+ ref
802
+ }
803
+ );
796
804
  });
797
805
 
798
806
  // src/actions/useCopyMessage.tsx
799
807
  var useCopyMessage = ({ copiedDuration = 3e3 }) => {
800
- const context = useMessageContext("ActionBar.Copy", (s) => {
801
- const {
802
- editState: { isEditing },
803
- message: { content: content2 },
804
- setIsCopied: setIsCopied2
805
- } = s;
806
- if (isEditing)
807
- return null;
808
- return { content: content2, setIsCopied: setIsCopied2 };
809
- });
810
- if (!context)
808
+ const { useMessage, useComposer } = useMessageContext();
809
+ const isEditing = useComposer((s) => s.isEditing);
810
+ if (isEditing)
811
811
  return null;
812
- const { content, setIsCopied } = context;
813
812
  return () => {
813
+ const {
814
+ message: { content },
815
+ setIsCopied
816
+ } = useMessage.getState();
814
817
  navigator.clipboard.writeText(content);
815
818
  setIsCopied(true);
816
819
  setTimeout(() => setIsCopied(false), copiedDuration);
@@ -822,19 +825,15 @@ var ActionBarCopy = createActionButton(useCopyMessage);
822
825
 
823
826
  // src/actions/useReloadMessage.tsx
824
827
  var useReloadMessage = () => {
825
- const [isLoading, reloadAt] = useThreadContext("ActionBar.Reload", (s) => [
826
- s.chat.isLoading,
827
- s.chat.reloadAt
828
- ]);
829
- const message = useMessageContext("ActionBar.Reload", (s) => {
830
- const message2 = s.message;
831
- if (message2.role !== "assistant" || isLoading)
832
- return null;
833
- return message2;
834
- });
835
- if (!message)
828
+ const { useThread, useBranchObserver } = useAssistantContext();
829
+ const { useMessage } = useMessageContext();
830
+ const isLoading = useThread((s) => s.isLoading);
831
+ const isAssistant = useMessage((s) => s.message.role === "assistant");
832
+ if (isLoading || !isAssistant)
836
833
  return null;
837
- return () => reloadAt(message);
834
+ return () => {
835
+ useBranchObserver.getState().reloadAt(useMessage.getState().message);
836
+ };
838
837
  };
839
838
 
840
839
  // src/primitives/actionBar/ActionBarReload.tsx
@@ -842,115 +841,137 @@ var ActionBarReload = createActionButton(useReloadMessage);
842
841
 
843
842
  // src/actions/useBeginMessageEdit.tsx
844
843
  var useBeginMessageEdit = () => {
845
- const context = useMessageContext("ActionBar.Edit", (s) => {
846
- const {
847
- message: { content: content2 },
848
- editState: { isEditing },
849
- setEditState: setEditState2
850
- } = s;
851
- if (isEditing)
852
- return null;
853
- return { content: content2, setEditState: setEditState2 };
854
- });
855
- if (!context)
844
+ const { useMessage, useComposer } = useMessageContext();
845
+ const isUser = useMessage((s) => s.message.role === "user");
846
+ const isEditing = useComposer((s) => s.isEditing);
847
+ if (!isUser || isEditing)
856
848
  return null;
857
- const { content, setEditState } = context;
858
849
  return () => {
859
- setEditState({ isEditing: true, value: content });
850
+ const { edit } = useComposer.getState();
851
+ edit();
860
852
  };
861
853
  };
862
854
 
863
855
  // src/primitives/actionBar/ActionBarEdit.tsx
864
856
  var ActionBarEdit = createActionButton(useBeginMessageEdit);
865
857
 
866
- // src/primitives/editBar/index.ts
867
- var editBar_exports = {};
868
- __export(editBar_exports, {
869
- Cancel: () => EditBarCancel,
870
- Root: () => EditBarRoot,
871
- Save: () => EditBarSave
872
- });
873
-
874
- // src/primitives/editBar/EditBarRoot.tsx
875
- var import_react_primitive9 = require("@radix-ui/react-primitive");
876
- var import_react15 = require("react");
877
- var EditBarRoot = (0, import_react15.forwardRef)(
878
- ({ ...rest }, ref) => {
879
- return /* @__PURE__ */ React.createElement(import_react_primitive9.Primitive.div, { ...rest, ref });
880
- }
881
- );
882
-
883
- // src/actions/useSaveMessageEdit.tsx
884
- var useSaveMessageEdit = () => {
885
- const chat = useThreadContext("EditBar.Save", (s) => s.chat);
886
- const context = useMessageContext("EditBar.Save", (s) => {
887
- const { message: message2, editState, setEditState: setEditState2 } = s;
888
- if (!editState.isEditing)
889
- return null;
890
- return { message: message2, content: editState.value, setEditState: setEditState2 };
891
- });
892
- if (!context)
893
- return null;
894
- const { message, content, setEditState } = context;
895
- return () => {
896
- chat.editAt(message, {
897
- ...message,
898
- id: void 0,
899
- // remove id to create a new message
900
- content
901
- });
902
- setEditState({ isEditing: false });
903
- };
904
- };
905
-
906
- // src/primitives/editBar/EditBarSave.tsx
907
- var EditBarSave = createActionButton(useSaveMessageEdit);
908
-
909
- // src/actions/useCancelMessageEdit.tsx
910
- var useCancelMessageEdit = () => {
911
- const context = useMessageContext("EditBar.Cancel", (s) => {
912
- const {
913
- editState: { isEditing },
914
- setEditState: setEditState2
915
- } = s;
916
- if (!isEditing)
917
- return null;
918
- return { setEditState: setEditState2 };
858
+ // src/vercel/VercelAIAssistantProvider.tsx
859
+ var import_react17 = require("react");
860
+ var import_zustand2 = require("zustand");
861
+ var useAIAssistantContext = () => {
862
+ const [context] = (0, import_react17.useState)(() => {
863
+ const useThread = (0, import_zustand2.create)()(() => ({
864
+ messages: [],
865
+ setMessages: () => {
866
+ },
867
+ isLoading: false,
868
+ reload: async () => {
869
+ },
870
+ append: async () => {
871
+ },
872
+ stop: () => {
873
+ }
874
+ }));
875
+ const useComposer = (0, import_zustand2.create)()(() => ({
876
+ isEditing: true,
877
+ canCancel: false,
878
+ value: "",
879
+ setValue: () => {
880
+ },
881
+ edit: () => {
882
+ throw new Error("Not implemented");
883
+ },
884
+ send: () => {
885
+ useThread.getState().append({
886
+ content: useComposer.getState().value,
887
+ role: "user",
888
+ createdAt: /* @__PURE__ */ new Date()
889
+ });
890
+ useComposer.getState().setValue("");
891
+ },
892
+ cancel: () => {
893
+ useThread.getState().stop();
894
+ }
895
+ }));
896
+ const useBranchObserver = (0, import_zustand2.create)()(() => ({
897
+ getBranchState: () => ({
898
+ branchId: 0,
899
+ branchCount: 0
900
+ }),
901
+ switchToBranch: () => {
902
+ },
903
+ editAt: async () => {
904
+ },
905
+ reloadAt: async () => {
906
+ }
907
+ }));
908
+ return { useThread, useComposer, useBranchObserver };
919
909
  });
920
- if (!context)
921
- return null;
922
- const { setEditState } = context;
923
- return () => {
924
- setEditState({ isEditing: false });
925
- };
910
+ return context;
926
911
  };
927
-
928
- // src/primitives/editBar/EditBarCancel.tsx
929
- var EditBarCancel = createActionButton(useCancelMessageEdit);
930
-
931
- // src/vercel/VercelAIThreadProvider.tsx
932
- var VercelAIThreadProvider = ({
912
+ var VercelAIAssistantProvider = ({
933
913
  chat,
934
914
  children
935
915
  }) => {
916
+ const context = useAIAssistantContext();
917
+ (0, import_react17.useMemo)(() => {
918
+ context.useThread.setState(
919
+ {
920
+ messages: chat.messages,
921
+ setMessages: (value) => {
922
+ chat.setMessages(value);
923
+ },
924
+ isLoading: chat.isLoading,
925
+ reload: async () => {
926
+ await chat.reload();
927
+ },
928
+ append: async (message) => {
929
+ await chat.append(message);
930
+ },
931
+ stop: () => {
932
+ const lastMessage = chat.messages.at(-1);
933
+ chat.stop();
934
+ if (lastMessage?.role === "user") {
935
+ chat.setInput(lastMessage.content);
936
+ }
937
+ }
938
+ },
939
+ true
940
+ );
941
+ }, [context, chat]);
942
+ (0, import_react17.useMemo)(() => {
943
+ context.useComposer.setState({
944
+ canCancel: chat.isLoading,
945
+ value: chat.input,
946
+ setValue: chat.setInput
947
+ });
948
+ }, [context, chat.isLoading, chat.input, chat.setInput]);
936
949
  const branches = useChatWithBranches(chat);
937
- return /* @__PURE__ */ React.createElement(ThreadContextProvider, { chat: branches }, children);
950
+ (0, import_react17.useMemo)(() => {
951
+ context.useBranchObserver.setState(
952
+ {
953
+ getBranchState: (message) => branches.getBranchState(message),
954
+ switchToBranch: (message, branchId) => branches.switchToBranch(message, branchId),
955
+ editAt: async (message, newMessage) => branches.editAt(message, newMessage),
956
+ reloadAt: async (message) => branches.reloadAt(message)
957
+ },
958
+ true
959
+ );
960
+ }, [context, branches]);
961
+ return /* @__PURE__ */ React.createElement(AssistantContext.Provider, { value: context }, children);
938
962
  };
939
963
  // Annotate the CommonJS export names for ESM import in node:
940
964
  0 && (module.exports = {
941
965
  ActionBarPrimitive,
942
966
  BranchPickerPrimitive,
943
967
  ComposerPrimitive,
944
- EditBarPrimitive,
945
968
  MessagePrimitive,
946
969
  ThreadPrimitive,
947
970
  VercelAIThreadProvider,
948
971
  unstable_useMessageContext,
949
972
  useBeginMessageEdit,
950
- useCancelMessageEdit,
951
973
  useCopyMessage,
952
974
  useGoToNextBranch,
953
975
  useGoToPreviousBranch,
954
- useReloadMessage,
955
- useSaveMessageEdit
976
+ useReloadMessage
956
977
  });