@assistant-ui/core 0.3.17 → 0.3.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (470) hide show
  1. package/dist/adapters/attachment.d.ts.map +1 -1
  2. package/dist/adapters/attachment.js +5 -4
  3. package/dist/adapters/attachment.js.map +1 -1
  4. package/dist/adapters/speech.d.ts.map +1 -1
  5. package/dist/adapters/speech.js +13 -3
  6. package/dist/adapters/speech.js.map +1 -1
  7. package/dist/adapters/thread-history.d.ts +4 -0
  8. package/dist/adapters/thread-history.d.ts.map +1 -1
  9. package/dist/index.d.ts +3 -3
  10. package/dist/index.js.map +1 -1
  11. package/dist/internal.d.ts +4 -3
  12. package/dist/internal.js +3 -2
  13. package/dist/model-context/frame/host.d.ts.map +1 -1
  14. package/dist/model-context/frame/host.js +35 -14
  15. package/dist/model-context/frame/host.js.map +1 -1
  16. package/dist/model-context/frame/provider.d.ts +2 -0
  17. package/dist/model-context/frame/provider.d.ts.map +1 -1
  18. package/dist/model-context/frame/provider.js +30 -7
  19. package/dist/model-context/frame/provider.js.map +1 -1
  20. package/dist/model-context/interactable-composer-metadata.d.ts.map +1 -1
  21. package/dist/model-context/interactable-composer-metadata.js +27 -18
  22. package/dist/model-context/interactable-composer-metadata.js.map +1 -1
  23. package/dist/model-context/registry.d.ts.map +1 -1
  24. package/dist/model-context/registry.js +3 -5
  25. package/dist/model-context/registry.js.map +1 -1
  26. package/dist/model-context/types.d.ts.map +1 -1
  27. package/dist/model-context/types.js +5 -4
  28. package/dist/model-context/types.js.map +1 -1
  29. package/dist/react/adapters/LocalStorageThreadListAdapter.d.ts.map +1 -1
  30. package/dist/react/adapters/LocalStorageThreadListAdapter.js +45 -7
  31. package/dist/react/adapters/LocalStorageThreadListAdapter.js.map +1 -1
  32. package/dist/react/client/DataRenderers.d.ts.map +1 -1
  33. package/dist/react/client/DataRenderers.js +20 -15
  34. package/dist/react/client/DataRenderers.js.map +1 -1
  35. package/dist/react/client/InMemoryThreadList.d.ts.map +1 -1
  36. package/dist/react/client/InMemoryThreadList.js +62 -56
  37. package/dist/react/client/InMemoryThreadList.js.map +1 -1
  38. package/dist/react/client/Interactables.d.ts.map +1 -1
  39. package/dist/react/client/Interactables.js +35 -32
  40. package/dist/react/client/Interactables.js.map +1 -1
  41. package/dist/react/client/RemoteThreadList.d.ts +1 -0
  42. package/dist/react/client/RemoteThreadList.d.ts.map +1 -1
  43. package/dist/react/client/RemoteThreadList.js +154 -143
  44. package/dist/react/client/RemoteThreadList.js.map +1 -1
  45. package/dist/react/client/Tools.d.ts.map +1 -1
  46. package/dist/react/client/Tools.js +18 -16
  47. package/dist/react/client/Tools.js.map +1 -1
  48. package/dist/react/client/interactable-model-context.d.ts.map +1 -1
  49. package/dist/react/client/interactable-model-context.js +3 -2
  50. package/dist/react/client/interactable-model-context.js.map +1 -1
  51. package/dist/react/index.d.ts +2 -2
  52. package/dist/react/index.js +2 -2
  53. package/dist/react/interactables-legacy/Interactables.js +242 -121
  54. package/dist/react/interactables-legacy/Interactables.js.map +1 -1
  55. package/dist/react/interactables-legacy/useAssistantInteractable.d.ts.map +1 -1
  56. package/dist/react/interactables-legacy/useAssistantInteractable.js +3 -0
  57. package/dist/react/interactables-legacy/useAssistantInteractable.js.map +1 -1
  58. package/dist/react/interactables-shared/useInteractablePersistenceQueue.d.ts.map +1 -1
  59. package/dist/react/interactables-shared/useInteractablePersistenceQueue.js +11 -9
  60. package/dist/react/interactables-shared/useInteractablePersistenceQueue.js.map +1 -1
  61. package/dist/react/model-context/makeAssistantTool.d.ts +2 -2
  62. package/dist/react/model-context/makeAssistantTool.js +1 -1
  63. package/dist/react/model-context/makeAssistantTool.js.map +1 -1
  64. package/dist/react/model-context/useAssistantTool.d.ts +2 -2
  65. package/dist/react/model-context/useAssistantTool.js +1 -1
  66. package/dist/react/model-context/useAssistantTool.js.map +1 -1
  67. package/dist/react/model-context/useInteractable.d.ts.map +1 -1
  68. package/dist/react/model-context/useInteractable.js +4 -1
  69. package/dist/react/model-context/useInteractable.js.map +1 -1
  70. package/dist/react/model-context/useInteractableVersions.js +1 -1
  71. package/dist/react/model-context/useToolArgsStatus.d.ts.map +1 -1
  72. package/dist/react/model-context/useToolArgsStatus.js +2 -1
  73. package/dist/react/model-context/useToolArgsStatus.js.map +1 -1
  74. package/dist/react/primitives/message/MessageGroupedParts.d.ts +11 -2
  75. package/dist/react/primitives/message/MessageGroupedParts.d.ts.map +1 -1
  76. package/dist/react/primitives/message/MessageGroupedParts.js +3 -2
  77. package/dist/react/primitives/message/MessageGroupedParts.js.map +1 -1
  78. package/dist/react/primitives/part/PartMessages.d.ts +1 -0
  79. package/dist/react/primitives/part/PartMessages.d.ts.map +1 -1
  80. package/dist/react/primitives/part/PartMessages.js +1 -0
  81. package/dist/react/primitives/part/PartMessages.js.map +1 -1
  82. package/dist/react/primitives/thread/ThreadMessages.d.ts.map +1 -1
  83. package/dist/react/primitives/thread/ThreadMessages.js +6 -5
  84. package/dist/react/primitives/thread/ThreadMessages.js.map +1 -1
  85. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
  86. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +16 -8
  87. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
  88. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +5 -1
  89. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
  90. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +105 -104
  91. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
  92. package/dist/react/runtimes/RemoteThreadResource.d.ts +1 -0
  93. package/dist/react/runtimes/RemoteThreadResource.d.ts.map +1 -1
  94. package/dist/react/runtimes/RemoteThreadResource.js +13 -11
  95. package/dist/react/runtimes/RemoteThreadResource.js.map +1 -1
  96. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts +5 -24
  97. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
  98. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +354 -226
  99. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
  100. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts +1 -0
  101. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts.map +1 -1
  102. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js +22 -2
  103. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js.map +1 -1
  104. package/dist/react/runtimes/cloud/auiV0.d.ts +40 -15
  105. package/dist/react/runtimes/cloud/auiV0.d.ts.map +1 -1
  106. package/dist/react/runtimes/cloud/auiV0.js +62 -15
  107. package/dist/react/runtimes/cloud/auiV0.js.map +1 -1
  108. package/dist/react/runtimes/cloud/createCloudThreadListAdapter.d.ts +2 -1
  109. package/dist/react/runtimes/cloud/createCloudThreadListAdapter.d.ts.map +1 -1
  110. package/dist/react/runtimes/cloud/createCloudThreadListAdapter.js +6 -1
  111. package/dist/react/runtimes/cloud/createCloudThreadListAdapter.js.map +1 -1
  112. package/dist/react/runtimes/cloud/sdkIdentity.d.ts +6 -0
  113. package/dist/react/runtimes/cloud/sdkIdentity.d.ts.map +1 -0
  114. package/dist/react/runtimes/cloud/sdkIdentity.js +9 -0
  115. package/dist/react/runtimes/cloud/sdkIdentity.js.map +1 -0
  116. package/dist/react/runtimes/external-message-converter.d.ts +12 -2
  117. package/dist/react/runtimes/external-message-converter.d.ts.map +1 -1
  118. package/dist/react/runtimes/external-message-converter.js +26 -61
  119. package/dist/react/runtimes/external-message-converter.js.map +1 -1
  120. package/dist/react/runtimes/useExternalStoreRuntime.js +75 -46
  121. package/dist/react/runtimes/useExternalStoreRuntime.js.map +1 -1
  122. package/dist/react/runtimes/useRemoteThreadListRuntime.d.ts.map +1 -1
  123. package/dist/react/runtimes/useRemoteThreadListRuntime.js +64 -24
  124. package/dist/react/runtimes/useRemoteThreadListRuntime.js.map +1 -1
  125. package/dist/react/utils/groupParts.d.ts +6 -1
  126. package/dist/react/utils/groupParts.d.ts.map +1 -1
  127. package/dist/react/utils/groupParts.js +6 -0
  128. package/dist/react/utils/groupParts.js.map +1 -1
  129. package/dist/react/utils/useJSONEqual.d.ts +3 -1
  130. package/dist/react/utils/useJSONEqual.d.ts.map +1 -1
  131. package/dist/react/utils/useJSONEqual.js +6 -1
  132. package/dist/react/utils/useJSONEqual.js.map +1 -1
  133. package/dist/react/utils/useJSONSchemaDependency.d.ts +7 -0
  134. package/dist/react/utils/useJSONSchemaDependency.d.ts.map +1 -0
  135. package/dist/react/utils/useJSONSchemaDependency.js +20 -0
  136. package/dist/react/utils/useJSONSchemaDependency.js.map +1 -0
  137. package/dist/runtime/api/thread-list-item-runtime.d.ts +7 -3
  138. package/dist/runtime/api/thread-list-item-runtime.d.ts.map +1 -1
  139. package/dist/runtime/api/thread-list-item-runtime.js +2 -2
  140. package/dist/runtime/api/thread-list-item-runtime.js.map +1 -1
  141. package/dist/runtime/api/thread-list-runtime.d.ts +3 -0
  142. package/dist/runtime/api/thread-list-runtime.d.ts.map +1 -1
  143. package/dist/runtime/api/thread-list-runtime.js +18 -14
  144. package/dist/runtime/api/thread-list-runtime.js.map +1 -1
  145. package/dist/runtime/api/thread-runtime.d.ts +4 -0
  146. package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
  147. package/dist/runtime/api/thread-runtime.js +3 -6
  148. package/dist/runtime/api/thread-runtime.js.map +1 -1
  149. package/dist/runtime/base/base-composer-runtime-core.d.ts +1 -0
  150. package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
  151. package/dist/runtime/base/base-composer-runtime-core.js +62 -22
  152. package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
  153. package/dist/runtime/base/base-thread-runtime-core.d.ts +2 -0
  154. package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
  155. package/dist/runtime/base/base-thread-runtime-core.js +161 -69
  156. package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
  157. package/dist/runtime/interfaces/composer-runtime-core.d.ts +12 -5
  158. package/dist/runtime/interfaces/composer-runtime-core.d.ts.map +1 -1
  159. package/dist/runtime/interfaces/thread-list-runtime-core.d.ts +4 -1
  160. package/dist/runtime/interfaces/thread-list-runtime-core.d.ts.map +1 -1
  161. package/dist/runtime/interfaces/thread-runtime-core.d.ts +6 -0
  162. package/dist/runtime/interfaces/thread-runtime-core.d.ts.map +1 -1
  163. package/dist/runtime/queue/message-queue.d.ts +5 -0
  164. package/dist/runtime/queue/message-queue.d.ts.map +1 -1
  165. package/dist/runtime/queue/message-queue.js +61 -6
  166. package/dist/runtime/queue/message-queue.js.map +1 -1
  167. package/dist/runtime/utils/auto-status.d.ts +6 -2
  168. package/dist/runtime/utils/auto-status.d.ts.map +1 -1
  169. package/dist/runtime/utils/auto-status.js +12 -4
  170. package/dist/runtime/utils/auto-status.js.map +1 -1
  171. package/dist/runtime/utils/external-message-conversion.d.ts +16 -4
  172. package/dist/runtime/utils/external-message-conversion.d.ts.map +1 -1
  173. package/dist/runtime/utils/external-message-conversion.js +49 -13
  174. package/dist/runtime/utils/external-message-conversion.js.map +1 -1
  175. package/dist/runtime/utils/message-repository.d.ts +1 -0
  176. package/dist/runtime/utils/message-repository.d.ts.map +1 -1
  177. package/dist/runtime/utils/message-repository.js +18 -9
  178. package/dist/runtime/utils/message-repository.js.map +1 -1
  179. package/dist/runtime/utils/thread-message-like.d.ts +2 -1
  180. package/dist/runtime/utils/thread-message-like.d.ts.map +1 -1
  181. package/dist/runtime/utils/thread-message-like.js +5 -3
  182. package/dist/runtime/utils/thread-message-like.js.map +1 -1
  183. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts.map +1 -1
  184. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js +21 -27
  185. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js.map +1 -1
  186. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
  187. package/dist/runtimes/external-store/external-store-thread-runtime-core.js +8 -1
  188. package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
  189. package/dist/runtimes/internal.d.ts +3 -3
  190. package/dist/runtimes/internal.js +2 -2
  191. package/dist/runtimes/local/local-thread-runtime-core.d.ts +1 -1
  192. package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
  193. package/dist/runtimes/local/local-thread-runtime-core.js +4 -1
  194. package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
  195. package/dist/runtimes/remote-thread-list/remote-thread-state.d.ts +18 -1
  196. package/dist/runtimes/remote-thread-list/remote-thread-state.d.ts.map +1 -1
  197. package/dist/runtimes/remote-thread-list/remote-thread-state.js +130 -42
  198. package/dist/runtimes/remote-thread-list/remote-thread-state.js.map +1 -1
  199. package/dist/runtimes/remote-thread-list/title-generation.d.ts +49 -0
  200. package/dist/runtimes/remote-thread-list/title-generation.d.ts.map +1 -0
  201. package/dist/runtimes/remote-thread-list/title-generation.js +197 -0
  202. package/dist/runtimes/remote-thread-list/title-generation.js.map +1 -0
  203. package/dist/runtimes/remote-thread-list/title.d.ts +3 -1
  204. package/dist/runtimes/remote-thread-list/title.d.ts.map +1 -1
  205. package/dist/runtimes/remote-thread-list/title.js +9 -1
  206. package/dist/runtimes/remote-thread-list/title.js.map +1 -1
  207. package/dist/runtimes/remote-thread-list/types.d.ts +10 -0
  208. package/dist/runtimes/remote-thread-list/types.d.ts.map +1 -1
  209. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts.map +1 -1
  210. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js +2 -1
  211. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js.map +1 -1
  212. package/dist/store/clients/external-thread.d.ts.map +1 -1
  213. package/dist/store/clients/external-thread.js +260 -203
  214. package/dist/store/clients/external-thread.js.map +1 -1
  215. package/dist/store/clients/model-context-client.d.ts.map +1 -1
  216. package/dist/store/clients/model-context-client.js +2 -1
  217. package/dist/store/clients/model-context-client.js.map +1 -1
  218. package/dist/store/clients/single-thread-list.d.ts.map +1 -1
  219. package/dist/store/clients/single-thread-list.js +1 -0
  220. package/dist/store/clients/single-thread-list.js.map +1 -1
  221. package/dist/store/clients/suggestions.d.ts.map +1 -1
  222. package/dist/store/clients/suggestions.js +5 -4
  223. package/dist/store/clients/suggestions.js.map +1 -1
  224. package/dist/store/clients/thread-tasks.d.ts +13 -0
  225. package/dist/store/clients/thread-tasks.d.ts.map +1 -0
  226. package/dist/store/clients/thread-tasks.js +69 -0
  227. package/dist/store/clients/thread-tasks.js.map +1 -0
  228. package/dist/store/index.d.ts +3 -2
  229. package/dist/store/index.js +3 -3
  230. package/dist/store/primitive-predicates.d.ts.map +1 -1
  231. package/dist/store/primitive-predicates.js +4 -4
  232. package/dist/store/primitive-predicates.js.map +1 -1
  233. package/dist/store/runtime-clients/composer-runtime-client.d.ts +1 -0
  234. package/dist/store/runtime-clients/composer-runtime-client.d.ts.map +1 -1
  235. package/dist/store/runtime-clients/composer-runtime-client.js +97 -61
  236. package/dist/store/runtime-clients/composer-runtime-client.js.map +1 -1
  237. package/dist/store/runtime-clients/message-runtime-client.d.ts +1 -0
  238. package/dist/store/runtime-clients/message-runtime-client.d.ts.map +1 -1
  239. package/dist/store/runtime-clients/message-runtime-client.js +221 -144
  240. package/dist/store/runtime-clients/message-runtime-client.js.map +1 -1
  241. package/dist/store/runtime-clients/thread-list-item-runtime-client.d.ts.map +1 -1
  242. package/dist/store/runtime-clients/thread-list-item-runtime-client.js +1 -1
  243. package/dist/store/runtime-clients/thread-list-item-runtime-client.js.map +1 -1
  244. package/dist/store/runtime-clients/thread-list-runtime-client.d.ts.map +1 -1
  245. package/dist/store/runtime-clients/thread-list-runtime-client.js +54 -52
  246. package/dist/store/runtime-clients/thread-list-runtime-client.js.map +1 -1
  247. package/dist/store/runtime-clients/thread-runtime-client.d.ts.map +1 -1
  248. package/dist/store/runtime-clients/thread-runtime-client.js +246 -126
  249. package/dist/store/runtime-clients/thread-runtime-client.js.map +1 -1
  250. package/dist/store/scope-registration.d.ts +2 -0
  251. package/dist/store/scope-registration.d.ts.map +1 -1
  252. package/dist/store/scopes/composer.d.ts +10 -2
  253. package/dist/store/scopes/composer.d.ts.map +1 -1
  254. package/dist/store/scopes/message.d.ts +30 -1
  255. package/dist/store/scopes/message.d.ts.map +1 -1
  256. package/dist/store/scopes/task.d.ts +36 -0
  257. package/dist/store/scopes/task.d.ts.map +1 -0
  258. package/dist/store/scopes/task.js +0 -0
  259. package/dist/store/scopes/thread-list-item.d.ts +2 -2
  260. package/dist/store/scopes/thread-list-item.d.ts.map +1 -1
  261. package/dist/store/scopes/thread.d.ts +28 -0
  262. package/dist/store/scopes/thread.d.ts.map +1 -1
  263. package/dist/store/scopes/threads.d.ts +1 -0
  264. package/dist/store/scopes/threads.d.ts.map +1 -1
  265. package/dist/subscribable/subscribable.d.ts +2 -1
  266. package/dist/subscribable/subscribable.d.ts.map +1 -1
  267. package/dist/subscribable/subscribable.js +23 -15
  268. package/dist/subscribable/subscribable.js.map +1 -1
  269. package/dist/types/attachment.d.ts +2 -1
  270. package/dist/types/attachment.d.ts.map +1 -1
  271. package/dist/types/attachment.js +2 -1
  272. package/dist/types/attachment.js.map +1 -1
  273. package/dist/types/index.d.ts +2 -2
  274. package/dist/types/message.d.ts +8 -1
  275. package/dist/types/message.d.ts.map +1 -1
  276. package/dist/types/message.js.map +1 -1
  277. package/dist/utils/abortable-iterable.d.ts +19 -0
  278. package/dist/utils/abortable-iterable.d.ts.map +1 -0
  279. package/dist/utils/abortable-iterable.js +88 -0
  280. package/dist/utils/abortable-iterable.js.map +1 -0
  281. package/dist/utils/composite-context-provider.d.ts.map +1 -1
  282. package/dist/utils/composite-context-provider.js +20 -2
  283. package/dist/utils/composite-context-provider.js.map +1 -1
  284. package/dist/utils/getGroupStatus.d.ts +18 -2
  285. package/dist/utils/getGroupStatus.d.ts.map +1 -1
  286. package/dist/utils/getGroupStatus.js +32 -7
  287. package/dist/utils/getGroupStatus.js.map +1 -1
  288. package/dist/utils/record.d.ts +11 -0
  289. package/dist/utils/record.d.ts.map +1 -0
  290. package/dist/utils/record.js +12 -0
  291. package/dist/utils/record.js.map +1 -0
  292. package/dist/utils/wire-media.d.ts.map +1 -1
  293. package/dist/utils/wire-media.js +2 -2
  294. package/dist/utils/wire-media.js.map +1 -1
  295. package/package.json +11 -11
  296. package/src/adapters/attachment.test.ts +50 -1
  297. package/src/adapters/attachment.ts +7 -4
  298. package/src/adapters/speech.test.ts +236 -0
  299. package/src/adapters/speech.ts +17 -10
  300. package/src/adapters/thread-history.ts +3 -0
  301. package/src/index.ts +2 -0
  302. package/src/internal.ts +4 -0
  303. package/src/model-context/frame/host.test.ts +137 -1
  304. package/src/model-context/frame/host.ts +49 -16
  305. package/src/model-context/frame/provider.test.ts +71 -0
  306. package/src/model-context/frame/provider.ts +37 -7
  307. package/src/model-context/interactable-composer-metadata.test.ts +58 -0
  308. package/src/model-context/interactable-composer-metadata.ts +19 -13
  309. package/src/model-context/registry.test.ts +12 -0
  310. package/src/model-context/registry.ts +3 -2
  311. package/src/model-context/types.test.ts +25 -0
  312. package/src/model-context/types.ts +9 -4
  313. package/src/react/RuntimeAdapter.test.ts +34 -0
  314. package/src/react/adapters/LocalStorageThreadListAdapter.test.ts +244 -0
  315. package/src/react/adapters/LocalStorageThreadListAdapter.tsx +104 -7
  316. package/src/react/client/DataRenderers.test.tsx +45 -0
  317. package/src/react/client/DataRenderers.ts +13 -9
  318. package/src/react/client/InMemoryThreadList.ts +1 -0
  319. package/src/react/client/Interactables.test.ts +72 -1
  320. package/src/react/client/Interactables.ts +22 -14
  321. package/src/react/client/RemoteThreadList.background.test.ts +148 -6
  322. package/src/react/client/RemoteThreadList.concurrent.test.tsx +42 -1
  323. package/src/react/client/RemoteThreadList.test.ts +386 -4
  324. package/src/react/client/RemoteThreadList.ts +181 -112
  325. package/src/react/client/Tools.ts +22 -11
  326. package/src/react/client/interactable-model-context.test.ts +44 -0
  327. package/src/react/client/interactable-model-context.ts +3 -2
  328. package/src/react/index.ts +5 -1
  329. package/src/react/interactables-legacy/Interactables.ts +16 -16
  330. package/src/react/interactables-legacy/useAssistantInteractable.test.tsx +132 -0
  331. package/src/react/interactables-legacy/useAssistantInteractable.ts +10 -1
  332. package/src/react/interactables-shared/useInteractablePersistenceQueue.ts +9 -10
  333. package/src/react/model-context/makeAssistantTool.ts +2 -2
  334. package/src/react/model-context/useAssistantTool.ts +2 -2
  335. package/src/react/model-context/useInteractable.test.tsx +177 -0
  336. package/src/react/model-context/useInteractable.ts +3 -0
  337. package/src/react/model-context/useToolArgsStatus.test.tsx +30 -0
  338. package/src/react/model-context/useToolArgsStatus.ts +2 -1
  339. package/src/react/primitive-hooks/useActionBarCopy.test.ts +0 -1
  340. package/src/react/primitive-hooks/useSuggestionTrigger.test.ts +0 -1
  341. package/src/react/primitives/message/MessageGroupedParts.test.tsx +96 -0
  342. package/src/react/primitives/message/MessageGroupedParts.tsx +15 -4
  343. package/src/react/primitives/part/PartMessages.test.tsx +104 -1
  344. package/src/react/primitives/part/PartMessages.tsx +1 -0
  345. package/src/react/primitives/thread/ThreadMessages.test.tsx +142 -0
  346. package/src/react/primitives/thread/ThreadMessages.tsx +8 -5
  347. package/src/react/providers/ReadonlyThreadProvider.test.tsx +56 -0
  348. package/src/react/runtimes/RemoteThreadListHookInstanceManager.destroy.test.tsx +172 -0
  349. package/src/react/runtimes/RemoteThreadListHookInstanceManager.running.test.tsx +33 -0
  350. package/src/react/runtimes/RemoteThreadListHookInstanceManager.test.tsx +7 -1
  351. package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +28 -5
  352. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.load-error.test.ts +132 -0
  353. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.switch-delete.test.ts +105 -0
  354. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +143 -112
  355. package/src/react/runtimes/RemoteThreadResource.test.ts +9 -0
  356. package/src/react/runtimes/RemoteThreadResource.ts +19 -12
  357. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.ts +20 -14
  358. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.tsx +703 -6
  359. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +492 -402
  360. package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.test.ts +77 -0
  361. package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.ts +27 -1
  362. package/src/react/runtimes/cloud/auiV0.ts +160 -25
  363. package/src/react/runtimes/cloud/createCloudThreadListAdapter.test.ts +36 -0
  364. package/src/react/runtimes/cloud/createCloudThreadListAdapter.ts +8 -1
  365. package/src/react/runtimes/cloud/sdkIdentity.ts +9 -0
  366. package/src/react/runtimes/cloud/useCloudThreadListAdapter.test.tsx +18 -4
  367. package/src/react/runtimes/external-message-converter.test.ts +136 -1
  368. package/src/react/runtimes/external-message-converter.ts +39 -93
  369. package/src/react/runtimes/useExternalStoreRuntime.lifecycle.test.tsx +41 -0
  370. package/src/react/runtimes/useExternalStoreRuntime.ts +10 -4
  371. package/src/react/runtimes/useLocalRuntime.test.tsx +20 -0
  372. package/src/react/runtimes/useRemoteThreadListRuntime.load-error.test.tsx +108 -0
  373. package/src/react/runtimes/useRemoteThreadListRuntime.ts +34 -1
  374. package/src/react/utils/groupParts.ts +12 -1
  375. package/src/react/utils/useJSONEqual.ts +9 -0
  376. package/src/react/utils/useJSONSchemaDependency.ts +22 -0
  377. package/src/runtime/api/message-runtime.test.ts +75 -0
  378. package/src/runtime/api/thread-list-item-runtime.ts +10 -3
  379. package/src/runtime/api/thread-list-runtime.ts +21 -11
  380. package/src/runtime/api/thread-runtime.test.ts +136 -0
  381. package/src/runtime/api/thread-runtime.ts +10 -5
  382. package/src/runtime/base/base-composer-runtime-core.ts +105 -24
  383. package/src/runtime/base/base-thread-runtime-core.test.ts +1063 -2
  384. package/src/runtime/base/base-thread-runtime-core.ts +228 -87
  385. package/src/runtime/interfaces/composer-runtime-core.ts +10 -5
  386. package/src/runtime/interfaces/thread-list-runtime-core.ts +5 -1
  387. package/src/runtime/interfaces/thread-runtime-core.ts +6 -0
  388. package/src/runtime/queue/message-queue.ts +68 -6
  389. package/src/runtime/utils/auto-status.test.ts +112 -1
  390. package/src/runtime/utils/auto-status.ts +31 -5
  391. package/src/runtime/utils/external-message-conversion.test.ts +202 -0
  392. package/src/runtime/utils/external-message-conversion.ts +123 -32
  393. package/src/runtime/utils/message-repository.test.ts +49 -0
  394. package/src/runtime/utils/message-repository.ts +32 -20
  395. package/src/runtime/utils/thread-message-like.test.ts +52 -0
  396. package/src/runtime/utils/thread-message-like.ts +5 -1
  397. package/src/runtimes/external-store/external-store-thread-list-runtime-core.ts +18 -13
  398. package/src/runtimes/external-store/external-store-thread-runtime-core.ts +31 -1
  399. package/src/runtimes/internal.ts +1 -0
  400. package/src/runtimes/local/local-thread-runtime-core.test.ts +21 -0
  401. package/src/runtimes/local/local-thread-runtime-core.ts +11 -1
  402. package/src/runtimes/remote-thread-list/remote-thread-state.test.ts +128 -2
  403. package/src/runtimes/remote-thread-list/remote-thread-state.ts +182 -42
  404. package/src/runtimes/remote-thread-list/title-generation.test.ts +602 -0
  405. package/src/runtimes/remote-thread-list/title-generation.ts +329 -0
  406. package/src/runtimes/remote-thread-list/title.test.ts +62 -0
  407. package/src/runtimes/remote-thread-list/title.ts +13 -0
  408. package/src/runtimes/remote-thread-list/types.ts +10 -0
  409. package/src/runtimes/tool-invocations/EDGE_CASES.md +2 -6
  410. package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +133 -0
  411. package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +10 -6
  412. package/src/store/clients/external-thread.ts +67 -4
  413. package/src/store/clients/model-context-client.ts +5 -1
  414. package/src/store/clients/single-thread-list.ts +1 -0
  415. package/src/store/clients/suggestions.test.ts +40 -0
  416. package/src/store/clients/suggestions.ts +13 -10
  417. package/src/store/clients/thread-tasks.test.ts +274 -0
  418. package/src/store/clients/thread-tasks.ts +138 -0
  419. package/src/store/index.ts +8 -0
  420. package/src/store/primitive-predicates.test.ts +48 -5
  421. package/src/store/primitive-predicates.ts +7 -2
  422. package/src/store/runtime-clients/composer-runtime-client.ts +42 -9
  423. package/src/store/runtime-clients/message-runtime-client.ts +54 -6
  424. package/src/store/runtime-clients/thread-list-item-runtime-client.ts +4 -2
  425. package/src/store/runtime-clients/thread-list-runtime-client.ts +1 -0
  426. package/src/store/runtime-clients/thread-runtime-client.ts +89 -11
  427. package/src/store/scope-registration.ts +2 -0
  428. package/src/store/scopes/composer.ts +16 -4
  429. package/src/store/scopes/message.ts +14 -0
  430. package/src/store/scopes/task.ts +34 -0
  431. package/src/store/scopes/thread-list-item.ts +5 -2
  432. package/src/store/scopes/thread.ts +20 -0
  433. package/src/store/scopes/threads.ts +1 -0
  434. package/src/store/thread-tasks.test.tsx +209 -0
  435. package/src/subscribable/subscribable.test.ts +156 -1
  436. package/src/subscribable/subscribable.ts +25 -15
  437. package/src/tests/MessageRepository.test.ts +117 -5
  438. package/src/tests/OptimisticState-list-race.test.ts +1 -0
  439. package/src/tests/RemoteThreadListThreadListRuntimeCore-initialize-adapter-change.test.ts +38 -0
  440. package/src/tests/RemoteThreadListThreadListRuntimeCore-load-race.test.ts +47 -0
  441. package/src/tests/RemoteThreadListThreadListRuntimeCore-title-race.test.ts +89 -0
  442. package/src/tests/attachment-adapters.test.ts +14 -0
  443. package/src/tests/auiV0Encode.test.ts +300 -0
  444. package/src/tests/base-composer-runtime-core-send.test.ts +51 -0
  445. package/src/tests/base-composer-runtime-core.test.ts +353 -2
  446. package/src/tests/external-store-thread-list-runtime-core.test.ts +83 -0
  447. package/src/tests/external-store-thread-runtime-core-adapter.test.ts +178 -18
  448. package/src/tests/external-thread-attachments.test.tsx +208 -0
  449. package/src/tests/external-thread-parity.test.tsx +57 -0
  450. package/src/tests/groupParts.test.ts +71 -0
  451. package/src/tests/message-queue.test.ts +253 -0
  452. package/src/tests/remote-thread-list-isLoading.test.ts +1 -0
  453. package/src/tests/remote-thread-list-reactive-threadId.test.ts +51 -0
  454. package/src/tests/thread-list-runtime-getLoadThreadsPromise.test.ts +1 -0
  455. package/src/tests/thread-switch-events.test.tsx +78 -0
  456. package/src/tests/tools-scope-migration.test.tsx +28 -0
  457. package/src/tests/useRemoteThreadListRuntime-controlled.test.tsx +43 -0
  458. package/src/types/attachment.ts +4 -0
  459. package/src/types/index.ts +1 -0
  460. package/src/types/message.ts +8 -0
  461. package/src/utils/abortable-iterable.test.ts +328 -0
  462. package/src/utils/abortable-iterable.ts +104 -0
  463. package/src/utils/composite-context-provider.test.ts +25 -0
  464. package/src/utils/composite-context-provider.ts +23 -2
  465. package/src/utils/getGroupStatus.test.ts +70 -4
  466. package/src/utils/getGroupStatus.ts +35 -12
  467. package/src/utils/record.test.ts +48 -0
  468. package/src/utils/record.ts +11 -0
  469. package/src/utils/wire-media.test.ts +10 -0
  470. package/src/utils/wire-media.ts +6 -2
@@ -1,6 +1,7 @@
1
1
  import { MessageTiming, ThreadMessage } from "../../types/message.js";
2
2
  import { ThreadMessageLike } from "./thread-message-like.js";
3
3
  import { ToolExecutionStatus } from "../../runtimes/tool-invocations/ToolInvocationTracker.js";
4
+ import { ThreadMessageConverter } from "../../runtimes/external-store/thread-message-converter.js";
4
5
  import { ReadonlyJSONValue } from "assistant-stream/utils";
5
6
  //#region src/runtime/utils/external-message-conversion.d.ts
6
7
  type JoinStrategy = "concat-content" | "none";
@@ -36,13 +37,24 @@ declare const convertExternalMessageCallback: <T>(input: T, callback: ExternalMe
36
37
  declare const joinExternalMessages: (messages: readonly ExternalMessageConverterMessage[]) => ThreadMessageLike;
37
38
  declare const chunkExternalMessages: <T>(callbackResults: ExternalMessageConverterCallbackResult<T>[], joinStrategy?: JoinStrategy) => ExternalMessageConverterChunk<T>[];
38
39
  declare const shallowArrayEqual: (a: readonly unknown[], b: readonly unknown[]) => boolean;
39
- type ExternalMessageConversionCache = {
40
+ type ExternalMessageChunkConversionCache = {
40
41
  message: ThreadMessage | undefined;
41
42
  generatedFallbackMessages: WeakSet<object>;
42
43
  };
43
- declare const convertExternalMessageChunk: <T>(message: ExternalMessageConverterChunk<T>, idx: number, chunkCount: number, isRunning: boolean, error: ReadonlyJSONValue | undefined, cache?: ExternalMessageConversionCache, cancelledMessageIds?: ReadonlySet<string>) => ThreadMessage;
44
+ type ExternalMessageConversionCallbackCacheEntry<T> = ExternalMessageConverterCallbackResult<T> & {
45
+ metadata: ExternalMessageConverterMetadata;
46
+ callback: ExternalMessageConverterCallback<T>;
47
+ };
48
+ type InternalExternalMessageConversionCache<T extends WeakKey = WeakKey> = {
49
+ callbackCache: WeakMap<T, ExternalMessageConversionCallbackCacheEntry<T>>;
50
+ chunkCache: WeakMap<ExternalMessageConverterMessage, ExternalMessageConverterChunk<T>>;
51
+ converterCache: ThreadMessageConverter;
52
+ generatedFallbackMessages: WeakSet<object>;
53
+ };
54
+ declare const createExternalMessageConversionCache: <T extends WeakKey = WeakKey>() => InternalExternalMessageConversionCache<T>;
55
+ declare const convertExternalMessageChunk: <T>(message: ExternalMessageConverterChunk<T>, idx: number, chunkCount: number, isRunning: boolean, error: ReadonlyJSONValue | undefined, cache?: ExternalMessageChunkConversionCache, cancelledMessageIds?: ReadonlySet<string>) => ThreadMessage;
44
56
  declare const completeExternalMessageConversion: (messages: ThreadMessage[], error: ReadonlyJSONValue | undefined) => ThreadMessage[];
45
- declare const convertExternalMessages: <T extends WeakKey>(messages: T[], callback: ExternalMessageConverterCallback<T>, isRunning: boolean, metadata: ExternalMessageConverterMetadata) => ThreadMessage[];
57
+ declare const convertExternalMessages: <T extends WeakKey>(messages: T[], callback: ExternalMessageConverterCallback<T>, isRunning: boolean, metadata: ExternalMessageConverterMetadata, joinStrategy?: JoinStrategy, cache?: InternalExternalMessageConversionCache<T>) => ThreadMessage[];
46
58
  //#endregion
47
- export { ExternalMessageConverterCallback, ExternalMessageConverterCallbackResult, ExternalMessageConverterChunk, ExternalMessageConverterMessage, ExternalMessageConverterMetadata, JoinStrategy, chunkExternalMessages, completeExternalMessageConversion, convertExternalMessageCallback, convertExternalMessageChunk, convertExternalMessages, joinExternalMessages, shallowArrayEqual };
59
+ export { ExternalMessageConverterCallback, ExternalMessageConverterCallbackResult, ExternalMessageConverterChunk, ExternalMessageConverterMessage, ExternalMessageConverterMetadata, InternalExternalMessageConversionCache, JoinStrategy, chunkExternalMessages, completeExternalMessageConversion, convertExternalMessageCallback, convertExternalMessageChunk, convertExternalMessages, createExternalMessageConversionCache, joinExternalMessages, shallowArrayEqual };
48
60
  //# sourceMappingURL=external-message-conversion.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"external-message-conversion.d.ts","names":[],"sources":["../../../src/runtime/utils/external-message-conversion.ts"],"mappings":";;;;;KA2BY;KAEA,mCACP;WACU;aACE,eAAe;;;EAI1B;EACA;EACA;EACA;EACA;EACA;EACA,oBAAoB;;KAGd;WACD,eAAe,eAAe;WAC9B,QAAQ;WACR,sBAAsB;WACtB,gBAAgB,eAAe;;KAG9B,iCAAiC,MAC3C,SAAS,GACT,UAAU,qCACP,kCAAkC;KAE3B,uCAAuC;EACjD,OAAO;EACP,SAAS;;KAGC,8BAA8B;EACxC,QAAQ;EACR,SAAS;;cAsDE,iCAAkC,GAC7C,OAAO,GACP,UAAU,iCAAiC,IAC3C,UAAU,qCACT,uCAAuC;cAY7B,uBACX,mBAAmB,sCAClB;cA4KU,wBAAyB,GACpC,iBAAiB,uCAAuC,MACxD,eAAe,iBAAY,8BAAA;cAmDhB,oBACX,uBACA;KASG;EACH,SAAS;EACT,2BAA2B;;cAGhB,8BAA+B,GAC1C,SAAS,8BAA8B,IACvC,aACA,oBACA,oBACA,OAAO,+BACP,QAAQ,gCACR,sBAAsB,wBAAmB;cA0F9B,oCACX,UAAU,iBACV,OAAO,kCAA6B;cAWzB,0BAA2B,UAAU,SAChD,UAAU,KACV,UAAU,iCAAiC,IAC3C,oBACA,UAAU,qCAAgC"}
1
+ {"version":3,"file":"external-message-conversion.d.ts","names":[],"sources":["../../../src/runtime/utils/external-message-conversion.ts"],"mappings":";;;;;;KA6BY;KAEA,mCACP;WACU;aACE,eAAe;;;EAI1B;EACA;EACA;EACA;EACA;EACA;EACA,oBAAoB;;KAGd;WACD,eAAe,eAAe;WAC9B,QAAQ;WACR,sBAAsB;WACtB,gBAAgB,eAAe;;KAG9B,iCAAiC,MAC3C,SAAS,GACT,UAAU,qCACP,kCAAkC;KAE3B,uCAAuC;EACjD,OAAO;EACP,SAAS;;KAGC,8BAA8B;EACxC,QAAQ;EACR,SAAS;;cAsDE,iCAAkC,GAC7C,OAAO,GACP,UAAU,iCAAiC,IAC3C,UAAU,qCACT,uCAAuC;cAe7B,uBACX,mBAAmB,sCAClB;cAwLU,wBAAyB,GACpC,iBAAiB,uCAAuC,MACxD,eAAe,iBAAY,8BAAA;cAmDhB,oBACX,uBACA;KASG;EACH,SAAS;EACT,2BAA2B;;KAGxB,4CAA4C,KAC/C,uCAAuC;EACrC,UAAU;EACV,UAAU,iCAAiC;;KAGnC,uCACV,UAAU,UAAU;EAEpB,eAAe,QAAQ,GAAG,4CAA4C;EACtE,YAAY,QACV,iCACA,8BAA8B;EAEhC,gBAAgB;EAEhB,2BAA2B;;cAGhB,uCACX,UAAU,UAAU,cACjB,uCAAuC;cAO/B,8BAA+B,GAC1C,SAAS,8BAA8B,IACvC,aACA,oBACA,oBACA,OAAO,+BACP,QAAQ,qCACR,sBAAsB,wBAAmB;cA8F9B,oCACX,UAAU,iBACV,OAAO,kCAA6B;cAWzB,0BAA2B,UAAU,SAChD,UAAU,KACV,UAAU,iCAAiC,IAC3C,oBACA,UAAU,kCACV,eAAe,cACf,QAAQ,uCAAuC,OAAE"}
@@ -2,7 +2,8 @@ import { isJSONValueEqual } from "../../utils/json/is-json-equal.js";
2
2
  import { generateErrorMessageId } from "../../utils/id.js";
3
3
  import { fromThreadMessageLike } from "./thread-message-like.js";
4
4
  import { FALLBACK_ID_PREFIX, bindExternalStoreMessage, getExternalStoreMessages, symbolInnerMessage } from "./external-store-message.js";
5
- import { getAutoStatus, isAutoStatus, isInterruptedToolCall, isPendingToolCall } from "./auto-status.js";
5
+ import { getAutoStatus, isAutoStatus, isBackgroundToolCall, isInterruptedToolCall, isPendingToolCall } from "./auto-status.js";
6
+ import { ThreadMessageConverter } from "../../runtimes/external-store/thread-message-converter.js";
6
7
  //#region src/runtime/utils/external-message-conversion.ts
7
8
  const stringifyForError = (value) => {
8
9
  let text;
@@ -31,13 +32,16 @@ const convertExternalMessageCallback = (input, callback, metadata) => ({
31
32
  outputs: toCallbackOutputs(callback(input, metadata), input)
32
33
  });
33
34
  const mergeInnerMessages = (existing, incoming) => ({ [symbolInnerMessage]: [...existing[symbolInnerMessage] ?? [], ...incoming[symbolInnerMessage] ?? []] });
35
+ const isNaNToolCallId = (toolCallId) => typeof toolCallId === "number" && Number.isNaN(toolCallId);
34
36
  const joinExternalMessages = (messages) => {
35
37
  const assistantMessage = {
36
38
  role: "assistant",
37
39
  content: []
38
40
  };
41
+ const toolCallIndices = /* @__PURE__ */ new Map();
42
+ const reasoningIndices = /* @__PURE__ */ new Map();
39
43
  for (const output of messages) if (output.role === "tool") {
40
- const toolCallIdx = assistantMessage.content.findIndex((c) => c.type === "tool-call" && c.toolCallId === output.toolCallId);
44
+ const toolCallIdx = !isNaNToolCallId(output.toolCallId) ? toolCallIndices.get(output.toolCallId) ?? -1 : -1;
41
45
  if (toolCallIdx !== -1) {
42
46
  const toolCall = assistantMessage.content[toolCallIdx];
43
47
  if (output.toolName != null) {
@@ -85,13 +89,14 @@ const joinExternalMessages = (messages) => {
85
89
  ...output.metadata.custom
86
90
  };
87
91
  if (output.metadata.timing) assistantMessage.metadata.timing = output.metadata.timing;
92
+ if (output.metadata.modality) assistantMessage.metadata.modality = output.metadata.modality;
88
93
  if (output.metadata.submittedFeedback) assistantMessage.metadata.submittedFeedback = output.metadata.submittedFeedback;
89
94
  if (output.metadata.isOptimistic) assistantMessage.metadata.isOptimistic = true;
90
95
  }
91
96
  for (const part of content) {
92
- if (part.type === "tool-call") {
93
- const existingIdx = assistantMessage.content.findIndex((c) => c.type === "tool-call" && c.toolCallId === part.toolCallId);
94
- if (existingIdx !== -1) {
97
+ if (part.type === "tool-call" && part.toolCallId) {
98
+ const existingIdx = toolCallIndices.get(part.toolCallId);
99
+ if (existingIdx !== void 0) {
95
100
  const existing = assistantMessage.content[existingIdx];
96
101
  assistantMessage.content[existingIdx] = {
97
102
  ...existing,
@@ -102,8 +107,8 @@ const joinExternalMessages = (messages) => {
102
107
  }
103
108
  }
104
109
  if (part.type === "reasoning" && "parentId" in part && part.parentId) {
105
- const existingIdx = assistantMessage.content.findIndex((c) => c.type === "reasoning" && "parentId" in c && c.parentId === part.parentId);
106
- if (existingIdx !== -1) {
110
+ const existingIdx = reasoningIndices.get(part.parentId);
111
+ if (existingIdx !== void 0) {
107
112
  const existing = assistantMessage.content[existingIdx];
108
113
  assistantMessage.content[existingIdx] = {
109
114
  ...existing,
@@ -113,7 +118,10 @@ const joinExternalMessages = (messages) => {
113
118
  continue;
114
119
  }
115
120
  }
121
+ const partIdx = assistantMessage.content.length;
116
122
  assistantMessage.content.push(part);
123
+ if (part.type === "tool-call" && !isNaNToolCallId(part.toolCallId) && !toolCallIndices.has(part.toolCallId)) toolCallIndices.set(part.toolCallId, partIdx);
124
+ else if (part.type === "reasoning" && "parentId" in part && part.parentId) reasoningIndices.set(part.parentId, partIdx);
117
125
  }
118
126
  break;
119
127
  default: throw new Error(`Unknown message role: ${role}`);
@@ -152,13 +160,20 @@ const shallowArrayEqual = (a, b) => {
152
160
  for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
153
161
  return true;
154
162
  };
163
+ const createExternalMessageConversionCache = () => ({
164
+ callbackCache: /* @__PURE__ */ new WeakMap(),
165
+ chunkCache: /* @__PURE__ */ new WeakMap(),
166
+ converterCache: new ThreadMessageConverter(),
167
+ generatedFallbackMessages: /* @__PURE__ */ new WeakSet()
168
+ });
155
169
  const convertExternalMessageChunk = (message, idx, chunkCount, isRunning, error, cache, cancelledMessageIds) => {
156
170
  const isLast = idx === chunkCount - 1;
157
171
  const joined = joinExternalMessages(message.outputs);
158
172
  const isCancelled = cancelledMessageIds !== void 0 && message.outputs.some((output) => output.role !== "tool" && output.id != null && cancelledMessageIds.has(output.id));
159
173
  const hasInterruptedToolCalls = typeof joined.content === "object" && joined.content.some(isInterruptedToolCall);
160
174
  const hasPendingToolCalls = typeof joined.content === "object" && joined.content.some(isPendingToolCall);
161
- const autoStatus = getAutoStatus(isLast, isRunning, hasInterruptedToolCalls, hasPendingToolCalls, isLast ? error : void 0, isCancelled);
175
+ const hasBackgroundToolCalls = typeof joined.content === "object" && joined.content.some(isBackgroundToolCall);
176
+ const autoStatus = getAutoStatus(isLast, isRunning, hasInterruptedToolCalls, hasPendingToolCalls, isLast ? error : void 0, isCancelled, hasBackgroundToolCalls);
162
177
  const fallbackId = `${FALLBACK_ID_PREFIX}${idx}`;
163
178
  const cachedMessage = cache?.message;
164
179
  if (cachedMessage && (cachedMessage.role !== "assistant" || !isAutoStatus(cachedMessage.status) || cachedMessage.status === autoStatus || cachedMessage.status.type === "incomplete" && cachedMessage.status.reason === "error" && cachedMessage.status.error !== void 0 && autoStatus.type === "incomplete" && autoStatus.reason === "error" && autoStatus.error !== void 0 && (cachedMessage.status.error === autoStatus.error || isJSONValueEqual(cachedMessage.status.error, autoStatus.error)))) {
@@ -210,13 +225,34 @@ const completeExternalMessageConversion = (messages, error) => {
210
225
  }
211
226
  return messages;
212
227
  };
213
- const convertExternalMessages = (messages, callback, isRunning, metadata) => {
214
- const callbackResults = messages.map((message) => convertExternalMessageCallback(message, callback, metadata));
215
- const chunks = chunkExternalMessages(callbackResults);
216
- const result = chunks.map((message, idx) => convertExternalMessageChunk(message, idx, chunks.length, isRunning, metadata.error, void 0, metadata.cancelledMessageIds));
228
+ const convertExternalMessages = (messages, callback, isRunning, metadata, joinStrategy, cache) => {
229
+ const callbackResults = messages.map((message) => {
230
+ let result = cache?.callbackCache.get(message);
231
+ if (!result || result.metadata !== metadata || result.callback !== callback) {
232
+ result = {
233
+ ...convertExternalMessageCallback(message, callback, metadata),
234
+ metadata,
235
+ callback
236
+ };
237
+ cache?.callbackCache.set(message, result);
238
+ }
239
+ return result;
240
+ });
241
+ const chunks = chunkExternalMessages(callbackResults, joinStrategy).map((message) => {
242
+ const key = message.outputs[0];
243
+ if (!key || !cache) return message;
244
+ const cached = cache.chunkCache.get(key);
245
+ if (cached && shallowArrayEqual(cached.outputs, message.outputs)) return cached;
246
+ cache.chunkCache.set(key, message);
247
+ return message;
248
+ });
249
+ const result = cache ? cache.converterCache.convertMessages(chunks, (cached, message, idx) => convertExternalMessageChunk(message, idx, chunks.length, isRunning, metadata.error, {
250
+ message: cached,
251
+ generatedFallbackMessages: cache.generatedFallbackMessages
252
+ }, metadata.cancelledMessageIds)) : chunks.map((message, idx) => convertExternalMessageChunk(message, idx, chunks.length, isRunning, metadata.error, void 0, metadata.cancelledMessageIds));
217
253
  return completeExternalMessageConversion(result, metadata.error);
218
254
  };
219
255
  //#endregion
220
- export { chunkExternalMessages, completeExternalMessageConversion, convertExternalMessageCallback, convertExternalMessageChunk, convertExternalMessages, joinExternalMessages, shallowArrayEqual };
256
+ export { chunkExternalMessages, completeExternalMessageConversion, convertExternalMessageCallback, convertExternalMessageChunk, convertExternalMessages, createExternalMessageConversionCache, joinExternalMessages, shallowArrayEqual };
221
257
 
222
258
  //# sourceMappingURL=external-message-conversion.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"external-message-conversion.js","names":["ReadonlyJSONValue","ToolExecutionStatus","ThreadAssistantMessage","ThreadMessage","ToolCallMessagePart","MessageTiming","generateErrorMessageId","isJSONValueEqual","getAutoStatus","isAutoStatus","isInterruptedToolCall","isPendingToolCall","bindExternalStoreMessage","FALLBACK_ID_PREFIX","getExternalStoreMessages","symbolInnerMessage","fromThreadMessageLike","ThreadMessageLike","JoinStrategy","ExternalMessageConverterMessage","convertConfig","joinStrategy","role","toolCallId","toolName","result","artifact","isError","messages","ExternalMessageConverterMetadata","toolStatuses","Record","error","cancelledMessageIds","ReadonlySet","messageTiming","ExternalMessageConverterCallback","message","T","metadata","ExternalMessageConverterCallbackResult","input","outputs","ExternalMessageConverterChunk","inputs","Mutable","P","stringifyForError","value","text","Error","String","JSON","stringify","length","slice","toCallbackOutputs","output","Array","isArray","o","valid","content","filter","warnedDroppedToolResults","has","add","console","warn","WeakSet","convertExternalMessageCallback","callback","mergeInnerMessages","existing","incoming","joinExternalMessages","assistantMessage","Omit","Exclude","toolCallIdx","findIndex","c","type","toolCall","const","map","id","createdAt","status","attachments","unstable_state","undefined","unstable_annotations","unstable_data","steps","custom","timing","submittedFeedback","isOptimistic","part","existingIdx","parentId","push","unsupportedRole","chunkExternalMessages","callbackResults","results","isAssistant","pendingNone","flush","callbackResult","at","shallowArrayEqual","a","b","i","ExternalMessageConversionCache","generatedFallbackMessages","convertExternalMessageChunk","idx","chunkCount","isRunning","cache","isLast","joined","isCancelled","some","hasInterruptedToolCalls","hasPendingToolCalls","autoStatus","fallbackId","cachedMessage","reason","updated","newMessage","createErrorAssistantMessage","msg","Date","completeExternalMessageConversion","lastMessage","convertExternalMessages","WeakKey","chunks"],"sources":["../../../src/runtime/utils/external-message-conversion.ts"],"sourcesContent":["import type { ReadonlyJSONValue } from \"assistant-stream/utils\";\nimport type { ToolExecutionStatus } from \"../../runtimes/tool-invocations/ToolInvocationTracker\";\nimport type {\n ThreadAssistantMessage,\n ThreadMessage,\n ToolCallMessagePart,\n} from \"../../types/message\";\nimport type { MessageTiming } from \"../../types/message\";\nimport { generateErrorMessageId } from \"../../utils/id\";\nimport { isJSONValueEqual } from \"../../utils/json/is-json-equal\";\nimport {\n getAutoStatus,\n isAutoStatus,\n isInterruptedToolCall,\n isPendingToolCall,\n} from \"./auto-status\";\nimport {\n bindExternalStoreMessage,\n FALLBACK_ID_PREFIX,\n getExternalStoreMessages,\n symbolInnerMessage,\n} from \"./external-store-message\";\nimport {\n fromThreadMessageLike,\n type ThreadMessageLike,\n} from \"./thread-message-like\";\n\nexport type JoinStrategy = \"concat-content\" | \"none\";\n\nexport type ExternalMessageConverterMessage =\n | (ThreadMessageLike & {\n readonly convertConfig?: {\n readonly joinStrategy?: JoinStrategy;\n };\n })\n | {\n role: \"tool\";\n toolCallId: string;\n toolName?: string | undefined;\n result: any;\n artifact?: any;\n isError?: boolean;\n messages?: readonly ThreadMessage[];\n };\n\nexport type ExternalMessageConverterMetadata = {\n readonly toolStatuses?: Record<string, ToolExecutionStatus>;\n readonly error?: ReadonlyJSONValue;\n readonly cancelledMessageIds?: ReadonlySet<string>;\n readonly messageTiming?: Record<string, MessageTiming>;\n};\n\nexport type ExternalMessageConverterCallback<T> = (\n message: T,\n metadata: ExternalMessageConverterMetadata,\n) => ExternalMessageConverterMessage | ExternalMessageConverterMessage[];\n\nexport type ExternalMessageConverterCallbackResult<T> = {\n input: T;\n outputs: ExternalMessageConverterMessage[];\n};\n\nexport type ExternalMessageConverterChunk<T> = {\n inputs: T[];\n outputs: ExternalMessageConverterMessage[];\n};\n\ntype Mutable<T> = {\n -readonly [P in keyof T]: T[P];\n};\n\nconst stringifyForError = (value: unknown) => {\n let text;\n try {\n text = value instanceof Error ? String(value) : JSON.stringify(value);\n } catch {\n /* circular */\n }\n text ??= String(value);\n return text.length > 200 ? `${text.slice(0, 200)}…` : text;\n};\n\nconst toCallbackOutputs = (\n output: ExternalMessageConverterMessage | ExternalMessageConverterMessage[],\n input: unknown,\n): ExternalMessageConverterMessage[] => {\n const outputs = Array.isArray(output) ? output : [output];\n for (const o of outputs) {\n const valid =\n typeof o === \"object\" &&\n o !== null &&\n (o.role === \"tool\" ||\n ((o.role === \"assistant\" || o.role === \"user\" || o.role === \"system\") &&\n (typeof o.content === \"string\" || Array.isArray(o.content))));\n if (!valid)\n throw new Error(\n `External message converter: the converter callback returned an invalid message (${stringifyForError(o)}) for input ${stringifyForError(input)}. Return an empty array to skip a message.`,\n );\n }\n // Providers can emit tool results without a usable id (react-langchain maps\n // a missing tool_call_id to \"\"); converters must not throw on those, so the\n // result is dropped like any other orphaned tool output.\n return outputs.filter((o) => {\n if (o.role !== \"tool\") return true;\n if (typeof o.toolCallId === \"string\" && o.toolCallId.length > 0)\n return true;\n if (!warnedDroppedToolResults.has(o)) {\n warnedDroppedToolResults.add(o);\n console.warn(\n `External message converter: dropping a tool result without a toolCallId (${stringifyForError(o)}) for input ${stringifyForError(input)}.`,\n );\n }\n return false;\n });\n};\n\nconst warnedDroppedToolResults = new WeakSet<object>();\n\nexport const convertExternalMessageCallback = <T>(\n input: T,\n callback: ExternalMessageConverterCallback<T>,\n metadata: ExternalMessageConverterMetadata,\n): ExternalMessageConverterCallbackResult<T> => ({\n input,\n outputs: toCallbackOutputs(callback(input, metadata), input),\n});\n\nconst mergeInnerMessages = (existing: object, incoming: object) => ({\n [symbolInnerMessage]: [\n ...((existing as any)[symbolInnerMessage] ?? []),\n ...((incoming as any)[symbolInnerMessage] ?? []),\n ],\n});\n\nexport const joinExternalMessages = (\n messages: readonly ExternalMessageConverterMessage[],\n): ThreadMessageLike => {\n const assistantMessage: Mutable<Omit<ThreadMessageLike, \"metadata\">> & {\n content: Exclude<ThreadMessageLike[\"content\"][0], string>[];\n metadata?: Mutable<ThreadMessageLike[\"metadata\"]>;\n } = {\n role: \"assistant\",\n content: [],\n };\n for (const output of messages) {\n if (output.role === \"tool\") {\n const toolCallIdx = assistantMessage.content.findIndex(\n (c) => c.type === \"tool-call\" && c.toolCallId === output.toolCallId,\n );\n // Ignore orphaned tool results so one bad tool message does not\n // prevent rendering the rest of the conversation.\n if (toolCallIdx !== -1) {\n const toolCall = assistantMessage.content[\n toolCallIdx\n ]! as ToolCallMessagePart;\n if (output.toolName != null) {\n if (toolCall.toolName !== output.toolName)\n throw new Error(\n `Tool call name ${output.toolCallId} ${output.toolName} does not match existing tool call ${toolCall.toolName}`,\n );\n }\n assistantMessage.content[toolCallIdx] = {\n ...toolCall,\n ...{\n [symbolInnerMessage]: [\n ...((toolCall as any)[symbolInnerMessage] ?? []),\n output,\n ],\n },\n result: output.result,\n artifact: output.artifact,\n isError: output.isError,\n messages: output.messages,\n };\n }\n } else {\n const role = output.role;\n const content = (\n typeof output.content === \"string\"\n ? [{ type: \"text\" as const, text: output.content }]\n : output.content\n ).map((c) => ({\n ...c,\n ...{ [symbolInnerMessage]: [output] },\n }));\n switch (role) {\n case \"system\":\n case \"user\":\n return {\n ...output,\n content,\n };\n case \"assistant\":\n if (assistantMessage.content.length === 0) {\n assistantMessage.id = output.id;\n assistantMessage.createdAt ??= output.createdAt;\n assistantMessage.status ??= output.status;\n\n if (output.attachments) {\n assistantMessage.attachments = [\n ...(assistantMessage.attachments ?? []),\n ...output.attachments,\n ];\n }\n }\n\n if (output.metadata) {\n assistantMessage.metadata ??= {};\n if (output.metadata.unstable_state !== undefined) {\n assistantMessage.metadata.unstable_state =\n output.metadata.unstable_state;\n }\n if (output.metadata.unstable_annotations) {\n assistantMessage.metadata.unstable_annotations = [\n ...(assistantMessage.metadata.unstable_annotations ?? []),\n ...output.metadata.unstable_annotations,\n ];\n }\n if (output.metadata.unstable_data) {\n assistantMessage.metadata.unstable_data = [\n ...(assistantMessage.metadata.unstable_data ?? []),\n ...output.metadata.unstable_data,\n ];\n }\n if (output.metadata.steps) {\n assistantMessage.metadata.steps = [\n ...(assistantMessage.metadata.steps ?? []),\n ...output.metadata.steps,\n ];\n }\n if (output.metadata.custom) {\n assistantMessage.metadata.custom = {\n ...(assistantMessage.metadata.custom ?? {}),\n ...output.metadata.custom,\n };\n }\n\n if (output.metadata.timing) {\n assistantMessage.metadata.timing = output.metadata.timing;\n }\n\n if (output.metadata.submittedFeedback) {\n assistantMessage.metadata.submittedFeedback =\n output.metadata.submittedFeedback;\n }\n\n if (output.metadata.isOptimistic) {\n assistantMessage.metadata.isOptimistic = true;\n }\n // TODO keep this in sync with ThreadMessageLike[\"metadata\"] / fromThreadMessageLike\n }\n\n // Add content parts, merging reasoning parts with same parentId\n for (const part of content) {\n if (part.type === \"tool-call\") {\n const existingIdx = assistantMessage.content.findIndex(\n (c) =>\n c.type === \"tool-call\" && c.toolCallId === part.toolCallId,\n );\n if (existingIdx !== -1) {\n const existing = assistantMessage.content[\n existingIdx\n ] as typeof part;\n assistantMessage.content[existingIdx] = {\n ...existing,\n ...part,\n ...mergeInnerMessages(existing, part),\n };\n continue;\n }\n }\n\n if (\n part.type === \"reasoning\" &&\n \"parentId\" in part &&\n part.parentId\n ) {\n const existingIdx = assistantMessage.content.findIndex(\n (c) =>\n c.type === \"reasoning\" &&\n \"parentId\" in c &&\n c.parentId === part.parentId,\n );\n if (existingIdx !== -1) {\n const existing = assistantMessage.content[\n existingIdx\n ] as typeof part;\n assistantMessage.content[existingIdx] = {\n ...existing,\n text: `${existing.text}\\n\\n${part.text}`,\n ...mergeInnerMessages(existing, part),\n };\n continue;\n }\n }\n assistantMessage.content.push(part);\n }\n break;\n default: {\n const unsupportedRole: never = role;\n throw new Error(`Unknown message role: ${unsupportedRole}`);\n }\n }\n }\n }\n return assistantMessage;\n};\n\nexport const chunkExternalMessages = <T>(\n callbackResults: ExternalMessageConverterCallbackResult<T>[],\n joinStrategy?: JoinStrategy,\n) => {\n const results: ExternalMessageConverterChunk<T>[] = [];\n let isAssistant = false;\n let pendingNone = false; // true if the previous assistant message had joinStrategy \"none\"\n let inputs: T[] = [];\n let outputs: ExternalMessageConverterMessage[] = [];\n\n const flush = () => {\n if (outputs.length) {\n results.push({\n inputs,\n outputs,\n });\n }\n inputs = [];\n outputs = [];\n isAssistant = false;\n pendingNone = false;\n };\n\n for (const callbackResult of callbackResults) {\n for (const output of callbackResult.outputs) {\n if (\n (pendingNone && output.role !== \"tool\") ||\n !isAssistant ||\n output.role === \"user\" ||\n output.role === \"system\"\n ) {\n flush();\n }\n isAssistant = output.role === \"assistant\" || output.role === \"tool\";\n\n if (inputs.at(-1) !== callbackResult.input) {\n inputs.push(callbackResult.input);\n }\n outputs.push(output);\n\n if (\n output.role === \"assistant\" &&\n (output.convertConfig?.joinStrategy === \"none\" ||\n joinStrategy === \"none\")\n ) {\n pendingNone = true;\n }\n }\n }\n flush();\n return results;\n};\n\nexport const shallowArrayEqual = (\n a: readonly unknown[],\n b: readonly unknown[],\n) => {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false;\n }\n return true;\n};\n\ntype ExternalMessageConversionCache = {\n message: ThreadMessage | undefined;\n generatedFallbackMessages: WeakSet<object>;\n};\n\nexport const convertExternalMessageChunk = <T>(\n message: ExternalMessageConverterChunk<T>,\n idx: number,\n chunkCount: number,\n isRunning: boolean,\n error: ReadonlyJSONValue | undefined,\n cache?: ExternalMessageConversionCache,\n cancelledMessageIds?: ReadonlySet<string>,\n) => {\n const isLast = idx === chunkCount - 1;\n const joined = joinExternalMessages(message.outputs);\n const isCancelled =\n cancelledMessageIds !== undefined &&\n message.outputs.some(\n (output) =>\n output.role !== \"tool\" &&\n output.id != null &&\n cancelledMessageIds.has(output.id),\n );\n const hasInterruptedToolCalls =\n typeof joined.content === \"object\" &&\n joined.content.some(isInterruptedToolCall);\n const hasPendingToolCalls =\n typeof joined.content === \"object\" &&\n joined.content.some(isPendingToolCall);\n const autoStatus = getAutoStatus(\n isLast,\n isRunning,\n hasInterruptedToolCalls,\n hasPendingToolCalls,\n isLast ? error : undefined,\n isCancelled,\n );\n const fallbackId = `${FALLBACK_ID_PREFIX}${idx}`;\n\n const cachedMessage = cache?.message;\n if (\n cachedMessage &&\n (cachedMessage.role !== \"assistant\" ||\n !isAutoStatus(cachedMessage.status) ||\n cachedMessage.status === autoStatus ||\n (cachedMessage.status.type === \"incomplete\" &&\n cachedMessage.status.reason === \"error\" &&\n cachedMessage.status.error !== undefined &&\n autoStatus.type === \"incomplete\" &&\n autoStatus.reason === \"error\" &&\n autoStatus.error !== undefined &&\n (cachedMessage.status.error === autoStatus.error ||\n isJSONValueEqual(cachedMessage.status.error, autoStatus.error))))\n ) {\n const inputs = getExternalStoreMessages<T>(cachedMessage);\n if (shallowArrayEqual(inputs, message.inputs)) {\n // A positional fallback id goes stale when messages are prepended\n // or reordered; serving it unchanged makes two messages collide on\n // one id and the dedup downstream drops one of them.\n if (\n cache.generatedFallbackMessages.has(cachedMessage) &&\n cachedMessage.id !== fallbackId\n ) {\n const updated = { ...cachedMessage, id: fallbackId };\n cache.generatedFallbackMessages.add(updated);\n bindExternalStoreMessage(updated, message.inputs);\n return updated;\n }\n return cachedMessage;\n }\n }\n\n const newMessage = fromThreadMessageLike(joined, fallbackId, autoStatus);\n if (cache && joined.id == null) {\n cache.generatedFallbackMessages.add(newMessage);\n }\n bindExternalStoreMessage(newMessage, message.inputs);\n return newMessage;\n};\n\nfunction createErrorAssistantMessage(\n error: ReadonlyJSONValue,\n): ThreadAssistantMessage {\n const msg: ThreadAssistantMessage = {\n id: generateErrorMessageId(),\n role: \"assistant\",\n content: [],\n status: { type: \"incomplete\", reason: \"error\", error },\n createdAt: new Date(),\n metadata: {\n unstable_state: null,\n unstable_annotations: [],\n unstable_data: [],\n custom: {},\n steps: [],\n },\n };\n bindExternalStoreMessage(msg, []);\n return msg;\n}\n\nexport const completeExternalMessageConversion = (\n messages: ThreadMessage[],\n error: ReadonlyJSONValue | undefined,\n) => {\n if (error) {\n const lastMessage = messages.at(-1);\n if (!lastMessage || lastMessage.role !== \"assistant\") {\n messages.push(createErrorAssistantMessage(error));\n }\n }\n return messages;\n};\n\nexport const convertExternalMessages = <T extends WeakKey>(\n messages: T[],\n callback: ExternalMessageConverterCallback<T>,\n isRunning: boolean,\n metadata: ExternalMessageConverterMetadata,\n) => {\n const callbackResults = messages.map((message) =>\n convertExternalMessageCallback(message, callback, metadata),\n );\n const chunks = chunkExternalMessages(callbackResults);\n const result = chunks.map((message, idx) =>\n convertExternalMessageChunk(\n message,\n idx,\n chunks.length,\n isRunning,\n metadata.error,\n undefined,\n metadata.cancelledMessageIds,\n ),\n );\n return completeExternalMessageConversion(result, metadata.error);\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"external-message-conversion.js","names":["ReadonlyJSONValue","ToolExecutionStatus","ThreadMessageConverter","ThreadAssistantMessage","ThreadMessage","ToolCallMessagePart","MessageTiming","generateErrorMessageId","isJSONValueEqual","getAutoStatus","isAutoStatus","isBackgroundToolCall","isInterruptedToolCall","isPendingToolCall","bindExternalStoreMessage","FALLBACK_ID_PREFIX","getExternalStoreMessages","symbolInnerMessage","fromThreadMessageLike","ThreadMessageLike","JoinStrategy","ExternalMessageConverterMessage","convertConfig","joinStrategy","role","toolCallId","toolName","result","artifact","isError","messages","ExternalMessageConverterMetadata","toolStatuses","Record","error","cancelledMessageIds","ReadonlySet","messageTiming","ExternalMessageConverterCallback","message","T","metadata","ExternalMessageConverterCallbackResult","input","outputs","ExternalMessageConverterChunk","inputs","Mutable","P","stringifyForError","value","text","Error","String","JSON","stringify","length","slice","toCallbackOutputs","output","Array","isArray","o","valid","content","filter","warnedDroppedToolResults","has","add","console","warn","WeakSet","convertExternalMessageCallback","callback","mergeInnerMessages","existing","incoming","isNaNToolCallId","Number","isNaN","joinExternalMessages","assistantMessage","Omit","Exclude","toolCallIndices","Map","reasoningIndices","toolCallIdx","get","toolCall","type","const","map","c","id","createdAt","status","attachments","unstable_state","undefined","unstable_annotations","unstable_data","steps","custom","timing","modality","submittedFeedback","isOptimistic","part","existingIdx","parentId","partIdx","push","set","unsupportedRole","chunkExternalMessages","callbackResults","results","isAssistant","pendingNone","flush","callbackResult","at","shallowArrayEqual","a","b","i","ExternalMessageChunkConversionCache","generatedFallbackMessages","ExternalMessageConversionCallbackCacheEntry","InternalExternalMessageConversionCache","WeakKey","callbackCache","WeakMap","chunkCache","converterCache","createExternalMessageConversionCache","convertExternalMessageChunk","idx","chunkCount","isRunning","cache","isLast","joined","isCancelled","some","hasInterruptedToolCalls","hasPendingToolCalls","hasBackgroundToolCalls","autoStatus","fallbackId","cachedMessage","reason","updated","newMessage","createErrorAssistantMessage","msg","Date","completeExternalMessageConversion","lastMessage","convertExternalMessages","chunks","key","cached","convertMessages"],"sources":["../../../src/runtime/utils/external-message-conversion.ts"],"sourcesContent":["import type { ReadonlyJSONValue } from \"assistant-stream/utils\";\nimport type { ToolExecutionStatus } from \"../../runtimes/tool-invocations/ToolInvocationTracker\";\nimport { ThreadMessageConverter } from \"../../runtimes/external-store/thread-message-converter\";\nimport type {\n ThreadAssistantMessage,\n ThreadMessage,\n ToolCallMessagePart,\n} from \"../../types/message\";\nimport type { MessageTiming } from \"../../types/message\";\nimport { generateErrorMessageId } from \"../../utils/id\";\nimport { isJSONValueEqual } from \"../../utils/json/is-json-equal\";\nimport {\n getAutoStatus,\n isAutoStatus,\n isBackgroundToolCall,\n isInterruptedToolCall,\n isPendingToolCall,\n} from \"./auto-status\";\nimport {\n bindExternalStoreMessage,\n FALLBACK_ID_PREFIX,\n getExternalStoreMessages,\n symbolInnerMessage,\n} from \"./external-store-message\";\nimport {\n fromThreadMessageLike,\n type ThreadMessageLike,\n} from \"./thread-message-like\";\n\nexport type JoinStrategy = \"concat-content\" | \"none\";\n\nexport type ExternalMessageConverterMessage =\n | (ThreadMessageLike & {\n readonly convertConfig?: {\n readonly joinStrategy?: JoinStrategy;\n };\n })\n | {\n role: \"tool\";\n toolCallId: string;\n toolName?: string | undefined;\n result: any;\n artifact?: any;\n isError?: boolean;\n messages?: readonly ThreadMessage[];\n };\n\nexport type ExternalMessageConverterMetadata = {\n readonly toolStatuses?: Record<string, ToolExecutionStatus>;\n readonly error?: ReadonlyJSONValue;\n readonly cancelledMessageIds?: ReadonlySet<string>;\n readonly messageTiming?: Record<string, MessageTiming>;\n};\n\nexport type ExternalMessageConverterCallback<T> = (\n message: T,\n metadata: ExternalMessageConverterMetadata,\n) => ExternalMessageConverterMessage | ExternalMessageConverterMessage[];\n\nexport type ExternalMessageConverterCallbackResult<T> = {\n input: T;\n outputs: ExternalMessageConverterMessage[];\n};\n\nexport type ExternalMessageConverterChunk<T> = {\n inputs: T[];\n outputs: ExternalMessageConverterMessage[];\n};\n\ntype Mutable<T> = {\n -readonly [P in keyof T]: T[P];\n};\n\nconst stringifyForError = (value: unknown) => {\n let text;\n try {\n text = value instanceof Error ? String(value) : JSON.stringify(value);\n } catch {\n /* circular */\n }\n text ??= String(value);\n return text.length > 200 ? `${text.slice(0, 200)}…` : text;\n};\n\nconst toCallbackOutputs = (\n output: ExternalMessageConverterMessage | ExternalMessageConverterMessage[],\n input: unknown,\n): ExternalMessageConverterMessage[] => {\n const outputs = Array.isArray(output) ? output : [output];\n for (const o of outputs) {\n const valid =\n typeof o === \"object\" &&\n o !== null &&\n (o.role === \"tool\" ||\n ((o.role === \"assistant\" || o.role === \"user\" || o.role === \"system\") &&\n (typeof o.content === \"string\" || Array.isArray(o.content))));\n if (!valid)\n throw new Error(\n `External message converter: the converter callback returned an invalid message (${stringifyForError(o)}) for input ${stringifyForError(input)}. Return an empty array to skip a message.`,\n );\n }\n // Providers can emit tool results without a usable id (react-langchain maps\n // a missing tool_call_id to \"\"); converters must not throw on those, so the\n // result is dropped like any other orphaned tool output.\n return outputs.filter((o) => {\n if (o.role !== \"tool\") return true;\n if (typeof o.toolCallId === \"string\" && o.toolCallId.length > 0)\n return true;\n if (!warnedDroppedToolResults.has(o)) {\n warnedDroppedToolResults.add(o);\n console.warn(\n `External message converter: dropping a tool result without a toolCallId (${stringifyForError(o)}) for input ${stringifyForError(input)}.`,\n );\n }\n return false;\n });\n};\n\nconst warnedDroppedToolResults = new WeakSet<object>();\n\nexport const convertExternalMessageCallback = <T>(\n input: T,\n callback: ExternalMessageConverterCallback<T>,\n metadata: ExternalMessageConverterMetadata,\n): ExternalMessageConverterCallbackResult<T> => ({\n input,\n outputs: toCallbackOutputs(callback(input, metadata), input),\n});\n\nconst mergeInnerMessages = (existing: object, incoming: object) => ({\n [symbolInnerMessage]: [\n ...((existing as any)[symbolInnerMessage] ?? []),\n ...((incoming as any)[symbolInnerMessage] ?? []),\n ],\n});\n\nconst isNaNToolCallId = (toolCallId: unknown) =>\n typeof toolCallId === \"number\" && Number.isNaN(toolCallId);\n\nexport const joinExternalMessages = (\n messages: readonly ExternalMessageConverterMessage[],\n): ThreadMessageLike => {\n const assistantMessage: Mutable<Omit<ThreadMessageLike, \"metadata\">> & {\n content: Exclude<ThreadMessageLike[\"content\"][0], string>[];\n metadata?: Mutable<ThreadMessageLike[\"metadata\"]>;\n } = {\n role: \"assistant\",\n content: [],\n };\n const toolCallIndices = new Map<unknown, number>();\n const reasoningIndices = new Map<string, number>();\n for (const output of messages) {\n if (output.role === \"tool\") {\n const toolCallIdx = !isNaNToolCallId(output.toolCallId)\n ? (toolCallIndices.get(output.toolCallId) ?? -1)\n : -1;\n // Ignore orphaned tool results so one bad tool message does not\n // prevent rendering the rest of the conversation.\n if (toolCallIdx !== -1) {\n const toolCall = assistantMessage.content[\n toolCallIdx\n ]! as ToolCallMessagePart;\n if (output.toolName != null) {\n if (toolCall.toolName !== output.toolName)\n throw new Error(\n `Tool call name ${output.toolCallId} ${output.toolName} does not match existing tool call ${toolCall.toolName}`,\n );\n }\n assistantMessage.content[toolCallIdx] = {\n ...toolCall,\n ...{\n [symbolInnerMessage]: [\n ...((toolCall as any)[symbolInnerMessage] ?? []),\n output,\n ],\n },\n result: output.result,\n artifact: output.artifact,\n isError: output.isError,\n messages: output.messages,\n };\n }\n } else {\n const role = output.role;\n const content = (\n typeof output.content === \"string\"\n ? [{ type: \"text\" as const, text: output.content }]\n : output.content\n ).map((c) => ({\n ...c,\n ...{ [symbolInnerMessage]: [output] },\n }));\n switch (role) {\n case \"system\":\n case \"user\":\n return {\n ...output,\n content,\n };\n case \"assistant\":\n if (assistantMessage.content.length === 0) {\n assistantMessage.id = output.id;\n assistantMessage.createdAt ??= output.createdAt;\n assistantMessage.status ??= output.status;\n\n if (output.attachments) {\n assistantMessage.attachments = [\n ...(assistantMessage.attachments ?? []),\n ...output.attachments,\n ];\n }\n }\n\n if (output.metadata) {\n assistantMessage.metadata ??= {};\n if (output.metadata.unstable_state !== undefined) {\n assistantMessage.metadata.unstable_state =\n output.metadata.unstable_state;\n }\n if (output.metadata.unstable_annotations) {\n assistantMessage.metadata.unstable_annotations = [\n ...(assistantMessage.metadata.unstable_annotations ?? []),\n ...output.metadata.unstable_annotations,\n ];\n }\n if (output.metadata.unstable_data) {\n assistantMessage.metadata.unstable_data = [\n ...(assistantMessage.metadata.unstable_data ?? []),\n ...output.metadata.unstable_data,\n ];\n }\n if (output.metadata.steps) {\n assistantMessage.metadata.steps = [\n ...(assistantMessage.metadata.steps ?? []),\n ...output.metadata.steps,\n ];\n }\n if (output.metadata.custom) {\n assistantMessage.metadata.custom = {\n ...(assistantMessage.metadata.custom ?? {}),\n ...output.metadata.custom,\n };\n }\n\n if (output.metadata.timing) {\n assistantMessage.metadata.timing = output.metadata.timing;\n }\n\n if (output.metadata.modality) {\n assistantMessage.metadata.modality = output.metadata.modality;\n }\n\n if (output.metadata.submittedFeedback) {\n assistantMessage.metadata.submittedFeedback =\n output.metadata.submittedFeedback;\n }\n\n if (output.metadata.isOptimistic) {\n assistantMessage.metadata.isOptimistic = true;\n }\n // TODO keep this in sync with ThreadMessageLike[\"metadata\"] / fromThreadMessageLike\n }\n\n // Add content parts, merging reasoning parts with same parentId\n for (const part of content) {\n if (part.type === \"tool-call\" && part.toolCallId) {\n const existingIdx = toolCallIndices.get(part.toolCallId);\n if (existingIdx !== undefined) {\n const existing = assistantMessage.content[\n existingIdx\n ] as typeof part;\n assistantMessage.content[existingIdx] = {\n ...existing,\n ...part,\n ...mergeInnerMessages(existing, part),\n };\n continue;\n }\n }\n\n if (\n part.type === \"reasoning\" &&\n \"parentId\" in part &&\n part.parentId\n ) {\n const existingIdx = reasoningIndices.get(part.parentId);\n if (existingIdx !== undefined) {\n const existing = assistantMessage.content[\n existingIdx\n ] as typeof part;\n assistantMessage.content[existingIdx] = {\n ...existing,\n text: `${existing.text}\\n\\n${part.text}`,\n ...mergeInnerMessages(existing, part),\n };\n continue;\n }\n }\n const partIdx = assistantMessage.content.length;\n assistantMessage.content.push(part);\n if (\n part.type === \"tool-call\" &&\n !isNaNToolCallId(part.toolCallId) &&\n !toolCallIndices.has(part.toolCallId)\n ) {\n toolCallIndices.set(part.toolCallId, partIdx);\n } else if (\n part.type === \"reasoning\" &&\n \"parentId\" in part &&\n part.parentId\n ) {\n reasoningIndices.set(part.parentId, partIdx);\n }\n }\n break;\n default: {\n const unsupportedRole: never = role;\n throw new Error(`Unknown message role: ${unsupportedRole}`);\n }\n }\n }\n }\n return assistantMessage;\n};\n\nexport const chunkExternalMessages = <T>(\n callbackResults: ExternalMessageConverterCallbackResult<T>[],\n joinStrategy?: JoinStrategy,\n) => {\n const results: ExternalMessageConverterChunk<T>[] = [];\n let isAssistant = false;\n let pendingNone = false; // true if the previous assistant message had joinStrategy \"none\"\n let inputs: T[] = [];\n let outputs: ExternalMessageConverterMessage[] = [];\n\n const flush = () => {\n if (outputs.length) {\n results.push({\n inputs,\n outputs,\n });\n }\n inputs = [];\n outputs = [];\n isAssistant = false;\n pendingNone = false;\n };\n\n for (const callbackResult of callbackResults) {\n for (const output of callbackResult.outputs) {\n if (\n (pendingNone && output.role !== \"tool\") ||\n !isAssistant ||\n output.role === \"user\" ||\n output.role === \"system\"\n ) {\n flush();\n }\n isAssistant = output.role === \"assistant\" || output.role === \"tool\";\n\n if (inputs.at(-1) !== callbackResult.input) {\n inputs.push(callbackResult.input);\n }\n outputs.push(output);\n\n if (\n output.role === \"assistant\" &&\n (output.convertConfig?.joinStrategy === \"none\" ||\n joinStrategy === \"none\")\n ) {\n pendingNone = true;\n }\n }\n }\n flush();\n return results;\n};\n\nexport const shallowArrayEqual = (\n a: readonly unknown[],\n b: readonly unknown[],\n) => {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false;\n }\n return true;\n};\n\ntype ExternalMessageChunkConversionCache = {\n message: ThreadMessage | undefined;\n generatedFallbackMessages: WeakSet<object>;\n};\n\ntype ExternalMessageConversionCallbackCacheEntry<T> =\n ExternalMessageConverterCallbackResult<T> & {\n metadata: ExternalMessageConverterMetadata;\n callback: ExternalMessageConverterCallback<T>;\n };\n\nexport type InternalExternalMessageConversionCache<\n T extends WeakKey = WeakKey,\n> = {\n callbackCache: WeakMap<T, ExternalMessageConversionCallbackCacheEntry<T>>;\n chunkCache: WeakMap<\n ExternalMessageConverterMessage,\n ExternalMessageConverterChunk<T>\n >;\n converterCache: ThreadMessageConverter;\n // Generatedness is tracked by identity, not by id shape: a caller-supplied id that happens to match the generated pattern must never be rewritten.\n generatedFallbackMessages: WeakSet<object>;\n};\n\nexport const createExternalMessageConversionCache = <\n T extends WeakKey = WeakKey,\n>(): InternalExternalMessageConversionCache<T> => ({\n callbackCache: new WeakMap(),\n chunkCache: new WeakMap(),\n converterCache: new ThreadMessageConverter(),\n generatedFallbackMessages: new WeakSet(),\n});\n\nexport const convertExternalMessageChunk = <T>(\n message: ExternalMessageConverterChunk<T>,\n idx: number,\n chunkCount: number,\n isRunning: boolean,\n error: ReadonlyJSONValue | undefined,\n cache?: ExternalMessageChunkConversionCache,\n cancelledMessageIds?: ReadonlySet<string>,\n) => {\n const isLast = idx === chunkCount - 1;\n const joined = joinExternalMessages(message.outputs);\n const isCancelled =\n cancelledMessageIds !== undefined &&\n message.outputs.some(\n (output) =>\n output.role !== \"tool\" &&\n output.id != null &&\n cancelledMessageIds.has(output.id),\n );\n const hasInterruptedToolCalls =\n typeof joined.content === \"object\" &&\n joined.content.some(isInterruptedToolCall);\n const hasPendingToolCalls =\n typeof joined.content === \"object\" &&\n joined.content.some(isPendingToolCall);\n const hasBackgroundToolCalls =\n typeof joined.content === \"object\" &&\n joined.content.some(isBackgroundToolCall);\n const autoStatus = getAutoStatus(\n isLast,\n isRunning,\n hasInterruptedToolCalls,\n hasPendingToolCalls,\n isLast ? error : undefined,\n isCancelled,\n hasBackgroundToolCalls,\n );\n const fallbackId = `${FALLBACK_ID_PREFIX}${idx}`;\n\n const cachedMessage = cache?.message;\n if (\n cachedMessage &&\n (cachedMessage.role !== \"assistant\" ||\n !isAutoStatus(cachedMessage.status) ||\n cachedMessage.status === autoStatus ||\n (cachedMessage.status.type === \"incomplete\" &&\n cachedMessage.status.reason === \"error\" &&\n cachedMessage.status.error !== undefined &&\n autoStatus.type === \"incomplete\" &&\n autoStatus.reason === \"error\" &&\n autoStatus.error !== undefined &&\n (cachedMessage.status.error === autoStatus.error ||\n isJSONValueEqual(cachedMessage.status.error, autoStatus.error))))\n ) {\n const inputs = getExternalStoreMessages<T>(cachedMessage);\n if (shallowArrayEqual(inputs, message.inputs)) {\n // A positional fallback id goes stale when messages are prepended\n // or reordered; serving it unchanged makes two messages collide on\n // one id and the dedup downstream drops one of them.\n if (\n cache.generatedFallbackMessages.has(cachedMessage) &&\n cachedMessage.id !== fallbackId\n ) {\n const updated = { ...cachedMessage, id: fallbackId };\n cache.generatedFallbackMessages.add(updated);\n bindExternalStoreMessage(updated, message.inputs);\n return updated;\n }\n return cachedMessage;\n }\n }\n\n const newMessage = fromThreadMessageLike(joined, fallbackId, autoStatus);\n if (cache && joined.id == null) {\n cache.generatedFallbackMessages.add(newMessage);\n }\n bindExternalStoreMessage(newMessage, message.inputs);\n return newMessage;\n};\n\nfunction createErrorAssistantMessage(\n error: ReadonlyJSONValue,\n): ThreadAssistantMessage {\n const msg: ThreadAssistantMessage = {\n id: generateErrorMessageId(),\n role: \"assistant\",\n content: [],\n status: { type: \"incomplete\", reason: \"error\", error },\n createdAt: new Date(),\n metadata: {\n unstable_state: null,\n unstable_annotations: [],\n unstable_data: [],\n custom: {},\n steps: [],\n },\n };\n bindExternalStoreMessage(msg, []);\n return msg;\n}\n\nexport const completeExternalMessageConversion = (\n messages: ThreadMessage[],\n error: ReadonlyJSONValue | undefined,\n) => {\n if (error) {\n const lastMessage = messages.at(-1);\n if (!lastMessage || lastMessage.role !== \"assistant\") {\n messages.push(createErrorAssistantMessage(error));\n }\n }\n return messages;\n};\n\nexport const convertExternalMessages = <T extends WeakKey>(\n messages: T[],\n callback: ExternalMessageConverterCallback<T>,\n isRunning: boolean,\n metadata: ExternalMessageConverterMetadata,\n joinStrategy?: JoinStrategy,\n cache?: InternalExternalMessageConversionCache<T>,\n) => {\n const callbackResults = messages.map((message) => {\n let result = cache?.callbackCache.get(message);\n if (\n !result ||\n result.metadata !== metadata ||\n result.callback !== callback\n ) {\n result = {\n ...convertExternalMessageCallback(message, callback, metadata),\n metadata,\n callback,\n };\n cache?.callbackCache.set(message, result);\n }\n return result;\n });\n const chunks = chunkExternalMessages(callbackResults, joinStrategy).map(\n (message) => {\n const key = message.outputs[0];\n if (!key || !cache) return message;\n\n const cached = cache.chunkCache.get(key);\n if (cached && shallowArrayEqual(cached.outputs, message.outputs)) {\n return cached;\n }\n cache.chunkCache.set(key, message);\n return message;\n },\n );\n const result = cache\n ? cache.converterCache.convertMessages(chunks, (cached, message, idx) =>\n convertExternalMessageChunk(\n message,\n idx,\n chunks.length,\n isRunning,\n metadata.error,\n {\n message: cached,\n generatedFallbackMessages: cache.generatedFallbackMessages,\n },\n metadata.cancelledMessageIds,\n ),\n )\n : chunks.map((message, idx) =>\n convertExternalMessageChunk(\n message,\n idx,\n chunks.length,\n isRunning,\n metadata.error,\n undefined,\n metadata.cancelledMessageIds,\n ),\n );\n return completeExternalMessageConversion(result, metadata.error);\n};\n"],"mappings":"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"}
@@ -28,6 +28,7 @@ declare class MessageRepository {
28
28
  private head;
29
29
  private root;
30
30
  private updateLevels;
31
+ private selectPathTo;
31
32
  private performOp;
32
33
  private _messages;
33
34
  get headId(): string | null;
@@ -1 +1 @@
1
- {"version":3,"file":"message-repository.d.ts","names":[],"sources":["../../../src/runtime/utils/message-repository.ts"],"mappings":";;;KAOY;EACV,SAAS;EACT;EACA,YAAY;;KAGF;EACV;EACA,UAAU;IACR,SAAS;IACT;IACA,YAAY;;;cAIH;EAEC,YAAA,mBAAS,wBAClB;EAkBM,sBAAA;IACL,SAAS;IACT;OACC;IACS;QACX;;cAgEQ;UACH;UACA;UACA;UAKA;UAgBA;UA2DA;MAQJ;MAIA;EAUJ,YAAY,2BAAe;EAuB3B,mBAAmB,yBAAyB,SAAS;EAiCrD,WAAW;;;;;EAcX,cAAc,mBAAmB;EAsCjC,YAAY;;;;;;;;;UAmBJ;EA+BR,eAAe;EAkBf,UAAU;EAiDV;EAUA,UAAU;EAwBV,SAAS,QAAQ,YAAY"}
1
+ {"version":3,"file":"message-repository.d.ts","names":[],"sources":["../../../src/runtime/utils/message-repository.ts"],"mappings":";;;KAOY;EACV,SAAS;EACT;EACA,YAAY;;KAGF;EACV;EACA,UAAU;IACR,SAAS;IACT;IACA,YAAY;;;cAIH;EAEC,YAAA,mBAAS,wBAClB;EAkBM,sBAAA;IACL,SAAS;IACT;OACC;IACS;QACX;;cAgEQ;UACH;UACA;UACA;UAKA;UAgBA;UAUA;UAgEA;MAQJ;MAIA;EAUJ,YAAY,2BAAe;EAuB3B,mBAAmB,yBAAyB,SAAS;EAiCrD,WAAW;;;;;EAcX,cAAc,mBAAmB;EAsCjC,YAAY;;;;;;;;;UAmBJ;EA+BR,eAAe;EAiBf,UAAU;EAuCV;EAUA,UAAU;EAgCV,SAAS,QAAQ,YAAY"}
@@ -1,10 +1,10 @@
1
1
  import { generateId } from "../../utils/id.js";
2
2
  import { fromThreadMessageLike } from "./thread-message-like.js";
3
- import { getContentAutoStatus } from "./auto-status.js";
3
+ import { getRepositoryContentAutoStatus } from "./auto-status.js";
4
4
  //#region src/runtime/utils/message-repository.ts
5
5
  const ExportedMessageRepository = {
6
6
  fromArray: (messages) => {
7
- const conv = messages.map((m) => fromThreadMessageLike(m, generateId(), getContentAutoStatus(m.content, false, false)));
7
+ const conv = messages.map((m) => fromThreadMessageLike(m, generateId(), getRepositoryContentAutoStatus(m.content)));
8
8
  return { messages: conv.map((m, idx) => ({
9
9
  parentId: idx > 0 ? conv[idx - 1].id : null,
10
10
  message: m
@@ -17,7 +17,7 @@ const ExportedMessageRepository = {
17
17
  if (!message.id) throw new Error("ExportedMessageRepository.fromBranchableArray: Each message must have an 'id' field set.");
18
18
  return {
19
19
  parentId,
20
- message: fromThreadMessageLike(message, message.id, getContentAutoStatus(message.content, false, false))
20
+ message: fromThreadMessageLike(message, message.id, getRepositoryContentAutoStatus(message.content))
21
21
  };
22
22
  })
23
23
  };
@@ -66,6 +66,9 @@ var MessageRepository = class {
66
66
  }
67
67
  }
68
68
  }
69
+ selectPathTo(message) {
70
+ for (let current = message; current; current = current.prev) (current.prev ?? this.root).next = current;
71
+ }
69
72
  performOp(newParent, child, operation) {
70
73
  const parentOrRoot = child.prev ?? this.root;
71
74
  const newParentOrRoot = newParent ?? this.root;
@@ -84,8 +87,12 @@ var MessageRepository = class {
84
87
  }
85
88
  if (operation !== "cut") {
86
89
  newParentOrRoot.children = [...newParentOrRoot.children, child.current.id];
87
- if (findHead(child) === this.head || newParentOrRoot.next === null) newParentOrRoot.next = child;
88
90
  child.prev = newParent;
91
+ if (findHead(child) === this.head) this.selectPathTo(child);
92
+ else if (newParentOrRoot.next === null) {
93
+ newParentOrRoot.next = child;
94
+ if (this.head === newParentOrRoot) this.head = findHead(child);
95
+ }
89
96
  const newLevel = newParent ? newParent.level + 1 : 0;
90
97
  this.updateLevels(child, newLevel);
91
98
  }
@@ -186,8 +193,7 @@ var MessageRepository = class {
186
193
  const message = this.messages.get(messageId);
187
194
  if (!message) throw new Error("MessageRepository(switchToBranch): Branch not found. This is likely an internal bug in assistant-ui.");
188
195
  const previousHead = this.head;
189
- const prevOrRoot = message.prev ?? this.root;
190
- prevOrRoot.next = message;
196
+ this.selectPathTo(message);
191
197
  this.head = findHead(message);
192
198
  this.evictOffBranchOptimisticMessages(previousHead, this.head);
193
199
  this._messages.dirty();
@@ -214,8 +220,7 @@ var MessageRepository = class {
214
220
  message.next = null;
215
221
  }
216
222
  this.head = message;
217
- for (let current = message; current; current = current.prev) if (current.prev) current.prev.next = current;
218
- else this.root.next = current;
223
+ this.selectPathTo(message);
219
224
  this.evictOffBranchOptimisticMessages(previousHead, this.head);
220
225
  this._messages.dirty();
221
226
  }
@@ -230,7 +235,11 @@ var MessageRepository = class {
230
235
  }
231
236
  export() {
232
237
  const exportItems = [];
233
- for (const [, message] of this.messages) {
238
+ const pending = [...this.root.children].reverse();
239
+ while (pending.length > 0) {
240
+ const message = this.messages.get(pending.pop());
241
+ if (!message) continue;
242
+ for (let i = message.children.length - 1; i >= 0; i--) pending.push(message.children[i]);
234
243
  if (message.current.metadata?.isOptimistic) continue;
235
244
  let prev = message.prev;
236
245
  while (prev && prev.current.metadata?.isOptimistic) prev = prev.prev;
@@ -1 +1 @@
1
- {"version":3,"file":"message-repository.js","names":["ThreadMessage","RunConfig","generateId","ThreadMessageLike","getContentAutoStatus","fromThreadMessageLike","ExportedMessageRepositoryItem","message","parentId","runConfig","ExportedMessageRepository","headId","messages","Array","fromArray","conv","map","m","content","idx","id","fromBranchableArray","items","options","undefined","Error","RepositoryParent","children","next","RepositoryMessage","prev","current","level","findHead","CachedValue","_value","T","func","constructor","value","dirty","MessageRepository","Map","head","root","updateLevels","newLevel","pending","length","pop","childId","childMessage","get","push","performOp","newParent","child","operation","parentOrRoot","newParentOrRoot","filter","fallbackId","at","fallback","_messages","canonicalHeadId","metadata","isOptimistic","getMessages","headMessage","addOrUpdateMessage","existingItem","newItem","set","getMessage","messageId","index","deleteMessage","replacementId","replacement","delete","getBranches","evictOffBranchOptimisticMessages","previousHead","currentHead","onHeadBranch","Set","add","stale","has","switchToBranch","prevOrRoot","resetHead","clear","descendantId","export","exportItems","import"],"sources":["../../../src/runtime/utils/message-repository.ts"],"sourcesContent":["import type { ThreadMessage } from \"../../types/message\";\nimport type { RunConfig } from \"../../types/message\";\nimport { generateId } from \"../../utils/id\";\nimport type { ThreadMessageLike } from \"./thread-message-like\";\nimport { getContentAutoStatus } from \"./auto-status\";\nimport { fromThreadMessageLike } from \"./thread-message-like\";\n\nexport type ExportedMessageRepositoryItem = {\n message: ThreadMessage;\n parentId: string | null;\n runConfig?: RunConfig;\n};\n\nexport type ExportedMessageRepository = {\n headId?: string | null;\n messages: Array<{\n message: ThreadMessage;\n parentId: string | null;\n runConfig?: RunConfig;\n }>;\n};\n\nexport const ExportedMessageRepository = {\n fromArray: (\n messages: readonly ThreadMessageLike[],\n ): ExportedMessageRepository => {\n const conv = messages.map((m) =>\n fromThreadMessageLike(\n m,\n generateId(),\n getContentAutoStatus(m.content, false, false),\n ),\n );\n\n return {\n messages: conv.map((m, idx) => ({\n parentId: idx > 0 ? conv[idx - 1]!.id : null,\n message: m,\n })),\n };\n },\n\n fromBranchableArray: (\n items: readonly {\n message: ThreadMessageLike;\n parentId: string | null;\n }[],\n options?: { headId?: string | null },\n ): ExportedMessageRepository => {\n return {\n ...(options?.headId !== undefined\n ? { headId: options.headId }\n : undefined),\n messages: items.map(({ message, parentId }) => {\n if (!message.id) {\n throw new Error(\n \"ExportedMessageRepository.fromBranchableArray: Each message must have an 'id' field set.\",\n );\n }\n return {\n parentId,\n message: fromThreadMessageLike(\n message,\n message.id,\n getContentAutoStatus(message.content, false, false),\n ),\n };\n }),\n };\n },\n};\n\ntype RepositoryParent = {\n children: string[];\n next: RepositoryMessage | null;\n};\n\ntype RepositoryMessage = RepositoryParent & {\n prev: RepositoryMessage | null;\n current: ThreadMessage;\n level: number;\n};\n\nconst findHead = (\n message: RepositoryMessage | RepositoryParent,\n): RepositoryMessage | null => {\n let current = message;\n while (current.next) current = current.next;\n return \"current\" in current ? current : null;\n};\n\nclass CachedValue<T> {\n private _value: T | null = null;\n\n private func: () => T;\n\n constructor(func: () => T) {\n this.func = func;\n }\n\n get value() {\n if (this._value === null) {\n this._value = this.func();\n }\n return this._value;\n }\n\n dirty() {\n this._value = null;\n }\n}\n\nexport class MessageRepository {\n private messages = new Map<string, RepositoryMessage>();\n private head: RepositoryMessage | null = null;\n private root: RepositoryParent = {\n children: [],\n next: null,\n };\n\n private updateLevels(message: RepositoryMessage, newLevel: number) {\n const pending = [{ message, level: newLevel }];\n\n while (pending.length > 0) {\n const current = pending.pop()!;\n current.message.level = current.level;\n\n for (const childId of current.message.children) {\n const childMessage = this.messages.get(childId);\n if (childMessage) {\n pending.push({ message: childMessage, level: current.level + 1 });\n }\n }\n }\n }\n\n private performOp(\n newParent: RepositoryMessage | null,\n child: RepositoryMessage,\n operation: \"cut\" | \"link\" | \"relink\",\n ) {\n const parentOrRoot = child.prev ?? this.root;\n const newParentOrRoot = newParent ?? this.root;\n\n if (operation === \"relink\" && parentOrRoot === newParentOrRoot) return;\n\n // `link` receives a fresh ID from `addOrUpdateMessage`; only `relink` can introduce a cycle.\n if (operation === \"relink\") {\n for (\n let current: RepositoryMessage | null = newParent;\n current;\n current = current.prev\n ) {\n if (current.current.id === child.current.id) {\n throw new Error(\n \"MessageRepository(performOp/relink): A message with the same id already exists in the parent tree. This error occurs if the same message id is found multiple times. This is likely an internal bug in assistant-ui.\",\n );\n }\n }\n }\n\n if (operation !== \"link\") {\n parentOrRoot.children = parentOrRoot.children.filter(\n (m) => m !== child.current.id,\n );\n\n if (parentOrRoot.next === child) {\n const fallbackId = parentOrRoot.children.at(-1);\n const fallback = fallbackId ? this.messages.get(fallbackId) : null;\n if (fallback === undefined) {\n throw new Error(\n \"MessageRepository(performOp/cut): Fallback sibling message not found. This is likely an internal bug in assistant-ui.\",\n );\n }\n parentOrRoot.next = fallback;\n }\n }\n\n if (operation !== \"cut\") {\n newParentOrRoot.children = [\n ...newParentOrRoot.children,\n child.current.id,\n ];\n\n if (findHead(child) === this.head || newParentOrRoot.next === null) {\n newParentOrRoot.next = child;\n }\n\n child.prev = newParent;\n\n const newLevel = newParent ? newParent.level + 1 : 0;\n this.updateLevels(child, newLevel);\n }\n }\n\n private _messages = new CachedValue<readonly ThreadMessage[]>(() => {\n const messages = new Array<ThreadMessage>((this.head?.level ?? -1) + 1);\n for (let current = this.head; current; current = current.prev) {\n messages[current.level] = current.current;\n }\n return messages;\n });\n\n get headId() {\n return this.head?.current.id ?? null;\n }\n\n get canonicalHeadId() {\n // Optimistic messages are ephemeral, so persisted callers need the nearest\n // non-optimistic ancestor rather than the raw head.\n let head = this.head;\n while (head?.current.metadata?.isOptimistic) {\n head = head.prev;\n }\n return head?.current.id ?? null;\n }\n\n getMessages(headId?: string) {\n if (headId === undefined || headId === this.head?.current.id) {\n return this._messages.value;\n }\n\n const headMessage = this.messages.get(headId);\n if (!headMessage) {\n throw new Error(\n \"MessageRepository(getMessages): Head message not found. This is likely an internal bug in assistant-ui.\",\n );\n }\n\n const messages = new Array<ThreadMessage>(headMessage.level + 1);\n for (\n let current: RepositoryMessage | null = headMessage;\n current;\n current = current.prev\n ) {\n messages[current.level] = current.current;\n }\n return messages;\n }\n\n addOrUpdateMessage(parentId: string | null, message: ThreadMessage) {\n const existingItem = this.messages.get(message.id);\n const prev = parentId ? this.messages.get(parentId) : null;\n if (prev === undefined)\n throw new Error(\n \"MessageRepository(addOrUpdateMessage): Parent message not found. This is likely an internal bug in assistant-ui.\",\n );\n\n if (existingItem) {\n existingItem.current = message;\n this.performOp(prev, existingItem, \"relink\");\n this._messages.dirty();\n return;\n }\n\n const newItem: RepositoryMessage = {\n prev,\n current: message,\n next: null,\n children: [],\n level: prev ? prev.level + 1 : 0,\n };\n\n this.messages.set(message.id, newItem);\n this.performOp(prev, newItem, \"link\");\n\n if (this.head === prev) {\n this.head = newItem;\n }\n\n this._messages.dirty();\n }\n\n getMessage(messageId: string) {\n const message = this.messages.get(messageId);\n if (!message)\n throw new Error(\n \"MessageRepository(updateMessage): Message not found. This is likely an internal bug in assistant-ui.\",\n );\n\n return {\n parentId: message.prev?.current.id ?? null,\n message: message.current,\n index: message.level,\n };\n }\n\n deleteMessage(messageId: string, replacementId?: string | null | undefined) {\n const message = this.messages.get(messageId);\n\n if (!message)\n throw new Error(\n \"MessageRepository(deleteMessage): Message not found. This is likely an internal bug in assistant-ui.\",\n );\n\n const replacement =\n replacementId === undefined\n ? message.prev\n : replacementId === null\n ? null\n : this.messages.get(replacementId);\n if (replacement === undefined)\n throw new Error(\n \"MessageRepository(deleteMessage): Replacement not found. This is likely an internal bug in assistant-ui.\",\n );\n\n for (const child of message.children) {\n const childMessage = this.messages.get(child);\n if (!childMessage)\n throw new Error(\n \"MessageRepository(deleteMessage): Child message not found. This is likely an internal bug in assistant-ui.\",\n );\n this.performOp(replacement, childMessage, \"relink\");\n }\n\n this.performOp(null, message, \"cut\");\n this.messages.delete(messageId);\n\n if (this.head === message) {\n this.head = findHead(replacement ?? this.root);\n }\n\n this._messages.dirty();\n }\n\n getBranches(messageId: string) {\n const message = this.messages.get(messageId);\n if (!message)\n throw new Error(\n \"MessageRepository(getBranches): Message not found. This is likely an internal bug in assistant-ui.\",\n );\n\n const { children } = message.prev ?? this.root;\n return children;\n }\n\n /**\n * Evicts optimistic messages (`metadata.isOptimistic`) the head just moved\n * away from. Since eviction runs on every head move, the only optimistic\n * messages in the repository live on the branch the head previously pointed\n * at — so we walk just that branch rather than the whole repository. Keeps a\n * client→server id swap from leaving a phantom sibling, and drops off-branch\n * placeholders.\n */\n private evictOffBranchOptimisticMessages(\n previousHead: RepositoryMessage | null,\n currentHead: RepositoryMessage | null,\n ) {\n if (!previousHead) return;\n\n const onHeadBranch = new Set<string>();\n for (let current = currentHead; current; current = current.prev) {\n onHeadBranch.add(current.current.id);\n }\n\n const stale: string[] = [];\n for (\n let current: RepositoryMessage | null = previousHead;\n current;\n current = current.prev\n ) {\n // Stop at the first node shared with the current head branch: every\n // ancestor above it is shared too, so nothing further can be off-branch.\n if (onHeadBranch.has(current.current.id)) break;\n if (current.current.metadata?.isOptimistic) {\n stale.push(current.current.id);\n }\n }\n\n for (const id of stale) {\n // A prior deletion may have already removed this node.\n if (this.messages.has(id)) this.deleteMessage(id);\n }\n }\n\n switchToBranch(messageId: string) {\n const message = this.messages.get(messageId);\n if (!message)\n throw new Error(\n \"MessageRepository(switchToBranch): Branch not found. This is likely an internal bug in assistant-ui.\",\n );\n\n const previousHead = this.head;\n const prevOrRoot = message.prev ?? this.root;\n prevOrRoot.next = message;\n\n this.head = findHead(message);\n\n this.evictOffBranchOptimisticMessages(previousHead, this.head);\n\n this._messages.dirty();\n }\n\n resetHead(messageId: string | null) {\n if (messageId === null) {\n this.clear();\n return;\n }\n\n const message = this.messages.get(messageId);\n if (!message)\n throw new Error(\n \"MessageRepository(resetHead): Branch not found. This is likely an internal bug in assistant-ui.\",\n );\n\n const previousHead = this.head;\n\n if (message.children.length > 0) {\n const pending = [...message.children];\n while (pending.length > 0) {\n const childId = pending.pop()!;\n const childMessage = this.messages.get(childId);\n if (childMessage) {\n for (const descendantId of childMessage.children) {\n pending.push(descendantId);\n }\n this.messages.delete(childId);\n }\n }\n\n message.children = [];\n message.next = null;\n }\n\n this.head = message;\n for (\n let current: RepositoryMessage | null = message;\n current;\n current = current.prev\n ) {\n if (current.prev) {\n current.prev.next = current;\n } else {\n this.root.next = current;\n }\n }\n\n this.evictOffBranchOptimisticMessages(previousHead, this.head);\n\n this._messages.dirty();\n }\n\n clear(): void {\n this.messages.clear();\n this.head = null;\n this.root = {\n children: [],\n next: null,\n };\n this._messages.dirty();\n }\n\n export(): ExportedMessageRepository {\n const exportItems: ExportedMessageRepository[\"messages\"] = [];\n\n // Optimistic messages are ephemeral and never persisted. A persisted child\n // of an optimistic node is re-parented onto its nearest persisted ancestor\n // so the exported tree never references a skipped id.\n for (const [, message] of this.messages) {\n if (message.current.metadata?.isOptimistic) continue;\n let prev = message.prev;\n while (prev && prev.current.metadata?.isOptimistic) {\n prev = prev.prev;\n }\n exportItems.push({\n message: message.current,\n parentId: prev?.current.id ?? null,\n });\n }\n\n return {\n headId: this.canonicalHeadId,\n messages: exportItems,\n };\n }\n\n import({ headId, messages }: ExportedMessageRepository) {\n for (const { message, parentId } of messages) {\n this.addOrUpdateMessage(parentId, message);\n }\n\n this.resetHead(headId ?? messages.at(-1)?.message.id ?? null);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"message-repository.js","names":["ThreadMessage","RunConfig","generateId","ThreadMessageLike","getRepositoryContentAutoStatus","fromThreadMessageLike","ExportedMessageRepositoryItem","message","parentId","runConfig","ExportedMessageRepository","headId","messages","Array","fromArray","conv","map","m","content","idx","id","fromBranchableArray","items","options","undefined","Error","RepositoryParent","children","next","RepositoryMessage","prev","current","level","findHead","CachedValue","_value","T","func","constructor","value","dirty","MessageRepository","Map","head","root","updateLevels","newLevel","pending","length","pop","childId","childMessage","get","push","selectPathTo","performOp","newParent","child","operation","parentOrRoot","newParentOrRoot","filter","fallbackId","at","fallback","_messages","canonicalHeadId","metadata","isOptimistic","getMessages","headMessage","addOrUpdateMessage","existingItem","newItem","set","getMessage","messageId","index","deleteMessage","replacementId","replacement","delete","getBranches","evictOffBranchOptimisticMessages","previousHead","currentHead","onHeadBranch","Set","add","stale","has","switchToBranch","resetHead","clear","descendantId","export","exportItems","reverse","i","import"],"sources":["../../../src/runtime/utils/message-repository.ts"],"sourcesContent":["import type { ThreadMessage } from \"../../types/message\";\nimport type { RunConfig } from \"../../types/message\";\nimport { generateId } from \"../../utils/id\";\nimport type { ThreadMessageLike } from \"./thread-message-like\";\nimport { getRepositoryContentAutoStatus } from \"./auto-status\";\nimport { fromThreadMessageLike } from \"./thread-message-like\";\n\nexport type ExportedMessageRepositoryItem = {\n message: ThreadMessage;\n parentId: string | null;\n runConfig?: RunConfig;\n};\n\nexport type ExportedMessageRepository = {\n headId?: string | null;\n messages: Array<{\n message: ThreadMessage;\n parentId: string | null;\n runConfig?: RunConfig;\n }>;\n};\n\nexport const ExportedMessageRepository = {\n fromArray: (\n messages: readonly ThreadMessageLike[],\n ): ExportedMessageRepository => {\n const conv = messages.map((m) =>\n fromThreadMessageLike(\n m,\n generateId(),\n getRepositoryContentAutoStatus(m.content),\n ),\n );\n\n return {\n messages: conv.map((m, idx) => ({\n parentId: idx > 0 ? conv[idx - 1]!.id : null,\n message: m,\n })),\n };\n },\n\n fromBranchableArray: (\n items: readonly {\n message: ThreadMessageLike;\n parentId: string | null;\n }[],\n options?: { headId?: string | null },\n ): ExportedMessageRepository => {\n return {\n ...(options?.headId !== undefined\n ? { headId: options.headId }\n : undefined),\n messages: items.map(({ message, parentId }) => {\n if (!message.id) {\n throw new Error(\n \"ExportedMessageRepository.fromBranchableArray: Each message must have an 'id' field set.\",\n );\n }\n return {\n parentId,\n message: fromThreadMessageLike(\n message,\n message.id,\n getRepositoryContentAutoStatus(message.content),\n ),\n };\n }),\n };\n },\n};\n\ntype RepositoryParent = {\n children: string[];\n next: RepositoryMessage | null;\n};\n\ntype RepositoryMessage = RepositoryParent & {\n prev: RepositoryMessage | null;\n current: ThreadMessage;\n level: number;\n};\n\nconst findHead = (\n message: RepositoryMessage | RepositoryParent,\n): RepositoryMessage | null => {\n let current = message;\n while (current.next) current = current.next;\n return \"current\" in current ? current : null;\n};\n\nclass CachedValue<T> {\n private _value: T | null = null;\n\n private func: () => T;\n\n constructor(func: () => T) {\n this.func = func;\n }\n\n get value() {\n if (this._value === null) {\n this._value = this.func();\n }\n return this._value;\n }\n\n dirty() {\n this._value = null;\n }\n}\n\nexport class MessageRepository {\n private messages = new Map<string, RepositoryMessage>();\n private head: RepositoryMessage | null = null;\n private root: RepositoryParent = {\n children: [],\n next: null,\n };\n\n private updateLevels(message: RepositoryMessage, newLevel: number) {\n const pending = [{ message, level: newLevel }];\n\n while (pending.length > 0) {\n const current = pending.pop()!;\n current.message.level = current.level;\n\n for (const childId of current.message.children) {\n const childMessage = this.messages.get(childId);\n if (childMessage) {\n pending.push({ message: childMessage, level: current.level + 1 });\n }\n }\n }\n }\n\n private selectPathTo(message: RepositoryMessage) {\n for (\n let current: RepositoryMessage | null = message;\n current;\n current = current.prev\n ) {\n (current.prev ?? this.root).next = current;\n }\n }\n\n private performOp(\n newParent: RepositoryMessage | null,\n child: RepositoryMessage,\n operation: \"cut\" | \"link\" | \"relink\",\n ) {\n const parentOrRoot = child.prev ?? this.root;\n const newParentOrRoot = newParent ?? this.root;\n\n if (operation === \"relink\" && parentOrRoot === newParentOrRoot) return;\n\n // `link` receives a fresh ID from `addOrUpdateMessage`; only `relink` can introduce a cycle.\n if (operation === \"relink\") {\n for (\n let current: RepositoryMessage | null = newParent;\n current;\n current = current.prev\n ) {\n if (current.current.id === child.current.id) {\n throw new Error(\n \"MessageRepository(performOp/relink): A message with the same id already exists in the parent tree. This error occurs if the same message id is found multiple times. This is likely an internal bug in assistant-ui.\",\n );\n }\n }\n }\n\n if (operation !== \"link\") {\n parentOrRoot.children = parentOrRoot.children.filter(\n (m) => m !== child.current.id,\n );\n\n if (parentOrRoot.next === child) {\n const fallbackId = parentOrRoot.children.at(-1);\n const fallback = fallbackId ? this.messages.get(fallbackId) : null;\n if (fallback === undefined) {\n throw new Error(\n \"MessageRepository(performOp/cut): Fallback sibling message not found. This is likely an internal bug in assistant-ui.\",\n );\n }\n parentOrRoot.next = fallback;\n }\n }\n\n if (operation !== \"cut\") {\n newParentOrRoot.children = [\n ...newParentOrRoot.children,\n child.current.id,\n ];\n\n child.prev = newParent;\n\n if (findHead(child) === this.head) {\n this.selectPathTo(child);\n } else if (newParentOrRoot.next === null) {\n newParentOrRoot.next = child;\n if (this.head === newParentOrRoot) {\n this.head = findHead(child);\n }\n }\n\n const newLevel = newParent ? newParent.level + 1 : 0;\n this.updateLevels(child, newLevel);\n }\n }\n\n private _messages = new CachedValue<readonly ThreadMessage[]>(() => {\n const messages = new Array<ThreadMessage>((this.head?.level ?? -1) + 1);\n for (let current = this.head; current; current = current.prev) {\n messages[current.level] = current.current;\n }\n return messages;\n });\n\n get headId() {\n return this.head?.current.id ?? null;\n }\n\n get canonicalHeadId() {\n // Optimistic messages are ephemeral, so persisted callers need the nearest\n // non-optimistic ancestor rather than the raw head.\n let head = this.head;\n while (head?.current.metadata?.isOptimistic) {\n head = head.prev;\n }\n return head?.current.id ?? null;\n }\n\n getMessages(headId?: string) {\n if (headId === undefined || headId === this.head?.current.id) {\n return this._messages.value;\n }\n\n const headMessage = this.messages.get(headId);\n if (!headMessage) {\n throw new Error(\n \"MessageRepository(getMessages): Head message not found. This is likely an internal bug in assistant-ui.\",\n );\n }\n\n const messages = new Array<ThreadMessage>(headMessage.level + 1);\n for (\n let current: RepositoryMessage | null = headMessage;\n current;\n current = current.prev\n ) {\n messages[current.level] = current.current;\n }\n return messages;\n }\n\n addOrUpdateMessage(parentId: string | null, message: ThreadMessage) {\n const existingItem = this.messages.get(message.id);\n const prev = parentId ? this.messages.get(parentId) : null;\n if (prev === undefined)\n throw new Error(\n \"MessageRepository(addOrUpdateMessage): Parent message not found. This is likely an internal bug in assistant-ui.\",\n );\n\n if (existingItem) {\n existingItem.current = message;\n this.performOp(prev, existingItem, \"relink\");\n this._messages.dirty();\n return;\n }\n\n const newItem: RepositoryMessage = {\n prev,\n current: message,\n next: null,\n children: [],\n level: prev ? prev.level + 1 : 0,\n };\n\n this.messages.set(message.id, newItem);\n this.performOp(prev, newItem, \"link\");\n\n if (this.head === prev) {\n this.head = newItem;\n }\n\n this._messages.dirty();\n }\n\n getMessage(messageId: string) {\n const message = this.messages.get(messageId);\n if (!message)\n throw new Error(\n \"MessageRepository(updateMessage): Message not found. This is likely an internal bug in assistant-ui.\",\n );\n\n return {\n parentId: message.prev?.current.id ?? null,\n message: message.current,\n index: message.level,\n };\n }\n\n deleteMessage(messageId: string, replacementId?: string | null | undefined) {\n const message = this.messages.get(messageId);\n\n if (!message)\n throw new Error(\n \"MessageRepository(deleteMessage): Message not found. This is likely an internal bug in assistant-ui.\",\n );\n\n const replacement =\n replacementId === undefined\n ? message.prev\n : replacementId === null\n ? null\n : this.messages.get(replacementId);\n if (replacement === undefined)\n throw new Error(\n \"MessageRepository(deleteMessage): Replacement not found. This is likely an internal bug in assistant-ui.\",\n );\n\n for (const child of message.children) {\n const childMessage = this.messages.get(child);\n if (!childMessage)\n throw new Error(\n \"MessageRepository(deleteMessage): Child message not found. This is likely an internal bug in assistant-ui.\",\n );\n this.performOp(replacement, childMessage, \"relink\");\n }\n\n this.performOp(null, message, \"cut\");\n this.messages.delete(messageId);\n\n if (this.head === message) {\n this.head = findHead(replacement ?? this.root);\n }\n\n this._messages.dirty();\n }\n\n getBranches(messageId: string) {\n const message = this.messages.get(messageId);\n if (!message)\n throw new Error(\n \"MessageRepository(getBranches): Message not found. This is likely an internal bug in assistant-ui.\",\n );\n\n const { children } = message.prev ?? this.root;\n return children;\n }\n\n /**\n * Evicts optimistic messages (`metadata.isOptimistic`) the head just moved\n * away from. Since eviction runs on every head move, the only optimistic\n * messages in the repository live on the branch the head previously pointed\n * at — so we walk just that branch rather than the whole repository. Keeps a\n * client→server id swap from leaving a phantom sibling, and drops off-branch\n * placeholders.\n */\n private evictOffBranchOptimisticMessages(\n previousHead: RepositoryMessage | null,\n currentHead: RepositoryMessage | null,\n ) {\n if (!previousHead) return;\n\n const onHeadBranch = new Set<string>();\n for (let current = currentHead; current; current = current.prev) {\n onHeadBranch.add(current.current.id);\n }\n\n const stale: string[] = [];\n for (\n let current: RepositoryMessage | null = previousHead;\n current;\n current = current.prev\n ) {\n // Stop at the first node shared with the current head branch: every\n // ancestor above it is shared too, so nothing further can be off-branch.\n if (onHeadBranch.has(current.current.id)) break;\n if (current.current.metadata?.isOptimistic) {\n stale.push(current.current.id);\n }\n }\n\n for (const id of stale) {\n // A prior deletion may have already removed this node.\n if (this.messages.has(id)) this.deleteMessage(id);\n }\n }\n\n switchToBranch(messageId: string) {\n const message = this.messages.get(messageId);\n if (!message)\n throw new Error(\n \"MessageRepository(switchToBranch): Branch not found. This is likely an internal bug in assistant-ui.\",\n );\n\n const previousHead = this.head;\n this.selectPathTo(message);\n\n this.head = findHead(message);\n\n this.evictOffBranchOptimisticMessages(previousHead, this.head);\n\n this._messages.dirty();\n }\n\n resetHead(messageId: string | null) {\n if (messageId === null) {\n this.clear();\n return;\n }\n\n const message = this.messages.get(messageId);\n if (!message)\n throw new Error(\n \"MessageRepository(resetHead): Branch not found. This is likely an internal bug in assistant-ui.\",\n );\n\n const previousHead = this.head;\n\n if (message.children.length > 0) {\n const pending = [...message.children];\n while (pending.length > 0) {\n const childId = pending.pop()!;\n const childMessage = this.messages.get(childId);\n if (childMessage) {\n for (const descendantId of childMessage.children) {\n pending.push(descendantId);\n }\n this.messages.delete(childId);\n }\n }\n\n message.children = [];\n message.next = null;\n }\n\n this.head = message;\n this.selectPathTo(message);\n\n this.evictOffBranchOptimisticMessages(previousHead, this.head);\n\n this._messages.dirty();\n }\n\n clear(): void {\n this.messages.clear();\n this.head = null;\n this.root = {\n children: [],\n next: null,\n };\n this._messages.dirty();\n }\n\n export(): ExportedMessageRepository {\n const exportItems: ExportedMessageRepository[\"messages\"] = [];\n\n // Optimistic messages are ephemeral and never persisted. A persisted child\n // of an optimistic node is re-parented onto its nearest persisted ancestor\n // so the exported tree never references a skipped id.\n // Import and external-state conversion require parents before children, so\n // the tree is walked in pre-order rather than iterated in insertion order.\n const pending = [...this.root.children].reverse();\n while (pending.length > 0) {\n const message = this.messages.get(pending.pop()!);\n if (!message) continue;\n for (let i = message.children.length - 1; i >= 0; i--) {\n pending.push(message.children[i]!);\n }\n if (message.current.metadata?.isOptimistic) continue;\n let prev = message.prev;\n while (prev && prev.current.metadata?.isOptimistic) {\n prev = prev.prev;\n }\n exportItems.push({\n message: message.current,\n parentId: prev?.current.id ?? null,\n });\n }\n\n return {\n headId: this.canonicalHeadId,\n messages: exportItems,\n };\n }\n\n import({ headId, messages }: ExportedMessageRepository) {\n for (const { message, parentId } of messages) {\n this.addOrUpdateMessage(parentId, message);\n }\n\n this.resetHead(headId ?? messages.at(-1)?.message.id ?? null);\n }\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { DataMessagePart, FileMessagePart, GenerativeUIMessagePart, ImageMessagePart, MessageStatus, MessageTiming, PartProviderMetadata, ReasoningMessagePart, SourceMessagePart, TextMessagePart, ThreadMessage, ThreadStep, ThreadUserMessagePart, ToolCallMessagePart, ToolCallMessagePartMcpMetadata, ToolCallTiming, Unstable_AudioMessagePart } from "../../types/message.js";
1
+ import { DataMessagePart, FileMessagePart, GenerativeUIMessagePart, ImageMessagePart, MessageModality, MessageStatus, MessageTiming, PartProviderMetadata, ReasoningMessagePart, SourceMessagePart, TextMessagePart, ThreadMessage, ThreadStep, ThreadUserMessagePart, ToolCallMessagePart, ToolCallMessagePartMcpMetadata, ToolCallTiming, Unstable_AudioMessagePart } from "../../types/message.js";
2
2
  import { CompleteAttachment } from "../../types/attachment.js";
3
3
  import { ReadonlyJSONObject, ReadonlyJSONValue } from "assistant-stream/utils";
4
4
  //#region src/runtime/utils/thread-message-like.d.ts
@@ -44,6 +44,7 @@ type ThreadMessageLike = {
44
44
  readonly type: "positive" | "negative";
45
45
  };
46
46
  readonly isOptimistic?: boolean | undefined;
47
+ readonly modality?: MessageModality | undefined;
47
48
  readonly custom?: Record<string, unknown> | undefined;
48
49
  } | undefined;
49
50
  };
@@ -1 +1 @@
1
- {"version":3,"file":"thread-message-like.d.ts","names":[],"sources":["../../../src/runtime/utils/thread-message-like.ts"],"mappings":";;;;KAkCK;WACM;WACA;;KAGC;WACD;WACA,4BAGD,kBACA,uBACA,oBACA,mBACA,kBACA,kBACA,0BACA,4BACA;aAEW;aACA;aACA;aACA,OAAO;aACP;aACA;aACA;aACA;aACA;aACA,oBAAoB;aACpB;MAAc;MAAe;;aAC7B,SAAS;aACT,MAAM;aACN,mBAAmB;aACnB,WAAW,YAAY;;WAGjC;WACA,YAAY;WACZ,SAAS;WACT,wBACK,KAAK;aACJ,mBAAmB,wBAAwB;;WAGjD;aAEM,iBAAiB;aACjB,gCACI;aAEJ,yBAAyB;aACzB,iBAAiB;aACjB,SAAS;aACT;eAA+B;;aAC/B;aACA,SAAS;;;;;;cAgBb,wBACX,MAAM,mBACN,oBACA,gBAAgB,kBACf"}
1
+ {"version":3,"file":"thread-message-like.d.ts","names":[],"sources":["../../../src/runtime/utils/thread-message-like.ts"],"mappings":";;;;KAmCK;WACM;WACA;;KAGC;WACD;WACA,4BAGD,kBACA,uBACA,oBACA,mBACA,kBACA,kBACA,0BACA,4BACA;aAEW;aACA;aACA;aACA,OAAO;aACP;aACA;aACA;aACA;aACA;aACA,oBAAoB;aACpB;MAAc;MAAe;;aAC7B,SAAS;aACT,MAAM;aACN,mBAAmB;aACnB,WAAW,YAAY;;WAGjC;WACA,YAAY;WACZ,SAAS;WACT,wBACK,KAAK;aACJ,mBAAmB,wBAAwB;;WAGjD;aAEM,iBAAiB;aACjB,gCACI;aAEJ,yBAAyB;aACzB,iBAAiB;aACjB,SAAS;aACT;eAA+B;;aAC/B;aACA,WAAW;aACX,SAAS;;;;;;cAgBb,wBACX,MAAM,mBACN,oBACA,gBAAgB,kBACf"}
@@ -61,7 +61,7 @@ const fromThreadMessageLike = (like, fallbackId, fallbackStatus) => {
61
61
  const { parentId, messages, ...basePart } = part;
62
62
  const commonProps = {
63
63
  ...basePart,
64
- toolCallId: part.toolCallId ?? `tool-${generateId()}`,
64
+ toolCallId: part.toolCallId || `tool-${generateId()}`,
65
65
  ...parentId !== void 0 && { parentId },
66
66
  ...messages !== void 0 && { messages }
67
67
  };
@@ -92,7 +92,8 @@ const fromThreadMessageLike = (like, fallbackId, fallbackStatus) => {
92
92
  steps: metadata?.steps ?? [],
93
93
  ...metadata?.timing && { timing: metadata.timing },
94
94
  ...metadata?.submittedFeedback && { submittedFeedback: metadata.submittedFeedback },
95
- ...metadata?.isOptimistic && { isOptimistic: true }
95
+ ...metadata?.isOptimistic && { isOptimistic: true },
96
+ ...metadata?.modality && { modality: metadata.modality }
96
97
  }
97
98
  };
98
99
  case "user": return {
@@ -121,7 +122,8 @@ const fromThreadMessageLike = (like, fallbackId, fallbackStatus) => {
121
122
  })),
122
123
  metadata: {
123
124
  custom: metadata?.custom ?? {},
124
- ...metadata?.isOptimistic && { isOptimistic: true }
125
+ ...metadata?.isOptimistic && { isOptimistic: true },
126
+ ...metadata?.modality && { modality: metadata.modality }
125
127
  }
126
128
  };
127
129
  case "system":