@assistant-ui/core 0.3.16 → 0.3.17

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 (305) hide show
  1. package/dist/index.d.ts +2 -2
  2. package/dist/index.js +2 -2
  3. package/dist/index.js.map +1 -1
  4. package/dist/internal.d.ts +2 -1
  5. package/dist/internal.js +2 -1
  6. package/dist/model-context/frame/provider.d.ts +3 -0
  7. package/dist/model-context/frame/provider.d.ts.map +1 -1
  8. package/dist/model-context/frame/provider.js +71 -21
  9. package/dist/model-context/frame/provider.js.map +1 -1
  10. package/dist/model-context/tool-call-text.d.ts +26 -0
  11. package/dist/model-context/tool-call-text.d.ts.map +1 -0
  12. package/dist/model-context/tool-call-text.js +18 -0
  13. package/dist/model-context/tool-call-text.js.map +1 -0
  14. package/dist/react/RuntimeAdapter.js +1 -1
  15. package/dist/react/adapters/LocalStorageThreadListAdapter.d.ts.map +1 -1
  16. package/dist/react/adapters/LocalStorageThreadListAdapter.js +1 -1
  17. package/dist/react/adapters/LocalStorageThreadListAdapter.js.map +1 -1
  18. package/dist/react/client/AdaptedRemoteThread.js +1 -1
  19. package/dist/react/client/InMemoryThreadList.js +1 -1
  20. package/dist/react/client/Interactables.js +1 -1
  21. package/dist/react/client/RemoteThreadList.d.ts +15 -0
  22. package/dist/react/client/RemoteThreadList.d.ts.map +1 -1
  23. package/dist/react/client/RemoteThreadList.js +240 -138
  24. package/dist/react/client/RemoteThreadList.js.map +1 -1
  25. package/dist/react/client/Tools.d.ts.map +1 -1
  26. package/dist/react/client/Tools.js +6 -2
  27. package/dist/react/client/Tools.js.map +1 -1
  28. package/dist/react/index.d.ts +2 -1
  29. package/dist/react/index.js +2 -1
  30. package/dist/react/interactables-legacy/Interactables.js +4 -4
  31. package/dist/react/interactables-legacy/Interactables.js.map +1 -1
  32. package/dist/react/model-context/toolbox.d.ts +2 -14
  33. package/dist/react/model-context/toolbox.d.ts.map +1 -1
  34. package/dist/react/model-context/toolbox.js +1 -13
  35. package/dist/react/model-context/toolbox.js.map +1 -1
  36. package/dist/react/model-context/useAssistantContext.js +37 -7
  37. package/dist/react/model-context/useAssistantContext.js.map +1 -1
  38. package/dist/react/model-context/useAuiToolOverrides.js +31 -5
  39. package/dist/react/model-context/useAuiToolOverrides.js.map +1 -1
  40. package/dist/react/model-context/useInlineRender.d.ts.map +1 -1
  41. package/dist/react/model-context/useInlineRender.js +10 -36
  42. package/dist/react/model-context/useInlineRender.js.map +1 -1
  43. package/dist/react/primitive-hooks/useMessageError.d.ts.map +1 -1
  44. package/dist/react/primitive-hooks/useMessageError.js +2 -8
  45. package/dist/react/primitive-hooks/useMessageError.js.map +1 -1
  46. package/dist/react/primitive-hooks/useThreadListLoadMore.d.ts.map +1 -1
  47. package/dist/react/primitive-hooks/useThreadListLoadMore.js +2 -4
  48. package/dist/react/primitive-hooks/useThreadListLoadMore.js.map +1 -1
  49. package/dist/react/primitives/composer/ComposerAttachments.d.ts.map +1 -1
  50. package/dist/react/primitives/composer/ComposerAttachments.js +4 -3
  51. package/dist/react/primitives/composer/ComposerAttachments.js.map +1 -1
  52. package/dist/react/primitives/composer/ComposerQueue.d.ts.map +1 -1
  53. package/dist/react/primitives/composer/ComposerQueue.js +4 -3
  54. package/dist/react/primitives/composer/ComposerQueue.js.map +1 -1
  55. package/dist/react/primitives/message/MessageAttachments.d.ts.map +1 -1
  56. package/dist/react/primitives/message/MessageAttachments.js +7 -6
  57. package/dist/react/primitives/message/MessageAttachments.js.map +1 -1
  58. package/dist/react/primitives/message/MessageGroupedParts.js +2 -2
  59. package/dist/react/primitives/message/MessageGroupedParts.js.map +1 -1
  60. package/dist/react/primitives/message/MessageParts.js +3 -3
  61. package/dist/react/primitives/message/MessageParts.js.map +1 -1
  62. package/dist/react/primitives/threadList/ThreadListItems.d.ts.map +1 -1
  63. package/dist/react/primitives/threadList/ThreadListItems.js +5 -4
  64. package/dist/react/primitives/threadList/ThreadListItems.js.map +1 -1
  65. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts +6 -4
  66. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
  67. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +44 -22
  68. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
  69. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +6 -5
  70. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
  71. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +79 -62
  72. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
  73. package/dist/react/runtimes/RemoteThreadResource.d.ts +1 -6
  74. package/dist/react/runtimes/RemoteThreadResource.d.ts.map +1 -1
  75. package/dist/react/runtimes/RemoteThreadResource.js +3 -3
  76. package/dist/react/runtimes/RemoteThreadResource.js.map +1 -1
  77. package/dist/react/runtimes/assistant-transport/useLatestRef.js +2 -2
  78. package/dist/react/runtimes/assistant-transport/useLatestRef.js.map +1 -1
  79. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
  80. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +23 -18
  81. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
  82. package/dist/react/runtimes/cloud/auiV0.d.ts +5 -1
  83. package/dist/react/runtimes/cloud/auiV0.d.ts.map +1 -1
  84. package/dist/react/runtimes/cloud/auiV0.js.map +1 -1
  85. package/dist/react/runtimes/cloud/createCloudThreadListAdapter.d.ts +29 -0
  86. package/dist/react/runtimes/cloud/createCloudThreadListAdapter.d.ts.map +1 -0
  87. package/dist/react/runtimes/cloud/createCloudThreadListAdapter.js +159 -0
  88. package/dist/react/runtimes/cloud/createCloudThreadListAdapter.js.map +1 -0
  89. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.d.ts +1 -9
  90. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.d.ts.map +1 -1
  91. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js +16 -153
  92. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js.map +1 -1
  93. package/dist/react/runtimes/external-message-converter.js +1 -1
  94. package/dist/react/runtimes/external-message-converter.js.map +1 -1
  95. package/dist/react/runtimes/useRemoteThreadListRuntime.d.ts.map +1 -1
  96. package/dist/react/runtimes/useRemoteThreadListRuntime.js +14 -6
  97. package/dist/react/runtimes/useRemoteThreadListRuntime.js.map +1 -1
  98. package/dist/react/types/MessagePartComponentTypes.d.ts +7 -3
  99. package/dist/react/types/MessagePartComponentTypes.d.ts.map +1 -1
  100. package/dist/react/types/scopes/tools.d.ts +2 -0
  101. package/dist/react/types/scopes/tools.d.ts.map +1 -1
  102. package/dist/runtime/api/message-part-runtime.d.ts +2 -2
  103. package/dist/runtime/api/message-part-runtime.d.ts.map +1 -1
  104. package/dist/runtime/api/message-part-runtime.js +1 -1
  105. package/dist/runtime/api/message-part-runtime.js.map +1 -1
  106. package/dist/runtime/api/thread-list-runtime.d.ts +9 -1
  107. package/dist/runtime/api/thread-list-runtime.d.ts.map +1 -1
  108. package/dist/runtime/api/thread-list-runtime.js +5 -0
  109. package/dist/runtime/api/thread-list-runtime.js.map +1 -1
  110. package/dist/runtime/api/thread-runtime.d.ts +1 -1
  111. package/dist/runtime/base/base-thread-runtime-core.d.ts +2 -2
  112. package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
  113. package/dist/runtime/base/base-thread-runtime-core.js +2 -2
  114. package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
  115. package/dist/runtime/interfaces/thread-list-runtime-core.d.ts +14 -2
  116. package/dist/runtime/interfaces/thread-list-runtime-core.d.ts.map +1 -1
  117. package/dist/runtime/interfaces/thread-runtime-core.d.ts +15 -1
  118. package/dist/runtime/interfaces/thread-runtime-core.d.ts.map +1 -1
  119. package/dist/runtime/utils/auto-status.d.ts +1 -1
  120. package/dist/runtime/utils/auto-status.d.ts.map +1 -1
  121. package/dist/runtime/utils/auto-status.js +6 -2
  122. package/dist/runtime/utils/auto-status.js.map +1 -1
  123. package/dist/runtime/utils/external-message-conversion.d.ts +3 -2
  124. package/dist/runtime/utils/external-message-conversion.d.ts.map +1 -1
  125. package/dist/runtime/utils/external-message-conversion.js +4 -3
  126. package/dist/runtime/utils/external-message-conversion.js.map +1 -1
  127. package/dist/runtime/utils/resolveToolApprovalResponse.d.ts +6 -3
  128. package/dist/runtime/utils/resolveToolApprovalResponse.d.ts.map +1 -1
  129. package/dist/runtime/utils/resolveToolApprovalResponse.js +12 -3
  130. package/dist/runtime/utils/resolveToolApprovalResponse.js.map +1 -1
  131. package/dist/runtime/utils/thread-message-like.d.ts +2 -10
  132. package/dist/runtime/utils/thread-message-like.d.ts.map +1 -1
  133. package/dist/runtime/utils/thread-message-like.js.map +1 -1
  134. package/dist/runtime/utils/tool-call-tree.d.ts +39 -0
  135. package/dist/runtime/utils/tool-call-tree.d.ts.map +1 -0
  136. package/dist/runtime/utils/tool-call-tree.js +85 -0
  137. package/dist/runtime/utils/tool-call-tree.js.map +1 -0
  138. package/dist/runtimes/external-store/external-store-adapter.d.ts +29 -2
  139. package/dist/runtimes/external-store/external-store-adapter.d.ts.map +1 -1
  140. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts +2 -1
  141. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
  142. package/dist/runtimes/external-store/external-store-thread-runtime-core.js +34 -28
  143. package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
  144. package/dist/runtimes/inert/InertThreadRuntimeCore.d.ts +1 -1
  145. package/dist/runtimes/inert/InertThreadRuntimeCore.d.ts.map +1 -1
  146. package/dist/runtimes/inert/InertThreadRuntimeCore.js.map +1 -1
  147. package/dist/runtimes/local/local-thread-runtime-core.d.ts +1 -1
  148. package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
  149. package/dist/runtimes/local/local-thread-runtime-core.js +3 -1
  150. package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
  151. package/dist/runtimes/remote-thread-list/remote-thread-state.d.ts +1 -1
  152. package/dist/runtimes/remote-thread-list/remote-thread-state.d.ts.map +1 -1
  153. package/dist/runtimes/remote-thread-list/remote-thread-state.js +30 -13
  154. package/dist/runtimes/remote-thread-list/remote-thread-state.js.map +1 -1
  155. package/dist/runtimes/remote-thread-list/title.d.ts +9 -0
  156. package/dist/runtimes/remote-thread-list/title.d.ts.map +1 -0
  157. package/dist/runtimes/remote-thread-list/title.js +6 -0
  158. package/dist/runtimes/remote-thread-list/title.js.map +1 -0
  159. package/dist/runtimes/remote-thread-list/types.d.ts +6 -5
  160. package/dist/runtimes/remote-thread-list/types.d.ts.map +1 -1
  161. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts +31 -8
  162. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts.map +1 -1
  163. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js +97 -60
  164. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js.map +1 -1
  165. package/dist/store/clients/external-thread.d.ts +1 -1
  166. package/dist/store/clients/external-thread.d.ts.map +1 -1
  167. package/dist/store/clients/external-thread.js +11 -4
  168. package/dist/store/clients/external-thread.js.map +1 -1
  169. package/dist/store/clients/single-thread-list.js +1 -1
  170. package/dist/store/clients/suggestions.d.ts.map +1 -1
  171. package/dist/store/clients/suggestions.js +18 -6
  172. package/dist/store/clients/suggestions.js.map +1 -1
  173. package/dist/store/clients/thread-message-client.js +1 -1
  174. package/dist/store/clients/thread-selection-events.js +1 -1
  175. package/dist/store/index.d.ts +2 -1
  176. package/dist/store/index.js +2 -1
  177. package/dist/store/internal.d.ts +2 -2
  178. package/dist/store/internal.js +2 -2
  179. package/dist/store/primitive-predicates.d.ts +4 -1
  180. package/dist/store/primitive-predicates.d.ts.map +1 -1
  181. package/dist/store/primitive-predicates.js +9 -1
  182. package/dist/store/primitive-predicates.js.map +1 -1
  183. package/dist/store/runtime-clients/composer-runtime-client.js +1 -1
  184. package/dist/store/runtime-clients/message-runtime-client.js +1 -1
  185. package/dist/store/runtime-clients/thread-list-item-runtime-client.js +1 -1
  186. package/dist/store/runtime-clients/thread-list-runtime-client.d.ts.map +1 -1
  187. package/dist/store/runtime-clients/thread-list-runtime-client.js +124 -105
  188. package/dist/store/runtime-clients/thread-list-runtime-client.js.map +1 -1
  189. package/dist/store/runtime-clients/thread-runtime-client.js +1 -1
  190. package/dist/store/runtime-clients/useSubscribable.d.ts +3 -1
  191. package/dist/store/runtime-clients/useSubscribable.d.ts.map +1 -1
  192. package/dist/store/runtime-clients/useSubscribable.js +1 -1
  193. package/dist/store/runtime-clients/useSubscribable.js.map +1 -1
  194. package/dist/store/scopes/part.d.ts +6 -3
  195. package/dist/store/scopes/part.d.ts.map +1 -1
  196. package/dist/subscribable/subscribable.d.ts +8 -1
  197. package/dist/subscribable/subscribable.d.ts.map +1 -1
  198. package/dist/subscribable/subscribable.js +24 -16
  199. package/dist/subscribable/subscribable.js.map +1 -1
  200. package/dist/types/message.d.ts +40 -1
  201. package/dist/types/message.d.ts.map +1 -1
  202. package/dist/types/message.js +7 -1
  203. package/dist/types/message.js.map +1 -1
  204. package/package.json +12 -17
  205. package/src/index.ts +6 -1
  206. package/src/internal.ts +8 -0
  207. package/src/model-context/frame/provider.test.ts +217 -1
  208. package/src/model-context/frame/provider.ts +111 -23
  209. package/src/model-context/tool-call-text.test.ts +67 -0
  210. package/src/model-context/tool-call-text.ts +67 -0
  211. package/src/react/AssistantRuntimeProvider.test.tsx +66 -2
  212. package/src/react/adapters/LocalStorageThreadListAdapter.tsx +1 -3
  213. package/src/react/client/RemoteThreadList.background.test.ts +384 -0
  214. package/src/react/client/RemoteThreadList.concurrent.test.tsx +274 -0
  215. package/src/react/client/RemoteThreadList.test.ts +273 -1
  216. package/src/react/client/RemoteThreadList.ts +293 -83
  217. package/src/react/client/Tools.ts +7 -1
  218. package/src/react/index.ts +4 -0
  219. package/src/react/model-context/modelContextHooks.test.tsx +131 -0
  220. package/src/react/model-context/toolbox.test.ts +9 -9
  221. package/src/react/model-context/toolbox.ts +9 -36
  222. package/src/react/model-context/useAssistantContext.ts +4 -2
  223. package/src/react/model-context/useAuiToolOverrides.ts +4 -2
  224. package/src/react/model-context/useInlineRender.test.tsx +48 -0
  225. package/src/react/model-context/useInlineRender.ts +14 -10
  226. package/src/react/primitive-hooks/useMessageError.ts +2 -19
  227. package/src/react/primitive-hooks/useThreadListLoadMore.ts +2 -3
  228. package/src/react/primitives/composer/ComposerAttachments.test.tsx +76 -0
  229. package/src/react/primitives/composer/ComposerAttachments.tsx +9 -4
  230. package/src/react/primitives/composer/ComposerQueue.test.tsx +72 -0
  231. package/src/react/primitives/composer/ComposerQueue.tsx +7 -4
  232. package/src/react/primitives/message/MessageAttachments.test.tsx +107 -37
  233. package/src/react/primitives/message/MessageAttachments.tsx +10 -7
  234. package/src/react/primitives/message/MessageGroupedParts.tsx +2 -2
  235. package/src/react/primitives/message/MessageParts.tsx +3 -3
  236. package/src/react/primitives/threadList/ThreadListItems.test.tsx +99 -0
  237. package/src/react/primitives/threadList/ThreadListItems.tsx +8 -5
  238. package/src/react/runtimes/RemoteThreadListHookInstanceManager.running.test.tsx +94 -1
  239. package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +72 -31
  240. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.switch-delete.test.ts +169 -0
  241. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +114 -68
  242. package/src/react/runtimes/RemoteThreadResource.ts +1 -4
  243. package/src/react/runtimes/assistant-transport/transport-scheduling.test.ts +51 -2
  244. package/src/react/runtimes/assistant-transport/useLatestRef.ts +2 -2
  245. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.ts +45 -0
  246. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.tsx +65 -1
  247. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +42 -35
  248. package/src/react/runtimes/cloud/auiV0.ts +5 -0
  249. package/src/react/runtimes/cloud/createCloudThreadListAdapter.test.ts +88 -0
  250. package/src/react/runtimes/cloud/createCloudThreadListAdapter.ts +236 -0
  251. package/src/react/runtimes/cloud/useCloudThreadListAdapter.test.tsx +90 -1
  252. package/src/react/runtimes/cloud/useCloudThreadListAdapter.tsx +33 -238
  253. package/src/react/runtimes/external-message-converter.ts +1 -0
  254. package/src/react/runtimes/useRemoteThreadListRuntime.concurrent.test.tsx +216 -0
  255. package/src/react/runtimes/useRemoteThreadListRuntime.ts +24 -6
  256. package/src/react/types/MessagePartComponentTypes.ts +7 -3
  257. package/src/react/types/scopes/tools.ts +2 -0
  258. package/src/runtime/api/message-part-runtime.ts +3 -3
  259. package/src/runtime/api/thread-list-runtime.ts +25 -1
  260. package/src/runtime/base/base-thread-runtime-core.test.ts +94 -3
  261. package/src/runtime/base/base-thread-runtime-core.ts +10 -4
  262. package/src/runtime/interfaces/thread-list-runtime-core.ts +20 -1
  263. package/src/runtime/interfaces/thread-runtime-core.ts +17 -1
  264. package/src/runtime/utils/auto-status.test.ts +57 -0
  265. package/src/runtime/utils/auto-status.ts +13 -1
  266. package/src/runtime/utils/external-message-conversion.test.ts +97 -0
  267. package/src/runtime/utils/external-message-conversion.ts +17 -1
  268. package/src/runtime/utils/resolveToolApprovalResponse.test.ts +73 -0
  269. package/src/runtime/utils/resolveToolApprovalResponse.ts +27 -6
  270. package/src/runtime/utils/thread-message-like.ts +2 -10
  271. package/src/runtime/utils/tool-call-tree.test.ts +191 -0
  272. package/src/runtime/utils/tool-call-tree.ts +97 -0
  273. package/src/runtimes/external-store/external-store-adapter.ts +38 -2
  274. package/src/runtimes/external-store/external-store-thread-runtime-core.ts +56 -33
  275. package/src/runtimes/inert/InertThreadRuntimeCore.ts +1 -1
  276. package/src/runtimes/local/local-thread-runtime-core.test.ts +29 -3
  277. package/src/runtimes/local/local-thread-runtime-core.ts +5 -1
  278. package/src/runtimes/remote-thread-list/remote-thread-state.test.ts +112 -0
  279. package/src/runtimes/remote-thread-list/remote-thread-state.ts +55 -16
  280. package/src/runtimes/remote-thread-list/title.ts +3 -0
  281. package/src/runtimes/remote-thread-list/types.ts +6 -5
  282. package/src/runtimes/tool-invocations/EDGE_CASES.md +110 -5
  283. package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +750 -136
  284. package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +144 -91
  285. package/src/store/clients/external-thread.ts +14 -8
  286. package/src/store/clients/suggestions.test.ts +155 -1
  287. package/src/store/clients/suggestions.ts +42 -34
  288. package/src/store/index.ts +4 -0
  289. package/src/store/internal.ts +2 -0
  290. package/src/store/primitive-predicates.ts +35 -0
  291. package/src/store/runtime-clients/thread-list-runtime-client.ts +16 -2
  292. package/src/store/runtime-clients/useSubscribable.ts +8 -2
  293. package/src/store/scopes/part.ts +6 -3
  294. package/src/subscribable/subscribable.test.ts +50 -0
  295. package/src/subscribable/subscribable.ts +33 -21
  296. package/src/tests/RemoteThreadListThreadListRuntimeCore-load-race.test.ts +111 -0
  297. package/src/tests/RemoteThreadListThreadListRuntimeCore-loadMore.test.ts +78 -0
  298. package/src/tests/RemoteThreadListThreadListRuntimeCore-reload.test.ts +52 -0
  299. package/src/tests/external-store-optimistic-id.test.ts +79 -0
  300. package/src/tests/external-store-repository-instance.test.ts +166 -0
  301. package/src/tests/external-store-thread-runtime-core-adapter.test.ts +22 -16
  302. package/src/tests/external-thread-attachments.test.tsx +85 -1
  303. package/src/tests/remote-thread-list-adapter-switch.test.ts +66 -1
  304. package/src/tests/thread-switch-events.test.tsx +397 -2
  305. package/src/types/message.ts +50 -2
@@ -22,6 +22,7 @@ import {
22
22
  type RuntimeAdapters,
23
23
  } from "./RuntimeAdapterProvider";
24
24
  import { isSilentRuntimeAction } from "../../utils/silent-runtime-action";
25
+ import { isTitleSourceMessage } from "../../runtimes/remote-thread-list/title";
25
26
 
26
27
  export type RemoteThreadListHook = () => AssistantRuntime;
27
28
 
@@ -39,10 +40,6 @@ export type RemoteThreadResourceProps = {
39
40
  ) => void;
40
41
  };
41
42
 
42
- export const isTitleSourceMessage = (message: {
43
- status?: { type: string } | undefined;
44
- }) => message.status?.type !== "running";
45
-
46
43
  export const subscribeToTitleGeneration = (
47
44
  threadRuntime: AssistantRuntime["thread"],
48
45
  itemRuntime: ThreadListItemRuntime,
@@ -1,8 +1,8 @@
1
1
  // @vitest-environment jsdom
2
2
 
3
- import { act, renderHook, waitFor } from "@testing-library/react";
3
+ import { act, render, renderHook, waitFor } from "@testing-library/react";
4
4
  import { describe, expect, it, vi } from "vitest";
5
- import { createElement, StrictMode, useRef } from "react";
5
+ import { createElement, StrictMode, useLayoutEffect, useRef } from "react";
6
6
  import { useCommandQueue } from "./commandQueue";
7
7
  import { useRunManager } from "./runManager";
8
8
  import type { AssistantTransportCommand } from "./types";
@@ -85,6 +85,55 @@ const useTransportSchedulingHarness = (
85
85
  };
86
86
 
87
87
  describe("assistant transport scheduling contracts", () => {
88
+ it("uses current callbacks when scheduled by a descendant layout effect", async () => {
89
+ const onRunA = vi.fn(async () => {});
90
+ const onRunB = vi.fn(async () => {});
91
+ // act flushes passive effects before real microtasks, so preserve the
92
+ // browser's microtask-before-passive-effect ordering at the layout boundary.
93
+ const queueMicrotaskSpy = vi
94
+ .spyOn(globalThis, "queueMicrotask")
95
+ .mockImplementation((callback) => callback());
96
+
97
+ const Scheduler = ({
98
+ schedule,
99
+ enabled,
100
+ }: {
101
+ schedule: () => void;
102
+ enabled: boolean;
103
+ }) => {
104
+ useLayoutEffect(() => {
105
+ if (enabled) schedule();
106
+ }, [enabled, schedule]);
107
+ return null;
108
+ };
109
+ const Probe = ({
110
+ enabled,
111
+ onRun,
112
+ }: {
113
+ enabled: boolean;
114
+ onRun: (signal: AbortSignal) => Promise<void>;
115
+ }) => {
116
+ const runManager = useRunManager({ onRun });
117
+ return createElement(Scheduler, {
118
+ enabled,
119
+ schedule: runManager.schedule,
120
+ });
121
+ };
122
+
123
+ try {
124
+ const view = render(
125
+ createElement(Probe, { enabled: false, onRun: onRunA }),
126
+ );
127
+ view.rerender(createElement(Probe, { enabled: true, onRun: onRunB }));
128
+ await act(async () => {});
129
+
130
+ expect(onRunB).toHaveBeenCalledTimes(1);
131
+ expect(onRunA).not.toHaveBeenCalled();
132
+ } finally {
133
+ queueMicrotaskSpy.mockRestore();
134
+ }
135
+ });
136
+
88
137
  it("runs in single-flight mode and schedules exactly one follow-up run", async () => {
89
138
  const gate = createDeferred();
90
139
  const { result } = renderHook(() =>
@@ -1,8 +1,8 @@
1
- import { useEffect, useRef } from "react";
1
+ import { useInsertionEffect, useRef } from "react";
2
2
 
3
3
  export function useLatestRef<T>(value: T) {
4
4
  const ref = useRef(value);
5
- useEffect(() => {
5
+ useInsertionEffect(() => {
6
6
  ref.current = value;
7
7
  }, [value]);
8
8
  return ref as { current: T };
@@ -31,4 +31,49 @@ describe("extractAuiV0", () => {
31
31
  expect(result?.inputTokens).toBe(1);
32
32
  expect(result?.outputTokens).toBe(2);
33
33
  });
34
+
35
+ it("sums step usage reported under the AI SDK v7 token details", () => {
36
+ const result = extractAuiV0({
37
+ ...auiV0Message({ type: "complete" }),
38
+ metadata: {
39
+ steps: [
40
+ {
41
+ usage: {
42
+ inputTokens: 10,
43
+ outputTokens: 4,
44
+ inputTokenDetails: { cacheReadTokens: 6 },
45
+ outputTokenDetails: { reasoningTokens: 1 },
46
+ },
47
+ },
48
+ {
49
+ usage: {
50
+ inputTokens: 5,
51
+ outputTokens: 2,
52
+ inputTokenDetails: { cacheReadTokens: 3 },
53
+ outputTokenDetails: { reasoningTokens: 1 },
54
+ },
55
+ },
56
+ ],
57
+ },
58
+ });
59
+
60
+ expect(result?.inputTokens).toBe(15);
61
+ expect(result?.outputTokens).toBe(6);
62
+ expect(result?.cachedInputTokens).toBe(9);
63
+ expect(result?.reasoningTokens).toBe(2);
64
+ expect(result?.steps).toEqual([
65
+ {
66
+ input_tokens: 10,
67
+ output_tokens: 4,
68
+ reasoning_tokens: 1,
69
+ cached_input_tokens: 6,
70
+ },
71
+ {
72
+ input_tokens: 5,
73
+ output_tokens: 2,
74
+ reasoning_tokens: 1,
75
+ cached_input_tokens: 3,
76
+ },
77
+ ]);
78
+ });
34
79
  });
@@ -21,12 +21,33 @@ const mocks = vi.hoisted(() => {
21
21
  };
22
22
  return {
23
23
  threadListItem,
24
- threads: { item: vi.fn(() => threadListItem) },
24
+ threads: {
25
+ item: vi.fn(() => threadListItem),
26
+ getState: () => ({ threadItems: [{ id, remoteId }] }),
27
+ },
28
+ } as unknown as import("@assistant-ui/store").AssistantClient;
29
+ };
30
+
31
+ const makeSplitClient = (remoteId: string) => {
32
+ const itemShape = () => ({
33
+ source: "threads",
34
+ getState: () => ({ id: remoteId, remoteId }),
35
+ initialize: async () => ({ remoteId, externalId: undefined }),
36
+ });
37
+ const live = itemShape();
38
+ const listItem = itemShape();
39
+ return {
40
+ threadListItem: live,
41
+ threads: {
42
+ item: vi.fn(() => listItem),
43
+ getState: () => ({ threadItems: [{ id: remoteId, remoteId }] }),
44
+ },
25
45
  } as unknown as import("@assistant-ui/store").AssistantClient;
26
46
  };
27
47
 
28
48
  return {
29
49
  makeClient,
50
+ makeSplitClient,
30
51
  aui: makeClient("thread-1"),
31
52
  };
32
53
  });
@@ -308,4 +329,47 @@ describe("useAssistantCloudThreadHistoryAdapter", () => {
308
329
  expect.anything(),
309
330
  );
310
331
  });
332
+
333
+ it("updates a history-loaded message when the list item identity differs from the live item", async () => {
334
+ mocks.aui = mocks.makeSplitClient("thread-split");
335
+ const cloud = makeCloud();
336
+ (cloud.threads.messages.list as ReturnType<typeof vi.fn>).mockResolvedValue(
337
+ {
338
+ messages: [
339
+ {
340
+ id: "m1",
341
+ parent_id: null,
342
+ format: "test",
343
+ content: { id: "m1" },
344
+ },
345
+ ],
346
+ },
347
+ );
348
+ const cloudRef = { current: cloud };
349
+ const { result } = renderHook(() =>
350
+ useAssistantCloudThreadHistoryAdapter(cloudRef),
351
+ );
352
+ const formatted = result.current.withFormat<
353
+ { id: string },
354
+ Record<string, unknown>
355
+ >({
356
+ format: "test",
357
+ encode: ({ message }) => message,
358
+ decode: ({ parent_id, content }) => ({
359
+ parentId: parent_id,
360
+ message: content as { id: string },
361
+ }),
362
+ getId: (message) => message.id,
363
+ });
364
+
365
+ formatted.pin!();
366
+ await formatted.load();
367
+ await formatted.update!({ parentId: null, message: { id: "m1" } }, "m1");
368
+
369
+ expect(cloud.threads.messages.update).toHaveBeenCalledWith(
370
+ "thread-split",
371
+ "m1",
372
+ expect.anything(),
373
+ );
374
+ });
311
375
  });
@@ -69,7 +69,12 @@ class AssistantCloudThreadHistoryAdapter implements ThreadHistoryAdapter {
69
69
  if (!live.source) return undefined;
70
70
  const id = live.getState().id;
71
71
  if (id === undefined) return undefined;
72
- return this.aui.threads.item({ id });
72
+ // A body can resolve before the list's committed items include its
73
+ // thread; the live item is already the per-thread anchor in that window.
74
+ const listed = this.aui.threads
75
+ .getState()
76
+ .threadItems.some((item) => item.id === id || item.remoteId === id);
77
+ return listed ? this.aui.threads.item({ id }) : live;
73
78
  }
74
79
 
75
80
  withFormat<TMessage, TStorageFormat extends Record<string, unknown>>(
@@ -83,8 +88,6 @@ class AssistantCloudThreadHistoryAdapter implements ThreadHistoryAdapter {
83
88
  return threadListItem;
84
89
  };
85
90
  const resolvePinned = () => threadListItem ?? pinCurrent();
86
- const getFormatted = () =>
87
- createFormattedPersistence(adapter._persistence, formatAdapter);
88
91
  const getTargetFormatted = (item: CloudThreadListItem) =>
89
92
  createFormattedPersistence(adapter.getPersistence(item), formatAdapter);
90
93
  return {
@@ -135,11 +138,14 @@ class AssistantCloudThreadHistoryAdapter implements ThreadHistoryAdapter {
135
138
  );
136
139
  },
137
140
  async load(): Promise<MessageFormatRepository<TMessage>> {
138
- pinCurrent();
141
+ // Loads re-pin and resolve through the pinned item, so the id mapping
142
+ // they populate lives on the same persistence instance later writes
143
+ // resolve, whichever of the list item or the live graft won the pin.
144
+ const pinned = pinCurrent();
139
145
  const live = adapter.aui.threadListItem;
140
146
  const remoteId = live.source ? live.getState().remoteId : undefined;
141
147
  if (!remoteId) return { messages: [] };
142
- return getFormatted().load(remoteId);
148
+ return getTargetFormatted(pinned ?? live).load(remoteId);
143
149
  },
144
150
  };
145
151
  }
@@ -358,14 +364,7 @@ export function extractAuiV0<T>(content: T): TelemetryData | null {
358
364
  }[];
359
365
  metadata?: {
360
366
  modelId?: string;
361
- steps?: readonly {
362
- usage?: {
363
- inputTokens?: number;
364
- outputTokens?: number;
365
- reasoningTokens?: number;
366
- cachedInputTokens?: number;
367
- };
368
- }[];
367
+ steps?: readonly { usage?: RunTelemetryUsageInit }[];
369
368
  custom?: Record<string, unknown> & { modelId?: string };
370
369
  };
371
370
  };
@@ -408,20 +407,23 @@ export function extractAuiV0<T>(content: T): TelemetryData | null {
408
407
  let hasReasoning = false;
409
408
  let hasCachedInput = false;
410
409
  for (const step of steps) {
411
- if (step.usage?.inputTokens != null) {
412
- totalInput += step.usage.inputTokens;
410
+ if (!step.usage) continue;
411
+ const usage = normalizeRunTelemetryUsage(step.usage);
412
+ if (!usage) continue;
413
+ if (usage.inputTokens != null) {
414
+ totalInput += usage.inputTokens;
413
415
  hasInput = true;
414
416
  }
415
- if (step.usage?.outputTokens != null) {
416
- totalOutput += step.usage.outputTokens;
417
+ if (usage.outputTokens != null) {
418
+ totalOutput += usage.outputTokens;
417
419
  hasOutput = true;
418
420
  }
419
- if (step.usage?.reasoningTokens != null) {
420
- totalReasoning += step.usage.reasoningTokens;
421
+ if (usage.reasoningTokens != null) {
422
+ totalReasoning += usage.reasoningTokens;
421
423
  hasReasoning = true;
422
424
  }
423
- if (step.usage?.cachedInputTokens != null) {
424
- totalCachedInput += step.usage.cachedInputTokens;
425
+ if (usage.cachedInputTokens != null) {
426
+ totalCachedInput += usage.cachedInputTokens;
425
427
  hasCachedInput = true;
426
428
  }
427
429
  }
@@ -444,20 +446,25 @@ export function extractAuiV0<T>(content: T): TelemetryData | null {
444
446
 
445
447
  const telemetrySteps: TelemetryStepData[] | undefined =
446
448
  steps && steps.length > 1
447
- ? steps.map((s) => ({
448
- ...(s.usage?.inputTokens != null
449
- ? { input_tokens: s.usage.inputTokens }
450
- : undefined),
451
- ...(s.usage?.outputTokens != null
452
- ? { output_tokens: s.usage.outputTokens }
453
- : undefined),
454
- ...(s.usage?.reasoningTokens != null
455
- ? { reasoning_tokens: s.usage.reasoningTokens }
456
- : undefined),
457
- ...(s.usage?.cachedInputTokens != null
458
- ? { cached_input_tokens: s.usage.cachedInputTokens }
459
- : undefined),
460
- }))
449
+ ? steps.map((s) => {
450
+ const usage = s.usage
451
+ ? normalizeRunTelemetryUsage(s.usage)
452
+ : undefined;
453
+ return {
454
+ ...(usage?.inputTokens != null
455
+ ? { input_tokens: usage.inputTokens }
456
+ : undefined),
457
+ ...(usage?.outputTokens != null
458
+ ? { output_tokens: usage.outputTokens }
459
+ : undefined),
460
+ ...(usage?.reasoningTokens != null
461
+ ? { reasoning_tokens: usage.reasoningTokens }
462
+ : undefined),
463
+ ...(usage?.cachedInputTokens != null
464
+ ? { cached_input_tokens: usage.cachedInputTokens }
465
+ : undefined),
466
+ };
467
+ })
461
468
  : undefined;
462
469
 
463
470
  return {
@@ -2,6 +2,7 @@ import type {
2
2
  MessageStatus,
3
3
  SourceProviderMetadata,
4
4
  ThreadMessage,
5
+ ToolApprovalDisplay,
5
6
  ToolApprovalOption,
6
7
  } from "../../../types/message";
7
8
  import type { CompleteAttachment } from "../../../types/attachment";
@@ -16,11 +17,15 @@ import type { ExportedMessageRepositoryItem } from "../../../runtime/utils/messa
16
17
 
17
18
  type AuiV0ToolApproval = {
18
19
  readonly id: string;
20
+ readonly prompt?: string;
21
+ readonly display?: ToolApprovalDisplay;
22
+ readonly allowFreeform?: boolean;
19
23
  readonly approved?: boolean;
20
24
  readonly reason?: string;
21
25
  readonly isAutomatic?: boolean;
22
26
  readonly options?: readonly ToolApprovalOption[];
23
27
  readonly optionId?: string;
28
+ readonly text?: string;
24
29
  readonly resolution?: "cancelled" | "expired";
25
30
  };
26
31
 
@@ -0,0 +1,88 @@
1
+ // @vitest-environment jsdom
2
+
3
+ import { describe, expect, it, vi } from "vitest";
4
+ import { renderHook } from "@testing-library/react";
5
+ import type { AssistantCloud } from "assistant-cloud";
6
+ import { createCloudThreadListAdapter } from "./createCloudThreadListAdapter";
7
+
8
+ const makeCloud = () =>
9
+ ({
10
+ threads: {
11
+ list: vi.fn(async () => ({ threads: [] })),
12
+ create: vi.fn(async () => ({ thread_id: "remote-1" })),
13
+ update: vi.fn(async () => {}),
14
+ delete: vi.fn(async () => {}),
15
+ get: vi.fn(),
16
+ },
17
+ runs: { stream: vi.fn(async () => new ReadableStream()) },
18
+ }) as unknown as AssistantCloud;
19
+
20
+ describe("createCloudThreadListAdapter", () => {
21
+ it("falls back to an in-memory list without a cloud instance", async () => {
22
+ const create = vi.fn(async () => ({ externalId: "ext-1" }));
23
+ const adapter = createCloudThreadListAdapter({ create });
24
+ expect(await adapter.list()).toEqual({ threads: [] });
25
+ expect(await adapter.initialize("local-1")).toEqual({
26
+ remoteId: "local-1",
27
+ externalId: "ext-1",
28
+ });
29
+ expect(create).toHaveBeenCalledOnce();
30
+ });
31
+
32
+ it("maps the cloud api and reads callbacks through the getter", async () => {
33
+ const cloud = makeCloud();
34
+ const options: {
35
+ cloud: AssistantCloud;
36
+ delete?: (threadId: string) => Promise<void>;
37
+ } = { cloud };
38
+ const adapter = createCloudThreadListAdapter(() => options);
39
+
40
+ await adapter.list();
41
+ expect(cloud.threads.list).toHaveBeenCalledTimes(2);
42
+
43
+ expect(await adapter.initialize("local-1")).toEqual({
44
+ remoteId: "remote-1",
45
+ externalId: undefined,
46
+ });
47
+
48
+ await adapter.rename("remote-1", "Renamed");
49
+ expect(cloud.threads.update).toHaveBeenCalledWith("remote-1", {
50
+ title: "Renamed",
51
+ });
52
+ await adapter.archive("remote-1");
53
+ expect(cloud.threads.update).toHaveBeenCalledWith("remote-1", {
54
+ is_archived: true,
55
+ });
56
+ await adapter.unarchive("remote-1");
57
+ expect(cloud.threads.update).toHaveBeenCalledWith("remote-1", {
58
+ is_archived: false,
59
+ });
60
+
61
+ const onDelete = vi.fn(async () => {});
62
+ options.delete = onDelete;
63
+ await adapter.delete("remote-1");
64
+ expect(onDelete).toHaveBeenCalledWith("remote-1");
65
+ expect(cloud.threads.delete).toHaveBeenCalledWith("remote-1");
66
+
67
+ expect(adapter.unstable_useAdapters).toBeTypeOf("function");
68
+ expect(adapter.unstable_Provider).toBeUndefined();
69
+ });
70
+
71
+ it("constructs stable history and attachment adapters when the hook runs", () => {
72
+ const cloud = makeCloud();
73
+ const adapter = createCloudThreadListAdapter({ cloud });
74
+ const { result, rerender } = renderHook(() =>
75
+ adapter.unstable_useAdapters!(),
76
+ );
77
+ const first = result.current!;
78
+ expect(first.history).toBeDefined();
79
+ expect((first.history as { withFormat?: unknown }).withFormat).toBeTypeOf(
80
+ "function",
81
+ );
82
+ expect(first.attachments).toBeDefined();
83
+
84
+ rerender();
85
+ expect(result.current!.history).toBe(first.history);
86
+ expect(result.current!.attachments).toBe(first.attachments);
87
+ });
88
+ });