@assistant-ui/core 0.3.13 → 0.3.15

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 (463) hide show
  1. package/dist/adapters/speech.d.ts.map +1 -1
  2. package/dist/adapters/speech.js +9 -15
  3. package/dist/adapters/speech.js.map +1 -1
  4. package/dist/adapters/thread-history.d.ts +2 -0
  5. package/dist/adapters/thread-history.d.ts.map +1 -1
  6. package/dist/adapters/voice.d.ts.map +1 -1
  7. package/dist/adapters/voice.js +38 -15
  8. package/dist/adapters/voice.js.map +1 -1
  9. package/dist/index.d.ts +2 -2
  10. package/dist/index.js +1 -1
  11. package/dist/index.js.map +1 -1
  12. package/dist/internal.d.ts +3 -2
  13. package/dist/internal.js +8 -7
  14. package/dist/model-context/frame/host.d.ts +1 -1
  15. package/dist/model-context/frame/host.d.ts.map +1 -1
  16. package/dist/model-context/frame/host.js +19 -4
  17. package/dist/model-context/frame/host.js.map +1 -1
  18. package/dist/model-context/frame/provider.d.ts +4 -0
  19. package/dist/model-context/frame/provider.d.ts.map +1 -1
  20. package/dist/model-context/frame/provider.js +50 -3
  21. package/dist/model-context/frame/provider.js.map +1 -1
  22. package/dist/model-context/frame/types.d.ts +4 -1
  23. package/dist/model-context/frame/types.d.ts.map +1 -1
  24. package/dist/model-context/frame/types.js.map +1 -1
  25. package/dist/model-context/registry.d.ts.map +1 -1
  26. package/dist/model-context/registry.js +16 -4
  27. package/dist/model-context/registry.js.map +1 -1
  28. package/dist/react/RuntimeAdapter.d.ts +8 -1
  29. package/dist/react/RuntimeAdapter.d.ts.map +1 -1
  30. package/dist/react/RuntimeAdapter.js +23 -18
  31. package/dist/react/RuntimeAdapter.js.map +1 -1
  32. package/dist/react/adapters/LocalStorageThreadListAdapter.d.ts.map +1 -1
  33. package/dist/react/adapters/LocalStorageThreadListAdapter.js +28 -12
  34. package/dist/react/adapters/LocalStorageThreadListAdapter.js.map +1 -1
  35. package/dist/react/client/AdaptedRemoteThread.d.ts +11 -0
  36. package/dist/react/client/AdaptedRemoteThread.d.ts.map +1 -0
  37. package/dist/react/client/AdaptedRemoteThread.js +27 -0
  38. package/dist/react/client/AdaptedRemoteThread.js.map +1 -0
  39. package/dist/react/client/InMemoryThreadList.d.ts +19 -0
  40. package/dist/react/client/InMemoryThreadList.d.ts.map +1 -0
  41. package/dist/react/client/InMemoryThreadList.js +418 -0
  42. package/dist/react/client/InMemoryThreadList.js.map +1 -0
  43. package/dist/react/client/Interactables.d.ts.map +1 -1
  44. package/dist/react/client/Interactables.js +159 -102
  45. package/dist/react/client/Interactables.js.map +1 -1
  46. package/dist/react/client/RemoteThreadList.d.ts +34 -0
  47. package/dist/react/client/RemoteThreadList.d.ts.map +1 -0
  48. package/dist/react/client/RemoteThreadList.js +898 -0
  49. package/dist/react/client/RemoteThreadList.js.map +1 -0
  50. package/dist/react/client/Tools.d.ts.map +1 -1
  51. package/dist/react/client/Tools.js +38 -27
  52. package/dist/react/client/Tools.js.map +1 -1
  53. package/dist/react/index.d.ts +7 -2
  54. package/dist/react/index.js +5 -2
  55. package/dist/react/interactables-legacy/Interactables.d.ts.map +1 -1
  56. package/dist/react/interactables-legacy/Interactables.js +145 -110
  57. package/dist/react/interactables-legacy/Interactables.js.map +1 -1
  58. package/dist/react/primitive-hooks/useActionBarCopy.d.ts.map +1 -1
  59. package/dist/react/primitive-hooks/useActionBarCopy.js +20 -19
  60. package/dist/react/primitive-hooks/useActionBarCopy.js.map +1 -1
  61. package/dist/react/primitive-hooks/useActionBarEdit.d.ts.map +1 -1
  62. package/dist/react/primitive-hooks/useActionBarEdit.js +2 -4
  63. package/dist/react/primitive-hooks/useActionBarEdit.js.map +1 -1
  64. package/dist/react/primitive-hooks/useActionBarReload.d.ts.map +1 -1
  65. package/dist/react/primitive-hooks/useActionBarReload.js +2 -4
  66. package/dist/react/primitive-hooks/useActionBarReload.js.map +1 -1
  67. package/dist/react/primitive-hooks/useBranchPickerNext.d.ts.map +1 -1
  68. package/dist/react/primitive-hooks/useBranchPickerNext.js +2 -6
  69. package/dist/react/primitive-hooks/useBranchPickerNext.js.map +1 -1
  70. package/dist/react/primitive-hooks/useBranchPickerPrevious.d.ts.map +1 -1
  71. package/dist/react/primitive-hooks/useBranchPickerPrevious.js +2 -6
  72. package/dist/react/primitive-hooks/useBranchPickerPrevious.js.map +1 -1
  73. package/dist/react/primitive-hooks/useComposerCancel.d.ts.map +1 -1
  74. package/dist/react/primitive-hooks/useComposerCancel.js +2 -4
  75. package/dist/react/primitive-hooks/useComposerCancel.js.map +1 -1
  76. package/dist/react/primitive-hooks/useComposerSend.d.ts.map +1 -1
  77. package/dist/react/primitive-hooks/useComposerSend.js +2 -4
  78. package/dist/react/primitive-hooks/useComposerSend.js.map +1 -1
  79. package/dist/react/primitive-hooks/useSuggestionTrigger.d.ts.map +1 -1
  80. package/dist/react/primitive-hooks/useSuggestionTrigger.js +6 -2
  81. package/dist/react/primitive-hooks/useSuggestionTrigger.js.map +1 -1
  82. package/dist/react/primitive-hooks/useThreadIsEmpty.d.ts +3 -0
  83. package/dist/react/primitive-hooks/useThreadIsEmpty.d.ts.map +1 -1
  84. package/dist/react/primitive-hooks/useThreadIsEmpty.js +3 -0
  85. package/dist/react/primitive-hooks/useThreadIsEmpty.js.map +1 -1
  86. package/dist/react/primitive-hooks/useThreadIsRunning.d.ts +3 -0
  87. package/dist/react/primitive-hooks/useThreadIsRunning.d.ts.map +1 -1
  88. package/dist/react/primitive-hooks/useThreadIsRunning.js +3 -0
  89. package/dist/react/primitive-hooks/useThreadIsRunning.js.map +1 -1
  90. package/dist/react/primitives/message/MessageParts.d.ts +13 -0
  91. package/dist/react/primitives/message/MessageParts.d.ts.map +1 -1
  92. package/dist/react/primitives/message/MessageParts.js.map +1 -1
  93. package/dist/react/primitives/thread/ThreadMessages.d.ts.map +1 -1
  94. package/dist/react/primitives/thread/ThreadMessages.js +1 -1
  95. package/dist/react/primitives/thread/ThreadMessages.js.map +1 -1
  96. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts +24 -10
  97. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
  98. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +115 -71
  99. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
  100. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +14 -2
  101. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
  102. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +232 -63
  103. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
  104. package/dist/react/runtimes/RemoteThreadResource.d.ts +30 -0
  105. package/dist/react/runtimes/RemoteThreadResource.d.ts.map +1 -0
  106. package/dist/react/runtimes/RemoteThreadResource.js +136 -0
  107. package/dist/react/runtimes/RemoteThreadResource.js.map +1 -0
  108. package/dist/react/runtimes/RuntimeAdapterProvider.d.ts +3 -10
  109. package/dist/react/runtimes/RuntimeAdapterProvider.d.ts.map +1 -1
  110. package/dist/react/runtimes/RuntimeAdapterProvider.js +3 -6
  111. package/dist/react/runtimes/RuntimeAdapterProvider.js.map +1 -1
  112. package/dist/react/runtimes/assistant-transport/commandQueue.d.ts +17 -0
  113. package/dist/react/runtimes/assistant-transport/commandQueue.d.ts.map +1 -0
  114. package/dist/react/runtimes/assistant-transport/commandQueue.js +55 -0
  115. package/dist/react/runtimes/assistant-transport/commandQueue.js.map +1 -0
  116. package/dist/react/runtimes/assistant-transport/replayBoundaryStream.d.ts +11 -0
  117. package/dist/react/runtimes/assistant-transport/replayBoundaryStream.d.ts.map +1 -0
  118. package/dist/react/runtimes/assistant-transport/replayBoundaryStream.js +165 -0
  119. package/dist/react/runtimes/assistant-transport/replayBoundaryStream.js.map +1 -0
  120. package/dist/react/runtimes/assistant-transport/runManager.d.ts +15 -0
  121. package/dist/react/runtimes/assistant-transport/runManager.d.ts.map +1 -0
  122. package/dist/react/runtimes/assistant-transport/runManager.js +86 -0
  123. package/dist/react/runtimes/assistant-transport/runManager.js.map +1 -0
  124. package/dist/react/runtimes/assistant-transport/types.d.ts +130 -0
  125. package/dist/react/runtimes/assistant-transport/types.d.ts.map +1 -0
  126. package/dist/react/runtimes/assistant-transport/types.js +0 -0
  127. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.d.ts +14 -0
  128. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.d.ts.map +1 -0
  129. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.js +296 -0
  130. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.js.map +1 -0
  131. package/dist/react/runtimes/assistant-transport/useConvertedState.d.ts +7 -0
  132. package/dist/react/runtimes/assistant-transport/useConvertedState.d.ts.map +1 -0
  133. package/dist/react/runtimes/assistant-transport/useConvertedState.js +25 -0
  134. package/dist/react/runtimes/assistant-transport/useConvertedState.js.map +1 -0
  135. package/dist/react/runtimes/assistant-transport/useLatestRef.d.ts +7 -0
  136. package/dist/react/runtimes/assistant-transport/useLatestRef.d.ts.map +1 -0
  137. package/dist/react/runtimes/assistant-transport/useLatestRef.js +27 -0
  138. package/dist/react/runtimes/assistant-transport/useLatestRef.js.map +1 -0
  139. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
  140. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +39 -13
  141. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
  142. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts +2 -1
  143. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts.map +1 -1
  144. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js +3 -3
  145. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js.map +1 -1
  146. package/dist/react/runtimes/cloud/auiV0.d.ts +4 -0
  147. package/dist/react/runtimes/cloud/auiV0.d.ts.map +1 -1
  148. package/dist/react/runtimes/cloud/auiV0.js +7 -0
  149. package/dist/react/runtimes/cloud/auiV0.js.map +1 -1
  150. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.d.ts.map +1 -1
  151. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js +60 -17
  152. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js.map +1 -1
  153. package/dist/react/runtimes/cloud/useCloudThreadListRuntime.d.ts +16 -0
  154. package/dist/react/runtimes/cloud/useCloudThreadListRuntime.d.ts.map +1 -0
  155. package/dist/react/runtimes/cloud/useCloudThreadListRuntime.js +36 -0
  156. package/dist/react/runtimes/cloud/useCloudThreadListRuntime.js.map +1 -0
  157. package/dist/react/runtimes/external-message-converter.js +14 -14
  158. package/dist/react/runtimes/external-message-converter.js.map +1 -1
  159. package/dist/react/runtimes/useExternalStoreRuntime.d.ts.map +1 -1
  160. package/dist/react/runtimes/useExternalStoreRuntime.js +44 -28
  161. package/dist/react/runtimes/useExternalStoreRuntime.js.map +1 -1
  162. package/dist/react/runtimes/useExternalStoreSharedOptions.js.map +1 -1
  163. package/dist/react/runtimes/useLocalRuntime.js +1 -1
  164. package/dist/react/runtimes/useRuntimeAdapters.d.ts +9 -0
  165. package/dist/react/runtimes/useRuntimeAdapters.d.ts.map +1 -0
  166. package/dist/react/runtimes/useRuntimeAdapters.js +20 -0
  167. package/dist/react/runtimes/useRuntimeAdapters.js.map +1 -0
  168. package/dist/runtime/api/composer-runtime.d.ts +5 -0
  169. package/dist/runtime/api/composer-runtime.d.ts.map +1 -1
  170. package/dist/runtime/api/composer-runtime.js.map +1 -1
  171. package/dist/runtime/api/message-runtime.js +1 -1
  172. package/dist/runtime/api/thread-list-runtime.d.ts +1 -0
  173. package/dist/runtime/api/thread-list-runtime.d.ts.map +1 -1
  174. package/dist/runtime/api/thread-list-runtime.js +4 -2
  175. package/dist/runtime/api/thread-list-runtime.js.map +1 -1
  176. package/dist/runtime/api/thread-runtime.d.ts +12 -2
  177. package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
  178. package/dist/runtime/api/thread-runtime.js +8 -2
  179. package/dist/runtime/api/thread-runtime.js.map +1 -1
  180. package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
  181. package/dist/runtime/base/base-composer-runtime-core.js +8 -7
  182. package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
  183. package/dist/runtime/base/base-thread-runtime-core.d.ts +1 -0
  184. package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
  185. package/dist/runtime/base/base-thread-runtime-core.js +3 -3
  186. package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
  187. package/dist/runtime/base/default-thread-composer-runtime-core.d.ts +0 -1
  188. package/dist/runtime/base/default-thread-composer-runtime-core.d.ts.map +1 -1
  189. package/dist/runtime/base/default-thread-composer-runtime-core.js +10 -4
  190. package/dist/runtime/base/default-thread-composer-runtime-core.js.map +1 -1
  191. package/dist/runtime/interfaces/thread-runtime-core.d.ts +6 -0
  192. package/dist/runtime/interfaces/thread-runtime-core.d.ts.map +1 -1
  193. package/dist/runtime/internal.js +5 -5
  194. package/dist/runtime/queue/message-queue.d.ts.map +1 -1
  195. package/dist/runtime/queue/message-queue.js +2 -1
  196. package/dist/runtime/queue/message-queue.js.map +1 -1
  197. package/dist/runtime/utils/message-repository.d.ts.map +1 -1
  198. package/dist/runtime/utils/message-repository.js +27 -18
  199. package/dist/runtime/utils/message-repository.js.map +1 -1
  200. package/dist/runtime/utils/thread-runtime-lifecycle.d.ts +8 -0
  201. package/dist/runtime/utils/thread-runtime-lifecycle.d.ts.map +1 -0
  202. package/dist/runtime/utils/thread-runtime-lifecycle.js +11 -0
  203. package/dist/runtime/utils/thread-runtime-lifecycle.js.map +1 -0
  204. package/dist/runtimes/external-store/external-store-shared-options.js.map +1 -1
  205. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts.map +1 -1
  206. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js +4 -1
  207. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js.map +1 -1
  208. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts +8 -0
  209. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
  210. package/dist/runtimes/external-store/external-store-thread-runtime-core.js +37 -13
  211. package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
  212. package/dist/runtimes/inert/InertThreadRuntimeCore.d.ts +102 -0
  213. package/dist/runtimes/inert/InertThreadRuntimeCore.d.ts.map +1 -0
  214. package/dist/runtimes/inert/InertThreadRuntimeCore.js +156 -0
  215. package/dist/runtimes/inert/InertThreadRuntimeCore.js.map +1 -0
  216. package/dist/runtimes/internal.d.ts +1 -1
  217. package/dist/runtimes/local/local-thread-runtime-core.d.ts +3 -0
  218. package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
  219. package/dist/runtimes/local/local-thread-runtime-core.js +78 -19
  220. package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
  221. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts +12 -59
  222. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts.map +1 -1
  223. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.js +10 -142
  224. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.js.map +1 -1
  225. package/dist/runtimes/remote-thread-list/adapter-changed.d.ts +9 -0
  226. package/dist/runtimes/remote-thread-list/adapter-changed.d.ts.map +1 -0
  227. package/dist/runtimes/remote-thread-list/adapter-changed.js +13 -0
  228. package/dist/runtimes/remote-thread-list/adapter-changed.js.map +1 -0
  229. package/dist/runtimes/remote-thread-list/empty-thread-core.d.ts.map +1 -1
  230. package/dist/runtimes/remote-thread-list/empty-thread-core.js +16 -152
  231. package/dist/runtimes/remote-thread-list/empty-thread-core.js.map +1 -1
  232. package/dist/runtimes/remote-thread-list/optimistic-state.d.ts +2 -0
  233. package/dist/runtimes/remote-thread-list/optimistic-state.d.ts.map +1 -1
  234. package/dist/runtimes/remote-thread-list/optimistic-state.js +11 -0
  235. package/dist/runtimes/remote-thread-list/optimistic-state.js.map +1 -1
  236. package/dist/runtimes/remote-thread-list/types.d.ts +32 -1
  237. package/dist/runtimes/remote-thread-list/types.d.ts.map +1 -1
  238. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts +1 -12
  239. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts.map +1 -1
  240. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js +67 -38
  241. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js.map +1 -1
  242. package/dist/store/clients/external-thread.js +1 -1
  243. package/dist/store/clients/external-thread.js.map +1 -1
  244. package/dist/store/clients/suggestions.js +2 -2
  245. package/dist/store/clients/suggestions.js.map +1 -1
  246. package/dist/store/clients/thread-selection-events.d.ts +10 -0
  247. package/dist/store/clients/thread-selection-events.d.ts.map +1 -0
  248. package/dist/store/clients/thread-selection-events.js +40 -0
  249. package/dist/store/clients/thread-selection-events.js.map +1 -0
  250. package/dist/store/env.d.ts +5 -0
  251. package/dist/store/env.d.ts.map +1 -0
  252. package/dist/store/env.js +12 -0
  253. package/dist/store/env.js.map +1 -0
  254. package/dist/store/index.d.ts +5 -3
  255. package/dist/store/index.js +4 -2
  256. package/dist/store/internal.d.ts +4 -1
  257. package/dist/store/internal.js +4 -1
  258. package/dist/store/primitive-predicates.d.ts +19 -0
  259. package/dist/store/primitive-predicates.d.ts.map +1 -0
  260. package/dist/store/primitive-predicates.js +19 -0
  261. package/dist/store/primitive-predicates.js.map +1 -0
  262. package/dist/store/runtime-clients/attachment-runtime-client.d.ts.map +1 -1
  263. package/dist/store/runtime-clients/attachment-runtime-client.js +18 -11
  264. package/dist/store/runtime-clients/attachment-runtime-client.js.map +1 -1
  265. package/dist/store/runtime-clients/handle-runtime-action.d.ts +5 -0
  266. package/dist/store/runtime-clients/handle-runtime-action.d.ts.map +1 -0
  267. package/dist/store/runtime-clients/handle-runtime-action.js +14 -0
  268. package/dist/store/runtime-clients/handle-runtime-action.js.map +1 -0
  269. package/dist/store/runtime-clients/handle-thread-list-action.d.ts +5 -0
  270. package/dist/store/runtime-clients/handle-thread-list-action.d.ts.map +1 -0
  271. package/dist/store/runtime-clients/handle-thread-list-action.js +7 -0
  272. package/dist/store/runtime-clients/handle-thread-list-action.js.map +1 -0
  273. package/dist/store/runtime-clients/thread-list-item-runtime-client.d.ts.map +1 -1
  274. package/dist/store/runtime-clients/thread-list-item-runtime-client.js +62 -29
  275. package/dist/store/runtime-clients/thread-list-item-runtime-client.js.map +1 -1
  276. package/dist/store/runtime-clients/thread-list-runtime-client.d.ts.map +1 -1
  277. package/dist/store/runtime-clients/thread-list-runtime-client.js +5 -6
  278. package/dist/store/runtime-clients/thread-list-runtime-client.js.map +1 -1
  279. package/dist/store/scopes/composer.d.ts +9 -4
  280. package/dist/store/scopes/composer.d.ts.map +1 -1
  281. package/dist/store/scopes/thread-list-item.d.ts +7 -6
  282. package/dist/store/scopes/thread-list-item.d.ts.map +1 -1
  283. package/dist/store/scopes/thread.d.ts +8 -7
  284. package/dist/store/scopes/thread.d.ts.map +1 -1
  285. package/dist/store/scopes/threads.d.ts +17 -1
  286. package/dist/store/scopes/threads.d.ts.map +1 -1
  287. package/dist/subscribable/subscribable.d.ts +2 -1
  288. package/dist/subscribable/subscribable.d.ts.map +1 -1
  289. package/dist/subscribable/subscribable.js +23 -18
  290. package/dist/subscribable/subscribable.js.map +1 -1
  291. package/dist/types/message.d.ts +1 -1
  292. package/dist/types/message.js.map +1 -1
  293. package/dist/utils/composite-context-provider.d.ts +1 -0
  294. package/dist/utils/composite-context-provider.d.ts.map +1 -1
  295. package/dist/utils/composite-context-provider.js +25 -9
  296. package/dist/utils/composite-context-provider.js.map +1 -1
  297. package/dist/utils/notify-event-listeners.d.ts +2 -2
  298. package/dist/utils/notify-event-listeners.d.ts.map +1 -1
  299. package/dist/utils/notify-event-listeners.js +2 -2
  300. package/dist/utils/notify-event-listeners.js.map +1 -1
  301. package/dist/utils/silent-runtime-action.d.ts +6 -0
  302. package/dist/utils/silent-runtime-action.d.ts.map +1 -0
  303. package/dist/utils/silent-runtime-action.js +7 -0
  304. package/dist/utils/silent-runtime-action.js.map +1 -0
  305. package/package.json +8 -8
  306. package/src/adapters/speech.test.ts +118 -1
  307. package/src/adapters/speech.ts +21 -22
  308. package/src/adapters/thread-history.ts +2 -0
  309. package/src/adapters/voice.test.ts +134 -0
  310. package/src/adapters/voice.ts +35 -27
  311. package/src/index.ts +1 -0
  312. package/src/internal.ts +1 -0
  313. package/src/model-context/frame/host.test.ts +87 -5
  314. package/src/model-context/frame/host.ts +18 -4
  315. package/src/model-context/frame/provider.test.ts +347 -20
  316. package/src/model-context/frame/provider.ts +58 -2
  317. package/src/model-context/frame/types.ts +5 -0
  318. package/src/model-context/registry.test.ts +131 -0
  319. package/src/model-context/registry.ts +16 -6
  320. package/src/react/RuntimeAdapter.test.ts +2 -0
  321. package/src/react/RuntimeAdapter.ts +20 -8
  322. package/src/react/adapters/LocalStorageThreadListAdapter.tsx +34 -17
  323. package/src/react/client/AdaptedRemoteThread.ts +41 -0
  324. package/src/react/client/InMemoryThreadList.test.tsx +148 -0
  325. package/src/react/client/InMemoryThreadList.ts +290 -0
  326. package/src/react/client/Interactables.test.ts +326 -2
  327. package/src/react/client/Interactables.ts +227 -110
  328. package/src/react/client/RemoteThreadList.test.ts +1222 -0
  329. package/src/react/client/RemoteThreadList.ts +1136 -0
  330. package/src/react/client/Tools.ts +36 -29
  331. package/src/react/index.ts +13 -0
  332. package/src/react/interactables-legacy/Interactables.test.ts +317 -0
  333. package/src/react/interactables-legacy/Interactables.ts +204 -128
  334. package/src/react/primitive-hooks/useActionBarCopy.test.ts +15 -0
  335. package/src/react/primitive-hooks/useActionBarCopy.ts +15 -10
  336. package/src/react/primitive-hooks/useActionBarEdit.ts +2 -1
  337. package/src/react/primitive-hooks/useActionBarReload.ts +2 -6
  338. package/src/react/primitive-hooks/useBranchPickerNext.ts +2 -7
  339. package/src/react/primitive-hooks/useBranchPickerPrevious.ts +2 -7
  340. package/src/react/primitive-hooks/useComposerCancel.ts +2 -1
  341. package/src/react/primitive-hooks/useComposerSend.ts +2 -5
  342. package/src/react/primitive-hooks/useSuggestionTrigger.test.ts +11 -0
  343. package/src/react/primitive-hooks/useSuggestionTrigger.ts +4 -5
  344. package/src/react/primitive-hooks/useThreadIsEmpty.ts +3 -0
  345. package/src/react/primitive-hooks/useThreadIsRunning.ts +3 -0
  346. package/src/react/primitives/message/MessageParts.tsx +0 -1
  347. package/src/react/primitives/thread/ThreadMessages.tsx +2 -1
  348. package/src/react/runtimes/RemoteThreadListHookInstanceManager.retry.test.tsx +116 -0
  349. package/src/react/runtimes/RemoteThreadListHookInstanceManager.running.test.tsx +1 -1
  350. package/src/react/runtimes/RemoteThreadListHookInstanceManager.test.tsx +57 -6
  351. package/src/react/runtimes/RemoteThreadListHookInstanceManager.title.test.tsx +272 -0
  352. package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +171 -124
  353. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.republish.test.ts +87 -0
  354. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +327 -83
  355. package/src/react/runtimes/RemoteThreadResource.test.ts +141 -0
  356. package/src/react/runtimes/RemoteThreadResource.ts +233 -0
  357. package/src/react/runtimes/RuntimeAdapterProvider.tsx +8 -20
  358. package/src/react/runtimes/assistant-transport/commandQueue.ts +68 -0
  359. package/src/react/runtimes/assistant-transport/replayBoundaryStream.test.ts +455 -0
  360. package/src/react/runtimes/assistant-transport/replayBoundaryStream.ts +172 -0
  361. package/src/react/runtimes/assistant-transport/runManager.ts +124 -0
  362. package/src/react/runtimes/assistant-transport/transport-delivery.test.tsx +79 -0
  363. package/src/react/runtimes/assistant-transport/transport-parentid.test.tsx +97 -0
  364. package/src/react/runtimes/assistant-transport/transport-scheduling.test.ts +414 -0
  365. package/src/react/runtimes/assistant-transport/types.ts +170 -0
  366. package/src/react/runtimes/assistant-transport/useAssistantTransport.spec.md +141 -0
  367. package/src/react/runtimes/assistant-transport/useAssistantTransportRuntime.test.tsx +683 -0
  368. package/src/react/runtimes/assistant-transport/useAssistantTransportRuntime.ts +483 -0
  369. package/src/react/runtimes/assistant-transport/useConvertedState.ts +20 -0
  370. package/src/react/runtimes/assistant-transport/useLatestRef.ts +9 -0
  371. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.tsx +131 -6
  372. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +61 -15
  373. package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.ts +6 -4
  374. package/src/react/runtimes/cloud/auiV0.ts +17 -1
  375. package/src/react/runtimes/cloud/useCloudThreadListAdapter.test.tsx +98 -3
  376. package/src/react/runtimes/cloud/useCloudThreadListAdapter.tsx +104 -27
  377. package/src/react/runtimes/cloud/useCloudThreadListRuntime.test.tsx +56 -0
  378. package/src/react/runtimes/cloud/useCloudThreadListRuntime.ts +31 -0
  379. package/src/react/runtimes/external-message-converter.test.ts +143 -0
  380. package/src/react/runtimes/external-message-converter.ts +41 -41
  381. package/src/react/runtimes/remote-thread-hook-on-tap.test.ts +58 -0
  382. package/src/react/runtimes/useExternalStoreRuntime.lifecycle.test.tsx +83 -0
  383. package/src/react/runtimes/useExternalStoreRuntime.suggestions.test.tsx +13 -3
  384. package/src/react/runtimes/useExternalStoreRuntime.ts +7 -0
  385. package/src/react/runtimes/useExternalStoreSharedOptions.ts +3 -1
  386. package/src/react/runtimes/useLocalRuntime.test.tsx +134 -8
  387. package/src/react/runtimes/useRuntimeAdapters.test.tsx +62 -0
  388. package/src/react/runtimes/useRuntimeAdapters.ts +28 -0
  389. package/src/runtime/api/composer-runtime.ts +5 -0
  390. package/src/runtime/api/thread-list-runtime.ts +3 -1
  391. package/src/runtime/api/thread-runtime.ts +20 -2
  392. package/src/runtime/base/base-composer-runtime-core.ts +6 -5
  393. package/src/runtime/base/base-thread-runtime-core.test.ts +191 -0
  394. package/src/runtime/base/base-thread-runtime-core.ts +11 -2
  395. package/src/runtime/base/default-thread-composer-runtime-core.ts +12 -4
  396. package/src/runtime/interfaces/thread-runtime-core.ts +6 -0
  397. package/src/runtime/queue/message-queue.ts +2 -1
  398. package/src/runtime/utils/message-repository.ts +26 -18
  399. package/src/runtime/utils/thread-runtime-lifecycle.ts +18 -0
  400. package/src/runtimes/external-store/external-store-shared-options.ts +3 -1
  401. package/src/runtimes/external-store/external-store-thread-list-runtime-core.ts +4 -1
  402. package/src/runtimes/external-store/external-store-thread-runtime-core.ts +103 -34
  403. package/src/runtimes/inert/InertThreadRuntimeCore.test.ts +253 -0
  404. package/src/runtimes/inert/InertThreadRuntimeCore.ts +232 -0
  405. package/src/runtimes/local/local-thread-runtime-core.test.ts +692 -4
  406. package/src/runtimes/local/local-thread-runtime-core.ts +117 -22
  407. package/src/runtimes/readonly/ReadonlyThreadRuntimeCore.ts +17 -205
  408. package/src/runtimes/remote-thread-list/adapter-changed.ts +10 -0
  409. package/src/runtimes/remote-thread-list/empty-thread-core.ts +28 -217
  410. package/src/runtimes/remote-thread-list/optimistic-state.test.ts +18 -0
  411. package/src/runtimes/remote-thread-list/optimistic-state.ts +13 -0
  412. package/src/runtimes/remote-thread-list/types.ts +34 -0
  413. package/src/runtimes/tool-invocations/EDGE_CASES.md +17 -6
  414. package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +243 -0
  415. package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +127 -61
  416. package/src/store/clients/external-thread.ts +1 -1
  417. package/src/store/clients/model-context-client.test.ts +16 -8
  418. package/src/store/clients/suggestions.ts +2 -2
  419. package/src/store/clients/thread-selection-events.ts +21 -0
  420. package/src/store/env.ts +11 -0
  421. package/src/store/index.ts +14 -1
  422. package/src/store/internal.ts +13 -0
  423. package/src/store/primitive-predicates.test.ts +184 -0
  424. package/src/store/primitive-predicates.ts +43 -0
  425. package/src/store/runtime-clients/attachment-runtime-client.test.ts +41 -0
  426. package/src/store/runtime-clients/attachment-runtime-client.ts +2 -1
  427. package/src/store/runtime-clients/handle-runtime-action.test.ts +40 -0
  428. package/src/store/runtime-clients/handle-runtime-action.ts +14 -0
  429. package/src/store/runtime-clients/handle-thread-list-action.test.ts +69 -0
  430. package/src/store/runtime-clients/handle-thread-list-action.ts +6 -0
  431. package/src/store/runtime-clients/thread-list-item-runtime-client.ts +15 -7
  432. package/src/store/runtime-clients/thread-list-runtime-client.ts +9 -6
  433. package/src/store/scopes/composer.ts +9 -4
  434. package/src/store/scopes/thread-list-item.ts +7 -6
  435. package/src/store/scopes/thread.ts +8 -7
  436. package/src/store/scopes/threads.ts +14 -0
  437. package/src/subscribable/subscribable.test.ts +77 -1
  438. package/src/subscribable/subscribable.ts +38 -23
  439. package/src/tests/MessageRepository.test.ts +48 -0
  440. package/src/tests/RemoteThreadListThreadListRuntimeCore-errors.test.ts +2 -2
  441. package/src/tests/RemoteThreadListThreadListRuntimeCore-loadMore.test.ts +8 -6
  442. package/src/tests/RemoteThreadListThreadListRuntimeCore-switchToThread-unarchive.test.ts +25 -0
  443. package/src/tests/auiV0Encode.test.ts +66 -0
  444. package/src/tests/base-composer-runtime-core-send.test.ts +30 -0
  445. package/src/tests/base-composer-runtime-core.test.ts +28 -0
  446. package/src/tests/composer-can-cancel.test.ts +101 -0
  447. package/src/tests/empty-thread-core.test.ts +6 -0
  448. package/src/tests/external-store-thread-list-runtime-core.test.ts +101 -0
  449. package/src/tests/external-store-thread-runtime-core-adapter.test.ts +211 -1
  450. package/src/tests/external-store-thread-runtime-core.test.ts +124 -0
  451. package/src/tests/external-thread-isEmpty.test.tsx +100 -0
  452. package/src/tests/interactables-toolui-migration.test.tsx +66 -0
  453. package/src/tests/message-queue.test.ts +28 -0
  454. package/src/tests/remote-thread-list-adapter-switch.test.ts +383 -0
  455. package/src/tests/session-reset-notification.test.ts +145 -0
  456. package/src/tests/thread-switch-events.test.tsx +99 -1
  457. package/src/tests/tools-scope-migration.test.tsx +58 -0
  458. package/src/tests/useRemoteThreadListRuntime-controlled.test.tsx +67 -0
  459. package/src/types/message.ts +1 -1
  460. package/src/utils/composite-context-provider.test.ts +139 -0
  461. package/src/utils/composite-context-provider.ts +26 -8
  462. package/src/utils/notify-event-listeners.ts +10 -5
  463. package/src/utils/silent-runtime-action.ts +6 -0
@@ -42,9 +42,25 @@ import { generateId } from "../../utils/id";
42
42
  import { ToolInvocationTracker } from "../tool-invocations/ToolInvocationTracker";
43
43
  import { EMPTY_QUEUE_ITEMS } from "../../store/scopes/queue-item";
44
44
  import type { QuoteInfo } from "../../types/quote";
45
+ import {
46
+ captureThreadRuntimeGeneration,
47
+ isThreadRuntimeGenerationCurrent,
48
+ } from "../../runtime/utils/thread-runtime-lifecycle";
45
49
 
46
50
  const EMPTY_ARRAY: readonly ThreadSuggestion[] = Object.freeze([]);
47
51
 
52
+ const observeAdapterCallback = (
53
+ name: "onAddToolResult" | "onRespondToToolApproval" | "onCancel",
54
+ result: Promise<void> | void,
55
+ ) => {
56
+ void Promise.resolve(result).catch((error) => {
57
+ console.error(
58
+ `[ExternalStoreThreadRuntimeCore] ${name} callback rejected`,
59
+ error,
60
+ );
61
+ });
62
+ };
63
+
48
64
  const shallowEqual = (a: object, b: object): boolean => {
49
65
  const aKeys = Object.keys(a);
50
66
  if (aKeys.length !== Object.keys(b).length) return false;
@@ -122,6 +138,14 @@ export class ExternalStoreThreadRuntimeCore
122
138
 
123
139
  private _store!: ExternalStoreAdapter<any>;
124
140
 
141
+ private _getInitializePromise?: () => Promise<unknown> | undefined;
142
+
143
+ public __internal_setGetInitializePromise(
144
+ getPromise: () => Promise<unknown> | undefined,
145
+ ) {
146
+ this._getInitializePromise = getPromise;
147
+ }
148
+
125
149
  private _transformedQueue: ExternalThreadQueueAdapter | undefined;
126
150
 
127
151
  /**
@@ -375,19 +399,22 @@ export class ExternalStoreThreadRuntimeCore
375
399
  // rolled back). Drop the result.
376
400
  return;
377
401
  }
378
- this._store.onAddToolResult?.({
379
- messageId,
380
- toolCallId: command.toolCallId,
381
- toolName: command.toolName,
382
- result: command.result,
383
- isError: command.isError,
384
- ...(command.artifact !== undefined && {
385
- artifact: command.artifact,
402
+ observeAdapterCallback(
403
+ "onAddToolResult",
404
+ this._store.onAddToolResult?.({
405
+ messageId,
406
+ toolCallId: command.toolCallId,
407
+ toolName: command.toolName,
408
+ result: command.result,
409
+ isError: command.isError,
410
+ ...(command.artifact !== undefined && {
411
+ artifact: command.artifact,
412
+ }),
413
+ ...(command.modelContent !== undefined && {
414
+ modelContent: command.modelContent,
415
+ }),
386
416
  }),
387
- ...(command.modelContent !== undefined && {
388
- modelContent: command.modelContent,
389
- }),
390
- });
417
+ );
391
418
  } catch (err) {
392
419
  console.error(
393
420
  "[ExternalStoreThreadRuntimeCore] onAddToolResult dispatch failed",
@@ -492,22 +519,46 @@ export class ExternalStoreThreadRuntimeCore
492
519
  rawMessage.sourceId != null ||
493
520
  rawMessage.parentId !== (this.messages.at(-1)?.id ?? null);
494
521
 
495
- // Buffering does not start a run, so the tool-abort below must wait until
496
- // the queue flushes. By then the prior run (and its tools) has settled.
522
+ // A transformed-queue send is stamped at flush; any other queue's
523
+ // transform would gate against its own thread's messages, so those stamp
524
+ // at send.
525
+ const message =
526
+ !isEdit &&
527
+ this._store.queue &&
528
+ this._store.queue === this._transformedQueue
529
+ ? rawMessage
530
+ : this.enrichAppendMetadata(rawMessage);
531
+
532
+ const generation = captureThreadRuntimeGeneration(this);
533
+ this.ensureInitialized();
534
+
535
+ // The getter call is what starts thread initialization.
536
+ const initPromise = this._getInitializePromise?.();
537
+
538
+ // The queue driver dispatches through the host adapter, outside this
539
+ // core, so the initialization barrier must run before a message can
540
+ // enter the queue.
497
541
  if (!isEdit && this._store.queue) {
498
- // Skip only for the queue this core actually installed on: another
499
- // core's transform would gate against its own thread's messages.
500
- const queued =
501
- this._store.queue === this._transformedQueue
502
- ? rawMessage
503
- : this.enrichAppendMetadata(rawMessage);
504
- if (queued.steer ?? this._store.isRunning ?? false)
505
- this._store.queue.steer(queued);
506
- else this._store.queue.enqueue(queued);
542
+ if (initPromise) {
543
+ await initPromise;
544
+ }
545
+ if (!isThreadRuntimeGenerationCurrent(this, generation)) return;
546
+
547
+ // Buffering does not start a run, so the tool-abort below must wait
548
+ // until the queue flushes. By then the prior run (and its tools) has
549
+ // settled.
550
+ if (message.steer ?? this._store.isRunning ?? false)
551
+ this._store.queue.steer(message);
552
+ else this._store.queue.enqueue(message);
507
553
  return;
508
554
  }
509
555
 
510
- const message = this.enrichAppendMetadata(rawMessage);
556
+ // The optimistic insert lives inside the adapter's dispatch, so holding
557
+ // `onNew` on initialization would keep the message off screen for the
558
+ // whole roundtrip. Seams that need the remote identity await
559
+ // `threadListItem.initialize()` themselves, and a rejection surfaces
560
+ // there.
561
+ void initPromise?.catch(() => {});
511
562
 
512
563
  // Auto-abort in-flight client-side tool executions when a new run is
513
564
  // about to start. Without this, a tool that finishes after the new turn
@@ -518,6 +569,7 @@ export class ExternalStoreThreadRuntimeCore
518
569
  if (message.startRun ?? message.role === "user") {
519
570
  await this._toolInvocations?.abort();
520
571
  }
572
+ if (!isThreadRuntimeGenerationCurrent(this, generation)) return;
521
573
 
522
574
  if (isEdit) {
523
575
  if (!this._store.onEdit)
@@ -600,21 +652,30 @@ export class ExternalStoreThreadRuntimeCore
600
652
  // imported state) is treated as historical — no streamCall/execute
601
653
  // fires for the loaded tool calls. The adapter is expected to update
602
654
  // its messages in response to onLoadExternalState; that update flows
603
- // back here via __internal_setAdapter. We only clear adapter-side
604
- // tool statuses when the tracker is the source of truth — otherwise
605
- // we'd wipe statuses the adapter is managing on its own.
606
- if (this._toolInvocations) {
607
- this._toolInvocations.reset();
608
- this._store.setToolStatuses?.({});
609
- }
655
+ // back here via __internal_setAdapter. The tracker publishes the
656
+ // cleared status map itself, so adapter-side statuses reset only when
657
+ // the tracker is the source of truth.
658
+ this._toolInvocations?.reset();
610
659
 
611
660
  this._store.onLoadExternalState(state);
612
661
  }
613
662
 
663
+ /**
664
+ * Adapter-facing notification that the backing session was discarded.
665
+ * Clears session-scoped tool-invocation state and parks queued work,
666
+ * without run-cancel semantics (`onCancel`, composer draft restoration).
667
+ */
668
+ public unstable_notifySessionReset(): void {
669
+ this._toolInvocations?.reset();
670
+ this._store.queue?.__internal_notifyCancelled?.();
671
+ }
672
+
614
673
  public cancelRun(): void {
615
674
  if (!this._store.onCancel)
616
675
  throw new Error("Runtime does not support cancelling runs.");
617
676
 
677
+ const generation = captureThreadRuntimeGeneration(this);
678
+
618
679
  // Abort any in-flight client-side tool executions. Fire-and-forget —
619
680
  // the abort resolves once executions settle, but we don't gate the
620
681
  // cancel on it.
@@ -625,7 +686,7 @@ export class ExternalStoreThreadRuntimeCore
625
686
  // stopped.
626
687
  this._store.queue?.__internal_notifyCancelled?.();
627
688
 
628
- this._store.onCancel();
689
+ observeAdapterCallback("onCancel", this._store.onCancel());
629
690
 
630
691
  this.dropEmptyOptimisticHead();
631
692
 
@@ -672,6 +733,8 @@ export class ExternalStoreThreadRuntimeCore
672
733
  // tick. Read the repository at flush time and re-apply the rollbacks to
673
734
  // it, instead of stamping a snapshot captured above over the newer state.
674
735
  setTimeout(() => {
736
+ if (!isThreadRuntimeGenerationCurrent(this, generation)) return;
737
+
675
738
  this.dropEmptyOptimisticHead();
676
739
  if (movedLeaf) {
677
740
  const current = this.repository.getMessages();
@@ -700,7 +763,10 @@ export class ExternalStoreThreadRuntimeCore
700
763
  public addToolResult(options: AddToolResultOptions) {
701
764
  if (!this._store.onAddToolResult)
702
765
  throw new Error("Runtime does not support tool results.");
703
- this._store.onAddToolResult?.(options);
766
+ observeAdapterCallback(
767
+ "onAddToolResult",
768
+ this._store.onAddToolResult(options),
769
+ );
704
770
  }
705
771
 
706
772
  public resumeToolCall(options: ResumeToolCallOptions) {
@@ -726,7 +792,10 @@ export class ExternalStoreThreadRuntimeCore
726
792
  public respondToToolApproval(options: RespondToToolApprovalOptions) {
727
793
  if (!this._store.onRespondToToolApproval)
728
794
  throw new Error("Runtime does not support tool approvals.");
729
- this._store.onRespondToToolApproval(options);
795
+ observeAdapterCallback(
796
+ "onRespondToToolApproval",
797
+ this._store.onRespondToToolApproval(options),
798
+ );
730
799
  }
731
800
 
732
801
  public override reset(initialMessages?: readonly ThreadMessageLike[]) {
@@ -0,0 +1,253 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { BaseSubscribable } from "../../subscribable/subscribable";
3
+ import { ReadonlyThreadRuntimeCore } from "../readonly/ReadonlyThreadRuntimeCore";
4
+ import { EMPTY_THREAD_CORE } from "../remote-thread-list/empty-thread-core";
5
+
6
+ const READONLY_ERROR = /readonly thread/;
7
+ const EMPTY_ERROR = /empty thread/;
8
+
9
+ const SHARED_THROWING_METHODS = [
10
+ "switchToBranch",
11
+ "append",
12
+ "deleteMessage",
13
+ "startRun",
14
+ "resumeRun",
15
+ "unstable_notifySessionReset",
16
+ "addToolResult",
17
+ "resumeToolCall",
18
+ "respondToToolApproval",
19
+ "speak",
20
+ "connectVoice",
21
+ "muteVoice",
22
+ "unmuteVoice",
23
+ "submitFeedback",
24
+ "exportExternalState",
25
+ "importExternalState",
26
+ "beginEdit",
27
+ "import",
28
+ "reset",
29
+ ] as const;
30
+
31
+ const SHARED_THROWING_COMPOSER_METHODS = [
32
+ "setText",
33
+ "setRole",
34
+ "setRunConfig",
35
+ "send",
36
+ "startDictation",
37
+ "setQuote",
38
+ ] as const;
39
+
40
+ const SHARED_NOOP_COMPOSER_METHODS = [
41
+ "cancel",
42
+ "stopDictation",
43
+ "moveQueueItem",
44
+ "removeQueueItem",
45
+ ] as const;
46
+
47
+ type AnyCore = Record<string, any>;
48
+
49
+ const cores = [
50
+ [
51
+ "ReadonlyThreadRuntimeCore",
52
+ () => new ReadonlyThreadRuntimeCore() as unknown as AnyCore,
53
+ READONLY_ERROR,
54
+ ],
55
+ [
56
+ "EMPTY_THREAD_CORE",
57
+ () => EMPTY_THREAD_CORE as unknown as AnyCore,
58
+ EMPTY_ERROR,
59
+ ],
60
+ ] as const;
61
+
62
+ describe.each(cores)("%s shared inert surface", (_name, makeCore, error) => {
63
+ it.each(SHARED_THROWING_METHODS)("%s throws the core's error", (method) => {
64
+ expect(() => makeCore()[method]!()).toThrow(error);
65
+ });
66
+
67
+ it.each(SHARED_THROWING_COMPOSER_METHODS)(
68
+ "composer.%s throws the core's error",
69
+ (method) => {
70
+ expect(() => makeCore().composer[method]!()).toThrow(error);
71
+ },
72
+ );
73
+
74
+ it.each(["addAttachment", "removeAttachment"] as const)(
75
+ "composer.%s rejects with the core's error",
76
+ async (method) => {
77
+ await expect(makeCore().composer[method]!()).rejects.toThrow(error);
78
+ },
79
+ );
80
+
81
+ it.each(SHARED_NOOP_COMPOSER_METHODS)("composer.%s is a no-op", (method) => {
82
+ expect(() => makeCore().composer[method]!()).not.toThrow();
83
+ });
84
+
85
+ it("composer.reset and composer.clearAttachments resolve without throwing", async () => {
86
+ const core = makeCore();
87
+ await expect(core.composer.reset()).resolves.toBeUndefined();
88
+ await expect(core.composer.clearAttachments()).resolves.toBeUndefined();
89
+ });
90
+
91
+ it("reports every capability as disabled", () => {
92
+ expect(makeCore().capabilities).toEqual({
93
+ switchToBranch: false,
94
+ switchBranchDuringRun: false,
95
+ edit: false,
96
+ delete: false,
97
+ reload: false,
98
+ refetchThread: false,
99
+ cancel: false,
100
+ unstable_copy: false,
101
+ speech: false,
102
+ dictation: false,
103
+ voice: false,
104
+ attachments: false,
105
+ feedback: false,
106
+ queue: false,
107
+ });
108
+ });
109
+
110
+ it("exposes inert read-only state", () => {
111
+ const core = makeCore();
112
+ expect(core.getModelContext()).toEqual({});
113
+ expect(core.getEditComposer()).toBeUndefined();
114
+ expect(core.getVoiceVolume()).toBe(0);
115
+ expect(core.speech).toBeUndefined();
116
+ expect(core.voice).toBeUndefined();
117
+ expect(core.state).toBeNull();
118
+ expect(core.suggestions).toEqual([]);
119
+ expect(core.extras).toBeUndefined();
120
+ expect(core.isDisabled).toBe(false);
121
+ expect(core.isSendDisabled).toBe(false);
122
+ });
123
+
124
+ it("exposes an empty composer that accepts everything and holds nothing", () => {
125
+ const composer = makeCore().composer;
126
+ expect(composer.attachmentAccept).toBe("*");
127
+ expect(composer.attachments).toEqual([]);
128
+ expect(composer.text).toBe("");
129
+ expect(composer.role).toBe("user");
130
+ expect(composer.runConfig).toEqual({});
131
+ expect(composer.queue).toEqual([]);
132
+ expect(composer.dictation).toBeUndefined();
133
+ expect(composer.quote).toBeUndefined();
134
+ expect(composer.isEmpty).toBe(true);
135
+ expect(composer.canSend).toBe(false);
136
+ expect(composer.canCancel).toBe(false);
137
+ });
138
+
139
+ it("throws one stable error object from every mutator", () => {
140
+ const core = makeCore();
141
+ const thrown = SHARED_THROWING_METHODS.map((method) => {
142
+ try {
143
+ core[method]!();
144
+ return undefined;
145
+ } catch (e) {
146
+ return e;
147
+ }
148
+ });
149
+
150
+ expect(thrown[0]).toBeInstanceOf(Error);
151
+ expect(thrown.every((e) => e === thrown[0])).toBe(true);
152
+ });
153
+
154
+ it("throws a receiver TypeError when a mutator is detached", () => {
155
+ const detached = makeCore().append!;
156
+ expect(() => detached()).toThrow(TypeError);
157
+ });
158
+
159
+ it("subscribeVoiceVolume and unstable_on hand back no-op unsubscribers", () => {
160
+ const core = makeCore();
161
+ expect(() => core.subscribeVoiceVolume(() => {})()).not.toThrow();
162
+ expect(() => core.unstable_on("runStart", () => {})()).not.toThrow();
163
+ });
164
+ });
165
+
166
+ describe("no-op versus throw divergences", () => {
167
+ it.each(["cancelRun", "stopSpeaking", "disconnectVoice"] as const)(
168
+ "%s is a no-op on the readonly core but throws on the empty core",
169
+ (method) => {
170
+ const readonly = new ReadonlyThreadRuntimeCore() as unknown as AnyCore;
171
+ expect(() => readonly[method]!()).not.toThrow();
172
+ expect(() =>
173
+ (EMPTY_THREAD_CORE as unknown as AnyCore)[method]!(),
174
+ ).toThrow(EMPTY_ERROR);
175
+ },
176
+ );
177
+
178
+ it("readonly is not loading; empty is loading so it is not read as an empty conversation", () => {
179
+ expect(new ReadonlyThreadRuntimeCore().isLoading).toBe(false);
180
+ expect(EMPTY_THREAD_CORE.isLoading).toBe(true);
181
+ });
182
+
183
+ it("readonly composer is not editing; empty composer is", () => {
184
+ expect(new ReadonlyThreadRuntimeCore().composer.isEditing).toBe(false);
185
+ expect(EMPTY_THREAD_CORE.composer.isEditing).toBe(true);
186
+ });
187
+
188
+ it("the two cores carry distinct error objects and messages", () => {
189
+ const grab = (fn: () => void) => {
190
+ try {
191
+ fn();
192
+ return undefined;
193
+ } catch (e) {
194
+ return e as Error;
195
+ }
196
+ };
197
+
198
+ const readonlyError = grab(() => new ReadonlyThreadRuntimeCore().append());
199
+ const emptyError = grab(() =>
200
+ (EMPTY_THREAD_CORE as unknown as AnyCore).append!(),
201
+ );
202
+
203
+ expect(readonlyError).not.toBe(emptyError);
204
+ expect(readonlyError?.message).toBe(
205
+ "This is a readonly thread. You cannot perform mutations on readonly threads.",
206
+ );
207
+ expect(emptyError?.message).toMatch(/placeholder for the main thread/);
208
+ });
209
+ });
210
+
211
+ describe("readonly notifications", () => {
212
+ it("notifies subscribers and settles waitForUpdate when messages change", async () => {
213
+ const core = new ReadonlyThreadRuntimeCore();
214
+ const seen: number[] = [];
215
+ const unsubscribe = core.subscribe(() => {
216
+ seen.push(core.messages.length);
217
+ });
218
+ const update = core.waitForUpdate();
219
+
220
+ core.setMessages([
221
+ {
222
+ id: "m1",
223
+ role: "user",
224
+ content: [{ type: "text", text: "hi" }],
225
+ createdAt: new Date(0),
226
+ status: { type: "complete", reason: "stop" },
227
+ metadata: { custom: {} },
228
+ } as any,
229
+ ]);
230
+
231
+ await expect(update).resolves.toBeUndefined();
232
+ expect(seen).toEqual([1]);
233
+ unsubscribe();
234
+ });
235
+ });
236
+
237
+ describe("empty singleton", () => {
238
+ it("does not retain subscribe callbacks", () => {
239
+ const subscribers = (
240
+ EMPTY_THREAD_CORE as unknown as Record<string, unknown>
241
+ )._subscribers as Set<unknown>;
242
+ const before = subscribers.size;
243
+ const unsubscribe = EMPTY_THREAD_CORE.subscribe(() => undefined);
244
+ expect(subscribers.size).toBe(before);
245
+ expect(() => unsubscribe()).not.toThrow();
246
+ });
247
+
248
+ it("rejects waitForUpdate instead of hanging", async () => {
249
+ await expect(
250
+ (EMPTY_THREAD_CORE as unknown as BaseSubscribable).waitForUpdate(),
251
+ ).rejects.toThrow(EMPTY_ERROR);
252
+ });
253
+ });
@@ -0,0 +1,232 @@
1
+ import type { Unsubscribe } from "../../types/unsubscribe";
2
+ import type { ThreadMessage } from "../../types/message";
3
+ import type { ThreadRuntimeCore } from "../../runtime/interfaces/thread-runtime-core";
4
+ import type { ExportedMessageRepository } from "../../runtime/utils/message-repository";
5
+ import { BaseSubscribable } from "../../subscribable/subscribable";
6
+
7
+ export const createInertComposer = <TIsEditing extends boolean>(
8
+ error: Error,
9
+ isEditing: TIsEditing,
10
+ ) => ({
11
+ attachments: [] as never[],
12
+ attachmentAccept: "*",
13
+
14
+ async addAttachment() {
15
+ throw error;
16
+ },
17
+
18
+ async removeAttachment() {
19
+ throw error;
20
+ },
21
+
22
+ isEditing,
23
+ canCancel: false,
24
+ canSend: false,
25
+ isEmpty: true,
26
+ text: "",
27
+
28
+ setText() {
29
+ throw error;
30
+ },
31
+
32
+ role: "user" as const,
33
+
34
+ setRole() {
35
+ throw error;
36
+ },
37
+
38
+ runConfig: {},
39
+
40
+ setRunConfig() {
41
+ throw error;
42
+ },
43
+
44
+ async reset() {},
45
+
46
+ async clearAttachments() {},
47
+
48
+ send() {
49
+ throw error;
50
+ },
51
+
52
+ cancel() {},
53
+
54
+ queue: [] as never[],
55
+ moveQueueItem() {},
56
+ removeQueueItem() {},
57
+
58
+ dictation: undefined,
59
+
60
+ startDictation() {
61
+ throw error;
62
+ },
63
+
64
+ stopDictation() {},
65
+
66
+ quote: undefined,
67
+
68
+ setQuote() {
69
+ throw error;
70
+ },
71
+
72
+ subscribe() {
73
+ return () => {};
74
+ },
75
+
76
+ unstable_on() {
77
+ return () => {};
78
+ },
79
+ });
80
+
81
+ export abstract class InertThreadRuntimeCore
82
+ extends BaseSubscribable
83
+ implements ThreadRuntimeCore
84
+ {
85
+ protected abstract get error(): Error;
86
+
87
+ abstract readonly messages: readonly ThreadMessage[];
88
+ abstract readonly isLoading: boolean;
89
+ abstract readonly composer: ThreadRuntimeCore["composer"];
90
+
91
+ abstract getMessageById(messageId: string):
92
+ | {
93
+ parentId: string | null;
94
+ message: ThreadMessage;
95
+ index: number;
96
+ }
97
+ | undefined;
98
+
99
+ abstract getBranches(messageId: string): readonly string[];
100
+
101
+ abstract export(): ExportedMessageRepository;
102
+
103
+ switchToBranch(): void {
104
+ throw this.error;
105
+ }
106
+
107
+ append(): void {
108
+ throw this.error;
109
+ }
110
+
111
+ deleteMessage(): void {
112
+ throw this.error;
113
+ }
114
+
115
+ startRun(): void {
116
+ throw this.error;
117
+ }
118
+
119
+ resumeRun(): void {
120
+ throw this.error;
121
+ }
122
+
123
+ cancelRun(): void {
124
+ throw this.error;
125
+ }
126
+
127
+ unstable_notifySessionReset(): void {
128
+ throw this.error;
129
+ }
130
+
131
+ addToolResult(): void {
132
+ throw this.error;
133
+ }
134
+
135
+ resumeToolCall(): void {
136
+ throw this.error;
137
+ }
138
+
139
+ respondToToolApproval(): void {
140
+ throw this.error;
141
+ }
142
+
143
+ speak(): void {
144
+ throw this.error;
145
+ }
146
+
147
+ stopSpeaking(): void {
148
+ throw this.error;
149
+ }
150
+
151
+ connectVoice(): void {
152
+ throw this.error;
153
+ }
154
+
155
+ disconnectVoice(): void {
156
+ throw this.error;
157
+ }
158
+
159
+ muteVoice(): void {
160
+ throw this.error;
161
+ }
162
+
163
+ unmuteVoice(): void {
164
+ throw this.error;
165
+ }
166
+
167
+ submitFeedback(): void {
168
+ throw this.error;
169
+ }
170
+
171
+ exportExternalState(): void {
172
+ throw this.error;
173
+ }
174
+
175
+ importExternalState(): void {
176
+ throw this.error;
177
+ }
178
+
179
+ beginEdit(): void {
180
+ throw this.error;
181
+ }
182
+
183
+ import(): void {
184
+ throw this.error;
185
+ }
186
+
187
+ reset(): void {
188
+ throw this.error;
189
+ }
190
+
191
+ getModelContext() {
192
+ return {};
193
+ }
194
+
195
+ getEditComposer() {
196
+ return undefined;
197
+ }
198
+
199
+ getVoiceVolume = () => 0;
200
+ subscribeVoiceVolume = (): Unsubscribe => () => {};
201
+
202
+ speech = undefined;
203
+ voice = undefined;
204
+
205
+ capabilities = {
206
+ switchToBranch: false,
207
+ switchBranchDuringRun: false,
208
+ edit: false,
209
+ delete: false,
210
+ reload: false,
211
+ refetchThread: false,
212
+ cancel: false,
213
+ unstable_copy: false,
214
+ speech: false,
215
+ dictation: false,
216
+ voice: false,
217
+ attachments: false,
218
+ feedback: false,
219
+ queue: false,
220
+ } as const;
221
+
222
+ isDisabled = false;
223
+ isSendDisabled = false;
224
+
225
+ state = null;
226
+ suggestions = [] as never[];
227
+ extras = undefined;
228
+
229
+ unstable_on(): Unsubscribe {
230
+ return () => {};
231
+ }
232
+ }