@assistant-ui/react 0.0.9 → 0.0.10
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.d.mts +10 -10
- package/dist/index.d.ts +10 -10
- package/dist/index.js +131 -95
- package/dist/index.mjs +134 -96
- package/package.json +1 -1
    
        package/dist/index.d.mts
    CHANGED
    
    | @@ -21,7 +21,7 @@ type RequireAtLeastOne<T, Keys extends keyof T = keyof T> = Pick<T, Exclude<keyo | |
| 21 21 |  | 
| 22 22 | 
             
            type ThreadIfFilters = {
         | 
| 23 23 | 
             
                empty: boolean | undefined;
         | 
| 24 | 
            -
                 | 
| 24 | 
            +
                running: boolean | undefined;
         | 
| 25 25 | 
             
            };
         | 
| 26 26 | 
             
            type ThreadIfProps = PropsWithChildren<RequireAtLeastOne<ThreadIfFilters>>;
         | 
| 27 27 | 
             
            declare const ThreadIf: FC<ThreadIfProps>;
         | 
| @@ -91,17 +91,16 @@ declare namespace index$3 { | |
| 91 91 | 
             
              export { ComposerCancel as Cancel, ComposerIf as If, ComposerInput as Input, ComposerRoot as Root, ComposerSend as Send };
         | 
| 92 92 | 
             
            }
         | 
| 93 93 |  | 
| 94 | 
            -
            type  | 
| 94 | 
            +
            type BaseComposerState = {
         | 
| 95 | 
            +
                value: string;
         | 
| 96 | 
            +
                setValue: (value: string) => void;
         | 
| 97 | 
            +
            };
         | 
| 98 | 
            +
            type MessageComposerState = BaseComposerState & {
         | 
| 95 99 | 
             
                isEditing: boolean;
         | 
| 96 | 
            -
                canCancel:  | 
| 100 | 
            +
                canCancel: true;
         | 
| 97 101 | 
             
                edit: () => void;
         | 
| 98 102 | 
             
                send: () => void;
         | 
| 99 103 | 
             
                cancel: () => void;
         | 
| 100 | 
            -
                value: string;
         | 
| 101 | 
            -
                setValue: (value: string) => void;
         | 
| 102 | 
            -
            };
         | 
| 103 | 
            -
            type ComposerStore = {
         | 
| 104 | 
            -
                useComposer: UseBoundStore<StoreApi<ComposerState>>;
         | 
| 105 104 | 
             
            };
         | 
| 106 105 |  | 
| 107 106 | 
             
            type ThreadMessageTextPart = {
         | 
| @@ -226,7 +225,7 @@ declare const ActionBarRoot: react.ForwardRefExoticComponent<Pick<Omit<react.Det | |
| 226 225 | 
             
            } & {
         | 
| 227 226 | 
             
                asChild?: boolean;
         | 
| 228 227 | 
             
            }, "key" | keyof react.HTMLAttributes<HTMLDivElement> | "asChild"> & {
         | 
| 229 | 
            -
                 | 
| 228 | 
            +
                hideWhenRunning?: boolean;
         | 
| 230 229 | 
             
                autohide?: "always" | "not-last" | "never";
         | 
| 231 230 | 
             
                autohideFloat?: "always" | "single-branch" | "never";
         | 
| 232 231 | 
             
            } & react.RefAttributes<HTMLDivElement>>;
         | 
| @@ -283,8 +282,9 @@ type MessageState = { | |
| 283 282 | 
             
                isHovering: boolean;
         | 
| 284 283 | 
             
                setIsHovering: (value: boolean) => void;
         | 
| 285 284 | 
             
            };
         | 
| 286 | 
            -
            type MessageStore =  | 
| 285 | 
            +
            type MessageStore = {
         | 
| 287 286 | 
             
                useMessage: UseBoundStore<StoreApi<MessageState>>;
         | 
| 287 | 
            +
                useComposer: UseBoundStore<StoreApi<MessageComposerState>>;
         | 
| 288 288 | 
             
            };
         | 
| 289 289 |  | 
| 290 290 | 
             
            declare const useMessageContext: () => MessageStore;
         | 
    
        package/dist/index.d.ts
    CHANGED
    
    | @@ -21,7 +21,7 @@ type RequireAtLeastOne<T, Keys extends keyof T = keyof T> = Pick<T, Exclude<keyo | |
| 21 21 |  | 
| 22 22 | 
             
            type ThreadIfFilters = {
         | 
| 23 23 | 
             
                empty: boolean | undefined;
         | 
| 24 | 
            -
                 | 
| 24 | 
            +
                running: boolean | undefined;
         | 
| 25 25 | 
             
            };
         | 
| 26 26 | 
             
            type ThreadIfProps = PropsWithChildren<RequireAtLeastOne<ThreadIfFilters>>;
         | 
| 27 27 | 
             
            declare const ThreadIf: FC<ThreadIfProps>;
         | 
| @@ -91,17 +91,16 @@ declare namespace index$3 { | |
| 91 91 | 
             
              export { ComposerCancel as Cancel, ComposerIf as If, ComposerInput as Input, ComposerRoot as Root, ComposerSend as Send };
         | 
| 92 92 | 
             
            }
         | 
| 93 93 |  | 
| 94 | 
            -
            type  | 
| 94 | 
            +
            type BaseComposerState = {
         | 
| 95 | 
            +
                value: string;
         | 
| 96 | 
            +
                setValue: (value: string) => void;
         | 
| 97 | 
            +
            };
         | 
| 98 | 
            +
            type MessageComposerState = BaseComposerState & {
         | 
| 95 99 | 
             
                isEditing: boolean;
         | 
| 96 | 
            -
                canCancel:  | 
| 100 | 
            +
                canCancel: true;
         | 
| 97 101 | 
             
                edit: () => void;
         | 
| 98 102 | 
             
                send: () => void;
         | 
| 99 103 | 
             
                cancel: () => void;
         | 
| 100 | 
            -
                value: string;
         | 
| 101 | 
            -
                setValue: (value: string) => void;
         | 
| 102 | 
            -
            };
         | 
| 103 | 
            -
            type ComposerStore = {
         | 
| 104 | 
            -
                useComposer: UseBoundStore<StoreApi<ComposerState>>;
         | 
| 105 104 | 
             
            };
         | 
| 106 105 |  | 
| 107 106 | 
             
            type ThreadMessageTextPart = {
         | 
| @@ -226,7 +225,7 @@ declare const ActionBarRoot: react.ForwardRefExoticComponent<Pick<Omit<react.Det | |
| 226 225 | 
             
            } & {
         | 
| 227 226 | 
             
                asChild?: boolean;
         | 
| 228 227 | 
             
            }, "key" | keyof react.HTMLAttributes<HTMLDivElement> | "asChild"> & {
         | 
| 229 | 
            -
                 | 
| 228 | 
            +
                hideWhenRunning?: boolean;
         | 
| 230 229 | 
             
                autohide?: "always" | "not-last" | "never";
         | 
| 231 230 | 
             
                autohideFloat?: "always" | "single-branch" | "never";
         | 
| 232 231 | 
             
            } & react.RefAttributes<HTMLDivElement>>;
         | 
| @@ -283,8 +282,9 @@ type MessageState = { | |
| 283 282 | 
             
                isHovering: boolean;
         | 
| 284 283 | 
             
                setIsHovering: (value: boolean) => void;
         | 
| 285 284 | 
             
            };
         | 
| 286 | 
            -
            type MessageStore =  | 
| 285 | 
            +
            type MessageStore = {
         | 
| 287 286 | 
             
                useMessage: UseBoundStore<StoreApi<MessageState>>;
         | 
| 287 | 
            +
                useComposer: UseBoundStore<StoreApi<MessageComposerState>>;
         | 
| 288 288 | 
             
            };
         | 
| 289 289 |  | 
| 290 290 | 
             
            declare const useMessageContext: () => MessageStore;
         | 
    
        package/dist/index.js
    CHANGED
    
    | @@ -86,9 +86,9 @@ var useThreadIf = (props) => { | |
| 86 86 | 
             
                  return false;
         | 
| 87 87 | 
             
                if (props.empty === false && thread.messages.length === 0)
         | 
| 88 88 | 
             
                  return false;
         | 
| 89 | 
            -
                if (props. | 
| 89 | 
            +
                if (props.running === true && !thread.isRunning)
         | 
| 90 90 | 
             
                  return false;
         | 
| 91 | 
            -
                if (props. | 
| 91 | 
            +
                if (props.running === false && thread.isRunning)
         | 
| 92 92 | 
             
                  return false;
         | 
| 93 93 | 
             
                return true;
         | 
| 94 94 | 
             
              });
         | 
| @@ -153,12 +153,12 @@ var import_react4 = require("react"); | |
| 153 153 | 
             
            var useOnScrollToBottom = (callback) => {
         | 
| 154 154 | 
             
              const callbackRef = (0, import_react4.useRef)(callback);
         | 
| 155 155 | 
             
              callbackRef.current = callback;
         | 
| 156 | 
            -
              const {  | 
| 156 | 
            +
              const { useViewport } = useAssistantContext();
         | 
| 157 157 | 
             
              (0, import_react4.useEffect)(() => {
         | 
| 158 | 
            -
                return  | 
| 158 | 
            +
                return useViewport.getState().onScrollToBottom(() => {
         | 
| 159 159 | 
             
                  callbackRef.current();
         | 
| 160 160 | 
             
                });
         | 
| 161 | 
            -
              }, [ | 
| 161 | 
            +
              }, [useViewport]);
         | 
| 162 162 | 
             
            };
         | 
| 163 163 |  | 
| 164 164 | 
             
            // src/primitives/thread/ThreadViewport.tsx
         | 
| @@ -166,7 +166,7 @@ var ThreadViewport = (0, import_react5.forwardRef)(({ autoScroll = true, onScrol | |
| 166 166 | 
             
              const messagesEndRef = (0, import_react5.useRef)(null);
         | 
| 167 167 | 
             
              const divRef = (0, import_react5.useRef)(null);
         | 
| 168 168 | 
             
              const ref = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, divRef);
         | 
| 169 | 
            -
              const {  | 
| 169 | 
            +
              const { useViewport } = useAssistantContext();
         | 
| 170 170 | 
             
              const firstRenderRef = (0, import_react5.useRef)(true);
         | 
| 171 171 | 
             
              const lastScrollTop = (0, import_react5.useRef)(0);
         | 
| 172 172 | 
             
              const scrollToBottom = () => {
         | 
| @@ -175,11 +175,11 @@ var ThreadViewport = (0, import_react5.forwardRef)(({ autoScroll = true, onScrol | |
| 175 175 | 
             
                  return;
         | 
| 176 176 | 
             
                const behavior = firstRenderRef.current ? "instant" : "auto";
         | 
| 177 177 | 
             
                firstRenderRef.current = false;
         | 
| 178 | 
            -
                 | 
| 178 | 
            +
                useViewport.setState({ isAtBottom: true });
         | 
| 179 179 | 
             
                div.scrollIntoView({ behavior });
         | 
| 180 180 | 
             
              };
         | 
| 181 181 | 
             
              useOnResizeContent(divRef, () => {
         | 
| 182 | 
            -
                if (! | 
| 182 | 
            +
                if (!useViewport.getState().isAtBottom)
         | 
| 183 183 | 
             
                  return;
         | 
| 184 184 | 
             
                scrollToBottom();
         | 
| 185 185 | 
             
              });
         | 
| @@ -190,11 +190,11 @@ var ThreadViewport = (0, import_react5.forwardRef)(({ autoScroll = true, onScrol | |
| 190 190 | 
             
                const div = divRef.current;
         | 
| 191 191 | 
             
                if (!div)
         | 
| 192 192 | 
             
                  return;
         | 
| 193 | 
            -
                const isAtBottom =  | 
| 193 | 
            +
                const isAtBottom = useViewport.getState().isAtBottom;
         | 
| 194 194 | 
             
                const newIsAtBottom = div.scrollHeight - div.scrollTop <= div.clientHeight;
         | 
| 195 195 | 
             
                if (!newIsAtBottom && lastScrollTop.current < div.scrollTop) {
         | 
| 196 196 | 
             
                } else if (newIsAtBottom !== isAtBottom) {
         | 
| 197 | 
            -
                   | 
| 197 | 
            +
                  useViewport.setState({ isAtBottom: newIsAtBottom });
         | 
| 198 198 | 
             
                }
         | 
| 199 199 | 
             
                lastScrollTop.current = div.scrollTop;
         | 
| 200 200 | 
             
              };
         | 
| @@ -310,13 +310,13 @@ var useVercelAIBranches = (chat, context) => { | |
| 310 310 | 
             
                [data, chat.messages, chat.setMessages]
         | 
| 311 311 | 
             
              );
         | 
| 312 312 | 
             
              const reloadMaybe = "reload" in chat ? chat.reload : void 0;
         | 
| 313 | 
            -
              const  | 
| 314 | 
            -
                async ( | 
| 313 | 
            +
              const startRun = (0, import_react6.useCallback)(
         | 
| 314 | 
            +
                async (parentId) => {
         | 
| 315 315 | 
             
                  if (!reloadMaybe)
         | 
| 316 316 | 
             
                    throw new Error("Reload not supported by Vercel AI SDK's useAssistant");
         | 
| 317 | 
            -
                  const newMessages = sliceMessagesUntil(chat.messages,  | 
| 317 | 
            +
                  const newMessages = sliceMessagesUntil(chat.messages, parentId);
         | 
| 318 318 | 
             
                  chat.setMessages(newMessages);
         | 
| 319 | 
            -
                  context. | 
| 319 | 
            +
                  context.useViewport.getState().scrollToBottom();
         | 
| 320 320 | 
             
                  await reloadMaybe();
         | 
| 321 321 | 
             
                },
         | 
| 322 322 | 
             
                [context, chat.messages, chat.setMessages, reloadMaybe]
         | 
| @@ -327,7 +327,7 @@ var useVercelAIBranches = (chat, context) => { | |
| 327 327 | 
             
                  chat.setMessages(newMessages);
         | 
| 328 328 | 
             
                  if (message.content.length !== 1 || message.content[0]?.type !== "text")
         | 
| 329 329 | 
             
                    throw new Error("Only text content is currently supported");
         | 
| 330 | 
            -
                  context. | 
| 330 | 
            +
                  context.useViewport.getState().scrollToBottom();
         | 
| 331 331 | 
             
                  await chat.append({
         | 
| 332 332 | 
             
                    role: "user",
         | 
| 333 333 | 
             
                    content: message.content[0].text
         | 
| @@ -340,13 +340,13 @@ var useVercelAIBranches = (chat, context) => { | |
| 340 340 | 
             
                  getBranchState,
         | 
| 341 341 | 
             
                  switchToBranch,
         | 
| 342 342 | 
             
                  append,
         | 
| 343 | 
            -
                   | 
| 343 | 
            +
                  startRun
         | 
| 344 344 | 
             
                }),
         | 
| 345 | 
            -
                [getBranchState, switchToBranch, append,  | 
| 345 | 
            +
                [getBranchState, switchToBranch, append, startRun]
         | 
| 346 346 | 
             
              );
         | 
| 347 347 | 
             
            };
         | 
| 348 348 | 
             
            var hasUpcomingMessage = (thread) => {
         | 
| 349 | 
            -
              return thread. | 
| 349 | 
            +
              return thread.isRunning && thread.messages[thread.messages.length - 1]?.role !== "assistant";
         | 
| 350 350 | 
             
            };
         | 
| 351 351 |  | 
| 352 352 | 
             
            // src/utils/context/useComposerContext.ts
         | 
| @@ -399,7 +399,54 @@ __export(message_exports, { | |
| 399 399 |  | 
| 400 400 | 
             
            // src/primitives/message/MessageProvider.tsx
         | 
| 401 401 | 
             
            var import_react9 = require("react");
         | 
| 402 | 
            +
            var import_zustand2 = require("zustand");
         | 
| 403 | 
            +
             | 
| 404 | 
            +
            // src/utils/context/stores/ComposerStore.ts
         | 
| 402 405 | 
             
            var import_zustand = require("zustand");
         | 
| 406 | 
            +
            var makeBaseComposer = (set) => ({
         | 
| 407 | 
            +
              value: "",
         | 
| 408 | 
            +
              setValue: (value) => {
         | 
| 409 | 
            +
                set({ value });
         | 
| 410 | 
            +
              }
         | 
| 411 | 
            +
            });
         | 
| 412 | 
            +
            var makeMessageComposerStore = ({
         | 
| 413 | 
            +
              onEdit,
         | 
| 414 | 
            +
              onSend
         | 
| 415 | 
            +
            }) => (0, import_zustand.create)()((set, get, store) => ({
         | 
| 416 | 
            +
              ...makeBaseComposer(set, get, store),
         | 
| 417 | 
            +
              canCancel: true,
         | 
| 418 | 
            +
              isEditing: false,
         | 
| 419 | 
            +
              edit: () => {
         | 
| 420 | 
            +
                const value = onEdit();
         | 
| 421 | 
            +
                set({ isEditing: true, value });
         | 
| 422 | 
            +
              },
         | 
| 423 | 
            +
              send: () => {
         | 
| 424 | 
            +
                const value = get().value;
         | 
| 425 | 
            +
                set({ isEditing: false });
         | 
| 426 | 
            +
                return onSend(value);
         | 
| 427 | 
            +
              },
         | 
| 428 | 
            +
              cancel: () => {
         | 
| 429 | 
            +
                set({ isEditing: false });
         | 
| 430 | 
            +
              }
         | 
| 431 | 
            +
            }));
         | 
| 432 | 
            +
            var makeThreadComposerStore = ({
         | 
| 433 | 
            +
              onSend,
         | 
| 434 | 
            +
              onCancel
         | 
| 435 | 
            +
            }) => (0, import_zustand.create)()((set, get, store) => ({
         | 
| 436 | 
            +
              ...makeBaseComposer(set, get, store),
         | 
| 437 | 
            +
              isEditing: true,
         | 
| 438 | 
            +
              canCancel: false,
         | 
| 439 | 
            +
              send: () => {
         | 
| 440 | 
            +
                const value = get().value;
         | 
| 441 | 
            +
                set({ value: "", canCancel: true });
         | 
| 442 | 
            +
                onSend(value).then(() => {
         | 
| 443 | 
            +
                  set({ canCancel: false });
         | 
| 444 | 
            +
                });
         | 
| 445 | 
            +
              },
         | 
| 446 | 
            +
              cancel: onCancel
         | 
| 447 | 
            +
            }));
         | 
| 448 | 
            +
             | 
| 449 | 
            +
            // src/primitives/message/MessageProvider.tsx
         | 
| 403 450 | 
             
            var getIsLast = (thread, message) => {
         | 
| 404 451 | 
             
              const hasUpcoming = hasUpcomingMessage(thread);
         | 
| 405 452 | 
             
              return hasUpcoming ? message.id === UPCOMING_MESSAGE_ID : thread.messages[thread.messages.length - 1]?.id === message.id;
         | 
| @@ -407,7 +454,7 @@ var getIsLast = (thread, message) => { | |
| 407 454 | 
             
            var useMessageContext2 = () => {
         | 
| 408 455 | 
             
              const [context] = (0, import_react9.useState)(() => {
         | 
| 409 456 | 
             
                const { useThread } = useAssistantContext();
         | 
| 410 | 
            -
                const useMessage = (0,  | 
| 457 | 
            +
                const useMessage = (0, import_zustand2.create)(() => ({
         | 
| 411 458 | 
             
                  message: null,
         | 
| 412 459 | 
             
                  isLast: false,
         | 
| 413 460 | 
             
                  isCopied: false,
         | 
| @@ -417,34 +464,23 @@ var useMessageContext2 = () => { | |
| 417 464 | 
             
                  setIsHovering: () => {
         | 
| 418 465 | 
             
                  }
         | 
| 419 466 | 
             
                }));
         | 
| 420 | 
            -
                const useComposer = ( | 
| 421 | 
            -
                   | 
| 422 | 
            -
                  canCancel: true,
         | 
| 423 | 
            -
                  edit: () => {
         | 
| 467 | 
            +
                const useComposer = makeMessageComposerStore({
         | 
| 468 | 
            +
                  onEdit: () => {
         | 
| 424 469 | 
             
                    const message = useMessage.getState().message;
         | 
| 425 470 | 
             
                    if (message.role !== "user")
         | 
| 426 471 | 
             
                      throw new Error("Editing is only supported for user messages");
         | 
| 427 472 | 
             
                    if (message.content[0]?.type !== "text")
         | 
| 428 473 | 
             
                      throw new Error("Editing is only supported for text-only messages");
         | 
| 429 | 
            -
                    return  | 
| 430 | 
            -
                      isEditing: true,
         | 
| 431 | 
            -
                      value: message.content[0].text
         | 
| 432 | 
            -
                    });
         | 
| 474 | 
            +
                    return message.content[0].text;
         | 
| 433 475 | 
             
                  },
         | 
| 434 | 
            -
                   | 
| 435 | 
            -
                  send: () => {
         | 
| 476 | 
            +
                  onSend: (text) => {
         | 
| 436 477 | 
             
                    const message = useMessage.getState().message;
         | 
| 437 | 
            -
                     | 
| 438 | 
            -
                      throw new Error("Editing is only supported for user messages");
         | 
| 439 | 
            -
                    useThread.getState().append({
         | 
| 478 | 
            +
                    return useThread.getState().append({
         | 
| 440 479 | 
             
                      parentId: message.parentId,
         | 
| 441 | 
            -
                      content: [{ type: "text", text | 
| 480 | 
            +
                      content: [{ type: "text", text }]
         | 
| 442 481 | 
             
                    });
         | 
| 443 | 
            -
             | 
| 444 | 
            -
             | 
| 445 | 
            -
                  value: "",
         | 
| 446 | 
            -
                  setValue: (value) => set({ value })
         | 
| 447 | 
            -
                }));
         | 
| 482 | 
            +
                  }
         | 
| 483 | 
            +
                });
         | 
| 448 484 | 
             
                return { useMessage, useComposer };
         | 
| 449 485 | 
             
              });
         | 
| 450 486 | 
             
              return context;
         | 
| @@ -605,11 +641,10 @@ var import_primitive3 = require("@radix-ui/primitive"); | |
| 605 641 | 
             
            var import_react_primitive4 = require("@radix-ui/react-primitive");
         | 
| 606 642 | 
             
            var import_react11 = require("react");
         | 
| 607 643 | 
             
            var ThreadScrollToBottom = (0, import_react11.forwardRef)(({ onClick, ...rest }, ref) => {
         | 
| 608 | 
            -
              const {  | 
| 609 | 
            -
              const isAtBottom =  | 
| 644 | 
            +
              const { useViewport } = useAssistantContext();
         | 
| 645 | 
            +
              const isAtBottom = useViewport((s) => s.isAtBottom);
         | 
| 610 646 | 
             
              const handleScrollToBottom = () => {
         | 
| 611 | 
            -
                 | 
| 612 | 
            -
                thread.scrollToBottom();
         | 
| 647 | 
            +
                useViewport.getState().scrollToBottom();
         | 
| 613 648 | 
             
              };
         | 
| 614 649 | 
             
              return /* @__PURE__ */ React.createElement(
         | 
| 615 650 | 
             
                import_react_primitive4.Primitive.button,
         | 
| @@ -685,8 +720,8 @@ var ComposerInput = (0, import_react13.forwardRef)( | |
| 685 720 | 
             
                    useComposer.getState().cancel();
         | 
| 686 721 | 
             
                  }
         | 
| 687 722 | 
             
                  if (e.key === "Enter" && e.shiftKey === false) {
         | 
| 688 | 
            -
                    const  | 
| 689 | 
            -
                    if (! | 
| 723 | 
            +
                    const isRunning = useThread.getState().isRunning;
         | 
| 724 | 
            +
                    if (!isRunning) {
         | 
| 690 725 | 
             
                      e.preventDefault();
         | 
| 691 726 | 
             
                      composer.send();
         | 
| 692 727 | 
             
                    }
         | 
| @@ -813,7 +848,7 @@ var useGoToNextBranch = () => { | |
| 813 848 | 
             
              const { useComposer, useMessage } = useMessageContext();
         | 
| 814 849 | 
             
              const disabled = useCombinedStore(
         | 
| 815 850 | 
             
                [useThread, useComposer, useMessage],
         | 
| 816 | 
            -
                (t, c, m) => t. | 
| 851 | 
            +
                (t, c, m) => t.isRunning || c.isEditing || m.message.branchId + 1 >= m.message.branchCount
         | 
| 817 852 | 
             
              );
         | 
| 818 853 | 
             
              if (disabled)
         | 
| 819 854 | 
             
                return null;
         | 
| @@ -854,7 +889,7 @@ var useGoToPreviousBranch = () => { | |
| 854 889 | 
             
              const { useComposer, useMessage } = useMessageContext();
         | 
| 855 890 | 
             
              const disabled = useCombinedStore(
         | 
| 856 891 | 
             
                [useThread, useComposer, useMessage],
         | 
| 857 | 
            -
                (t, c, m) => t. | 
| 892 | 
            +
                (t, c, m) => t.isRunning || c.isEditing || m.message.branchId <= 0
         | 
| 858 893 | 
             
              );
         | 
| 859 894 | 
             
              if (disabled)
         | 
| 860 895 | 
             
                return null;
         | 
| @@ -900,13 +935,13 @@ __export(actionBar_exports, { | |
| 900 935 | 
             
            // src/primitives/actionBar/ActionBarRoot.tsx
         | 
| 901 936 | 
             
            var import_react_primitive10 = require("@radix-ui/react-primitive");
         | 
| 902 937 | 
             
            var import_react20 = require("react");
         | 
| 903 | 
            -
            var ActionBarRoot = (0, import_react20.forwardRef)(({  | 
| 938 | 
            +
            var ActionBarRoot = (0, import_react20.forwardRef)(({ hideWhenRunning, autohide, autohideFloat, ...rest }, ref) => {
         | 
| 904 939 | 
             
              const { useThread } = useAssistantContext();
         | 
| 905 940 | 
             
              const { useMessage } = useMessageContext();
         | 
| 906 941 | 
             
              const hideAndfloatStatus = useCombinedStore(
         | 
| 907 942 | 
             
                [useThread, useMessage],
         | 
| 908 943 | 
             
                (t, m) => {
         | 
| 909 | 
            -
                  if ( | 
| 944 | 
            +
                  if (hideWhenRunning && t.isRunning)
         | 
| 910 945 | 
             
                    return "hidden" /* Hidden */;
         | 
| 911 946 | 
             
                  const autohideEnabled = autohide === "always" || autohide === "not-last" && !m.isLast;
         | 
| 912 947 | 
             
                  if (!autohideEnabled)
         | 
| @@ -955,7 +990,7 @@ var useReloadMessage = () => { | |
| 955 990 | 
             
              const { useMessage } = useMessageContext();
         | 
| 956 991 | 
             
              const disabled = useCombinedStore(
         | 
| 957 992 | 
             
                [useThread, useMessage],
         | 
| 958 | 
            -
                (t, m) => t. | 
| 993 | 
            +
                (t, m) => t.isRunning || m.message.role !== "assistant"
         | 
| 959 994 | 
             
              );
         | 
| 960 995 | 
             
              if (disabled)
         | 
| 961 996 | 
             
                return null;
         | 
| @@ -963,7 +998,7 @@ var useReloadMessage = () => { | |
| 963 998 | 
             
                const message = useMessage.getState().message;
         | 
| 964 999 | 
             
                if (message.role !== "assistant")
         | 
| 965 1000 | 
             
                  throw new Error("Reloading is only supported on assistant messages");
         | 
| 966 | 
            -
                useThread.getState(). | 
| 1001 | 
            +
                useThread.getState().startRun(message.parentId);
         | 
| 967 1002 | 
             
              };
         | 
| 968 1003 | 
             
            };
         | 
| 969 1004 |  | 
| @@ -993,60 +1028,61 @@ var import_react22 = require("react"); | |
| 993 1028 |  | 
| 994 1029 | 
             
            // src/adapters/vercel/useDummyAIAssistantContext.tsx
         | 
| 995 1030 | 
             
            var import_react21 = require("react");
         | 
| 996 | 
            -
            var  | 
| 1031 | 
            +
            var import_zustand4 = require("zustand");
         | 
| 1032 | 
            +
             | 
| 1033 | 
            +
            // src/utils/context/stores/ViewportStore.tsx
         | 
| 1034 | 
            +
            var import_zustand3 = require("zustand");
         | 
| 1035 | 
            +
            var makeViewportStore = () => {
         | 
| 1036 | 
            +
              const scrollToBottomListeners = /* @__PURE__ */ new Set();
         | 
| 1037 | 
            +
              return (0, import_zustand3.create)(() => ({
         | 
| 1038 | 
            +
                isAtBottom: true,
         | 
| 1039 | 
            +
                scrollToBottom: () => {
         | 
| 1040 | 
            +
                  for (const listener of scrollToBottomListeners) {
         | 
| 1041 | 
            +
                    listener();
         | 
| 1042 | 
            +
                  }
         | 
| 1043 | 
            +
                },
         | 
| 1044 | 
            +
                onScrollToBottom: (callback) => {
         | 
| 1045 | 
            +
                  scrollToBottomListeners.add(callback);
         | 
| 1046 | 
            +
                  return () => {
         | 
| 1047 | 
            +
                    scrollToBottomListeners.delete(callback);
         | 
| 1048 | 
            +
                  };
         | 
| 1049 | 
            +
                }
         | 
| 1050 | 
            +
              }));
         | 
| 1051 | 
            +
            };
         | 
| 1052 | 
            +
             | 
| 1053 | 
            +
            // src/adapters/vercel/useDummyAIAssistantContext.tsx
         | 
| 997 1054 | 
             
            var useDummyAIAssistantContext = () => {
         | 
| 998 1055 | 
             
              const [context] = (0, import_react21.useState)(() => {
         | 
| 999 | 
            -
                const  | 
| 1000 | 
            -
             | 
| 1056 | 
            +
                const useThread = (0, import_zustand4.create)()(() => ({
         | 
| 1057 | 
            +
                  id: "",
         | 
| 1001 1058 | 
             
                  messages: [],
         | 
| 1002 | 
            -
                   | 
| 1059 | 
            +
                  isRunning: false,
         | 
| 1003 1060 | 
             
                  append: async () => {
         | 
| 1004 1061 | 
             
                    throw new Error("Not implemented");
         | 
| 1005 1062 | 
             
                  },
         | 
| 1006 | 
            -
                   | 
| 1063 | 
            +
                  cancelRun: () => {
         | 
| 1007 1064 | 
             
                    throw new Error("Not implemented");
         | 
| 1008 1065 | 
             
                  },
         | 
| 1009 1066 | 
             
                  switchToBranch: () => {
         | 
| 1010 1067 | 
             
                    throw new Error("Not implemented");
         | 
| 1011 1068 | 
             
                  },
         | 
| 1012 | 
            -
                   | 
| 1069 | 
            +
                  startRun: async () => {
         | 
| 1013 1070 | 
             
                    throw new Error("Not implemented");
         | 
| 1014 | 
            -
                  },
         | 
| 1015 | 
            -
                  isAtBottom: true,
         | 
| 1016 | 
            -
                  scrollToBottom: () => {
         | 
| 1017 | 
            -
                    for (const listener of scrollToBottomListeners) {
         | 
| 1018 | 
            -
                      listener();
         | 
| 1019 | 
            -
                    }
         | 
| 1020 | 
            -
                  },
         | 
| 1021 | 
            -
                  onScrollToBottom: (callback) => {
         | 
| 1022 | 
            -
                    scrollToBottomListeners.add(callback);
         | 
| 1023 | 
            -
                    return () => {
         | 
| 1024 | 
            -
                      scrollToBottomListeners.delete(callback);
         | 
| 1025 | 
            -
                    };
         | 
| 1026 1071 | 
             
                  }
         | 
| 1027 1072 | 
             
                }));
         | 
| 1028 | 
            -
                const  | 
| 1029 | 
            -
             | 
| 1030 | 
            -
                   | 
| 1031 | 
            -
             | 
| 1032 | 
            -
                  setValue: (value) => {
         | 
| 1033 | 
            -
                    useComposer.setState({ value });
         | 
| 1034 | 
            -
                  },
         | 
| 1035 | 
            -
                  edit: () => {
         | 
| 1036 | 
            -
                    throw new Error("Not implemented");
         | 
| 1037 | 
            -
                  },
         | 
| 1038 | 
            -
                  send: () => {
         | 
| 1039 | 
            -
                    useThread.getState().append({
         | 
| 1073 | 
            +
                const useViewport = makeViewportStore();
         | 
| 1074 | 
            +
                const useComposer = makeThreadComposerStore({
         | 
| 1075 | 
            +
                  onSend: async (text) => {
         | 
| 1076 | 
            +
                    await useThread.getState().append({
         | 
| 1040 1077 | 
             
                      parentId: useThread.getState().messages.at(-1)?.id ?? ROOT_PARENT_ID,
         | 
| 1041 | 
            -
                      content: [{ type: "text", text | 
| 1078 | 
            +
                      content: [{ type: "text", text }]
         | 
| 1042 1079 | 
             
                    });
         | 
| 1043 | 
            -
                    useComposer.getState().setValue("");
         | 
| 1044 1080 | 
             
                  },
         | 
| 1045 | 
            -
                   | 
| 1046 | 
            -
                    useThread.getState(). | 
| 1081 | 
            +
                  onCancel: () => {
         | 
| 1082 | 
            +
                    useThread.getState().cancelRun();
         | 
| 1047 1083 | 
             
                  }
         | 
| 1048 | 
            -
                }) | 
| 1049 | 
            -
                return { useThread, useComposer };
         | 
| 1084 | 
            +
                });
         | 
| 1085 | 
            +
                return { useThread, useViewport, useComposer };
         | 
| 1050 1086 | 
             
              });
         | 
| 1051 1087 | 
             
              return context;
         | 
| 1052 1088 | 
             
            };
         | 
| @@ -1096,31 +1132,31 @@ var VercelAIAssistantProvider = ({ | |
| 1096 1132 | 
             
                  branches.getBranchState
         | 
| 1097 1133 | 
             
                );
         | 
| 1098 1134 | 
             
              }, [vercel.messages, branches.getBranchState]);
         | 
| 1099 | 
            -
              const  | 
| 1135 | 
            +
              const cancelRun = (0, import_react22.useCallback)(() => {
         | 
| 1100 1136 | 
             
                const lastMessage = vercel.messages.at(-1);
         | 
| 1101 1137 | 
             
                vercel.stop();
         | 
| 1102 1138 | 
             
                if (lastMessage?.role === "user") {
         | 
| 1103 1139 | 
             
                  vercel.setInput(lastMessage.content);
         | 
| 1104 1140 | 
             
                }
         | 
| 1105 1141 | 
             
              }, [vercel.messages, vercel.stop, vercel.setInput]);
         | 
| 1106 | 
            -
              const  | 
| 1142 | 
            +
              const isRunning = "isLoading" in vercel ? vercel.isLoading : vercel.status === "in_progress";
         | 
| 1107 1143 | 
             
              (0, import_react22.useMemo)(() => {
         | 
| 1108 1144 | 
             
                context.useThread.setState({
         | 
| 1109 1145 | 
             
                  messages,
         | 
| 1110 | 
            -
                   | 
| 1111 | 
            -
                   | 
| 1146 | 
            +
                  isRunning,
         | 
| 1147 | 
            +
                  cancelRun,
         | 
| 1112 1148 | 
             
                  switchToBranch: branches.switchToBranch,
         | 
| 1113 1149 | 
             
                  append: branches.append,
         | 
| 1114 | 
            -
                   | 
| 1150 | 
            +
                  startRun: branches.startRun
         | 
| 1115 1151 | 
             
                });
         | 
| 1116 | 
            -
              }, [context, messages,  | 
| 1152 | 
            +
              }, [context, messages, isRunning, cancelRun, branches]);
         | 
| 1117 1153 | 
             
              (0, import_react22.useMemo)(() => {
         | 
| 1118 1154 | 
             
                context.useComposer.setState({
         | 
| 1119 | 
            -
                  canCancel:  | 
| 1155 | 
            +
                  canCancel: isRunning,
         | 
| 1120 1156 | 
             
                  value: vercel.input,
         | 
| 1121 1157 | 
             
                  setValue: vercel.setInput
         | 
| 1122 1158 | 
             
                });
         | 
| 1123 | 
            -
              }, [context,  | 
| 1159 | 
            +
              }, [context, isRunning, vercel.input, vercel.setInput]);
         | 
| 1124 1160 | 
             
              return /* @__PURE__ */ React.createElement(AssistantContext.Provider, { value: context }, children);
         | 
| 1125 1161 | 
             
            };
         | 
| 1126 1162 |  | 
| @@ -1167,7 +1203,7 @@ var VercelRSCAssistantProvider = ({ | |
| 1167 1203 | 
             
                  if (message.content[0]?.type !== "text") {
         | 
| 1168 1204 | 
             
                    throw new Error("Only text content is currently supported");
         | 
| 1169 1205 | 
             
                  }
         | 
| 1170 | 
            -
                  context. | 
| 1206 | 
            +
                  context.useViewport.getState().scrollToBottom();
         | 
| 1171 1207 | 
             
                  await vercelAppend(message);
         | 
| 1172 1208 | 
             
                },
         | 
| 1173 1209 | 
             
                [context, vercelAppend]
         | 
    
        package/dist/index.mjs
    CHANGED
    
    | @@ -46,9 +46,9 @@ var useThreadIf = (props) => { | |
| 46 46 | 
             
                  return false;
         | 
| 47 47 | 
             
                if (props.empty === false && thread.messages.length === 0)
         | 
| 48 48 | 
             
                  return false;
         | 
| 49 | 
            -
                if (props. | 
| 49 | 
            +
                if (props.running === true && !thread.isRunning)
         | 
| 50 50 | 
             
                  return false;
         | 
| 51 | 
            -
                if (props. | 
| 51 | 
            +
                if (props.running === false && thread.isRunning)
         | 
| 52 52 | 
             
                  return false;
         | 
| 53 53 | 
             
                return true;
         | 
| 54 54 | 
             
              });
         | 
| @@ -115,12 +115,12 @@ import { useEffect, useRef as useRef2 } from "react"; | |
| 115 115 | 
             
            var useOnScrollToBottom = (callback) => {
         | 
| 116 116 | 
             
              const callbackRef = useRef2(callback);
         | 
| 117 117 | 
             
              callbackRef.current = callback;
         | 
| 118 | 
            -
              const {  | 
| 118 | 
            +
              const { useViewport } = useAssistantContext();
         | 
| 119 119 | 
             
              useEffect(() => {
         | 
| 120 | 
            -
                return  | 
| 120 | 
            +
                return useViewport.getState().onScrollToBottom(() => {
         | 
| 121 121 | 
             
                  callbackRef.current();
         | 
| 122 122 | 
             
                });
         | 
| 123 | 
            -
              }, [ | 
| 123 | 
            +
              }, [useViewport]);
         | 
| 124 124 | 
             
            };
         | 
| 125 125 |  | 
| 126 126 | 
             
            // src/primitives/thread/ThreadViewport.tsx
         | 
| @@ -128,7 +128,7 @@ var ThreadViewport = forwardRef2(({ autoScroll = true, onScroll, children, ...re | |
| 128 128 | 
             
              const messagesEndRef = useRef3(null);
         | 
| 129 129 | 
             
              const divRef = useRef3(null);
         | 
| 130 130 | 
             
              const ref = useComposedRefs(forwardedRef, divRef);
         | 
| 131 | 
            -
              const {  | 
| 131 | 
            +
              const { useViewport } = useAssistantContext();
         | 
| 132 132 | 
             
              const firstRenderRef = useRef3(true);
         | 
| 133 133 | 
             
              const lastScrollTop = useRef3(0);
         | 
| 134 134 | 
             
              const scrollToBottom = () => {
         | 
| @@ -137,11 +137,11 @@ var ThreadViewport = forwardRef2(({ autoScroll = true, onScroll, children, ...re | |
| 137 137 | 
             
                  return;
         | 
| 138 138 | 
             
                const behavior = firstRenderRef.current ? "instant" : "auto";
         | 
| 139 139 | 
             
                firstRenderRef.current = false;
         | 
| 140 | 
            -
                 | 
| 140 | 
            +
                useViewport.setState({ isAtBottom: true });
         | 
| 141 141 | 
             
                div.scrollIntoView({ behavior });
         | 
| 142 142 | 
             
              };
         | 
| 143 143 | 
             
              useOnResizeContent(divRef, () => {
         | 
| 144 | 
            -
                if (! | 
| 144 | 
            +
                if (!useViewport.getState().isAtBottom)
         | 
| 145 145 | 
             
                  return;
         | 
| 146 146 | 
             
                scrollToBottom();
         | 
| 147 147 | 
             
              });
         | 
| @@ -152,11 +152,11 @@ var ThreadViewport = forwardRef2(({ autoScroll = true, onScroll, children, ...re | |
| 152 152 | 
             
                const div = divRef.current;
         | 
| 153 153 | 
             
                if (!div)
         | 
| 154 154 | 
             
                  return;
         | 
| 155 | 
            -
                const isAtBottom =  | 
| 155 | 
            +
                const isAtBottom = useViewport.getState().isAtBottom;
         | 
| 156 156 | 
             
                const newIsAtBottom = div.scrollHeight - div.scrollTop <= div.clientHeight;
         | 
| 157 157 | 
             
                if (!newIsAtBottom && lastScrollTop.current < div.scrollTop) {
         | 
| 158 158 | 
             
                } else if (newIsAtBottom !== isAtBottom) {
         | 
| 159 | 
            -
                   | 
| 159 | 
            +
                  useViewport.setState({ isAtBottom: newIsAtBottom });
         | 
| 160 160 | 
             
                }
         | 
| 161 161 | 
             
                lastScrollTop.current = div.scrollTop;
         | 
| 162 162 | 
             
              };
         | 
| @@ -272,13 +272,13 @@ var useVercelAIBranches = (chat, context) => { | |
| 272 272 | 
             
                [data, chat.messages, chat.setMessages]
         | 
| 273 273 | 
             
              );
         | 
| 274 274 | 
             
              const reloadMaybe = "reload" in chat ? chat.reload : void 0;
         | 
| 275 | 
            -
              const  | 
| 276 | 
            -
                async ( | 
| 275 | 
            +
              const startRun = useCallback(
         | 
| 276 | 
            +
                async (parentId) => {
         | 
| 277 277 | 
             
                  if (!reloadMaybe)
         | 
| 278 278 | 
             
                    throw new Error("Reload not supported by Vercel AI SDK's useAssistant");
         | 
| 279 | 
            -
                  const newMessages = sliceMessagesUntil(chat.messages,  | 
| 279 | 
            +
                  const newMessages = sliceMessagesUntil(chat.messages, parentId);
         | 
| 280 280 | 
             
                  chat.setMessages(newMessages);
         | 
| 281 | 
            -
                  context. | 
| 281 | 
            +
                  context.useViewport.getState().scrollToBottom();
         | 
| 282 282 | 
             
                  await reloadMaybe();
         | 
| 283 283 | 
             
                },
         | 
| 284 284 | 
             
                [context, chat.messages, chat.setMessages, reloadMaybe]
         | 
| @@ -289,7 +289,7 @@ var useVercelAIBranches = (chat, context) => { | |
| 289 289 | 
             
                  chat.setMessages(newMessages);
         | 
| 290 290 | 
             
                  if (message.content.length !== 1 || message.content[0]?.type !== "text")
         | 
| 291 291 | 
             
                    throw new Error("Only text content is currently supported");
         | 
| 292 | 
            -
                  context. | 
| 292 | 
            +
                  context.useViewport.getState().scrollToBottom();
         | 
| 293 293 | 
             
                  await chat.append({
         | 
| 294 294 | 
             
                    role: "user",
         | 
| 295 295 | 
             
                    content: message.content[0].text
         | 
| @@ -302,13 +302,13 @@ var useVercelAIBranches = (chat, context) => { | |
| 302 302 | 
             
                  getBranchState,
         | 
| 303 303 | 
             
                  switchToBranch,
         | 
| 304 304 | 
             
                  append,
         | 
| 305 | 
            -
                   | 
| 305 | 
            +
                  startRun
         | 
| 306 306 | 
             
                }),
         | 
| 307 | 
            -
                [getBranchState, switchToBranch, append,  | 
| 307 | 
            +
                [getBranchState, switchToBranch, append, startRun]
         | 
| 308 308 | 
             
              );
         | 
| 309 309 | 
             
            };
         | 
| 310 310 | 
             
            var hasUpcomingMessage = (thread) => {
         | 
| 311 | 
            -
              return thread. | 
| 311 | 
            +
              return thread.isRunning && thread.messages[thread.messages.length - 1]?.role !== "assistant";
         | 
| 312 312 | 
             
            };
         | 
| 313 313 |  | 
| 314 314 | 
             
            // src/utils/context/useComposerContext.ts
         | 
| @@ -361,7 +361,56 @@ __export(message_exports, { | |
| 361 361 |  | 
| 362 362 | 
             
            // src/primitives/message/MessageProvider.tsx
         | 
| 363 363 | 
             
            import { useMemo as useMemo2, useState } from "react";
         | 
| 364 | 
            -
            import { create } from "zustand";
         | 
| 364 | 
            +
            import { create as create2 } from "zustand";
         | 
| 365 | 
            +
             | 
| 366 | 
            +
            // src/utils/context/stores/ComposerStore.ts
         | 
| 367 | 
            +
            import {
         | 
| 368 | 
            +
              create
         | 
| 369 | 
            +
            } from "zustand";
         | 
| 370 | 
            +
            var makeBaseComposer = (set) => ({
         | 
| 371 | 
            +
              value: "",
         | 
| 372 | 
            +
              setValue: (value) => {
         | 
| 373 | 
            +
                set({ value });
         | 
| 374 | 
            +
              }
         | 
| 375 | 
            +
            });
         | 
| 376 | 
            +
            var makeMessageComposerStore = ({
         | 
| 377 | 
            +
              onEdit,
         | 
| 378 | 
            +
              onSend
         | 
| 379 | 
            +
            }) => create()((set, get, store) => ({
         | 
| 380 | 
            +
              ...makeBaseComposer(set, get, store),
         | 
| 381 | 
            +
              canCancel: true,
         | 
| 382 | 
            +
              isEditing: false,
         | 
| 383 | 
            +
              edit: () => {
         | 
| 384 | 
            +
                const value = onEdit();
         | 
| 385 | 
            +
                set({ isEditing: true, value });
         | 
| 386 | 
            +
              },
         | 
| 387 | 
            +
              send: () => {
         | 
| 388 | 
            +
                const value = get().value;
         | 
| 389 | 
            +
                set({ isEditing: false });
         | 
| 390 | 
            +
                return onSend(value);
         | 
| 391 | 
            +
              },
         | 
| 392 | 
            +
              cancel: () => {
         | 
| 393 | 
            +
                set({ isEditing: false });
         | 
| 394 | 
            +
              }
         | 
| 395 | 
            +
            }));
         | 
| 396 | 
            +
            var makeThreadComposerStore = ({
         | 
| 397 | 
            +
              onSend,
         | 
| 398 | 
            +
              onCancel
         | 
| 399 | 
            +
            }) => create()((set, get, store) => ({
         | 
| 400 | 
            +
              ...makeBaseComposer(set, get, store),
         | 
| 401 | 
            +
              isEditing: true,
         | 
| 402 | 
            +
              canCancel: false,
         | 
| 403 | 
            +
              send: () => {
         | 
| 404 | 
            +
                const value = get().value;
         | 
| 405 | 
            +
                set({ value: "", canCancel: true });
         | 
| 406 | 
            +
                onSend(value).then(() => {
         | 
| 407 | 
            +
                  set({ canCancel: false });
         | 
| 408 | 
            +
                });
         | 
| 409 | 
            +
              },
         | 
| 410 | 
            +
              cancel: onCancel
         | 
| 411 | 
            +
            }));
         | 
| 412 | 
            +
             | 
| 413 | 
            +
            // src/primitives/message/MessageProvider.tsx
         | 
| 365 414 | 
             
            var getIsLast = (thread, message) => {
         | 
| 366 415 | 
             
              const hasUpcoming = hasUpcomingMessage(thread);
         | 
| 367 416 | 
             
              return hasUpcoming ? message.id === UPCOMING_MESSAGE_ID : thread.messages[thread.messages.length - 1]?.id === message.id;
         | 
| @@ -369,7 +418,7 @@ var getIsLast = (thread, message) => { | |
| 369 418 | 
             
            var useMessageContext2 = () => {
         | 
| 370 419 | 
             
              const [context] = useState(() => {
         | 
| 371 420 | 
             
                const { useThread } = useAssistantContext();
         | 
| 372 | 
            -
                const useMessage =  | 
| 421 | 
            +
                const useMessage = create2(() => ({
         | 
| 373 422 | 
             
                  message: null,
         | 
| 374 423 | 
             
                  isLast: false,
         | 
| 375 424 | 
             
                  isCopied: false,
         | 
| @@ -379,34 +428,23 @@ var useMessageContext2 = () => { | |
| 379 428 | 
             
                  setIsHovering: () => {
         | 
| 380 429 | 
             
                  }
         | 
| 381 430 | 
             
                }));
         | 
| 382 | 
            -
                const useComposer =  | 
| 383 | 
            -
                   | 
| 384 | 
            -
                  canCancel: true,
         | 
| 385 | 
            -
                  edit: () => {
         | 
| 431 | 
            +
                const useComposer = makeMessageComposerStore({
         | 
| 432 | 
            +
                  onEdit: () => {
         | 
| 386 433 | 
             
                    const message = useMessage.getState().message;
         | 
| 387 434 | 
             
                    if (message.role !== "user")
         | 
| 388 435 | 
             
                      throw new Error("Editing is only supported for user messages");
         | 
| 389 436 | 
             
                    if (message.content[0]?.type !== "text")
         | 
| 390 437 | 
             
                      throw new Error("Editing is only supported for text-only messages");
         | 
| 391 | 
            -
                    return  | 
| 392 | 
            -
                      isEditing: true,
         | 
| 393 | 
            -
                      value: message.content[0].text
         | 
| 394 | 
            -
                    });
         | 
| 438 | 
            +
                    return message.content[0].text;
         | 
| 395 439 | 
             
                  },
         | 
| 396 | 
            -
                   | 
| 397 | 
            -
                  send: () => {
         | 
| 440 | 
            +
                  onSend: (text) => {
         | 
| 398 441 | 
             
                    const message = useMessage.getState().message;
         | 
| 399 | 
            -
                     | 
| 400 | 
            -
                      throw new Error("Editing is only supported for user messages");
         | 
| 401 | 
            -
                    useThread.getState().append({
         | 
| 442 | 
            +
                    return useThread.getState().append({
         | 
| 402 443 | 
             
                      parentId: message.parentId,
         | 
| 403 | 
            -
                      content: [{ type: "text", text | 
| 444 | 
            +
                      content: [{ type: "text", text }]
         | 
| 404 445 | 
             
                    });
         | 
| 405 | 
            -
             | 
| 406 | 
            -
             | 
| 407 | 
            -
                  value: "",
         | 
| 408 | 
            -
                  setValue: (value) => set({ value })
         | 
| 409 | 
            -
                }));
         | 
| 446 | 
            +
                  }
         | 
| 447 | 
            +
                });
         | 
| 410 448 | 
             
                return { useMessage, useComposer };
         | 
| 411 449 | 
             
              });
         | 
| 412 450 | 
             
              return context;
         | 
| @@ -571,11 +609,10 @@ import { | |
| 571 609 | 
             
            } from "@radix-ui/react-primitive";
         | 
| 572 610 | 
             
            import { forwardRef as forwardRef4 } from "react";
         | 
| 573 611 | 
             
            var ThreadScrollToBottom = forwardRef4(({ onClick, ...rest }, ref) => {
         | 
| 574 | 
            -
              const {  | 
| 575 | 
            -
              const isAtBottom =  | 
| 612 | 
            +
              const { useViewport } = useAssistantContext();
         | 
| 613 | 
            +
              const isAtBottom = useViewport((s) => s.isAtBottom);
         | 
| 576 614 | 
             
              const handleScrollToBottom = () => {
         | 
| 577 | 
            -
                 | 
| 578 | 
            -
                thread.scrollToBottom();
         | 
| 615 | 
            +
                useViewport.getState().scrollToBottom();
         | 
| 579 616 | 
             
              };
         | 
| 580 617 | 
             
              return /* @__PURE__ */ React.createElement(
         | 
| 581 618 | 
             
                Primitive4.button,
         | 
| @@ -658,8 +695,8 @@ var ComposerInput = forwardRef6( | |
| 658 695 | 
             
                    useComposer.getState().cancel();
         | 
| 659 696 | 
             
                  }
         | 
| 660 697 | 
             
                  if (e.key === "Enter" && e.shiftKey === false) {
         | 
| 661 | 
            -
                    const  | 
| 662 | 
            -
                    if (! | 
| 698 | 
            +
                    const isRunning = useThread.getState().isRunning;
         | 
| 699 | 
            +
                    if (!isRunning) {
         | 
| 663 700 | 
             
                      e.preventDefault();
         | 
| 664 701 | 
             
                      composer.send();
         | 
| 665 702 | 
             
                    }
         | 
| @@ -790,7 +827,7 @@ var useGoToNextBranch = () => { | |
| 790 827 | 
             
              const { useComposer, useMessage } = useMessageContext();
         | 
| 791 828 | 
             
              const disabled = useCombinedStore(
         | 
| 792 829 | 
             
                [useThread, useComposer, useMessage],
         | 
| 793 | 
            -
                (t, c, m) => t. | 
| 830 | 
            +
                (t, c, m) => t.isRunning || c.isEditing || m.message.branchId + 1 >= m.message.branchCount
         | 
| 794 831 | 
             
              );
         | 
| 795 832 | 
             
              if (disabled)
         | 
| 796 833 | 
             
                return null;
         | 
| @@ -833,7 +870,7 @@ var useGoToPreviousBranch = () => { | |
| 833 870 | 
             
              const { useComposer, useMessage } = useMessageContext();
         | 
| 834 871 | 
             
              const disabled = useCombinedStore(
         | 
| 835 872 | 
             
                [useThread, useComposer, useMessage],
         | 
| 836 | 
            -
                (t, c, m) => t. | 
| 873 | 
            +
                (t, c, m) => t.isRunning || c.isEditing || m.message.branchId <= 0
         | 
| 837 874 | 
             
              );
         | 
| 838 875 | 
             
              if (disabled)
         | 
| 839 876 | 
             
                return null;
         | 
| @@ -883,13 +920,13 @@ import { | |
| 883 920 | 
             
              Primitive as Primitive10
         | 
| 884 921 | 
             
            } from "@radix-ui/react-primitive";
         | 
| 885 922 | 
             
            import { forwardRef as forwardRef11 } from "react";
         | 
| 886 | 
            -
            var ActionBarRoot = forwardRef11(({  | 
| 923 | 
            +
            var ActionBarRoot = forwardRef11(({ hideWhenRunning, autohide, autohideFloat, ...rest }, ref) => {
         | 
| 887 924 | 
             
              const { useThread } = useAssistantContext();
         | 
| 888 925 | 
             
              const { useMessage } = useMessageContext();
         | 
| 889 926 | 
             
              const hideAndfloatStatus = useCombinedStore(
         | 
| 890 927 | 
             
                [useThread, useMessage],
         | 
| 891 928 | 
             
                (t, m) => {
         | 
| 892 | 
            -
                  if ( | 
| 929 | 
            +
                  if (hideWhenRunning && t.isRunning)
         | 
| 893 930 | 
             
                    return "hidden" /* Hidden */;
         | 
| 894 931 | 
             
                  const autohideEnabled = autohide === "always" || autohide === "not-last" && !m.isLast;
         | 
| 895 932 | 
             
                  if (!autohideEnabled)
         | 
| @@ -938,7 +975,7 @@ var useReloadMessage = () => { | |
| 938 975 | 
             
              const { useMessage } = useMessageContext();
         | 
| 939 976 | 
             
              const disabled = useCombinedStore(
         | 
| 940 977 | 
             
                [useThread, useMessage],
         | 
| 941 | 
            -
                (t, m) => t. | 
| 978 | 
            +
                (t, m) => t.isRunning || m.message.role !== "assistant"
         | 
| 942 979 | 
             
              );
         | 
| 943 980 | 
             
              if (disabled)
         | 
| 944 981 | 
             
                return null;
         | 
| @@ -946,7 +983,7 @@ var useReloadMessage = () => { | |
| 946 983 | 
             
                const message = useMessage.getState().message;
         | 
| 947 984 | 
             
                if (message.role !== "assistant")
         | 
| 948 985 | 
             
                  throw new Error("Reloading is only supported on assistant messages");
         | 
| 949 | 
            -
                useThread.getState(). | 
| 986 | 
            +
                useThread.getState().startRun(message.parentId);
         | 
| 950 987 | 
             
              };
         | 
| 951 988 | 
             
            };
         | 
| 952 989 |  | 
| @@ -976,60 +1013,61 @@ import { useCallback as useCallback3, useMemo as useMemo4 } from "react"; | |
| 976 1013 |  | 
| 977 1014 | 
             
            // src/adapters/vercel/useDummyAIAssistantContext.tsx
         | 
| 978 1015 | 
             
            import { useState as useState2 } from "react";
         | 
| 979 | 
            -
            import { create as  | 
| 1016 | 
            +
            import { create as create4 } from "zustand";
         | 
| 1017 | 
            +
             | 
| 1018 | 
            +
            // src/utils/context/stores/ViewportStore.tsx
         | 
| 1019 | 
            +
            import { create as create3 } from "zustand";
         | 
| 1020 | 
            +
            var makeViewportStore = () => {
         | 
| 1021 | 
            +
              const scrollToBottomListeners = /* @__PURE__ */ new Set();
         | 
| 1022 | 
            +
              return create3(() => ({
         | 
| 1023 | 
            +
                isAtBottom: true,
         | 
| 1024 | 
            +
                scrollToBottom: () => {
         | 
| 1025 | 
            +
                  for (const listener of scrollToBottomListeners) {
         | 
| 1026 | 
            +
                    listener();
         | 
| 1027 | 
            +
                  }
         | 
| 1028 | 
            +
                },
         | 
| 1029 | 
            +
                onScrollToBottom: (callback) => {
         | 
| 1030 | 
            +
                  scrollToBottomListeners.add(callback);
         | 
| 1031 | 
            +
                  return () => {
         | 
| 1032 | 
            +
                    scrollToBottomListeners.delete(callback);
         | 
| 1033 | 
            +
                  };
         | 
| 1034 | 
            +
                }
         | 
| 1035 | 
            +
              }));
         | 
| 1036 | 
            +
            };
         | 
| 1037 | 
            +
             | 
| 1038 | 
            +
            // src/adapters/vercel/useDummyAIAssistantContext.tsx
         | 
| 980 1039 | 
             
            var useDummyAIAssistantContext = () => {
         | 
| 981 1040 | 
             
              const [context] = useState2(() => {
         | 
| 982 | 
            -
                const  | 
| 983 | 
            -
             | 
| 1041 | 
            +
                const useThread = create4()(() => ({
         | 
| 1042 | 
            +
                  id: "",
         | 
| 984 1043 | 
             
                  messages: [],
         | 
| 985 | 
            -
                   | 
| 1044 | 
            +
                  isRunning: false,
         | 
| 986 1045 | 
             
                  append: async () => {
         | 
| 987 1046 | 
             
                    throw new Error("Not implemented");
         | 
| 988 1047 | 
             
                  },
         | 
| 989 | 
            -
                   | 
| 1048 | 
            +
                  cancelRun: () => {
         | 
| 990 1049 | 
             
                    throw new Error("Not implemented");
         | 
| 991 1050 | 
             
                  },
         | 
| 992 1051 | 
             
                  switchToBranch: () => {
         | 
| 993 1052 | 
             
                    throw new Error("Not implemented");
         | 
| 994 1053 | 
             
                  },
         | 
| 995 | 
            -
                   | 
| 1054 | 
            +
                  startRun: async () => {
         | 
| 996 1055 | 
             
                    throw new Error("Not implemented");
         | 
| 997 | 
            -
                  },
         | 
| 998 | 
            -
                  isAtBottom: true,
         | 
| 999 | 
            -
                  scrollToBottom: () => {
         | 
| 1000 | 
            -
                    for (const listener of scrollToBottomListeners) {
         | 
| 1001 | 
            -
                      listener();
         | 
| 1002 | 
            -
                    }
         | 
| 1003 | 
            -
                  },
         | 
| 1004 | 
            -
                  onScrollToBottom: (callback) => {
         | 
| 1005 | 
            -
                    scrollToBottomListeners.add(callback);
         | 
| 1006 | 
            -
                    return () => {
         | 
| 1007 | 
            -
                      scrollToBottomListeners.delete(callback);
         | 
| 1008 | 
            -
                    };
         | 
| 1009 1056 | 
             
                  }
         | 
| 1010 1057 | 
             
                }));
         | 
| 1011 | 
            -
                const  | 
| 1012 | 
            -
             | 
| 1013 | 
            -
                   | 
| 1014 | 
            -
             | 
| 1015 | 
            -
                  setValue: (value) => {
         | 
| 1016 | 
            -
                    useComposer.setState({ value });
         | 
| 1017 | 
            -
                  },
         | 
| 1018 | 
            -
                  edit: () => {
         | 
| 1019 | 
            -
                    throw new Error("Not implemented");
         | 
| 1020 | 
            -
                  },
         | 
| 1021 | 
            -
                  send: () => {
         | 
| 1022 | 
            -
                    useThread.getState().append({
         | 
| 1058 | 
            +
                const useViewport = makeViewportStore();
         | 
| 1059 | 
            +
                const useComposer = makeThreadComposerStore({
         | 
| 1060 | 
            +
                  onSend: async (text) => {
         | 
| 1061 | 
            +
                    await useThread.getState().append({
         | 
| 1023 1062 | 
             
                      parentId: useThread.getState().messages.at(-1)?.id ?? ROOT_PARENT_ID,
         | 
| 1024 | 
            -
                      content: [{ type: "text", text | 
| 1063 | 
            +
                      content: [{ type: "text", text }]
         | 
| 1025 1064 | 
             
                    });
         | 
| 1026 | 
            -
                    useComposer.getState().setValue("");
         | 
| 1027 1065 | 
             
                  },
         | 
| 1028 | 
            -
                   | 
| 1029 | 
            -
                    useThread.getState(). | 
| 1066 | 
            +
                  onCancel: () => {
         | 
| 1067 | 
            +
                    useThread.getState().cancelRun();
         | 
| 1030 1068 | 
             
                  }
         | 
| 1031 | 
            -
                }) | 
| 1032 | 
            -
                return { useThread, useComposer };
         | 
| 1069 | 
            +
                });
         | 
| 1070 | 
            +
                return { useThread, useViewport, useComposer };
         | 
| 1033 1071 | 
             
              });
         | 
| 1034 1072 | 
             
              return context;
         | 
| 1035 1073 | 
             
            };
         | 
| @@ -1079,31 +1117,31 @@ var VercelAIAssistantProvider = ({ | |
| 1079 1117 | 
             
                  branches.getBranchState
         | 
| 1080 1118 | 
             
                );
         | 
| 1081 1119 | 
             
              }, [vercel.messages, branches.getBranchState]);
         | 
| 1082 | 
            -
              const  | 
| 1120 | 
            +
              const cancelRun = useCallback3(() => {
         | 
| 1083 1121 | 
             
                const lastMessage = vercel.messages.at(-1);
         | 
| 1084 1122 | 
             
                vercel.stop();
         | 
| 1085 1123 | 
             
                if (lastMessage?.role === "user") {
         | 
| 1086 1124 | 
             
                  vercel.setInput(lastMessage.content);
         | 
| 1087 1125 | 
             
                }
         | 
| 1088 1126 | 
             
              }, [vercel.messages, vercel.stop, vercel.setInput]);
         | 
| 1089 | 
            -
              const  | 
| 1127 | 
            +
              const isRunning = "isLoading" in vercel ? vercel.isLoading : vercel.status === "in_progress";
         | 
| 1090 1128 | 
             
              useMemo4(() => {
         | 
| 1091 1129 | 
             
                context.useThread.setState({
         | 
| 1092 1130 | 
             
                  messages,
         | 
| 1093 | 
            -
                   | 
| 1094 | 
            -
                   | 
| 1131 | 
            +
                  isRunning,
         | 
| 1132 | 
            +
                  cancelRun,
         | 
| 1095 1133 | 
             
                  switchToBranch: branches.switchToBranch,
         | 
| 1096 1134 | 
             
                  append: branches.append,
         | 
| 1097 | 
            -
                   | 
| 1135 | 
            +
                  startRun: branches.startRun
         | 
| 1098 1136 | 
             
                });
         | 
| 1099 | 
            -
              }, [context, messages,  | 
| 1137 | 
            +
              }, [context, messages, isRunning, cancelRun, branches]);
         | 
| 1100 1138 | 
             
              useMemo4(() => {
         | 
| 1101 1139 | 
             
                context.useComposer.setState({
         | 
| 1102 | 
            -
                  canCancel:  | 
| 1140 | 
            +
                  canCancel: isRunning,
         | 
| 1103 1141 | 
             
                  value: vercel.input,
         | 
| 1104 1142 | 
             
                  setValue: vercel.setInput
         | 
| 1105 1143 | 
             
                });
         | 
| 1106 | 
            -
              }, [context,  | 
| 1144 | 
            +
              }, [context, isRunning, vercel.input, vercel.setInput]);
         | 
| 1107 1145 | 
             
              return /* @__PURE__ */ React.createElement(AssistantContext.Provider, { value: context }, children);
         | 
| 1108 1146 | 
             
            };
         | 
| 1109 1147 |  | 
| @@ -1153,7 +1191,7 @@ var VercelRSCAssistantProvider = ({ | |
| 1153 1191 | 
             
                  if (message.content[0]?.type !== "text") {
         | 
| 1154 1192 | 
             
                    throw new Error("Only text content is currently supported");
         | 
| 1155 1193 | 
             
                  }
         | 
| 1156 | 
            -
                  context. | 
| 1194 | 
            +
                  context.useViewport.getState().scrollToBottom();
         | 
| 1157 1195 | 
             
                  await vercelAppend(message);
         | 
| 1158 1196 | 
             
                },
         | 
| 1159 1197 | 
             
                [context, vercelAppend]
         |