@assistant-ui/react 0.1.11 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.mjs CHANGED
@@ -1,19 +1,24 @@
1
- import {
2
- AssistantContext,
3
- ContentPartContext,
4
- MessageContext,
5
- ThreadContext,
6
- __export,
7
- useAssistantContext,
8
- useComposerContext,
9
- useContentPartContext,
10
- useMessageContext,
11
- useThreadContext
12
- } from "./chunk-KUACYNLE.mjs";
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, { get: all[name], enumerable: true });
5
+ };
13
6
 
14
7
  // src/primitive-hooks/actionBar/useActionBarCopy.tsx
15
8
  import { useCallback } from "react";
16
9
 
10
+ // src/context/react/MessageContext.ts
11
+ import { createContext, useContext } from "react";
12
+ var MessageContext = createContext(null);
13
+ var useMessageContext = () => {
14
+ const context = useContext(MessageContext);
15
+ if (!context)
16
+ throw new Error(
17
+ "This component can only be used inside a component passed to <ThreadPrimitive.Messages components={...} />."
18
+ );
19
+ return context;
20
+ };
21
+
17
22
  // src/utils/combined/useCombinedStore.ts
18
23
  import { useMemo } from "react";
19
24
 
@@ -90,8 +95,22 @@ var useActionBarEdit = () => {
90
95
 
91
96
  // src/primitive-hooks/actionBar/useActionBarReload.tsx
92
97
  import { useCallback as useCallback3 } from "react";
98
+
99
+ // src/context/react/ThreadContext.ts
100
+ import { createContext as createContext2, useContext as useContext2 } from "react";
101
+ var ThreadContext = createContext2(null);
102
+ var useThreadContext = () => {
103
+ const context = useContext2(ThreadContext);
104
+ if (!context)
105
+ throw new Error(
106
+ "This component must be used within an AssistantRuntimeProvider."
107
+ );
108
+ return context;
109
+ };
110
+
111
+ // src/primitive-hooks/actionBar/useActionBarReload.tsx
93
112
  var useActionBarReload = () => {
94
- const { useThread, useThreadActions, useViewport } = useThreadContext();
113
+ const { useThread, useThreadActions, useComposer, useViewport } = useThreadContext();
95
114
  const { useMessage } = useMessageContext();
96
115
  const disabled = useCombinedStore(
97
116
  [useThread, useMessage],
@@ -101,7 +120,8 @@ var useActionBarReload = () => {
101
120
  const { parentId } = useMessage.getState();
102
121
  useThreadActions.getState().startRun(parentId);
103
122
  useViewport.getState().scrollToBottom();
104
- }, [useThreadActions, useMessage, useViewport]);
123
+ useComposer.getState().focus();
124
+ }, [useThreadActions, useComposer, useViewport, useMessage]);
105
125
  if (disabled) return null;
106
126
  return callback;
107
127
  };
@@ -156,6 +176,309 @@ var useBranchPickerPrevious = () => {
156
176
 
157
177
  // src/primitive-hooks/composer/useComposerCancel.tsx
158
178
  import { useCallback as useCallback6 } from "react";
179
+
180
+ // src/context/providers/AssistantRuntimeProvider.tsx
181
+ import { memo } from "react";
182
+
183
+ // src/context/providers/AssistantProvider.tsx
184
+ import { useEffect as useEffect2, useInsertionEffect as useInsertionEffect2, useRef as useRef2, useState as useState2 } from "react";
185
+
186
+ // src/context/react/AssistantContext.ts
187
+ import { createContext as createContext3, useContext as useContext3 } from "react";
188
+ var AssistantContext = createContext3(
189
+ null
190
+ );
191
+ var useAssistantContext = () => {
192
+ const context = useContext3(AssistantContext);
193
+ if (!context)
194
+ throw new Error(
195
+ "This component must be used within an AssistantRuntimeProvider."
196
+ );
197
+ return context;
198
+ };
199
+
200
+ // src/context/stores/AssistantModelConfig.ts
201
+ import { create } from "zustand";
202
+
203
+ // src/types/ModelConfigTypes.ts
204
+ var mergeModelConfigs = (configSet) => {
205
+ const configs = Array.from(configSet).map((c) => c()).sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
206
+ return configs.reduce((acc, config) => {
207
+ if (config.system) {
208
+ if (acc.system) {
209
+ acc.system += `
210
+
211
+ ${config.system}`;
212
+ } else {
213
+ acc.system = config.system;
214
+ }
215
+ }
216
+ if (config.tools) {
217
+ for (const [name, tool] of Object.entries(config.tools)) {
218
+ if (acc.tools?.[name]) {
219
+ throw new Error(
220
+ `You tried to define a tool with the name ${name}, but it already exists.`
221
+ );
222
+ }
223
+ if (!acc.tools) acc.tools = {};
224
+ acc.tools[name] = tool;
225
+ }
226
+ }
227
+ return acc;
228
+ }, {});
229
+ };
230
+
231
+ // src/utils/ProxyConfigProvider.ts
232
+ var ProxyConfigProvider = class {
233
+ _providers = /* @__PURE__ */ new Set();
234
+ getModelConfig() {
235
+ return mergeModelConfigs(this._providers);
236
+ }
237
+ registerModelConfigProvider(provider) {
238
+ this._providers.add(provider);
239
+ return () => {
240
+ this._providers.delete(provider);
241
+ };
242
+ }
243
+ };
244
+
245
+ // src/context/stores/AssistantModelConfig.ts
246
+ var makeAssistantModelConfigStore = () => create(() => {
247
+ const proxy = new ProxyConfigProvider();
248
+ return Object.freeze({
249
+ getModelConfig: () => {
250
+ return proxy.getModelConfig();
251
+ },
252
+ registerModelConfigProvider: (provider) => {
253
+ return proxy.registerModelConfigProvider(provider);
254
+ }
255
+ });
256
+ });
257
+
258
+ // src/context/stores/AssistantToolUIs.ts
259
+ import { create as create2 } from "zustand";
260
+ var makeAssistantToolUIsStore = () => create2((set) => {
261
+ const renderers = /* @__PURE__ */ new Map();
262
+ return Object.freeze({
263
+ getToolUI: (name) => {
264
+ const arr = renderers.get(name);
265
+ const last = arr?.at(-1);
266
+ if (last) return last;
267
+ return null;
268
+ },
269
+ setToolUI: (name, render) => {
270
+ let arr = renderers.get(name);
271
+ if (!arr) {
272
+ arr = [];
273
+ renderers.set(name, arr);
274
+ }
275
+ arr.push(render);
276
+ set({});
277
+ return () => {
278
+ const index = arr.indexOf(render);
279
+ if (index !== -1) {
280
+ arr.splice(index, 1);
281
+ }
282
+ if (index === arr.length) {
283
+ set({});
284
+ }
285
+ };
286
+ }
287
+ });
288
+ });
289
+
290
+ // src/context/providers/ThreadProvider.tsx
291
+ import { useEffect, useInsertionEffect, useRef, useState } from "react";
292
+
293
+ // src/context/stores/Composer.ts
294
+ import { create as create3 } from "zustand";
295
+
296
+ // src/context/stores/BaseComposer.ts
297
+ var makeBaseComposer = (set) => ({
298
+ value: "",
299
+ setValue: (value) => {
300
+ set({ value });
301
+ }
302
+ });
303
+
304
+ // src/context/stores/Composer.ts
305
+ var makeComposerStore = (useThread, useThreadActions) => {
306
+ const focusListeners = /* @__PURE__ */ new Set();
307
+ return create3()((set, get, store) => {
308
+ return {
309
+ ...makeBaseComposer(set, get, store),
310
+ isEditing: true,
311
+ send: () => {
312
+ const { setValue, value } = get();
313
+ setValue("");
314
+ useThreadActions.getState().append({
315
+ parentId: useThread.getState().messages.at(-1)?.id ?? null,
316
+ role: "user",
317
+ content: [{ type: "text", text: value }]
318
+ });
319
+ },
320
+ cancel: () => {
321
+ const thread = useThread.getState();
322
+ if (!thread.isRunning) return false;
323
+ useThreadActions.getState().cancelRun();
324
+ return true;
325
+ },
326
+ focus: () => {
327
+ for (const listener of focusListeners) {
328
+ listener();
329
+ }
330
+ },
331
+ onFocus: (listener) => {
332
+ focusListeners.add(listener);
333
+ return () => {
334
+ focusListeners.delete(listener);
335
+ };
336
+ }
337
+ };
338
+ });
339
+ };
340
+
341
+ // src/context/stores/Thread.ts
342
+ import { create as create4 } from "zustand";
343
+ var makeThreadStore = (runtimeRef) => {
344
+ return create4(() => ({
345
+ messages: runtimeRef.current.messages,
346
+ isRunning: runtimeRef.current.isRunning
347
+ }));
348
+ };
349
+
350
+ // src/context/stores/ThreadViewport.tsx
351
+ import { create as create5 } from "zustand";
352
+ var makeThreadViewportStore = () => {
353
+ const scrollToBottomListeners = /* @__PURE__ */ new Set();
354
+ return create5(() => ({
355
+ isAtBottom: true,
356
+ scrollToBottom: () => {
357
+ for (const listener of scrollToBottomListeners) {
358
+ listener();
359
+ }
360
+ },
361
+ onScrollToBottom: (callback) => {
362
+ scrollToBottomListeners.add(callback);
363
+ return () => {
364
+ scrollToBottomListeners.delete(callback);
365
+ };
366
+ }
367
+ }));
368
+ };
369
+
370
+ // src/context/stores/ThreadActions.ts
371
+ import { create as create6 } from "zustand";
372
+ var makeThreadActionStore = (runtimeRef) => {
373
+ return create6(
374
+ () => Object.freeze({
375
+ getBranches: (messageId) => runtimeRef.current.getBranches(messageId),
376
+ switchToBranch: (branchId) => runtimeRef.current.switchToBranch(branchId),
377
+ startRun: (parentId) => runtimeRef.current.startRun(parentId),
378
+ append: (message) => runtimeRef.current.append(message),
379
+ cancelRun: () => runtimeRef.current.cancelRun(),
380
+ addToolResult: (toolCallId, result) => runtimeRef.current.addToolResult(toolCallId, result)
381
+ })
382
+ );
383
+ };
384
+
385
+ // src/context/providers/ThreadProvider.tsx
386
+ import { jsx, jsxs } from "react/jsx-runtime";
387
+ var ThreadProvider = ({
388
+ children,
389
+ runtime
390
+ }) => {
391
+ const runtimeRef = useRef(runtime);
392
+ useInsertionEffect(() => {
393
+ runtimeRef.current = runtime;
394
+ });
395
+ const [context] = useState(() => {
396
+ const useThread = makeThreadStore(runtimeRef);
397
+ const useThreadActions = makeThreadActionStore(runtimeRef);
398
+ const useViewport = makeThreadViewportStore();
399
+ const useComposer = makeComposerStore(useThread, useThreadActions);
400
+ return {
401
+ useThread,
402
+ useThreadActions,
403
+ useComposer,
404
+ useViewport
405
+ };
406
+ });
407
+ useEffect(() => {
408
+ const onRuntimeUpdate = () => {
409
+ context.useThread.setState(
410
+ Object.freeze({
411
+ messages: runtimeRef.current.messages,
412
+ isRunning: runtimeRef.current.isRunning
413
+ }),
414
+ true
415
+ );
416
+ };
417
+ onRuntimeUpdate();
418
+ return runtime.subscribe(onRuntimeUpdate);
419
+ }, [context, runtime]);
420
+ const RuntimeSynchronizer = runtime.unstable_synchronizer;
421
+ return /* @__PURE__ */ jsxs(ThreadContext.Provider, { value: context, children: [
422
+ RuntimeSynchronizer && /* @__PURE__ */ jsx(RuntimeSynchronizer, {}),
423
+ children
424
+ ] });
425
+ };
426
+
427
+ // src/context/providers/AssistantProvider.tsx
428
+ import { jsx as jsx2 } from "react/jsx-runtime";
429
+ var AssistantProvider = ({ children, runtime }) => {
430
+ const runtimeRef = useRef2(runtime);
431
+ useInsertionEffect2(() => {
432
+ runtimeRef.current = runtime;
433
+ });
434
+ const [context] = useState2(() => {
435
+ const useModelConfig = makeAssistantModelConfigStore();
436
+ const useToolUIs = makeAssistantToolUIsStore();
437
+ return { useModelConfig, useToolUIs };
438
+ });
439
+ const getModelCOnfig = context.useModelConfig((c) => c.getModelConfig);
440
+ useEffect2(() => {
441
+ return runtime.registerModelConfigProvider(getModelCOnfig);
442
+ }, [runtime, getModelCOnfig]);
443
+ return /* @__PURE__ */ jsx2(AssistantContext.Provider, { value: context, children: /* @__PURE__ */ jsx2(ThreadProvider, { runtime, children }) });
444
+ };
445
+
446
+ // src/context/providers/AssistantRuntimeProvider.tsx
447
+ import { jsx as jsx3 } from "react/jsx-runtime";
448
+ var AssistantRuntimeProviderImpl = ({ children, runtime }) => {
449
+ return /* @__PURE__ */ jsx3(AssistantProvider, { runtime, children });
450
+ };
451
+ var AssistantRuntimeProvider = memo(AssistantRuntimeProviderImpl);
452
+
453
+ // src/context/react/ComposerContext.ts
454
+ import { useContext as useContext4, useMemo as useMemo2 } from "react";
455
+ var useComposerContext = () => {
456
+ const { useComposer } = useThreadContext();
457
+ const { useEditComposer } = useContext4(MessageContext) ?? {};
458
+ return useMemo2(
459
+ () => ({
460
+ useComposer: useEditComposer ?? useComposer,
461
+ type: useEditComposer ? "edit" : "new"
462
+ }),
463
+ [useEditComposer, useComposer]
464
+ );
465
+ };
466
+
467
+ // src/context/react/ContentPartContext.ts
468
+ import { createContext as createContext4, useContext as useContext5 } from "react";
469
+ var ContentPartContext = createContext4(
470
+ null
471
+ );
472
+ var useContentPartContext = () => {
473
+ const context = useContext5(ContentPartContext);
474
+ if (!context)
475
+ throw new Error(
476
+ "This component can only be used inside a component passed to <MessagePrimitive.Content components={...} >."
477
+ );
478
+ return context;
479
+ };
480
+
481
+ // src/primitive-hooks/composer/useComposerCancel.tsx
159
482
  var useComposerCancel = () => {
160
483
  const { useComposer } = useComposerContext();
161
484
  const disabled = useComposer((c) => !c.isEditing);
@@ -180,7 +503,7 @@ var useComposerIf = (props) => {
180
503
  // src/primitive-hooks/composer/useComposerSend.tsx
181
504
  import { useCallback as useCallback7 } from "react";
182
505
  var useComposerSend = () => {
183
- const { useViewport } = useThreadContext();
506
+ const { useViewport, useComposer: useNewComposer } = useThreadContext();
184
507
  const { useComposer } = useComposerContext();
185
508
  const disabled = useComposer((c) => !c.isEditing || c.value.length === 0);
186
509
  const callback = useCallback7(() => {
@@ -188,7 +511,8 @@ var useComposerSend = () => {
188
511
  if (!composerState.isEditing) return;
189
512
  composerState.send();
190
513
  useViewport.getState().scrollToBottom();
191
- }, [useComposer, useViewport]);
514
+ useNewComposer.getState().focus();
515
+ }, [useNewComposer, useComposer, useViewport]);
192
516
  if (disabled) return null;
193
517
  return callback;
194
518
  };
@@ -280,12 +604,12 @@ var useThreadEmpty = () => {
280
604
  // src/primitive-hooks/thread/useThreadScrollToBottom.tsx
281
605
  import { useCallback as useCallback8 } from "react";
282
606
  var useThreadScrollToBottom = () => {
283
- const { useViewport } = useThreadContext();
607
+ const { useComposer, useViewport } = useThreadContext();
284
608
  const isAtBottom = useViewport((s) => s.isAtBottom);
285
609
  const handleScrollToBottom = useCallback8(() => {
286
- const { scrollToBottom } = useViewport.getState();
287
- scrollToBottom();
288
- }, [useViewport]);
610
+ useViewport.getState().scrollToBottom();
611
+ useComposer.getState().focus();
612
+ }, [useViewport, useComposer]);
289
613
  if (isAtBottom) return null;
290
614
  return handleScrollToBottom;
291
615
  };
@@ -310,416 +634,449 @@ var useThreadSuggestion = ({
310
634
  return callback;
311
635
  };
312
636
 
313
- // src/primitives/thread/index.ts
314
- var thread_exports = {};
315
- __export(thread_exports, {
316
- Empty: () => ThreadEmpty,
317
- If: () => ThreadIf,
318
- Messages: () => ThreadMessages,
319
- Root: () => ThreadRoot,
320
- ScrollToBottom: () => ThreadScrollToBottom,
321
- Suggestion: () => ThreadSuggestion,
322
- Viewport: () => ThreadViewport
637
+ // src/primitives/actionBar/index.ts
638
+ var actionBar_exports = {};
639
+ __export(actionBar_exports, {
640
+ Copy: () => ActionBarCopy,
641
+ Edit: () => ActionBarEdit,
642
+ Reload: () => ActionBarReload,
643
+ Root: () => ActionBarRoot
323
644
  });
324
645
 
325
- // src/primitives/thread/ThreadRoot.tsx
646
+ // src/primitives/actionBar/ActionBarRoot.tsx
326
647
  import { Primitive } from "@radix-ui/react-primitive";
327
648
  import { forwardRef } from "react";
328
- import { jsx } from "react/jsx-runtime";
329
- var ThreadRoot = forwardRef(
330
- (props, ref) => {
331
- return /* @__PURE__ */ jsx(Primitive.div, { ...props, ref });
332
- }
333
- );
334
- ThreadRoot.displayName = "ThreadRoot";
335
-
336
- // src/primitives/thread/ThreadEmpty.tsx
337
- var ThreadEmpty = ({ children }) => {
338
- const empty = useThreadEmpty();
339
- return empty ? children : null;
340
- };
341
-
342
- // src/primitives/thread/ThreadIf.tsx
343
- var ThreadIf = ({ children, ...query }) => {
344
- const result = useThreadIf(query);
345
- return result ? children : null;
649
+ import { jsx as jsx4 } from "react/jsx-runtime";
650
+ var useActionBarFloatStatus = ({
651
+ hideWhenRunning,
652
+ autohide,
653
+ autohideFloat
654
+ }) => {
655
+ const { useThread } = useThreadContext();
656
+ const { useMessage, useMessageUtils } = useMessageContext();
657
+ return useCombinedStore(
658
+ [useThread, useMessage, useMessageUtils],
659
+ (t, m, mu) => {
660
+ if (hideWhenRunning && t.isRunning) return "hidden" /* Hidden */;
661
+ const autohideEnabled = autohide === "always" || autohide === "not-last" && !m.isLast;
662
+ if (!autohideEnabled) return "normal" /* Normal */;
663
+ if (!mu.isHovering) return "hidden" /* Hidden */;
664
+ if (autohideFloat === "always" || autohideFloat === "single-branch" && m.branches.length <= 1)
665
+ return "floating" /* Floating */;
666
+ return "normal" /* Normal */;
667
+ }
668
+ );
346
669
  };
670
+ var ActionBarRoot = forwardRef(({ hideWhenRunning, autohide, autohideFloat, ...rest }, ref) => {
671
+ const hideAndfloatStatus = useActionBarFloatStatus({
672
+ hideWhenRunning,
673
+ autohide,
674
+ autohideFloat
675
+ });
676
+ if (hideAndfloatStatus === "hidden" /* Hidden */) return null;
677
+ return /* @__PURE__ */ jsx4(
678
+ Primitive.div,
679
+ {
680
+ ...hideAndfloatStatus === "floating" /* Floating */ ? { "data-floating": "true" } : null,
681
+ ...rest,
682
+ ref
683
+ }
684
+ );
685
+ });
686
+ ActionBarRoot.displayName = "ActionBarRoot";
347
687
 
348
- // src/primitives/thread/ThreadViewport.tsx
349
- import { useComposedRefs as useComposedRefs2 } from "@radix-ui/react-compose-refs";
688
+ // src/utils/createActionButton.tsx
689
+ import { composeEventHandlers } from "@radix-ui/primitive";
350
690
  import { Primitive as Primitive2 } from "@radix-ui/react-primitive";
351
691
  import { forwardRef as forwardRef2 } from "react";
692
+ import { jsx as jsx5 } from "react/jsx-runtime";
693
+ var createActionButton = (displayName, useActionButton) => {
694
+ const ActionButton = forwardRef2((props, forwardedRef) => {
695
+ const callback = useActionButton(props);
696
+ return /* @__PURE__ */ jsx5(
697
+ Primitive2.button,
698
+ {
699
+ type: "button",
700
+ disabled: !callback,
701
+ ...props,
702
+ ref: forwardedRef,
703
+ onClick: composeEventHandlers(props.onClick, () => {
704
+ callback?.();
705
+ })
706
+ }
707
+ );
708
+ });
709
+ ActionButton.displayName = displayName;
710
+ return ActionButton;
711
+ };
352
712
 
353
- // src/primitive-hooks/thread/useThreadViewportAutoScroll.tsx
354
- import { useComposedRefs } from "@radix-ui/react-compose-refs";
355
- import { useRef as useRef2 } from "react";
713
+ // src/primitives/actionBar/ActionBarCopy.tsx
714
+ var ActionBarCopy = createActionButton(
715
+ "ActionBarCopy",
716
+ useActionBarCopy
717
+ );
356
718
 
357
- // src/utils/hooks/useOnResizeContent.tsx
358
- import { useCallbackRef } from "@radix-ui/react-use-callback-ref";
359
- import { useCallback as useCallback11 } from "react";
719
+ // src/primitives/actionBar/ActionBarReload.tsx
720
+ var ActionBarReload = createActionButton(
721
+ "ActionBarReload",
722
+ useActionBarReload
723
+ );
360
724
 
361
- // src/utils/hooks/useManagedRef.ts
362
- import { useCallback as useCallback10, useRef } from "react";
363
- var useManagedRef = (callback) => {
364
- const cleanupRef = useRef();
365
- const ref = useCallback10(
366
- (el) => {
367
- if (cleanupRef.current) {
368
- cleanupRef.current();
369
- }
370
- if (el) {
371
- cleanupRef.current = callback(el);
372
- }
373
- },
374
- [callback]
375
- );
376
- return ref;
377
- };
725
+ // src/primitives/actionBar/ActionBarEdit.tsx
726
+ var ActionBarEdit = createActionButton(
727
+ "ActionBarEdit",
728
+ useActionBarEdit
729
+ );
378
730
 
379
- // src/utils/hooks/useOnResizeContent.tsx
380
- var useOnResizeContent = (callback) => {
381
- const callbackRef = useCallbackRef(callback);
382
- const refCallback = useCallback11(
383
- (el) => {
384
- const resizeObserver = new ResizeObserver(() => {
385
- callbackRef();
386
- });
387
- const mutationObserver = new MutationObserver((mutations) => {
388
- for (const mutation of mutations) {
389
- for (const node of mutation.addedNodes) {
390
- if (node instanceof Element) {
391
- resizeObserver.observe(node);
392
- }
393
- }
394
- for (const node of mutation.removedNodes) {
395
- if (node instanceof Element) {
396
- resizeObserver.unobserve(node);
397
- }
398
- }
399
- }
400
- callbackRef();
401
- });
402
- resizeObserver.observe(el);
403
- mutationObserver.observe(el, { childList: true });
404
- for (const child of el.children) {
405
- resizeObserver.observe(child);
406
- }
407
- return () => {
408
- resizeObserver.disconnect();
409
- mutationObserver.disconnect();
410
- };
411
- },
412
- [callbackRef]
413
- );
414
- return useManagedRef(refCallback);
415
- };
731
+ // src/primitives/assistantModal/index.ts
732
+ var assistantModal_exports = {};
733
+ __export(assistantModal_exports, {
734
+ Content: () => AssistantModalContent,
735
+ Root: () => AssistantModalRoot,
736
+ Trigger: () => AssistantModalTrigger
737
+ });
416
738
 
417
- // src/utils/hooks/useOnScrollToBottom.tsx
418
- import { useCallbackRef as useCallbackRef2 } from "@radix-ui/react-use-callback-ref";
419
- import { useEffect } from "react";
420
- var useOnScrollToBottom = (callback) => {
421
- const callbackRef = useCallbackRef2(callback);
422
- const { useViewport } = useThreadContext();
423
- useEffect(() => {
424
- return useViewport.getState().onScrollToBottom(() => {
739
+ // src/primitives/assistantModal/AssistantModalRoot.tsx
740
+ import { useState as useState3 } from "react";
741
+ import * as PopoverPrimitive from "@radix-ui/react-popover";
742
+ import { composeEventHandlers as composeEventHandlers2 } from "@radix-ui/primitive";
743
+
744
+ // src/utils/hooks/useOnComposerFocus.tsx
745
+ import { useCallbackRef } from "@radix-ui/react-use-callback-ref";
746
+ import { useEffect as useEffect3 } from "react";
747
+ var useOnComposerFocus = (callback) => {
748
+ const callbackRef = useCallbackRef(callback);
749
+ const { useComposer } = useThreadContext();
750
+ useEffect3(() => {
751
+ return useComposer.getState().onFocus(() => {
425
752
  callbackRef();
426
753
  });
427
- }, [useViewport, callbackRef]);
754
+ }, [useComposer, callbackRef]);
428
755
  };
429
756
 
430
- // src/primitive-hooks/thread/useThreadViewportAutoScroll.tsx
431
- var useThreadViewportAutoScroll = ({
432
- autoScroll = true
757
+ // src/primitives/assistantModal/AssistantModalRoot.tsx
758
+ import { jsx as jsx6 } from "react/jsx-runtime";
759
+ var usePopoverScope = PopoverPrimitive.createPopoverScope();
760
+ var useAssistantModalOpenState = (defaultOpen = false) => {
761
+ const state = useState3(defaultOpen);
762
+ const [, setOpen] = state;
763
+ useOnComposerFocus(() => {
764
+ setOpen(true);
765
+ });
766
+ return state;
767
+ };
768
+ var AssistantModalRoot = ({
769
+ __scopeAssistantModal,
770
+ defaultOpen,
771
+ open,
772
+ onOpenChange,
773
+ ...rest
433
774
  }) => {
434
- const divRef = useRef2(null);
435
- const { useViewport } = useThreadContext();
436
- const firstRenderRef = useRef2(true);
437
- const lastScrollTop = useRef2(0);
438
- const isScrollingToBottomRef = useRef2(false);
439
- const scrollToBottom = () => {
440
- const div = divRef.current;
441
- if (!div || !autoScroll) return;
442
- const behavior = firstRenderRef.current ? "instant" : "auto";
443
- firstRenderRef.current = false;
444
- isScrollingToBottomRef.current = true;
445
- div.scrollTo({ top: div.scrollHeight, behavior });
446
- };
447
- const handleScroll = () => {
448
- const div = divRef.current;
449
- if (!div) return;
450
- const isAtBottom = useViewport.getState().isAtBottom;
451
- const newIsAtBottom = div.scrollHeight - div.scrollTop <= div.clientHeight;
452
- if (!newIsAtBottom && lastScrollTop.current < div.scrollTop) {
453
- } else {
454
- isScrollingToBottomRef.current = newIsAtBottom;
455
- if (newIsAtBottom !== isAtBottom) {
456
- useViewport.setState({
457
- isAtBottom: newIsAtBottom
458
- });
459
- }
460
- }
461
- lastScrollTop.current = div.scrollTop;
462
- };
463
- const resizeRef = useOnResizeContent(() => {
464
- if (!isScrollingToBottomRef.current && !useViewport.getState().isAtBottom && !firstRenderRef.current) {
465
- handleScroll();
466
- } else {
467
- scrollToBottom();
775
+ const scope = usePopoverScope(__scopeAssistantModal);
776
+ const [modalOpen, setOpen] = useAssistantModalOpenState(defaultOpen);
777
+ return /* @__PURE__ */ jsx6(
778
+ PopoverPrimitive.Root,
779
+ {
780
+ ...scope,
781
+ open: open === void 0 ? modalOpen : open,
782
+ onOpenChange: composeEventHandlers2(onOpenChange, setOpen),
783
+ ...rest
468
784
  }
469
- });
470
- const scrollRef = useManagedRef((el) => {
471
- el.addEventListener("scroll", handleScroll);
472
- return () => {
473
- el.removeEventListener("scroll", handleScroll);
474
- };
475
- });
476
- const autoScrollRef = useComposedRefs(resizeRef, scrollRef, divRef);
477
- useOnScrollToBottom(() => {
478
- scrollToBottom();
479
- });
480
- return autoScrollRef;
785
+ );
481
786
  };
787
+ AssistantModalRoot.displayName = "AssistantModalRoot";
482
788
 
483
- // src/primitives/thread/ThreadViewport.tsx
484
- import { jsx as jsx2 } from "react/jsx-runtime";
485
- var ThreadViewport = forwardRef2(({ autoScroll, onScroll, children, ...rest }, forwardedRef) => {
486
- const autoScrollRef = useThreadViewportAutoScroll({
487
- autoScroll
488
- });
489
- const ref = useComposedRefs2(forwardedRef, autoScrollRef);
490
- return /* @__PURE__ */ jsx2(Primitive2.div, { ...rest, ref, children });
491
- });
492
- ThreadViewport.displayName = "ThreadViewport";
493
-
494
- // src/primitives/thread/ThreadMessages.tsx
495
- import { memo } from "react";
496
-
497
- // src/context/providers/MessageProvider.tsx
498
- import { useEffect as useEffect2, useState } from "react";
499
- import { create as create3 } from "zustand";
500
-
501
- // src/context/stores/EditComposer.ts
502
- import { create } from "zustand";
789
+ // src/primitives/assistantModal/AssistantModalTrigger.tsx
790
+ import { forwardRef as forwardRef3 } from "react";
791
+ import * as PopoverPrimitive2 from "@radix-ui/react-popover";
792
+ import { jsx as jsx7 } from "react/jsx-runtime";
793
+ var AssistantModalTrigger = forwardRef3(
794
+ ({ __scopeAssistantModal, ...rest }, ref) => {
795
+ const scope = usePopoverScope(__scopeAssistantModal);
796
+ return /* @__PURE__ */ jsx7(PopoverPrimitive2.Trigger, { ...scope, ...rest, ref });
797
+ }
798
+ );
799
+ AssistantModalTrigger.displayName = "AssistantModalTrigger";
503
800
 
504
- // src/context/stores/BaseComposer.ts
505
- var makeBaseComposer = (set) => ({
506
- value: "",
507
- setValue: (value) => {
508
- set({ value });
801
+ // src/primitives/assistantModal/AssistantModalContent.tsx
802
+ import { forwardRef as forwardRef4 } from "react";
803
+ import * as PopoverPrimitive3 from "@radix-ui/react-popover";
804
+ import { composeEventHandlers as composeEventHandlers3 } from "@radix-ui/primitive";
805
+ import { jsx as jsx8 } from "react/jsx-runtime";
806
+ var AssistantModalContent = forwardRef4(
807
+ ({
808
+ __scopeAssistantModal,
809
+ side,
810
+ align,
811
+ onInteractOutside,
812
+ dissmissOnInteractOutside = false,
813
+ ...props
814
+ }, forwardedRef) => {
815
+ const scope = usePopoverScope(__scopeAssistantModal);
816
+ return /* @__PURE__ */ jsx8(PopoverPrimitive3.Portal, { ...scope, children: /* @__PURE__ */ jsx8(
817
+ PopoverPrimitive3.Content,
818
+ {
819
+ ...scope,
820
+ ...props,
821
+ ref: forwardedRef,
822
+ side: side ?? "top",
823
+ align: align ?? "end",
824
+ onInteractOutside: composeEventHandlers3(
825
+ onInteractOutside,
826
+ dissmissOnInteractOutside ? void 0 : (e) => e.preventDefault()
827
+ )
828
+ }
829
+ ) });
509
830
  }
510
- });
831
+ );
832
+ AssistantModalContent.displayName = "AssistantModalContent";
511
833
 
512
- // src/context/stores/EditComposer.ts
513
- var makeEditComposerStore = ({
514
- onEdit,
515
- onSend
516
- }) => create()((set, get, store) => ({
517
- ...makeBaseComposer(set, get, store),
518
- isEditing: false,
519
- edit: () => {
520
- const value = onEdit();
521
- set({ isEditing: true, value });
522
- },
523
- send: () => {
524
- const value = get().value;
525
- set({ isEditing: false });
526
- onSend(value);
527
- },
528
- cancel: () => {
529
- if (!get().isEditing) return false;
530
- set({ isEditing: false });
531
- return true;
532
- }
533
- }));
834
+ // src/primitives/branchPicker/index.ts
835
+ var branchPicker_exports = {};
836
+ __export(branchPicker_exports, {
837
+ Count: () => BranchPickerCount,
838
+ Next: () => BranchPickerNext,
839
+ Number: () => BranchPickerNumber,
840
+ Previous: () => BranchPickerPrevious,
841
+ Root: () => BranchPickerRoot
842
+ });
534
843
 
535
- // src/context/stores/MessageUtils.ts
536
- import { create as create2 } from "zustand";
537
- var makeMessageUtilsStore = () => create2((set) => ({
538
- inProgressIndicator: null,
539
- setInProgressIndicator: (value) => {
540
- set({ inProgressIndicator: value });
541
- },
542
- isCopied: false,
543
- setIsCopied: (value) => {
544
- set({ isCopied: value });
545
- },
546
- isHovering: false,
547
- setIsHovering: (value) => {
548
- set({ isHovering: value });
549
- }
550
- }));
844
+ // src/primitives/branchPicker/BranchPickerNext.tsx
845
+ var BranchPickerNext = createActionButton(
846
+ "BranchPickerNext",
847
+ useBranchPickerNext
848
+ );
551
849
 
552
- // src/context/providers/MessageProvider.tsx
553
- import { jsx as jsx3 } from "react/jsx-runtime";
554
- var getIsLast = (thread, message) => {
555
- return thread.messages[thread.messages.length - 1]?.id === message.id;
850
+ // src/primitives/branchPicker/BranchPickerPrevious.tsx
851
+ var BranchPickerPrevious = createActionButton(
852
+ "BranchPickerPrevious",
853
+ useBranchPickerPrevious
854
+ );
855
+
856
+ // src/primitives/branchPicker/BranchPickerCount.tsx
857
+ import { Fragment, jsx as jsx9 } from "react/jsx-runtime";
858
+ var BranchPickerCount = () => {
859
+ const branchCount = useBranchPickerCount();
860
+ return /* @__PURE__ */ jsx9(Fragment, { children: branchCount });
556
861
  };
557
- var syncMessage = (thread, getBranches, useMessage, messageIndex) => {
558
- const parentId = thread.messages[messageIndex - 1]?.id ?? null;
559
- const message = thread.messages[messageIndex];
560
- if (!message) return;
561
- const isLast = getIsLast(thread, message);
562
- const branches = getBranches(message.id);
563
- const currentState = useMessage.getState();
564
- if (currentState.message === message && currentState.parentId === parentId && currentState.branches === branches && currentState.isLast === isLast)
565
- return;
566
- useMessage.setState({
567
- message,
568
- parentId,
569
- branches,
570
- isLast
571
- });
862
+
863
+ // src/primitives/branchPicker/BranchPickerNumber.tsx
864
+ import { Fragment as Fragment2, jsx as jsx10 } from "react/jsx-runtime";
865
+ var BranchPickerNumber = () => {
866
+ const branchNumber = useBranchPickerNumber();
867
+ return /* @__PURE__ */ jsx10(Fragment2, { children: branchNumber });
572
868
  };
573
- var useMessageContext2 = (messageIndex) => {
574
- const { useThread, useThreadActions } = useThreadContext();
575
- const [context] = useState(() => {
576
- const useMessage = create3(() => ({}));
577
- const useMessageUtils = makeMessageUtilsStore();
578
- const useEditComposer = makeEditComposerStore({
579
- onEdit: () => {
580
- const message = useMessage.getState().message;
581
- if (message.role !== "user")
582
- throw new Error(
583
- "Tried to edit a non-user message. Editing is only supported for user messages. This is likely an internal bug in assistant-ui."
584
- );
585
- const text = getMessageText(message);
586
- return text;
587
- },
588
- onSend: (text) => {
589
- const { message, parentId } = useMessage.getState();
590
- if (message.role !== "user")
591
- throw new Error(
592
- "Tried to edit a non-user message. Editing is only supported for user messages. This is likely an internal bug in assistant-ui."
593
- );
594
- const nonTextParts = message.content.filter(
595
- (part) => part.type !== "text" && part.type !== "ui"
596
- );
597
- useThreadActions.getState().append({
598
- parentId,
599
- role: "user",
600
- content: [{ type: "text", text }, ...nonTextParts]
601
- });
869
+
870
+ // src/primitives/branchPicker/BranchPickerRoot.tsx
871
+ import { Primitive as Primitive6 } from "@radix-ui/react-primitive";
872
+ import { forwardRef as forwardRef8 } from "react";
873
+
874
+ // src/primitives/message/index.ts
875
+ var message_exports = {};
876
+ __export(message_exports, {
877
+ Content: () => MessageContent,
878
+ If: () => MessageIf,
879
+ InProgress: () => MessageInProgress,
880
+ Root: () => MessageRoot
881
+ });
882
+
883
+ // src/primitives/message/MessageRoot.tsx
884
+ import { composeEventHandlers as composeEventHandlers4 } from "@radix-ui/primitive";
885
+ import { Primitive as Primitive3 } from "@radix-ui/react-primitive";
886
+ import { forwardRef as forwardRef5 } from "react";
887
+ import { jsx as jsx11 } from "react/jsx-runtime";
888
+ var MessageRoot = forwardRef5(
889
+ ({ onMouseEnter, onMouseLeave, ...rest }, ref) => {
890
+ const { useMessageUtils } = useMessageContext();
891
+ const setIsHovering = useMessageUtils((s) => s.setIsHovering);
892
+ const handleMouseEnter = () => {
893
+ setIsHovering(true);
894
+ };
895
+ const handleMouseLeave = () => {
896
+ setIsHovering(false);
897
+ };
898
+ return /* @__PURE__ */ jsx11(
899
+ Primitive3.div,
900
+ {
901
+ ...rest,
902
+ ref,
903
+ onMouseEnter: composeEventHandlers4(onMouseEnter, handleMouseEnter),
904
+ onMouseLeave: composeEventHandlers4(onMouseLeave, handleMouseLeave)
602
905
  }
603
- });
604
- syncMessage(
605
- useThread.getState(),
606
- useThreadActions.getState().getBranches,
607
- useMessage,
608
- messageIndex
609
906
  );
610
- return { useMessage, useMessageUtils, useEditComposer };
907
+ }
908
+ );
909
+ MessageRoot.displayName = "MessageRoot";
910
+
911
+ // src/primitives/message/MessageIf.tsx
912
+ var MessageIf = ({ children, ...query }) => {
913
+ const result = useMessageIf(query);
914
+ return result ? children : null;
915
+ };
916
+
917
+ // src/primitives/message/MessageContent.tsx
918
+ import { memo as memo2 } from "react";
919
+
920
+ // src/context/providers/ContentPartProvider.tsx
921
+ import { useEffect as useEffect4, useState as useState4 } from "react";
922
+ import { create as create7 } from "zustand";
923
+ import { jsx as jsx12 } from "react/jsx-runtime";
924
+ var syncContentPart = ({ message }, useContentPart, partIndex) => {
925
+ const part = message.content[partIndex];
926
+ if (!part) return;
927
+ const messageStatus = message.role === "assistant" ? message.status : "done";
928
+ const status = partIndex === message.content.length - 1 ? messageStatus : "done";
929
+ const currentState = useContentPart.getState();
930
+ if (currentState.part === part && currentState.status === status) return;
931
+ useContentPart.setState(
932
+ Object.freeze({
933
+ part,
934
+ status
935
+ })
936
+ );
937
+ };
938
+ var useContentPartContext2 = (partIndex) => {
939
+ const { useMessage } = useMessageContext();
940
+ const [context] = useState4(() => {
941
+ const useContentPart = create7(
942
+ () => ({})
943
+ );
944
+ syncContentPart(useMessage.getState(), useContentPart, partIndex);
945
+ return { useContentPart };
611
946
  });
612
- useEffect2(() => {
613
- return useThread.subscribe((thread) => {
614
- syncMessage(
615
- thread,
616
- useThreadActions.getState().getBranches,
617
- context.useMessage,
618
- messageIndex
619
- );
947
+ useEffect4(() => {
948
+ syncContentPart(useMessage.getState(), context.useContentPart, partIndex);
949
+ return useMessage.subscribe((message) => {
950
+ syncContentPart(message, context.useContentPart, partIndex);
620
951
  });
621
- }, [useThread, useThreadActions, context, messageIndex]);
952
+ }, [context, useMessage, partIndex]);
622
953
  return context;
623
954
  };
624
- var MessageProvider = ({
625
- messageIndex,
955
+ var ContentPartProvider = ({
956
+ partIndex,
626
957
  children
627
958
  }) => {
628
- const context = useMessageContext2(messageIndex);
629
- return /* @__PURE__ */ jsx3(MessageContext.Provider, { value: context, children });
959
+ const context = useContentPartContext2(partIndex);
960
+ return /* @__PURE__ */ jsx12(ContentPartContext.Provider, { value: context, children });
630
961
  };
631
962
 
632
- // src/primitives/composer/ComposerIf.tsx
633
- var ComposerIf = ({ children, ...query }) => {
634
- const result = useComposerIf(query);
635
- return result ? children : null;
963
+ // src/primitives/contentPart/ContentPartDisplay.tsx
964
+ var ContentPartDisplay = () => {
965
+ const display = useContentPartDisplay();
966
+ return display ?? null;
636
967
  };
637
968
 
638
- // src/primitives/message/MessageIf.tsx
639
- var MessageIf = ({ children, ...query }) => {
640
- const result = useMessageIf(query);
641
- return result ? children : null;
969
+ // src/primitives/contentPart/ContentPartInProgressIndicator.tsx
970
+ var ContentPartInProgressIndicator = () => {
971
+ const indicator = useContentPartInProgressIndicator();
972
+ return indicator;
642
973
  };
643
974
 
644
- // src/primitives/thread/ThreadMessages.tsx
645
- import { jsx as jsx4, jsxs } from "react/jsx-runtime";
646
- var getComponents = (components) => {
647
- return {
648
- EditComposer: components.EditComposer ?? components.UserMessage ?? components.Message,
649
- UserMessage: components.UserMessage ?? components.Message,
650
- AssistantMessage: components.AssistantMessage ?? components.Message
651
- };
975
+ // src/primitives/contentPart/ContentPartText.tsx
976
+ import { Primitive as Primitive4 } from "@radix-ui/react-primitive";
977
+ import { forwardRef as forwardRef6 } from "react";
978
+ import { jsx as jsx13 } from "react/jsx-runtime";
979
+ var ContentPartText = forwardRef6((props, forwardedRef) => {
980
+ const text = useContentPartText();
981
+ return /* @__PURE__ */ jsx13(Primitive4.p, { ...props, ref: forwardedRef, children: text });
982
+ });
983
+ ContentPartText.displayName = "ContentPartText";
984
+
985
+ // src/primitives/message/MessageContent.tsx
986
+ import { Fragment as Fragment3, jsx as jsx14, jsxs as jsxs2 } from "react/jsx-runtime";
987
+ var defaultComponents = {
988
+ Text: () => /* @__PURE__ */ jsxs2(Fragment3, { children: [
989
+ /* @__PURE__ */ jsx14(ContentPartText, { style: { whiteSpace: "pre-line" } }),
990
+ /* @__PURE__ */ jsx14(ContentPartInProgressIndicator, {})
991
+ ] }),
992
+ Image: () => null,
993
+ UI: () => /* @__PURE__ */ jsx14(ContentPartDisplay, {}),
994
+ tools: {
995
+ Fallback: (props) => {
996
+ const { useToolUIs } = useAssistantContext();
997
+ const Render = useToolUIs((s) => s.getToolUI(props.part.toolName));
998
+ if (!Render) return null;
999
+ return /* @__PURE__ */ jsx14(Render, { ...props });
1000
+ }
1001
+ }
652
1002
  };
653
- var ThreadMessageImpl = ({
654
- messageIndex,
655
- components
1003
+ var MessageContentPartComponent = ({
1004
+ components: {
1005
+ Text = defaultComponents.Text,
1006
+ Image = defaultComponents.Image,
1007
+ UI = defaultComponents.UI,
1008
+ tools: { by_name = {}, Fallback = defaultComponents.tools.Fallback } = {}
1009
+ } = {}
656
1010
  }) => {
657
- const { UserMessage, EditComposer, AssistantMessage } = getComponents(components);
658
- return /* @__PURE__ */ jsxs(MessageProvider, { messageIndex, children: [
659
- /* @__PURE__ */ jsxs(MessageIf, { user: true, children: [
660
- /* @__PURE__ */ jsx4(ComposerIf, { editing: false, children: /* @__PURE__ */ jsx4(UserMessage, {}) }),
661
- /* @__PURE__ */ jsx4(ComposerIf, { editing: true, children: /* @__PURE__ */ jsx4(EditComposer, {}) })
662
- ] }),
663
- /* @__PURE__ */ jsx4(MessageIf, { assistant: true, children: /* @__PURE__ */ jsx4(AssistantMessage, {}) })
664
- ] });
665
- };
666
- var ThreadMessage = memo(
667
- ThreadMessageImpl,
668
- (prev, next) => prev.messageIndex === next.messageIndex && prev.components.UserMessage === next.components.UserMessage && prev.components.EditComposer === next.components.EditComposer && prev.components.AssistantMessage === next.components.AssistantMessage
1011
+ const { useThreadActions } = useThreadContext();
1012
+ const addToolResult = useThreadActions((t) => t.addToolResult);
1013
+ const { useContentPart } = useContentPartContext();
1014
+ const { part, status } = useContentPart();
1015
+ const type = part.type;
1016
+ switch (type) {
1017
+ case "text":
1018
+ return /* @__PURE__ */ jsx14(Text, { part, status });
1019
+ case "image":
1020
+ return /* @__PURE__ */ jsx14(Image, { part, status });
1021
+ case "ui":
1022
+ return /* @__PURE__ */ jsx14(UI, { part, status });
1023
+ case "tool-call": {
1024
+ const Tool = by_name[part.toolName] || Fallback;
1025
+ const addResult = (result) => addToolResult(part.toolCallId, result);
1026
+ return /* @__PURE__ */ jsx14(Tool, { part, status, addResult });
1027
+ }
1028
+ default:
1029
+ throw new Error(`Unknown content part type: ${type}`);
1030
+ }
1031
+ };
1032
+ var MessageContentPartImpl = ({
1033
+ partIndex,
1034
+ components
1035
+ }) => {
1036
+ return /* @__PURE__ */ jsx14(ContentPartProvider, { partIndex, children: /* @__PURE__ */ jsx14(MessageContentPartComponent, { components }) });
1037
+ };
1038
+ var MessageContentPart = memo2(
1039
+ MessageContentPartImpl,
1040
+ (prev, next) => prev.partIndex === next.partIndex && prev.components?.Text === next.components?.Text && prev.components?.Image === next.components?.Image && prev.components?.UI === next.components?.UI && prev.components?.tools === next.components?.tools
669
1041
  );
670
- var ThreadMessages = ({ components }) => {
671
- const { useThread } = useThreadContext();
672
- const messagesLength = useThread((t) => t.messages.length);
673
- if (messagesLength === 0) return null;
674
- return new Array(messagesLength).fill(null).map((_, idx) => {
675
- const messageIndex = idx;
676
- return /* @__PURE__ */ jsx4(
677
- ThreadMessage,
1042
+ var MessageContent = ({ components }) => {
1043
+ const { useMessage } = useMessageContext();
1044
+ const contentLength = useMessage((s) => s.message.content.length);
1045
+ return new Array(contentLength).fill(null).map((_, idx) => {
1046
+ const partIndex = idx;
1047
+ return /* @__PURE__ */ jsx14(
1048
+ MessageContentPart,
678
1049
  {
679
- messageIndex,
1050
+ partIndex,
680
1051
  components
681
1052
  },
682
- messageIndex
683
- );
684
- });
685
- };
686
-
687
- // src/utils/createActionButton.tsx
688
- import { composeEventHandlers } from "@radix-ui/primitive";
689
- import { Primitive as Primitive3 } from "@radix-ui/react-primitive";
690
- import { forwardRef as forwardRef3 } from "react";
691
- import { jsx as jsx5 } from "react/jsx-runtime";
692
- var createActionButton = (displayName, useActionButton) => {
693
- const ActionButton = forwardRef3((props, forwardedRef) => {
694
- const callback = useActionButton(props);
695
- return /* @__PURE__ */ jsx5(
696
- Primitive3.button,
697
- {
698
- type: "button",
699
- disabled: !callback,
700
- ...props,
701
- ref: forwardedRef,
702
- onClick: composeEventHandlers(props.onClick, () => {
703
- callback?.();
704
- })
705
- }
1053
+ partIndex
706
1054
  );
707
1055
  });
708
- ActionButton.displayName = displayName;
709
- return ActionButton;
710
1056
  };
711
1057
 
712
- // src/primitives/thread/ThreadScrollToBottom.tsx
713
- var ThreadScrollToBottom = createActionButton(
714
- "ThreadScrollToBottom",
715
- useThreadScrollToBottom
716
- );
1058
+ // src/primitives/message/MessageInProgress.tsx
1059
+ import { Primitive as Primitive5 } from "@radix-ui/react-primitive";
1060
+ import {
1061
+ forwardRef as forwardRef7,
1062
+ useMemo as useMemo3
1063
+ } from "react";
1064
+ import { jsx as jsx15 } from "react/jsx-runtime";
1065
+ var MessageInProgress = forwardRef7((props, ref) => {
1066
+ const { useMessageUtils } = useMessageContext();
1067
+ useMemo3(() => {
1068
+ useMessageUtils.getState().setInProgressIndicator(/* @__PURE__ */ jsx15(Primitive5.span, { ...props, ref }));
1069
+ }, [useMessageUtils, props, ref]);
1070
+ return null;
1071
+ });
1072
+ MessageInProgress.displayName = "MessageInProgress";
717
1073
 
718
- // src/primitives/thread/ThreadSuggestion.tsx
719
- var ThreadSuggestion = createActionButton(
720
- "ThreadSuggestion",
721
- useThreadSuggestion
722
- );
1074
+ // src/primitives/branchPicker/BranchPickerRoot.tsx
1075
+ import { jsx as jsx16 } from "react/jsx-runtime";
1076
+ var BranchPickerRoot = forwardRef8(({ hideWhenSingleBranch, ...rest }, ref) => {
1077
+ return /* @__PURE__ */ jsx16(MessageIf, { hasBranches: hideWhenSingleBranch ? true : void 0, children: /* @__PURE__ */ jsx16(Primitive6.div, { ...rest, ref }) });
1078
+ });
1079
+ BranchPickerRoot.displayName = "BranchPickerRoot";
723
1080
 
724
1081
  // src/primitives/composer/index.ts
725
1082
  var composer_exports = {};
@@ -732,13 +1089,13 @@ __export(composer_exports, {
732
1089
  });
733
1090
 
734
1091
  // src/primitives/composer/ComposerRoot.tsx
735
- import { composeEventHandlers as composeEventHandlers2 } from "@radix-ui/primitive";
736
- import { Primitive as Primitive4 } from "@radix-ui/react-primitive";
1092
+ import { composeEventHandlers as composeEventHandlers5 } from "@radix-ui/primitive";
1093
+ import { Primitive as Primitive7 } from "@radix-ui/react-primitive";
737
1094
  import {
738
- forwardRef as forwardRef4
1095
+ forwardRef as forwardRef9
739
1096
  } from "react";
740
- import { jsx as jsx6 } from "react/jsx-runtime";
741
- var ComposerRoot = forwardRef4(
1097
+ import { jsx as jsx17 } from "react/jsx-runtime";
1098
+ var ComposerRoot = forwardRef9(
742
1099
  ({ onSubmit, ...rest }, forwardedRef) => {
743
1100
  const send = useComposerSend();
744
1101
  const handleSubmit = (e) => {
@@ -746,12 +1103,12 @@ var ComposerRoot = forwardRef4(
746
1103
  e.preventDefault();
747
1104
  send();
748
1105
  };
749
- return /* @__PURE__ */ jsx6(
750
- Primitive4.form,
1106
+ return /* @__PURE__ */ jsx17(
1107
+ Primitive7.form,
751
1108
  {
752
1109
  ...rest,
753
1110
  ref: forwardedRef,
754
- onSubmit: composeEventHandlers2(onSubmit, handleSubmit)
1111
+ onSubmit: composeEventHandlers5(onSubmit, handleSubmit)
755
1112
  }
756
1113
  );
757
1114
  }
@@ -759,19 +1116,19 @@ var ComposerRoot = forwardRef4(
759
1116
  ComposerRoot.displayName = "ComposerRoot";
760
1117
 
761
1118
  // src/primitives/composer/ComposerInput.tsx
762
- import { composeEventHandlers as composeEventHandlers3 } from "@radix-ui/primitive";
763
- import { useComposedRefs as useComposedRefs3 } from "@radix-ui/react-compose-refs";
1119
+ import { composeEventHandlers as composeEventHandlers6 } from "@radix-ui/primitive";
1120
+ import { useComposedRefs } from "@radix-ui/react-compose-refs";
764
1121
  import { Slot } from "@radix-ui/react-slot";
765
1122
  import {
766
- forwardRef as forwardRef5,
767
- useCallback as useCallback12,
768
- useEffect as useEffect3,
1123
+ forwardRef as forwardRef10,
1124
+ useCallback as useCallback10,
1125
+ useEffect as useEffect5,
769
1126
  useRef as useRef3
770
1127
  } from "react";
771
1128
  import TextareaAutosize from "react-textarea-autosize";
772
1129
  import { useEscapeKeydown } from "@radix-ui/react-use-escape-keydown";
773
- import { jsx as jsx7 } from "react/jsx-runtime";
774
- var ComposerInput = forwardRef5(
1130
+ import { jsx as jsx18 } from "react/jsx-runtime";
1131
+ var ComposerInput = forwardRef10(
775
1132
  ({ autoFocus = false, asChild, disabled, onChange, onKeyDown, ...rest }, forwardedRef) => {
776
1133
  const { useThread } = useThreadContext();
777
1134
  const { useComposer, type } = useComposerContext();
@@ -781,7 +1138,7 @@ var ComposerInput = forwardRef5(
781
1138
  });
782
1139
  const Component = asChild ? Slot : TextareaAutosize;
783
1140
  const textareaRef = useRef3(null);
784
- const ref = useComposedRefs3(forwardedRef, textareaRef);
1141
+ const ref = useComposedRefs(forwardedRef, textareaRef);
785
1142
  useEscapeKeydown((e) => {
786
1143
  const composer = useComposer.getState();
787
1144
  if (composer.cancel()) {
@@ -799,35 +1156,34 @@ var ComposerInput = forwardRef5(
799
1156
  }
800
1157
  };
801
1158
  const autoFocusEnabled = autoFocus && !disabled;
802
- const focus = useCallback12(() => {
1159
+ const focus = useCallback10(() => {
803
1160
  const textarea = textareaRef.current;
804
1161
  if (!textarea || !autoFocusEnabled) return;
805
- textarea.focus();
1162
+ textarea.focus({ preventScroll: true });
806
1163
  textarea.setSelectionRange(
807
1164
  textareaRef.current.value.length,
808
1165
  textareaRef.current.value.length
809
1166
  );
810
1167
  }, [autoFocusEnabled]);
811
- useEffect3(() => focus(), [focus]);
812
- useOnScrollToBottom(() => {
1168
+ useEffect5(() => focus(), [focus]);
1169
+ useOnComposerFocus(() => {
813
1170
  if (type === "new") {
814
1171
  focus();
815
1172
  }
816
1173
  });
817
- return /* @__PURE__ */ jsx7(
1174
+ return /* @__PURE__ */ jsx18(
818
1175
  Component,
819
1176
  {
820
1177
  value,
821
1178
  ...rest,
822
1179
  ref,
823
- autoFocus,
824
1180
  disabled,
825
- onChange: composeEventHandlers3(onChange, (e) => {
1181
+ onChange: composeEventHandlers6(onChange, (e) => {
826
1182
  const composerState = useComposer.getState();
827
1183
  if (!composerState.isEditing) return;
828
1184
  return composerState.setValue(e.target.value);
829
1185
  }),
830
- onKeyDown: composeEventHandlers3(onKeyDown, handleKeyPress)
1186
+ onKeyDown: composeEventHandlers6(onKeyDown, handleKeyPress)
831
1187
  }
832
1188
  );
833
1189
  }
@@ -835,15 +1191,15 @@ var ComposerInput = forwardRef5(
835
1191
  ComposerInput.displayName = "ComposerInput";
836
1192
 
837
1193
  // src/primitives/composer/ComposerSend.tsx
838
- import { forwardRef as forwardRef6 } from "react";
839
- import { Primitive as Primitive5 } from "@radix-ui/react-primitive";
840
- import { jsx as jsx8 } from "react/jsx-runtime";
841
- var ComposerSend = forwardRef6(
1194
+ import { forwardRef as forwardRef11 } from "react";
1195
+ import { Primitive as Primitive8 } from "@radix-ui/react-primitive";
1196
+ import { jsx as jsx19 } from "react/jsx-runtime";
1197
+ var ComposerSend = forwardRef11(
842
1198
  ({ disabled, ...rest }, ref) => {
843
1199
  const { useComposer } = useComposerContext();
844
1200
  const hasValue = useComposer((c) => c.isEditing && c.value.length > 0);
845
- return /* @__PURE__ */ jsx8(
846
- Primitive5.button,
1201
+ return /* @__PURE__ */ jsx19(
1202
+ Primitive8.button,
847
1203
  {
848
1204
  type: "submit",
849
1205
  ...rest,
@@ -861,363 +1217,397 @@ var ComposerCancel = createActionButton(
861
1217
  useComposerCancel
862
1218
  );
863
1219
 
864
- // src/primitives/message/index.ts
865
- var message_exports = {};
866
- __export(message_exports, {
867
- Content: () => MessageContent,
868
- If: () => MessageIf,
869
- InProgress: () => MessageInProgress,
870
- Root: () => MessageRoot
1220
+ // src/primitives/composer/ComposerIf.tsx
1221
+ var ComposerIf = ({ children, ...query }) => {
1222
+ const result = useComposerIf(query);
1223
+ return result ? children : null;
1224
+ };
1225
+
1226
+ // src/primitives/contentPart/index.ts
1227
+ var contentPart_exports = {};
1228
+ __export(contentPart_exports, {
1229
+ Display: () => ContentPartDisplay,
1230
+ Image: () => ContentPartImage,
1231
+ InProgressIndicator: () => ContentPartInProgressIndicator,
1232
+ Text: () => ContentPartText
871
1233
  });
872
1234
 
873
- // src/primitives/message/MessageRoot.tsx
874
- import { composeEventHandlers as composeEventHandlers4 } from "@radix-ui/primitive";
875
- import { Primitive as Primitive6 } from "@radix-ui/react-primitive";
876
- import { forwardRef as forwardRef7 } from "react";
877
- import { jsx as jsx9 } from "react/jsx-runtime";
878
- var MessageRoot = forwardRef7(
879
- ({ onMouseEnter, onMouseLeave, ...rest }, ref) => {
880
- const { useMessageUtils } = useMessageContext();
881
- const setIsHovering = useMessageUtils((s) => s.setIsHovering);
882
- const handleMouseEnter = () => {
883
- setIsHovering(true);
884
- };
885
- const handleMouseLeave = () => {
886
- setIsHovering(false);
887
- };
888
- return /* @__PURE__ */ jsx9(
889
- Primitive6.div,
890
- {
891
- ...rest,
892
- ref,
893
- onMouseEnter: composeEventHandlers4(onMouseEnter, handleMouseEnter),
894
- onMouseLeave: composeEventHandlers4(onMouseLeave, handleMouseLeave)
895
- }
896
- );
1235
+ // src/primitives/contentPart/ContentPartImage.tsx
1236
+ import { Primitive as Primitive9 } from "@radix-ui/react-primitive";
1237
+ import { forwardRef as forwardRef12 } from "react";
1238
+ import { jsx as jsx20 } from "react/jsx-runtime";
1239
+ var ContentPartImage = forwardRef12((props, forwardedRef) => {
1240
+ const image = useContentPartImage();
1241
+ return /* @__PURE__ */ jsx20(Primitive9.img, { src: image, ...props, ref: forwardedRef });
1242
+ });
1243
+ ContentPartImage.displayName = "ContentPartImage";
1244
+
1245
+ // src/primitives/thread/index.ts
1246
+ var thread_exports = {};
1247
+ __export(thread_exports, {
1248
+ Empty: () => ThreadEmpty,
1249
+ If: () => ThreadIf,
1250
+ Messages: () => ThreadMessages,
1251
+ Root: () => ThreadRoot,
1252
+ ScrollToBottom: () => ThreadScrollToBottom,
1253
+ Suggestion: () => ThreadSuggestion,
1254
+ Viewport: () => ThreadViewport
1255
+ });
1256
+
1257
+ // src/primitives/thread/ThreadRoot.tsx
1258
+ import { Primitive as Primitive10 } from "@radix-ui/react-primitive";
1259
+ import { forwardRef as forwardRef13 } from "react";
1260
+ import { jsx as jsx21 } from "react/jsx-runtime";
1261
+ var ThreadRoot = forwardRef13(
1262
+ (props, ref) => {
1263
+ return /* @__PURE__ */ jsx21(Primitive10.div, { ...props, ref });
897
1264
  }
898
1265
  );
899
- MessageRoot.displayName = "MessageRoot";
900
-
901
- // src/primitives/message/MessageContent.tsx
902
- import { memo as memo2 } from "react";
1266
+ ThreadRoot.displayName = "ThreadRoot";
903
1267
 
904
- // src/context/providers/ContentPartProvider.tsx
905
- import { useEffect as useEffect4, useState as useState2 } from "react";
906
- import { create as create4 } from "zustand";
907
- import { jsx as jsx10 } from "react/jsx-runtime";
908
- var syncContentPart = ({ message }, useContentPart, partIndex) => {
909
- const part = message.content[partIndex];
910
- if (!part) return;
911
- const messageStatus = message.role === "assistant" ? message.status : "done";
912
- const status = partIndex === message.content.length - 1 ? messageStatus : "done";
913
- const currentState = useContentPart.getState();
914
- if (currentState.part === part && currentState.status === status) return;
915
- useContentPart.setState(
916
- Object.freeze({
917
- part,
918
- status
919
- })
920
- );
921
- };
922
- var useContentPartContext2 = (partIndex) => {
923
- const { useMessage } = useMessageContext();
924
- const [context] = useState2(() => {
925
- const useContentPart = create4(
926
- () => ({})
927
- );
928
- syncContentPart(useMessage.getState(), useContentPart, partIndex);
929
- return { useContentPart };
930
- });
931
- useEffect4(() => {
932
- syncContentPart(useMessage.getState(), context.useContentPart, partIndex);
933
- return useMessage.subscribe((message) => {
934
- syncContentPart(message, context.useContentPart, partIndex);
935
- });
936
- }, [context, useMessage, partIndex]);
937
- return context;
938
- };
939
- var ContentPartProvider = ({
940
- partIndex,
941
- children
942
- }) => {
943
- const context = useContentPartContext2(partIndex);
944
- return /* @__PURE__ */ jsx10(ContentPartContext.Provider, { value: context, children });
1268
+ // src/primitives/thread/ThreadEmpty.tsx
1269
+ var ThreadEmpty = ({ children }) => {
1270
+ const empty = useThreadEmpty();
1271
+ return empty ? children : null;
945
1272
  };
946
1273
 
947
- // src/primitives/contentPart/ContentPartDisplay.tsx
948
- var ContentPartDisplay = () => {
949
- const display = useContentPartDisplay();
950
- return display ?? null;
1274
+ // src/primitives/thread/ThreadIf.tsx
1275
+ var ThreadIf = ({ children, ...query }) => {
1276
+ const result = useThreadIf(query);
1277
+ return result ? children : null;
951
1278
  };
952
1279
 
953
- // src/primitives/contentPart/ContentPartInProgressIndicator.tsx
954
- var ContentPartInProgressIndicator = () => {
955
- const indicator = useContentPartInProgressIndicator();
956
- return indicator;
957
- };
1280
+ // src/primitives/thread/ThreadViewport.tsx
1281
+ import { useComposedRefs as useComposedRefs3 } from "@radix-ui/react-compose-refs";
1282
+ import { Primitive as Primitive11 } from "@radix-ui/react-primitive";
1283
+ import { forwardRef as forwardRef14 } from "react";
958
1284
 
959
- // src/primitives/contentPart/ContentPartText.tsx
960
- import { Primitive as Primitive7 } from "@radix-ui/react-primitive";
961
- import { forwardRef as forwardRef8 } from "react";
962
- import { jsx as jsx11 } from "react/jsx-runtime";
963
- var ContentPartText = forwardRef8((props, forwardedRef) => {
964
- const text = useContentPartText();
965
- return /* @__PURE__ */ jsx11(Primitive7.span, { ...props, ref: forwardedRef, children: text });
966
- });
967
- ContentPartText.displayName = "ContentPartText";
1285
+ // src/primitive-hooks/thread/useThreadViewportAutoScroll.tsx
1286
+ import { useComposedRefs as useComposedRefs2 } from "@radix-ui/react-compose-refs";
1287
+ import { useRef as useRef5 } from "react";
968
1288
 
969
- // src/primitives/message/MessageContent.tsx
970
- import { Fragment, jsx as jsx12, jsxs as jsxs2 } from "react/jsx-runtime";
971
- var defaultComponents = {
972
- Text: () => /* @__PURE__ */ jsxs2(Fragment, { children: [
973
- /* @__PURE__ */ jsx12(ContentPartText, {}),
974
- /* @__PURE__ */ jsx12(ContentPartInProgressIndicator, {})
975
- ] }),
976
- Image: () => null,
977
- UI: () => /* @__PURE__ */ jsx12(ContentPartDisplay, {}),
978
- tools: {
979
- Fallback: (props) => {
980
- const { useToolUIs } = useAssistantContext();
981
- const Render = useToolUIs((s) => s.getToolUI(props.part.toolName));
982
- if (!Render) return null;
983
- return /* @__PURE__ */ jsx12(Render, { ...props });
984
- }
985
- }
986
- };
987
- var MessageContentPartComponent = ({
988
- components: {
989
- Text = defaultComponents.Text,
990
- Image = defaultComponents.Image,
991
- UI = defaultComponents.UI,
992
- tools: { by_name = {}, Fallback = defaultComponents.tools.Fallback } = {}
993
- } = {}
994
- }) => {
995
- const { useThreadActions } = useThreadContext();
996
- const addToolResult = useThreadActions((t) => t.addToolResult);
997
- const { useContentPart } = useContentPartContext();
998
- const { part, status } = useContentPart();
999
- const type = part.type;
1000
- switch (type) {
1001
- case "text":
1002
- return /* @__PURE__ */ jsx12(Text, { part, status });
1003
- case "image":
1004
- return /* @__PURE__ */ jsx12(Image, { part, status });
1005
- case "ui":
1006
- return /* @__PURE__ */ jsx12(UI, { part, status });
1007
- case "tool-call": {
1008
- const Tool = by_name[part.toolName] || Fallback;
1009
- const addResult = (result) => addToolResult(part.toolCallId, result);
1010
- return /* @__PURE__ */ jsx12(Tool, { part, status, addResult });
1011
- }
1012
- default:
1013
- throw new Error(`Unknown content part type: ${type}`);
1014
- }
1289
+ // src/utils/hooks/useOnResizeContent.tsx
1290
+ import { useCallbackRef as useCallbackRef2 } from "@radix-ui/react-use-callback-ref";
1291
+ import { useCallback as useCallback12 } from "react";
1292
+
1293
+ // src/utils/hooks/useManagedRef.ts
1294
+ import { useCallback as useCallback11, useRef as useRef4 } from "react";
1295
+ var useManagedRef = (callback) => {
1296
+ const cleanupRef = useRef4();
1297
+ const ref = useCallback11(
1298
+ (el) => {
1299
+ if (cleanupRef.current) {
1300
+ cleanupRef.current();
1301
+ }
1302
+ if (el) {
1303
+ cleanupRef.current = callback(el);
1304
+ }
1305
+ },
1306
+ [callback]
1307
+ );
1308
+ return ref;
1015
1309
  };
1016
- var MessageContentPartImpl = ({
1017
- partIndex,
1018
- components
1019
- }) => {
1020
- return /* @__PURE__ */ jsx12(ContentPartProvider, { partIndex, children: /* @__PURE__ */ jsx12(MessageContentPartComponent, { components }) });
1310
+
1311
+ // src/utils/hooks/useOnResizeContent.tsx
1312
+ var useOnResizeContent = (callback) => {
1313
+ const callbackRef = useCallbackRef2(callback);
1314
+ const refCallback = useCallback12(
1315
+ (el) => {
1316
+ const resizeObserver = new ResizeObserver(() => {
1317
+ callbackRef();
1318
+ });
1319
+ const mutationObserver = new MutationObserver((mutations) => {
1320
+ for (const mutation of mutations) {
1321
+ for (const node of mutation.addedNodes) {
1322
+ if (node instanceof Element) {
1323
+ resizeObserver.observe(node);
1324
+ }
1325
+ }
1326
+ for (const node of mutation.removedNodes) {
1327
+ if (node instanceof Element) {
1328
+ resizeObserver.unobserve(node);
1329
+ }
1330
+ }
1331
+ }
1332
+ callbackRef();
1333
+ });
1334
+ resizeObserver.observe(el);
1335
+ mutationObserver.observe(el, { childList: true });
1336
+ for (const child of el.children) {
1337
+ resizeObserver.observe(child);
1338
+ }
1339
+ return () => {
1340
+ resizeObserver.disconnect();
1341
+ mutationObserver.disconnect();
1342
+ };
1343
+ },
1344
+ [callbackRef]
1345
+ );
1346
+ return useManagedRef(refCallback);
1021
1347
  };
1022
- var MessageContentPart = memo2(
1023
- MessageContentPartImpl,
1024
- (prev, next) => prev.partIndex === next.partIndex && prev.components?.Text === next.components?.Text && prev.components?.Image === next.components?.Image && prev.components?.UI === next.components?.UI && prev.components?.tools === next.components?.tools
1025
- );
1026
- var MessageContent = ({ components }) => {
1027
- const { useMessage } = useMessageContext();
1028
- const contentLength = useMessage((s) => s.message.content.length);
1029
- return new Array(contentLength).fill(null).map((_, idx) => {
1030
- const partIndex = idx;
1031
- return /* @__PURE__ */ jsx12(
1032
- MessageContentPart,
1033
- {
1034
- partIndex,
1035
- components
1036
- },
1037
- partIndex
1038
- );
1348
+
1349
+ // src/utils/hooks/useOnScrollToBottom.tsx
1350
+ import { useCallbackRef as useCallbackRef3 } from "@radix-ui/react-use-callback-ref";
1351
+ import { useEffect as useEffect6 } from "react";
1352
+ var useOnScrollToBottom = (callback) => {
1353
+ const callbackRef = useCallbackRef3(callback);
1354
+ const { useViewport } = useThreadContext();
1355
+ useEffect6(() => {
1356
+ return useViewport.getState().onScrollToBottom(() => {
1357
+ callbackRef();
1358
+ });
1359
+ }, [useViewport, callbackRef]);
1360
+ };
1361
+
1362
+ // src/primitive-hooks/thread/useThreadViewportAutoScroll.tsx
1363
+ var useThreadViewportAutoScroll = ({
1364
+ autoScroll = true
1365
+ }) => {
1366
+ const divRef = useRef5(null);
1367
+ const { useViewport } = useThreadContext();
1368
+ const firstRenderRef = useRef5(true);
1369
+ const lastScrollTop = useRef5(0);
1370
+ const isScrollingToBottomRef = useRef5(false);
1371
+ const scrollToBottom = () => {
1372
+ const div = divRef.current;
1373
+ if (!div || !autoScroll) return;
1374
+ const behavior = firstRenderRef.current ? "instant" : "auto";
1375
+ firstRenderRef.current = false;
1376
+ isScrollingToBottomRef.current = true;
1377
+ div.scrollTo({ top: div.scrollHeight, behavior });
1378
+ };
1379
+ const handleScroll = () => {
1380
+ const div = divRef.current;
1381
+ if (!div) return;
1382
+ const isAtBottom = useViewport.getState().isAtBottom;
1383
+ const newIsAtBottom = div.scrollHeight - div.scrollTop <= div.clientHeight;
1384
+ if (!newIsAtBottom && lastScrollTop.current < div.scrollTop) {
1385
+ } else {
1386
+ isScrollingToBottomRef.current = newIsAtBottom;
1387
+ if (newIsAtBottom !== isAtBottom) {
1388
+ useViewport.setState({
1389
+ isAtBottom: newIsAtBottom
1390
+ });
1391
+ }
1392
+ }
1393
+ lastScrollTop.current = div.scrollTop;
1394
+ };
1395
+ const resizeRef = useOnResizeContent(() => {
1396
+ if (!isScrollingToBottomRef.current && !useViewport.getState().isAtBottom && !firstRenderRef.current) {
1397
+ handleScroll();
1398
+ } else {
1399
+ scrollToBottom();
1400
+ }
1401
+ });
1402
+ const scrollRef = useManagedRef((el) => {
1403
+ el.addEventListener("scroll", handleScroll);
1404
+ return () => {
1405
+ el.removeEventListener("scroll", handleScroll);
1406
+ };
1407
+ });
1408
+ const autoScrollRef = useComposedRefs2(resizeRef, scrollRef, divRef);
1409
+ useOnScrollToBottom(() => {
1410
+ scrollToBottom();
1039
1411
  });
1412
+ return autoScrollRef;
1040
1413
  };
1041
1414
 
1042
- // src/primitives/message/MessageInProgress.tsx
1043
- import { Primitive as Primitive8 } from "@radix-ui/react-primitive";
1044
- import {
1045
- forwardRef as forwardRef9,
1046
- useMemo as useMemo2
1047
- } from "react";
1048
- import { jsx as jsx13 } from "react/jsx-runtime";
1049
- var MessageInProgress = forwardRef9((props, ref) => {
1050
- const { useMessageUtils } = useMessageContext();
1051
- useMemo2(() => {
1052
- useMessageUtils.getState().setInProgressIndicator(/* @__PURE__ */ jsx13(Primitive8.span, { ...props, ref }));
1053
- }, [useMessageUtils, props, ref]);
1054
- return null;
1415
+ // src/primitives/thread/ThreadViewport.tsx
1416
+ import { jsx as jsx22 } from "react/jsx-runtime";
1417
+ var ThreadViewport = forwardRef14(({ autoScroll, onScroll, children, ...rest }, forwardedRef) => {
1418
+ const autoScrollRef = useThreadViewportAutoScroll({
1419
+ autoScroll
1420
+ });
1421
+ const ref = useComposedRefs3(forwardedRef, autoScrollRef);
1422
+ return /* @__PURE__ */ jsx22(Primitive11.div, { ...rest, ref, children });
1055
1423
  });
1056
- MessageInProgress.displayName = "MessageInProgress";
1424
+ ThreadViewport.displayName = "ThreadViewport";
1057
1425
 
1058
- // src/primitives/branchPicker/index.ts
1059
- var branchPicker_exports = {};
1060
- __export(branchPicker_exports, {
1061
- Count: () => BranchPickerCount,
1062
- Next: () => BranchPickerNext,
1063
- Number: () => BranchPickerNumber,
1064
- Previous: () => BranchPickerPrevious,
1065
- Root: () => BranchPickerRoot
1066
- });
1426
+ // src/primitives/thread/ThreadMessages.tsx
1427
+ import { memo as memo3 } from "react";
1067
1428
 
1068
- // src/primitives/branchPicker/BranchPickerNext.tsx
1069
- var BranchPickerNext = createActionButton(
1070
- "BranchPickerNext",
1071
- useBranchPickerNext
1072
- );
1429
+ // src/context/providers/MessageProvider.tsx
1430
+ import { useEffect as useEffect7, useState as useState5 } from "react";
1431
+ import { create as create10 } from "zustand";
1073
1432
 
1074
- // src/primitives/branchPicker/BranchPickerPrevious.tsx
1075
- var BranchPickerPrevious = createActionButton(
1076
- "BranchPickerPrevious",
1077
- useBranchPickerPrevious
1078
- );
1433
+ // src/context/stores/EditComposer.ts
1434
+ import { create as create8 } from "zustand";
1435
+ var makeEditComposerStore = ({
1436
+ onEdit,
1437
+ onSend
1438
+ }) => create8()((set, get, store) => ({
1439
+ ...makeBaseComposer(set, get, store),
1440
+ isEditing: false,
1441
+ edit: () => {
1442
+ const value = onEdit();
1443
+ set({ isEditing: true, value });
1444
+ },
1445
+ send: () => {
1446
+ const value = get().value;
1447
+ set({ isEditing: false });
1448
+ onSend(value);
1449
+ },
1450
+ cancel: () => {
1451
+ if (!get().isEditing) return false;
1452
+ set({ isEditing: false });
1453
+ return true;
1454
+ }
1455
+ }));
1079
1456
 
1080
- // src/primitives/branchPicker/BranchPickerCount.tsx
1081
- import { Fragment as Fragment2, jsx as jsx14 } from "react/jsx-runtime";
1082
- var BranchPickerCount = () => {
1083
- const branchCount = useBranchPickerCount();
1084
- return /* @__PURE__ */ jsx14(Fragment2, { children: branchCount });
1085
- };
1457
+ // src/context/stores/MessageUtils.ts
1458
+ import { create as create9 } from "zustand";
1459
+ var makeMessageUtilsStore = () => create9((set) => ({
1460
+ inProgressIndicator: null,
1461
+ setInProgressIndicator: (value) => {
1462
+ set({ inProgressIndicator: value });
1463
+ },
1464
+ isCopied: false,
1465
+ setIsCopied: (value) => {
1466
+ set({ isCopied: value });
1467
+ },
1468
+ isHovering: false,
1469
+ setIsHovering: (value) => {
1470
+ set({ isHovering: value });
1471
+ }
1472
+ }));
1086
1473
 
1087
- // src/primitives/branchPicker/BranchPickerNumber.tsx
1088
- import { Fragment as Fragment3, jsx as jsx15 } from "react/jsx-runtime";
1089
- var BranchPickerNumber = () => {
1090
- const branchNumber = useBranchPickerNumber();
1091
- return /* @__PURE__ */ jsx15(Fragment3, { children: branchNumber });
1474
+ // src/context/providers/MessageProvider.tsx
1475
+ import { jsx as jsx23 } from "react/jsx-runtime";
1476
+ var getIsLast = (thread, message) => {
1477
+ return thread.messages[thread.messages.length - 1]?.id === message.id;
1092
1478
  };
1093
-
1094
- // src/primitives/branchPicker/BranchPickerRoot.tsx
1095
- import { Primitive as Primitive9 } from "@radix-ui/react-primitive";
1096
- import { forwardRef as forwardRef10 } from "react";
1097
- import { jsx as jsx16 } from "react/jsx-runtime";
1098
- var BranchPickerRoot = forwardRef10(({ hideWhenSingleBranch, ...rest }, ref) => {
1099
- return /* @__PURE__ */ jsx16(MessageIf, { hasBranches: hideWhenSingleBranch ? true : void 0, children: /* @__PURE__ */ jsx16(Primitive9.div, { ...rest, ref }) });
1100
- });
1101
- BranchPickerRoot.displayName = "BranchPickerRoot";
1102
-
1103
- // src/primitives/actionBar/index.ts
1104
- var actionBar_exports = {};
1105
- __export(actionBar_exports, {
1106
- Copy: () => ActionBarCopy,
1107
- Edit: () => ActionBarEdit,
1108
- Reload: () => ActionBarReload,
1109
- Root: () => ActionBarRoot
1110
- });
1111
-
1112
- // src/primitives/actionBar/ActionBarRoot.tsx
1113
- import { Primitive as Primitive10 } from "@radix-ui/react-primitive";
1114
- import { forwardRef as forwardRef11 } from "react";
1115
- import { jsx as jsx17 } from "react/jsx-runtime";
1116
- var useActionBarFloatStatus = ({
1117
- hideWhenRunning,
1118
- autohide,
1119
- autohideFloat
1120
- }) => {
1121
- const { useThread } = useThreadContext();
1122
- const { useMessage, useMessageUtils } = useMessageContext();
1123
- return useCombinedStore(
1124
- [useThread, useMessage, useMessageUtils],
1125
- (t, m, mu) => {
1126
- if (hideWhenRunning && t.isRunning) return "hidden" /* Hidden */;
1127
- const autohideEnabled = autohide === "always" || autohide === "not-last" && !m.isLast;
1128
- if (!autohideEnabled) return "normal" /* Normal */;
1129
- if (!mu.isHovering) return "hidden" /* Hidden */;
1130
- if (autohideFloat === "always" || autohideFloat === "single-branch" && m.branches.length <= 1)
1131
- return "floating" /* Floating */;
1132
- return "normal" /* Normal */;
1133
- }
1134
- );
1479
+ var syncMessage = (thread, getBranches, useMessage, messageIndex) => {
1480
+ const parentId = thread.messages[messageIndex - 1]?.id ?? null;
1481
+ const message = thread.messages[messageIndex];
1482
+ if (!message) return;
1483
+ const isLast = getIsLast(thread, message);
1484
+ const branches = getBranches(message.id);
1485
+ const currentState = useMessage.getState();
1486
+ if (currentState.message === message && currentState.parentId === parentId && currentState.branches === branches && currentState.isLast === isLast)
1487
+ return;
1488
+ useMessage.setState({
1489
+ message,
1490
+ parentId,
1491
+ branches,
1492
+ isLast
1493
+ });
1135
1494
  };
1136
- var ActionBarRoot = forwardRef11(({ hideWhenRunning, autohide, autohideFloat, ...rest }, ref) => {
1137
- const hideAndfloatStatus = useActionBarFloatStatus({
1138
- hideWhenRunning,
1139
- autohide,
1140
- autohideFloat
1495
+ var useMessageContext2 = (messageIndex) => {
1496
+ const { useThread, useThreadActions } = useThreadContext();
1497
+ const [context] = useState5(() => {
1498
+ const useMessage = create10(() => ({}));
1499
+ const useMessageUtils = makeMessageUtilsStore();
1500
+ const useEditComposer = makeEditComposerStore({
1501
+ onEdit: () => {
1502
+ const message = useMessage.getState().message;
1503
+ if (message.role !== "user")
1504
+ throw new Error(
1505
+ "Tried to edit a non-user message. Editing is only supported for user messages. This is likely an internal bug in assistant-ui."
1506
+ );
1507
+ const text = getMessageText(message);
1508
+ return text;
1509
+ },
1510
+ onSend: (text) => {
1511
+ const { message, parentId } = useMessage.getState();
1512
+ if (message.role !== "user")
1513
+ throw new Error(
1514
+ "Tried to edit a non-user message. Editing is only supported for user messages. This is likely an internal bug in assistant-ui."
1515
+ );
1516
+ const nonTextParts = message.content.filter(
1517
+ (part) => part.type !== "text" && part.type !== "ui"
1518
+ );
1519
+ useThreadActions.getState().append({
1520
+ parentId,
1521
+ role: "user",
1522
+ content: [{ type: "text", text }, ...nonTextParts]
1523
+ });
1524
+ }
1525
+ });
1526
+ syncMessage(
1527
+ useThread.getState(),
1528
+ useThreadActions.getState().getBranches,
1529
+ useMessage,
1530
+ messageIndex
1531
+ );
1532
+ return { useMessage, useMessageUtils, useEditComposer };
1141
1533
  });
1142
- if (hideAndfloatStatus === "hidden" /* Hidden */) return null;
1143
- return /* @__PURE__ */ jsx17(
1144
- Primitive10.div,
1145
- {
1146
- ...hideAndfloatStatus === "floating" /* Floating */ ? { "data-floating": "true" } : null,
1147
- ...rest,
1148
- ref
1149
- }
1150
- );
1151
- });
1152
- ActionBarRoot.displayName = "ActionBarRoot";
1534
+ useEffect7(() => {
1535
+ return useThread.subscribe((thread) => {
1536
+ syncMessage(
1537
+ thread,
1538
+ useThreadActions.getState().getBranches,
1539
+ context.useMessage,
1540
+ messageIndex
1541
+ );
1542
+ });
1543
+ }, [useThread, useThreadActions, context, messageIndex]);
1544
+ return context;
1545
+ };
1546
+ var MessageProvider = ({
1547
+ messageIndex,
1548
+ children
1549
+ }) => {
1550
+ const context = useMessageContext2(messageIndex);
1551
+ return /* @__PURE__ */ jsx23(MessageContext.Provider, { value: context, children });
1552
+ };
1153
1553
 
1154
- // src/primitives/actionBar/ActionBarCopy.tsx
1155
- var ActionBarCopy = createActionButton(
1156
- "ActionBarCopy",
1157
- useActionBarCopy
1554
+ // src/primitives/thread/ThreadMessages.tsx
1555
+ import { jsx as jsx24, jsxs as jsxs3 } from "react/jsx-runtime";
1556
+ var getComponents = (components) => {
1557
+ return {
1558
+ EditComposer: components.EditComposer ?? components.UserMessage ?? components.Message,
1559
+ UserMessage: components.UserMessage ?? components.Message,
1560
+ AssistantMessage: components.AssistantMessage ?? components.Message
1561
+ };
1562
+ };
1563
+ var ThreadMessageImpl = ({
1564
+ messageIndex,
1565
+ components
1566
+ }) => {
1567
+ const { UserMessage, EditComposer, AssistantMessage } = getComponents(components);
1568
+ return /* @__PURE__ */ jsxs3(MessageProvider, { messageIndex, children: [
1569
+ /* @__PURE__ */ jsxs3(MessageIf, { user: true, children: [
1570
+ /* @__PURE__ */ jsx24(ComposerIf, { editing: false, children: /* @__PURE__ */ jsx24(UserMessage, {}) }),
1571
+ /* @__PURE__ */ jsx24(ComposerIf, { editing: true, children: /* @__PURE__ */ jsx24(EditComposer, {}) })
1572
+ ] }),
1573
+ /* @__PURE__ */ jsx24(MessageIf, { assistant: true, children: /* @__PURE__ */ jsx24(AssistantMessage, {}) })
1574
+ ] });
1575
+ };
1576
+ var ThreadMessage = memo3(
1577
+ ThreadMessageImpl,
1578
+ (prev, next) => prev.messageIndex === next.messageIndex && prev.components.UserMessage === next.components.UserMessage && prev.components.EditComposer === next.components.EditComposer && prev.components.AssistantMessage === next.components.AssistantMessage
1158
1579
  );
1580
+ var ThreadMessages = ({ components }) => {
1581
+ const { useThread } = useThreadContext();
1582
+ const messagesLength = useThread((t) => t.messages.length);
1583
+ if (messagesLength === 0) return null;
1584
+ return new Array(messagesLength).fill(null).map((_, idx) => {
1585
+ const messageIndex = idx;
1586
+ return /* @__PURE__ */ jsx24(
1587
+ ThreadMessage,
1588
+ {
1589
+ messageIndex,
1590
+ components
1591
+ },
1592
+ messageIndex
1593
+ );
1594
+ });
1595
+ };
1159
1596
 
1160
- // src/primitives/actionBar/ActionBarReload.tsx
1161
- var ActionBarReload = createActionButton(
1162
- "ActionBarReload",
1163
- useActionBarReload
1597
+ // src/primitives/thread/ThreadScrollToBottom.tsx
1598
+ var ThreadScrollToBottom = createActionButton(
1599
+ "ThreadScrollToBottom",
1600
+ useThreadScrollToBottom
1164
1601
  );
1165
1602
 
1166
- // src/primitives/actionBar/ActionBarEdit.tsx
1167
- var ActionBarEdit = createActionButton(
1168
- "ActionBarEdit",
1169
- useActionBarEdit
1603
+ // src/primitives/thread/ThreadSuggestion.tsx
1604
+ var ThreadSuggestion = createActionButton(
1605
+ "ThreadSuggestion",
1606
+ useThreadSuggestion
1170
1607
  );
1171
1608
 
1172
- // src/primitives/contentPart/index.ts
1173
- var contentPart_exports = {};
1174
- __export(contentPart_exports, {
1175
- Display: () => ContentPartDisplay,
1176
- Image: () => ContentPartImage,
1177
- InProgressIndicator: () => ContentPartInProgressIndicator,
1178
- Text: () => ContentPartText
1179
- });
1180
-
1181
- // src/primitives/contentPart/ContentPartImage.tsx
1182
- import { Primitive as Primitive11 } from "@radix-ui/react-primitive";
1183
- import { forwardRef as forwardRef12 } from "react";
1184
- import { jsx as jsx18 } from "react/jsx-runtime";
1185
- var ContentPartImage = forwardRef12((props, forwardedRef) => {
1186
- const image = useContentPartImage();
1187
- return /* @__PURE__ */ jsx18(Primitive11.img, { src: image, ...props, ref: forwardedRef });
1188
- });
1189
- ContentPartImage.displayName = "ContentPartImage";
1190
-
1191
1609
  // src/runtime/local/useLocalRuntime.tsx
1192
- import { useInsertionEffect, useState as useState3 } from "react";
1193
-
1194
- // src/utils/ModelConfigTypes.ts
1195
- var mergeModelConfigs = (configSet) => {
1196
- const configs = Array.from(configSet).map((c) => c()).sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
1197
- return configs.reduce((acc, config) => {
1198
- if (config.system) {
1199
- if (acc.system) {
1200
- acc.system += `
1201
-
1202
- ${config.system}`;
1203
- } else {
1204
- acc.system = config.system;
1205
- }
1206
- }
1207
- if (config.tools) {
1208
- for (const [name, tool] of Object.entries(config.tools)) {
1209
- if (acc.tools?.[name]) {
1210
- throw new Error(
1211
- `You tried to define a tool with the name ${name}, but it already exists.`
1212
- );
1213
- }
1214
- if (!acc.tools) acc.tools = {};
1215
- acc.tools[name] = tool;
1216
- }
1217
- }
1218
- return acc;
1219
- }, {});
1220
- };
1610
+ import { useInsertionEffect as useInsertionEffect3, useState as useState6 } from "react";
1221
1611
 
1222
1612
  // src/runtime/utils/idUtils.tsx
1223
1613
  import { customAlphabet } from "nanoid/non-secure";
@@ -1475,219 +1865,81 @@ var LocalRuntime = class {
1475
1865
 
1476
1866
  // src/runtime/local/useLocalRuntime.tsx
1477
1867
  var useLocalRuntime = (adapter) => {
1478
- const [runtime] = useState3(() => new LocalRuntime(adapter));
1479
- useInsertionEffect(() => {
1868
+ const [runtime] = useState6(() => new LocalRuntime(adapter));
1869
+ useInsertionEffect3(() => {
1480
1870
  runtime.adapter = adapter;
1481
1871
  });
1482
1872
  return runtime;
1483
1873
  };
1484
1874
 
1485
- // src/context/providers/AssistantRuntimeProvider.tsx
1486
- import { memo as memo3 } from "react";
1487
-
1488
- // src/context/providers/AssistantProvider.tsx
1489
- import { useEffect as useEffect6, useInsertionEffect as useInsertionEffect3, useRef as useRef5, useState as useState5 } from "react";
1490
-
1491
- // src/context/stores/AssistantModelConfig.ts
1492
- import { create as create5 } from "zustand";
1493
-
1494
- // src/utils/ProxyConfigProvider.ts
1495
- var ProxyConfigProvider = class {
1496
- _providers = /* @__PURE__ */ new Set();
1497
- getModelConfig() {
1498
- return mergeModelConfigs(this._providers);
1499
- }
1500
- registerModelConfigProvider(provider) {
1501
- this._providers.add(provider);
1875
+ // src/model-config/useAssistantTool.tsx
1876
+ import { useEffect as useEffect8 } from "react";
1877
+ var useAssistantTool = (tool) => {
1878
+ const { useModelConfig, useToolUIs } = useAssistantContext();
1879
+ const registerModelConfigProvider = useModelConfig(
1880
+ (s) => s.registerModelConfigProvider
1881
+ );
1882
+ const setToolUI = useToolUIs((s) => s.setToolUI);
1883
+ useEffect8(() => {
1884
+ const { toolName, render, ...rest } = tool;
1885
+ const config = {
1886
+ tools: {
1887
+ [tool.toolName]: rest
1888
+ }
1889
+ };
1890
+ const unsub1 = registerModelConfigProvider(() => config);
1891
+ const unsub2 = render ? setToolUI(toolName, render) : void 0;
1502
1892
  return () => {
1503
- this._providers.delete(provider);
1893
+ unsub1();
1894
+ unsub2?.();
1504
1895
  };
1505
- }
1896
+ }, [registerModelConfigProvider, setToolUI, tool]);
1506
1897
  };
1507
1898
 
1508
- // src/context/stores/AssistantModelConfig.ts
1509
- var makeAssistantModelConfigStore = () => create5(() => {
1510
- const proxy = new ProxyConfigProvider();
1511
- return Object.freeze({
1512
- getModelConfig: () => {
1513
- return proxy.getModelConfig();
1514
- },
1515
- registerModelConfigProvider: (provider) => {
1516
- return proxy.registerModelConfigProvider(provider);
1517
- }
1518
- });
1519
- });
1520
-
1521
- // src/context/stores/AssistantToolUIs.ts
1522
- import { create as create6 } from "zustand";
1523
- var makeAssistantToolUIsStore = () => create6((set) => {
1524
- const renderers = /* @__PURE__ */ new Map();
1525
- return Object.freeze({
1526
- getToolUI: (name) => {
1527
- const arr = renderers.get(name);
1528
- const last = arr?.at(-1);
1529
- if (last) return last;
1530
- return null;
1531
- },
1532
- setToolUI: (name, render) => {
1533
- let arr = renderers.get(name);
1534
- if (!arr) {
1535
- arr = [];
1536
- renderers.set(name, arr);
1537
- }
1538
- arr.push(render);
1539
- set({});
1540
- return () => {
1541
- const index = arr.indexOf(render);
1542
- if (index !== -1) {
1543
- arr.splice(index, 1);
1544
- }
1545
- if (index === arr.length) {
1546
- set({});
1547
- }
1548
- };
1549
- }
1550
- });
1551
- });
1552
-
1553
- // src/context/providers/ThreadProvider.tsx
1554
- import { useEffect as useEffect5, useInsertionEffect as useInsertionEffect2, useRef as useRef4, useState as useState4 } from "react";
1555
-
1556
- // src/context/stores/Composer.ts
1557
- import { create as create7 } from "zustand";
1558
- var makeComposerStore = (useThread, useThreadActions) => create7()((set, get, store) => {
1559
- return {
1560
- ...makeBaseComposer(set, get, store),
1561
- isEditing: true,
1562
- send: () => {
1563
- const { setValue, value } = get();
1564
- setValue("");
1565
- useThreadActions.getState().append({
1566
- parentId: useThread.getState().messages.at(-1)?.id ?? null,
1567
- role: "user",
1568
- content: [{ type: "text", text: value }]
1569
- });
1570
- },
1571
- cancel: () => {
1572
- const thread = useThread.getState();
1573
- if (!thread.isRunning) return false;
1574
- useThreadActions.getState().cancelRun();
1575
- return true;
1576
- }
1899
+ // src/model-config/makeAssistantTool.tsx
1900
+ var makeAssistantTool = (tool) => {
1901
+ const Tool = () => {
1902
+ useAssistantTool(tool);
1903
+ return null;
1577
1904
  };
1578
- });
1579
-
1580
- // src/context/stores/Thread.ts
1581
- import { create as create8 } from "zustand";
1582
- var makeThreadStore = (runtimeRef) => {
1583
- return create8(() => ({
1584
- messages: runtimeRef.current.messages,
1585
- isRunning: runtimeRef.current.isRunning
1586
- }));
1905
+ return Tool;
1587
1906
  };
1588
1907
 
1589
- // src/context/stores/ThreadViewport.tsx
1590
- import { create as create9 } from "zustand";
1591
- var makeThreadViewportStore = () => {
1592
- const scrollToBottomListeners = /* @__PURE__ */ new Set();
1593
- return create9(() => ({
1594
- isAtBottom: true,
1595
- scrollToBottom: () => {
1596
- for (const listener of scrollToBottomListeners) {
1597
- listener();
1598
- }
1599
- },
1600
- onScrollToBottom: (callback) => {
1601
- scrollToBottomListeners.add(callback);
1602
- return () => {
1603
- scrollToBottomListeners.delete(callback);
1604
- };
1605
- }
1606
- }));
1908
+ // src/model-config/useAssistantToolUI.tsx
1909
+ import { useEffect as useEffect9 } from "react";
1910
+ var useAssistantToolUI = (tool) => {
1911
+ const { useToolUIs } = useAssistantContext();
1912
+ const setToolUI = useToolUIs((s) => s.setToolUI);
1913
+ useEffect9(() => {
1914
+ if (!tool) return;
1915
+ const { toolName, render } = tool;
1916
+ return setToolUI(toolName, render);
1917
+ }, [setToolUI, tool]);
1607
1918
  };
1608
1919
 
1609
- // src/context/stores/ThreadActions.ts
1610
- import { create as create10 } from "zustand";
1611
- var makeThreadActionStore = (runtimeRef) => {
1612
- return create10(
1613
- () => Object.freeze({
1614
- getBranches: (messageId) => runtimeRef.current.getBranches(messageId),
1615
- switchToBranch: (branchId) => runtimeRef.current.switchToBranch(branchId),
1616
- startRun: (parentId) => runtimeRef.current.startRun(parentId),
1617
- append: (message) => runtimeRef.current.append(message),
1618
- cancelRun: () => runtimeRef.current.cancelRun(),
1619
- addToolResult: (toolCallId, result) => runtimeRef.current.addToolResult(toolCallId, result)
1620
- })
1621
- );
1920
+ // src/model-config/makeAssistantToolUI.tsx
1921
+ var makeAssistantToolUI = (tool) => {
1922
+ const ToolUI = () => {
1923
+ useAssistantToolUI(tool);
1924
+ return null;
1925
+ };
1926
+ return ToolUI;
1622
1927
  };
1623
1928
 
1624
- // src/context/providers/ThreadProvider.tsx
1625
- import { jsx as jsx19, jsxs as jsxs3 } from "react/jsx-runtime";
1626
- var ThreadProvider = ({
1627
- children,
1628
- runtime
1629
- }) => {
1630
- const runtimeRef = useRef4(runtime);
1631
- useInsertionEffect2(() => {
1632
- runtimeRef.current = runtime;
1633
- });
1634
- const [context] = useState4(() => {
1635
- const useThread = makeThreadStore(runtimeRef);
1636
- const useThreadActions = makeThreadActionStore(runtimeRef);
1637
- const useViewport = makeThreadViewportStore();
1638
- const useComposer = makeComposerStore(useThread, useThreadActions);
1639
- return {
1640
- useThread,
1641
- useThreadActions,
1642
- useComposer,
1643
- useViewport
1644
- };
1645
- });
1646
- useEffect5(() => {
1647
- const onRuntimeUpdate = () => {
1648
- context.useThread.setState(
1649
- Object.freeze({
1650
- messages: runtimeRef.current.messages,
1651
- isRunning: runtimeRef.current.isRunning
1652
- }),
1653
- true
1654
- );
1929
+ // src/model-config/useAssistantInstructions.tsx
1930
+ import { useEffect as useEffect10 } from "react";
1931
+ var useAssistantInstructions = (instruction) => {
1932
+ const { useModelConfig } = useAssistantContext();
1933
+ const registerModelConfigProvider = useModelConfig(
1934
+ (s) => s.registerModelConfigProvider
1935
+ );
1936
+ useEffect10(() => {
1937
+ const config = {
1938
+ system: instruction
1655
1939
  };
1656
- onRuntimeUpdate();
1657
- return runtime.subscribe(onRuntimeUpdate);
1658
- }, [context, runtime]);
1659
- const RuntimeSynchronizer = runtime.unstable_synchronizer;
1660
- return /* @__PURE__ */ jsxs3(ThreadContext.Provider, { value: context, children: [
1661
- RuntimeSynchronizer && /* @__PURE__ */ jsx19(RuntimeSynchronizer, {}),
1662
- children
1663
- ] });
1664
- };
1665
-
1666
- // src/context/providers/AssistantProvider.tsx
1667
- import { jsx as jsx20 } from "react/jsx-runtime";
1668
- var AssistantProvider = ({ children, runtime }) => {
1669
- const runtimeRef = useRef5(runtime);
1670
- useInsertionEffect3(() => {
1671
- runtimeRef.current = runtime;
1672
- });
1673
- const [context] = useState5(() => {
1674
- const useModelConfig = makeAssistantModelConfigStore();
1675
- const useToolUIs = makeAssistantToolUIsStore();
1676
- return { useModelConfig, useToolUIs };
1677
- });
1678
- const getModelCOnfig = context.useModelConfig((c) => c.getModelConfig);
1679
- useEffect6(() => {
1680
- return runtime.registerModelConfigProvider(getModelCOnfig);
1681
- }, [runtime, getModelCOnfig]);
1682
- return /* @__PURE__ */ jsx20(AssistantContext.Provider, { value: context, children: /* @__PURE__ */ jsx20(ThreadProvider, { runtime, children }) });
1683
- };
1684
-
1685
- // src/context/providers/AssistantRuntimeProvider.tsx
1686
- import { jsx as jsx21 } from "react/jsx-runtime";
1687
- var AssistantRuntimeProviderImpl = ({ children, runtime }) => {
1688
- return /* @__PURE__ */ jsx21(AssistantProvider, { runtime, children });
1940
+ return registerModelConfigProvider(() => config);
1941
+ }, [registerModelConfigProvider, instruction]);
1689
1942
  };
1690
- var AssistantRuntimeProvider = memo3(AssistantRuntimeProviderImpl);
1691
1943
 
1692
1944
  // src/internal.ts
1693
1945
  var internal_exports = {};
@@ -1697,6 +1949,7 @@ __export(internal_exports, {
1697
1949
  });
1698
1950
  export {
1699
1951
  actionBar_exports as ActionBarPrimitive,
1952
+ assistantModal_exports as AssistantModalPrimitive,
1700
1953
  AssistantRuntimeProvider,
1701
1954
  branchPicker_exports as BranchPickerPrimitive,
1702
1955
  composer_exports as ComposerPrimitive,
@@ -1704,22 +1957,32 @@ export {
1704
1957
  internal_exports as INTERNAL,
1705
1958
  message_exports as MessagePrimitive,
1706
1959
  thread_exports as ThreadPrimitive,
1960
+ makeAssistantTool,
1961
+ makeAssistantToolUI,
1707
1962
  useActionBarCopy,
1708
1963
  useActionBarEdit,
1709
1964
  useActionBarReload,
1965
+ useAssistantContext,
1966
+ useAssistantInstructions,
1967
+ useAssistantTool,
1968
+ useAssistantToolUI,
1710
1969
  useBranchPickerCount,
1711
1970
  useBranchPickerNext,
1712
1971
  useBranchPickerNumber,
1713
1972
  useBranchPickerPrevious,
1714
1973
  useComposerCancel,
1974
+ useComposerContext,
1715
1975
  useComposerIf,
1716
1976
  useComposerSend,
1977
+ useContentPartContext,
1717
1978
  useContentPartDisplay,
1718
1979
  useContentPartImage,
1719
1980
  useContentPartInProgressIndicator,
1720
1981
  useContentPartText,
1721
1982
  useLocalRuntime,
1983
+ useMessageContext,
1722
1984
  useMessageIf,
1985
+ useThreadContext,
1723
1986
  useThreadEmpty,
1724
1987
  useThreadIf,
1725
1988
  useThreadScrollToBottom,