@a2a-js/sdk 0.3.0 → 0.3.2
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 +2 -1
- package/dist/a2a_request_handler-B5t-IxgA.d.ts +17 -0
- package/dist/a2a_request_handler-DUvKWfix.d.cts +17 -0
- package/dist/chunk-67JNQ6TZ.js +6 -0
- package/dist/chunk-JA52GYRU.js +207 -0
- package/dist/client/index.cjs +90 -40
- package/dist/client/index.d.cts +88 -8
- package/dist/client/index.d.ts +88 -8
- package/dist/client/index.js +89 -39
- package/dist/index.cjs +14 -0
- package/dist/index.d.cts +9 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +6 -0
- package/dist/server/express/index.cjs +342 -0
- package/dist/server/express/index.d.cts +20 -0
- package/dist/server/express/index.d.ts +20 -0
- package/dist/server/express/index.js +106 -0
- package/dist/server/index.d.cts +2 -15
- package/dist/server/index.d.ts +2 -15
- package/dist/server/index.js +5 -203
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -55,6 +55,7 @@ const movieAgentCard: AgentCard = {
|
|
|
55
55
|
organization: "A2A Agents",
|
|
56
56
|
url: "https://example.com/a2a-agents", // Added provider URL
|
|
57
57
|
},
|
|
58
|
+
protocolVersion: "0.3.0", // A2A protocol this agent supports.
|
|
58
59
|
version: "0.0.2", // Incremented version
|
|
59
60
|
capabilities: {
|
|
60
61
|
streaming: true, // Supports streaming
|
|
@@ -247,7 +248,7 @@ expressApp.listen(PORT, () => {
|
|
|
247
248
|
`[MyAgent] Server using new framework started on http://localhost:${PORT}`
|
|
248
249
|
);
|
|
249
250
|
console.log(
|
|
250
|
-
`[MyAgent] Agent Card: http://localhost:${PORT}/.well-known/agent.json`
|
|
251
|
+
`[MyAgent] Agent Card: http://localhost:${PORT}/.well-known/agent-card.json`
|
|
251
252
|
);
|
|
252
253
|
console.log("[MyAgent] Press Ctrl+C to stop the server");
|
|
253
254
|
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ac as AgentCard, w as MessageSendParams, B as Message, aw as Task, aO as TaskStatusUpdateEvent, aQ as TaskArtifactUpdateEvent, V as TaskQueryParams, X as TaskIdParams, Z as TaskPushNotificationConfig, a1 as GetTaskPushNotificationConfigParams, a5 as ListTaskPushNotificationConfigParams, a7 as DeleteTaskPushNotificationConfigParams } from './types-DNKcmF0f.js';
|
|
2
|
+
|
|
3
|
+
interface A2ARequestHandler {
|
|
4
|
+
getAgentCard(): Promise<AgentCard>;
|
|
5
|
+
getAuthenticatedExtendedAgentCard(): Promise<AgentCard>;
|
|
6
|
+
sendMessage(params: MessageSendParams): Promise<Message | Task>;
|
|
7
|
+
sendMessageStream(params: MessageSendParams): AsyncGenerator<Message | Task | TaskStatusUpdateEvent | TaskArtifactUpdateEvent, void, undefined>;
|
|
8
|
+
getTask(params: TaskQueryParams): Promise<Task>;
|
|
9
|
+
cancelTask(params: TaskIdParams): Promise<Task>;
|
|
10
|
+
setTaskPushNotificationConfig(params: TaskPushNotificationConfig): Promise<TaskPushNotificationConfig>;
|
|
11
|
+
getTaskPushNotificationConfig(params: TaskIdParams | GetTaskPushNotificationConfigParams): Promise<TaskPushNotificationConfig>;
|
|
12
|
+
listTaskPushNotificationConfigs(params: ListTaskPushNotificationConfigParams): Promise<TaskPushNotificationConfig[]>;
|
|
13
|
+
deleteTaskPushNotificationConfig(params: DeleteTaskPushNotificationConfigParams): Promise<void>;
|
|
14
|
+
resubscribe(params: TaskIdParams): AsyncGenerator<Task | TaskStatusUpdateEvent | TaskArtifactUpdateEvent, void, undefined>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type { A2ARequestHandler as A };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ac as AgentCard, w as MessageSendParams, B as Message, aw as Task, aO as TaskStatusUpdateEvent, aQ as TaskArtifactUpdateEvent, V as TaskQueryParams, X as TaskIdParams, Z as TaskPushNotificationConfig, a1 as GetTaskPushNotificationConfigParams, a5 as ListTaskPushNotificationConfigParams, a7 as DeleteTaskPushNotificationConfigParams } from './types-DNKcmF0f.cjs';
|
|
2
|
+
|
|
3
|
+
interface A2ARequestHandler {
|
|
4
|
+
getAgentCard(): Promise<AgentCard>;
|
|
5
|
+
getAuthenticatedExtendedAgentCard(): Promise<AgentCard>;
|
|
6
|
+
sendMessage(params: MessageSendParams): Promise<Message | Task>;
|
|
7
|
+
sendMessageStream(params: MessageSendParams): AsyncGenerator<Message | Task | TaskStatusUpdateEvent | TaskArtifactUpdateEvent, void, undefined>;
|
|
8
|
+
getTask(params: TaskQueryParams): Promise<Task>;
|
|
9
|
+
cancelTask(params: TaskIdParams): Promise<Task>;
|
|
10
|
+
setTaskPushNotificationConfig(params: TaskPushNotificationConfig): Promise<TaskPushNotificationConfig>;
|
|
11
|
+
getTaskPushNotificationConfig(params: TaskIdParams | GetTaskPushNotificationConfigParams): Promise<TaskPushNotificationConfig>;
|
|
12
|
+
listTaskPushNotificationConfigs(params: ListTaskPushNotificationConfigParams): Promise<TaskPushNotificationConfig[]>;
|
|
13
|
+
deleteTaskPushNotificationConfig(params: DeleteTaskPushNotificationConfigParams): Promise<void>;
|
|
14
|
+
resubscribe(params: TaskIdParams): AsyncGenerator<Task | TaskStatusUpdateEvent | TaskArtifactUpdateEvent, void, undefined>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type { A2ARequestHandler as A };
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
// src/server/error.ts
|
|
2
|
+
var A2AError = class _A2AError extends Error {
|
|
3
|
+
code;
|
|
4
|
+
data;
|
|
5
|
+
taskId;
|
|
6
|
+
// Optional task ID context
|
|
7
|
+
constructor(code, message, data, taskId) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.name = "A2AError";
|
|
10
|
+
this.code = code;
|
|
11
|
+
this.data = data;
|
|
12
|
+
this.taskId = taskId;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Formats the error into a standard JSON-RPC error object structure.
|
|
16
|
+
*/
|
|
17
|
+
toJSONRPCError() {
|
|
18
|
+
const errorObject = {
|
|
19
|
+
code: this.code,
|
|
20
|
+
message: this.message
|
|
21
|
+
};
|
|
22
|
+
if (this.data !== void 0) {
|
|
23
|
+
errorObject.data = this.data;
|
|
24
|
+
}
|
|
25
|
+
return errorObject;
|
|
26
|
+
}
|
|
27
|
+
// Static factory methods for common errors
|
|
28
|
+
static parseError(message, data) {
|
|
29
|
+
return new _A2AError(-32700, message, data);
|
|
30
|
+
}
|
|
31
|
+
static invalidRequest(message, data) {
|
|
32
|
+
return new _A2AError(-32600, message, data);
|
|
33
|
+
}
|
|
34
|
+
static methodNotFound(method) {
|
|
35
|
+
return new _A2AError(
|
|
36
|
+
-32601,
|
|
37
|
+
`Method not found: ${method}`
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
static invalidParams(message, data) {
|
|
41
|
+
return new _A2AError(-32602, message, data);
|
|
42
|
+
}
|
|
43
|
+
static internalError(message, data) {
|
|
44
|
+
return new _A2AError(-32603, message, data);
|
|
45
|
+
}
|
|
46
|
+
static taskNotFound(taskId) {
|
|
47
|
+
return new _A2AError(
|
|
48
|
+
-32001,
|
|
49
|
+
`Task not found: ${taskId}`,
|
|
50
|
+
void 0,
|
|
51
|
+
taskId
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
static taskNotCancelable(taskId) {
|
|
55
|
+
return new _A2AError(
|
|
56
|
+
-32002,
|
|
57
|
+
`Task not cancelable: ${taskId}`,
|
|
58
|
+
void 0,
|
|
59
|
+
taskId
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
static pushNotificationNotSupported() {
|
|
63
|
+
return new _A2AError(
|
|
64
|
+
-32003,
|
|
65
|
+
"Push Notification is not supported"
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
static unsupportedOperation(operation) {
|
|
69
|
+
return new _A2AError(
|
|
70
|
+
-32004,
|
|
71
|
+
`Unsupported operation: ${operation}`
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
static authenticatedExtendedCardNotConfigured() {
|
|
75
|
+
return new _A2AError(
|
|
76
|
+
-32007,
|
|
77
|
+
`Extended card not configured.`
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
// src/server/transports/jsonrpc_transport_handler.ts
|
|
83
|
+
var JsonRpcTransportHandler = class {
|
|
84
|
+
requestHandler;
|
|
85
|
+
constructor(requestHandler) {
|
|
86
|
+
this.requestHandler = requestHandler;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Handles an incoming JSON-RPC request.
|
|
90
|
+
* For streaming methods, it returns an AsyncGenerator of JSONRPCResult.
|
|
91
|
+
* For non-streaming methods, it returns a Promise of a single JSONRPCMessage (Result or ErrorResponse).
|
|
92
|
+
*/
|
|
93
|
+
async handle(requestBody) {
|
|
94
|
+
let rpcRequest;
|
|
95
|
+
try {
|
|
96
|
+
if (typeof requestBody === "string") {
|
|
97
|
+
rpcRequest = JSON.parse(requestBody);
|
|
98
|
+
} else if (typeof requestBody === "object" && requestBody !== null) {
|
|
99
|
+
rpcRequest = requestBody;
|
|
100
|
+
} else {
|
|
101
|
+
throw A2AError.parseError("Invalid request body type.");
|
|
102
|
+
}
|
|
103
|
+
if (rpcRequest.jsonrpc !== "2.0" || !rpcRequest.method || typeof rpcRequest.method !== "string") {
|
|
104
|
+
throw A2AError.invalidRequest(
|
|
105
|
+
"Invalid JSON-RPC request structure."
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
} catch (error) {
|
|
109
|
+
const a2aError = error instanceof A2AError ? error : A2AError.parseError(error.message || "Failed to parse JSON request.");
|
|
110
|
+
return {
|
|
111
|
+
jsonrpc: "2.0",
|
|
112
|
+
id: typeof rpcRequest?.id !== "undefined" ? rpcRequest.id : null,
|
|
113
|
+
error: a2aError.toJSONRPCError()
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
const { method, id: requestId = null } = rpcRequest;
|
|
117
|
+
try {
|
|
118
|
+
if (method === "agent/getAuthenticatedExtendedCard") {
|
|
119
|
+
const result = await this.requestHandler.getAuthenticatedExtendedAgentCard();
|
|
120
|
+
return {
|
|
121
|
+
jsonrpc: "2.0",
|
|
122
|
+
id: requestId,
|
|
123
|
+
result
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
if (!rpcRequest.params) {
|
|
127
|
+
throw A2AError.invalidParams(`'params' is required for '${method}'`);
|
|
128
|
+
}
|
|
129
|
+
if (method === "message/stream" || method === "tasks/resubscribe") {
|
|
130
|
+
const params = rpcRequest.params;
|
|
131
|
+
const agentCard = await this.requestHandler.getAgentCard();
|
|
132
|
+
if (!agentCard.capabilities.streaming) {
|
|
133
|
+
throw A2AError.unsupportedOperation(`Method ${method} requires streaming capability.`);
|
|
134
|
+
}
|
|
135
|
+
const agentEventStream = method === "message/stream" ? this.requestHandler.sendMessageStream(params) : this.requestHandler.resubscribe(params);
|
|
136
|
+
return async function* jsonRpcEventStream() {
|
|
137
|
+
try {
|
|
138
|
+
for await (const event of agentEventStream) {
|
|
139
|
+
yield {
|
|
140
|
+
jsonrpc: "2.0",
|
|
141
|
+
id: requestId,
|
|
142
|
+
// Use the original request ID for all streamed responses
|
|
143
|
+
result: event
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
} catch (streamError) {
|
|
147
|
+
console.error(`Error in agent event stream for ${method} (request ${requestId}):`, streamError);
|
|
148
|
+
throw streamError;
|
|
149
|
+
}
|
|
150
|
+
}();
|
|
151
|
+
} else {
|
|
152
|
+
let result;
|
|
153
|
+
switch (method) {
|
|
154
|
+
case "message/send":
|
|
155
|
+
result = await this.requestHandler.sendMessage(rpcRequest.params);
|
|
156
|
+
break;
|
|
157
|
+
case "tasks/get":
|
|
158
|
+
result = await this.requestHandler.getTask(rpcRequest.params);
|
|
159
|
+
break;
|
|
160
|
+
case "tasks/cancel":
|
|
161
|
+
result = await this.requestHandler.cancelTask(rpcRequest.params);
|
|
162
|
+
break;
|
|
163
|
+
case "tasks/pushNotificationConfig/set":
|
|
164
|
+
result = await this.requestHandler.setTaskPushNotificationConfig(
|
|
165
|
+
rpcRequest.params
|
|
166
|
+
);
|
|
167
|
+
break;
|
|
168
|
+
case "tasks/pushNotificationConfig/get":
|
|
169
|
+
result = await this.requestHandler.getTaskPushNotificationConfig(
|
|
170
|
+
rpcRequest.params
|
|
171
|
+
);
|
|
172
|
+
break;
|
|
173
|
+
case "tasks/pushNotificationConfig/delete":
|
|
174
|
+
await this.requestHandler.deleteTaskPushNotificationConfig(
|
|
175
|
+
rpcRequest.params
|
|
176
|
+
);
|
|
177
|
+
result = null;
|
|
178
|
+
break;
|
|
179
|
+
case "tasks/pushNotificationConfig/list":
|
|
180
|
+
result = await this.requestHandler.listTaskPushNotificationConfigs(
|
|
181
|
+
rpcRequest.params
|
|
182
|
+
);
|
|
183
|
+
break;
|
|
184
|
+
default:
|
|
185
|
+
throw A2AError.methodNotFound(method);
|
|
186
|
+
}
|
|
187
|
+
return {
|
|
188
|
+
jsonrpc: "2.0",
|
|
189
|
+
id: requestId,
|
|
190
|
+
result
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
} catch (error) {
|
|
194
|
+
const a2aError = error instanceof A2AError ? error : A2AError.internalError(error.message || "An unexpected error occurred.");
|
|
195
|
+
return {
|
|
196
|
+
jsonrpc: "2.0",
|
|
197
|
+
id: requestId,
|
|
198
|
+
error: a2aError.toJSONRPCError()
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
export {
|
|
205
|
+
A2AError,
|
|
206
|
+
JsonRpcTransportHandler
|
|
207
|
+
};
|
package/dist/client/index.cjs
CHANGED
|
@@ -19,41 +19,44 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
19
19
|
// src/client/index.ts
|
|
20
20
|
var client_exports = {};
|
|
21
21
|
__export(client_exports, {
|
|
22
|
-
A2AClient: () => A2AClient
|
|
22
|
+
A2AClient: () => A2AClient,
|
|
23
|
+
createAuthenticatingFetchWithRetry: () => createAuthenticatingFetchWithRetry
|
|
23
24
|
});
|
|
24
25
|
module.exports = __toCommonJS(client_exports);
|
|
25
26
|
|
|
27
|
+
// src/constants.ts
|
|
28
|
+
var AGENT_CARD_PATH = ".well-known/agent-card.json";
|
|
29
|
+
|
|
26
30
|
// src/client/client.ts
|
|
27
|
-
var A2AClient = class
|
|
28
|
-
agentBaseUrl;
|
|
29
|
-
agentCardPath;
|
|
31
|
+
var A2AClient = class {
|
|
30
32
|
agentCardPromise;
|
|
31
|
-
static DEFAULT_AGENT_CARD_PATH = ".well-known/agent.json";
|
|
32
33
|
requestIdCounter = 1;
|
|
33
34
|
serviceEndpointUrl;
|
|
34
35
|
// To be populated from AgentCard after fetching
|
|
36
|
+
fetchImpl;
|
|
35
37
|
/**
|
|
36
38
|
* Constructs an A2AClient instance.
|
|
37
39
|
* It initiates fetching the agent card from the provided agent baseUrl.
|
|
38
|
-
* The Agent Card is fetched from a path relative to the agentBaseUrl, which defaults to '.well-known/agent.json'.
|
|
40
|
+
* The Agent Card is fetched from a path relative to the agentBaseUrl, which defaults to '.well-known/agent-card.json'.
|
|
39
41
|
* The `url` field from the Agent Card will be used as the RPC service endpoint.
|
|
40
42
|
* @param agentBaseUrl The base URL of the A2A agent (e.g., https://agent.example.com)
|
|
41
|
-
* @param
|
|
43
|
+
* @param options Optional. The options for the A2AClient including the fetch implementation, agent card path, and authentication handler.
|
|
42
44
|
*/
|
|
43
|
-
constructor(agentBaseUrl,
|
|
44
|
-
this.
|
|
45
|
-
this.
|
|
46
|
-
this.agentCardPromise = this._fetchAndCacheAgentCard();
|
|
45
|
+
constructor(agentBaseUrl, options) {
|
|
46
|
+
this.fetchImpl = options?.fetchImpl ?? fetch;
|
|
47
|
+
this.agentCardPromise = this._fetchAndCacheAgentCard(agentBaseUrl, options?.agentCardPath);
|
|
47
48
|
}
|
|
48
49
|
/**
|
|
49
50
|
* Fetches the Agent Card from the agent's well-known URI and caches its service endpoint URL.
|
|
50
51
|
* This method is called by the constructor.
|
|
52
|
+
* @param agentBaseUrl The base URL of the A2A agent (e.g., https://agent.example.com)
|
|
53
|
+
* @param agentCardPath path to the agent card, defaults to .well-known/agent-card.json
|
|
51
54
|
* @returns A Promise that resolves to the AgentCard.
|
|
52
55
|
*/
|
|
53
|
-
async _fetchAndCacheAgentCard() {
|
|
54
|
-
const agentCardUrl = `${this.agentBaseUrl}/${this.agentCardPath}`;
|
|
56
|
+
async _fetchAndCacheAgentCard(agentBaseUrl, agentCardPath) {
|
|
55
57
|
try {
|
|
56
|
-
const
|
|
58
|
+
const agentCardUrl = this.resolveAgentCardUrl(agentBaseUrl, agentCardPath);
|
|
59
|
+
const response = await this.fetchImpl(agentCardUrl, {
|
|
57
60
|
headers: { "Accept": "application/json" }
|
|
58
61
|
});
|
|
59
62
|
if (!response.ok) {
|
|
@@ -66,7 +69,7 @@ var A2AClient = class _A2AClient {
|
|
|
66
69
|
this.serviceEndpointUrl = agentCard.url;
|
|
67
70
|
return agentCard;
|
|
68
71
|
} catch (error) {
|
|
69
|
-
console.error("Error fetching or parsing Agent Card:");
|
|
72
|
+
console.error("Error fetching or parsing Agent Card:", error);
|
|
70
73
|
throw error;
|
|
71
74
|
}
|
|
72
75
|
}
|
|
@@ -75,14 +78,14 @@ var A2AClient = class _A2AClient {
|
|
|
75
78
|
* If an `agentBaseUrl` is provided, it fetches the card from that specific URL.
|
|
76
79
|
* Otherwise, it returns the card fetched and cached during client construction.
|
|
77
80
|
* @param agentBaseUrl Optional. The base URL of the agent to fetch the card from.
|
|
78
|
-
* @param agentCardPath path to the agent card, defaults to .well-known/agent.json
|
|
81
|
+
* @param agentCardPath path to the agent card, defaults to .well-known/agent-card.json
|
|
79
82
|
* If provided, this will fetch a new card, not use the cached one from the constructor's URL.
|
|
80
83
|
* @returns A Promise that resolves to the AgentCard.
|
|
81
84
|
*/
|
|
82
|
-
async getAgentCard(agentBaseUrl, agentCardPath
|
|
85
|
+
async getAgentCard(agentBaseUrl, agentCardPath) {
|
|
83
86
|
if (agentBaseUrl) {
|
|
84
|
-
const agentCardUrl =
|
|
85
|
-
const response = await
|
|
87
|
+
const agentCardUrl = this.resolveAgentCardUrl(agentBaseUrl, agentCardPath);
|
|
88
|
+
const response = await this.fetchImpl(agentCardUrl, {
|
|
86
89
|
headers: { "Accept": "application/json" }
|
|
87
90
|
});
|
|
88
91
|
if (!response.ok) {
|
|
@@ -92,6 +95,14 @@ var A2AClient = class _A2AClient {
|
|
|
92
95
|
}
|
|
93
96
|
return this.agentCardPromise;
|
|
94
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* Determines the agent card URL based on the agent URL.
|
|
100
|
+
* @param agentBaseUrl The agent URL.
|
|
101
|
+
* @param agentCardPath Optional relative path to the agent card, defaults to .well-known/agent-card.json
|
|
102
|
+
*/
|
|
103
|
+
resolveAgentCardUrl(agentBaseUrl, agentCardPath = AGENT_CARD_PATH) {
|
|
104
|
+
return `${agentBaseUrl.replace(/\/$/, "")}/${agentCardPath.replace(/^\//, "")}`;
|
|
105
|
+
}
|
|
95
106
|
/**
|
|
96
107
|
* Gets the RPC service endpoint URL. Ensures the agent card has been fetched first.
|
|
97
108
|
* @returns A Promise that resolves to the service endpoint URL string.
|
|
@@ -122,21 +133,15 @@ var A2AClient = class _A2AClient {
|
|
|
122
133
|
// Cast because TParams structure varies per method
|
|
123
134
|
id: requestId
|
|
124
135
|
};
|
|
125
|
-
const httpResponse = await
|
|
126
|
-
method: "POST",
|
|
127
|
-
headers: {
|
|
128
|
-
"Content-Type": "application/json",
|
|
129
|
-
"Accept": "application/json"
|
|
130
|
-
// Expect JSON response for non-streaming requests
|
|
131
|
-
},
|
|
132
|
-
body: JSON.stringify(rpcRequest)
|
|
133
|
-
});
|
|
136
|
+
const httpResponse = await this._fetchRpc(endpoint, rpcRequest);
|
|
134
137
|
if (!httpResponse.ok) {
|
|
135
138
|
let errorBodyText = "(empty or non-JSON response)";
|
|
136
139
|
try {
|
|
137
140
|
errorBodyText = await httpResponse.text();
|
|
138
141
|
const errorJson = JSON.parse(errorBodyText);
|
|
139
|
-
if (
|
|
142
|
+
if (errorJson.jsonrpc && errorJson.error) {
|
|
143
|
+
return errorJson;
|
|
144
|
+
} else if (!errorJson.jsonrpc && errorJson.error) {
|
|
140
145
|
throw new Error(`RPC error for ${method}: ${errorJson.error.message} (Code: ${errorJson.error.code}, HTTP Status: ${httpResponse.status}) Data: ${JSON.stringify(errorJson.error.data || {})}`);
|
|
141
146
|
} else if (!errorJson.jsonrpc) {
|
|
142
147
|
throw new Error(`HTTP error for ${method}! Status: ${httpResponse.status} ${httpResponse.statusText}. Response: ${errorBodyText}`);
|
|
@@ -152,6 +157,25 @@ var A2AClient = class _A2AClient {
|
|
|
152
157
|
}
|
|
153
158
|
return rpcResponse;
|
|
154
159
|
}
|
|
160
|
+
/**
|
|
161
|
+
* Internal helper method to fetch the RPC service endpoint.
|
|
162
|
+
* @param url The URL to fetch.
|
|
163
|
+
* @param rpcRequest The JSON-RPC request to send.
|
|
164
|
+
* @param acceptHeader The Accept header to use. Defaults to "application/json".
|
|
165
|
+
* @returns A Promise that resolves to the fetch HTTP response.
|
|
166
|
+
*/
|
|
167
|
+
async _fetchRpc(url, rpcRequest, acceptHeader = "application/json") {
|
|
168
|
+
const requestInit = {
|
|
169
|
+
method: "POST",
|
|
170
|
+
headers: {
|
|
171
|
+
"Content-Type": "application/json",
|
|
172
|
+
"Accept": acceptHeader
|
|
173
|
+
// Expect JSON response for non-streaming requests
|
|
174
|
+
},
|
|
175
|
+
body: JSON.stringify(rpcRequest)
|
|
176
|
+
};
|
|
177
|
+
return this.fetchImpl(url, requestInit);
|
|
178
|
+
}
|
|
155
179
|
/**
|
|
156
180
|
* Sends a message to the agent.
|
|
157
181
|
* The behavior (blocking/non-blocking) and push notification configuration
|
|
@@ -186,15 +210,7 @@ var A2AClient = class _A2AClient {
|
|
|
186
210
|
params,
|
|
187
211
|
id: clientRequestId
|
|
188
212
|
};
|
|
189
|
-
const response = await
|
|
190
|
-
method: "POST",
|
|
191
|
-
headers: {
|
|
192
|
-
"Content-Type": "application/json",
|
|
193
|
-
"Accept": "text/event-stream"
|
|
194
|
-
// Crucial for SSE
|
|
195
|
-
},
|
|
196
|
-
body: JSON.stringify(rpcRequest)
|
|
197
|
-
});
|
|
213
|
+
const response = await this._fetchRpc(endpoint, rpcRequest, "text/event-stream");
|
|
198
214
|
if (!response.ok) {
|
|
199
215
|
let errorBody = "";
|
|
200
216
|
try {
|
|
@@ -278,7 +294,7 @@ var A2AClient = class _A2AClient {
|
|
|
278
294
|
params,
|
|
279
295
|
id: clientRequestId
|
|
280
296
|
};
|
|
281
|
-
const response = await
|
|
297
|
+
const response = await this.fetchImpl(endpoint, {
|
|
282
298
|
method: "POST",
|
|
283
299
|
headers: {
|
|
284
300
|
"Content-Type": "application/json",
|
|
@@ -394,7 +410,41 @@ var A2AClient = class _A2AClient {
|
|
|
394
410
|
return "error" in response;
|
|
395
411
|
}
|
|
396
412
|
};
|
|
413
|
+
|
|
414
|
+
// src/client/auth-handler.ts
|
|
415
|
+
function createAuthenticatingFetchWithRetry(fetchImpl, authHandler) {
|
|
416
|
+
async function authFetch(url, init) {
|
|
417
|
+
const authHeaders = await authHandler.headers() || {};
|
|
418
|
+
const mergedInit = {
|
|
419
|
+
...init || {},
|
|
420
|
+
headers: {
|
|
421
|
+
...authHeaders,
|
|
422
|
+
...init?.headers || {}
|
|
423
|
+
}
|
|
424
|
+
};
|
|
425
|
+
let response = await fetchImpl(url, mergedInit);
|
|
426
|
+
const updatedHeaders = await authHandler.shouldRetryWithHeaders(mergedInit, response);
|
|
427
|
+
if (updatedHeaders) {
|
|
428
|
+
const retryInit = {
|
|
429
|
+
...init || {},
|
|
430
|
+
headers: {
|
|
431
|
+
...updatedHeaders,
|
|
432
|
+
...init?.headers || {}
|
|
433
|
+
}
|
|
434
|
+
};
|
|
435
|
+
response = await fetchImpl(url, retryInit);
|
|
436
|
+
if (response.ok && authHandler.onSuccessfulRetry) {
|
|
437
|
+
await authHandler.onSuccessfulRetry(updatedHeaders);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return response;
|
|
441
|
+
}
|
|
442
|
+
Object.setPrototypeOf(authFetch, Object.getPrototypeOf(fetchImpl));
|
|
443
|
+
Object.defineProperties(authFetch, Object.getOwnPropertyDescriptors(fetchImpl));
|
|
444
|
+
return authFetch;
|
|
445
|
+
}
|
|
397
446
|
// Annotate the CommonJS export names for ESM import in node:
|
|
398
447
|
0 && (module.exports = {
|
|
399
|
-
A2AClient
|
|
448
|
+
A2AClient,
|
|
449
|
+
createAuthenticatingFetchWithRetry
|
|
400
450
|
});
|
package/dist/client/index.d.cts
CHANGED
|
@@ -1,28 +1,32 @@
|
|
|
1
1
|
import { ac as AgentCard, w as MessageSendParams, S as SendMessageResponse, B as Message, aw as Task, aO as TaskStatusUpdateEvent, aQ as TaskArtifactUpdateEvent, Z as TaskPushNotificationConfig, b as SetTaskPushNotificationConfigResponse, X as TaskIdParams, c as GetTaskPushNotificationConfigResponse, V as TaskQueryParams, G as GetTaskResponse, C as CancelTaskResponse, i as JSONRPCResponse, J as JSONRPCErrorResponse } from '../types-DNKcmF0f.cjs';
|
|
2
2
|
|
|
3
3
|
type A2AStreamEventData = Message | Task | TaskStatusUpdateEvent | TaskArtifactUpdateEvent;
|
|
4
|
+
interface A2AClientOptions {
|
|
5
|
+
agentCardPath?: string;
|
|
6
|
+
fetchImpl?: typeof fetch;
|
|
7
|
+
}
|
|
4
8
|
/**
|
|
5
9
|
* A2AClient is a TypeScript HTTP client for interacting with A2A-compliant agents.
|
|
6
10
|
*/
|
|
7
11
|
declare class A2AClient {
|
|
8
|
-
private agentBaseUrl;
|
|
9
|
-
private agentCardPath;
|
|
10
12
|
private agentCardPromise;
|
|
11
|
-
private static readonly DEFAULT_AGENT_CARD_PATH;
|
|
12
13
|
private requestIdCounter;
|
|
13
14
|
private serviceEndpointUrl?;
|
|
15
|
+
private fetchImpl;
|
|
14
16
|
/**
|
|
15
17
|
* Constructs an A2AClient instance.
|
|
16
18
|
* It initiates fetching the agent card from the provided agent baseUrl.
|
|
17
|
-
* The Agent Card is fetched from a path relative to the agentBaseUrl, which defaults to '.well-known/agent.json'.
|
|
19
|
+
* The Agent Card is fetched from a path relative to the agentBaseUrl, which defaults to '.well-known/agent-card.json'.
|
|
18
20
|
* The `url` field from the Agent Card will be used as the RPC service endpoint.
|
|
19
21
|
* @param agentBaseUrl The base URL of the A2A agent (e.g., https://agent.example.com)
|
|
20
|
-
* @param
|
|
22
|
+
* @param options Optional. The options for the A2AClient including the fetch implementation, agent card path, and authentication handler.
|
|
21
23
|
*/
|
|
22
|
-
constructor(agentBaseUrl: string,
|
|
24
|
+
constructor(agentBaseUrl: string, options?: A2AClientOptions);
|
|
23
25
|
/**
|
|
24
26
|
* Fetches the Agent Card from the agent's well-known URI and caches its service endpoint URL.
|
|
25
27
|
* This method is called by the constructor.
|
|
28
|
+
* @param agentBaseUrl The base URL of the A2A agent (e.g., https://agent.example.com)
|
|
29
|
+
* @param agentCardPath path to the agent card, defaults to .well-known/agent-card.json
|
|
26
30
|
* @returns A Promise that resolves to the AgentCard.
|
|
27
31
|
*/
|
|
28
32
|
private _fetchAndCacheAgentCard;
|
|
@@ -31,11 +35,17 @@ declare class A2AClient {
|
|
|
31
35
|
* If an `agentBaseUrl` is provided, it fetches the card from that specific URL.
|
|
32
36
|
* Otherwise, it returns the card fetched and cached during client construction.
|
|
33
37
|
* @param agentBaseUrl Optional. The base URL of the agent to fetch the card from.
|
|
34
|
-
* @param agentCardPath path to the agent card, defaults to .well-known/agent.json
|
|
38
|
+
* @param agentCardPath path to the agent card, defaults to .well-known/agent-card.json
|
|
35
39
|
* If provided, this will fetch a new card, not use the cached one from the constructor's URL.
|
|
36
40
|
* @returns A Promise that resolves to the AgentCard.
|
|
37
41
|
*/
|
|
38
42
|
getAgentCard(agentBaseUrl?: string, agentCardPath?: string): Promise<AgentCard>;
|
|
43
|
+
/**
|
|
44
|
+
* Determines the agent card URL based on the agent URL.
|
|
45
|
+
* @param agentBaseUrl The agent URL.
|
|
46
|
+
* @param agentCardPath Optional relative path to the agent card, defaults to .well-known/agent-card.json
|
|
47
|
+
*/
|
|
48
|
+
private resolveAgentCardUrl;
|
|
39
49
|
/**
|
|
40
50
|
* Gets the RPC service endpoint URL. Ensures the agent card has been fetched first.
|
|
41
51
|
* @returns A Promise that resolves to the service endpoint URL string.
|
|
@@ -48,6 +58,14 @@ declare class A2AClient {
|
|
|
48
58
|
* @returns A Promise that resolves to the RPC response.
|
|
49
59
|
*/
|
|
50
60
|
private _postRpcRequest;
|
|
61
|
+
/**
|
|
62
|
+
* Internal helper method to fetch the RPC service endpoint.
|
|
63
|
+
* @param url The URL to fetch.
|
|
64
|
+
* @param rpcRequest The JSON-RPC request to send.
|
|
65
|
+
* @param acceptHeader The Accept header to use. Defaults to "application/json".
|
|
66
|
+
* @returns A Promise that resolves to the fetch HTTP response.
|
|
67
|
+
*/
|
|
68
|
+
private _fetchRpc;
|
|
51
69
|
/**
|
|
52
70
|
* Sends a message to the agent.
|
|
53
71
|
* The behavior (blocking/non-blocking) and push notification configuration
|
|
@@ -121,4 +139,66 @@ declare class A2AClient {
|
|
|
121
139
|
isErrorResponse(response: JSONRPCResponse): response is JSONRPCErrorResponse;
|
|
122
140
|
}
|
|
123
141
|
|
|
124
|
-
|
|
142
|
+
interface HttpHeaders {
|
|
143
|
+
[key: string]: string;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Generic interface for handling authentication for HTTP requests.
|
|
147
|
+
*
|
|
148
|
+
* - For each HTTP request, this handler is called to provide additional headers to the request through
|
|
149
|
+
* the headers() function.
|
|
150
|
+
* - After the server returns a response, the shouldRetryWithHeaders() function is called. Usually this
|
|
151
|
+
* function responds to a 401 or 403 response or JSON-RPC codes, but can respond to any other signal -
|
|
152
|
+
* that is an implementation detail of the AuthenticationHandler.
|
|
153
|
+
* - If the shouldRetryWithHeaders() function returns new headers, then the request should retried with the provided
|
|
154
|
+
* revised headers. These provisional headers may, or may not, be optimistically stored for subsequent requests -
|
|
155
|
+
* that is an implementation detail of the AuthenticationHandler.
|
|
156
|
+
* - If the request is successful and the onSuccessfulRetry() is defined, then the onSuccessfulRetry() function is
|
|
157
|
+
* called with the headers that were used to successfully complete the request. This callback provides an
|
|
158
|
+
* opportunity to save the headers for subsequent requests if they were not already saved.
|
|
159
|
+
*
|
|
160
|
+
*/
|
|
161
|
+
interface AuthenticationHandler {
|
|
162
|
+
/**
|
|
163
|
+
* Provides additional HTTP request headers.
|
|
164
|
+
* @returns HTTP headers which may include Authorization if available.
|
|
165
|
+
*/
|
|
166
|
+
headers: () => Promise<HttpHeaders>;
|
|
167
|
+
/**
|
|
168
|
+
* For every HTTP response (even 200s) the shouldRetryWithHeaders() method is called.
|
|
169
|
+
* This method is supposed to check if the request needs to be retried and if, yes,
|
|
170
|
+
* return a set of headers. An A2A server might indicate auth failures in its response
|
|
171
|
+
* by JSON-rpc codes, HTTP codes like 401, 403 or headers like WWW-Authenticate.
|
|
172
|
+
*
|
|
173
|
+
* @param req The RequestInit object used to invoke fetch()
|
|
174
|
+
* @param res The fetch Response object
|
|
175
|
+
* @returns If the HTTP request should be retried then returns the HTTP headers to use,
|
|
176
|
+
* or returns undefined if no retry should be made.
|
|
177
|
+
*/
|
|
178
|
+
shouldRetryWithHeaders: (req: RequestInit, res: Response) => Promise<HttpHeaders | undefined>;
|
|
179
|
+
/**
|
|
180
|
+
* If the last HTTP request using the headers from shouldRetryWithHeaders() was successful, and
|
|
181
|
+
* this function is implemented, then it will be called with the headers provided from
|
|
182
|
+
* shouldRetryWithHeaders().
|
|
183
|
+
*
|
|
184
|
+
* This callback allows transient headers to be saved for subsequent requests only when they
|
|
185
|
+
* are validated by the server.
|
|
186
|
+
*/
|
|
187
|
+
onSuccessfulRetry?: (headers: HttpHeaders) => Promise<void>;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Higher-order function that wraps fetch with authentication handling logic.
|
|
191
|
+
* Returns a new fetch function that automatically handles authentication retries for 401/403 responses.
|
|
192
|
+
*
|
|
193
|
+
* @param fetchImpl The underlying fetch implementation to wrap
|
|
194
|
+
* @param authHandler Authentication handler for managing auth headers and retries
|
|
195
|
+
* @returns A new fetch function with authentication handling capabilities
|
|
196
|
+
*
|
|
197
|
+
* Usage examples:
|
|
198
|
+
* - const authFetch = createAuthHandlingFetch(fetch, authHandler);
|
|
199
|
+
* - const response = await authFetch(url, options);
|
|
200
|
+
* - const response = await authFetch(url); // Direct function call
|
|
201
|
+
*/
|
|
202
|
+
declare function createAuthenticatingFetchWithRetry(fetchImpl: typeof fetch, authHandler: AuthenticationHandler): typeof fetch;
|
|
203
|
+
|
|
204
|
+
export { A2AClient, type A2AClientOptions, type AuthenticationHandler, type HttpHeaders, createAuthenticatingFetchWithRetry };
|