@assistant-ui/react 0.1.7 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  useContentPartContext,
10
10
  useMessageContext,
11
11
  useThreadContext
12
- } from "./chunk-XVZ2GVQM.mjs";
12
+ } from "./chunk-7O2URLFI.mjs";
13
13
 
14
14
  // src/actions/useCopyMessage.tsx
15
15
  import { useCallback } from "react";
@@ -50,7 +50,7 @@ var getMessageText = (message) => {
50
50
 
51
51
  // src/actions/useCopyMessage.tsx
52
52
  var useCopyMessage = ({ copiedDuration = 3e3 }) => {
53
- const { useMessage, useComposer } = useMessageContext();
53
+ const { useMessage, useMessageUtils, useComposer } = useMessageContext();
54
54
  const hasCopyableContent = useCombinedStore(
55
55
  [useMessage, useComposer],
56
56
  (m, c) => {
@@ -58,13 +58,14 @@ var useCopyMessage = ({ copiedDuration = 3e3 }) => {
58
58
  }
59
59
  );
60
60
  const callback = useCallback(() => {
61
+ const { message } = useMessage.getState();
62
+ const { setIsCopied } = useMessageUtils.getState();
61
63
  const { isEditing, value: composerValue } = useComposer.getState();
62
- const { message, setIsCopied } = useMessage.getState();
63
64
  const valueToCopy = isEditing ? composerValue : getMessageText(message);
64
65
  navigator.clipboard.writeText(valueToCopy);
65
66
  setIsCopied(true);
66
67
  setTimeout(() => setIsCopied(false), copiedDuration);
67
- }, [useComposer, useMessage, copiedDuration]);
68
+ }, [useMessage, useMessageUtils, useComposer, copiedDuration]);
68
69
  if (!hasCopyableContent) return null;
69
70
  return callback;
70
71
  };
@@ -72,7 +73,7 @@ var useCopyMessage = ({ copiedDuration = 3e3 }) => {
72
73
  // src/actions/useReloadMessage.tsx
73
74
  import { useCallback as useCallback2 } from "react";
74
75
  var useReloadMessage = () => {
75
- const { useThread, useViewport } = useThreadContext();
76
+ const { useThread, useThreadActions, useViewport } = useThreadContext();
76
77
  const { useMessage } = useMessageContext();
77
78
  const disabled = useCombinedStore(
78
79
  [useThread, useMessage],
@@ -80,9 +81,9 @@ var useReloadMessage = () => {
80
81
  );
81
82
  const callback = useCallback2(() => {
82
83
  const { parentId } = useMessage.getState();
83
- useThread.getState().startRun(parentId);
84
+ useThreadActions.getState().startRun(parentId);
84
85
  useViewport.getState().scrollToBottom();
85
- }, [useMessage, useThread, useViewport]);
86
+ }, [useThreadActions, useMessage, useViewport]);
86
87
  if (disabled) return null;
87
88
  return callback;
88
89
  };
@@ -106,7 +107,7 @@ var useBeginMessageEdit = () => {
106
107
  // src/actions/useGoToNextBranch.tsx
107
108
  import { useCallback as useCallback4 } from "react";
108
109
  var useGoToNextBranch = () => {
109
- const { useThread } = useThreadContext();
110
+ const { useThreadActions } = useThreadContext();
110
111
  const { useMessage, useComposer } = useMessageContext();
111
112
  const disabled = useCombinedStore(
112
113
  [useMessage, useComposer],
@@ -114,8 +115,8 @@ var useGoToNextBranch = () => {
114
115
  );
115
116
  const callback = useCallback4(() => {
116
117
  const { message, branches } = useMessage.getState();
117
- useThread.getState().switchToBranch(branches[branches.indexOf(message.id) + 1]);
118
- }, [useMessage, useThread]);
118
+ useThreadActions.getState().switchToBranch(branches[branches.indexOf(message.id) + 1]);
119
+ }, [useThreadActions, useMessage]);
119
120
  if (disabled) return null;
120
121
  return callback;
121
122
  };
@@ -123,7 +124,7 @@ var useGoToNextBranch = () => {
123
124
  // src/actions/useGoToPreviousBranch.tsx
124
125
  import { useCallback as useCallback5 } from "react";
125
126
  var useGoToPreviousBranch = () => {
126
- const { useThread } = useThreadContext();
127
+ const { useThreadActions } = useThreadContext();
127
128
  const { useMessage, useComposer } = useMessageContext();
128
129
  const disabled = useCombinedStore(
129
130
  [useMessage, useComposer],
@@ -131,8 +132,8 @@ var useGoToPreviousBranch = () => {
131
132
  );
132
133
  const callback = useCallback5(() => {
133
134
  const { message, branches } = useMessage.getState();
134
- useThread.getState().switchToBranch(branches[branches.indexOf(message.id) - 1]);
135
- }, [useMessage, useThread]);
135
+ useThreadActions.getState().switchToBranch(branches[branches.indexOf(message.id) - 1]);
136
+ }, [useThreadActions, useMessage]);
136
137
  if (disabled) return null;
137
138
  return callback;
138
139
  };
@@ -278,7 +279,9 @@ var ThreadViewport = forwardRef2(({ autoScroll = true, onScroll, children, ...re
278
279
  if (!newIsAtBottom && lastScrollTop.current < div.scrollTop) {
279
280
  } else if (newIsAtBottom !== isAtBottom) {
280
281
  isScrollingToBottomRef.current = false;
281
- useViewport.setState({ isAtBottom: newIsAtBottom });
282
+ useViewport.setState({
283
+ isAtBottom: newIsAtBottom
284
+ });
282
285
  }
283
286
  lastScrollTop.current = div.scrollTop;
284
287
  };
@@ -302,7 +305,7 @@ import { memo } from "react";
302
305
 
303
306
  // src/context/providers/MessageProvider.tsx
304
307
  import { useEffect as useEffect3, useState } from "react";
305
- import { create as create2 } from "zustand";
308
+ import { create as create3 } from "zustand";
306
309
 
307
310
  // src/context/stores/MessageComposer.ts
308
311
  import { create } from "zustand";
@@ -338,17 +341,34 @@ var makeEditComposerStore = ({
338
341
  }
339
342
  }));
340
343
 
344
+ // src/context/stores/MessageUtils.ts
345
+ import { create as create2 } from "zustand";
346
+ var makeMessageUtilsStore = () => create2((set) => ({
347
+ inProgressIndicator: null,
348
+ setInProgressIndicator: (value) => {
349
+ set({ inProgressIndicator: value });
350
+ },
351
+ isCopied: false,
352
+ setIsCopied: (value) => {
353
+ set({ isCopied: value });
354
+ },
355
+ isHovering: false,
356
+ setIsHovering: (value) => {
357
+ set({ isHovering: value });
358
+ }
359
+ }));
360
+
341
361
  // src/context/providers/MessageProvider.tsx
342
362
  import { jsx as jsx4 } from "react/jsx-runtime";
343
363
  var getIsLast = (thread, message) => {
344
364
  return thread.messages[thread.messages.length - 1]?.id === message.id;
345
365
  };
346
- var syncMessage = (thread, useMessage, messageIndex) => {
366
+ var syncMessage = (thread, getBranches, useMessage, messageIndex) => {
347
367
  const parentId = thread.messages[messageIndex - 1]?.id ?? null;
348
368
  const message = thread.messages[messageIndex];
349
369
  if (!message) return;
350
370
  const isLast = getIsLast(thread, message);
351
- const branches = thread.getBranches(message.id);
371
+ const branches = getBranches(message.id);
352
372
  const currentState = useMessage.getState();
353
373
  if (currentState.message === message && currentState.parentId === parentId && currentState.branches === branches && currentState.isLast === isLast)
354
374
  return;
@@ -360,26 +380,10 @@ var syncMessage = (thread, useMessage, messageIndex) => {
360
380
  });
361
381
  };
362
382
  var useMessageContext2 = (messageIndex) => {
363
- const { useThread } = useThreadContext();
383
+ const { useThread, useThreadActions } = useThreadContext();
364
384
  const [context] = useState(() => {
365
- const useMessage = create2((set) => ({
366
- message: null,
367
- parentId: null,
368
- branches: [],
369
- isLast: false,
370
- inProgressIndicator: null,
371
- isCopied: false,
372
- isHovering: false,
373
- setInProgressIndicator: (value) => {
374
- set({ inProgressIndicator: value });
375
- },
376
- setIsCopied: (value) => {
377
- set({ isCopied: value });
378
- },
379
- setIsHovering: (value) => {
380
- set({ isHovering: value });
381
- }
382
- }));
385
+ const useMessage = create3(() => ({}));
386
+ const useMessageUtils = makeMessageUtilsStore();
383
387
  const useComposer = makeEditComposerStore({
384
388
  onEdit: () => {
385
389
  const message = useMessage.getState().message;
@@ -399,20 +403,30 @@ var useMessageContext2 = (messageIndex) => {
399
403
  const nonTextParts = message.content.filter(
400
404
  (part) => part.type !== "text" && part.type !== "ui"
401
405
  );
402
- useThread.getState().append({
406
+ useThreadActions.getState().append({
403
407
  parentId,
404
408
  content: [{ type: "text", text }, ...nonTextParts]
405
409
  });
406
410
  }
407
411
  });
408
- syncMessage(useThread.getState(), useMessage, messageIndex);
409
- return { useMessage, useComposer };
412
+ syncMessage(
413
+ useThread.getState(),
414
+ useThreadActions.getState().getBranches,
415
+ useMessage,
416
+ messageIndex
417
+ );
418
+ return { useMessage, useMessageUtils, useComposer };
410
419
  });
411
420
  useEffect3(() => {
412
421
  return useThread.subscribe((thread) => {
413
- syncMessage(thread, context.useMessage, messageIndex);
422
+ syncMessage(
423
+ thread,
424
+ useThreadActions.getState().getBranches,
425
+ context.useMessage,
426
+ messageIndex
427
+ );
414
428
  });
415
- }, [context, useThread, messageIndex]);
429
+ }, [useThread, useThreadActions, context, messageIndex]);
416
430
  return context;
417
431
  };
418
432
  var MessageProvider = ({
@@ -439,16 +453,19 @@ var ComposerIf = ({ children, ...query }) => {
439
453
 
440
454
  // src/primitives/message/MessageIf.tsx
441
455
  var useMessageIf = (props) => {
442
- const { useMessage } = useMessageContext();
443
- return useMessage(({ message, branches, isLast, isCopied, isHovering }) => {
444
- if (props.hasBranches === true && branches.length < 2) return false;
445
- if (props.user && message.role !== "user") return false;
446
- if (props.assistant && message.role !== "assistant") return false;
447
- if (props.lastOrHover === true && !isHovering && !isLast) return false;
448
- if (props.copied === true && !isCopied) return false;
449
- if (props.copied === false && isCopied) return false;
450
- return true;
451
- });
456
+ const { useMessage, useMessageUtils } = useMessageContext();
457
+ return useCombinedStore(
458
+ [useMessage, useMessageUtils],
459
+ ({ message, branches, isLast }, { isCopied, isHovering }) => {
460
+ if (props.hasBranches === true && branches.length < 2) return false;
461
+ if (props.user && message.role !== "user") return false;
462
+ if (props.assistant && message.role !== "assistant") return false;
463
+ if (props.lastOrHover === true && !isHovering && !isLast) return false;
464
+ if (props.copied === true && !isCopied) return false;
465
+ if (props.copied === false && isCopied) return false;
466
+ return true;
467
+ }
468
+ );
452
469
  };
453
470
  var MessageIf = ({ children, ...query }) => {
454
471
  const result = useMessageIf(query);
@@ -727,8 +744,8 @@ import { forwardRef as forwardRef9 } from "react";
727
744
  import { jsx as jsx12 } from "react/jsx-runtime";
728
745
  var MessageRoot = forwardRef9(
729
746
  ({ onMouseEnter, onMouseLeave, ...rest }, ref) => {
730
- const { useMessage } = useMessageContext();
731
- const setIsHovering = useMessage((s) => s.setIsHovering);
747
+ const { useMessageUtils } = useMessageContext();
748
+ const setIsHovering = useMessageUtils((s) => s.setIsHovering);
732
749
  const handleMouseEnter = () => {
733
750
  setIsHovering(true);
734
751
  };
@@ -753,7 +770,7 @@ import { memo as memo2 } from "react";
753
770
 
754
771
  // src/context/providers/ContentPartProvider.tsx
755
772
  import { useEffect as useEffect5, useState as useState2 } from "react";
756
- import { create as create3 } from "zustand";
773
+ import { create as create4 } from "zustand";
757
774
  import { jsx as jsx13 } from "react/jsx-runtime";
758
775
  var syncContentPart = ({ message }, useContentPart, partIndex) => {
759
776
  const part = message.content[partIndex];
@@ -762,19 +779,24 @@ var syncContentPart = ({ message }, useContentPart, partIndex) => {
762
779
  const status = partIndex === message.content.length - 1 ? messageStatus : "done";
763
780
  const currentState = useContentPart.getState();
764
781
  if (currentState.part === part && currentState.status === status) return;
765
- useContentPart.setState({ part, status });
782
+ useContentPart.setState(
783
+ Object.freeze({
784
+ part,
785
+ status
786
+ })
787
+ );
766
788
  };
767
789
  var useContentPartContext2 = (partIndex) => {
768
790
  const { useMessage } = useMessageContext();
769
791
  const [context] = useState2(() => {
770
- const useContentPart = create3(() => ({
771
- part: { type: "text", text: "" },
772
- status: "done"
773
- }));
792
+ const useContentPart = create4(
793
+ () => ({})
794
+ );
774
795
  syncContentPart(useMessage.getState(), useContentPart, partIndex);
775
796
  return { useContentPart };
776
797
  });
777
798
  useEffect5(() => {
799
+ syncContentPart(useMessage.getState(), context.useContentPart, partIndex);
778
800
  return useMessage.subscribe((message) => {
779
801
  syncContentPart(message, context.useContentPart, partIndex);
780
802
  });
@@ -804,10 +826,10 @@ var ContentPartDisplay = () => {
804
826
 
805
827
  // src/primitives/contentPart/ContentPartInProgressIndicator.tsx
806
828
  var ContentPartInProgressIndicator = () => {
807
- const { useMessage } = useMessageContext();
829
+ const { useMessageUtils } = useMessageContext();
808
830
  const { useContentPart } = useContentPartContext();
809
831
  const indicator = useCombinedStore(
810
- [useMessage, useContentPart],
832
+ [useMessageUtils, useContentPart],
811
833
  (m, c) => c.status === "in_progress" ? m.inProgressIndicator : null
812
834
  );
813
835
  return indicator;
@@ -841,10 +863,8 @@ var defaultComponents = {
841
863
  UI: () => /* @__PURE__ */ jsx15(ContentPartDisplay, {}),
842
864
  tools: {
843
865
  Fallback: (props) => {
844
- const { useToolRenderers } = useAssistantContext();
845
- const Render = useToolRenderers(
846
- (s) => s.getToolRenderer(props.part.toolName)
847
- );
866
+ const { useToolUIs } = useAssistantContext();
867
+ const Render = useToolUIs((s) => s.getToolUI(props.part.toolName));
848
868
  if (!Render) return null;
849
869
  return /* @__PURE__ */ jsx15(Render, { ...props });
850
870
  }
@@ -858,6 +878,8 @@ var MessageContentPartComponent = ({
858
878
  tools: { by_name = {}, Fallback = defaultComponents.tools.Fallback } = {}
859
879
  } = {}
860
880
  }) => {
881
+ const { useThreadActions } = useThreadContext();
882
+ const addToolResult = useThreadActions((t) => t.addToolResult);
861
883
  const { useContentPart } = useContentPartContext();
862
884
  const { part, status } = useContentPart();
863
885
  const type = part.type;
@@ -870,7 +892,8 @@ var MessageContentPartComponent = ({
870
892
  return /* @__PURE__ */ jsx15(UI, { part, status });
871
893
  case "tool-call": {
872
894
  const Tool = by_name[part.toolName] || Fallback;
873
- return /* @__PURE__ */ jsx15(Tool, { part, status });
895
+ const addResult = (result) => addToolResult(part.toolCallId, result);
896
+ return /* @__PURE__ */ jsx15(Tool, { part, status, addResult });
874
897
  }
875
898
  default:
876
899
  throw new Error(`Unknown content part type: ${type}`);
@@ -910,10 +933,10 @@ import {
910
933
  } from "react";
911
934
  import { jsx as jsx16 } from "react/jsx-runtime";
912
935
  var MessageInProgress = forwardRef11((props, ref) => {
913
- const { useMessage } = useMessageContext();
936
+ const { useMessageUtils } = useMessageContext();
914
937
  useMemo2(() => {
915
- useMessage.getState().setInProgressIndicator(/* @__PURE__ */ jsx16(Primitive10.span, { ...props, ref }));
916
- }, [useMessage, props, ref]);
938
+ useMessageUtils.getState().setInProgressIndicator(/* @__PURE__ */ jsx16(Primitive10.span, { ...props, ref }));
939
+ }, [useMessageUtils, props, ref]);
917
940
  return null;
918
941
  });
919
942
  MessageInProgress.displayName = "MessageInProgress";
@@ -997,14 +1020,14 @@ import { forwardRef as forwardRef14 } from "react";
997
1020
  import { jsx as jsx21 } from "react/jsx-runtime";
998
1021
  var ActionBarRoot = forwardRef14(({ hideWhenRunning, autohide, autohideFloat, ...rest }, ref) => {
999
1022
  const { useThread } = useThreadContext();
1000
- const { useMessage } = useMessageContext();
1023
+ const { useMessage, useMessageUtils } = useMessageContext();
1001
1024
  const hideAndfloatStatus = useCombinedStore(
1002
- [useThread, useMessage],
1003
- (t, m) => {
1025
+ [useThread, useMessage, useMessageUtils],
1026
+ (t, m, mu) => {
1004
1027
  if (hideWhenRunning && t.isRunning) return "hidden" /* Hidden */;
1005
1028
  const autohideEnabled = autohide === "always" || autohide === "not-last" && !m.isLast;
1006
1029
  if (!autohideEnabled) return "normal" /* Normal */;
1007
- if (!m.isHovering) return "hidden" /* Hidden */;
1030
+ if (!mu.isHovering) return "hidden" /* Hidden */;
1008
1031
  if (autohideFloat === "always" || autohideFloat === "single-branch" && m.branches.length <= 1)
1009
1032
  return "floating" /* Floating */;
1010
1033
  return "normal" /* Normal */;
@@ -1337,6 +1360,9 @@ var LocalRuntime = class {
1337
1360
  this._configProviders.add(provider);
1338
1361
  return () => this._configProviders.delete(provider);
1339
1362
  }
1363
+ addToolResult() {
1364
+ throw new Error("LocalRuntime does not yet support tool results");
1365
+ }
1340
1366
  };
1341
1367
 
1342
1368
  // src/runtime/local/useLocalRuntime.tsx
@@ -1355,7 +1381,7 @@ import { memo as memo3 } from "react";
1355
1381
  import { useEffect as useEffect7, useInsertionEffect as useInsertionEffect3, useRef as useRef5, useState as useState5 } from "react";
1356
1382
 
1357
1383
  // src/context/stores/AssistantModelConfig.ts
1358
- import { create as create4 } from "zustand";
1384
+ import { create as create5 } from "zustand";
1359
1385
 
1360
1386
  // src/utils/ProxyConfigProvider.ts
1361
1387
  var ProxyConfigProvider = class {
@@ -1372,30 +1398,30 @@ var ProxyConfigProvider = class {
1372
1398
  };
1373
1399
 
1374
1400
  // src/context/stores/AssistantModelConfig.ts
1375
- var makeAssistantModelConfigStore = () => create4(() => {
1401
+ var makeAssistantModelConfigStore = () => create5(() => {
1376
1402
  const proxy = new ProxyConfigProvider();
1377
- return {
1403
+ return Object.freeze({
1378
1404
  getModelConfig: () => {
1379
1405
  return proxy.getModelConfig();
1380
1406
  },
1381
1407
  registerModelConfigProvider: (provider) => {
1382
1408
  return proxy.registerModelConfigProvider(provider);
1383
1409
  }
1384
- };
1410
+ });
1385
1411
  });
1386
1412
 
1387
- // src/context/stores/AssistantToolRenderers.ts
1388
- import { create as create5 } from "zustand";
1389
- var makeAssistantToolRenderersStore = () => create5((set) => {
1413
+ // src/context/stores/AssistantToolUIs.ts
1414
+ import { create as create6 } from "zustand";
1415
+ var makeAssistantToolUIsStore = () => create6((set) => {
1390
1416
  const renderers = /* @__PURE__ */ new Map();
1391
- return {
1392
- getToolRenderer: (name) => {
1417
+ return Object.freeze({
1418
+ getToolUI: (name) => {
1393
1419
  const arr = renderers.get(name);
1394
1420
  const last = arr?.at(-1);
1395
1421
  if (last) return last;
1396
1422
  return null;
1397
1423
  },
1398
- setToolRenderer: (name, render) => {
1424
+ setToolUI: (name, render) => {
1399
1425
  let arr = renderers.get(name);
1400
1426
  if (!arr) {
1401
1427
  arr = [];
@@ -1408,25 +1434,27 @@ var makeAssistantToolRenderersStore = () => create5((set) => {
1408
1434
  if (index !== -1) {
1409
1435
  arr.splice(index, 1);
1410
1436
  }
1411
- set({});
1437
+ if (index === arr.length) {
1438
+ set({});
1439
+ }
1412
1440
  };
1413
1441
  }
1414
- };
1442
+ });
1415
1443
  });
1416
1444
 
1417
1445
  // src/context/providers/ThreadProvider.tsx
1418
1446
  import { useEffect as useEffect6, useInsertionEffect as useInsertionEffect2, useRef as useRef4, useState as useState4 } from "react";
1419
1447
 
1420
1448
  // src/context/stores/Composer.ts
1421
- import { create as create6 } from "zustand";
1422
- var makeComposerStore = (useThread) => create6()((set, get, store) => {
1449
+ import { create as create7 } from "zustand";
1450
+ var makeComposerStore = (useThread, useThreadActions) => create7()((set, get, store) => {
1423
1451
  return {
1424
1452
  ...makeBaseComposer(set, get, store),
1425
1453
  isEditing: true,
1426
1454
  send: () => {
1427
1455
  const { setValue, value } = get();
1428
1456
  setValue("");
1429
- useThread.getState().append({
1457
+ useThreadActions.getState().append({
1430
1458
  parentId: useThread.getState().messages.at(-1)?.id ?? null,
1431
1459
  content: [{ type: "text", text: value }]
1432
1460
  });
@@ -1434,41 +1462,26 @@ var makeComposerStore = (useThread) => create6()((set, get, store) => {
1434
1462
  cancel: () => {
1435
1463
  const thread = useThread.getState();
1436
1464
  if (!thread.isRunning) return false;
1437
- useThread.getState().cancelRun();
1465
+ useThreadActions.getState().cancelRun();
1438
1466
  return true;
1439
1467
  }
1440
1468
  };
1441
1469
  });
1442
1470
 
1443
1471
  // src/context/stores/Thread.ts
1444
- import { create as create7 } from "zustand";
1472
+ import { create as create8 } from "zustand";
1445
1473
  var makeThreadStore = (runtimeRef) => {
1446
- const useThread = create7(() => ({
1474
+ return create8(() => ({
1447
1475
  messages: runtimeRef.current.messages,
1448
- isRunning: runtimeRef.current.isRunning,
1449
- getBranches: (messageId) => runtimeRef.current.getBranches(messageId),
1450
- switchToBranch: (branchId) => runtimeRef.current.switchToBranch(branchId),
1451
- startRun: (parentId) => runtimeRef.current.startRun(parentId),
1452
- append: (message) => runtimeRef.current.append(message),
1453
- cancelRun: () => runtimeRef.current.cancelRun()
1476
+ isRunning: runtimeRef.current.isRunning
1454
1477
  }));
1455
- const onRuntimeUpdate = () => {
1456
- useThread.setState({
1457
- messages: runtimeRef.current.messages,
1458
- isRunning: runtimeRef.current.isRunning
1459
- });
1460
- };
1461
- return {
1462
- useThread,
1463
- onRuntimeUpdate
1464
- };
1465
1478
  };
1466
1479
 
1467
1480
  // src/context/stores/ThreadViewport.tsx
1468
- import { create as create8 } from "zustand";
1481
+ import { create as create9 } from "zustand";
1469
1482
  var makeThreadViewportStore = () => {
1470
1483
  const scrollToBottomListeners = /* @__PURE__ */ new Set();
1471
- return create8(() => ({
1484
+ return create9(() => ({
1472
1485
  isAtBottom: true,
1473
1486
  scrollToBottom: () => {
1474
1487
  for (const listener of scrollToBottomListeners) {
@@ -1484,6 +1497,21 @@ var makeThreadViewportStore = () => {
1484
1497
  }));
1485
1498
  };
1486
1499
 
1500
+ // src/context/stores/ThreadActions.ts
1501
+ import { create as create10 } from "zustand";
1502
+ var makeThreadActionStore = (runtimeRef) => {
1503
+ return create10(
1504
+ () => Object.freeze({
1505
+ getBranches: (messageId) => runtimeRef.current.getBranches(messageId),
1506
+ switchToBranch: (branchId) => runtimeRef.current.switchToBranch(branchId),
1507
+ startRun: (parentId) => runtimeRef.current.startRun(parentId),
1508
+ append: (message) => runtimeRef.current.append(message),
1509
+ cancelRun: () => runtimeRef.current.cancelRun(),
1510
+ addToolResult: (toolCallId, result) => runtimeRef.current.addToolResult(toolCallId, result)
1511
+ })
1512
+ );
1513
+ };
1514
+
1487
1515
  // src/context/providers/ThreadProvider.tsx
1488
1516
  import { jsx as jsx23, jsxs as jsxs4 } from "react/jsx-runtime";
1489
1517
  var ThreadProvider = ({
@@ -1494,23 +1522,31 @@ var ThreadProvider = ({
1494
1522
  useInsertionEffect2(() => {
1495
1523
  runtimeRef.current = runtime;
1496
1524
  });
1497
- const [{ context, onRuntimeUpdate }] = useState4(() => {
1498
- const { useThread, onRuntimeUpdate: onRuntimeUpdate2 } = makeThreadStore(runtimeRef);
1525
+ const [context] = useState4(() => {
1526
+ const useThread = makeThreadStore(runtimeRef);
1527
+ const useThreadActions = makeThreadActionStore(runtimeRef);
1499
1528
  const useViewport = makeThreadViewportStore();
1500
- const useComposer = makeComposerStore(useThread);
1529
+ const useComposer = makeComposerStore(useThread, useThreadActions);
1501
1530
  return {
1502
- context: {
1503
- useViewport,
1504
- useThread,
1505
- useComposer
1506
- },
1507
- onRuntimeUpdate: onRuntimeUpdate2
1531
+ useThread,
1532
+ useThreadActions,
1533
+ useComposer,
1534
+ useViewport
1508
1535
  };
1509
1536
  });
1510
1537
  useEffect6(() => {
1538
+ const onRuntimeUpdate = () => {
1539
+ context.useThread.setState(
1540
+ Object.freeze({
1541
+ messages: runtimeRef.current.messages,
1542
+ isRunning: runtimeRef.current.isRunning
1543
+ }),
1544
+ true
1545
+ );
1546
+ };
1511
1547
  onRuntimeUpdate();
1512
1548
  return runtime.subscribe(onRuntimeUpdate);
1513
- }, [onRuntimeUpdate, runtime]);
1549
+ }, [context, runtime]);
1514
1550
  const RuntimeSynchronizer = runtime.unstable_synchronizer;
1515
1551
  return /* @__PURE__ */ jsxs4(ThreadContext.Provider, { value: context, children: [
1516
1552
  RuntimeSynchronizer && /* @__PURE__ */ jsx23(RuntimeSynchronizer, {}),
@@ -1527,8 +1563,8 @@ var AssistantProvider = ({ children, runtime }) => {
1527
1563
  });
1528
1564
  const [context] = useState5(() => {
1529
1565
  const useModelConfig = makeAssistantModelConfigStore();
1530
- const useToolRenderers = makeAssistantToolRenderersStore();
1531
- return { useModelConfig, useToolRenderers };
1566
+ const useToolUIs = makeAssistantToolUIsStore();
1567
+ return { useModelConfig, useToolUIs };
1532
1568
  });
1533
1569
  const getModelCOnfig = context.useModelConfig((c) => c.getModelConfig);
1534
1570
  useEffect7(() => {