@assistant-ui/core 0.3.17 → 0.3.19

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 (470) hide show
  1. package/dist/adapters/attachment.d.ts.map +1 -1
  2. package/dist/adapters/attachment.js +5 -4
  3. package/dist/adapters/attachment.js.map +1 -1
  4. package/dist/adapters/speech.d.ts.map +1 -1
  5. package/dist/adapters/speech.js +13 -3
  6. package/dist/adapters/speech.js.map +1 -1
  7. package/dist/adapters/thread-history.d.ts +4 -0
  8. package/dist/adapters/thread-history.d.ts.map +1 -1
  9. package/dist/index.d.ts +3 -3
  10. package/dist/index.js.map +1 -1
  11. package/dist/internal.d.ts +4 -3
  12. package/dist/internal.js +3 -2
  13. package/dist/model-context/frame/host.d.ts.map +1 -1
  14. package/dist/model-context/frame/host.js +35 -14
  15. package/dist/model-context/frame/host.js.map +1 -1
  16. package/dist/model-context/frame/provider.d.ts +2 -0
  17. package/dist/model-context/frame/provider.d.ts.map +1 -1
  18. package/dist/model-context/frame/provider.js +30 -7
  19. package/dist/model-context/frame/provider.js.map +1 -1
  20. package/dist/model-context/interactable-composer-metadata.d.ts.map +1 -1
  21. package/dist/model-context/interactable-composer-metadata.js +27 -18
  22. package/dist/model-context/interactable-composer-metadata.js.map +1 -1
  23. package/dist/model-context/registry.d.ts.map +1 -1
  24. package/dist/model-context/registry.js +3 -5
  25. package/dist/model-context/registry.js.map +1 -1
  26. package/dist/model-context/types.d.ts.map +1 -1
  27. package/dist/model-context/types.js +5 -4
  28. package/dist/model-context/types.js.map +1 -1
  29. package/dist/react/adapters/LocalStorageThreadListAdapter.d.ts.map +1 -1
  30. package/dist/react/adapters/LocalStorageThreadListAdapter.js +45 -7
  31. package/dist/react/adapters/LocalStorageThreadListAdapter.js.map +1 -1
  32. package/dist/react/client/DataRenderers.d.ts.map +1 -1
  33. package/dist/react/client/DataRenderers.js +20 -15
  34. package/dist/react/client/DataRenderers.js.map +1 -1
  35. package/dist/react/client/InMemoryThreadList.d.ts.map +1 -1
  36. package/dist/react/client/InMemoryThreadList.js +62 -56
  37. package/dist/react/client/InMemoryThreadList.js.map +1 -1
  38. package/dist/react/client/Interactables.d.ts.map +1 -1
  39. package/dist/react/client/Interactables.js +35 -32
  40. package/dist/react/client/Interactables.js.map +1 -1
  41. package/dist/react/client/RemoteThreadList.d.ts +1 -0
  42. package/dist/react/client/RemoteThreadList.d.ts.map +1 -1
  43. package/dist/react/client/RemoteThreadList.js +154 -143
  44. package/dist/react/client/RemoteThreadList.js.map +1 -1
  45. package/dist/react/client/Tools.d.ts.map +1 -1
  46. package/dist/react/client/Tools.js +18 -16
  47. package/dist/react/client/Tools.js.map +1 -1
  48. package/dist/react/client/interactable-model-context.d.ts.map +1 -1
  49. package/dist/react/client/interactable-model-context.js +3 -2
  50. package/dist/react/client/interactable-model-context.js.map +1 -1
  51. package/dist/react/index.d.ts +2 -2
  52. package/dist/react/index.js +2 -2
  53. package/dist/react/interactables-legacy/Interactables.js +242 -121
  54. package/dist/react/interactables-legacy/Interactables.js.map +1 -1
  55. package/dist/react/interactables-legacy/useAssistantInteractable.d.ts.map +1 -1
  56. package/dist/react/interactables-legacy/useAssistantInteractable.js +3 -0
  57. package/dist/react/interactables-legacy/useAssistantInteractable.js.map +1 -1
  58. package/dist/react/interactables-shared/useInteractablePersistenceQueue.d.ts.map +1 -1
  59. package/dist/react/interactables-shared/useInteractablePersistenceQueue.js +11 -9
  60. package/dist/react/interactables-shared/useInteractablePersistenceQueue.js.map +1 -1
  61. package/dist/react/model-context/makeAssistantTool.d.ts +2 -2
  62. package/dist/react/model-context/makeAssistantTool.js +1 -1
  63. package/dist/react/model-context/makeAssistantTool.js.map +1 -1
  64. package/dist/react/model-context/useAssistantTool.d.ts +2 -2
  65. package/dist/react/model-context/useAssistantTool.js +1 -1
  66. package/dist/react/model-context/useAssistantTool.js.map +1 -1
  67. package/dist/react/model-context/useInteractable.d.ts.map +1 -1
  68. package/dist/react/model-context/useInteractable.js +4 -1
  69. package/dist/react/model-context/useInteractable.js.map +1 -1
  70. package/dist/react/model-context/useInteractableVersions.js +1 -1
  71. package/dist/react/model-context/useToolArgsStatus.d.ts.map +1 -1
  72. package/dist/react/model-context/useToolArgsStatus.js +2 -1
  73. package/dist/react/model-context/useToolArgsStatus.js.map +1 -1
  74. package/dist/react/primitives/message/MessageGroupedParts.d.ts +11 -2
  75. package/dist/react/primitives/message/MessageGroupedParts.d.ts.map +1 -1
  76. package/dist/react/primitives/message/MessageGroupedParts.js +3 -2
  77. package/dist/react/primitives/message/MessageGroupedParts.js.map +1 -1
  78. package/dist/react/primitives/part/PartMessages.d.ts +1 -0
  79. package/dist/react/primitives/part/PartMessages.d.ts.map +1 -1
  80. package/dist/react/primitives/part/PartMessages.js +1 -0
  81. package/dist/react/primitives/part/PartMessages.js.map +1 -1
  82. package/dist/react/primitives/thread/ThreadMessages.d.ts.map +1 -1
  83. package/dist/react/primitives/thread/ThreadMessages.js +6 -5
  84. package/dist/react/primitives/thread/ThreadMessages.js.map +1 -1
  85. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
  86. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +16 -8
  87. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
  88. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +5 -1
  89. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
  90. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +105 -104
  91. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
  92. package/dist/react/runtimes/RemoteThreadResource.d.ts +1 -0
  93. package/dist/react/runtimes/RemoteThreadResource.d.ts.map +1 -1
  94. package/dist/react/runtimes/RemoteThreadResource.js +13 -11
  95. package/dist/react/runtimes/RemoteThreadResource.js.map +1 -1
  96. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts +5 -24
  97. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
  98. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +354 -226
  99. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
  100. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts +1 -0
  101. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts.map +1 -1
  102. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js +22 -2
  103. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js.map +1 -1
  104. package/dist/react/runtimes/cloud/auiV0.d.ts +40 -15
  105. package/dist/react/runtimes/cloud/auiV0.d.ts.map +1 -1
  106. package/dist/react/runtimes/cloud/auiV0.js +62 -15
  107. package/dist/react/runtimes/cloud/auiV0.js.map +1 -1
  108. package/dist/react/runtimes/cloud/createCloudThreadListAdapter.d.ts +2 -1
  109. package/dist/react/runtimes/cloud/createCloudThreadListAdapter.d.ts.map +1 -1
  110. package/dist/react/runtimes/cloud/createCloudThreadListAdapter.js +6 -1
  111. package/dist/react/runtimes/cloud/createCloudThreadListAdapter.js.map +1 -1
  112. package/dist/react/runtimes/cloud/sdkIdentity.d.ts +6 -0
  113. package/dist/react/runtimes/cloud/sdkIdentity.d.ts.map +1 -0
  114. package/dist/react/runtimes/cloud/sdkIdentity.js +9 -0
  115. package/dist/react/runtimes/cloud/sdkIdentity.js.map +1 -0
  116. package/dist/react/runtimes/external-message-converter.d.ts +12 -2
  117. package/dist/react/runtimes/external-message-converter.d.ts.map +1 -1
  118. package/dist/react/runtimes/external-message-converter.js +26 -61
  119. package/dist/react/runtimes/external-message-converter.js.map +1 -1
  120. package/dist/react/runtimes/useExternalStoreRuntime.js +75 -46
  121. package/dist/react/runtimes/useExternalStoreRuntime.js.map +1 -1
  122. package/dist/react/runtimes/useRemoteThreadListRuntime.d.ts.map +1 -1
  123. package/dist/react/runtimes/useRemoteThreadListRuntime.js +64 -24
  124. package/dist/react/runtimes/useRemoteThreadListRuntime.js.map +1 -1
  125. package/dist/react/utils/groupParts.d.ts +6 -1
  126. package/dist/react/utils/groupParts.d.ts.map +1 -1
  127. package/dist/react/utils/groupParts.js +6 -0
  128. package/dist/react/utils/groupParts.js.map +1 -1
  129. package/dist/react/utils/useJSONEqual.d.ts +3 -1
  130. package/dist/react/utils/useJSONEqual.d.ts.map +1 -1
  131. package/dist/react/utils/useJSONEqual.js +6 -1
  132. package/dist/react/utils/useJSONEqual.js.map +1 -1
  133. package/dist/react/utils/useJSONSchemaDependency.d.ts +7 -0
  134. package/dist/react/utils/useJSONSchemaDependency.d.ts.map +1 -0
  135. package/dist/react/utils/useJSONSchemaDependency.js +20 -0
  136. package/dist/react/utils/useJSONSchemaDependency.js.map +1 -0
  137. package/dist/runtime/api/thread-list-item-runtime.d.ts +7 -3
  138. package/dist/runtime/api/thread-list-item-runtime.d.ts.map +1 -1
  139. package/dist/runtime/api/thread-list-item-runtime.js +2 -2
  140. package/dist/runtime/api/thread-list-item-runtime.js.map +1 -1
  141. package/dist/runtime/api/thread-list-runtime.d.ts +3 -0
  142. package/dist/runtime/api/thread-list-runtime.d.ts.map +1 -1
  143. package/dist/runtime/api/thread-list-runtime.js +18 -14
  144. package/dist/runtime/api/thread-list-runtime.js.map +1 -1
  145. package/dist/runtime/api/thread-runtime.d.ts +4 -0
  146. package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
  147. package/dist/runtime/api/thread-runtime.js +3 -6
  148. package/dist/runtime/api/thread-runtime.js.map +1 -1
  149. package/dist/runtime/base/base-composer-runtime-core.d.ts +1 -0
  150. package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
  151. package/dist/runtime/base/base-composer-runtime-core.js +62 -22
  152. package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
  153. package/dist/runtime/base/base-thread-runtime-core.d.ts +2 -0
  154. package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
  155. package/dist/runtime/base/base-thread-runtime-core.js +161 -69
  156. package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
  157. package/dist/runtime/interfaces/composer-runtime-core.d.ts +12 -5
  158. package/dist/runtime/interfaces/composer-runtime-core.d.ts.map +1 -1
  159. package/dist/runtime/interfaces/thread-list-runtime-core.d.ts +4 -1
  160. package/dist/runtime/interfaces/thread-list-runtime-core.d.ts.map +1 -1
  161. package/dist/runtime/interfaces/thread-runtime-core.d.ts +6 -0
  162. package/dist/runtime/interfaces/thread-runtime-core.d.ts.map +1 -1
  163. package/dist/runtime/queue/message-queue.d.ts +5 -0
  164. package/dist/runtime/queue/message-queue.d.ts.map +1 -1
  165. package/dist/runtime/queue/message-queue.js +61 -6
  166. package/dist/runtime/queue/message-queue.js.map +1 -1
  167. package/dist/runtime/utils/auto-status.d.ts +6 -2
  168. package/dist/runtime/utils/auto-status.d.ts.map +1 -1
  169. package/dist/runtime/utils/auto-status.js +12 -4
  170. package/dist/runtime/utils/auto-status.js.map +1 -1
  171. package/dist/runtime/utils/external-message-conversion.d.ts +16 -4
  172. package/dist/runtime/utils/external-message-conversion.d.ts.map +1 -1
  173. package/dist/runtime/utils/external-message-conversion.js +49 -13
  174. package/dist/runtime/utils/external-message-conversion.js.map +1 -1
  175. package/dist/runtime/utils/message-repository.d.ts +1 -0
  176. package/dist/runtime/utils/message-repository.d.ts.map +1 -1
  177. package/dist/runtime/utils/message-repository.js +18 -9
  178. package/dist/runtime/utils/message-repository.js.map +1 -1
  179. package/dist/runtime/utils/thread-message-like.d.ts +2 -1
  180. package/dist/runtime/utils/thread-message-like.d.ts.map +1 -1
  181. package/dist/runtime/utils/thread-message-like.js +5 -3
  182. package/dist/runtime/utils/thread-message-like.js.map +1 -1
  183. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts.map +1 -1
  184. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js +21 -27
  185. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js.map +1 -1
  186. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
  187. package/dist/runtimes/external-store/external-store-thread-runtime-core.js +8 -1
  188. package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
  189. package/dist/runtimes/internal.d.ts +3 -3
  190. package/dist/runtimes/internal.js +2 -2
  191. package/dist/runtimes/local/local-thread-runtime-core.d.ts +1 -1
  192. package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
  193. package/dist/runtimes/local/local-thread-runtime-core.js +4 -1
  194. package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
  195. package/dist/runtimes/remote-thread-list/remote-thread-state.d.ts +18 -1
  196. package/dist/runtimes/remote-thread-list/remote-thread-state.d.ts.map +1 -1
  197. package/dist/runtimes/remote-thread-list/remote-thread-state.js +130 -42
  198. package/dist/runtimes/remote-thread-list/remote-thread-state.js.map +1 -1
  199. package/dist/runtimes/remote-thread-list/title-generation.d.ts +49 -0
  200. package/dist/runtimes/remote-thread-list/title-generation.d.ts.map +1 -0
  201. package/dist/runtimes/remote-thread-list/title-generation.js +197 -0
  202. package/dist/runtimes/remote-thread-list/title-generation.js.map +1 -0
  203. package/dist/runtimes/remote-thread-list/title.d.ts +3 -1
  204. package/dist/runtimes/remote-thread-list/title.d.ts.map +1 -1
  205. package/dist/runtimes/remote-thread-list/title.js +9 -1
  206. package/dist/runtimes/remote-thread-list/title.js.map +1 -1
  207. package/dist/runtimes/remote-thread-list/types.d.ts +10 -0
  208. package/dist/runtimes/remote-thread-list/types.d.ts.map +1 -1
  209. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts.map +1 -1
  210. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js +2 -1
  211. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js.map +1 -1
  212. package/dist/store/clients/external-thread.d.ts.map +1 -1
  213. package/dist/store/clients/external-thread.js +260 -203
  214. package/dist/store/clients/external-thread.js.map +1 -1
  215. package/dist/store/clients/model-context-client.d.ts.map +1 -1
  216. package/dist/store/clients/model-context-client.js +2 -1
  217. package/dist/store/clients/model-context-client.js.map +1 -1
  218. package/dist/store/clients/single-thread-list.d.ts.map +1 -1
  219. package/dist/store/clients/single-thread-list.js +1 -0
  220. package/dist/store/clients/single-thread-list.js.map +1 -1
  221. package/dist/store/clients/suggestions.d.ts.map +1 -1
  222. package/dist/store/clients/suggestions.js +5 -4
  223. package/dist/store/clients/suggestions.js.map +1 -1
  224. package/dist/store/clients/thread-tasks.d.ts +13 -0
  225. package/dist/store/clients/thread-tasks.d.ts.map +1 -0
  226. package/dist/store/clients/thread-tasks.js +69 -0
  227. package/dist/store/clients/thread-tasks.js.map +1 -0
  228. package/dist/store/index.d.ts +3 -2
  229. package/dist/store/index.js +3 -3
  230. package/dist/store/primitive-predicates.d.ts.map +1 -1
  231. package/dist/store/primitive-predicates.js +4 -4
  232. package/dist/store/primitive-predicates.js.map +1 -1
  233. package/dist/store/runtime-clients/composer-runtime-client.d.ts +1 -0
  234. package/dist/store/runtime-clients/composer-runtime-client.d.ts.map +1 -1
  235. package/dist/store/runtime-clients/composer-runtime-client.js +97 -61
  236. package/dist/store/runtime-clients/composer-runtime-client.js.map +1 -1
  237. package/dist/store/runtime-clients/message-runtime-client.d.ts +1 -0
  238. package/dist/store/runtime-clients/message-runtime-client.d.ts.map +1 -1
  239. package/dist/store/runtime-clients/message-runtime-client.js +221 -144
  240. package/dist/store/runtime-clients/message-runtime-client.js.map +1 -1
  241. package/dist/store/runtime-clients/thread-list-item-runtime-client.d.ts.map +1 -1
  242. package/dist/store/runtime-clients/thread-list-item-runtime-client.js +1 -1
  243. package/dist/store/runtime-clients/thread-list-item-runtime-client.js.map +1 -1
  244. package/dist/store/runtime-clients/thread-list-runtime-client.d.ts.map +1 -1
  245. package/dist/store/runtime-clients/thread-list-runtime-client.js +54 -52
  246. package/dist/store/runtime-clients/thread-list-runtime-client.js.map +1 -1
  247. package/dist/store/runtime-clients/thread-runtime-client.d.ts.map +1 -1
  248. package/dist/store/runtime-clients/thread-runtime-client.js +246 -126
  249. package/dist/store/runtime-clients/thread-runtime-client.js.map +1 -1
  250. package/dist/store/scope-registration.d.ts +2 -0
  251. package/dist/store/scope-registration.d.ts.map +1 -1
  252. package/dist/store/scopes/composer.d.ts +10 -2
  253. package/dist/store/scopes/composer.d.ts.map +1 -1
  254. package/dist/store/scopes/message.d.ts +30 -1
  255. package/dist/store/scopes/message.d.ts.map +1 -1
  256. package/dist/store/scopes/task.d.ts +36 -0
  257. package/dist/store/scopes/task.d.ts.map +1 -0
  258. package/dist/store/scopes/task.js +0 -0
  259. package/dist/store/scopes/thread-list-item.d.ts +2 -2
  260. package/dist/store/scopes/thread-list-item.d.ts.map +1 -1
  261. package/dist/store/scopes/thread.d.ts +28 -0
  262. package/dist/store/scopes/thread.d.ts.map +1 -1
  263. package/dist/store/scopes/threads.d.ts +1 -0
  264. package/dist/store/scopes/threads.d.ts.map +1 -1
  265. package/dist/subscribable/subscribable.d.ts +2 -1
  266. package/dist/subscribable/subscribable.d.ts.map +1 -1
  267. package/dist/subscribable/subscribable.js +23 -15
  268. package/dist/subscribable/subscribable.js.map +1 -1
  269. package/dist/types/attachment.d.ts +2 -1
  270. package/dist/types/attachment.d.ts.map +1 -1
  271. package/dist/types/attachment.js +2 -1
  272. package/dist/types/attachment.js.map +1 -1
  273. package/dist/types/index.d.ts +2 -2
  274. package/dist/types/message.d.ts +8 -1
  275. package/dist/types/message.d.ts.map +1 -1
  276. package/dist/types/message.js.map +1 -1
  277. package/dist/utils/abortable-iterable.d.ts +19 -0
  278. package/dist/utils/abortable-iterable.d.ts.map +1 -0
  279. package/dist/utils/abortable-iterable.js +88 -0
  280. package/dist/utils/abortable-iterable.js.map +1 -0
  281. package/dist/utils/composite-context-provider.d.ts.map +1 -1
  282. package/dist/utils/composite-context-provider.js +20 -2
  283. package/dist/utils/composite-context-provider.js.map +1 -1
  284. package/dist/utils/getGroupStatus.d.ts +18 -2
  285. package/dist/utils/getGroupStatus.d.ts.map +1 -1
  286. package/dist/utils/getGroupStatus.js +32 -7
  287. package/dist/utils/getGroupStatus.js.map +1 -1
  288. package/dist/utils/record.d.ts +11 -0
  289. package/dist/utils/record.d.ts.map +1 -0
  290. package/dist/utils/record.js +12 -0
  291. package/dist/utils/record.js.map +1 -0
  292. package/dist/utils/wire-media.d.ts.map +1 -1
  293. package/dist/utils/wire-media.js +2 -2
  294. package/dist/utils/wire-media.js.map +1 -1
  295. package/package.json +11 -11
  296. package/src/adapters/attachment.test.ts +50 -1
  297. package/src/adapters/attachment.ts +7 -4
  298. package/src/adapters/speech.test.ts +236 -0
  299. package/src/adapters/speech.ts +17 -10
  300. package/src/adapters/thread-history.ts +3 -0
  301. package/src/index.ts +2 -0
  302. package/src/internal.ts +4 -0
  303. package/src/model-context/frame/host.test.ts +137 -1
  304. package/src/model-context/frame/host.ts +49 -16
  305. package/src/model-context/frame/provider.test.ts +71 -0
  306. package/src/model-context/frame/provider.ts +37 -7
  307. package/src/model-context/interactable-composer-metadata.test.ts +58 -0
  308. package/src/model-context/interactable-composer-metadata.ts +19 -13
  309. package/src/model-context/registry.test.ts +12 -0
  310. package/src/model-context/registry.ts +3 -2
  311. package/src/model-context/types.test.ts +25 -0
  312. package/src/model-context/types.ts +9 -4
  313. package/src/react/RuntimeAdapter.test.ts +34 -0
  314. package/src/react/adapters/LocalStorageThreadListAdapter.test.ts +244 -0
  315. package/src/react/adapters/LocalStorageThreadListAdapter.tsx +104 -7
  316. package/src/react/client/DataRenderers.test.tsx +45 -0
  317. package/src/react/client/DataRenderers.ts +13 -9
  318. package/src/react/client/InMemoryThreadList.ts +1 -0
  319. package/src/react/client/Interactables.test.ts +72 -1
  320. package/src/react/client/Interactables.ts +22 -14
  321. package/src/react/client/RemoteThreadList.background.test.ts +148 -6
  322. package/src/react/client/RemoteThreadList.concurrent.test.tsx +42 -1
  323. package/src/react/client/RemoteThreadList.test.ts +386 -4
  324. package/src/react/client/RemoteThreadList.ts +181 -112
  325. package/src/react/client/Tools.ts +22 -11
  326. package/src/react/client/interactable-model-context.test.ts +44 -0
  327. package/src/react/client/interactable-model-context.ts +3 -2
  328. package/src/react/index.ts +5 -1
  329. package/src/react/interactables-legacy/Interactables.ts +16 -16
  330. package/src/react/interactables-legacy/useAssistantInteractable.test.tsx +132 -0
  331. package/src/react/interactables-legacy/useAssistantInteractable.ts +10 -1
  332. package/src/react/interactables-shared/useInteractablePersistenceQueue.ts +9 -10
  333. package/src/react/model-context/makeAssistantTool.ts +2 -2
  334. package/src/react/model-context/useAssistantTool.ts +2 -2
  335. package/src/react/model-context/useInteractable.test.tsx +177 -0
  336. package/src/react/model-context/useInteractable.ts +3 -0
  337. package/src/react/model-context/useToolArgsStatus.test.tsx +30 -0
  338. package/src/react/model-context/useToolArgsStatus.ts +2 -1
  339. package/src/react/primitive-hooks/useActionBarCopy.test.ts +0 -1
  340. package/src/react/primitive-hooks/useSuggestionTrigger.test.ts +0 -1
  341. package/src/react/primitives/message/MessageGroupedParts.test.tsx +96 -0
  342. package/src/react/primitives/message/MessageGroupedParts.tsx +15 -4
  343. package/src/react/primitives/part/PartMessages.test.tsx +104 -1
  344. package/src/react/primitives/part/PartMessages.tsx +1 -0
  345. package/src/react/primitives/thread/ThreadMessages.test.tsx +142 -0
  346. package/src/react/primitives/thread/ThreadMessages.tsx +8 -5
  347. package/src/react/providers/ReadonlyThreadProvider.test.tsx +56 -0
  348. package/src/react/runtimes/RemoteThreadListHookInstanceManager.destroy.test.tsx +172 -0
  349. package/src/react/runtimes/RemoteThreadListHookInstanceManager.running.test.tsx +33 -0
  350. package/src/react/runtimes/RemoteThreadListHookInstanceManager.test.tsx +7 -1
  351. package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +28 -5
  352. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.load-error.test.ts +132 -0
  353. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.switch-delete.test.ts +105 -0
  354. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +143 -112
  355. package/src/react/runtimes/RemoteThreadResource.test.ts +9 -0
  356. package/src/react/runtimes/RemoteThreadResource.ts +19 -12
  357. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.ts +20 -14
  358. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.tsx +703 -6
  359. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +492 -402
  360. package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.test.ts +77 -0
  361. package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.ts +27 -1
  362. package/src/react/runtimes/cloud/auiV0.ts +160 -25
  363. package/src/react/runtimes/cloud/createCloudThreadListAdapter.test.ts +36 -0
  364. package/src/react/runtimes/cloud/createCloudThreadListAdapter.ts +8 -1
  365. package/src/react/runtimes/cloud/sdkIdentity.ts +9 -0
  366. package/src/react/runtimes/cloud/useCloudThreadListAdapter.test.tsx +18 -4
  367. package/src/react/runtimes/external-message-converter.test.ts +136 -1
  368. package/src/react/runtimes/external-message-converter.ts +39 -93
  369. package/src/react/runtimes/useExternalStoreRuntime.lifecycle.test.tsx +41 -0
  370. package/src/react/runtimes/useExternalStoreRuntime.ts +10 -4
  371. package/src/react/runtimes/useLocalRuntime.test.tsx +20 -0
  372. package/src/react/runtimes/useRemoteThreadListRuntime.load-error.test.tsx +108 -0
  373. package/src/react/runtimes/useRemoteThreadListRuntime.ts +34 -1
  374. package/src/react/utils/groupParts.ts +12 -1
  375. package/src/react/utils/useJSONEqual.ts +9 -0
  376. package/src/react/utils/useJSONSchemaDependency.ts +22 -0
  377. package/src/runtime/api/message-runtime.test.ts +75 -0
  378. package/src/runtime/api/thread-list-item-runtime.ts +10 -3
  379. package/src/runtime/api/thread-list-runtime.ts +21 -11
  380. package/src/runtime/api/thread-runtime.test.ts +136 -0
  381. package/src/runtime/api/thread-runtime.ts +10 -5
  382. package/src/runtime/base/base-composer-runtime-core.ts +105 -24
  383. package/src/runtime/base/base-thread-runtime-core.test.ts +1063 -2
  384. package/src/runtime/base/base-thread-runtime-core.ts +228 -87
  385. package/src/runtime/interfaces/composer-runtime-core.ts +10 -5
  386. package/src/runtime/interfaces/thread-list-runtime-core.ts +5 -1
  387. package/src/runtime/interfaces/thread-runtime-core.ts +6 -0
  388. package/src/runtime/queue/message-queue.ts +68 -6
  389. package/src/runtime/utils/auto-status.test.ts +112 -1
  390. package/src/runtime/utils/auto-status.ts +31 -5
  391. package/src/runtime/utils/external-message-conversion.test.ts +202 -0
  392. package/src/runtime/utils/external-message-conversion.ts +123 -32
  393. package/src/runtime/utils/message-repository.test.ts +49 -0
  394. package/src/runtime/utils/message-repository.ts +32 -20
  395. package/src/runtime/utils/thread-message-like.test.ts +52 -0
  396. package/src/runtime/utils/thread-message-like.ts +5 -1
  397. package/src/runtimes/external-store/external-store-thread-list-runtime-core.ts +18 -13
  398. package/src/runtimes/external-store/external-store-thread-runtime-core.ts +31 -1
  399. package/src/runtimes/internal.ts +1 -0
  400. package/src/runtimes/local/local-thread-runtime-core.test.ts +21 -0
  401. package/src/runtimes/local/local-thread-runtime-core.ts +11 -1
  402. package/src/runtimes/remote-thread-list/remote-thread-state.test.ts +128 -2
  403. package/src/runtimes/remote-thread-list/remote-thread-state.ts +182 -42
  404. package/src/runtimes/remote-thread-list/title-generation.test.ts +602 -0
  405. package/src/runtimes/remote-thread-list/title-generation.ts +329 -0
  406. package/src/runtimes/remote-thread-list/title.test.ts +62 -0
  407. package/src/runtimes/remote-thread-list/title.ts +13 -0
  408. package/src/runtimes/remote-thread-list/types.ts +10 -0
  409. package/src/runtimes/tool-invocations/EDGE_CASES.md +2 -6
  410. package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +133 -0
  411. package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +10 -6
  412. package/src/store/clients/external-thread.ts +67 -4
  413. package/src/store/clients/model-context-client.ts +5 -1
  414. package/src/store/clients/single-thread-list.ts +1 -0
  415. package/src/store/clients/suggestions.test.ts +40 -0
  416. package/src/store/clients/suggestions.ts +13 -10
  417. package/src/store/clients/thread-tasks.test.ts +274 -0
  418. package/src/store/clients/thread-tasks.ts +138 -0
  419. package/src/store/index.ts +8 -0
  420. package/src/store/primitive-predicates.test.ts +48 -5
  421. package/src/store/primitive-predicates.ts +7 -2
  422. package/src/store/runtime-clients/composer-runtime-client.ts +42 -9
  423. package/src/store/runtime-clients/message-runtime-client.ts +54 -6
  424. package/src/store/runtime-clients/thread-list-item-runtime-client.ts +4 -2
  425. package/src/store/runtime-clients/thread-list-runtime-client.ts +1 -0
  426. package/src/store/runtime-clients/thread-runtime-client.ts +89 -11
  427. package/src/store/scope-registration.ts +2 -0
  428. package/src/store/scopes/composer.ts +16 -4
  429. package/src/store/scopes/message.ts +14 -0
  430. package/src/store/scopes/task.ts +34 -0
  431. package/src/store/scopes/thread-list-item.ts +5 -2
  432. package/src/store/scopes/thread.ts +20 -0
  433. package/src/store/scopes/threads.ts +1 -0
  434. package/src/store/thread-tasks.test.tsx +209 -0
  435. package/src/subscribable/subscribable.test.ts +156 -1
  436. package/src/subscribable/subscribable.ts +25 -15
  437. package/src/tests/MessageRepository.test.ts +117 -5
  438. package/src/tests/OptimisticState-list-race.test.ts +1 -0
  439. package/src/tests/RemoteThreadListThreadListRuntimeCore-initialize-adapter-change.test.ts +38 -0
  440. package/src/tests/RemoteThreadListThreadListRuntimeCore-load-race.test.ts +47 -0
  441. package/src/tests/RemoteThreadListThreadListRuntimeCore-title-race.test.ts +89 -0
  442. package/src/tests/attachment-adapters.test.ts +14 -0
  443. package/src/tests/auiV0Encode.test.ts +300 -0
  444. package/src/tests/base-composer-runtime-core-send.test.ts +51 -0
  445. package/src/tests/base-composer-runtime-core.test.ts +353 -2
  446. package/src/tests/external-store-thread-list-runtime-core.test.ts +83 -0
  447. package/src/tests/external-store-thread-runtime-core-adapter.test.ts +178 -18
  448. package/src/tests/external-thread-attachments.test.tsx +208 -0
  449. package/src/tests/external-thread-parity.test.tsx +57 -0
  450. package/src/tests/groupParts.test.ts +71 -0
  451. package/src/tests/message-queue.test.ts +253 -0
  452. package/src/tests/remote-thread-list-isLoading.test.ts +1 -0
  453. package/src/tests/remote-thread-list-reactive-threadId.test.ts +51 -0
  454. package/src/tests/thread-list-runtime-getLoadThreadsPromise.test.ts +1 -0
  455. package/src/tests/thread-switch-events.test.tsx +78 -0
  456. package/src/tests/tools-scope-migration.test.tsx +28 -0
  457. package/src/tests/useRemoteThreadListRuntime-controlled.test.tsx +43 -0
  458. package/src/types/attachment.ts +4 -0
  459. package/src/types/index.ts +1 -0
  460. package/src/types/message.ts +8 -0
  461. package/src/utils/abortable-iterable.test.ts +328 -0
  462. package/src/utils/abortable-iterable.ts +104 -0
  463. package/src/utils/composite-context-provider.test.ts +25 -0
  464. package/src/utils/composite-context-provider.ts +23 -2
  465. package/src/utils/getGroupStatus.test.ts +70 -4
  466. package/src/utils/getGroupStatus.ts +35 -12
  467. package/src/utils/record.test.ts +48 -0
  468. package/src/utils/record.ts +11 -0
  469. package/src/utils/wire-media.test.ts +10 -0
  470. package/src/utils/wire-media.ts +6 -2
@@ -11,6 +11,7 @@ import {
11
11
  type MessageStateBinding,
12
12
  } from "./message-runtime";
13
13
  import { toMessagePartStatus } from "../../utils/normalizePartStatus";
14
+ import { convertExternalMessageChunk } from "../utils/external-message-conversion";
14
15
 
15
16
  const messagePath = {
16
17
  ref: "threads.main.messages[0]",
@@ -256,6 +257,80 @@ describe("toMessagePartStatus", () => {
256
257
  });
257
258
 
258
259
  describe("MessageRuntimeImpl paths", () => {
260
+ it.each([undefined, ""])(
261
+ "looks up separate tool calls with ID %s without breaking provider result matching",
262
+ (toolCallId) => {
263
+ const id = toolCallId === undefined ? {} : { toolCallId };
264
+ const converted = convertExternalMessageChunk(
265
+ {
266
+ inputs: [{}],
267
+ outputs: [
268
+ {
269
+ role: "assistant",
270
+ content: [
271
+ { type: "tool-call", ...id, toolName: "weather", args: {} },
272
+ { type: "tool-call", ...id, toolName: "search", args: {} },
273
+ {
274
+ type: "tool-call",
275
+ toolCallId: "provider-call",
276
+ toolName: "calendar",
277
+ args: { day: "Monday" },
278
+ },
279
+ ],
280
+ },
281
+ {
282
+ role: "assistant",
283
+ content: [
284
+ {
285
+ type: "tool-call",
286
+ toolCallId: "provider-call",
287
+ toolName: "calendar",
288
+ args: { day: "Tuesday" },
289
+ },
290
+ ],
291
+ },
292
+ {
293
+ role: "tool",
294
+ toolCallId: "provider-call",
295
+ toolName: "calendar",
296
+ result: "Meeting at noon",
297
+ },
298
+ ],
299
+ },
300
+ 0,
301
+ 1,
302
+ false,
303
+ undefined,
304
+ );
305
+ const runtime = new MessageRuntimeImpl(
306
+ {
307
+ ...messageBinding,
308
+ getState: () => ({ ...message, ...converted }),
309
+ },
310
+ threadBinding,
311
+ );
312
+ const calls = converted.content.filter(
313
+ (part) => part.type === "tool-call",
314
+ );
315
+
316
+ expect(
317
+ calls.map((call) =>
318
+ runtime.getMessagePartByToolCallId(call.toolCallId).getState(),
319
+ ),
320
+ ).toMatchObject([
321
+ { type: "tool-call", toolName: "weather" },
322
+ { type: "tool-call", toolName: "search" },
323
+ {
324
+ type: "tool-call",
325
+ toolCallId: "provider-call",
326
+ toolName: "calendar",
327
+ args: { day: "Tuesday" },
328
+ result: "Meeting at noon",
329
+ },
330
+ ]);
331
+ },
332
+ );
333
+
259
334
  it("appends nested selectors to the message path", () => {
260
335
  const runtime = new MessageRuntimeImpl(messageBinding, threadBinding);
261
336
 
@@ -30,12 +30,17 @@ import type { ThreadListItemStatus } from "../interfaces/thread-list-runtime-cor
30
30
 
31
31
  export type { ThreadListItemState, ThreadListItemStatus };
32
32
 
33
+ export type ThreadListItemGenerateTitleOptions = {
34
+ /** Marks a generation started by the automatic title trigger. */
35
+ automatic?: boolean;
36
+ };
37
+
33
38
  export type ThreadListItemRuntime = {
34
39
  readonly path: ThreadListItemRuntimePath;
35
40
  getState(): ThreadListItemState;
36
41
 
37
42
  initialize(): Promise<{ remoteId: string; externalId: string | undefined }>;
38
- generateTitle(): Promise<void>;
43
+ generateTitle(options?: ThreadListItemGenerateTitleOptions): Promise<void>;
39
44
 
40
45
  switchTo(options?: { unarchive?: boolean }): Promise<void>;
41
46
  rename(newTitle: string): Promise<void>;
@@ -147,9 +152,11 @@ export class ThreadListItemRuntimeImpl implements ThreadListItemRuntime {
147
152
  return this._threadListBinding.initialize(state.id);
148
153
  }
149
154
 
150
- public generateTitle(): Promise<void> {
155
+ public generateTitle(
156
+ options?: ThreadListItemGenerateTitleOptions,
157
+ ): Promise<void> {
151
158
  const state = this._core.getState();
152
- return this._threadListBinding.generateTitle(state.id);
159
+ return this._threadListBinding.generateTitle(state.id, options);
153
160
  }
154
161
 
155
162
  public unstable_on<E extends ThreadListItemEventType>(
@@ -15,6 +15,7 @@ import {
15
15
  type ThreadListItemRuntime,
16
16
  ThreadListItemRuntimeImpl,
17
17
  type ThreadListItemState,
18
+ type ThreadListItemStateBinding,
18
19
  } from "./thread-list-item-runtime";
19
20
  import {
20
21
  type ThreadListItemRuntimeBinding,
@@ -32,6 +33,8 @@ export type ThreadListState = {
32
33
  readonly threadIds: readonly string[];
33
34
  readonly archivedThreadIds: readonly string[];
34
35
  readonly isLoading: boolean;
36
+ /** The error thrown by the most recent thread list load that failed, cleared when a later load starts. */
37
+ readonly loadError: unknown;
35
38
  readonly isLoadingMore: boolean;
36
39
  readonly hasMore: boolean;
37
40
  readonly threadItems: Readonly<
@@ -97,6 +100,7 @@ const getThreadListState = (
97
100
  threadIds: threadList.threadIds,
98
101
  archivedThreadIds: threadList.archivedThreadIds,
99
102
  isLoading: threadList.isLoading,
103
+ loadError: threadList.loadError,
100
104
  isLoadingMore: threadList.isLoadingMore ?? false,
101
105
  hasMore: threadList.hasMore ?? false,
102
106
  threadItems: threadList.threadItems,
@@ -250,6 +254,21 @@ export class ThreadListRuntimeImpl implements ThreadListRuntime {
250
254
  return this._mainThreadListItemRuntime;
251
255
  }
252
256
 
257
+ private _createItemStateBinding(
258
+ threadId: string,
259
+ ): ThreadListItemStateBinding {
260
+ return new ShallowMemoizeSubject({
261
+ path: {
262
+ ref: `threadItems[threadId=${threadId}]`,
263
+ threadSelector: { type: "threadId", threadId },
264
+ },
265
+ getState: () => {
266
+ return getThreadListItemState(this._core, threadId);
267
+ },
268
+ subscribe: (callback) => this._core.subscribe(callback),
269
+ });
270
+ }
271
+
253
272
  public getById(threadId: string) {
254
273
  return new this._runtimeFactory(
255
274
  new NestedSubscriptionSubject({
@@ -260,7 +279,7 @@ export class ThreadListRuntimeImpl implements ThreadListRuntime {
260
279
  getState: () => this._core.getThreadRuntimeCore(threadId),
261
280
  subscribe: (callback) => this._core.subscribe(callback),
262
281
  }),
263
- this.mainItem,
282
+ this._createItemStateBinding(threadId),
264
283
  );
265
284
  }
266
285
 
@@ -301,16 +320,7 @@ export class ThreadListRuntimeImpl implements ThreadListRuntime {
301
320
 
302
321
  public getItemById(threadId: string) {
303
322
  return new ThreadListItemRuntimeImpl(
304
- new ShallowMemoizeSubject({
305
- path: {
306
- ref: `threadItems[threadId=${threadId}]`,
307
- threadSelector: { type: "threadId", threadId },
308
- },
309
- getState: () => {
310
- return getThreadListItemState(this._core, threadId);
311
- },
312
- subscribe: (callback) => this._core.subscribe(callback),
313
- }),
323
+ this._createItemStateBinding(threadId),
314
324
  this._core,
315
325
  );
316
326
  }
@@ -0,0 +1,136 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { LocalRuntimeCore } from "../../runtimes/local/local-runtime-core";
3
+ import { ExternalStoreRuntimeCore } from "../../runtimes/external-store/external-store-runtime-core";
4
+ import { ReadonlyThreadRuntimeCore } from "../../runtimes/readonly/ReadonlyThreadRuntimeCore";
5
+ import { AssistantRuntimeImpl } from "./assistant-runtime";
6
+ import {
7
+ ThreadRuntimeImpl,
8
+ type ThreadListItemRuntimeBinding,
9
+ type ThreadRuntimeCoreBinding,
10
+ } from "./thread-runtime";
11
+
12
+ describe("ThreadRuntime.append", () => {
13
+ it.each([
14
+ { parent: { parentId: null }, expectedParent: null, visible: ["new"] },
15
+ {
16
+ parent: {},
17
+ expectedParent: "tail",
18
+ visible: ["root", "tail", "new"],
19
+ },
20
+ {
21
+ parent: { parentId: "root" },
22
+ expectedParent: "root",
23
+ visible: ["root", "new"],
24
+ },
25
+ ])(
26
+ "selects the branch under $expectedParent",
27
+ ({ parent, expectedParent, visible }) => {
28
+ const core = new LocalRuntimeCore(
29
+ { adapters: { chatModel: { run: async () => ({ content: [] }) } } },
30
+ [
31
+ { id: "root", role: "user", content: "root" },
32
+ { id: "tail", role: "assistant", content: "tail" },
33
+ ],
34
+ );
35
+ const thread = new AssistantRuntimeImpl(core).thread;
36
+
37
+ thread.append({
38
+ ...parent,
39
+ content: [{ type: "text", text: "new" }],
40
+ startRun: false,
41
+ });
42
+
43
+ expect(
44
+ thread.getState().messages.map((message) => message.content),
45
+ ).toEqual(visible.map((text) => [{ type: "text", text }]));
46
+ expect(thread.export().messages.at(-1)?.parentId).toBe(expectedParent);
47
+ },
48
+ );
49
+ });
50
+
51
+ describe("ThreadRuntime.append with an external store", () => {
52
+ it("routes an explicit root parent to onEdit instead of onNew", async () => {
53
+ const onNew = vi.fn(async () => {});
54
+ const onEdit = vi.fn(async () => {});
55
+ const core = new ExternalStoreRuntimeCore({
56
+ messages: [
57
+ {
58
+ id: "old",
59
+ role: "user",
60
+ content: [{ type: "text", text: "old" }],
61
+ createdAt: new Date(0),
62
+ attachments: [],
63
+ metadata: { custom: {} },
64
+ },
65
+ ],
66
+ onNew,
67
+ onEdit,
68
+ });
69
+ const thread = new AssistantRuntimeImpl(core).thread;
70
+
71
+ thread.append({
72
+ parentId: null,
73
+ content: [{ type: "text", text: "new root" }],
74
+ startRun: false,
75
+ });
76
+
77
+ await vi.waitFor(() =>
78
+ expect(onEdit).toHaveBeenCalledExactlyOnceWith(
79
+ expect.objectContaining({ parentId: null }),
80
+ ),
81
+ );
82
+ expect(onNew).not.toHaveBeenCalled();
83
+ });
84
+ });
85
+
86
+ describe("ThreadRuntime state subscriptions", () => {
87
+ it("tears down every source before reconnecting after an error", () => {
88
+ const core = new ReadonlyThreadRuntimeCore();
89
+ const cleanupError = new Error("thread cleanup failed");
90
+ const threadCleanup = vi.fn(() => {
91
+ throw cleanupError;
92
+ });
93
+ const itemCleanup = vi.fn();
94
+ let threadSubscriptions = 0;
95
+ let itemSubscriptions = 0;
96
+ const path = {
97
+ ref: "test.thread",
98
+ threadSelector: { type: "main" as const },
99
+ };
100
+ const runtime = new ThreadRuntimeImpl(
101
+ {
102
+ path,
103
+ getState: () => core,
104
+ subscribe: () => {
105
+ threadSubscriptions += 1;
106
+ return threadCleanup;
107
+ },
108
+ outerSubscribe: () => () => {},
109
+ } satisfies ThreadRuntimeCoreBinding,
110
+ {
111
+ path,
112
+ getState: () => ({
113
+ id: "test",
114
+ remoteId: undefined,
115
+ externalId: undefined,
116
+ isMain: true,
117
+ isRunning: false,
118
+ status: "regular",
119
+ title: undefined,
120
+ }),
121
+ subscribe: () => {
122
+ itemSubscriptions += 1;
123
+ return itemCleanup;
124
+ },
125
+ } satisfies ThreadListItemRuntimeBinding,
126
+ );
127
+
128
+ const unsubscribe = runtime.subscribe(() => {});
129
+ expect(() => unsubscribe()).toThrow(cleanupError);
130
+ expect(itemCleanup).toHaveBeenCalledOnce();
131
+
132
+ runtime.subscribe(() => {});
133
+ expect(threadSubscriptions).toBe(2);
134
+ expect(itemSubscriptions).toBe(2);
135
+ });
136
+ });
@@ -18,6 +18,7 @@ import {
18
18
  } from "./message-runtime";
19
19
  import { NestedSubscriptionSubject } from "../../subscribable/subscribable";
20
20
  import {
21
+ runCleanups,
21
22
  ShallowMemoizeSubject,
22
23
  SKIP_UPDATE,
23
24
  } from "../../subscribable/subscribable";
@@ -77,6 +78,10 @@ const toStartRunConfig = (message: CreateStartRunConfig): StartRunConfig => {
77
78
  export type CreateAppendMessage =
78
79
  | string
79
80
  | {
81
+ /**
82
+ * An omitted value or `undefined` selects the current tail.
83
+ * `null` selects a root branch.
84
+ */
80
85
  parentId?: string | null | undefined;
81
86
  sourceId?: string | null | undefined;
82
87
  role?: AppendMessage["role"] | undefined;
@@ -107,7 +112,10 @@ const toAppendMessage = (
107
112
 
108
113
  return {
109
114
  createdAt: message.createdAt ?? new Date(),
110
- parentId: message.parentId ?? messages.at(-1)?.id ?? null,
115
+ parentId:
116
+ message.parentId === undefined
117
+ ? (messages.at(-1)?.id ?? null)
118
+ : message.parentId,
111
119
  sourceId: message.sourceId ?? null,
112
120
  role: message.role ?? "user",
113
121
  content: message.content,
@@ -365,10 +373,7 @@ export class ThreadRuntimeImpl implements ThreadRuntime {
365
373
  subscribe: (callback) => {
366
374
  const sub1 = threadBinding.subscribe(callback);
367
375
  const sub2 = threadListItemBinding.subscribe(callback);
368
- return () => {
369
- sub1();
370
- sub2();
371
- };
376
+ return () => runCleanups([sub1, sub2]);
372
377
  },
373
378
  });
374
379
 
@@ -1,4 +1,5 @@
1
1
  import {
2
+ isAttachmentComplete,
2
3
  isCreateAttachment,
3
4
  type Attachment,
4
5
  type CompleteAttachment,
@@ -34,9 +35,6 @@ import {
34
35
  drainAttachmentAdd,
35
36
  } from "../utils/attachment-add-operations";
36
37
 
37
- const isAttachmentComplete = (a: Attachment): a is CompleteAttachment =>
38
- a.status.type === "complete";
39
-
40
38
  export abstract class BaseComposerRuntimeCore
41
39
  extends BaseSubscribable
42
40
  implements ComposerRuntimeCore
@@ -161,6 +159,7 @@ export abstract class BaseComposerRuntimeCore
161
159
  private _emptyTextAndAttachments() {
162
160
  this._attachments = [];
163
161
  this._text = "";
162
+ this._rebaseDictation("");
164
163
  this._notifySubscribers();
165
164
  }
166
165
 
@@ -168,7 +167,7 @@ export abstract class BaseComposerRuntimeCore
168
167
  const adapter = this.getAttachmentAdapter();
169
168
  if (adapter) {
170
169
  const pending = this._attachments.filter((a) => !isAttachmentComplete(a));
171
- await Promise.all(pending.map((a) => adapter.remove(a)));
170
+ await Promise.all(pending.map(async (a) => adapter.remove(a)));
172
171
  }
173
172
  }
174
173
 
@@ -204,6 +203,10 @@ export abstract class BaseComposerRuntimeCore
204
203
 
205
204
  public async clearAttachments() {
206
205
  this._cancelAllAttachmentAdds();
206
+ if (this._isSending) {
207
+ for (const attachment of this._attachments)
208
+ this._removedDuringSend.add(attachment.id);
209
+ }
207
210
  const task = this._onClearAttachments();
208
211
  this.setAttachments([]);
209
212
 
@@ -214,8 +217,13 @@ export abstract class BaseComposerRuntimeCore
214
217
  if (!this.canSend || this._isSending) return;
215
218
 
216
219
  if (this._dictationSession) {
217
- this._dictationSession.cancel();
218
- this._cleanupDictation();
220
+ try {
221
+ this._dictationSession.cancel();
222
+ } catch (error) {
223
+ console.error("[assistant-ui] Dictation session cancel threw", error);
224
+ } finally {
225
+ this._cleanupDictation();
226
+ }
219
227
  }
220
228
 
221
229
  const adapter = this.getAttachmentAdapter();
@@ -301,7 +309,10 @@ export abstract class BaseComposerRuntimeCore
301
309
  void sendTask.catch((error) => {
302
310
  this._restoreUnsentDraft(error, generation, draft);
303
311
  });
304
- this._notifyEventSubscribers("send", {});
312
+ this._notifyEventSubscribers("send", {
313
+ chars: text.length,
314
+ attachments: finalAttachments.length,
315
+ });
305
316
  }
306
317
 
307
318
  /**
@@ -417,6 +428,7 @@ export abstract class BaseComposerRuntimeCore
417
428
  message,
418
429
  undefined,
419
430
  err,
431
+ fileOrAttachment.contentType,
420
432
  );
421
433
  throw err;
422
434
  }
@@ -431,7 +443,9 @@ export abstract class BaseComposerRuntimeCore
431
443
  };
432
444
  this._attachments = [...this._attachments, a];
433
445
  this._notifySubscribers();
434
- this._notifyEventSubscribers("attachmentAdd", {});
446
+ this._notifyEventSubscribers("attachmentAdd", {
447
+ ...(a.contentType ? { contentType: a.contentType } : undefined),
448
+ });
435
449
  return;
436
450
  }
437
451
 
@@ -439,7 +453,13 @@ export abstract class BaseComposerRuntimeCore
439
453
  if (!adapter) {
440
454
  const message = "Attachments are not supported";
441
455
  const err = new Error(message);
442
- this._safeEmitAttachmentAddError("no-adapter", message, undefined, err);
456
+ this._safeEmitAttachmentAddError(
457
+ "no-adapter",
458
+ message,
459
+ undefined,
460
+ err,
461
+ fileOrAttachment.type,
462
+ );
443
463
  throw err;
444
464
  }
445
465
 
@@ -451,7 +471,13 @@ export abstract class BaseComposerRuntimeCore
451
471
  ) {
452
472
  const message = `File type ${fileOrAttachment.type || "unknown"} is not accepted. Accepted types: ${adapter.accept}`;
453
473
  const err = new Error(message);
454
- this._safeEmitAttachmentAddError("not-accepted", message, undefined, err);
474
+ this._safeEmitAttachmentAddError(
475
+ "not-accepted",
476
+ message,
477
+ undefined,
478
+ err,
479
+ fileOrAttachment.type,
480
+ );
455
481
  throw err;
456
482
  }
457
483
 
@@ -501,6 +527,7 @@ export abstract class BaseComposerRuntimeCore
501
527
  e instanceof Error ? e.message : String(e),
502
528
  lastAttachment?.id,
503
529
  e instanceof Error ? e : undefined,
530
+ lastAttachment?.contentType || fileOrAttachment.type,
504
531
  );
505
532
  throw e;
506
533
  } finally {
@@ -517,9 +544,17 @@ export abstract class BaseComposerRuntimeCore
517
544
  lastAttachment.status.message ??
518
545
  "Attachment upload did not complete successfully.",
519
546
  lastAttachment.id,
547
+ undefined,
548
+ lastAttachment.contentType || fileOrAttachment.type,
520
549
  );
521
550
  } else {
522
- this._notifyEventSubscribers("attachmentAdd", {});
551
+ this._notifyEventSubscribers("attachmentAdd", {
552
+ ...(lastAttachment?.contentType
553
+ ? { contentType: lastAttachment.contentType }
554
+ : fileOrAttachment.type
555
+ ? { contentType: fileOrAttachment.type }
556
+ : undefined),
557
+ });
523
558
  }
524
559
  }
525
560
 
@@ -528,6 +563,7 @@ export abstract class BaseComposerRuntimeCore
528
563
  message: string,
529
564
  attachmentId?: string,
530
565
  error?: Error,
566
+ contentType?: string,
531
567
  ) {
532
568
  try {
533
569
  this._notifyEventSubscribers("attachmentAddError", {
@@ -535,6 +571,7 @@ export abstract class BaseComposerRuntimeCore
535
571
  message,
536
572
  ...(attachmentId !== undefined && { attachmentId }),
537
573
  ...(error !== undefined && { error }),
574
+ ...(contentType ? { contentType } : undefined),
538
575
  });
539
576
  } catch (subscriberError) {
540
577
  console.error(
@@ -608,14 +645,11 @@ export abstract class BaseComposerRuntimeCore
608
645
  throw new Error("Dictation adapter not configured");
609
646
  }
610
647
 
648
+ const isReplacing = this._dictationSession !== undefined;
611
649
  if (this._dictationSession) {
612
- for (const unsub of this._dictationUnsubscribes) {
613
- unsub();
614
- }
615
- this._dictationUnsubscribes = [];
616
650
  const oldSession = this._dictationSession;
617
- oldSession.stop().catch(() => {});
618
- this._dictationSession = undefined;
651
+ this._cleanupDictation({ notify: false });
652
+ this._stopDictationSession(oldSession);
619
653
  }
620
654
 
621
655
  const inputDisabled = adapter.disableInputDuringDictation ?? false;
@@ -623,7 +657,22 @@ export abstract class BaseComposerRuntimeCore
623
657
  this._dictationBaseText = this._text;
624
658
  this._currentInterimText = "";
625
659
 
626
- const session = adapter.listen();
660
+ let session: DictationAdapter.Session;
661
+ try {
662
+ session = adapter.listen();
663
+ } catch (error) {
664
+ if (isReplacing) {
665
+ try {
666
+ this._notifySubscribers();
667
+ } catch (notifyError) {
668
+ console.error(
669
+ "[assistant-ui] Dictation replacement rollback notification threw",
670
+ notifyError,
671
+ );
672
+ }
673
+ }
674
+ throw error;
675
+ }
627
676
  this._dictationSession = session;
628
677
  const sessionId = ++this._dictationSessionIdCounter;
629
678
  this._activeDictationSessionId = sessionId;
@@ -701,27 +750,59 @@ export abstract class BaseComposerRuntimeCore
701
750
  const session = this._dictationSession;
702
751
  const sessionId = this._activeDictationSessionId;
703
752
  const cleanup = () => this._cleanupDictation({ sessionId });
704
- void session.stop().then(cleanup, cleanup);
753
+ this._stopDictationSession(session, cleanup);
754
+ }
755
+
756
+ private _stopDictationSession(
757
+ session: DictationAdapter.Session,
758
+ onSettled: () => void = () => {},
759
+ ): void {
760
+ let task: Promise<void>;
761
+ try {
762
+ task = session.stop();
763
+ } catch (error) {
764
+ console.error("[assistant-ui] Dictation session stop threw", error);
765
+ onSettled();
766
+ return;
767
+ }
768
+
769
+ void task.then(onSettled, (error) => {
770
+ console.error("[assistant-ui] Dictation session stop rejected", error);
771
+ onSettled();
772
+ });
705
773
  }
706
774
 
707
- private _cleanupDictation(options?: { sessionId: number | undefined }): void {
775
+ private _cleanupDictation(options?: {
776
+ sessionId?: number | undefined;
777
+ notify?: boolean | undefined;
778
+ }): void {
708
779
  const isStaleSession =
709
780
  options?.sessionId !== undefined &&
710
781
  options.sessionId !== this._activeDictationSessionId;
711
782
  if (isStaleSession || this._isCleaningDictation) return;
712
783
 
713
784
  this._isCleaningDictation = true;
714
- try {
715
- for (const unsub of this._dictationUnsubscribes) {
716
- unsub();
785
+ const runCleanup = (cleanup: () => void) => {
786
+ try {
787
+ cleanup();
788
+ } catch (error) {
789
+ console.error("[assistant-ui] Dictation cleanup threw", error);
717
790
  }
791
+ };
792
+
793
+ try {
794
+ const unsubscribes = this._dictationUnsubscribes;
718
795
  this._dictationUnsubscribes = [];
719
796
  this._dictationSession = undefined;
720
797
  this._activeDictationSessionId = undefined;
721
798
  this._dictation = undefined;
722
799
  this._dictationBaseText = "";
723
800
  this._currentInterimText = "";
724
- this._notifySubscribers();
801
+
802
+ for (const unsubscribe of unsubscribes) runCleanup(unsubscribe);
803
+ if (options?.notify !== false) {
804
+ runCleanup(() => this._notifySubscribers());
805
+ }
725
806
  } finally {
726
807
  this._isCleaningDictation = false;
727
808
  }