@assistant-ui/react 0.5.10 → 0.5.12

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.mjs CHANGED
@@ -1192,7 +1192,7 @@ var toContentPartStatus = (message, partIndex, part) => {
1192
1192
  return message.status;
1193
1193
  };
1194
1194
  var EMPTY_CONTENT = Object.freeze({ type: "text", text: "" });
1195
- var syncContentPart = ({ message }, useContentPart, partIndex) => {
1195
+ var getContentPartState = ({ message }, useContentPart, partIndex) => {
1196
1196
  let part = message.content[partIndex];
1197
1197
  if (!part) {
1198
1198
  if (message.content.length === 0 && partIndex === 0) {
@@ -1202,29 +1202,32 @@ var syncContentPart = ({ message }, useContentPart, partIndex) => {
1202
1202
  }
1203
1203
  }
1204
1204
  const status = toContentPartStatus(message, partIndex, part);
1205
- const currentState = useContentPart.getState();
1206
- if (currentState.part === part && currentState.status === status) return;
1207
- useContentPart.setState(
1208
- Object.freeze({
1209
- part,
1210
- status
1211
- })
1212
- );
1205
+ const currentState = useContentPart?.getState();
1206
+ if (currentState && currentState.part === part && currentState.status === status)
1207
+ return null;
1208
+ return Object.freeze({ part, status });
1213
1209
  };
1214
1210
  var useContentPartContext2 = (partIndex) => {
1215
1211
  const { useMessage } = useMessageContext();
1216
1212
  const [context] = useState4(() => {
1217
1213
  const useContentPart = create10(
1218
- () => ({})
1214
+ () => getContentPartState(useMessage.getState(), void 0, partIndex)
1219
1215
  );
1220
- syncContentPart(useMessage.getState(), useContentPart, partIndex);
1216
+ getContentPartState(useMessage.getState(), useContentPart, partIndex);
1221
1217
  return { useContentPart };
1222
1218
  });
1223
1219
  useEffect6(() => {
1224
- syncContentPart(useMessage.getState(), context.useContentPart, partIndex);
1225
- return useMessage.subscribe((message) => {
1226
- syncContentPart(message, context.useContentPart, partIndex);
1227
- });
1220
+ const syncContentPart = (message) => {
1221
+ const newState = getContentPartState(
1222
+ message,
1223
+ context.useContentPart,
1224
+ partIndex
1225
+ );
1226
+ if (!newState) return;
1227
+ context.useContentPart.setState(newState, true);
1228
+ };
1229
+ syncContentPart(useMessage.getState());
1230
+ return useMessage.subscribe(syncContentPart);
1228
1231
  }, [context, useMessage, partIndex]);
1229
1232
  return context;
1230
1233
  };
@@ -1828,16 +1831,15 @@ import { jsx as jsx23 } from "react/jsx-runtime";
1828
1831
  var getIsLast = (messages, message) => {
1829
1832
  return messages[messages.length - 1]?.id === message.id;
1830
1833
  };
1831
- var syncMessage = (messages, getBranches, useMessage, messageIndex) => {
1834
+ var getMessageState = (messages, getBranches, useMessage, messageIndex) => {
1832
1835
  const parentId = messages[messageIndex - 1]?.id ?? null;
1833
1836
  const message = messages[messageIndex];
1834
- if (!message) return;
1835
1837
  const isLast = getIsLast(messages, message);
1836
1838
  const branches = getBranches(message.id);
1837
- const currentState = useMessage.getState();
1838
- if (currentState.message === message && currentState.parentId === parentId && currentState.branches === branches && currentState.isLast === isLast)
1839
- return;
1840
- useMessage.setState({
1839
+ const currentState = useMessage?.getState();
1840
+ if (currentState && currentState.message === message && currentState.parentId === parentId && currentState.branches === branches && currentState.isLast === isLast)
1841
+ return null;
1842
+ return Object.freeze({
1841
1843
  message,
1842
1844
  parentId,
1843
1845
  branches,
@@ -1847,7 +1849,14 @@ var syncMessage = (messages, getBranches, useMessage, messageIndex) => {
1847
1849
  var useMessageContext2 = (messageIndex) => {
1848
1850
  const { useThreadMessages, useThreadActions } = useThreadContext();
1849
1851
  const [context] = useState6(() => {
1850
- const useMessage = create13(() => ({}));
1852
+ const useMessage = create13(
1853
+ () => getMessageState(
1854
+ useThreadMessages.getState(),
1855
+ useThreadActions.getState().getBranches,
1856
+ void 0,
1857
+ messageIndex
1858
+ )
1859
+ );
1851
1860
  const useMessageUtils = makeMessageUtilsStore();
1852
1861
  const useEditComposer = makeEditComposerStore({
1853
1862
  onEdit: () => {
@@ -1875,23 +1884,24 @@ var useMessageContext2 = (messageIndex) => {
1875
1884
  });
1876
1885
  }
1877
1886
  });
1878
- syncMessage(
1879
- useThreadMessages.getState(),
1880
- useThreadActions.getState().getBranches,
1881
- useMessage,
1882
- messageIndex
1883
- );
1884
1887
  return { useMessage, useMessageUtils, useEditComposer };
1885
1888
  });
1886
1889
  useEffect10(() => {
1887
- return useThreadMessages.subscribe((thread) => {
1888
- syncMessage(
1890
+ const syncMessage = (thread) => {
1891
+ const newState = getMessageState(
1889
1892
  thread,
1890
1893
  useThreadActions.getState().getBranches,
1891
1894
  context.useMessage,
1892
1895
  messageIndex
1893
1896
  );
1894
- });
1897
+ if (!newState) return;
1898
+ context.useMessage.setState(
1899
+ newState,
1900
+ true
1901
+ );
1902
+ };
1903
+ syncMessage(useThreadMessages.getState());
1904
+ return useThreadMessages.subscribe(syncMessage);
1895
1905
  }, [useThreadMessages, useThreadActions, context, messageIndex]);
1896
1906
  return context;
1897
1907
  };
@@ -3572,7 +3582,7 @@ var getExternalStoreMessage = (message) => {
3572
3582
  };
3573
3583
 
3574
3584
  // src/runtimes/external-store/useExternalStoreSync.tsx
3575
- import { useEffect as useEffect11, useMemo as useMemo3 } from "react";
3585
+ import { useEffect as useEffect11, useInsertionEffect as useInsertionEffect4, useMemo as useMemo3, useRef as useRef6 } from "react";
3576
3586
 
3577
3587
  // src/runtimes/external-store/ThreadMessageConverter.ts
3578
3588
  var ThreadMessageConverter = class {
@@ -3588,13 +3598,104 @@ var ThreadMessageConverter = class {
3588
3598
  }
3589
3599
  };
3590
3600
 
3601
+ // src/runtimes/external-store/auto-status.tsx
3602
+ var AUTO_STATUS_RUNNING = Object.freeze({ type: "running" });
3603
+ var AUTO_STATUS_COMPLETE = Object.freeze({
3604
+ type: "complete",
3605
+ reason: "unknown"
3606
+ });
3607
+ var isAutoStatus = (status) => status === AUTO_STATUS_RUNNING || status === AUTO_STATUS_COMPLETE;
3608
+ var getAutoStatus = (isLast, isRunning) => isLast && isRunning ? AUTO_STATUS_RUNNING : AUTO_STATUS_COMPLETE;
3609
+
3610
+ // src/runtimes/external-store/ThreadMessageLike.tsx
3611
+ var fromThreadMessageLike = (like, fallbackId, fallbackStatus) => {
3612
+ const { role, content, id, createdAt, status } = like;
3613
+ const common = {
3614
+ id: id ?? fallbackId,
3615
+ createdAt: createdAt ?? /* @__PURE__ */ new Date()
3616
+ };
3617
+ switch (role) {
3618
+ case "assistant":
3619
+ return {
3620
+ ...common,
3621
+ role,
3622
+ content: content.map((part) => {
3623
+ const type = part.type;
3624
+ switch (type) {
3625
+ case "text":
3626
+ case "ui":
3627
+ return part;
3628
+ case "tool-call": {
3629
+ if ("argsText" in part) return part;
3630
+ return {
3631
+ ...part,
3632
+ argsText: JSON.stringify(part.args)
3633
+ };
3634
+ }
3635
+ default: {
3636
+ const unhandledType = type;
3637
+ throw new Error(`Unknown content part type: ${unhandledType}`);
3638
+ }
3639
+ }
3640
+ }),
3641
+ status: status ?? fallbackStatus
3642
+ };
3643
+ case "user":
3644
+ return {
3645
+ ...common,
3646
+ role,
3647
+ content: content.map((part) => {
3648
+ const type = part.type;
3649
+ switch (type) {
3650
+ case "text":
3651
+ case "ui":
3652
+ case "image":
3653
+ return part;
3654
+ default: {
3655
+ const unhandledType = type;
3656
+ throw new Error(`Unknown content part type: ${unhandledType}`);
3657
+ }
3658
+ }
3659
+ })
3660
+ };
3661
+ case "system":
3662
+ if (content.length !== 1 || content[0].type !== "text")
3663
+ throw new Error(
3664
+ "System messages must have exactly one text content part."
3665
+ );
3666
+ return {
3667
+ ...common,
3668
+ role,
3669
+ content
3670
+ };
3671
+ default: {
3672
+ const unsupportedRole = role;
3673
+ throw new Error(`Unknown message role: ${unsupportedRole}`);
3674
+ }
3675
+ }
3676
+ };
3677
+
3591
3678
  // src/runtimes/external-store/useExternalStoreSync.tsx
3592
3679
  var useExternalStoreSync = (adapter, updateData) => {
3680
+ const adapterRef = useRef6(adapter);
3681
+ useInsertionEffect4(() => {
3682
+ adapterRef.current = adapter;
3683
+ });
3593
3684
  const [converter, convertCallback] = useMemo3(() => {
3594
3685
  const converter2 = adapter.convertMessage ?? ((m) => m);
3595
3686
  const convertCallback2 = (cache, m, idx) => {
3687
+ const autoStatus = getAutoStatus(
3688
+ adapterRef.current.messages.at(-1) === m,
3689
+ adapterRef.current.isRunning ?? false
3690
+ );
3691
+ if (cache && (cache.role !== "assistant" || !isAutoStatus(cache.status) || cache.status.type === autoStatus.type))
3692
+ return cache;
3596
3693
  if (cache) return cache;
3597
- const newMessage = converter2(m, idx);
3694
+ const newMessage = fromThreadMessageLike(
3695
+ converter2(m, idx),
3696
+ idx.toString(),
3697
+ autoStatus
3698
+ );
3598
3699
  newMessage[symbolInnerMessage] = m;
3599
3700
  return newMessage;
3600
3701
  };
@@ -3760,10 +3861,10 @@ var ExternalStoreRuntime = class extends BaseAssistantRuntime {
3760
3861
  };
3761
3862
 
3762
3863
  // src/runtimes/external-store/useExternalStoreRuntime.tsx
3763
- import { useEffect as useEffect12, useInsertionEffect as useInsertionEffect4, useState as useState9 } from "react";
3864
+ import { useEffect as useEffect12, useInsertionEffect as useInsertionEffect5, useState as useState9 } from "react";
3764
3865
  var useExternalStoreRuntime = (store) => {
3765
3866
  const [runtime] = useState9(() => new ExternalStoreRuntime(store));
3766
- useInsertionEffect4(() => {
3867
+ useInsertionEffect5(() => {
3767
3868
  runtime.store = store;
3768
3869
  });
3769
3870
  useEffect12(() => {