@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
@@ -18,11 +18,12 @@ import { ModelContext } from "../../store";
18
18
  import { buildInteractableModelContext } from "./interactable-model-context";
19
19
  import { notifySubscribers as notifyStateSubscribers } from "../../subscribable/subscribable";
20
20
  import { useInteractablePersistenceQueue } from "../interactables-shared/useInteractablePersistenceQueue";
21
+ import { nullProtoRecord } from "../../utils/record";
21
22
 
22
23
  const useInteractables = (): ClientOutput<"interactables"> => {
23
24
  const [state, setState] = useState<InteractablesState>(() => ({
24
- definitions: {},
25
- persistence: {},
25
+ definitions: nullProtoRecord(),
26
+ persistence: nullProtoRecord(),
26
27
  }));
27
28
 
28
29
  const clientRef = useAssistantClientRef();
@@ -49,7 +50,7 @@ const useInteractables = (): ClientOutput<"interactables"> => {
49
50
  );
50
51
 
51
52
  const exportState = useCallback((): InteractablePersistedState => {
52
- const result: InteractablePersistedState = {};
53
+ const result = nullProtoRecord<InteractablePersistedState[string]>();
53
54
  for (const [id, def] of Object.entries(stateRef.current.definitions)) {
54
55
  result[id] = { name: def.name, state: def.state };
55
56
  }
@@ -86,7 +87,7 @@ const useInteractables = (): ClientOutput<"interactables"> => {
86
87
  }
87
88
  setStateAndRef((prev) => {
88
89
  let changed = false;
89
- const definitions = { ...prev.definitions };
90
+ const definitions = nullProtoRecord(prev.definitions);
90
91
  for (const [id, entry] of Object.entries(saved)) {
91
92
  if (definitions[id]) {
92
93
  definitions[id] = { ...definitions[id], state: entry.state };
@@ -114,10 +115,9 @@ const useInteractables = (): ClientOutput<"interactables"> => {
114
115
  if (!existing) return prev;
115
116
  return {
116
117
  ...prev,
117
- definitions: {
118
- ...prev.definitions,
118
+ definitions: nullProtoRecord(prev.definitions, {
119
119
  [id]: { ...existing, state: updater(existing.state) },
120
- },
120
+ }),
121
121
  };
122
122
  });
123
123
  if (stateRef.current.definitions[id]) schedulePersistence(id);
@@ -132,10 +132,9 @@ const useInteractables = (): ClientOutput<"interactables"> => {
132
132
  if (!existing) return prev;
133
133
  return {
134
134
  ...prev,
135
- definitions: {
136
- ...prev.definitions,
135
+ definitions: nullProtoRecord(prev.definitions, {
137
136
  [id]: { ...existing, selected },
138
- },
137
+ }),
139
138
  };
140
139
  });
141
140
  },
@@ -194,8 +193,7 @@ const useInteractables = (): ClientOutput<"interactables"> => {
194
193
 
195
194
  setStateAndRef((prev) => ({
196
195
  ...prev,
197
- definitions: {
198
- ...prev.definitions,
196
+ definitions: nullProtoRecord(prev.definitions, {
199
197
  [def.id]: {
200
198
  id: def.id,
201
199
  name: def.name,
@@ -205,7 +203,7 @@ const useInteractables = (): ClientOutput<"interactables"> => {
205
203
  prev.definitions[def.id]?.state ?? detached ?? def.initialState,
206
204
  selected: def.selected,
207
205
  },
208
- },
206
+ }),
209
207
  }));
210
208
 
211
209
  return () => {
@@ -216,9 +214,11 @@ const useInteractables = (): ClientOutput<"interactables"> => {
216
214
  detachedStateRef.current.set(def.id, existing.state);
217
215
  }
218
216
  partialSchemaCacheRef.current.delete(def.id);
219
- const { [def.id]: _, ...rest } = prev.definitions;
220
- const { [def.id]: __, ...restPersistence } = prev.persistence;
221
- return { ...prev, definitions: rest, persistence: restPersistence };
217
+ const definitions = nullProtoRecord(prev.definitions);
218
+ const persistence = nullProtoRecord(prev.persistence);
219
+ delete definitions[def.id];
220
+ delete persistence[def.id];
221
+ return { ...prev, definitions, persistence };
222
222
  });
223
223
  };
224
224
  },
@@ -0,0 +1,132 @@
1
+ // @vitest-environment jsdom
2
+
3
+ import { cleanup, renderHook, waitFor } from "@testing-library/react";
4
+ import { afterEach, describe, expect, it, vi } from "vitest";
5
+
6
+ const mocks = vi.hoisted(() => {
7
+ const unregister = vi.fn();
8
+ const register = vi.fn(() => unregister);
9
+ return {
10
+ register,
11
+ unregister,
12
+ aui: { interactables: { register } },
13
+ };
14
+ });
15
+
16
+ vi.mock("@assistant-ui/store", async (importOriginal) => ({
17
+ ...(await importOriginal<typeof import("@assistant-ui/store")>()),
18
+ useAui: () => mocks.aui,
19
+ }));
20
+
21
+ import { useAssistantInteractable } from "./useAssistantInteractable";
22
+
23
+ afterEach(() => {
24
+ cleanup();
25
+ vi.clearAllMocks();
26
+ });
27
+
28
+ describe("useAssistantInteractable", () => {
29
+ it("refreshes the registration when its JSON schema changes", async () => {
30
+ const schemaA = {
31
+ type: "object" as const,
32
+ properties: { first: { type: "string" } },
33
+ };
34
+ const schemaB = {
35
+ type: "object" as const,
36
+ properties: { second: { type: "number" } },
37
+ };
38
+ const initialA = { first: "one" };
39
+ const initialB = { second: 2 };
40
+
41
+ const hook = renderHook(
42
+ ({ stateSchema, initialState }) =>
43
+ useAssistantInteractable("panel", {
44
+ id: "panel-1",
45
+ description: "A panel",
46
+ stateSchema,
47
+ initialState,
48
+ }),
49
+ { initialProps: { stateSchema: schemaA, initialState: initialA } },
50
+ );
51
+ await waitFor(() => expect(mocks.register).toHaveBeenCalledTimes(1));
52
+
53
+ hook.rerender({ stateSchema: schemaB, initialState: initialB });
54
+
55
+ await waitFor(() => expect(mocks.register).toHaveBeenCalledTimes(2));
56
+ expect(mocks.unregister).toHaveBeenCalledTimes(1);
57
+ expect(mocks.register).toHaveBeenLastCalledWith(
58
+ expect.objectContaining({ stateSchema: schemaB, initialState: initialB }),
59
+ );
60
+
61
+ hook.rerender({
62
+ stateSchema: {
63
+ type: "object",
64
+ properties: { second: { type: "number" } },
65
+ },
66
+ initialState: { second: 3 },
67
+ });
68
+ expect(mocks.register).toHaveBeenCalledTimes(2);
69
+ });
70
+
71
+ it("stabilizes equivalent rebuilt standard schemas", async () => {
72
+ const createSchema = (property: string) => ({
73
+ "~standard": {
74
+ version: 1 as const,
75
+ vendor: "test",
76
+ validate: (value: unknown) => ({ value }),
77
+ toJSONSchema: () => ({
78
+ type: "object" as const,
79
+ properties: { [property]: { type: "string" as const } },
80
+ }),
81
+ },
82
+ });
83
+ const firstSchema = createSchema("value");
84
+
85
+ const hook = renderHook(
86
+ ({ stateSchema }) =>
87
+ useAssistantInteractable("panel", {
88
+ id: "panel-1",
89
+ description: "A panel",
90
+ stateSchema,
91
+ initialState: {},
92
+ }),
93
+ { initialProps: { stateSchema: firstSchema } },
94
+ );
95
+ await waitFor(() => expect(mocks.register).toHaveBeenCalledTimes(1));
96
+
97
+ hook.rerender({ stateSchema: createSchema("value") });
98
+ expect(mocks.register).toHaveBeenCalledTimes(1);
99
+
100
+ const changedSchema = createSchema("other");
101
+ hook.rerender({ stateSchema: changedSchema });
102
+ await waitFor(() => expect(mocks.register).toHaveBeenCalledTimes(2));
103
+ expect(mocks.register).toHaveBeenLastCalledWith(
104
+ expect.objectContaining({ stateSchema: changedSchema }),
105
+ );
106
+ });
107
+
108
+ it("keeps unsupported standard schemas from failing during render", async () => {
109
+ const createSchema = () => ({
110
+ "~standard": {
111
+ version: 1 as const,
112
+ vendor: "test",
113
+ validate: (value: unknown) => ({ value }),
114
+ },
115
+ });
116
+
117
+ const hook = renderHook(
118
+ ({ stateSchema }) =>
119
+ useAssistantInteractable("panel", {
120
+ id: "panel-1",
121
+ description: "A panel",
122
+ stateSchema,
123
+ initialState: {},
124
+ }),
125
+ { initialProps: { stateSchema: createSchema() } },
126
+ );
127
+ await waitFor(() => expect(mocks.register).toHaveBeenCalledTimes(1));
128
+
129
+ hook.rerender({ stateSchema: createSchema() });
130
+ expect(mocks.register).toHaveBeenCalledTimes(1);
131
+ });
132
+ });
@@ -1,5 +1,6 @@
1
1
  import { useEffect, useId, useRef } from "react";
2
2
  import { useAui } from "@assistant-ui/store";
3
+ import { useJSONSchemaDependency } from "../utils/useJSONSchemaDependency";
3
4
  import type { InteractableStateSchema } from "./scopes";
4
5
 
5
6
  /**
@@ -38,6 +39,7 @@ export const useAssistantInteractable = (
38
39
 
39
40
  const stateSchemaRef = useRef(config.stateSchema);
40
41
  stateSchemaRef.current = config.stateSchema;
42
+ const normalizedStateSchema = useJSONSchemaDependency(config.stateSchema);
41
43
  const initialStateRef = useRef(config.initialState);
42
44
  initialStateRef.current = config.initialState;
43
45
 
@@ -50,7 +52,14 @@ export const useAssistantInteractable = (
50
52
  initialState: initialStateRef.current,
51
53
  selected: config.selected,
52
54
  });
53
- }, [aui, id, name, config.description, config.selected]);
55
+ }, [
56
+ aui,
57
+ id,
58
+ name,
59
+ config.description,
60
+ normalizedStateSchema,
61
+ config.selected,
62
+ ]);
54
63
 
55
64
  return id;
56
65
  };
@@ -1,4 +1,5 @@
1
1
  import { useCallback, useRef, type RefObject } from "react";
2
+ import { nullProtoRecord } from "../../utils/record";
2
3
 
3
4
  const PERSISTENCE_DEBOUNCE_MS = 500;
4
5
 
@@ -90,15 +91,13 @@ export const useInteractablePersistenceQueue = <State>({
90
91
  const { adapter, payload, dirtyIds, seq } = resolved;
91
92
  inFlightPersistenceRef.current += 1;
92
93
 
93
- updatePersistenceStatus((prev) => ({
94
- ...prev,
95
- ...Object.fromEntries(
96
- [...dirtyIds].map((id) => [
97
- id,
98
- { isPending: true, error: undefined },
99
- ]),
100
- ),
101
- }));
94
+ updatePersistenceStatus((prev) => {
95
+ const persistence = nullProtoRecord(prev);
96
+ for (const id of dirtyIds) {
97
+ persistence[id] = { isPending: true, error: undefined };
98
+ }
99
+ return persistence;
100
+ });
102
101
 
103
102
  const settleBatch = (status: PersistenceStatus | undefined) => {
104
103
  const settledIds: string[] = [];
@@ -114,7 +113,7 @@ export const useInteractablePersistenceQueue = <State>({
114
113
  if (settledIds.length === 0) return;
115
114
  updatePersistenceStatus((prev) => {
116
115
  let changed = false;
117
- const persistence = { ...prev };
116
+ const persistence = nullProtoRecord(prev);
118
117
  for (const id of settledIds) {
119
118
  if (prev[id] === undefined) continue;
120
119
  if (status === undefined) delete persistence[id];
@@ -8,7 +8,7 @@ import { type AssistantToolProps, useAssistantTool } from "./useAssistantTool";
8
8
  * subtree.
9
9
  *
10
10
  * @deprecated Use a toolkit with `Tools({ toolkit })` and register it via
11
- * `useAui({ tools: Tools({ toolkit }) })` instead. See
11
+ * `AuiConfig({ tools: Tools({ toolkit }) })` on the provider's `config` prop instead. See
12
12
  * https://assistant-ui.com/docs/migrations/toolkit-tools.
13
13
  */
14
14
  export type AssistantTool = FC & {
@@ -25,7 +25,7 @@ export type AssistantTool = FC & {
25
25
  * @param tool - Tool definition and name to register.
26
26
  *
27
27
  * @deprecated Use a toolkit with `Tools({ toolkit })` and register it via
28
- * `useAui({ tools: Tools({ toolkit }) })` instead. See
28
+ * `AuiConfig({ tools: Tools({ toolkit }) })` on the provider's `config` prop instead. See
29
29
  * https://assistant-ui.com/docs/migrations/toolkit-tools.
30
30
  */
31
31
  export const makeAssistantTool = <
@@ -12,7 +12,7 @@ import {
12
12
  * Props used to register a tool from React.
13
13
  *
14
14
  * @deprecated Use a toolkit with `Tools({ toolkit })` and register it via
15
- * `useAui({ tools: Tools({ toolkit }) })` instead. See
15
+ * `AuiConfig({ tools: Tools({ toolkit }) })` on the provider's `config` prop instead. See
16
16
  * https://assistant-ui.com/docs/migrations/toolkit-tools.
17
17
  */
18
18
  export type AssistantToolProps<
@@ -39,7 +39,7 @@ export type AssistantToolProps<
39
39
  * @param tool - Tool definition and name to register.
40
40
  *
41
41
  * @deprecated Use a toolkit with `Tools({ toolkit })` and register it via
42
- * `useAui({ tools: Tools({ toolkit }) })` instead. See
42
+ * `AuiConfig({ tools: Tools({ toolkit }) })` on the provider's `config` prop instead. See
43
43
  * https://assistant-ui.com/docs/migrations/toolkit-tools.
44
44
  *
45
45
  * @example
@@ -0,0 +1,177 @@
1
+ // @vitest-environment jsdom
2
+
3
+ import { cleanup, renderHook, waitFor } from "@testing-library/react";
4
+ import { afterEach, describe, expect, it, vi } from "vitest";
5
+
6
+ const mocks = vi.hoisted(() => {
7
+ const unregister = vi.fn();
8
+ const register = vi.fn(() => unregister);
9
+ return {
10
+ register,
11
+ unregister,
12
+ aui: { unstable_interactables: { register } },
13
+ state: { optional: { part: undefined }, thread: { messages: [] } },
14
+ methods: {
15
+ setState: vi.fn(),
16
+ isPending: false,
17
+ error: undefined,
18
+ flush: vi.fn(async () => undefined),
19
+ },
20
+ };
21
+ });
22
+
23
+ vi.mock("@assistant-ui/store", async (importOriginal) => ({
24
+ ...(await importOriginal<typeof import("@assistant-ui/store")>()),
25
+ useAui: () => mocks.aui,
26
+ useAuiState: (selector: (state: typeof mocks.state) => unknown) =>
27
+ selector(mocks.state),
28
+ }));
29
+
30
+ vi.mock("./useInteractableState", async (importOriginal) => ({
31
+ ...(await importOriginal<typeof import("./useInteractableState")>()),
32
+ unstable_useInteractableState: () => [undefined, mocks.methods],
33
+ }));
34
+
35
+ import { unstable_useInteractable } from "./useInteractable";
36
+
37
+ afterEach(() => {
38
+ cleanup();
39
+ vi.clearAllMocks();
40
+ });
41
+
42
+ describe("unstable_useInteractable", () => {
43
+ it("refreshes the registration when its JSON schema changes", async () => {
44
+ const schemaA = {
45
+ type: "object" as const,
46
+ properties: { first: { type: "string" } },
47
+ };
48
+ const schemaB = {
49
+ type: "object" as const,
50
+ properties: { second: { type: "number" } },
51
+ };
52
+ const initialA = { first: "one" };
53
+ const initialB = { second: 2 };
54
+
55
+ const hook = renderHook(
56
+ ({ stateSchema, initialState }) =>
57
+ unstable_useInteractable("panel", {
58
+ id: "panel-1",
59
+ description: "A panel",
60
+ stateSchema,
61
+ initialState,
62
+ }),
63
+ { initialProps: { stateSchema: schemaA, initialState: initialA } },
64
+ );
65
+ await waitFor(() => expect(mocks.register).toHaveBeenCalledTimes(1));
66
+
67
+ hook.rerender({ stateSchema: schemaB, initialState: initialB });
68
+
69
+ await waitFor(() => expect(mocks.register).toHaveBeenCalledTimes(2));
70
+ expect(mocks.unregister).toHaveBeenCalledTimes(1);
71
+ expect(mocks.register).toHaveBeenLastCalledWith(
72
+ expect.objectContaining({ stateSchema: schemaB, initialState: initialB }),
73
+ );
74
+
75
+ hook.rerender({
76
+ stateSchema: {
77
+ type: "object",
78
+ properties: { second: { type: "number" } },
79
+ },
80
+ initialState: { second: 3 },
81
+ });
82
+ expect(mocks.register).toHaveBeenCalledTimes(2);
83
+ });
84
+
85
+ it("stabilizes equivalent rebuilt standard schemas", async () => {
86
+ const createSchema = (property: string) => ({
87
+ "~standard": {
88
+ version: 1 as const,
89
+ vendor: "test",
90
+ validate: (value: unknown) => ({ value }),
91
+ toJSONSchema: () => ({
92
+ type: "object" as const,
93
+ properties: { [property]: { type: "string" as const } },
94
+ }),
95
+ },
96
+ });
97
+ const firstSchema = createSchema("value");
98
+
99
+ const hook = renderHook(
100
+ ({ stateSchema }) =>
101
+ unstable_useInteractable("panel", {
102
+ id: "panel-1",
103
+ description: "A panel",
104
+ stateSchema,
105
+ initialState: {},
106
+ }),
107
+ { initialProps: { stateSchema: firstSchema } },
108
+ );
109
+ await waitFor(() => expect(mocks.register).toHaveBeenCalledTimes(1));
110
+
111
+ hook.rerender({ stateSchema: createSchema("value") });
112
+ expect(mocks.register).toHaveBeenCalledTimes(1);
113
+
114
+ const changedSchema = createSchema("other");
115
+ hook.rerender({ stateSchema: changedSchema });
116
+ await waitFor(() => expect(mocks.register).toHaveBeenCalledTimes(2));
117
+ expect(mocks.register).toHaveBeenLastCalledWith(
118
+ expect.objectContaining({ stateSchema: changedSchema }),
119
+ );
120
+ });
121
+
122
+ it("keeps unsupported standard schemas from failing during render", async () => {
123
+ const createSchema = () => ({
124
+ "~standard": {
125
+ version: 1 as const,
126
+ vendor: "test",
127
+ validate: (value: unknown) => ({ value }),
128
+ },
129
+ });
130
+
131
+ const hook = renderHook(
132
+ ({ stateSchema }) =>
133
+ unstable_useInteractable("panel", {
134
+ id: "panel-1",
135
+ description: "A panel",
136
+ stateSchema,
137
+ initialState: {},
138
+ }),
139
+ { initialProps: { stateSchema: createSchema() } },
140
+ );
141
+ await waitFor(() => expect(mocks.register).toHaveBeenCalledTimes(1));
142
+
143
+ hook.rerender({ stateSchema: createSchema() });
144
+ expect(mocks.register).toHaveBeenCalledTimes(1);
145
+ });
146
+
147
+ it("converts a referentially stable schema only once", async () => {
148
+ const toJSONSchema = vi.fn(() => ({
149
+ type: "object" as const,
150
+ properties: { value: { type: "string" as const } },
151
+ }));
152
+ const stateSchema = {
153
+ "~standard": {
154
+ version: 1 as const,
155
+ vendor: "test",
156
+ validate: (value: unknown) => ({ value }),
157
+ toJSONSchema,
158
+ },
159
+ };
160
+
161
+ const hook = renderHook(
162
+ ({ initialState }) =>
163
+ unstable_useInteractable("panel", {
164
+ id: "panel-1",
165
+ description: "A panel",
166
+ stateSchema,
167
+ initialState,
168
+ }),
169
+ { initialProps: { initialState: { value: "first" } } },
170
+ );
171
+ await waitFor(() => expect(mocks.register).toHaveBeenCalledTimes(1));
172
+
173
+ hook.rerender({ initialState: { value: "second" } });
174
+ expect(toJSONSchema).toHaveBeenCalledTimes(1);
175
+ expect(mocks.register).toHaveBeenCalledTimes(1);
176
+ });
177
+ });
@@ -10,6 +10,7 @@ import {
10
10
  } from "../../model-context/interactable-composer-metadata";
11
11
  import { unstable_useInteractableState as useInteractableState } from "./useInteractableState";
12
12
  import { useJSONEqual } from "../utils/useJSONEqual";
13
+ import { useJSONSchemaDependency } from "../utils/useJSONSchemaDependency";
13
14
 
14
15
  /**
15
16
  * The state type described by an interactable's `stateSchema`. Resolves the
@@ -116,6 +117,7 @@ const useInteractable = <TSchema extends Unstable_InteractableStateSchema>(
116
117
 
117
118
  const stateSchemaRef = useRef(config.stateSchema);
118
119
  stateSchemaRef.current = config.stateSchema;
120
+ const normalizedStateSchema = useJSONSchemaDependency(config.stateSchema);
119
121
  const initialStateRef = useRef(config.initialState);
120
122
  initialStateRef.current = config.initialState;
121
123
 
@@ -138,6 +140,7 @@ const useInteractable = <TSchema extends Unstable_InteractableStateSchema>(
138
140
  id,
139
141
  name,
140
142
  config.description,
143
+ normalizedStateSchema,
141
144
  internalScope,
142
145
  config.updateRender,
143
146
  ]);
@@ -0,0 +1,30 @@
1
+ // @vitest-environment jsdom
2
+
3
+ import { renderHook } from "@testing-library/react";
4
+ import { describe, expect, it, vi } from "vitest";
5
+
6
+ const part = vi.hoisted(() => ({
7
+ type: "tool-call" as const,
8
+ status: { type: "complete" as const },
9
+ args: JSON.parse('{"__proto__":"value"}') as Record<string, unknown>,
10
+ }));
11
+
12
+ vi.mock("@assistant-ui/store", async (importOriginal) => {
13
+ const actual = await importOriginal<typeof import("@assistant-ui/store")>();
14
+ return {
15
+ ...actual,
16
+ useAuiState: (selector: (state: { part: typeof part }) => unknown) =>
17
+ selector({ part }),
18
+ };
19
+ });
20
+
21
+ import { useToolArgsStatus } from "./useToolArgsStatus";
22
+
23
+ describe("useToolArgsStatus", () => {
24
+ it("reports status for an argument named __proto__", () => {
25
+ const { result } = renderHook(() => useToolArgsStatus());
26
+
27
+ expect(Object.hasOwn(result.current.propStatus, "__proto__")).toBe(true);
28
+ expect(result.current.propStatus.__proto__).toBe("complete");
29
+ });
30
+ });
@@ -4,6 +4,7 @@ import {
4
4
  getPartialJsonObjectFieldState,
5
5
  getPartialJsonObjectMeta,
6
6
  } from "assistant-stream/utils";
7
+ import { nullProtoRecord } from "../../utils/record";
7
8
 
8
9
  type PropFieldStatus = "streaming" | "complete";
9
10
 
@@ -60,7 +61,7 @@ export const useToolArgsStatus = <
60
61
  const isStreaming = statusType === "running";
61
62
  const args = part.args as Record<string, unknown>;
62
63
  const meta = getPartialJsonObjectMeta(args as Record<symbol, unknown>);
63
- const propStatus: Partial<Record<string, PropFieldStatus>> = {};
64
+ const propStatus = nullProtoRecord<PropFieldStatus>();
64
65
 
65
66
  for (const key of Object.keys(args)) {
66
67
  if (meta) {
@@ -45,7 +45,6 @@ import { useActionBarCopy } from "./useActionBarCopy";
45
45
 
46
46
  afterEach(() => {
47
47
  cleanup();
48
- vi.clearAllMocks();
49
48
  vi.useRealTimers();
50
49
  mocks.currentAui = mocks.aui;
51
50
  });
@@ -47,7 +47,6 @@ import { useSuggestionTrigger } from "./useSuggestionTrigger";
47
47
 
48
48
  afterEach(() => {
49
49
  cleanup();
50
- vi.clearAllMocks();
51
50
  mocks.state.thread.isDisabled = false;
52
51
  mocks.state.thread.isRunning = false;
53
52
  mocks.state.thread.capabilities = { queue: false };