@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
@@ -0,0 +1,223 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import type { RemoteThreadMetadata } from "../runtimes/remote-thread-list/types";
3
+ import {
4
+ createCore,
5
+ deferred,
6
+ makeAdapter,
7
+ setStartThreadRuntime,
8
+ } from "./remote-thread-list-test-helpers";
9
+
10
+ const thread = (id: string): RemoteThreadMetadata => ({
11
+ status: "regular",
12
+ remoteId: id,
13
+ externalId: id,
14
+ title: id,
15
+ });
16
+
17
+ describe("RemoteThreadListThreadListRuntimeCore.switchToThread order", () => {
18
+ it("preserves the latest switch when an earlier fetch resolves last", async () => {
19
+ const fetchB = deferred<RemoteThreadMetadata>();
20
+ const fetchC = deferred<RemoteThreadMetadata>();
21
+ const adapter = makeAdapter({
22
+ fetch: vi.fn((id: string) =>
23
+ id === "thread-b" ? fetchB.promise : fetchC.promise,
24
+ ),
25
+ });
26
+ const core = createCore(adapter);
27
+
28
+ const switchToB = core.switchToThread("thread-b");
29
+ const switchToC = core.switchToThread("thread-c");
30
+
31
+ fetchC.resolve(thread("thread-c"));
32
+ await switchToC;
33
+ fetchB.resolve(thread("thread-b"));
34
+ await switchToB;
35
+
36
+ expect(core.mainThreadId).toBe(core.getItemById("thread-c")?.id);
37
+ });
38
+
39
+ it("preserves the latest switch when an earlier runtime starts last", async () => {
40
+ const runtimeB = deferred<unknown>();
41
+ const runtimeC = deferred<unknown>();
42
+ const adapter = makeAdapter({
43
+ list: vi.fn(async () => ({
44
+ threads: [thread("thread-b"), thread("thread-c")],
45
+ })),
46
+ });
47
+ const core = createCore(adapter);
48
+ await core.getLoadThreadsPromise();
49
+
50
+ setStartThreadRuntime(core, (id) =>
51
+ id === core.getItemById("thread-b")?.id
52
+ ? runtimeB.promise
53
+ : runtimeC.promise,
54
+ );
55
+
56
+ const switchToB = core.switchToThread("thread-b");
57
+ const switchToC = core.switchToThread("thread-c");
58
+
59
+ runtimeC.resolve({});
60
+ await switchToC;
61
+ runtimeB.resolve({});
62
+ await switchToB;
63
+
64
+ expect(core.mainThreadId).toBe(core.getItemById("thread-c")?.id);
65
+ });
66
+
67
+ it("invalidates an earlier switch while a new thread request is pending", async () => {
68
+ const initializeThread = deferred<{
69
+ remoteId: string;
70
+ externalId: string;
71
+ }>();
72
+ const runtimeB = deferred<unknown>();
73
+ const adapter = makeAdapter({
74
+ initialize: vi.fn(() => initializeThread.promise),
75
+ list: vi.fn(async () => ({ threads: [thread("thread-b")] })),
76
+ });
77
+ const core = createCore(adapter);
78
+ await core.getLoadThreadsPromise();
79
+
80
+ const initialNewThreadId = core.newThreadId;
81
+ if (!initialNewThreadId) throw new Error("Expected an initial new thread");
82
+
83
+ const threadBId = core.getItemById("thread-b")?.id;
84
+ setStartThreadRuntime(core, (id) =>
85
+ id === threadBId ? runtimeB.promise : Promise.resolve({}),
86
+ );
87
+
88
+ const initialize = core.initialize(initialNewThreadId);
89
+ const switchToB = core.switchToThread("thread-b");
90
+ const switchToNewThread = core.switchToNewThread();
91
+
92
+ runtimeB.resolve({});
93
+ await switchToB;
94
+
95
+ expect(core.mainThreadId).not.toBe(threadBId);
96
+
97
+ initializeThread.resolve({
98
+ remoteId: "initialized-thread",
99
+ externalId: "initialized-thread",
100
+ });
101
+ await initialize;
102
+ await switchToNewThread;
103
+
104
+ expect(core.mainThreadId).toBe(core.getItemById(core.newThreadId!)?.id);
105
+ });
106
+
107
+ it("does not let a pending new thread request override a later switch", async () => {
108
+ const initializeThread = deferred<{
109
+ remoteId: string;
110
+ externalId: string;
111
+ }>();
112
+ const adapter = makeAdapter({
113
+ initialize: vi.fn(() => initializeThread.promise),
114
+ list: vi.fn(async () => ({ threads: [thread("thread-c")] })),
115
+ });
116
+ const core = createCore(adapter);
117
+ await core.getLoadThreadsPromise();
118
+
119
+ const initialNewThreadId = core.newThreadId;
120
+ if (!initialNewThreadId) throw new Error("Expected an initial new thread");
121
+
122
+ const initialize = core.initialize(initialNewThreadId);
123
+ const switchToNewThread = core.switchToNewThread();
124
+ await core.switchToThread("thread-c");
125
+
126
+ initializeThread.resolve({
127
+ remoteId: "initialized-thread",
128
+ externalId: "initialized-thread",
129
+ });
130
+ await initialize;
131
+ await switchToNewThread;
132
+
133
+ expect(core.mainThreadId).toBe(core.getItemById("thread-c")?.id);
134
+ });
135
+
136
+ it("keeps mutations waiting when a newer switch fails", async () => {
137
+ const fetchB = deferred<RemoteThreadMetadata>();
138
+ const newThreadRuntime = deferred<unknown>();
139
+ const adapter = makeAdapter({
140
+ fetch: vi.fn(() => fetchB.promise),
141
+ list: vi.fn(async () => ({ threads: [thread("thread-a")] })),
142
+ });
143
+ const core = createCore(adapter);
144
+ await core.getLoadThreadsPromise();
145
+ await core.switchToThread("thread-a");
146
+
147
+ const threadAId = core.getItemById("thread-a")?.id;
148
+ const newThreadId = core.newThreadId;
149
+ if (!newThreadId) throw new Error("Expected an initial new thread");
150
+
151
+ setStartThreadRuntime(core, (id) =>
152
+ id === core.getItemById(newThreadId)?.id
153
+ ? newThreadRuntime.promise
154
+ : Promise.resolve({}),
155
+ );
156
+
157
+ const deleteA = core.delete("thread-a");
158
+ const switchToB = core.switchToThread("thread-b");
159
+ const switchToBResult = expect(switchToB).rejects.toThrow("fetch failed");
160
+
161
+ newThreadRuntime.resolve({});
162
+ fetchB.reject(new Error("fetch failed"));
163
+
164
+ await switchToBResult;
165
+ await deleteA;
166
+
167
+ expect(core.mainThreadId).not.toBe(threadAId);
168
+ expect(core.mainThreadId).toBe(core.getItemById(core.newThreadId!)?.id);
169
+ });
170
+
171
+ it("lets a newer successful switch move the mutation target away", async () => {
172
+ const fetchB = deferred<RemoteThreadMetadata>();
173
+ const newThreadRuntime = deferred<unknown>();
174
+ const adapter = makeAdapter({
175
+ fetch: vi.fn(() => fetchB.promise),
176
+ list: vi.fn(async () => ({ threads: [thread("thread-a")] })),
177
+ });
178
+ const core = createCore(adapter);
179
+ await core.getLoadThreadsPromise();
180
+ await core.switchToThread("thread-a");
181
+
182
+ const newThreadId = core.newThreadId;
183
+ if (!newThreadId) throw new Error("Expected an initial new thread");
184
+
185
+ setStartThreadRuntime(core, (id) =>
186
+ id === core.getItemById(newThreadId)?.id
187
+ ? newThreadRuntime.promise
188
+ : Promise.resolve({}),
189
+ );
190
+
191
+ const deleteA = core.delete("thread-a");
192
+ const switchToB = core.switchToThread("thread-b");
193
+
194
+ newThreadRuntime.resolve({});
195
+ fetchB.resolve(thread("thread-b"));
196
+
197
+ await switchToB;
198
+ await deleteA;
199
+
200
+ expect(core.mainThreadId).toBe(core.getItemById("thread-b")?.id);
201
+ });
202
+
203
+ it("does not let a mutation cancel an existing pending switch", async () => {
204
+ const fetchB = deferred<RemoteThreadMetadata>();
205
+ const adapter = makeAdapter({
206
+ fetch: vi.fn(() => fetchB.promise),
207
+ list: vi.fn(async () => ({ threads: [thread("thread-a")] })),
208
+ });
209
+ const core = createCore(adapter);
210
+ await core.getLoadThreadsPromise();
211
+ await core.switchToThread("thread-a");
212
+
213
+ const switchToB = core.switchToThread("thread-b");
214
+ const deleteA = core.delete("thread-a");
215
+
216
+ fetchB.resolve(thread("thread-b"));
217
+
218
+ await switchToB;
219
+ await deleteA;
220
+
221
+ expect(core.mainThreadId).toBe(core.getItemById("thread-b")?.id);
222
+ });
223
+ });
@@ -0,0 +1,121 @@
1
+ import { describe, it, expect, vi } from "vitest";
2
+ import type {
3
+ RemoteThreadListResponse,
4
+ RemoteThreadMetadata,
5
+ } from "../runtimes/remote-thread-list/types";
6
+ import {
7
+ createCore,
8
+ deferred,
9
+ makeAdapter,
10
+ } from "./remote-thread-list-test-helpers";
11
+
12
+ const thread = (id: string): RemoteThreadMetadata => ({
13
+ status: "regular",
14
+ remoteId: id,
15
+ externalId: id,
16
+ title: id,
17
+ });
18
+
19
+ const archivedThread = (id: string): RemoteThreadMetadata => ({
20
+ status: "archived",
21
+ remoteId: id,
22
+ externalId: id,
23
+ title: id,
24
+ });
25
+
26
+ describe("RemoteThreadListThreadListRuntimeCore.switchToThread position", () => {
27
+ it("keeps the position a concurrent list() already gave the thread", async () => {
28
+ const TARGET = "thread-target";
29
+ const listDeferred = deferred<RemoteThreadListResponse>();
30
+ const fetchDeferred = deferred<RemoteThreadMetadata>();
31
+
32
+ const adapter = makeAdapter({
33
+ list: vi.fn(() => listDeferred.promise),
34
+ fetch: vi.fn(() => fetchDeferred.promise),
35
+ });
36
+
37
+ const core = createCore(adapter, TARGET);
38
+
39
+ const loadPromise = core.getLoadThreadsPromise();
40
+ const switchPromise = core.switchToThread(TARGET);
41
+
42
+ // `list()` resolves first and places TARGET at the top, as the most recent.
43
+ listDeferred.resolve({
44
+ threads: [thread(TARGET), thread("thread-a"), thread("thread-b")],
45
+ });
46
+ await loadPromise;
47
+
48
+ expect(core.threadIds).toEqual([TARGET, "thread-a", "thread-b"]);
49
+
50
+ fetchDeferred.resolve(thread(TARGET));
51
+ await switchPromise;
52
+
53
+ // The fetch path must not filter TARGET out of position and re-append it.
54
+ expect(core.threadIds).toEqual([TARGET, "thread-a", "thread-b"]);
55
+ });
56
+
57
+ it("appends a thread that is genuinely absent from the loaded list", async () => {
58
+ const TARGET = "thread-target";
59
+ const listDeferred = deferred<RemoteThreadListResponse>();
60
+ const fetchDeferred = deferred<RemoteThreadMetadata>();
61
+
62
+ const adapter = makeAdapter({
63
+ list: vi.fn(() => listDeferred.promise),
64
+ fetch: vi.fn(() => fetchDeferred.promise),
65
+ });
66
+
67
+ const core = createCore(adapter, TARGET);
68
+
69
+ const loadPromise = core.getLoadThreadsPromise();
70
+ const switchPromise = core.switchToThread(TARGET);
71
+
72
+ // `list()` resolves first but does not include TARGET (e.g. it is past the
73
+ // first page).
74
+ listDeferred.resolve({
75
+ threads: [thread("thread-a"), thread("thread-b")],
76
+ });
77
+ await loadPromise;
78
+
79
+ expect(core.threadIds).toEqual(["thread-a", "thread-b"]);
80
+
81
+ fetchDeferred.resolve(thread(TARGET));
82
+ await switchPromise;
83
+
84
+ // An absent thread may live on an unloaded page; appending keeps it below
85
+ // every loaded (newer) thread instead of pinning it to the top.
86
+ expect(core.threadIds).toEqual(["thread-a", "thread-b", TARGET]);
87
+ });
88
+
89
+ it("keeps the position a concurrent list() gave an archived thread", async () => {
90
+ const TARGET = "thread-target";
91
+ const listDeferred = deferred<RemoteThreadListResponse>();
92
+ const fetchDeferred = deferred<RemoteThreadMetadata>();
93
+
94
+ const adapter = makeAdapter({
95
+ list: vi.fn(() => listDeferred.promise),
96
+ fetch: vi.fn(() => fetchDeferred.promise),
97
+ });
98
+
99
+ const core = createCore(adapter, TARGET);
100
+ // Stub unarchive so auto-unarchive doesn't move the thread into `threadIds`
101
+ // via `updateStatusReducer`, hiding the position written by the fetch path.
102
+ (
103
+ core as unknown as { unarchive: (id: string) => Promise<void> }
104
+ ).unarchive = async () => {};
105
+
106
+ const loadPromise = core.getLoadThreadsPromise();
107
+ const switchPromise = core.switchToThread(TARGET);
108
+
109
+ listDeferred.resolve({
110
+ threads: [archivedThread(TARGET), archivedThread("thread-a")],
111
+ });
112
+ await loadPromise;
113
+
114
+ expect(core.archivedThreadIds).toEqual([TARGET, "thread-a"]);
115
+
116
+ fetchDeferred.resolve(archivedThread(TARGET));
117
+ await switchPromise;
118
+
119
+ expect(core.archivedThreadIds).toEqual([TARGET, "thread-a"]);
120
+ });
121
+ });
@@ -53,6 +53,35 @@ describe("auiV0Encode", () => {
53
53
  ]);
54
54
  });
55
55
 
56
+ it("preserves a pending tool-call approval in the core cloud encoder", () => {
57
+ const encoded = auiV0Encode({
58
+ id: "m1",
59
+ createdAt: new Date("2026-03-15T00:00:00.000Z"),
60
+ role: "assistant",
61
+ status: { type: "requires-action", reason: "tool-calls" },
62
+ metadata: {
63
+ unstable_state: null,
64
+ unstable_annotations: [],
65
+ unstable_data: [],
66
+ steps: [],
67
+ custom: {},
68
+ },
69
+ content: [
70
+ {
71
+ type: "tool-call",
72
+ toolCallId: "call-1",
73
+ toolName: "send_email",
74
+ args: {},
75
+ argsText: "{}",
76
+ approval: { id: "a1" },
77
+ },
78
+ ],
79
+ });
80
+
81
+ const toolCall = encoded.content.find((p) => p.type === "tool-call");
82
+ expect(toolCall).toMatchObject({ approval: { id: "a1" } });
83
+ });
84
+
56
85
  it("preserves user attachments in the core cloud encoder", () => {
57
86
  const encoded = auiV0Encode({
58
87
  id: "m1",
@@ -129,6 +158,51 @@ describe("auiV0Encode", () => {
129
158
  });
130
159
 
131
160
  describe("auiV0Decode", () => {
161
+ it("round-trips a pending tool-call approval so a paused run stays resumable", () => {
162
+ const content = auiV0Encode({
163
+ id: "local",
164
+ createdAt: new Date("2026-03-15T00:00:00.000Z"),
165
+ role: "assistant",
166
+ status: { type: "requires-action", reason: "tool-calls" },
167
+ metadata: {
168
+ unstable_state: null,
169
+ unstable_annotations: [],
170
+ unstable_data: [],
171
+ steps: [],
172
+ custom: {},
173
+ },
174
+ content: [
175
+ {
176
+ type: "tool-call",
177
+ toolCallId: "call-1",
178
+ toolName: "send_email",
179
+ args: {},
180
+ argsText: "{}",
181
+ approval: { id: "a1" },
182
+ },
183
+ ],
184
+ });
185
+
186
+ const decoded = auiV0Decode({
187
+ id: "cloud",
188
+ parent_id: null,
189
+ height: 0,
190
+ created_at: new Date("2026-03-15T00:00:00.000Z"),
191
+ updated_at: new Date("2026-03-15T00:00:00.000Z"),
192
+ format: "aui/v0",
193
+ content: content as never,
194
+ });
195
+
196
+ if (decoded.message.role !== "assistant")
197
+ throw new Error("expected assistant");
198
+ const toolCall = decoded.message.content.find(
199
+ (p) => p.type === "tool-call",
200
+ );
201
+ expect(toolCall?.type === "tool-call" && toolCall.approval).toEqual({
202
+ id: "a1",
203
+ });
204
+ });
205
+
132
206
  it("restores user attachments from core cloud history", () => {
133
207
  const content = auiV0Encode({
134
208
  id: "local",
@@ -128,6 +128,50 @@ describe("BaseComposerRuntimeCore.addAttachment error events", () => {
128
128
  expect(onError).not.toHaveBeenCalled();
129
129
  });
130
130
 
131
+ it("adds prepared attachments when File is unavailable", async () => {
132
+ const composer = makeComposer();
133
+ const fileConstructor = globalThis.File;
134
+ vi.stubGlobal("File", undefined);
135
+
136
+ try {
137
+ await composer.addAttachment({
138
+ name: "notes.txt",
139
+ contentType: "text/plain",
140
+ content: [{ type: "text", text: "hello" }],
141
+ });
142
+ } finally {
143
+ vi.stubGlobal("File", fileConstructor);
144
+ }
145
+
146
+ expect(composer.attachments[0]).toMatchObject({
147
+ type: "document",
148
+ name: "notes.txt",
149
+ contentType: "text/plain",
150
+ content: [{ type: "text", text: "hello" }],
151
+ status: { type: "complete" },
152
+ });
153
+ });
154
+
155
+ it("uses the adapter for foreign files that expose content", async () => {
156
+ const add = vi.fn(makeAdapter().add);
157
+ const composer = makeComposer(makeAdapter({ add }));
158
+ const foreignFile = {
159
+ name: "photo.png",
160
+ type: "image/png",
161
+ lastModified: 0,
162
+ content: [{ type: "text", text: "implementation detail" }],
163
+ } as File;
164
+
165
+ await composer.addAttachment(foreignFile);
166
+
167
+ expect(add).toHaveBeenCalledWith({ file: foreignFile });
168
+ expect(composer.attachments[0]).toMatchObject({
169
+ type: "image",
170
+ name: "photo.png",
171
+ contentType: "image/png",
172
+ });
173
+ });
174
+
131
175
  it("accepts JSON files with the application/json media type", async () => {
132
176
  const composer = makeComposer(new SimpleTextAttachmentAdapter());
133
177