@mailmodo/a2a 0.3.5 → 0.3.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.
- package/README.md +171 -93
- package/dist/{a2a_request_handler-DQfg1Q-R.d.ts → a2a_request_handler-1Isk3l-0.d.mts} +16 -4
- package/dist/{a2a_request_handler-DPkhsCMt.d.mts → a2a_request_handler-BuP9LgXH.d.ts} +16 -4
- package/dist/chunk-7JFJW6P6.mjs +38 -0
- package/dist/{chunk-LVD4GF26.mjs → chunk-AZGEDUZX.mjs} +6 -7
- package/dist/chunk-BNBEZNW7.mjs +122 -0
- package/dist/client/index.d.mts +401 -47
- package/dist/client/index.d.ts +401 -47
- package/dist/client/index.js +525 -78
- package/dist/client/index.mjs +1110 -29
- package/dist/{types-Due_Cv6t.d.mts → extensions-DvruCIzw.d.mts} +40 -1
- package/dist/{types-Due_Cv6t.d.ts → extensions-DvruCIzw.d.ts} +40 -1
- package/dist/index.d.mts +5 -33
- package/dist/index.d.ts +5 -33
- package/dist/index.js +27 -2083
- package/dist/index.mjs +6 -42
- package/dist/server/express/index.d.mts +76 -4
- package/dist/server/express/index.d.ts +76 -4
- package/dist/server/express/index.js +563 -37
- package/dist/server/express/index.mjs +642 -6
- package/dist/server/index.d.mts +296 -6
- package/dist/server/index.d.ts +296 -6
- package/dist/server/index.js +265 -52
- package/dist/server/index.mjs +1050 -12
- package/package.json +39 -17
- package/dist/auth-handler-DVLcl8yj.d.mts +0 -209
- package/dist/auth-handler-Gzpf3xHC.d.ts +0 -209
- package/dist/chunk-HZFUOBJQ.mjs +0 -198
- package/dist/chunk-LIEYEFQG.mjs +0 -879
- package/dist/chunk-UBRSFN2J.mjs +0 -776
- package/dist/error-DExKs0Q3.d.mts +0 -233
- package/dist/error-j1vYKII2.d.ts +0 -233
package/dist/client/index.js
CHANGED
|
@@ -21,20 +21,48 @@ var client_exports = {};
|
|
|
21
21
|
__export(client_exports, {
|
|
22
22
|
A2AClient: () => A2AClient,
|
|
23
23
|
AgentCardResolver: () => AgentCardResolver,
|
|
24
|
+
AuthenticatedExtendedCardNotConfiguredError: () => AuthenticatedExtendedCardNotConfiguredError,
|
|
24
25
|
Client: () => Client,
|
|
26
|
+
ClientCallContext: () => ClientCallContext,
|
|
27
|
+
ClientCallContextKey: () => ClientCallContextKey,
|
|
25
28
|
ClientFactory: () => ClientFactory,
|
|
26
29
|
ClientFactoryOptions: () => ClientFactoryOptions,
|
|
30
|
+
ContentTypeNotSupportedError: () => ContentTypeNotSupportedError,
|
|
27
31
|
DefaultAgentCardResolver: () => DefaultAgentCardResolver,
|
|
32
|
+
InvalidAgentResponseError: () => InvalidAgentResponseError,
|
|
28
33
|
JsonRpcTransport: () => JsonRpcTransport,
|
|
29
34
|
JsonRpcTransportFactory: () => JsonRpcTransportFactory,
|
|
30
|
-
|
|
35
|
+
PushNotificationNotSupportedError: () => PushNotificationNotSupportedError,
|
|
36
|
+
RestTransport: () => RestTransport,
|
|
37
|
+
RestTransportFactory: () => RestTransportFactory,
|
|
38
|
+
ServiceParameters: () => ServiceParameters,
|
|
39
|
+
TaskNotCancelableError: () => TaskNotCancelableError,
|
|
40
|
+
TaskNotFoundError: () => TaskNotFoundError,
|
|
41
|
+
UnsupportedOperationError: () => UnsupportedOperationError,
|
|
42
|
+
createAuthenticatingFetchWithRetry: () => createAuthenticatingFetchWithRetry,
|
|
43
|
+
withA2AExtensions: () => withA2AExtensions
|
|
31
44
|
});
|
|
32
45
|
module.exports = __toCommonJS(client_exports);
|
|
33
46
|
|
|
34
47
|
// src/constants.ts
|
|
35
48
|
var AGENT_CARD_PATH = ".well-known/agent-card.json";
|
|
49
|
+
var HTTP_EXTENSION_HEADER = "X-A2A-Extensions";
|
|
36
50
|
|
|
37
51
|
// src/errors.ts
|
|
52
|
+
var A2A_ERROR_CODE = {
|
|
53
|
+
PARSE_ERROR: -32700,
|
|
54
|
+
INVALID_REQUEST: -32600,
|
|
55
|
+
METHOD_NOT_FOUND: -32601,
|
|
56
|
+
INVALID_PARAMS: -32602,
|
|
57
|
+
INTERNAL_ERROR: -32603,
|
|
58
|
+
TASK_NOT_FOUND: -32001,
|
|
59
|
+
TASK_NOT_CANCELABLE: -32002,
|
|
60
|
+
PUSH_NOTIFICATION_NOT_SUPPORTED: -32003,
|
|
61
|
+
UNSUPPORTED_OPERATION: -32004,
|
|
62
|
+
CONTENT_TYPE_NOT_SUPPORTED: -32005,
|
|
63
|
+
INVALID_AGENT_RESPONSE: -32006,
|
|
64
|
+
AUTHENTICATED_EXTENDED_CARD_NOT_CONFIGURED: -32007
|
|
65
|
+
};
|
|
38
66
|
var TaskNotFoundError = class extends Error {
|
|
39
67
|
constructor(message) {
|
|
40
68
|
super(message ?? "Task not found");
|
|
@@ -78,6 +106,38 @@ var AuthenticatedExtendedCardNotConfiguredError = class extends Error {
|
|
|
78
106
|
}
|
|
79
107
|
};
|
|
80
108
|
|
|
109
|
+
// src/sse_utils.ts
|
|
110
|
+
async function* parseSseStream(response) {
|
|
111
|
+
if (!response.body) {
|
|
112
|
+
throw new Error("SSE response body is undefined. Cannot read stream.");
|
|
113
|
+
}
|
|
114
|
+
let buffer = "";
|
|
115
|
+
let eventType = "message";
|
|
116
|
+
let eventData = "";
|
|
117
|
+
for await (const value of response.body.pipeThrough(new TextDecoderStream())) {
|
|
118
|
+
buffer += value;
|
|
119
|
+
let lineEndIndex;
|
|
120
|
+
while ((lineEndIndex = buffer.indexOf("\n")) >= 0) {
|
|
121
|
+
const line = buffer.substring(0, lineEndIndex).trim();
|
|
122
|
+
buffer = buffer.substring(lineEndIndex + 1);
|
|
123
|
+
if (line === "") {
|
|
124
|
+
if (eventData) {
|
|
125
|
+
yield { type: eventType, data: eventData };
|
|
126
|
+
eventData = "";
|
|
127
|
+
eventType = "message";
|
|
128
|
+
}
|
|
129
|
+
} else if (line.startsWith("event:")) {
|
|
130
|
+
eventType = line.substring("event:".length).trim();
|
|
131
|
+
} else if (line.startsWith("data:")) {
|
|
132
|
+
eventData = line.substring("data:".length).trim();
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (eventData) {
|
|
137
|
+
yield { type: eventType, data: eventData };
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
81
141
|
// src/client/transports/json_rpc_transport.ts
|
|
82
142
|
var JsonRpcTransport = class _JsonRpcTransport {
|
|
83
143
|
customFetchImpl;
|
|
@@ -87,6 +147,10 @@ var JsonRpcTransport = class _JsonRpcTransport {
|
|
|
87
147
|
this.endpoint = options.endpoint;
|
|
88
148
|
this.customFetchImpl = options.fetchImpl;
|
|
89
149
|
}
|
|
150
|
+
async getExtendedAgentCard(options, idOverride) {
|
|
151
|
+
const rpcResponse = await this._sendRpcRequest("agent/getAuthenticatedExtendedCard", void 0, idOverride, options);
|
|
152
|
+
return rpcResponse.result;
|
|
153
|
+
}
|
|
90
154
|
async sendMessage(params, options, idOverride) {
|
|
91
155
|
const rpcResponse = await this._sendRpcRequest(
|
|
92
156
|
"message/send",
|
|
@@ -162,7 +226,7 @@ var JsonRpcTransport = class _JsonRpcTransport {
|
|
|
162
226
|
params,
|
|
163
227
|
id: requestId
|
|
164
228
|
};
|
|
165
|
-
const httpResponse = await this._fetchRpc(rpcRequest, "application/json", options
|
|
229
|
+
const httpResponse = await this._fetchRpc(rpcRequest, "application/json", options);
|
|
166
230
|
if (!httpResponse.ok) {
|
|
167
231
|
let errorBodyText = "(empty or non-JSON response)";
|
|
168
232
|
let errorJson;
|
|
@@ -194,15 +258,16 @@ var JsonRpcTransport = class _JsonRpcTransport {
|
|
|
194
258
|
}
|
|
195
259
|
return rpcResponse;
|
|
196
260
|
}
|
|
197
|
-
async _fetchRpc(rpcRequest, acceptHeader = "application/json",
|
|
261
|
+
async _fetchRpc(rpcRequest, acceptHeader = "application/json", options) {
|
|
198
262
|
const requestInit = {
|
|
199
263
|
method: "POST",
|
|
200
264
|
headers: {
|
|
265
|
+
...options?.serviceParameters,
|
|
201
266
|
"Content-Type": "application/json",
|
|
202
267
|
Accept: acceptHeader
|
|
203
268
|
},
|
|
204
269
|
body: JSON.stringify(rpcRequest),
|
|
205
|
-
signal
|
|
270
|
+
signal: options?.signal
|
|
206
271
|
};
|
|
207
272
|
return this._fetch(this.endpoint, requestInit);
|
|
208
273
|
}
|
|
@@ -214,7 +279,7 @@ var JsonRpcTransport = class _JsonRpcTransport {
|
|
|
214
279
|
params,
|
|
215
280
|
id: clientRequestId
|
|
216
281
|
};
|
|
217
|
-
const response = await this._fetchRpc(rpcRequest, "text/event-stream", options
|
|
282
|
+
const response = await this._fetchRpc(rpcRequest, "text/event-stream", options);
|
|
218
283
|
if (!response.ok) {
|
|
219
284
|
let errorBody = "";
|
|
220
285
|
let errorJson;
|
|
@@ -241,55 +306,8 @@ var JsonRpcTransport = class _JsonRpcTransport {
|
|
|
241
306
|
`Invalid response Content-Type for SSE stream for ${method}. Expected 'text/event-stream'.`
|
|
242
307
|
);
|
|
243
308
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
async *_parseA2ASseStream(response, originalRequestId) {
|
|
247
|
-
if (!response.body) {
|
|
248
|
-
throw new Error("SSE response body is undefined. Cannot read stream.");
|
|
249
|
-
}
|
|
250
|
-
const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
|
|
251
|
-
let buffer = "";
|
|
252
|
-
let eventDataBuffer = "";
|
|
253
|
-
try {
|
|
254
|
-
while (true) {
|
|
255
|
-
const { done, value } = await reader.read();
|
|
256
|
-
if (done) {
|
|
257
|
-
if (eventDataBuffer.trim()) {
|
|
258
|
-
const result = this._processSseEventData(
|
|
259
|
-
eventDataBuffer,
|
|
260
|
-
originalRequestId
|
|
261
|
-
);
|
|
262
|
-
yield result;
|
|
263
|
-
}
|
|
264
|
-
break;
|
|
265
|
-
}
|
|
266
|
-
buffer += value;
|
|
267
|
-
let lineEndIndex;
|
|
268
|
-
while ((lineEndIndex = buffer.indexOf("\n")) >= 0) {
|
|
269
|
-
const line = buffer.substring(0, lineEndIndex).trim();
|
|
270
|
-
buffer = buffer.substring(lineEndIndex + 1);
|
|
271
|
-
if (line === "") {
|
|
272
|
-
if (eventDataBuffer) {
|
|
273
|
-
const result = this._processSseEventData(
|
|
274
|
-
eventDataBuffer,
|
|
275
|
-
originalRequestId
|
|
276
|
-
);
|
|
277
|
-
yield result;
|
|
278
|
-
eventDataBuffer = "";
|
|
279
|
-
}
|
|
280
|
-
} else if (line.startsWith("data:")) {
|
|
281
|
-
eventDataBuffer += line.substring(5).trimStart() + "\n";
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
} catch (error) {
|
|
286
|
-
console.error(
|
|
287
|
-
"Error reading or parsing SSE stream:",
|
|
288
|
-
error instanceof Error && error.message || "Error unknown"
|
|
289
|
-
);
|
|
290
|
-
throw error;
|
|
291
|
-
} finally {
|
|
292
|
-
reader.releaseLock();
|
|
309
|
+
for await (const event of parseSseStream(response)) {
|
|
310
|
+
yield this._processSseEventData(event.data, clientRequestId);
|
|
293
311
|
}
|
|
294
312
|
}
|
|
295
313
|
_processSseEventData(jsonData, originalRequestId) {
|
|
@@ -297,7 +315,7 @@ var JsonRpcTransport = class _JsonRpcTransport {
|
|
|
297
315
|
throw new Error("Attempted to process empty SSE event data.");
|
|
298
316
|
}
|
|
299
317
|
try {
|
|
300
|
-
const sseJsonRpcResponse = JSON.parse(jsonData
|
|
318
|
+
const sseJsonRpcResponse = JSON.parse(jsonData);
|
|
301
319
|
const a2aStreamResponse = sseJsonRpcResponse;
|
|
302
320
|
if (a2aStreamResponse.id !== originalRequestId) {
|
|
303
321
|
console.warn(
|
|
@@ -827,7 +845,7 @@ var DefaultAgentCardResolver = class {
|
|
|
827
845
|
}
|
|
828
846
|
};
|
|
829
847
|
var AgentCardResolver = {
|
|
830
|
-
|
|
848
|
+
default: new DefaultAgentCardResolver()
|
|
831
849
|
};
|
|
832
850
|
|
|
833
851
|
// src/client/multitransport-client.ts
|
|
@@ -837,6 +855,20 @@ var Client = class {
|
|
|
837
855
|
this.agentCard = agentCard;
|
|
838
856
|
this.config = config;
|
|
839
857
|
}
|
|
858
|
+
/**
|
|
859
|
+
* If the current agent card supports the extended feature, it will try to fetch the extended agent card from the server,
|
|
860
|
+
* Otherwise it will return the current agent card value.
|
|
861
|
+
*/
|
|
862
|
+
async getAgentCard(options) {
|
|
863
|
+
if (this.agentCard.supportsAuthenticatedExtendedCard) {
|
|
864
|
+
this.agentCard = await this.executeWithInterceptors(
|
|
865
|
+
{ method: "getAgentCard" },
|
|
866
|
+
options,
|
|
867
|
+
(_, options2) => this.transport.getExtendedAgentCard(options2)
|
|
868
|
+
);
|
|
869
|
+
}
|
|
870
|
+
return this.agentCard;
|
|
871
|
+
}
|
|
840
872
|
/**
|
|
841
873
|
* Sends a message to an agent to initiate a new interaction or to continue an existing one.
|
|
842
874
|
* Uses blocking mode by default.
|
|
@@ -861,6 +893,7 @@ var Client = class {
|
|
|
861
893
|
params = this.applyClientConfig({ params, blocking: true });
|
|
862
894
|
const beforeArgs = {
|
|
863
895
|
input: { method, value: params },
|
|
896
|
+
agentCard: this.agentCard,
|
|
864
897
|
options
|
|
865
898
|
};
|
|
866
899
|
const beforeResult = await this.interceptBefore(beforeArgs);
|
|
@@ -868,6 +901,7 @@ var Client = class {
|
|
|
868
901
|
const earlyReturn = beforeResult.earlyReturn.value;
|
|
869
902
|
const afterArgs = {
|
|
870
903
|
result: { method, value: earlyReturn },
|
|
904
|
+
agentCard: this.agentCard,
|
|
871
905
|
options: beforeArgs.options
|
|
872
906
|
};
|
|
873
907
|
await this.interceptAfter(afterArgs, beforeResult.executed);
|
|
@@ -878,6 +912,7 @@ var Client = class {
|
|
|
878
912
|
const result = await this.transport.sendMessage(beforeArgs.input.value, beforeArgs.options);
|
|
879
913
|
const afterArgs = {
|
|
880
914
|
result: { method, value: result },
|
|
915
|
+
agentCard: this.agentCard,
|
|
881
916
|
options: beforeArgs.options
|
|
882
917
|
};
|
|
883
918
|
await this.interceptAfter(afterArgs);
|
|
@@ -890,6 +925,7 @@ var Client = class {
|
|
|
890
925
|
)) {
|
|
891
926
|
const afterArgs = {
|
|
892
927
|
result: { method, value: event },
|
|
928
|
+
agentCard: this.agentCard,
|
|
893
929
|
options: beforeArgs.options
|
|
894
930
|
};
|
|
895
931
|
await this.interceptAfter(afterArgs);
|
|
@@ -977,12 +1013,17 @@ var Client = class {
|
|
|
977
1013
|
*/
|
|
978
1014
|
async *resubscribeTask(params, options) {
|
|
979
1015
|
const method = "resubscribeTask";
|
|
980
|
-
const beforeArgs = {
|
|
1016
|
+
const beforeArgs = {
|
|
1017
|
+
input: { method, value: params },
|
|
1018
|
+
agentCard: this.agentCard,
|
|
1019
|
+
options
|
|
1020
|
+
};
|
|
981
1021
|
const beforeResult = await this.interceptBefore(beforeArgs);
|
|
982
1022
|
if (beforeResult) {
|
|
983
1023
|
const earlyReturn = beforeResult.earlyReturn.value;
|
|
984
1024
|
const afterArgs = {
|
|
985
1025
|
result: { method, value: earlyReturn },
|
|
1026
|
+
agentCard: this.agentCard,
|
|
986
1027
|
options: beforeArgs.options
|
|
987
1028
|
};
|
|
988
1029
|
await this.interceptAfter(afterArgs, beforeResult.executed);
|
|
@@ -995,6 +1036,7 @@ var Client = class {
|
|
|
995
1036
|
)) {
|
|
996
1037
|
const afterArgs = {
|
|
997
1038
|
result: { method, value: event },
|
|
1039
|
+
agentCard: this.agentCard,
|
|
998
1040
|
options: beforeArgs.options
|
|
999
1041
|
};
|
|
1000
1042
|
await this.interceptAfter(afterArgs);
|
|
@@ -1021,6 +1063,7 @@ var Client = class {
|
|
|
1021
1063
|
async executeWithInterceptors(input, options, transportCall) {
|
|
1022
1064
|
const beforeArgs = {
|
|
1023
1065
|
input,
|
|
1066
|
+
agentCard: this.agentCard,
|
|
1024
1067
|
options
|
|
1025
1068
|
};
|
|
1026
1069
|
const beforeResult = await this.interceptBefore(beforeArgs);
|
|
@@ -1030,6 +1073,7 @@ var Client = class {
|
|
|
1030
1073
|
method: input.method,
|
|
1031
1074
|
value: beforeResult.earlyReturn.value
|
|
1032
1075
|
},
|
|
1076
|
+
agentCard: this.agentCard,
|
|
1033
1077
|
options: beforeArgs.options
|
|
1034
1078
|
};
|
|
1035
1079
|
await this.interceptAfter(afterArgs2, beforeResult.executed);
|
|
@@ -1038,6 +1082,7 @@ var Client = class {
|
|
|
1038
1082
|
const result = await transportCall(beforeArgs.input.value, beforeArgs.options);
|
|
1039
1083
|
const afterArgs = {
|
|
1040
1084
|
result: { method: input.method, value: result },
|
|
1085
|
+
agentCard: this.agentCard,
|
|
1041
1086
|
options: beforeArgs.options
|
|
1042
1087
|
};
|
|
1043
1088
|
await this.interceptAfter(afterArgs);
|
|
@@ -1060,10 +1105,8 @@ var Client = class {
|
|
|
1060
1105
|
}
|
|
1061
1106
|
}
|
|
1062
1107
|
async interceptAfter(args, interceptors) {
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
}
|
|
1066
|
-
for (const interceptor of interceptors ?? this.config.interceptors) {
|
|
1108
|
+
const reversedInterceptors = [...interceptors ?? this.config?.interceptors ?? []].reverse();
|
|
1109
|
+
for (const interceptor of reversedInterceptors) {
|
|
1067
1110
|
await interceptor.after(args);
|
|
1068
1111
|
if (args.earlyReturn) {
|
|
1069
1112
|
return;
|
|
@@ -1072,35 +1115,283 @@ var Client = class {
|
|
|
1072
1115
|
}
|
|
1073
1116
|
};
|
|
1074
1117
|
|
|
1118
|
+
// src/client/transports/rest_transport.ts
|
|
1119
|
+
var RestTransport = class _RestTransport {
|
|
1120
|
+
customFetchImpl;
|
|
1121
|
+
endpoint;
|
|
1122
|
+
constructor(options) {
|
|
1123
|
+
this.endpoint = options.endpoint.replace(/\/+$/, "");
|
|
1124
|
+
this.customFetchImpl = options.fetchImpl;
|
|
1125
|
+
}
|
|
1126
|
+
async getExtendedAgentCard(options) {
|
|
1127
|
+
return this._sendRequest("GET", "/v1/card", void 0, options);
|
|
1128
|
+
}
|
|
1129
|
+
async sendMessage(params, options) {
|
|
1130
|
+
return this._sendRequest("POST", "/v1/message:send", params, options);
|
|
1131
|
+
}
|
|
1132
|
+
async *sendMessageStream(params, options) {
|
|
1133
|
+
yield* this._sendStreamingRequest("/v1/message:stream", params, options);
|
|
1134
|
+
}
|
|
1135
|
+
async setTaskPushNotificationConfig(params, options) {
|
|
1136
|
+
return this._sendRequest(
|
|
1137
|
+
"POST",
|
|
1138
|
+
`/v1/tasks/${encodeURIComponent(params.taskId)}/pushNotificationConfigs`,
|
|
1139
|
+
{
|
|
1140
|
+
pushNotificationConfig: params.pushNotificationConfig
|
|
1141
|
+
},
|
|
1142
|
+
options
|
|
1143
|
+
);
|
|
1144
|
+
}
|
|
1145
|
+
async getTaskPushNotificationConfig(params, options) {
|
|
1146
|
+
const { pushNotificationConfigId } = params;
|
|
1147
|
+
if (!pushNotificationConfigId) {
|
|
1148
|
+
throw new Error(
|
|
1149
|
+
"pushNotificationConfigId is required for getTaskPushNotificationConfig with REST transport."
|
|
1150
|
+
);
|
|
1151
|
+
}
|
|
1152
|
+
return this._sendRequest(
|
|
1153
|
+
"GET",
|
|
1154
|
+
`/v1/tasks/${encodeURIComponent(params.id)}/pushNotificationConfigs/${encodeURIComponent(pushNotificationConfigId)}`,
|
|
1155
|
+
void 0,
|
|
1156
|
+
options
|
|
1157
|
+
);
|
|
1158
|
+
}
|
|
1159
|
+
async listTaskPushNotificationConfig(params, options) {
|
|
1160
|
+
return this._sendRequest(
|
|
1161
|
+
"GET",
|
|
1162
|
+
`/v1/tasks/${encodeURIComponent(params.id)}/pushNotificationConfigs`,
|
|
1163
|
+
void 0,
|
|
1164
|
+
options
|
|
1165
|
+
);
|
|
1166
|
+
}
|
|
1167
|
+
async deleteTaskPushNotificationConfig(params, options) {
|
|
1168
|
+
await this._sendRequest(
|
|
1169
|
+
"DELETE",
|
|
1170
|
+
`/v1/tasks/${encodeURIComponent(params.id)}/pushNotificationConfigs/${encodeURIComponent(params.pushNotificationConfigId)}`,
|
|
1171
|
+
void 0,
|
|
1172
|
+
options
|
|
1173
|
+
);
|
|
1174
|
+
}
|
|
1175
|
+
async getTask(params, options) {
|
|
1176
|
+
const queryParams = new URLSearchParams();
|
|
1177
|
+
if (params.historyLength !== void 0) {
|
|
1178
|
+
queryParams.set("historyLength", String(params.historyLength));
|
|
1179
|
+
}
|
|
1180
|
+
const queryString = queryParams.toString();
|
|
1181
|
+
const path = `/v1/tasks/${encodeURIComponent(params.id)}${queryString ? `?${queryString}` : ""}`;
|
|
1182
|
+
return this._sendRequest("GET", path, void 0, options);
|
|
1183
|
+
}
|
|
1184
|
+
async cancelTask(params, options) {
|
|
1185
|
+
return this._sendRequest(
|
|
1186
|
+
"POST",
|
|
1187
|
+
`/v1/tasks/${encodeURIComponent(params.id)}:cancel`,
|
|
1188
|
+
void 0,
|
|
1189
|
+
options
|
|
1190
|
+
);
|
|
1191
|
+
}
|
|
1192
|
+
async *resubscribeTask(params, options) {
|
|
1193
|
+
yield* this._sendStreamingRequest(
|
|
1194
|
+
`/v1/tasks/${encodeURIComponent(params.id)}:subscribe`,
|
|
1195
|
+
void 0,
|
|
1196
|
+
options
|
|
1197
|
+
);
|
|
1198
|
+
}
|
|
1199
|
+
_fetch(...args) {
|
|
1200
|
+
if (this.customFetchImpl) {
|
|
1201
|
+
return this.customFetchImpl(...args);
|
|
1202
|
+
}
|
|
1203
|
+
if (typeof fetch === "function") {
|
|
1204
|
+
return fetch(...args);
|
|
1205
|
+
}
|
|
1206
|
+
throw new Error(
|
|
1207
|
+
"A `fetch` implementation was not provided and is not available in the global scope. Please provide a `fetchImpl` in the RestTransportOptions."
|
|
1208
|
+
);
|
|
1209
|
+
}
|
|
1210
|
+
_buildHeaders(options, acceptHeader = "application/json") {
|
|
1211
|
+
return {
|
|
1212
|
+
...options?.serviceParameters,
|
|
1213
|
+
"Content-Type": "application/json",
|
|
1214
|
+
Accept: acceptHeader
|
|
1215
|
+
};
|
|
1216
|
+
}
|
|
1217
|
+
async _sendRequest(method, path, body, options) {
|
|
1218
|
+
const url = `${this.endpoint}${path}`;
|
|
1219
|
+
const requestInit = {
|
|
1220
|
+
method,
|
|
1221
|
+
headers: this._buildHeaders(options),
|
|
1222
|
+
signal: options?.signal
|
|
1223
|
+
};
|
|
1224
|
+
if (body !== void 0 && method !== "GET") {
|
|
1225
|
+
requestInit.body = JSON.stringify(body);
|
|
1226
|
+
}
|
|
1227
|
+
const response = await this._fetch(url, requestInit);
|
|
1228
|
+
if (!response.ok) {
|
|
1229
|
+
await this._handleErrorResponse(response, path);
|
|
1230
|
+
}
|
|
1231
|
+
if (response.status === 204) {
|
|
1232
|
+
return void 0;
|
|
1233
|
+
}
|
|
1234
|
+
const result = await response.json();
|
|
1235
|
+
return result;
|
|
1236
|
+
}
|
|
1237
|
+
async _handleErrorResponse(response, path) {
|
|
1238
|
+
let errorBodyText = "(empty or non-JSON response)";
|
|
1239
|
+
let errorBody;
|
|
1240
|
+
try {
|
|
1241
|
+
errorBodyText = await response.text();
|
|
1242
|
+
if (errorBodyText) {
|
|
1243
|
+
errorBody = JSON.parse(errorBodyText);
|
|
1244
|
+
}
|
|
1245
|
+
} catch (e) {
|
|
1246
|
+
throw new Error(
|
|
1247
|
+
`HTTP error for ${path}! Status: ${response.status} ${response.statusText}. Response: ${errorBodyText}`,
|
|
1248
|
+
{ cause: e }
|
|
1249
|
+
);
|
|
1250
|
+
}
|
|
1251
|
+
if (errorBody && typeof errorBody.code === "number") {
|
|
1252
|
+
throw _RestTransport.mapToError(errorBody);
|
|
1253
|
+
}
|
|
1254
|
+
throw new Error(
|
|
1255
|
+
`HTTP error for ${path}! Status: ${response.status} ${response.statusText}. Response: ${errorBodyText}`
|
|
1256
|
+
);
|
|
1257
|
+
}
|
|
1258
|
+
async *_sendStreamingRequest(path, body, options) {
|
|
1259
|
+
const url = `${this.endpoint}${path}`;
|
|
1260
|
+
const requestInit = {
|
|
1261
|
+
method: "POST",
|
|
1262
|
+
headers: this._buildHeaders(options, "text/event-stream"),
|
|
1263
|
+
signal: options?.signal
|
|
1264
|
+
};
|
|
1265
|
+
if (body !== void 0) {
|
|
1266
|
+
requestInit.body = JSON.stringify(body);
|
|
1267
|
+
}
|
|
1268
|
+
const response = await this._fetch(url, requestInit);
|
|
1269
|
+
if (!response.ok) {
|
|
1270
|
+
await this._handleErrorResponse(response, path);
|
|
1271
|
+
}
|
|
1272
|
+
const contentType = response.headers.get("Content-Type");
|
|
1273
|
+
if (!contentType?.startsWith("text/event-stream")) {
|
|
1274
|
+
throw new Error(
|
|
1275
|
+
`Invalid response Content-Type for SSE stream. Expected 'text/event-stream', got '${contentType}'.`
|
|
1276
|
+
);
|
|
1277
|
+
}
|
|
1278
|
+
for await (const event of parseSseStream(response)) {
|
|
1279
|
+
if (event.type === "error") {
|
|
1280
|
+
const errorData = JSON.parse(event.data);
|
|
1281
|
+
throw _RestTransport.mapToError(errorData);
|
|
1282
|
+
}
|
|
1283
|
+
yield this._processSseEventData(event.data);
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
_processSseEventData(jsonData) {
|
|
1287
|
+
if (!jsonData.trim()) {
|
|
1288
|
+
throw new Error("Attempted to process empty SSE event data.");
|
|
1289
|
+
}
|
|
1290
|
+
try {
|
|
1291
|
+
const data = JSON.parse(jsonData);
|
|
1292
|
+
return data;
|
|
1293
|
+
} catch (e) {
|
|
1294
|
+
console.error("Failed to parse SSE event data:", jsonData, e);
|
|
1295
|
+
throw new Error(
|
|
1296
|
+
`Failed to parse SSE event data: "${jsonData.substring(0, 100)}...". Original error: ${e instanceof Error && e.message || "Unknown error"}`
|
|
1297
|
+
);
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
static mapToError(error) {
|
|
1301
|
+
switch (error.code) {
|
|
1302
|
+
case A2A_ERROR_CODE.TASK_NOT_FOUND:
|
|
1303
|
+
return new TaskNotFoundError(error.message);
|
|
1304
|
+
case A2A_ERROR_CODE.TASK_NOT_CANCELABLE:
|
|
1305
|
+
return new TaskNotCancelableError(error.message);
|
|
1306
|
+
case A2A_ERROR_CODE.PUSH_NOTIFICATION_NOT_SUPPORTED:
|
|
1307
|
+
return new PushNotificationNotSupportedError(error.message);
|
|
1308
|
+
case A2A_ERROR_CODE.UNSUPPORTED_OPERATION:
|
|
1309
|
+
return new UnsupportedOperationError(error.message);
|
|
1310
|
+
case A2A_ERROR_CODE.CONTENT_TYPE_NOT_SUPPORTED:
|
|
1311
|
+
return new ContentTypeNotSupportedError(error.message);
|
|
1312
|
+
case A2A_ERROR_CODE.INVALID_AGENT_RESPONSE:
|
|
1313
|
+
return new InvalidAgentResponseError(error.message);
|
|
1314
|
+
case A2A_ERROR_CODE.AUTHENTICATED_EXTENDED_CARD_NOT_CONFIGURED:
|
|
1315
|
+
return new AuthenticatedExtendedCardNotConfiguredError(error.message);
|
|
1316
|
+
default:
|
|
1317
|
+
return new Error(
|
|
1318
|
+
`REST error: ${error.message} (Code: ${error.code})${error.data ? ` Data: ${JSON.stringify(error.data)}` : ""}`
|
|
1319
|
+
);
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
};
|
|
1323
|
+
var RestTransportFactory = class _RestTransportFactory {
|
|
1324
|
+
constructor(options) {
|
|
1325
|
+
this.options = options;
|
|
1326
|
+
}
|
|
1327
|
+
static name = "HTTP+JSON";
|
|
1328
|
+
get protocolName() {
|
|
1329
|
+
return _RestTransportFactory.name;
|
|
1330
|
+
}
|
|
1331
|
+
async create(url, _agentCard) {
|
|
1332
|
+
return new RestTransport({
|
|
1333
|
+
endpoint: url,
|
|
1334
|
+
fetchImpl: this.options?.fetchImpl
|
|
1335
|
+
});
|
|
1336
|
+
}
|
|
1337
|
+
};
|
|
1338
|
+
|
|
1075
1339
|
// src/client/factory.ts
|
|
1076
1340
|
var ClientFactoryOptions = {
|
|
1077
|
-
|
|
1078
|
-
|
|
1341
|
+
/**
|
|
1342
|
+
* SDK default options for {@link ClientFactory}.
|
|
1343
|
+
*/
|
|
1344
|
+
default: {
|
|
1345
|
+
transports: [new JsonRpcTransportFactory(), new RestTransportFactory()]
|
|
1346
|
+
},
|
|
1347
|
+
/**
|
|
1348
|
+
* Creates new options by merging an original and an override object.
|
|
1349
|
+
* Transports are merged based on `TransportFactory.protocolName`,
|
|
1350
|
+
* interceptors are concatenated, other fields are overriden.
|
|
1351
|
+
*
|
|
1352
|
+
* @example
|
|
1353
|
+
* ```ts
|
|
1354
|
+
* const options = ClientFactoryOptions.createFrom(ClientFactoryOptions.default, {
|
|
1355
|
+
* transports: [new MyCustomTransportFactory()], // adds a custom transport
|
|
1356
|
+
* clientConfig: { interceptors: [new MyInterceptor()] }, // adds a custom interceptor
|
|
1357
|
+
* });
|
|
1358
|
+
* ```
|
|
1359
|
+
*/
|
|
1360
|
+
createFrom(original, overrides) {
|
|
1361
|
+
return {
|
|
1362
|
+
...original,
|
|
1363
|
+
...overrides,
|
|
1364
|
+
transports: mergeTransports(original.transports, overrides.transports),
|
|
1365
|
+
clientConfig: {
|
|
1366
|
+
...original.clientConfig ?? {},
|
|
1367
|
+
...overrides.clientConfig ?? {},
|
|
1368
|
+
interceptors: mergeArrays(
|
|
1369
|
+
original.clientConfig?.interceptors,
|
|
1370
|
+
overrides.clientConfig?.interceptors
|
|
1371
|
+
),
|
|
1372
|
+
acceptedOutputModes: overrides.clientConfig?.acceptedOutputModes ?? original.clientConfig?.acceptedOutputModes
|
|
1373
|
+
},
|
|
1374
|
+
preferredTransports: overrides.preferredTransports ?? original.preferredTransports
|
|
1375
|
+
};
|
|
1079
1376
|
}
|
|
1080
1377
|
};
|
|
1081
1378
|
var ClientFactory = class {
|
|
1082
|
-
constructor(options = ClientFactoryOptions.
|
|
1379
|
+
constructor(options = ClientFactoryOptions.default) {
|
|
1083
1380
|
this.options = options;
|
|
1084
1381
|
if (!options.transports || options.transports.length === 0) {
|
|
1085
1382
|
throw new Error("No transports provided");
|
|
1086
1383
|
}
|
|
1087
|
-
|
|
1088
|
-
if (this.transportsByName.has(transport.protocolName)) {
|
|
1089
|
-
throw new Error(`Duplicate transport name: ${transport.protocolName}`);
|
|
1090
|
-
}
|
|
1091
|
-
this.transportsByName.set(transport.protocolName, transport);
|
|
1092
|
-
}
|
|
1384
|
+
this.transportsByName = transportsByName(options.transports);
|
|
1093
1385
|
for (const transport of options.preferredTransports ?? []) {
|
|
1094
|
-
|
|
1095
|
-
if (!factory) {
|
|
1386
|
+
if (!this.transportsByName.has(transport)) {
|
|
1096
1387
|
throw new Error(
|
|
1097
1388
|
`Unknown preferred transport: ${transport}, available transports: ${[...this.transportsByName.keys()].join()}`
|
|
1098
1389
|
);
|
|
1099
1390
|
}
|
|
1100
1391
|
}
|
|
1101
|
-
this.agentCardResolver = options.cardResolver ?? AgentCardResolver.
|
|
1392
|
+
this.agentCardResolver = options.cardResolver ?? AgentCardResolver.default;
|
|
1102
1393
|
}
|
|
1103
|
-
transportsByName
|
|
1394
|
+
transportsByName;
|
|
1104
1395
|
agentCardResolver;
|
|
1105
1396
|
/**
|
|
1106
1397
|
* Creates a new client from the provided agent card.
|
|
@@ -1108,7 +1399,7 @@ var ClientFactory = class {
|
|
|
1108
1399
|
async createFromAgentCard(agentCard) {
|
|
1109
1400
|
const agentCardPreferred = agentCard.preferredTransport ?? JsonRpcTransportFactory.name;
|
|
1110
1401
|
const additionalInterfaces = agentCard.additionalInterfaces ?? [];
|
|
1111
|
-
const urlsPerAgentTransports = new
|
|
1402
|
+
const urlsPerAgentTransports = new CaseInsensitiveMap([
|
|
1112
1403
|
[agentCardPreferred, agentCard.url],
|
|
1113
1404
|
...additionalInterfaces.map((i) => [i.transport, i.url])
|
|
1114
1405
|
]);
|
|
@@ -1138,21 +1429,177 @@ var ClientFactory = class {
|
|
|
1138
1429
|
/**
|
|
1139
1430
|
* Downloads agent card using AgentCardResolver from options
|
|
1140
1431
|
* and creates a new client from the downloaded card.
|
|
1432
|
+
*
|
|
1433
|
+
* @example
|
|
1434
|
+
* ```ts
|
|
1435
|
+
* const factory = new ClientFactory(); // use default options and default {@link AgentCardResolver}.
|
|
1436
|
+
* const client1 = await factory.createFromUrl('https://example.com'); // /.well-known/agent-card.json is used by default
|
|
1437
|
+
* const client2 = await factory.createFromUrl('https://example.com', '/my-agent-card.json'); // specify custom path
|
|
1438
|
+
* const client3 = await factory.createFromUrl('https://example.com/my-agent-card.json', ''); // specify full URL and set path to empty
|
|
1439
|
+
* ```
|
|
1141
1440
|
*/
|
|
1142
|
-
async
|
|
1441
|
+
async createFromUrl(baseUrl, path) {
|
|
1143
1442
|
const agentCard = await this.agentCardResolver.resolve(baseUrl, path);
|
|
1144
|
-
return
|
|
1443
|
+
return this.createFromAgentCard(agentCard);
|
|
1444
|
+
}
|
|
1445
|
+
};
|
|
1446
|
+
function mergeTransports(original, overrides) {
|
|
1447
|
+
if (!overrides) {
|
|
1448
|
+
return original;
|
|
1449
|
+
}
|
|
1450
|
+
const result = transportsByName(original);
|
|
1451
|
+
const overridesByName = transportsByName(overrides);
|
|
1452
|
+
for (const [name, factory] of overridesByName) {
|
|
1453
|
+
result.set(name, factory);
|
|
1454
|
+
}
|
|
1455
|
+
return Array.from(result.values());
|
|
1456
|
+
}
|
|
1457
|
+
function transportsByName(transports) {
|
|
1458
|
+
const result = new CaseInsensitiveMap();
|
|
1459
|
+
if (!transports) {
|
|
1460
|
+
return result;
|
|
1461
|
+
}
|
|
1462
|
+
for (const t of transports) {
|
|
1463
|
+
if (result.has(t.protocolName)) {
|
|
1464
|
+
throw new Error(`Duplicate protocol name: ${t.protocolName}`);
|
|
1465
|
+
}
|
|
1466
|
+
result.set(t.protocolName, t);
|
|
1467
|
+
}
|
|
1468
|
+
return result;
|
|
1469
|
+
}
|
|
1470
|
+
function mergeArrays(a1, a2) {
|
|
1471
|
+
if (!a1 && !a2) {
|
|
1472
|
+
return void 0;
|
|
1473
|
+
}
|
|
1474
|
+
return [...a1 ?? [], ...a2 ?? []];
|
|
1475
|
+
}
|
|
1476
|
+
var CaseInsensitiveMap = class extends Map {
|
|
1477
|
+
normalizeKey(key) {
|
|
1478
|
+
return key.toUpperCase();
|
|
1479
|
+
}
|
|
1480
|
+
set(key, value) {
|
|
1481
|
+
return super.set(this.normalizeKey(key), value);
|
|
1482
|
+
}
|
|
1483
|
+
get(key) {
|
|
1484
|
+
return super.get(this.normalizeKey(key));
|
|
1485
|
+
}
|
|
1486
|
+
has(key) {
|
|
1487
|
+
return super.has(this.normalizeKey(key));
|
|
1488
|
+
}
|
|
1489
|
+
delete(key) {
|
|
1490
|
+
return super.delete(this.normalizeKey(key));
|
|
1491
|
+
}
|
|
1492
|
+
};
|
|
1493
|
+
|
|
1494
|
+
// src/extensions.ts
|
|
1495
|
+
var Extensions = {
|
|
1496
|
+
/**
|
|
1497
|
+
* Creates new {@link Extensions} from `current` and `additional`.
|
|
1498
|
+
* If `current` already contains `additional` it is returned unmodified.
|
|
1499
|
+
*/
|
|
1500
|
+
createFrom: (current, additional) => {
|
|
1501
|
+
if (current?.includes(additional)) {
|
|
1502
|
+
return current;
|
|
1503
|
+
}
|
|
1504
|
+
return [...current ?? [], additional];
|
|
1505
|
+
},
|
|
1506
|
+
/**
|
|
1507
|
+
* Creates {@link Extensions} from comma separated extensions identifiers as per
|
|
1508
|
+
* https://a2a-protocol.org/latest/specification/#326-service-parameters.
|
|
1509
|
+
* Parses the output of `toServiceParameter`.
|
|
1510
|
+
*/
|
|
1511
|
+
parseServiceParameter: (value) => {
|
|
1512
|
+
if (!value) {
|
|
1513
|
+
return [];
|
|
1514
|
+
}
|
|
1515
|
+
const unique = new Set(
|
|
1516
|
+
value.split(",").map((ext) => ext.trim()).filter((ext) => ext.length > 0)
|
|
1517
|
+
);
|
|
1518
|
+
return Array.from(unique);
|
|
1519
|
+
},
|
|
1520
|
+
/**
|
|
1521
|
+
* Converts {@link Extensions} to comma separated extensions identifiers as per
|
|
1522
|
+
* https://a2a-protocol.org/latest/specification/#326-service-parameters.
|
|
1523
|
+
*/
|
|
1524
|
+
toServiceParameter: (value) => {
|
|
1525
|
+
return value.join(",");
|
|
1526
|
+
}
|
|
1527
|
+
};
|
|
1528
|
+
|
|
1529
|
+
// src/client/service-parameters.ts
|
|
1530
|
+
var ServiceParameters = {
|
|
1531
|
+
create(...updates) {
|
|
1532
|
+
return ServiceParameters.createFrom(void 0, ...updates);
|
|
1533
|
+
},
|
|
1534
|
+
createFrom: (serviceParameters, ...updates) => {
|
|
1535
|
+
const result = serviceParameters ? { ...serviceParameters } : {};
|
|
1536
|
+
for (const update of updates) {
|
|
1537
|
+
update(result);
|
|
1538
|
+
}
|
|
1539
|
+
return result;
|
|
1540
|
+
}
|
|
1541
|
+
};
|
|
1542
|
+
function withA2AExtensions(...extensions) {
|
|
1543
|
+
return (parameters) => {
|
|
1544
|
+
parameters[HTTP_EXTENSION_HEADER] = Extensions.toServiceParameter(extensions);
|
|
1545
|
+
};
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
// src/client/context.ts
|
|
1549
|
+
var ClientCallContext = {
|
|
1550
|
+
/**
|
|
1551
|
+
* Create a new {@link ClientCallContext} with optional updates applied.
|
|
1552
|
+
*/
|
|
1553
|
+
create: (...updates) => {
|
|
1554
|
+
return ClientCallContext.createFrom(void 0, ...updates);
|
|
1555
|
+
},
|
|
1556
|
+
/**
|
|
1557
|
+
* Create a new {@link ClientCallContext} based on an existing one with updates applied.
|
|
1558
|
+
*/
|
|
1559
|
+
createFrom: (context, ...updates) => {
|
|
1560
|
+
const result = context ? { ...context } : {};
|
|
1561
|
+
for (const update of updates) {
|
|
1562
|
+
update(result);
|
|
1563
|
+
}
|
|
1564
|
+
return result;
|
|
1565
|
+
}
|
|
1566
|
+
};
|
|
1567
|
+
var ClientCallContextKey = class {
|
|
1568
|
+
symbol;
|
|
1569
|
+
constructor(description) {
|
|
1570
|
+
this.symbol = Symbol(description);
|
|
1571
|
+
}
|
|
1572
|
+
set(value) {
|
|
1573
|
+
return (context) => {
|
|
1574
|
+
context[this.symbol] = value;
|
|
1575
|
+
};
|
|
1576
|
+
}
|
|
1577
|
+
get(context) {
|
|
1578
|
+
return context[this.symbol];
|
|
1145
1579
|
}
|
|
1146
1580
|
};
|
|
1147
1581
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1148
1582
|
0 && (module.exports = {
|
|
1149
1583
|
A2AClient,
|
|
1150
1584
|
AgentCardResolver,
|
|
1585
|
+
AuthenticatedExtendedCardNotConfiguredError,
|
|
1151
1586
|
Client,
|
|
1587
|
+
ClientCallContext,
|
|
1588
|
+
ClientCallContextKey,
|
|
1152
1589
|
ClientFactory,
|
|
1153
1590
|
ClientFactoryOptions,
|
|
1591
|
+
ContentTypeNotSupportedError,
|
|
1154
1592
|
DefaultAgentCardResolver,
|
|
1593
|
+
InvalidAgentResponseError,
|
|
1155
1594
|
JsonRpcTransport,
|
|
1156
1595
|
JsonRpcTransportFactory,
|
|
1157
|
-
|
|
1596
|
+
PushNotificationNotSupportedError,
|
|
1597
|
+
RestTransport,
|
|
1598
|
+
RestTransportFactory,
|
|
1599
|
+
ServiceParameters,
|
|
1600
|
+
TaskNotCancelableError,
|
|
1601
|
+
TaskNotFoundError,
|
|
1602
|
+
UnsupportedOperationError,
|
|
1603
|
+
createAuthenticatingFetchWithRetry,
|
|
1604
|
+
withA2AExtensions
|
|
1158
1605
|
});
|