@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
@@ -1,167 +1,28 @@
1
+ import { InertThreadRuntimeCore, createInertComposer } from "../inert/InertThreadRuntimeCore.js";
1
2
  //#region src/runtimes/remote-thread-list/empty-thread-core.ts
2
3
  const EMPTY_THREAD_ERROR = /* @__PURE__ */ new Error("This is the empty thread, a placeholder for the main thread. You cannot perform any actions on this thread instance. This error is probably because you tried to call a thread method in your render function. Call the method inside a `useEffect` hook instead.");
3
- const EMPTY_THREAD_CORE = {
4
- getMessageById() {},
4
+ var EmptyThreadRuntimeCore = class extends InertThreadRuntimeCore {
5
+ get error() {
6
+ return EMPTY_THREAD_ERROR;
7
+ }
8
+ messages = [];
9
+ composer = createInertComposer(EMPTY_THREAD_ERROR, true);
10
+ isLoading = true;
11
+ getMessageById() {}
5
12
  getBranches() {
6
13
  return [];
7
- },
8
- switchToBranch() {
9
- throw EMPTY_THREAD_ERROR;
10
- },
11
- append() {
12
- throw EMPTY_THREAD_ERROR;
13
- },
14
- deleteMessage() {
15
- throw EMPTY_THREAD_ERROR;
16
- },
17
- startRun() {
18
- throw EMPTY_THREAD_ERROR;
19
- },
20
- resumeRun() {
21
- throw EMPTY_THREAD_ERROR;
22
- },
23
- cancelRun() {
24
- throw EMPTY_THREAD_ERROR;
25
- },
26
- addToolResult() {
27
- throw EMPTY_THREAD_ERROR;
28
- },
29
- resumeToolCall() {
30
- throw EMPTY_THREAD_ERROR;
31
- },
32
- respondToToolApproval() {
33
- throw EMPTY_THREAD_ERROR;
34
- },
35
- speak() {
36
- throw EMPTY_THREAD_ERROR;
37
- },
38
- stopSpeaking() {
39
- throw EMPTY_THREAD_ERROR;
40
- },
41
- connectVoice() {
42
- throw EMPTY_THREAD_ERROR;
43
- },
44
- disconnectVoice() {
45
- throw EMPTY_THREAD_ERROR;
46
- },
47
- getVoiceVolume: () => 0,
48
- subscribeVoiceVolume: () => () => {},
49
- muteVoice() {
50
- throw EMPTY_THREAD_ERROR;
51
- },
52
- unmuteVoice() {
53
- throw EMPTY_THREAD_ERROR;
54
- },
55
- submitFeedback() {
56
- throw EMPTY_THREAD_ERROR;
57
- },
58
- getModelContext() {
59
- return {};
60
- },
61
- exportExternalState() {
62
- throw EMPTY_THREAD_ERROR;
63
- },
64
- importExternalState() {
65
- throw EMPTY_THREAD_ERROR;
66
- },
67
- unstable_notifySessionReset() {
68
- throw EMPTY_THREAD_ERROR;
69
- },
70
- composer: {
71
- attachments: [],
72
- attachmentAccept: "*",
73
- async addAttachment() {
74
- throw EMPTY_THREAD_ERROR;
75
- },
76
- async removeAttachment() {
77
- throw EMPTY_THREAD_ERROR;
78
- },
79
- isEditing: true,
80
- canCancel: false,
81
- canSend: false,
82
- isEmpty: true,
83
- text: "",
84
- setText() {
85
- throw EMPTY_THREAD_ERROR;
86
- },
87
- role: "user",
88
- setRole() {
89
- throw EMPTY_THREAD_ERROR;
90
- },
91
- runConfig: {},
92
- setRunConfig() {
93
- throw EMPTY_THREAD_ERROR;
94
- },
95
- async reset() {},
96
- async clearAttachments() {},
97
- send() {
98
- throw EMPTY_THREAD_ERROR;
99
- },
100
- cancel() {},
101
- queue: [],
102
- moveQueueItem() {},
103
- removeQueueItem() {},
104
- dictation: void 0,
105
- startDictation() {
106
- throw EMPTY_THREAD_ERROR;
107
- },
108
- stopDictation() {},
109
- quote: void 0,
110
- setQuote() {
111
- throw EMPTY_THREAD_ERROR;
112
- },
113
- subscribe() {
114
- return () => {};
115
- },
116
- unstable_on() {
117
- return () => {};
118
- }
119
- },
120
- getEditComposer() {},
121
- beginEdit() {
122
- throw EMPTY_THREAD_ERROR;
123
- },
124
- speech: void 0,
125
- voice: void 0,
126
- capabilities: {
127
- switchToBranch: false,
128
- switchBranchDuringRun: false,
129
- edit: false,
130
- delete: false,
131
- reload: false,
132
- refetchThread: false,
133
- cancel: false,
134
- unstable_copy: false,
135
- speech: false,
136
- dictation: false,
137
- voice: false,
138
- attachments: false,
139
- feedback: false,
140
- queue: false
141
- },
142
- isDisabled: false,
143
- isSendDisabled: false,
144
- isLoading: true,
145
- messages: [],
146
- state: null,
147
- suggestions: [],
148
- extras: void 0,
149
- subscribe() {
150
- return () => {};
151
- },
152
- import() {
153
- throw EMPTY_THREAD_ERROR;
154
- },
14
+ }
155
15
  export() {
156
16
  return { messages: [] };
157
- },
158
- reset() {
159
- throw EMPTY_THREAD_ERROR;
160
- },
161
- unstable_on() {
17
+ }
18
+ subscribe() {
162
19
  return () => {};
163
20
  }
21
+ waitForUpdate() {
22
+ return Promise.reject(EMPTY_THREAD_ERROR);
23
+ }
164
24
  };
25
+ const EMPTY_THREAD_CORE = new EmptyThreadRuntimeCore();
165
26
  //#endregion
166
27
  export { EMPTY_THREAD_CORE };
167
28
 
@@ -1 +1 @@
1
- {"version":3,"file":"empty-thread-core.js","names":["ThreadRuntimeCore","EMPTY_THREAD_ERROR","Error","EMPTY_THREAD_CORE","getMessageById","undefined","getBranches","switchToBranch","append","deleteMessage","startRun","resumeRun","cancelRun","addToolResult","resumeToolCall","respondToToolApproval","speak","stopSpeaking","connectVoice","disconnectVoice","getVoiceVolume","subscribeVoiceVolume","muteVoice","unmuteVoice","submitFeedback","getModelContext","exportExternalState","importExternalState","unstable_notifySessionReset","composer","attachments","attachmentAccept","addAttachment","removeAttachment","isEditing","canCancel","canSend","isEmpty","text","setText","role","setRole","runConfig","setRunConfig","reset","clearAttachments","send","cancel","queue","moveQueueItem","removeQueueItem","dictation","startDictation","stopDictation","quote","setQuote","subscribe","unstable_on","getEditComposer","beginEdit","speech","voice","capabilities","switchBranchDuringRun","edit","delete","reload","refetchThread","unstable_copy","feedback","isDisabled","isSendDisabled","isLoading","messages","state","suggestions","extras","import","export"],"sources":["../../../src/runtimes/remote-thread-list/empty-thread-core.ts"],"sourcesContent":["import type { ThreadRuntimeCore } from \"../../runtime/interfaces/thread-runtime-core\";\n\nconst EMPTY_THREAD_ERROR = new Error(\n \"This is the empty thread, a placeholder for the main thread. You cannot perform any actions on this thread instance. This error is probably because you tried to call a thread method in your render function. Call the method inside a `useEffect` hook instead.\",\n);\nexport const EMPTY_THREAD_CORE: ThreadRuntimeCore = {\n getMessageById() {\n return undefined;\n },\n\n getBranches() {\n return [];\n },\n\n switchToBranch() {\n throw EMPTY_THREAD_ERROR;\n },\n\n append() {\n throw EMPTY_THREAD_ERROR;\n },\n\n deleteMessage() {\n throw EMPTY_THREAD_ERROR;\n },\n\n startRun() {\n throw EMPTY_THREAD_ERROR;\n },\n\n resumeRun() {\n throw EMPTY_THREAD_ERROR;\n },\n\n cancelRun() {\n throw EMPTY_THREAD_ERROR;\n },\n\n addToolResult() {\n throw EMPTY_THREAD_ERROR;\n },\n\n resumeToolCall() {\n throw EMPTY_THREAD_ERROR;\n },\n\n respondToToolApproval() {\n throw EMPTY_THREAD_ERROR;\n },\n\n speak() {\n throw EMPTY_THREAD_ERROR;\n },\n\n stopSpeaking() {\n throw EMPTY_THREAD_ERROR;\n },\n\n connectVoice() {\n throw EMPTY_THREAD_ERROR;\n },\n\n disconnectVoice() {\n throw EMPTY_THREAD_ERROR;\n },\n\n getVoiceVolume: () => 0,\n subscribeVoiceVolume: () => () => {},\n\n muteVoice() {\n throw EMPTY_THREAD_ERROR;\n },\n\n unmuteVoice() {\n throw EMPTY_THREAD_ERROR;\n },\n\n submitFeedback() {\n throw EMPTY_THREAD_ERROR;\n },\n\n getModelContext() {\n return {};\n },\n\n exportExternalState() {\n throw EMPTY_THREAD_ERROR;\n },\n\n importExternalState() {\n throw EMPTY_THREAD_ERROR;\n },\n\n unstable_notifySessionReset() {\n throw EMPTY_THREAD_ERROR;\n },\n\n composer: {\n attachments: [],\n attachmentAccept: \"*\",\n\n async addAttachment() {\n throw EMPTY_THREAD_ERROR;\n },\n\n async removeAttachment() {\n throw EMPTY_THREAD_ERROR;\n },\n\n isEditing: true,\n\n canCancel: false,\n canSend: false,\n isEmpty: true,\n\n text: \"\",\n\n setText() {\n throw EMPTY_THREAD_ERROR;\n },\n\n role: \"user\",\n\n setRole() {\n throw EMPTY_THREAD_ERROR;\n },\n\n runConfig: {},\n\n setRunConfig() {\n throw EMPTY_THREAD_ERROR;\n },\n\n async reset() {\n // noop\n },\n\n async clearAttachments() {\n // noop\n },\n\n send() {\n throw EMPTY_THREAD_ERROR;\n },\n\n cancel() {\n // noop\n },\n\n queue: [] as never[],\n moveQueueItem() {},\n removeQueueItem() {},\n\n dictation: undefined,\n\n startDictation() {\n throw EMPTY_THREAD_ERROR;\n },\n\n stopDictation() {\n // noop\n },\n\n quote: undefined,\n\n setQuote() {\n throw EMPTY_THREAD_ERROR;\n },\n\n subscribe() {\n return () => {};\n },\n\n unstable_on() {\n return () => {};\n },\n },\n\n getEditComposer() {\n return undefined;\n },\n\n beginEdit() {\n throw EMPTY_THREAD_ERROR;\n },\n\n speech: undefined,\n voice: undefined,\n\n capabilities: {\n switchToBranch: false,\n switchBranchDuringRun: false,\n edit: false,\n delete: false,\n reload: false,\n refetchThread: false,\n cancel: false,\n unstable_copy: false,\n speech: false,\n dictation: false,\n voice: false,\n attachments: false,\n feedback: false,\n queue: false,\n },\n\n isDisabled: false,\n isSendDisabled: false,\n isLoading: true,\n\n messages: [],\n\n state: null,\n\n suggestions: [],\n\n extras: undefined,\n\n subscribe() {\n return () => {};\n },\n\n import() {\n throw EMPTY_THREAD_ERROR;\n },\n\n export() {\n return { messages: [] };\n },\n\n reset() {\n throw EMPTY_THREAD_ERROR;\n },\n\n unstable_on() {\n return () => {};\n },\n};\n"],"mappings":";AAEA,MAAMC,qCAAqB,IAAIC,MAC7B,mQACF;AACA,MAAaC,oBAAuC;CAClDC,iBAAiB,CAEjB;CAEAE,cAAc;EACZ,OAAO,CAAA;CACT;CAEAC,iBAAiB;EACf,MAAMN;CACR;CAEAO,SAAS;EACP,MAAMP;CACR;CAEAQ,gBAAgB;EACd,MAAMR;CACR;CAEAS,WAAW;EACT,MAAMT;CACR;CAEAU,YAAY;EACV,MAAMV;CACR;CAEAW,YAAY;EACV,MAAMX;CACR;CAEAY,gBAAgB;EACd,MAAMZ;CACR;CAEAa,iBAAiB;EACf,MAAMb;CACR;CAEAc,wBAAwB;EACtB,MAAMd;CACR;CAEAe,QAAQ;EACN,MAAMf;CACR;CAEAgB,eAAe;EACb,MAAMhB;CACR;CAEAiB,eAAe;EACb,MAAMjB;CACR;CAEAkB,kBAAkB;EAChB,MAAMlB;CACR;CAEAmB,sBAAsB;CACtBC,kCAAkC,CAAC;CAEnCC,YAAY;EACV,MAAMrB;CACR;CAEAsB,cAAc;EACZ,MAAMtB;CACR;CAEAuB,iBAAiB;EACf,MAAMvB;CACR;CAEAwB,kBAAkB;EAChB,OAAO,CAAC;CACV;CAEAC,sBAAsB;EACpB,MAAMzB;CACR;CAEA0B,sBAAsB;EACpB,MAAM1B;CACR;CAEA2B,8BAA8B;EAC5B,MAAM3B;CACR;CAEA4B,UAAU;EACRC,aAAa,CAAA;EACbC,kBAAkB;EAElB,MAAMC,gBAAgB;GACpB,MAAM/B;EACR;EAEA,MAAMgC,mBAAmB;GACvB,MAAMhC;EACR;EAEAiC,WAAW;EAEXC,WAAW;EACXC,SAAS;EACTC,SAAS;EAETC,MAAM;EAENC,UAAU;GACR,MAAMtC;EACR;EAEAuC,MAAM;EAENC,UAAU;GACR,MAAMxC;EACR;EAEAyC,WAAW,CAAC;EAEZC,eAAe;GACb,MAAM1C;EACR;EAEA,MAAM2C,QAAQ,CACZ;EAGF,MAAMC,mBAAmB,CACvB;EAGFC,OAAO;GACL,MAAM7C;EACR;EAEA8C,SAAS,CACP;EAGFC,OAAO,CAAA;EACPC,gBAAgB,CAAC;EACjBC,kBAAkB,CAAC;EAEnBC,WAAW9C,KAAAA;EAEX+C,iBAAiB;GACf,MAAMnD;EACR;EAEAoD,gBAAgB,CACd;EAGFC,OAAOjD,KAAAA;EAEPkD,WAAW;GACT,MAAMtD;EACR;EAEAuD,YAAY;GACV,aAAa,CAAC;EAChB;EAEAC,cAAc;GACZ,aAAa,CAAC;EAChB;CACF;CAEAC,kBAAkB,CAElB;CAEAC,YAAY;EACV,MAAM1D;CACR;CAEA2D,QAAQvD,KAAAA;CACRwD,OAAOxD,KAAAA;CAEPyD,cAAc;EACZvD,gBAAgB;EAChBwD,uBAAuB;EACvBC,MAAM;EACNC,QAAQ;EACRC,QAAQ;EACRC,eAAe;EACfpB,QAAQ;EACRqB,eAAe;EACfR,QAAQ;EACRT,WAAW;EACXU,OAAO;EACP/B,aAAa;EACbuC,UAAU;EACVrB,OAAO;CACT;CAEAsB,YAAY;CACZC,gBAAgB;CAChBC,WAAW;CAEXC,UAAU,CAAA;CAEVC,OAAO;CAEPC,aAAa,CAAA;CAEbC,QAAQvE,KAAAA;CAERmD,YAAY;EACV,aAAa,CAAC;CAChB;CAEAqB,SAAS;EACP,MAAM5E;CACR;CAEA6E,SAAS;EACP,OAAO,EAAEL,UAAU,CAAA,EAAG;CACxB;CAEA7B,QAAQ;EACN,MAAM3C;CACR;CAEAwD,cAAc;EACZ,aAAa,CAAC;CAChB;AACF"}
1
+ {"version":3,"file":"empty-thread-core.js","names":["Unsubscribe","ThreadRuntimeCore","InertThreadRuntimeCore","createInertComposer","EMPTY_THREAD_ERROR","Error","EmptyThreadRuntimeCore","error","messages","composer","isLoading","getMessageById","undefined","getBranches","export","subscribe","waitForUpdate","Promise","reject","EMPTY_THREAD_CORE"],"sources":["../../../src/runtimes/remote-thread-list/empty-thread-core.ts"],"sourcesContent":["import type { Unsubscribe } from \"../../types/unsubscribe\";\nimport type { ThreadRuntimeCore } from \"../../runtime/interfaces/thread-runtime-core\";\nimport {\n InertThreadRuntimeCore,\n createInertComposer,\n} from \"../inert/InertThreadRuntimeCore\";\n\nconst EMPTY_THREAD_ERROR = new Error(\n \"This is the empty thread, a placeholder for the main thread. You cannot perform any actions on this thread instance. This error is probably because you tried to call a thread method in your render function. Call the method inside a `useEffect` hook instead.\",\n);\n\nclass EmptyThreadRuntimeCore extends InertThreadRuntimeCore {\n protected get error() {\n return EMPTY_THREAD_ERROR;\n }\n\n messages = [] as never[];\n\n composer = createInertComposer(EMPTY_THREAD_ERROR, true);\n\n isLoading = true;\n\n getMessageById() {\n return undefined;\n }\n\n getBranches() {\n return [];\n }\n\n export() {\n return { messages: [] };\n }\n\n override subscribe(): Unsubscribe {\n return () => {};\n }\n\n override waitForUpdate(): Promise<void> {\n return Promise.reject(EMPTY_THREAD_ERROR);\n }\n}\n\nexport const EMPTY_THREAD_CORE: ThreadRuntimeCore =\n new EmptyThreadRuntimeCore();\n"],"mappings":";;AAOA,MAAMI,qCAAqB,IAAIC,MAC7B,mQACF;AAEA,IAAMC,yBAAN,cAAqCJ,uBAAuB;CAC1D,IAAcK,QAAQ;EACpB,OAAOH;CACT;CAEAI,WAAW,CAAA;CAEXC,WAAWN,oBAAoBC,oBAAoB,IAAI;CAEvDM,YAAY;CAEZC,iBAAiB,CAEjB;CAEAE,cAAc;EACZ,OAAO,CAAA;CACT;CAEAC,SAAS;EACP,OAAO,EAAEN,UAAU,CAAA,EAAG;CACxB;CAEA,YAAkC;EAChC,aAAa,CAAC;CAChB;CAEA,gBAAwC;EACtC,OAAOS,QAAQC,OAAOd,kBAAkB;CAC1C;AACF;AAEA,MAAae,oBACX,IAAIb,uBAAuB"}
@@ -20,6 +20,7 @@ declare class OptimisticState<TState> extends BaseSubscribable {
20
20
  */
21
21
  private readonly _completedOptimistics;
22
22
  private _nextTransformOrder;
23
+ private _epoch;
23
24
  private _baseValue;
24
25
  private _cachedValue;
25
26
  constructor(initialState: TState);
@@ -27,6 +28,7 @@ declare class OptimisticState<TState> extends BaseSubscribable {
27
28
  get baseValue(): TState;
28
29
  get value(): TState;
29
30
  update(state: TState): void;
31
+ reset(state: TState): void;
30
32
  optimisticUpdate<TResult>(transform: Transform<TState, TResult>): Promise<TResult>;
31
33
  }
32
34
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"optimistic-state.d.ts","names":[],"sources":["../../../src/runtimes/remote-thread-list/optimistic-state.ts"],"mappings":";;KAEK,UAAU,QAAQ;EACrB,eAAe,QAAQ;;EAGvB,QAAQ,OAAO,QAAQ,QAAQ,YAAY;;EAG3C,cAAc,OAAO,WAAW;;EAGhC,WAAW,OAAO,QAAQ,MAAM,QAAQ,aAAa;;cAuB1C,gBAAgB,gBAAgB;mBAC1B;;;;;;;;mBAUA;UAGT;UAEA;UACA;EAEW,YAAA,cAAc;UAMzB;MAwBG,aAAa;MAIb,SAAS;EAIb,OAAO,OAAO;EAKR,iBAAiB,SAC5B,WAAW,UAAU,QAAQ,WAC5B,QAAQ"}
1
+ {"version":3,"file":"optimistic-state.d.ts","names":[],"sources":["../../../src/runtimes/remote-thread-list/optimistic-state.ts"],"mappings":";;KAEK,UAAU,QAAQ;EACrB,eAAe,QAAQ;;EAGvB,QAAQ,OAAO,QAAQ,QAAQ,YAAY;;EAG3C,cAAc,OAAO,WAAW;;EAGhC,WAAW,OAAO,QAAQ,MAAM,QAAQ,aAAa;;cAuB1C,gBAAgB,gBAAgB;mBAC1B;;;;;;;;mBAUA;UAGT;UACA;UAEA;UACA;EAEW,YAAA,cAAc;UAMzB;MAwBG,aAAa;MAIb,SAAS;EAIb,OAAO,OAAO;EAKd,MAAM,OAAO;EAUP,iBAAiB,SAC5B,WAAW,UAAU,QAAQ,WAC5B,QAAQ"}
@@ -16,6 +16,7 @@ var OptimisticState = class extends BaseSubscribable {
16
16
  */
17
17
  _completedOptimistics = [];
18
18
  _nextTransformOrder = 0;
19
+ _epoch = 0;
19
20
  _baseValue;
20
21
  _cachedValue;
21
22
  constructor(initialState) {
@@ -44,7 +45,16 @@ var OptimisticState = class extends BaseSubscribable {
44
45
  this._baseValue = state;
45
46
  this._updateState();
46
47
  }
48
+ reset(state) {
49
+ this._epoch++;
50
+ this._pendingTransforms.length = 0;
51
+ this._completedOptimistics.length = 0;
52
+ this._baseValue = state;
53
+ this._cachedValue = state;
54
+ this._notifySubscribers();
55
+ }
47
56
  async optimisticUpdate(transform) {
57
+ const epoch = this._epoch;
48
58
  const order = this._nextTransformOrder++;
49
59
  const task = transform.execute();
50
60
  const pendingTransform = {
@@ -56,6 +66,7 @@ var OptimisticState = class extends BaseSubscribable {
56
66
  this._pendingTransforms.push(pendingTransform);
57
67
  this._updateState();
58
68
  const result = await task;
69
+ if (epoch !== this._epoch) return result;
59
70
  this._baseValue = pipeTransforms(this._baseValue, result, [transform.optimistic, transform.then]);
60
71
  for (const completed of this._completedOptimistics) if (transform.then || completed.order > pendingTransform.order) this._baseValue = completed.optimistic(this._baseValue);
61
72
  if (transform.optimistic) {
@@ -1 +1 @@
1
- {"version":3,"file":"optimistic-state.js","names":["BaseSubscribable","Transform","execute","Promise","TResult","then","state","TState","result","optimistic","loading","task","PendingTransform","order","CompletedOptimistic","pipeTransforms","initialState","extraParam","TExtra","transforms","extra","reduce","transform","OptimisticState","_pendingTransforms","Array","_completedOptimistics","_nextTransformOrder","_baseValue","_cachedValue","constructor","_updateState","activeTransforms","map","apply","sort","a","b","_notifySubscribers","baseValue","value","update","optimisticUpdate","pendingTransform","push","completed","index","indexOf","splice","length"],"sources":["../../../src/runtimes/remote-thread-list/optimistic-state.ts"],"sourcesContent":["import { BaseSubscribable } from \"../../subscribable/subscribable\";\n\ntype Transform<TState, TResult> = {\n execute: () => Promise<TResult>;\n\n /** transform the state after the promise resolves */\n then?: (state: TState, result: TResult) => TState;\n\n /** transform the state during resolution and afterwards */\n optimistic?: (state: TState) => TState;\n\n /** transform the state only while loading */\n loading?: (state: TState, task: Promise<TResult>) => TState;\n};\n\ntype PendingTransform<TState, TResult> = Transform<TState, TResult> & {\n order: number;\n task: Promise<TResult>;\n};\n\ntype CompletedOptimistic<TState> = {\n order: number;\n optimistic: (state: TState) => TState;\n};\n\nconst pipeTransforms = <TState, TExtra>(\n initialState: TState,\n extraParam: TExtra,\n transforms: (((state: TState, extra: TExtra) => TState) | undefined)[],\n): TState => {\n return transforms.reduce((state, transform) => {\n return transform?.(state, extraParam) ?? state;\n }, initialState);\n};\n\nexport class OptimisticState<TState> extends BaseSubscribable {\n private readonly _pendingTransforms: Array<PendingTransform<TState, any>> =\n [];\n\n /**\n * Completed optimistic callbacks remain active while any transform is\n * pending, so later state replacements cannot erase them. Invocation order\n * determines which overlapping optimistic update wins.\n *\n * Correctness requirement: `optimistic` callbacks must be idempotent.\n */\n private readonly _completedOptimistics: Array<CompletedOptimistic<TState>> =\n [];\n\n private _nextTransformOrder = 0;\n\n private _baseValue: TState;\n private _cachedValue: TState;\n\n public constructor(initialState: TState) {\n super();\n this._baseValue = initialState;\n this._cachedValue = initialState;\n }\n\n private _updateState(): void {\n const activeTransforms = [\n ...this._pendingTransforms.map((transform) => ({\n order: transform.order,\n apply: (state: TState) =>\n pipeTransforms(state, transform.task, [\n transform.loading,\n transform.optimistic,\n ]),\n })),\n ...this._completedOptimistics.map(({ order, optimistic }) => ({\n order,\n apply: optimistic,\n })),\n ].sort((a, b) => a.order - b.order);\n\n this._cachedValue = activeTransforms.reduce(\n (state, transform) => transform.apply(state),\n this._baseValue,\n );\n\n this._notifySubscribers();\n }\n\n public get baseValue(): TState {\n return this._baseValue;\n }\n\n public get value(): TState {\n return this._cachedValue;\n }\n\n public update(state: TState): void {\n this._baseValue = state;\n this._updateState();\n }\n\n public async optimisticUpdate<TResult>(\n transform: Transform<TState, TResult>,\n ): Promise<TResult> {\n const order = this._nextTransformOrder++;\n const task = transform.execute();\n const pendingTransform = {\n ...transform,\n order,\n task,\n };\n try {\n this._pendingTransforms.push(pendingTransform);\n this._updateState();\n\n const result = await task;\n this._baseValue = pipeTransforms(this._baseValue, result, [\n transform.optimistic,\n transform.then,\n ]);\n\n // `then` can replace state with a stale snapshot, so replay every\n // completed effect; otherwise replay only newer overlapping effects.\n for (const completed of this._completedOptimistics) {\n if (transform.then || completed.order > pendingTransform.order) {\n this._baseValue = completed.optimistic(this._baseValue);\n }\n }\n\n if (transform.optimistic) {\n this._completedOptimistics.push({\n order: pendingTransform.order,\n optimistic: transform.optimistic,\n });\n this._completedOptimistics.sort((a, b) => a.order - b.order);\n }\n\n return result;\n } finally {\n const index = this._pendingTransforms.indexOf(pendingTransform);\n if (index > -1) {\n this._pendingTransforms.splice(index, 1);\n }\n\n if (this._pendingTransforms.length === 0) {\n this._completedOptimistics.length = 0;\n }\n\n this._updateState();\n }\n }\n}\n"],"mappings":";;AAyBA,MAAMe,kBACJC,cACAC,YACAE,eACW;CACX,OAAOA,WAAWE,QAAQf,OAAOgB,cAAc;EAC7C,OAAOA,YAAYhB,OAAOW,UAAU,KAAKX;CAC3C,GAAGU,YAAY;AACjB;AAEA,IAAaO,kBAAb,cAA6CvB,iBAAiB;CAC5D,qBACE,CAAA;;;;;;;;CASF,wBACE,CAAA;CAEF,sBAA8B;CAE9B;CACA;CAEA,YAAmBgB,cAAsB;EACvC,MAAM;EACN,KAAKY,aAAaZ;EAClB,KAAKa,eAAeb;CACtB;CAEA,eAA6B;EAC3B,MAAMgB,mBAAmB,CACvB,GAAG,KAAKR,mBAAmBS,KAAKX,eAAe;GAC7CT,OAAOS,UAAUT;GACjBqB,QAAQ5B,UACNS,eAAeT,OAAOgB,UAAUX,MAAM,CACpCW,UAAUZ,SACVY,UAAUb,UAAU,CACrB;EACL,EAAE,GACF,GAAG,KAAKiB,sBAAsBO,KAAK,EAAEpB,OAAOJ,kBAAkB;GAC5DI;GACAqB,OAAOzB;EACT,EAAE,CAAC,CACJ,CAAC0B,MAAMC,GAAGC,MAAMD,EAAEvB,QAAQwB,EAAExB,KAAK;EAElC,KAAKgB,eAAeG,iBAAiBX,QAClCf,OAAOgB,cAAcA,UAAUY,MAAM5B,KAAK,GAC3C,KAAKsB,UACP;EAEA,KAAKU,mBAAmB;CAC1B;CAEA,IAAWC,YAAoB;EAC7B,OAAO,KAAKX;CACd;CAEA,IAAWY,QAAgB;EACzB,OAAO,KAAKX;CACd;CAEA,OAAcvB,OAAqB;EACjC,KAAKsB,aAAatB;EAClB,KAAKyB,aAAa;CACpB;CAEA,MAAaW,iBACXpB,WACkB;EAClB,MAAMT,QAAQ,KAAKc;EACnB,MAAMhB,OAAOW,UAAUpB,QAAQ;EAC/B,MAAMyC,mBAAmB;GACvB,GAAGrB;GACHT;GACAF;EACF;EACA,IAAI;GACF,KAAKa,mBAAmBoB,KAAKD,gBAAgB;GAC7C,KAAKZ,aAAa;GAElB,MAAMvB,SAAS,MAAMG;GACrB,KAAKiB,aAAab,eAAe,KAAKa,YAAYpB,QAAQ,CACxDc,UAAUb,YACVa,UAAUjB,IAAI,CACf;GAID,KAAK,MAAMwC,aAAa,KAAKnB,uBAC3B,IAAIJ,UAAUjB,QAAQwC,UAAUhC,QAAQ8B,iBAAiB9B,OACvD,KAAKe,aAAaiB,UAAUpC,WAAW,KAAKmB,UAAU;GAI1D,IAAIN,UAAUb,YAAY;IACxB,KAAKiB,sBAAsBkB,KAAK;KAC9B/B,OAAO8B,iBAAiB9B;KACxBJ,YAAYa,UAAUb;IACxB,CAAC;IACD,KAAKiB,sBAAsBS,MAAMC,GAAGC,MAAMD,EAAEvB,QAAQwB,EAAExB,KAAK;GAC7D;GAEA,OAAOL;EACT,UAAU;GACR,MAAMsC,QAAQ,KAAKtB,mBAAmBuB,QAAQJ,gBAAgB;GAC9D,IAAIG,QAAQ,IACV,KAAKtB,mBAAmBwB,OAAOF,OAAO,CAAC;GAGzC,IAAI,KAAKtB,mBAAmByB,WAAW,GACrC,KAAKvB,sBAAsBuB,SAAS;GAGtC,KAAKlB,aAAa;EACpB;CACF;AACF"}
1
+ {"version":3,"file":"optimistic-state.js","names":["BaseSubscribable","Transform","execute","Promise","TResult","then","state","TState","result","optimistic","loading","task","PendingTransform","order","CompletedOptimistic","pipeTransforms","initialState","extraParam","TExtra","transforms","extra","reduce","transform","OptimisticState","_pendingTransforms","Array","_completedOptimistics","_nextTransformOrder","_epoch","_baseValue","_cachedValue","constructor","_updateState","activeTransforms","map","apply","sort","a","b","_notifySubscribers","baseValue","value","update","reset","length","optimisticUpdate","epoch","pendingTransform","push","completed","index","indexOf","splice"],"sources":["../../../src/runtimes/remote-thread-list/optimistic-state.ts"],"sourcesContent":["import { BaseSubscribable } from \"../../subscribable/subscribable\";\n\ntype Transform<TState, TResult> = {\n execute: () => Promise<TResult>;\n\n /** transform the state after the promise resolves */\n then?: (state: TState, result: TResult) => TState;\n\n /** transform the state during resolution and afterwards */\n optimistic?: (state: TState) => TState;\n\n /** transform the state only while loading */\n loading?: (state: TState, task: Promise<TResult>) => TState;\n};\n\ntype PendingTransform<TState, TResult> = Transform<TState, TResult> & {\n order: number;\n task: Promise<TResult>;\n};\n\ntype CompletedOptimistic<TState> = {\n order: number;\n optimistic: (state: TState) => TState;\n};\n\nconst pipeTransforms = <TState, TExtra>(\n initialState: TState,\n extraParam: TExtra,\n transforms: (((state: TState, extra: TExtra) => TState) | undefined)[],\n): TState => {\n return transforms.reduce((state, transform) => {\n return transform?.(state, extraParam) ?? state;\n }, initialState);\n};\n\nexport class OptimisticState<TState> extends BaseSubscribable {\n private readonly _pendingTransforms: Array<PendingTransform<TState, any>> =\n [];\n\n /**\n * Completed optimistic callbacks remain active while any transform is\n * pending, so later state replacements cannot erase them. Invocation order\n * determines which overlapping optimistic update wins.\n *\n * Correctness requirement: `optimistic` callbacks must be idempotent.\n */\n private readonly _completedOptimistics: Array<CompletedOptimistic<TState>> =\n [];\n\n private _nextTransformOrder = 0;\n private _epoch = 0;\n\n private _baseValue: TState;\n private _cachedValue: TState;\n\n public constructor(initialState: TState) {\n super();\n this._baseValue = initialState;\n this._cachedValue = initialState;\n }\n\n private _updateState(): void {\n const activeTransforms = [\n ...this._pendingTransforms.map((transform) => ({\n order: transform.order,\n apply: (state: TState) =>\n pipeTransforms(state, transform.task, [\n transform.loading,\n transform.optimistic,\n ]),\n })),\n ...this._completedOptimistics.map(({ order, optimistic }) => ({\n order,\n apply: optimistic,\n })),\n ].sort((a, b) => a.order - b.order);\n\n this._cachedValue = activeTransforms.reduce(\n (state, transform) => transform.apply(state),\n this._baseValue,\n );\n\n this._notifySubscribers();\n }\n\n public get baseValue(): TState {\n return this._baseValue;\n }\n\n public get value(): TState {\n return this._cachedValue;\n }\n\n public update(state: TState): void {\n this._baseValue = state;\n this._updateState();\n }\n\n public reset(state: TState): void {\n // In-flight optimisticUpdate calls must not write into the replacement state.\n this._epoch++;\n this._pendingTransforms.length = 0;\n this._completedOptimistics.length = 0;\n this._baseValue = state;\n this._cachedValue = state;\n this._notifySubscribers();\n }\n\n public async optimisticUpdate<TResult>(\n transform: Transform<TState, TResult>,\n ): Promise<TResult> {\n const epoch = this._epoch;\n const order = this._nextTransformOrder++;\n const task = transform.execute();\n const pendingTransform = {\n ...transform,\n order,\n task,\n };\n try {\n this._pendingTransforms.push(pendingTransform);\n this._updateState();\n\n const result = await task;\n if (epoch !== this._epoch) return result;\n this._baseValue = pipeTransforms(this._baseValue, result, [\n transform.optimistic,\n transform.then,\n ]);\n\n // `then` can replace state with a stale snapshot, so replay every\n // completed effect; otherwise replay only newer overlapping effects.\n for (const completed of this._completedOptimistics) {\n if (transform.then || completed.order > pendingTransform.order) {\n this._baseValue = completed.optimistic(this._baseValue);\n }\n }\n\n if (transform.optimistic) {\n this._completedOptimistics.push({\n order: pendingTransform.order,\n optimistic: transform.optimistic,\n });\n this._completedOptimistics.sort((a, b) => a.order - b.order);\n }\n\n return result;\n } finally {\n const index = this._pendingTransforms.indexOf(pendingTransform);\n if (index > -1) {\n this._pendingTransforms.splice(index, 1);\n }\n\n if (this._pendingTransforms.length === 0) {\n this._completedOptimistics.length = 0;\n }\n\n this._updateState();\n }\n }\n}\n"],"mappings":";;AAyBA,MAAMe,kBACJC,cACAC,YACAE,eACW;CACX,OAAOA,WAAWE,QAAQf,OAAOgB,cAAc;EAC7C,OAAOA,YAAYhB,OAAOW,UAAU,KAAKX;CAC3C,GAAGU,YAAY;AACjB;AAEA,IAAaO,kBAAb,cAA6CvB,iBAAiB;CAC5D,qBACE,CAAA;;;;;;;;CASF,wBACE,CAAA;CAEF,sBAA8B;CAC9B,SAAiB;CAEjB;CACA;CAEA,YAAmBgB,cAAsB;EACvC,MAAM;EACN,KAAKa,aAAab;EAClB,KAAKc,eAAed;CACtB;CAEA,eAA6B;EAC3B,MAAMiB,mBAAmB,CACvB,GAAG,KAAKT,mBAAmBU,KAAKZ,eAAe;GAC7CT,OAAOS,UAAUT;GACjBsB,QAAQ7B,UACNS,eAAeT,OAAOgB,UAAUX,MAAM,CACpCW,UAAUZ,SACVY,UAAUb,UAAU,CACrB;EACL,EAAE,GACF,GAAG,KAAKiB,sBAAsBQ,KAAK,EAAErB,OAAOJ,kBAAkB;GAC5DI;GACAsB,OAAO1B;EACT,EAAE,CAAC,CACJ,CAAC2B,MAAMC,GAAGC,MAAMD,EAAExB,QAAQyB,EAAEzB,KAAK;EAElC,KAAKiB,eAAeG,iBAAiBZ,QAClCf,OAAOgB,cAAcA,UAAUa,MAAM7B,KAAK,GAC3C,KAAKuB,UACP;EAEA,KAAKU,mBAAmB;CAC1B;CAEA,IAAWC,YAAoB;EAC7B,OAAO,KAAKX;CACd;CAEA,IAAWY,QAAgB;EACzB,OAAO,KAAKX;CACd;CAEA,OAAcxB,OAAqB;EACjC,KAAKuB,aAAavB;EAClB,KAAK0B,aAAa;CACpB;CAEA,MAAa1B,OAAqB;EAEhC,KAAKsB;EACL,KAAKJ,mBAAmBoB,SAAS;EACjC,KAAKlB,sBAAsBkB,SAAS;EACpC,KAAKf,aAAavB;EAClB,KAAKwB,eAAexB;EACpB,KAAKiC,mBAAmB;CAC1B;CAEA,MAAaM,iBACXvB,WACkB;EAClB,MAAMwB,QAAQ,KAAKlB;EACnB,MAAMf,QAAQ,KAAKc;EACnB,MAAMhB,OAAOW,UAAUpB,QAAQ;EAC/B,MAAM6C,mBAAmB;GACvB,GAAGzB;GACHT;GACAF;EACF;EACA,IAAI;GACF,KAAKa,mBAAmBwB,KAAKD,gBAAgB;GAC7C,KAAKf,aAAa;GAElB,MAAMxB,SAAS,MAAMG;GACrB,IAAImC,UAAU,KAAKlB,QAAQ,OAAOpB;GAClC,KAAKqB,aAAad,eAAe,KAAKc,YAAYrB,QAAQ,CACxDc,UAAUb,YACVa,UAAUjB,IAAI,CACf;GAID,KAAK,MAAM4C,aAAa,KAAKvB,uBAC3B,IAAIJ,UAAUjB,QAAQ4C,UAAUpC,QAAQkC,iBAAiBlC,OACvD,KAAKgB,aAAaoB,UAAUxC,WAAW,KAAKoB,UAAU;GAI1D,IAAIP,UAAUb,YAAY;IACxB,KAAKiB,sBAAsBsB,KAAK;KAC9BnC,OAAOkC,iBAAiBlC;KACxBJ,YAAYa,UAAUb;IACxB,CAAC;IACD,KAAKiB,sBAAsBU,MAAMC,GAAGC,MAAMD,EAAExB,QAAQyB,EAAEzB,KAAK;GAC7D;GAEA,OAAOL;EACT,UAAU;GACR,MAAM0C,QAAQ,KAAK1B,mBAAmB2B,QAAQJ,gBAAgB;GAC9D,IAAIG,QAAQ,IACV,KAAK1B,mBAAmB4B,OAAOF,OAAO,CAAC;GAGzC,IAAI,KAAK1B,mBAAmBoB,WAAW,GACrC,KAAKlB,sBAAsBkB,SAAS;GAGtC,KAAKZ,aAAa;EACpB;CACF;AACF"}
@@ -7,6 +7,7 @@ type RemoteThreadData = {
7
7
  readonly status: "new";
8
8
  readonly title: undefined;
9
9
  readonly custom: undefined;
10
+ readonly localOrigin?: true;
10
11
  } | {
11
12
  readonly id: string;
12
13
  readonly initializeTask: Promise<RemoteThreadInitializeResponse>;
@@ -15,6 +16,7 @@ type RemoteThreadData = {
15
16
  readonly status: "regular" | "archived";
16
17
  readonly title?: string | undefined;
17
18
  readonly custom: undefined;
19
+ readonly localOrigin?: true;
18
20
  } | {
19
21
  readonly id: string;
20
22
  readonly initializeTask: Promise<RemoteThreadInitializeResponse>;
@@ -24,11 +26,13 @@ type RemoteThreadData = {
24
26
  readonly title?: string | undefined;
25
27
  readonly lastMessageAt?: Date | undefined;
26
28
  readonly custom?: Record<string, unknown> | undefined;
29
+ readonly localOrigin?: true;
27
30
  };
28
31
  type THREAD_MAPPING_ID = string & {
29
32
  __brand: "THREAD_MAPPING_ID";
30
33
  };
31
34
  declare function createThreadMappingId(id: string): THREAD_MAPPING_ID;
35
+ declare const LOCAL_THREAD_ID_PREFIX = "__LOCALID_";
32
36
  declare const normalizeCursor: (c: string | undefined) => string | undefined;
33
37
  type ClassifyAccumulator = {
34
38
  threadIds: string[];
@@ -47,8 +51,15 @@ type RemoteThreadState = {
47
51
  readonly threadIdMap: Readonly<Record<string, THREAD_MAPPING_ID>>;
48
52
  readonly threadData: Readonly<Record<THREAD_MAPPING_ID, RemoteThreadData>>;
49
53
  };
54
+ declare const createEmptyRemoteThreadState: () => RemoteThreadState;
55
+ declare const seedNewThread: (state: RemoteThreadState) => {
56
+ id: string;
57
+ state: RemoteThreadState;
58
+ };
59
+ declare const preserveMidLoadTransitions: (state: RemoteThreadState, priorOrder: Pick<RemoteThreadState, "threadIds" | "archivedThreadIds">, statusAtRequest: ReadonlyMap<string, RemoteThreadData["status"]>) => RemoteThreadState;
60
+ declare const statusSnapshot: (state: RemoteThreadState) => ReadonlyMap<string, RemoteThreadData["status"]>;
50
61
  declare const getThreadData: (state: RemoteThreadState, threadIdOrRemoteId: string) => RemoteThreadData | undefined;
51
62
  declare const updateStatusReducer: (state: RemoteThreadState, threadIdOrRemoteId: string, newStatus: "regular" | "archived" | "deleted") => RemoteThreadState;
52
63
  //#endregion
53
- export { RemoteThreadData, RemoteThreadState, THREAD_MAPPING_ID, classifyThreads, createThreadMappingId, getThreadData, normalizeCursor, updateStatusReducer };
64
+ export { LOCAL_THREAD_ID_PREFIX, RemoteThreadData, RemoteThreadState, THREAD_MAPPING_ID, classifyThreads, createEmptyRemoteThreadState, createThreadMappingId, getThreadData, normalizeCursor, preserveMidLoadTransitions, seedNewThread, statusSnapshot, updateStatusReducer };
54
65
  //# sourceMappingURL=remote-thread-state.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"remote-thread-state.d.ts","names":[],"sources":["../../../src/runtimes/remote-thread-list/remote-thread-state.ts"],"mappings":";;KAKY;WAEG;WACA;WACA;WACA;WACA;WACA;;WAGA;WACA,gBAAgB,QAAQ;WACxB;WACA;WACA;WACA;WACA;;WAGA;WACA,gBAAgB,QAAQ;WACxB;WACA;WACA;WACA;WACA,gBAAgB;WAChB,SAAS;;KAGZ;EAA+B;;iBAE3B,sBAAsB,aAAa;cAItC,kBAAmB;KAG3B;EACH;EACA;EACA,aAAa,eAAe;EAC5B,YAAY,OAAO,mBAAmB;;cAG3B,kBACX,kBAAkB,wBAClB,KAAK,wBACJ;KAoCS;WACD;WACA;WACA;WACA;WACA;WACA;WACA,aAAa,SAAS,eAAe;WACrC,YAAY,SAAS,OAAO,mBAAmB;;cAG7C,gBACX,OAAO,mBACP,+BAA0B;cAOf,sBACX,OAAO,mBACP,4BACA,kDAA6C"}
1
+ {"version":3,"file":"remote-thread-state.d.ts","names":[],"sources":["../../../src/runtimes/remote-thread-list/remote-thread-state.ts"],"mappings":";;KAMY;WAEG;WACA;WACA;WACA;WACA;WACA;WACA;;WAGA;WACA,gBAAgB,QAAQ;WACxB;WACA;WACA;WACA;WACA;WACA;;WAGA;WACA,gBAAgB,QAAQ;WACxB;WACA;WACA;WACA;WACA,gBAAgB;WAChB,SAAS;WACT;;KAGH;EAA+B;;iBAE3B,sBAAsB,aAAa;cAItC;cAEA,kBAAmB;KAG3B;EACH;EACA;EACA,aAAa,eAAe;EAC5B,YAAY,OAAO,mBAAmB;;cAG3B,kBACX,kBAAkB,wBAClB,KAAK,wBACJ;KAoCS;WACD;WACA;WACA;WACA;WACA;WACA;WACA,aAAa,SAAS,eAAe;WACrC,YAAY,SAAS,OAAO,mBAAmB;;cAG7C,oCAAmC;cAWnC,gBACX,OAAO;EACJ;EAAY,OAAO;;cA2CX,6BACX,OAAO,mBACP,YAAY,KAAK,uDACjB,iBAAiB,oBAAoB,gCACpC;cAoDU,iBACX,OAAO,sBACN,oBAAoB;cAGV,gBACX,OAAO,mBACP,+BAA0B;cAOf,sBACX,OAAO,mBACP,4BACA,kDAA6C"}
@@ -1,7 +1,9 @@
1
+ import { generateId } from "../../utils/id.js";
1
2
  //#region src/runtimes/remote-thread-list/remote-thread-state.ts
2
3
  function createThreadMappingId(id) {
3
4
  return id;
4
5
  }
6
+ const LOCAL_THREAD_ID_PREFIX = "__LOCALID_";
5
7
  const normalizeCursor = (c) => c || void 0;
6
8
  const classifyThreads = (threads, acc) => {
7
9
  for (const thread of threads) {
@@ -36,6 +38,80 @@ const classifyThreads = (threads, acc) => {
36
38
  }
37
39
  return acc;
38
40
  };
41
+ const createEmptyRemoteThreadState = () => ({
42
+ isLoading: true,
43
+ isLoadingMore: false,
44
+ cursor: void 0,
45
+ newThreadId: void 0,
46
+ threadIds: [],
47
+ archivedThreadIds: [],
48
+ threadIdMap: {},
49
+ threadData: {}
50
+ });
51
+ const seedNewThread = (state) => {
52
+ let id;
53
+ do
54
+ id = `${LOCAL_THREAD_ID_PREFIX}${generateId()}`;
55
+ while (state.threadIdMap[id]);
56
+ const mappingId = createThreadMappingId(id);
57
+ return {
58
+ id,
59
+ state: {
60
+ ...state,
61
+ newThreadId: id,
62
+ threadIdMap: {
63
+ ...state.threadIdMap,
64
+ [id]: mappingId
65
+ },
66
+ threadData: {
67
+ ...state.threadData,
68
+ [mappingId]: {
69
+ status: "new",
70
+ id,
71
+ remoteId: void 0,
72
+ externalId: void 0,
73
+ title: void 0,
74
+ custom: void 0,
75
+ localOrigin: true
76
+ }
77
+ }
78
+ }
79
+ };
80
+ };
81
+ const preserveMidLoadTransitions = (state, priorOrder, statusAtRequest) => {
82
+ const regular = new Set(state.threadIds);
83
+ const archived = new Set(state.archivedThreadIds);
84
+ const rescuedRegular = [];
85
+ const rescuedArchived = [];
86
+ const contains = (ids, data) => ids.has(data.id) || data.remoteId !== void 0 && ids.has(data.remoteId);
87
+ for (const data of Object.values(state.threadData)) {
88
+ const before = statusAtRequest.get(data.id);
89
+ if (before !== void 0 && before !== "new") continue;
90
+ if (before === void 0 && data.localOrigin !== true) continue;
91
+ if (data.status === "regular" && !contains(regular, data)) {
92
+ rescuedRegular.push(data);
93
+ regular.add(data.id);
94
+ } else if (data.status === "archived" && !contains(archived, data)) {
95
+ rescuedArchived.push(data);
96
+ archived.add(data.id);
97
+ }
98
+ }
99
+ if (rescuedRegular.length === 0 && rescuedArchived.length === 0) return state;
100
+ const position = (ids, data) => {
101
+ const byId = ids.indexOf(data.id);
102
+ if (byId !== -1) return byId;
103
+ const byRemoteId = data.remoteId !== void 0 ? ids.indexOf(data.remoteId) : -1;
104
+ return byRemoteId !== -1 ? byRemoteId : Number.MAX_SAFE_INTEGER;
105
+ };
106
+ rescuedRegular.sort((a, b) => position(priorOrder.threadIds, a) - position(priorOrder.threadIds, b));
107
+ rescuedArchived.sort((a, b) => position(priorOrder.archivedThreadIds, a) - position(priorOrder.archivedThreadIds, b));
108
+ return {
109
+ ...state,
110
+ threadIds: [...rescuedRegular.map((d) => d.id), ...state.threadIds],
111
+ archivedThreadIds: [...rescuedArchived.map((d) => d.id), ...state.archivedThreadIds]
112
+ };
113
+ };
114
+ const statusSnapshot = (state) => new Map(Object.values(state.threadData).map((d) => [d.id, d.status]));
39
115
  const getThreadData = (state, threadIdOrRemoteId) => {
40
116
  const idx = state.threadIdMap[threadIdOrRemoteId];
41
117
  if (idx === void 0) return void 0;
@@ -82,6 +158,6 @@ const updateStatusReducer = (state, threadIdOrRemoteId, newStatus) => {
82
158
  return newState;
83
159
  };
84
160
  //#endregion
85
- export { classifyThreads, createThreadMappingId, getThreadData, normalizeCursor, updateStatusReducer };
161
+ export { LOCAL_THREAD_ID_PREFIX, classifyThreads, createEmptyRemoteThreadState, createThreadMappingId, getThreadData, normalizeCursor, preserveMidLoadTransitions, seedNewThread, statusSnapshot, updateStatusReducer };
86
162
 
87
163
  //# sourceMappingURL=remote-thread-state.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"remote-thread-state.js","names":["RemoteThreadInitializeResponse","RemoteThreadMetadata","RemoteThreadData","id","remoteId","externalId","status","title","custom","initializeTask","Promise","lastMessageAt","Date","Record","THREAD_MAPPING_ID","__brand","createThreadMappingId","normalizeCursor","c","undefined","ClassifyAccumulator","threadIds","archivedThreadIds","threadIdMap","threadData","classifyThreads","threads","acc","thread","push","_exhaustiveCheck","Error","mappingId","resolve","RemoteThreadState","isLoading","isLoadingMore","cursor","newThreadId","Readonly","getThreadData","state","threadIdOrRemoteId","idx","updateStatusReducer","newStatus","data","lastStatus","newState","filter","t","Object","fromEntries","entries","key"],"sources":["../../../src/runtimes/remote-thread-list/remote-thread-state.ts"],"sourcesContent":["import type {\n RemoteThreadInitializeResponse,\n RemoteThreadMetadata,\n} from \"./types\";\n\nexport type RemoteThreadData =\n | {\n readonly id: string;\n readonly remoteId: undefined;\n readonly externalId: undefined;\n readonly status: \"new\";\n readonly title: undefined;\n readonly custom: undefined;\n }\n | {\n readonly id: string;\n readonly initializeTask: Promise<RemoteThreadInitializeResponse>;\n readonly remoteId: undefined;\n readonly externalId: undefined;\n readonly status: \"regular\" | \"archived\";\n readonly title?: string | undefined;\n readonly custom: undefined;\n }\n | {\n readonly id: string;\n readonly initializeTask: Promise<RemoteThreadInitializeResponse>;\n readonly remoteId: string;\n readonly externalId: string | undefined;\n readonly status: \"regular\" | \"archived\";\n readonly title?: string | undefined;\n readonly lastMessageAt?: Date | undefined;\n readonly custom?: Record<string, unknown> | undefined;\n };\n\nexport type THREAD_MAPPING_ID = string & { __brand: \"THREAD_MAPPING_ID\" };\n\nexport function createThreadMappingId(id: string): THREAD_MAPPING_ID {\n return id as THREAD_MAPPING_ID;\n}\n\nexport const normalizeCursor = (c: string | undefined): string | undefined =>\n c || undefined;\n\ntype ClassifyAccumulator = {\n threadIds: string[];\n archivedThreadIds: string[];\n threadIdMap: Record<string, THREAD_MAPPING_ID>;\n threadData: Record<THREAD_MAPPING_ID, RemoteThreadData>;\n};\n\nexport const classifyThreads = (\n threads: readonly RemoteThreadMetadata[],\n acc: ClassifyAccumulator,\n): ClassifyAccumulator => {\n for (const thread of threads) {\n if (acc.threadIdMap[thread.remoteId] !== undefined) continue;\n\n switch (thread.status) {\n case \"regular\":\n acc.threadIds.push(thread.remoteId);\n break;\n case \"archived\":\n acc.archivedThreadIds.push(thread.remoteId);\n break;\n default: {\n const _exhaustiveCheck: never = thread.status;\n throw new Error(`Unsupported state: ${_exhaustiveCheck}`);\n }\n }\n\n const mappingId = createThreadMappingId(thread.remoteId);\n acc.threadIdMap[thread.remoteId] = mappingId;\n acc.threadData[mappingId] = {\n id: thread.remoteId,\n remoteId: thread.remoteId,\n externalId: thread.externalId,\n status: thread.status,\n title: thread.title,\n lastMessageAt: thread.lastMessageAt,\n custom: thread.custom,\n initializeTask: Promise.resolve({\n remoteId: thread.remoteId,\n externalId: thread.externalId,\n }),\n };\n }\n return acc;\n};\n\nexport type RemoteThreadState = {\n readonly isLoading: boolean;\n readonly isLoadingMore: boolean;\n readonly cursor: string | undefined;\n readonly newThreadId: string | undefined;\n readonly threadIds: readonly string[];\n readonly archivedThreadIds: readonly string[];\n readonly threadIdMap: Readonly<Record<string, THREAD_MAPPING_ID>>;\n readonly threadData: Readonly<Record<THREAD_MAPPING_ID, RemoteThreadData>>;\n};\n\nexport const getThreadData = (\n state: RemoteThreadState,\n threadIdOrRemoteId: string,\n) => {\n const idx = state.threadIdMap[threadIdOrRemoteId];\n if (idx === undefined) return undefined;\n return state.threadData[idx];\n};\n\nexport const updateStatusReducer = (\n state: RemoteThreadState,\n threadIdOrRemoteId: string,\n newStatus: \"regular\" | \"archived\" | \"deleted\",\n) => {\n const data = getThreadData(state, threadIdOrRemoteId);\n if (!data) return state;\n\n const { id, remoteId, status: lastStatus } = data;\n if (lastStatus === newStatus) return state;\n\n const newState = { ...state };\n\n // lastStatus\n switch (lastStatus) {\n case \"new\":\n newState.newThreadId = undefined;\n break;\n case \"regular\":\n newState.threadIds = newState.threadIds.filter((t) => t !== id);\n break;\n case \"archived\":\n newState.archivedThreadIds = newState.archivedThreadIds.filter(\n (t) => t !== id,\n );\n break;\n\n default: {\n const _exhaustiveCheck: never = lastStatus;\n throw new Error(`Unsupported state: ${_exhaustiveCheck}`);\n }\n }\n\n // newStatus\n switch (newStatus) {\n case \"regular\":\n newState.threadIds = [id, ...newState.threadIds];\n break;\n\n case \"archived\":\n newState.archivedThreadIds = [id, ...newState.archivedThreadIds];\n break;\n\n case \"deleted\":\n newState.threadData = Object.fromEntries(\n Object.entries(newState.threadData).filter(([key]) => key !== id),\n );\n newState.threadIdMap = Object.fromEntries(\n Object.entries(newState.threadIdMap).filter(\n ([key]) => key !== id && key !== remoteId,\n ),\n );\n break;\n\n default: {\n const _exhaustiveCheck: never = newStatus;\n throw new Error(`Unsupported state: ${_exhaustiveCheck}`);\n }\n }\n\n if (newStatus !== \"deleted\") {\n newState.threadData = {\n ...newState.threadData,\n [id]: {\n ...data,\n status: newStatus,\n },\n };\n }\n\n return newState;\n};\n"],"mappings":";AAoCA,SAAgBgB,sBAAsBb,IAA+B;CACnE,OAAOA;AACT;AAEA,MAAac,mBAAmBC,MAC9BA,KAAKC,KAAAA;AASP,MAAaM,mBACXC,SACAC,QACwB;CACxB,KAAK,MAAMC,UAAUF,SAAS;EAC5B,IAAIC,IAAIJ,YAAYK,OAAOxB,cAAce,KAAAA,GAAW;EAEpD,QAAQS,OAAOtB,QAAf;GACE,KAAK;IACHqB,IAAIN,UAAUQ,KAAKD,OAAOxB,QAAQ;IAClC;GACF,KAAK;IACHuB,IAAIL,kBAAkBO,KAAKD,OAAOxB,QAAQ;IAC1C;GACF,SAAS;IACP,MAAM0B,mBAA0BF,OAAOtB;IACvC,MAAM,IAAIyB,MAAM,sBAAsBD,kBAAkB;GAC1D;EACF;EAEA,MAAME,YAAYhB,sBAAsBY,OAAOxB,QAAQ;EACvDuB,IAAIJ,YAAYK,OAAOxB,YAAY4B;EACnCL,IAAIH,WAAWQ,aAAa;GAC1B7B,IAAIyB,OAAOxB;GACXA,UAAUwB,OAAOxB;GACjBC,YAAYuB,OAAOvB;GACnBC,QAAQsB,OAAOtB;GACfC,OAAOqB,OAAOrB;GACdI,eAAeiB,OAAOjB;GACtBH,QAAQoB,OAAOpB;GACfC,gBAAgBC,QAAQuB,QAAQ;IAC9B7B,UAAUwB,OAAOxB;IACjBC,YAAYuB,OAAOvB;GACrB,CAAC;EACH;CACF;CACA,OAAOsB;AACT;AAaA,MAAaa,iBACXC,OACAC,uBACG;CACH,MAAMC,MAAMF,MAAMlB,YAAYmB;CAC9B,IAAIC,QAAQxB,KAAAA,GAAW,OAAOA,KAAAA;CAC9B,OAAOsB,MAAMjB,WAAWmB;AAC1B;AAEA,MAAaC,uBACXH,OACAC,oBACAG,cACG;CACH,MAAMC,OAAON,cAAcC,OAAOC,kBAAkB;CACpD,IAAI,CAACI,MAAM,OAAOL;CAElB,MAAM,EAAEtC,IAAIC,UAAUE,QAAQyC,eAAeD;CAC7C,IAAIC,eAAeF,WAAW,OAAOJ;CAErC,MAAMO,WAAW,EAAE,GAAGP,MAAM;CAG5B,QAAQM,YAAR;EACE,KAAK;GACHC,SAASV,cAAcnB,KAAAA;GACvB;EACF,KAAK;GACH6B,SAAS3B,YAAY2B,SAAS3B,UAAU4B,QAAQC,MAAMA,MAAM/C,EAAE;GAC9D;EACF,KAAK;GACH6C,SAAS1B,oBAAoB0B,SAAS1B,kBAAkB2B,QACrDC,MAAMA,MAAM/C,EACf;GACA;EAEF,SAEE,MAAM,IAAI4B,MAAM,sBAAsBD,YAAkB;CAE5D;CAGA,QAAQe,WAAR;EACE,KAAK;GACHG,SAAS3B,YAAY,CAAClB,IAAI,GAAG6C,SAAS3B,SAAS;GAC/C;EAEF,KAAK;GACH2B,SAAS1B,oBAAoB,CAACnB,IAAI,GAAG6C,SAAS1B,iBAAiB;GAC/D;EAEF,KAAK;GACH0B,SAASxB,aAAa2B,OAAOC,YAC3BD,OAAOE,QAAQL,SAASxB,UAAU,CAAC,CAACyB,QAAQ,CAACK,SAASA,QAAQnD,EAAE,CAClE;GACA6C,SAASzB,cAAc4B,OAAOC,YAC5BD,OAAOE,QAAQL,SAASzB,WAAW,CAAC,CAAC0B,QAClC,CAACK,SAASA,QAAQnD,MAAMmD,QAAQlD,QACnC,CACF;GACA;EAEF,SAEE,MAAM,IAAI2B,MAAM,sBAAsBD,WAAkB;CAE5D;CAEA,IAAIe,cAAc,WAChBG,SAASxB,aAAa;EACpB,GAAGwB,SAASxB;GACXrB,KAAK;GACJ,GAAG2C;GACHxC,QAAQuC;EACV;CACF;CAGF,OAAOG;AACT"}
1
+ {"version":3,"file":"remote-thread-state.js","names":["RemoteThreadInitializeResponse","RemoteThreadMetadata","generateId","RemoteThreadData","id","remoteId","externalId","status","title","custom","localOrigin","initializeTask","Promise","lastMessageAt","Date","Record","THREAD_MAPPING_ID","__brand","createThreadMappingId","LOCAL_THREAD_ID_PREFIX","normalizeCursor","c","undefined","ClassifyAccumulator","threadIds","archivedThreadIds","threadIdMap","threadData","classifyThreads","threads","acc","thread","push","_exhaustiveCheck","Error","mappingId","resolve","RemoteThreadState","isLoading","isLoadingMore","cursor","newThreadId","Readonly","createEmptyRemoteThreadState","seedNewThread","state","preserveMidLoadTransitions","priorOrder","Pick","statusAtRequest","ReadonlyMap","regular","Set","archived","rescuedRegular","rescuedArchived","contains","ids","ReadonlySet","data","has","Object","values","before","get","add","length","position","byId","indexOf","byRemoteId","Number","MAX_SAFE_INTEGER","sort","a","b","map","d","statusSnapshot","Map","getThreadData","threadIdOrRemoteId","idx","updateStatusReducer","newStatus","lastStatus","newState","filter","t","fromEntries","entries","key"],"sources":["../../../src/runtimes/remote-thread-list/remote-thread-state.ts"],"sourcesContent":["import type {\n RemoteThreadInitializeResponse,\n RemoteThreadMetadata,\n} from \"./types\";\nimport { generateId } from \"../../utils/id\";\n\nexport type RemoteThreadData =\n | {\n readonly id: string;\n readonly remoteId: undefined;\n readonly externalId: undefined;\n readonly status: \"new\";\n readonly title: undefined;\n readonly custom: undefined;\n readonly localOrigin?: true;\n }\n | {\n readonly id: string;\n readonly initializeTask: Promise<RemoteThreadInitializeResponse>;\n readonly remoteId: undefined;\n readonly externalId: undefined;\n readonly status: \"regular\" | \"archived\";\n readonly title?: string | undefined;\n readonly custom: undefined;\n readonly localOrigin?: true;\n }\n | {\n readonly id: string;\n readonly initializeTask: Promise<RemoteThreadInitializeResponse>;\n readonly remoteId: string;\n readonly externalId: string | undefined;\n readonly status: \"regular\" | \"archived\";\n readonly title?: string | undefined;\n readonly lastMessageAt?: Date | undefined;\n readonly custom?: Record<string, unknown> | undefined;\n readonly localOrigin?: true;\n };\n\nexport type THREAD_MAPPING_ID = string & { __brand: \"THREAD_MAPPING_ID\" };\n\nexport function createThreadMappingId(id: string): THREAD_MAPPING_ID {\n return id as THREAD_MAPPING_ID;\n}\n\nexport const LOCAL_THREAD_ID_PREFIX = \"__LOCALID_\";\n\nexport const normalizeCursor = (c: string | undefined): string | undefined =>\n c || undefined;\n\ntype ClassifyAccumulator = {\n threadIds: string[];\n archivedThreadIds: string[];\n threadIdMap: Record<string, THREAD_MAPPING_ID>;\n threadData: Record<THREAD_MAPPING_ID, RemoteThreadData>;\n};\n\nexport const classifyThreads = (\n threads: readonly RemoteThreadMetadata[],\n acc: ClassifyAccumulator,\n): ClassifyAccumulator => {\n for (const thread of threads) {\n if (acc.threadIdMap[thread.remoteId] !== undefined) continue;\n\n switch (thread.status) {\n case \"regular\":\n acc.threadIds.push(thread.remoteId);\n break;\n case \"archived\":\n acc.archivedThreadIds.push(thread.remoteId);\n break;\n default: {\n const _exhaustiveCheck: never = thread.status;\n throw new Error(`Unsupported state: ${_exhaustiveCheck}`);\n }\n }\n\n const mappingId = createThreadMappingId(thread.remoteId);\n acc.threadIdMap[thread.remoteId] = mappingId;\n acc.threadData[mappingId] = {\n id: thread.remoteId,\n remoteId: thread.remoteId,\n externalId: thread.externalId,\n status: thread.status,\n title: thread.title,\n lastMessageAt: thread.lastMessageAt,\n custom: thread.custom,\n initializeTask: Promise.resolve({\n remoteId: thread.remoteId,\n externalId: thread.externalId,\n }),\n };\n }\n return acc;\n};\n\nexport type RemoteThreadState = {\n readonly isLoading: boolean;\n readonly isLoadingMore: boolean;\n readonly cursor: string | undefined;\n readonly newThreadId: string | undefined;\n readonly threadIds: readonly string[];\n readonly archivedThreadIds: readonly string[];\n readonly threadIdMap: Readonly<Record<string, THREAD_MAPPING_ID>>;\n readonly threadData: Readonly<Record<THREAD_MAPPING_ID, RemoteThreadData>>;\n};\n\nexport const createEmptyRemoteThreadState = (): RemoteThreadState => ({\n isLoading: true,\n isLoadingMore: false,\n cursor: undefined,\n newThreadId: undefined,\n threadIds: [],\n archivedThreadIds: [],\n threadIdMap: {},\n threadData: {},\n});\n\nexport const seedNewThread = (\n state: RemoteThreadState,\n): { id: string; state: RemoteThreadState } => {\n let id: string;\n do {\n id = `${LOCAL_THREAD_ID_PREFIX}${generateId()}`;\n } while (state.threadIdMap[id]);\n const mappingId = createThreadMappingId(id);\n return {\n id,\n state: {\n ...state,\n newThreadId: id,\n threadIdMap: {\n ...state.threadIdMap,\n [id]: mappingId,\n },\n threadData: {\n ...state.threadData,\n [mappingId]: {\n status: \"new\",\n id,\n remoteId: undefined,\n externalId: undefined,\n title: undefined,\n custom: undefined,\n localOrigin: true,\n } satisfies RemoteThreadData,\n },\n },\n };\n};\n\n// A list() response predating a mid-flight local transition (a thread\n// initialized while the request was running) omits that thread, and the\n// completed-optimistic replay cannot re-add it because the merged threadData\n// already carries the final status. Threads whose status moved from new (or\n// nonexistent) at request time to regular/archived are re-inserted at the\n// top, in the order the pre-response lists carried them: updateStatusReducer\n// prepends as transitions happen, so the pre-response lists hold newest\n// first, which threadData insertion order need not match. Threads the server already knew stay governed by the response, so\n// a server-side deletion is not resurrected — and a thread unknown to the\n// snapshot is only rescued when it carries the localOrigin marker stamped at\n// draft creation, so a deep-linked thread the fetch path deliberately\n// appended at the tail is not hoisted, whatever its remote id looks like.\nexport const preserveMidLoadTransitions = (\n state: RemoteThreadState,\n priorOrder: Pick<RemoteThreadState, \"threadIds\" | \"archivedThreadIds\">,\n statusAtRequest: ReadonlyMap<string, RemoteThreadData[\"status\"]>,\n): RemoteThreadState => {\n const regular = new Set(state.threadIds);\n const archived = new Set(state.archivedThreadIds);\n const rescuedRegular: RemoteThreadData[] = [];\n const rescuedArchived: RemoteThreadData[] = [];\n\n const contains = (ids: ReadonlySet<string>, data: RemoteThreadData) =>\n ids.has(data.id) || (data.remoteId !== undefined && ids.has(data.remoteId));\n\n for (const data of Object.values(state.threadData)) {\n const before = statusAtRequest.get(data.id);\n if (before !== undefined && before !== \"new\") continue;\n if (before === undefined && data.localOrigin !== true) continue;\n\n if (data.status === \"regular\" && !contains(regular, data)) {\n rescuedRegular.push(data);\n regular.add(data.id);\n } else if (data.status === \"archived\" && !contains(archived, data)) {\n rescuedArchived.push(data);\n archived.add(data.id);\n }\n }\n\n if (rescuedRegular.length === 0 && rescuedArchived.length === 0) return state;\n\n const position = (ids: readonly string[], data: RemoteThreadData) => {\n const byId = ids.indexOf(data.id);\n if (byId !== -1) return byId;\n const byRemoteId =\n data.remoteId !== undefined ? ids.indexOf(data.remoteId) : -1;\n return byRemoteId !== -1 ? byRemoteId : Number.MAX_SAFE_INTEGER;\n };\n rescuedRegular.sort(\n (a, b) =>\n position(priorOrder.threadIds, a) - position(priorOrder.threadIds, b),\n );\n rescuedArchived.sort(\n (a, b) =>\n position(priorOrder.archivedThreadIds, a) -\n position(priorOrder.archivedThreadIds, b),\n );\n\n return {\n ...state,\n threadIds: [...rescuedRegular.map((d) => d.id), ...state.threadIds],\n archivedThreadIds: [\n ...rescuedArchived.map((d) => d.id),\n ...state.archivedThreadIds,\n ],\n };\n};\n\nexport const statusSnapshot = (\n state: RemoteThreadState,\n): ReadonlyMap<string, RemoteThreadData[\"status\"]> =>\n new Map(Object.values(state.threadData).map((d) => [d.id, d.status]));\n\nexport const getThreadData = (\n state: RemoteThreadState,\n threadIdOrRemoteId: string,\n) => {\n const idx = state.threadIdMap[threadIdOrRemoteId];\n if (idx === undefined) return undefined;\n return state.threadData[idx];\n};\n\nexport const updateStatusReducer = (\n state: RemoteThreadState,\n threadIdOrRemoteId: string,\n newStatus: \"regular\" | \"archived\" | \"deleted\",\n) => {\n const data = getThreadData(state, threadIdOrRemoteId);\n if (!data) return state;\n\n const { id, remoteId, status: lastStatus } = data;\n if (lastStatus === newStatus) return state;\n\n const newState = { ...state };\n\n // lastStatus\n switch (lastStatus) {\n case \"new\":\n newState.newThreadId = undefined;\n break;\n case \"regular\":\n newState.threadIds = newState.threadIds.filter((t) => t !== id);\n break;\n case \"archived\":\n newState.archivedThreadIds = newState.archivedThreadIds.filter(\n (t) => t !== id,\n );\n break;\n\n default: {\n const _exhaustiveCheck: never = lastStatus;\n throw new Error(`Unsupported state: ${_exhaustiveCheck}`);\n }\n }\n\n // newStatus\n switch (newStatus) {\n case \"regular\":\n newState.threadIds = [id, ...newState.threadIds];\n break;\n\n case \"archived\":\n newState.archivedThreadIds = [id, ...newState.archivedThreadIds];\n break;\n\n case \"deleted\":\n newState.threadData = Object.fromEntries(\n Object.entries(newState.threadData).filter(([key]) => key !== id),\n );\n newState.threadIdMap = Object.fromEntries(\n Object.entries(newState.threadIdMap).filter(\n ([key]) => key !== id && key !== remoteId,\n ),\n );\n break;\n\n default: {\n const _exhaustiveCheck: never = newStatus;\n throw new Error(`Unsupported state: ${_exhaustiveCheck}`);\n }\n }\n\n if (newStatus !== \"deleted\") {\n newState.threadData = {\n ...newState.threadData,\n [id]: {\n ...data,\n status: newStatus,\n },\n };\n }\n\n return newState;\n};\n"],"mappings":"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"}
@@ -77,6 +77,9 @@ type RemoteThreadListAdapter = {
77
77
  };
78
78
  type RemoteThreadListOptions = {
79
79
  runtimeHook: () => AssistantRuntime;
80
+ /**
81
+ * The adapter reference should remain stable across renders. Replacing it reloads the list and drops cached threads that are not in the replacement page. In-flight mutations from the previous adapter are cancelled.
82
+ */
80
83
  adapter: RemoteThreadListAdapter;
81
84
  /**
82
85
  * When provided, the runtime starts on this thread instead of creating a
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","names":[],"sources":["../../../src/runtimes/remote-thread-list/types.ts"],"mappings":";;;;;;;KAQK;EAAkC;;KAE3B,sCACN,OAAO,+CACH,OAAO;KAGL;EACV;EACA;;KAGU;WACD;WACA;WACA;WACA;WACA,gBAAgB;WAChB,SAAS;;KAGR;EACV,SAAS;EACT;;KAGU;EACV;;KAGU;EACV,eAAe;EACf,UAAU;EACV,cAAc;;KAGJ;EACV,KAAK,SAAS,8BAA8B,QAAQ;EAEpD,OAAO,kBAAkB,mBAAmB;EAC5C,cACE,kBACA,QAAQ,sCACP;EACH,QAAQ,mBAAmB;EAC3B,UAAU,mBAAmB;EAC7B,OAAO,mBAAmB;EAC1B,WAAW,mBAAmB,QAAQ;EACtC,cACE,kBACA,4BAA4B,kBAC3B,QAAQ;EACX,MAAM,mBAAmB,QAAQ;;;;;;;;;;;;;;;;EAiBjC,oBAAoB;;;;;;;;;;;;;;;EAgBpB,8BAA8B;;KAGpB;EACV,mBAAmB;EACnB,SAAS;;;;;;;;EAST;;;;;;EAOA;;;;;;;;;;;;;EAcA,qBAAqB;;;;;;EAOrB"}
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../../../src/runtimes/remote-thread-list/types.ts"],"mappings":";;;;;;;KAQK;EAAkC;;KAE3B,sCACN,OAAO,+CACH,OAAO;KAGL;EACV;EACA;;KAGU;WACD;WACA;WACA;WACA;WACA,gBAAgB;WAChB,SAAS;;KAGR;EACV,SAAS;EACT;;KAGU;EACV;;KAGU;EACV,eAAe;EACf,UAAU;EACV,cAAc;;KAGJ;EACV,KAAK,SAAS,8BAA8B,QAAQ;EAEpD,OAAO,kBAAkB,mBAAmB;EAC5C,cACE,kBACA,QAAQ,sCACP;EACH,QAAQ,mBAAmB;EAC3B,UAAU,mBAAmB;EAC7B,OAAO,mBAAmB;EAC1B,WAAW,mBAAmB,QAAQ;EACtC,cACE,kBACA,4BAA4B,kBAC3B,QAAQ;EACX,MAAM,mBAAmB,QAAQ;;;;;;;;;;;;;;;;EAiBjC,oBAAoB;;;;;;;;;;;;;;;EAgBpB,8BAA8B;;KAGpB;EACV,mBAAmB;;;;EAKnB,SAAS;;;;;;;;EAST;;;;;;EAOA;;;;;;;;;;;;;EAcA,qBAAqB;;;;;;EAOrB"}
@@ -1 +1 @@
1
- {"version":3,"file":"ToolInvocationTracker.d.ts","names":[],"sources":["../../../src/runtimes/tool-invocations/ToolInvocationTracker.ts"],"mappings":";;;;;;;KAuBY;EACN;;EAEA;EACA;IAAW;IAAe;;;KAGpB;WACD;WACA;WACA;WACA,QAAQ;WACR;WACA,WAAW;WACX,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;cA8EtB;mBACM;mBACA;mBAEA;mBACA;mBAQA;mBACA;UAET;UAEA;UACA;;UAGA;UACA;UAEA;;;;;;;;;UAUA;UACA;EAGN,YAAA,gBAAgB,eAAe,mBAC/B,WAAW,sBAAsB;;;;;;UAa3B;;;;;EAsDD,SAAS,UAAU,sBAAsB;;;;;;EAmEzC;;;;;EAwBA,SAAS;;;;;;;EAkCT,OAAO,oBAAoB;;;;;;;EAoB3B,eAAe,oBAAoB;UAMlC;UA6CA;UAaA;UAmCA;UAYA;UA0BA;UAiCA;UAWA;UAaA;UAOA;UAUA;UAKA;UAgBA;;;;;;;;UA4BA;UAWA;UA0GA;;kBAiFO;OACH,kBAAkB;OAElB;aACD,mBAAmB;;aAEnB;;;;;;aAMA;;OAGC;;;;;IAKV,WAAW,SAAS;;;;;;IAMpB,mBACE,UAAU,oBAAoB"}
1
+ {"version":3,"file":"ToolInvocationTracker.d.ts","names":[],"sources":["../../../src/runtimes/tool-invocations/ToolInvocationTracker.ts"],"mappings":";;;;;;;KAuBY;EACN;;EAEA;EACA;IAAW;IAAe;;;KAGpB;WACD;WACA;WACA;WACA,QAAQ;WACR;WACA,WAAW;WACX,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;cA8EtB;mBACM;mBACA;mBAEA;mBACA;mBAQA;mBACA;UAET;UAEA;UACA;;UAGA;UACA;UAEA;;;;;;;;;UAUA;UACA;EAGN,YAAA,gBAAgB,eAAe,mBAC/B,WAAW,sBAAsB;;;;;;UAa3B;;;;;EAsDD,SAAS,UAAU,sBAAsB;;;;;;EAmEzC;;;;;EAwBA,SAAS;;;;;;;EAkCT,OAAO,oBAAoB;;;;;;;EAoB3B,eAAe,oBAAoB;UAMlC;UA6CA;UAaA;UAmCA;UAYA;UA0BA;UAkCA;UAWA;UAaA;UAOA;UAUA;UAKA;UAgBA;;;;;;;;UA4BA;UAWA;UA0GA;;kBAmFO;OACH,kBAAkB;OAElB;aACD,mBAAmB;;aAEnB;;;;;;aAMA;;OAGC;;;;;IAKV,WAAW,SAAS;;;;;;IAMpB,mBACE,UAAU,oBAAoB"}
@@ -292,6 +292,7 @@ var ToolInvocationTracker = class {
292
292
  const entry = this._entries.get(toolCallId);
293
293
  if (!entry || entry.executionId !== executionId) return;
294
294
  if (entry?.hasResult) return;
295
+ if (entry.skipExecute) return;
295
296
  this._invokeOnResult({
296
297
  type: "add-tool-result",
297
298
  toolCallId,
@@ -457,6 +458,7 @@ var ToolInvocationTracker = class {
457
458
  entry = void 0;
458
459
  }
459
460
  if (!entry) entry = this._startActiveEntry(content.toolCallId, content.toolName, content.result !== void 0);
461
+ if (content.approval !== void 0) entry.skipExecute = true;
460
462
  this._processArgsText(entry, content);
461
463
  if (content.result !== void 0 && !entry.hasResult) {
462
464
  const { controller: activeController } = entry;