@assistant-ui/core 0.3.14 → 0.3.16

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 (341) hide show
  1. package/dist/adapters/voice.js +11 -0
  2. package/dist/adapters/voice.js.map +1 -1
  3. package/dist/index.js +1 -1
  4. package/dist/internal.d.ts +8 -2
  5. package/dist/internal.js +9 -3
  6. package/dist/model-context/frame/host.d.ts +1 -1
  7. package/dist/model-context/frame/host.d.ts.map +1 -1
  8. package/dist/model-context/frame/host.js +20 -5
  9. package/dist/model-context/frame/host.js.map +1 -1
  10. package/dist/model-context/frame/provider.d.ts +6 -0
  11. package/dist/model-context/frame/provider.d.ts.map +1 -1
  12. package/dist/model-context/frame/provider.js +126 -16
  13. package/dist/model-context/frame/provider.js.map +1 -1
  14. package/dist/model-context/frame/types.d.ts +4 -1
  15. package/dist/model-context/frame/types.d.ts.map +1 -1
  16. package/dist/model-context/frame/types.js.map +1 -1
  17. package/dist/model-context/interactable-composer-metadata.d.ts +1 -1
  18. package/dist/model-context/interactable-composer-metadata.js +1 -1
  19. package/dist/model-context/interactable-composer-metadata.js.map +1 -1
  20. package/dist/model-context/registry.d.ts +2 -2
  21. package/dist/model-context/registry.d.ts.map +1 -1
  22. package/dist/model-context/registry.js +9 -28
  23. package/dist/model-context/registry.js.map +1 -1
  24. package/dist/react/client/InMemoryThreadList.d.ts.map +1 -1
  25. package/dist/react/client/InMemoryThreadList.js +24 -20
  26. package/dist/react/client/InMemoryThreadList.js.map +1 -1
  27. package/dist/react/client/Interactables.d.ts.map +1 -1
  28. package/dist/react/client/Interactables.js +59 -177
  29. package/dist/react/client/Interactables.js.map +1 -1
  30. package/dist/react/client/RemoteThreadList.d.ts +1 -1
  31. package/dist/react/client/RemoteThreadList.d.ts.map +1 -1
  32. package/dist/react/client/RemoteThreadList.js +117 -78
  33. package/dist/react/client/RemoteThreadList.js.map +1 -1
  34. package/dist/react/index.d.ts +2 -1
  35. package/dist/react/interactables-legacy/Interactables.d.ts.map +1 -1
  36. package/dist/react/interactables-legacy/Interactables.js +56 -174
  37. package/dist/react/interactables-legacy/Interactables.js.map +1 -1
  38. package/dist/react/interactables-shared/useInteractablePersistenceQueue.d.ts +24 -0
  39. package/dist/react/interactables-shared/useInteractablePersistenceQueue.d.ts.map +1 -0
  40. package/dist/react/interactables-shared/useInteractablePersistenceQueue.js +138 -0
  41. package/dist/react/interactables-shared/useInteractablePersistenceQueue.js.map +1 -0
  42. package/dist/react/primitive-hooks/useActionBarCopy.js +7 -1
  43. package/dist/react/primitive-hooks/useActionBarCopy.js.map +1 -1
  44. package/dist/react/primitive-hooks/useThreadIsEmpty.d.ts +3 -0
  45. package/dist/react/primitive-hooks/useThreadIsEmpty.d.ts.map +1 -1
  46. package/dist/react/primitive-hooks/useThreadIsEmpty.js +3 -0
  47. package/dist/react/primitive-hooks/useThreadIsEmpty.js.map +1 -1
  48. package/dist/react/primitive-hooks/useThreadIsRunning.d.ts +3 -0
  49. package/dist/react/primitive-hooks/useThreadIsRunning.d.ts.map +1 -1
  50. package/dist/react/primitive-hooks/useThreadIsRunning.js +3 -0
  51. package/dist/react/primitive-hooks/useThreadIsRunning.js.map +1 -1
  52. package/dist/react/primitives/composer/ComposerIf.js.map +1 -1
  53. package/dist/react/primitives/composer/ComposerQueue.d.ts +2 -1
  54. package/dist/react/primitives/composer/ComposerQueue.d.ts.map +1 -1
  55. package/dist/react/primitives/message/MessageParts.js.map +1 -1
  56. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts +3 -1
  57. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
  58. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +6 -0
  59. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
  60. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +7 -1
  61. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
  62. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +174 -64
  63. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
  64. package/dist/react/runtimes/RemoteThreadResource.d.ts.map +1 -1
  65. package/dist/react/runtimes/RemoteThreadResource.js +2 -0
  66. package/dist/react/runtimes/RemoteThreadResource.js.map +1 -1
  67. package/dist/react/runtimes/assistant-transport/runManager.d.ts.map +1 -1
  68. package/dist/react/runtimes/assistant-transport/runManager.js +2 -12
  69. package/dist/react/runtimes/assistant-transport/runManager.js.map +1 -1
  70. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.d.ts.map +1 -1
  71. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.js +1 -1
  72. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.js.map +1 -1
  73. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts +3 -10
  74. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
  75. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +20 -67
  76. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
  77. package/dist/react/runtimes/cloud/createCloudThreadListAdapterCreateFallback.d.ts +12 -0
  78. package/dist/react/runtimes/cloud/createCloudThreadListAdapterCreateFallback.d.ts.map +1 -0
  79. package/dist/react/runtimes/cloud/createCloudThreadListAdapterCreateFallback.js +10 -0
  80. package/dist/react/runtimes/cloud/createCloudThreadListAdapterCreateFallback.js.map +1 -0
  81. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.d.ts.map +1 -1
  82. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js +38 -5
  83. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js.map +1 -1
  84. package/dist/react/runtimes/cloud/useCloudThreadListRuntime.js.map +1 -1
  85. package/dist/react/runtimes/createMessageConverter.d.ts +2 -1
  86. package/dist/react/runtimes/createMessageConverter.d.ts.map +1 -1
  87. package/dist/react/runtimes/external-message-converter.d.ts +6 -25
  88. package/dist/react/runtimes/external-message-converter.d.ts.map +1 -1
  89. package/dist/react/runtimes/external-message-converter.js +33 -233
  90. package/dist/react/runtimes/external-message-converter.js.map +1 -1
  91. package/dist/runtime/api/composer-runtime.d.ts +1 -1
  92. package/dist/runtime/api/composer-runtime.js.map +1 -1
  93. package/dist/runtime/api/thread-runtime.d.ts +1 -2
  94. package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
  95. package/dist/runtime/base/base-composer-runtime-core.d.ts +1 -1
  96. package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
  97. package/dist/runtime/base/base-composer-runtime-core.js +14 -29
  98. package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
  99. package/dist/runtime/base/base-thread-runtime-core.d.ts +2 -4
  100. package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
  101. package/dist/runtime/base/base-thread-runtime-core.js +3 -9
  102. package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
  103. package/dist/runtime/base/default-thread-composer-runtime-core.d.ts +1 -1
  104. package/dist/runtime/base/default-thread-composer-runtime-core.d.ts.map +1 -1
  105. package/dist/runtime/base/default-thread-composer-runtime-core.js +1 -1
  106. package/dist/runtime/base/default-thread-composer-runtime-core.js.map +1 -1
  107. package/dist/runtime/interfaces/composer-runtime-core.d.ts +1 -1
  108. package/dist/runtime/interfaces/thread-runtime-core.d.ts +1 -1
  109. package/dist/runtime/internal.d.ts +2 -1
  110. package/dist/runtime/internal.js +2 -1
  111. package/dist/runtime/queue/external-thread-queue-adapter.d.ts +1 -1
  112. package/dist/runtime/queue/message-queue.d.ts.map +1 -1
  113. package/dist/runtime/queue/message-queue.js +1 -1
  114. package/dist/runtime/queue/message-queue.js.map +1 -1
  115. package/dist/runtime/queue/queue-item.d.ts +12 -0
  116. package/dist/runtime/queue/queue-item.d.ts.map +1 -0
  117. package/dist/runtime/queue/queue-item.js +6 -0
  118. package/dist/runtime/queue/queue-item.js.map +1 -0
  119. package/dist/runtime/utils/abortable-thread-load.d.ts +15 -0
  120. package/dist/runtime/utils/abortable-thread-load.d.ts.map +1 -0
  121. package/dist/runtime/utils/abortable-thread-load.js +35 -0
  122. package/dist/runtime/utils/abortable-thread-load.js.map +1 -0
  123. package/dist/runtime/utils/attachment-add-operations.d.ts +18 -0
  124. package/dist/runtime/utils/attachment-add-operations.d.ts.map +1 -0
  125. package/dist/runtime/utils/attachment-add-operations.js +43 -0
  126. package/dist/runtime/utils/attachment-add-operations.js.map +1 -0
  127. package/dist/runtime/utils/auto-status.d.ts +6 -1
  128. package/dist/runtime/utils/auto-status.d.ts.map +1 -1
  129. package/dist/runtime/utils/auto-status.js +7 -1
  130. package/dist/runtime/utils/auto-status.js.map +1 -1
  131. package/dist/runtime/utils/external-message-conversion.d.ts +47 -0
  132. package/dist/runtime/utils/external-message-conversion.d.ts.map +1 -0
  133. package/dist/runtime/utils/external-message-conversion.js +221 -0
  134. package/dist/runtime/utils/external-message-conversion.js.map +1 -0
  135. package/dist/runtime/utils/external-store-message.d.ts +2 -1
  136. package/dist/runtime/utils/external-store-message.d.ts.map +1 -1
  137. package/dist/runtime/utils/external-store-message.js +2 -1
  138. package/dist/runtime/utils/external-store-message.js.map +1 -1
  139. package/dist/runtime/utils/message-repository-session.d.ts +30 -0
  140. package/dist/runtime/utils/message-repository-session.d.ts.map +1 -0
  141. package/dist/runtime/utils/message-repository-session.js +130 -0
  142. package/dist/runtime/utils/message-repository-session.js.map +1 -0
  143. package/dist/runtime/utils/message-repository.d.ts.map +1 -1
  144. package/dist/runtime/utils/message-repository.js +30 -22
  145. package/dist/runtime/utils/message-repository.js.map +1 -1
  146. package/dist/runtime/utils/pending-tool-calls.d.ts +20 -0
  147. package/dist/runtime/utils/pending-tool-calls.d.ts.map +1 -0
  148. package/dist/runtime/utils/pending-tool-calls.js +22 -0
  149. package/dist/runtime/utils/pending-tool-calls.js.map +1 -0
  150. package/dist/runtime/utils/thread-message-like.d.ts +2 -1
  151. package/dist/runtime/utils/thread-message-like.d.ts.map +1 -1
  152. package/dist/runtime/utils/thread-message-like.js.map +1 -1
  153. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts +2 -5
  154. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts.map +1 -1
  155. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js +3 -10
  156. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js.map +1 -1
  157. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts +19 -1
  158. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
  159. package/dist/runtimes/external-store/external-store-thread-runtime-core.js +124 -20
  160. package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
  161. package/dist/runtimes/inert/InertThreadRuntimeCore.d.ts +102 -0
  162. package/dist/runtimes/inert/InertThreadRuntimeCore.d.ts.map +1 -0
  163. package/dist/runtimes/inert/InertThreadRuntimeCore.js +156 -0
  164. package/dist/runtimes/inert/InertThreadRuntimeCore.js.map +1 -0
  165. package/dist/runtimes/local/local-thread-runtime-core.d.ts +3 -1
  166. package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
  167. package/dist/runtimes/local/local-thread-runtime-core.js +45 -8
  168. package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
  169. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts +12 -60
  170. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts.map +1 -1
  171. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.js +10 -145
  172. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.js.map +1 -1
  173. package/dist/runtimes/remote-thread-list/adapter-changed.d.ts +9 -0
  174. package/dist/runtimes/remote-thread-list/adapter-changed.d.ts.map +1 -0
  175. package/dist/runtimes/remote-thread-list/adapter-changed.js +13 -0
  176. package/dist/runtimes/remote-thread-list/adapter-changed.js.map +1 -0
  177. package/dist/runtimes/remote-thread-list/empty-thread-core.d.ts.map +1 -1
  178. package/dist/runtimes/remote-thread-list/empty-thread-core.js +16 -155
  179. package/dist/runtimes/remote-thread-list/empty-thread-core.js.map +1 -1
  180. package/dist/runtimes/remote-thread-list/optimistic-state.d.ts +2 -0
  181. package/dist/runtimes/remote-thread-list/optimistic-state.d.ts.map +1 -1
  182. package/dist/runtimes/remote-thread-list/optimistic-state.js +11 -0
  183. package/dist/runtimes/remote-thread-list/optimistic-state.js.map +1 -1
  184. package/dist/runtimes/remote-thread-list/remote-thread-state.d.ts +12 -1
  185. package/dist/runtimes/remote-thread-list/remote-thread-state.d.ts.map +1 -1
  186. package/dist/runtimes/remote-thread-list/remote-thread-state.js +77 -1
  187. package/dist/runtimes/remote-thread-list/remote-thread-state.js.map +1 -1
  188. package/dist/runtimes/remote-thread-list/types.d.ts +3 -0
  189. package/dist/runtimes/remote-thread-list/types.d.ts.map +1 -1
  190. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts.map +1 -1
  191. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js +2 -0
  192. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js.map +1 -1
  193. package/dist/store/clients/external-thread.d.ts.map +1 -1
  194. package/dist/store/clients/external-thread.js +75 -100
  195. package/dist/store/clients/external-thread.js.map +1 -1
  196. package/dist/store/clients/single-thread-list.d.ts.map +1 -1
  197. package/dist/store/clients/single-thread-list.js +1 -1
  198. package/dist/store/clients/single-thread-list.js.map +1 -1
  199. package/dist/store/clients/suggestions.d.ts.map +1 -1
  200. package/dist/store/clients/suggestions.js +16 -7
  201. package/dist/store/clients/suggestions.js.map +1 -1
  202. package/dist/store/index.d.ts +4 -2
  203. package/dist/store/runtime-clients/handle-runtime-action.d.ts.map +1 -1
  204. package/dist/store/runtime-clients/handle-runtime-action.js +2 -0
  205. package/dist/store/runtime-clients/handle-runtime-action.js.map +1 -1
  206. package/dist/store/scope-registration.d.ts +1 -1
  207. package/dist/store/scopes/composer.d.ts +2 -1
  208. package/dist/store/scopes/composer.d.ts.map +1 -1
  209. package/dist/store/scopes/message.d.ts +1 -1
  210. package/dist/store/scopes/queue-item.d.ts +2 -9
  211. package/dist/store/scopes/queue-item.d.ts.map +1 -1
  212. package/dist/store/scopes/queue-item.js +0 -6
  213. package/dist/types/message.d.ts +8 -4
  214. package/dist/types/message.d.ts.map +1 -1
  215. package/dist/types/message.js.map +1 -1
  216. package/dist/utils/data-url.d.ts +14 -1
  217. package/dist/utils/data-url.d.ts.map +1 -1
  218. package/dist/utils/data-url.js +13 -1
  219. package/dist/utils/data-url.js.map +1 -1
  220. package/dist/utils/invoke-user-callback.d.ts +5 -0
  221. package/dist/utils/invoke-user-callback.d.ts.map +1 -0
  222. package/dist/utils/invoke-user-callback.js +19 -0
  223. package/dist/utils/invoke-user-callback.js.map +1 -0
  224. package/dist/utils/normalizePartStatus.js.map +1 -1
  225. package/dist/utils/silent-runtime-action.d.ts +6 -0
  226. package/dist/utils/silent-runtime-action.d.ts.map +1 -0
  227. package/dist/utils/silent-runtime-action.js +7 -0
  228. package/dist/utils/silent-runtime-action.js.map +1 -0
  229. package/package.json +10 -10
  230. package/src/adapters/voice.test.ts +66 -1
  231. package/src/adapters/voice.ts +8 -0
  232. package/src/internal.ts +13 -0
  233. package/src/model-context/frame/host.test.ts +152 -9
  234. package/src/model-context/frame/host.ts +23 -5
  235. package/src/model-context/frame/provider.test.ts +601 -19
  236. package/src/model-context/frame/provider.ts +158 -20
  237. package/src/model-context/frame/types.ts +5 -0
  238. package/src/model-context/interactable-composer-metadata.ts +1 -1
  239. package/src/model-context/registry.test.ts +44 -0
  240. package/src/model-context/registry.ts +13 -35
  241. package/src/react/client/InMemoryThreadList.test.tsx +49 -0
  242. package/src/react/client/InMemoryThreadList.ts +7 -1
  243. package/src/react/client/Interactables.ts +19 -178
  244. package/src/react/client/RemoteThreadList.test.ts +292 -0
  245. package/src/react/client/RemoteThreadList.ts +119 -82
  246. package/src/react/interactables-legacy/Interactables.ts +20 -177
  247. package/src/react/interactables-shared/useInteractablePersistenceQueue.test.tsx +161 -0
  248. package/src/react/interactables-shared/useInteractablePersistenceQueue.ts +206 -0
  249. package/src/react/primitive-hooks/useActionBarCopy.test.ts +15 -0
  250. package/src/react/primitive-hooks/useActionBarCopy.ts +13 -3
  251. package/src/react/primitive-hooks/useThreadIsEmpty.ts +3 -0
  252. package/src/react/primitive-hooks/useThreadIsRunning.ts +3 -0
  253. package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +12 -0
  254. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.republish.test.ts +87 -0
  255. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +251 -76
  256. package/src/react/runtimes/RemoteThreadResource.ts +2 -0
  257. package/src/react/runtimes/assistant-transport/runManager.ts +4 -17
  258. package/src/react/runtimes/assistant-transport/useAssistantTransportRuntime.test.tsx +58 -0
  259. package/src/react/runtimes/assistant-transport/useAssistantTransportRuntime.ts +3 -1
  260. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.tsx +92 -0
  261. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +40 -141
  262. package/src/react/runtimes/cloud/createCloudThreadListAdapterCreateFallback.test.ts +37 -0
  263. package/src/react/runtimes/cloud/createCloudThreadListAdapterCreateFallback.ts +18 -0
  264. package/src/react/runtimes/cloud/useCloudThreadListAdapter.test.tsx +98 -3
  265. package/src/react/runtimes/cloud/useCloudThreadListAdapter.tsx +68 -6
  266. package/src/react/runtimes/external-message-converter.test.ts +0 -14
  267. package/src/react/runtimes/external-message-converter.test.tsx +77 -0
  268. package/src/react/runtimes/external-message-converter.ts +58 -481
  269. package/src/react/runtimes/useLocalRuntime.test.tsx +5 -5
  270. package/src/runtime/api/composer-runtime.ts +1 -1
  271. package/src/runtime/api/message-runtime.test.ts +28 -1
  272. package/src/runtime/base/base-composer-runtime-core.ts +20 -40
  273. package/src/runtime/base/base-thread-runtime-core.test.ts +16 -0
  274. package/src/runtime/base/base-thread-runtime-core.ts +6 -11
  275. package/src/runtime/base/default-thread-composer-runtime-core.ts +1 -4
  276. package/src/runtime/interfaces/composer-runtime-core.ts +1 -1
  277. package/src/runtime/interfaces/thread-runtime-core.ts +1 -1
  278. package/src/runtime/internal.ts +5 -0
  279. package/src/runtime/queue/external-thread-queue-adapter.ts +1 -1
  280. package/src/runtime/queue/message-queue.ts +1 -4
  281. package/src/runtime/queue/queue-item.ts +10 -0
  282. package/src/runtime/utils/abortable-thread-load.test.ts +87 -0
  283. package/src/runtime/utils/abortable-thread-load.ts +53 -0
  284. package/src/runtime/utils/attachment-add-operations.ts +59 -0
  285. package/src/runtime/utils/auto-status.ts +33 -0
  286. package/src/runtime/utils/external-message-conversion.test.ts +113 -0
  287. package/src/runtime/utils/external-message-conversion.ts +494 -0
  288. package/src/runtime/utils/external-store-message.ts +2 -0
  289. package/src/runtime/utils/message-repository-session.test.ts +195 -0
  290. package/src/runtime/utils/message-repository-session.ts +176 -0
  291. package/src/runtime/utils/message-repository.ts +33 -22
  292. package/src/runtime/utils/pending-tool-calls.test.ts +57 -0
  293. package/src/runtime/utils/pending-tool-calls.ts +35 -0
  294. package/src/runtime/utils/thread-message-like.ts +2 -0
  295. package/src/runtimes/external-store/external-store-thread-list-runtime-core.ts +6 -14
  296. package/src/runtimes/external-store/external-store-thread-runtime-core.ts +179 -28
  297. package/src/runtimes/inert/InertThreadRuntimeCore.test.ts +253 -0
  298. package/src/runtimes/inert/InertThreadRuntimeCore.ts +232 -0
  299. package/src/runtimes/local/local-thread-runtime-core.test.ts +491 -1
  300. package/src/runtimes/local/local-thread-runtime-core.ts +86 -11
  301. package/src/runtimes/readonly/ReadonlyThreadRuntimeCore.ts +17 -209
  302. package/src/runtimes/remote-thread-list/adapter-changed.ts +10 -0
  303. package/src/runtimes/remote-thread-list/empty-thread-core.ts +28 -221
  304. package/src/runtimes/remote-thread-list/optimistic-state.test.ts +18 -0
  305. package/src/runtimes/remote-thread-list/optimistic-state.ts +13 -0
  306. package/src/runtimes/remote-thread-list/remote-thread-state.test.ts +37 -0
  307. package/src/runtimes/remote-thread-list/remote-thread-state.ts +123 -0
  308. package/src/runtimes/remote-thread-list/types.ts +4 -0
  309. package/src/runtimes/tool-invocations/EDGE_CASES.md +17 -0
  310. package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +140 -0
  311. package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +3 -0
  312. package/src/store/clients/external-thread.ts +17 -62
  313. package/src/store/clients/single-thread-list.ts +4 -1
  314. package/src/store/clients/suggestions.test.ts +31 -0
  315. package/src/store/clients/suggestions.ts +18 -19
  316. package/src/store/runtime-clients/handle-runtime-action.test.ts +40 -0
  317. package/src/store/runtime-clients/handle-runtime-action.ts +3 -0
  318. package/src/store/scopes/message.ts +1 -1
  319. package/src/store/scopes/queue-item.ts +2 -9
  320. package/src/tests/MessageRepository.test.ts +125 -0
  321. package/src/tests/RemoteThreadListThreadListRuntimeCore-errors.test.ts +2 -2
  322. package/src/tests/RemoteThreadListThreadListRuntimeCore-load-race.test.ts +194 -0
  323. package/src/tests/RemoteThreadListThreadListRuntimeCore-loadMore.test.ts +8 -6
  324. package/src/tests/RemoteThreadListThreadListRuntimeCore-title-race.test.ts +158 -0
  325. package/src/tests/empty-thread-core.test.ts +6 -0
  326. package/src/tests/external-store-thread-runtime-core-adapter.test.ts +184 -0
  327. package/src/tests/external-store-thread-runtime-core.test.ts +642 -0
  328. package/src/tests/external-thread-attachments.test.tsx +173 -0
  329. package/src/tests/external-thread-isEmpty.test.tsx +100 -0
  330. package/src/tests/remote-thread-list-adapter-switch.test.ts +383 -0
  331. package/src/tests/single-thread-list-item.test.tsx +47 -0
  332. package/src/tests/thread-message-like.test.ts +39 -1
  333. package/src/tests/useRemoteThreadListRuntime-controlled.test.tsx +67 -0
  334. package/src/types/message.ts +9 -4
  335. package/src/utils/data-url.test.ts +52 -1
  336. package/src/utils/data-url.ts +21 -0
  337. package/src/utils/invoke-user-callback.test.ts +82 -0
  338. package/src/utils/invoke-user-callback.ts +31 -0
  339. package/src/utils/normalizePartStatus.ts +1 -1
  340. package/src/utils/silent-runtime-action.ts +6 -0
  341. package/dist/store/scopes/queue-item.js.map +0 -1
@@ -66,6 +66,13 @@ function createVoiceSession(options, setup) {
66
66
  if (disconnected) return;
67
67
  disconnected = true;
68
68
  detachAbortHandler();
69
+ if (currentStatus.type !== "ended") {
70
+ currentStatus = {
71
+ type: "ended",
72
+ reason: "cancelled"
73
+ };
74
+ notifyEventListeners(statusCbs, currentStatus, "Voice session");
75
+ }
69
76
  try {
70
77
  controls?.disconnect();
71
78
  } finally {
@@ -100,6 +107,10 @@ function createVoiceSession(options, setup) {
100
107
  if (abortSignal) {
101
108
  abortHandler = () => session.disconnect();
102
109
  abortSignal.addEventListener("abort", abortHandler, { once: true });
110
+ if (abortSignal.aborted) {
111
+ session.disconnect();
112
+ return session;
113
+ }
103
114
  }
104
115
  const doSetup = async () => {
105
116
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"voice.js","names":["Unsubscribe","notifyEventListeners","RealtimeVoiceAdapter","Status","type","reason","error","Mode","TranscriptItem","role","text","isFinal","Session","status","isMuted","disconnect","mute","unmute","onStatusChange","callback","onTranscript","transcript","onModeChange","mode","onVolumeChange","volume","connect","options","abortSignal","AbortSignal","VoiceSessionControls","VoiceSessionHelpers","setStatus","end","emitTranscript","item","emitMode","emitVolume","isDisposed","createVoiceSession","setup","helpers","Promise","statusCbs","Set","s","transcriptCbs","t","modeCbs","m","volumeCbs","v","currentStatus","disposed","disconnected","controls","abortHandler","detachAbortHandler","removeEventListener","undefined","cleanup","clear","session","cb","add","delete","addEventListener","once","doSetup"],"sources":["../../src/adapters/voice.ts"],"sourcesContent":["import type { Unsubscribe } from \"../types/unsubscribe\";\nimport { notifyEventListeners } from \"../utils/notify-event-listeners\";\n\nexport namespace RealtimeVoiceAdapter {\n export type Status =\n | {\n type: \"starting\" | \"running\";\n }\n | {\n type: \"ended\";\n reason: \"finished\" | \"cancelled\" | \"error\";\n error?: unknown;\n };\n\n export type Mode = \"listening\" | \"speaking\";\n\n export type TranscriptItem = {\n role: \"user\" | \"assistant\";\n text: string;\n isFinal?: boolean;\n };\n\n export type Session = {\n status: Status;\n isMuted: boolean;\n\n disconnect: () => void;\n mute: () => void;\n unmute: () => void;\n\n onStatusChange: (callback: (status: Status) => void) => Unsubscribe;\n onTranscript: (\n callback: (transcript: TranscriptItem) => void,\n ) => Unsubscribe;\n onModeChange: (callback: (mode: Mode) => void) => Unsubscribe;\n onVolumeChange: (callback: (volume: number) => void) => Unsubscribe;\n };\n}\n\nexport type RealtimeVoiceAdapter = {\n connect: (options: {\n abortSignal?: AbortSignal;\n }) => RealtimeVoiceAdapter.Session;\n};\n\nexport type VoiceSessionControls = {\n disconnect: () => void;\n mute: () => void;\n unmute: () => void;\n};\n\nexport type VoiceSessionHelpers = {\n setStatus: (status: RealtimeVoiceAdapter.Status) => void;\n end: (reason: \"finished\" | \"cancelled\" | \"error\", error?: unknown) => void;\n emitTranscript: (item: RealtimeVoiceAdapter.TranscriptItem) => void;\n emitMode: (mode: RealtimeVoiceAdapter.Mode) => void;\n emitVolume: (volume: number) => void;\n isDisposed: () => boolean;\n};\n\nexport function createVoiceSession(\n options: { abortSignal?: AbortSignal },\n setup: (helpers: VoiceSessionHelpers) => Promise<VoiceSessionControls>,\n): RealtimeVoiceAdapter.Session {\n const statusCbs = new Set<(s: RealtimeVoiceAdapter.Status) => void>();\n const transcriptCbs = new Set<\n (t: RealtimeVoiceAdapter.TranscriptItem) => void\n >();\n const modeCbs = new Set<(m: RealtimeVoiceAdapter.Mode) => void>();\n const volumeCbs = new Set<(v: number) => void>();\n\n let currentStatus: RealtimeVoiceAdapter.Status = { type: \"starting\" };\n let isMuted = false;\n let disposed = false;\n let disconnected = false;\n let controls: VoiceSessionControls | null = null;\n const abortSignal = options.abortSignal;\n let abortHandler: (() => void) | undefined;\n\n const detachAbortHandler = () => {\n if (abortHandler) {\n abortSignal?.removeEventListener(\"abort\", abortHandler);\n abortHandler = undefined;\n }\n };\n\n const cleanup = () => {\n disposed = true;\n statusCbs.clear();\n transcriptCbs.clear();\n modeCbs.clear();\n volumeCbs.clear();\n };\n\n const helpers: VoiceSessionHelpers = {\n setStatus: (status) => {\n if (disposed) return;\n currentStatus = status;\n notifyEventListeners(statusCbs, status, \"Voice session\");\n },\n end: (reason, error?) => {\n if (disposed) return;\n currentStatus = { type: \"ended\", reason, error };\n notifyEventListeners(statusCbs, currentStatus, \"Voice session\");\n cleanup();\n },\n emitTranscript: (item) => {\n if (disposed) return;\n notifyEventListeners(transcriptCbs, item, \"Voice session\");\n },\n emitMode: (mode) => {\n if (disposed) return;\n notifyEventListeners(modeCbs, mode, \"Voice session\");\n },\n emitVolume: (volume) => {\n if (disposed) return;\n notifyEventListeners(volumeCbs, volume, \"Voice session\");\n },\n isDisposed: () => disposed,\n };\n\n const session: RealtimeVoiceAdapter.Session = {\n get status() {\n return currentStatus;\n },\n get isMuted() {\n return isMuted;\n },\n disconnect: () => {\n if (disconnected) return;\n disconnected = true;\n detachAbortHandler();\n try {\n controls?.disconnect();\n } finally {\n cleanup();\n }\n },\n mute: () => {\n controls?.mute();\n isMuted = true;\n },\n unmute: () => {\n controls?.unmute();\n isMuted = false;\n },\n onStatusChange: (cb) => {\n statusCbs.add(cb);\n return () => statusCbs.delete(cb);\n },\n onTranscript: (cb) => {\n transcriptCbs.add(cb);\n return () => transcriptCbs.delete(cb);\n },\n onModeChange: (cb) => {\n modeCbs.add(cb);\n return () => modeCbs.delete(cb);\n },\n onVolumeChange: (cb) => {\n volumeCbs.add(cb);\n return () => volumeCbs.delete(cb);\n },\n };\n\n if (abortSignal) {\n abortHandler = () => session.disconnect();\n abortSignal.addEventListener(\"abort\", abortHandler, { once: true });\n }\n\n const doSetup = async () => {\n try {\n if (disposed) return;\n controls = await setup(helpers);\n if (disposed) {\n controls.disconnect();\n } else if (isMuted) {\n controls.mute();\n }\n } catch (error) {\n helpers.end(\"error\", error);\n }\n };\n\n doSetup();\n return session;\n}\n"],"mappings":";;AA4DA,SAAgBuC,mBACdZ,SACAa,OAC8B;CAC9B,MAAMG,4BAAY,IAAIC,IAA8C;CACpE,MAAME,gCAAgB,IAAIF,IAExB;CACF,MAAMI,0BAAU,IAAIJ,IAA4C;CAChE,MAAMM,4BAAY,IAAIN,IAAyB;CAE/C,IAAIQ,gBAA6C,EAAEhD,MAAM,WAAW;CACpE,IAAIU,UAAU;CACd,IAAIuC,WAAW;CACf,IAAIC,eAAe;CACnB,IAAIC,WAAwC;CAC5C,MAAM3B,cAAcD,QAAQC;CAC5B,IAAI4B;CAEJ,MAAMC,2BAA2B;EAC/B,IAAID,cAAc;GAChB5B,aAAa8B,oBAAoB,SAASF,YAAY;GACtDA,eAAeG,KAAAA;EACjB;CACF;CAEA,MAAMC,gBAAgB;EACpBP,WAAW;EACXV,UAAUkB,MAAM;EAChBf,cAAce,MAAM;EACpBb,QAAQa,MAAM;EACdX,UAAUW,MAAM;CAClB;CAEA,MAAMpB,UAA+B;EACnCT,YAAYnB,WAAW;GACrB,IAAIwC,UAAU;GACdD,gBAAgBvC;GAChBZ,qBAAqB0C,WAAW9B,QAAQ,eAAe;EACzD;EACAoB,MAAM5B,QAAQC,UAAW;GACvB,IAAI+C,UAAU;GACdD,gBAAgB;IAAEhD,MAAM;IAASC;IAAQC;GAAM;GAC/CL,qBAAqB0C,WAAWS,eAAe,eAAe;GAC9DQ,QAAQ;EACV;EACA1B,iBAAiBC,SAAS;GACxB,IAAIkB,UAAU;GACdpD,qBAAqB6C,eAAeX,MAAM,eAAe;EAC3D;EACAC,WAAWb,SAAS;GAClB,IAAI8B,UAAU;GACdpD,qBAAqB+C,SAASzB,MAAM,eAAe;EACrD;EACAc,aAAaZ,WAAW;GACtB,IAAI4B,UAAU;GACdpD,qBAAqBiD,WAAWzB,QAAQ,eAAe;EACzD;EACAa,kBAAkBe;CACpB;CAEA,MAAMS,UAAwC;EAC5C,IAAIjD,SAAS;GACX,OAAOuC;EACT;EACA,IAAItC,UAAU;GACZ,OAAOA;EACT;EACAC,kBAAkB;GAChB,IAAIuC,cAAc;GAClBA,eAAe;GACfG,mBAAmB;GACnB,IAAI;IACFF,UAAUxC,WAAW;GACvB,UAAU;IACR6C,QAAQ;GACV;EACF;EACA5C,YAAY;GACVuC,UAAUvC,KAAK;GACfF,UAAU;EACZ;EACAG,cAAc;GACZsC,UAAUtC,OAAO;GACjBH,UAAU;EACZ;EACAI,iBAAiB6C,OAAO;GACtBpB,UAAUqB,IAAID,EAAE;GAChB,aAAapB,UAAUsB,OAAOF,EAAE;EAClC;EACA3C,eAAe2C,OAAO;GACpBjB,cAAckB,IAAID,EAAE;GACpB,aAAajB,cAAcmB,OAAOF,EAAE;EACtC;EACAzC,eAAeyC,OAAO;GACpBf,QAAQgB,IAAID,EAAE;GACd,aAAaf,QAAQiB,OAAOF,EAAE;EAChC;EACAvC,iBAAiBuC,OAAO;GACtBb,UAAUc,IAAID,EAAE;GAChB,aAAab,UAAUe,OAAOF,EAAE;EAClC;CACF;CAEA,IAAInC,aAAa;EACf4B,qBAAqBM,QAAQ/C,WAAW;EACxCa,YAAYsC,iBAAiB,SAASV,cAAc,EAAEW,MAAM,KAAK,CAAC;CACpE;CAEA,MAAMC,UAAU,YAAY;EAC1B,IAAI;GACF,IAAIf,UAAU;GACdE,WAAW,MAAMf,MAAMC,OAAO;GAC9B,IAAIY,UACFE,SAASxC,WAAW;QACf,IAAID,SACTyC,SAASvC,KAAK;EAElB,SAASV,OAAO;GACdmC,QAAQR,IAAI,SAAS3B,KAAK;EAC5B;CACF;CAEA8D,QAAQ;CACR,OAAON;AACT"}
1
+ {"version":3,"file":"voice.js","names":["Unsubscribe","notifyEventListeners","RealtimeVoiceAdapter","Status","type","reason","error","Mode","TranscriptItem","role","text","isFinal","Session","status","isMuted","disconnect","mute","unmute","onStatusChange","callback","onTranscript","transcript","onModeChange","mode","onVolumeChange","volume","connect","options","abortSignal","AbortSignal","VoiceSessionControls","VoiceSessionHelpers","setStatus","end","emitTranscript","item","emitMode","emitVolume","isDisposed","createVoiceSession","setup","helpers","Promise","statusCbs","Set","s","transcriptCbs","t","modeCbs","m","volumeCbs","v","currentStatus","disposed","disconnected","controls","abortHandler","detachAbortHandler","removeEventListener","undefined","cleanup","clear","session","cb","add","delete","addEventListener","once","aborted","doSetup"],"sources":["../../src/adapters/voice.ts"],"sourcesContent":["import type { Unsubscribe } from \"../types/unsubscribe\";\nimport { notifyEventListeners } from \"../utils/notify-event-listeners\";\n\nexport namespace RealtimeVoiceAdapter {\n export type Status =\n | {\n type: \"starting\" | \"running\";\n }\n | {\n type: \"ended\";\n reason: \"finished\" | \"cancelled\" | \"error\";\n error?: unknown;\n };\n\n export type Mode = \"listening\" | \"speaking\";\n\n export type TranscriptItem = {\n role: \"user\" | \"assistant\";\n text: string;\n isFinal?: boolean;\n };\n\n export type Session = {\n status: Status;\n isMuted: boolean;\n\n disconnect: () => void;\n mute: () => void;\n unmute: () => void;\n\n onStatusChange: (callback: (status: Status) => void) => Unsubscribe;\n onTranscript: (\n callback: (transcript: TranscriptItem) => void,\n ) => Unsubscribe;\n onModeChange: (callback: (mode: Mode) => void) => Unsubscribe;\n onVolumeChange: (callback: (volume: number) => void) => Unsubscribe;\n };\n}\n\nexport type RealtimeVoiceAdapter = {\n connect: (options: {\n abortSignal?: AbortSignal;\n }) => RealtimeVoiceAdapter.Session;\n};\n\nexport type VoiceSessionControls = {\n disconnect: () => void;\n mute: () => void;\n unmute: () => void;\n};\n\nexport type VoiceSessionHelpers = {\n setStatus: (status: RealtimeVoiceAdapter.Status) => void;\n end: (reason: \"finished\" | \"cancelled\" | \"error\", error?: unknown) => void;\n emitTranscript: (item: RealtimeVoiceAdapter.TranscriptItem) => void;\n emitMode: (mode: RealtimeVoiceAdapter.Mode) => void;\n emitVolume: (volume: number) => void;\n isDisposed: () => boolean;\n};\n\nexport function createVoiceSession(\n options: { abortSignal?: AbortSignal },\n setup: (helpers: VoiceSessionHelpers) => Promise<VoiceSessionControls>,\n): RealtimeVoiceAdapter.Session {\n const statusCbs = new Set<(s: RealtimeVoiceAdapter.Status) => void>();\n const transcriptCbs = new Set<\n (t: RealtimeVoiceAdapter.TranscriptItem) => void\n >();\n const modeCbs = new Set<(m: RealtimeVoiceAdapter.Mode) => void>();\n const volumeCbs = new Set<(v: number) => void>();\n\n let currentStatus: RealtimeVoiceAdapter.Status = { type: \"starting\" };\n let isMuted = false;\n let disposed = false;\n let disconnected = false;\n let controls: VoiceSessionControls | null = null;\n const abortSignal = options.abortSignal;\n let abortHandler: (() => void) | undefined;\n\n const detachAbortHandler = () => {\n if (abortHandler) {\n abortSignal?.removeEventListener(\"abort\", abortHandler);\n abortHandler = undefined;\n }\n };\n\n const cleanup = () => {\n disposed = true;\n statusCbs.clear();\n transcriptCbs.clear();\n modeCbs.clear();\n volumeCbs.clear();\n };\n\n const helpers: VoiceSessionHelpers = {\n setStatus: (status) => {\n if (disposed) return;\n currentStatus = status;\n notifyEventListeners(statusCbs, status, \"Voice session\");\n },\n end: (reason, error?) => {\n if (disposed) return;\n currentStatus = { type: \"ended\", reason, error };\n notifyEventListeners(statusCbs, currentStatus, \"Voice session\");\n cleanup();\n },\n emitTranscript: (item) => {\n if (disposed) return;\n notifyEventListeners(transcriptCbs, item, \"Voice session\");\n },\n emitMode: (mode) => {\n if (disposed) return;\n notifyEventListeners(modeCbs, mode, \"Voice session\");\n },\n emitVolume: (volume) => {\n if (disposed) return;\n notifyEventListeners(volumeCbs, volume, \"Voice session\");\n },\n isDisposed: () => disposed,\n };\n\n const session: RealtimeVoiceAdapter.Session = {\n get status() {\n return currentStatus;\n },\n get isMuted() {\n return isMuted;\n },\n disconnect: () => {\n if (disconnected) return;\n disconnected = true;\n detachAbortHandler();\n if (currentStatus.type !== \"ended\") {\n currentStatus = { type: \"ended\", reason: \"cancelled\" };\n notifyEventListeners(statusCbs, currentStatus, \"Voice session\");\n }\n try {\n controls?.disconnect();\n } finally {\n cleanup();\n }\n },\n mute: () => {\n controls?.mute();\n isMuted = true;\n },\n unmute: () => {\n controls?.unmute();\n isMuted = false;\n },\n onStatusChange: (cb) => {\n statusCbs.add(cb);\n return () => statusCbs.delete(cb);\n },\n onTranscript: (cb) => {\n transcriptCbs.add(cb);\n return () => transcriptCbs.delete(cb);\n },\n onModeChange: (cb) => {\n modeCbs.add(cb);\n return () => modeCbs.delete(cb);\n },\n onVolumeChange: (cb) => {\n volumeCbs.add(cb);\n return () => volumeCbs.delete(cb);\n },\n };\n\n if (abortSignal) {\n abortHandler = () => session.disconnect();\n abortSignal.addEventListener(\"abort\", abortHandler, { once: true });\n if (abortSignal.aborted) {\n session.disconnect();\n return session;\n }\n }\n\n const doSetup = async () => {\n try {\n if (disposed) return;\n controls = await setup(helpers);\n if (disposed) {\n controls.disconnect();\n } else if (isMuted) {\n controls.mute();\n }\n } catch (error) {\n helpers.end(\"error\", error);\n }\n };\n\n doSetup();\n return session;\n}\n"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -4,10 +4,10 @@ import { mergeModelContexts } from "./model-context/types.js";
4
4
  import { tool } from "./model-context/tool.js";
5
5
  import { unstable_formatInteractableSnapshot, unstable_getInteractableSnapshots, unstable_getInteractableVersions } from "./model-context/interactable-composer-metadata.js";
6
6
  import { ModelContextRegistry } from "./model-context/registry.js";
7
+ import { generateId } from "./utils/id.js";
7
8
  import { FRAME_MESSAGE_CHANNEL } from "./model-context/frame/types.js";
8
9
  import { AssistantFrameHost } from "./model-context/frame/host.js";
9
10
  import { AssistantFrameProvider } from "./model-context/frame/provider.js";
10
- import { generateId } from "./utils/id.js";
11
11
  import { CompositeAttachmentAdapter, SimpleImageAttachmentAdapter, SimpleTextAttachmentAdapter } from "./adapters/attachment.js";
12
12
  import { WebSpeechDictationAdapter, WebSpeechSynthesisAdapter } from "./adapters/speech.js";
13
13
  import { createVoiceSession } from "./adapters/voice.js";
@@ -8,13 +8,18 @@ import { BaseSubject, BaseSubscribable, EventSubscribable, EventSubscriptionSubj
8
8
  import { generateErrorMessageId, generateId, isErrorMessageId } from "./utils/id.js";
9
9
  import { getThreadMessageText } from "./utils/text.js";
10
10
  import { toMessagePartStatus } from "./utils/normalizePartStatus.js";
11
+ import { notifyEventListeners } from "./utils/notify-event-listeners.js";
11
12
  import { resolveToolApprovalResponse } from "./runtime/utils/resolveToolApprovalResponse.js";
12
13
  import { CompositeContextProvider } from "./utils/composite-context-provider.js";
13
14
  import { stableStringifyToolArgs, trackToolArgsKeyOrder } from "./utils/json/stable-stringify-tool-args.js";
14
15
  import { isJSONValue, isRecord } from "./utils/json/is-json.js";
15
- import { dataUrlMediaType, httpUrlPattern, isParsableUrl, parseDataUrl } from "./utils/data-url.js";
16
+ import { FilePartSource, dataUrlMediaType, httpUrlPattern, isParsableUrl, parseDataUrl, resolveFilePartSource } from "./utils/data-url.js";
17
+ import { invokeUserCallback } from "./utils/invoke-user-callback.js";
16
18
  import { detectImageMediaType } from "./utils/image-media-type.js";
17
19
  import { resolveFileMediaType, resolveImageMediaType, toMediaWireUrl } from "./utils/wire-media.js";
20
+ import { createToolCallCancellationStub, scanPendingToolCalls } from "./runtime/utils/pending-tool-calls.js";
21
+ import { AbortableThreadLoadPurpose, createAbortableThreadLoad } from "./runtime/utils/abortable-thread-load.js";
22
+ import { createCloudThreadListAdapterCreateFallback } from "./react/runtimes/cloud/createCloudThreadListAdapterCreateFallback.js";
18
23
  import { ComposerRuntimeCoreBinding, EditComposerRuntimeCoreBinding, MessageStateBinding, ThreadComposerRuntimeCoreBinding } from "./runtime/api/bindings.js";
19
24
  import { BaseAssistantRuntimeCore } from "./runtime/base/base-assistant-runtime-core.js";
20
25
  import { BaseComposerRuntimeCore } from "./runtime/base/base-composer-runtime-core.js";
@@ -29,6 +34,7 @@ import { MessagePartRuntimeImpl } from "./runtime/api/message-part-runtime.js";
29
34
  import { MessageRuntimeImpl } from "./runtime/api/message-runtime.js";
30
35
  import { symbolInnerMessage } from "./runtime/utils/external-store-message.js";
31
36
  import { getAutoStatus, isAutoStatus } from "./runtime/utils/auto-status.js";
37
+ import { MessageRepositorySession, MessageRepositorySessionOptions, createMessageRepositorySession } from "./runtime/utils/message-repository-session.js";
32
38
  import "./runtime/internal.js";
33
39
  import { LocalRuntimeOptionsBase } from "./runtimes/local/local-runtime-options.js";
34
40
  import { LocalThreadRuntimeCore } from "./runtimes/local/local-thread-runtime-core.js";
@@ -47,4 +53,4 @@ import { RemoteThreadData, RemoteThreadState, THREAD_MAPPING_ID, createThreadMap
47
53
  import "./runtimes/internal.js";
48
54
  import { ThreadListItemRuntimeBinding, ThreadRuntimeCoreBinding, ThreadRuntimeImpl, getThreadState } from "./runtime/api/thread-runtime.js";
49
55
  import { AssistantRuntimeImpl } from "./runtime/api/assistant-runtime.js";
50
- export { AssistantRuntimeImpl, AttachmentRuntimeImpl, BaseAssistantRuntimeCore, BaseComposerRuntimeCore, BaseSubject, BaseSubscribable, BaseThreadRuntimeCore, type ComposerRuntimeCoreBinding, ComposerRuntimeImpl, CompositeContextProvider, type ConverterCallback, DefaultEditComposerRuntimeCore, DefaultThreadComposerRuntimeCore, EMPTY_THREAD_CORE, EditComposerAttachmentRuntimeImpl, type EditComposerRuntimeCoreBinding, EditComposerRuntimeImpl, type EventSubscribable, EventSubscriptionSubject, ExportedMessageRepository, type ExportedMessageRepositoryItem, ExternalStoreRuntimeCore, type ExternalStoreThreadFactory, ExternalStoreThreadListRuntimeCore, ExternalStoreThreadRuntimeCore, LazyMemoizeSubject, LocalRuntimeCore, type LocalRuntimeOptionsBase, type LocalThreadFactory, LocalThreadListRuntimeCore, LocalThreadRuntimeCore, MessageAttachmentRuntimeImpl, MessagePartRuntimeImpl, MessageRepository, MessageRuntimeImpl, type MessageStateBinding, type NestedSubscribable, NestedSubscriptionSubject, OptimisticState, ReadonlyThreadRuntimeCore, type RemoteThreadData, type RemoteThreadInitializeResponse, type RemoteThreadListOptions, type RemoteThreadState, SKIP_UPDATE, type SKIP_UPDATE as SKIP_UPDATE_TYPE, ShallowMemoizeSubject, type Subscribable, type SubscribableWithState, type THREAD_MAPPING_ID, ThreadComposerAttachmentRuntimeImpl, type ThreadComposerRuntimeCoreBinding, ThreadComposerRuntimeImpl, type ThreadListItemRuntimeBinding, ThreadListItemRuntimeImpl, type ThreadListItemStateBinding, type ThreadListRuntimeCoreBinding, ThreadListRuntimeImpl, ThreadMessageConverter, type ThreadRuntimeCoreBinding, ThreadRuntimeImpl, ToolInvocationTracker, consumeSuggestionResult, createThreadMappingId, dataUrlMediaType, detectImageMediaType, fileMatchesAccept, fromThreadMessageLike, generateErrorMessageId, generateId, getAutoStatus, getFileDataURL, getThreadData, getThreadMessageText, getThreadState, hasUpcomingMessage, httpUrlPattern, isAutoStatus, isCreateAttachment, isErrorMessageId, isJSONValue, isParsableUrl, isRecord, parseDataUrl, resolveFileMediaType, resolveImageMediaType, resolveToolApprovalResponse, shouldContinue, stableStringifyToolArgs, symbolInnerMessage, toMediaWireUrl, toMessagePartStatus, trackToolArgsKeyOrder, updateStatusReducer };
56
+ export { type AbortableThreadLoadPurpose, AssistantRuntimeImpl, AttachmentRuntimeImpl, BaseAssistantRuntimeCore, BaseComposerRuntimeCore, BaseSubject, BaseSubscribable, BaseThreadRuntimeCore, type ComposerRuntimeCoreBinding, ComposerRuntimeImpl, CompositeContextProvider, type ConverterCallback, DefaultEditComposerRuntimeCore, DefaultThreadComposerRuntimeCore, EMPTY_THREAD_CORE, EditComposerAttachmentRuntimeImpl, type EditComposerRuntimeCoreBinding, EditComposerRuntimeImpl, type EventSubscribable, EventSubscriptionSubject, ExportedMessageRepository, type ExportedMessageRepositoryItem, ExternalStoreRuntimeCore, type ExternalStoreThreadFactory, ExternalStoreThreadListRuntimeCore, ExternalStoreThreadRuntimeCore, type FilePartSource, LazyMemoizeSubject, LocalRuntimeCore, type LocalRuntimeOptionsBase, type LocalThreadFactory, LocalThreadListRuntimeCore, LocalThreadRuntimeCore, MessageAttachmentRuntimeImpl, MessagePartRuntimeImpl, MessageRepository, type MessageRepositorySession, type MessageRepositorySessionOptions, MessageRuntimeImpl, type MessageStateBinding, type NestedSubscribable, NestedSubscriptionSubject, OptimisticState, ReadonlyThreadRuntimeCore, type RemoteThreadData, type RemoteThreadInitializeResponse, type RemoteThreadListOptions, type RemoteThreadState, SKIP_UPDATE, type SKIP_UPDATE as SKIP_UPDATE_TYPE, ShallowMemoizeSubject, type Subscribable, type SubscribableWithState, type THREAD_MAPPING_ID, ThreadComposerAttachmentRuntimeImpl, type ThreadComposerRuntimeCoreBinding, ThreadComposerRuntimeImpl, type ThreadListItemRuntimeBinding, ThreadListItemRuntimeImpl, type ThreadListItemStateBinding, type ThreadListRuntimeCoreBinding, ThreadListRuntimeImpl, ThreadMessageConverter, type ThreadRuntimeCoreBinding, ThreadRuntimeImpl, ToolInvocationTracker, consumeSuggestionResult, createAbortableThreadLoad, createCloudThreadListAdapterCreateFallback, createMessageRepositorySession, createThreadMappingId, createToolCallCancellationStub, dataUrlMediaType, detectImageMediaType, fileMatchesAccept, fromThreadMessageLike, generateErrorMessageId, generateId, getAutoStatus, getFileDataURL, getThreadData, getThreadMessageText, getThreadState, hasUpcomingMessage, httpUrlPattern, invokeUserCallback, isAutoStatus, isCreateAttachment, isErrorMessageId, isJSONValue, isParsableUrl, isRecord, notifyEventListeners, parseDataUrl, resolveFileMediaType, resolveFilePartSource, resolveImageMediaType, resolveToolApprovalResponse, scanPendingToolCalls, shouldContinue, stableStringifyToolArgs, symbolInnerMessage, toMediaWireUrl, toMessagePartStatus, trackToolArgsKeyOrder, updateStatusReducer };
package/dist/internal.js CHANGED
@@ -1,21 +1,26 @@
1
1
  import { isJSONValue, isRecord } from "./utils/json/is-json.js";
2
+ import { notifyEventListeners } from "./utils/notify-event-listeners.js";
2
3
  import { BaseSubject, BaseSubscribable, EventSubscriptionSubject, LazyMemoizeSubject, NestedSubscriptionSubject, SKIP_UPDATE, ShallowMemoizeSubject } from "./subscribable/subscribable.js";
4
+ import { CompositeContextProvider } from "./utils/composite-context-provider.js";
3
5
  import { generateErrorMessageId, generateId, isErrorMessageId } from "./utils/id.js";
4
6
  import { fileMatchesAccept, getFileDataURL } from "./adapters/attachment.js";
5
7
  import { getThreadMessageText } from "./utils/text.js";
6
8
  import { consumeSuggestionResult } from "./adapters/suggestion.js";
7
- import { dataUrlMediaType, httpUrlPattern, isParsableUrl, parseDataUrl } from "./utils/data-url.js";
9
+ import { dataUrlMediaType, httpUrlPattern, isParsableUrl, parseDataUrl, resolveFilePartSource } from "./utils/data-url.js";
8
10
  import { fromThreadMessageLike } from "./runtime/utils/thread-message-like.js";
9
11
  import { symbolInnerMessage } from "./runtime/utils/external-store-message.js";
10
12
  import { getAutoStatus, isAutoStatus } from "./runtime/utils/auto-status.js";
11
13
  import { ExportedMessageRepository, MessageRepository } from "./runtime/utils/message-repository.js";
12
14
  import { toMessagePartStatus } from "./utils/normalizePartStatus.js";
13
15
  import { resolveToolApprovalResponse } from "./runtime/utils/resolveToolApprovalResponse.js";
14
- import { CompositeContextProvider } from "./utils/composite-context-provider.js";
15
16
  import { isCreateAttachment } from "./types/attachment.js";
16
17
  import { stableStringifyToolArgs, trackToolArgsKeyOrder } from "./utils/json/stable-stringify-tool-args.js";
18
+ import { invokeUserCallback } from "./utils/invoke-user-callback.js";
17
19
  import { detectImageMediaType } from "./utils/image-media-type.js";
18
20
  import { resolveFileMediaType, resolveImageMediaType, toMediaWireUrl } from "./utils/wire-media.js";
21
+ import { createToolCallCancellationStub, scanPendingToolCalls } from "./runtime/utils/pending-tool-calls.js";
22
+ import { createAbortableThreadLoad } from "./runtime/utils/abortable-thread-load.js";
23
+ import { createCloudThreadListAdapterCreateFallback } from "./react/runtimes/cloud/createCloudThreadListAdapterCreateFallback.js";
19
24
  import { BaseAssistantRuntimeCore } from "./runtime/base/base-assistant-runtime-core.js";
20
25
  import { AttachmentRuntimeImpl, EditComposerAttachmentRuntimeImpl, MessageAttachmentRuntimeImpl, ThreadComposerAttachmentRuntimeImpl } from "./runtime/api/attachment-runtime.js";
21
26
  import { ComposerRuntimeImpl, EditComposerRuntimeImpl, ThreadComposerRuntimeImpl } from "./runtime/api/composer-runtime.js";
@@ -29,6 +34,7 @@ import { BaseThreadRuntimeCore } from "./runtime/base/base-thread-runtime-core.j
29
34
  import { ThreadListItemRuntimeImpl } from "./runtime/api/thread-list-item-runtime.js";
30
35
  import { ThreadListRuntimeImpl } from "./runtime/api/thread-list-runtime.js";
31
36
  import { AssistantRuntimeImpl } from "./runtime/api/assistant-runtime.js";
37
+ import { createMessageRepositorySession } from "./runtime/utils/message-repository-session.js";
32
38
  import { shouldContinue } from "./runtimes/local/should-continue.js";
33
39
  import { LocalThreadRuntimeCore } from "./runtimes/local/local-thread-runtime-core.js";
34
40
  import { LocalThreadListRuntimeCore } from "./runtimes/local/local-thread-list-runtime-core.js";
@@ -42,4 +48,4 @@ import { ReadonlyThreadRuntimeCore } from "./runtimes/readonly/ReadonlyThreadRun
42
48
  import { OptimisticState } from "./runtimes/remote-thread-list/optimistic-state.js";
43
49
  import { EMPTY_THREAD_CORE } from "./runtimes/remote-thread-list/empty-thread-core.js";
44
50
  import { createThreadMappingId, getThreadData, updateStatusReducer } from "./runtimes/remote-thread-list/remote-thread-state.js";
45
- export { AssistantRuntimeImpl, AttachmentRuntimeImpl, BaseAssistantRuntimeCore, BaseComposerRuntimeCore, BaseSubject, BaseSubscribable, BaseThreadRuntimeCore, ComposerRuntimeImpl, CompositeContextProvider, DefaultEditComposerRuntimeCore, DefaultThreadComposerRuntimeCore, EMPTY_THREAD_CORE, EditComposerAttachmentRuntimeImpl, EditComposerRuntimeImpl, EventSubscriptionSubject, ExportedMessageRepository, ExternalStoreRuntimeCore, ExternalStoreThreadListRuntimeCore, ExternalStoreThreadRuntimeCore, LazyMemoizeSubject, LocalRuntimeCore, LocalThreadListRuntimeCore, LocalThreadRuntimeCore, MessageAttachmentRuntimeImpl, MessagePartRuntimeImpl, MessageRepository, MessageRuntimeImpl, NestedSubscriptionSubject, OptimisticState, ReadonlyThreadRuntimeCore, SKIP_UPDATE, ShallowMemoizeSubject, ThreadComposerAttachmentRuntimeImpl, ThreadComposerRuntimeImpl, ThreadListItemRuntimeImpl, ThreadListRuntimeImpl, ThreadMessageConverter, ThreadRuntimeImpl, ToolInvocationTracker, consumeSuggestionResult, createThreadMappingId, dataUrlMediaType, detectImageMediaType, fileMatchesAccept, fromThreadMessageLike, generateErrorMessageId, generateId, getAutoStatus, getFileDataURL, getThreadData, getThreadMessageText, getThreadState, hasUpcomingMessage, httpUrlPattern, isAutoStatus, isCreateAttachment, isErrorMessageId, isJSONValue, isParsableUrl, isRecord, parseDataUrl, resolveFileMediaType, resolveImageMediaType, resolveToolApprovalResponse, shouldContinue, stableStringifyToolArgs, symbolInnerMessage, toMediaWireUrl, toMessagePartStatus, trackToolArgsKeyOrder, updateStatusReducer };
51
+ export { AssistantRuntimeImpl, AttachmentRuntimeImpl, BaseAssistantRuntimeCore, BaseComposerRuntimeCore, BaseSubject, BaseSubscribable, BaseThreadRuntimeCore, ComposerRuntimeImpl, CompositeContextProvider, DefaultEditComposerRuntimeCore, DefaultThreadComposerRuntimeCore, EMPTY_THREAD_CORE, EditComposerAttachmentRuntimeImpl, EditComposerRuntimeImpl, EventSubscriptionSubject, ExportedMessageRepository, ExternalStoreRuntimeCore, ExternalStoreThreadListRuntimeCore, ExternalStoreThreadRuntimeCore, LazyMemoizeSubject, LocalRuntimeCore, LocalThreadListRuntimeCore, LocalThreadRuntimeCore, MessageAttachmentRuntimeImpl, MessagePartRuntimeImpl, MessageRepository, MessageRuntimeImpl, NestedSubscriptionSubject, OptimisticState, ReadonlyThreadRuntimeCore, SKIP_UPDATE, ShallowMemoizeSubject, ThreadComposerAttachmentRuntimeImpl, ThreadComposerRuntimeImpl, ThreadListItemRuntimeImpl, ThreadListRuntimeImpl, ThreadMessageConverter, ThreadRuntimeImpl, ToolInvocationTracker, consumeSuggestionResult, createAbortableThreadLoad, createCloudThreadListAdapterCreateFallback, createMessageRepositorySession, createThreadMappingId, createToolCallCancellationStub, dataUrlMediaType, detectImageMediaType, fileMatchesAccept, fromThreadMessageLike, generateErrorMessageId, generateId, getAutoStatus, getFileDataURL, getThreadData, getThreadMessageText, getThreadState, hasUpcomingMessage, httpUrlPattern, invokeUserCallback, isAutoStatus, isCreateAttachment, isErrorMessageId, isJSONValue, isParsableUrl, isRecord, notifyEventListeners, parseDataUrl, resolveFileMediaType, resolveFilePartSource, resolveImageMediaType, resolveToolApprovalResponse, scanPendingToolCalls, shouldContinue, stableStringifyToolArgs, symbolInnerMessage, toMediaWireUrl, toMessagePartStatus, trackToolArgsKeyOrder, updateStatusReducer };
@@ -5,7 +5,6 @@ declare class AssistantFrameHost implements ModelContextProvider {
5
5
  private _context;
6
6
  private _subscribers;
7
7
  private _pendingRequests;
8
- private _requestCounter;
9
8
  private _iframeWindow;
10
9
  private _targetOrigin;
11
10
  private _disposed;
@@ -14,6 +13,7 @@ declare class AssistantFrameHost implements ModelContextProvider {
14
13
  private updateContext;
15
14
  private callTool;
16
15
  private sendRequest;
16
+ private cancelToolCall;
17
17
  private requestContext;
18
18
  private notifySubscribers;
19
19
  getModelContext(): ModelContext;
@@ -1 +1 @@
1
- {"version":3,"file":"host.d.ts","names":[],"sources":["../../../src/model-context/frame/host.ts"],"mappings":";;;cAkDa,8BAA8B;UACjC;UACA;UACA;UAOA;UACA;UACA;UACA;EAEI,YAAA,cAAc,QAAQ;UAU1B;UA6BA;UAoBA;UAkBA;UAuDA;UAYA;EAIR,mBAAmB;EAInB,UAAU,uBAAuB;EAKjC"}
1
+ {"version":3,"file":"host.d.ts","names":[],"sources":["../../../src/model-context/frame/host.ts"],"mappings":";;;cAqDa,8BAA8B;UACjC;UACA;UACA;UAOA;UACA;UACA;EAGN,YAAA,cAAc,QACd;UAWM;UA6BA;UAoBA;UAkBA;UAyDA;UAUA;UAYA;EAIR,mBAAmB;EAInB,UAAU,uBAAuB;EAKjC"}
@@ -1,6 +1,8 @@
1
1
  import { notifySubscribers } from "../../subscribable/subscribable.js";
2
+ import { generateId } from "../../utils/id.js";
2
3
  import { FRAME_MESSAGE_CHANNEL } from "./types.js";
3
4
  //#region src/model-context/frame/host.ts
5
+ const getDefaultTargetOrigin = () => window.location.origin;
4
6
  /**
5
7
  * Deserializes tools from JSON Schema format back to Tool objects
6
8
  */
@@ -27,11 +29,10 @@ var AssistantFrameHost = class {
27
29
  _context = {};
28
30
  _subscribers = /* @__PURE__ */ new Set();
29
31
  _pendingRequests = /* @__PURE__ */ new Map();
30
- _requestCounter = 0;
31
32
  _iframeWindow;
32
33
  _targetOrigin;
33
34
  _disposed = false;
34
- constructor(iframeWindow, targetOrigin = "*") {
35
+ constructor(iframeWindow, targetOrigin = getDefaultTargetOrigin()) {
35
36
  this._iframeWindow = iframeWindow;
36
37
  this._targetOrigin = targetOrigin;
37
38
  this.handleMessage = this.handleMessage.bind(this);
@@ -50,7 +51,7 @@ var AssistantFrameHost = class {
50
51
  case "tool-result": {
51
52
  const pending = this._pendingRequests.get(message.id);
52
53
  if (pending) {
53
- if (message.error) pending.reject(new Error(message.error));
54
+ if (typeof message.error === "string") pending.reject(new Error(message.error));
54
55
  else pending.resolve(message.result);
55
56
  this._pendingRequests.delete(message.id);
56
57
  }
@@ -72,7 +73,7 @@ var AssistantFrameHost = class {
72
73
  callTool(toolName, args, abortSignal) {
73
74
  return this.sendRequest({
74
75
  type: "tool-call",
75
- id: `tool-${this._requestCounter++}`,
76
+ id: `tool-${generateId()}`,
76
77
  toolName,
77
78
  args
78
79
  }, 3e4, `Tool call "${toolName}" timed out`, abortSignal);
@@ -86,6 +87,7 @@ var AssistantFrameHost = class {
86
87
  if (!abortSignal) return;
87
88
  const pending = this._pendingRequests.get(message.id);
88
89
  if (pending) {
90
+ this.cancelToolCall(message.id);
89
91
  pending.reject(getAbortReason(abortSignal));
90
92
  this._pendingRequests.delete(message.id);
91
93
  }
@@ -107,6 +109,7 @@ var AssistantFrameHost = class {
107
109
  timeoutId = setTimeout(() => {
108
110
  const pending = this._pendingRequests.get(message.id);
109
111
  if (pending) {
112
+ this.cancelToolCall(message.id);
110
113
  pending.reject(new Error(timeoutMessage));
111
114
  this._pendingRequests.delete(message.id);
112
115
  }
@@ -118,6 +121,15 @@ var AssistantFrameHost = class {
118
121
  }, this._targetOrigin);
119
122
  });
120
123
  }
124
+ cancelToolCall(id) {
125
+ this._iframeWindow.postMessage({
126
+ channel: FRAME_MESSAGE_CHANNEL,
127
+ message: {
128
+ type: "tool-cancel",
129
+ id
130
+ }
131
+ }, this._targetOrigin);
132
+ }
121
133
  requestContext() {
122
134
  this._iframeWindow.postMessage({
123
135
  channel: FRAME_MESSAGE_CHANNEL,
@@ -139,7 +151,10 @@ var AssistantFrameHost = class {
139
151
  window.removeEventListener("message", this.handleMessage);
140
152
  this._subscribers.clear();
141
153
  const error = /* @__PURE__ */ new Error("AssistantFrameHost has been disposed");
142
- for (const pending of this._pendingRequests.values()) pending.reject(error);
154
+ for (const [id, pending] of this._pendingRequests) {
155
+ this.cancelToolCall(id);
156
+ pending.reject(error);
157
+ }
143
158
  this._pendingRequests.clear();
144
159
  }
145
160
  };
@@ -1 +1 @@
1
- {"version":3,"file":"host.js","names":["ModelContextProvider","ModelContext","Unsubscribe","Tool","notifySubscribers","notifyStateSubscribers","FrameMessage","FRAME_MESSAGE_CHANNEL","SerializedModelContext","SerializedTool","deserializeTool","serializedTool","parameters","description","disabled","undefined","type","deserializeModelContext","serialized","system","tools","Object","fromEntries","entries","map","name","tool","getAbortReason","signal","AbortSignal","reason","error","Error","AssistantFrameHost","_context","_subscribers","Set","_pendingRequests","Map","resolve","value","reject","_requestCounter","_iframeWindow","Window","_targetOrigin","_disposed","constructor","iframeWindow","targetOrigin","handleMessage","bind","window","addEventListener","requestContext","event","MessageEvent","origin","source","data","channel","message","updateContext","context","pending","get","id","result","delete","serializedContext","execute","args","abortSignal","callTool","toolName","Promise","sendRequest","T","timeout","timeoutMessage","aborted","timeoutId","ReturnType","setTimeout","onAbort","cleanup","clearTimeout","removeEventListener","set","once","postMessage","getModelContext","subscribe","callback","add","dispose","clear","values"],"sources":["../../../src/model-context/frame/host.ts"],"sourcesContent":["import type { ModelContextProvider, ModelContext } from \"../types\";\nimport type { Unsubscribe } from \"../../types/unsubscribe\";\nimport type { Tool } from \"assistant-stream\";\nimport { notifySubscribers as notifyStateSubscribers } from \"../../subscribable/subscribable\";\nimport {\n type FrameMessage,\n FRAME_MESSAGE_CHANNEL,\n type SerializedModelContext,\n type SerializedTool,\n} from \"./types\";\n\n/**\n * Deserializes tools from JSON Schema format back to Tool objects\n */\nconst deserializeTool = (serializedTool: SerializedTool): Tool<any, any> =>\n ({\n parameters: serializedTool.parameters,\n ...(serializedTool.description && {\n description: serializedTool.description,\n }),\n ...(serializedTool.disabled !== undefined && {\n disabled: serializedTool.disabled,\n }),\n ...(serializedTool.type && { type: serializedTool.type }),\n }) as Tool<any, any>;\n\n/**\n * Deserializes a ModelContext from transmission format\n */\nconst deserializeModelContext = (\n serialized: SerializedModelContext,\n): ModelContext => ({\n ...(serialized.system !== undefined && { system: serialized.system }),\n ...(serialized.tools && {\n tools: Object.fromEntries(\n Object.entries(serialized.tools).map(([name, tool]) => [\n name,\n deserializeTool(tool),\n ]),\n ),\n }),\n});\n\nconst getAbortReason = (signal: AbortSignal): unknown => {\n if (signal.reason !== undefined) return signal.reason;\n const error = new Error(\"Tool call was aborted\");\n error.name = \"AbortError\";\n return error;\n};\n\nexport class AssistantFrameHost implements ModelContextProvider {\n private _context: ModelContext = {};\n private _subscribers = new Set<() => void>();\n private _pendingRequests = new Map<\n string,\n {\n resolve: (value: any) => void;\n reject: (error: any) => void;\n }\n >();\n private _requestCounter = 0;\n private _iframeWindow: Window;\n private _targetOrigin: string;\n private _disposed = false;\n\n constructor(iframeWindow: Window, targetOrigin: string = \"*\") {\n this._iframeWindow = iframeWindow;\n this._targetOrigin = targetOrigin;\n\n this.handleMessage = this.handleMessage.bind(this);\n window.addEventListener(\"message\", this.handleMessage);\n\n this.requestContext();\n }\n\n private handleMessage(event: MessageEvent) {\n if (this._targetOrigin !== \"*\" && event.origin !== this._targetOrigin)\n return;\n if (event.source !== this._iframeWindow) return;\n if (event.data?.channel !== FRAME_MESSAGE_CHANNEL) return;\n\n const message = event.data.message as FrameMessage;\n\n switch (message.type) {\n case \"model-context-update\": {\n this.updateContext(message.context);\n break;\n }\n\n case \"tool-result\": {\n const pending = this._pendingRequests.get(message.id);\n if (pending) {\n if (message.error) {\n pending.reject(new Error(message.error));\n } else {\n pending.resolve(message.result);\n }\n this._pendingRequests.delete(message.id);\n }\n break;\n }\n }\n }\n\n private updateContext(serializedContext: SerializedModelContext) {\n const context = deserializeModelContext(serializedContext);\n this._context = {\n ...context,\n tools:\n context.tools &&\n Object.fromEntries(\n Object.entries(context.tools).map(([name, tool]) => [\n name,\n {\n ...tool,\n execute: (args: any, context: { abortSignal: AbortSignal }) =>\n this.callTool(name, args, context.abortSignal),\n } as Tool<any, any>,\n ]),\n ),\n };\n this.notifySubscribers();\n }\n\n private callTool(\n toolName: string,\n args: any,\n abortSignal: AbortSignal,\n ): Promise<any> {\n return this.sendRequest(\n {\n type: \"tool-call\",\n id: `tool-${this._requestCounter++}`,\n toolName,\n args,\n },\n 30000,\n `Tool call \"${toolName}\" timed out`,\n abortSignal,\n );\n }\n\n private sendRequest<T extends FrameMessage & { id: string }>(\n message: T,\n timeout = 30000,\n timeoutMessage = \"Request timed out\",\n abortSignal?: AbortSignal,\n ): Promise<any> {\n if (this._disposed) {\n return Promise.reject(new Error(\"AssistantFrameHost has been disposed\"));\n }\n if (abortSignal?.aborted) {\n return Promise.reject(getAbortReason(abortSignal));\n }\n\n return new Promise((resolve, reject) => {\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n const onAbort = () => {\n if (!abortSignal) return;\n const pending = this._pendingRequests.get(message.id);\n if (pending) {\n pending.reject(getAbortReason(abortSignal));\n this._pendingRequests.delete(message.id);\n }\n };\n const cleanup = () => {\n if (timeoutId !== undefined) clearTimeout(timeoutId);\n abortSignal?.removeEventListener(\"abort\", onAbort);\n };\n\n this._pendingRequests.set(message.id, {\n resolve: (value: any) => {\n cleanup();\n resolve(value);\n },\n reject: (error: any) => {\n cleanup();\n reject(error);\n },\n });\n\n timeoutId = setTimeout(() => {\n const pending = this._pendingRequests.get(message.id);\n if (pending) {\n pending.reject(new Error(timeoutMessage));\n this._pendingRequests.delete(message.id);\n }\n }, timeout);\n abortSignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n this._iframeWindow.postMessage(\n { channel: FRAME_MESSAGE_CHANNEL, message },\n this._targetOrigin,\n );\n });\n }\n\n private requestContext() {\n this._iframeWindow.postMessage(\n {\n channel: FRAME_MESSAGE_CHANNEL,\n message: {\n type: \"model-context-request\",\n } as FrameMessage,\n },\n this._targetOrigin,\n );\n }\n\n private notifySubscribers() {\n notifyStateSubscribers(this._subscribers);\n }\n\n getModelContext(): ModelContext {\n return this._context;\n }\n\n subscribe(callback: () => void): Unsubscribe {\n this._subscribers.add(callback);\n return () => this._subscribers.delete(callback);\n }\n\n dispose() {\n this._disposed = true;\n window.removeEventListener(\"message\", this.handleMessage);\n this._subscribers.clear();\n const error = new Error(\"AssistantFrameHost has been disposed\");\n for (const pending of this._pendingRequests.values()) {\n pending.reject(error);\n }\n this._pendingRequests.clear();\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"host.js","names":["ModelContextProvider","ModelContext","Unsubscribe","Tool","notifySubscribers","notifyStateSubscribers","generateId","FrameMessage","FRAME_MESSAGE_CHANNEL","SerializedModelContext","SerializedTool","getDefaultTargetOrigin","window","location","origin","deserializeTool","serializedTool","parameters","description","disabled","undefined","type","deserializeModelContext","serialized","system","tools","Object","fromEntries","entries","map","name","tool","getAbortReason","signal","AbortSignal","reason","error","Error","AssistantFrameHost","_context","_subscribers","Set","_pendingRequests","Map","resolve","value","reject","_iframeWindow","Window","_targetOrigin","_disposed","constructor","iframeWindow","targetOrigin","handleMessage","bind","addEventListener","requestContext","event","MessageEvent","source","data","channel","message","updateContext","context","pending","get","id","result","delete","serializedContext","execute","args","abortSignal","callTool","toolName","Promise","sendRequest","T","timeout","timeoutMessage","aborted","timeoutId","ReturnType","setTimeout","onAbort","cancelToolCall","cleanup","clearTimeout","removeEventListener","set","once","postMessage","getModelContext","subscribe","callback","add","dispose","clear"],"sources":["../../../src/model-context/frame/host.ts"],"sourcesContent":["import type { ModelContextProvider, ModelContext } from \"../types\";\nimport type { Unsubscribe } from \"../../types/unsubscribe\";\nimport type { Tool } from \"assistant-stream\";\nimport { notifySubscribers as notifyStateSubscribers } from \"../../subscribable/subscribable\";\nimport { generateId } from \"../../utils/id\";\nimport {\n type FrameMessage,\n FRAME_MESSAGE_CHANNEL,\n type SerializedModelContext,\n type SerializedTool,\n} from \"./types\";\n\nconst getDefaultTargetOrigin = () => window.location.origin;\n\n/**\n * Deserializes tools from JSON Schema format back to Tool objects\n */\nconst deserializeTool = (serializedTool: SerializedTool): Tool<any, any> =>\n ({\n parameters: serializedTool.parameters,\n ...(serializedTool.description && {\n description: serializedTool.description,\n }),\n ...(serializedTool.disabled !== undefined && {\n disabled: serializedTool.disabled,\n }),\n ...(serializedTool.type && { type: serializedTool.type }),\n }) as Tool<any, any>;\n\n/**\n * Deserializes a ModelContext from transmission format\n */\nconst deserializeModelContext = (\n serialized: SerializedModelContext,\n): ModelContext => ({\n ...(serialized.system !== undefined && { system: serialized.system }),\n ...(serialized.tools && {\n tools: Object.fromEntries(\n Object.entries(serialized.tools).map(([name, tool]) => [\n name,\n deserializeTool(tool),\n ]),\n ),\n }),\n});\n\nconst getAbortReason = (signal: AbortSignal): unknown => {\n if (signal.reason !== undefined) return signal.reason;\n const error = new Error(\"Tool call was aborted\");\n error.name = \"AbortError\";\n return error;\n};\n\nexport class AssistantFrameHost implements ModelContextProvider {\n private _context: ModelContext = {};\n private _subscribers = new Set<() => void>();\n private _pendingRequests = new Map<\n string,\n {\n resolve: (value: any) => void;\n reject: (error: any) => void;\n }\n >();\n private _iframeWindow: Window;\n private _targetOrigin: string;\n private _disposed = false;\n\n constructor(\n iframeWindow: Window,\n targetOrigin: string = getDefaultTargetOrigin(),\n ) {\n this._iframeWindow = iframeWindow;\n this._targetOrigin = targetOrigin;\n\n this.handleMessage = this.handleMessage.bind(this);\n window.addEventListener(\"message\", this.handleMessage);\n\n this.requestContext();\n }\n\n private handleMessage(event: MessageEvent) {\n if (this._targetOrigin !== \"*\" && event.origin !== this._targetOrigin)\n return;\n if (event.source !== this._iframeWindow) return;\n if (event.data?.channel !== FRAME_MESSAGE_CHANNEL) return;\n\n const message = event.data.message as FrameMessage;\n\n switch (message.type) {\n case \"model-context-update\": {\n this.updateContext(message.context);\n break;\n }\n\n case \"tool-result\": {\n const pending = this._pendingRequests.get(message.id);\n if (pending) {\n if (typeof message.error === \"string\") {\n pending.reject(new Error(message.error));\n } else {\n pending.resolve(message.result);\n }\n this._pendingRequests.delete(message.id);\n }\n break;\n }\n }\n }\n\n private updateContext(serializedContext: SerializedModelContext) {\n const context = deserializeModelContext(serializedContext);\n this._context = {\n ...context,\n tools:\n context.tools &&\n Object.fromEntries(\n Object.entries(context.tools).map(([name, tool]) => [\n name,\n {\n ...tool,\n execute: (args: any, context: { abortSignal: AbortSignal }) =>\n this.callTool(name, args, context.abortSignal),\n } as Tool<any, any>,\n ]),\n ),\n };\n this.notifySubscribers();\n }\n\n private callTool(\n toolName: string,\n args: any,\n abortSignal: AbortSignal,\n ): Promise<any> {\n return this.sendRequest(\n {\n type: \"tool-call\",\n id: `tool-${generateId()}`,\n toolName,\n args,\n },\n 30000,\n `Tool call \"${toolName}\" timed out`,\n abortSignal,\n );\n }\n\n private sendRequest<T extends FrameMessage & { id: string }>(\n message: T,\n timeout = 30000,\n timeoutMessage = \"Request timed out\",\n abortSignal?: AbortSignal,\n ): Promise<any> {\n if (this._disposed) {\n return Promise.reject(new Error(\"AssistantFrameHost has been disposed\"));\n }\n if (abortSignal?.aborted) {\n return Promise.reject(getAbortReason(abortSignal));\n }\n\n return new Promise((resolve, reject) => {\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n const onAbort = () => {\n if (!abortSignal) return;\n const pending = this._pendingRequests.get(message.id);\n if (pending) {\n this.cancelToolCall(message.id);\n pending.reject(getAbortReason(abortSignal));\n this._pendingRequests.delete(message.id);\n }\n };\n const cleanup = () => {\n if (timeoutId !== undefined) clearTimeout(timeoutId);\n abortSignal?.removeEventListener(\"abort\", onAbort);\n };\n\n this._pendingRequests.set(message.id, {\n resolve: (value: any) => {\n cleanup();\n resolve(value);\n },\n reject: (error: any) => {\n cleanup();\n reject(error);\n },\n });\n\n timeoutId = setTimeout(() => {\n const pending = this._pendingRequests.get(message.id);\n if (pending) {\n this.cancelToolCall(message.id);\n pending.reject(new Error(timeoutMessage));\n this._pendingRequests.delete(message.id);\n }\n }, timeout);\n abortSignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n this._iframeWindow.postMessage(\n { channel: FRAME_MESSAGE_CHANNEL, message },\n this._targetOrigin,\n );\n });\n }\n\n private cancelToolCall(id: string) {\n this._iframeWindow.postMessage(\n {\n channel: FRAME_MESSAGE_CHANNEL,\n message: { type: \"tool-cancel\", id } satisfies FrameMessage,\n },\n this._targetOrigin,\n );\n }\n\n private requestContext() {\n this._iframeWindow.postMessage(\n {\n channel: FRAME_MESSAGE_CHANNEL,\n message: {\n type: \"model-context-request\",\n } as FrameMessage,\n },\n this._targetOrigin,\n );\n }\n\n private notifySubscribers() {\n notifyStateSubscribers(this._subscribers);\n }\n\n getModelContext(): ModelContext {\n return this._context;\n }\n\n subscribe(callback: () => void): Unsubscribe {\n this._subscribers.add(callback);\n return () => this._subscribers.delete(callback);\n }\n\n dispose() {\n this._disposed = true;\n window.removeEventListener(\"message\", this.handleMessage);\n this._subscribers.clear();\n const error = new Error(\"AssistantFrameHost has been disposed\");\n for (const [id, pending] of this._pendingRequests) {\n this.cancelToolCall(id);\n pending.reject(error);\n }\n this._pendingRequests.clear();\n }\n}\n"],"mappings":"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"}
@@ -5,14 +5,20 @@ declare class AssistantFrameProvider {
5
5
  private static _instance;
6
6
  private _providers;
7
7
  private _providerUnsubscribes;
8
+ private _activeToolCalls;
8
9
  private _targetOrigin;
10
+ private _strictRegistrations;
11
+ private _wildcardRegistrations;
9
12
  private constructor();
10
13
  private static getInstance;
14
+ private reconcileTargetOrigin;
11
15
  private handleMessage;
12
16
  private handleToolCall;
17
+ private cancelToolCall;
13
18
  private sendMessage;
14
19
  private getModelContext;
15
20
  private broadcastUpdate;
21
+ private removeProvider;
16
22
  static addModelContextProvider(provider: ModelContextProvider, targetOrigin?: string): Unsubscribe;
17
23
  static dispose(): void;
18
24
  }
@@ -1 +1 @@
1
- {"version":3,"file":"provider.d.ts","names":[],"sources":["../../../src/model-context/frame/provider.ts"],"mappings":";;;cA+Ba;iBACI;UAEP;UACA;UAIA;UAED;iBAQQ;UASP;UAsBM;UAoCN;UAOA;UAkBA;SAcD,wBACL,UAAU,sBACV,wBACC;SAmBI"}
1
+ {"version":3,"file":"provider.d.ts","names":[],"sources":["../../../src/model-context/frame/provider.ts"],"mappings":";;;cAiCa;iBACI;UAEP;UACA;UACA;UAIA;UACA;UACA;UAED;iBAQQ;UAWP;UAsBA;UA0BM;UA2CN;UAOA;UAOA;UAkBA;UAcA;SAsBD,wBACL,UAAU,sBACV,wBACC;SA2DI"}
@@ -11,12 +11,16 @@ const serializeModelContext = (context) => ({
11
11
  ...context.system !== void 0 && { system: context.system },
12
12
  ...context.tools && { tools: Object.fromEntries(Object.entries(context.tools).map(([name, tool]) => [name, serializeTool(tool)])) }
13
13
  });
14
+ const getDefaultTargetOrigin = () => window.location.origin;
14
15
  var AssistantFrameProvider = class AssistantFrameProvider {
15
16
  static _instance = null;
16
- _providers = /* @__PURE__ */ new Set();
17
+ _providers = /* @__PURE__ */ new Map();
17
18
  _providerUnsubscribes = /* @__PURE__ */ new Map();
19
+ _activeToolCalls = /* @__PURE__ */ new Map();
18
20
  _targetOrigin;
19
- constructor(targetOrigin = "*") {
21
+ _strictRegistrations = 0;
22
+ _wildcardRegistrations = 0;
23
+ constructor(targetOrigin = getDefaultTargetOrigin()) {
20
24
  this._targetOrigin = targetOrigin;
21
25
  this.handleMessage = this.handleMessage.bind(this);
22
26
  window.addEventListener("message", this.handleMessage);
@@ -24,8 +28,22 @@ var AssistantFrameProvider = class AssistantFrameProvider {
24
28
  }
25
29
  static getInstance(targetOrigin) {
26
30
  if (!AssistantFrameProvider._instance) AssistantFrameProvider._instance = new AssistantFrameProvider(targetOrigin);
31
+ else AssistantFrameProvider._instance.reconcileTargetOrigin(targetOrigin);
27
32
  return AssistantFrameProvider._instance;
28
33
  }
34
+ reconcileTargetOrigin(targetOrigin = getDefaultTargetOrigin()) {
35
+ if (targetOrigin === this._targetOrigin) return;
36
+ if (this._providers.size === 0) {
37
+ this._targetOrigin = targetOrigin;
38
+ return;
39
+ }
40
+ if (targetOrigin === "*") return;
41
+ if (this._targetOrigin === "*") {
42
+ this._targetOrigin = targetOrigin;
43
+ return;
44
+ }
45
+ throw new Error(`AssistantFrameProvider cannot register conflicting target origins: "${this._targetOrigin}" and "${targetOrigin}"`);
46
+ }
29
47
  handleMessage(event) {
30
48
  if (this._targetOrigin !== "*" && event.origin !== this._targetOrigin) return;
31
49
  if (event.source !== window.parent) return;
@@ -38,18 +56,28 @@ var AssistantFrameProvider = class AssistantFrameProvider {
38
56
  context: serializeModelContext(this.getModelContext())
39
57
  });
40
58
  break;
41
- case "tool-call": this.handleToolCall(message, event);
59
+ case "tool-call":
60
+ this.handleToolCall(message, event);
61
+ break;
62
+ case "tool-cancel": this.cancelToolCall(message.id);
42
63
  }
43
64
  }
44
65
  async handleToolCall(message, event) {
45
66
  const tool = this.getModelContext().tools?.[message.toolName];
67
+ const abortController = new AbortController();
68
+ this._activeToolCalls.get(message.id)?.abortController.abort();
69
+ const activeCall = {
70
+ abortController,
71
+ event
72
+ };
73
+ this._activeToolCalls.set(message.id, activeCall);
46
74
  let result;
47
75
  let error;
48
76
  if (!tool) error = `Tool "${message.toolName}" not found`;
49
77
  else try {
50
78
  result = tool.execute ? await tool.execute(message.args, {
51
79
  toolCallId: message.id,
52
- abortSignal: new AbortController().signal,
80
+ abortSignal: abortController.signal,
53
81
  human: async () => {
54
82
  throw new Error("Tool human input is not supported in frame context");
55
83
  }
@@ -57,12 +85,20 @@ var AssistantFrameProvider = class AssistantFrameProvider {
57
85
  } catch (e) {
58
86
  error = e instanceof Error ? e.message : String(e);
59
87
  }
88
+ if (this._activeToolCalls.get(message.id) !== activeCall) return;
89
+ this._activeToolCalls.delete(message.id);
60
90
  this.sendMessage(event, {
61
91
  type: "tool-result",
62
92
  id: message.id,
63
- ...error ? { error } : { result }
93
+ ...error !== void 0 ? { error } : { result }
64
94
  });
65
95
  }
96
+ cancelToolCall(id) {
97
+ const activeCall = this._activeToolCalls.get(id);
98
+ if (!activeCall) return;
99
+ this._activeToolCalls.delete(id);
100
+ activeCall.abortController.abort();
101
+ }
66
102
  sendMessage(event, message) {
67
103
  event.source?.postMessage({
68
104
  channel: FRAME_MESSAGE_CHANNEL,
@@ -70,7 +106,7 @@ var AssistantFrameProvider = class AssistantFrameProvider {
70
106
  }, { targetOrigin: event.origin });
71
107
  }
72
108
  getModelContext() {
73
- return Array.from(this._providers).map((p) => p.getModelContext()).reduce((merged, context) => ({
109
+ return Array.from(new Set(this._providers.values())).map((p) => p.getModelContext()).reduce((merged, context) => ({
74
110
  system: context.system ? merged.system ? `${merged.system}\n\n${context.system}` : context.system : merged.system,
75
111
  tools: {
76
112
  ...merged.tools || {},
@@ -90,27 +126,101 @@ var AssistantFrameProvider = class AssistantFrameProvider {
90
126
  }, this._targetOrigin);
91
127
  }
92
128
  }
129
+ removeProvider(id, origin) {
130
+ this._providers.delete(id);
131
+ const unsubscribe = this._providerUnsubscribes.get(id);
132
+ this._providerUnsubscribes.delete(id);
133
+ if (origin === "*") {
134
+ this._wildcardRegistrations -= 1;
135
+ if (this._wildcardRegistrations === 0 && this._strictRegistrations === 0) this._targetOrigin = getDefaultTargetOrigin();
136
+ } else {
137
+ this._strictRegistrations -= 1;
138
+ if (this._strictRegistrations === 0) this._targetOrigin = this._wildcardRegistrations > 0 ? "*" : getDefaultTargetOrigin();
139
+ }
140
+ return unsubscribe;
141
+ }
93
142
  static addModelContextProvider(provider, targetOrigin) {
94
- const instance = AssistantFrameProvider.getInstance(targetOrigin);
95
- instance._providers.add(provider);
96
- const unsubscribe = provider.subscribe?.(() => instance.broadcastUpdate());
97
- if (unsubscribe) instance._providerUnsubscribes.set(provider, unsubscribe);
98
- instance.broadcastUpdate();
99
- return () => {
100
- instance._providers.delete(provider);
101
- instance._providerUnsubscribes.get(provider)?.();
102
- instance._providerUnsubscribes.delete(provider);
143
+ const origin = targetOrigin ?? getDefaultTargetOrigin();
144
+ const instance = AssistantFrameProvider.getInstance(origin);
145
+ const id = Symbol();
146
+ instance._providers.set(id, provider);
147
+ if (origin === "*") instance._wildcardRegistrations += 1;
148
+ else instance._strictRegistrations += 1;
149
+ try {
150
+ const unsubscribe = provider.subscribe?.(() => instance.broadcastUpdate());
151
+ if (unsubscribe) instance._providerUnsubscribes.set(id, unsubscribe);
103
152
  instance.broadcastUpdate();
153
+ } catch (error) {
154
+ const unsubscribe = instance.removeProvider(id, origin);
155
+ try {
156
+ unsubscribe?.();
157
+ } catch (unsubscribeError) {
158
+ console.error(unsubscribeError);
159
+ }
160
+ try {
161
+ instance.broadcastUpdate();
162
+ } catch (broadcastError) {
163
+ console.error(broadcastError);
164
+ }
165
+ throw error;
166
+ }
167
+ let released = false;
168
+ return () => {
169
+ if (released) return;
170
+ released = true;
171
+ const unsubscribe = instance.removeProvider(id, origin);
172
+ let unsubscribeFailed = false;
173
+ let unsubscribeError;
174
+ try {
175
+ unsubscribe?.();
176
+ } catch (error) {
177
+ unsubscribeFailed = true;
178
+ unsubscribeError = error;
179
+ }
180
+ try {
181
+ instance.broadcastUpdate();
182
+ } catch (error) {
183
+ if (!unsubscribeFailed) throw error;
184
+ console.error(error);
185
+ }
186
+ if (unsubscribeFailed) throw unsubscribeError;
104
187
  };
105
188
  }
106
189
  static dispose() {
107
190
  if (AssistantFrameProvider._instance) {
108
191
  const instance = AssistantFrameProvider._instance;
109
192
  window.removeEventListener("message", instance.handleMessage);
110
- instance._providerUnsubscribes.forEach((unsubscribe) => unsubscribe?.());
193
+ let cleanupFailed = false;
194
+ let cleanupError;
195
+ const runCleanup = (cleanup) => {
196
+ try {
197
+ cleanup();
198
+ } catch (error) {
199
+ if (cleanupFailed) console.error(error);
200
+ else {
201
+ cleanupFailed = true;
202
+ cleanupError = error;
203
+ }
204
+ }
205
+ };
206
+ instance._providerUnsubscribes.forEach((unsubscribe) => {
207
+ if (unsubscribe) runCleanup(unsubscribe);
208
+ });
111
209
  instance._providerUnsubscribes.clear();
112
210
  instance._providers.clear();
211
+ instance._activeToolCalls.forEach(({ abortController, event }, id) => {
212
+ runCleanup(() => {
213
+ abortController.abort();
214
+ instance.sendMessage(event, {
215
+ type: "tool-result",
216
+ id,
217
+ error: "AssistantFrameProvider has been disposed"
218
+ });
219
+ });
220
+ });
221
+ instance._activeToolCalls.clear();
113
222
  AssistantFrameProvider._instance = null;
223
+ if (cleanupFailed) throw cleanupError;
114
224
  }
115
225
  }
116
226
  };