@a2a-js/sdk 0.3.3 → 0.3.5
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 +155 -22
- package/dist/{chunk-JA52GYRU.js → chunk-SY3G7ITG.js} +35 -6
- package/dist/client/index.cjs +33 -0
- package/dist/client/index.d.cts +22 -1
- package/dist/client/index.d.ts +22 -1
- package/dist/client/index.js +33 -0
- package/dist/server/express/index.cjs +48 -7
- package/dist/server/express/index.d.cts +1 -1
- package/dist/server/express/index.d.ts +1 -1
- package/dist/server/express/index.js +14 -2
- package/dist/server/index.cjs +201 -27
- package/dist/server/index.d.cts +43 -4
- package/dist/server/index.d.ts +43 -4
- package/dist/server/index.js +165 -22
- package/package.json +7 -4
package/README.md
CHANGED
|
@@ -163,19 +163,22 @@ class TaskExecutor implements AgentExecutor {
|
|
|
163
163
|
requestContext: RequestContext,
|
|
164
164
|
eventBus: ExecutionEventBus
|
|
165
165
|
): Promise<void> {
|
|
166
|
-
const { taskId, contextId } = requestContext;
|
|
167
|
-
|
|
168
|
-
// 1. Create and publish the initial task object.
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
166
|
+
const { taskId, contextId, userMessage, task } = requestContext;
|
|
167
|
+
|
|
168
|
+
// 1. Create and publish the initial task object if it doesn't exist.
|
|
169
|
+
if (!task) {
|
|
170
|
+
const initialTask: Task = {
|
|
171
|
+
kind: "task",
|
|
172
|
+
id: taskId,
|
|
173
|
+
contextId: contextId,
|
|
174
|
+
status: {
|
|
175
|
+
state: "submitted",
|
|
176
|
+
timestamp: new Date().toISOString(),
|
|
177
|
+
},
|
|
178
|
+
history: [userMessage]
|
|
179
|
+
};
|
|
180
|
+
eventBus.publish(initialTask);
|
|
181
|
+
}
|
|
179
182
|
|
|
180
183
|
// 2. Create and publish an artifact.
|
|
181
184
|
const artifactUpdate: TaskArtifactUpdateEvent = {
|
|
@@ -281,6 +284,28 @@ const client = await A2AClient.fromCardUrl(
|
|
|
281
284
|
await client.sendMessage({ message: { messageId: uuidv4(), role: "user", parts: [{ kind: "text", text: "A message requiring custom headers." }], kind: "message" } });
|
|
282
285
|
```
|
|
283
286
|
|
|
287
|
+
### Example: Specifying a Timeout
|
|
288
|
+
|
|
289
|
+
This example creates a `fetch` wrapper that sets a timeout for every outgoing request.
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
import { A2AClient } from "@a2a-js/sdk/client";
|
|
293
|
+
|
|
294
|
+
// 1. Create a wrapper around the global fetch function.
|
|
295
|
+
const fetchWithTimeout: typeof fetch = async (url, init) => {
|
|
296
|
+
return fetch(url, { ...init, signal: AbortSignal.timeout(5000)});
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
// 2. Provide the custom fetch implementation to the client.
|
|
300
|
+
const client = await A2AClient.fromCardUrl(
|
|
301
|
+
"http://localhost:4000/.well-known/agent-card.json",
|
|
302
|
+
{ fetchImpl: fetchWithTimeout }
|
|
303
|
+
);
|
|
304
|
+
|
|
305
|
+
// Now, all requests made by this client instance will have a configured timeout.
|
|
306
|
+
await client.sendMessage({ message: { messageId: uuidv4(), role: "user", parts: [{ kind: "text", text: "A message requiring custom headers." }], kind: "message" } });
|
|
307
|
+
```
|
|
308
|
+
|
|
284
309
|
### Using the Provided `AuthenticationHandler`
|
|
285
310
|
|
|
286
311
|
For advanced authentication scenarios, the SDK includes a higher-order function `createAuthenticatingFetchWithRetry` and an `AuthenticationHandler` interface. This utility automatically adds authorization headers and can retry requests that fail with authentication errors (e.g., 401 Unauthorized).
|
|
@@ -354,15 +379,22 @@ class StreamingExecutor implements AgentExecutor {
|
|
|
354
379
|
requestContext: RequestContext,
|
|
355
380
|
eventBus: ExecutionEventBus
|
|
356
381
|
): Promise<void> {
|
|
357
|
-
const { taskId, contextId } = requestContext;
|
|
358
|
-
|
|
359
|
-
// 1.
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
382
|
+
const { taskId, contextId, userMessage, task } = requestContext;
|
|
383
|
+
|
|
384
|
+
// 1. Create and publish the initial task object if it doesn't exist.
|
|
385
|
+
if (!task) {
|
|
386
|
+
const initialTask: Task = {
|
|
387
|
+
kind: "task",
|
|
388
|
+
id: taskId,
|
|
389
|
+
contextId: contextId,
|
|
390
|
+
status: {
|
|
391
|
+
state: "submitted",
|
|
392
|
+
timestamp: new Date().toISOString(),
|
|
393
|
+
},
|
|
394
|
+
history: [userMessage]
|
|
395
|
+
};
|
|
396
|
+
eventBus.publish(initialTask);
|
|
397
|
+
}
|
|
366
398
|
|
|
367
399
|
// 2. Publish 'working' state.
|
|
368
400
|
eventBus.publish({
|
|
@@ -535,6 +567,107 @@ class CancellableExecutor implements AgentExecutor {
|
|
|
535
567
|
}
|
|
536
568
|
```
|
|
537
569
|
|
|
570
|
+
## A2A Push Notifications
|
|
571
|
+
|
|
572
|
+
For very long-running tasks (e.g., lasting minutes, hours, or even days) or when clients cannot or prefer not to maintain persistent connections (like mobile clients or serverless functions), A2A supports asynchronous updates via push notifications. This mechanism allows the A2A Server to actively notify a client-provided webhook when a significant task update occurs.
|
|
573
|
+
|
|
574
|
+
### Server-Side Configuration
|
|
575
|
+
|
|
576
|
+
To enable push notifications, your agent card must declare support:
|
|
577
|
+
|
|
578
|
+
```typescript
|
|
579
|
+
const movieAgentCard: AgentCard = {
|
|
580
|
+
// ... other properties
|
|
581
|
+
capabilities: {
|
|
582
|
+
streaming: true,
|
|
583
|
+
pushNotifications: true, // Enable push notifications
|
|
584
|
+
stateTransitionHistory: true,
|
|
585
|
+
},
|
|
586
|
+
// ... rest of agent card
|
|
587
|
+
};
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
When creating the `DefaultRequestHandler`, you can optionally provide custom push notification components:
|
|
591
|
+
|
|
592
|
+
```typescript
|
|
593
|
+
import {
|
|
594
|
+
DefaultRequestHandler,
|
|
595
|
+
InMemoryPushNotificationStore,
|
|
596
|
+
DefaultPushNotificationSender
|
|
597
|
+
} from "@a2a-js/sdk/server";
|
|
598
|
+
|
|
599
|
+
// Optional: Custom push notification store and sender
|
|
600
|
+
const pushNotificationStore = new InMemoryPushNotificationStore();
|
|
601
|
+
const pushNotificationSender = new DefaultPushNotificationSender(
|
|
602
|
+
pushNotificationStore,
|
|
603
|
+
{
|
|
604
|
+
timeout: 5000, // 5 second timeout
|
|
605
|
+
tokenHeaderName: 'X-A2A-Notification-Token' // Custom header name
|
|
606
|
+
}
|
|
607
|
+
);
|
|
608
|
+
|
|
609
|
+
const requestHandler = new DefaultRequestHandler(
|
|
610
|
+
movieAgentCard,
|
|
611
|
+
taskStore,
|
|
612
|
+
agentExecutor,
|
|
613
|
+
undefined, // eventBusManager (optional)
|
|
614
|
+
pushNotificationStore, // custom store
|
|
615
|
+
pushNotificationSender, // custom sender
|
|
616
|
+
undefined // extendedAgentCard (optional)
|
|
617
|
+
);
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
### Client-Side Usage
|
|
621
|
+
|
|
622
|
+
Configure push notifications when sending messages:
|
|
623
|
+
|
|
624
|
+
```typescript
|
|
625
|
+
// Configure push notification for a message
|
|
626
|
+
const pushConfig: PushNotificationConfig = {
|
|
627
|
+
id: "my-notification-config", // Optional, defaults to task ID
|
|
628
|
+
url: "https://my-app.com/webhook/task-updates",
|
|
629
|
+
token: "your-auth-token" // Optional authentication token
|
|
630
|
+
};
|
|
631
|
+
|
|
632
|
+
const sendParams: MessageSendParams = {
|
|
633
|
+
message: {
|
|
634
|
+
messageId: uuidv4(),
|
|
635
|
+
role: "user",
|
|
636
|
+
parts: [{ kind: "text", text: "Hello, agent!" }],
|
|
637
|
+
kind: "message",
|
|
638
|
+
},
|
|
639
|
+
configuration: {
|
|
640
|
+
blocking: true,
|
|
641
|
+
acceptedOutputModes: ["text/plain"],
|
|
642
|
+
pushNotificationConfig: pushConfig // Add push notification config
|
|
643
|
+
},
|
|
644
|
+
};
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
### Webhook Endpoint Implementation
|
|
648
|
+
|
|
649
|
+
Your webhook endpoint should expect POST requests with the task data:
|
|
650
|
+
|
|
651
|
+
```typescript
|
|
652
|
+
// Example Express.js webhook endpoint
|
|
653
|
+
app.post('/webhook/task-updates', (req, res) => {
|
|
654
|
+
const task = req.body; // The complete task object
|
|
655
|
+
|
|
656
|
+
// Verify the token if provided
|
|
657
|
+
const token = req.headers['x-a2a-notification-token'];
|
|
658
|
+
if (token !== 'your-auth-token') {
|
|
659
|
+
return res.status(401).json({ error: 'Unauthorized' });
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
console.log(`Task ${task.id} status: ${task.status.state}`);
|
|
663
|
+
|
|
664
|
+
// Process the task update
|
|
665
|
+
// ...
|
|
666
|
+
|
|
667
|
+
res.status(200).json({ received: true });
|
|
668
|
+
});
|
|
669
|
+
```
|
|
670
|
+
|
|
538
671
|
## License
|
|
539
672
|
|
|
540
673
|
This project is licensed under the terms of the [Apache 2.0 License](https://raw.githubusercontent.com/google-a2a/a2a-python/refs/heads/main/LICENSE).
|
|
@@ -100,10 +100,8 @@ var JsonRpcTransportHandler = class {
|
|
|
100
100
|
} else {
|
|
101
101
|
throw A2AError.parseError("Invalid request body type.");
|
|
102
102
|
}
|
|
103
|
-
if (
|
|
104
|
-
throw A2AError.invalidRequest(
|
|
105
|
-
"Invalid JSON-RPC request structure."
|
|
106
|
-
);
|
|
103
|
+
if (!this.isRequestValid(rpcRequest)) {
|
|
104
|
+
throw A2AError.invalidRequest("Invalid JSON-RPC Request.");
|
|
107
105
|
}
|
|
108
106
|
} catch (error) {
|
|
109
107
|
const a2aError = error instanceof A2AError ? error : A2AError.parseError(error.message || "Failed to parse JSON request.");
|
|
@@ -123,8 +121,8 @@ var JsonRpcTransportHandler = class {
|
|
|
123
121
|
result
|
|
124
122
|
};
|
|
125
123
|
}
|
|
126
|
-
if (!rpcRequest.params) {
|
|
127
|
-
throw A2AError.invalidParams(`
|
|
124
|
+
if (!this.paramsAreValid(rpcRequest.params)) {
|
|
125
|
+
throw A2AError.invalidParams(`Invalid method parameters.`);
|
|
128
126
|
}
|
|
129
127
|
if (method === "message/stream" || method === "tasks/resubscribe") {
|
|
130
128
|
const params = rpcRequest.params;
|
|
@@ -199,6 +197,37 @@ var JsonRpcTransportHandler = class {
|
|
|
199
197
|
};
|
|
200
198
|
}
|
|
201
199
|
}
|
|
200
|
+
// Validates the basic structure of a JSON-RPC request
|
|
201
|
+
isRequestValid(rpcRequest) {
|
|
202
|
+
if (rpcRequest.jsonrpc !== "2.0") {
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
if ("id" in rpcRequest) {
|
|
206
|
+
const id = rpcRequest.id;
|
|
207
|
+
const isString = typeof id === "string";
|
|
208
|
+
const isInteger = typeof id === "number" && Number.isInteger(id);
|
|
209
|
+
const isNull = id === null;
|
|
210
|
+
if (!isString && !isInteger && !isNull) {
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
if (!rpcRequest.method || typeof rpcRequest.method !== "string") {
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
return true;
|
|
218
|
+
}
|
|
219
|
+
// Validates that params is an object with non-empty string keys
|
|
220
|
+
paramsAreValid(params) {
|
|
221
|
+
if (typeof params !== "object" || params === null || Array.isArray(params)) {
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
for (const key of Object.keys(params)) {
|
|
225
|
+
if (key === "") {
|
|
226
|
+
return false;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return true;
|
|
230
|
+
}
|
|
202
231
|
};
|
|
203
232
|
|
|
204
233
|
export {
|
package/dist/client/index.cjs
CHANGED
|
@@ -243,6 +243,28 @@ var A2AClient = class _A2AClient {
|
|
|
243
243
|
params
|
|
244
244
|
);
|
|
245
245
|
}
|
|
246
|
+
/**
|
|
247
|
+
* Lists the push notification configurations for a given task.
|
|
248
|
+
* @param params Parameters containing the taskId.
|
|
249
|
+
* @returns A Promise resolving to ListTaskPushNotificationConfigResponse.
|
|
250
|
+
*/
|
|
251
|
+
async listTaskPushNotificationConfig(params) {
|
|
252
|
+
return this._postRpcRequest(
|
|
253
|
+
"tasks/pushNotificationConfig/list",
|
|
254
|
+
params
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Deletes the push notification configuration for a given task.
|
|
259
|
+
* @param params Parameters containing the taskId and push notification configuration ID.
|
|
260
|
+
* @returns A Promise resolving to DeleteTaskPushNotificationConfigResponse.
|
|
261
|
+
*/
|
|
262
|
+
async deleteTaskPushNotificationConfig(params) {
|
|
263
|
+
return this._postRpcRequest(
|
|
264
|
+
"tasks/pushNotificationConfig/delete",
|
|
265
|
+
params
|
|
266
|
+
);
|
|
267
|
+
}
|
|
246
268
|
/**
|
|
247
269
|
* Retrieves a task by its ID.
|
|
248
270
|
* @param params Parameters containing the taskId and optional historyLength.
|
|
@@ -259,6 +281,17 @@ var A2AClient = class _A2AClient {
|
|
|
259
281
|
async cancelTask(params) {
|
|
260
282
|
return this._postRpcRequest("tasks/cancel", params);
|
|
261
283
|
}
|
|
284
|
+
/**
|
|
285
|
+
* @template TExtensionParams The type of parameters for the custom extension method.
|
|
286
|
+
* @template TExtensionResponse The type of response expected from the custom extension method.
|
|
287
|
+
* This should extend JSONRPCResponse. This ensures the extension response is still a valid A2A response.
|
|
288
|
+
* @param method Custom JSON-RPC method defined in the AgentCard's extensions.
|
|
289
|
+
* @param params Extension paramters defined in the AgentCard's extensions.
|
|
290
|
+
* @returns A Promise that resolves to the RPC response.
|
|
291
|
+
*/
|
|
292
|
+
async callExtensionMethod(method, params) {
|
|
293
|
+
return this._postRpcRequest(method, params);
|
|
294
|
+
}
|
|
262
295
|
/**
|
|
263
296
|
* Resubscribes to a task's event stream using Server-Sent Events (SSE).
|
|
264
297
|
* This is used if a previous SSE connection for an active task was broken.
|
package/dist/client/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
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';
|
|
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, a5 as ListTaskPushNotificationConfigParams, j as ListTaskPushNotificationConfigResponse, a7 as DeleteTaskPushNotificationConfigParams, g as DeleteTaskPushNotificationConfigResponse, 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
4
|
interface A2AClientOptions {
|
|
@@ -81,6 +81,18 @@ declare class A2AClient {
|
|
|
81
81
|
* @returns A Promise resolving to GetTaskPushNotificationConfigResponse.
|
|
82
82
|
*/
|
|
83
83
|
getTaskPushNotificationConfig(params: TaskIdParams): Promise<GetTaskPushNotificationConfigResponse>;
|
|
84
|
+
/**
|
|
85
|
+
* Lists the push notification configurations for a given task.
|
|
86
|
+
* @param params Parameters containing the taskId.
|
|
87
|
+
* @returns A Promise resolving to ListTaskPushNotificationConfigResponse.
|
|
88
|
+
*/
|
|
89
|
+
listTaskPushNotificationConfig(params: ListTaskPushNotificationConfigParams): Promise<ListTaskPushNotificationConfigResponse>;
|
|
90
|
+
/**
|
|
91
|
+
* Deletes the push notification configuration for a given task.
|
|
92
|
+
* @param params Parameters containing the taskId and push notification configuration ID.
|
|
93
|
+
* @returns A Promise resolving to DeleteTaskPushNotificationConfigResponse.
|
|
94
|
+
*/
|
|
95
|
+
deleteTaskPushNotificationConfig(params: DeleteTaskPushNotificationConfigParams): Promise<DeleteTaskPushNotificationConfigResponse>;
|
|
84
96
|
/**
|
|
85
97
|
* Retrieves a task by its ID.
|
|
86
98
|
* @param params Parameters containing the taskId and optional historyLength.
|
|
@@ -93,6 +105,15 @@ declare class A2AClient {
|
|
|
93
105
|
* @returns A Promise resolving to CancelTaskResponse, which contains the updated Task object or an error.
|
|
94
106
|
*/
|
|
95
107
|
cancelTask(params: TaskIdParams): Promise<CancelTaskResponse>;
|
|
108
|
+
/**
|
|
109
|
+
* @template TExtensionParams The type of parameters for the custom extension method.
|
|
110
|
+
* @template TExtensionResponse The type of response expected from the custom extension method.
|
|
111
|
+
* This should extend JSONRPCResponse. This ensures the extension response is still a valid A2A response.
|
|
112
|
+
* @param method Custom JSON-RPC method defined in the AgentCard's extensions.
|
|
113
|
+
* @param params Extension paramters defined in the AgentCard's extensions.
|
|
114
|
+
* @returns A Promise that resolves to the RPC response.
|
|
115
|
+
*/
|
|
116
|
+
callExtensionMethod<TExtensionParams, TExtensionResponse extends JSONRPCResponse>(method: string, params: TExtensionParams): Promise<TExtensionResponse>;
|
|
96
117
|
/**
|
|
97
118
|
* Resubscribes to a task's event stream using Server-Sent Events (SSE).
|
|
98
119
|
* This is used if a previous SSE connection for an active task was broken.
|
package/dist/client/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
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.js';
|
|
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, a5 as ListTaskPushNotificationConfigParams, j as ListTaskPushNotificationConfigResponse, a7 as DeleteTaskPushNotificationConfigParams, g as DeleteTaskPushNotificationConfigResponse, V as TaskQueryParams, G as GetTaskResponse, C as CancelTaskResponse, i as JSONRPCResponse, J as JSONRPCErrorResponse } from '../types-DNKcmF0f.js';
|
|
2
2
|
|
|
3
3
|
type A2AStreamEventData = Message | Task | TaskStatusUpdateEvent | TaskArtifactUpdateEvent;
|
|
4
4
|
interface A2AClientOptions {
|
|
@@ -81,6 +81,18 @@ declare class A2AClient {
|
|
|
81
81
|
* @returns A Promise resolving to GetTaskPushNotificationConfigResponse.
|
|
82
82
|
*/
|
|
83
83
|
getTaskPushNotificationConfig(params: TaskIdParams): Promise<GetTaskPushNotificationConfigResponse>;
|
|
84
|
+
/**
|
|
85
|
+
* Lists the push notification configurations for a given task.
|
|
86
|
+
* @param params Parameters containing the taskId.
|
|
87
|
+
* @returns A Promise resolving to ListTaskPushNotificationConfigResponse.
|
|
88
|
+
*/
|
|
89
|
+
listTaskPushNotificationConfig(params: ListTaskPushNotificationConfigParams): Promise<ListTaskPushNotificationConfigResponse>;
|
|
90
|
+
/**
|
|
91
|
+
* Deletes the push notification configuration for a given task.
|
|
92
|
+
* @param params Parameters containing the taskId and push notification configuration ID.
|
|
93
|
+
* @returns A Promise resolving to DeleteTaskPushNotificationConfigResponse.
|
|
94
|
+
*/
|
|
95
|
+
deleteTaskPushNotificationConfig(params: DeleteTaskPushNotificationConfigParams): Promise<DeleteTaskPushNotificationConfigResponse>;
|
|
84
96
|
/**
|
|
85
97
|
* Retrieves a task by its ID.
|
|
86
98
|
* @param params Parameters containing the taskId and optional historyLength.
|
|
@@ -93,6 +105,15 @@ declare class A2AClient {
|
|
|
93
105
|
* @returns A Promise resolving to CancelTaskResponse, which contains the updated Task object or an error.
|
|
94
106
|
*/
|
|
95
107
|
cancelTask(params: TaskIdParams): Promise<CancelTaskResponse>;
|
|
108
|
+
/**
|
|
109
|
+
* @template TExtensionParams The type of parameters for the custom extension method.
|
|
110
|
+
* @template TExtensionResponse The type of response expected from the custom extension method.
|
|
111
|
+
* This should extend JSONRPCResponse. This ensures the extension response is still a valid A2A response.
|
|
112
|
+
* @param method Custom JSON-RPC method defined in the AgentCard's extensions.
|
|
113
|
+
* @param params Extension paramters defined in the AgentCard's extensions.
|
|
114
|
+
* @returns A Promise that resolves to the RPC response.
|
|
115
|
+
*/
|
|
116
|
+
callExtensionMethod<TExtensionParams, TExtensionResponse extends JSONRPCResponse>(method: string, params: TExtensionParams): Promise<TExtensionResponse>;
|
|
96
117
|
/**
|
|
97
118
|
* Resubscribes to a task's event stream using Server-Sent Events (SSE).
|
|
98
119
|
* This is used if a previous SSE connection for an active task was broken.
|
package/dist/client/index.js
CHANGED
|
@@ -218,6 +218,28 @@ var A2AClient = class _A2AClient {
|
|
|
218
218
|
params
|
|
219
219
|
);
|
|
220
220
|
}
|
|
221
|
+
/**
|
|
222
|
+
* Lists the push notification configurations for a given task.
|
|
223
|
+
* @param params Parameters containing the taskId.
|
|
224
|
+
* @returns A Promise resolving to ListTaskPushNotificationConfigResponse.
|
|
225
|
+
*/
|
|
226
|
+
async listTaskPushNotificationConfig(params) {
|
|
227
|
+
return this._postRpcRequest(
|
|
228
|
+
"tasks/pushNotificationConfig/list",
|
|
229
|
+
params
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Deletes the push notification configuration for a given task.
|
|
234
|
+
* @param params Parameters containing the taskId and push notification configuration ID.
|
|
235
|
+
* @returns A Promise resolving to DeleteTaskPushNotificationConfigResponse.
|
|
236
|
+
*/
|
|
237
|
+
async deleteTaskPushNotificationConfig(params) {
|
|
238
|
+
return this._postRpcRequest(
|
|
239
|
+
"tasks/pushNotificationConfig/delete",
|
|
240
|
+
params
|
|
241
|
+
);
|
|
242
|
+
}
|
|
221
243
|
/**
|
|
222
244
|
* Retrieves a task by its ID.
|
|
223
245
|
* @param params Parameters containing the taskId and optional historyLength.
|
|
@@ -234,6 +256,17 @@ var A2AClient = class _A2AClient {
|
|
|
234
256
|
async cancelTask(params) {
|
|
235
257
|
return this._postRpcRequest("tasks/cancel", params);
|
|
236
258
|
}
|
|
259
|
+
/**
|
|
260
|
+
* @template TExtensionParams The type of parameters for the custom extension method.
|
|
261
|
+
* @template TExtensionResponse The type of response expected from the custom extension method.
|
|
262
|
+
* This should extend JSONRPCResponse. This ensures the extension response is still a valid A2A response.
|
|
263
|
+
* @param method Custom JSON-RPC method defined in the AgentCard's extensions.
|
|
264
|
+
* @param params Extension paramters defined in the AgentCard's extensions.
|
|
265
|
+
* @returns A Promise that resolves to the RPC response.
|
|
266
|
+
*/
|
|
267
|
+
async callExtensionMethod(method, params) {
|
|
268
|
+
return this._postRpcRequest(method, params);
|
|
269
|
+
}
|
|
237
270
|
/**
|
|
238
271
|
* Resubscribes to a task's event stream using Server-Sent Events (SSE).
|
|
239
272
|
* This is used if a previous SSE connection for an active task was broken.
|
|
@@ -138,10 +138,8 @@ var JsonRpcTransportHandler = class {
|
|
|
138
138
|
} else {
|
|
139
139
|
throw A2AError.parseError("Invalid request body type.");
|
|
140
140
|
}
|
|
141
|
-
if (
|
|
142
|
-
throw A2AError.invalidRequest(
|
|
143
|
-
"Invalid JSON-RPC request structure."
|
|
144
|
-
);
|
|
141
|
+
if (!this.isRequestValid(rpcRequest)) {
|
|
142
|
+
throw A2AError.invalidRequest("Invalid JSON-RPC Request.");
|
|
145
143
|
}
|
|
146
144
|
} catch (error) {
|
|
147
145
|
const a2aError = error instanceof A2AError ? error : A2AError.parseError(error.message || "Failed to parse JSON request.");
|
|
@@ -161,8 +159,8 @@ var JsonRpcTransportHandler = class {
|
|
|
161
159
|
result
|
|
162
160
|
};
|
|
163
161
|
}
|
|
164
|
-
if (!rpcRequest.params) {
|
|
165
|
-
throw A2AError.invalidParams(`
|
|
162
|
+
if (!this.paramsAreValid(rpcRequest.params)) {
|
|
163
|
+
throw A2AError.invalidParams(`Invalid method parameters.`);
|
|
166
164
|
}
|
|
167
165
|
if (method === "message/stream" || method === "tasks/resubscribe") {
|
|
168
166
|
const params = rpcRequest.params;
|
|
@@ -237,6 +235,37 @@ var JsonRpcTransportHandler = class {
|
|
|
237
235
|
};
|
|
238
236
|
}
|
|
239
237
|
}
|
|
238
|
+
// Validates the basic structure of a JSON-RPC request
|
|
239
|
+
isRequestValid(rpcRequest) {
|
|
240
|
+
if (rpcRequest.jsonrpc !== "2.0") {
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
if ("id" in rpcRequest) {
|
|
244
|
+
const id = rpcRequest.id;
|
|
245
|
+
const isString = typeof id === "string";
|
|
246
|
+
const isInteger = typeof id === "number" && Number.isInteger(id);
|
|
247
|
+
const isNull = id === null;
|
|
248
|
+
if (!isString && !isInteger && !isNull) {
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
if (!rpcRequest.method || typeof rpcRequest.method !== "string") {
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
return true;
|
|
256
|
+
}
|
|
257
|
+
// Validates that params is an object with non-empty string keys
|
|
258
|
+
paramsAreValid(params) {
|
|
259
|
+
if (typeof params !== "object" || params === null || Array.isArray(params)) {
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
for (const key of Object.keys(params)) {
|
|
263
|
+
if (key === "") {
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return true;
|
|
268
|
+
}
|
|
240
269
|
};
|
|
241
270
|
|
|
242
271
|
// src/constants.ts
|
|
@@ -256,12 +285,24 @@ var A2AExpressApp = class {
|
|
|
256
285
|
* @param app Optional existing Express app.
|
|
257
286
|
* @param baseUrl The base URL for A2A endpoints (e.g., "/a2a/api").
|
|
258
287
|
* @param middlewares Optional array of Express middlewares to apply to the A2A routes.
|
|
259
|
-
* @param agentCardPath Optional custom path for the agent card endpoint (defaults to
|
|
288
|
+
* @param agentCardPath Optional custom path for the agent card endpoint (defaults to .well-known/agent-card.json).
|
|
260
289
|
* @returns The Express app with A2A routes.
|
|
261
290
|
*/
|
|
262
291
|
setupRoutes(app, baseUrl = "", middlewares, agentCardPath = AGENT_CARD_PATH) {
|
|
263
292
|
const router = import_express.default.Router();
|
|
264
293
|
router.use(import_express.default.json(), ...middlewares ?? []);
|
|
294
|
+
router.use((err, req, res, next) => {
|
|
295
|
+
if (err instanceof SyntaxError && "body" in err) {
|
|
296
|
+
const a2aError = A2AError.parseError("Invalid JSON payload.");
|
|
297
|
+
const errorResponse = {
|
|
298
|
+
jsonrpc: "2.0",
|
|
299
|
+
id: null,
|
|
300
|
+
error: a2aError.toJSONRPCError()
|
|
301
|
+
};
|
|
302
|
+
return res.status(400).json(errorResponse);
|
|
303
|
+
}
|
|
304
|
+
next(err);
|
|
305
|
+
});
|
|
265
306
|
router.get(`/${agentCardPath}`, async (req, res) => {
|
|
266
307
|
try {
|
|
267
308
|
const agentCard = await this.requestHandler.getAgentCard();
|
|
@@ -11,7 +11,7 @@ declare class A2AExpressApp {
|
|
|
11
11
|
* @param app Optional existing Express app.
|
|
12
12
|
* @param baseUrl The base URL for A2A endpoints (e.g., "/a2a/api").
|
|
13
13
|
* @param middlewares Optional array of Express middlewares to apply to the A2A routes.
|
|
14
|
-
* @param agentCardPath Optional custom path for the agent card endpoint (defaults to
|
|
14
|
+
* @param agentCardPath Optional custom path for the agent card endpoint (defaults to .well-known/agent-card.json).
|
|
15
15
|
* @returns The Express app with A2A routes.
|
|
16
16
|
*/
|
|
17
17
|
setupRoutes(app: Express, baseUrl?: string, middlewares?: Array<RequestHandler | ErrorRequestHandler>, agentCardPath?: string): Express;
|
|
@@ -11,7 +11,7 @@ declare class A2AExpressApp {
|
|
|
11
11
|
* @param app Optional existing Express app.
|
|
12
12
|
* @param baseUrl The base URL for A2A endpoints (e.g., "/a2a/api").
|
|
13
13
|
* @param middlewares Optional array of Express middlewares to apply to the A2A routes.
|
|
14
|
-
* @param agentCardPath Optional custom path for the agent card endpoint (defaults to
|
|
14
|
+
* @param agentCardPath Optional custom path for the agent card endpoint (defaults to .well-known/agent-card.json).
|
|
15
15
|
* @returns The Express app with A2A routes.
|
|
16
16
|
*/
|
|
17
17
|
setupRoutes(app: Express, baseUrl?: string, middlewares?: Array<RequestHandler | ErrorRequestHandler>, agentCardPath?: string): Express;
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
A2AError,
|
|
6
6
|
JsonRpcTransportHandler
|
|
7
|
-
} from "../../chunk-
|
|
7
|
+
} from "../../chunk-SY3G7ITG.js";
|
|
8
8
|
|
|
9
9
|
// src/server/express/a2a_express_app.ts
|
|
10
10
|
import express from "express";
|
|
@@ -21,12 +21,24 @@ var A2AExpressApp = class {
|
|
|
21
21
|
* @param app Optional existing Express app.
|
|
22
22
|
* @param baseUrl The base URL for A2A endpoints (e.g., "/a2a/api").
|
|
23
23
|
* @param middlewares Optional array of Express middlewares to apply to the A2A routes.
|
|
24
|
-
* @param agentCardPath Optional custom path for the agent card endpoint (defaults to
|
|
24
|
+
* @param agentCardPath Optional custom path for the agent card endpoint (defaults to .well-known/agent-card.json).
|
|
25
25
|
* @returns The Express app with A2A routes.
|
|
26
26
|
*/
|
|
27
27
|
setupRoutes(app, baseUrl = "", middlewares, agentCardPath = AGENT_CARD_PATH) {
|
|
28
28
|
const router = express.Router();
|
|
29
29
|
router.use(express.json(), ...middlewares ?? []);
|
|
30
|
+
router.use((err, req, res, next) => {
|
|
31
|
+
if (err instanceof SyntaxError && "body" in err) {
|
|
32
|
+
const a2aError = A2AError.parseError("Invalid JSON payload.");
|
|
33
|
+
const errorResponse = {
|
|
34
|
+
jsonrpc: "2.0",
|
|
35
|
+
id: null,
|
|
36
|
+
error: a2aError.toJSONRPCError()
|
|
37
|
+
};
|
|
38
|
+
return res.status(400).json(errorResponse);
|
|
39
|
+
}
|
|
40
|
+
next(err);
|
|
41
|
+
});
|
|
30
42
|
router.get(`/${agentCardPath}`, async (req, res) => {
|
|
31
43
|
try {
|
|
32
44
|
const agentCard = await this.requestHandler.getAgentCard();
|