@assistant-ui/react-a2a 0.2.5 → 0.2.7

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 (60) hide show
  1. package/README.md +47 -1
  2. package/dist/A2AClient.d.ts +43 -0
  3. package/dist/A2AClient.d.ts.map +1 -0
  4. package/dist/A2AClient.js +358 -0
  5. package/dist/A2AClient.js.map +1 -0
  6. package/dist/A2AThreadRuntimeCore.d.ts +75 -0
  7. package/dist/A2AThreadRuntimeCore.d.ts.map +1 -0
  8. package/dist/A2AThreadRuntimeCore.js +483 -0
  9. package/dist/A2AThreadRuntimeCore.js.map +1 -0
  10. package/dist/conversions.d.ts +14 -0
  11. package/dist/conversions.d.ts.map +1 -0
  12. package/dist/conversions.js +92 -0
  13. package/dist/conversions.js.map +1 -0
  14. package/dist/index.d.ts +7 -6
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +7 -6
  17. package/dist/index.js.map +1 -1
  18. package/dist/types.d.ts +228 -84
  19. package/dist/types.d.ts.map +1 -1
  20. package/dist/types.js +4 -9
  21. package/dist/types.js.map +1 -1
  22. package/dist/useA2ARuntime.d.ts +35 -48
  23. package/dist/useA2ARuntime.d.ts.map +1 -1
  24. package/dist/useA2ARuntime.js +126 -172
  25. package/dist/useA2ARuntime.js.map +1 -1
  26. package/package.json +9 -9
  27. package/src/A2AClient.test.ts +773 -0
  28. package/src/A2AClient.ts +519 -0
  29. package/src/A2AThreadRuntimeCore.test.ts +692 -0
  30. package/src/A2AThreadRuntimeCore.ts +633 -0
  31. package/src/conversions.test.ts +276 -0
  32. package/src/conversions.ts +115 -0
  33. package/src/index.ts +66 -6
  34. package/src/types.ts +276 -95
  35. package/src/useA2ARuntime.ts +204 -296
  36. package/dist/A2AMessageAccumulator.d.ts +0 -16
  37. package/dist/A2AMessageAccumulator.d.ts.map +0 -1
  38. package/dist/A2AMessageAccumulator.js +0 -29
  39. package/dist/A2AMessageAccumulator.js.map +0 -1
  40. package/dist/appendA2AChunk.d.ts +0 -3
  41. package/dist/appendA2AChunk.d.ts.map +0 -1
  42. package/dist/appendA2AChunk.js +0 -110
  43. package/dist/appendA2AChunk.js.map +0 -1
  44. package/dist/convertA2AMessages.d.ts +0 -64
  45. package/dist/convertA2AMessages.d.ts.map +0 -1
  46. package/dist/convertA2AMessages.js +0 -90
  47. package/dist/convertA2AMessages.js.map +0 -1
  48. package/dist/testUtils.d.ts +0 -4
  49. package/dist/testUtils.d.ts.map +0 -1
  50. package/dist/testUtils.js +0 -6
  51. package/dist/testUtils.js.map +0 -1
  52. package/dist/useA2AMessages.d.ts +0 -25
  53. package/dist/useA2AMessages.d.ts.map +0 -1
  54. package/dist/useA2AMessages.js +0 -122
  55. package/dist/useA2AMessages.js.map +0 -1
  56. package/src/A2AMessageAccumulator.ts +0 -48
  57. package/src/appendA2AChunk.ts +0 -121
  58. package/src/convertA2AMessages.ts +0 -108
  59. package/src/testUtils.ts +0 -11
  60. package/src/useA2AMessages.ts +0 -180
@@ -1,110 +0,0 @@
1
- import { parsePartialJsonObject } from "assistant-stream/utils";
2
- export const appendA2AChunk = (prev, curr) => {
3
- // If no previous message or different message type, return current as-is
4
- if (!prev || prev.role !== curr.role || prev.id !== curr.id) {
5
- return curr;
6
- }
7
- // For assistant messages, we need to handle streaming content and tool calls
8
- if (curr.role === "assistant") {
9
- const newContent = Array.isArray(prev.content)
10
- ? [...prev.content]
11
- : typeof prev.content === "string"
12
- ? [{ type: "text", text: prev.content }]
13
- : [];
14
- // Append new content chunks
15
- if (typeof curr.content === "string") {
16
- const lastIndex = newContent.length - 1;
17
- const lastPart = newContent[lastIndex];
18
- if (lastPart?.type === "text") {
19
- // Append to existing text part
20
- lastPart.text += curr.content;
21
- }
22
- else {
23
- // Create new text part
24
- newContent.push({ type: "text", text: curr.content });
25
- }
26
- }
27
- else if (Array.isArray(curr.content)) {
28
- for (const contentPart of curr.content) {
29
- const lastIndex = newContent.length - 1;
30
- const lastPart = newContent[lastIndex];
31
- if (contentPart.type === "text" && lastPart?.type === "text") {
32
- // Append to existing text part
33
- lastPart.text += contentPart.text;
34
- }
35
- else {
36
- // Add new content part
37
- newContent.push(contentPart);
38
- }
39
- }
40
- }
41
- // Merge tool calls - A2A typically sends complete tool calls rather than chunks
42
- const newToolCalls = [...(prev.tool_calls ?? [])];
43
- if (curr.tool_calls) {
44
- for (const toolCall of curr.tool_calls) {
45
- const existingIndex = newToolCalls.findIndex((tc) => tc.id === toolCall.id);
46
- if (existingIndex >= 0) {
47
- // Update existing tool call (merge args if needed)
48
- const existing = newToolCalls[existingIndex];
49
- newToolCalls[existingIndex] = {
50
- ...existing,
51
- ...toolCall,
52
- // If argsText is provided in chunks, concatenate it
53
- argsText: (existing.argsText || "") + (toolCall.argsText || ""),
54
- // Try to parse merged args, fallback to existing or new args
55
- args: parsePartialJsonObject((existing.argsText || "") + (toolCall.argsText || "")) ||
56
- toolCall.args ||
57
- existing.args,
58
- };
59
- }
60
- else {
61
- // Add new tool call
62
- newToolCalls.push(toolCall);
63
- }
64
- }
65
- }
66
- // Merge artifacts
67
- const newArtifacts = [...(prev.artifacts ?? [])];
68
- if (curr.artifacts) {
69
- for (const artifact of curr.artifacts) {
70
- const existingIndex = newArtifacts.findIndex((a) => a.name === artifact.name);
71
- if (existingIndex >= 0) {
72
- // Merge artifact parts
73
- const existingArtifact = newArtifacts[existingIndex];
74
- newArtifacts[existingIndex] = {
75
- name: existingArtifact.name,
76
- parts: [...existingArtifact.parts, ...artifact.parts],
77
- };
78
- }
79
- else {
80
- // Add new artifact
81
- newArtifacts.push(artifact);
82
- }
83
- }
84
- }
85
- const result = {
86
- ...prev,
87
- content: newContent,
88
- };
89
- const newStatus = curr.status || prev.status;
90
- if (newStatus)
91
- result.status = newStatus;
92
- if (newToolCalls.length > 0)
93
- result.tool_calls = newToolCalls;
94
- if (newArtifacts.length > 0)
95
- result.artifacts = newArtifacts;
96
- return result;
97
- }
98
- // For other message types (user, system, tool), just return the current message
99
- // as they typically don't stream in chunks
100
- const result = {
101
- ...prev,
102
- ...curr,
103
- };
104
- // Preserve any existing artifacts and merge with new ones
105
- if (curr.artifacts || prev.artifacts) {
106
- result.artifacts = [...(prev.artifacts ?? []), ...(curr.artifacts ?? [])];
107
- }
108
- return result;
109
- };
110
- //# sourceMappingURL=appendA2AChunk.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"appendA2AChunk.js","sourceRoot":"","sources":["../src/appendA2AChunk.ts"],"names":[],"mappings":"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"}
@@ -1,64 +0,0 @@
1
- import { A2AMessage } from "./types.js";
2
- import { ToolCallMessagePart } from "@assistant-ui/react";
3
- export declare const convertA2AMessage: (message: A2AMessage) => {
4
- id: string | undefined;
5
- role: "system";
6
- content: {
7
- type: "text";
8
- text: string;
9
- }[];
10
- status?: never;
11
- } | {
12
- id: string | undefined;
13
- role: "user";
14
- content: NonNullable<import("@assistant-ui/core").ThreadUserMessagePart | null>[];
15
- status?: never;
16
- } | {
17
- id: string | undefined;
18
- role: "assistant";
19
- content: (NonNullable<import("@assistant-ui/core").ThreadUserMessagePart | null> | ToolCallMessagePart)[];
20
- status: import("@assistant-ui/core").MessageStatus | undefined;
21
- } | {
22
- id: string | undefined;
23
- role: "user";
24
- content: {
25
- type: "tool-call";
26
- toolCallId: string;
27
- toolName: string;
28
- result: any;
29
- isError: boolean;
30
- }[];
31
- status?: never;
32
- };
33
- export declare const convertA2AMessages: (messages: A2AMessage[]) => ({
34
- id: string | undefined;
35
- role: "system";
36
- content: {
37
- type: "text";
38
- text: string;
39
- }[];
40
- status?: never;
41
- } | {
42
- id: string | undefined;
43
- role: "user";
44
- content: NonNullable<import("@assistant-ui/core").ThreadUserMessagePart | null>[];
45
- status?: never;
46
- } | {
47
- id: string | undefined;
48
- role: "assistant";
49
- content: (NonNullable<import("@assistant-ui/core").ThreadUserMessagePart | null> | ToolCallMessagePart)[];
50
- status: import("@assistant-ui/core").MessageStatus | undefined;
51
- } | {
52
- id: string | undefined;
53
- role: "user";
54
- content: {
55
- type: "tool-call";
56
- toolCallId: string;
57
- toolName: string;
58
- result: any;
59
- isError: boolean;
60
- }[];
61
- status?: never;
62
- })[];
63
- export declare const useA2AMessageConverter: (messages: A2AMessage[], isRunning: boolean) => import("@assistant-ui/core").ThreadMessage[];
64
- //# sourceMappingURL=convertA2AMessages.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"convertA2AMessages.d.ts","sourceRoot":"","sources":["../src/convertA2AMessages.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,mBAAgB;AACrC,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAkC1D,eAAO,MAAM,iBAAiB,GAAI,SAAS,UAAU;;;;;cAOe,MAAM;;;;;;;;;;;;;;;;;;;;;;;;CAiDzE,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,UAAU,UAAU,EAAE;;;;;cAnDW,MAAM;;;;;;;;;;;;;;;;;;;;;;;;IAoDzC,CAAC;AAElC,eAAO,MAAM,sBAAsB,GACjC,UAAU,UAAU,EAAE,EACtB,WAAW,OAAO,iDAMhB,CAAC"}
@@ -1,90 +0,0 @@
1
- "use client";
2
- import { useExternalMessageConverter } from "@assistant-ui/react";
3
- const contentToParts = (content) => {
4
- if (typeof content === "string")
5
- return [{ type: "text", text: content }];
6
- return content
7
- .map((part) => {
8
- const type = part.type;
9
- switch (type) {
10
- case "text":
11
- return { type: "text", text: part.text };
12
- case "image_url":
13
- if (typeof part.image_url === "string") {
14
- return { type: "image", image: part.image_url };
15
- }
16
- else {
17
- return {
18
- type: "image",
19
- image: part.image_url.url,
20
- };
21
- }
22
- case "data":
23
- // Convert data parts to text representation for display
24
- return {
25
- type: "text",
26
- text: `[Data: ${JSON.stringify(part.data)}]`,
27
- };
28
- default:
29
- return null;
30
- }
31
- })
32
- .filter((part) => part !== null);
33
- };
34
- export const convertA2AMessage = (message) => {
35
- const role = message.role;
36
- switch (role) {
37
- case "system":
38
- return {
39
- id: message.id,
40
- role: "system",
41
- content: [{ type: "text", text: message.content }],
42
- };
43
- case "user":
44
- return {
45
- id: message.id,
46
- role: "user",
47
- content: contentToParts(message.content),
48
- };
49
- case "assistant": {
50
- const toolCallParts = message.tool_calls?.map((toolCall) => ({
51
- type: "tool-call",
52
- toolCallId: toolCall.id,
53
- toolName: toolCall.name,
54
- args: toolCall.args,
55
- argsText: toolCall.argsText ?? JSON.stringify(toolCall.args),
56
- })) ?? [];
57
- return {
58
- id: message.id,
59
- role: "assistant",
60
- content: [...contentToParts(message.content), ...toolCallParts],
61
- status: message.status,
62
- };
63
- }
64
- case "tool":
65
- return {
66
- id: message.id,
67
- role: "user",
68
- content: [
69
- {
70
- type: "tool-call",
71
- toolCallId: message.tool_call_id,
72
- toolName: "", // A2A doesn't store tool name in tool messages
73
- result: JSON.parse(message.content),
74
- isError: message.status?.type === "incomplete" &&
75
- message.status?.reason === "error",
76
- },
77
- ],
78
- };
79
- default:
80
- const _exhaustiveCheck = role;
81
- throw new Error(`Unknown message role: ${_exhaustiveCheck}`);
82
- }
83
- };
84
- export const convertA2AMessages = (messages) => messages.map(convertA2AMessage);
85
- export const useA2AMessageConverter = (messages, isRunning) => useExternalMessageConverter({
86
- callback: convertA2AMessage,
87
- messages,
88
- isRunning,
89
- });
90
- //# sourceMappingURL=convertA2AMessages.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"convertA2AMessages.js","sourceRoot":"","sources":["../src/convertA2AMessages.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAKlE,MAAM,cAAc,GAAG,CAAC,OAA8B,EAAE,EAAE;IACxD,IAAI,OAAO,OAAO,KAAK,QAAQ;QAC7B,OAAO,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IACpD,OAAO,OAAO;SACX,GAAG,CAAC,CAAC,IAAI,EAA+C,EAAE;QACzD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACvB,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,MAAM;gBACT,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;YAC3C,KAAK,WAAW;gBACd,IAAI,OAAO,IAAI,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;oBACvC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC;gBAClD,CAAC;qBAAM,CAAC;oBACN,OAAO;wBACL,IAAI,EAAE,OAAO;wBACb,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG;qBAC1B,CAAC;gBACJ,CAAC;YACH,KAAK,MAAM;gBACT,wDAAwD;gBACxD,OAAO;oBACL,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,UAAU,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;iBAC7C,CAAC;YACJ;gBACE,OAAO,IAAI,CAAC;QAChB,CAAC;IACH,CAAC,CAAC;SACD,MAAM,CAAC,CAAC,IAAI,EAAoC,EAAE,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;AACvE,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,OAAmB,EAAE,EAAE;IACvD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAC1B,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,QAAQ;YACX,OAAO;gBACL,EAAE,EAAE,OAAO,CAAC,EAAE;gBACd,IAAI,EAAE,QAAiB;gBACvB,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,OAAO,CAAC,OAAiB,EAAE,CAAC;aACtE,CAAC;QAEJ,KAAK,MAAM;YACT,OAAO;gBACL,EAAE,EAAE,OAAO,CAAC,EAAE;gBACd,IAAI,EAAE,MAAe;gBACrB,OAAO,EAAE,cAAc,CAAC,OAAO,CAAC,OAAO,CAAC;aACzC,CAAC;QAEJ,KAAK,WAAW,CAAC,CAAC,CAAC;YACjB,MAAM,aAAa,GACjB,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;gBACrC,IAAI,EAAE,WAAW;gBACjB,UAAU,EAAE,QAAQ,CAAC,EAAE;gBACvB,QAAQ,EAAE,QAAQ,CAAC,IAAI;gBACvB,IAAI,EAAE,QAAQ,CAAC,IAAI;gBACnB,QAAQ,EAAE,QAAQ,CAAC,QAAQ,IAAI,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC;aAC7D,CAAC,CAAC,IAAI,EAAE,CAAC;YAEZ,OAAO;gBACL,EAAE,EAAE,OAAO,CAAC,EAAE;gBACd,IAAI,EAAE,WAAoB;gBAC1B,OAAO,EAAE,CAAC,GAAG,cAAc,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,GAAG,aAAa,CAAC;gBAC/D,MAAM,EAAE,OAAO,CAAC,MAAM;aACvB,CAAC;QACJ,CAAC;QAED,KAAK,MAAM;YACT,OAAO;gBACL,EAAE,EAAE,OAAO,CAAC,EAAE;gBACd,IAAI,EAAE,MAAe;gBACrB,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,WAAoB;wBAC1B,UAAU,EAAE,OAAO,CAAC,YAAa;wBACjC,QAAQ,EAAE,EAAE,EAAE,+CAA+C;wBAC7D,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAiB,CAAC;wBAC7C,OAAO,EACL,OAAO,CAAC,MAAM,EAAE,IAAI,KAAK,YAAY;4BACrC,OAAO,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO;qBACrC;iBACF;aACF,CAAC;QAEJ;YACE,MAAM,gBAAgB,GAAU,IAAI,CAAC;YACrC,MAAM,IAAI,KAAK,CAAC,yBAAyB,gBAAgB,EAAE,CAAC,CAAC;IACjE,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,QAAsB,EAAE,EAAE,CAC3D,QAAQ,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;AAElC,MAAM,CAAC,MAAM,sBAAsB,GAAG,CACpC,QAAsB,EACtB,SAAkB,EAClB,EAAE,CACF,2BAA2B,CAAC;IAC1B,QAAQ,EAAE,iBAAiB;IAC3B,QAAQ;IACR,SAAS;CACV,CAAC,CAAC"}
@@ -1,4 +0,0 @@
1
- import { A2AMessage } from "./types.js";
2
- import { A2AMessagesEvent } from "./useA2AMessages.js";
3
- export declare const mockStreamCallbackFactory: (events: Array<A2AMessagesEvent<A2AMessage>>) => () => AsyncGenerator<import("./types").A2AEvent, void, unknown>;
4
- //# sourceMappingURL=testUtils.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"testUtils.d.ts","sourceRoot":"","sources":["../src/testUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,mBAAgB;AACrC,OAAO,EAAE,gBAAgB,EAAE,4BAAyB;AAEpD,eAAO,MAAM,yBAAyB,GACpC,QAAQ,KAAK,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC,oEAM1C,CAAC"}
package/dist/testUtils.js DELETED
@@ -1,6 +0,0 @@
1
- export const mockStreamCallbackFactory = (events) => async function* () {
2
- for (const event of events) {
3
- yield event;
4
- }
5
- };
6
- //# sourceMappingURL=testUtils.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"testUtils.js","sourceRoot":"","sources":["../src/testUtils.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,MAAM,yBAAyB,GAAG,CACvC,MAA2C,EAC3C,EAAE,CACF,KAAK,SAAS,CAAC;IACb,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC,CAAC"}
@@ -1,25 +0,0 @@
1
- import { A2AEvent, A2ATaskState, A2AArtifact, A2ASendMessageConfig, A2AStreamCallback, OnTaskUpdateEventCallback, OnArtifactsEventCallback, OnErrorEventCallback, OnStateUpdateEventCallback, OnCustomEventCallback } from "./types.js";
2
- export type A2AMessagesEvent<_TMessage> = A2AEvent;
3
- export declare const useA2AMessages: <TMessage extends {
4
- id?: string;
5
- }>({ stream, appendMessage, eventHandlers, }: {
6
- stream: A2AStreamCallback<TMessage>;
7
- appendMessage?: (prev: TMessage | undefined, curr: TMessage) => TMessage;
8
- eventHandlers?: {
9
- onTaskUpdate?: OnTaskUpdateEventCallback;
10
- onArtifacts?: OnArtifactsEventCallback;
11
- onError?: OnErrorEventCallback;
12
- onStateUpdate?: OnStateUpdateEventCallback;
13
- onCustomEvent?: OnCustomEventCallback;
14
- };
15
- }) => {
16
- messages: TMessage[];
17
- artifacts: A2AArtifact[];
18
- taskState: A2ATaskState | undefined;
19
- sendMessage: (newMessages: TMessage[], config: A2ASendMessageConfig) => Promise<void>;
20
- cancel: () => void;
21
- setMessages: import("react").Dispatch<import("react").SetStateAction<TMessage[]>>;
22
- setArtifacts: import("react").Dispatch<import("react").SetStateAction<A2AArtifact[]>>;
23
- setTaskState: import("react").Dispatch<import("react").SetStateAction<A2ATaskState | undefined>>;
24
- };
25
- //# sourceMappingURL=useA2AMessages.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useA2AMessages.d.ts","sourceRoot":"","sources":["../src/useA2AMessages.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,QAAQ,EAER,YAAY,EACZ,WAAW,EACX,oBAAoB,EACpB,iBAAiB,EACjB,yBAAyB,EACzB,wBAAwB,EACxB,oBAAoB,EACpB,0BAA0B,EAC1B,qBAAqB,EACtB,mBAAgB;AAEjB,MAAM,MAAM,gBAAgB,CAAC,SAAS,IAAI,QAAQ,CAAC;AAOnD,eAAO,MAAM,cAAc,GAAI,QAAQ,SAAS;IAAE,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,2CAI9D;IACD,MAAM,EAAE,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IACpC,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,EAAE,IAAI,EAAE,QAAQ,KAAK,QAAQ,CAAC;IACzE,aAAa,CAAC,EAAE;QACd,YAAY,CAAC,EAAE,yBAAyB,CAAC;QACzC,WAAW,CAAC,EAAE,wBAAwB,CAAC;QACvC,OAAO,CAAC,EAAE,oBAAoB,CAAC;QAC/B,aAAa,CAAC,EAAE,0BAA0B,CAAC;QAC3C,aAAa,CAAC,EAAE,qBAAqB,CAAC;KACvC,CAAC;CACH;;;;+BAUuB,QAAQ,EAAE,UAAU,oBAAoB;;;;;CAmI/D,CAAC"}
@@ -1,122 +0,0 @@
1
- import { useState, useCallback, useRef, useMemo } from "react";
2
- import { v4 as uuidv4 } from "uuid";
3
- import { A2AMessageAccumulator } from "./A2AMessageAccumulator.js";
4
- import { A2AKnownEventTypes, } from "./types.js";
5
- const DEFAULT_APPEND_MESSAGE = (_, curr) => curr;
6
- export const useA2AMessages = ({ stream, appendMessage = DEFAULT_APPEND_MESSAGE, eventHandlers, }) => {
7
- const [messages, setMessages] = useState([]);
8
- const [taskState, setTaskState] = useState();
9
- const [artifacts, setArtifacts] = useState([]);
10
- const abortControllerRef = useRef(null);
11
- const { onTaskUpdate, onArtifacts, onError, onStateUpdate, onCustomEvent } = useMemo(() => eventHandlers ?? {}, [eventHandlers]);
12
- const sendMessage = useCallback(async (newMessages, config) => {
13
- // ensure all messages have an ID
14
- const newMessagesWithId = newMessages.map((m) => m.id ? m : { ...m, id: uuidv4() });
15
- const accumulator = new A2AMessageAccumulator({
16
- initialMessages: messages,
17
- appendMessage,
18
- });
19
- setMessages(accumulator.addMessages(newMessagesWithId));
20
- const abortController = new AbortController();
21
- abortControllerRef.current = abortController;
22
- const response = await stream(newMessagesWithId, {
23
- ...config,
24
- abortSignal: abortController.signal,
25
- });
26
- for await (const event of response) {
27
- switch (event.event) {
28
- case A2AKnownEventTypes.TaskUpdate:
29
- const taskData = event.data;
30
- setTaskState(taskData);
31
- onTaskUpdate?.(taskData);
32
- break;
33
- case A2AKnownEventTypes.TaskComplete:
34
- // Extract messages and artifacts from completed task
35
- const { messages: taskMessages, artifacts: taskArtifacts } = event.data;
36
- if (taskMessages) {
37
- setMessages(accumulator.addMessages(taskMessages));
38
- }
39
- if (taskArtifacts) {
40
- setArtifacts(taskArtifacts);
41
- onArtifacts?.(taskArtifacts);
42
- }
43
- // Clear task state on completion
44
- setTaskState(undefined);
45
- break;
46
- case A2AKnownEventTypes.TaskFailed:
47
- onError?.(event.data);
48
- // Update task state to failed
49
- if (taskState) {
50
- setTaskState({
51
- ...taskState,
52
- state: "failed",
53
- message: event.data?.message,
54
- });
55
- }
56
- break;
57
- case A2AKnownEventTypes.Artifacts:
58
- const artifactData = event.data;
59
- setArtifacts(artifactData);
60
- onArtifacts?.(artifactData);
61
- break;
62
- case A2AKnownEventTypes.StateUpdate:
63
- onStateUpdate?.(event.data);
64
- break;
65
- case A2AKnownEventTypes.Error:
66
- onError?.(event.data);
67
- // Update the last assistant message with error status if available
68
- const messages = accumulator.getMessages();
69
- const lastAssistantMessage = messages.findLast((m) => m != null &&
70
- "role" in m &&
71
- m.role === "assistant" &&
72
- m.id != null);
73
- if (lastAssistantMessage) {
74
- const errorMessage = {
75
- ...lastAssistantMessage,
76
- status: {
77
- type: "incomplete",
78
- reason: "error",
79
- error: event.data,
80
- },
81
- };
82
- setMessages(accumulator.addMessages([errorMessage]));
83
- }
84
- break;
85
- default:
86
- if (onCustomEvent) {
87
- onCustomEvent(event.event, event.data);
88
- }
89
- else {
90
- console.warn("Unhandled A2A event received:", event.event, event.data);
91
- }
92
- break;
93
- }
94
- }
95
- }, [
96
- messages,
97
- appendMessage,
98
- stream,
99
- onTaskUpdate,
100
- onArtifacts,
101
- onError,
102
- onStateUpdate,
103
- onCustomEvent,
104
- taskState,
105
- ]);
106
- const cancel = useCallback(() => {
107
- if (abortControllerRef.current) {
108
- abortControllerRef.current.abort();
109
- }
110
- }, []);
111
- return {
112
- messages,
113
- artifacts,
114
- taskState,
115
- sendMessage,
116
- cancel,
117
- setMessages,
118
- setArtifacts,
119
- setTaskState,
120
- };
121
- };
122
- //# sourceMappingURL=useA2AMessages.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useA2AMessages.js","sourceRoot":"","sources":["../src/useA2AMessages.ts"],"names":[],"mappings":"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"}
@@ -1,48 +0,0 @@
1
- import { v4 as uuidv4 } from "uuid";
2
-
3
- export type A2AStateAccumulatorConfig<TMessage> = {
4
- initialMessages?: TMessage[];
5
- appendMessage?: (prev: TMessage | undefined, curr: TMessage) => TMessage;
6
- };
7
-
8
- export class A2AMessageAccumulator<TMessage extends { id?: string }> {
9
- private messagesMap = new Map<string, TMessage>();
10
- private appendMessage: (
11
- prev: TMessage | undefined,
12
- curr: TMessage,
13
- ) => TMessage;
14
-
15
- constructor({
16
- initialMessages = [],
17
- appendMessage = ((_: TMessage | undefined, curr: TMessage) => curr) as (
18
- prev: TMessage | undefined,
19
- curr: TMessage,
20
- ) => TMessage,
21
- }: A2AStateAccumulatorConfig<TMessage> = {}) {
22
- this.appendMessage = appendMessage;
23
- this.addMessages(initialMessages);
24
- }
25
-
26
- private ensureMessageId(message: TMessage): TMessage {
27
- return message.id ? message : { ...message, id: uuidv4() };
28
- }
29
-
30
- public addMessages(newMessages: TMessage[]) {
31
- if (newMessages.length === 0) return this.getMessages();
32
-
33
- for (const message of newMessages.map(this.ensureMessageId)) {
34
- const messageId = message.id!; // ensureMessageId guarantees id exists
35
- const previous = this.messagesMap.get(messageId);
36
- this.messagesMap.set(messageId, this.appendMessage(previous, message));
37
- }
38
- return this.getMessages();
39
- }
40
-
41
- public getMessages(): TMessage[] {
42
- return [...this.messagesMap.values()];
43
- }
44
-
45
- public clear() {
46
- this.messagesMap.clear();
47
- }
48
- }
@@ -1,121 +0,0 @@
1
- import { A2AMessage } from "./types";
2
- import { parsePartialJsonObject } from "assistant-stream/utils";
3
-
4
- export const appendA2AChunk = (
5
- prev: A2AMessage | undefined,
6
- curr: A2AMessage,
7
- ): A2AMessage => {
8
- // If no previous message or different message type, return current as-is
9
- if (!prev || prev.role !== curr.role || prev.id !== curr.id) {
10
- return curr;
11
- }
12
-
13
- // For assistant messages, we need to handle streaming content and tool calls
14
- if (curr.role === "assistant") {
15
- const newContent = Array.isArray(prev.content)
16
- ? [...prev.content]
17
- : typeof prev.content === "string"
18
- ? [{ type: "text" as const, text: prev.content }]
19
- : [];
20
-
21
- // Append new content chunks
22
- if (typeof curr.content === "string") {
23
- const lastIndex = newContent.length - 1;
24
- const lastPart = newContent[lastIndex];
25
-
26
- if (lastPart?.type === "text") {
27
- // Append to existing text part
28
- (lastPart as { type: "text"; text: string }).text += curr.content;
29
- } else {
30
- // Create new text part
31
- newContent.push({ type: "text", text: curr.content });
32
- }
33
- } else if (Array.isArray(curr.content)) {
34
- for (const contentPart of curr.content) {
35
- const lastIndex = newContent.length - 1;
36
- const lastPart = newContent[lastIndex];
37
-
38
- if (contentPart.type === "text" && lastPart?.type === "text") {
39
- // Append to existing text part
40
- (lastPart as { type: "text"; text: string }).text += contentPart.text;
41
- } else {
42
- // Add new content part
43
- newContent.push(contentPart);
44
- }
45
- }
46
- }
47
-
48
- // Merge tool calls - A2A typically sends complete tool calls rather than chunks
49
- const newToolCalls = [...(prev.tool_calls ?? [])];
50
- if (curr.tool_calls) {
51
- for (const toolCall of curr.tool_calls) {
52
- const existingIndex = newToolCalls.findIndex(
53
- (tc) => tc.id === toolCall.id,
54
- );
55
- if (existingIndex >= 0) {
56
- // Update existing tool call (merge args if needed)
57
- const existing = newToolCalls[existingIndex]!;
58
- newToolCalls[existingIndex] = {
59
- ...existing,
60
- ...toolCall,
61
- // If argsText is provided in chunks, concatenate it
62
- argsText: (existing.argsText || "") + (toolCall.argsText || ""),
63
- // Try to parse merged args, fallback to existing or new args
64
- args:
65
- parsePartialJsonObject(
66
- (existing.argsText || "") + (toolCall.argsText || ""),
67
- ) ||
68
- toolCall.args ||
69
- existing.args,
70
- };
71
- } else {
72
- // Add new tool call
73
- newToolCalls.push(toolCall);
74
- }
75
- }
76
- }
77
-
78
- // Merge artifacts
79
- const newArtifacts = [...(prev.artifacts ?? [])];
80
- if (curr.artifacts) {
81
- for (const artifact of curr.artifacts) {
82
- const existingIndex = newArtifacts.findIndex(
83
- (a) => a.name === artifact.name,
84
- );
85
- if (existingIndex >= 0) {
86
- // Merge artifact parts
87
- const existingArtifact = newArtifacts[existingIndex]!;
88
- newArtifacts[existingIndex] = {
89
- name: existingArtifact.name,
90
- parts: [...existingArtifact.parts, ...artifact.parts],
91
- };
92
- } else {
93
- // Add new artifact
94
- newArtifacts.push(artifact);
95
- }
96
- }
97
- }
98
-
99
- const result: A2AMessage = {
100
- ...prev,
101
- content: newContent,
102
- };
103
- const newStatus = curr.status || prev.status;
104
- if (newStatus) result.status = newStatus;
105
- if (newToolCalls.length > 0) result.tool_calls = newToolCalls;
106
- if (newArtifacts.length > 0) result.artifacts = newArtifacts;
107
- return result;
108
- }
109
-
110
- // For other message types (user, system, tool), just return the current message
111
- // as they typically don't stream in chunks
112
- const result: A2AMessage = {
113
- ...prev,
114
- ...curr,
115
- };
116
- // Preserve any existing artifacts and merge with new ones
117
- if (curr.artifacts || prev.artifacts) {
118
- result.artifacts = [...(prev.artifacts ?? []), ...(curr.artifacts ?? [])];
119
- }
120
- return result;
121
- };