@assistant-ui/core 0.2.21 → 0.2.23

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.
Files changed (345) hide show
  1. package/dist/adapters/attachment.d.ts.map +1 -1
  2. package/dist/adapters/speech.d.ts.map +1 -1
  3. package/dist/adapters/speech.js +9 -2
  4. package/dist/adapters/speech.js.map +1 -1
  5. package/dist/adapters/thread-history.d.ts +8 -0
  6. package/dist/adapters/thread-history.d.ts.map +1 -1
  7. package/dist/adapters/voice.d.ts.map +1 -1
  8. package/dist/adapters/voice.js +13 -5
  9. package/dist/adapters/voice.js.map +1 -1
  10. package/dist/internal.d.ts +5 -2
  11. package/dist/internal.js +5 -2
  12. package/dist/model-context/frame/host.d.ts +1 -0
  13. package/dist/model-context/frame/host.d.ts.map +1 -1
  14. package/dist/model-context/frame/host.js +41 -21
  15. package/dist/model-context/frame/host.js.map +1 -1
  16. package/dist/model-context/frame/provider.d.ts.map +1 -1
  17. package/dist/model-context/frame/provider.js +1 -0
  18. package/dist/model-context/frame/provider.js.map +1 -1
  19. package/dist/model-context/interactable-composer-metadata.js.map +1 -1
  20. package/dist/model-context/types.d.ts.map +1 -1
  21. package/dist/model-context/types.js +13 -4
  22. package/dist/model-context/types.js.map +1 -1
  23. package/dist/react/AssistantProvider.js.map +1 -1
  24. package/dist/react/adapters/LocalStorageThreadListAdapter.d.ts.map +1 -1
  25. package/dist/react/adapters/LocalStorageThreadListAdapter.js +78 -50
  26. package/dist/react/adapters/LocalStorageThreadListAdapter.js.map +1 -1
  27. package/dist/react/client/Interactables.js.map +1 -1
  28. package/dist/react/client/Tools.d.ts.map +1 -1
  29. package/dist/react/client/interactable-model-context.d.ts.map +1 -1
  30. package/dist/react/client/interactable-model-context.js +1 -0
  31. package/dist/react/client/interactable-model-context.js.map +1 -1
  32. package/dist/react/interactables-legacy/useInteractableState.js +1 -0
  33. package/dist/react/interactables-legacy/useInteractableState.js.map +1 -1
  34. package/dist/react/model-context/useInteractable.js.map +1 -1
  35. package/dist/react/model-context/useInteractableState.js +1 -0
  36. package/dist/react/model-context/useInteractableState.js.map +1 -1
  37. package/dist/react/model-context/useInteractableVersions.js +1 -0
  38. package/dist/react/model-context/useInteractableVersions.js.map +1 -1
  39. package/dist/react/model-context/useToolArgsStatus.js +1 -0
  40. package/dist/react/model-context/useToolArgsStatus.js.map +1 -1
  41. package/dist/react/primitive-hooks/useActionBarCopy.js +14 -13
  42. package/dist/react/primitive-hooks/useActionBarCopy.js.map +1 -1
  43. package/dist/react/primitive-hooks/useActionBarEdit.js +1 -0
  44. package/dist/react/primitive-hooks/useActionBarEdit.js.map +1 -1
  45. package/dist/react/primitive-hooks/useActionBarFeedback.js +1 -0
  46. package/dist/react/primitive-hooks/useActionBarFeedback.js.map +1 -1
  47. package/dist/react/primitive-hooks/useActionBarReload.js +1 -0
  48. package/dist/react/primitive-hooks/useActionBarReload.js.map +1 -1
  49. package/dist/react/primitive-hooks/useActionBarSpeak.js +1 -0
  50. package/dist/react/primitive-hooks/useActionBarSpeak.js.map +1 -1
  51. package/dist/react/primitive-hooks/useActionBarStopSpeaking.js +1 -0
  52. package/dist/react/primitive-hooks/useActionBarStopSpeaking.js.map +1 -1
  53. package/dist/react/primitive-hooks/useBranchPickerNext.js +1 -0
  54. package/dist/react/primitive-hooks/useBranchPickerNext.js.map +1 -1
  55. package/dist/react/primitive-hooks/useBranchPickerPrevious.js +1 -0
  56. package/dist/react/primitive-hooks/useBranchPickerPrevious.js.map +1 -1
  57. package/dist/react/primitive-hooks/useComposerAddAttachment.d.ts.map +1 -1
  58. package/dist/react/primitive-hooks/useComposerAddAttachment.js +1 -0
  59. package/dist/react/primitive-hooks/useComposerAddAttachment.js.map +1 -1
  60. package/dist/react/primitive-hooks/useComposerCancel.js +1 -0
  61. package/dist/react/primitive-hooks/useComposerCancel.js.map +1 -1
  62. package/dist/react/primitive-hooks/useComposerDictate.js +1 -0
  63. package/dist/react/primitive-hooks/useComposerDictate.js.map +1 -1
  64. package/dist/react/primitive-hooks/useComposerSend.d.ts.map +1 -1
  65. package/dist/react/primitive-hooks/useComposerSend.js +1 -0
  66. package/dist/react/primitive-hooks/useComposerSend.js.map +1 -1
  67. package/dist/react/primitive-hooks/useEditComposerCancel.js +1 -0
  68. package/dist/react/primitive-hooks/useEditComposerCancel.js.map +1 -1
  69. package/dist/react/primitive-hooks/useEditComposerSend.js +1 -0
  70. package/dist/react/primitive-hooks/useEditComposerSend.js.map +1 -1
  71. package/dist/react/primitive-hooks/useMessageBranching.js +1 -0
  72. package/dist/react/primitive-hooks/useMessageBranching.js.map +1 -1
  73. package/dist/react/primitive-hooks/useMessageReload.js +1 -0
  74. package/dist/react/primitive-hooks/useMessageReload.js.map +1 -1
  75. package/dist/react/primitive-hooks/useSuggestionTrigger.js +1 -0
  76. package/dist/react/primitive-hooks/useSuggestionTrigger.js.map +1 -1
  77. package/dist/react/primitive-hooks/useThreadListItemArchive.js +1 -0
  78. package/dist/react/primitive-hooks/useThreadListItemArchive.js.map +1 -1
  79. package/dist/react/primitive-hooks/useThreadListItemDelete.js +1 -0
  80. package/dist/react/primitive-hooks/useThreadListItemDelete.js.map +1 -1
  81. package/dist/react/primitive-hooks/useThreadListItemTrigger.js +1 -0
  82. package/dist/react/primitive-hooks/useThreadListItemTrigger.js.map +1 -1
  83. package/dist/react/primitive-hooks/useThreadListItemUnarchive.js +1 -0
  84. package/dist/react/primitive-hooks/useThreadListItemUnarchive.js.map +1 -1
  85. package/dist/react/primitive-hooks/useThreadListLoadMore.js +1 -0
  86. package/dist/react/primitive-hooks/useThreadListLoadMore.js.map +1 -1
  87. package/dist/react/primitive-hooks/useThreadListNew.js +1 -0
  88. package/dist/react/primitive-hooks/useThreadListNew.js.map +1 -1
  89. package/dist/react/primitives/chainOfThought/ChainOfThoughtParts.d.ts.map +1 -1
  90. package/dist/react/primitives/chainOfThought/ChainOfThoughtParts.js +1 -1
  91. package/dist/react/primitives/chainOfThought/ChainOfThoughtParts.js.map +1 -1
  92. package/dist/react/primitives/composer/ComposerAttachments.js.map +1 -1
  93. package/dist/react/primitives/composer/ComposerQueue.d.ts.map +1 -1
  94. package/dist/react/primitives/composer/ComposerQueue.js.map +1 -1
  95. package/dist/react/primitives/generativeUI/GenerativeUI.d.ts.map +1 -1
  96. package/dist/react/primitives/message/MessageAttachments.js.map +1 -1
  97. package/dist/react/primitives/message/MessageGroupedParts.js.map +1 -1
  98. package/dist/react/primitives/message/MessageParts.d.ts +2 -1
  99. package/dist/react/primitives/message/MessageParts.d.ts.map +1 -1
  100. package/dist/react/primitives/message/MessageParts.js +46 -36
  101. package/dist/react/primitives/message/MessageParts.js.map +1 -1
  102. package/dist/react/primitives/part/PartMessages.js.map +1 -1
  103. package/dist/react/primitives/thread/ThreadMessages.js.map +1 -1
  104. package/dist/react/primitives/thread/ThreadSuggestions.js.map +1 -1
  105. package/dist/react/primitives/threadList/ThreadListItems.js.map +1 -1
  106. package/dist/react/providers/ChainOfThoughtPartByIndexProvider.d.ts.map +1 -1
  107. package/dist/react/providers/ChainOfThoughtPartByIndexProvider.js +18 -30
  108. package/dist/react/providers/ChainOfThoughtPartByIndexProvider.js.map +1 -1
  109. package/dist/react/providers/PartByIndexProvider.d.ts.map +1 -1
  110. package/dist/react/providers/PartByIndexProvider.js +18 -30
  111. package/dist/react/providers/PartByIndexProvider.js.map +1 -1
  112. package/dist/react/providers/TextMessagePartProvider.js +1 -0
  113. package/dist/react/providers/TextMessagePartProvider.js.map +1 -1
  114. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
  115. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +1 -0
  116. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
  117. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +9 -2
  118. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
  119. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +55 -12
  120. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
  121. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts +31 -1
  122. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
  123. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +12 -2
  124. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
  125. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts +1 -1
  126. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts.map +1 -1
  127. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js +3 -2
  128. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js.map +1 -1
  129. package/dist/react/runtimes/cloud/auiV0.d.ts +12 -1
  130. package/dist/react/runtimes/cloud/auiV0.d.ts.map +1 -1
  131. package/dist/react/runtimes/cloud/auiV0.js +2 -1
  132. package/dist/react/runtimes/cloud/auiV0.js.map +1 -1
  133. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js +75 -73
  134. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js.map +1 -1
  135. package/dist/react/runtimes/createMessageConverter.d.ts.map +1 -1
  136. package/dist/react/runtimes/external-message-converter.js +2 -2
  137. package/dist/react/runtimes/external-message-converter.js.map +1 -1
  138. package/dist/react/runtimes/useExternalStoreSharedOptions.js +1 -0
  139. package/dist/react/runtimes/useExternalStoreSharedOptions.js.map +1 -1
  140. package/dist/react/runtimes/useLocalRuntime.d.ts.map +1 -1
  141. package/dist/react/runtimes/useLocalRuntime.js +9 -1
  142. package/dist/react/runtimes/useLocalRuntime.js.map +1 -1
  143. package/dist/runtime/api/assistant-runtime.d.ts +1 -1
  144. package/dist/runtime/api/assistant-runtime.d.ts.map +1 -1
  145. package/dist/runtime/api/assistant-runtime.js +1 -1
  146. package/dist/runtime/api/assistant-runtime.js.map +1 -1
  147. package/dist/runtime/api/attachment-runtime.d.ts +1 -1
  148. package/dist/runtime/api/attachment-runtime.d.ts.map +1 -1
  149. package/dist/runtime/api/attachment-runtime.js +1 -1
  150. package/dist/runtime/api/attachment-runtime.js.map +1 -1
  151. package/dist/runtime/api/composer-runtime.d.ts +2 -2
  152. package/dist/runtime/api/composer-runtime.d.ts.map +1 -1
  153. package/dist/runtime/api/composer-runtime.js +2 -2
  154. package/dist/runtime/api/composer-runtime.js.map +1 -1
  155. package/dist/runtime/api/message-part-runtime.d.ts +4 -4
  156. package/dist/runtime/api/message-part-runtime.d.ts.map +1 -1
  157. package/dist/runtime/api/message-part-runtime.js +3 -3
  158. package/dist/runtime/api/message-part-runtime.js.map +1 -1
  159. package/dist/runtime/api/message-runtime.d.ts +1 -1
  160. package/dist/runtime/api/message-runtime.d.ts.map +1 -1
  161. package/dist/runtime/api/message-runtime.js +6 -6
  162. package/dist/runtime/api/message-runtime.js.map +1 -1
  163. package/dist/runtime/api/thread-list-item-runtime.d.ts +1 -1
  164. package/dist/runtime/api/thread-list-item-runtime.d.ts.map +1 -1
  165. package/dist/runtime/api/thread-list-item-runtime.js +4 -3
  166. package/dist/runtime/api/thread-list-item-runtime.js.map +1 -1
  167. package/dist/runtime/api/thread-list-runtime.d.ts +1 -1
  168. package/dist/runtime/api/thread-list-runtime.d.ts.map +1 -1
  169. package/dist/runtime/api/thread-list-runtime.js +1 -1
  170. package/dist/runtime/api/thread-list-runtime.js.map +1 -1
  171. package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
  172. package/dist/runtime/base/base-composer-runtime-core.d.ts +4 -1
  173. package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
  174. package/dist/runtime/base/base-composer-runtime-core.js +41 -14
  175. package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
  176. package/dist/runtime/base/base-thread-runtime-core.d.ts +1 -1
  177. package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
  178. package/dist/runtime/base/base-thread-runtime-core.js +3 -2
  179. package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
  180. package/dist/runtime/base/default-edit-composer-runtime-core.d.ts +2 -2
  181. package/dist/runtime/base/default-edit-composer-runtime-core.d.ts.map +1 -1
  182. package/dist/runtime/base/default-edit-composer-runtime-core.js +6 -4
  183. package/dist/runtime/base/default-edit-composer-runtime-core.js.map +1 -1
  184. package/dist/runtime/base/default-thread-composer-runtime-core.d.ts +1 -1
  185. package/dist/runtime/base/default-thread-composer-runtime-core.d.ts.map +1 -1
  186. package/dist/runtime/base/default-thread-composer-runtime-core.js +3 -3
  187. package/dist/runtime/base/default-thread-composer-runtime-core.js.map +1 -1
  188. package/dist/runtime/utils/message-repository.d.ts.map +1 -1
  189. package/dist/runtime/utils/message-repository.js +4 -2
  190. package/dist/runtime/utils/message-repository.js.map +1 -1
  191. package/dist/runtime/utils/thread-message-like.js +4 -1
  192. package/dist/runtime/utils/thread-message-like.js.map +1 -1
  193. package/dist/runtimes/external-store/external-store-runtime-core.d.ts.map +1 -1
  194. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts +1 -1
  195. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts.map +1 -1
  196. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js +1 -1
  197. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js.map +1 -1
  198. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
  199. package/dist/runtimes/external-store/external-store-thread-runtime-core.js +12 -0
  200. package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
  201. package/dist/runtimes/internal.d.ts +2 -1
  202. package/dist/runtimes/internal.js +2 -1
  203. package/dist/runtimes/local/local-runtime-core.d.ts.map +1 -1
  204. package/dist/runtimes/local/local-thread-list-runtime-core.d.ts.map +1 -1
  205. package/dist/runtimes/local/local-thread-runtime-core.d.ts +3 -0
  206. package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
  207. package/dist/runtimes/local/local-thread-runtime-core.js +49 -15
  208. package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
  209. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts.map +1 -1
  210. package/dist/runtimes/remote-thread-list/optimistic-state.d.ts +4 -4
  211. package/dist/runtimes/remote-thread-list/optimistic-state.d.ts.map +1 -1
  212. package/dist/runtimes/remote-thread-list/optimistic-state.js +22 -9
  213. package/dist/runtimes/remote-thread-list/optimistic-state.js.map +1 -1
  214. package/dist/runtimes/remote-thread-list/types.d.ts +1 -1
  215. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts +32 -27
  216. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts.map +1 -1
  217. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js +3 -2
  218. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js.map +1 -1
  219. package/dist/store/clients/chain-of-thought-client.d.ts.map +1 -1
  220. package/dist/store/clients/no-op-composer-client.d.ts.map +1 -1
  221. package/dist/store/clients/no-op-composer-client.js +1 -0
  222. package/dist/store/clients/no-op-composer-client.js.map +1 -1
  223. package/dist/store/runtime-clients/attachment-runtime-client.d.ts.map +1 -1
  224. package/dist/store/runtime-clients/composer-runtime-client.d.ts.map +1 -1
  225. package/dist/store/runtime-clients/message-part-runtime-client.d.ts.map +1 -1
  226. package/dist/store/runtime-clients/message-runtime-client.d.ts.map +1 -1
  227. package/dist/store/runtime-clients/thread-list-item-runtime-client.d.ts.map +1 -1
  228. package/dist/store/runtime-clients/thread-list-runtime-client.d.ts.map +1 -1
  229. package/dist/store/runtime-clients/thread-list-runtime-client.js +1 -0
  230. package/dist/store/runtime-clients/thread-list-runtime-client.js.map +1 -1
  231. package/dist/store/runtime-clients/thread-runtime-client.d.ts.map +1 -1
  232. package/dist/store/runtime-clients/thread-runtime-client.js +17 -15
  233. package/dist/store/runtime-clients/thread-runtime-client.js.map +1 -1
  234. package/dist/store/scopes/thread.d.ts +1 -0
  235. package/dist/store/scopes/thread.d.ts.map +1 -1
  236. package/dist/subscribable/subscribable.d.ts +4 -4
  237. package/dist/subscribable/subscribable.d.ts.map +1 -1
  238. package/dist/subscribable/subscribable.js +14 -6
  239. package/dist/subscribable/subscribable.js.map +1 -1
  240. package/dist/tests/remote-thread-list-test-helpers.d.ts +2 -1
  241. package/dist/tests/remote-thread-list-test-helpers.d.ts.map +1 -1
  242. package/dist/tests/remote-thread-list-test-helpers.js +5 -2
  243. package/dist/tests/remote-thread-list-test-helpers.js.map +1 -1
  244. package/dist/types/attachment.d.ts +2 -1
  245. package/dist/types/attachment.d.ts.map +1 -1
  246. package/dist/types/attachment.js +6 -0
  247. package/dist/types/attachment.js.map +1 -0
  248. package/dist/types/message.d.ts +1 -0
  249. package/dist/types/message.d.ts.map +1 -1
  250. package/dist/types/message.js.map +1 -1
  251. package/dist/utils/data-url.d.ts +9 -0
  252. package/dist/utils/data-url.d.ts.map +1 -0
  253. package/dist/utils/data-url.js +14 -0
  254. package/dist/utils/data-url.js.map +1 -0
  255. package/dist/utils/notify-event-listeners.d.ts +6 -0
  256. package/dist/utils/notify-event-listeners.d.ts.map +1 -0
  257. package/dist/utils/notify-event-listeners.js +16 -0
  258. package/dist/utils/notify-event-listeners.js.map +1 -0
  259. package/package.json +10 -9
  260. package/src/adapters/speech.test.ts +88 -0
  261. package/src/adapters/speech.ts +17 -2
  262. package/src/adapters/thread-history.ts +8 -0
  263. package/src/adapters/voice.test.ts +130 -0
  264. package/src/adapters/voice.ts +26 -6
  265. package/src/internal.ts +6 -1
  266. package/src/model-context/frame/host.test.ts +147 -0
  267. package/src/model-context/frame/host.ts +56 -19
  268. package/src/model-context/frame/provider.test.ts +83 -0
  269. package/src/model-context/frame/provider.ts +1 -0
  270. package/src/model-context/types.ts +16 -6
  271. package/src/react/adapters/LocalStorageThreadListAdapter.test.ts +82 -0
  272. package/src/react/adapters/LocalStorageThreadListAdapter.tsx +108 -58
  273. package/src/react/primitive-hooks/useActionBarCopy.test.ts +79 -0
  274. package/src/react/primitive-hooks/useActionBarCopy.ts +4 -3
  275. package/src/react/primitives/chainOfThought/ChainOfThoughtParts.tsx +1 -3
  276. package/src/react/primitives/message/MessageParts.tsx +48 -35
  277. package/src/react/providers/ChainOfThoughtPartByIndexProvider.tsx +19 -2
  278. package/src/react/providers/PartByIndexProvider.tsx +16 -2
  279. package/src/react/runtimes/RemoteThreadListHookInstanceManager.test.tsx +18 -0
  280. package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +1 -0
  281. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +68 -13
  282. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.ts +34 -0
  283. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.tsx +69 -0
  284. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +27 -6
  285. package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.test.ts +16 -0
  286. package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.ts +7 -2
  287. package/src/react/runtimes/cloud/auiV0.ts +14 -0
  288. package/src/react/runtimes/cloud/useCloudThreadListAdapter.tsx +90 -88
  289. package/src/react/runtimes/external-message-converter.test.ts +346 -0
  290. package/src/react/runtimes/external-message-converter.test.tsx +21 -0
  291. package/src/react/runtimes/external-message-converter.ts +2 -2
  292. package/src/react/runtimes/useLocalRuntime.test.tsx +99 -0
  293. package/src/react/runtimes/useLocalRuntime.ts +13 -1
  294. package/src/runtime/api/assistant-runtime.ts +4 -1
  295. package/src/runtime/api/attachment-runtime.ts +8 -2
  296. package/src/runtime/api/composer-runtime.ts +9 -5
  297. package/src/runtime/api/message-part-runtime.ts +10 -3
  298. package/src/runtime/api/message-runtime.test.ts +81 -0
  299. package/src/runtime/api/message-runtime.ts +11 -8
  300. package/src/runtime/api/thread-list-item-runtime.ts +13 -3
  301. package/src/runtime/api/thread-list-runtime.ts +10 -2
  302. package/src/runtime/base/base-composer-runtime-core.ts +77 -31
  303. package/src/runtime/base/base-thread-runtime-core.ts +7 -2
  304. package/src/runtime/base/default-edit-composer-runtime-core.ts +18 -4
  305. package/src/runtime/base/default-thread-composer-runtime-core.ts +13 -3
  306. package/src/runtime/utils/message-repository.ts +19 -13
  307. package/src/runtime/utils/thread-message-like.ts +1 -0
  308. package/src/runtimes/external-store/external-store-thread-list-runtime-core.ts +4 -1
  309. package/src/runtimes/external-store/external-store-thread-runtime-core.ts +15 -0
  310. package/src/runtimes/internal.ts +3 -0
  311. package/src/runtimes/local/local-thread-runtime-core.test.ts +746 -1
  312. package/src/runtimes/local/local-thread-runtime-core.ts +89 -23
  313. package/src/runtimes/local/should-continue.test.ts +122 -0
  314. package/src/runtimes/remote-thread-list/optimistic-state.test.ts +63 -0
  315. package/src/runtimes/remote-thread-list/optimistic-state.ts +49 -17
  316. package/src/runtimes/remote-thread-list/types.ts +1 -1
  317. package/src/runtimes/tool-invocations/EDGE_CASES.md +13 -19
  318. package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +128 -8
  319. package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +42 -34
  320. package/src/store/clients/model-context-client.test.ts +21 -1
  321. package/src/store/runtime-clients/thread-runtime-client.ts +2 -1
  322. package/src/store/scopes/thread.ts +1 -0
  323. package/src/subscribable/subscribable.test.ts +58 -0
  324. package/src/subscribable/subscribable.ts +29 -11
  325. package/src/tests/MessageRepository.test.ts +12 -0
  326. package/src/tests/OptimisticState-list-race.test.ts +33 -0
  327. package/src/tests/RemoteThreadListThreadListRuntimeCore-switchToThread-order.test.ts +223 -0
  328. package/src/tests/RemoteThreadListThreadListRuntimeCore-switchToThread-position.test.ts +121 -0
  329. package/src/tests/auiV0Encode.test.ts +74 -0
  330. package/src/tests/base-composer-runtime-core-addAttachment.test.ts +44 -0
  331. package/src/tests/base-composer-runtime-core-send.test.ts +433 -5
  332. package/src/tests/base-composer-runtime-core.test.ts +422 -0
  333. package/src/tests/default-edit-composer-runtime-core.test.ts +43 -5
  334. package/src/tests/event-subscription-listener-errors.test.ts +205 -0
  335. package/src/tests/external-store-thread-list-runtime-core.test.ts +6 -6
  336. package/src/tests/external-store-thread-runtime-core-adapter.test.ts +575 -0
  337. package/src/tests/external-store-thread-runtime-core.test.ts +55 -1
  338. package/src/tests/remote-thread-list-test-helpers.ts +14 -7
  339. package/src/tests/thread-message-like.test.ts +57 -0
  340. package/src/types/attachment.ts +5 -0
  341. package/src/types/message.ts +1 -0
  342. package/src/utils/data-url.test.ts +50 -0
  343. package/src/utils/data-url.ts +9 -0
  344. package/src/utils/notify-event-listeners.ts +30 -0
  345. package/src/tests/OptimisticState-delete-crash.test.ts +0 -208
@@ -18,6 +18,19 @@ export const contextProvider: ModelContextProvider = {
18
18
  subscribe: () => () => {},
19
19
  };
20
20
 
21
+ export function setStartThreadRuntime(
22
+ core: RemoteThreadListThreadListRuntimeCore,
23
+ startThreadRuntime: (id: string) => Promise<unknown>,
24
+ ) {
25
+ (
26
+ core as unknown as {
27
+ _hookManager: {
28
+ startThreadRuntime: (id: string) => Promise<unknown>;
29
+ };
30
+ }
31
+ )._hookManager.startThreadRuntime = startThreadRuntime;
32
+ }
33
+
21
34
  export function makeAdapter(
22
35
  overrides: Partial<RemoteThreadListAdapter> = {},
23
36
  ): RemoteThreadListAdapter {
@@ -60,12 +73,6 @@ export function createCore(
60
73
  );
61
74
  // `startThreadRuntime` blocks until a React component attaches a runtime;
62
75
  // stub it so non-React unit tests don't hang.
63
- (
64
- core as unknown as {
65
- _hookManager: {
66
- startThreadRuntime: (id: string) => Promise<unknown>;
67
- };
68
- }
69
- )._hookManager.startThreadRuntime = async () => ({});
76
+ setStartThreadRuntime(core, async () => ({}));
70
77
  return core;
71
78
  }
@@ -200,4 +200,61 @@ describe("fromThreadMessageLike", () => {
200
200
  });
201
201
  });
202
202
  });
203
+
204
+ describe("metadata.isOptimistic", () => {
205
+ it("preserves isOptimistic on user messages", () => {
206
+ const result = fromThreadMessageLike(
207
+ {
208
+ role: "user",
209
+ content: [{ type: "text", text: "hello" }],
210
+ metadata: { isOptimistic: true },
211
+ },
212
+ fallbackId,
213
+ fallbackStatus,
214
+ );
215
+
216
+ expect(result.metadata.isOptimistic).toBe(true);
217
+ });
218
+
219
+ it("preserves isOptimistic on assistant messages", () => {
220
+ const result = fromThreadMessageLike(
221
+ {
222
+ role: "assistant",
223
+ content: [{ type: "text", text: "hello" }],
224
+ metadata: { isOptimistic: true },
225
+ },
226
+ fallbackId,
227
+ fallbackStatus,
228
+ );
229
+
230
+ expect(result.metadata.isOptimistic).toBe(true);
231
+ });
232
+
233
+ it("omits isOptimistic when false", () => {
234
+ const result = fromThreadMessageLike(
235
+ {
236
+ role: "user",
237
+ content: [{ type: "text", text: "hello" }],
238
+ metadata: { isOptimistic: false },
239
+ },
240
+ fallbackId,
241
+ fallbackStatus,
242
+ );
243
+
244
+ expect(result.metadata).not.toHaveProperty("isOptimistic");
245
+ });
246
+
247
+ it("omits isOptimistic when not set", () => {
248
+ const result = fromThreadMessageLike(
249
+ {
250
+ role: "user",
251
+ content: [{ type: "text", text: "hello" }],
252
+ },
253
+ fallbackId,
254
+ fallbackStatus,
255
+ );
256
+
257
+ expect(result.metadata).not.toHaveProperty("isOptimistic");
258
+ });
259
+ });
203
260
  });
@@ -52,3 +52,8 @@ export type CreateAttachment = {
52
52
  contentType?: string;
53
53
  content: ThreadUserMessagePart[];
54
54
  };
55
+
56
+ export const isCreateAttachment = (
57
+ attachment: File | CreateAttachment,
58
+ ): attachment is CreateAttachment =>
59
+ "content" in attachment && !("lastModified" in attachment);
@@ -349,6 +349,7 @@ export type ThreadUserMessage = MessageCommonProps & {
349
349
  readonly steps?: undefined;
350
350
  readonly submittedFeedback?: undefined;
351
351
  readonly timing?: undefined;
352
+ readonly isOptimistic?: boolean;
352
353
  readonly custom: Record<string, unknown>;
353
354
  };
354
355
  };
@@ -0,0 +1,50 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { httpUrlPattern, parseDataUrl } from "./data-url";
3
+
4
+ describe("parseDataUrl", () => {
5
+ it("parses a base64 data URL", () => {
6
+ expect(parseDataUrl("data:image/png;base64,aGVsbG8=")).toEqual({
7
+ mimeType: "image/png",
8
+ data: "aGVsbG8=",
9
+ });
10
+ });
11
+
12
+ it("parses a data URL with extra parameters", () => {
13
+ expect(parseDataUrl("data:text/plain;charset=utf-8;base64,aGk=")).toEqual({
14
+ mimeType: "text/plain",
15
+ data: "aGk=",
16
+ });
17
+ });
18
+
19
+ it("returns null for non-base64 data URLs", () => {
20
+ expect(parseDataUrl("data:text/plain,hello")).toBeNull();
21
+ });
22
+
23
+ it("returns null for data URLs with an empty payload", () => {
24
+ expect(parseDataUrl("data:image/png;base64,")).toBeNull();
25
+ });
26
+
27
+ it("returns null for plain strings", () => {
28
+ expect(parseDataUrl("aGVsbG8=")).toBeNull();
29
+ });
30
+
31
+ it("returns null for http URLs", () => {
32
+ expect(parseDataUrl("https://example.com/a.png")).toBeNull();
33
+ });
34
+ });
35
+
36
+ describe("httpUrlPattern", () => {
37
+ it.each(["http://example.com", "https://example.com", "HTTPS://EXAMPLE.COM"])(
38
+ "matches %s",
39
+ (value) => {
40
+ expect(httpUrlPattern.test(value)).toBe(true);
41
+ },
42
+ );
43
+
44
+ it.each(["ftp://example.com", "data:image/png;base64,aGk=", "/relative"])(
45
+ "does not match %s",
46
+ (value) => {
47
+ expect(httpUrlPattern.test(value)).toBe(false);
48
+ },
49
+ );
50
+ });
@@ -0,0 +1,9 @@
1
+ export const httpUrlPattern = /^https?:\/\//i;
2
+
3
+ export function parseDataUrl(
4
+ value: string,
5
+ ): { mimeType: string; data: string } | null {
6
+ const match = value.match(/^data:([^;,]+)(?:;[^;,]+)*;base64,(.+)$/);
7
+ if (!match) return null;
8
+ return { mimeType: match[1]!, data: match[2]! };
9
+ }
@@ -0,0 +1,30 @@
1
+ type EventListener = (payload?: unknown) => void;
2
+
3
+ export const notifyEventListeners = (
4
+ listeners: Iterable<EventListener>,
5
+ payload: unknown,
6
+ errorContext: string,
7
+ ) => {
8
+ const reportError = (error: unknown) => {
9
+ console.error(
10
+ `[assistant-ui] ${errorContext} listener threw an error`,
11
+ error,
12
+ );
13
+ };
14
+
15
+ for (const listener of listeners) {
16
+ try {
17
+ const result = listener(payload) as unknown;
18
+ if (
19
+ result !== null &&
20
+ (typeof result === "object" || typeof result === "function") &&
21
+ "then" in result &&
22
+ typeof result.then === "function"
23
+ ) {
24
+ void Promise.resolve(result).catch(reportError);
25
+ }
26
+ } catch (error) {
27
+ reportError(error);
28
+ }
29
+ }
30
+ };
@@ -1,208 +0,0 @@
1
- import { describe, it, expect, vi } from "vitest";
2
- import { OptimisticState } from "../runtimes/remote-thread-list/optimistic-state";
3
- import {
4
- type RemoteThreadState,
5
- createThreadMappingId,
6
- updateStatusReducer,
7
- getThreadData,
8
- } from "../runtimes/remote-thread-list/remote-thread-state";
9
-
10
- /**
11
- * This test reproduces the crash from issue #3346:
12
- * "Entry not available in the store" when deleting the active thread.
13
- *
14
- * Root cause: optimisticUpdate's `optimistic` callback runs synchronously
15
- * and removes the thread from threadData, but mainThreadId still points to
16
- * the deleted thread. Subscribers that fire during _notifySubscribers() see
17
- * this inconsistent state and crash.
18
- */
19
-
20
- const createThreadState = (
21
- threadId: string,
22
- status: "regular" | "archived" = "regular",
23
- ): RemoteThreadState => {
24
- const mappingId = createThreadMappingId(threadId);
25
- return {
26
- isLoading: false,
27
- isLoadingMore: false,
28
- cursor: undefined,
29
- newThreadId: undefined,
30
- threadIds: status === "regular" ? [threadId] : [],
31
- archivedThreadIds: status === "archived" ? [threadId] : [],
32
- threadIdMap: { [threadId]: mappingId },
33
- threadData: {
34
- [mappingId]: {
35
- id: threadId,
36
- remoteId: threadId,
37
- externalId: undefined,
38
- status,
39
- title: undefined,
40
- initializeTask: Promise.resolve({
41
- remoteId: threadId,
42
- externalId: undefined,
43
- }),
44
- },
45
- },
46
- };
47
- };
48
-
49
- describe("OptimisticState delete crash (#3346)", () => {
50
- it("optimistic callback runs synchronously before execute completes", async () => {
51
- const state = new OptimisticState(createThreadState("thread-1"));
52
- const events: string[] = [];
53
-
54
- state.subscribe(() => {
55
- events.push("subscriber-notified");
56
- });
57
-
58
- const executeStarted = vi.fn();
59
- const executeCompleted = vi.fn();
60
-
61
- const promise = state.optimisticUpdate({
62
- execute: async () => {
63
- executeStarted();
64
- // simulate async work like _ensureThreadIsNotMain
65
- await Promise.resolve();
66
- executeCompleted();
67
- },
68
- optimistic: (s) => {
69
- events.push("optimistic-ran");
70
- return updateStatusReducer(s, "thread-1", "deleted");
71
- },
72
- });
73
-
74
- // After calling optimisticUpdate but before awaiting:
75
- // - optimistic callback has already run (synchronous)
76
- // - execute has started but not completed (async)
77
- expect(events).toEqual(["optimistic-ran", "subscriber-notified"]);
78
- expect(executeStarted).toHaveBeenCalled();
79
- expect(executeCompleted).not.toHaveBeenCalled();
80
-
81
- // Thread data is already gone from the optimistic value
82
- expect(getThreadData(state.value, "thread-1")).toBeUndefined();
83
-
84
- await promise;
85
- });
86
-
87
- it("BUG SCENARIO: subscriber sees deleted thread data while mainThreadId still references it", async () => {
88
- const state = new OptimisticState(createThreadState("thread-1"));
89
-
90
- // Simulate what happens in the real code:
91
- // mainThreadId is external state that _ensureThreadIsNotMain would update
92
- let mainThreadId = "thread-1";
93
- let subscriberSawInconsistentState = false;
94
-
95
- state.subscribe(() => {
96
- // This fires synchronously during optimisticUpdate.
97
- // In the real code, React components would re-render here and try to
98
- // access the main thread's data.
99
- const threadData = getThreadData(state.value, mainThreadId);
100
- if (threadData === undefined && mainThreadId === "thread-1") {
101
- // mainThreadId points to a deleted thread — this is the crash condition
102
- subscriberSawInconsistentState = true;
103
- }
104
- });
105
-
106
- // OLD CODE: _ensureThreadIsNotMain inside execute
107
- // The optimistic callback deletes thread data BEFORE execute can update mainThreadId
108
- const promise = state.optimisticUpdate({
109
- execute: async () => {
110
- // In old code, _ensureThreadIsNotMain was here.
111
- // It would switch mainThreadId, but this runs AFTER optimistic callback
112
- await Promise.resolve();
113
- mainThreadId = "thread-2"; // too late — subscriber already fired
114
- },
115
- optimistic: (s) => {
116
- return updateStatusReducer(s, "thread-1", "deleted");
117
- },
118
- });
119
-
120
- // The subscriber saw inconsistent state — mainThreadId points to deleted thread
121
- expect(subscriberSawInconsistentState).toBe(true);
122
-
123
- await promise;
124
- });
125
-
126
- it("FIX: switching mainThreadId before optimisticUpdate prevents inconsistency", async () => {
127
- const state = new OptimisticState(createThreadState("thread-1"));
128
-
129
- let mainThreadId = "thread-1";
130
- let subscriberSawInconsistentState = false;
131
-
132
- state.subscribe(() => {
133
- const threadData = getThreadData(state.value, mainThreadId);
134
- if (threadData === undefined) {
135
- subscriberSawInconsistentState = true;
136
- }
137
- });
138
-
139
- // FIX: _ensureThreadIsNotMain runs BEFORE optimisticUpdate.
140
- // switchToNewThread() both creates the new thread in state AND updates mainThreadId.
141
- const newThreadId = "thread-2";
142
- const mappingId = createThreadMappingId(newThreadId);
143
- const currentState = state.value;
144
- state.update({
145
- ...currentState,
146
- newThreadId: newThreadId,
147
- threadIdMap: {
148
- ...currentState.threadIdMap,
149
- [newThreadId]: mappingId,
150
- },
151
- threadData: {
152
- ...currentState.threadData,
153
- [mappingId]: {
154
- status: "new" as const,
155
- id: newThreadId,
156
- remoteId: undefined,
157
- externalId: undefined,
158
- title: undefined,
159
- },
160
- },
161
- });
162
- mainThreadId = newThreadId;
163
-
164
- // Reset flag — the state.update above triggered the subscriber
165
- subscriberSawInconsistentState = false;
166
-
167
- const promise = state.optimisticUpdate({
168
- execute: async () => {
169
- // _ensureThreadIsNotMain no longer here
170
- return undefined;
171
- },
172
- optimistic: (s) => {
173
- return updateStatusReducer(s, "thread-1", "deleted");
174
- },
175
- });
176
-
177
- // mainThreadId was already switched to thread-2 which exists in state
178
- // — subscriber sees consistent state, no crash
179
- expect(subscriberSawInconsistentState).toBe(false);
180
-
181
- await promise;
182
- });
183
-
184
- it("archive does NOT remove threadData (no crash even without fix)", async () => {
185
- const state = new OptimisticState(createThreadState("thread-1"));
186
-
187
- let threadDataMissingDuringNotify = false;
188
-
189
- state.subscribe(() => {
190
- const threadData = getThreadData(state.value, "thread-1");
191
- if (threadData === undefined) {
192
- threadDataMissingDuringNotify = true;
193
- }
194
- });
195
-
196
- await state.optimisticUpdate({
197
- execute: async () => undefined,
198
- optimistic: (s) => {
199
- return updateStatusReducer(s, "thread-1", "archived");
200
- },
201
- });
202
-
203
- // Archive keeps threadData — no SKIP_UPDATE, no crash
204
- expect(threadDataMissingDuringNotify).toBe(false);
205
- expect(getThreadData(state.value, "thread-1")).toBeDefined();
206
- expect(getThreadData(state.value, "thread-1")?.status).toBe("archived");
207
- });
208
- });