@assistant-ui/react 0.5.30 → 0.5.31

Sign up to get free protection for your applications and to get access to all the features.
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 = () => {