@assistant-ui/react 0.5.42 → 0.5.45

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
@@ -164,6 +164,7 @@ import { create as create4 } from "zustand";
164
164
  var getThreadStateFromRuntime = (runtime) => {
165
165
  const lastMessage = runtime.messages.at(-1);
166
166
  return Object.freeze({
167
+ threadId: runtime.threadId,
167
168
  capabilities: runtime.capabilities,
168
169
  isDisabled: runtime.isDisabled,
169
170
  isRunning: lastMessage?.role !== "assistant" ? false : lastMessage.status.type === "running"
@@ -636,6 +637,9 @@ var useSmooth = (state, smooth = false) => {
636
637
  setDisplayedText(text2);
637
638
  useSmoothStatus2?.setState(text2 !== state.part.text ? SMOOTH_STATUS : state.status);
638
639
  });
640
+ useEffect(() => {
641
+ useSmoothStatus2?.setState(text !== displayedText ? SMOOTH_STATUS : state.status);
642
+ }, [useSmoothStatus2, text, displayedText, state.status]);
639
643
  const [animatorRef] = useState2(
640
644
  new TextStreamAnimator(text, setText)
641
645
  );
@@ -1077,6 +1081,7 @@ var LocalThreadRuntime = class {
1077
1081
  constructor(configProvider, adapter, { initialMessages, ...options }) {
1078
1082
  this.configProvider = configProvider;
1079
1083
  this.adapter = adapter;
1084
+ this.threadId = generateId();
1080
1085
  this.options = options;
1081
1086
  if (initialMessages) {
1082
1087
  let parentId = null;
@@ -1098,6 +1103,7 @@ var LocalThreadRuntime = class {
1098
1103
  unstable_copy: true,
1099
1104
  speak: false
1100
1105
  };
1106
+ threadId;
1101
1107
  isDisabled = false;
1102
1108
  get messages() {
1103
1109
  return this.repository.getMessages();
@@ -1400,11 +1406,12 @@ var getAutoStatus = (isLast, isRunning) => isLast && isRunning ? AUTO_STATUS_RUN
1400
1406
 
1401
1407
  // src/runtimes/external-store/ThreadMessageLike.tsx
1402
1408
  var fromThreadMessageLike = (like, fallbackId, fallbackStatus) => {
1403
- const { role, content, id, createdAt, status } = like;
1409
+ const { role, id, createdAt, status } = like;
1404
1410
  const common = {
1405
1411
  id: id ?? fallbackId,
1406
1412
  createdAt: createdAt ?? /* @__PURE__ */ new Date()
1407
1413
  };
1414
+ const content = typeof like.content === "string" ? [{ type: "text", text: like.content }] : like.content;
1408
1415
  switch (role) {
1409
1416
  case "assistant":
1410
1417
  return {
@@ -1414,6 +1421,8 @@ var fromThreadMessageLike = (like, fallbackId, fallbackStatus) => {
1414
1421
  const type = part.type;
1415
1422
  switch (type) {
1416
1423
  case "text":
1424
+ if (part.text.trim().length === 0) return null;
1425
+ return part;
1417
1426
  case "ui":
1418
1427
  return part;
1419
1428
  case "tool-call": {
@@ -1428,7 +1437,7 @@ var fromThreadMessageLike = (like, fallbackId, fallbackStatus) => {
1428
1437
  throw new Error(`Unknown content part type: ${unhandledType}`);
1429
1438
  }
1430
1439
  }
1431
- }),
1440
+ }).filter((c) => !!c),
1432
1441
  status: status ?? fallbackStatus
1433
1442
  };
1434
1443
  case "user":
@@ -1493,8 +1502,9 @@ var ExternalStoreThreadRuntime = class {
1493
1502
  get capabilities() {
1494
1503
  return this._capabilities;
1495
1504
  }
1496
- messages = [];
1497
- isDisabled = false;
1505
+ threadId;
1506
+ messages;
1507
+ isDisabled;
1498
1508
  converter = new ThreadMessageConverter();
1499
1509
  _store;
1500
1510
  composer = {
@@ -1507,8 +1517,12 @@ var ExternalStoreThreadRuntime = class {
1507
1517
  constructor(store) {
1508
1518
  this.store = store;
1509
1519
  }
1520
+ get store() {
1521
+ return this._store;
1522
+ }
1510
1523
  set store(store) {
1511
1524
  if (this._store === store) return;
1525
+ this.threadId = store.threadId ?? this.threadId ?? generateId();
1512
1526
  const isRunning = store.isRunning ?? false;
1513
1527
  this.isDisabled = store.isDisabled ?? false;
1514
1528
  const oldStore = this._store;
@@ -1644,6 +1658,9 @@ var ExternalStoreRuntime = class extends BaseAssistantRuntime {
1644
1658
  constructor(store) {
1645
1659
  super(new ExternalStoreThreadRuntime(store));
1646
1660
  }
1661
+ get store() {
1662
+ return this.thread.store;
1663
+ }
1647
1664
  set store(store) {
1648
1665
  this.thread.store = store;
1649
1666
  }
@@ -1684,6 +1701,153 @@ var useExternalStoreRuntime = (store) => {
1684
1701
  return runtime;
1685
1702
  };
1686
1703
 
1704
+ // src/runtimes/external-store/external-message-converter.tsx
1705
+ import { useMemo as useMemo2 } from "react";
1706
+ var joinExternalMessages = (messages) => {
1707
+ const assistantMessage = {
1708
+ role: "assistant",
1709
+ content: []
1710
+ };
1711
+ for (const output of messages) {
1712
+ if (output.role === "tool") {
1713
+ const toolCallIdx = assistantMessage.content.findIndex(
1714
+ (c) => c.type === "tool-call" && c.toolCallId === output.toolCallId
1715
+ );
1716
+ if (toolCallIdx !== -1) {
1717
+ const toolCall = assistantMessage.content[toolCallIdx];
1718
+ if (output.toolName) {
1719
+ if (toolCall.toolName !== output.toolName)
1720
+ throw new Error(
1721
+ `Tool call name ${output.toolCallId} ${output.toolName} does not match existing tool call ${toolCall.toolName}`
1722
+ );
1723
+ }
1724
+ assistantMessage.content[toolCallIdx] = {
1725
+ ...toolCall,
1726
+ result: output.result
1727
+ };
1728
+ } else {
1729
+ throw new Error(
1730
+ `Tool call ${output.toolCallId} ${output.toolName} not found in assistant message`
1731
+ );
1732
+ }
1733
+ } else {
1734
+ const content = output.content;
1735
+ const role = output.role;
1736
+ switch (role) {
1737
+ case "system":
1738
+ case "user":
1739
+ return { role, content };
1740
+ case "assistant":
1741
+ if (assistantMessage.content.length === 0) {
1742
+ assistantMessage.id = output.id;
1743
+ assistantMessage.createdAt ??= output.createdAt;
1744
+ assistantMessage.status ??= output.status;
1745
+ }
1746
+ assistantMessage.content.push(...content);
1747
+ break;
1748
+ default: {
1749
+ const unsupportedRole = role;
1750
+ throw new Error(`Unknown message role: ${unsupportedRole}`);
1751
+ }
1752
+ }
1753
+ }
1754
+ }
1755
+ return assistantMessage;
1756
+ };
1757
+ var chunkExternalMessages = (callbackResults) => {
1758
+ const results = [];
1759
+ let isAssistant = false;
1760
+ let inputs = [];
1761
+ let outputs = [];
1762
+ const flush = () => {
1763
+ if (outputs.length) {
1764
+ results.push({
1765
+ inputs,
1766
+ outputs
1767
+ });
1768
+ }
1769
+ inputs = [];
1770
+ outputs = [];
1771
+ };
1772
+ for (const callbackResult of callbackResults) {
1773
+ for (const output of callbackResult.outputs) {
1774
+ if (!isAssistant || output.role === "user" || output.role === "system") {
1775
+ flush();
1776
+ }
1777
+ isAssistant = output.role === "assistant" || output.role === "tool";
1778
+ if (inputs.at(-1) !== callbackResult.input) {
1779
+ inputs.push(callbackResult.input);
1780
+ }
1781
+ outputs.push(output);
1782
+ }
1783
+ }
1784
+ flush();
1785
+ return results;
1786
+ };
1787
+ var useExternalMessageConverter = ({
1788
+ callback,
1789
+ messages,
1790
+ isRunning
1791
+ }) => {
1792
+ const state = useMemo2(
1793
+ () => ({
1794
+ callback,
1795
+ callbackCache: /* @__PURE__ */ new WeakMap(),
1796
+ chunkCache: /* @__PURE__ */ new WeakMap(),
1797
+ converterCache: new ThreadMessageConverter()
1798
+ }),
1799
+ [callback]
1800
+ );
1801
+ return useMemo2(() => {
1802
+ const callbackResults = [];
1803
+ for (const message of messages) {
1804
+ let result = state.callbackCache.get(message);
1805
+ if (!result) {
1806
+ const output = state.callback(message);
1807
+ const outputs = Array.isArray(output) ? output : [output];
1808
+ result = { input: message, outputs };
1809
+ state.callbackCache.set(message, result);
1810
+ }
1811
+ callbackResults.push(result);
1812
+ }
1813
+ const chunks = chunkExternalMessages(callbackResults).map((m) => {
1814
+ const key = m.outputs[0];
1815
+ if (!key) return m;
1816
+ const cached = state.chunkCache.get(key);
1817
+ if (cached && shallowArrayEqual(cached.outputs, m.outputs)) return cached;
1818
+ state.chunkCache.set(key, m);
1819
+ return m;
1820
+ });
1821
+ return state.converterCache.convertMessages(
1822
+ chunks,
1823
+ (cache, message, idx) => {
1824
+ const isLast = idx === chunks.length - 1;
1825
+ const autoStatus = getAutoStatus(isLast, isRunning);
1826
+ if (cache && (cache.role !== "assistant" || !isAutoStatus(cache.status) || cache.status === autoStatus)) {
1827
+ const inputs = getExternalStoreMessage(cache);
1828
+ if (shallowArrayEqual(inputs, message.inputs)) {
1829
+ return cache;
1830
+ }
1831
+ }
1832
+ const newMessage = fromThreadMessageLike(
1833
+ joinExternalMessages(message.outputs),
1834
+ idx.toString(),
1835
+ autoStatus
1836
+ );
1837
+ newMessage[symbolInnerMessage] = message.inputs;
1838
+ return newMessage;
1839
+ }
1840
+ );
1841
+ }, [state, messages, isRunning]);
1842
+ };
1843
+ var shallowArrayEqual = (a, b) => {
1844
+ if (a.length !== b.length) return false;
1845
+ for (let i = 0; i < a.length; i++) {
1846
+ if (a[i] !== b[i]) return false;
1847
+ }
1848
+ return true;
1849
+ };
1850
+
1687
1851
  // src/runtimes/dangerous-in-browser/useDangerousInBrowserRuntime.ts
1688
1852
  import { useState as useState6 } from "react";
1689
1853
 
@@ -1788,7 +1952,7 @@ var ThreadProvider = ({
1788
1952
  const thread = provider.thread;
1789
1953
  const oldState = context.useThread.getState();
1790
1954
  const state = getThreadStateFromRuntime(thread);
1791
- if (oldState.isDisabled !== state.isDisabled || oldState.isRunning !== state.isRunning || // TODO ensure capabilities is memoized
1955
+ if (oldState.threadId !== state.threadId || oldState.isDisabled !== state.isDisabled || oldState.isRunning !== state.isRunning || // TODO ensure capabilities is memoized
1792
1956
  oldState.capabilities !== state.capabilities) {
1793
1957
  context.useThread.setState(
1794
1958
  state,
@@ -1877,7 +2041,7 @@ var AssistantRuntimeProviderImpl = ({ children, runtime }) => {
1877
2041
  var AssistantRuntimeProvider = memo(AssistantRuntimeProviderImpl);
1878
2042
 
1879
2043
  // src/context/react/ComposerContext.ts
1880
- import { useMemo as useMemo2 } from "react";
2044
+ import { useMemo as useMemo3 } from "react";
1881
2045
 
1882
2046
  // src/context/react/MessageContext.ts
1883
2047
  import { createContext as createContext4, useContext as useContext4 } from "react";
@@ -1895,7 +2059,7 @@ function useMessageContext(options) {
1895
2059
  var useComposerContext = () => {
1896
2060
  const { useComposer } = useThreadContext();
1897
2061
  const { useEditComposer } = useMessageContext({ optional: true }) ?? {};
1898
- return useMemo2(
2062
+ return useMemo3(
1899
2063
  () => ({
1900
2064
  useComposer: useEditComposer ?? useComposer,
1901
2065
  type: useEditComposer ? "edit" : "new"
@@ -2035,7 +2199,7 @@ var useAssistantInstructions = (instruction) => {
2035
2199
  import { useCallback as useCallback3 } from "react";
2036
2200
 
2037
2201
  // src/utils/combined/useCombinedStore.ts
2038
- import { useMemo as useMemo3 } from "react";
2202
+ import { useMemo as useMemo4 } from "react";
2039
2203
 
2040
2204
  // src/utils/combined/createCombinedStore.ts
2041
2205
  import { useSyncExternalStore } from "react";
@@ -2056,7 +2220,7 @@ var createCombinedStore = (stores) => {
2056
2220
 
2057
2221
  // src/utils/combined/useCombinedStore.ts
2058
2222
  var useCombinedStore = (stores, selector) => {
2059
- const useCombined = useMemo3(() => createCombinedStore(stores), stores);
2223
+ const useCombined = useMemo4(() => createCombinedStore(stores), stores);
2060
2224
  return useCombined(selector);
2061
2225
  };
2062
2226
 
@@ -2918,6 +3082,7 @@ var MessageContentPartComponent = ({
2918
3082
  const Tool = by_name[part.toolName] || Fallback2;
2919
3083
  const addResult = (result) => addToolResult({
2920
3084
  messageId: useMessage.getState().message.id,
3085
+ toolName: part.toolName,
2921
3086
  toolCallId: part.toolCallId,
2922
3087
  result
2923
3088
  });
@@ -4327,6 +4492,7 @@ export {
4327
4492
  useContentPartText,
4328
4493
  useDangerousInBrowserRuntime,
4329
4494
  useEdgeRuntime,
4495
+ useExternalMessageConverter,
4330
4496
  useExternalStoreRuntime,
4331
4497
  useLocalRuntime,
4332
4498
  useMessageContext,