@assistant-ui/core 0.3.14 → 0.3.16

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 (341) hide show
  1. package/dist/adapters/voice.js +11 -0
  2. package/dist/adapters/voice.js.map +1 -1
  3. package/dist/index.js +1 -1
  4. package/dist/internal.d.ts +8 -2
  5. package/dist/internal.js +9 -3
  6. package/dist/model-context/frame/host.d.ts +1 -1
  7. package/dist/model-context/frame/host.d.ts.map +1 -1
  8. package/dist/model-context/frame/host.js +20 -5
  9. package/dist/model-context/frame/host.js.map +1 -1
  10. package/dist/model-context/frame/provider.d.ts +6 -0
  11. package/dist/model-context/frame/provider.d.ts.map +1 -1
  12. package/dist/model-context/frame/provider.js +126 -16
  13. package/dist/model-context/frame/provider.js.map +1 -1
  14. package/dist/model-context/frame/types.d.ts +4 -1
  15. package/dist/model-context/frame/types.d.ts.map +1 -1
  16. package/dist/model-context/frame/types.js.map +1 -1
  17. package/dist/model-context/interactable-composer-metadata.d.ts +1 -1
  18. package/dist/model-context/interactable-composer-metadata.js +1 -1
  19. package/dist/model-context/interactable-composer-metadata.js.map +1 -1
  20. package/dist/model-context/registry.d.ts +2 -2
  21. package/dist/model-context/registry.d.ts.map +1 -1
  22. package/dist/model-context/registry.js +9 -28
  23. package/dist/model-context/registry.js.map +1 -1
  24. package/dist/react/client/InMemoryThreadList.d.ts.map +1 -1
  25. package/dist/react/client/InMemoryThreadList.js +24 -20
  26. package/dist/react/client/InMemoryThreadList.js.map +1 -1
  27. package/dist/react/client/Interactables.d.ts.map +1 -1
  28. package/dist/react/client/Interactables.js +59 -177
  29. package/dist/react/client/Interactables.js.map +1 -1
  30. package/dist/react/client/RemoteThreadList.d.ts +1 -1
  31. package/dist/react/client/RemoteThreadList.d.ts.map +1 -1
  32. package/dist/react/client/RemoteThreadList.js +117 -78
  33. package/dist/react/client/RemoteThreadList.js.map +1 -1
  34. package/dist/react/index.d.ts +2 -1
  35. package/dist/react/interactables-legacy/Interactables.d.ts.map +1 -1
  36. package/dist/react/interactables-legacy/Interactables.js +56 -174
  37. package/dist/react/interactables-legacy/Interactables.js.map +1 -1
  38. package/dist/react/interactables-shared/useInteractablePersistenceQueue.d.ts +24 -0
  39. package/dist/react/interactables-shared/useInteractablePersistenceQueue.d.ts.map +1 -0
  40. package/dist/react/interactables-shared/useInteractablePersistenceQueue.js +138 -0
  41. package/dist/react/interactables-shared/useInteractablePersistenceQueue.js.map +1 -0
  42. package/dist/react/primitive-hooks/useActionBarCopy.js +7 -1
  43. package/dist/react/primitive-hooks/useActionBarCopy.js.map +1 -1
  44. package/dist/react/primitive-hooks/useThreadIsEmpty.d.ts +3 -0
  45. package/dist/react/primitive-hooks/useThreadIsEmpty.d.ts.map +1 -1
  46. package/dist/react/primitive-hooks/useThreadIsEmpty.js +3 -0
  47. package/dist/react/primitive-hooks/useThreadIsEmpty.js.map +1 -1
  48. package/dist/react/primitive-hooks/useThreadIsRunning.d.ts +3 -0
  49. package/dist/react/primitive-hooks/useThreadIsRunning.d.ts.map +1 -1
  50. package/dist/react/primitive-hooks/useThreadIsRunning.js +3 -0
  51. package/dist/react/primitive-hooks/useThreadIsRunning.js.map +1 -1
  52. package/dist/react/primitives/composer/ComposerIf.js.map +1 -1
  53. package/dist/react/primitives/composer/ComposerQueue.d.ts +2 -1
  54. package/dist/react/primitives/composer/ComposerQueue.d.ts.map +1 -1
  55. package/dist/react/primitives/message/MessageParts.js.map +1 -1
  56. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts +3 -1
  57. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
  58. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +6 -0
  59. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
  60. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +7 -1
  61. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
  62. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +174 -64
  63. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
  64. package/dist/react/runtimes/RemoteThreadResource.d.ts.map +1 -1
  65. package/dist/react/runtimes/RemoteThreadResource.js +2 -0
  66. package/dist/react/runtimes/RemoteThreadResource.js.map +1 -1
  67. package/dist/react/runtimes/assistant-transport/runManager.d.ts.map +1 -1
  68. package/dist/react/runtimes/assistant-transport/runManager.js +2 -12
  69. package/dist/react/runtimes/assistant-transport/runManager.js.map +1 -1
  70. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.d.ts.map +1 -1
  71. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.js +1 -1
  72. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.js.map +1 -1
  73. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts +3 -10
  74. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
  75. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +20 -67
  76. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
  77. package/dist/react/runtimes/cloud/createCloudThreadListAdapterCreateFallback.d.ts +12 -0
  78. package/dist/react/runtimes/cloud/createCloudThreadListAdapterCreateFallback.d.ts.map +1 -0
  79. package/dist/react/runtimes/cloud/createCloudThreadListAdapterCreateFallback.js +10 -0
  80. package/dist/react/runtimes/cloud/createCloudThreadListAdapterCreateFallback.js.map +1 -0
  81. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.d.ts.map +1 -1
  82. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js +38 -5
  83. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js.map +1 -1
  84. package/dist/react/runtimes/cloud/useCloudThreadListRuntime.js.map +1 -1
  85. package/dist/react/runtimes/createMessageConverter.d.ts +2 -1
  86. package/dist/react/runtimes/createMessageConverter.d.ts.map +1 -1
  87. package/dist/react/runtimes/external-message-converter.d.ts +6 -25
  88. package/dist/react/runtimes/external-message-converter.d.ts.map +1 -1
  89. package/dist/react/runtimes/external-message-converter.js +33 -233
  90. package/dist/react/runtimes/external-message-converter.js.map +1 -1
  91. package/dist/runtime/api/composer-runtime.d.ts +1 -1
  92. package/dist/runtime/api/composer-runtime.js.map +1 -1
  93. package/dist/runtime/api/thread-runtime.d.ts +1 -2
  94. package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
  95. package/dist/runtime/base/base-composer-runtime-core.d.ts +1 -1
  96. package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
  97. package/dist/runtime/base/base-composer-runtime-core.js +14 -29
  98. package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
  99. package/dist/runtime/base/base-thread-runtime-core.d.ts +2 -4
  100. package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
  101. package/dist/runtime/base/base-thread-runtime-core.js +3 -9
  102. package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
  103. package/dist/runtime/base/default-thread-composer-runtime-core.d.ts +1 -1
  104. package/dist/runtime/base/default-thread-composer-runtime-core.d.ts.map +1 -1
  105. package/dist/runtime/base/default-thread-composer-runtime-core.js +1 -1
  106. package/dist/runtime/base/default-thread-composer-runtime-core.js.map +1 -1
  107. package/dist/runtime/interfaces/composer-runtime-core.d.ts +1 -1
  108. package/dist/runtime/interfaces/thread-runtime-core.d.ts +1 -1
  109. package/dist/runtime/internal.d.ts +2 -1
  110. package/dist/runtime/internal.js +2 -1
  111. package/dist/runtime/queue/external-thread-queue-adapter.d.ts +1 -1
  112. package/dist/runtime/queue/message-queue.d.ts.map +1 -1
  113. package/dist/runtime/queue/message-queue.js +1 -1
  114. package/dist/runtime/queue/message-queue.js.map +1 -1
  115. package/dist/runtime/queue/queue-item.d.ts +12 -0
  116. package/dist/runtime/queue/queue-item.d.ts.map +1 -0
  117. package/dist/runtime/queue/queue-item.js +6 -0
  118. package/dist/runtime/queue/queue-item.js.map +1 -0
  119. package/dist/runtime/utils/abortable-thread-load.d.ts +15 -0
  120. package/dist/runtime/utils/abortable-thread-load.d.ts.map +1 -0
  121. package/dist/runtime/utils/abortable-thread-load.js +35 -0
  122. package/dist/runtime/utils/abortable-thread-load.js.map +1 -0
  123. package/dist/runtime/utils/attachment-add-operations.d.ts +18 -0
  124. package/dist/runtime/utils/attachment-add-operations.d.ts.map +1 -0
  125. package/dist/runtime/utils/attachment-add-operations.js +43 -0
  126. package/dist/runtime/utils/attachment-add-operations.js.map +1 -0
  127. package/dist/runtime/utils/auto-status.d.ts +6 -1
  128. package/dist/runtime/utils/auto-status.d.ts.map +1 -1
  129. package/dist/runtime/utils/auto-status.js +7 -1
  130. package/dist/runtime/utils/auto-status.js.map +1 -1
  131. package/dist/runtime/utils/external-message-conversion.d.ts +47 -0
  132. package/dist/runtime/utils/external-message-conversion.d.ts.map +1 -0
  133. package/dist/runtime/utils/external-message-conversion.js +221 -0
  134. package/dist/runtime/utils/external-message-conversion.js.map +1 -0
  135. package/dist/runtime/utils/external-store-message.d.ts +2 -1
  136. package/dist/runtime/utils/external-store-message.d.ts.map +1 -1
  137. package/dist/runtime/utils/external-store-message.js +2 -1
  138. package/dist/runtime/utils/external-store-message.js.map +1 -1
  139. package/dist/runtime/utils/message-repository-session.d.ts +30 -0
  140. package/dist/runtime/utils/message-repository-session.d.ts.map +1 -0
  141. package/dist/runtime/utils/message-repository-session.js +130 -0
  142. package/dist/runtime/utils/message-repository-session.js.map +1 -0
  143. package/dist/runtime/utils/message-repository.d.ts.map +1 -1
  144. package/dist/runtime/utils/message-repository.js +30 -22
  145. package/dist/runtime/utils/message-repository.js.map +1 -1
  146. package/dist/runtime/utils/pending-tool-calls.d.ts +20 -0
  147. package/dist/runtime/utils/pending-tool-calls.d.ts.map +1 -0
  148. package/dist/runtime/utils/pending-tool-calls.js +22 -0
  149. package/dist/runtime/utils/pending-tool-calls.js.map +1 -0
  150. package/dist/runtime/utils/thread-message-like.d.ts +2 -1
  151. package/dist/runtime/utils/thread-message-like.d.ts.map +1 -1
  152. package/dist/runtime/utils/thread-message-like.js.map +1 -1
  153. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts +2 -5
  154. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts.map +1 -1
  155. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js +3 -10
  156. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js.map +1 -1
  157. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts +19 -1
  158. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
  159. package/dist/runtimes/external-store/external-store-thread-runtime-core.js +124 -20
  160. package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
  161. package/dist/runtimes/inert/InertThreadRuntimeCore.d.ts +102 -0
  162. package/dist/runtimes/inert/InertThreadRuntimeCore.d.ts.map +1 -0
  163. package/dist/runtimes/inert/InertThreadRuntimeCore.js +156 -0
  164. package/dist/runtimes/inert/InertThreadRuntimeCore.js.map +1 -0
  165. package/dist/runtimes/local/local-thread-runtime-core.d.ts +3 -1
  166. package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
  167. package/dist/runtimes/local/local-thread-runtime-core.js +45 -8
  168. package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
  169. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts +12 -60
  170. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts.map +1 -1
  171. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.js +10 -145
  172. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.js.map +1 -1
  173. package/dist/runtimes/remote-thread-list/adapter-changed.d.ts +9 -0
  174. package/dist/runtimes/remote-thread-list/adapter-changed.d.ts.map +1 -0
  175. package/dist/runtimes/remote-thread-list/adapter-changed.js +13 -0
  176. package/dist/runtimes/remote-thread-list/adapter-changed.js.map +1 -0
  177. package/dist/runtimes/remote-thread-list/empty-thread-core.d.ts.map +1 -1
  178. package/dist/runtimes/remote-thread-list/empty-thread-core.js +16 -155
  179. package/dist/runtimes/remote-thread-list/empty-thread-core.js.map +1 -1
  180. package/dist/runtimes/remote-thread-list/optimistic-state.d.ts +2 -0
  181. package/dist/runtimes/remote-thread-list/optimistic-state.d.ts.map +1 -1
  182. package/dist/runtimes/remote-thread-list/optimistic-state.js +11 -0
  183. package/dist/runtimes/remote-thread-list/optimistic-state.js.map +1 -1
  184. package/dist/runtimes/remote-thread-list/remote-thread-state.d.ts +12 -1
  185. package/dist/runtimes/remote-thread-list/remote-thread-state.d.ts.map +1 -1
  186. package/dist/runtimes/remote-thread-list/remote-thread-state.js +77 -1
  187. package/dist/runtimes/remote-thread-list/remote-thread-state.js.map +1 -1
  188. package/dist/runtimes/remote-thread-list/types.d.ts +3 -0
  189. package/dist/runtimes/remote-thread-list/types.d.ts.map +1 -1
  190. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts.map +1 -1
  191. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js +2 -0
  192. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js.map +1 -1
  193. package/dist/store/clients/external-thread.d.ts.map +1 -1
  194. package/dist/store/clients/external-thread.js +75 -100
  195. package/dist/store/clients/external-thread.js.map +1 -1
  196. package/dist/store/clients/single-thread-list.d.ts.map +1 -1
  197. package/dist/store/clients/single-thread-list.js +1 -1
  198. package/dist/store/clients/single-thread-list.js.map +1 -1
  199. package/dist/store/clients/suggestions.d.ts.map +1 -1
  200. package/dist/store/clients/suggestions.js +16 -7
  201. package/dist/store/clients/suggestions.js.map +1 -1
  202. package/dist/store/index.d.ts +4 -2
  203. package/dist/store/runtime-clients/handle-runtime-action.d.ts.map +1 -1
  204. package/dist/store/runtime-clients/handle-runtime-action.js +2 -0
  205. package/dist/store/runtime-clients/handle-runtime-action.js.map +1 -1
  206. package/dist/store/scope-registration.d.ts +1 -1
  207. package/dist/store/scopes/composer.d.ts +2 -1
  208. package/dist/store/scopes/composer.d.ts.map +1 -1
  209. package/dist/store/scopes/message.d.ts +1 -1
  210. package/dist/store/scopes/queue-item.d.ts +2 -9
  211. package/dist/store/scopes/queue-item.d.ts.map +1 -1
  212. package/dist/store/scopes/queue-item.js +0 -6
  213. package/dist/types/message.d.ts +8 -4
  214. package/dist/types/message.d.ts.map +1 -1
  215. package/dist/types/message.js.map +1 -1
  216. package/dist/utils/data-url.d.ts +14 -1
  217. package/dist/utils/data-url.d.ts.map +1 -1
  218. package/dist/utils/data-url.js +13 -1
  219. package/dist/utils/data-url.js.map +1 -1
  220. package/dist/utils/invoke-user-callback.d.ts +5 -0
  221. package/dist/utils/invoke-user-callback.d.ts.map +1 -0
  222. package/dist/utils/invoke-user-callback.js +19 -0
  223. package/dist/utils/invoke-user-callback.js.map +1 -0
  224. package/dist/utils/normalizePartStatus.js.map +1 -1
  225. package/dist/utils/silent-runtime-action.d.ts +6 -0
  226. package/dist/utils/silent-runtime-action.d.ts.map +1 -0
  227. package/dist/utils/silent-runtime-action.js +7 -0
  228. package/dist/utils/silent-runtime-action.js.map +1 -0
  229. package/package.json +10 -10
  230. package/src/adapters/voice.test.ts +66 -1
  231. package/src/adapters/voice.ts +8 -0
  232. package/src/internal.ts +13 -0
  233. package/src/model-context/frame/host.test.ts +152 -9
  234. package/src/model-context/frame/host.ts +23 -5
  235. package/src/model-context/frame/provider.test.ts +601 -19
  236. package/src/model-context/frame/provider.ts +158 -20
  237. package/src/model-context/frame/types.ts +5 -0
  238. package/src/model-context/interactable-composer-metadata.ts +1 -1
  239. package/src/model-context/registry.test.ts +44 -0
  240. package/src/model-context/registry.ts +13 -35
  241. package/src/react/client/InMemoryThreadList.test.tsx +49 -0
  242. package/src/react/client/InMemoryThreadList.ts +7 -1
  243. package/src/react/client/Interactables.ts +19 -178
  244. package/src/react/client/RemoteThreadList.test.ts +292 -0
  245. package/src/react/client/RemoteThreadList.ts +119 -82
  246. package/src/react/interactables-legacy/Interactables.ts +20 -177
  247. package/src/react/interactables-shared/useInteractablePersistenceQueue.test.tsx +161 -0
  248. package/src/react/interactables-shared/useInteractablePersistenceQueue.ts +206 -0
  249. package/src/react/primitive-hooks/useActionBarCopy.test.ts +15 -0
  250. package/src/react/primitive-hooks/useActionBarCopy.ts +13 -3
  251. package/src/react/primitive-hooks/useThreadIsEmpty.ts +3 -0
  252. package/src/react/primitive-hooks/useThreadIsRunning.ts +3 -0
  253. package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +12 -0
  254. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.republish.test.ts +87 -0
  255. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +251 -76
  256. package/src/react/runtimes/RemoteThreadResource.ts +2 -0
  257. package/src/react/runtimes/assistant-transport/runManager.ts +4 -17
  258. package/src/react/runtimes/assistant-transport/useAssistantTransportRuntime.test.tsx +58 -0
  259. package/src/react/runtimes/assistant-transport/useAssistantTransportRuntime.ts +3 -1
  260. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.tsx +92 -0
  261. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +40 -141
  262. package/src/react/runtimes/cloud/createCloudThreadListAdapterCreateFallback.test.ts +37 -0
  263. package/src/react/runtimes/cloud/createCloudThreadListAdapterCreateFallback.ts +18 -0
  264. package/src/react/runtimes/cloud/useCloudThreadListAdapter.test.tsx +98 -3
  265. package/src/react/runtimes/cloud/useCloudThreadListAdapter.tsx +68 -6
  266. package/src/react/runtimes/external-message-converter.test.ts +0 -14
  267. package/src/react/runtimes/external-message-converter.test.tsx +77 -0
  268. package/src/react/runtimes/external-message-converter.ts +58 -481
  269. package/src/react/runtimes/useLocalRuntime.test.tsx +5 -5
  270. package/src/runtime/api/composer-runtime.ts +1 -1
  271. package/src/runtime/api/message-runtime.test.ts +28 -1
  272. package/src/runtime/base/base-composer-runtime-core.ts +20 -40
  273. package/src/runtime/base/base-thread-runtime-core.test.ts +16 -0
  274. package/src/runtime/base/base-thread-runtime-core.ts +6 -11
  275. package/src/runtime/base/default-thread-composer-runtime-core.ts +1 -4
  276. package/src/runtime/interfaces/composer-runtime-core.ts +1 -1
  277. package/src/runtime/interfaces/thread-runtime-core.ts +1 -1
  278. package/src/runtime/internal.ts +5 -0
  279. package/src/runtime/queue/external-thread-queue-adapter.ts +1 -1
  280. package/src/runtime/queue/message-queue.ts +1 -4
  281. package/src/runtime/queue/queue-item.ts +10 -0
  282. package/src/runtime/utils/abortable-thread-load.test.ts +87 -0
  283. package/src/runtime/utils/abortable-thread-load.ts +53 -0
  284. package/src/runtime/utils/attachment-add-operations.ts +59 -0
  285. package/src/runtime/utils/auto-status.ts +33 -0
  286. package/src/runtime/utils/external-message-conversion.test.ts +113 -0
  287. package/src/runtime/utils/external-message-conversion.ts +494 -0
  288. package/src/runtime/utils/external-store-message.ts +2 -0
  289. package/src/runtime/utils/message-repository-session.test.ts +195 -0
  290. package/src/runtime/utils/message-repository-session.ts +176 -0
  291. package/src/runtime/utils/message-repository.ts +33 -22
  292. package/src/runtime/utils/pending-tool-calls.test.ts +57 -0
  293. package/src/runtime/utils/pending-tool-calls.ts +35 -0
  294. package/src/runtime/utils/thread-message-like.ts +2 -0
  295. package/src/runtimes/external-store/external-store-thread-list-runtime-core.ts +6 -14
  296. package/src/runtimes/external-store/external-store-thread-runtime-core.ts +179 -28
  297. package/src/runtimes/inert/InertThreadRuntimeCore.test.ts +253 -0
  298. package/src/runtimes/inert/InertThreadRuntimeCore.ts +232 -0
  299. package/src/runtimes/local/local-thread-runtime-core.test.ts +491 -1
  300. package/src/runtimes/local/local-thread-runtime-core.ts +86 -11
  301. package/src/runtimes/readonly/ReadonlyThreadRuntimeCore.ts +17 -209
  302. package/src/runtimes/remote-thread-list/adapter-changed.ts +10 -0
  303. package/src/runtimes/remote-thread-list/empty-thread-core.ts +28 -221
  304. package/src/runtimes/remote-thread-list/optimistic-state.test.ts +18 -0
  305. package/src/runtimes/remote-thread-list/optimistic-state.ts +13 -0
  306. package/src/runtimes/remote-thread-list/remote-thread-state.test.ts +37 -0
  307. package/src/runtimes/remote-thread-list/remote-thread-state.ts +123 -0
  308. package/src/runtimes/remote-thread-list/types.ts +4 -0
  309. package/src/runtimes/tool-invocations/EDGE_CASES.md +17 -0
  310. package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +140 -0
  311. package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +3 -0
  312. package/src/store/clients/external-thread.ts +17 -62
  313. package/src/store/clients/single-thread-list.ts +4 -1
  314. package/src/store/clients/suggestions.test.ts +31 -0
  315. package/src/store/clients/suggestions.ts +18 -19
  316. package/src/store/runtime-clients/handle-runtime-action.test.ts +40 -0
  317. package/src/store/runtime-clients/handle-runtime-action.ts +3 -0
  318. package/src/store/scopes/message.ts +1 -1
  319. package/src/store/scopes/queue-item.ts +2 -9
  320. package/src/tests/MessageRepository.test.ts +125 -0
  321. package/src/tests/RemoteThreadListThreadListRuntimeCore-errors.test.ts +2 -2
  322. package/src/tests/RemoteThreadListThreadListRuntimeCore-load-race.test.ts +194 -0
  323. package/src/tests/RemoteThreadListThreadListRuntimeCore-loadMore.test.ts +8 -6
  324. package/src/tests/RemoteThreadListThreadListRuntimeCore-title-race.test.ts +158 -0
  325. package/src/tests/empty-thread-core.test.ts +6 -0
  326. package/src/tests/external-store-thread-runtime-core-adapter.test.ts +184 -0
  327. package/src/tests/external-store-thread-runtime-core.test.ts +642 -0
  328. package/src/tests/external-thread-attachments.test.tsx +173 -0
  329. package/src/tests/external-thread-isEmpty.test.tsx +100 -0
  330. package/src/tests/remote-thread-list-adapter-switch.test.ts +383 -0
  331. package/src/tests/single-thread-list-item.test.tsx +47 -0
  332. package/src/tests/thread-message-like.test.ts +39 -1
  333. package/src/tests/useRemoteThreadListRuntime-controlled.test.tsx +67 -0
  334. package/src/types/message.ts +9 -4
  335. package/src/utils/data-url.test.ts +52 -1
  336. package/src/utils/data-url.ts +21 -0
  337. package/src/utils/invoke-user-callback.test.ts +82 -0
  338. package/src/utils/invoke-user-callback.ts +31 -0
  339. package/src/utils/normalizePartStatus.ts +1 -1
  340. package/src/utils/silent-runtime-action.ts +6 -0
  341. package/dist/store/scopes/queue-item.js.map +0 -1
@@ -29,17 +29,22 @@ const serializeModelContext = (
29
29
  }),
30
30
  });
31
31
 
32
+ const getDefaultTargetOrigin = () => window.location.origin;
33
+
32
34
  export class AssistantFrameProvider {
33
35
  private static _instance: AssistantFrameProvider | null = null;
34
36
 
35
- private _providers = new Set<ModelContextProvider>();
36
- private _providerUnsubscribes = new Map<
37
- ModelContextProvider,
38
- Unsubscribe | undefined
37
+ private _providers = new Map<symbol, ModelContextProvider>();
38
+ private _providerUnsubscribes = new Map<symbol, Unsubscribe | undefined>();
39
+ private _activeToolCalls = new Map<
40
+ string,
41
+ { abortController: AbortController; event: MessageEvent }
39
42
  >();
40
43
  private _targetOrigin: string;
44
+ private _strictRegistrations = 0;
45
+ private _wildcardRegistrations = 0;
41
46
 
42
- private constructor(targetOrigin: string = "*") {
47
+ private constructor(targetOrigin: string = getDefaultTargetOrigin()) {
43
48
  this._targetOrigin = targetOrigin;
44
49
  this.handleMessage = this.handleMessage.bind(this);
45
50
  window.addEventListener("message", this.handleMessage);
@@ -52,10 +57,34 @@ export class AssistantFrameProvider {
52
57
  AssistantFrameProvider._instance = new AssistantFrameProvider(
53
58
  targetOrigin,
54
59
  );
60
+ } else {
61
+ AssistantFrameProvider._instance.reconcileTargetOrigin(targetOrigin);
55
62
  }
56
63
  return AssistantFrameProvider._instance;
57
64
  }
58
65
 
66
+ private reconcileTargetOrigin(
67
+ targetOrigin: string = getDefaultTargetOrigin(),
68
+ ) {
69
+ if (targetOrigin === this._targetOrigin) return;
70
+
71
+ if (this._providers.size === 0) {
72
+ this._targetOrigin = targetOrigin;
73
+ return;
74
+ }
75
+
76
+ if (targetOrigin === "*") return;
77
+
78
+ if (this._targetOrigin === "*") {
79
+ this._targetOrigin = targetOrigin;
80
+ return;
81
+ }
82
+
83
+ throw new Error(
84
+ `AssistantFrameProvider cannot register conflicting target origins: "${this._targetOrigin}" and "${targetOrigin}"`,
85
+ );
86
+ }
87
+
59
88
  private handleMessage(event: MessageEvent) {
60
89
  if (this._targetOrigin !== "*" && event.origin !== this._targetOrigin)
61
90
  return;
@@ -75,6 +104,10 @@ export class AssistantFrameProvider {
75
104
  case "tool-call":
76
105
  this.handleToolCall(message, event);
77
106
  break;
107
+
108
+ case "tool-cancel":
109
+ this.cancelToolCall(message.id);
110
+ break;
78
111
  }
79
112
  }
80
113
 
@@ -83,6 +116,10 @@ export class AssistantFrameProvider {
83
116
  event: MessageEvent,
84
117
  ) {
85
118
  const tool = this.getModelContext().tools?.[message.toolName];
119
+ const abortController = new AbortController();
120
+ this._activeToolCalls.get(message.id)?.abortController.abort();
121
+ const activeCall = { abortController, event };
122
+ this._activeToolCalls.set(message.id, activeCall);
86
123
 
87
124
  let result: any;
88
125
  let error: string | undefined;
@@ -94,7 +131,7 @@ export class AssistantFrameProvider {
94
131
  result = tool.execute
95
132
  ? await tool.execute(message.args, {
96
133
  toolCallId: message.id,
97
- abortSignal: new AbortController().signal,
134
+ abortSignal: abortController.signal,
98
135
  human: async () => {
99
136
  throw new Error(
100
137
  "Tool human input is not supported in frame context",
@@ -107,13 +144,23 @@ export class AssistantFrameProvider {
107
144
  }
108
145
  }
109
146
 
147
+ if (this._activeToolCalls.get(message.id) !== activeCall) return;
148
+ this._activeToolCalls.delete(message.id);
149
+
110
150
  this.sendMessage(event, {
111
151
  type: "tool-result",
112
152
  id: message.id,
113
- ...(error ? { error } : { result }),
153
+ ...(error !== undefined ? { error } : { result }),
114
154
  });
115
155
  }
116
156
 
157
+ private cancelToolCall(id: string) {
158
+ const activeCall = this._activeToolCalls.get(id);
159
+ if (!activeCall) return;
160
+ this._activeToolCalls.delete(id);
161
+ activeCall.abortController.abort();
162
+ }
163
+
117
164
  private sendMessage(event: MessageEvent, message: FrameMessage) {
118
165
  event.source?.postMessage(
119
166
  { channel: FRAME_MESSAGE_CHANNEL, message },
@@ -122,7 +169,7 @@ export class AssistantFrameProvider {
122
169
  }
123
170
 
124
171
  private getModelContext(): ModelContext {
125
- const contexts = Array.from(this._providers).map((p) =>
172
+ const contexts = Array.from(new Set(this._providers.values())).map((p) =>
126
173
  p.getModelContext(),
127
174
  );
128
175
 
@@ -153,25 +200,87 @@ export class AssistantFrameProvider {
153
200
  }
154
201
  }
155
202
 
203
+ private removeProvider(id: symbol, origin: string): Unsubscribe | undefined {
204
+ this._providers.delete(id);
205
+ const unsubscribe = this._providerUnsubscribes.get(id);
206
+ this._providerUnsubscribes.delete(id);
207
+ if (origin === "*") {
208
+ this._wildcardRegistrations -= 1;
209
+ if (
210
+ this._wildcardRegistrations === 0 &&
211
+ this._strictRegistrations === 0
212
+ ) {
213
+ this._targetOrigin = getDefaultTargetOrigin();
214
+ }
215
+ } else {
216
+ this._strictRegistrations -= 1;
217
+ if (this._strictRegistrations === 0) {
218
+ this._targetOrigin =
219
+ this._wildcardRegistrations > 0 ? "*" : getDefaultTargetOrigin();
220
+ }
221
+ }
222
+ return unsubscribe;
223
+ }
224
+
156
225
  static addModelContextProvider(
157
226
  provider: ModelContextProvider,
158
227
  targetOrigin?: string,
159
228
  ): Unsubscribe {
160
- const instance = AssistantFrameProvider.getInstance(targetOrigin);
161
- instance._providers.add(provider);
162
-
163
- const unsubscribe = provider.subscribe?.(() => instance.broadcastUpdate());
164
- if (unsubscribe) {
165
- instance._providerUnsubscribes.set(provider, unsubscribe);
229
+ const origin = targetOrigin ?? getDefaultTargetOrigin();
230
+ const instance = AssistantFrameProvider.getInstance(origin);
231
+ const id = Symbol();
232
+ instance._providers.set(id, provider);
233
+ if (origin === "*") {
234
+ instance._wildcardRegistrations += 1;
235
+ } else {
236
+ instance._strictRegistrations += 1;
166
237
  }
167
238
 
168
- instance.broadcastUpdate();
239
+ try {
240
+ const unsubscribe = provider.subscribe?.(() =>
241
+ instance.broadcastUpdate(),
242
+ );
243
+ if (unsubscribe) {
244
+ instance._providerUnsubscribes.set(id, unsubscribe);
245
+ }
169
246
 
170
- return () => {
171
- instance._providers.delete(provider);
172
- instance._providerUnsubscribes.get(provider)?.();
173
- instance._providerUnsubscribes.delete(provider);
174
247
  instance.broadcastUpdate();
248
+ } catch (error) {
249
+ const unsubscribe = instance.removeProvider(id, origin);
250
+ // Rollback failures must not replace the registration error.
251
+ try {
252
+ unsubscribe?.();
253
+ } catch (unsubscribeError) {
254
+ console.error(unsubscribeError);
255
+ }
256
+ try {
257
+ instance.broadcastUpdate();
258
+ } catch (broadcastError) {
259
+ console.error(broadcastError);
260
+ }
261
+ throw error;
262
+ }
263
+
264
+ let released = false;
265
+ return () => {
266
+ if (released) return;
267
+ released = true;
268
+ const unsubscribe = instance.removeProvider(id, origin);
269
+ let unsubscribeFailed = false;
270
+ let unsubscribeError: unknown;
271
+ try {
272
+ unsubscribe?.();
273
+ } catch (error) {
274
+ unsubscribeFailed = true;
275
+ unsubscribeError = error;
276
+ }
277
+ try {
278
+ instance.broadcastUpdate();
279
+ } catch (error) {
280
+ if (!unsubscribeFailed) throw error;
281
+ console.error(error);
282
+ }
283
+ if (unsubscribeFailed) throw unsubscribeError;
175
284
  };
176
285
  }
177
286
 
@@ -180,11 +289,40 @@ export class AssistantFrameProvider {
180
289
  const instance = AssistantFrameProvider._instance;
181
290
  window.removeEventListener("message", instance.handleMessage);
182
291
 
183
- instance._providerUnsubscribes.forEach((unsubscribe) => unsubscribe?.());
292
+ let cleanupFailed = false;
293
+ let cleanupError: unknown;
294
+ const runCleanup = (cleanup: () => void) => {
295
+ try {
296
+ cleanup();
297
+ } catch (error) {
298
+ if (cleanupFailed) {
299
+ console.error(error);
300
+ } else {
301
+ cleanupFailed = true;
302
+ cleanupError = error;
303
+ }
304
+ }
305
+ };
306
+
307
+ instance._providerUnsubscribes.forEach((unsubscribe) => {
308
+ if (unsubscribe) runCleanup(unsubscribe);
309
+ });
184
310
  instance._providerUnsubscribes.clear();
185
311
  instance._providers.clear();
312
+ instance._activeToolCalls.forEach(({ abortController, event }, id) => {
313
+ runCleanup(() => {
314
+ abortController.abort();
315
+ instance.sendMessage(event, {
316
+ type: "tool-result",
317
+ id,
318
+ error: "AssistantFrameProvider has been disposed",
319
+ });
320
+ });
321
+ });
322
+ instance._activeToolCalls.clear();
186
323
 
187
324
  AssistantFrameProvider._instance = null;
325
+ if (cleanupFailed) throw cleanupError;
188
326
  }
189
327
  }
190
328
  }
@@ -14,6 +14,7 @@ export type FrameMessageType =
14
14
  | "model-context-request"
15
15
  | "model-context-update"
16
16
  | "tool-call"
17
+ | "tool-cancel"
17
18
  | "tool-result";
18
19
 
19
20
  export type FrameMessage =
@@ -30,6 +31,10 @@ export type FrameMessage =
30
31
  toolName: string;
31
32
  args: unknown;
32
33
  }
34
+ | {
35
+ type: "tool-cancel";
36
+ id: string;
37
+ }
33
38
  | {
34
39
  type: "tool-result";
35
40
  id: string;
@@ -33,7 +33,7 @@ type SnapshotCarrierMessage = {
33
33
  * `metadata.custom.interactables`, or `undefined` if none. This is the read
34
34
  * half of the snapshot channel — integrations use it to surface interactable
35
35
  * state to the model (see `unstable_injectInteractableContext` in
36
- * `@assistant-ui/react-ai-sdk` for the AI SDK implementation).
36
+ * `@assistant-ui/ai-sdk` for the AI SDK implementation).
37
37
  *
38
38
  * @deprecated Unstable / Experimental (not actually removed).
39
39
  */
@@ -128,4 +128,48 @@ describe("ModelContextRegistry", () => {
128
128
  expect(() => publishUpdate()).toThrow(error);
129
129
  expect(laterSubscriber).toHaveBeenCalledTimes(1);
130
130
  });
131
+
132
+ it("notifies subscribers exactly once when a provider changes", () => {
133
+ const registry = new ModelContextRegistry();
134
+ const callbacks = new Set<() => void>();
135
+ const subscriber = vi.fn();
136
+
137
+ registry.addProvider({
138
+ getModelContext: () => ({ system: "provider instructions" }),
139
+ subscribe: (callback) => {
140
+ callbacks.add(callback);
141
+ return () => callbacks.delete(callback);
142
+ },
143
+ });
144
+ registry.subscribe(subscriber);
145
+
146
+ for (const callback of callbacks) {
147
+ callback();
148
+ }
149
+
150
+ expect(subscriber).toHaveBeenCalledTimes(1);
151
+ });
152
+
153
+ it("removes a provider's context and subscription through the addProvider handle", () => {
154
+ const registry = new ModelContextRegistry();
155
+ const unsubscribe = vi.fn();
156
+
157
+ const handle = registry.addProvider({
158
+ getModelContext: () => ({ system: "provider instructions" }),
159
+ subscribe: () => unsubscribe,
160
+ });
161
+ expect(registry.getModelContext().system).toContain(
162
+ "provider instructions",
163
+ );
164
+
165
+ const subscriber = vi.fn();
166
+ registry.subscribe(subscriber);
167
+ handle.remove();
168
+
169
+ expect(unsubscribe).toHaveBeenCalledTimes(1);
170
+ expect(registry.getModelContext().system ?? "").not.toContain(
171
+ "provider instructions",
172
+ );
173
+ expect(subscriber).toHaveBeenCalledTimes(1);
174
+ });
131
175
  });
@@ -2,12 +2,12 @@ import type { Tool } from "assistant-stream";
2
2
  import {
3
3
  type ModelContext,
4
4
  type ModelContextProvider,
5
- mergeModelContexts,
6
5
  type AssistantToolProps,
7
6
  type AssistantInstructionsConfig,
8
7
  } from "./types";
9
- import type { Unsubscribe } from "../types/unsubscribe";
10
8
  import { notifySubscribers as notifyStateSubscribers } from "../subscribable/subscribable";
9
+ import { CompositeContextProvider } from "../utils/composite-context-provider";
10
+ import type { Unsubscribe } from "../types/unsubscribe";
11
11
  import type {
12
12
  ModelContextRegistryToolHandle,
13
13
  ModelContextRegistryInstructionHandle,
@@ -17,9 +17,14 @@ import type {
17
17
  export class ModelContextRegistry implements ModelContextProvider {
18
18
  private _tools = new Map<symbol, AssistantToolProps<any, any>>();
19
19
  private _instructions = new Map<symbol, string>();
20
- private _providers = new Map<symbol, ModelContextProvider>();
20
+ private _contextProviders = new CompositeContextProvider();
21
21
  private _subscribers = new Set<() => void>();
22
- private _providerUnsubscribes = new Map<symbol, Unsubscribe | undefined>();
22
+
23
+ constructor() {
24
+ this._contextProviders.subscribe(() => {
25
+ this.notifySubscribers();
26
+ });
27
+ }
23
28
 
24
29
  getModelContext(): ModelContext {
25
30
  const instructions = Array.from(this._instructions.values()).filter(
@@ -35,9 +40,7 @@ export class ModelContextRegistry implements ModelContextProvider {
35
40
  tools[toolName] = tool;
36
41
  }
37
42
 
38
- const providerContexts = mergeModelContexts(
39
- new Set(this._providers.values()),
40
- );
43
+ const providerContexts = this._contextProviders.getModelContext();
41
44
 
42
45
  const context: ModelContext = {
43
46
  system,
@@ -139,36 +142,11 @@ export class ModelContextRegistry implements ModelContextProvider {
139
142
  addProvider(
140
143
  provider: ModelContextProvider,
141
144
  ): ModelContextRegistryProviderHandle {
142
- const id = Symbol();
143
-
144
- this._providers.set(id, provider);
145
-
146
- let unsubscribe: Unsubscribe | undefined;
147
- try {
148
- unsubscribe = provider.subscribe?.(() => {
149
- this.notifySubscribers();
150
- });
151
- } catch (error) {
152
- this._providers.delete(id);
153
- try {
154
- this.notifySubscribers();
155
- } catch (notifyError) {
156
- console.error(notifyError);
157
- }
158
- throw error;
159
- }
160
- this._providerUnsubscribes.set(id, unsubscribe);
161
-
162
- this.notifySubscribers();
145
+ const unregister =
146
+ this._contextProviders.registerModelContextProvider(provider);
163
147
 
164
148
  return {
165
- remove: () => {
166
- this._providers.delete(id);
167
- const unsubscribe = this._providerUnsubscribes.get(id);
168
- unsubscribe?.();
169
- this._providerUnsubscribes.delete(id);
170
- this.notifySubscribers();
171
- },
149
+ remove: unregister,
172
150
  };
173
151
  }
174
152
  }
@@ -146,3 +146,52 @@ describe("InMemoryThreadList delete", () => {
146
146
  expect(state.mainThreadId).not.toBe("main");
147
147
  });
148
148
  });
149
+
150
+ describe("InMemoryThreadList item index selectors", () => {
151
+ it("resolves index selectors within the archived and regular subsets", async () => {
152
+ const { getAui } = setup();
153
+ await act(async () => {});
154
+
155
+ await act(async () => {
156
+ getAui().threads.switchToNewThread();
157
+ });
158
+ await act(async () => {});
159
+ const b = getAui().threads.getState().mainThreadId;
160
+
161
+ await act(async () => {
162
+ getAui().threads.switchToNewThread();
163
+ });
164
+ await act(async () => {});
165
+
166
+ await act(async () => {
167
+ getAui().threads.item({ id: b }).archive();
168
+ });
169
+ await act(async () => {});
170
+
171
+ const state = getAui().threads.getState();
172
+ expect(state.archivedThreadIds).toEqual([b]);
173
+ expect(state.threadIds).toHaveLength(2);
174
+
175
+ for (const [index, id] of state.archivedThreadIds.entries()) {
176
+ expect(
177
+ getAui().threads.item({ index, archived: true }).getState().id,
178
+ ).toBe(id);
179
+ }
180
+ for (const [index, id] of state.threadIds.entries()) {
181
+ expect(getAui().threads.item({ index }).getState().id).toBe(id);
182
+ expect(
183
+ getAui().threads.item({ index, archived: false }).getState().id,
184
+ ).toBe(id);
185
+ }
186
+
187
+ expect(() =>
188
+ getAui().threads.item({ index: state.threadIds.length }),
189
+ ).toThrow("out of bounds");
190
+ expect(() =>
191
+ getAui().threads.item({
192
+ index: state.archivedThreadIds.length,
193
+ archived: true,
194
+ }),
195
+ ).toThrow("out of bounds");
196
+ });
197
+ });
@@ -236,7 +236,13 @@ const useInMemoryThreadList = (
236
236
  const index = threads.findIndex((t) => t.id === selector.id);
237
237
  return threadListItems.get({ index });
238
238
  }
239
- return threadListItems.get(selector);
239
+ // The lookup is keyed over the combined thread array, while index
240
+ // selectors address the regular/archived subset the primitives render.
241
+ const ids = selector.archived ? state.archivedThreadIds : state.threadIds;
242
+ const id = ids[selector.index];
243
+ if (id === undefined) return threadListItems.get({ index: -1 });
244
+ const index = threads.findIndex((t) => t.id === id);
245
+ return threadListItems.get({ index });
240
246
  },
241
247
  thread: () => mainThreadClient.methods,
242
248
  };