@assistant-ui/core 0.3.18 → 0.3.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (274) hide show
  1. package/dist/adapters/speech.d.ts.map +1 -1
  2. package/dist/adapters/speech.js +13 -3
  3. package/dist/adapters/speech.js.map +1 -1
  4. package/dist/adapters/thread-history.d.ts +4 -0
  5. package/dist/adapters/thread-history.d.ts.map +1 -1
  6. package/dist/index.d.ts +2 -2
  7. package/dist/index.js.map +1 -1
  8. package/dist/internal.d.ts +1 -1
  9. package/dist/model-context/frame/host.d.ts.map +1 -1
  10. package/dist/model-context/frame/host.js +26 -11
  11. package/dist/model-context/frame/host.js.map +1 -1
  12. package/dist/model-context/interactable-composer-metadata.js +11 -9
  13. package/dist/model-context/interactable-composer-metadata.js.map +1 -1
  14. package/dist/react/adapters/LocalStorageThreadListAdapter.d.ts.map +1 -1
  15. package/dist/react/adapters/LocalStorageThreadListAdapter.js +45 -7
  16. package/dist/react/adapters/LocalStorageThreadListAdapter.js.map +1 -1
  17. package/dist/react/client/DataRenderers.d.ts.map +1 -1
  18. package/dist/react/client/DataRenderers.js +20 -15
  19. package/dist/react/client/DataRenderers.js.map +1 -1
  20. package/dist/react/client/Interactables.d.ts.map +1 -1
  21. package/dist/react/client/Interactables.js +11 -5
  22. package/dist/react/client/Interactables.js.map +1 -1
  23. package/dist/react/client/RemoteThreadList.d.ts.map +1 -1
  24. package/dist/react/client/RemoteThreadList.js +3 -2
  25. package/dist/react/client/RemoteThreadList.js.map +1 -1
  26. package/dist/react/client/interactable-model-context.d.ts.map +1 -1
  27. package/dist/react/client/interactable-model-context.js +3 -2
  28. package/dist/react/client/interactable-model-context.js.map +1 -1
  29. package/dist/react/index.d.ts +2 -2
  30. package/dist/react/index.js +2 -2
  31. package/dist/react/interactables-legacy/useAssistantInteractable.d.ts.map +1 -1
  32. package/dist/react/interactables-legacy/useAssistantInteractable.js +3 -0
  33. package/dist/react/interactables-legacy/useAssistantInteractable.js.map +1 -1
  34. package/dist/react/model-context/useInteractable.d.ts.map +1 -1
  35. package/dist/react/model-context/useInteractable.js +4 -1
  36. package/dist/react/model-context/useInteractable.js.map +1 -1
  37. package/dist/react/model-context/useInteractableVersions.js +1 -1
  38. package/dist/react/primitives/message/MessageGroupedParts.d.ts +11 -2
  39. package/dist/react/primitives/message/MessageGroupedParts.d.ts.map +1 -1
  40. package/dist/react/primitives/message/MessageGroupedParts.js +3 -2
  41. package/dist/react/primitives/message/MessageGroupedParts.js.map +1 -1
  42. package/dist/react/primitives/part/PartMessages.d.ts +1 -0
  43. package/dist/react/primitives/part/PartMessages.d.ts.map +1 -1
  44. package/dist/react/primitives/part/PartMessages.js +1 -0
  45. package/dist/react/primitives/part/PartMessages.js.map +1 -1
  46. package/dist/react/primitives/thread/ThreadMessages.d.ts.map +1 -1
  47. package/dist/react/primitives/thread/ThreadMessages.js +6 -5
  48. package/dist/react/primitives/thread/ThreadMessages.js.map +1 -1
  49. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
  50. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +2 -1
  51. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
  52. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts +2 -24
  53. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
  54. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +135 -374
  55. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
  56. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts +1 -0
  57. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts.map +1 -1
  58. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js +22 -2
  59. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js.map +1 -1
  60. package/dist/react/runtimes/cloud/auiV0.d.ts +40 -15
  61. package/dist/react/runtimes/cloud/auiV0.d.ts.map +1 -1
  62. package/dist/react/runtimes/cloud/auiV0.js +62 -15
  63. package/dist/react/runtimes/cloud/auiV0.js.map +1 -1
  64. package/dist/react/runtimes/cloud/createCloudThreadListAdapter.d.ts +2 -1
  65. package/dist/react/runtimes/cloud/createCloudThreadListAdapter.d.ts.map +1 -1
  66. package/dist/react/runtimes/cloud/createCloudThreadListAdapter.js +4 -0
  67. package/dist/react/runtimes/cloud/createCloudThreadListAdapter.js.map +1 -1
  68. package/dist/react/runtimes/cloud/sdkIdentity.d.ts +6 -0
  69. package/dist/react/runtimes/cloud/sdkIdentity.d.ts.map +1 -0
  70. package/dist/react/runtimes/cloud/sdkIdentity.js +9 -0
  71. package/dist/react/runtimes/cloud/sdkIdentity.js.map +1 -0
  72. package/dist/react/runtimes/external-message-converter.d.ts +12 -2
  73. package/dist/react/runtimes/external-message-converter.d.ts.map +1 -1
  74. package/dist/react/runtimes/external-message-converter.js +26 -61
  75. package/dist/react/runtimes/external-message-converter.js.map +1 -1
  76. package/dist/react/runtimes/useRemoteThreadListRuntime.js +1 -1
  77. package/dist/react/runtimes/useRemoteThreadListRuntime.js.map +1 -1
  78. package/dist/react/utils/groupParts.d.ts +6 -1
  79. package/dist/react/utils/groupParts.d.ts.map +1 -1
  80. package/dist/react/utils/groupParts.js +6 -0
  81. package/dist/react/utils/groupParts.js.map +1 -1
  82. package/dist/react/utils/useJSONEqual.d.ts +3 -1
  83. package/dist/react/utils/useJSONEqual.d.ts.map +1 -1
  84. package/dist/react/utils/useJSONEqual.js +6 -1
  85. package/dist/react/utils/useJSONEqual.js.map +1 -1
  86. package/dist/react/utils/useJSONSchemaDependency.d.ts +7 -0
  87. package/dist/react/utils/useJSONSchemaDependency.d.ts.map +1 -0
  88. package/dist/react/utils/useJSONSchemaDependency.js +20 -0
  89. package/dist/react/utils/useJSONSchemaDependency.js.map +1 -0
  90. package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
  91. package/dist/runtime/api/thread-runtime.js +2 -5
  92. package/dist/runtime/api/thread-runtime.js.map +1 -1
  93. package/dist/runtime/base/base-composer-runtime-core.d.ts +1 -0
  94. package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
  95. package/dist/runtime/base/base-composer-runtime-core.js +46 -10
  96. package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
  97. package/dist/runtime/base/base-thread-runtime-core.d.ts +2 -0
  98. package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
  99. package/dist/runtime/base/base-thread-runtime-core.js +155 -64
  100. package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
  101. package/dist/runtime/interfaces/thread-runtime-core.d.ts +6 -0
  102. package/dist/runtime/interfaces/thread-runtime-core.d.ts.map +1 -1
  103. package/dist/runtime/queue/message-queue.d.ts +5 -0
  104. package/dist/runtime/queue/message-queue.d.ts.map +1 -1
  105. package/dist/runtime/queue/message-queue.js +61 -6
  106. package/dist/runtime/queue/message-queue.js.map +1 -1
  107. package/dist/runtime/utils/auto-status.d.ts +6 -2
  108. package/dist/runtime/utils/auto-status.d.ts.map +1 -1
  109. package/dist/runtime/utils/auto-status.js +12 -4
  110. package/dist/runtime/utils/auto-status.js.map +1 -1
  111. package/dist/runtime/utils/external-message-conversion.d.ts +16 -4
  112. package/dist/runtime/utils/external-message-conversion.d.ts.map +1 -1
  113. package/dist/runtime/utils/external-message-conversion.js +48 -12
  114. package/dist/runtime/utils/external-message-conversion.js.map +1 -1
  115. package/dist/runtime/utils/message-repository.js +3 -3
  116. package/dist/runtime/utils/message-repository.js.map +1 -1
  117. package/dist/runtime/utils/thread-message-like.d.ts +2 -1
  118. package/dist/runtime/utils/thread-message-like.d.ts.map +1 -1
  119. package/dist/runtime/utils/thread-message-like.js +4 -2
  120. package/dist/runtime/utils/thread-message-like.js.map +1 -1
  121. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
  122. package/dist/runtimes/external-store/external-store-thread-runtime-core.js +8 -1
  123. package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
  124. package/dist/runtimes/internal.d.ts +1 -1
  125. package/dist/runtimes/local/local-thread-runtime-core.d.ts +1 -1
  126. package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
  127. package/dist/runtimes/local/local-thread-runtime-core.js +4 -1
  128. package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
  129. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts.map +1 -1
  130. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js +2 -1
  131. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js.map +1 -1
  132. package/dist/store/clients/external-thread.d.ts.map +1 -1
  133. package/dist/store/clients/external-thread.js +241 -200
  134. package/dist/store/clients/external-thread.js.map +1 -1
  135. package/dist/store/clients/thread-tasks.d.ts +13 -0
  136. package/dist/store/clients/thread-tasks.d.ts.map +1 -0
  137. package/dist/store/clients/thread-tasks.js +69 -0
  138. package/dist/store/clients/thread-tasks.js.map +1 -0
  139. package/dist/store/index.d.ts +3 -2
  140. package/dist/store/index.js +3 -3
  141. package/dist/store/primitive-predicates.d.ts.map +1 -1
  142. package/dist/store/primitive-predicates.js +4 -4
  143. package/dist/store/primitive-predicates.js.map +1 -1
  144. package/dist/store/runtime-clients/thread-runtime-client.d.ts.map +1 -1
  145. package/dist/store/runtime-clients/thread-runtime-client.js +176 -128
  146. package/dist/store/runtime-clients/thread-runtime-client.js.map +1 -1
  147. package/dist/store/scope-registration.d.ts +2 -0
  148. package/dist/store/scope-registration.d.ts.map +1 -1
  149. package/dist/store/scopes/task.d.ts +36 -0
  150. package/dist/store/scopes/task.d.ts.map +1 -0
  151. package/dist/store/scopes/task.js +0 -0
  152. package/dist/store/scopes/thread.d.ts +20 -0
  153. package/dist/store/scopes/thread.d.ts.map +1 -1
  154. package/dist/subscribable/subscribable.d.ts +2 -1
  155. package/dist/subscribable/subscribable.d.ts.map +1 -1
  156. package/dist/subscribable/subscribable.js +23 -15
  157. package/dist/subscribable/subscribable.js.map +1 -1
  158. package/dist/types/index.d.ts +2 -2
  159. package/dist/types/message.d.ts +8 -1
  160. package/dist/types/message.d.ts.map +1 -1
  161. package/dist/types/message.js.map +1 -1
  162. package/dist/utils/abortable-iterable.d.ts.map +1 -1
  163. package/dist/utils/abortable-iterable.js +30 -14
  164. package/dist/utils/abortable-iterable.js.map +1 -1
  165. package/dist/utils/getGroupStatus.d.ts +18 -2
  166. package/dist/utils/getGroupStatus.d.ts.map +1 -1
  167. package/dist/utils/getGroupStatus.js +32 -7
  168. package/dist/utils/getGroupStatus.js.map +1 -1
  169. package/dist/utils/wire-media.d.ts.map +1 -1
  170. package/dist/utils/wire-media.js +2 -2
  171. package/dist/utils/wire-media.js.map +1 -1
  172. package/package.json +6 -6
  173. package/src/adapters/speech.test.ts +236 -0
  174. package/src/adapters/speech.ts +17 -10
  175. package/src/adapters/thread-history.ts +3 -0
  176. package/src/index.ts +1 -0
  177. package/src/model-context/frame/host.test.ts +113 -1
  178. package/src/model-context/frame/host.ts +39 -12
  179. package/src/model-context/interactable-composer-metadata.test.ts +30 -0
  180. package/src/model-context/interactable-composer-metadata.ts +10 -10
  181. package/src/react/adapters/LocalStorageThreadListAdapter.test.ts +244 -0
  182. package/src/react/adapters/LocalStorageThreadListAdapter.tsx +104 -7
  183. package/src/react/client/DataRenderers.test.tsx +45 -0
  184. package/src/react/client/DataRenderers.ts +13 -9
  185. package/src/react/client/Interactables.test.ts +44 -1
  186. package/src/react/client/Interactables.ts +7 -1
  187. package/src/react/client/RemoteThreadList.test.ts +41 -1
  188. package/src/react/client/RemoteThreadList.ts +15 -2
  189. package/src/react/client/interactable-model-context.test.ts +44 -0
  190. package/src/react/client/interactable-model-context.ts +3 -2
  191. package/src/react/index.ts +5 -1
  192. package/src/react/interactables-legacy/useAssistantInteractable.test.tsx +132 -0
  193. package/src/react/interactables-legacy/useAssistantInteractable.ts +10 -1
  194. package/src/react/model-context/useInteractable.test.tsx +177 -0
  195. package/src/react/model-context/useInteractable.ts +3 -0
  196. package/src/react/primitive-hooks/useActionBarCopy.test.ts +0 -1
  197. package/src/react/primitive-hooks/useSuggestionTrigger.test.ts +0 -1
  198. package/src/react/primitives/message/MessageGroupedParts.test.tsx +96 -0
  199. package/src/react/primitives/message/MessageGroupedParts.tsx +15 -4
  200. package/src/react/primitives/part/PartMessages.test.tsx +104 -1
  201. package/src/react/primitives/part/PartMessages.tsx +1 -0
  202. package/src/react/primitives/thread/ThreadMessages.test.tsx +142 -0
  203. package/src/react/primitives/thread/ThreadMessages.tsx +8 -5
  204. package/src/react/providers/ReadonlyThreadProvider.test.tsx +56 -0
  205. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +7 -1
  206. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.ts +20 -14
  207. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.tsx +221 -1
  208. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +166 -512
  209. package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.test.ts +77 -0
  210. package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.ts +27 -1
  211. package/src/react/runtimes/cloud/auiV0.ts +160 -25
  212. package/src/react/runtimes/cloud/createCloudThreadListAdapter.test.ts +21 -0
  213. package/src/react/runtimes/cloud/createCloudThreadListAdapter.ts +7 -1
  214. package/src/react/runtimes/cloud/sdkIdentity.ts +9 -0
  215. package/src/react/runtimes/cloud/useCloudThreadListAdapter.test.tsx +18 -4
  216. package/src/react/runtimes/external-message-converter.test.ts +136 -1
  217. package/src/react/runtimes/external-message-converter.ts +39 -93
  218. package/src/react/runtimes/useRemoteThreadListRuntime.ts +1 -1
  219. package/src/react/utils/groupParts.ts +12 -1
  220. package/src/react/utils/useJSONEqual.ts +9 -0
  221. package/src/react/utils/useJSONSchemaDependency.ts +22 -0
  222. package/src/runtime/api/thread-runtime.test.ts +58 -0
  223. package/src/runtime/api/thread-runtime.ts +2 -4
  224. package/src/runtime/base/base-composer-runtime-core.ts +69 -16
  225. package/src/runtime/base/base-thread-runtime-core.test.ts +1008 -1
  226. package/src/runtime/base/base-thread-runtime-core.ts +222 -83
  227. package/src/runtime/interfaces/thread-runtime-core.ts +6 -0
  228. package/src/runtime/queue/message-queue.ts +68 -6
  229. package/src/runtime/utils/auto-status.test.ts +112 -1
  230. package/src/runtime/utils/auto-status.ts +31 -5
  231. package/src/runtime/utils/external-message-conversion.test.ts +134 -0
  232. package/src/runtime/utils/external-message-conversion.ts +122 -31
  233. package/src/runtime/utils/message-repository.test.ts +49 -0
  234. package/src/runtime/utils/message-repository.ts +3 -3
  235. package/src/runtime/utils/thread-message-like.test.ts +52 -0
  236. package/src/runtime/utils/thread-message-like.ts +4 -0
  237. package/src/runtimes/external-store/external-store-thread-runtime-core.ts +31 -1
  238. package/src/runtimes/local/local-thread-runtime-core.test.ts +21 -0
  239. package/src/runtimes/local/local-thread-runtime-core.ts +11 -1
  240. package/src/runtimes/tool-invocations/EDGE_CASES.md +2 -6
  241. package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +133 -0
  242. package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +10 -6
  243. package/src/store/clients/external-thread.ts +19 -1
  244. package/src/store/clients/thread-tasks.test.ts +274 -0
  245. package/src/store/clients/thread-tasks.ts +138 -0
  246. package/src/store/index.ts +8 -0
  247. package/src/store/primitive-predicates.test.ts +48 -5
  248. package/src/store/primitive-predicates.ts +7 -2
  249. package/src/store/runtime-clients/thread-runtime-client.ts +31 -1
  250. package/src/store/scope-registration.ts +2 -0
  251. package/src/store/scopes/task.ts +34 -0
  252. package/src/store/scopes/thread.ts +16 -0
  253. package/src/store/thread-tasks.test.tsx +209 -0
  254. package/src/subscribable/subscribable.test.ts +156 -1
  255. package/src/subscribable/subscribable.ts +25 -15
  256. package/src/tests/MessageRepository.test.ts +1 -5
  257. package/src/tests/auiV0Encode.test.ts +300 -0
  258. package/src/tests/base-composer-runtime-core-send.test.ts +51 -0
  259. package/src/tests/base-composer-runtime-core.test.ts +314 -2
  260. package/src/tests/external-store-thread-runtime-core-adapter.test.ts +151 -0
  261. package/src/tests/external-thread-attachments.test.tsx +69 -0
  262. package/src/tests/external-thread-parity.test.tsx +34 -0
  263. package/src/tests/groupParts.test.ts +71 -0
  264. package/src/tests/message-queue.test.ts +253 -0
  265. package/src/tests/remote-thread-list-reactive-threadId.test.ts +51 -0
  266. package/src/tests/useRemoteThreadListRuntime-controlled.test.tsx +43 -0
  267. package/src/types/index.ts +1 -0
  268. package/src/types/message.ts +8 -0
  269. package/src/utils/abortable-iterable.test.ts +115 -0
  270. package/src/utils/abortable-iterable.ts +34 -23
  271. package/src/utils/getGroupStatus.test.ts +70 -4
  272. package/src/utils/getGroupStatus.ts +35 -12
  273. package/src/utils/wire-media.test.ts +10 -0
  274. package/src/utils/wire-media.ts +6 -2
@@ -1,24 +1,28 @@
1
1
  const done = <T>(): IteratorResult<T> => ({ done: true, value: undefined });
2
2
 
3
- /** Resolves at cancellation, so an await on a stream can stop being the only way out. */
4
- const whenAborted = (signal: AbortSignal): Promise<undefined> =>
5
- new Promise((resolve) => {
6
- if (signal.aborted) return resolve(undefined);
7
- signal.addEventListener("abort", () => resolve(undefined), { once: true });
8
- });
9
-
10
3
  export const openAbortableIterable = async <T>(
11
4
  source: AsyncIterable<T> | Promise<AsyncIterable<T>>,
12
5
  signal: AbortSignal,
13
6
  ): Promise<AsyncIterable<T> | undefined> => {
14
7
  const opened = Promise.resolve(source);
15
- const iterable = await Promise.race([opened, whenAborted(signal)]);
16
- if (!iterable) {
17
- void opened
18
- .then((late) => late[Symbol.asyncIterator]().return?.(undefined))
19
- .catch(() => {});
8
+ let release = () => {};
9
+ const aborted = new Promise<undefined>((resolve) => {
10
+ const onAbort = () => resolve(undefined);
11
+ if (signal.aborted) return onAbort();
12
+ signal.addEventListener("abort", onAbort, { once: true });
13
+ release = () => signal.removeEventListener("abort", onAbort);
14
+ });
15
+ try {
16
+ const iterable = await Promise.race([opened, aborted]);
17
+ if (!iterable) {
18
+ void opened
19
+ .then((late) => late[Symbol.asyncIterator]().return?.(undefined))
20
+ .catch(() => {});
21
+ }
22
+ return iterable;
23
+ } finally {
24
+ release();
20
25
  }
21
- return iterable;
22
26
  };
23
27
 
24
28
  /**
@@ -40,7 +44,10 @@ export const abortableIterable = <T>(
40
44
  ): AsyncIterable<T> => ({
41
45
  [Symbol.asyncIterator]: () => {
42
46
  const iterator = source[Symbol.asyncIterator]();
47
+ let finished = false;
43
48
  const finalize = () => {
49
+ if (finished) return;
50
+ finished = true;
44
51
  try {
45
52
  iterator.return?.(undefined)?.catch(() => {});
46
53
  } catch {
@@ -53,7 +60,7 @@ export const abortableIterable = <T>(
53
60
  return this;
54
61
  },
55
62
  next: () => {
56
- if (signal.aborted) {
63
+ if (finished || signal.aborted) {
57
64
  finalize();
58
65
  return Promise.resolve(done<T>());
59
66
  }
@@ -68,17 +75,21 @@ export const abortableIterable = <T>(
68
75
  signal.addEventListener("abort", onAbort, { once: true });
69
76
  const release = () => signal.removeEventListener("abort", onAbort);
70
77
 
71
- iterator.next().then(
72
- (result) => {
78
+ const onError = (error: unknown) => {
79
+ release();
80
+ finalize();
81
+ reject(error);
82
+ };
83
+ try {
84
+ void iterator.next().then((result) => {
73
85
  release();
86
+ if (finished) return resolve(done<T>());
87
+ if (result.done) finished = true;
74
88
  resolve(result);
75
- },
76
- (error: unknown) => {
77
- release();
78
- finalize();
79
- reject(error);
80
- },
81
- );
89
+ }, onError);
90
+ } catch (error) {
91
+ onError(error);
92
+ }
82
93
  });
83
94
  },
84
95
  // The consumer breaks out of the loop to stop a cancelled run, so this is
@@ -1,5 +1,13 @@
1
1
  import { describe, expect, it } from "vitest";
2
- import { getGroupStatus } from "./getGroupStatus";
2
+ import type {
3
+ MessagePartStatus,
4
+ ToolCallMessagePartStatus,
5
+ } from "../types/message";
6
+ import { getGroupStatus, getGroupSummary } from "./getGroupStatus";
7
+
8
+ type Status = MessagePartStatus | ToolCallMessagePartStatus;
9
+
10
+ const part = (status: Status) => ({ status });
3
11
 
4
12
  describe("getGroupStatus", () => {
5
13
  it("reports running when the first member is running and the last is complete", () => {
@@ -10,7 +18,6 @@ describe("getGroupStatus", () => {
10
18
  const status = getGroupStatus(parts);
11
19
 
12
20
  expect(status).toEqual({ type: "running" });
13
- expect(getGroupStatus(parts, [0, 1])).toBe(status);
14
21
  expect(status).toBe(getGroupStatus([{ status: { type: "running" } }]));
15
22
  expect(Object.isFrozen(status)).toBe(true);
16
23
  });
@@ -27,10 +34,69 @@ describe("getGroupStatus", () => {
27
34
 
28
35
  it("matches the positional outcome for statusless adapters", () => {
29
36
  expect(
30
- getGroupStatus(
37
+ getGroupSummary(
31
38
  [{ status: { type: "complete" } }, { status: { type: "running" } }],
32
39
  [0, 1],
33
- ),
40
+ ).status,
34
41
  ).toEqual({ type: "running" });
35
42
  });
36
43
  });
44
+
45
+ describe("getGroupSummary", () => {
46
+ it("tallies every status over the requested indices and reports running when any part runs", () => {
47
+ const summary = getGroupSummary(
48
+ [
49
+ part({ type: "complete" }),
50
+ part({ type: "running" }),
51
+ part({ type: "incomplete", reason: "error" }),
52
+ part({ type: "requires-action", reason: "tool-calls" }),
53
+ ],
54
+ [0, 1, 2, 3],
55
+ );
56
+
57
+ expect(summary.counts).toEqual({
58
+ running: 1,
59
+ complete: 1,
60
+ incomplete: 1,
61
+ requiresAction: 1,
62
+ });
63
+ expect(
64
+ Object.values(summary.counts).reduce((sum, count) => sum + count),
65
+ ).toBe(4);
66
+ expect(summary.status).toEqual({ type: "running" });
67
+ });
68
+
69
+ it("uses the last status when no part runs and treats missing parts as complete", () => {
70
+ const summary = getGroupSummary(
71
+ [
72
+ undefined,
73
+ part({ type: "incomplete", reason: "cancelled" }),
74
+ part({ type: "requires-action", reason: "interrupt" }),
75
+ ],
76
+ [0, 1, 2],
77
+ );
78
+
79
+ expect(summary.counts).toEqual({
80
+ running: 0,
81
+ complete: 1,
82
+ incomplete: 1,
83
+ requiresAction: 1,
84
+ });
85
+ expect(summary.status).toEqual({
86
+ type: "requires-action",
87
+ reason: "interrupt",
88
+ });
89
+ });
90
+
91
+ it("returns complete with zero counts for empty indices", () => {
92
+ expect(getGroupSummary([], [])).toEqual({
93
+ status: { type: "complete" },
94
+ counts: {
95
+ running: 0,
96
+ complete: 0,
97
+ incomplete: 0,
98
+ requiresAction: 0,
99
+ },
100
+ });
101
+ });
102
+ });
@@ -10,22 +10,45 @@ type PartWithStatus = {
10
10
 
11
11
  export const getGroupStatus = (
12
12
  parts: readonly (PartWithStatus | undefined)[],
13
- indices?: readonly number[],
14
13
  ): MessagePartStatus | ToolCallMessagePartStatus => {
15
- if (indices) {
16
- for (const index of indices) {
17
- if (parts[index]?.status.type === "running") return RUNNING_STATUS;
18
- }
19
-
20
- const lastIndex = indices.at(-1);
21
- return lastIndex === undefined
22
- ? COMPLETE_STATUS
23
- : (parts[lastIndex]?.status ?? COMPLETE_STATUS);
24
- }
25
-
26
14
  for (const part of parts) {
27
15
  if (part?.status.type === "running") return RUNNING_STATUS;
28
16
  }
29
17
 
30
18
  return parts.at(-1)?.status ?? COMPLETE_STATUS;
31
19
  };
20
+
21
+ export const getGroupSummary = (
22
+ parts: readonly (PartWithStatus | undefined)[],
23
+ indices: readonly number[],
24
+ ) => {
25
+ const counts = {
26
+ running: 0,
27
+ complete: 0,
28
+ incomplete: 0,
29
+ requiresAction: 0,
30
+ };
31
+ let status: MessagePartStatus | ToolCallMessagePartStatus = COMPLETE_STATUS;
32
+ let isRunning = false;
33
+
34
+ for (const index of indices) {
35
+ status = parts[index]?.status ?? COMPLETE_STATUS;
36
+ switch (status.type) {
37
+ case "running":
38
+ counts.running++;
39
+ isRunning = true;
40
+ break;
41
+ case "complete":
42
+ counts.complete++;
43
+ break;
44
+ case "incomplete":
45
+ counts.incomplete++;
46
+ break;
47
+ case "requires-action":
48
+ counts.requiresAction++;
49
+ break;
50
+ }
51
+ }
52
+
53
+ return { status: isRunning ? RUNNING_STATUS : status, counts };
54
+ };
@@ -20,6 +20,16 @@ describe("resolveImageMediaType", () => {
20
20
  );
21
21
  });
22
22
 
23
+ it("ignores a wildcard image content type", () => {
24
+ expect(resolveImageMediaType(JPEG, "image/*")).toBe("image/jpeg");
25
+ });
26
+
27
+ it("ignores a wildcard data url media type", () => {
28
+ expect(resolveImageMediaType(`data:image/*;base64,${JPEG}`)).toBe(
29
+ "image/jpeg",
30
+ );
31
+ });
32
+
23
33
  it("takes the data url declaration when it is an image type", () => {
24
34
  expect(
25
35
  resolveImageMediaType("data:image/svg+xml,%3Csvg%3E%3C/svg%3E"),
@@ -14,10 +14,14 @@ export function resolveImageMediaType(
14
14
  image: string,
15
15
  contentType?: string | undefined,
16
16
  ): string {
17
- if (contentType?.startsWith("image/")) return contentType;
17
+ if (contentType?.startsWith("image/") && !contentType.includes("*")) {
18
+ return contentType;
19
+ }
18
20
 
19
21
  const declared = dataUrlMediaType(image);
20
- if (declared?.startsWith("image/")) return declared;
22
+ if (declared?.startsWith("image/") && !declared.includes("*")) {
23
+ return declared;
24
+ }
21
25
 
22
26
  // Read through a data URL envelope too, so a generic one such as
23
27
  // `application/octet-stream` does not mask the format. A url of any other