@assistant-ui/react 0.0.4 → 0.0.5

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
@@ -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
  });