@assistant-ui/react 0.5.30 → 0.5.31

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.mjs CHANGED
@@ -113,36 +113,35 @@ function useThreadContext(options) {
113
113
 
114
114
  // src/context/stores/Composer.ts
115
115
  import { create as create3 } from "zustand";
116
-
117
- // src/context/stores/BaseComposer.ts
118
- var makeBaseComposer = (set) => ({
119
- value: "",
120
- setValue: (value) => {
121
- set({ value });
122
- }
123
- });
124
-
125
- // src/context/stores/Composer.ts
126
- var makeComposerStore = (useThreadMessages, useThreadActions) => {
116
+ var makeComposerStore = (useThreadRuntime) => {
127
117
  const focusListeners = /* @__PURE__ */ new Set();
128
- return create3()((set, get, store) => {
118
+ return create3()((_, get) => {
119
+ const runtime = useThreadRuntime.getState();
129
120
  return {
130
- ...makeBaseComposer(set, get, store),
131
- get canCancel() {
132
- return useThreadActions.getState().capabilities.cancel;
121
+ get value() {
122
+ return get().text;
123
+ },
124
+ setValue(value) {
125
+ get().setText(value);
126
+ },
127
+ text: runtime.composer.text,
128
+ setText: (value) => {
129
+ useThreadRuntime.getState().composer.setText(value);
133
130
  },
131
+ canCancel: runtime.capabilities.cancel,
134
132
  isEditing: true,
135
133
  send: () => {
136
- const { setValue, value } = get();
137
- setValue("");
138
- useThreadActions.getState().append({
139
- parentId: useThreadMessages.getState().at(-1)?.id ?? null,
134
+ const runtime2 = useThreadRuntime.getState();
135
+ const text = runtime2.composer.text;
136
+ runtime2.composer.setText("");
137
+ runtime2.append({
138
+ parentId: runtime2.messages.at(-1)?.id ?? null,
140
139
  role: "user",
141
- content: [{ type: "text", text: value }]
140
+ content: [{ type: "text", text }]
142
141
  });
143
142
  },
144
143
  cancel: () => {
145
- useThreadActions.getState().cancelRun();
144
+ useThreadRuntime.getState().cancelRun();
146
145
  },
147
146
  focus: () => {
148
147
  for (const listener of focusListeners) {
@@ -163,14 +162,10 @@ var makeComposerStore = (useThreadMessages, useThreadActions) => {
163
162
  import { create as create4 } from "zustand";
164
163
  var getThreadStateFromRuntime = (runtime) => {
165
164
  const lastMessage = runtime.messages.at(-1);
166
- if (lastMessage?.role !== "assistant")
167
- return Object.freeze({
168
- isDisabled: runtime.isDisabled,
169
- isRunning: false
170
- });
171
165
  return Object.freeze({
166
+ capabilities: runtime.capabilities,
172
167
  isDisabled: runtime.isDisabled,
173
- isRunning: lastMessage.status.type === "running"
168
+ isRunning: lastMessage?.role !== "assistant" ? false : lastMessage.status.type === "running"
174
169
  });
175
170
  };
176
171
  var makeThreadStore = (runtimeRef) => {
@@ -203,9 +198,6 @@ import { create as create6 } from "zustand";
203
198
  var makeThreadActionStore = (runtimeStore) => {
204
199
  return create6(
205
200
  () => Object.freeze({
206
- get capabilities() {
207
- return runtimeStore.getState().capabilities;
208
- },
209
201
  getBranches: (messageId) => runtimeStore.getState().getBranches(messageId),
210
202
  switchToBranch: (branchId) => runtimeStore.getState().switchToBranch(branchId),
211
203
  startRun: (parentId) => runtimeStore.getState().startRun(parentId),
@@ -258,7 +250,7 @@ var ThreadProvider = ({
258
250
  const useThreadMessages = makeThreadMessagesStore(useThreadRuntime);
259
251
  const useThreadActions = makeThreadActionStore(useThreadRuntime);
260
252
  const useViewport = makeThreadViewportStore();
261
- const useComposer = makeComposerStore(useThreadMessages, useThreadActions);
253
+ const useComposer = makeComposerStore(useThreadRuntime);
262
254
  return {
263
255
  useThread,
264
256
  useThreadRuntime,
@@ -274,15 +266,23 @@ var ThreadProvider = ({
274
266
  const onThreadUpdate = () => {
275
267
  const oldState = context.useThread.getState();
276
268
  const state = getThreadStateFromRuntime(thread);
277
- if (oldState.isDisabled !== state.isDisabled || oldState.isRunning !== state.isRunning) {
269
+ if (oldState.isDisabled !== state.isDisabled || oldState.isRunning !== state.isRunning || // TODO ensure capabilities is memoized
270
+ oldState.capabilities !== state.capabilities) {
278
271
  context.useThread.setState(
279
- getThreadStateFromRuntime(thread),
272
+ state,
280
273
  true
281
274
  );
282
275
  }
283
276
  if (thread.messages !== context.useThreadMessages.getState()) {
284
277
  context.useThreadMessages.setState(thread.messages, true);
285
278
  }
279
+ const composerState = context.useComposer.getState();
280
+ if (thread.composer.text !== composerState.text || state.capabilities.cancel !== composerState.canCancel) {
281
+ context.useComposer.setState({
282
+ text: thread.composer.text,
283
+ canCancel: state.capabilities.cancel
284
+ });
285
+ }
286
286
  };
287
287
  onThreadUpdate();
288
288
  return thread.subscribe(onThreadUpdate);
@@ -552,7 +552,7 @@ var useActionBarCopy = ({
552
552
  const callback = useCallback5(() => {
553
553
  const { message } = useMessage.getState();
554
554
  const { setIsCopied } = useMessageUtils.getState();
555
- const { isEditing, value: composerValue } = useEditComposer.getState();
555
+ const { isEditing, text: composerValue } = useEditComposer.getState();
556
556
  const valueToCopy = isEditing ? composerValue : getThreadMessageText(message);
557
557
  navigator.clipboard.writeText(valueToCopy).then(() => {
558
558
  setIsCopied(true);
@@ -680,7 +680,7 @@ var useComposerSend = () => {
680
680
  const { useComposer } = useComposerContext();
681
681
  const disabled = useCombinedStore(
682
682
  [useThread, useComposer],
683
- (t, c) => t.isRunning || !c.isEditing || c.value.length === 0
683
+ (t, c) => t.isRunning || !c.isEditing || c.text.length === 0
684
684
  );
685
685
  const callback = useCallback11(() => {
686
686
  const composerState = useComposer.getState();
@@ -799,9 +799,9 @@ var useThreadSuggestion = ({
799
799
  const composer = useComposer.getState();
800
800
  if (autoSend && !thread.isRunning) {
801
801
  append(prompt);
802
- composer.setValue("");
802
+ composer.setText("");
803
803
  } else {
804
- composer.setValue(prompt);
804
+ composer.setText(prompt);
805
805
  }
806
806
  }, [useThread, useComposer, autoSend, append, prompt]);
807
807
  if (disabled) return null;
@@ -1562,7 +1562,7 @@ var ComposerPrimitiveInput = forwardRef12(
1562
1562
  const { useComposer, type } = useComposerContext();
1563
1563
  const value = useComposer((c) => {
1564
1564
  if (!c.isEditing) return "";
1565
- return c.value;
1565
+ return c.text;
1566
1566
  });
1567
1567
  const Component = asChild ? Slot : TextareaAutosize;
1568
1568
  const isDisabled = useThread((t) => t.isDisabled) ?? disabledProp ?? false;
@@ -1613,7 +1613,7 @@ var ComposerPrimitiveInput = forwardRef12(
1613
1613
  onChange: composeEventHandlers5(onChange, (e) => {
1614
1614
  const composerState = useComposer.getState();
1615
1615
  if (!composerState.isEditing) return;
1616
- return composerState.setValue(e.target.value);
1616
+ return composerState.setText(e.target.value);
1617
1617
  }),
1618
1618
  onKeyDown: composeEventHandlers5(onKeyDown, handleKeyPress)
1619
1619
  }
@@ -1628,7 +1628,7 @@ import { Primitive as Primitive7 } from "@radix-ui/react-primitive";
1628
1628
  import { jsx as jsx21 } from "react/jsx-runtime";
1629
1629
  var ComposerPrimitiveSend = forwardRef13(({ disabled, ...rest }, ref) => {
1630
1630
  const { useComposer } = useComposerContext();
1631
- const hasValue = useComposer((c) => c.isEditing && c.value.length > 0);
1631
+ const hasValue = useComposer((c) => c.isEditing && c.text.length > 0);
1632
1632
  return /* @__PURE__ */ jsx21(
1633
1633
  Primitive7.button,
1634
1634
  {
@@ -1842,18 +1842,27 @@ import { create as create12 } from "zustand";
1842
1842
  var makeEditComposerStore = ({
1843
1843
  onEdit,
1844
1844
  onSend
1845
- }) => create12()((set, get, store) => ({
1846
- ...makeBaseComposer(set, get, store),
1845
+ }) => create12()((set, get) => ({
1846
+ get value() {
1847
+ return get().text;
1848
+ },
1849
+ setValue(value) {
1850
+ get().setText(value);
1851
+ },
1852
+ text: "",
1853
+ setText: (text) => {
1854
+ set({ text });
1855
+ },
1847
1856
  canCancel: false,
1848
1857
  isEditing: false,
1849
1858
  edit: () => {
1850
- const value = onEdit();
1851
- set({ isEditing: true, canCancel: true, value });
1859
+ const text = onEdit();
1860
+ set({ isEditing: true, canCancel: true, text });
1852
1861
  },
1853
1862
  send: () => {
1854
- const value = get().value;
1863
+ const text = get().text;
1855
1864
  set({ isEditing: false, canCancel: false });
1856
- onSend(value);
1865
+ onSend(text);
1857
1866
  },
1858
1867
  cancel: () => {
1859
1868
  set({ isEditing: false, canCancel: false });
@@ -2737,6 +2746,13 @@ var LocalThreadRuntime = class {
2737
2746
  get messages() {
2738
2747
  return this.repository.getMessages();
2739
2748
  }
2749
+ composer = {
2750
+ text: "",
2751
+ setText: (value) => {
2752
+ this.composer.text = value;
2753
+ this.notifySubscribers();
2754
+ }
2755
+ };
2740
2756
  getBranches(messageId) {
2741
2757
  return this.repository.getBranches(messageId);
2742
2758
  }
@@ -3028,34 +3044,51 @@ var ExternalStoreThreadRuntime = class {
3028
3044
  _subscriptions = /* @__PURE__ */ new Set();
3029
3045
  repository = new MessageRepository();
3030
3046
  assistantOptimisticId = null;
3047
+ _capabilities = {
3048
+ switchToBranch: false,
3049
+ edit: false,
3050
+ reload: false,
3051
+ cancel: false,
3052
+ copy: false
3053
+ };
3031
3054
  get capabilities() {
3032
- return {
3033
- switchToBranch: this._store.setMessages !== void 0,
3034
- edit: this._store.onEdit !== void 0,
3035
- reload: this._store.onReload !== void 0,
3036
- cancel: this._store.onCancel !== void 0,
3037
- copy: this._store.onCopy !== null
3038
- };
3055
+ return this._capabilities;
3039
3056
  }
3040
3057
  messages = [];
3041
3058
  isDisabled = false;
3042
3059
  converter = new ThreadMessageConverter();
3043
3060
  _store;
3061
+ composer = {
3062
+ text: "",
3063
+ setText: (value) => {
3064
+ this.composer.text = value;
3065
+ this.notifySubscribers();
3066
+ }
3067
+ };
3044
3068
  constructor(store) {
3045
3069
  this.store = store;
3046
3070
  }
3047
3071
  set store(store) {
3072
+ if (this._store === store) return;
3073
+ const isRunning = store.isRunning ?? false;
3074
+ this.isDisabled = store.isDisabled ?? false;
3048
3075
  const oldStore = this._store;
3076
+ this._store = store;
3077
+ this._capabilities = {
3078
+ switchToBranch: this._store.setMessages !== void 0,
3079
+ edit: this._store.onEdit !== void 0,
3080
+ reload: this._store.onReload !== void 0,
3081
+ cancel: this._store.onCancel !== void 0,
3082
+ copy: this._store.onCopy !== null
3083
+ };
3049
3084
  if (oldStore) {
3050
3085
  if (oldStore.convertMessage !== store.convertMessage) {
3051
3086
  this.converter = new ThreadMessageConverter();
3052
- } else if (oldStore.isDisabled === store.isDisabled && oldStore.isRunning === store.isRunning && oldStore.messages === store.messages) {
3087
+ } else if (oldStore.isRunning === store.isRunning && oldStore.messages === store.messages) {
3088
+ this.notifySubscribers();
3053
3089
  return;
3054
3090
  }
3055
3091
  }
3056
- this._store = store;
3057
- const isRunning = store.isRunning ?? false;
3058
- const isDisabled = store.isDisabled ?? false;
3059
3092
  const convertCallback = (cache, m, idx) => {
3060
3093
  if (!store.convertMessage) return m;
3061
3094
  const isLast = idx === store.messages.length - 1;
@@ -3096,7 +3129,9 @@ var ExternalStoreThreadRuntime = class {
3096
3129
  this.assistantOptimisticId ?? messages.at(-1)?.id ?? null
3097
3130
  );
3098
3131
  this.messages = this.repository.getMessages();
3099
- this.isDisabled = isDisabled;
3132
+ this.notifySubscribers();
3133
+ }
3134
+ notifySubscribers() {
3100
3135
  for (const callback of this._subscriptions) callback();
3101
3136
  }
3102
3137
  getBranches(messageId) {
@@ -3221,14 +3256,14 @@ import { CheckIcon, CopyIcon, RefreshCwIcon } from "lucide-react";
3221
3256
  import { Fragment as Fragment4, jsx as jsx31, jsxs as jsxs5 } from "react/jsx-runtime";
3222
3257
  var useAllowCopy = () => {
3223
3258
  const { assistantMessage: { allowCopy = true } = {} } = useThreadConfig();
3224
- const { useThreadActions } = useThreadContext();
3225
- const copySupported = useThreadActions((t) => t.capabilities.copy);
3259
+ const { useThread } = useThreadContext();
3260
+ const copySupported = useThread((t) => t.capabilities.copy);
3226
3261
  return copySupported && allowCopy;
3227
3262
  };
3228
3263
  var useAllowReload = () => {
3229
3264
  const { assistantMessage: { allowReload = true } = {} } = useThreadConfig();
3230
- const { useThreadActions } = useThreadContext();
3231
- const reloadSupported = useThreadActions((t) => t.capabilities.reload);
3265
+ const { useThread } = useThreadContext();
3266
+ const reloadSupported = useThread((t) => t.capabilities.reload);
3232
3267
  return reloadSupported && allowReload;
3233
3268
  };
3234
3269
  var AssistantActionBar = () => {
@@ -3297,8 +3332,8 @@ import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
3297
3332
  import { jsx as jsx32, jsxs as jsxs6 } from "react/jsx-runtime";
3298
3333
  var useAllowBranchPicker = () => {
3299
3334
  const { branchPicker: { allowBranchPicker = true } = {} } = useThreadConfig();
3300
- const { useThreadActions } = useThreadContext();
3301
- const branchPickerSupported = useThreadActions((t) => t.capabilities.edit);
3335
+ const { useThread } = useThreadContext();
3336
+ const branchPickerSupported = useThread((t) => t.capabilities.edit);
3302
3337
  return branchPickerSupported && allowBranchPicker;
3303
3338
  };
3304
3339
  var BranchPicker = () => {
@@ -3458,6 +3493,8 @@ var CircleStopIcon = () => {
3458
3493
  xmlns: "http://www.w3.org/2000/svg",
3459
3494
  viewBox: "0 0 16 16",
3460
3495
  fill: "currentColor",
3496
+ width: "16",
3497
+ height: "16",
3461
3498
  children: /* @__PURE__ */ jsx36("rect", { width: "10", height: "10", x: "3", y: "3", rx: "2" })
3462
3499
  }
3463
3500
  );
@@ -3494,8 +3531,8 @@ var ComposerInput = forwardRef22(
3494
3531
  );
3495
3532
  ComposerInput.displayName = "ComposerInput";
3496
3533
  var useAllowCancel = () => {
3497
- const { useThreadActions } = useThreadContext();
3498
- const cancelSupported = useThreadActions((t) => t.capabilities.cancel);
3534
+ const { useThread } = useThreadContext();
3535
+ const cancelSupported = useThread((t) => t.capabilities.cancel);
3499
3536
  return cancelSupported;
3500
3537
  };
3501
3538
  var ComposerAction = () => {
@@ -3621,8 +3658,8 @@ import { PencilIcon } from "lucide-react";
3621
3658
  import { jsx as jsx39 } from "react/jsx-runtime";
3622
3659
  var useAllowEdit = () => {
3623
3660
  const { userMessage: { allowEdit = true } = {} } = useThreadConfig();
3624
- const { useThreadActions } = useThreadContext();
3625
- const editSupported = useThreadActions((t) => t.capabilities.edit);
3661
+ const { useThread } = useThreadContext();
3662
+ const editSupported = useThread((t) => t.capabilities.edit);
3626
3663
  return editSupported && allowEdit;
3627
3664
  };
3628
3665
  var UserActionBar = () => {