@assistant-ui/core 0.2.20 → 0.2.22

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 (610) hide show
  1. package/dist/adapters/attachment.d.ts +2 -2
  2. package/dist/adapters/attachment.d.ts.map +1 -1
  3. package/dist/adapters/attachment.js +14 -7
  4. package/dist/adapters/attachment.js.map +1 -1
  5. package/dist/adapters/directive-formatter.d.ts +0 -1
  6. package/dist/adapters/directive-formatter.d.ts.map +1 -1
  7. package/dist/adapters/feedback.d.ts +0 -1
  8. package/dist/adapters/feedback.d.ts.map +1 -1
  9. package/dist/adapters/index.d.ts +2 -2
  10. package/dist/adapters/index.js +2 -1
  11. package/dist/adapters/speech.d.ts +0 -1
  12. package/dist/adapters/speech.d.ts.map +1 -1
  13. package/dist/adapters/speech.js +9 -2
  14. package/dist/adapters/speech.js.map +1 -1
  15. package/dist/adapters/suggestion.d.ts +16 -2
  16. package/dist/adapters/suggestion.d.ts.map +1 -1
  17. package/dist/adapters/suggestion.js +36 -0
  18. package/dist/adapters/suggestion.js.map +1 -0
  19. package/dist/adapters/thread-history.d.ts +2 -2
  20. package/dist/adapters/thread-history.d.ts.map +1 -1
  21. package/dist/adapters/trigger.d.ts +5 -3
  22. package/dist/adapters/trigger.d.ts.map +1 -1
  23. package/dist/adapters/voice.d.ts +0 -1
  24. package/dist/adapters/voice.d.ts.map +1 -1
  25. package/dist/adapters/voice.js +13 -5
  26. package/dist/adapters/voice.js.map +1 -1
  27. package/dist/index.d.ts +4 -3
  28. package/dist/index.js +3 -1
  29. package/dist/index.js.map +1 -1
  30. package/dist/internal/duplicate-detection.d.ts.map +1 -1
  31. package/dist/internal.d.ts +9 -1
  32. package/dist/internal.js +8 -2
  33. package/dist/model-context/frame/host.d.ts +1 -1
  34. package/dist/model-context/frame/host.d.ts.map +1 -1
  35. package/dist/model-context/frame/host.js +5 -0
  36. package/dist/model-context/frame/host.js.map +1 -1
  37. package/dist/model-context/frame/provider.d.ts +0 -1
  38. package/dist/model-context/frame/provider.d.ts.map +1 -1
  39. package/dist/model-context/frame/provider.js +1 -0
  40. package/dist/model-context/frame/provider.js.map +1 -1
  41. package/dist/model-context/frame/types.d.ts.map +1 -1
  42. package/dist/model-context/interactable-composer-metadata.d.ts +4 -2
  43. package/dist/model-context/interactable-composer-metadata.d.ts.map +1 -1
  44. package/dist/model-context/interactable-composer-metadata.js.map +1 -1
  45. package/dist/model-context/registry-handles.d.ts +0 -1
  46. package/dist/model-context/registry-handles.d.ts.map +1 -1
  47. package/dist/model-context/registry.d.ts +0 -1
  48. package/dist/model-context/registry.d.ts.map +1 -1
  49. package/dist/model-context/tool.d.ts +23 -9
  50. package/dist/model-context/tool.d.ts.map +1 -1
  51. package/dist/model-context/tool.js +0 -25
  52. package/dist/model-context/tool.js.map +1 -1
  53. package/dist/model-context/types.d.ts +0 -1
  54. package/dist/model-context/types.d.ts.map +1 -1
  55. package/dist/react/AssistantProvider.d.ts +0 -1
  56. package/dist/react/AssistantProvider.d.ts.map +1 -1
  57. package/dist/react/AssistantProvider.js.map +1 -1
  58. package/dist/react/AssistantRuntimeProvider.d.ts +1 -6
  59. package/dist/react/AssistantRuntimeProvider.d.ts.map +1 -1
  60. package/dist/react/RuntimeAdapter.d.ts +1 -0
  61. package/dist/react/RuntimeAdapter.d.ts.map +1 -1
  62. package/dist/react/adapters/LocalStorageThreadListAdapter.d.ts +13 -2
  63. package/dist/react/adapters/LocalStorageThreadListAdapter.d.ts.map +1 -1
  64. package/dist/react/adapters/LocalStorageThreadListAdapter.js +196 -54
  65. package/dist/react/adapters/LocalStorageThreadListAdapter.js.map +1 -1
  66. package/dist/react/adapters/TitleGenerationAdapter.d.ts +0 -1
  67. package/dist/react/adapters/TitleGenerationAdapter.d.ts.map +1 -1
  68. package/dist/react/client/DataRenderers.d.ts +0 -1
  69. package/dist/react/client/DataRenderers.d.ts.map +1 -1
  70. package/dist/react/client/Interactables.d.ts +0 -1
  71. package/dist/react/client/Interactables.d.ts.map +1 -1
  72. package/dist/react/client/Interactables.js.map +1 -1
  73. package/dist/react/client/Tools.d.ts +3 -2
  74. package/dist/react/client/Tools.d.ts.map +1 -1
  75. package/dist/react/client/interactable-model-context.d.ts +0 -1
  76. package/dist/react/client/interactable-model-context.d.ts.map +1 -1
  77. package/dist/react/index.d.ts +2 -2
  78. package/dist/react/interactables-legacy/Interactables.d.ts +0 -1
  79. package/dist/react/interactables-legacy/Interactables.d.ts.map +1 -1
  80. package/dist/react/interactables-legacy/interactable-model-context.d.ts +0 -1
  81. package/dist/react/interactables-legacy/interactable-model-context.d.ts.map +1 -1
  82. package/dist/react/interactables-legacy/scopes.d.ts +4 -2
  83. package/dist/react/interactables-legacy/scopes.d.ts.map +1 -1
  84. package/dist/react/interactables-legacy/useAssistantInteractable.d.ts +0 -1
  85. package/dist/react/interactables-legacy/useAssistantInteractable.d.ts.map +1 -1
  86. package/dist/react/interactables-legacy/useInteractableState.d.ts.map +1 -1
  87. package/dist/react/model-context/define-mcp-toolkit.d.ts +19 -4
  88. package/dist/react/model-context/define-mcp-toolkit.d.ts.map +1 -1
  89. package/dist/react/model-context/define-mcp-toolkit.js +17 -5
  90. package/dist/react/model-context/define-mcp-toolkit.js.map +1 -1
  91. package/dist/react/model-context/define-toolkit.d.ts +1 -2
  92. package/dist/react/model-context/define-toolkit.d.ts.map +1 -1
  93. package/dist/react/model-context/external-tool.d.ts.map +1 -1
  94. package/dist/react/model-context/human-tool.d.ts.map +1 -1
  95. package/dist/react/model-context/interactableTool.d.ts +2 -2
  96. package/dist/react/model-context/interactableTool.d.ts.map +1 -1
  97. package/dist/react/model-context/makeAssistantDataUI.d.ts +2 -2
  98. package/dist/react/model-context/makeAssistantDataUI.d.ts.map +1 -1
  99. package/dist/react/model-context/makeAssistantTool.d.ts +2 -2
  100. package/dist/react/model-context/makeAssistantTool.d.ts.map +1 -1
  101. package/dist/react/model-context/makeAssistantToolUI.d.ts +2 -2
  102. package/dist/react/model-context/makeAssistantToolUI.d.ts.map +1 -1
  103. package/dist/react/model-context/provider-tool.d.ts +0 -1
  104. package/dist/react/model-context/provider-tool.d.ts.map +1 -1
  105. package/dist/react/model-context/stub-tool.d.ts.map +1 -1
  106. package/dist/react/model-context/toolbox.d.ts +5 -5
  107. package/dist/react/model-context/toolbox.d.ts.map +1 -1
  108. package/dist/react/model-context/useAssistantContext.d.ts +1 -0
  109. package/dist/react/model-context/useAssistantContext.d.ts.map +1 -1
  110. package/dist/react/model-context/useAssistantDataUI.d.ts +3 -2
  111. package/dist/react/model-context/useAssistantDataUI.d.ts.map +1 -1
  112. package/dist/react/model-context/useAssistantInstructions.d.ts +1 -0
  113. package/dist/react/model-context/useAssistantInstructions.d.ts.map +1 -1
  114. package/dist/react/model-context/useAssistantTool.d.ts +4 -2
  115. package/dist/react/model-context/useAssistantTool.d.ts.map +1 -1
  116. package/dist/react/model-context/useAssistantToolUI.d.ts +3 -2
  117. package/dist/react/model-context/useAssistantToolUI.d.ts.map +1 -1
  118. package/dist/react/model-context/useAuiToolOverrides.d.ts +0 -1
  119. package/dist/react/model-context/useAuiToolOverrides.d.ts.map +1 -1
  120. package/dist/react/model-context/useInlineRender.d.ts +0 -1
  121. package/dist/react/model-context/useInlineRender.d.ts.map +1 -1
  122. package/dist/react/model-context/useInteractable.d.ts +7 -4
  123. package/dist/react/model-context/useInteractable.d.ts.map +1 -1
  124. package/dist/react/model-context/useInteractable.js.map +1 -1
  125. package/dist/react/model-context/useInteractableState.d.ts.map +1 -1
  126. package/dist/react/model-context/useInteractableVersions.d.ts +0 -1
  127. package/dist/react/model-context/useInteractableVersions.d.ts.map +1 -1
  128. package/dist/react/model-context/useToolArgsStatus.d.ts +3 -1
  129. package/dist/react/model-context/useToolArgsStatus.d.ts.map +1 -1
  130. package/dist/react/primitive-hooks/useActionBarCopy.d.ts +1 -4
  131. package/dist/react/primitive-hooks/useActionBarCopy.d.ts.map +1 -1
  132. package/dist/react/primitive-hooks/useActionBarCopy.js +13 -13
  133. package/dist/react/primitive-hooks/useActionBarCopy.js.map +1 -1
  134. package/dist/react/primitive-hooks/useActionBarEdit.d.ts.map +1 -1
  135. package/dist/react/primitive-hooks/useActionBarFeedback.d.ts.map +1 -1
  136. package/dist/react/primitive-hooks/useActionBarReload.d.ts.map +1 -1
  137. package/dist/react/primitive-hooks/useActionBarSpeak.d.ts.map +1 -1
  138. package/dist/react/primitive-hooks/useActionBarStopSpeaking.d.ts.map +1 -1
  139. package/dist/react/primitive-hooks/useBranchPickerNext.d.ts.map +1 -1
  140. package/dist/react/primitive-hooks/useBranchPickerPrevious.d.ts.map +1 -1
  141. package/dist/react/primitive-hooks/useComposerAddAttachment.d.ts +0 -1
  142. package/dist/react/primitive-hooks/useComposerAddAttachment.d.ts.map +1 -1
  143. package/dist/react/primitive-hooks/useComposerCancel.d.ts.map +1 -1
  144. package/dist/react/primitive-hooks/useComposerDictate.d.ts.map +1 -1
  145. package/dist/react/primitive-hooks/useComposerSend.d.ts +0 -1
  146. package/dist/react/primitive-hooks/useComposerSend.d.ts.map +1 -1
  147. package/dist/react/primitive-hooks/useEditComposerCancel.d.ts.map +1 -1
  148. package/dist/react/primitive-hooks/useEditComposerSend.d.ts.map +1 -1
  149. package/dist/react/primitive-hooks/useMessageBranching.d.ts.map +1 -1
  150. package/dist/react/primitive-hooks/useMessageError.d.ts.map +1 -1
  151. package/dist/react/primitive-hooks/useMessageError.js +5 -1
  152. package/dist/react/primitive-hooks/useMessageError.js.map +1 -1
  153. package/dist/react/primitive-hooks/useMessageReload.d.ts.map +1 -1
  154. package/dist/react/primitive-hooks/useSuggestionTrigger.d.ts +1 -5
  155. package/dist/react/primitive-hooks/useSuggestionTrigger.d.ts.map +1 -1
  156. package/dist/react/primitive-hooks/useThreadIsEmpty.d.ts.map +1 -1
  157. package/dist/react/primitive-hooks/useThreadIsRunning.d.ts.map +1 -1
  158. package/dist/react/primitive-hooks/useThreadListItemArchive.d.ts.map +1 -1
  159. package/dist/react/primitive-hooks/useThreadListItemDelete.d.ts.map +1 -1
  160. package/dist/react/primitive-hooks/useThreadListItemTrigger.d.ts.map +1 -1
  161. package/dist/react/primitive-hooks/useThreadListItemUnarchive.d.ts.map +1 -1
  162. package/dist/react/primitive-hooks/useThreadListLoadMore.d.ts.map +1 -1
  163. package/dist/react/primitive-hooks/useThreadListNew.d.ts.map +1 -1
  164. package/dist/react/primitive-hooks/useThreadMessageIds.d.ts.map +1 -1
  165. package/dist/react/primitive-hooks/useThreadMessages.d.ts +0 -1
  166. package/dist/react/primitive-hooks/useThreadMessages.d.ts.map +1 -1
  167. package/dist/react/primitive-hooks/useVoice.d.ts +0 -1
  168. package/dist/react/primitive-hooks/useVoice.d.ts.map +1 -1
  169. package/dist/react/primitives/chainOfThought/ChainOfThoughtParts.d.ts +7 -4
  170. package/dist/react/primitives/chainOfThought/ChainOfThoughtParts.d.ts.map +1 -1
  171. package/dist/react/primitives/chainOfThought/ChainOfThoughtParts.js +1 -1
  172. package/dist/react/primitives/chainOfThought/ChainOfThoughtParts.js.map +1 -1
  173. package/dist/react/primitives/composer/ComposerAttachments.d.ts +4 -3
  174. package/dist/react/primitives/composer/ComposerAttachments.d.ts.map +1 -1
  175. package/dist/react/primitives/composer/ComposerAttachments.js.map +1 -1
  176. package/dist/react/primitives/composer/ComposerIf.d.ts +4 -3
  177. package/dist/react/primitives/composer/ComposerIf.d.ts.map +1 -1
  178. package/dist/react/primitives/composer/ComposerQueue.d.ts +2 -2
  179. package/dist/react/primitives/composer/ComposerQueue.d.ts.map +1 -1
  180. package/dist/react/primitives/composer/ComposerQueue.js.map +1 -1
  181. package/dist/react/primitives/generativeUI/GenerativeUI.d.ts +2 -2
  182. package/dist/react/primitives/generativeUI/GenerativeUI.d.ts.map +1 -1
  183. package/dist/react/primitives/message/MessageAttachments.d.ts +4 -3
  184. package/dist/react/primitives/message/MessageAttachments.d.ts.map +1 -1
  185. package/dist/react/primitives/message/MessageAttachments.js.map +1 -1
  186. package/dist/react/primitives/message/MessageGroupedParts.d.ts +1 -6
  187. package/dist/react/primitives/message/MessageGroupedParts.d.ts.map +1 -1
  188. package/dist/react/primitives/message/MessageGroupedParts.js.map +1 -1
  189. package/dist/react/primitives/message/MessageParts.d.ts +44 -25
  190. package/dist/react/primitives/message/MessageParts.d.ts.map +1 -1
  191. package/dist/react/primitives/message/MessageParts.js +48 -37
  192. package/dist/react/primitives/message/MessageParts.js.map +1 -1
  193. package/dist/react/primitives/message/MessageQuote.d.ts +2 -2
  194. package/dist/react/primitives/message/MessageQuote.d.ts.map +1 -1
  195. package/dist/react/primitives/messagePart/MessagePartInProgress.d.ts +0 -1
  196. package/dist/react/primitives/messagePart/MessagePartInProgress.d.ts.map +1 -1
  197. package/dist/react/primitives/part/PartMessages.d.ts +2 -2
  198. package/dist/react/primitives/part/PartMessages.d.ts.map +1 -1
  199. package/dist/react/primitives/part/PartMessages.js.map +1 -1
  200. package/dist/react/primitives/thread/ThreadMessages.d.ts +35 -17
  201. package/dist/react/primitives/thread/ThreadMessages.d.ts.map +1 -1
  202. package/dist/react/primitives/thread/ThreadMessages.js.map +1 -1
  203. package/dist/react/primitives/thread/ThreadSuggestions.d.ts +6 -4
  204. package/dist/react/primitives/thread/ThreadSuggestions.d.ts.map +1 -1
  205. package/dist/react/primitives/thread/ThreadSuggestions.js.map +1 -1
  206. package/dist/react/primitives/threadList/ThreadListItems.d.ts +4 -3
  207. package/dist/react/primitives/threadList/ThreadListItems.d.ts.map +1 -1
  208. package/dist/react/primitives/threadList/ThreadListItems.js.map +1 -1
  209. package/dist/react/primitives/threadListItem/ThreadListItemTitle.d.ts +0 -1
  210. package/dist/react/primitives/threadListItem/ThreadListItemTitle.d.ts.map +1 -1
  211. package/dist/react/providers/AttachmentByIndexProvider.d.ts +0 -1
  212. package/dist/react/providers/AttachmentByIndexProvider.d.ts.map +1 -1
  213. package/dist/react/providers/ChainOfThoughtByIndicesProvider.d.ts +0 -1
  214. package/dist/react/providers/ChainOfThoughtByIndicesProvider.d.ts.map +1 -1
  215. package/dist/react/providers/ChainOfThoughtPartByIndexProvider.d.ts +0 -1
  216. package/dist/react/providers/ChainOfThoughtPartByIndexProvider.d.ts.map +1 -1
  217. package/dist/react/providers/ChainOfThoughtPartByIndexProvider.js +18 -30
  218. package/dist/react/providers/ChainOfThoughtPartByIndexProvider.js.map +1 -1
  219. package/dist/react/providers/MessageByIdProvider.d.ts +0 -1
  220. package/dist/react/providers/MessageByIdProvider.d.ts.map +1 -1
  221. package/dist/react/providers/MessageByIndexProvider.d.ts +0 -1
  222. package/dist/react/providers/MessageByIndexProvider.d.ts.map +1 -1
  223. package/dist/react/providers/PartByIndexProvider.d.ts +0 -1
  224. package/dist/react/providers/PartByIndexProvider.d.ts.map +1 -1
  225. package/dist/react/providers/PartByIndexProvider.js +18 -30
  226. package/dist/react/providers/PartByIndexProvider.js.map +1 -1
  227. package/dist/react/providers/QueueItemByIndexProvider.d.ts +0 -1
  228. package/dist/react/providers/QueueItemByIndexProvider.d.ts.map +1 -1
  229. package/dist/react/providers/ReadonlyThreadProvider.d.ts +0 -1
  230. package/dist/react/providers/ReadonlyThreadProvider.d.ts.map +1 -1
  231. package/dist/react/providers/SuggestionByIndexProvider.d.ts +0 -1
  232. package/dist/react/providers/SuggestionByIndexProvider.d.ts.map +1 -1
  233. package/dist/react/providers/TextMessagePartProvider.d.ts +0 -1
  234. package/dist/react/providers/TextMessagePartProvider.d.ts.map +1 -1
  235. package/dist/react/providers/ThreadListItemByIndexProvider.d.ts +0 -1
  236. package/dist/react/providers/ThreadListItemByIndexProvider.d.ts.map +1 -1
  237. package/dist/react/providers/ThreadListItemRuntimeProvider.d.ts +1 -1
  238. package/dist/react/providers/ThreadListItemRuntimeProvider.d.ts.map +1 -1
  239. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts +2 -1
  240. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
  241. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +2 -1
  242. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
  243. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +12 -3
  244. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
  245. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +70 -27
  246. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
  247. package/dist/react/runtimes/RuntimeAdapterProvider.d.ts +0 -1
  248. package/dist/react/runtimes/RuntimeAdapterProvider.d.ts.map +1 -1
  249. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts +0 -1
  250. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
  251. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +1 -1
  252. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
  253. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts +1 -4
  254. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts.map +1 -1
  255. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js +8 -4
  256. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js.map +1 -1
  257. package/dist/react/runtimes/cloud/auiV0.d.ts +12 -2
  258. package/dist/react/runtimes/cloud/auiV0.d.ts.map +1 -1
  259. package/dist/react/runtimes/cloud/auiV0.js +30 -1
  260. package/dist/react/runtimes/cloud/auiV0.js.map +1 -1
  261. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.d.ts +0 -1
  262. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.d.ts.map +1 -1
  263. package/dist/react/runtimes/createMessageConverter.d.ts +1 -7
  264. package/dist/react/runtimes/createMessageConverter.d.ts.map +1 -1
  265. package/dist/react/runtimes/createRuntimeExtras.d.ts +0 -1
  266. package/dist/react/runtimes/createRuntimeExtras.d.ts.map +1 -1
  267. package/dist/react/runtimes/external-message-converter.d.ts +1 -8
  268. package/dist/react/runtimes/external-message-converter.d.ts.map +1 -1
  269. package/dist/react/runtimes/external-message-converter.js +43 -45
  270. package/dist/react/runtimes/external-message-converter.js.map +1 -1
  271. package/dist/react/runtimes/useExternalStoreRuntime.d.ts +0 -1
  272. package/dist/react/runtimes/useExternalStoreRuntime.d.ts.map +1 -1
  273. package/dist/react/runtimes/useExternalStoreSharedOptions.d.ts +0 -1
  274. package/dist/react/runtimes/useExternalStoreSharedOptions.d.ts.map +1 -1
  275. package/dist/react/runtimes/useLocalRuntime.d.ts +3 -5
  276. package/dist/react/runtimes/useLocalRuntime.d.ts.map +1 -1
  277. package/dist/react/runtimes/useLocalRuntime.js +9 -1
  278. package/dist/react/runtimes/useLocalRuntime.js.map +1 -1
  279. package/dist/react/runtimes/useRemoteThreadListRuntime.d.ts +0 -1
  280. package/dist/react/runtimes/useRemoteThreadListRuntime.d.ts.map +1 -1
  281. package/dist/react/runtimes/useStreamingTiming.d.ts +0 -1
  282. package/dist/react/runtimes/useStreamingTiming.d.ts.map +1 -1
  283. package/dist/react/types/MessagePartComponentTypes.d.ts +6 -3
  284. package/dist/react/types/MessagePartComponentTypes.d.ts.map +1 -1
  285. package/dist/react/types/scopes/dataRenderers.d.ts +1 -1
  286. package/dist/react/types/scopes/dataRenderers.d.ts.map +1 -1
  287. package/dist/react/types/scopes/interactables.d.ts +4 -2
  288. package/dist/react/types/scopes/interactables.d.ts.map +1 -1
  289. package/dist/react/types/scopes/tools.d.ts +5 -3
  290. package/dist/react/types/scopes/tools.d.ts.map +1 -1
  291. package/dist/react/types/store-augmentation.d.ts +1 -2
  292. package/dist/react/types/store-augmentation.d.ts.map +1 -1
  293. package/dist/react/utils/getMessageQuote.d.ts +0 -1
  294. package/dist/react/utils/getMessageQuote.d.ts.map +1 -1
  295. package/dist/react/utils/groupParts.d.ts +2 -2
  296. package/dist/react/utils/groupParts.d.ts.map +1 -1
  297. package/dist/react/utils/useJSONEqual.d.ts.map +1 -1
  298. package/dist/runtime/api/assistant-runtime.d.ts +0 -1
  299. package/dist/runtime/api/assistant-runtime.d.ts.map +1 -1
  300. package/dist/runtime/api/attachment-runtime.d.ts +0 -1
  301. package/dist/runtime/api/attachment-runtime.d.ts.map +1 -1
  302. package/dist/runtime/api/bindings.d.ts +0 -1
  303. package/dist/runtime/api/bindings.d.ts.map +1 -1
  304. package/dist/runtime/api/composer-runtime.d.ts +6 -4
  305. package/dist/runtime/api/composer-runtime.d.ts.map +1 -1
  306. package/dist/runtime/api/message-part-runtime.d.ts +0 -1
  307. package/dist/runtime/api/message-part-runtime.d.ts.map +1 -1
  308. package/dist/runtime/api/message-runtime.d.ts +6 -16
  309. package/dist/runtime/api/message-runtime.d.ts.map +1 -1
  310. package/dist/runtime/api/message-runtime.js +5 -5
  311. package/dist/runtime/api/message-runtime.js.map +1 -1
  312. package/dist/runtime/api/paths.d.ts.map +1 -1
  313. package/dist/runtime/api/thread-list-item-runtime.d.ts +0 -1
  314. package/dist/runtime/api/thread-list-item-runtime.d.ts.map +1 -1
  315. package/dist/runtime/api/thread-list-item-runtime.js +2 -1
  316. package/dist/runtime/api/thread-list-item-runtime.js.map +1 -1
  317. package/dist/runtime/api/thread-list-runtime.d.ts +0 -1
  318. package/dist/runtime/api/thread-list-runtime.d.ts.map +1 -1
  319. package/dist/runtime/api/thread-runtime.d.ts +3 -1
  320. package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
  321. package/dist/runtime/base/base-assistant-runtime-core.d.ts +0 -1
  322. package/dist/runtime/base/base-assistant-runtime-core.d.ts.map +1 -1
  323. package/dist/runtime/base/base-composer-runtime-core.d.ts +4 -2
  324. package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
  325. package/dist/runtime/base/base-composer-runtime-core.js +51 -10
  326. package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
  327. package/dist/runtime/base/base-thread-runtime-core.d.ts +2 -4
  328. package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
  329. package/dist/runtime/base/base-thread-runtime-core.js +3 -2
  330. package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
  331. package/dist/runtime/base/default-edit-composer-runtime-core.d.ts +1 -5
  332. package/dist/runtime/base/default-edit-composer-runtime-core.d.ts.map +1 -1
  333. package/dist/runtime/base/default-edit-composer-runtime-core.js +4 -2
  334. package/dist/runtime/base/default-edit-composer-runtime-core.js.map +1 -1
  335. package/dist/runtime/base/default-thread-composer-runtime-core.d.ts +1 -0
  336. package/dist/runtime/base/default-thread-composer-runtime-core.d.ts.map +1 -1
  337. package/dist/runtime/base/default-thread-composer-runtime-core.js +2 -2
  338. package/dist/runtime/base/default-thread-composer-runtime-core.js.map +1 -1
  339. package/dist/runtime/branch/external-thread-branch-adapter.d.ts.map +1 -1
  340. package/dist/runtime/interfaces/assistant-runtime-core.d.ts +0 -1
  341. package/dist/runtime/interfaces/assistant-runtime-core.d.ts.map +1 -1
  342. package/dist/runtime/interfaces/composer-runtime-core.d.ts +2 -2
  343. package/dist/runtime/interfaces/composer-runtime-core.d.ts.map +1 -1
  344. package/dist/runtime/interfaces/thread-list-runtime-core.d.ts +0 -1
  345. package/dist/runtime/interfaces/thread-list-runtime-core.d.ts.map +1 -1
  346. package/dist/runtime/interfaces/thread-runtime-core.d.ts +2 -2
  347. package/dist/runtime/interfaces/thread-runtime-core.d.ts.map +1 -1
  348. package/dist/runtime/queue/external-thread-queue-adapter.d.ts +0 -1
  349. package/dist/runtime/queue/external-thread-queue-adapter.d.ts.map +1 -1
  350. package/dist/runtime/queue/message-queue.d.ts +6 -4
  351. package/dist/runtime/queue/message-queue.d.ts.map +1 -1
  352. package/dist/runtime/queue/message-queue.js +1 -1
  353. package/dist/runtime/utils/auto-status.d.ts +0 -1
  354. package/dist/runtime/utils/auto-status.d.ts.map +1 -1
  355. package/dist/runtime/utils/chat-model-adapter.d.ts +0 -1
  356. package/dist/runtime/utils/chat-model-adapter.d.ts.map +1 -1
  357. package/dist/runtime/utils/external-store-message.d.ts +0 -1
  358. package/dist/runtime/utils/external-store-message.d.ts.map +1 -1
  359. package/dist/runtime/utils/message-repository.d.ts +1 -5
  360. package/dist/runtime/utils/message-repository.d.ts.map +1 -1
  361. package/dist/runtime/utils/message-repository.js +3 -1
  362. package/dist/runtime/utils/message-repository.js.map +1 -1
  363. package/dist/runtime/utils/resolveToolApprovalResponse.d.ts +0 -1
  364. package/dist/runtime/utils/resolveToolApprovalResponse.d.ts.map +1 -1
  365. package/dist/runtime/utils/streaming-timing.d.ts +5 -3
  366. package/dist/runtime/utils/streaming-timing.d.ts.map +1 -1
  367. package/dist/runtime/utils/thread-message-like.d.ts +2 -2
  368. package/dist/runtime/utils/thread-message-like.d.ts.map +1 -1
  369. package/dist/runtime/utils/thread-message-like.js +4 -1
  370. package/dist/runtime/utils/thread-message-like.js.map +1 -1
  371. package/dist/runtimes/assistant-transport/utils.d.ts.map +1 -1
  372. package/dist/runtimes/external-store/external-store-adapter.d.ts +2 -2
  373. package/dist/runtimes/external-store/external-store-adapter.d.ts.map +1 -1
  374. package/dist/runtimes/external-store/external-store-runtime-core.d.ts +0 -1
  375. package/dist/runtimes/external-store/external-store-runtime-core.d.ts.map +1 -1
  376. package/dist/runtimes/external-store/external-store-shared-options.d.ts +0 -1
  377. package/dist/runtimes/external-store/external-store-shared-options.d.ts.map +1 -1
  378. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts +0 -1
  379. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts.map +1 -1
  380. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts +2 -0
  381. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
  382. package/dist/runtimes/external-store/external-store-thread-runtime-core.js +1 -1
  383. package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
  384. package/dist/runtimes/external-store/thread-message-converter.d.ts +0 -1
  385. package/dist/runtimes/external-store/thread-message-converter.d.ts.map +1 -1
  386. package/dist/runtimes/local/local-runtime-core.d.ts +0 -1
  387. package/dist/runtimes/local/local-runtime-core.d.ts.map +1 -1
  388. package/dist/runtimes/local/local-runtime-options.d.ts +0 -1
  389. package/dist/runtimes/local/local-runtime-options.d.ts.map +1 -1
  390. package/dist/runtimes/local/local-thread-list-runtime-core.d.ts +0 -1
  391. package/dist/runtimes/local/local-thread-list-runtime-core.d.ts.map +1 -1
  392. package/dist/runtimes/local/local-thread-runtime-core.d.ts +5 -21
  393. package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
  394. package/dist/runtimes/local/local-thread-runtime-core.js +29 -17
  395. package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
  396. package/dist/runtimes/local/should-continue.d.ts +0 -1
  397. package/dist/runtimes/local/should-continue.d.ts.map +1 -1
  398. package/dist/runtimes/local/should-continue.js +2 -2
  399. package/dist/runtimes/local/should-continue.js.map +1 -1
  400. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts +0 -1
  401. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts.map +1 -1
  402. package/dist/runtimes/remote-thread-list/adapter/in-memory.d.ts +1 -2
  403. package/dist/runtimes/remote-thread-list/adapter/in-memory.d.ts.map +1 -1
  404. package/dist/runtimes/remote-thread-list/adapter/in-memory.js +5 -3
  405. package/dist/runtimes/remote-thread-list/adapter/in-memory.js.map +1 -1
  406. package/dist/runtimes/remote-thread-list/empty-thread-core.d.ts +0 -1
  407. package/dist/runtimes/remote-thread-list/empty-thread-core.d.ts.map +1 -1
  408. package/dist/runtimes/remote-thread-list/optimistic-state.d.ts +10 -8
  409. package/dist/runtimes/remote-thread-list/optimistic-state.d.ts.map +1 -1
  410. package/dist/runtimes/remote-thread-list/optimistic-state.js +22 -9
  411. package/dist/runtimes/remote-thread-list/optimistic-state.js.map +1 -1
  412. package/dist/runtimes/remote-thread-list/remote-thread-state.d.ts +0 -1
  413. package/dist/runtimes/remote-thread-list/remote-thread-state.d.ts.map +1 -1
  414. package/dist/runtimes/remote-thread-list/types.d.ts +1 -2
  415. package/dist/runtimes/remote-thread-list/types.d.ts.map +1 -1
  416. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts +2 -2
  417. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts.map +1 -1
  418. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js +1 -2
  419. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js.map +1 -1
  420. package/dist/store/clients/chain-of-thought-client.d.ts +0 -1
  421. package/dist/store/clients/chain-of-thought-client.d.ts.map +1 -1
  422. package/dist/store/clients/model-context-client.d.ts +0 -1
  423. package/dist/store/clients/model-context-client.d.ts.map +1 -1
  424. package/dist/store/clients/no-op-composer-client.d.ts +0 -1
  425. package/dist/store/clients/no-op-composer-client.d.ts.map +1 -1
  426. package/dist/store/clients/runtime-adapter.d.ts +0 -1
  427. package/dist/store/clients/runtime-adapter.d.ts.map +1 -1
  428. package/dist/store/clients/suggestions.d.ts +0 -1
  429. package/dist/store/clients/suggestions.d.ts.map +1 -1
  430. package/dist/store/clients/thread-message-client.d.ts +0 -1
  431. package/dist/store/clients/thread-message-client.d.ts.map +1 -1
  432. package/dist/store/runtime-clients/attachment-runtime-client.d.ts +0 -1
  433. package/dist/store/runtime-clients/attachment-runtime-client.d.ts.map +1 -1
  434. package/dist/store/runtime-clients/composer-runtime-client.d.ts +0 -1
  435. package/dist/store/runtime-clients/composer-runtime-client.d.ts.map +1 -1
  436. package/dist/store/runtime-clients/liveRef.d.ts.map +1 -1
  437. package/dist/store/runtime-clients/message-part-runtime-client.d.ts +0 -1
  438. package/dist/store/runtime-clients/message-part-runtime-client.d.ts.map +1 -1
  439. package/dist/store/runtime-clients/message-runtime-client.d.ts +0 -1
  440. package/dist/store/runtime-clients/message-runtime-client.d.ts.map +1 -1
  441. package/dist/store/runtime-clients/thread-list-item-runtime-client.d.ts +0 -1
  442. package/dist/store/runtime-clients/thread-list-item-runtime-client.d.ts.map +1 -1
  443. package/dist/store/runtime-clients/thread-list-runtime-client.d.ts +0 -1
  444. package/dist/store/runtime-clients/thread-list-runtime-client.d.ts.map +1 -1
  445. package/dist/store/runtime-clients/thread-runtime-client.d.ts +0 -1
  446. package/dist/store/runtime-clients/thread-runtime-client.d.ts.map +1 -1
  447. package/dist/store/runtime-clients/useSubscribable.d.ts +0 -1
  448. package/dist/store/runtime-clients/useSubscribable.d.ts.map +1 -1
  449. package/dist/store/scope-registration.d.ts +1 -2
  450. package/dist/store/scope-registration.d.ts.map +1 -1
  451. package/dist/store/scopes/attachment.d.ts +0 -1
  452. package/dist/store/scopes/attachment.d.ts.map +1 -1
  453. package/dist/store/scopes/chain-of-thought.d.ts +0 -1
  454. package/dist/store/scopes/chain-of-thought.d.ts.map +1 -1
  455. package/dist/store/scopes/composer.d.ts +0 -1
  456. package/dist/store/scopes/composer.d.ts.map +1 -1
  457. package/dist/store/scopes/message.d.ts +6 -4
  458. package/dist/store/scopes/message.d.ts.map +1 -1
  459. package/dist/store/scopes/model-context.d.ts +0 -1
  460. package/dist/store/scopes/model-context.d.ts.map +1 -1
  461. package/dist/store/scopes/part.d.ts +0 -1
  462. package/dist/store/scopes/part.d.ts.map +1 -1
  463. package/dist/store/scopes/queue-item.d.ts.map +1 -1
  464. package/dist/store/scopes/suggestion.d.ts.map +1 -1
  465. package/dist/store/scopes/suggestions.d.ts +0 -1
  466. package/dist/store/scopes/suggestions.d.ts.map +1 -1
  467. package/dist/store/scopes/thread-list-item.d.ts +0 -1
  468. package/dist/store/scopes/thread-list-item.d.ts.map +1 -1
  469. package/dist/store/scopes/thread.d.ts +4 -3
  470. package/dist/store/scopes/thread.d.ts.map +1 -1
  471. package/dist/store/scopes/threads.d.ts +0 -1
  472. package/dist/store/scopes/threads.d.ts.map +1 -1
  473. package/dist/subscribable/subscribable.d.ts +1 -2
  474. package/dist/subscribable/subscribable.d.ts.map +1 -1
  475. package/dist/subscribable/subscribable.js +11 -3
  476. package/dist/subscribable/subscribable.js.map +1 -1
  477. package/dist/tests/remote-thread-list-test-helpers.d.ts +2 -2
  478. package/dist/tests/remote-thread-list-test-helpers.d.ts.map +1 -1
  479. package/dist/tests/remote-thread-list-test-helpers.js +5 -2
  480. package/dist/tests/remote-thread-list-test-helpers.js.map +1 -1
  481. package/dist/types/attachment.d.ts +3 -2
  482. package/dist/types/attachment.d.ts.map +1 -1
  483. package/dist/types/attachment.js +6 -0
  484. package/dist/types/attachment.js.map +1 -0
  485. package/dist/types/directive.d.ts +3 -2
  486. package/dist/types/directive.d.ts.map +1 -1
  487. package/dist/types/error.d.ts +15 -0
  488. package/dist/types/error.d.ts.map +1 -0
  489. package/dist/types/error.js +46 -0
  490. package/dist/types/error.js.map +1 -0
  491. package/dist/types/index.d.ts +2 -2
  492. package/dist/types/message.d.ts +71 -33
  493. package/dist/types/message.d.ts.map +1 -1
  494. package/dist/types/message.js.map +1 -1
  495. package/dist/types/quote.d.ts.map +1 -1
  496. package/dist/types/trigger.d.ts +0 -1
  497. package/dist/types/trigger.d.ts.map +1 -1
  498. package/dist/types/unsubscribe.d.ts.map +1 -1
  499. package/dist/utils/composite-context-provider.d.ts +1 -0
  500. package/dist/utils/composite-context-provider.d.ts.map +1 -1
  501. package/dist/utils/data-url.d.ts +9 -0
  502. package/dist/utils/data-url.d.ts.map +1 -0
  503. package/dist/utils/data-url.js +14 -0
  504. package/dist/utils/data-url.js.map +1 -0
  505. package/dist/utils/id.d.ts.map +1 -1
  506. package/dist/utils/json/is-json-equal.d.ts.map +1 -1
  507. package/dist/utils/json/is-json.d.ts +0 -1
  508. package/dist/utils/json/is-json.d.ts.map +1 -1
  509. package/dist/utils/json/is-json.js +1 -1
  510. package/dist/utils/json/is-json.js.map +1 -1
  511. package/dist/utils/json/stable-stringify-tool-args.d.ts +7 -0
  512. package/dist/utils/json/stable-stringify-tool-args.d.ts.map +1 -0
  513. package/dist/utils/json/stable-stringify-tool-args.js +32 -0
  514. package/dist/utils/json/stable-stringify-tool-args.js.map +1 -0
  515. package/dist/utils/notify-event-listeners.d.ts +6 -0
  516. package/dist/utils/notify-event-listeners.d.ts.map +1 -0
  517. package/dist/utils/notify-event-listeners.js +16 -0
  518. package/dist/utils/notify-event-listeners.js.map +1 -0
  519. package/dist/utils/text.d.ts +0 -1
  520. package/dist/utils/text.d.ts.map +1 -1
  521. package/package.json +14 -10
  522. package/src/adapters/attachment.test.ts +107 -0
  523. package/src/adapters/attachment.ts +20 -10
  524. package/src/adapters/index.ts +6 -1
  525. package/src/adapters/speech.test.ts +88 -0
  526. package/src/adapters/speech.ts +17 -2
  527. package/src/adapters/suggestion.test.ts +187 -0
  528. package/src/adapters/suggestion.ts +75 -1
  529. package/src/adapters/voice.test.ts +130 -0
  530. package/src/adapters/voice.ts +26 -6
  531. package/src/index.ts +15 -1
  532. package/src/internal.ts +21 -0
  533. package/src/model-context/frame/host.test.ts +100 -0
  534. package/src/model-context/frame/host.ts +10 -0
  535. package/src/model-context/frame/provider.test.ts +83 -0
  536. package/src/model-context/frame/provider.ts +1 -0
  537. package/src/model-context/tool.test.ts +110 -0
  538. package/src/model-context/tool.ts +31 -9
  539. package/src/react/adapters/LocalStorageThreadListAdapter.test.ts +304 -0
  540. package/src/react/adapters/LocalStorageThreadListAdapter.tsx +307 -60
  541. package/src/react/index.ts +2 -0
  542. package/src/react/model-context/define-mcp-toolkit.ts +39 -6
  543. package/src/react/model-context/define-toolkit.test.ts +107 -0
  544. package/src/react/primitive-hooks/useActionBarCopy.test.ts +79 -0
  545. package/src/react/primitive-hooks/useActionBarCopy.ts +4 -3
  546. package/src/react/primitive-hooks/useMessageError.test.ts +64 -0
  547. package/src/react/primitive-hooks/useMessageError.ts +19 -6
  548. package/src/react/primitives/chainOfThought/ChainOfThoughtParts.tsx +1 -3
  549. package/src/react/primitives/message/MessageParts.tsx +48 -35
  550. package/src/react/providers/ChainOfThoughtPartByIndexProvider.tsx +19 -2
  551. package/src/react/providers/PartByIndexProvider.tsx +16 -2
  552. package/src/react/runtimes/RemoteThreadListHookInstanceManager.test.tsx +18 -0
  553. package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +4 -1
  554. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +96 -26
  555. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.tsx +69 -0
  556. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +1 -1
  557. package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.test.ts +127 -0
  558. package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.ts +15 -4
  559. package/src/react/runtimes/cloud/auiV0.ts +71 -2
  560. package/src/react/runtimes/external-message-converter.test.tsx +123 -0
  561. package/src/react/runtimes/external-message-converter.ts +36 -11
  562. package/src/react/runtimes/useLocalRuntime.test.tsx +56 -0
  563. package/src/react/runtimes/useLocalRuntime.ts +13 -1
  564. package/src/runtime/api/message-runtime.test.ts +81 -0
  565. package/src/runtime/api/message-runtime.ts +4 -6
  566. package/src/runtime/api/thread-list-item-runtime.ts +6 -1
  567. package/src/runtime/base/base-composer-runtime-core.ts +95 -30
  568. package/src/runtime/base/base-thread-runtime-core.ts +2 -1
  569. package/src/runtime/base/default-edit-composer-runtime-core.ts +4 -2
  570. package/src/runtime/base/default-thread-composer-runtime-core.ts +2 -2
  571. package/src/runtime/utils/message-repository.ts +8 -3
  572. package/src/runtime/utils/thread-message-like.ts +3 -0
  573. package/src/runtimes/local/local-thread-runtime-core.test.ts +276 -3
  574. package/src/runtimes/local/local-thread-runtime-core.ts +29 -25
  575. package/src/runtimes/local/should-continue.ts +5 -2
  576. package/src/runtimes/remote-thread-list/adapter/in-memory.test.ts +14 -0
  577. package/src/runtimes/remote-thread-list/adapter/in-memory.ts +13 -5
  578. package/src/runtimes/remote-thread-list/optimistic-state.test.ts +63 -0
  579. package/src/runtimes/remote-thread-list/optimistic-state.ts +49 -17
  580. package/src/runtimes/remote-thread-list/types.ts +1 -1
  581. package/src/runtimes/tool-invocations/EDGE_CASES.md +13 -19
  582. package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +127 -6
  583. package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +4 -2
  584. package/src/subscribable/subscribable.test.ts +58 -0
  585. package/src/subscribable/subscribable.ts +13 -3
  586. package/src/tests/MessageRepository.test.ts +26 -0
  587. package/src/tests/OptimisticState-list-race.test.ts +33 -0
  588. package/src/tests/RemoteThreadListThreadListRuntimeCore-errors.test.ts +42 -0
  589. package/src/tests/RemoteThreadListThreadListRuntimeCore-switchToThread-order.test.ts +223 -0
  590. package/src/tests/attachment-adapters.test.ts +14 -2
  591. package/src/tests/auiV0Encode.test.ts +134 -1
  592. package/src/tests/base-composer-runtime-core-addAttachment.test.ts +123 -5
  593. package/src/tests/base-composer-runtime-core-send.test.ts +573 -0
  594. package/src/tests/default-edit-composer-runtime-core.test.ts +43 -5
  595. package/src/tests/event-subscription-listener-errors.test.ts +205 -0
  596. package/src/tests/remote-thread-list-test-helpers.ts +14 -7
  597. package/src/tests/thread-message-like.test.ts +97 -0
  598. package/src/types/attachment.ts +6 -0
  599. package/src/types/error.test.ts +122 -0
  600. package/src/types/error.ts +74 -0
  601. package/src/types/index.ts +1 -0
  602. package/src/types/message.ts +12 -3
  603. package/src/utils/data-url.test.ts +50 -0
  604. package/src/utils/data-url.ts +9 -0
  605. package/src/utils/json/is-json-equal.test.ts +84 -0
  606. package/src/utils/json/is-json.test.ts +123 -0
  607. package/src/utils/json/is-json.ts +1 -1
  608. package/src/utils/json/stable-stringify-tool-args.test.ts +105 -0
  609. package/src/utils/json/stable-stringify-tool-args.ts +70 -0
  610. package/src/utils/notify-event-listeners.ts +30 -0
@@ -41,6 +41,15 @@ Subsequent snapshots that *are* prefixes of the new (regressed) snapshot
41
41
  also won't be appended, because `entry.argsText` still points at the
42
42
  pre-regression value used for delta calculation.
43
43
 
44
+ The args stream closes only when the controller's *streamed* content
45
+ (`entry.argsText`) is complete, not when a later snapshot is. A divergent
46
+ snapshot can be complete while the controller still holds an incomplete
47
+ stale prefix; closing on the snapshot would parse that stale prefix and
48
+ auto-submit a bogus parse-error result (resuming the host graph and
49
+ abandoning a pending interrupt). Gating the close on the streamed content
50
+ leaves the stream open until the prefix itself completes, so no stale
51
+ parse runs and no error result is fabricated from divergent args.
52
+
44
53
  ### A.3. Args complete then equivalent-JSON key reorder
45
54
  Both old and new `argsText` parse to equivalent JSON values (e.g. keys
46
55
  reordered by the backend). The tracker updates its tracked `argsText`
@@ -53,9 +62,10 @@ existing `streamCall` keeps its original args view.
53
62
 
54
63
  ### A.5. First resolution (`result` becomes defined)
55
64
  The tracker calls `setResponse` on the active controller and closes it.
56
- `reader.response.get()` resolves. If the tool also had a frontend
57
- `execute`, the executor is short-circuited via `_skipExecuteStreamIds`.
58
- Single fire.
65
+ The backend result is emitted before the args stream closes, so a stale
66
+ args parse failure cannot replace it. `reader.response.get()` resolves.
67
+ If the tool also had a frontend `execute`, the executor is short-circuited
68
+ via `_skipExecuteStreamIds`. Single fire.
59
69
 
60
70
  ### A.6. Previously-resolved tool's `result` is replaced
61
71
  Silently ignored — `entry.hasResult` short-circuits both the
@@ -167,22 +177,6 @@ keep the tracker dead with a visible error to avoid restart loops.
167
177
 
168
178
  ## Known limitations
169
179
 
170
- ### Result delivery after args regression (A.2 + A.5 in the same snapshot)
171
- When a snapshot has both a regressed `argsText` *and* a backend result
172
- on the same tool call, `activeController.setResponse(result)` closes
173
- `argsText` before enqueueing the result chunk. The args-text-finish
174
- chunk reaches `ToolExecutionStream` first, attempts to parse the
175
- (stale) accumulated argsText, fails, and emits a parse-error result
176
- that beats the backend result to the reader's response promise.
177
-
178
- The tracker's `entry.hasResult` short-circuit *does* suppress both
179
- result chunks at the `onResult` callback level (no double-fire), but
180
- the reader's `response.get()` already resolved with the parse error.
181
-
182
- Fixable upstream in `ToolCallStreamControllerImpl.setResponse` by
183
- enqueueing the result chunk before closing argsText. Tracked separately;
184
- out of scope for the tracker layer.
185
-
186
180
  ### Host callback throws
187
181
  `onResult` and `onStatusesChange` are invoked through wrappers that
188
182
  catch and log. The tracker continues to function; the host's bad
@@ -152,6 +152,131 @@ describe("ToolInvocationTracker", () => {
152
152
  }
153
153
  });
154
154
 
155
+ it("does not auto-submit a parse-error result when divergent argsText closes without a backend result (#5130)", async () => {
156
+ // Mirrors the #5098 production shape: a human-in-the-loop tool whose
157
+ // argsText diverges mid-stream and never re-converges, with no backend
158
+ // result at close time. The args stream must not close on the divergent
159
+ // snapshot (which holds a stale prefix the execution path would parse),
160
+ // so no bogus parse-error result is auto-submitted to resume the host
161
+ // graph and abandon the pending interrupt.
162
+ const execute = vi.fn(async () => ({ forecast: "ok" }));
163
+ const streamCall = vi.fn((_reader, { human }) => {
164
+ // Request human input immediately — sets up the pending interrupt.
165
+ void human({ request: "approve" });
166
+ });
167
+ const getTools = () => ({
168
+ weatherSearch: {
169
+ parameters: { type: "object", properties: {} },
170
+ execute,
171
+ streamCall,
172
+ } satisfies Tool,
173
+ });
174
+ const onResult = vi.fn();
175
+ let statuses: Record<string, ToolExecutionStatus> = {};
176
+ const onStatusesChange = (s: ReadonlyMap<string, ToolExecutionStatus>) => {
177
+ statuses = Object.fromEntries(s);
178
+ };
179
+ const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
180
+
181
+ try {
182
+ const tracker = new ToolInvocationTracker(getTools, {
183
+ onResult,
184
+ onStatusesChange,
185
+ });
186
+ tracker.setState(createState([]));
187
+
188
+ tracker.setState(
189
+ createState([
190
+ createAssistantMessage('{"query":"London","longitude":0', {
191
+ query: "London",
192
+ longitude: 0,
193
+ }),
194
+ ]),
195
+ );
196
+
197
+ // The pending interrupt is set up via streamCall → human().
198
+ await waitFor(() => {
199
+ expect(statuses["tool-1"]?.type).toBe("interrupt");
200
+ });
201
+
202
+ // Divergent regression (not a prefix of the streamed text).
203
+ tracker.setState(
204
+ createState([
205
+ createAssistantMessage('{"query":"London","longitude":-0.125', {
206
+ query: "London",
207
+ longitude: -0.125,
208
+ }),
209
+ ]),
210
+ );
211
+
212
+ // Complete valid JSON, divergent from the streamed prefix, no backend
213
+ // result. Previously this closed the args stream on the snapshot's
214
+ // completeness, parsed the stale prefix, and auto-submitted an error.
215
+ tracker.setState(
216
+ createState([
217
+ createAssistantMessage(
218
+ '{"query":"London","longitude":-0.125,"latitude":51.5072}',
219
+ { query: "London", longitude: -0.125, latitude: 51.5072 },
220
+ ),
221
+ ]),
222
+ );
223
+
224
+ for (let i = 0; i < 5; i++) {
225
+ await new Promise((r) => setTimeout(r, 0));
226
+ }
227
+
228
+ // No bogus parse-error result is auto-submitted, so the host graph is
229
+ // not resumed with a fake tool failure and the pending interrupt is
230
+ // preserved.
231
+ expect(onResult).not.toHaveBeenCalled();
232
+ // The frontend execute never ran: the stale prefix was never parsed.
233
+ expect(execute).not.toHaveBeenCalled();
234
+ } finally {
235
+ warnSpy.mockRestore();
236
+ }
237
+ });
238
+
239
+ it("does not auto-submit a parse-error result for a non-executable tool whose divergent argsText closes (#5130)", async () => {
240
+ // Same close-gating mismatch as the executable case, but for a tool with
241
+ // no frontend execute. Closing on the divergent complete snapshot would
242
+ // still parse the incomplete stale prefix and fabricate a parse-error
243
+ // result, so the close must gate on the controller's streamed content.
244
+ const getTools = () => ({
245
+ weatherSearch: {
246
+ parameters: { type: "object", properties: {} },
247
+ } satisfies Tool,
248
+ });
249
+ const onResult = vi.fn();
250
+ const onStatusesChange = () => {};
251
+ const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
252
+
253
+ try {
254
+ const tracker = new ToolInvocationTracker(getTools, {
255
+ onResult,
256
+ onStatusesChange,
257
+ });
258
+ tracker.setState(createState([]));
259
+
260
+ // Incomplete prefix while the run is still streaming.
261
+ tracker.setState(
262
+ createState([createAssistantMessage('{"a":1', { a: 1 })], true),
263
+ );
264
+
265
+ // Run settles and the snapshot regresses to a complete divergent text.
266
+ tracker.setState(
267
+ createState([createAssistantMessage('{"a":2}', { a: 2 })], false),
268
+ );
269
+
270
+ for (let i = 0; i < 5; i++) {
271
+ await new Promise((r) => setTimeout(r, 0));
272
+ }
273
+
274
+ expect(onResult).not.toHaveBeenCalled();
275
+ } finally {
276
+ warnSpy.mockRestore();
277
+ }
278
+ });
279
+
155
280
  it("clears executing status under the logical toolCallId when reset() lands while execute is pending", async () => {
156
281
  // Tests the F.1 lifecycle: reset() aborts in-flight execute() invocations
157
282
  // and clears their executing status. The status key is the logical
@@ -948,12 +1073,8 @@ describe("ToolInvocationTracker", () => {
948
1073
  // result replacement) and verifying streamCall fires exactly once.
949
1074
  //
950
1075
  // The pathological mid-stream regression case (A.2) is covered by
951
- // the dedicated regression test above. Mixing A.2 with a backend
952
- // result in the same snapshot exposes a separate issue inside
953
- // assistant-stream's `ToolCallStreamController.setResponse` ordering
954
- // (parse-failure result reaches the reader before the backend
955
- // result); that's tracked separately and out of scope for the
956
- // tracker-level contract.
1076
+ // the assistant-stream ordering regression test in
1077
+ // packages/assistant-stream/src/core/modules/tool-call.test.ts.
957
1078
  const streamCall = vi.fn();
958
1079
  const execute = vi.fn(async () => ({ forecast: "ok" }));
959
1080
  const getTools = () => ({
@@ -687,14 +687,16 @@ export class ToolInvocationTracker {
687
687
  }
688
688
 
689
689
  if (!entry.argsComplete && entry.controller) {
690
+ // ToolExecutionStream parses the streamed prefix on close, so the close
691
+ // gates on the streamed content; a divergent snapshot (A.2) can be
692
+ // complete while the controller still holds an incomplete stale prefix.
690
693
  const shouldClose = this._shouldCloseArgsStream({
691
694
  toolName: content.toolName,
692
- argsText: content.argsText,
695
+ argsText: entry.argsText,
693
696
  hasResult,
694
697
  });
695
698
  if (shouldClose) {
696
699
  entry.controller.argsText.close();
697
- entry.argsText = content.argsText;
698
700
  entry.argsComplete = true;
699
701
  }
700
702
  }
@@ -0,0 +1,58 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import type { SubscribableWithState } from "./subscribable";
3
+ import { ShallowMemoizeSubject } from "./subscribable";
4
+
5
+ type TestState = {
6
+ status: string;
7
+ error?: string;
8
+ };
9
+
10
+ const createBinding = (initialState: TestState) => {
11
+ let state = initialState;
12
+ const subscribers = new Set<() => void>();
13
+
14
+ const binding: SubscribableWithState<TestState, null> = {
15
+ path: null,
16
+ getState: () => state,
17
+ subscribe: (callback) => {
18
+ subscribers.add(callback);
19
+ return () => subscribers.delete(callback);
20
+ },
21
+ };
22
+
23
+ return {
24
+ binding,
25
+ update(nextState: TestState) {
26
+ state = nextState;
27
+ for (const callback of subscribers) callback();
28
+ },
29
+ };
30
+ };
31
+
32
+ describe("ShallowMemoizeSubject", () => {
33
+ it("notifies subscribers when a state key is removed", () => {
34
+ const source = createBinding({
35
+ status: "running",
36
+ error: "Connection failed",
37
+ });
38
+ const subject = new ShallowMemoizeSubject(source.binding);
39
+ const subscriber = vi.fn();
40
+ subject.subscribe(subscriber);
41
+
42
+ source.update({ status: "running" });
43
+
44
+ expect(subscriber).toHaveBeenCalledOnce();
45
+ expect(subject.getState()).toEqual({ status: "running" });
46
+ });
47
+
48
+ it("does not notify subscribers for a shallow-equal state", () => {
49
+ const source = createBinding({ status: "running" });
50
+ const subject = new ShallowMemoizeSubject(source.binding);
51
+ const subscriber = vi.fn();
52
+ subject.subscribe(subscriber);
53
+
54
+ source.update({ status: "running" });
55
+
56
+ expect(subscriber).not.toHaveBeenCalled();
57
+ });
58
+ });
@@ -1,4 +1,5 @@
1
1
  import type { Unsubscribe } from "../types/unsubscribe";
2
+ import { notifyEventListeners } from "../utils/notify-event-listeners";
2
3
 
3
4
  export const SKIP_UPDATE = Symbol("skip-update");
4
5
  export type SKIP_UPDATE = typeof SKIP_UPDATE;
@@ -39,7 +40,10 @@ function shallowEqual<T extends object>(
39
40
  if (objA === undefined) return false;
40
41
  if (objB === undefined) return false;
41
42
 
42
- for (const key of Object.keys(objA)) {
43
+ const keysA = Object.keys(objA);
44
+ if (keysA.length !== Object.keys(objB).length) return false;
45
+
46
+ for (const key of keysA) {
43
47
  const valueA = objA[key as keyof T];
44
48
  const valueB = objB[key as keyof T];
45
49
  if (!Object.is(valueA, valueB)) return false;
@@ -99,7 +103,12 @@ export abstract class BaseSubject {
99
103
 
100
104
  protected abstract _connect(): Unsubscribe;
101
105
 
102
- protected notifySubscribers(payload?: unknown) {
106
+ protected notifySubscribers(payload?: unknown, errorContext?: string) {
107
+ if (errorContext) {
108
+ notifyEventListeners(this._subscriptions, payload, errorContext);
109
+ return;
110
+ }
111
+
103
112
  for (const callback of this._subscriptions) callback(payload);
104
113
  }
105
114
 
@@ -273,8 +282,9 @@ export class EventSubscriptionSubject<
273
282
  }
274
283
 
275
284
  protected _connect(): Unsubscribe {
285
+ const errorContext = `Runtime event "${this.config.event}"`;
276
286
  const callback = (payload?: unknown) => {
277
- this.notifySubscribers(payload);
287
+ this.notifySubscribers(payload, errorContext);
278
288
  };
279
289
 
280
290
  let lastState = this.config.binding.getState();
@@ -309,6 +309,32 @@ describe("MessageRepository", () => {
309
309
  expect(exported.headId).toBe("u");
310
310
  });
311
311
 
312
+ it("re-parents children of a skipped optimistic message in export()", () => {
313
+ repository.addOrUpdateMessage(null, createTestMessage({ id: "u1" }));
314
+ repository.addOrUpdateMessage("u1", optimistic({ id: "a1" }));
315
+ repository.addOrUpdateMessage(
316
+ "a1",
317
+ createTestMessage({ id: "u2", role: "user" }),
318
+ );
319
+ repository.addOrUpdateMessage("u2", createTestMessage({ id: "a2" }));
320
+ repository.resetHead("a2");
321
+
322
+ const exported = repository.export();
323
+ const byId = new Map(exported.messages.map((m) => [m.message.id, m]));
324
+
325
+ expect([...byId.keys()].sort()).toEqual(["a2", "u1", "u2"]);
326
+ expect(byId.get("u2")?.parentId).toBe("u1");
327
+ expect(byId.get("a2")?.parentId).toBe("u2");
328
+
329
+ const restored = new MessageRepository();
330
+ restored.import(exported);
331
+ expect(restored.getMessages().map((m) => m.id)).toEqual([
332
+ "u1",
333
+ "u2",
334
+ "a2",
335
+ ]);
336
+ });
337
+
312
338
  it("round-trips through export/import without resurrecting the placeholder", () => {
313
339
  const parent = createTestMessage({ id: "u" });
314
340
  const real = createTestMessage({ id: "a" });
@@ -79,6 +79,39 @@ const applyListResult = (
79
79
  };
80
80
 
81
81
  describe("list + delete race condition", () => {
82
+ it("stale list() does not re-add a thread deleted before list started", async () => {
83
+ const state = new OptimisticState<RemoteThreadState>(
84
+ applyListResult(EMPTY_STATE, {
85
+ threads: [{ remoteId: "thread-A", status: "regular", title: "A" }],
86
+ }),
87
+ );
88
+ const deleteDeferred = deferred<void>();
89
+ const listDeferred = deferred<ListResult>();
90
+
91
+ const deletePromise = state.optimisticUpdate({
92
+ execute: () => deleteDeferred.promise,
93
+ optimistic: (s) => updateStatusReducer(s, "thread-A", "deleted"),
94
+ });
95
+ const listPromise = state.optimisticUpdate({
96
+ execute: () => listDeferred.promise,
97
+ loading: (s) => ({ ...s, isLoading: true }),
98
+ then: applyListResult,
99
+ });
100
+
101
+ deleteDeferred.resolve();
102
+ await deletePromise;
103
+
104
+ listDeferred.resolve({
105
+ threads: [{ remoteId: "thread-A", status: "regular", title: "A" }],
106
+ });
107
+ await listPromise;
108
+
109
+ expect(state.value.threadIds).not.toContain("thread-A");
110
+ expect(
111
+ state.value.threadData[createThreadMappingId("thread-A")],
112
+ ).toBeUndefined();
113
+ });
114
+
82
115
  it("stale list() does not re-add a thread deleted while list was in flight", async () => {
83
116
  const state = new OptimisticState<RemoteThreadState>(EMPTY_STATE);
84
117
 
@@ -0,0 +1,42 @@
1
+ import { describe, it, expect, vi } from "vitest";
2
+ import { createCore, makeAdapter } from "./remote-thread-list-test-helpers";
3
+ import { InMemoryThreadListAdapter } from "../runtimes/remote-thread-list/adapter/in-memory";
4
+
5
+ describe("RemoteThreadListThreadListRuntimeCore errors", () => {
6
+ it("includes the requested thread id when a thread is missing", () => {
7
+ const core = createCore(makeAdapter());
8
+
9
+ expect(() => core.rename("missing-thread", "New title")).toThrow(
10
+ 'Thread "missing-thread" not found while renaming it.',
11
+ );
12
+ });
13
+
14
+ it("includes the requested thread id and status when an operation is invalid", async () => {
15
+ const adapter = makeAdapter({
16
+ list: vi.fn(async () => ({
17
+ threads: [
18
+ {
19
+ status: "archived" as const,
20
+ remoteId: "archived-thread",
21
+ externalId: "archived-thread",
22
+ title: "Archived",
23
+ },
24
+ ],
25
+ })),
26
+ });
27
+ const core = createCore(adapter);
28
+ await core.getLoadThreadsPromise();
29
+
30
+ await expect(core.archive("archived-thread")).rejects.toThrow(
31
+ 'Thread "archived-thread" has status "archived", so it cannot be archived.',
32
+ );
33
+ });
34
+
35
+ it("includes the requested thread id when the in-memory adapter cannot fetch it", async () => {
36
+ const adapter = new InMemoryThreadListAdapter();
37
+
38
+ await expect(adapter.fetch("missing-thread")).rejects.toThrow(
39
+ 'Thread "missing-thread" not found in in-memory thread list.',
40
+ );
41
+ });
42
+ });
@@ -0,0 +1,223 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import type { RemoteThreadMetadata } from "../runtimes/remote-thread-list/types";
3
+ import {
4
+ createCore,
5
+ deferred,
6
+ makeAdapter,
7
+ setStartThreadRuntime,
8
+ } from "./remote-thread-list-test-helpers";
9
+
10
+ const thread = (id: string): RemoteThreadMetadata => ({
11
+ status: "regular",
12
+ remoteId: id,
13
+ externalId: id,
14
+ title: id,
15
+ });
16
+
17
+ describe("RemoteThreadListThreadListRuntimeCore.switchToThread order", () => {
18
+ it("preserves the latest switch when an earlier fetch resolves last", async () => {
19
+ const fetchB = deferred<RemoteThreadMetadata>();
20
+ const fetchC = deferred<RemoteThreadMetadata>();
21
+ const adapter = makeAdapter({
22
+ fetch: vi.fn((id: string) =>
23
+ id === "thread-b" ? fetchB.promise : fetchC.promise,
24
+ ),
25
+ });
26
+ const core = createCore(adapter);
27
+
28
+ const switchToB = core.switchToThread("thread-b");
29
+ const switchToC = core.switchToThread("thread-c");
30
+
31
+ fetchC.resolve(thread("thread-c"));
32
+ await switchToC;
33
+ fetchB.resolve(thread("thread-b"));
34
+ await switchToB;
35
+
36
+ expect(core.mainThreadId).toBe(core.getItemById("thread-c")?.id);
37
+ });
38
+
39
+ it("preserves the latest switch when an earlier runtime starts last", async () => {
40
+ const runtimeB = deferred<unknown>();
41
+ const runtimeC = deferred<unknown>();
42
+ const adapter = makeAdapter({
43
+ list: vi.fn(async () => ({
44
+ threads: [thread("thread-b"), thread("thread-c")],
45
+ })),
46
+ });
47
+ const core = createCore(adapter);
48
+ await core.getLoadThreadsPromise();
49
+
50
+ setStartThreadRuntime(core, (id) =>
51
+ id === core.getItemById("thread-b")?.id
52
+ ? runtimeB.promise
53
+ : runtimeC.promise,
54
+ );
55
+
56
+ const switchToB = core.switchToThread("thread-b");
57
+ const switchToC = core.switchToThread("thread-c");
58
+
59
+ runtimeC.resolve({});
60
+ await switchToC;
61
+ runtimeB.resolve({});
62
+ await switchToB;
63
+
64
+ expect(core.mainThreadId).toBe(core.getItemById("thread-c")?.id);
65
+ });
66
+
67
+ it("invalidates an earlier switch while a new thread request is pending", async () => {
68
+ const initializeThread = deferred<{
69
+ remoteId: string;
70
+ externalId: string;
71
+ }>();
72
+ const runtimeB = deferred<unknown>();
73
+ const adapter = makeAdapter({
74
+ initialize: vi.fn(() => initializeThread.promise),
75
+ list: vi.fn(async () => ({ threads: [thread("thread-b")] })),
76
+ });
77
+ const core = createCore(adapter);
78
+ await core.getLoadThreadsPromise();
79
+
80
+ const initialNewThreadId = core.newThreadId;
81
+ if (!initialNewThreadId) throw new Error("Expected an initial new thread");
82
+
83
+ const threadBId = core.getItemById("thread-b")?.id;
84
+ setStartThreadRuntime(core, (id) =>
85
+ id === threadBId ? runtimeB.promise : Promise.resolve({}),
86
+ );
87
+
88
+ const initialize = core.initialize(initialNewThreadId);
89
+ const switchToB = core.switchToThread("thread-b");
90
+ const switchToNewThread = core.switchToNewThread();
91
+
92
+ runtimeB.resolve({});
93
+ await switchToB;
94
+
95
+ expect(core.mainThreadId).not.toBe(threadBId);
96
+
97
+ initializeThread.resolve({
98
+ remoteId: "initialized-thread",
99
+ externalId: "initialized-thread",
100
+ });
101
+ await initialize;
102
+ await switchToNewThread;
103
+
104
+ expect(core.mainThreadId).toBe(core.getItemById(core.newThreadId!)?.id);
105
+ });
106
+
107
+ it("does not let a pending new thread request override a later switch", async () => {
108
+ const initializeThread = deferred<{
109
+ remoteId: string;
110
+ externalId: string;
111
+ }>();
112
+ const adapter = makeAdapter({
113
+ initialize: vi.fn(() => initializeThread.promise),
114
+ list: vi.fn(async () => ({ threads: [thread("thread-c")] })),
115
+ });
116
+ const core = createCore(adapter);
117
+ await core.getLoadThreadsPromise();
118
+
119
+ const initialNewThreadId = core.newThreadId;
120
+ if (!initialNewThreadId) throw new Error("Expected an initial new thread");
121
+
122
+ const initialize = core.initialize(initialNewThreadId);
123
+ const switchToNewThread = core.switchToNewThread();
124
+ await core.switchToThread("thread-c");
125
+
126
+ initializeThread.resolve({
127
+ remoteId: "initialized-thread",
128
+ externalId: "initialized-thread",
129
+ });
130
+ await initialize;
131
+ await switchToNewThread;
132
+
133
+ expect(core.mainThreadId).toBe(core.getItemById("thread-c")?.id);
134
+ });
135
+
136
+ it("keeps mutations waiting when a newer switch fails", async () => {
137
+ const fetchB = deferred<RemoteThreadMetadata>();
138
+ const newThreadRuntime = deferred<unknown>();
139
+ const adapter = makeAdapter({
140
+ fetch: vi.fn(() => fetchB.promise),
141
+ list: vi.fn(async () => ({ threads: [thread("thread-a")] })),
142
+ });
143
+ const core = createCore(adapter);
144
+ await core.getLoadThreadsPromise();
145
+ await core.switchToThread("thread-a");
146
+
147
+ const threadAId = core.getItemById("thread-a")?.id;
148
+ const newThreadId = core.newThreadId;
149
+ if (!newThreadId) throw new Error("Expected an initial new thread");
150
+
151
+ setStartThreadRuntime(core, (id) =>
152
+ id === core.getItemById(newThreadId)?.id
153
+ ? newThreadRuntime.promise
154
+ : Promise.resolve({}),
155
+ );
156
+
157
+ const deleteA = core.delete("thread-a");
158
+ const switchToB = core.switchToThread("thread-b");
159
+ const switchToBResult = expect(switchToB).rejects.toThrow("fetch failed");
160
+
161
+ newThreadRuntime.resolve({});
162
+ fetchB.reject(new Error("fetch failed"));
163
+
164
+ await switchToBResult;
165
+ await deleteA;
166
+
167
+ expect(core.mainThreadId).not.toBe(threadAId);
168
+ expect(core.mainThreadId).toBe(core.getItemById(core.newThreadId!)?.id);
169
+ });
170
+
171
+ it("lets a newer successful switch move the mutation target away", async () => {
172
+ const fetchB = deferred<RemoteThreadMetadata>();
173
+ const newThreadRuntime = deferred<unknown>();
174
+ const adapter = makeAdapter({
175
+ fetch: vi.fn(() => fetchB.promise),
176
+ list: vi.fn(async () => ({ threads: [thread("thread-a")] })),
177
+ });
178
+ const core = createCore(adapter);
179
+ await core.getLoadThreadsPromise();
180
+ await core.switchToThread("thread-a");
181
+
182
+ const newThreadId = core.newThreadId;
183
+ if (!newThreadId) throw new Error("Expected an initial new thread");
184
+
185
+ setStartThreadRuntime(core, (id) =>
186
+ id === core.getItemById(newThreadId)?.id
187
+ ? newThreadRuntime.promise
188
+ : Promise.resolve({}),
189
+ );
190
+
191
+ const deleteA = core.delete("thread-a");
192
+ const switchToB = core.switchToThread("thread-b");
193
+
194
+ newThreadRuntime.resolve({});
195
+ fetchB.resolve(thread("thread-b"));
196
+
197
+ await switchToB;
198
+ await deleteA;
199
+
200
+ expect(core.mainThreadId).toBe(core.getItemById("thread-b")?.id);
201
+ });
202
+
203
+ it("does not let a mutation cancel an existing pending switch", async () => {
204
+ const fetchB = deferred<RemoteThreadMetadata>();
205
+ const adapter = makeAdapter({
206
+ fetch: vi.fn(() => fetchB.promise),
207
+ list: vi.fn(async () => ({ threads: [thread("thread-a")] })),
208
+ });
209
+ const core = createCore(adapter);
210
+ await core.getLoadThreadsPromise();
211
+ await core.switchToThread("thread-a");
212
+
213
+ const switchToB = core.switchToThread("thread-b");
214
+ const deleteA = core.delete("thread-a");
215
+
216
+ fetchB.resolve(thread("thread-b"));
217
+
218
+ await switchToB;
219
+ await deleteA;
220
+
221
+ expect(core.mainThreadId).toBe(core.getItemById("thread-b")?.id);
222
+ });
223
+ });