@assistant-ui/core 0.1.13 → 0.1.15

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 (330) hide show
  1. package/dist/adapters/attachment.d.ts +6 -0
  2. package/dist/adapters/attachment.d.ts.map +1 -1
  3. package/dist/adapters/attachment.js +54 -9
  4. package/dist/adapters/attachment.js.map +1 -1
  5. package/dist/adapters/{mention.d.ts → directive-formatter.d.ts} +2 -4
  6. package/dist/adapters/directive-formatter.d.ts.map +1 -0
  7. package/dist/adapters/{mention.js → directive-formatter.js} +4 -9
  8. package/dist/adapters/directive-formatter.js.map +1 -0
  9. package/dist/adapters/index.d.ts +1 -3
  10. package/dist/adapters/index.d.ts.map +1 -1
  11. package/dist/adapters/index.js +2 -1
  12. package/dist/adapters/index.js.map +1 -1
  13. package/dist/adapters/speech.d.ts.map +1 -1
  14. package/dist/adapters/speech.js +1 -3
  15. package/dist/adapters/speech.js.map +1 -1
  16. package/dist/adapters/thread-history.d.ts +1 -0
  17. package/dist/adapters/thread-history.d.ts.map +1 -1
  18. package/dist/adapters/trigger.d.ts +1 -18
  19. package/dist/adapters/trigger.d.ts.map +1 -1
  20. package/dist/index.d.ts +2 -4
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +2 -1
  23. package/dist/index.js.map +1 -1
  24. package/dist/model-context/frame/host.d.ts +1 -1
  25. package/dist/model-context/frame/host.d.ts.map +1 -1
  26. package/dist/model-context/frame/host.js +1 -0
  27. package/dist/model-context/frame/host.js.map +1 -1
  28. package/dist/model-context/frame/provider.d.ts +1 -1
  29. package/dist/model-context/frame/provider.d.ts.map +1 -1
  30. package/dist/model-context/frame/provider.js +1 -0
  31. package/dist/model-context/frame/provider.js.map +1 -1
  32. package/dist/model-context/registry.d.ts +2 -2
  33. package/dist/model-context/registry.d.ts.map +1 -1
  34. package/dist/model-context/tool.d.ts +1 -1
  35. package/dist/model-context/tool.d.ts.map +1 -1
  36. package/dist/model-context/types.d.ts +1 -1
  37. package/dist/model-context/types.d.ts.map +1 -1
  38. package/dist/model-context/types.js +0 -3
  39. package/dist/model-context/types.js.map +1 -1
  40. package/dist/react/AssistantRuntimeProvider.d.ts +1 -1
  41. package/dist/react/AssistantRuntimeProvider.d.ts.map +1 -1
  42. package/dist/react/adapters/LocalStorageThreadListAdapter.js.map +1 -1
  43. package/dist/react/client/DataRenderers.d.ts +1 -1
  44. package/dist/react/client/DataRenderers.d.ts.map +1 -1
  45. package/dist/react/client/DataRenderers.js +14 -0
  46. package/dist/react/client/DataRenderers.js.map +1 -1
  47. package/dist/react/client/Tools.d.ts +1 -1
  48. package/dist/react/client/Tools.d.ts.map +1 -1
  49. package/dist/react/client/Tools.js +1 -0
  50. package/dist/react/client/Tools.js.map +1 -1
  51. package/dist/react/model-context/makeAssistantTool.d.ts +1 -1
  52. package/dist/react/model-context/makeAssistantTool.d.ts.map +1 -1
  53. package/dist/react/model-context/makeAssistantToolUI.d.ts +1 -1
  54. package/dist/react/model-context/makeAssistantToolUI.d.ts.map +1 -1
  55. package/dist/react/model-context/useInlineRender.d.ts +2 -2
  56. package/dist/react/model-context/useInlineRender.d.ts.map +1 -1
  57. package/dist/react/model-context/useInlineRender.js +1 -0
  58. package/dist/react/model-context/useInlineRender.js.map +1 -1
  59. package/dist/react/primitives/chainOfThought/ChainOfThoughtParts.d.ts.map +1 -1
  60. package/dist/react/primitives/chainOfThought/ChainOfThoughtParts.js +1 -0
  61. package/dist/react/primitives/chainOfThought/ChainOfThoughtParts.js.map +1 -1
  62. package/dist/react/primitives/composer/ComposerAttachments.d.ts +1 -1
  63. package/dist/react/primitives/composer/ComposerAttachments.d.ts.map +1 -1
  64. package/dist/react/primitives/composer/ComposerAttachments.js +1 -1
  65. package/dist/react/primitives/composer/ComposerAttachments.js.map +1 -1
  66. package/dist/react/primitives/message/MessageAttachments.d.ts +1 -1
  67. package/dist/react/primitives/message/MessageAttachments.d.ts.map +1 -1
  68. package/dist/react/primitives/message/MessageAttachments.js +1 -1
  69. package/dist/react/primitives/message/MessageAttachments.js.map +1 -1
  70. package/dist/react/primitives/message/MessageParts.d.ts +1 -1
  71. package/dist/react/primitives/message/MessageParts.d.ts.map +1 -1
  72. package/dist/react/primitives/message/MessageParts.js +16 -17
  73. package/dist/react/primitives/message/MessageParts.js.map +1 -1
  74. package/dist/react/primitives/part/PartMessages.d.ts +1 -1
  75. package/dist/react/primitives/part/PartMessages.d.ts.map +1 -1
  76. package/dist/react/primitives/thread/ThreadMessages.d.ts +1 -1
  77. package/dist/react/primitives/thread/ThreadMessages.d.ts.map +1 -1
  78. package/dist/react/primitives/thread/ThreadMessages.js +2 -1
  79. package/dist/react/primitives/thread/ThreadMessages.js.map +1 -1
  80. package/dist/react/primitives/threadList/ThreadListItems.d.ts +1 -1
  81. package/dist/react/primitives/threadList/ThreadListItems.d.ts.map +1 -1
  82. package/dist/react/primitives/threadList/ThreadListItems.js +1 -1
  83. package/dist/react/primitives/threadList/ThreadListItems.js.map +1 -1
  84. package/dist/react/providers/AttachmentByIndexProvider.d.ts +1 -1
  85. package/dist/react/providers/AttachmentByIndexProvider.d.ts.map +1 -1
  86. package/dist/react/providers/ChainOfThoughtByIndicesProvider.d.ts +1 -1
  87. package/dist/react/providers/ChainOfThoughtByIndicesProvider.d.ts.map +1 -1
  88. package/dist/react/providers/ChainOfThoughtPartByIndexProvider.d.ts +1 -1
  89. package/dist/react/providers/ChainOfThoughtPartByIndexProvider.d.ts.map +1 -1
  90. package/dist/react/providers/MessageByIndexProvider.d.ts +1 -1
  91. package/dist/react/providers/MessageByIndexProvider.d.ts.map +1 -1
  92. package/dist/react/providers/PartByIndexProvider.d.ts +1 -1
  93. package/dist/react/providers/PartByIndexProvider.d.ts.map +1 -1
  94. package/dist/react/providers/QueueItemByIndexProvider.d.ts +1 -1
  95. package/dist/react/providers/QueueItemByIndexProvider.d.ts.map +1 -1
  96. package/dist/react/providers/SuggestionByIndexProvider.d.ts +1 -1
  97. package/dist/react/providers/SuggestionByIndexProvider.d.ts.map +1 -1
  98. package/dist/react/providers/TextMessagePartProvider.d.ts +1 -1
  99. package/dist/react/providers/TextMessagePartProvider.d.ts.map +1 -1
  100. package/dist/react/providers/ThreadListItemByIndexProvider.d.ts +1 -1
  101. package/dist/react/providers/ThreadListItemByIndexProvider.d.ts.map +1 -1
  102. package/dist/react/providers/ThreadListItemRuntimeProvider.d.ts +1 -1
  103. package/dist/react/providers/ThreadListItemRuntimeProvider.d.ts.map +1 -1
  104. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts +3 -1
  105. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
  106. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +2 -1
  107. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
  108. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +5 -1
  109. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
  110. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +22 -7
  111. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
  112. package/dist/react/runtimes/RuntimeAdapterProvider.d.ts +1 -1
  113. package/dist/react/runtimes/RuntimeAdapterProvider.d.ts.map +1 -1
  114. package/dist/react/runtimes/RuntimeAdapterProvider.js.map +1 -1
  115. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts +2 -2
  116. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
  117. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
  118. package/dist/react/runtimes/cloud/auiV0.d.ts +2 -2
  119. package/dist/react/runtimes/cloud/auiV0.d.ts.map +1 -1
  120. package/dist/react/runtimes/cloud/auiV0.js.map +1 -1
  121. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.d.ts.map +1 -1
  122. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js +4 -1
  123. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js.map +1 -1
  124. package/dist/react/runtimes/useLocalRuntime.d.ts.map +1 -1
  125. package/dist/react/runtimes/useLocalRuntime.js +10 -0
  126. package/dist/react/runtimes/useLocalRuntime.js.map +1 -1
  127. package/dist/react/runtimes/useRemoteThreadListRuntime.d.ts.map +1 -1
  128. package/dist/react/runtimes/useRemoteThreadListRuntime.js +6 -0
  129. package/dist/react/runtimes/useRemoteThreadListRuntime.js.map +1 -1
  130. package/dist/react/runtimes/useToolInvocations.d.ts.map +1 -1
  131. package/dist/react/runtimes/useToolInvocations.js +2 -0
  132. package/dist/react/runtimes/useToolInvocations.js.map +1 -1
  133. package/dist/react/types/MessagePartComponentTypes.d.ts +1 -1
  134. package/dist/react/types/MessagePartComponentTypes.d.ts.map +1 -1
  135. package/dist/react/types/scopes/dataRenderers.d.ts +2 -0
  136. package/dist/react/types/scopes/dataRenderers.d.ts.map +1 -1
  137. package/dist/runtime/api/assistant-runtime.d.ts +1 -1
  138. package/dist/runtime/api/assistant-runtime.d.ts.map +1 -1
  139. package/dist/runtime/api/attachment-runtime.d.ts +0 -1
  140. package/dist/runtime/api/attachment-runtime.d.ts.map +1 -1
  141. package/dist/runtime/api/attachment-runtime.js +0 -3
  142. package/dist/runtime/api/attachment-runtime.js.map +1 -1
  143. package/dist/runtime/api/message-runtime.d.ts +6 -6
  144. package/dist/runtime/api/message-runtime.d.ts.map +1 -1
  145. package/dist/runtime/api/thread-list-runtime.d.ts +4 -2
  146. package/dist/runtime/api/thread-list-runtime.d.ts.map +1 -1
  147. package/dist/runtime/api/thread-list-runtime.js +5 -0
  148. package/dist/runtime/api/thread-list-runtime.js.map +1 -1
  149. package/dist/runtime/api/thread-runtime.d.ts +10 -9
  150. package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
  151. package/dist/runtime/api/thread-runtime.js +4 -3
  152. package/dist/runtime/api/thread-runtime.js.map +1 -1
  153. package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
  154. package/dist/runtime/base/default-edit-composer-runtime-core.d.ts +2 -1
  155. package/dist/runtime/base/default-edit-composer-runtime-core.d.ts.map +1 -1
  156. package/dist/runtime/base/default-edit-composer-runtime-core.js +26 -5
  157. package/dist/runtime/base/default-edit-composer-runtime-core.js.map +1 -1
  158. package/dist/runtime/interfaces/thread-list-runtime-core.d.ts +1 -0
  159. package/dist/runtime/interfaces/thread-list-runtime-core.d.ts.map +1 -1
  160. package/dist/runtime/interfaces/thread-runtime-core.d.ts +7 -0
  161. package/dist/runtime/interfaces/thread-runtime-core.d.ts.map +1 -1
  162. package/dist/runtime/internal.d.ts.map +1 -1
  163. package/dist/runtime/internal.js +1 -4
  164. package/dist/runtime/internal.js.map +1 -1
  165. package/dist/runtime/utils/auto-status.d.ts +1 -1
  166. package/dist/runtime/utils/auto-status.d.ts.map +1 -1
  167. package/dist/runtime/utils/chat-model-adapter.d.ts +1 -1
  168. package/dist/runtime/utils/chat-model-adapter.d.ts.map +1 -1
  169. package/dist/runtime/utils/message-repository.d.ts +6 -0
  170. package/dist/runtime/utils/message-repository.d.ts.map +1 -1
  171. package/dist/runtime/utils/message-repository.js +17 -0
  172. package/dist/runtime/utils/message-repository.js.map +1 -1
  173. package/dist/runtime/utils/thread-message-like.d.ts +1 -1
  174. package/dist/runtime/utils/thread-message-like.d.ts.map +1 -1
  175. package/dist/runtime/utils/thread-message-like.js.map +1 -1
  176. package/dist/runtimes/assistant-transport/utils.d.ts +1 -1
  177. package/dist/runtimes/assistant-transport/utils.d.ts.map +1 -1
  178. package/dist/runtimes/assistant-transport/utils.js +1 -1
  179. package/dist/runtimes/assistant-transport/utils.js.map +1 -1
  180. package/dist/runtimes/external-store/external-store-adapter.d.ts +8 -0
  181. package/dist/runtimes/external-store/external-store-adapter.d.ts.map +1 -1
  182. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts +1 -1
  183. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts.map +1 -1
  184. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js +27 -25
  185. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js.map +1 -1
  186. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts +1 -0
  187. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
  188. package/dist/runtimes/external-store/external-store-thread-runtime-core.js +4 -0
  189. package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
  190. package/dist/runtimes/remote-thread-list/adapter/in-memory.d.ts +2 -2
  191. package/dist/runtimes/remote-thread-list/adapter/in-memory.d.ts.map +1 -1
  192. package/dist/runtimes/remote-thread-list/types.d.ts +1 -1
  193. package/dist/runtimes/remote-thread-list/types.d.ts.map +1 -1
  194. package/dist/store/runtime-clients/attachment-runtime-client.d.ts +2 -2
  195. package/dist/store/runtime-clients/attachment-runtime-client.d.ts.map +1 -1
  196. package/dist/store/runtime-clients/composer-runtime-client.d.ts +1 -1
  197. package/dist/store/runtime-clients/composer-runtime-client.d.ts.map +1 -1
  198. package/dist/store/runtime-clients/message-part-runtime-client.d.ts +2 -2
  199. package/dist/store/runtime-clients/message-part-runtime-client.d.ts.map +1 -1
  200. package/dist/store/runtime-clients/message-runtime-client.d.ts +1 -1
  201. package/dist/store/runtime-clients/message-runtime-client.d.ts.map +1 -1
  202. package/dist/store/runtime-clients/thread-list-item-runtime-client.d.ts +1 -1
  203. package/dist/store/runtime-clients/thread-list-item-runtime-client.d.ts.map +1 -1
  204. package/dist/store/runtime-clients/thread-list-runtime-client.d.ts +2 -2
  205. package/dist/store/runtime-clients/thread-list-runtime-client.d.ts.map +1 -1
  206. package/dist/store/runtime-clients/thread-list-runtime-client.js +1 -0
  207. package/dist/store/runtime-clients/thread-list-runtime-client.js.map +1 -1
  208. package/dist/store/runtime-clients/thread-runtime-client.d.ts +1 -1
  209. package/dist/store/runtime-clients/thread-runtime-client.d.ts.map +1 -1
  210. package/dist/store/scopes/threads.d.ts +1 -0
  211. package/dist/store/scopes/threads.d.ts.map +1 -1
  212. package/dist/subscribable/subscribable.d.ts.map +1 -1
  213. package/dist/subscribable/subscribable.js +1 -15
  214. package/dist/subscribable/subscribable.js.map +1 -1
  215. package/dist/tests/remote-thread-list-test-helpers.d.ts +12 -0
  216. package/dist/tests/remote-thread-list-test-helpers.d.ts.map +1 -0
  217. package/dist/tests/remote-thread-list-test-helpers.js +48 -0
  218. package/dist/tests/remote-thread-list-test-helpers.js.map +1 -0
  219. package/dist/types/directive.d.ts +19 -0
  220. package/dist/types/directive.d.ts.map +1 -0
  221. package/dist/types/directive.js +2 -0
  222. package/dist/types/directive.js.map +1 -0
  223. package/dist/types/index.d.ts +1 -1
  224. package/dist/types/index.d.ts.map +1 -1
  225. package/dist/types/message.d.ts.map +1 -1
  226. package/dist/types/trigger.d.ts +2 -2
  227. package/dist/types/trigger.d.ts.map +1 -1
  228. package/dist/utils/json/is-json.d.ts +1 -1
  229. package/dist/utils/json/is-json.d.ts.map +1 -1
  230. package/package.json +12 -12
  231. package/src/adapters/attachment.ts +68 -16
  232. package/src/adapters/{mention.ts → directive-formatter.ts} +8 -20
  233. package/src/adapters/index.ts +2 -9
  234. package/src/adapters/speech.ts +1 -16
  235. package/src/adapters/thread-history.ts +1 -8
  236. package/src/adapters/trigger.ts +1 -37
  237. package/src/index.ts +3 -24
  238. package/src/model-context/frame/host.ts +6 -5
  239. package/src/model-context/frame/provider.ts +6 -5
  240. package/src/model-context/registry.ts +6 -6
  241. package/src/model-context/tool.ts +1 -1
  242. package/src/model-context/types.ts +1 -17
  243. package/src/react/AssistantRuntimeProvider.tsx +1 -1
  244. package/src/react/adapters/LocalStorageThreadListAdapter.tsx +1 -1
  245. package/src/react/client/DataRenderers.ts +19 -3
  246. package/src/react/client/Tools.ts +4 -3
  247. package/src/react/model-context/makeAssistantTool.ts +1 -1
  248. package/src/react/model-context/makeAssistantToolUI.ts +1 -1
  249. package/src/react/model-context/useInlineRender.ts +3 -2
  250. package/src/react/primitives/chainOfThought/ChainOfThoughtParts.tsx +1 -0
  251. package/src/react/primitives/composer/ComposerAttachments.tsx +7 -1
  252. package/src/react/primitives/message/MessageAttachments.tsx +7 -1
  253. package/src/react/primitives/message/MessageParts.tsx +27 -17
  254. package/src/react/primitives/part/PartMessages.tsx +1 -1
  255. package/src/react/primitives/thread/ThreadMessages.tsx +3 -2
  256. package/src/react/primitives/threadList/ThreadListItems.tsx +7 -1
  257. package/src/react/providers/AttachmentByIndexProvider.tsx +1 -1
  258. package/src/react/providers/ChainOfThoughtByIndicesProvider.tsx +1 -1
  259. package/src/react/providers/ChainOfThoughtPartByIndexProvider.tsx +1 -1
  260. package/src/react/providers/MessageByIndexProvider.tsx +1 -1
  261. package/src/react/providers/PartByIndexProvider.tsx +1 -1
  262. package/src/react/providers/QueueItemByIndexProvider.tsx +1 -1
  263. package/src/react/providers/SuggestionByIndexProvider.tsx +1 -1
  264. package/src/react/providers/TextMessagePartProvider.tsx +1 -1
  265. package/src/react/providers/ThreadListItemByIndexProvider.tsx +1 -1
  266. package/src/react/providers/ThreadListItemRuntimeProvider.tsx +1 -1
  267. package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +7 -8
  268. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +28 -8
  269. package/src/react/runtimes/RuntimeAdapterProvider.tsx +1 -1
  270. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +3 -3
  271. package/src/react/runtimes/cloud/auiV0.ts +5 -2
  272. package/src/react/runtimes/cloud/useCloudThreadListAdapter.tsx +6 -3
  273. package/src/react/runtimes/useLocalRuntime.ts +10 -0
  274. package/src/react/runtimes/useRemoteThreadListRuntime.ts +6 -0
  275. package/src/react/runtimes/useToolInvocations.ts +2 -0
  276. package/src/react/types/MessagePartComponentTypes.ts +1 -1
  277. package/src/react/types/scopes/dataRenderers.ts +2 -0
  278. package/src/runtime/api/assistant-runtime.ts +1 -1
  279. package/src/runtime/api/attachment-runtime.ts +0 -4
  280. package/src/runtime/api/message-runtime.ts +8 -8
  281. package/src/runtime/api/thread-list-runtime.ts +13 -5
  282. package/src/runtime/api/thread-runtime.ts +13 -12
  283. package/src/runtime/base/base-thread-runtime-core.ts +1 -1
  284. package/src/runtime/base/default-edit-composer-runtime-core.ts +35 -5
  285. package/src/runtime/interfaces/thread-list-runtime-core.ts +1 -0
  286. package/src/runtime/interfaces/thread-runtime-core.ts +7 -0
  287. package/src/runtime/internal.ts +1 -4
  288. package/src/runtime/utils/auto-status.ts +1 -1
  289. package/src/runtime/utils/chat-model-adapter.ts +1 -1
  290. package/src/runtime/utils/message-repository.ts +26 -0
  291. package/src/runtime/utils/thread-message-like.ts +4 -1
  292. package/src/runtimes/assistant-transport/utils.ts +5 -1
  293. package/src/runtimes/external-store/external-store-adapter.ts +8 -0
  294. package/src/runtimes/external-store/external-store-thread-list-runtime-core.ts +35 -29
  295. package/src/runtimes/external-store/external-store-thread-runtime-core.ts +4 -0
  296. package/src/runtimes/remote-thread-list/adapter/in-memory.ts +2 -2
  297. package/src/runtimes/remote-thread-list/types.ts +1 -1
  298. package/src/store/runtime-clients/attachment-runtime-client.ts +2 -2
  299. package/src/store/runtime-clients/composer-runtime-client.ts +2 -2
  300. package/src/store/runtime-clients/message-part-runtime-client.ts +2 -2
  301. package/src/store/runtime-clients/message-runtime-client.ts +2 -2
  302. package/src/store/runtime-clients/thread-list-item-runtime-client.ts +1 -1
  303. package/src/store/runtime-clients/thread-list-runtime-client.ts +4 -3
  304. package/src/store/runtime-clients/thread-runtime-client.ts +3 -3
  305. package/src/store/scopes/threads.ts +1 -0
  306. package/src/subscribable/subscribable.ts +1 -24
  307. package/src/tests/MessageRepository.test.ts +141 -0
  308. package/src/tests/OptimisticState-list-race.test.ts +5 -9
  309. package/src/tests/RemoteThreadListThreadListRuntimeCore-reload.test.ts +209 -0
  310. package/src/tests/RemoteThreadListThreadListRuntimeCore-switchToThread-dedupe.test.ts +139 -0
  311. package/src/tests/attachment.test.ts +180 -0
  312. package/src/tests/default-edit-composer-runtime-core.test.ts +312 -0
  313. package/src/tests/{mention-formatter.test.ts → directive-formatter.test.ts} +26 -1
  314. package/src/tests/external-store-thread-list-runtime-core.test.ts +212 -0
  315. package/src/tests/get-thread-state-isRunning.test.ts +93 -0
  316. package/src/tests/remote-thread-list-isLoading.test.ts +6 -10
  317. package/src/tests/remote-thread-list-test-helpers.ts +70 -0
  318. package/src/tests/thread-list-runtime-getLoadThreadsPromise.test.ts +17 -1
  319. package/src/types/directive.ts +19 -0
  320. package/src/types/index.ts +1 -3
  321. package/src/types/message.ts +0 -12
  322. package/src/types/trigger.ts +2 -10
  323. package/src/utils/json/is-json.ts +1 -1
  324. package/dist/adapters/mention.d.ts.map +0 -1
  325. package/dist/adapters/mention.js.map +0 -1
  326. package/dist/types/mention.d.ts +0 -21
  327. package/dist/types/mention.d.ts.map +0 -1
  328. package/dist/types/mention.js +0 -2
  329. package/dist/types/mention.js.map +0 -1
  330. package/src/types/mention.ts +0 -39
@@ -27,6 +27,7 @@ export type ThreadsMethods = {
27
27
  ): ThreadListItemMethods;
28
28
  thread(selector: "main"): ThreadMethods;
29
29
  getLoadThreadsPromise(): Promise<void>;
30
+ reload(): Promise<void>;
30
31
  __internal_getAssistantRuntime?(): AssistantRuntime;
31
32
  };
32
33
 
@@ -1,16 +1,8 @@
1
1
  import type { Unsubscribe } from "../types/unsubscribe";
2
2
 
3
- // =============================================================================
4
- // Sentinel
5
- // =============================================================================
6
-
7
3
  export const SKIP_UPDATE = Symbol("skip-update");
8
4
  export type SKIP_UPDATE = typeof SKIP_UPDATE;
9
5
 
10
- // =============================================================================
11
- // Types
12
- // =============================================================================
13
-
14
6
  export type Subscribable = {
15
7
  subscribe: (callback: () => void) => Unsubscribe;
16
8
  };
@@ -36,10 +28,6 @@ export type EventSubscribable<TEvent extends string> = {
36
28
  >;
37
29
  };
38
30
 
39
- // =============================================================================
40
- // Utilities
41
- // =============================================================================
42
-
43
31
  function shallowEqual<T extends object>(
44
32
  objA: T | undefined,
45
33
  objB: T | undefined,
@@ -57,10 +45,6 @@ function shallowEqual<T extends object>(
57
45
  return true;
58
46
  }
59
47
 
60
- // =============================================================================
61
- // Base Subscribable (simple pub-sub)
62
- // =============================================================================
63
-
64
48
  export class BaseSubscribable {
65
49
  private _subscribers = new Set<() => void>();
66
50
 
@@ -101,10 +85,7 @@ export class BaseSubscribable {
101
85
  }
102
86
  }
103
87
 
104
- // =============================================================================
105
- // Base Subject (lazy connect/disconnect)
106
- // =============================================================================
107
-
88
+ // lazy connect/disconnect: only opens upstream subscription while it has subscribers
108
89
  export abstract class BaseSubject {
109
90
  private _subscriptions = new Set<() => void>();
110
91
  private _connection: Unsubscribe | undefined;
@@ -140,10 +121,6 @@ export abstract class BaseSubject {
140
121
  }
141
122
  }
142
123
 
143
- // =============================================================================
144
- // Subject Implementations
145
- // =============================================================================
146
-
147
124
  export class ShallowMemoizeSubject<TState extends object, TPath>
148
125
  extends BaseSubject
149
126
  implements SubscribableWithState<TState, TPath>
@@ -457,6 +457,147 @@ describe("MessageRepository", () => {
457
457
  });
458
458
  });
459
459
 
460
+ describe("ExportedMessageRepository.fromBranchableArray", () => {
461
+ it("should create a branching tree structure", () => {
462
+ const items = [
463
+ {
464
+ message: {
465
+ id: "user-1",
466
+ role: "user" as const,
467
+ content: [{ type: "text" as const, text: "Hello" }],
468
+ },
469
+ parentId: null,
470
+ },
471
+ {
472
+ message: {
473
+ id: "assistant-1",
474
+ role: "assistant" as const,
475
+ content: [{ type: "text" as const, text: "Hi there" }],
476
+ },
477
+ parentId: "user-1",
478
+ },
479
+ {
480
+ message: {
481
+ id: "assistant-2",
482
+ role: "assistant" as const,
483
+ content: [{ type: "text" as const, text: "Hey!" }],
484
+ },
485
+ parentId: "user-1",
486
+ },
487
+ ];
488
+
489
+ const result = ExportedMessageRepository.fromBranchableArray(items);
490
+
491
+ expect(result.messages).toHaveLength(3);
492
+ expect(result.messages[0]!.parentId).toBeNull();
493
+ expect(result.messages[0]!.message.id).toBe("user-1");
494
+ expect(result.messages[1]!.parentId).toBe("user-1");
495
+ expect(result.messages[1]!.message.id).toBe("assistant-1");
496
+ expect(result.messages[2]!.parentId).toBe("user-1");
497
+ expect(result.messages[2]!.message.id).toBe("assistant-2");
498
+ });
499
+
500
+ it("should support headId option", () => {
501
+ const items = [
502
+ {
503
+ message: {
504
+ id: "msg-1",
505
+ role: "user" as const,
506
+ content: [{ type: "text" as const, text: "Hello" }],
507
+ },
508
+ parentId: null,
509
+ },
510
+ {
511
+ message: {
512
+ id: "msg-2a",
513
+ role: "assistant" as const,
514
+ content: [{ type: "text" as const, text: "Branch A" }],
515
+ },
516
+ parentId: "msg-1",
517
+ },
518
+ {
519
+ message: {
520
+ id: "msg-2b",
521
+ role: "assistant" as const,
522
+ content: [{ type: "text" as const, text: "Branch B" }],
523
+ },
524
+ parentId: "msg-1",
525
+ },
526
+ ];
527
+
528
+ const result = ExportedMessageRepository.fromBranchableArray(items, {
529
+ headId: "msg-2b",
530
+ });
531
+
532
+ expect(result.headId).toBe("msg-2b");
533
+ });
534
+
535
+ it("should throw if a message has no id", () => {
536
+ const items = [
537
+ {
538
+ message: {
539
+ role: "user" as const,
540
+ content: [{ type: "text" as const, text: "Hello" }],
541
+ },
542
+ parentId: null,
543
+ },
544
+ ];
545
+
546
+ expect(() =>
547
+ ExportedMessageRepository.fromBranchableArray(items),
548
+ ).toThrow(/Each message must have an 'id' field set/);
549
+ });
550
+
551
+ it("should handle empty arrays", () => {
552
+ const result = ExportedMessageRepository.fromBranchableArray([]);
553
+ expect(result.messages).toHaveLength(0);
554
+ });
555
+
556
+ it("should work with MessageRepository.import for branch switching", () => {
557
+ const items = [
558
+ {
559
+ message: {
560
+ id: "user-1",
561
+ role: "user" as const,
562
+ content: [{ type: "text" as const, text: "Hello" }],
563
+ },
564
+ parentId: null,
565
+ },
566
+ {
567
+ message: {
568
+ id: "assistant-a",
569
+ role: "assistant" as const,
570
+ content: [{ type: "text" as const, text: "Response A" }],
571
+ },
572
+ parentId: "user-1",
573
+ },
574
+ {
575
+ message: {
576
+ id: "assistant-b",
577
+ role: "assistant" as const,
578
+ content: [{ type: "text" as const, text: "Response B" }],
579
+ },
580
+ parentId: "user-1",
581
+ },
582
+ ];
583
+
584
+ const repo = ExportedMessageRepository.fromBranchableArray(items, {
585
+ headId: "assistant-a",
586
+ });
587
+
588
+ repository.import(repo);
589
+
590
+ // Should show branch A
591
+ let messages = repository.getMessages();
592
+ expect(messages.map((m) => m.id)).toEqual(["user-1", "assistant-a"]);
593
+
594
+ // Switch to branch B
595
+ repository.switchToBranch("assistant-b");
596
+ messages = repository.getMessages();
597
+ expect(messages.map((m) => m.id)).toEqual(["user-1", "assistant-b"]);
598
+ });
599
+ });
600
+
460
601
  describe("Complex scenarios", () => {
461
602
  it("should maintain tree structure after deletions", () => {
462
603
  const root = createTestMessage({ id: "root-id" });
@@ -7,6 +7,7 @@ import {
7
7
  createThreadMappingId,
8
8
  updateStatusReducer,
9
9
  } from "../runtimes/remote-thread-list/remote-thread-state";
10
+ import { deferred } from "./remote-thread-list-test-helpers";
10
11
 
11
12
  /**
12
13
  * Reproduces the race condition where a stale list() response
@@ -75,15 +76,6 @@ const applyListResult = (
75
76
  };
76
77
  };
77
78
 
78
- /** Creates a deferred promise for controlling resolution order. */
79
- function deferred<T>() {
80
- let resolve!: (v: T) => void;
81
- const promise = new Promise<T>((r) => {
82
- resolve = r;
83
- });
84
- return { promise, resolve };
85
- }
86
-
87
79
  describe("list + delete race condition", () => {
88
80
  it("stale list() does not re-add a thread deleted while list was in flight", async () => {
89
81
  const state = new OptimisticState<RemoteThreadState>(EMPTY_STATE);
@@ -95,6 +87,7 @@ describe("list + delete race condition", () => {
95
87
  const listPromise = state.optimisticUpdate({
96
88
  execute: () => listDeferred.promise,
97
89
  loading: (s) => ({ ...s, isLoading: true }),
90
+ // biome-ignore lint/suspicious/noThenProperty: OptimisticState reducer pattern
98
91
  then: applyListResult,
99
92
  });
100
93
 
@@ -152,6 +145,7 @@ describe("list + delete race condition", () => {
152
145
  const listPromise = state.optimisticUpdate({
153
146
  execute: () => listDeferred.promise,
154
147
  loading: (s) => ({ ...s, isLoading: true }),
148
+ // biome-ignore lint/suspicious/noThenProperty: OptimisticState reducer pattern
155
149
  then: applyListResult,
156
150
  });
157
151
 
@@ -189,6 +183,7 @@ describe("list + delete race condition", () => {
189
183
  const listPromise = state.optimisticUpdate({
190
184
  execute: () => listDeferred.promise,
191
185
  loading: (s) => ({ ...s, isLoading: true }),
186
+ // biome-ignore lint/suspicious/noThenProperty: OptimisticState reducer pattern
192
187
  then: applyListResult,
193
188
  });
194
189
 
@@ -226,6 +221,7 @@ describe("list + delete race condition", () => {
226
221
  const listPromise = state.optimisticUpdate({
227
222
  execute: () => listDeferred.promise,
228
223
  loading: (s) => ({ ...s, isLoading: true }),
224
+ // biome-ignore lint/suspicious/noThenProperty: OptimisticState reducer pattern
229
225
  then: applyListResult,
230
226
  });
231
227
 
@@ -0,0 +1,209 @@
1
+ import { describe, it, expect, vi } from "vitest";
2
+ import type { RemoteThreadListResponse } from "../runtimes/remote-thread-list/types";
3
+ import {
4
+ createCore,
5
+ deferred,
6
+ makeAdapter,
7
+ } from "./remote-thread-list-test-helpers";
8
+
9
+ describe("RemoteThreadListThreadListRuntimeCore.reload", () => {
10
+ it("refetches list() after a successful empty load", async () => {
11
+ const listFn = vi
12
+ .fn<() => Promise<RemoteThreadListResponse>>()
13
+ .mockResolvedValueOnce({ threads: [] })
14
+ .mockResolvedValueOnce({
15
+ threads: [
16
+ {
17
+ status: "regular",
18
+ remoteId: "t-1",
19
+ externalId: "t-1",
20
+ title: "After auth",
21
+ },
22
+ ],
23
+ });
24
+ const adapter = makeAdapter({ list: listFn });
25
+ const core = createCore(adapter);
26
+
27
+ await core.getLoadThreadsPromise();
28
+ expect(listFn).toHaveBeenCalledTimes(1);
29
+ expect(core.threadIds).toEqual([]);
30
+
31
+ await core.reload();
32
+ expect(listFn).toHaveBeenCalledTimes(2);
33
+ expect(core.threadIds).toEqual(["t-1"]);
34
+ });
35
+
36
+ it("returns the same cached promise from getLoadThreadsPromise when reload is not called", async () => {
37
+ const adapter = makeAdapter({
38
+ list: vi.fn(async () => ({ threads: [] })),
39
+ });
40
+ const core = createCore(adapter);
41
+
42
+ const p1 = core.getLoadThreadsPromise();
43
+ const p2 = core.getLoadThreadsPromise();
44
+ await p1;
45
+ await p2;
46
+
47
+ expect(adapter.list).toHaveBeenCalledTimes(1);
48
+ });
49
+
50
+ it("drops stale responses when a reload is triggered mid-flight", async () => {
51
+ const first = deferred<RemoteThreadListResponse>();
52
+ const second = deferred<RemoteThreadListResponse>();
53
+ const listFn = vi
54
+ .fn<() => Promise<RemoteThreadListResponse>>()
55
+ .mockReturnValueOnce(first.promise)
56
+ .mockReturnValueOnce(second.promise);
57
+
58
+ const adapter = makeAdapter({ list: listFn });
59
+ const core = createCore(adapter);
60
+
61
+ core.getLoadThreadsPromise();
62
+ const reloaded = core.reload();
63
+
64
+ second.resolve({
65
+ threads: [
66
+ {
67
+ status: "regular",
68
+ remoteId: "fresh",
69
+ externalId: "fresh",
70
+ title: "Fresh",
71
+ },
72
+ ],
73
+ });
74
+ await reloaded;
75
+
76
+ first.resolve({
77
+ threads: [
78
+ {
79
+ status: "regular",
80
+ remoteId: "stale",
81
+ externalId: "stale",
82
+ title: "Stale",
83
+ },
84
+ ],
85
+ });
86
+ // flush microtasks so the stale then() reducer runs and its generation
87
+ // guard has a chance to discard the result
88
+ await Promise.resolve();
89
+
90
+ expect(core.threadIds).toEqual(["fresh"]);
91
+ expect(core.threadIds).not.toContain("stale");
92
+ });
93
+
94
+ it("recovers after a failed initial load", async () => {
95
+ const listFn = vi
96
+ .fn<() => Promise<RemoteThreadListResponse>>()
97
+ .mockRejectedValueOnce(new Error("401"))
98
+ .mockResolvedValueOnce({
99
+ threads: [
100
+ {
101
+ status: "regular",
102
+ remoteId: "t-1",
103
+ externalId: "t-1",
104
+ title: "Authed",
105
+ },
106
+ ],
107
+ });
108
+ const adapter = makeAdapter({ list: listFn });
109
+ const core = createCore(adapter);
110
+
111
+ await core.getLoadThreadsPromise();
112
+ expect(core.threadIds).toEqual([]);
113
+ expect(core.isLoading).toBe(false);
114
+
115
+ await core.reload();
116
+ expect(listFn).toHaveBeenCalledTimes(2);
117
+ expect(core.threadIds).toEqual(["t-1"]);
118
+ });
119
+
120
+ it("does not clear the active reload's promise when a stale load rejects", async () => {
121
+ const first = deferred<RemoteThreadListResponse>();
122
+ const second = deferred<RemoteThreadListResponse>();
123
+ const listFn = vi
124
+ .fn<() => Promise<RemoteThreadListResponse>>()
125
+ .mockReturnValueOnce(first.promise)
126
+ .mockReturnValueOnce(second.promise);
127
+
128
+ const adapter = makeAdapter({ list: listFn });
129
+ const core = createCore(adapter);
130
+
131
+ core.getLoadThreadsPromise();
132
+ const reloaded = core.reload();
133
+
134
+ first.reject(new Error("stale 401"));
135
+ await Promise.resolve();
136
+
137
+ second.resolve({
138
+ threads: [
139
+ {
140
+ status: "regular",
141
+ remoteId: "fresh",
142
+ externalId: "fresh",
143
+ title: "Fresh",
144
+ },
145
+ ],
146
+ });
147
+
148
+ await reloaded;
149
+ expect(core.threadIds).toEqual(["fresh"]);
150
+ expect(core.isLoading).toBe(false);
151
+ });
152
+
153
+ it("only the last of several overlapping reloads wins", async () => {
154
+ const deferreds = [
155
+ deferred<RemoteThreadListResponse>(),
156
+ deferred<RemoteThreadListResponse>(),
157
+ deferred<RemoteThreadListResponse>(),
158
+ ];
159
+ const listFn = vi
160
+ .fn<() => Promise<RemoteThreadListResponse>>()
161
+ .mockImplementationOnce(() => deferreds[0]!.promise)
162
+ .mockImplementationOnce(() => deferreds[1]!.promise)
163
+ .mockImplementationOnce(() => deferreds[2]!.promise);
164
+
165
+ const adapter = makeAdapter({ list: listFn });
166
+ const core = createCore(adapter);
167
+
168
+ const r1 = core.getLoadThreadsPromise();
169
+ const r2 = core.reload();
170
+ const r3 = core.reload();
171
+
172
+ deferreds[2]!.resolve({
173
+ threads: [
174
+ {
175
+ status: "regular",
176
+ remoteId: "c",
177
+ externalId: "c",
178
+ title: "c",
179
+ },
180
+ ],
181
+ });
182
+ await r3;
183
+
184
+ deferreds[0]!.resolve({
185
+ threads: [
186
+ {
187
+ status: "regular",
188
+ remoteId: "a",
189
+ externalId: "a",
190
+ title: "a",
191
+ },
192
+ ],
193
+ });
194
+ deferreds[1]!.resolve({
195
+ threads: [
196
+ {
197
+ status: "regular",
198
+ remoteId: "b",
199
+ externalId: "b",
200
+ title: "b",
201
+ },
202
+ ],
203
+ });
204
+ await r1;
205
+ await r2;
206
+
207
+ expect(core.threadIds).toEqual(["c"]);
208
+ });
209
+ });
@@ -0,0 +1,139 @@
1
+ import { describe, it, expect, vi } from "vitest";
2
+ import type {
3
+ RemoteThreadListResponse,
4
+ RemoteThreadMetadata,
5
+ } from "../runtimes/remote-thread-list/types";
6
+ import {
7
+ createCore,
8
+ deferred,
9
+ makeAdapter,
10
+ } from "./remote-thread-list-test-helpers";
11
+
12
+ describe("RemoteThreadListThreadListRuntimeCore.switchToThread dedupe", () => {
13
+ it("does not duplicate threadIds when list() resolves during fetch()", async () => {
14
+ const THREAD_ID = "thread-1";
15
+ const listDeferred = deferred<RemoteThreadListResponse>();
16
+ const fetchDeferred = deferred<RemoteThreadMetadata>();
17
+
18
+ const adapter = makeAdapter({
19
+ list: vi.fn(() => listDeferred.promise),
20
+ fetch: vi.fn(() => fetchDeferred.promise),
21
+ });
22
+
23
+ const core = createCore(adapter, THREAD_ID);
24
+
25
+ const loadPromise = core.getLoadThreadsPromise();
26
+ const switchPromise = core.switchToThread(THREAD_ID);
27
+
28
+ // Commit `list()` before resolving `fetch()` so `switchToThread` reads a
29
+ // state that already contains THREAD_ID.
30
+ listDeferred.resolve({
31
+ threads: [
32
+ {
33
+ status: "regular",
34
+ remoteId: THREAD_ID,
35
+ externalId: THREAD_ID,
36
+ title: "Test",
37
+ },
38
+ ],
39
+ });
40
+ await loadPromise;
41
+
42
+ fetchDeferred.resolve({
43
+ status: "regular",
44
+ remoteId: THREAD_ID,
45
+ externalId: THREAD_ID,
46
+ title: "Test",
47
+ });
48
+ await switchPromise;
49
+
50
+ expect(core.threadIds.filter((id) => id === THREAD_ID)).toEqual([
51
+ THREAD_ID,
52
+ ]);
53
+ });
54
+
55
+ it("does not duplicate archivedThreadIds when list() resolves during fetch()", async () => {
56
+ const THREAD_ID = "archived-1";
57
+ const listDeferred = deferred<RemoteThreadListResponse>();
58
+ const fetchDeferred = deferred<RemoteThreadMetadata>();
59
+
60
+ const adapter = makeAdapter({
61
+ list: vi.fn(() => listDeferred.promise),
62
+ fetch: vi.fn(() => fetchDeferred.promise),
63
+ });
64
+
65
+ const core = createCore(adapter, THREAD_ID);
66
+ // Without this stub, auto-unarchive would filter `archivedThreadIds` via
67
+ // `updateStatusReducer`, hiding any duplicate written by `switchToThread`.
68
+ (
69
+ core as unknown as { unarchive: (id: string) => Promise<void> }
70
+ ).unarchive = async () => {};
71
+
72
+ const loadPromise = core.getLoadThreadsPromise();
73
+ const switchPromise = core.switchToThread(THREAD_ID);
74
+
75
+ listDeferred.resolve({
76
+ threads: [
77
+ {
78
+ status: "archived",
79
+ remoteId: THREAD_ID,
80
+ externalId: THREAD_ID,
81
+ title: "Archived",
82
+ },
83
+ ],
84
+ });
85
+ await loadPromise;
86
+
87
+ fetchDeferred.resolve({
88
+ status: "archived",
89
+ remoteId: THREAD_ID,
90
+ externalId: THREAD_ID,
91
+ title: "Archived",
92
+ });
93
+ await switchPromise;
94
+
95
+ expect(core.archivedThreadIds.filter((id) => id === THREAD_ID)).toEqual([
96
+ THREAD_ID,
97
+ ]);
98
+ });
99
+
100
+ it("moves the id to the correct array when list() and fetch() disagree on status", async () => {
101
+ const THREAD_ID = "flipped-1";
102
+ const listDeferred = deferred<RemoteThreadListResponse>();
103
+ const fetchDeferred = deferred<RemoteThreadMetadata>();
104
+
105
+ const adapter = makeAdapter({
106
+ list: vi.fn(() => listDeferred.promise),
107
+ fetch: vi.fn(() => fetchDeferred.promise),
108
+ });
109
+
110
+ const core = createCore(adapter, THREAD_ID);
111
+
112
+ const loadPromise = core.getLoadThreadsPromise();
113
+ const switchPromise = core.switchToThread(THREAD_ID);
114
+
115
+ // A concurrent unarchive between `list()` and `fetch()` flips the status.
116
+ listDeferred.resolve({
117
+ threads: [
118
+ {
119
+ status: "archived",
120
+ remoteId: THREAD_ID,
121
+ externalId: THREAD_ID,
122
+ title: "Flipped",
123
+ },
124
+ ],
125
+ });
126
+ await loadPromise;
127
+
128
+ fetchDeferred.resolve({
129
+ status: "regular",
130
+ remoteId: THREAD_ID,
131
+ externalId: THREAD_ID,
132
+ title: "Flipped",
133
+ });
134
+ await switchPromise;
135
+
136
+ expect(core.threadIds).toContain(THREAD_ID);
137
+ expect(core.archivedThreadIds).not.toContain(THREAD_ID);
138
+ });
139
+ });