@assistant-ui/react-ag-ui 0.0.60 → 0.0.61

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 (45) hide show
  1. package/dist/agUiExtras.d.ts +1 -3
  2. package/dist/agUiExtras.d.ts.map +1 -1
  3. package/dist/hooks.d.ts +3 -5
  4. package/dist/hooks.d.ts.map +1 -1
  5. package/dist/index.d.ts +7 -5
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/runtime/AgUiThreadRuntimeCore.d.ts +152 -144
  8. package/dist/runtime/AgUiThreadRuntimeCore.d.ts.map +1 -1
  9. package/dist/runtime/AgUiThreadRuntimeCore.js +141 -23
  10. package/dist/runtime/AgUiThreadRuntimeCore.js.map +1 -1
  11. package/dist/runtime/adapter/conversions.d.ts +51 -53
  12. package/dist/runtime/adapter/conversions.d.ts.map +1 -1
  13. package/dist/runtime/adapter/conversions.js +65 -21
  14. package/dist/runtime/adapter/conversions.js.map +1 -1
  15. package/dist/runtime/adapter/run-aggregator.d.ts +89 -88
  16. package/dist/runtime/adapter/run-aggregator.d.ts.map +1 -1
  17. package/dist/runtime/adapter/run-aggregator.js +35 -2
  18. package/dist/runtime/adapter/run-aggregator.js.map +1 -1
  19. package/dist/runtime/adapter/subscriber.d.ts +107 -108
  20. package/dist/runtime/adapter/subscriber.d.ts.map +1 -1
  21. package/dist/runtime/adapter/tool-approval.d.ts +3 -4
  22. package/dist/runtime/adapter/tool-approval.d.ts.map +1 -1
  23. package/dist/runtime/event-parser.d.ts +3 -5
  24. package/dist/runtime/event-parser.d.ts.map +1 -1
  25. package/dist/runtime/interrupt-internals.d.ts +1 -3
  26. package/dist/runtime/interrupt-internals.d.ts.map +1 -1
  27. package/dist/runtime/logger.d.ts +2 -4
  28. package/dist/runtime/logger.d.ts.map +1 -1
  29. package/dist/runtime/mcp-tool-result.d.ts +4 -6
  30. package/dist/runtime/mcp-tool-result.d.ts.map +1 -1
  31. package/dist/runtime/types.d.ts +237 -238
  32. package/dist/runtime/types.d.ts.map +1 -1
  33. package/dist/useAgUiRuntime.d.ts +13 -15
  34. package/dist/useAgUiRuntime.d.ts.map +1 -1
  35. package/dist/useAgUiRuntime.js +9 -2
  36. package/dist/useAgUiRuntime.js.map +1 -1
  37. package/package.json +6 -6
  38. package/src/runtime/AgUiThreadRuntimeCore.ts +239 -32
  39. package/src/runtime/adapter/conversions.content.test.ts +56 -0
  40. package/src/runtime/adapter/conversions.ts +112 -44
  41. package/src/runtime/adapter/run-aggregator.ts +53 -2
  42. package/src/useAgUiRuntime.history.test.tsx +93 -2
  43. package/src/useAgUiRuntime.thread-switch.test.tsx +84 -4
  44. package/src/useAgUiRuntime.ts +12 -3
  45. package/src/useAgUiRuntime.voice.test.tsx +402 -0
@@ -1,69 +1,67 @@
1
- import { ThreadMessageLike } from "@assistant-ui/core";
2
- import { InputContent, RunAgentParameters } from "@ag-ui/client";
3
- import { Tool } from "assistant-stream";
4
- //#region src/runtime/adapter/conversions.d.ts
1
+ import type { InputContent, RunAgentParameters } from "@ag-ui/client";
2
+ import type { ThreadMessageLike as CoreThreadMessageLike } from "@assistant-ui/core";
3
+ import { type Tool } from "assistant-stream";
4
+ export type { InputContent };
5
5
  type AttachmentLike = {
6
- name?: string | undefined;
7
- contentType?: string | undefined;
8
- content?: readonly unknown[] | undefined;
6
+ name?: string | undefined;
7
+ contentType?: string | undefined;
8
+ content?: readonly unknown[] | undefined;
9
9
  };
10
- type ThreadMessageLike$1 = {
11
- id?: string | undefined;
12
- role: string;
13
- content: unknown;
14
- metadata?: unknown;
15
- name?: string | undefined;
16
- toolCallId?: string | undefined;
17
- error?: string | undefined;
18
- attachments?: readonly AttachmentLike[] | undefined;
10
+ type ThreadMessageLike = {
11
+ id?: string | undefined;
12
+ role: string;
13
+ content: unknown;
14
+ metadata?: unknown;
15
+ name?: string | undefined;
16
+ toolCallId?: string | undefined;
17
+ error?: string | undefined;
18
+ attachments?: readonly AttachmentLike[] | undefined;
19
19
  };
20
20
  type AgUiToolCall = {
21
- id: string;
22
- type: "function";
23
- function: {
24
- name: string;
25
- arguments: string;
26
- };
21
+ id: string;
22
+ type: "function";
23
+ function: {
24
+ name: string;
25
+ arguments: string;
26
+ };
27
27
  };
28
28
  export type AgUiMessage = {
29
- id: string;
30
- role: "user";
31
- content: string | InputContent[];
32
- name?: string;
29
+ id: string;
30
+ role: "user";
31
+ content: string | InputContent[];
32
+ name?: string;
33
33
  } | {
34
- id: string;
35
- role: "assistant";
36
- content: string;
37
- name?: string;
38
- toolCalls?: AgUiToolCall[];
34
+ id: string;
35
+ role: "assistant";
36
+ content: string;
37
+ name?: string;
38
+ toolCalls?: AgUiToolCall[];
39
39
  } | {
40
- id: string;
41
- role: "system" | "developer";
42
- content: string;
43
- name?: string;
40
+ id: string;
41
+ role: "system" | "developer";
42
+ content: string;
43
+ name?: string;
44
44
  } | {
45
- id: string;
46
- role: "reasoning";
47
- content: string;
48
- encryptedValue?: string;
45
+ id: string;
46
+ role: "reasoning";
47
+ content: string;
48
+ encryptedValue?: string;
49
49
  } | {
50
- id: string;
51
- role: "tool";
52
- content: string;
53
- toolCallId: string;
54
- error?: string;
50
+ id: string;
51
+ role: "tool";
52
+ content: string;
53
+ toolCallId: string;
54
+ error?: string;
55
55
  };
56
56
  export type FromAgUiMessagesOptions = {
57
- /**
58
- * Whether to convert `reasoning` messages into visible reasoning parts.
59
- * Matches the `showThinking` option of `useAgUiRuntime`. Defaults to `true`.
60
- */
61
- showThinking?: boolean;
57
+ /**
58
+ * Whether to convert `reasoning` messages into visible reasoning parts.
59
+ * Matches the `showThinking` option of `useAgUiRuntime`. Defaults to `true`.
60
+ */
61
+ showThinking?: boolean;
62
62
  };
63
- export declare function fromAgUiMessages(messages: readonly unknown[], options?: FromAgUiMessagesOptions): ThreadMessageLike[];
64
- export declare function toAgUiMessages(messages: readonly ThreadMessageLike$1[]): AgUiMessage[];
63
+ export declare function fromAgUiMessages(messages: readonly unknown[], options?: FromAgUiMessagesOptions): CoreThreadMessageLike[];
64
+ export declare function toAgUiMessages(messages: readonly ThreadMessageLike[]): AgUiMessage[];
65
65
  type AgUiTool = NonNullable<RunAgentParameters["tools"]>[number];
66
66
  export declare function toAgUiTools(tools: Record<string, Tool> | undefined): AgUiTool[];
67
- //#endregion
68
- export type { InputContent };
69
67
  //# sourceMappingURL=conversions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"conversions.d.ts","names":[],"sources":["../../../src/runtime/adapter/conversions.ts"],"mappings":";;;;KAwCK;EACH;EACA;EACA;;KAGG;EACH;EACA;EACA;EACA;EACA;EACA;EACA;EACA,uBAAuB;;KAKpB;EACH;EACA;EACA;IAAY;IAAc;;;YAGhB;EAEN;EACA;EACA,kBAAkB;EAClB;;EAGA;EACA;EACA;EACA;EACA,YAAY;;EAGZ;EACA;EACA;EACA;;EAGA;EACA;EACA;EACA;;EAGA;EACA;EACA;EACA;EACA;;YA0uBM;;;;;EAKV;;wBAGc,iBACd,8BACA,UAAU,0BACT;wBA0ea,eACd,mBAAmB,wBAClB;KAsFE,WAAW,YAAY;wBAEZ,YACd,OAAO,eAAe,oBACrB"}
1
+ {"version":3,"file":"conversions.d.ts","sourceRoot":"","sources":["../../../src/runtime/adapter/conversions.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAEtE,OAAO,KAAK,EACV,iBAAiB,IAAI,qBAAqB,EAM3C,MAAM,oBAAoB,CAAC;AAM5B,OAAO,EAAE,KAAK,IAAI,EAAqB,MAAM,kBAAkB,CAAC;AAuBhE,YAAY,EAAE,YAAY,EAAE,CAAC;AAE7B,KAAK,cAAc,GAAG;IACpB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,OAAO,CAAC,EAAE,SAAS,OAAO,EAAE,GAAG,SAAS,CAAC;CAC1C,CAAC;AAEF,KAAK,iBAAiB,GAAG;IACvB,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,WAAW,CAAC,EAAE,SAAS,cAAc,EAAE,GAAG,SAAS,CAAC;CACrD,CAAC;AAIF,KAAK,YAAY,GAAG;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/C,CAAC;AAEF,MAAM,MAAM,WAAW,GACnB;IACE,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,YAAY,EAAE,CAAC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GACD;IACE,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,YAAY,EAAE,CAAC;CAC5B,GACD;IACE,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,QAAQ,GAAG,WAAW,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GACD;IACE,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,GACD;IACE,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AA8vBN,MAAM,MAAM,uBAAuB,GAAG;IACpC;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB,CAAC;AAEF,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,SAAS,OAAO,EAAE,EAC5B,OAAO,CAAC,EAAE,uBAAuB,GAChC,qBAAqB,EAAE,CAsXzB;AAiKD,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,SAAS,iBAAiB,EAAE,GACrC,WAAW,EAAE,CAoFf;AAED,KAAK,QAAQ,GAAG,WAAW,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjE,wBAAgB,WAAW,CACzB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,SAAS,GACtC,QAAQ,EAAE,CASZ"}
@@ -4,7 +4,7 @@ import { projectAgUiToolApprovals } from "./tool-approval.js";
4
4
  import { AG_UI_METADATA_NAMESPACE } from "./run-aggregator.js";
5
5
  import { generateId } from "@assistant-ui/core";
6
6
  import { getAutoStatus, parseDataUrl, resolveFilePartSource } from "@assistant-ui/core/internal";
7
- import { applyA2uiOperations, convertSurfaceToUISpec } from "@assistant-ui/react-generative-ui/a2ui";
7
+ import { applyA2uiOperations, convertSurfaceToUISpec, surfaceToOperations } from "@assistant-ui/react-generative-ui/a2ui";
8
8
  import { toToolsJSONSchema } from "assistant-stream";
9
9
  //#region src/runtime/adapter/conversions.ts
10
10
  const isObject = (value) => typeof value === "object" && value !== null;
@@ -79,7 +79,7 @@ function buildInputSource(value, declaredMimeType, sourceType) {
79
79
  const source = resolveFilePartSource({
80
80
  data: value,
81
81
  mimeType: declaredMimeType ?? "application/octet-stream",
82
- sourceType
82
+ sourceType: /^data:/i.test(value) && !parseDataUrl(value) ? "url" : sourceType
83
83
  });
84
84
  if (source.kind === "url") return declaredMimeType !== void 0 ? {
85
85
  type: "url",
@@ -424,7 +424,8 @@ function attachA2uiSurfaces(message, state) {
424
424
  toolName: "present",
425
425
  args: spec,
426
426
  argsText: JSON.stringify(spec),
427
- result: {}
427
+ result: {},
428
+ artifact: { a2ui: surfaceToOperations(surface) }
428
429
  });
429
430
  }
430
431
  const preserved = (Array.isArray(message.content) ? message.content : []).filter((part) => !(isObject(part) && part.type === "tool-call" && typeof part.toolCallId === "string" && part.toolCallId.startsWith("a2ui:")));
@@ -443,13 +444,19 @@ function isSyntheticToolCallContainer(message) {
443
444
  }
444
445
  return carriesOwnId;
445
446
  }
447
+ function carriesPart(message, type) {
448
+ return Array.isArray(message.content) && message.content.some((part) => isObject(part) && part.type === type);
449
+ }
446
450
  function carriesText(message) {
447
- return Array.isArray(message.content) && message.content.some((part) => isObject(part) && part.type === "text");
451
+ return carriesPart(message, "text");
452
+ }
453
+ function opensTurn(message) {
454
+ return message.role === "assistant" && (carriesText(message) || carriesPart(message, "tool-call"));
448
455
  }
449
- function foldsOntoToolCallContainer(message) {
456
+ function answersToolCallContainer(message) {
450
457
  if (message.role !== "assistant" || !Array.isArray(message.content)) return false;
451
458
  if (message.content.length === 0) return false;
452
- return isSyntheticToolCallContainer(message) || !message.content.some((part) => isObject(part) && part.type === "tool-call");
459
+ return !message.content.some((part) => isObject(part) && part.type === "tool-call");
453
460
  }
454
461
  function readCustomMetadata(metadata) {
455
462
  if (!isObject(metadata) || !isObject(metadata.custom)) return {};
@@ -459,33 +466,34 @@ function readNamespacedMetadata(metadata) {
459
466
  const namespaced = readCustomMetadata(metadata)[AG_UI_METADATA_NAMESPACE];
460
467
  return isObject(namespaced) ? namespaced : {};
461
468
  }
462
- function foldOntoToolCallContainer(container, message) {
463
- const interrupts = [...readPersistedInterrupts(container.metadata) ?? [], ...readPersistedInterrupts(message.metadata) ?? []];
464
- const opaqueReasoning = [...readOpaqueReasoning(container.metadata), ...readOpaqueReasoning(message.metadata).map((entry) => ({
469
+ function foldTurnRecords(previous, message) {
470
+ const interrupts = [...readPersistedInterrupts(previous.metadata) ?? [], ...readPersistedInterrupts(message.metadata) ?? []];
471
+ const trailsCalls = carriesPart(previous, "tool-call");
472
+ const opaqueReasoning = [...readOpaqueReasoning(previous.metadata), ...readOpaqueReasoning(message.metadata).map((entry) => trailsCalls ? {
465
473
  ...entry,
466
474
  after: true
467
- }))];
475
+ } : entry)];
468
476
  const namespaced = {
469
- ...readNamespacedMetadata(container.metadata),
477
+ ...readNamespacedMetadata(previous.metadata),
470
478
  ...readNamespacedMetadata(message.metadata),
471
479
  ...interrupts.length > 0 ? { interrupts } : {},
472
480
  ...opaqueReasoning.length > 0 ? { opaqueReasoning } : {}
473
481
  };
474
482
  const custom = {
475
- ...readCustomMetadata(container.metadata),
483
+ ...readCustomMetadata(previous.metadata),
476
484
  ...readCustomMetadata(message.metadata),
477
485
  ...Object.keys(namespaced).length > 0 ? { [AG_UI_METADATA_NAMESPACE]: namespaced } : {}
478
486
  };
479
487
  const metadata = {
480
- ...isObject(container.metadata) ? container.metadata : {},
488
+ ...isObject(previous.metadata) ? previous.metadata : {},
481
489
  ...isObject(message.metadata) ? message.metadata : {},
482
490
  ...Object.keys(custom).length > 0 ? { custom } : {}
483
491
  };
484
492
  return {
485
- ...container,
493
+ ...previous,
486
494
  ...message,
487
- id: carriesText(message) ? message.id : container.id,
488
- content: [...Array.isArray(container.content) ? container.content : [], ...Array.isArray(message.content) ? message.content : []],
495
+ id: carriesText(message) ? message.id : previous.id,
496
+ content: [...Array.isArray(previous.content) ? previous.content : [], ...Array.isArray(message.content) ? message.content : []],
489
497
  ...Object.keys(metadata).length > 0 ? { metadata } : {}
490
498
  };
491
499
  }
@@ -494,6 +502,7 @@ function fromAgUiMessages(messages, options) {
494
502
  const converted = [];
495
503
  const a2uiBuckets = /* @__PURE__ */ new Map();
496
504
  const a2uiBucketOwnerIndices = /* @__PURE__ */ new Map();
505
+ const activityParts = /* @__PURE__ */ new Map();
497
506
  const opaqueReasoning = [];
498
507
  const pendingReasoning = [];
499
508
  const flushPendingReasoning = () => {
@@ -578,9 +587,8 @@ function fromAgUiMessages(messages, options) {
578
587
  continue;
579
588
  }
580
589
  if (role === "activity") {
581
- if (getString(rawMessage, "activityType") !== "a2ui-surface") continue;
582
- const operations = (isObject(rawMessage.content) ? rawMessage.content : null)?.["a2ui_operations"];
583
- if (!Array.isArray(operations)) continue;
590
+ const activityType = getString(rawMessage, "activityType");
591
+ if (activityType === void 0 || activityType === "mcp-apps") continue;
584
592
  flushPendingReasoning();
585
593
  let ownerIndex = -1;
586
594
  for (let i = converted.length - 1; i >= 0; i--) {
@@ -592,6 +600,42 @@ function fromAgUiMessages(messages, options) {
592
600
  }
593
601
  if (ownerIndex === -1) continue;
594
602
  const owner = converted[ownerIndex];
603
+ if (activityType !== "a2ui-surface") {
604
+ const bucketKey = getString(rawMessage, "id") ?? `agui-activity:${activityType}`;
605
+ const part = {
606
+ type: "data",
607
+ name: `agui-activity/${activityType}`,
608
+ data: rawMessage.content
609
+ };
610
+ const existing = activityParts.get(bucketKey);
611
+ const existingOwner = existing && converted[existing.ownerIndex];
612
+ const existingIndex = existingOwner && Array.isArray(existingOwner.content) ? existingOwner.content.indexOf(existing.part) : -1;
613
+ if (existing && existingOwner && existingIndex !== -1) {
614
+ const content = [...existingOwner.content];
615
+ content[existingIndex] = part;
616
+ converted[existing.ownerIndex] = {
617
+ ...existingOwner,
618
+ content
619
+ };
620
+ activityParts.set(bucketKey, {
621
+ ownerIndex: existing.ownerIndex,
622
+ part
623
+ });
624
+ continue;
625
+ }
626
+ const content = Array.isArray(owner.content) ? owner.content : [];
627
+ activityParts.set(bucketKey, {
628
+ ownerIndex,
629
+ part
630
+ });
631
+ converted[ownerIndex] = {
632
+ ...owner,
633
+ content: [...content, part]
634
+ };
635
+ continue;
636
+ }
637
+ const operations = (isObject(rawMessage.content) ? rawMessage.content : null)?.["a2ui_operations"];
638
+ if (!Array.isArray(operations)) continue;
595
639
  const bucketKey = getString(rawMessage, "id") ?? "a2ui:anonymous";
596
640
  const { state } = applyA2uiOperations(/* @__PURE__ */ new Map(), operations);
597
641
  a2uiBuckets.delete(bucketKey);
@@ -669,8 +713,8 @@ function fromAgUiMessages(messages, options) {
669
713
  const folded = [];
670
714
  for (const message of converted) {
671
715
  const previous = folded[folded.length - 1];
672
- if (previous !== void 0 && isSyntheticToolCallContainer(previous) && foldsOntoToolCallContainer(message)) {
673
- folded[folded.length - 1] = foldOntoToolCallContainer(previous, message);
716
+ if (previous !== void 0 && (isSyntheticToolCallContainer(message) ? opensTurn(previous) : isSyntheticToolCallContainer(previous) && answersToolCallContainer(message))) {
717
+ folded[folded.length - 1] = foldTurnRecords(previous, message);
674
718
  continue;
675
719
  }
676
720
  folded.push(message);