@assistant-ui/react 0.12.14 → 0.12.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 (102) hide show
  1. package/dist/index.d.ts +1 -1
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +1 -1
  4. package/dist/index.js.map +1 -1
  5. package/dist/internal.d.ts +1 -1
  6. package/dist/internal.d.ts.map +1 -1
  7. package/dist/internal.js +1 -1
  8. package/dist/internal.js.map +1 -1
  9. package/dist/legacy-runtime/cloud/AssistantCloudThreadHistoryAdapter.d.ts +1 -4
  10. package/dist/legacy-runtime/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
  11. package/dist/legacy-runtime/cloud/AssistantCloudThreadHistoryAdapter.js +2 -527
  12. package/dist/legacy-runtime/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
  13. package/dist/legacy-runtime/hooks/AttachmentContext.d.ts +96 -96
  14. package/dist/legacy-runtime/runtime-cores/adapters/RuntimeAdapterProvider.d.ts +1 -16
  15. package/dist/legacy-runtime/runtime-cores/adapters/RuntimeAdapterProvider.d.ts.map +1 -1
  16. package/dist/legacy-runtime/runtime-cores/adapters/RuntimeAdapterProvider.js +1 -14
  17. package/dist/legacy-runtime/runtime-cores/adapters/RuntimeAdapterProvider.js.map +1 -1
  18. package/dist/legacy-runtime/runtime-cores/adapters/attachment/CloudFileAttachmentAdapter.d.ts +1 -13
  19. package/dist/legacy-runtime/runtime-cores/adapters/attachment/CloudFileAttachmentAdapter.d.ts.map +1 -1
  20. package/dist/legacy-runtime/runtime-cores/adapters/attachment/CloudFileAttachmentAdapter.js +2 -82
  21. package/dist/legacy-runtime/runtime-cores/adapters/attachment/CloudFileAttachmentAdapter.js.map +1 -1
  22. package/dist/legacy-runtime/runtime-cores/assistant-transport/useToolInvocations.d.ts +1 -23
  23. package/dist/legacy-runtime/runtime-cores/assistant-transport/useToolInvocations.d.ts.map +1 -1
  24. package/dist/legacy-runtime/runtime-cores/assistant-transport/useToolInvocations.js +1 -305
  25. package/dist/legacy-runtime/runtime-cores/assistant-transport/useToolInvocations.js.map +1 -1
  26. package/dist/legacy-runtime/runtime-cores/external-store/createMessageConverter.d.ts +1 -16
  27. package/dist/legacy-runtime/runtime-cores/external-store/createMessageConverter.d.ts.map +1 -1
  28. package/dist/legacy-runtime/runtime-cores/external-store/createMessageConverter.js +1 -48
  29. package/dist/legacy-runtime/runtime-cores/external-store/createMessageConverter.js.map +1 -1
  30. package/dist/legacy-runtime/runtime-cores/external-store/external-message-converter.d.ts +1 -33
  31. package/dist/legacy-runtime/runtime-cores/external-store/external-message-converter.d.ts.map +1 -1
  32. package/dist/legacy-runtime/runtime-cores/external-store/external-message-converter.js +1 -295
  33. package/dist/legacy-runtime/runtime-cores/external-store/external-message-converter.js.map +1 -1
  34. package/dist/legacy-runtime/runtime-cores/external-store/useExternalStoreRuntime.d.ts +1 -3
  35. package/dist/legacy-runtime/runtime-cores/external-store/useExternalStoreRuntime.d.ts.map +1 -1
  36. package/dist/legacy-runtime/runtime-cores/external-store/useExternalStoreRuntime.js +1 -17
  37. package/dist/legacy-runtime/runtime-cores/external-store/useExternalStoreRuntime.js.map +1 -1
  38. package/dist/legacy-runtime/runtime-cores/local/LocalRuntimeOptions.d.ts +1 -1
  39. package/dist/legacy-runtime/runtime-cores/remote-thread-list/RemoteThreadListHookInstanceManager.d.ts +1 -96
  40. package/dist/legacy-runtime/runtime-cores/remote-thread-list/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
  41. package/dist/legacy-runtime/runtime-cores/remote-thread-list/RemoteThreadListHookInstanceManager.js +1 -110
  42. package/dist/legacy-runtime/runtime-cores/remote-thread-list/RemoteThreadListHookInstanceManager.js.map +1 -1
  43. package/dist/legacy-runtime/runtime-cores/remote-thread-list/RemoteThreadListThreadListRuntimeCore.d.ts +1 -112
  44. package/dist/legacy-runtime/runtime-cores/remote-thread-list/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
  45. package/dist/legacy-runtime/runtime-cores/remote-thread-list/RemoteThreadListThreadListRuntimeCore.js +1 -439
  46. package/dist/legacy-runtime/runtime-cores/remote-thread-list/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
  47. package/dist/legacy-runtime/runtime-cores/remote-thread-list/adapter/cloud.d.ts +1 -12
  48. package/dist/legacy-runtime/runtime-cores/remote-thread-list/adapter/cloud.d.ts.map +1 -1
  49. package/dist/legacy-runtime/runtime-cores/remote-thread-list/adapter/cloud.js +1 -102
  50. package/dist/legacy-runtime/runtime-cores/remote-thread-list/adapter/cloud.js.map +1 -1
  51. package/dist/legacy-runtime/runtime-cores/remote-thread-list/useRemoteThreadListRuntime.d.ts +1 -3
  52. package/dist/legacy-runtime/runtime-cores/remote-thread-list/useRemoteThreadListRuntime.d.ts.map +1 -1
  53. package/dist/legacy-runtime/runtime-cores/remote-thread-list/useRemoteThreadListRuntime.js +1 -46
  54. package/dist/legacy-runtime/runtime-cores/remote-thread-list/useRemoteThreadListRuntime.js.map +1 -1
  55. package/dist/primitives/actionBar/ActionBarInteractionContext.d.ts +6 -0
  56. package/dist/primitives/actionBar/ActionBarInteractionContext.d.ts.map +1 -0
  57. package/dist/primitives/actionBar/ActionBarInteractionContext.js +5 -0
  58. package/dist/primitives/actionBar/ActionBarInteractionContext.js.map +1 -0
  59. package/dist/primitives/actionBar/ActionBarRoot.d.ts.map +1 -1
  60. package/dist/primitives/actionBar/ActionBarRoot.js +18 -4
  61. package/dist/primitives/actionBar/ActionBarRoot.js.map +1 -1
  62. package/dist/primitives/actionBar/useActionBarFloatStatus.d.ts +2 -1
  63. package/dist/primitives/actionBar/useActionBarFloatStatus.d.ts.map +1 -1
  64. package/dist/primitives/actionBar/useActionBarFloatStatus.js +3 -2
  65. package/dist/primitives/actionBar/useActionBarFloatStatus.js.map +1 -1
  66. package/dist/primitives/actionBarMore/ActionBarMoreRoot.d.ts.map +1 -1
  67. package/dist/primitives/actionBarMore/ActionBarMoreRoot.js +35 -2
  68. package/dist/primitives/actionBarMore/ActionBarMoreRoot.js.map +1 -1
  69. package/dist/utils/createActionButton.js +1 -1
  70. package/dist/utils/createActionButton.js.map +1 -1
  71. package/dist/utils/json/is-json-equal.d.ts +2 -0
  72. package/dist/utils/json/is-json-equal.d.ts.map +1 -0
  73. package/dist/utils/json/is-json-equal.js +31 -0
  74. package/dist/utils/json/is-json-equal.js.map +1 -0
  75. package/dist/utils/json/is-json.d.ts +1 -0
  76. package/dist/utils/json/is-json.d.ts.map +1 -1
  77. package/dist/utils/json/is-json.js +5 -3
  78. package/dist/utils/json/is-json.js.map +1 -1
  79. package/package.json +8 -8
  80. package/src/index.ts +1 -1
  81. package/src/internal.ts +1 -1
  82. package/src/legacy-runtime/cloud/AssistantCloudThreadHistoryAdapter.ts +2 -784
  83. package/src/legacy-runtime/runtime-cores/adapters/RuntimeAdapterProvider.tsx +5 -43
  84. package/src/legacy-runtime/runtime-cores/adapters/attachment/CloudFileAttachmentAdapter.ts +2 -100
  85. package/src/legacy-runtime/runtime-cores/assistant-transport/useToolInvocations.test.ts +225 -2
  86. package/src/legacy-runtime/runtime-cores/assistant-transport/useToolInvocations.ts +4 -439
  87. package/src/legacy-runtime/runtime-cores/external-store/createMessageConverter.ts +1 -76
  88. package/src/legacy-runtime/runtime-cores/external-store/external-message-converter.ts +4 -465
  89. package/src/legacy-runtime/runtime-cores/external-store/useExternalStoreRuntime.ts +1 -27
  90. package/src/legacy-runtime/runtime-cores/remote-thread-list/RemoteThreadListHookInstanceManager.tsx +1 -178
  91. package/src/legacy-runtime/runtime-cores/remote-thread-list/RemoteThreadListThreadListRuntimeCore.tsx +1 -529
  92. package/src/legacy-runtime/runtime-cores/remote-thread-list/adapter/cloud.tsx +1 -152
  93. package/src/legacy-runtime/runtime-cores/remote-thread-list/useRemoteThreadListRuntime.ts +1 -80
  94. package/src/primitives/actionBar/ActionBarInteractionContext.ts +13 -0
  95. package/src/primitives/actionBar/ActionBarRoot.tsx +38 -8
  96. package/src/primitives/actionBar/useActionBarFloatStatus.ts +4 -1
  97. package/src/primitives/actionBarMore/ActionBarMoreRoot.tsx +52 -2
  98. package/src/tests/BaseComposerRuntimeCore.test.ts +2 -3
  99. package/src/tests/external-message-converter.test.ts +80 -0
  100. package/src/utils/createActionButton.tsx +1 -1
  101. package/src/utils/json/is-json-equal.ts +48 -0
  102. package/src/utils/json/is-json.ts +6 -3
@@ -1,45 +1,7 @@
1
1
  "use client";
2
2
 
3
- import { createContext, FC, ReactNode, useContext } from "react";
4
- import type {
5
- ThreadHistoryAdapter,
6
- AttachmentAdapter,
7
- } from "@assistant-ui/core";
8
- import { ModelContextProvider } from "../../../model-context";
9
-
10
- export type RuntimeAdapters = {
11
- modelContext?: ModelContextProvider;
12
- history?: ThreadHistoryAdapter;
13
- attachments?: AttachmentAdapter;
14
- };
15
-
16
- const RuntimeAdaptersContext = createContext<RuntimeAdapters | null>(null);
17
-
18
- export namespace RuntimeAdapterProvider {
19
- export type Props = {
20
- adapters: RuntimeAdapters;
21
- children: ReactNode;
22
- };
23
- }
24
-
25
- export const RuntimeAdapterProvider: FC<RuntimeAdapterProvider.Props> = ({
26
- adapters,
27
- children,
28
- }) => {
29
- const context = useContext(RuntimeAdaptersContext);
30
- return (
31
- <RuntimeAdaptersContext.Provider
32
- value={{
33
- ...context,
34
- ...adapters,
35
- }}
36
- >
37
- {children}
38
- </RuntimeAdaptersContext.Provider>
39
- );
40
- };
41
-
42
- export const useRuntimeAdapters = () => {
43
- const adapters = useContext(RuntimeAdaptersContext);
44
- return adapters;
45
- };
3
+ export {
4
+ RuntimeAdapterProvider,
5
+ useRuntimeAdapters,
6
+ type RuntimeAdapters,
7
+ } from "@assistant-ui/core/react";
@@ -1,101 +1,3 @@
1
- import type { AssistantCloud } from "assistant-cloud";
2
- import type {
3
- Attachment,
4
- PendingAttachment,
5
- CompleteAttachment,
6
- ThreadUserMessagePart,
7
- AttachmentAdapter,
8
- } from "@assistant-ui/core";
1
+ "use client";
9
2
 
10
- const guessAttachmentType = (
11
- contentType: string,
12
- ): "image" | "document" | "file" => {
13
- if (contentType.startsWith("image/")) return "image";
14
- if (contentType.startsWith("text/")) return "document";
15
- return "file";
16
- };
17
-
18
- export class CloudFileAttachmentAdapter implements AttachmentAdapter {
19
- public accept = "*";
20
-
21
- constructor(private cloud: AssistantCloud) {}
22
-
23
- private uploadedUrls = new Map<string, string>();
24
-
25
- public async *add({
26
- file,
27
- }: {
28
- file: File;
29
- }): AsyncGenerator<PendingAttachment, void> {
30
- const id = crypto.randomUUID();
31
- const type = guessAttachmentType(file.type);
32
- let attachment: PendingAttachment = {
33
- id,
34
- type,
35
- name: file.name,
36
- contentType: file.type,
37
- file,
38
- status: { type: "running", reason: "uploading", progress: 0 },
39
- };
40
- yield attachment;
41
-
42
- try {
43
- const { signedUrl, publicUrl } =
44
- await this.cloud.files.generatePresignedUploadUrl({
45
- filename: file.name,
46
- });
47
- await fetch(signedUrl, {
48
- method: "PUT",
49
- body: file,
50
- headers: {
51
- "Content-Type": file.type,
52
- },
53
- mode: "cors",
54
- });
55
- this.uploadedUrls.set(id, publicUrl);
56
- attachment = {
57
- ...attachment,
58
- status: { type: "requires-action", reason: "composer-send" },
59
- };
60
- yield attachment;
61
- } catch {
62
- attachment = {
63
- ...attachment,
64
- status: { type: "incomplete", reason: "error" },
65
- };
66
- yield attachment;
67
- }
68
- }
69
-
70
- public async remove(attachment: Attachment): Promise<void> {
71
- this.uploadedUrls.delete(attachment.id);
72
- }
73
-
74
- public async send(
75
- attachment: PendingAttachment,
76
- ): Promise<CompleteAttachment> {
77
- const url = this.uploadedUrls.get(attachment.id);
78
- if (!url) throw new Error("Attachment not uploaded");
79
- this.uploadedUrls.delete(attachment.id);
80
-
81
- let content: ThreadUserMessagePart[];
82
- if (attachment.type === "image") {
83
- content = [{ type: "image", image: url, filename: attachment.name }];
84
- } else {
85
- content = [
86
- {
87
- type: "file",
88
- data: url,
89
- mimeType: attachment.contentType ?? "",
90
- filename: attachment.name,
91
- },
92
- ];
93
- }
94
-
95
- return {
96
- ...attachment,
97
- status: { type: "complete" },
98
- content,
99
- };
100
- }
101
- }
3
+ export { CloudFileAttachmentAdapter } from "@assistant-ui/core/react";
@@ -6,18 +6,20 @@ import { act, renderHook, waitFor } from "@testing-library/react";
6
6
  import { describe, expect, it, vi } from "vitest";
7
7
  import type { AssistantTransportState } from "./types";
8
8
  import { ToolExecutionStatus, useToolInvocations } from "./useToolInvocations";
9
- import { ReadonlyJSONObject } from "assistant-stream/utils";
9
+ import { ReadonlyJSONObject, ReadonlyJSONValue } from "assistant-stream/utils";
10
10
 
11
11
  const createState = (
12
12
  messages: ThreadAssistantMessage[],
13
+ isRunning: boolean = true,
13
14
  ): AssistantTransportState => ({
14
15
  messages,
15
- isRunning: true,
16
+ isRunning,
16
17
  });
17
18
 
18
19
  const createAssistantMessage = (
19
20
  argsText: string,
20
21
  args: Record<string, unknown>,
22
+ options?: { result?: ReadonlyJSONValue; isError?: boolean },
21
23
  ): ThreadAssistantMessage => ({
22
24
  id: "m-1",
23
25
  role: "assistant",
@@ -37,6 +39,8 @@ const createAssistantMessage = (
37
39
  toolName: "weatherSearch",
38
40
  args: args as ReadonlyJSONObject,
39
41
  argsText,
42
+ ...(options?.result !== undefined && { result: options.result }),
43
+ ...(options?.isError !== undefined && { isError: options.isError }),
40
44
  },
41
45
  ],
42
46
  });
@@ -223,4 +227,223 @@ describe("useToolInvocations", () => {
223
227
  });
224
228
  expect(Object.keys(statuses)).not.toContain("tool-1:rewrite:0");
225
229
  });
230
+
231
+ it("does not close args stream early for non-executable tool snapshots", () => {
232
+ const getTools = () => ({
233
+ weatherSearch: {
234
+ parameters: { type: "object", properties: {} },
235
+ } satisfies Tool,
236
+ });
237
+ const onResult = vi.fn();
238
+ const setToolStatuses = vi.fn();
239
+ const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
240
+
241
+ try {
242
+ const { rerender } = renderHook(
243
+ ({ state }: { state: AssistantTransportState }) =>
244
+ useToolInvocations({
245
+ state,
246
+ getTools,
247
+ onResult,
248
+ setToolStatuses,
249
+ }),
250
+ {
251
+ initialProps: {
252
+ state: createState([]),
253
+ },
254
+ },
255
+ );
256
+
257
+ act(() => {
258
+ rerender({
259
+ state: createState([createAssistantMessage("{}", {})]),
260
+ });
261
+ });
262
+
263
+ act(() => {
264
+ rerender({
265
+ state: createState([
266
+ createAssistantMessage('{"title":"Weekly"', {
267
+ title: "Weekly",
268
+ }),
269
+ ]),
270
+ });
271
+ });
272
+
273
+ act(() => {
274
+ rerender({
275
+ state: createState([
276
+ createAssistantMessage('{"title":"Weekly","columns":["name"]}', {
277
+ title: "Weekly",
278
+ columns: ["name"],
279
+ }),
280
+ ]),
281
+ });
282
+ });
283
+
284
+ expect(warnSpy).not.toHaveBeenCalledWith(
285
+ "argsText updated after controller was closed:",
286
+ expect.anything(),
287
+ );
288
+ expect(warnSpy).not.toHaveBeenCalledWith(
289
+ "argsText updated after controller was closed, restarting tool args stream:",
290
+ expect.anything(),
291
+ );
292
+ expect(onResult).not.toHaveBeenCalled();
293
+ } finally {
294
+ warnSpy.mockRestore();
295
+ }
296
+ });
297
+
298
+ it("closes non-executable complete args stream after run settles", () => {
299
+ const getTools = () => ({
300
+ weatherSearch: {
301
+ parameters: { type: "object", properties: {} },
302
+ } satisfies Tool,
303
+ });
304
+ const onResult = vi.fn();
305
+ const setToolStatuses = vi.fn();
306
+ const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
307
+
308
+ try {
309
+ const { rerender } = renderHook(
310
+ ({ state }: { state: AssistantTransportState }) =>
311
+ useToolInvocations({
312
+ state,
313
+ getTools,
314
+ onResult,
315
+ setToolStatuses,
316
+ }),
317
+ {
318
+ initialProps: {
319
+ state: createState([]),
320
+ },
321
+ },
322
+ );
323
+
324
+ act(() => {
325
+ rerender({
326
+ state: createState(
327
+ [
328
+ createAssistantMessage('{"title":"Weekly"}', {
329
+ title: "Weekly",
330
+ }),
331
+ ],
332
+ true,
333
+ ),
334
+ });
335
+ });
336
+
337
+ act(() => {
338
+ rerender({
339
+ state: createState(
340
+ [
341
+ createAssistantMessage('{"title":"Weekly"}', {
342
+ title: "Weekly",
343
+ }),
344
+ ],
345
+ false,
346
+ ),
347
+ });
348
+ });
349
+
350
+ act(() => {
351
+ rerender({
352
+ state: createState(
353
+ [
354
+ createAssistantMessage('{"title":"Weekly","columns":["name"]}', {
355
+ title: "Weekly",
356
+ columns: ["name"],
357
+ }),
358
+ ],
359
+ false,
360
+ ),
361
+ });
362
+ });
363
+
364
+ expect(warnSpy).toHaveBeenCalledWith(
365
+ "argsText updated after controller was closed, restarting tool args stream:",
366
+ expect.objectContaining({
367
+ previous: '{"title":"Weekly"}',
368
+ next: '{"title":"Weekly","columns":["name"]}',
369
+ }),
370
+ );
371
+ expect(onResult).not.toHaveBeenCalled();
372
+ } finally {
373
+ warnSpy.mockRestore();
374
+ }
375
+ });
376
+
377
+ it("handles backend result when equivalent complete argsText reorders keys", async () => {
378
+ let resolveExecute: ((value: unknown) => void) | undefined;
379
+ const execute = vi.fn(
380
+ () =>
381
+ new Promise<unknown>((resolve) => {
382
+ resolveExecute = resolve;
383
+ }),
384
+ );
385
+ const getTools = () => ({
386
+ weatherSearch: {
387
+ parameters: { type: "object", properties: {} },
388
+ execute,
389
+ } satisfies Tool,
390
+ });
391
+ const onResult = vi.fn();
392
+ const setToolStatuses = vi.fn();
393
+
394
+ const { rerender } = renderHook(
395
+ ({ state }: { state: AssistantTransportState }) =>
396
+ useToolInvocations({
397
+ state,
398
+ getTools,
399
+ onResult,
400
+ setToolStatuses,
401
+ }),
402
+ {
403
+ initialProps: {
404
+ state: createState([]),
405
+ },
406
+ },
407
+ );
408
+
409
+ act(() => {
410
+ rerender({
411
+ state: createState([
412
+ createAssistantMessage('{"a":1,"b":2}', {
413
+ a: 1,
414
+ b: 2,
415
+ }),
416
+ ]),
417
+ });
418
+ });
419
+
420
+ await waitFor(() => {
421
+ expect(execute).toHaveBeenCalledTimes(1);
422
+ });
423
+
424
+ act(() => {
425
+ rerender({
426
+ state: createState([
427
+ createAssistantMessage(
428
+ '{"b":2,"a":1}',
429
+ {
430
+ a: 1,
431
+ b: 2,
432
+ },
433
+ {
434
+ result: { source: "backend" },
435
+ },
436
+ ),
437
+ ]),
438
+ });
439
+ });
440
+
441
+ await act(async () => {
442
+ resolveExecute?.({ source: "client" });
443
+ });
444
+
445
+ await waitFor(() => {
446
+ expect(onResult).not.toHaveBeenCalled();
447
+ });
448
+ });
226
449
  });