@assistant-ui/core 0.2.22 → 0.3.0

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 (349) hide show
  1. package/dist/adapters/thread-history.d.ts +8 -0
  2. package/dist/adapters/thread-history.d.ts.map +1 -1
  3. package/dist/internal.d.ts +3 -2
  4. package/dist/internal.js +3 -2
  5. package/dist/model-context/frame/host.d.ts.map +1 -1
  6. package/dist/model-context/frame/host.js +36 -21
  7. package/dist/model-context/frame/host.js.map +1 -1
  8. package/dist/model-context/types.d.ts.map +1 -1
  9. package/dist/model-context/types.js +13 -4
  10. package/dist/model-context/types.js.map +1 -1
  11. package/dist/react/adapters/LocalStorageThreadListAdapter.d.ts.map +1 -1
  12. package/dist/react/adapters/LocalStorageThreadListAdapter.js +3 -2
  13. package/dist/react/adapters/LocalStorageThreadListAdapter.js.map +1 -1
  14. package/dist/react/client/Tools.d.ts.map +1 -1
  15. package/dist/react/client/Tools.js +40 -55
  16. package/dist/react/client/Tools.js.map +1 -1
  17. package/dist/react/client/interactable-model-context.js +1 -0
  18. package/dist/react/client/interactable-model-context.js.map +1 -1
  19. package/dist/react/interactables-legacy/useAssistantInteractable.js +1 -1
  20. package/dist/react/interactables-legacy/useAssistantInteractable.js.map +1 -1
  21. package/dist/react/interactables-legacy/useInteractableState.js +4 -3
  22. package/dist/react/interactables-legacy/useInteractableState.js.map +1 -1
  23. package/dist/react/model-context/useAssistantContext.js +1 -1
  24. package/dist/react/model-context/useAssistantContext.js.map +1 -1
  25. package/dist/react/model-context/useAssistantDataUI.js +1 -1
  26. package/dist/react/model-context/useAssistantDataUI.js.map +1 -1
  27. package/dist/react/model-context/useAssistantInstructions.js +1 -1
  28. package/dist/react/model-context/useAssistantInstructions.js.map +1 -1
  29. package/dist/react/model-context/useAssistantTool.js +29 -25
  30. package/dist/react/model-context/useAssistantTool.js.map +1 -1
  31. package/dist/react/model-context/useAssistantToolUI.js +1 -1
  32. package/dist/react/model-context/useAssistantToolUI.js.map +1 -1
  33. package/dist/react/model-context/useAuiToolOverrides.js +1 -1
  34. package/dist/react/model-context/useAuiToolOverrides.js.map +1 -1
  35. package/dist/react/model-context/useInteractable.js +1 -1
  36. package/dist/react/model-context/useInteractable.js.map +1 -1
  37. package/dist/react/model-context/useInteractableState.js +3 -2
  38. package/dist/react/model-context/useInteractableState.js.map +1 -1
  39. package/dist/react/model-context/useInteractableVersions.js +1 -0
  40. package/dist/react/model-context/useInteractableVersions.js.map +1 -1
  41. package/dist/react/model-context/useToolArgsStatus.js +1 -0
  42. package/dist/react/model-context/useToolArgsStatus.js.map +1 -1
  43. package/dist/react/primitive-hooks/useActionBarCopy.js +4 -3
  44. package/dist/react/primitive-hooks/useActionBarCopy.js.map +1 -1
  45. package/dist/react/primitive-hooks/useActionBarEdit.js +2 -1
  46. package/dist/react/primitive-hooks/useActionBarEdit.js.map +1 -1
  47. package/dist/react/primitive-hooks/useActionBarFeedback.js +3 -2
  48. package/dist/react/primitive-hooks/useActionBarFeedback.js.map +1 -1
  49. package/dist/react/primitive-hooks/useActionBarReload.js +2 -1
  50. package/dist/react/primitive-hooks/useActionBarReload.js.map +1 -1
  51. package/dist/react/primitive-hooks/useActionBarSpeak.js +2 -1
  52. package/dist/react/primitive-hooks/useActionBarSpeak.js.map +1 -1
  53. package/dist/react/primitive-hooks/useActionBarStopSpeaking.js +2 -1
  54. package/dist/react/primitive-hooks/useActionBarStopSpeaking.js.map +1 -1
  55. package/dist/react/primitive-hooks/useBranchPickerNext.js +2 -1
  56. package/dist/react/primitive-hooks/useBranchPickerNext.js.map +1 -1
  57. package/dist/react/primitive-hooks/useBranchPickerPrevious.js +2 -1
  58. package/dist/react/primitive-hooks/useBranchPickerPrevious.js.map +1 -1
  59. package/dist/react/primitive-hooks/useComposerAddAttachment.js +2 -1
  60. package/dist/react/primitive-hooks/useComposerAddAttachment.js.map +1 -1
  61. package/dist/react/primitive-hooks/useComposerCancel.js +2 -1
  62. package/dist/react/primitive-hooks/useComposerCancel.js.map +1 -1
  63. package/dist/react/primitive-hooks/useComposerDictate.js +2 -1
  64. package/dist/react/primitive-hooks/useComposerDictate.js.map +1 -1
  65. package/dist/react/primitive-hooks/useComposerSend.js +2 -1
  66. package/dist/react/primitive-hooks/useComposerSend.js.map +1 -1
  67. package/dist/react/primitive-hooks/useEditComposerCancel.js +2 -1
  68. package/dist/react/primitive-hooks/useEditComposerCancel.js.map +1 -1
  69. package/dist/react/primitive-hooks/useEditComposerSend.js +2 -1
  70. package/dist/react/primitive-hooks/useEditComposerSend.js.map +1 -1
  71. package/dist/react/primitive-hooks/useMessageBranching.js +3 -2
  72. package/dist/react/primitive-hooks/useMessageBranching.js.map +1 -1
  73. package/dist/react/primitive-hooks/useMessageReload.js +2 -1
  74. package/dist/react/primitive-hooks/useMessageReload.js.map +1 -1
  75. package/dist/react/primitive-hooks/useSuggestionTrigger.js +8 -7
  76. package/dist/react/primitive-hooks/useSuggestionTrigger.js.map +1 -1
  77. package/dist/react/primitive-hooks/useThreadListItemArchive.js +2 -1
  78. package/dist/react/primitive-hooks/useThreadListItemArchive.js.map +1 -1
  79. package/dist/react/primitive-hooks/useThreadListItemDelete.js +2 -1
  80. package/dist/react/primitive-hooks/useThreadListItemDelete.js.map +1 -1
  81. package/dist/react/primitive-hooks/useThreadListItemTrigger.js +2 -1
  82. package/dist/react/primitive-hooks/useThreadListItemTrigger.js.map +1 -1
  83. package/dist/react/primitive-hooks/useThreadListItemUnarchive.js +2 -1
  84. package/dist/react/primitive-hooks/useThreadListItemUnarchive.js.map +1 -1
  85. package/dist/react/primitive-hooks/useThreadListLoadMore.js +2 -1
  86. package/dist/react/primitive-hooks/useThreadListLoadMore.js.map +1 -1
  87. package/dist/react/primitive-hooks/useThreadListNew.js +2 -1
  88. package/dist/react/primitive-hooks/useThreadListNew.js.map +1 -1
  89. package/dist/react/primitive-hooks/useVoice.js +5 -13
  90. package/dist/react/primitive-hooks/useVoice.js.map +1 -1
  91. package/dist/react/primitives/chainOfThought/ChainOfThoughtParts.js +1 -1
  92. package/dist/react/primitives/chainOfThought/ChainOfThoughtParts.js.map +1 -1
  93. package/dist/react/primitives/composer/ComposerAttachments.js +1 -1
  94. package/dist/react/primitives/composer/ComposerAttachments.js.map +1 -1
  95. package/dist/react/primitives/composer/ComposerQueue.d.ts.map +1 -1
  96. package/dist/react/primitives/composer/ComposerQueue.js +1 -1
  97. package/dist/react/primitives/composer/ComposerQueue.js.map +1 -1
  98. package/dist/react/primitives/message/MessageAttachments.d.ts.map +1 -1
  99. package/dist/react/primitives/message/MessageAttachments.js +1 -1
  100. package/dist/react/primitives/message/MessageAttachments.js.map +1 -1
  101. package/dist/react/primitives/message/MessageParts.js +84 -122
  102. package/dist/react/primitives/message/MessageParts.js.map +1 -1
  103. package/dist/react/primitives/thread/ThreadMessages.js +1 -1
  104. package/dist/react/primitives/thread/ThreadMessages.js.map +1 -1
  105. package/dist/react/primitives/thread/ThreadSuggestions.js +1 -1
  106. package/dist/react/primitives/thread/ThreadSuggestions.js.map +1 -1
  107. package/dist/react/primitives/threadList/ThreadListItems.js +1 -1
  108. package/dist/react/primitives/threadList/ThreadListItems.js.map +1 -1
  109. package/dist/react/providers/AttachmentByIndexProvider.js +2 -2
  110. package/dist/react/providers/AttachmentByIndexProvider.js.map +1 -1
  111. package/dist/react/providers/ChainOfThoughtByIndicesProvider.js +1 -1
  112. package/dist/react/providers/ChainOfThoughtByIndicesProvider.js.map +1 -1
  113. package/dist/react/providers/ChainOfThoughtPartByIndexProvider.d.ts.map +1 -1
  114. package/dist/react/providers/ChainOfThoughtPartByIndexProvider.js +30 -18
  115. package/dist/react/providers/ChainOfThoughtPartByIndexProvider.js.map +1 -1
  116. package/dist/react/providers/MessageByIdProvider.js +2 -2
  117. package/dist/react/providers/MessageByIdProvider.js.map +1 -1
  118. package/dist/react/providers/MessageByIndexProvider.js +2 -2
  119. package/dist/react/providers/MessageByIndexProvider.js.map +1 -1
  120. package/dist/react/providers/PartByIndexProvider.d.ts.map +1 -1
  121. package/dist/react/providers/PartByIndexProvider.js +30 -18
  122. package/dist/react/providers/PartByIndexProvider.js.map +1 -1
  123. package/dist/react/providers/QueueItemByIndexProvider.js +1 -1
  124. package/dist/react/providers/QueueItemByIndexProvider.js.map +1 -1
  125. package/dist/react/providers/ReadonlyThreadProvider.js +1 -1
  126. package/dist/react/providers/ReadonlyThreadProvider.js.map +1 -1
  127. package/dist/react/providers/SuggestionByIndexProvider.js +1 -1
  128. package/dist/react/providers/SuggestionByIndexProvider.js.map +1 -1
  129. package/dist/react/providers/TextMessagePartProvider.js +1 -0
  130. package/dist/react/providers/TextMessagePartProvider.js.map +1 -1
  131. package/dist/react/providers/ThreadListItemByIndexProvider.js +1 -1
  132. package/dist/react/providers/ThreadListItemByIndexProvider.js.map +1 -1
  133. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +3 -3
  134. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
  135. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
  136. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +6 -4
  137. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
  138. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts +31 -1
  139. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
  140. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +42 -20
  141. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
  142. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts +1 -1
  143. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts.map +1 -1
  144. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js +1 -1
  145. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js.map +1 -1
  146. package/dist/react/runtimes/cloud/auiV0.d.ts +12 -1
  147. package/dist/react/runtimes/cloud/auiV0.d.ts.map +1 -1
  148. package/dist/react/runtimes/cloud/auiV0.js +2 -1
  149. package/dist/react/runtimes/cloud/auiV0.js.map +1 -1
  150. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js +75 -73
  151. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js.map +1 -1
  152. package/dist/react/runtimes/createRuntimeExtras.js +1 -1
  153. package/dist/react/runtimes/createRuntimeExtras.js.map +1 -1
  154. package/dist/react/runtimes/external-message-converter.js +1 -1
  155. package/dist/react/runtimes/external-message-converter.js.map +1 -1
  156. package/dist/react/runtimes/useExternalStoreSharedOptions.js +1 -0
  157. package/dist/react/runtimes/useExternalStoreSharedOptions.js.map +1 -1
  158. package/dist/react/runtimes/useLocalRuntime.d.ts +0 -1
  159. package/dist/react/runtimes/useLocalRuntime.d.ts.map +1 -1
  160. package/dist/react/types/scopes/tools.d.ts +0 -6
  161. package/dist/react/types/scopes/tools.d.ts.map +1 -1
  162. package/dist/react/utils/groupParts.d.ts +1 -3
  163. package/dist/react/utils/groupParts.d.ts.map +1 -1
  164. package/dist/react/utils/groupParts.js +1 -3
  165. package/dist/react/utils/groupParts.js.map +1 -1
  166. package/dist/runtime/api/assistant-runtime.d.ts +1 -1
  167. package/dist/runtime/api/assistant-runtime.d.ts.map +1 -1
  168. package/dist/runtime/api/assistant-runtime.js +1 -1
  169. package/dist/runtime/api/assistant-runtime.js.map +1 -1
  170. package/dist/runtime/api/attachment-runtime.d.ts +1 -1
  171. package/dist/runtime/api/attachment-runtime.d.ts.map +1 -1
  172. package/dist/runtime/api/attachment-runtime.js +1 -1
  173. package/dist/runtime/api/attachment-runtime.js.map +1 -1
  174. package/dist/runtime/api/composer-runtime.d.ts +2 -2
  175. package/dist/runtime/api/composer-runtime.d.ts.map +1 -1
  176. package/dist/runtime/api/composer-runtime.js +2 -2
  177. package/dist/runtime/api/composer-runtime.js.map +1 -1
  178. package/dist/runtime/api/message-part-runtime.d.ts +4 -4
  179. package/dist/runtime/api/message-part-runtime.d.ts.map +1 -1
  180. package/dist/runtime/api/message-part-runtime.js +3 -3
  181. package/dist/runtime/api/message-part-runtime.js.map +1 -1
  182. package/dist/runtime/api/message-runtime.d.ts +1 -1
  183. package/dist/runtime/api/message-runtime.d.ts.map +1 -1
  184. package/dist/runtime/api/message-runtime.js +2 -2
  185. package/dist/runtime/api/message-runtime.js.map +1 -1
  186. package/dist/runtime/api/thread-list-item-runtime.d.ts +1 -1
  187. package/dist/runtime/api/thread-list-item-runtime.d.ts.map +1 -1
  188. package/dist/runtime/api/thread-list-item-runtime.js +2 -2
  189. package/dist/runtime/api/thread-list-item-runtime.js.map +1 -1
  190. package/dist/runtime/api/thread-list-runtime.d.ts +1 -1
  191. package/dist/runtime/api/thread-list-runtime.d.ts.map +1 -1
  192. package/dist/runtime/api/thread-list-runtime.js +1 -1
  193. package/dist/runtime/api/thread-list-runtime.js.map +1 -1
  194. package/dist/runtime/base/base-thread-runtime-core.d.ts +1 -1
  195. package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
  196. package/dist/runtime/base/base-thread-runtime-core.js +1 -1
  197. package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
  198. package/dist/runtime/base/default-edit-composer-runtime-core.d.ts +2 -2
  199. package/dist/runtime/base/default-edit-composer-runtime-core.d.ts.map +1 -1
  200. package/dist/runtime/base/default-edit-composer-runtime-core.js +2 -2
  201. package/dist/runtime/base/default-edit-composer-runtime-core.js.map +1 -1
  202. package/dist/runtime/base/default-thread-composer-runtime-core.d.ts +1 -1
  203. package/dist/runtime/base/default-thread-composer-runtime-core.d.ts.map +1 -1
  204. package/dist/runtime/base/default-thread-composer-runtime-core.js +1 -1
  205. package/dist/runtime/base/default-thread-composer-runtime-core.js.map +1 -1
  206. package/dist/runtime/utils/message-repository.d.ts.map +1 -1
  207. package/dist/runtime/utils/message-repository.js +4 -2
  208. package/dist/runtime/utils/message-repository.js.map +1 -1
  209. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts +1 -1
  210. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts.map +1 -1
  211. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js +1 -1
  212. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js.map +1 -1
  213. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
  214. package/dist/runtimes/external-store/external-store-thread-runtime-core.js +12 -0
  215. package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
  216. package/dist/runtimes/internal.d.ts +2 -1
  217. package/dist/runtimes/internal.js +2 -1
  218. package/dist/runtimes/local/local-thread-runtime-core.d.ts +3 -0
  219. package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
  220. package/dist/runtimes/local/local-thread-runtime-core.js +44 -13
  221. package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
  222. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts +32 -27
  223. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts.map +1 -1
  224. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js +2 -0
  225. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js.map +1 -1
  226. package/dist/store/clients/no-op-composer-client.js +1 -0
  227. package/dist/store/clients/no-op-composer-client.js.map +1 -1
  228. package/dist/store/clients/runtime-adapter.js +3 -3
  229. package/dist/store/clients/runtime-adapter.js.map +1 -1
  230. package/dist/store/runtime-clients/thread-list-runtime-client.js +1 -0
  231. package/dist/store/runtime-clients/thread-list-runtime-client.js.map +1 -1
  232. package/dist/store/runtime-clients/thread-runtime-client.d.ts.map +1 -1
  233. package/dist/store/runtime-clients/thread-runtime-client.js +17 -15
  234. package/dist/store/runtime-clients/thread-runtime-client.js.map +1 -1
  235. package/dist/store/scopes/thread.d.ts +1 -0
  236. package/dist/store/scopes/thread.d.ts.map +1 -1
  237. package/dist/subscribable/subscribable.d.ts +3 -3
  238. package/dist/subscribable/subscribable.d.ts.map +1 -1
  239. package/dist/subscribable/subscribable.js +3 -3
  240. package/dist/subscribable/subscribable.js.map +1 -1
  241. package/package.json +8 -8
  242. package/src/adapters/thread-history.ts +8 -0
  243. package/src/internal.ts +1 -1
  244. package/src/model-context/frame/host.test.ts +47 -0
  245. package/src/model-context/frame/host.ts +46 -19
  246. package/src/model-context/types.ts +16 -6
  247. package/src/react/adapters/LocalStorageThreadListAdapter.tsx +17 -7
  248. package/src/react/client/Tools.ts +0 -7
  249. package/src/react/interactables-legacy/useAssistantInteractable.ts +1 -1
  250. package/src/react/interactables-legacy/useInteractableState.ts +3 -3
  251. package/src/react/model-context/useAssistantContext.ts +1 -1
  252. package/src/react/model-context/useAssistantDataUI.ts +1 -1
  253. package/src/react/model-context/useAssistantInstructions.ts +1 -1
  254. package/src/react/model-context/useAssistantTool.ts +2 -2
  255. package/src/react/model-context/useAssistantToolUI.ts +1 -1
  256. package/src/react/model-context/useAuiToolOverrides.ts +1 -1
  257. package/src/react/model-context/useInteractable.ts +1 -1
  258. package/src/react/model-context/useInteractableState.ts +2 -2
  259. package/src/react/primitive-hooks/useActionBarCopy.test.ts +2 -2
  260. package/src/react/primitive-hooks/useActionBarCopy.ts +3 -3
  261. package/src/react/primitive-hooks/useActionBarEdit.ts +1 -1
  262. package/src/react/primitive-hooks/useActionBarFeedback.ts +2 -2
  263. package/src/react/primitive-hooks/useActionBarReload.ts +1 -1
  264. package/src/react/primitive-hooks/useActionBarSpeak.ts +1 -1
  265. package/src/react/primitive-hooks/useActionBarStopSpeaking.ts +1 -1
  266. package/src/react/primitive-hooks/useBranchPickerNext.ts +1 -1
  267. package/src/react/primitive-hooks/useBranchPickerPrevious.ts +1 -1
  268. package/src/react/primitive-hooks/useComposerAddAttachment.ts +1 -1
  269. package/src/react/primitive-hooks/useComposerCancel.ts +1 -1
  270. package/src/react/primitive-hooks/useComposerDictate.ts +1 -1
  271. package/src/react/primitive-hooks/useComposerSend.ts +1 -1
  272. package/src/react/primitive-hooks/useEditComposerCancel.ts +1 -1
  273. package/src/react/primitive-hooks/useEditComposerSend.ts +1 -1
  274. package/src/react/primitive-hooks/useMessageBranching.ts +2 -2
  275. package/src/react/primitive-hooks/useMessageReload.ts +1 -1
  276. package/src/react/primitive-hooks/useSuggestionTrigger.ts +9 -9
  277. package/src/react/primitive-hooks/useThreadListItemArchive.ts +1 -1
  278. package/src/react/primitive-hooks/useThreadListItemDelete.ts +1 -1
  279. package/src/react/primitive-hooks/useThreadListItemTrigger.ts +1 -1
  280. package/src/react/primitive-hooks/useThreadListItemUnarchive.ts +1 -1
  281. package/src/react/primitive-hooks/useThreadListLoadMore.ts +1 -1
  282. package/src/react/primitive-hooks/useThreadListNew.ts +1 -1
  283. package/src/react/primitive-hooks/useVoice.ts +5 -5
  284. package/src/react/primitives/chainOfThought/ChainOfThoughtParts.tsx +1 -1
  285. package/src/react/primitives/composer/ComposerAttachments.tsx +1 -1
  286. package/src/react/primitives/composer/ComposerQueue.tsx +1 -3
  287. package/src/react/primitives/message/MessageAttachments.tsx +1 -3
  288. package/src/react/primitives/message/MessageParts.tsx +9 -9
  289. package/src/react/primitives/thread/ThreadMessages.tsx +1 -1
  290. package/src/react/primitives/thread/ThreadSuggestions.tsx +1 -1
  291. package/src/react/primitives/threadList/ThreadListItems.tsx +1 -1
  292. package/src/react/providers/AttachmentByIndexProvider.tsx +2 -2
  293. package/src/react/providers/ChainOfThoughtByIndicesProvider.tsx +1 -1
  294. package/src/react/providers/ChainOfThoughtPartByIndexProvider.tsx +2 -19
  295. package/src/react/providers/MessageByIdProvider.tsx +2 -2
  296. package/src/react/providers/MessageByIndexProvider.tsx +2 -2
  297. package/src/react/providers/PartByIndexProvider.tsx +2 -16
  298. package/src/react/providers/QueueItemByIndexProvider.tsx +1 -1
  299. package/src/react/providers/ReadonlyThreadProvider.tsx +1 -1
  300. package/src/react/providers/SuggestionByIndexProvider.tsx +1 -1
  301. package/src/react/providers/ThreadListItemByIndexProvider.tsx +1 -1
  302. package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +3 -3
  303. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +20 -6
  304. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.ts +34 -0
  305. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.tsx +32 -7
  306. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +47 -16
  307. package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.ts +5 -1
  308. package/src/react/runtimes/cloud/auiV0.ts +14 -0
  309. package/src/react/runtimes/cloud/useCloudThreadListAdapter.tsx +90 -88
  310. package/src/react/runtimes/createRuntimeExtras.test.ts +1 -1
  311. package/src/react/runtimes/createRuntimeExtras.ts +1 -1
  312. package/src/react/runtimes/external-message-converter.test.ts +346 -0
  313. package/src/react/runtimes/external-message-converter.ts +1 -1
  314. package/src/react/runtimes/useLocalRuntime.test.tsx +43 -0
  315. package/src/react/types/scopes/tools.ts +0 -6
  316. package/src/react/utils/groupParts.ts +1 -7
  317. package/src/runtime/api/assistant-runtime.ts +4 -1
  318. package/src/runtime/api/attachment-runtime.ts +8 -2
  319. package/src/runtime/api/composer-runtime.ts +9 -5
  320. package/src/runtime/api/message-part-runtime.ts +10 -3
  321. package/src/runtime/api/message-runtime.ts +7 -2
  322. package/src/runtime/api/thread-list-item-runtime.ts +7 -2
  323. package/src/runtime/api/thread-list-runtime.ts +10 -2
  324. package/src/runtime/base/base-thread-runtime-core.ts +5 -1
  325. package/src/runtime/base/default-edit-composer-runtime-core.ts +14 -2
  326. package/src/runtime/base/default-thread-composer-runtime-core.ts +11 -1
  327. package/src/runtime/utils/message-repository.ts +19 -13
  328. package/src/runtimes/external-store/external-store-thread-list-runtime-core.ts +4 -1
  329. package/src/runtimes/external-store/external-store-thread-runtime-core.ts +15 -0
  330. package/src/runtimes/internal.ts +3 -0
  331. package/src/runtimes/local/local-thread-runtime-core.test.ts +596 -0
  332. package/src/runtimes/local/local-thread-runtime-core.ts +85 -21
  333. package/src/runtimes/local/should-continue.test.ts +122 -0
  334. package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +9 -10
  335. package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +38 -32
  336. package/src/store/clients/model-context-client.test.ts +21 -1
  337. package/src/store/clients/runtime-adapter.ts +3 -3
  338. package/src/store/runtime-clients/thread-runtime-client.ts +2 -1
  339. package/src/store/scopes/thread.ts +1 -0
  340. package/src/subscribable/subscribable.ts +16 -8
  341. package/src/tests/MessageRepository.test.ts +12 -0
  342. package/src/tests/RemoteThreadListThreadListRuntimeCore-switchToThread-position.test.ts +121 -0
  343. package/src/tests/auiV0Encode.test.ts +74 -0
  344. package/src/tests/base-composer-runtime-core.test.ts +422 -0
  345. package/src/tests/external-store-thread-list-runtime-core.test.ts +6 -6
  346. package/src/tests/external-store-thread-runtime-core-adapter.test.ts +575 -0
  347. package/src/tests/external-store-thread-runtime-core.test.ts +55 -1
  348. package/src/tests/groupParts.test.ts +3 -48
  349. package/src/tests/OptimisticState-delete-crash.test.ts +0 -208
@@ -7,6 +7,7 @@ import type {
7
7
  } from "../../runtime/utils/chat-model-adapter";
8
8
  import type { AppendMessage } from "../../types/message";
9
9
  import type { LocalRuntimeOptionsBase } from "./local-runtime-options";
10
+ import type { ExportedMessageRepositoryItem } from "../../runtime/utils/message-repository";
10
11
 
11
12
  const flush = () => new Promise((resolve) => setTimeout(resolve, 10));
12
13
 
@@ -18,6 +19,8 @@ const createThread = (
18
19
  adapter: ChatModelAdapter,
19
20
  options?: {
20
21
  suggestion?: LocalRuntimeOptionsBase["adapters"]["suggestion"];
22
+ history?: LocalRuntimeOptionsBase["adapters"]["history"];
23
+ maxSteps?: number;
21
24
  },
22
25
  ) => {
23
26
  const core = new LocalRuntimeCore(
@@ -27,8 +30,12 @@ const createThread = (
27
30
  ...(options?.suggestion !== undefined && {
28
31
  suggestion: options.suggestion,
29
32
  }),
33
+ ...(options?.history !== undefined && {
34
+ history: options.history,
35
+ }),
30
36
  },
31
37
  unstable_humanToolNames: ["send_email"],
38
+ ...(options?.maxSteps !== undefined && { maxSteps: options.maxSteps }),
32
39
  },
33
40
  undefined,
34
41
  );
@@ -641,3 +648,592 @@ describe("LocalThreadRuntimeCore suggestions", () => {
641
648
  expect(thread.suggestions).toEqual([{ prompt: "follow up" }]);
642
649
  });
643
650
  });
651
+
652
+ describe("LocalThreadRuntimeCore tool approval persistence", () => {
653
+ const createHistory = (options?: { update?: boolean }) => {
654
+ const appended: ExportedMessageRepositoryItem[] = [];
655
+ const updated: ExportedMessageRepositoryItem[] = [];
656
+ const history = {
657
+ async load() {
658
+ return { messages: [] };
659
+ },
660
+ async append(item: ExportedMessageRepositoryItem) {
661
+ appended.push(item);
662
+ },
663
+ ...(options?.update !== false && {
664
+ async update(item: ExportedMessageRepositoryItem) {
665
+ updated.push(item);
666
+ },
667
+ }),
668
+ };
669
+ return { history, appended, updated };
670
+ };
671
+
672
+ const createApprovalThreadWithHistory = (
673
+ history: LocalRuntimeOptionsBase["adapters"]["history"],
674
+ ) => {
675
+ const runs: ChatModelRunOptions[] = [];
676
+ return createThread(
677
+ {
678
+ async run(options) {
679
+ runs.push(options);
680
+ if (runs.length === 1)
681
+ return toolCallResult("send_email", { id: "a1" });
682
+ return { content: [{ type: "text", text: "done" }] };
683
+ },
684
+ },
685
+ { history },
686
+ );
687
+ };
688
+
689
+ it("persists a run paused for approval and rewrites it once the run finishes", async () => {
690
+ const { history, appended, updated } = createHistory();
691
+ const thread = createApprovalThreadWithHistory(history);
692
+
693
+ await thread.append(userMessage("send an email"));
694
+ await flush();
695
+
696
+ const assistant = appended.find((i) => i.message.role === "assistant");
697
+ expect(assistant?.message.status?.type).toBe("requires-action");
698
+
699
+ thread.respondToToolApproval({ approvalId: "a1", approved: true });
700
+ await flush();
701
+
702
+ expect(thread.messages.at(-1)?.status?.type).toBe("complete");
703
+ expect(
704
+ appended.filter((i) => i.message.id === assistant?.message.id),
705
+ ).toHaveLength(1);
706
+ expect(updated.at(-1)?.message.id).toBe(assistant?.message.id);
707
+ expect(updated.at(-1)?.message.status?.type).toBe("complete");
708
+ });
709
+
710
+ it("keeps the append-only behavior for adapters without update", async () => {
711
+ const { history, appended } = createHistory({ update: false });
712
+ const thread = createApprovalThreadWithHistory(history);
713
+
714
+ await thread.append(userMessage("send an email"));
715
+ await flush();
716
+
717
+ expect(appended.some((i) => i.message.role === "assistant")).toBe(false);
718
+
719
+ thread.respondToToolApproval({ approvalId: "a1", approved: true });
720
+ await flush();
721
+
722
+ const assistants = appended.filter((i) => i.message.role === "assistant");
723
+ expect(assistants).toHaveLength(1);
724
+ expect(assistants[0]?.message.status?.type).toBe("complete");
725
+ });
726
+
727
+ it("rewrites a restored paused message instead of appending a duplicate", async () => {
728
+ const { history, appended, updated } = createHistory();
729
+ const runs: ChatModelRunOptions[] = [];
730
+ const paused: ExportedMessageRepositoryItem = {
731
+ parentId: null,
732
+ message: {
733
+ id: "restored",
734
+ role: "assistant",
735
+ content: [toolCallPart("send_email", { id: "a1" })],
736
+ status: { type: "requires-action", reason: "tool-calls" },
737
+ createdAt: new Date(),
738
+ metadata: {
739
+ unstable_state: null,
740
+ unstable_annotations: [],
741
+ unstable_data: [],
742
+ steps: [],
743
+ custom: {},
744
+ },
745
+ },
746
+ };
747
+ const thread = createThread(
748
+ {
749
+ async run(options) {
750
+ runs.push(options);
751
+ return { content: [{ type: "text", text: "done" }] };
752
+ },
753
+ },
754
+ {
755
+ history: {
756
+ ...history,
757
+ async load() {
758
+ return { headId: "restored", messages: [paused] };
759
+ },
760
+ },
761
+ },
762
+ );
763
+
764
+ thread.__internal_load();
765
+ await flush();
766
+
767
+ thread.respondToToolApproval({ approvalId: "a1", approved: true });
768
+ await flush();
769
+
770
+ expect(runs).toHaveLength(1);
771
+ expect(appended).toHaveLength(0);
772
+ expect(updated.at(-1)?.message.id).toBe("restored");
773
+ expect(updated.at(-1)?.message.status?.type).toBe("complete");
774
+ });
775
+
776
+ it("still appends a restored paused message when the adapter cannot update", async () => {
777
+ const { history, appended } = createHistory({ update: false });
778
+ const paused: ExportedMessageRepositoryItem = {
779
+ parentId: null,
780
+ message: {
781
+ id: "restored",
782
+ role: "assistant",
783
+ content: [toolCallPart("send_email", { id: "a1" })],
784
+ status: { type: "requires-action", reason: "tool-calls" },
785
+ createdAt: new Date(),
786
+ metadata: {
787
+ unstable_state: null,
788
+ unstable_annotations: [],
789
+ unstable_data: [],
790
+ steps: [],
791
+ custom: {},
792
+ },
793
+ },
794
+ };
795
+ const thread = createThread(
796
+ {
797
+ async run() {
798
+ return { content: [{ type: "text", text: "done" }] };
799
+ },
800
+ },
801
+ {
802
+ history: {
803
+ ...history,
804
+ async load() {
805
+ return { headId: "restored", messages: [paused] };
806
+ },
807
+ },
808
+ },
809
+ );
810
+
811
+ thread.__internal_load();
812
+ await flush();
813
+
814
+ thread.respondToToolApproval({ approvalId: "a1", approved: true });
815
+ await flush();
816
+
817
+ expect(appended).toHaveLength(1);
818
+ expect(appended[0]?.message.id).toBe("restored");
819
+ expect(appended[0]?.message.status?.type).toBe("complete");
820
+ });
821
+
822
+ it("persists a partial approval decision while another tool call is still pending", async () => {
823
+ const { history, updated } = createHistory();
824
+ const runs: ChatModelRunOptions[] = [];
825
+ const twoPendingApprovals: ChatModelRunResult = {
826
+ content: [
827
+ { ...toolCallPart("send_email", { id: "a1" }), toolCallId: "call-1" },
828
+ { ...toolCallPart("send_email", { id: "a2" }), toolCallId: "call-2" },
829
+ ],
830
+ status: { type: "requires-action", reason: "tool-calls" },
831
+ };
832
+ const thread = createThread(
833
+ {
834
+ async run(options) {
835
+ runs.push(options);
836
+ if (runs.length === 1) return twoPendingApprovals;
837
+ return { content: [{ type: "text", text: "done" }] };
838
+ },
839
+ },
840
+ { history },
841
+ );
842
+
843
+ await thread.append(userMessage("send two emails"));
844
+ await flush();
845
+
846
+ const assistant = thread.messages.at(-1)!;
847
+ expect(assistant.status?.type).toBe("requires-action");
848
+
849
+ thread.respondToToolApproval({ approvalId: "a1", approved: true });
850
+ await flush();
851
+
852
+ // The second approval is still pending, so the run must not resume yet —
853
+ // but the first decision has to survive a refresh in the meantime.
854
+ expect(runs).toHaveLength(1);
855
+ const persisted = updated
856
+ .at(-1)
857
+ ?.message.content.find(
858
+ (c) => c.type === "tool-call" && c.toolCallId === "call-1",
859
+ );
860
+ expect(
861
+ persisted?.type === "tool-call" && persisted.approval?.approved,
862
+ ).toBe(true);
863
+ });
864
+
865
+ it("persists a partial tool result while another human tool call is still pending", async () => {
866
+ const { history, updated } = createHistory();
867
+ const runs: ChatModelRunOptions[] = [];
868
+ const twoHumanTools: ChatModelRunResult = {
869
+ content: [
870
+ {
871
+ type: "tool-call",
872
+ toolCallId: "call-1",
873
+ toolName: "send_email",
874
+ args: {},
875
+ argsText: "{}",
876
+ },
877
+ {
878
+ type: "tool-call",
879
+ toolCallId: "call-2",
880
+ toolName: "send_email",
881
+ args: {},
882
+ argsText: "{}",
883
+ },
884
+ ],
885
+ status: { type: "requires-action", reason: "tool-calls" },
886
+ };
887
+ const thread = createThread(
888
+ {
889
+ async run(options) {
890
+ runs.push(options);
891
+ if (runs.length === 1) return twoHumanTools;
892
+ return { content: [{ type: "text", text: "done" }] };
893
+ },
894
+ },
895
+ { history },
896
+ );
897
+
898
+ await thread.append(userMessage("send two emails"));
899
+ await flush();
900
+
901
+ const assistant = thread.messages.at(-1)!;
902
+
903
+ thread.addToolResult({
904
+ messageId: assistant.id,
905
+ toolName: "send_email",
906
+ toolCallId: "call-1",
907
+ result: { ok: true },
908
+ isError: false,
909
+ });
910
+ await flush();
911
+
912
+ expect(runs).toHaveLength(1);
913
+ const persisted = updated
914
+ .at(-1)
915
+ ?.message.content.find(
916
+ (c) => c.type === "tool-call" && c.toolCallId === "call-1",
917
+ );
918
+ expect(persisted?.type === "tool-call" && persisted.result).toEqual({
919
+ ok: true,
920
+ });
921
+ });
922
+
923
+ it("persists a multi-step run once instead of writing intermediate steps", async () => {
924
+ const { history, appended, updated } = createHistory();
925
+ const runs: ChatModelRunOptions[] = [];
926
+ const thread = createThread(
927
+ {
928
+ async run(options) {
929
+ runs.push(options);
930
+ if (runs.length === 1)
931
+ return {
932
+ content: [
933
+ { ...toolCallPart("lookup_weather"), result: { ok: true } },
934
+ ],
935
+ status: { type: "requires-action", reason: "tool-calls" },
936
+ };
937
+ return { content: [{ type: "text", text: "done" }] };
938
+ },
939
+ },
940
+ { history },
941
+ );
942
+
943
+ await thread.append(userMessage("what is the weather"));
944
+ await flush();
945
+
946
+ expect(runs).toHaveLength(2);
947
+ const assistants = appended.filter((i) => i.message.role === "assistant");
948
+ expect(assistants).toHaveLength(1);
949
+ expect(assistants[0]?.message.status?.type).toBe("complete");
950
+ expect(updated).toHaveLength(0);
951
+ });
952
+
953
+ it("rewrites the same entry when a resumed run pauses again", async () => {
954
+ const { history, appended, updated } = createHistory();
955
+ const runs: ChatModelRunOptions[] = [];
956
+ const thread = createThread(
957
+ {
958
+ async run(options) {
959
+ runs.push(options);
960
+ if (runs.length === 1)
961
+ return toolCallResult("send_email", { id: "a1" });
962
+ if (runs.length === 2)
963
+ return {
964
+ content: [
965
+ {
966
+ ...toolCallPart("send_email", { id: "a2" }),
967
+ toolCallId: "call-2",
968
+ },
969
+ ],
970
+ status: { type: "requires-action", reason: "tool-calls" },
971
+ };
972
+ return { content: [{ type: "text", text: "done" }] };
973
+ },
974
+ },
975
+ { history },
976
+ );
977
+
978
+ await thread.append(userMessage("send two emails"));
979
+ await flush();
980
+
981
+ thread.respondToToolApproval({ approvalId: "a1", approved: true });
982
+ await flush();
983
+
984
+ expect(thread.messages.at(-1)?.status?.type).toBe("requires-action");
985
+
986
+ thread.respondToToolApproval({ approvalId: "a2", approved: true });
987
+ await flush();
988
+
989
+ expect(runs).toHaveLength(3);
990
+ const assistants = appended.filter((i) => i.message.role === "assistant");
991
+ expect(assistants).toHaveLength(1);
992
+ expect(assistants[0]?.message.status?.type).toBe("requires-action");
993
+ expect(updated).toHaveLength(2);
994
+ expect(
995
+ updated.every((i) => i.message.id === assistants[0]?.message.id),
996
+ ).toBe(true);
997
+ expect(updated.at(-1)?.message.status?.type).toBe("complete");
998
+ });
999
+
1000
+ it("finalizes the history entry when a resumed run hits max steps", async () => {
1001
+ const { history, appended, updated } = createHistory();
1002
+ const runs: ChatModelRunOptions[] = [];
1003
+ const thread = createThread(
1004
+ {
1005
+ async run(options) {
1006
+ runs.push(options);
1007
+ return {
1008
+ content: [toolCallPart("send_email", { id: "a1" })],
1009
+ status: { type: "requires-action", reason: "tool-calls" },
1010
+ metadata: { steps: [{}] },
1011
+ };
1012
+ },
1013
+ },
1014
+ { history, maxSteps: 1 },
1015
+ );
1016
+
1017
+ await thread.append(userMessage("send an email"));
1018
+ await flush();
1019
+
1020
+ thread.respondToToolApproval({ approvalId: "a1", approved: true });
1021
+ await flush();
1022
+
1023
+ expect(runs).toHaveLength(1);
1024
+ expect(thread.messages.at(-1)?.status?.type).toBe("incomplete");
1025
+ const assistants = appended.filter((i) => i.message.role === "assistant");
1026
+ expect(assistants).toHaveLength(1);
1027
+ expect(updated).toHaveLength(1);
1028
+ expect(updated.at(-1)?.message.status?.type).toBe("incomplete");
1029
+ });
1030
+
1031
+ it("orders the terminal rewrite after an in-flight partial decision write", async () => {
1032
+ const order: string[] = [];
1033
+ let releasePartial!: () => void;
1034
+ const gate = new Promise<void>((resolve) => {
1035
+ releasePartial = resolve;
1036
+ });
1037
+ const history = {
1038
+ async load() {
1039
+ return { messages: [] };
1040
+ },
1041
+ async append() {},
1042
+ async update(item: ExportedMessageRepositoryItem) {
1043
+ const kind =
1044
+ item.message.status?.type === "requires-action"
1045
+ ? "partial"
1046
+ : "terminal";
1047
+ order.push(`${kind}:start`);
1048
+ if (kind === "partial") await gate;
1049
+ order.push(`${kind}:end`);
1050
+ },
1051
+ };
1052
+ const runs: ChatModelRunOptions[] = [];
1053
+ const twoPendingApprovals: ChatModelRunResult = {
1054
+ content: [
1055
+ { ...toolCallPart("send_email", { id: "a1" }), toolCallId: "call-1" },
1056
+ { ...toolCallPart("send_email", { id: "a2" }), toolCallId: "call-2" },
1057
+ ],
1058
+ status: { type: "requires-action", reason: "tool-calls" },
1059
+ };
1060
+ const thread = createThread(
1061
+ {
1062
+ async run(options) {
1063
+ runs.push(options);
1064
+ if (runs.length === 1) return twoPendingApprovals;
1065
+ return { content: [{ type: "text", text: "done" }] };
1066
+ },
1067
+ },
1068
+ { history },
1069
+ );
1070
+
1071
+ await thread.append(userMessage("send two emails"));
1072
+ await flush();
1073
+
1074
+ thread.respondToToolApproval({ approvalId: "a1", approved: true });
1075
+ thread.respondToToolApproval({ approvalId: "a2", approved: true });
1076
+ await flush();
1077
+
1078
+ expect(order).toEqual(["partial:start"]);
1079
+
1080
+ releasePartial();
1081
+ await flush();
1082
+
1083
+ expect(order).toEqual([
1084
+ "partial:start",
1085
+ "partial:end",
1086
+ "terminal:start",
1087
+ "terminal:end",
1088
+ ]);
1089
+ });
1090
+ });
1091
+
1092
+ describe("LocalThreadRuntimeCore runs", () => {
1093
+ const createPlainThread = (
1094
+ adapter: ChatModelAdapter,
1095
+ options?: { maxSteps?: number },
1096
+ ) => {
1097
+ const core = new LocalRuntimeCore(
1098
+ {
1099
+ adapters: { chatModel: adapter },
1100
+ ...(options?.maxSteps !== undefined && { maxSteps: options.maxSteps }),
1101
+ },
1102
+ undefined,
1103
+ );
1104
+ return core.threads.getMainThreadRuntimeCore();
1105
+ };
1106
+
1107
+ it("appends the user message and the adapter result", async () => {
1108
+ const run = vi.fn(
1109
+ async (): Promise<ChatModelRunResult> => ({
1110
+ content: [{ type: "text", text: "Hello!" }],
1111
+ status: { type: "complete", reason: "stop" },
1112
+ }),
1113
+ );
1114
+ const thread = createPlainThread({ run });
1115
+
1116
+ await thread.append(userMessage("Hi"));
1117
+
1118
+ expect(run).toHaveBeenCalledOnce();
1119
+ expect(thread.messages).toHaveLength(2);
1120
+ expect(thread.messages[0]?.role).toBe("user");
1121
+ const assistant = thread.messages[1]!;
1122
+ expect(assistant.role).toBe("assistant");
1123
+ expect(assistant.content).toContainEqual(
1124
+ expect.objectContaining({ type: "text", text: "Hello!" }),
1125
+ );
1126
+ expect(assistant.status).toEqual({ type: "complete", reason: "stop" });
1127
+ });
1128
+
1129
+ it("streams the assistant response via an async generator", async () => {
1130
+ const thread = createPlainThread({
1131
+ async *run() {
1132
+ yield { content: [{ type: "text" as const, text: "Hel" }] };
1133
+ yield {
1134
+ content: [{ type: "text" as const, text: "Hello world" }],
1135
+ status: { type: "complete" as const, reason: "stop" as const },
1136
+ };
1137
+ },
1138
+ });
1139
+
1140
+ await thread.append(userMessage("Stream test"));
1141
+
1142
+ const assistant = thread.messages.at(-1)!;
1143
+ expect(assistant.content).toContainEqual(
1144
+ expect.objectContaining({ type: "text", text: "Hello world" }),
1145
+ );
1146
+ expect(assistant.status).toEqual({ type: "complete", reason: "stop" });
1147
+ });
1148
+
1149
+ it("marks the message errored when the adapter rejects", async () => {
1150
+ const thread = createPlainThread({
1151
+ async run() {
1152
+ throw new Error("Model unavailable");
1153
+ },
1154
+ });
1155
+
1156
+ await expect(thread.append(userMessage("Error test"))).rejects.toThrow(
1157
+ "Model unavailable",
1158
+ );
1159
+
1160
+ const assistant = thread.messages.at(-1)!;
1161
+ expect(assistant.status).toEqual({
1162
+ type: "incomplete",
1163
+ reason: "error",
1164
+ error: { code: "unknown", message: "Model unavailable" },
1165
+ });
1166
+ });
1167
+
1168
+ it("does not run again after a tool result once maxSteps is reached", async () => {
1169
+ const run = vi.fn(
1170
+ async (): Promise<ChatModelRunResult> => ({
1171
+ content: [
1172
+ {
1173
+ type: "tool-call",
1174
+ toolCallId: "tc1",
1175
+ toolName: "myTool",
1176
+ args: {},
1177
+ argsText: "{}",
1178
+ },
1179
+ ],
1180
+ status: { type: "requires-action", reason: "tool-calls" },
1181
+ metadata: {
1182
+ steps: [{ usage: { promptTokens: 10, completionTokens: 5 } }],
1183
+ },
1184
+ }),
1185
+ );
1186
+ const thread = createPlainThread({ run }, { maxSteps: 1 });
1187
+
1188
+ await thread.append(userMessage("Tool call"));
1189
+
1190
+ thread.addToolResult({
1191
+ messageId: thread.messages.at(-1)!.id,
1192
+ toolName: "myTool",
1193
+ toolCallId: "tc1",
1194
+ result: "result",
1195
+ isError: false,
1196
+ });
1197
+ await flush();
1198
+
1199
+ expect(run).toHaveBeenCalledTimes(1);
1200
+ expect(thread.messages.at(-1)?.status).toMatchObject({
1201
+ type: "incomplete",
1202
+ reason: "tool-calls",
1203
+ });
1204
+ });
1205
+
1206
+ it("derives capabilities from the configured adapters", () => {
1207
+ const adapter: ChatModelAdapter = {
1208
+ run: async () => ({ content: [] }),
1209
+ };
1210
+ const thread = createPlainThread(adapter);
1211
+
1212
+ expect(thread.capabilities.speech).toBe(false);
1213
+ expect(thread.capabilities.dictation).toBe(false);
1214
+ expect(thread.capabilities.attachments).toBe(false);
1215
+ expect(thread.capabilities.feedback).toBe(false);
1216
+
1217
+ thread.__internal_setOptions({
1218
+ adapters: {
1219
+ chatModel: adapter,
1220
+ speech: {} as any,
1221
+ dictation: {} as any,
1222
+ attachments: {} as any,
1223
+ feedback: {} as any,
1224
+ },
1225
+ });
1226
+
1227
+ expect(thread.capabilities.speech).toBe(true);
1228
+ expect(thread.capabilities.dictation).toBe(true);
1229
+ expect(thread.capabilities.attachments).toBe(true);
1230
+ expect(thread.capabilities.feedback).toBe(true);
1231
+
1232
+ thread.__internal_setOptions({ adapters: { chatModel: adapter } });
1233
+
1234
+ expect(thread.capabilities.speech).toBe(false);
1235
+ expect(thread.capabilities.dictation).toBe(false);
1236
+ expect(thread.capabilities.attachments).toBe(false);
1237
+ expect(thread.capabilities.feedback).toBe(false);
1238
+ });
1239
+ });