@assistant-ui/core 0.2.21 → 0.2.23

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 (345) hide show
  1. package/dist/adapters/attachment.d.ts.map +1 -1
  2. package/dist/adapters/speech.d.ts.map +1 -1
  3. package/dist/adapters/speech.js +9 -2
  4. package/dist/adapters/speech.js.map +1 -1
  5. package/dist/adapters/thread-history.d.ts +8 -0
  6. package/dist/adapters/thread-history.d.ts.map +1 -1
  7. package/dist/adapters/voice.d.ts.map +1 -1
  8. package/dist/adapters/voice.js +13 -5
  9. package/dist/adapters/voice.js.map +1 -1
  10. package/dist/internal.d.ts +5 -2
  11. package/dist/internal.js +5 -2
  12. package/dist/model-context/frame/host.d.ts +1 -0
  13. package/dist/model-context/frame/host.d.ts.map +1 -1
  14. package/dist/model-context/frame/host.js +41 -21
  15. package/dist/model-context/frame/host.js.map +1 -1
  16. package/dist/model-context/frame/provider.d.ts.map +1 -1
  17. package/dist/model-context/frame/provider.js +1 -0
  18. package/dist/model-context/frame/provider.js.map +1 -1
  19. package/dist/model-context/interactable-composer-metadata.js.map +1 -1
  20. package/dist/model-context/types.d.ts.map +1 -1
  21. package/dist/model-context/types.js +13 -4
  22. package/dist/model-context/types.js.map +1 -1
  23. package/dist/react/AssistantProvider.js.map +1 -1
  24. package/dist/react/adapters/LocalStorageThreadListAdapter.d.ts.map +1 -1
  25. package/dist/react/adapters/LocalStorageThreadListAdapter.js +78 -50
  26. package/dist/react/adapters/LocalStorageThreadListAdapter.js.map +1 -1
  27. package/dist/react/client/Interactables.js.map +1 -1
  28. package/dist/react/client/Tools.d.ts.map +1 -1
  29. package/dist/react/client/interactable-model-context.d.ts.map +1 -1
  30. package/dist/react/client/interactable-model-context.js +1 -0
  31. package/dist/react/client/interactable-model-context.js.map +1 -1
  32. package/dist/react/interactables-legacy/useInteractableState.js +1 -0
  33. package/dist/react/interactables-legacy/useInteractableState.js.map +1 -1
  34. package/dist/react/model-context/useInteractable.js.map +1 -1
  35. package/dist/react/model-context/useInteractableState.js +1 -0
  36. package/dist/react/model-context/useInteractableState.js.map +1 -1
  37. package/dist/react/model-context/useInteractableVersions.js +1 -0
  38. package/dist/react/model-context/useInteractableVersions.js.map +1 -1
  39. package/dist/react/model-context/useToolArgsStatus.js +1 -0
  40. package/dist/react/model-context/useToolArgsStatus.js.map +1 -1
  41. package/dist/react/primitive-hooks/useActionBarCopy.js +14 -13
  42. package/dist/react/primitive-hooks/useActionBarCopy.js.map +1 -1
  43. package/dist/react/primitive-hooks/useActionBarEdit.js +1 -0
  44. package/dist/react/primitive-hooks/useActionBarEdit.js.map +1 -1
  45. package/dist/react/primitive-hooks/useActionBarFeedback.js +1 -0
  46. package/dist/react/primitive-hooks/useActionBarFeedback.js.map +1 -1
  47. package/dist/react/primitive-hooks/useActionBarReload.js +1 -0
  48. package/dist/react/primitive-hooks/useActionBarReload.js.map +1 -1
  49. package/dist/react/primitive-hooks/useActionBarSpeak.js +1 -0
  50. package/dist/react/primitive-hooks/useActionBarSpeak.js.map +1 -1
  51. package/dist/react/primitive-hooks/useActionBarStopSpeaking.js +1 -0
  52. package/dist/react/primitive-hooks/useActionBarStopSpeaking.js.map +1 -1
  53. package/dist/react/primitive-hooks/useBranchPickerNext.js +1 -0
  54. package/dist/react/primitive-hooks/useBranchPickerNext.js.map +1 -1
  55. package/dist/react/primitive-hooks/useBranchPickerPrevious.js +1 -0
  56. package/dist/react/primitive-hooks/useBranchPickerPrevious.js.map +1 -1
  57. package/dist/react/primitive-hooks/useComposerAddAttachment.d.ts.map +1 -1
  58. package/dist/react/primitive-hooks/useComposerAddAttachment.js +1 -0
  59. package/dist/react/primitive-hooks/useComposerAddAttachment.js.map +1 -1
  60. package/dist/react/primitive-hooks/useComposerCancel.js +1 -0
  61. package/dist/react/primitive-hooks/useComposerCancel.js.map +1 -1
  62. package/dist/react/primitive-hooks/useComposerDictate.js +1 -0
  63. package/dist/react/primitive-hooks/useComposerDictate.js.map +1 -1
  64. package/dist/react/primitive-hooks/useComposerSend.d.ts.map +1 -1
  65. package/dist/react/primitive-hooks/useComposerSend.js +1 -0
  66. package/dist/react/primitive-hooks/useComposerSend.js.map +1 -1
  67. package/dist/react/primitive-hooks/useEditComposerCancel.js +1 -0
  68. package/dist/react/primitive-hooks/useEditComposerCancel.js.map +1 -1
  69. package/dist/react/primitive-hooks/useEditComposerSend.js +1 -0
  70. package/dist/react/primitive-hooks/useEditComposerSend.js.map +1 -1
  71. package/dist/react/primitive-hooks/useMessageBranching.js +1 -0
  72. package/dist/react/primitive-hooks/useMessageBranching.js.map +1 -1
  73. package/dist/react/primitive-hooks/useMessageReload.js +1 -0
  74. package/dist/react/primitive-hooks/useMessageReload.js.map +1 -1
  75. package/dist/react/primitive-hooks/useSuggestionTrigger.js +1 -0
  76. package/dist/react/primitive-hooks/useSuggestionTrigger.js.map +1 -1
  77. package/dist/react/primitive-hooks/useThreadListItemArchive.js +1 -0
  78. package/dist/react/primitive-hooks/useThreadListItemArchive.js.map +1 -1
  79. package/dist/react/primitive-hooks/useThreadListItemDelete.js +1 -0
  80. package/dist/react/primitive-hooks/useThreadListItemDelete.js.map +1 -1
  81. package/dist/react/primitive-hooks/useThreadListItemTrigger.js +1 -0
  82. package/dist/react/primitive-hooks/useThreadListItemTrigger.js.map +1 -1
  83. package/dist/react/primitive-hooks/useThreadListItemUnarchive.js +1 -0
  84. package/dist/react/primitive-hooks/useThreadListItemUnarchive.js.map +1 -1
  85. package/dist/react/primitive-hooks/useThreadListLoadMore.js +1 -0
  86. package/dist/react/primitive-hooks/useThreadListLoadMore.js.map +1 -1
  87. package/dist/react/primitive-hooks/useThreadListNew.js +1 -0
  88. package/dist/react/primitive-hooks/useThreadListNew.js.map +1 -1
  89. package/dist/react/primitives/chainOfThought/ChainOfThoughtParts.d.ts.map +1 -1
  90. package/dist/react/primitives/chainOfThought/ChainOfThoughtParts.js +1 -1
  91. package/dist/react/primitives/chainOfThought/ChainOfThoughtParts.js.map +1 -1
  92. package/dist/react/primitives/composer/ComposerAttachments.js.map +1 -1
  93. package/dist/react/primitives/composer/ComposerQueue.d.ts.map +1 -1
  94. package/dist/react/primitives/composer/ComposerQueue.js.map +1 -1
  95. package/dist/react/primitives/generativeUI/GenerativeUI.d.ts.map +1 -1
  96. package/dist/react/primitives/message/MessageAttachments.js.map +1 -1
  97. package/dist/react/primitives/message/MessageGroupedParts.js.map +1 -1
  98. package/dist/react/primitives/message/MessageParts.d.ts +2 -1
  99. package/dist/react/primitives/message/MessageParts.d.ts.map +1 -1
  100. package/dist/react/primitives/message/MessageParts.js +46 -36
  101. package/dist/react/primitives/message/MessageParts.js.map +1 -1
  102. package/dist/react/primitives/part/PartMessages.js.map +1 -1
  103. package/dist/react/primitives/thread/ThreadMessages.js.map +1 -1
  104. package/dist/react/primitives/thread/ThreadSuggestions.js.map +1 -1
  105. package/dist/react/primitives/threadList/ThreadListItems.js.map +1 -1
  106. package/dist/react/providers/ChainOfThoughtPartByIndexProvider.d.ts.map +1 -1
  107. package/dist/react/providers/ChainOfThoughtPartByIndexProvider.js +18 -30
  108. package/dist/react/providers/ChainOfThoughtPartByIndexProvider.js.map +1 -1
  109. package/dist/react/providers/PartByIndexProvider.d.ts.map +1 -1
  110. package/dist/react/providers/PartByIndexProvider.js +18 -30
  111. package/dist/react/providers/PartByIndexProvider.js.map +1 -1
  112. package/dist/react/providers/TextMessagePartProvider.js +1 -0
  113. package/dist/react/providers/TextMessagePartProvider.js.map +1 -1
  114. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
  115. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +1 -0
  116. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
  117. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +9 -2
  118. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
  119. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +55 -12
  120. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
  121. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts +31 -1
  122. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
  123. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +12 -2
  124. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
  125. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts +1 -1
  126. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts.map +1 -1
  127. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js +3 -2
  128. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js.map +1 -1
  129. package/dist/react/runtimes/cloud/auiV0.d.ts +12 -1
  130. package/dist/react/runtimes/cloud/auiV0.d.ts.map +1 -1
  131. package/dist/react/runtimes/cloud/auiV0.js +2 -1
  132. package/dist/react/runtimes/cloud/auiV0.js.map +1 -1
  133. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js +75 -73
  134. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js.map +1 -1
  135. package/dist/react/runtimes/createMessageConverter.d.ts.map +1 -1
  136. package/dist/react/runtimes/external-message-converter.js +2 -2
  137. package/dist/react/runtimes/external-message-converter.js.map +1 -1
  138. package/dist/react/runtimes/useExternalStoreSharedOptions.js +1 -0
  139. package/dist/react/runtimes/useExternalStoreSharedOptions.js.map +1 -1
  140. package/dist/react/runtimes/useLocalRuntime.d.ts.map +1 -1
  141. package/dist/react/runtimes/useLocalRuntime.js +9 -1
  142. package/dist/react/runtimes/useLocalRuntime.js.map +1 -1
  143. package/dist/runtime/api/assistant-runtime.d.ts +1 -1
  144. package/dist/runtime/api/assistant-runtime.d.ts.map +1 -1
  145. package/dist/runtime/api/assistant-runtime.js +1 -1
  146. package/dist/runtime/api/assistant-runtime.js.map +1 -1
  147. package/dist/runtime/api/attachment-runtime.d.ts +1 -1
  148. package/dist/runtime/api/attachment-runtime.d.ts.map +1 -1
  149. package/dist/runtime/api/attachment-runtime.js +1 -1
  150. package/dist/runtime/api/attachment-runtime.js.map +1 -1
  151. package/dist/runtime/api/composer-runtime.d.ts +2 -2
  152. package/dist/runtime/api/composer-runtime.d.ts.map +1 -1
  153. package/dist/runtime/api/composer-runtime.js +2 -2
  154. package/dist/runtime/api/composer-runtime.js.map +1 -1
  155. package/dist/runtime/api/message-part-runtime.d.ts +4 -4
  156. package/dist/runtime/api/message-part-runtime.d.ts.map +1 -1
  157. package/dist/runtime/api/message-part-runtime.js +3 -3
  158. package/dist/runtime/api/message-part-runtime.js.map +1 -1
  159. package/dist/runtime/api/message-runtime.d.ts +1 -1
  160. package/dist/runtime/api/message-runtime.d.ts.map +1 -1
  161. package/dist/runtime/api/message-runtime.js +6 -6
  162. package/dist/runtime/api/message-runtime.js.map +1 -1
  163. package/dist/runtime/api/thread-list-item-runtime.d.ts +1 -1
  164. package/dist/runtime/api/thread-list-item-runtime.d.ts.map +1 -1
  165. package/dist/runtime/api/thread-list-item-runtime.js +4 -3
  166. package/dist/runtime/api/thread-list-item-runtime.js.map +1 -1
  167. package/dist/runtime/api/thread-list-runtime.d.ts +1 -1
  168. package/dist/runtime/api/thread-list-runtime.d.ts.map +1 -1
  169. package/dist/runtime/api/thread-list-runtime.js +1 -1
  170. package/dist/runtime/api/thread-list-runtime.js.map +1 -1
  171. package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
  172. package/dist/runtime/base/base-composer-runtime-core.d.ts +4 -1
  173. package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
  174. package/dist/runtime/base/base-composer-runtime-core.js +41 -14
  175. package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
  176. package/dist/runtime/base/base-thread-runtime-core.d.ts +1 -1
  177. package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
  178. package/dist/runtime/base/base-thread-runtime-core.js +3 -2
  179. package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
  180. package/dist/runtime/base/default-edit-composer-runtime-core.d.ts +2 -2
  181. package/dist/runtime/base/default-edit-composer-runtime-core.d.ts.map +1 -1
  182. package/dist/runtime/base/default-edit-composer-runtime-core.js +6 -4
  183. package/dist/runtime/base/default-edit-composer-runtime-core.js.map +1 -1
  184. package/dist/runtime/base/default-thread-composer-runtime-core.d.ts +1 -1
  185. package/dist/runtime/base/default-thread-composer-runtime-core.d.ts.map +1 -1
  186. package/dist/runtime/base/default-thread-composer-runtime-core.js +3 -3
  187. package/dist/runtime/base/default-thread-composer-runtime-core.js.map +1 -1
  188. package/dist/runtime/utils/message-repository.d.ts.map +1 -1
  189. package/dist/runtime/utils/message-repository.js +4 -2
  190. package/dist/runtime/utils/message-repository.js.map +1 -1
  191. package/dist/runtime/utils/thread-message-like.js +4 -1
  192. package/dist/runtime/utils/thread-message-like.js.map +1 -1
  193. package/dist/runtimes/external-store/external-store-runtime-core.d.ts.map +1 -1
  194. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts +1 -1
  195. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts.map +1 -1
  196. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js +1 -1
  197. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js.map +1 -1
  198. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
  199. package/dist/runtimes/external-store/external-store-thread-runtime-core.js +12 -0
  200. package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
  201. package/dist/runtimes/internal.d.ts +2 -1
  202. package/dist/runtimes/internal.js +2 -1
  203. package/dist/runtimes/local/local-runtime-core.d.ts.map +1 -1
  204. package/dist/runtimes/local/local-thread-list-runtime-core.d.ts.map +1 -1
  205. package/dist/runtimes/local/local-thread-runtime-core.d.ts +3 -0
  206. package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
  207. package/dist/runtimes/local/local-thread-runtime-core.js +49 -15
  208. package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
  209. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts.map +1 -1
  210. package/dist/runtimes/remote-thread-list/optimistic-state.d.ts +4 -4
  211. package/dist/runtimes/remote-thread-list/optimistic-state.d.ts.map +1 -1
  212. package/dist/runtimes/remote-thread-list/optimistic-state.js +22 -9
  213. package/dist/runtimes/remote-thread-list/optimistic-state.js.map +1 -1
  214. package/dist/runtimes/remote-thread-list/types.d.ts +1 -1
  215. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts +32 -27
  216. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts.map +1 -1
  217. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js +3 -2
  218. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js.map +1 -1
  219. package/dist/store/clients/chain-of-thought-client.d.ts.map +1 -1
  220. package/dist/store/clients/no-op-composer-client.d.ts.map +1 -1
  221. package/dist/store/clients/no-op-composer-client.js +1 -0
  222. package/dist/store/clients/no-op-composer-client.js.map +1 -1
  223. package/dist/store/runtime-clients/attachment-runtime-client.d.ts.map +1 -1
  224. package/dist/store/runtime-clients/composer-runtime-client.d.ts.map +1 -1
  225. package/dist/store/runtime-clients/message-part-runtime-client.d.ts.map +1 -1
  226. package/dist/store/runtime-clients/message-runtime-client.d.ts.map +1 -1
  227. package/dist/store/runtime-clients/thread-list-item-runtime-client.d.ts.map +1 -1
  228. package/dist/store/runtime-clients/thread-list-runtime-client.d.ts.map +1 -1
  229. package/dist/store/runtime-clients/thread-list-runtime-client.js +1 -0
  230. package/dist/store/runtime-clients/thread-list-runtime-client.js.map +1 -1
  231. package/dist/store/runtime-clients/thread-runtime-client.d.ts.map +1 -1
  232. package/dist/store/runtime-clients/thread-runtime-client.js +17 -15
  233. package/dist/store/runtime-clients/thread-runtime-client.js.map +1 -1
  234. package/dist/store/scopes/thread.d.ts +1 -0
  235. package/dist/store/scopes/thread.d.ts.map +1 -1
  236. package/dist/subscribable/subscribable.d.ts +4 -4
  237. package/dist/subscribable/subscribable.d.ts.map +1 -1
  238. package/dist/subscribable/subscribable.js +14 -6
  239. package/dist/subscribable/subscribable.js.map +1 -1
  240. package/dist/tests/remote-thread-list-test-helpers.d.ts +2 -1
  241. package/dist/tests/remote-thread-list-test-helpers.d.ts.map +1 -1
  242. package/dist/tests/remote-thread-list-test-helpers.js +5 -2
  243. package/dist/tests/remote-thread-list-test-helpers.js.map +1 -1
  244. package/dist/types/attachment.d.ts +2 -1
  245. package/dist/types/attachment.d.ts.map +1 -1
  246. package/dist/types/attachment.js +6 -0
  247. package/dist/types/attachment.js.map +1 -0
  248. package/dist/types/message.d.ts +1 -0
  249. package/dist/types/message.d.ts.map +1 -1
  250. package/dist/types/message.js.map +1 -1
  251. package/dist/utils/data-url.d.ts +9 -0
  252. package/dist/utils/data-url.d.ts.map +1 -0
  253. package/dist/utils/data-url.js +14 -0
  254. package/dist/utils/data-url.js.map +1 -0
  255. package/dist/utils/notify-event-listeners.d.ts +6 -0
  256. package/dist/utils/notify-event-listeners.d.ts.map +1 -0
  257. package/dist/utils/notify-event-listeners.js +16 -0
  258. package/dist/utils/notify-event-listeners.js.map +1 -0
  259. package/package.json +10 -9
  260. package/src/adapters/speech.test.ts +88 -0
  261. package/src/adapters/speech.ts +17 -2
  262. package/src/adapters/thread-history.ts +8 -0
  263. package/src/adapters/voice.test.ts +130 -0
  264. package/src/adapters/voice.ts +26 -6
  265. package/src/internal.ts +6 -1
  266. package/src/model-context/frame/host.test.ts +147 -0
  267. package/src/model-context/frame/host.ts +56 -19
  268. package/src/model-context/frame/provider.test.ts +83 -0
  269. package/src/model-context/frame/provider.ts +1 -0
  270. package/src/model-context/types.ts +16 -6
  271. package/src/react/adapters/LocalStorageThreadListAdapter.test.ts +82 -0
  272. package/src/react/adapters/LocalStorageThreadListAdapter.tsx +108 -58
  273. package/src/react/primitive-hooks/useActionBarCopy.test.ts +79 -0
  274. package/src/react/primitive-hooks/useActionBarCopy.ts +4 -3
  275. package/src/react/primitives/chainOfThought/ChainOfThoughtParts.tsx +1 -3
  276. package/src/react/primitives/message/MessageParts.tsx +48 -35
  277. package/src/react/providers/ChainOfThoughtPartByIndexProvider.tsx +19 -2
  278. package/src/react/providers/PartByIndexProvider.tsx +16 -2
  279. package/src/react/runtimes/RemoteThreadListHookInstanceManager.test.tsx +18 -0
  280. package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +1 -0
  281. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +68 -13
  282. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.ts +34 -0
  283. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.tsx +69 -0
  284. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +27 -6
  285. package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.test.ts +16 -0
  286. package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.ts +7 -2
  287. package/src/react/runtimes/cloud/auiV0.ts +14 -0
  288. package/src/react/runtimes/cloud/useCloudThreadListAdapter.tsx +90 -88
  289. package/src/react/runtimes/external-message-converter.test.ts +346 -0
  290. package/src/react/runtimes/external-message-converter.test.tsx +21 -0
  291. package/src/react/runtimes/external-message-converter.ts +2 -2
  292. package/src/react/runtimes/useLocalRuntime.test.tsx +99 -0
  293. package/src/react/runtimes/useLocalRuntime.ts +13 -1
  294. package/src/runtime/api/assistant-runtime.ts +4 -1
  295. package/src/runtime/api/attachment-runtime.ts +8 -2
  296. package/src/runtime/api/composer-runtime.ts +9 -5
  297. package/src/runtime/api/message-part-runtime.ts +10 -3
  298. package/src/runtime/api/message-runtime.test.ts +81 -0
  299. package/src/runtime/api/message-runtime.ts +11 -8
  300. package/src/runtime/api/thread-list-item-runtime.ts +13 -3
  301. package/src/runtime/api/thread-list-runtime.ts +10 -2
  302. package/src/runtime/base/base-composer-runtime-core.ts +77 -31
  303. package/src/runtime/base/base-thread-runtime-core.ts +7 -2
  304. package/src/runtime/base/default-edit-composer-runtime-core.ts +18 -4
  305. package/src/runtime/base/default-thread-composer-runtime-core.ts +13 -3
  306. package/src/runtime/utils/message-repository.ts +19 -13
  307. package/src/runtime/utils/thread-message-like.ts +1 -0
  308. package/src/runtimes/external-store/external-store-thread-list-runtime-core.ts +4 -1
  309. package/src/runtimes/external-store/external-store-thread-runtime-core.ts +15 -0
  310. package/src/runtimes/internal.ts +3 -0
  311. package/src/runtimes/local/local-thread-runtime-core.test.ts +746 -1
  312. package/src/runtimes/local/local-thread-runtime-core.ts +89 -23
  313. package/src/runtimes/local/should-continue.test.ts +122 -0
  314. package/src/runtimes/remote-thread-list/optimistic-state.test.ts +63 -0
  315. package/src/runtimes/remote-thread-list/optimistic-state.ts +49 -17
  316. package/src/runtimes/remote-thread-list/types.ts +1 -1
  317. package/src/runtimes/tool-invocations/EDGE_CASES.md +13 -19
  318. package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +128 -8
  319. package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +42 -34
  320. package/src/store/clients/model-context-client.test.ts +21 -1
  321. package/src/store/runtime-clients/thread-runtime-client.ts +2 -1
  322. package/src/store/scopes/thread.ts +1 -0
  323. package/src/subscribable/subscribable.test.ts +58 -0
  324. package/src/subscribable/subscribable.ts +29 -11
  325. package/src/tests/MessageRepository.test.ts +12 -0
  326. package/src/tests/OptimisticState-list-race.test.ts +33 -0
  327. package/src/tests/RemoteThreadListThreadListRuntimeCore-switchToThread-order.test.ts +223 -0
  328. package/src/tests/RemoteThreadListThreadListRuntimeCore-switchToThread-position.test.ts +121 -0
  329. package/src/tests/auiV0Encode.test.ts +74 -0
  330. package/src/tests/base-composer-runtime-core-addAttachment.test.ts +44 -0
  331. package/src/tests/base-composer-runtime-core-send.test.ts +433 -5
  332. package/src/tests/base-composer-runtime-core.test.ts +422 -0
  333. package/src/tests/default-edit-composer-runtime-core.test.ts +43 -5
  334. package/src/tests/event-subscription-listener-errors.test.ts +205 -0
  335. package/src/tests/external-store-thread-list-runtime-core.test.ts +6 -6
  336. package/src/tests/external-store-thread-runtime-core-adapter.test.ts +575 -0
  337. package/src/tests/external-store-thread-runtime-core.test.ts +55 -1
  338. package/src/tests/remote-thread-list-test-helpers.ts +14 -7
  339. package/src/tests/thread-message-like.test.ts +57 -0
  340. package/src/types/attachment.ts +5 -0
  341. package/src/types/message.ts +1 -0
  342. package/src/utils/data-url.test.ts +50 -0
  343. package/src/utils/data-url.ts +9 -0
  344. package/src/utils/notify-event-listeners.ts +30 -0
  345. package/src/tests/OptimisticState-delete-crash.test.ts +0 -208
@@ -1 +1 @@
1
- {"version":3,"file":"interactable-composer-metadata.js","names":["isJSONValueEqual","isJSONValue","isRecord","Unstable_InteractableSnapshotEntry","id","name","state","partial","SnapshotCarrierMessage","role","metadata","content","unstable_getInteractableSnapshots","message","undefined","custom","Record","items","interactables","Array","isArray","unstable_formatInteractableSnapshot","entry","JSON","stringify","interactableToolName","replace","getArrayItemId","item","applyArrayUpdate","prev","update","mintId","next","set","clear","remove","length","ids","Set","filter","has","patches","map","patch","find","candidate","add","added","shallowMergeInteractableState","options","arrayBaseline","idFactory","field","idKeyedFields","ReadonlySet","baseline","key","value","Object","entries","baseValue","shallowDiffInteractableState","known","keys","diff","changed","ToolCallLikePart","type","toolCallId","toolName","args","result","asToolCallPart","part","p","updateCallTargets","success","argsId","createAddedItemIdFactory","addedItemIds","idsByField","Map","stringIds","size","get","shift","Unstable_InteractableVersion","origin","versionsCache","WeakMap","unstable_getInteractableVersions","messages","byName","byId","cached","versions","current","msg","it","push","_id","findModelKnownState","last","gateInteractableComposerMetadata","meta","rest","gated","pending","process","env","NODE_ENV","console","warn"],"sources":["../../src/model-context/interactable-composer-metadata.ts"],"sourcesContent":["import { isJSONValueEqual } from \"../utils/json/is-json-equal\";\nimport { isJSONValue, isRecord } from \"../utils/json/is-json\";\n\n/**\n * Unstable / Experimental — the interactables API is still evolving and may change in any release.\n * @deprecated Unstable / Experimental (not actually removed).\n */\nexport type Unstable_InteractableSnapshotEntry = {\n id: string;\n name: string;\n state: unknown;\n /**\n * When true, `state` carries only the top-level fields that changed since\n * the model's last known state; omitted fields are unchanged. The first\n * snapshot of an instance is always full.\n */\n partial?: boolean | undefined;\n};\n\n/**\n * Minimal message shape needed to read snapshots and `update_*` tool calls out\n * of history. Structurally compatible with both `ThreadMessage` and the AI\n * SDK's `UIMessage`.\n */\ntype SnapshotCarrierMessage = {\n role: string;\n metadata?: unknown;\n content?: readonly unknown[] | undefined;\n};\n\n/**\n * Reads the interactable snapshots stamped on a message's\n * `metadata.custom.interactables`, or `undefined` if none. This is the read\n * half of the snapshot channel — integrations use it to surface interactable\n * state to the model (see `unstable_injectInteractableContext` in\n * `@assistant-ui/react-ai-sdk` for the AI SDK implementation).\n *\n * @deprecated Unstable / Experimental (not actually removed).\n */\nexport function unstable_getInteractableSnapshots(message: {\n metadata?: unknown;\n}): Unstable_InteractableSnapshotEntry[] | undefined {\n const metadata = message.metadata;\n if (!metadata || typeof metadata !== \"object\") return undefined;\n const custom = (metadata as Record<string, unknown>).custom;\n if (!custom || typeof custom !== \"object\") return undefined;\n const items = (custom as Record<string, unknown>).interactables;\n return Array.isArray(items)\n ? (items as Unstable_InteractableSnapshotEntry[])\n : undefined;\n}\n\n/**\n * Canonical model-facing wording for one snapshot entry.\n *\n * @deprecated Unstable / Experimental (not actually removed).\n */\nexport function unstable_formatInteractableSnapshot(\n entry: Unstable_InteractableSnapshotEntry,\n): string {\n if (entry.partial) {\n return `[State of \"${entry.name}\" (id: ${JSON.stringify(entry.id)}) changed — updated fields: ${JSON.stringify(entry.state)}; fields not listed are unchanged]`;\n }\n return `[Current state of \"${entry.name}\" (id: ${JSON.stringify(entry.id)}): ${JSON.stringify(entry.state)}]`;\n}\n\n/** The model-facing tool name for an interactable `name`. One tool per name. */\nexport function interactableToolName(name: string): string {\n return `update_${name.replace(/[^a-zA-Z0-9_-]/g, \"_\")}`;\n}\n\nconst getArrayItemId = (item: unknown): string | number | undefined => {\n if (!isRecord(item)) return undefined;\n const id = item.id;\n return typeof id === \"string\" || typeof id === \"number\" ? id : undefined;\n};\n\nfunction applyArrayUpdate(\n prev: unknown[],\n update: Record<string, unknown>,\n mintId?: () => string | undefined,\n) {\n let next = Array.isArray(update.set) ? [...update.set] : [...prev];\n\n if (update.clear === true) next = [];\n\n if (Array.isArray(update.remove) && update.remove.length > 0) {\n const ids = new Set(update.remove);\n next = next.filter((item) => {\n const id = getArrayItemId(item);\n return id !== undefined ? !ids.has(id) : !ids.has(item);\n });\n }\n\n const patches = update.update;\n if (Array.isArray(patches) && patches.length > 0) {\n next = next.map((item) => {\n const id = getArrayItemId(item);\n if (id === undefined || !isRecord(item)) return item;\n const patch = patches.find(\n (candidate) => isRecord(candidate) && candidate.id === id,\n );\n return patch ? { ...item, ...patch } : item;\n });\n }\n\n if (Array.isArray(update.add) && update.add.length > 0) {\n const added = mintId\n ? update.add.map((item) => {\n if (!isRecord(item) || item.id !== undefined) return item;\n const id = mintId();\n return id === undefined ? item : { ...item, id };\n })\n : update.add;\n next = [...next, ...added];\n }\n\n return next;\n}\n\n/**\n * The merge `update_*` tools apply: top-level keys replace, rest preserved.\n * Array fields also accept operation objects (`add`, `update`, `remove`,\n * `clear`, `set`) so collection edits do not need a companion manage_* tool.\n */\nexport function shallowMergeInteractableState(\n prev: unknown,\n partial: unknown,\n options?:\n | {\n arrayBaseline?: unknown;\n /**\n * Supplies ids for added items in id-keyed array fields. The live\n * execute path mints fresh ids; history folds replay ids previously\n * returned by execute.\n */\n idFactory?: (field: string) => string | undefined;\n idKeyedFields?: ReadonlySet<string>;\n }\n | undefined,\n): unknown {\n if (!isRecord(prev) || !isRecord(partial)) return partial;\n const baseline = isRecord(options?.arrayBaseline)\n ? options.arrayBaseline\n : prev;\n const next = { ...prev };\n for (const [key, value] of Object.entries(partial)) {\n const baseValue = baseline[key];\n if (Array.isArray(baseValue) && isRecord(value)) {\n const mintId =\n options?.idFactory &&\n (options.idKeyedFields === undefined || options.idKeyedFields.has(key))\n ? () => options.idFactory?.(key)\n : undefined;\n next[key] = applyArrayUpdate(baseValue, value, mintId);\n } else {\n next[key] = value;\n }\n }\n return next;\n}\n\n/**\n * The top-level fields of `next` that differ from `known`, for stamping a\n * partial snapshot. Returns `undefined` when a partial stamp has no benefit:\n * the change is not expressible as a shallow merge (non-object states, or a\n * top-level key was removed), or every field changed anyway — the caller\n * falls back to a full snapshot.\n */\nfunction shallowDiffInteractableState(\n known: unknown,\n next: unknown,\n): Record<string, unknown> | undefined {\n if (!isRecord(known) || !isRecord(next)) return undefined;\n for (const key of Object.keys(known)) {\n if (!(key in next)) return undefined;\n }\n const diff: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(next)) {\n if (!(key in known) || !isJSONValueEqual(known[key], value)) {\n diff[key] = value;\n }\n }\n const changed = Object.keys(diff).length;\n if (changed === 0 || changed === Object.keys(next).length) return undefined;\n return diff;\n}\n\ntype ToolCallLikePart = {\n type?: string;\n toolCallId?: string;\n toolName?: string;\n args?: unknown;\n result?: unknown;\n};\n\nconst asToolCallPart = (part: unknown): ToolCallLikePart | undefined => {\n if (!part || typeof part !== \"object\") return undefined;\n const p = part as ToolCallLikePart;\n return p.type === \"tool-call\" ? p : undefined;\n};\n\n/** Whether an accepted `update_*` call addressed instance `id`. */\nconst updateCallTargets = (p: ToolCallLikePart, id: string): boolean => {\n if (!p.args || typeof p.args !== \"object\") return false;\n const result = isRecord(p.result) ? p.result : undefined;\n if (result?.success === false) return false;\n if (typeof result?.id === \"string\") return result.id === id;\n const argsId = (p.args as Record<string, unknown>).id;\n return argsId === id || argsId === undefined;\n};\n\nconst createAddedItemIdFactory = (result: unknown) => {\n const value = isRecord(result) ? result.addedItemIds : undefined;\n if (!isRecord(value)) return undefined;\n\n const idsByField = new Map<string, string[]>();\n for (const [field, ids] of Object.entries(value)) {\n if (!Array.isArray(ids)) continue;\n const stringIds = ids.filter(\n (item): item is string => typeof item === \"string\",\n );\n if (stringIds.length > 0) idsByField.set(field, stringIds);\n }\n if (idsByField.size === 0) return undefined;\n\n return (field: string) => idsByField.get(field)?.shift();\n};\n\n/**\n * Unstable / Experimental — the interactables API is still evolving and may change in any release.\n * @deprecated Unstable / Experimental (not actually removed).\n */\nexport type Unstable_InteractableVersion = {\n /** The full state as of this version. */\n state: unknown;\n origin: \"create\" | \"update\" | \"user-edit\";\n /** For create/update versions, the tool call that produced this version. */\n toolCallId?: string | undefined;\n};\n\n// Without this, every mounted anchor re-folds the whole thread on each streaming\n// token, since the repository hands out a new messages array per token.\nconst versionsCache = new WeakMap<\n readonly SnapshotCarrierMessage[],\n Map<string, Map<string, Unstable_InteractableVersion[]>>\n>();\n\n/**\n * Every version of interactable `id` recorded in the thread, oldest first,\n * folded chronologically:\n *\n * - the tool call whose `toolCallId` equals `id` seeds the baseline with its\n * args (`origin: \"create\"`) — the `id: toolCallId` convention for\n * tool-created interactables,\n * - a snapshot stamped on a user message is a `\"user-edit\"` version (a full\n * snapshot replaces the state; a partial one shallow-merges),\n * - each accepted `update_*` call shallow-merges an `\"update\"` version.\n *\n * The last entry is the state the model knows. Partial snapshots and update\n * calls with no baseline to merge into are skipped.\n *\n * @deprecated Unstable / Experimental (not actually removed).\n */\nexport function unstable_getInteractableVersions(\n messages: readonly SnapshotCarrierMessage[],\n id: string,\n name: string,\n): Unstable_InteractableVersion[] {\n let byName = versionsCache.get(messages);\n if (!byName) {\n byName = new Map();\n versionsCache.set(messages, byName);\n }\n let byId = byName.get(name);\n if (!byId) {\n byId = new Map();\n byName.set(name, byId);\n }\n const cached = byId.get(id);\n if (cached) return cached;\n\n const toolName = interactableToolName(name);\n const versions: Unstable_InteractableVersion[] = [];\n const current = () => versions[versions.length - 1];\n\n for (const msg of messages) {\n if (msg.role === \"user\") {\n const entry = unstable_getInteractableSnapshots(msg)?.find(\n (it) => it.id === id,\n );\n if (!entry) continue;\n if (entry.partial) {\n const prev = current();\n if (prev) {\n versions.push({\n state: shallowMergeInteractableState(prev.state, entry.state),\n origin: \"user-edit\",\n });\n }\n } else {\n versions.push({ state: entry.state, origin: \"user-edit\" });\n }\n continue;\n }\n\n if (msg.role !== \"assistant\") continue;\n for (const part of msg.content ?? []) {\n const p = asToolCallPart(part);\n if (!p) continue;\n if (p.toolCallId === id && p.toolName === name) {\n if (p.args && typeof p.args === \"object\") {\n versions.push({ state: p.args, origin: \"create\", toolCallId: id });\n }\n } else if (p.toolName === toolName && updateCallTargets(p, id)) {\n const prev = current();\n if (prev) {\n const { id: _id, ...partial } = p.args as Record<string, unknown>;\n const idFactory = createAddedItemIdFactory(p.result);\n versions.push({\n state: idFactory\n ? shallowMergeInteractableState(prev.state, partial, {\n idFactory,\n })\n : shallowMergeInteractableState(prev.state, partial),\n origin: \"update\",\n toolCallId: p.toolCallId,\n });\n }\n }\n }\n }\n byId.set(id, versions);\n return versions;\n}\n\n/**\n * The state the model knows for interactable `id` — its latest recorded\n * version, or `undefined` when no baseline exists yet.\n */\nexport function findModelKnownState(\n messages: readonly SnapshotCarrierMessage[],\n id: string,\n name: string,\n): { state: unknown } | undefined {\n const versions = unstable_getInteractableVersions(messages, id, name);\n const last = versions[versions.length - 1];\n return last ? { state: last.state } : undefined;\n}\n\n/**\n * Snapshot gate. Stamps an interactable only when the model doesn't already\n * know its state (no baseline yet, or the live state differs from the folded\n * thread record). A change that fits a shallow merge is stamped as a partial\n * snapshot carrying just the changed fields; otherwise the full state is\n * stamped. Other metadata keys pass through untouched.\n */\nexport function gateInteractableComposerMetadata(\n meta: Record<string, unknown> | undefined,\n messages: readonly SnapshotCarrierMessage[],\n): Record<string, unknown> | undefined {\n if (!meta) return undefined;\n const { interactables, ...rest } = meta as {\n interactables?: Unstable_InteractableSnapshotEntry[];\n } & Record<string, unknown>;\n\n const gated: Record<string, unknown> = { ...rest };\n if (Array.isArray(interactables)) {\n const pending: Unstable_InteractableSnapshotEntry[] = [];\n for (const it of interactables) {\n if (process.env.NODE_ENV !== \"production\" && !isJSONValue(it.state)) {\n console.warn(\n `[Interactables] state for \"${it.name}\" (${it.id}) is not JSON-equatable ` +\n `(an undefined, NaN, Infinity, function, or symbol value?). It will be ` +\n `re-snapshotted on every send, recreating per-message growth. Use plain ` +\n `JSON values.`,\n );\n }\n const known = findModelKnownState(messages, it.id, it.name);\n if (!known) {\n pending.push({ id: it.id, name: it.name, state: it.state });\n continue;\n }\n if (isJSONValueEqual(it.state, known.state)) continue;\n const diff = shallowDiffInteractableState(known.state, it.state);\n pending.push(\n diff\n ? { id: it.id, name: it.name, state: diff, partial: true }\n : { id: it.id, name: it.name, state: it.state },\n );\n }\n if (pending.length) gated.interactables = pending;\n }\n return Object.keys(gated).length ? gated : undefined;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"interactable-composer-metadata.js","names":["isJSONValueEqual","isJSONValue","isRecord","Unstable_InteractableSnapshotEntry","id","name","state","partial","SnapshotCarrierMessage","role","metadata","content","unstable_getInteractableSnapshots","message","undefined","custom","Record","items","interactables","Array","isArray","unstable_formatInteractableSnapshot","entry","JSON","stringify","interactableToolName","replace","getArrayItemId","item","applyArrayUpdate","prev","update","mintId","next","set","clear","remove","length","ids","Set","filter","has","patches","map","patch","find","candidate","add","added","shallowMergeInteractableState","options","arrayBaseline","idFactory","field","idKeyedFields","ReadonlySet","baseline","key","value","Object","entries","baseValue","shallowDiffInteractableState","known","keys","diff","changed","ToolCallLikePart","type","toolCallId","toolName","args","result","asToolCallPart","part","p","updateCallTargets","success","argsId","createAddedItemIdFactory","addedItemIds","idsByField","Map","stringIds","size","get","shift","Unstable_InteractableVersion","origin","versionsCache","WeakMap","unstable_getInteractableVersions","messages","byName","byId","cached","versions","current","msg","it","push","_id","findModelKnownState","last","gateInteractableComposerMetadata","meta","rest","gated","pending","process","env","NODE_ENV","console","warn"],"sources":["../../src/model-context/interactable-composer-metadata.ts"],"sourcesContent":["import { isJSONValueEqual } from \"../utils/json/is-json-equal\";\nimport { isJSONValue, isRecord } from \"../utils/json/is-json\";\n\n/**\n * Unstable / Experimental — the interactables API is still evolving and may change in any release.\n * @deprecated Unstable / Experimental (not actually removed).\n */\nexport type Unstable_InteractableSnapshotEntry = {\n id: string;\n name: string;\n state: unknown;\n /**\n * When true, `state` carries only the top-level fields that changed since\n * the model's last known state; omitted fields are unchanged. The first\n * snapshot of an instance is always full.\n */\n partial?: boolean | undefined;\n};\n\n/**\n * Minimal message shape needed to read snapshots and `update_*` tool calls out\n * of history. Structurally compatible with both `ThreadMessage` and the AI\n * SDK's `UIMessage`.\n */\ntype SnapshotCarrierMessage = {\n role: string;\n metadata?: unknown;\n content?: readonly unknown[] | undefined;\n};\n\n/**\n * Reads the interactable snapshots stamped on a message's\n * `metadata.custom.interactables`, or `undefined` if none. This is the read\n * half of the snapshot channel — integrations use it to surface interactable\n * state to the model (see `unstable_injectInteractableContext` in\n * `@assistant-ui/react-ai-sdk` for the AI SDK implementation).\n *\n * @deprecated Unstable / Experimental (not actually removed).\n */\nexport function unstable_getInteractableSnapshots(message: {\n metadata?: unknown;\n}): Unstable_InteractableSnapshotEntry[] | undefined {\n const metadata = message.metadata;\n if (!metadata || typeof metadata !== \"object\") return undefined;\n const custom = (metadata as Record<string, unknown>).custom;\n if (!custom || typeof custom !== \"object\") return undefined;\n const items = (custom as Record<string, unknown>).interactables;\n return Array.isArray(items)\n ? (items as Unstable_InteractableSnapshotEntry[])\n : undefined;\n}\n\n/**\n * Canonical model-facing wording for one snapshot entry.\n *\n * @deprecated Unstable / Experimental (not actually removed).\n */\nexport function unstable_formatInteractableSnapshot(\n entry: Unstable_InteractableSnapshotEntry,\n): string {\n if (entry.partial) {\n return `[State of \"${entry.name}\" (id: ${JSON.stringify(entry.id)}) changed — updated fields: ${JSON.stringify(entry.state)}; fields not listed are unchanged]`;\n }\n return `[Current state of \"${entry.name}\" (id: ${JSON.stringify(entry.id)}): ${JSON.stringify(entry.state)}]`;\n}\n\n/** The model-facing tool name for an interactable `name`. One tool per name. */\nexport function interactableToolName(name: string): string {\n return `update_${name.replace(/[^a-zA-Z0-9_-]/g, \"_\")}`;\n}\n\nconst getArrayItemId = (item: unknown): string | number | undefined => {\n if (!isRecord(item)) return undefined;\n const id = item.id;\n return typeof id === \"string\" || typeof id === \"number\" ? id : undefined;\n};\n\nfunction applyArrayUpdate(\n prev: unknown[],\n update: Record<string, unknown>,\n mintId?: () => string | undefined,\n) {\n let next = Array.isArray(update.set) ? [...update.set] : [...prev];\n\n if (update.clear === true) next = [];\n\n if (Array.isArray(update.remove) && update.remove.length > 0) {\n const ids = new Set(update.remove);\n next = next.filter((item) => {\n const id = getArrayItemId(item);\n return id !== undefined ? !ids.has(id) : !ids.has(item);\n });\n }\n\n const patches = update.update;\n if (Array.isArray(patches) && patches.length > 0) {\n next = next.map((item) => {\n const id = getArrayItemId(item);\n if (id === undefined || !isRecord(item)) return item;\n const patch = patches.find(\n (candidate) => isRecord(candidate) && candidate.id === id,\n );\n return patch ? { ...item, ...patch } : item;\n });\n }\n\n if (Array.isArray(update.add) && update.add.length > 0) {\n const added = mintId\n ? update.add.map((item) => {\n if (!isRecord(item) || item.id !== undefined) return item;\n const id = mintId();\n return id === undefined ? item : { ...item, id };\n })\n : update.add;\n next = [...next, ...added];\n }\n\n return next;\n}\n\n/**\n * The merge `update_*` tools apply: top-level keys replace, rest preserved.\n * Array fields also accept operation objects (`add`, `update`, `remove`,\n * `clear`, `set`) so collection edits do not need a companion manage_* tool.\n */\nexport function shallowMergeInteractableState(\n prev: unknown,\n partial: unknown,\n options?:\n | {\n arrayBaseline?: unknown;\n /**\n * Supplies ids for added items in id-keyed array fields. The live\n * execute path mints fresh ids; history folds replay ids previously\n * returned by execute.\n */\n idFactory?: (field: string) => string | undefined;\n idKeyedFields?: ReadonlySet<string>;\n }\n | undefined,\n): unknown {\n if (!isRecord(prev) || !isRecord(partial)) return partial;\n const baseline = isRecord(options?.arrayBaseline)\n ? options.arrayBaseline\n : prev;\n const next = { ...prev };\n for (const [key, value] of Object.entries(partial)) {\n const baseValue = baseline[key];\n if (Array.isArray(baseValue) && isRecord(value)) {\n const mintId =\n options?.idFactory &&\n (options.idKeyedFields === undefined || options.idKeyedFields.has(key))\n ? () => options.idFactory?.(key)\n : undefined;\n next[key] = applyArrayUpdate(baseValue, value, mintId);\n } else {\n next[key] = value;\n }\n }\n return next;\n}\n\n/**\n * The top-level fields of `next` that differ from `known`, for stamping a\n * partial snapshot. Returns `undefined` when a partial stamp has no benefit:\n * the change is not expressible as a shallow merge (non-object states, or a\n * top-level key was removed), or every field changed anyway — the caller\n * falls back to a full snapshot.\n */\nfunction shallowDiffInteractableState(\n known: unknown,\n next: unknown,\n): Record<string, unknown> | undefined {\n if (!isRecord(known) || !isRecord(next)) return undefined;\n for (const key of Object.keys(known)) {\n if (!(key in next)) return undefined;\n }\n const diff: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(next)) {\n if (!(key in known) || !isJSONValueEqual(known[key], value)) {\n diff[key] = value;\n }\n }\n const changed = Object.keys(diff).length;\n if (changed === 0 || changed === Object.keys(next).length) return undefined;\n return diff;\n}\n\ntype ToolCallLikePart = {\n type?: string;\n toolCallId?: string;\n toolName?: string;\n args?: unknown;\n result?: unknown;\n};\n\nconst asToolCallPart = (part: unknown): ToolCallLikePart | undefined => {\n if (!part || typeof part !== \"object\") return undefined;\n const p = part as ToolCallLikePart;\n return p.type === \"tool-call\" ? p : undefined;\n};\n\n/** Whether an accepted `update_*` call addressed instance `id`. */\nconst updateCallTargets = (p: ToolCallLikePart, id: string): boolean => {\n if (!p.args || typeof p.args !== \"object\") return false;\n const result = isRecord(p.result) ? p.result : undefined;\n if (result?.success === false) return false;\n if (typeof result?.id === \"string\") return result.id === id;\n const argsId = (p.args as Record<string, unknown>).id;\n return argsId === id || argsId === undefined;\n};\n\nconst createAddedItemIdFactory = (result: unknown) => {\n const value = isRecord(result) ? result.addedItemIds : undefined;\n if (!isRecord(value)) return undefined;\n\n const idsByField = new Map<string, string[]>();\n for (const [field, ids] of Object.entries(value)) {\n if (!Array.isArray(ids)) continue;\n const stringIds = ids.filter(\n (item): item is string => typeof item === \"string\",\n );\n if (stringIds.length > 0) idsByField.set(field, stringIds);\n }\n if (idsByField.size === 0) return undefined;\n\n return (field: string) => idsByField.get(field)?.shift();\n};\n\n/**\n * Unstable / Experimental — the interactables API is still evolving and may change in any release.\n * @deprecated Unstable / Experimental (not actually removed).\n */\nexport type Unstable_InteractableVersion = {\n /** The full state as of this version. */\n state: unknown;\n origin: \"create\" | \"update\" | \"user-edit\";\n /** For create/update versions, the tool call that produced this version. */\n toolCallId?: string | undefined;\n};\n\n// Without this, every mounted anchor re-folds the whole thread on each streaming\n// token, since the repository hands out a new messages array per token.\nconst versionsCache = new WeakMap<\n readonly SnapshotCarrierMessage[],\n Map<string, Map<string, Unstable_InteractableVersion[]>>\n>();\n\n/**\n * Every version of interactable `id` recorded in the thread, oldest first,\n * folded chronologically:\n *\n * - the tool call whose `toolCallId` equals `id` seeds the baseline with its\n * args (`origin: \"create\"`) — the `id: toolCallId` convention for\n * tool-created interactables,\n * - a snapshot stamped on a user message is a `\"user-edit\"` version (a full\n * snapshot replaces the state; a partial one shallow-merges),\n * - each accepted `update_*` call shallow-merges an `\"update\"` version.\n *\n * The last entry is the state the model knows. Partial snapshots and update\n * calls with no baseline to merge into are skipped.\n *\n * @deprecated Unstable / Experimental (not actually removed).\n */\nexport function unstable_getInteractableVersions(\n messages: readonly SnapshotCarrierMessage[],\n id: string,\n name: string,\n): Unstable_InteractableVersion[] {\n let byName = versionsCache.get(messages);\n if (!byName) {\n byName = new Map();\n versionsCache.set(messages, byName);\n }\n let byId = byName.get(name);\n if (!byId) {\n byId = new Map();\n byName.set(name, byId);\n }\n const cached = byId.get(id);\n if (cached) return cached;\n\n const toolName = interactableToolName(name);\n const versions: Unstable_InteractableVersion[] = [];\n const current = () => versions[versions.length - 1];\n\n for (const msg of messages) {\n if (msg.role === \"user\") {\n const entry = unstable_getInteractableSnapshots(msg)?.find(\n (it) => it.id === id,\n );\n if (!entry) continue;\n if (entry.partial) {\n const prev = current();\n if (prev) {\n versions.push({\n state: shallowMergeInteractableState(prev.state, entry.state),\n origin: \"user-edit\",\n });\n }\n } else {\n versions.push({ state: entry.state, origin: \"user-edit\" });\n }\n continue;\n }\n\n if (msg.role !== \"assistant\") continue;\n for (const part of msg.content ?? []) {\n const p = asToolCallPart(part);\n if (!p) continue;\n if (p.toolCallId === id && p.toolName === name) {\n if (p.args && typeof p.args === \"object\") {\n versions.push({ state: p.args, origin: \"create\", toolCallId: id });\n }\n } else if (p.toolName === toolName && updateCallTargets(p, id)) {\n const prev = current();\n if (prev) {\n const { id: _id, ...partial } = p.args as Record<string, unknown>;\n const idFactory = createAddedItemIdFactory(p.result);\n versions.push({\n state: idFactory\n ? shallowMergeInteractableState(prev.state, partial, {\n idFactory,\n })\n : shallowMergeInteractableState(prev.state, partial),\n origin: \"update\",\n toolCallId: p.toolCallId,\n });\n }\n }\n }\n }\n byId.set(id, versions);\n return versions;\n}\n\n/**\n * The state the model knows for interactable `id` — its latest recorded\n * version, or `undefined` when no baseline exists yet.\n */\nexport function findModelKnownState(\n messages: readonly SnapshotCarrierMessage[],\n id: string,\n name: string,\n): { state: unknown } | undefined {\n const versions = unstable_getInteractableVersions(messages, id, name);\n const last = versions[versions.length - 1];\n return last ? { state: last.state } : undefined;\n}\n\n/**\n * Snapshot gate. Stamps an interactable only when the model doesn't already\n * know its state (no baseline yet, or the live state differs from the folded\n * thread record). A change that fits a shallow merge is stamped as a partial\n * snapshot carrying just the changed fields; otherwise the full state is\n * stamped. Other metadata keys pass through untouched.\n */\nexport function gateInteractableComposerMetadata(\n meta: Record<string, unknown> | undefined,\n messages: readonly SnapshotCarrierMessage[],\n): Record<string, unknown> | undefined {\n if (!meta) return undefined;\n const { interactables, ...rest } = meta as {\n interactables?: Unstable_InteractableSnapshotEntry[];\n } & Record<string, unknown>;\n\n const gated: Record<string, unknown> = { ...rest };\n if (Array.isArray(interactables)) {\n const pending: Unstable_InteractableSnapshotEntry[] = [];\n for (const it of interactables) {\n if (process.env.NODE_ENV !== \"production\" && !isJSONValue(it.state)) {\n console.warn(\n `[Interactables] state for \"${it.name}\" (${it.id}) is not JSON-equatable ` +\n `(an undefined, NaN, Infinity, function, or symbol value?). It will be ` +\n `re-snapshotted on every send, recreating per-message growth. Use plain ` +\n `JSON values.`,\n );\n }\n const known = findModelKnownState(messages, it.id, it.name);\n if (!known) {\n pending.push({ id: it.id, name: it.name, state: it.state });\n continue;\n }\n if (isJSONValueEqual(it.state, known.state)) continue;\n const diff = shallowDiffInteractableState(known.state, it.state);\n pending.push(\n diff\n ? { id: it.id, name: it.name, state: diff, partial: true }\n : { id: it.id, name: it.name, state: it.state },\n );\n }\n if (pending.length) gated.interactables = pending;\n }\n return Object.keys(gated).length ? gated : undefined;\n}\n"],"mappings":";;;;;;;;;;;;AAuCA,SAAgBY,kCAAkCC,SAEG;CACnD,MAAMH,WAAWG,QAAQH;CACzB,IAAI,CAACA,YAAY,OAAOA,aAAa,UAAU,OAAOI,KAAAA;CACtD,MAAMC,SAAUL,SAAqCK;CACrD,IAAI,CAACA,UAAU,OAAOA,WAAW,UAAU,OAAOD,KAAAA;CAClD,MAAMG,QAASF,OAAmCG;CAClD,OAAOC,MAAMC,QAAQH,KAAK,IACrBA,QACDH,KAAAA;AACN;;;;;;AAOA,SAAgBO,oCACdC,OACQ;CACR,IAAIA,MAAMf,SACR,OAAO,cAAce,MAAMjB,KAAI,SAAUkB,KAAKC,UAAUF,MAAMlB,EAAE,EAAC,8BAA+BmB,KAAKC,UAAUF,MAAMhB,KAAK,EAAC;CAE7H,OAAO,sBAAsBgB,MAAMjB,KAAI,SAAUkB,KAAKC,UAAUF,MAAMlB,EAAE,EAAC,KAAMmB,KAAKC,UAAUF,MAAMhB,KAAK,EAAC;AAC5G;;AAGA,SAAgBmB,qBAAqBpB,MAAsB;CACzD,OAAO,UAAUA,KAAKqB,QAAQ,mBAAmB,GAAG;AACtD;AAEA,MAAMC,kBAAkBC,SAA+C;CACrE,IAAI,CAAC1B,SAAS0B,IAAI,GAAG,OAAOd,KAAAA;CAC5B,MAAMV,KAAKwB,KAAKxB;CAChB,OAAO,OAAOA,OAAO,YAAY,OAAOA,OAAO,WAAWA,KAAKU,KAAAA;AACjE;AAEA,SAASe,iBACPC,MACAC,QACAC,QACA;CACA,IAAIC,OAAOd,MAAMC,QAAQW,OAAOG,GAAG,IAAI,CAAC,GAAGH,OAAOG,GAAG,IAAI,CAAC,GAAGJ,IAAI;CAEjE,IAAIC,OAAOI,UAAU,MAAMF,OAAO,CAAA;CAElC,IAAId,MAAMC,QAAQW,OAAOK,MAAM,KAAKL,OAAOK,OAAOC,SAAS,GAAG;EAC5D,MAAMC,MAAM,IAAIC,IAAIR,OAAOK,MAAM;EACjCH,OAAOA,KAAKO,QAAQZ,SAAS;GAC3B,MAAMxB,KAAKuB,eAAeC,IAAI;GAC9B,OAAOxB,OAAOU,KAAAA,IAAY,CAACwB,IAAIG,IAAIrC,EAAE,IAAI,CAACkC,IAAIG,IAAIb,IAAI;EACxD,CAAC;CACH;CAEA,MAAMc,UAAUX,OAAOA;CACvB,IAAIZ,MAAMC,QAAQsB,OAAO,KAAKA,QAAQL,SAAS,GAC7CJ,OAAOA,KAAKU,KAAKf,SAAS;EACxB,MAAMxB,KAAKuB,eAAeC,IAAI;EAC9B,IAAIxB,OAAOU,KAAAA,KAAa,CAACZ,SAAS0B,IAAI,GAAG,OAAOA;EAChD,MAAMgB,QAAQF,QAAQG,MACnBC,cAAc5C,SAAS4C,SAAS,KAAKA,UAAU1C,OAAOA,EACzD;EACA,OAAOwC,QAAQ;GAAE,GAAGhB;GAAM,GAAGgB;EAAM,IAAIhB;CACzC,CAAC;CAGH,IAAIT,MAAMC,QAAQW,OAAOgB,GAAG,KAAKhB,OAAOgB,IAAIV,SAAS,GAAG;EACtD,MAAMW,QAAQhB,SACVD,OAAOgB,IAAIJ,KAAKf,SAAS;GACvB,IAAI,CAAC1B,SAAS0B,IAAI,KAAKA,KAAKxB,OAAOU,KAAAA,GAAW,OAAOc;GACrD,MAAMxB,KAAK4B,OAAO;GAClB,OAAO5B,OAAOU,KAAAA,IAAYc,OAAO;IAAE,GAAGA;IAAMxB;GAAG;EACjD,CAAC,IACD2B,OAAOgB;EACXd,OAAO,CAAC,GAAGA,MAAM,GAAGe,KAAK;CAC3B;CAEA,OAAOf;AACT;;;;;;AAOA,SAAgBgB,8BACdnB,MACAvB,SACA2C,SAYS;CACT,IAAI,CAAChD,SAAS4B,IAAI,KAAK,CAAC5B,SAASK,OAAO,GAAG,OAAOA;CAClD,MAAMiD,WAAWtD,SAASgD,SAASC,aAAa,IAC5CD,QAAQC,gBACRrB;CACJ,MAAMG,OAAO,EAAE,GAAGH,KAAK;CACvB,KAAK,MAAM,CAAC2B,KAAKC,UAAUC,OAAOC,QAAQrD,OAAO,GAAG;EAClD,MAAMsD,YAAYL,SAASC;EAC3B,IAAItC,MAAMC,QAAQyC,SAAS,KAAK3D,SAASwD,KAAK,GAM5CzB,KAAKwB,OAAO5B,iBAAiBgC,WAAWH,OAJtCR,SAASE,cACRF,QAAQI,kBAAkBxC,KAAAA,KAAaoC,QAAQI,cAAcb,IAAIgB,GAAG,WAC3DP,QAAQE,YAAYK,GAAG,IAC7B3C,KAAAA,CAC+C;OAErDmB,KAAKwB,OAAOC;CAEhB;CACA,OAAOzB;AACT;;;;;;;;AASA,SAAS6B,6BACPC,OACA9B,MACqC;CACrC,IAAI,CAAC/B,SAAS6D,KAAK,KAAK,CAAC7D,SAAS+B,IAAI,GAAG,OAAOnB,KAAAA;CAChD,KAAK,MAAM2C,OAAOE,OAAOK,KAAKD,KAAK,GACjC,IAAI,EAAEN,OAAOxB,OAAO,OAAOnB,KAAAA;CAE7B,MAAMmD,OAAgC,CAAC;CACvC,KAAK,MAAM,CAACR,KAAKC,UAAUC,OAAOC,QAAQ3B,IAAI,GAC5C,IAAI,EAAEwB,OAAOM,UAAU,CAAC/D,iBAAiB+D,MAAMN,MAAMC,KAAK,GACxDO,KAAKR,OAAOC;CAGhB,MAAMQ,UAAUP,OAAOK,KAAKC,IAAI,CAAC,CAAC5B;CAClC,IAAI6B,YAAY,KAAKA,YAAYP,OAAOK,KAAK/B,IAAI,CAAC,CAACI,QAAQ,OAAOvB,KAAAA;CAClE,OAAOmD;AACT;AAUA,MAAMQ,kBAAkBC,SAAgD;CACtE,IAAI,CAACA,QAAQ,OAAOA,SAAS,UAAU,OAAO5D,KAAAA;CAC9C,MAAM6D,IAAID;CACV,OAAOC,EAAEP,SAAS,cAAcO,IAAI7D,KAAAA;AACtC;;AAGA,MAAM8D,qBAAqBD,GAAqBvE,OAAwB;CACtE,IAAI,CAACuE,EAAEJ,QAAQ,OAAOI,EAAEJ,SAAS,UAAU,OAAO;CAClD,MAAMC,SAAStE,SAASyE,EAAEH,MAAM,IAAIG,EAAEH,SAAS1D,KAAAA;CAC/C,IAAI0D,QAAQK,YAAY,OAAO,OAAO;CACtC,IAAI,OAAOL,QAAQpE,OAAO,UAAU,OAAOoE,OAAOpE,OAAOA;CACzD,MAAM0E,SAAUH,EAAEJ,KAAiCnE;CACnD,OAAO0E,WAAW1E,MAAM0E,WAAWhE,KAAAA;AACrC;AAEA,MAAMiE,4BAA4BP,WAAoB;CACpD,MAAMd,QAAQxD,SAASsE,MAAM,IAAIA,OAAOQ,eAAelE,KAAAA;CACvD,IAAI,CAACZ,SAASwD,KAAK,GAAG,OAAO5C,KAAAA;CAE7B,MAAMmE,6BAAa,IAAIC,IAAsB;CAC7C,KAAK,MAAM,CAAC7B,OAAOf,QAAQqB,OAAOC,QAAQF,KAAK,GAAG;EAChD,IAAI,CAACvC,MAAMC,QAAQkB,GAAG,GAAG;EACzB,MAAM6C,YAAY7C,IAAIE,QACnBZ,SAAyB,OAAOA,SAAS,QAC5C;EACA,IAAIuD,UAAU9C,SAAS,GAAG4C,WAAW/C,IAAImB,OAAO8B,SAAS;CAC3D;CACA,IAAIF,WAAWG,SAAS,GAAG,OAAOtE,KAAAA;CAElC,QAAQuC,UAAkB4B,WAAWI,IAAIhC,KAAK,CAAC,EAAEiC,MAAM;AACzD;AAgBA,MAAMG,gCAAgB,IAAIC,QAGxB;;;;;;;;;;;;;;;;;AAkBF,SAAgBC,iCACdC,UACAxF,IACAC,MACgC;CAChC,IAAIwF,SAASJ,cAAcJ,IAAIO,QAAQ;CACvC,IAAI,CAACC,QAAQ;EACXA,yBAAS,IAAIX,IAAI;EACjBO,cAAcvD,IAAI0D,UAAUC,MAAM;CACpC;CACA,IAAIC,OAAOD,OAAOR,IAAIhF,IAAI;CAC1B,IAAI,CAACyF,MAAM;EACTA,uBAAO,IAAIZ,IAAI;EACfW,OAAO3D,IAAI7B,MAAMyF,IAAI;CACvB;CACA,MAAMC,SAASD,KAAKT,IAAIjF,EAAE;CAC1B,IAAI2F,QAAQ,OAAOA;CAEnB,MAAMzB,WAAW7C,qBAAqBpB,IAAI;CAC1C,MAAM2F,WAA2C,CAAA;CACjD,MAAMC,gBAAgBD,SAASA,SAAS3D,SAAS;CAEjD,KAAK,MAAM6D,OAAON,UAAU;EAC1B,IAAIM,IAAIzF,SAAS,QAAQ;GACvB,MAAMa,QAAQV,kCAAkCsF,GAAG,CAAC,EAAErD,MACnDsD,OAAOA,GAAG/F,OAAOA,EACpB;GACA,IAAI,CAACkB,OAAO;GACZ,IAAIA,MAAMf,SAAS;IACjB,MAAMuB,OAAOmE,QAAQ;IACrB,IAAInE,MACFkE,SAASI,KAAK;KACZ9F,OAAO2C,8BAA8BnB,KAAKxB,OAAOgB,MAAMhB,KAAK;KAC5DkF,QAAQ;IACV,CAAC;GAEL,OACEQ,SAASI,KAAK;IAAE9F,OAAOgB,MAAMhB;IAAOkF,QAAQ;GAAY,CAAC;GAE3D;EACF;EAEA,IAAIU,IAAIzF,SAAS,aAAa;EAC9B,KAAK,MAAMiE,QAAQwB,IAAIvF,WAAW,CAAA,GAAI;GACpC,MAAMgE,IAAIF,eAAeC,IAAI;GAC7B,IAAI,CAACC,GAAG;GACR,IAAIA,EAAEN,eAAejE,MAAMuE,EAAEL,aAAajE,MACpCsE;QAAAA,EAAEJ,QAAQ,OAAOI,EAAEJ,SAAS,UAC9ByB,SAASI,KAAK;KAAE9F,OAAOqE,EAAEJ;KAAMiB,QAAQ;KAAUnB,YAAYjE;IAAG,CAAC;GAAA,OAE9D,IAAIuE,EAAEL,aAAaA,YAAYM,kBAAkBD,GAAGvE,EAAE,GAAG;IAC9D,MAAM0B,OAAOmE,QAAQ;IACrB,IAAInE,MAAM;KACR,MAAM,EAAE1B,IAAIiG,KAAK,GAAG9F,YAAYoE,EAAEJ;KAClC,MAAMnB,YAAY2B,yBAAyBJ,EAAEH,MAAM;KACnDwB,SAASI,KAAK;MACZ9F,OAAO8C,YACHH,8BAA8BnB,KAAKxB,OAAOC,SAAS,EACjD6C,UACF,CAAC,IACDH,8BAA8BnB,KAAKxB,OAAOC,OAAO;MACrDiF,QAAQ;MACRnB,YAAYM,EAAEN;KAChB,CAAC;IACH;GACF;EACF;CACF;CACAyB,KAAK5D,IAAI9B,IAAI4F,QAAQ;CACrB,OAAOA;AACT;;;;;AAMA,SAAgBM,oBACdV,UACAxF,IACAC,MACgC;CAChC,MAAM2F,WAAWL,iCAAiCC,UAAUxF,IAAIC,IAAI;CACpE,MAAMkG,OAAOP,SAASA,SAAS3D,SAAS;CACxC,OAAOkE,OAAO,EAAEjG,OAAOiG,KAAKjG,MAAM,IAAIQ,KAAAA;AACxC;;;;;;;;AASA,SAAgB0F,iCACdC,MACAb,UACqC;CACrC,IAAI,CAACa,MAAM,OAAO3F,KAAAA;CAClB,MAAM,EAAEI,eAAe,GAAGwF,SAASD;CAInC,MAAME,QAAiC,EAAE,GAAGD,KAAK;CACjD,IAAIvF,MAAMC,QAAQF,aAAa,GAAG;EAChC,MAAM0F,UAAgD,CAAA;EACtD,KAAK,MAAMT,MAAMjF,eAAe;GAC9B,IAAI2F,QAAQC,IAAIC,aAAa,gBAAgB,CAAC9G,YAAYkG,GAAG7F,KAAK,GAChE0G,QAAQC,KACN,8BAA8Bd,GAAG9F,KAAI,KAAM8F,GAAG/F,GAAE,kLAIlD;GAEF,MAAM2D,QAAQuC,oBAAoBV,UAAUO,GAAG/F,IAAI+F,GAAG9F,IAAI;GAC1D,IAAI,CAAC0D,OAAO;IACV6C,QAAQR,KAAK;KAAEhG,IAAI+F,GAAG/F;KAAIC,MAAM8F,GAAG9F;KAAMC,OAAO6F,GAAG7F;IAAM,CAAC;IAC1D;GACF;GACA,IAAIN,iBAAiBmG,GAAG7F,OAAOyD,MAAMzD,KAAK,GAAG;GAC7C,MAAM2D,OAAOH,6BAA6BC,MAAMzD,OAAO6F,GAAG7F,KAAK;GAC/DsG,QAAQR,KACNnC,OACI;IAAE7D,IAAI+F,GAAG/F;IAAIC,MAAM8F,GAAG9F;IAAMC,OAAO2D;IAAM1D,SAAS;GAAK,IACvD;IAAEH,IAAI+F,GAAG/F;IAAIC,MAAM8F,GAAG9F;IAAMC,OAAO6F,GAAG7F;GAAM,CAClD;EACF;EACA,IAAIsG,QAAQvE,QAAQsE,MAAMzF,gBAAgB0F;CAC5C;CACA,OAAOjD,OAAOK,KAAK2C,KAAK,CAAC,CAACtE,SAASsE,QAAQ7F,KAAAA;AAC7C"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","names":[],"sources":["../../src/model-context/types.ts"],"mappings":";;;KAGY;EACV;EACA;EACA;EACA;EACA;EACA;EACA,UAAU;;KAGA;EACV;EACA;EACA;EACA;;KAGU;EACV;EACA;EACA,QAAQ,eAAe;EACvB,eAAe;EACf,SAAS;;;;;;EAMT,4BAA4B;;KAGlB;EACV,uBAAuB;EACvB,aAAa,yBAAyB;;KAG5B,mBACV,cAAc,yBACd,WACE,KAAK,OAAO;EACd;EACA;;KAGU;EACV;EACA;;KAGU;EACV;EACA;;cAGW,qBACX,WAAW,IAAI,0BACd"}
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../../src/model-context/types.ts"],"mappings":";;;KAGY;EACV;EACA;EACA;EACA;EACA;EACA;EACA,UAAU;;KAGA;EACV;EACA;EACA;EACA;;KAGU;EACV;EACA;EACA,QAAQ,eAAe;EACvB,eAAe;EACf,SAAS;;;;;;EAMT,4BAA4B;;KAGlB;EACV,uBAAuB;EACvB,aAAa,yBAAyB;;KAG5B,mBACV,cAAc,yBACd,WACE,KAAK,OAAO;EACd;EACA;;KAGU;EACV;EACA;;KAGU;EACV;EACA;;cASW,qBACX,WAAW,IAAI,0BACd"}
@@ -1,4 +1,9 @@
1
1
  //#region src/model-context/types.ts
2
+ const stripOverwrite = (tool) => {
3
+ if (!tool.overwrite) return tool;
4
+ const { overwrite: _, ...rest } = tool;
5
+ return rest;
6
+ };
2
7
  const mergeModelContexts = (configSet) => {
3
8
  const configs = Array.from(configSet).map((c) => c.getModelContext()).sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
4
9
  const toolPriorities = {};
@@ -10,18 +15,22 @@ const mergeModelContexts = (configSet) => {
10
15
  const existing = acc.tools?.[name];
11
16
  if (existing && existing !== tool) {
12
17
  const existingPriority = toolPriorities[name];
13
- if (existingPriority === priority) throw new Error(`You tried to define a tool with the name ${name}, but it already exists.`);
18
+ if (existingPriority === priority) {
19
+ if (!tool.overwrite) throw new Error(`You tried to define a tool with the name ${name}, but it already exists.`);
20
+ acc.tools[name] = stripOverwrite(tool);
21
+ continue;
22
+ }
14
23
  const higherPriorityTool = existingPriority > priority ? existing : tool;
15
24
  const lowerPriorityTool = existingPriority > priority ? tool : existing;
16
- acc.tools[name] = {
25
+ acc.tools[name] = stripOverwrite({
17
26
  ...lowerPriorityTool,
18
27
  ...higherPriorityTool
19
- };
28
+ });
20
29
  toolPriorities[name] = Math.max(existingPriority, priority);
21
30
  continue;
22
31
  }
23
32
  if (!acc.tools) acc.tools = {};
24
- acc.tools[name] = tool;
33
+ acc.tools[name] = stripOverwrite(tool);
25
34
  toolPriorities[name] ??= priority;
26
35
  }
27
36
  if (config.config) acc.config = {
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","names":["Unsubscribe","Tool","LanguageModelV1CallSettings","maxTokens","temperature","topP","presencePenalty","frequencyPenalty","seed","headers","Record","LanguageModelConfig","apiKey","baseUrl","modelName","reasoningEffort","ModelContext","priority","system","tools","callSettings","config","unstable_composerMetadata","ModelContextProvider","getModelContext","subscribe","callback","AssistantToolProps","TArgs","TResult","toolName","render","AssistantInstructionsConfig","disabled","instruction","AssistantContextConfig","getContext","mergeModelContexts","configSet","Set","configs","Array","from","map","c","sort","a","b","toolPriorities","reduce","acc","name","tool","Object","entries","existing","existingPriority","Error","higherPriorityTool","lowerPriorityTool","Math","max"],"sources":["../../src/model-context/types.ts"],"sourcesContent":["import type { Unsubscribe } from \"../types/unsubscribe\";\nimport type { Tool } from \"assistant-stream\";\n\nexport type LanguageModelV1CallSettings = {\n maxTokens?: number;\n temperature?: number;\n topP?: number;\n presencePenalty?: number;\n frequencyPenalty?: number;\n seed?: number;\n headers?: Record<string, string | undefined>;\n};\n\nexport type LanguageModelConfig = {\n apiKey?: string;\n baseUrl?: string;\n modelName?: string;\n reasoningEffort?: string;\n};\n\nexport type ModelContext = {\n priority?: number | undefined;\n system?: string | undefined;\n tools?: Record<string, Tool<any, any>> | undefined;\n callSettings?: LanguageModelV1CallSettings | undefined;\n config?: LanguageModelConfig | undefined;\n /**\n * Persisted message metadata pulled at send time and merged into the outgoing\n * user message's `metadata.custom` (not forwarded to the model directly).\n * Ignored by the transport, which only reads system/tools/callSettings/config.\n */\n unstable_composerMetadata?: Record<string, unknown> | undefined;\n};\n\nexport type ModelContextProvider = {\n getModelContext: () => ModelContext;\n subscribe?: (callback: () => void) => Unsubscribe;\n};\n\nexport type AssistantToolProps<\n TArgs extends Record<string, unknown>,\n TResult,\n> = Tool<TArgs, TResult> & {\n toolName: string;\n render?: unknown;\n};\n\nexport type AssistantInstructionsConfig = {\n disabled?: boolean | undefined;\n instruction: string;\n};\n\nexport type AssistantContextConfig = {\n getContext: () => string;\n disabled?: boolean | undefined;\n};\n\nexport const mergeModelContexts = (\n configSet: Set<ModelContextProvider>,\n): ModelContext => {\n const configs = Array.from(configSet)\n .map((c) => c.getModelContext())\n .sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));\n\n const toolPriorities: Record<string, number> = {};\n\n return configs.reduce((acc, config) => {\n const priority = config.priority ?? 0;\n if (config.system) {\n if (acc.system) {\n acc.system += `\\n\\n${config.system}`;\n } else {\n acc.system = config.system;\n }\n }\n if (config.tools) {\n for (const [name, tool] of Object.entries(config.tools)) {\n const existing = acc.tools?.[name];\n if (existing && existing !== tool) {\n const existingPriority = toolPriorities[name]!;\n if (existingPriority === priority) {\n throw new Error(\n `You tried to define a tool with the name ${name}, but it already exists.`,\n );\n }\n\n const higherPriorityTool =\n existingPriority > priority ? existing : tool;\n const lowerPriorityTool =\n existingPriority > priority ? tool : existing;\n acc.tools![name] = {\n ...lowerPriorityTool,\n ...higherPriorityTool,\n } as Tool<any, any>;\n toolPriorities[name] = Math.max(existingPriority, priority);\n continue;\n }\n\n if (!acc.tools) acc.tools = {};\n acc.tools[name] = tool;\n toolPriorities[name] ??= priority;\n }\n }\n if (config.config) {\n acc.config = {\n ...acc.config,\n ...config.config,\n };\n }\n if (config.callSettings) {\n acc.callSettings = {\n ...acc.callSettings,\n ...config.callSettings,\n };\n }\n if (config.unstable_composerMetadata) {\n acc.unstable_composerMetadata = {\n ...acc.unstable_composerMetadata,\n ...config.unstable_composerMetadata,\n };\n }\n return acc;\n }, {} as ModelContext);\n};\n"],"mappings":";AAyDA,MAAaqC,sBACXC,cACiB;CACjB,MAAME,UAAUC,MAAMC,KAAKJ,SAAS,CAAC,CAClCK,KAAKC,MAAMA,EAAEpB,gBAAgB,CAAC,CAAC,CAC/BqB,MAAMC,GAAGC,OAAOA,EAAE9B,YAAY,MAAM6B,EAAE7B,YAAY,EAAE;CAEvD,MAAM+B,iBAAyC,CAAC;CAEhD,OAAOR,QAAQS,QAAQC,KAAK7B,WAAW;EACrC,MAAMJ,WAAWI,OAAOJ,YAAY;EACpC,IAAII,OAAOH,QACT,IAAIgC,IAAIhC,QACNgC,IAAIhC,UAAU,OAAOG,OAAOH;OAE5BgC,IAAIhC,SAASG,OAAOH;EAGxB,IAAIG,OAAOF,OACT,KAAK,MAAM,CAACgC,MAAMC,SAASC,OAAOC,QAAQjC,OAAOF,KAAK,GAAG;GACvD,MAAMoC,WAAWL,IAAI/B,QAAQgC;GAC7B,IAAII,YAAYA,aAAaH,MAAM;IACjC,MAAMI,mBAAmBR,eAAeG;IACxC,IAAIK,qBAAqBvC,UACvB,MAAM,IAAIwC,MACR,4CAA4CN,KAAI,yBAClD;IAGF,MAAMO,qBACJF,mBAAmBvC,WAAWsC,WAAWH;IAC3C,MAAMO,oBACJH,mBAAmBvC,WAAWmC,OAAOG;IACvCL,IAAI/B,MAAOgC,QAAQ;KACjB,GAAGQ;KACH,GAAGD;IACL;IACAV,eAAeG,QAAQS,KAAKC,IAAIL,kBAAkBvC,QAAQ;IAC1D;GACF;GAEA,IAAI,CAACiC,IAAI/B,OAAO+B,IAAI/B,QAAQ,CAAC;GAC7B+B,IAAI/B,MAAMgC,QAAQC;GAClBJ,eAAeG,UAAUlC;EAC3B;EAEF,IAAII,OAAOA,QACT6B,IAAI7B,SAAS;GACX,GAAG6B,IAAI7B;GACP,GAAGA,OAAOA;EACZ;EAEF,IAAIA,OAAOD,cACT8B,IAAI9B,eAAe;GACjB,GAAG8B,IAAI9B;GACP,GAAGC,OAAOD;EACZ;EAEF,IAAIC,OAAOC,2BACT4B,IAAI5B,4BAA4B;GAC9B,GAAG4B,IAAI5B;GACP,GAAGD,OAAOC;EACZ;EAEF,OAAO4B;CACT,GAAG,CAAC,CAAiB;AACvB"}
1
+ {"version":3,"file":"types.js","names":["Unsubscribe","Tool","LanguageModelV1CallSettings","maxTokens","temperature","topP","presencePenalty","frequencyPenalty","seed","headers","Record","LanguageModelConfig","apiKey","baseUrl","modelName","reasoningEffort","ModelContext","priority","system","tools","callSettings","config","unstable_composerMetadata","ModelContextProvider","getModelContext","subscribe","callback","AssistantToolProps","TArgs","TResult","toolName","render","AssistantInstructionsConfig","disabled","instruction","AssistantContextConfig","getContext","stripOverwrite","tool","overwrite","_","rest","mergeModelContexts","configSet","Set","configs","Array","from","map","c","sort","a","b","toolPriorities","reduce","acc","name","Object","entries","existing","existingPriority","Error","higherPriorityTool","lowerPriorityTool","Math","max"],"sources":["../../src/model-context/types.ts"],"sourcesContent":["import type { Unsubscribe } from \"../types/unsubscribe\";\nimport type { Tool } from \"assistant-stream\";\n\nexport type LanguageModelV1CallSettings = {\n maxTokens?: number;\n temperature?: number;\n topP?: number;\n presencePenalty?: number;\n frequencyPenalty?: number;\n seed?: number;\n headers?: Record<string, string | undefined>;\n};\n\nexport type LanguageModelConfig = {\n apiKey?: string;\n baseUrl?: string;\n modelName?: string;\n reasoningEffort?: string;\n};\n\nexport type ModelContext = {\n priority?: number | undefined;\n system?: string | undefined;\n tools?: Record<string, Tool<any, any>> | undefined;\n callSettings?: LanguageModelV1CallSettings | undefined;\n config?: LanguageModelConfig | undefined;\n /**\n * Persisted message metadata pulled at send time and merged into the outgoing\n * user message's `metadata.custom` (not forwarded to the model directly).\n * Ignored by the transport, which only reads system/tools/callSettings/config.\n */\n unstable_composerMetadata?: Record<string, unknown> | undefined;\n};\n\nexport type ModelContextProvider = {\n getModelContext: () => ModelContext;\n subscribe?: (callback: () => void) => Unsubscribe;\n};\n\nexport type AssistantToolProps<\n TArgs extends Record<string, unknown>,\n TResult,\n> = Tool<TArgs, TResult> & {\n toolName: string;\n render?: unknown;\n};\n\nexport type AssistantInstructionsConfig = {\n disabled?: boolean | undefined;\n instruction: string;\n};\n\nexport type AssistantContextConfig = {\n getContext: () => string;\n disabled?: boolean | undefined;\n};\n\nconst stripOverwrite = (tool: Tool<any, any>): Tool<any, any> => {\n if (!tool.overwrite) return tool;\n const { overwrite: _, ...rest } = tool;\n return rest as Tool<any, any>;\n};\n\nexport const mergeModelContexts = (\n configSet: Set<ModelContextProvider>,\n): ModelContext => {\n const configs = Array.from(configSet)\n .map((c) => c.getModelContext())\n .sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));\n\n const toolPriorities: Record<string, number> = {};\n\n return configs.reduce((acc, config) => {\n const priority = config.priority ?? 0;\n if (config.system) {\n if (acc.system) {\n acc.system += `\\n\\n${config.system}`;\n } else {\n acc.system = config.system;\n }\n }\n if (config.tools) {\n for (const [name, tool] of Object.entries(config.tools)) {\n const existing = acc.tools?.[name];\n if (existing && existing !== tool) {\n const existingPriority = toolPriorities[name]!;\n if (existingPriority === priority) {\n if (!tool.overwrite) {\n throw new Error(\n `You tried to define a tool with the name ${name}, but it already exists.`,\n );\n }\n acc.tools![name] = stripOverwrite(tool);\n continue;\n }\n\n const higherPriorityTool =\n existingPriority > priority ? existing : tool;\n const lowerPriorityTool =\n existingPriority > priority ? tool : existing;\n acc.tools![name] = stripOverwrite({\n ...lowerPriorityTool,\n ...higherPriorityTool,\n } as Tool<any, any>);\n toolPriorities[name] = Math.max(existingPriority, priority);\n continue;\n }\n\n if (!acc.tools) acc.tools = {};\n acc.tools[name] = stripOverwrite(tool);\n toolPriorities[name] ??= priority;\n }\n }\n if (config.config) {\n acc.config = {\n ...acc.config,\n ...config.config,\n };\n }\n if (config.callSettings) {\n acc.callSettings = {\n ...acc.callSettings,\n ...config.callSettings,\n };\n }\n if (config.unstable_composerMetadata) {\n acc.unstable_composerMetadata = {\n ...acc.unstable_composerMetadata,\n ...config.unstable_composerMetadata,\n };\n }\n return acc;\n }, {} as ModelContext);\n};\n"],"mappings":";AAyDA,MAAMqC,kBAAkBC,SAAyC;CAC/D,IAAI,CAACA,KAAKC,WAAW,OAAOD;CAC5B,MAAM,EAAEC,WAAWC,GAAG,GAAGC,SAASH;CAClC,OAAOG;AACT;AAEA,MAAaC,sBACXC,cACiB;CACjB,MAAME,UAAUC,MAAMC,KAAKJ,SAAS,CAAC,CAClCK,KAAKC,MAAMA,EAAEzB,gBAAgB,CAAC,CAAC,CAC/B0B,MAAMC,GAAGC,OAAOA,EAAEnC,YAAY,MAAMkC,EAAElC,YAAY,EAAE;CAEvD,MAAMoC,iBAAyC,CAAC;CAEhD,OAAOR,QAAQS,QAAQC,KAAKlC,WAAW;EACrC,MAAMJ,WAAWI,OAAOJ,YAAY;EACpC,IAAII,OAAOH,QACT,IAAIqC,IAAIrC,QACNqC,IAAIrC,UAAU,OAAOG,OAAOH;OAE5BqC,IAAIrC,SAASG,OAAOH;EAGxB,IAAIG,OAAOF,OACT,KAAK,MAAM,CAACqC,MAAMlB,SAASmB,OAAOC,QAAQrC,OAAOF,KAAK,GAAG;GACvD,MAAMwC,WAAWJ,IAAIpC,QAAQqC;GAC7B,IAAIG,YAAYA,aAAarB,MAAM;IACjC,MAAMsB,mBAAmBP,eAAeG;IACxC,IAAII,qBAAqB3C,UAAU;KACjC,IAAI,CAACqB,KAAKC,WACR,MAAM,IAAIsB,MACR,4CAA4CL,KAAI,yBAClD;KAEFD,IAAIpC,MAAOqC,QAAQnB,eAAeC,IAAI;KACtC;IACF;IAEA,MAAMwB,qBACJF,mBAAmB3C,WAAW0C,WAAWrB;IAC3C,MAAMyB,oBACJH,mBAAmB3C,WAAWqB,OAAOqB;IACvCJ,IAAIpC,MAAOqC,QAAQnB,eAAe;KAChC,GAAG0B;KACH,GAAGD;IACL,CAAmB;IACnBT,eAAeG,QAAQQ,KAAKC,IAAIL,kBAAkB3C,QAAQ;IAC1D;GACF;GAEA,IAAI,CAACsC,IAAIpC,OAAOoC,IAAIpC,QAAQ,CAAC;GAC7BoC,IAAIpC,MAAMqC,QAAQnB,eAAeC,IAAI;GACrCe,eAAeG,UAAUvC;EAC3B;EAEF,IAAII,OAAOA,QACTkC,IAAIlC,SAAS;GACX,GAAGkC,IAAIlC;GACP,GAAGA,OAAOA;EACZ;EAEF,IAAIA,OAAOD,cACTmC,IAAInC,eAAe;GACjB,GAAGmC,IAAInC;GACP,GAAGC,OAAOD;EACZ;EAEF,IAAIC,OAAOC,2BACTiC,IAAIjC,4BAA4B;GAC9B,GAAGiC,IAAIjC;GACP,GAAGD,OAAOC;EACZ;EAEF,OAAOiC;CACT,GAAG,CAAC,CAAiB;AACvB"}
@@ -1 +1 @@
1
- {"version":3,"file":"AssistantProvider.js","names":["memo","ComponentType","FC","PropsWithChildren","useAui","AuiProvider","AssistantClient","AssistantRuntime","AssistantRuntimeCore","RuntimeAdapter","getRenderComponent","runtime","_core","RenderComponent","AssistantProviderBaseProps","aui","AssistantProviderBase","parent","children","threads","inner"],"sources":["../../src/react/AssistantProvider.tsx"],"sourcesContent":["import {\n memo,\n type ComponentType,\n type FC,\n type PropsWithChildren,\n} from \"react\";\nimport { useAui, AuiProvider, type AssistantClient } from \"@assistant-ui/store\";\nimport type { AssistantRuntime } from \"../runtime/api/assistant-runtime\";\nimport type { AssistantRuntimeCore } from \"../runtime/interfaces/assistant-runtime-core\";\nimport { RuntimeAdapter } from \"./RuntimeAdapter\";\n\nexport const getRenderComponent = (runtime: AssistantRuntime) => {\n return (runtime as { _core?: AssistantRuntimeCore })._core\n ?.RenderComponent as ComponentType | undefined;\n};\n\nexport type AssistantProviderBaseProps = PropsWithChildren<{\n runtime: AssistantRuntime;\n aui?: AssistantClient | null;\n}>;\n\nexport const AssistantProviderBase: FC<AssistantProviderBaseProps> = memo(\n ({ runtime, aui: parent = null, children }) => {\n // The runtime has a stable identity but mutates in place: its options are\n // pushed in by an unconditional effect inside <RenderComponent />, so that\n // element must be re-created every commit for React to re-render it and\n // re-run the effect. React Compiler caches <RenderComponent /> on the\n // stable RenderComponent type, which silences the effect and stops option\n // changes (e.g. unstable_enableMessageQueue) from reaching the runtime.\n \"use no memo\";\n const aui = useAui({ threads: RuntimeAdapter(runtime) }, { parent });\n const RenderComponent = getRenderComponent(runtime);\n const inner = (\n <AuiProvider value={aui}>\n {RenderComponent && <RenderComponent />}\n {children}\n </AuiProvider>\n );\n if (!parent) return inner;\n return <AuiProvider value={parent}>{inner}</AuiProvider>;\n },\n);\n"],"mappings":";;;;;AAWA,MAAaU,sBAAsBC,YAA8B;CAC/D,OAAQA,QAA6CC,OACjDC;AACN;AAOA,MAAaG,wBAAwDhB,MAClE,EAAEW,SAASI,KAAKE,SAAS,MAAMC,eAAe;CAO7C;CACA,MAAMH,MAAMX,OAAO,EAAEe,SAASV,eAAeE,OAAO,EAAE,GAAG,EAAEM,OAAO,CAAC;CACnE,MAAMJ,kBAAkBH,mBAAmBC,OAAO;CAClD,MAAMS,QACJ,qBAAC,aAAD;EAAa,OAAOL;YAApB,CACGF,mBAAmB,oBAAC,iBAAD,CAAgB,CAAA,GACnCK,QACU;;CAEf,IAAI,CAACD,QAAQ,OAAOG;CACpB,OAAO,oBAAC,aAAD;EAAa,OAAOH;YAASG;CAAmB,CAAA;AACzD,CACF"}
1
+ {"version":3,"file":"AssistantProvider.js","names":["memo","ComponentType","FC","PropsWithChildren","useAui","AuiProvider","AssistantClient","AssistantRuntime","AssistantRuntimeCore","RuntimeAdapter","getRenderComponent","runtime","_core","RenderComponent","AssistantProviderBaseProps","aui","AssistantProviderBase","parent","children","threads","inner"],"sources":["../../src/react/AssistantProvider.tsx"],"sourcesContent":["import {\n memo,\n type ComponentType,\n type FC,\n type PropsWithChildren,\n} from \"react\";\nimport { useAui, AuiProvider, type AssistantClient } from \"@assistant-ui/store\";\nimport type { AssistantRuntime } from \"../runtime/api/assistant-runtime\";\nimport type { AssistantRuntimeCore } from \"../runtime/interfaces/assistant-runtime-core\";\nimport { RuntimeAdapter } from \"./RuntimeAdapter\";\n\nexport const getRenderComponent = (runtime: AssistantRuntime) => {\n return (runtime as { _core?: AssistantRuntimeCore })._core\n ?.RenderComponent as ComponentType | undefined;\n};\n\nexport type AssistantProviderBaseProps = PropsWithChildren<{\n runtime: AssistantRuntime;\n aui?: AssistantClient | null;\n}>;\n\nexport const AssistantProviderBase: FC<AssistantProviderBaseProps> = memo(\n ({ runtime, aui: parent = null, children }) => {\n // The runtime has a stable identity but mutates in place: its options are\n // pushed in by an unconditional effect inside <RenderComponent />, so that\n // element must be re-created every commit for React to re-render it and\n // re-run the effect. React Compiler caches <RenderComponent /> on the\n // stable RenderComponent type, which silences the effect and stops option\n // changes (e.g. unstable_enableMessageQueue) from reaching the runtime.\n \"use no memo\";\n const aui = useAui({ threads: RuntimeAdapter(runtime) }, { parent });\n const RenderComponent = getRenderComponent(runtime);\n const inner = (\n <AuiProvider value={aui}>\n {RenderComponent && <RenderComponent />}\n {children}\n </AuiProvider>\n );\n if (!parent) return inner;\n return <AuiProvider value={parent}>{inner}</AuiProvider>;\n },\n);\n"],"mappings":";;;;;AAWA,MAAaU,sBAAsBC,YAA8B;CAC/D,OAAQA,QAA6CC,OACjDC;AACN;AAOA,MAAaG,wBAAwDhB,MAClE,EAAEW,SAASI,KAAKE,SAAS,MAAMC,eAAe;CAO7C;CACA,MAAMH,MAAMX,OAAO,EAAEe,SAASV,eAAeE,OAAO,EAAE,GAAG,EAAEM,OAAO,CAAC;CACnE,MAAMJ,kBAAkBH,mBAAmBC,OAAO;CAClD,MAAMS,QACJ,qBAAC,aAAD;EAAa,OAAOL;EAApB,UAAA,CACGF,mBAAmB,oBAAC,iBAAD,CAAgB,CAAA,GACnCK,QACU;;CAEf,IAAI,CAACD,QAAQ,OAAOG;CACpB,OAAO,oBAAC,aAAD;EAAa,OAAOH;EAASG,UAAAA;CAAmB,CAAA;AACzD,CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"LocalStorageThreadListAdapter.d.ts","names":[],"sources":["../../../src/react/adapters/LocalStorageThreadListAdapter.tsx"],"mappings":";;;;;;KAmBY;EACV,QAAQ,cAAc;EACtB,QAAQ,aAAa,gBAAgB;EACrC,WAAW,cAAc;;KAGtB;EACH,SAAS;EACT;EACA,iBAAiB;;KAGd;EACH;EACA;EACA;EACA;EACA,SAAS;;cAwIE,4BACX,uBACC;cAoCU,+BACX,uBACC;cA8FU,4BACX,SAAS,+BACR"}
1
+ {"version":3,"file":"LocalStorageThreadListAdapter.d.ts","names":[],"sources":["../../../src/react/adapters/LocalStorageThreadListAdapter.tsx"],"mappings":";;;;;;KAmBY;EACV,QAAQ,cAAc;EACtB,QAAQ,aAAa,gBAAgB;EACrC,WAAW,cAAc;;KAkCtB;EACH,SAAS;EACT;EACA,iBAAiB;;KAGd;EACH;EACA;EACA;EACA;EACA,SAAS;;cAwIE,4BACX,uBACC;cAoCU,+BACX,uBACC;cA4GU,4BACX,SAAS,+BACR"}
@@ -1,9 +1,32 @@
1
1
  import { RuntimeAdapterProvider } from "../runtimes/RuntimeAdapterProvider.js";
2
2
  import { createAssistantStream } from "assistant-stream";
3
3
  import { useAui } from "@assistant-ui/store";
4
+ import "@assistant-ui/tap/react-shim";
4
5
  import { c } from "@assistant-ui/tap/react-shim/compiler-runtime";
5
6
  import { jsx } from "react/jsx-runtime";
6
7
  //#region src/react/adapters/LocalStorageThreadListAdapter.tsx
8
+ var KeyedMutationQueue = class {
9
+ tails = /* @__PURE__ */ new Map();
10
+ run(key, mutation) {
11
+ const previous = this.tails.get(key);
12
+ const result = previous ? previous.then(mutation) : mutation();
13
+ const tail = result.then(() => void 0, () => void 0);
14
+ this.tails.set(key, tail);
15
+ tail.then(() => {
16
+ if (this.tails.get(key) === tail) this.tails.delete(key);
17
+ });
18
+ return result;
19
+ }
20
+ };
21
+ const mutationQueues = /* @__PURE__ */ new WeakMap();
22
+ const getMutationQueue = (storage) => {
23
+ let queue = mutationQueues.get(storage);
24
+ if (!queue) {
25
+ queue = new KeyedMutationQueue();
26
+ mutationQueues.set(storage, queue);
27
+ }
28
+ return queue;
29
+ };
7
30
  const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
8
31
  const parseJSON = (raw) => {
9
32
  if (!raw) return void 0;
@@ -123,10 +146,12 @@ var AsyncStorageHistoryAdapter = class {
123
146
  storage;
124
147
  aui;
125
148
  prefix;
126
- constructor(storage, aui, prefix) {
149
+ mutationQueue;
150
+ constructor(storage, aui, prefix, mutationQueue) {
127
151
  this.storage = storage;
128
152
  this.aui = aui;
129
153
  this.prefix = prefix;
154
+ this.mutationQueue = mutationQueue;
130
155
  }
131
156
  _messagesKey(remoteId) {
132
157
  return `${this.prefix}messages:${remoteId}`;
@@ -140,23 +165,25 @@ var AsyncStorageHistoryAdapter = class {
140
165
  async append(item) {
141
166
  const { remoteId } = await this.aui.threadListItem().initialize();
142
167
  const key = this._messagesKey(remoteId);
143
- const raw = await this.storage.getItem(key);
144
- const repo = parseStoredMessageRepository(raw);
145
- const idx = repo.messages.findIndex((m) => m.message.id === item.message.id);
146
- if (idx >= 0) repo.messages[idx] = item;
147
- else repo.messages.push(item);
148
- repo.headId = item.message.id;
149
- await this.storage.setItem(key, JSON.stringify(repo));
168
+ await this.mutationQueue.run(key, async () => {
169
+ const raw = await this.storage.getItem(key);
170
+ const repo = parseStoredMessageRepository(raw);
171
+ const idx = repo.messages.findIndex((m) => m.message.id === item.message.id);
172
+ if (idx >= 0) repo.messages[idx] = item;
173
+ else repo.messages.push(item);
174
+ repo.headId = item.message.id;
175
+ await this.storage.setItem(key, JSON.stringify(repo));
176
+ });
150
177
  }
151
178
  };
152
- const createHistoryProvider = (storage, prefix) => {
179
+ const createHistoryProvider = (storage, prefix, mutationQueue) => {
153
180
  const Provider = (t0) => {
154
181
  const $ = c(7);
155
182
  const { children } = t0;
156
183
  const aui = useAui();
157
184
  let t1;
158
185
  if ($[0] !== aui) {
159
- t1 = new AsyncStorageHistoryAdapter(storage, aui, prefix);
186
+ t1 = new AsyncStorageHistoryAdapter(storage, aui, prefix, mutationQueue);
160
187
  $[0] = aui;
161
188
  $[1] = t1;
162
189
  } else t1 = $[1];
@@ -186,6 +213,7 @@ const createLocalStorageAdapter = (options) => {
186
213
  const { storage, prefix = "@assistant-ui:", titleGenerator } = options;
187
214
  const threadsKey = `${prefix}threads`;
188
215
  const messagesKey = (threadId) => `${prefix}messages:${threadId}`;
216
+ const mutationQueue = getMutationQueue(storage);
189
217
  const loadThreadMetadata = async () => {
190
218
  const raw = await storage.getItem(threadsKey);
191
219
  return parseStoredThreadMetadata(raw);
@@ -193,8 +221,18 @@ const createLocalStorageAdapter = (options) => {
193
221
  const saveThreadMetadata = async (threads) => {
194
222
  await storage.setItem(threadsKey, JSON.stringify(threads));
195
223
  };
224
+ const updateThreadMetadata = async (remoteId, update) => {
225
+ await mutationQueue.run(threadsKey, async () => {
226
+ const threads = await loadThreadMetadata();
227
+ const thread = threads.find((item) => item.remoteId === remoteId);
228
+ if (thread) {
229
+ update(thread);
230
+ await saveThreadMetadata(threads);
231
+ }
232
+ });
233
+ };
196
234
  return {
197
- unstable_Provider: createHistoryProvider(storage, prefix),
235
+ unstable_Provider: createHistoryProvider(storage, prefix, mutationQueue),
198
236
  async list() {
199
237
  return { threads: (await loadThreadMetadata()).map((t) => ({
200
238
  remoteId: t.remoteId,
@@ -206,55 +244,48 @@ const createLocalStorageAdapter = (options) => {
206
244
  },
207
245
  async initialize(threadId) {
208
246
  const remoteId = threadId;
209
- const threads = await loadThreadMetadata();
210
- if (!threads.some((t) => t.remoteId === remoteId)) {
211
- threads.unshift({
247
+ return mutationQueue.run(threadsKey, async () => {
248
+ const threads = await loadThreadMetadata();
249
+ if (!threads.some((t) => t.remoteId === remoteId)) {
250
+ threads.unshift({
251
+ remoteId,
252
+ status: "regular"
253
+ });
254
+ await saveThreadMetadata(threads);
255
+ }
256
+ return {
212
257
  remoteId,
213
- status: "regular"
214
- });
215
- await saveThreadMetadata(threads);
216
- }
217
- return {
218
- remoteId,
219
- externalId: void 0
220
- };
258
+ externalId: void 0
259
+ };
260
+ });
221
261
  },
222
262
  async rename(remoteId, newTitle) {
223
- const threads = await loadThreadMetadata();
224
- const thread = threads.find((t) => t.remoteId === remoteId);
225
- if (thread) {
263
+ await updateThreadMetadata(remoteId, (thread) => {
226
264
  thread.title = newTitle;
227
- await saveThreadMetadata(threads);
228
- }
265
+ });
229
266
  },
230
267
  async updateCustom(remoteId, custom) {
231
- const threads = await loadThreadMetadata();
232
- const thread = threads.find((t) => t.remoteId === remoteId);
233
- if (thread) {
268
+ await updateThreadMetadata(remoteId, (thread) => {
234
269
  thread.custom = custom;
235
- await saveThreadMetadata(threads);
236
- }
270
+ });
237
271
  },
238
272
  async archive(remoteId) {
239
- const threads = await loadThreadMetadata();
240
- const thread = threads.find((t) => t.remoteId === remoteId);
241
- if (thread) {
273
+ await updateThreadMetadata(remoteId, (thread) => {
242
274
  thread.status = "archived";
243
- await saveThreadMetadata(threads);
244
- }
275
+ });
245
276
  },
246
277
  async unarchive(remoteId) {
247
- const threads = await loadThreadMetadata();
248
- const thread = threads.find((t) => t.remoteId === remoteId);
249
- if (thread) {
278
+ await updateThreadMetadata(remoteId, (thread) => {
250
279
  thread.status = "regular";
251
- await saveThreadMetadata(threads);
252
- }
280
+ });
253
281
  },
254
282
  async delete(remoteId) {
255
- const filtered = (await loadThreadMetadata()).filter((t) => t.remoteId !== remoteId);
256
- await saveThreadMetadata(filtered);
257
- await storage.removeItem(messagesKey(remoteId));
283
+ await mutationQueue.run(threadsKey, async () => {
284
+ const filtered = (await loadThreadMetadata()).filter((t) => t.remoteId !== remoteId);
285
+ await saveThreadMetadata(filtered);
286
+ });
287
+ const key = messagesKey(remoteId);
288
+ await mutationQueue.run(key, () => storage.removeItem(key));
258
289
  },
259
290
  async fetch(threadId) {
260
291
  const thread = (await loadThreadMetadata()).find((t) => t.remoteId === threadId);
@@ -270,12 +301,9 @@ const createLocalStorageAdapter = (options) => {
270
301
  async generateTitle(remoteId, messages) {
271
302
  if (titleGenerator) {
272
303
  const title = await titleGenerator.generateTitle(messages);
273
- const threads = await loadThreadMetadata();
274
- const thread = threads.find((t) => t.remoteId === remoteId);
275
- if (thread) {
304
+ await updateThreadMetadata(remoteId, (thread) => {
276
305
  thread.title = title;
277
- await saveThreadMetadata(threads);
278
- }
306
+ });
279
307
  return createAssistantStream((controller) => {
280
308
  controller.appendText(title);
281
309
  });
@@ -1 +1 @@
1
- {"version":3,"file":"LocalStorageThreadListAdapter.js","names":["AssistantStream","createAssistantStream","FC","PropsWithChildren","useMemo","useAui","RemoteThreadInitializeResponse","RemoteThreadListAdapter","RemoteThreadListResponse","RemoteThreadMetadata","ThreadHistoryAdapter","ThreadMessage","RunConfig","ExportedMessageRepository","ExportedMessageRepositoryItem","RuntimeAdapterProvider","TitleGenerationAdapter","AsyncStorageLike","getItem","key","Promise","setItem","value","removeItem","LocalStorageAdapterOptions","storage","prefix","titleGenerator","StoredThreadMetadata","remoteId","externalId","status","title","custom","Record","StoredSystemMessage","Extract","role","StoredUserMessage","StoredAssistantMessage","isRecord","Array","isArray","parseJSON","raw","undefined","JSON","parse","parseStoredThread","parseDate","Date","Number","isNaN","getTime","date","isMessageRole","parseStoredThreadMessage","id","content","createdAt","metadata","type","submittedFeedback","submittedFeedbackType","unstable_state","unstable_annotations","unstable_data","steps","timing","NonNullable","isOptimistic","attachments","length","parseStoredThreadMetadata","parsed","flatMap","item","thread","parseStoredMessageRepositoryItem","message","parentId","runConfig","parseStoredMessageRepository","messages","candidateMessages","parsedItem","acceptedIds","Set","has","add","headId","some","AsyncStorageHistoryAdapter","constructor","aui","ReturnType","_messagesKey","load","threadListItem","getState","append","initialize","repo","idx","findIndex","m","push","stringify","createHistoryProvider","Provider","t0","$","_c","children","t1","history","t2","adapters","t3","createLocalStorageAdapter","options","threadsKey","messagesKey","threadId","loadThreadMetadata","saveThreadMetadata","threads","adapter","unstable_Provider","list","map","t","unshift","rename","newTitle","find","updateCustom","archive","unarchive","delete","filtered","filter","fetch","Error","generateTitle","controller","appendText"],"sources":["../../../src/react/adapters/LocalStorageThreadListAdapter.tsx"],"sourcesContent":["import { type AssistantStream, createAssistantStream } from \"assistant-stream\";\nimport { type FC, type PropsWithChildren, useMemo } from \"react\";\nimport { useAui } from \"@assistant-ui/store\";\nimport type {\n RemoteThreadInitializeResponse,\n RemoteThreadListAdapter,\n RemoteThreadListResponse,\n RemoteThreadMetadata,\n ThreadHistoryAdapter,\n ThreadMessage,\n RunConfig,\n} from \"../../index\";\nimport type {\n ExportedMessageRepository,\n ExportedMessageRepositoryItem,\n} from \"../../internal\";\nimport { RuntimeAdapterProvider } from \"../runtimes/RuntimeAdapterProvider\";\nimport type { TitleGenerationAdapter } from \"./TitleGenerationAdapter\";\n\nexport type AsyncStorageLike = {\n getItem(key: string): Promise<string | null>;\n setItem(key: string, value: string): Promise<void>;\n removeItem(key: string): Promise<void>;\n};\n\ntype LocalStorageAdapterOptions = {\n storage: AsyncStorageLike;\n prefix?: string | undefined;\n titleGenerator?: TitleGenerationAdapter | undefined;\n};\n\ntype StoredThreadMetadata = {\n remoteId: string;\n externalId?: string;\n status: \"regular\" | \"archived\";\n title?: string;\n custom?: Record<string, unknown> | undefined;\n};\n\ntype StoredSystemMessage = Extract<ThreadMessage, { role: \"system\" }>;\ntype StoredUserMessage = Extract<ThreadMessage, { role: \"user\" }>;\ntype StoredAssistantMessage = Extract<ThreadMessage, { role: \"assistant\" }>;\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst parseJSON = (raw: string | null): unknown => {\n if (!raw) return undefined;\n try {\n return JSON.parse(raw) as unknown;\n } catch {\n return undefined;\n }\n};\n\nconst parseStoredThread = (value: unknown): StoredThreadMetadata | null => {\n if (!isRecord(value) || typeof value.remoteId !== \"string\") return null;\n\n const status = value.status ?? \"regular\";\n if (status !== \"regular\" && status !== \"archived\") return null;\n\n return {\n remoteId: value.remoteId,\n status,\n ...(typeof value.externalId === \"string\"\n ? { externalId: value.externalId }\n : undefined),\n ...(typeof value.title === \"string\" ? { title: value.title } : undefined),\n ...(isRecord(value.custom) ? { custom: value.custom } : undefined),\n };\n};\n\nconst parseDate = (value: unknown): Date | null => {\n if (value instanceof Date && !Number.isNaN(value.getTime())) return value;\n if (typeof value !== \"string\" && typeof value !== \"number\") return null;\n\n const date = new Date(value);\n return Number.isNaN(date.getTime()) ? null : date;\n};\n\nconst isMessageRole = (value: unknown): value is ThreadMessage[\"role\"] =>\n value === \"system\" || value === \"user\" || value === \"assistant\";\n\nconst parseStoredThreadMessage = (value: unknown): ThreadMessage | null => {\n if (!isRecord(value) || typeof value.id !== \"string\") return null;\n if (!isMessageRole(value.role)) return null;\n if (!Array.isArray(value.content)) return null;\n\n const createdAt = parseDate(value.createdAt);\n if (!createdAt) return null;\n\n const metadata = value.metadata;\n if (!isRecord(metadata) || !isRecord(metadata.custom)) return null;\n\n if (value.role === \"assistant\") {\n const status = value.status;\n if (!isRecord(status) || typeof status.type !== \"string\") return null;\n\n const submittedFeedback = isRecord(metadata.submittedFeedback)\n ? metadata.submittedFeedback\n : undefined;\n const submittedFeedbackType = submittedFeedback?.type;\n\n return {\n id: value.id,\n role: \"assistant\",\n content: value.content as StoredAssistantMessage[\"content\"],\n status: status as StoredAssistantMessage[\"status\"],\n createdAt,\n metadata: {\n unstable_state: (metadata.unstable_state ??\n null) as StoredAssistantMessage[\"metadata\"][\"unstable_state\"],\n unstable_annotations: Array.isArray(metadata.unstable_annotations)\n ? (metadata.unstable_annotations as StoredAssistantMessage[\"metadata\"][\"unstable_annotations\"])\n : [],\n unstable_data: Array.isArray(metadata.unstable_data)\n ? (metadata.unstable_data as StoredAssistantMessage[\"metadata\"][\"unstable_data\"])\n : [],\n steps: Array.isArray(metadata.steps)\n ? (metadata.steps as StoredAssistantMessage[\"metadata\"][\"steps\"])\n : [],\n ...(submittedFeedbackType === \"positive\" ||\n submittedFeedbackType === \"negative\"\n ? {\n submittedFeedback: {\n type: submittedFeedbackType,\n },\n }\n : undefined),\n ...(metadata.timing !== undefined\n ? {\n timing: metadata.timing as NonNullable<\n StoredAssistantMessage[\"metadata\"][\"timing\"]\n >,\n }\n : undefined),\n ...(metadata.isOptimistic === true\n ? { isOptimistic: true }\n : undefined),\n custom: metadata.custom,\n },\n };\n }\n\n if (value.role === \"user\") {\n return {\n id: value.id,\n role: \"user\",\n content: value.content as StoredUserMessage[\"content\"],\n attachments: Array.isArray(value.attachments)\n ? (value.attachments as StoredUserMessage[\"attachments\"])\n : [],\n createdAt,\n metadata: {\n custom: metadata.custom,\n },\n };\n }\n\n if (value.content.length !== 1) return null;\n\n return {\n id: value.id,\n role: \"system\",\n content: [value.content[0] as StoredSystemMessage[\"content\"][0]],\n createdAt,\n metadata: {\n custom: metadata.custom,\n },\n };\n};\n\nexport const parseStoredThreadMetadata = (\n raw: string | null,\n): StoredThreadMetadata[] => {\n const parsed = parseJSON(raw);\n if (!Array.isArray(parsed)) return [];\n\n return parsed.flatMap((item) => {\n const thread = parseStoredThread(item);\n return thread ? [thread] : [];\n });\n};\n\nconst parseStoredMessageRepositoryItem = (\n value: unknown,\n): ExportedMessageRepositoryItem | null => {\n if (!isRecord(value)) return null;\n\n const message = parseStoredThreadMessage(value.message);\n if (!message) return null;\n\n const parentId = value.parentId;\n if (\n parentId !== undefined &&\n parentId !== null &&\n typeof parentId !== \"string\"\n ) {\n return null;\n }\n\n return {\n message,\n parentId: parentId ?? null,\n ...(isRecord(value.runConfig)\n ? { runConfig: value.runConfig as RunConfig }\n : undefined),\n };\n};\n\nexport const parseStoredMessageRepository = (\n raw: string | null,\n): ExportedMessageRepository => {\n const parsed = parseJSON(raw);\n if (!isRecord(parsed) || !Array.isArray(parsed.messages)) {\n return { messages: [] };\n }\n\n const candidateMessages = parsed.messages.flatMap((item) => {\n const parsedItem = parseStoredMessageRepositoryItem(item);\n return parsedItem ? [parsedItem] : [];\n });\n\n const acceptedIds = new Set<string>();\n const messages = candidateMessages.flatMap((item) => {\n if (acceptedIds.has(item.message.id)) return [];\n if (item.parentId !== null && !acceptedIds.has(item.parentId)) return [];\n\n acceptedIds.add(item.message.id);\n return [item];\n });\n\n const headId =\n parsed.headId === null ||\n (typeof parsed.headId === \"string\" &&\n messages.some((item) => item.message.id === parsed.headId))\n ? parsed.headId\n : undefined;\n\n return {\n ...(headId !== undefined ? { headId } : undefined),\n messages,\n };\n};\n\nclass AsyncStorageHistoryAdapter implements ThreadHistoryAdapter {\n constructor(\n private storage: AsyncStorageLike,\n private aui: ReturnType<typeof useAui>,\n private prefix: string,\n ) {}\n\n private _messagesKey(remoteId: string) {\n return `${this.prefix}messages:${remoteId}`;\n }\n\n async load(): Promise<ExportedMessageRepository> {\n const remoteId = this.aui.threadListItem().getState().remoteId;\n if (!remoteId) return { messages: [] };\n\n const raw = await this.storage.getItem(this._messagesKey(remoteId));\n return parseStoredMessageRepository(raw);\n }\n\n async append(item: ExportedMessageRepositoryItem): Promise<void> {\n const { remoteId } = await this.aui.threadListItem().initialize();\n\n const key = this._messagesKey(remoteId);\n const raw = await this.storage.getItem(key);\n const repo = parseStoredMessageRepository(raw);\n\n const idx = repo.messages.findIndex(\n (m) => m.message.id === item.message.id,\n );\n if (idx >= 0) {\n repo.messages[idx] = item;\n } else {\n repo.messages.push(item);\n }\n repo.headId = item.message.id;\n\n await this.storage.setItem(key, JSON.stringify(repo));\n }\n}\n\nconst createHistoryProvider = (\n storage: AsyncStorageLike,\n prefix: string,\n): FC<PropsWithChildren> => {\n const Provider: FC<PropsWithChildren> = ({ children }) => {\n const aui = useAui();\n const history = useMemo(\n () => new AsyncStorageHistoryAdapter(storage, aui, prefix),\n [aui],\n );\n const adapters = useMemo(() => ({ history }), [history]);\n\n return (\n <RuntimeAdapterProvider adapters={adapters}>\n {children}\n </RuntimeAdapterProvider>\n );\n };\n return Provider;\n};\n\nexport const createLocalStorageAdapter = (\n options: LocalStorageAdapterOptions,\n): RemoteThreadListAdapter => {\n const { storage, prefix = \"@assistant-ui:\", titleGenerator } = options;\n\n const threadsKey = `${prefix}threads`;\n const messagesKey = (threadId: string) => `${prefix}messages:${threadId}`;\n\n const loadThreadMetadata = async (): Promise<StoredThreadMetadata[]> => {\n const raw = await storage.getItem(threadsKey);\n return parseStoredThreadMetadata(raw);\n };\n\n const saveThreadMetadata = async (\n threads: StoredThreadMetadata[],\n ): Promise<void> => {\n await storage.setItem(threadsKey, JSON.stringify(threads));\n };\n\n const adapter: RemoteThreadListAdapter = {\n unstable_Provider: createHistoryProvider(storage, prefix),\n\n async list(): Promise<RemoteThreadListResponse> {\n const threads = await loadThreadMetadata();\n return {\n threads: threads.map((t) => ({\n remoteId: t.remoteId,\n externalId: t.externalId,\n status: t.status,\n title: t.title,\n custom: t.custom,\n })),\n };\n },\n\n async initialize(\n threadId: string,\n ): Promise<RemoteThreadInitializeResponse> {\n const remoteId = threadId;\n const threads = await loadThreadMetadata();\n\n // Only add if not already present\n if (!threads.some((t) => t.remoteId === remoteId)) {\n threads.unshift({\n remoteId,\n status: \"regular\",\n });\n await saveThreadMetadata(threads);\n }\n\n return { remoteId, externalId: undefined };\n },\n\n async rename(remoteId: string, newTitle: string): Promise<void> {\n const threads = await loadThreadMetadata();\n const thread = threads.find((t) => t.remoteId === remoteId);\n if (thread) {\n thread.title = newTitle;\n await saveThreadMetadata(threads);\n }\n },\n\n async updateCustom(\n remoteId: string,\n custom: Record<string, unknown> | undefined,\n ): Promise<void> {\n const threads = await loadThreadMetadata();\n const thread = threads.find((t) => t.remoteId === remoteId);\n if (thread) {\n thread.custom = custom;\n await saveThreadMetadata(threads);\n }\n },\n\n async archive(remoteId: string): Promise<void> {\n const threads = await loadThreadMetadata();\n const thread = threads.find((t) => t.remoteId === remoteId);\n if (thread) {\n thread.status = \"archived\";\n await saveThreadMetadata(threads);\n }\n },\n\n async unarchive(remoteId: string): Promise<void> {\n const threads = await loadThreadMetadata();\n const thread = threads.find((t) => t.remoteId === remoteId);\n if (thread) {\n thread.status = \"regular\";\n await saveThreadMetadata(threads);\n }\n },\n\n async delete(remoteId: string): Promise<void> {\n const threads = await loadThreadMetadata();\n const filtered = threads.filter((t) => t.remoteId !== remoteId);\n await saveThreadMetadata(filtered);\n await storage.removeItem(messagesKey(remoteId));\n },\n\n async fetch(threadId: string): Promise<RemoteThreadMetadata> {\n const threads = await loadThreadMetadata();\n const thread = threads.find((t) => t.remoteId === threadId);\n if (!thread)\n throw new Error(\n `Stored thread \"${threadId}\" not found while fetching thread metadata.`,\n );\n return {\n remoteId: thread.remoteId,\n externalId: thread.externalId,\n status: thread.status,\n title: thread.title,\n custom: thread.custom,\n };\n },\n\n async generateTitle(\n remoteId: string,\n messages: readonly ThreadMessage[],\n ): Promise<AssistantStream> {\n if (titleGenerator) {\n const title = await titleGenerator.generateTitle(messages);\n\n // Update the stored title\n const threads = await loadThreadMetadata();\n const thread = threads.find((t) => t.remoteId === remoteId);\n if (thread) {\n thread.title = title;\n await saveThreadMetadata(threads);\n }\n\n // Return a stream with a single text part\n return createAssistantStream((controller) => {\n controller.appendText(title);\n });\n }\n\n // No title generator — return empty stream\n return createAssistantStream(() => {});\n },\n };\n\n return adapter;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"LocalStorageThreadListAdapter.js","names":["AssistantStream","createAssistantStream","FC","PropsWithChildren","useMemo","useAui","RemoteThreadInitializeResponse","RemoteThreadListAdapter","RemoteThreadListResponse","RemoteThreadMetadata","ThreadHistoryAdapter","ThreadMessage","RunConfig","ExportedMessageRepository","ExportedMessageRepositoryItem","RuntimeAdapterProvider","TitleGenerationAdapter","AsyncStorageLike","getItem","key","Promise","setItem","value","removeItem","KeyedMutationQueue","tails","Map","run","mutation","T","previous","get","result","then","tail","undefined","set","delete","mutationQueues","WeakMap","getMutationQueue","storage","queue","LocalStorageAdapterOptions","prefix","titleGenerator","StoredThreadMetadata","remoteId","externalId","status","title","custom","Record","StoredSystemMessage","Extract","role","StoredUserMessage","StoredAssistantMessage","isRecord","Array","isArray","parseJSON","raw","JSON","parse","parseStoredThread","parseDate","Date","Number","isNaN","getTime","date","isMessageRole","parseStoredThreadMessage","id","content","createdAt","metadata","type","submittedFeedback","submittedFeedbackType","unstable_state","unstable_annotations","unstable_data","steps","timing","NonNullable","isOptimistic","attachments","length","parseStoredThreadMetadata","parsed","flatMap","item","thread","parseStoredMessageRepositoryItem","message","parentId","runConfig","parseStoredMessageRepository","messages","candidateMessages","parsedItem","acceptedIds","Set","has","add","headId","some","AsyncStorageHistoryAdapter","aui","ReturnType","mutationQueue","constructor","_messagesKey","load","threadListItem","getState","append","initialize","repo","idx","findIndex","m","push","stringify","createHistoryProvider","Provider","t0","$","_c","children","t1","history","t2","adapters","t3","createLocalStorageAdapter","options","threadsKey","messagesKey","threadId","loadThreadMetadata","saveThreadMetadata","threads","updateThreadMetadata","update","find","adapter","unstable_Provider","list","map","t","unshift","rename","newTitle","updateCustom","archive","unarchive","filtered","filter","fetch","Error","generateTitle","controller","appendText"],"sources":["../../../src/react/adapters/LocalStorageThreadListAdapter.tsx"],"sourcesContent":["import { type AssistantStream, createAssistantStream } from \"assistant-stream\";\nimport { type FC, type PropsWithChildren, useMemo } from \"react\";\nimport { useAui } from \"@assistant-ui/store\";\nimport type {\n RemoteThreadInitializeResponse,\n RemoteThreadListAdapter,\n RemoteThreadListResponse,\n RemoteThreadMetadata,\n ThreadHistoryAdapter,\n ThreadMessage,\n RunConfig,\n} from \"../../index\";\nimport type {\n ExportedMessageRepository,\n ExportedMessageRepositoryItem,\n} from \"../../internal\";\nimport { RuntimeAdapterProvider } from \"../runtimes/RuntimeAdapterProvider\";\nimport type { TitleGenerationAdapter } from \"./TitleGenerationAdapter\";\n\nexport type AsyncStorageLike = {\n getItem(key: string): Promise<string | null>;\n setItem(key: string, value: string): Promise<void>;\n removeItem(key: string): Promise<void>;\n};\n\nclass KeyedMutationQueue {\n private readonly tails = new Map<string, Promise<void>>();\n\n run<T>(key: string, mutation: () => Promise<T>): Promise<T> {\n const previous = this.tails.get(key);\n const result = previous ? previous.then(mutation) : mutation();\n const tail = result.then(\n () => undefined,\n () => undefined,\n );\n\n this.tails.set(key, tail);\n void tail.then(() => {\n if (this.tails.get(key) === tail) this.tails.delete(key);\n });\n\n return result;\n }\n}\n\nconst mutationQueues = new WeakMap<AsyncStorageLike, KeyedMutationQueue>();\n\nconst getMutationQueue = (storage: AsyncStorageLike): KeyedMutationQueue => {\n let queue = mutationQueues.get(storage);\n if (!queue) {\n queue = new KeyedMutationQueue();\n mutationQueues.set(storage, queue);\n }\n return queue;\n};\n\ntype LocalStorageAdapterOptions = {\n storage: AsyncStorageLike;\n prefix?: string | undefined;\n titleGenerator?: TitleGenerationAdapter | undefined;\n};\n\ntype StoredThreadMetadata = {\n remoteId: string;\n externalId?: string;\n status: \"regular\" | \"archived\";\n title?: string;\n custom?: Record<string, unknown> | undefined;\n};\n\ntype StoredSystemMessage = Extract<ThreadMessage, { role: \"system\" }>;\ntype StoredUserMessage = Extract<ThreadMessage, { role: \"user\" }>;\ntype StoredAssistantMessage = Extract<ThreadMessage, { role: \"assistant\" }>;\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst parseJSON = (raw: string | null): unknown => {\n if (!raw) return undefined;\n try {\n return JSON.parse(raw) as unknown;\n } catch {\n return undefined;\n }\n};\n\nconst parseStoredThread = (value: unknown): StoredThreadMetadata | null => {\n if (!isRecord(value) || typeof value.remoteId !== \"string\") return null;\n\n const status = value.status ?? \"regular\";\n if (status !== \"regular\" && status !== \"archived\") return null;\n\n return {\n remoteId: value.remoteId,\n status,\n ...(typeof value.externalId === \"string\"\n ? { externalId: value.externalId }\n : undefined),\n ...(typeof value.title === \"string\" ? { title: value.title } : undefined),\n ...(isRecord(value.custom) ? { custom: value.custom } : undefined),\n };\n};\n\nconst parseDate = (value: unknown): Date | null => {\n if (value instanceof Date && !Number.isNaN(value.getTime())) return value;\n if (typeof value !== \"string\" && typeof value !== \"number\") return null;\n\n const date = new Date(value);\n return Number.isNaN(date.getTime()) ? null : date;\n};\n\nconst isMessageRole = (value: unknown): value is ThreadMessage[\"role\"] =>\n value === \"system\" || value === \"user\" || value === \"assistant\";\n\nconst parseStoredThreadMessage = (value: unknown): ThreadMessage | null => {\n if (!isRecord(value) || typeof value.id !== \"string\") return null;\n if (!isMessageRole(value.role)) return null;\n if (!Array.isArray(value.content)) return null;\n\n const createdAt = parseDate(value.createdAt);\n if (!createdAt) return null;\n\n const metadata = value.metadata;\n if (!isRecord(metadata) || !isRecord(metadata.custom)) return null;\n\n if (value.role === \"assistant\") {\n const status = value.status;\n if (!isRecord(status) || typeof status.type !== \"string\") return null;\n\n const submittedFeedback = isRecord(metadata.submittedFeedback)\n ? metadata.submittedFeedback\n : undefined;\n const submittedFeedbackType = submittedFeedback?.type;\n\n return {\n id: value.id,\n role: \"assistant\",\n content: value.content as StoredAssistantMessage[\"content\"],\n status: status as StoredAssistantMessage[\"status\"],\n createdAt,\n metadata: {\n unstable_state: (metadata.unstable_state ??\n null) as StoredAssistantMessage[\"metadata\"][\"unstable_state\"],\n unstable_annotations: Array.isArray(metadata.unstable_annotations)\n ? (metadata.unstable_annotations as StoredAssistantMessage[\"metadata\"][\"unstable_annotations\"])\n : [],\n unstable_data: Array.isArray(metadata.unstable_data)\n ? (metadata.unstable_data as StoredAssistantMessage[\"metadata\"][\"unstable_data\"])\n : [],\n steps: Array.isArray(metadata.steps)\n ? (metadata.steps as StoredAssistantMessage[\"metadata\"][\"steps\"])\n : [],\n ...(submittedFeedbackType === \"positive\" ||\n submittedFeedbackType === \"negative\"\n ? {\n submittedFeedback: {\n type: submittedFeedbackType,\n },\n }\n : undefined),\n ...(metadata.timing !== undefined\n ? {\n timing: metadata.timing as NonNullable<\n StoredAssistantMessage[\"metadata\"][\"timing\"]\n >,\n }\n : undefined),\n ...(metadata.isOptimistic === true\n ? { isOptimistic: true }\n : undefined),\n custom: metadata.custom,\n },\n };\n }\n\n if (value.role === \"user\") {\n return {\n id: value.id,\n role: \"user\",\n content: value.content as StoredUserMessage[\"content\"],\n attachments: Array.isArray(value.attachments)\n ? (value.attachments as StoredUserMessage[\"attachments\"])\n : [],\n createdAt,\n metadata: {\n custom: metadata.custom,\n },\n };\n }\n\n if (value.content.length !== 1) return null;\n\n return {\n id: value.id,\n role: \"system\",\n content: [value.content[0] as StoredSystemMessage[\"content\"][0]],\n createdAt,\n metadata: {\n custom: metadata.custom,\n },\n };\n};\n\nexport const parseStoredThreadMetadata = (\n raw: string | null,\n): StoredThreadMetadata[] => {\n const parsed = parseJSON(raw);\n if (!Array.isArray(parsed)) return [];\n\n return parsed.flatMap((item) => {\n const thread = parseStoredThread(item);\n return thread ? [thread] : [];\n });\n};\n\nconst parseStoredMessageRepositoryItem = (\n value: unknown,\n): ExportedMessageRepositoryItem | null => {\n if (!isRecord(value)) return null;\n\n const message = parseStoredThreadMessage(value.message);\n if (!message) return null;\n\n const parentId = value.parentId;\n if (\n parentId !== undefined &&\n parentId !== null &&\n typeof parentId !== \"string\"\n ) {\n return null;\n }\n\n return {\n message,\n parentId: parentId ?? null,\n ...(isRecord(value.runConfig)\n ? { runConfig: value.runConfig as RunConfig }\n : undefined),\n };\n};\n\nexport const parseStoredMessageRepository = (\n raw: string | null,\n): ExportedMessageRepository => {\n const parsed = parseJSON(raw);\n if (!isRecord(parsed) || !Array.isArray(parsed.messages)) {\n return { messages: [] };\n }\n\n const candidateMessages = parsed.messages.flatMap((item) => {\n const parsedItem = parseStoredMessageRepositoryItem(item);\n return parsedItem ? [parsedItem] : [];\n });\n\n const acceptedIds = new Set<string>();\n const messages = candidateMessages.flatMap((item) => {\n if (acceptedIds.has(item.message.id)) return [];\n if (item.parentId !== null && !acceptedIds.has(item.parentId)) return [];\n\n acceptedIds.add(item.message.id);\n return [item];\n });\n\n const headId =\n parsed.headId === null ||\n (typeof parsed.headId === \"string\" &&\n messages.some((item) => item.message.id === parsed.headId))\n ? parsed.headId\n : undefined;\n\n return {\n ...(headId !== undefined ? { headId } : undefined),\n messages,\n };\n};\n\nclass AsyncStorageHistoryAdapter implements ThreadHistoryAdapter {\n private storage: AsyncStorageLike;\n private aui: ReturnType<typeof useAui>;\n private prefix: string;\n private mutationQueue: KeyedMutationQueue;\n\n constructor(\n storage: AsyncStorageLike,\n aui: ReturnType<typeof useAui>,\n prefix: string,\n mutationQueue: KeyedMutationQueue,\n ) {\n this.storage = storage;\n this.aui = aui;\n this.prefix = prefix;\n this.mutationQueue = mutationQueue;\n }\n\n private _messagesKey(remoteId: string) {\n return `${this.prefix}messages:${remoteId}`;\n }\n\n async load(): Promise<ExportedMessageRepository> {\n const remoteId = this.aui.threadListItem().getState().remoteId;\n if (!remoteId) return { messages: [] };\n\n const raw = await this.storage.getItem(this._messagesKey(remoteId));\n return parseStoredMessageRepository(raw);\n }\n\n async append(item: ExportedMessageRepositoryItem): Promise<void> {\n const { remoteId } = await this.aui.threadListItem().initialize();\n\n const key = this._messagesKey(remoteId);\n await this.mutationQueue.run(key, async () => {\n const raw = await this.storage.getItem(key);\n const repo = parseStoredMessageRepository(raw);\n\n const idx = repo.messages.findIndex(\n (m) => m.message.id === item.message.id,\n );\n if (idx >= 0) {\n repo.messages[idx] = item;\n } else {\n repo.messages.push(item);\n }\n repo.headId = item.message.id;\n\n await this.storage.setItem(key, JSON.stringify(repo));\n });\n }\n}\n\nconst createHistoryProvider = (\n storage: AsyncStorageLike,\n prefix: string,\n mutationQueue: KeyedMutationQueue,\n): FC<PropsWithChildren> => {\n const Provider: FC<PropsWithChildren> = ({ children }) => {\n const aui = useAui();\n const history = useMemo(\n () => new AsyncStorageHistoryAdapter(storage, aui, prefix, mutationQueue),\n [aui],\n );\n const adapters = useMemo(() => ({ history }), [history]);\n\n return (\n <RuntimeAdapterProvider adapters={adapters}>\n {children}\n </RuntimeAdapterProvider>\n );\n };\n return Provider;\n};\n\nexport const createLocalStorageAdapter = (\n options: LocalStorageAdapterOptions,\n): RemoteThreadListAdapter => {\n const { storage, prefix = \"@assistant-ui:\", titleGenerator } = options;\n\n const threadsKey = `${prefix}threads`;\n const messagesKey = (threadId: string) => `${prefix}messages:${threadId}`;\n const mutationQueue = getMutationQueue(storage);\n\n const loadThreadMetadata = async (): Promise<StoredThreadMetadata[]> => {\n const raw = await storage.getItem(threadsKey);\n return parseStoredThreadMetadata(raw);\n };\n\n const saveThreadMetadata = async (\n threads: StoredThreadMetadata[],\n ): Promise<void> => {\n await storage.setItem(threadsKey, JSON.stringify(threads));\n };\n\n const updateThreadMetadata = async (\n remoteId: string,\n update: (thread: StoredThreadMetadata) => void,\n ): Promise<void> => {\n await mutationQueue.run(threadsKey, async () => {\n const threads = await loadThreadMetadata();\n const thread = threads.find((item) => item.remoteId === remoteId);\n if (thread) {\n update(thread);\n await saveThreadMetadata(threads);\n }\n });\n };\n\n const adapter: RemoteThreadListAdapter = {\n unstable_Provider: createHistoryProvider(storage, prefix, mutationQueue),\n\n async list(): Promise<RemoteThreadListResponse> {\n const threads = await loadThreadMetadata();\n return {\n threads: threads.map((t) => ({\n remoteId: t.remoteId,\n externalId: t.externalId,\n status: t.status,\n title: t.title,\n custom: t.custom,\n })),\n };\n },\n\n async initialize(\n threadId: string,\n ): Promise<RemoteThreadInitializeResponse> {\n const remoteId = threadId;\n return mutationQueue.run(threadsKey, async () => {\n const threads = await loadThreadMetadata();\n\n // Only add if not already present\n if (!threads.some((t) => t.remoteId === remoteId)) {\n threads.unshift({\n remoteId,\n status: \"regular\",\n });\n await saveThreadMetadata(threads);\n }\n\n return { remoteId, externalId: undefined };\n });\n },\n\n async rename(remoteId: string, newTitle: string): Promise<void> {\n await updateThreadMetadata(remoteId, (thread) => {\n thread.title = newTitle;\n });\n },\n\n async updateCustom(\n remoteId: string,\n custom: Record<string, unknown> | undefined,\n ): Promise<void> {\n await updateThreadMetadata(remoteId, (thread) => {\n thread.custom = custom;\n });\n },\n\n async archive(remoteId: string): Promise<void> {\n await updateThreadMetadata(remoteId, (thread) => {\n thread.status = \"archived\";\n });\n },\n\n async unarchive(remoteId: string): Promise<void> {\n await updateThreadMetadata(remoteId, (thread) => {\n thread.status = \"regular\";\n });\n },\n\n async delete(remoteId: string): Promise<void> {\n await mutationQueue.run(threadsKey, async () => {\n const threads = await loadThreadMetadata();\n const filtered = threads.filter((t) => t.remoteId !== remoteId);\n await saveThreadMetadata(filtered);\n });\n const key = messagesKey(remoteId);\n await mutationQueue.run(key, () => storage.removeItem(key));\n },\n\n async fetch(threadId: string): Promise<RemoteThreadMetadata> {\n const threads = await loadThreadMetadata();\n const thread = threads.find((t) => t.remoteId === threadId);\n if (!thread)\n throw new Error(\n `Stored thread \"${threadId}\" not found while fetching thread metadata.`,\n );\n return {\n remoteId: thread.remoteId,\n externalId: thread.externalId,\n status: thread.status,\n title: thread.title,\n custom: thread.custom,\n };\n },\n\n async generateTitle(\n remoteId: string,\n messages: readonly ThreadMessage[],\n ): Promise<AssistantStream> {\n if (titleGenerator) {\n const title = await titleGenerator.generateTitle(messages);\n\n // Update the stored title\n await updateThreadMetadata(remoteId, (thread) => {\n thread.title = title;\n });\n\n // Return a stream with a single text part\n return createAssistantStream((controller) => {\n controller.appendText(title);\n });\n }\n\n // No title generator — return empty stream\n return createAssistantStream(() => {});\n },\n };\n\n return adapter;\n};\n"],"mappings":"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"}