@a2a-js/sdk 0.3.3 → 0.3.4
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 +101 -0
- 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/index.cjs +136 -19
- package/dist/server/index.d.cts +40 -4
- package/dist/server/index.d.ts +40 -4
- package/dist/server/index.js +134 -19
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -535,6 +535,107 @@ class CancellableExecutor implements AgentExecutor {
|
|
|
535
535
|
}
|
|
536
536
|
```
|
|
537
537
|
|
|
538
|
+
## A2A Push Notifications
|
|
539
|
+
|
|
540
|
+
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.
|
|
541
|
+
|
|
542
|
+
### Server-Side Configuration
|
|
543
|
+
|
|
544
|
+
To enable push notifications, your agent card must declare support:
|
|
545
|
+
|
|
546
|
+
```typescript
|
|
547
|
+
const movieAgentCard: AgentCard = {
|
|
548
|
+
// ... other properties
|
|
549
|
+
capabilities: {
|
|
550
|
+
streaming: true,
|
|
551
|
+
pushNotifications: true, // Enable push notifications
|
|
552
|
+
stateTransitionHistory: true,
|
|
553
|
+
},
|
|
554
|
+
// ... rest of agent card
|
|
555
|
+
};
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
When creating the `DefaultRequestHandler`, you can optionally provide custom push notification components:
|
|
559
|
+
|
|
560
|
+
```typescript
|
|
561
|
+
import {
|
|
562
|
+
DefaultRequestHandler,
|
|
563
|
+
InMemoryPushNotificationStore,
|
|
564
|
+
DefaultPushNotificationSender
|
|
565
|
+
} from "@a2a-js/sdk/server";
|
|
566
|
+
|
|
567
|
+
// Optional: Custom push notification store and sender
|
|
568
|
+
const pushNotificationStore = new InMemoryPushNotificationStore();
|
|
569
|
+
const pushNotificationSender = new DefaultPushNotificationSender(
|
|
570
|
+
pushNotificationStore,
|
|
571
|
+
{
|
|
572
|
+
timeout: 5000, // 5 second timeout
|
|
573
|
+
tokenHeaderName: 'X-A2A-Notification-Token' // Custom header name
|
|
574
|
+
}
|
|
575
|
+
);
|
|
576
|
+
|
|
577
|
+
const requestHandler = new DefaultRequestHandler(
|
|
578
|
+
movieAgentCard,
|
|
579
|
+
taskStore,
|
|
580
|
+
agentExecutor,
|
|
581
|
+
undefined, // eventBusManager (optional)
|
|
582
|
+
pushNotificationStore, // custom store
|
|
583
|
+
pushNotificationSender, // custom sender
|
|
584
|
+
undefined // extendedAgentCard (optional)
|
|
585
|
+
);
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
### Client-Side Usage
|
|
589
|
+
|
|
590
|
+
Configure push notifications when sending messages:
|
|
591
|
+
|
|
592
|
+
```typescript
|
|
593
|
+
// Configure push notification for a message
|
|
594
|
+
const pushConfig: PushNotificationConfig = {
|
|
595
|
+
id: "my-notification-config", // Optional, defaults to task ID
|
|
596
|
+
url: "https://my-app.com/webhook/task-updates",
|
|
597
|
+
token: "your-auth-token" // Optional authentication token
|
|
598
|
+
};
|
|
599
|
+
|
|
600
|
+
const sendParams: MessageSendParams = {
|
|
601
|
+
message: {
|
|
602
|
+
messageId: uuidv4(),
|
|
603
|
+
role: "user",
|
|
604
|
+
parts: [{ kind: "text", text: "Hello, agent!" }],
|
|
605
|
+
kind: "message",
|
|
606
|
+
},
|
|
607
|
+
configuration: {
|
|
608
|
+
blocking: true,
|
|
609
|
+
acceptedOutputModes: ["text/plain"],
|
|
610
|
+
pushNotificationConfig: pushConfig // Add push notification config
|
|
611
|
+
},
|
|
612
|
+
};
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
### Webhook Endpoint Implementation
|
|
616
|
+
|
|
617
|
+
Your webhook endpoint should expect POST requests with the task data:
|
|
618
|
+
|
|
619
|
+
```typescript
|
|
620
|
+
// Example Express.js webhook endpoint
|
|
621
|
+
app.post('/webhook/task-updates', (req, res) => {
|
|
622
|
+
const task = req.body; // The complete task object
|
|
623
|
+
|
|
624
|
+
// Verify the token if provided
|
|
625
|
+
const token = req.headers['x-a2a-notification-token'];
|
|
626
|
+
if (token !== 'your-auth-token') {
|
|
627
|
+
return res.status(401).json({ error: 'Unauthorized' });
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
console.log(`Task ${task.id} status: ${task.status.state}`);
|
|
631
|
+
|
|
632
|
+
// Process the task update
|
|
633
|
+
// ...
|
|
634
|
+
|
|
635
|
+
res.status(200).json({ received: true });
|
|
636
|
+
});
|
|
637
|
+
```
|
|
638
|
+
|
|
538
639
|
## License
|
|
539
640
|
|
|
540
641
|
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).
|
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.
|
package/dist/server/index.cjs
CHANGED
|
@@ -22,8 +22,10 @@ __export(server_exports, {
|
|
|
22
22
|
A2AError: () => A2AError,
|
|
23
23
|
DefaultExecutionEventBus: () => DefaultExecutionEventBus,
|
|
24
24
|
DefaultExecutionEventBusManager: () => DefaultExecutionEventBusManager,
|
|
25
|
+
DefaultPushNotificationSender: () => DefaultPushNotificationSender,
|
|
25
26
|
DefaultRequestHandler: () => DefaultRequestHandler,
|
|
26
27
|
ExecutionEventQueue: () => ExecutionEventQueue,
|
|
28
|
+
InMemoryPushNotificationStore: () => InMemoryPushNotificationStore,
|
|
27
29
|
InMemoryTaskStore: () => InMemoryTaskStore,
|
|
28
30
|
JsonRpcTransportHandler: () => JsonRpcTransportHandler,
|
|
29
31
|
RequestContext: () => RequestContext,
|
|
@@ -366,6 +368,97 @@ var ResultManager = class {
|
|
|
366
368
|
}
|
|
367
369
|
};
|
|
368
370
|
|
|
371
|
+
// src/server/push_notification/push_notification_store.ts
|
|
372
|
+
var InMemoryPushNotificationStore = class {
|
|
373
|
+
store = /* @__PURE__ */ new Map();
|
|
374
|
+
async save(taskId, pushNotificationConfig) {
|
|
375
|
+
const configs = this.store.get(taskId) || [];
|
|
376
|
+
if (!pushNotificationConfig.id) {
|
|
377
|
+
pushNotificationConfig.id = taskId;
|
|
378
|
+
}
|
|
379
|
+
const existingIndex = configs.findIndex((config) => config.id === pushNotificationConfig.id);
|
|
380
|
+
if (existingIndex !== -1) {
|
|
381
|
+
configs.splice(existingIndex, 1);
|
|
382
|
+
}
|
|
383
|
+
configs.push(pushNotificationConfig);
|
|
384
|
+
this.store.set(taskId, configs);
|
|
385
|
+
}
|
|
386
|
+
async load(taskId) {
|
|
387
|
+
const configs = this.store.get(taskId);
|
|
388
|
+
return configs || [];
|
|
389
|
+
}
|
|
390
|
+
async delete(taskId, configId) {
|
|
391
|
+
if (configId === void 0) {
|
|
392
|
+
configId = taskId;
|
|
393
|
+
}
|
|
394
|
+
const configs = this.store.get(taskId);
|
|
395
|
+
if (!configs) {
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
const configIndex = configs.findIndex((config) => config.id === configId);
|
|
399
|
+
if (configIndex !== -1) {
|
|
400
|
+
configs.splice(configIndex, 1);
|
|
401
|
+
}
|
|
402
|
+
if (configs.length === 0) {
|
|
403
|
+
this.store.delete(taskId);
|
|
404
|
+
} else {
|
|
405
|
+
this.store.set(taskId, configs);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
// src/server/push_notification/default_push_notification_sender.ts
|
|
411
|
+
var DefaultPushNotificationSender = class {
|
|
412
|
+
pushNotificationStore;
|
|
413
|
+
options;
|
|
414
|
+
constructor(pushNotificationStore, options = {}) {
|
|
415
|
+
this.pushNotificationStore = pushNotificationStore;
|
|
416
|
+
this.options = {
|
|
417
|
+
timeout: 5e3,
|
|
418
|
+
tokenHeaderName: "X-A2A-Notification-Token",
|
|
419
|
+
...options
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
async send(task) {
|
|
423
|
+
const pushConfigs = await this.pushNotificationStore.load(task.id);
|
|
424
|
+
if (!pushConfigs || pushConfigs.length === 0) {
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
pushConfigs.forEach((pushConfig) => {
|
|
428
|
+
this._dispatchNotification(task, pushConfig).catch((error) => {
|
|
429
|
+
console.error(`Error sending push notification for task_id=${task.id} to URL: ${pushConfig.url}. Error:`, error);
|
|
430
|
+
});
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
async _dispatchNotification(task, pushConfig) {
|
|
434
|
+
const url = pushConfig.url;
|
|
435
|
+
const controller = new AbortController();
|
|
436
|
+
const timeoutId = setTimeout(() => controller.abort(), this.options.timeout);
|
|
437
|
+
try {
|
|
438
|
+
const headers = {
|
|
439
|
+
"Content-Type": "application/json"
|
|
440
|
+
};
|
|
441
|
+
if (pushConfig.token) {
|
|
442
|
+
headers[this.options.tokenHeaderName] = pushConfig.token;
|
|
443
|
+
}
|
|
444
|
+
const response = await fetch(url, {
|
|
445
|
+
method: "POST",
|
|
446
|
+
headers,
|
|
447
|
+
body: JSON.stringify(task),
|
|
448
|
+
signal: controller.signal
|
|
449
|
+
});
|
|
450
|
+
if (!response.ok) {
|
|
451
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
452
|
+
}
|
|
453
|
+
console.info(`Push notification sent for task_id=${task.id} to URL: ${url}`);
|
|
454
|
+
} catch (error) {
|
|
455
|
+
console.error(`Error sending push notification for task_id=${task.id} to URL: ${url}. Error:`, error);
|
|
456
|
+
} finally {
|
|
457
|
+
clearTimeout(timeoutId);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
|
|
369
462
|
// src/server/request_handler/default_request_handler.ts
|
|
370
463
|
var terminalStates = ["completed", "failed", "canceled", "rejected"];
|
|
371
464
|
var DefaultRequestHandler = class {
|
|
@@ -374,14 +467,18 @@ var DefaultRequestHandler = class {
|
|
|
374
467
|
taskStore;
|
|
375
468
|
agentExecutor;
|
|
376
469
|
eventBusManager;
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
constructor(agentCard, taskStore, agentExecutor, eventBusManager = new DefaultExecutionEventBusManager(), extendedAgentCard) {
|
|
470
|
+
pushNotificationStore;
|
|
471
|
+
pushNotificationSender;
|
|
472
|
+
constructor(agentCard, taskStore, agentExecutor, eventBusManager = new DefaultExecutionEventBusManager(), pushNotificationStore, pushNotificationSender, extendedAgentCard) {
|
|
380
473
|
this.agentCard = agentCard;
|
|
381
474
|
this.taskStore = taskStore;
|
|
382
475
|
this.agentExecutor = agentExecutor;
|
|
383
476
|
this.eventBusManager = eventBusManager;
|
|
384
477
|
this.extendedAgentCard = extendedAgentCard;
|
|
478
|
+
if (agentCard.capabilities.pushNotifications) {
|
|
479
|
+
this.pushNotificationStore = pushNotificationStore || new InMemoryPushNotificationStore();
|
|
480
|
+
this.pushNotificationSender = pushNotificationSender || new DefaultPushNotificationSender(this.pushNotificationStore);
|
|
481
|
+
}
|
|
385
482
|
}
|
|
386
483
|
async getAgentCard() {
|
|
387
484
|
return this.agentCard;
|
|
@@ -433,6 +530,7 @@ var DefaultRequestHandler = class {
|
|
|
433
530
|
try {
|
|
434
531
|
for await (const event of eventQueue.events()) {
|
|
435
532
|
await resultManager.processEvent(event);
|
|
533
|
+
await this._sendPushNotificationIfNeeded(event);
|
|
436
534
|
if (options?.firstResultResolver && !firstResultSent) {
|
|
437
535
|
if (event.kind === "message" || event.kind === "task") {
|
|
438
536
|
options.firstResultResolver(event);
|
|
@@ -464,6 +562,9 @@ var DefaultRequestHandler = class {
|
|
|
464
562
|
resultManager.setContext(incomingMessage);
|
|
465
563
|
const requestContext = await this._createRequestContext(incomingMessage, taskId, false);
|
|
466
564
|
const finalMessageForAgent = requestContext.userMessage;
|
|
565
|
+
if (params.configuration?.pushNotificationConfig && this.agentCard.capabilities.pushNotifications) {
|
|
566
|
+
await this.pushNotificationStore?.save(taskId, params.configuration.pushNotificationConfig);
|
|
567
|
+
}
|
|
467
568
|
const eventBus = this.eventBusManager.createOrGetByTaskId(taskId);
|
|
468
569
|
const eventQueue = new ExecutionEventQueue(eventBus);
|
|
469
570
|
this.agentExecutor.execute(requestContext, eventBus).catch((err) => {
|
|
@@ -531,6 +632,9 @@ var DefaultRequestHandler = class {
|
|
|
531
632
|
const finalMessageForAgent = requestContext.userMessage;
|
|
532
633
|
const eventBus = this.eventBusManager.createOrGetByTaskId(taskId);
|
|
533
634
|
const eventQueue = new ExecutionEventQueue(eventBus);
|
|
635
|
+
if (params.configuration?.pushNotificationConfig && this.agentCard.capabilities.pushNotifications) {
|
|
636
|
+
await this.pushNotificationStore?.save(taskId, params.configuration.pushNotificationConfig);
|
|
637
|
+
}
|
|
534
638
|
this.agentExecutor.execute(requestContext, eventBus).catch((err) => {
|
|
535
639
|
console.error(`Agent execution failed for stream message ${finalMessageForAgent.messageId}:`, err);
|
|
536
640
|
const errorTaskStatus = {
|
|
@@ -558,6 +662,7 @@ var DefaultRequestHandler = class {
|
|
|
558
662
|
try {
|
|
559
663
|
for await (const event of eventQueue.events()) {
|
|
560
664
|
await resultManager.processEvent(event);
|
|
665
|
+
await this._sendPushNotificationIfNeeded(event);
|
|
561
666
|
yield event;
|
|
562
667
|
}
|
|
563
668
|
} finally {
|
|
@@ -622,10 +727,7 @@ var DefaultRequestHandler = class {
|
|
|
622
727
|
if (!pushNotificationConfig.id) {
|
|
623
728
|
pushNotificationConfig.id = taskId;
|
|
624
729
|
}
|
|
625
|
-
|
|
626
|
-
const updatedConfigs = configs.filter((c) => c.id !== pushNotificationConfig.id);
|
|
627
|
-
updatedConfigs.push(pushNotificationConfig);
|
|
628
|
-
this.pushNotificationConfigs.set(taskId, updatedConfigs);
|
|
730
|
+
await this.pushNotificationStore?.save(taskId, pushNotificationConfig);
|
|
629
731
|
return params;
|
|
630
732
|
}
|
|
631
733
|
async getTaskPushNotificationConfig(params) {
|
|
@@ -636,7 +738,7 @@ var DefaultRequestHandler = class {
|
|
|
636
738
|
if (!task) {
|
|
637
739
|
throw A2AError.taskNotFound(params.id);
|
|
638
740
|
}
|
|
639
|
-
const configs = this.
|
|
741
|
+
const configs = await this.pushNotificationStore?.load(params.id) || [];
|
|
640
742
|
if (configs.length === 0) {
|
|
641
743
|
throw A2AError.internalError(`Push notification config not found for task ${params.id}.`);
|
|
642
744
|
}
|
|
@@ -660,7 +762,7 @@ var DefaultRequestHandler = class {
|
|
|
660
762
|
if (!task) {
|
|
661
763
|
throw A2AError.taskNotFound(params.id);
|
|
662
764
|
}
|
|
663
|
-
const configs = this.
|
|
765
|
+
const configs = await this.pushNotificationStore?.load(params.id) || [];
|
|
664
766
|
return configs.map((config) => ({
|
|
665
767
|
taskId: params.id,
|
|
666
768
|
pushNotificationConfig: config
|
|
@@ -675,16 +777,7 @@ var DefaultRequestHandler = class {
|
|
|
675
777
|
throw A2AError.taskNotFound(params.id);
|
|
676
778
|
}
|
|
677
779
|
const { id: taskId, pushNotificationConfigId } = params;
|
|
678
|
-
|
|
679
|
-
if (!configs) {
|
|
680
|
-
return;
|
|
681
|
-
}
|
|
682
|
-
const updatedConfigs = configs.filter((c) => c.id !== pushNotificationConfigId);
|
|
683
|
-
if (updatedConfigs.length === 0) {
|
|
684
|
-
this.pushNotificationConfigs.delete(taskId);
|
|
685
|
-
} else if (updatedConfigs.length < configs.length) {
|
|
686
|
-
this.pushNotificationConfigs.set(taskId, updatedConfigs);
|
|
687
|
-
}
|
|
780
|
+
await this.pushNotificationStore?.delete(taskId, pushNotificationConfigId);
|
|
688
781
|
}
|
|
689
782
|
async *resubscribe(params) {
|
|
690
783
|
if (!this.agentCard.capabilities.streaming) {
|
|
@@ -719,6 +812,28 @@ var DefaultRequestHandler = class {
|
|
|
719
812
|
eventQueue.stop();
|
|
720
813
|
}
|
|
721
814
|
}
|
|
815
|
+
async _sendPushNotificationIfNeeded(event) {
|
|
816
|
+
if (!this.agentCard.capabilities.pushNotifications) {
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
819
|
+
let taskId = "";
|
|
820
|
+
if (event.kind == "task") {
|
|
821
|
+
const task2 = event;
|
|
822
|
+
taskId = task2.id;
|
|
823
|
+
} else {
|
|
824
|
+
taskId = event.taskId;
|
|
825
|
+
}
|
|
826
|
+
if (!taskId) {
|
|
827
|
+
console.error(`Task ID not found for event ${event.kind}.`);
|
|
828
|
+
return;
|
|
829
|
+
}
|
|
830
|
+
const task = await this.taskStore.load(taskId);
|
|
831
|
+
if (!task) {
|
|
832
|
+
console.error(`Task ${taskId} not found.`);
|
|
833
|
+
return;
|
|
834
|
+
}
|
|
835
|
+
this.pushNotificationSender?.send(task);
|
|
836
|
+
}
|
|
722
837
|
};
|
|
723
838
|
|
|
724
839
|
// src/server/store.ts
|
|
@@ -859,8 +974,10 @@ var JsonRpcTransportHandler = class {
|
|
|
859
974
|
A2AError,
|
|
860
975
|
DefaultExecutionEventBus,
|
|
861
976
|
DefaultExecutionEventBusManager,
|
|
977
|
+
DefaultPushNotificationSender,
|
|
862
978
|
DefaultRequestHandler,
|
|
863
979
|
ExecutionEventQueue,
|
|
980
|
+
InMemoryPushNotificationStore,
|
|
864
981
|
InMemoryTaskStore,
|
|
865
982
|
JsonRpcTransportHandler,
|
|
866
983
|
RequestContext,
|
package/dist/server/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EventEmitter } from 'events';
|
|
2
|
-
import { B as Message, aw as Task, aO as TaskStatusUpdateEvent, aQ as TaskArtifactUpdateEvent, ac as AgentCard, w as MessageSendParams, V as TaskQueryParams, X as TaskIdParams, Z as TaskPushNotificationConfig, a1 as GetTaskPushNotificationConfigParams, a5 as ListTaskPushNotificationConfigParams, a7 as DeleteTaskPushNotificationConfigParams, i as JSONRPCResponse, au as JSONRPCError } from '../types-DNKcmF0f.cjs';
|
|
2
|
+
import { B as Message, aw as Task, aO as TaskStatusUpdateEvent, aQ as TaskArtifactUpdateEvent, y as PushNotificationConfig, ac as AgentCard, w as MessageSendParams, V as TaskQueryParams, X as TaskIdParams, Z as TaskPushNotificationConfig, a1 as GetTaskPushNotificationConfigParams, a5 as ListTaskPushNotificationConfigParams, a7 as DeleteTaskPushNotificationConfigParams, i as JSONRPCResponse, au as JSONRPCError } from '../types-DNKcmF0f.cjs';
|
|
3
3
|
import { A as A2ARequestHandler } from '../a2a_request_handler-DUvKWfix.cjs';
|
|
4
4
|
|
|
5
5
|
type AgentExecutionEvent = Message | Task | TaskStatusUpdateEvent | TaskArtifactUpdateEvent;
|
|
@@ -119,14 +119,31 @@ declare class InMemoryTaskStore implements TaskStore {
|
|
|
119
119
|
save(task: Task): Promise<void>;
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
+
interface PushNotificationStore {
|
|
123
|
+
save(taskId: string, pushNotificationConfig: PushNotificationConfig): Promise<void>;
|
|
124
|
+
load(taskId: string): Promise<PushNotificationConfig[]>;
|
|
125
|
+
delete(taskId: string, configId?: string): Promise<void>;
|
|
126
|
+
}
|
|
127
|
+
declare class InMemoryPushNotificationStore implements PushNotificationStore {
|
|
128
|
+
private store;
|
|
129
|
+
save(taskId: string, pushNotificationConfig: PushNotificationConfig): Promise<void>;
|
|
130
|
+
load(taskId: string): Promise<PushNotificationConfig[]>;
|
|
131
|
+
delete(taskId: string, configId?: string): Promise<void>;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
interface PushNotificationSender {
|
|
135
|
+
send(task: Task): Promise<void>;
|
|
136
|
+
}
|
|
137
|
+
|
|
122
138
|
declare class DefaultRequestHandler implements A2ARequestHandler {
|
|
123
139
|
private readonly agentCard;
|
|
124
140
|
private readonly extendedAgentCard?;
|
|
125
141
|
private readonly taskStore;
|
|
126
142
|
private readonly agentExecutor;
|
|
127
143
|
private readonly eventBusManager;
|
|
128
|
-
private readonly
|
|
129
|
-
|
|
144
|
+
private readonly pushNotificationStore?;
|
|
145
|
+
private readonly pushNotificationSender?;
|
|
146
|
+
constructor(agentCard: AgentCard, taskStore: TaskStore, agentExecutor: AgentExecutor, eventBusManager?: ExecutionEventBusManager, pushNotificationStore?: PushNotificationStore, pushNotificationSender?: PushNotificationSender, extendedAgentCard?: AgentCard);
|
|
130
147
|
getAgentCard(): Promise<AgentCard>;
|
|
131
148
|
getAuthenticatedExtendedAgentCard(): Promise<AgentCard>;
|
|
132
149
|
private _createRequestContext;
|
|
@@ -140,6 +157,7 @@ declare class DefaultRequestHandler implements A2ARequestHandler {
|
|
|
140
157
|
listTaskPushNotificationConfigs(params: ListTaskPushNotificationConfigParams): Promise<TaskPushNotificationConfig[]>;
|
|
141
158
|
deleteTaskPushNotificationConfig(params: DeleteTaskPushNotificationConfigParams): Promise<void>;
|
|
142
159
|
resubscribe(params: TaskIdParams): AsyncGenerator<Task | TaskStatusUpdateEvent | TaskArtifactUpdateEvent, void, undefined>;
|
|
160
|
+
private _sendPushNotificationIfNeeded;
|
|
143
161
|
}
|
|
144
162
|
|
|
145
163
|
declare class ResultManager {
|
|
@@ -207,4 +225,22 @@ declare class A2AError extends Error {
|
|
|
207
225
|
static authenticatedExtendedCardNotConfigured(): A2AError;
|
|
208
226
|
}
|
|
209
227
|
|
|
210
|
-
|
|
228
|
+
interface DefaultPushNotificationSenderOptions {
|
|
229
|
+
/**
|
|
230
|
+
* Timeout in milliseconds for the abort controller. Defaults to 5000ms.
|
|
231
|
+
*/
|
|
232
|
+
timeout?: number;
|
|
233
|
+
/**
|
|
234
|
+
* Custom header name for the token. Defaults to 'X-A2A-Notification-Token'.
|
|
235
|
+
*/
|
|
236
|
+
tokenHeaderName?: string;
|
|
237
|
+
}
|
|
238
|
+
declare class DefaultPushNotificationSender implements PushNotificationSender {
|
|
239
|
+
private readonly pushNotificationStore;
|
|
240
|
+
private readonly options;
|
|
241
|
+
constructor(pushNotificationStore: PushNotificationStore, options?: DefaultPushNotificationSenderOptions);
|
|
242
|
+
send(task: Task): Promise<void>;
|
|
243
|
+
private _dispatchNotification;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export { A2AError, A2ARequestHandler, type AgentExecutionEvent, type AgentExecutor, DefaultExecutionEventBus, DefaultExecutionEventBusManager, DefaultPushNotificationSender, type DefaultPushNotificationSenderOptions, DefaultRequestHandler, type ExecutionEventBus, type ExecutionEventBusManager, ExecutionEventQueue, InMemoryPushNotificationStore, InMemoryTaskStore, JsonRpcTransportHandler, type PushNotificationSender, type PushNotificationStore, RequestContext, ResultManager, type TaskStore };
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EventEmitter } from 'events';
|
|
2
|
-
import { B as Message, aw as Task, aO as TaskStatusUpdateEvent, aQ as TaskArtifactUpdateEvent, ac as AgentCard, w as MessageSendParams, V as TaskQueryParams, X as TaskIdParams, Z as TaskPushNotificationConfig, a1 as GetTaskPushNotificationConfigParams, a5 as ListTaskPushNotificationConfigParams, a7 as DeleteTaskPushNotificationConfigParams, i as JSONRPCResponse, au as JSONRPCError } from '../types-DNKcmF0f.js';
|
|
2
|
+
import { B as Message, aw as Task, aO as TaskStatusUpdateEvent, aQ as TaskArtifactUpdateEvent, y as PushNotificationConfig, ac as AgentCard, w as MessageSendParams, V as TaskQueryParams, X as TaskIdParams, Z as TaskPushNotificationConfig, a1 as GetTaskPushNotificationConfigParams, a5 as ListTaskPushNotificationConfigParams, a7 as DeleteTaskPushNotificationConfigParams, i as JSONRPCResponse, au as JSONRPCError } from '../types-DNKcmF0f.js';
|
|
3
3
|
import { A as A2ARequestHandler } from '../a2a_request_handler-B5t-IxgA.js';
|
|
4
4
|
|
|
5
5
|
type AgentExecutionEvent = Message | Task | TaskStatusUpdateEvent | TaskArtifactUpdateEvent;
|
|
@@ -119,14 +119,31 @@ declare class InMemoryTaskStore implements TaskStore {
|
|
|
119
119
|
save(task: Task): Promise<void>;
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
+
interface PushNotificationStore {
|
|
123
|
+
save(taskId: string, pushNotificationConfig: PushNotificationConfig): Promise<void>;
|
|
124
|
+
load(taskId: string): Promise<PushNotificationConfig[]>;
|
|
125
|
+
delete(taskId: string, configId?: string): Promise<void>;
|
|
126
|
+
}
|
|
127
|
+
declare class InMemoryPushNotificationStore implements PushNotificationStore {
|
|
128
|
+
private store;
|
|
129
|
+
save(taskId: string, pushNotificationConfig: PushNotificationConfig): Promise<void>;
|
|
130
|
+
load(taskId: string): Promise<PushNotificationConfig[]>;
|
|
131
|
+
delete(taskId: string, configId?: string): Promise<void>;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
interface PushNotificationSender {
|
|
135
|
+
send(task: Task): Promise<void>;
|
|
136
|
+
}
|
|
137
|
+
|
|
122
138
|
declare class DefaultRequestHandler implements A2ARequestHandler {
|
|
123
139
|
private readonly agentCard;
|
|
124
140
|
private readonly extendedAgentCard?;
|
|
125
141
|
private readonly taskStore;
|
|
126
142
|
private readonly agentExecutor;
|
|
127
143
|
private readonly eventBusManager;
|
|
128
|
-
private readonly
|
|
129
|
-
|
|
144
|
+
private readonly pushNotificationStore?;
|
|
145
|
+
private readonly pushNotificationSender?;
|
|
146
|
+
constructor(agentCard: AgentCard, taskStore: TaskStore, agentExecutor: AgentExecutor, eventBusManager?: ExecutionEventBusManager, pushNotificationStore?: PushNotificationStore, pushNotificationSender?: PushNotificationSender, extendedAgentCard?: AgentCard);
|
|
130
147
|
getAgentCard(): Promise<AgentCard>;
|
|
131
148
|
getAuthenticatedExtendedAgentCard(): Promise<AgentCard>;
|
|
132
149
|
private _createRequestContext;
|
|
@@ -140,6 +157,7 @@ declare class DefaultRequestHandler implements A2ARequestHandler {
|
|
|
140
157
|
listTaskPushNotificationConfigs(params: ListTaskPushNotificationConfigParams): Promise<TaskPushNotificationConfig[]>;
|
|
141
158
|
deleteTaskPushNotificationConfig(params: DeleteTaskPushNotificationConfigParams): Promise<void>;
|
|
142
159
|
resubscribe(params: TaskIdParams): AsyncGenerator<Task | TaskStatusUpdateEvent | TaskArtifactUpdateEvent, void, undefined>;
|
|
160
|
+
private _sendPushNotificationIfNeeded;
|
|
143
161
|
}
|
|
144
162
|
|
|
145
163
|
declare class ResultManager {
|
|
@@ -207,4 +225,22 @@ declare class A2AError extends Error {
|
|
|
207
225
|
static authenticatedExtendedCardNotConfigured(): A2AError;
|
|
208
226
|
}
|
|
209
227
|
|
|
210
|
-
|
|
228
|
+
interface DefaultPushNotificationSenderOptions {
|
|
229
|
+
/**
|
|
230
|
+
* Timeout in milliseconds for the abort controller. Defaults to 5000ms.
|
|
231
|
+
*/
|
|
232
|
+
timeout?: number;
|
|
233
|
+
/**
|
|
234
|
+
* Custom header name for the token. Defaults to 'X-A2A-Notification-Token'.
|
|
235
|
+
*/
|
|
236
|
+
tokenHeaderName?: string;
|
|
237
|
+
}
|
|
238
|
+
declare class DefaultPushNotificationSender implements PushNotificationSender {
|
|
239
|
+
private readonly pushNotificationStore;
|
|
240
|
+
private readonly options;
|
|
241
|
+
constructor(pushNotificationStore: PushNotificationStore, options?: DefaultPushNotificationSenderOptions);
|
|
242
|
+
send(task: Task): Promise<void>;
|
|
243
|
+
private _dispatchNotification;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export { A2AError, A2ARequestHandler, type AgentExecutionEvent, type AgentExecutor, DefaultExecutionEventBus, DefaultExecutionEventBusManager, DefaultPushNotificationSender, type DefaultPushNotificationSenderOptions, DefaultRequestHandler, type ExecutionEventBus, type ExecutionEventBusManager, ExecutionEventQueue, InMemoryPushNotificationStore, InMemoryTaskStore, JsonRpcTransportHandler, type PushNotificationSender, type PushNotificationStore, RequestContext, ResultManager, type TaskStore };
|
package/dist/server/index.js
CHANGED
|
@@ -257,6 +257,97 @@ var ResultManager = class {
|
|
|
257
257
|
}
|
|
258
258
|
};
|
|
259
259
|
|
|
260
|
+
// src/server/push_notification/push_notification_store.ts
|
|
261
|
+
var InMemoryPushNotificationStore = class {
|
|
262
|
+
store = /* @__PURE__ */ new Map();
|
|
263
|
+
async save(taskId, pushNotificationConfig) {
|
|
264
|
+
const configs = this.store.get(taskId) || [];
|
|
265
|
+
if (!pushNotificationConfig.id) {
|
|
266
|
+
pushNotificationConfig.id = taskId;
|
|
267
|
+
}
|
|
268
|
+
const existingIndex = configs.findIndex((config) => config.id === pushNotificationConfig.id);
|
|
269
|
+
if (existingIndex !== -1) {
|
|
270
|
+
configs.splice(existingIndex, 1);
|
|
271
|
+
}
|
|
272
|
+
configs.push(pushNotificationConfig);
|
|
273
|
+
this.store.set(taskId, configs);
|
|
274
|
+
}
|
|
275
|
+
async load(taskId) {
|
|
276
|
+
const configs = this.store.get(taskId);
|
|
277
|
+
return configs || [];
|
|
278
|
+
}
|
|
279
|
+
async delete(taskId, configId) {
|
|
280
|
+
if (configId === void 0) {
|
|
281
|
+
configId = taskId;
|
|
282
|
+
}
|
|
283
|
+
const configs = this.store.get(taskId);
|
|
284
|
+
if (!configs) {
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
const configIndex = configs.findIndex((config) => config.id === configId);
|
|
288
|
+
if (configIndex !== -1) {
|
|
289
|
+
configs.splice(configIndex, 1);
|
|
290
|
+
}
|
|
291
|
+
if (configs.length === 0) {
|
|
292
|
+
this.store.delete(taskId);
|
|
293
|
+
} else {
|
|
294
|
+
this.store.set(taskId, configs);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
// src/server/push_notification/default_push_notification_sender.ts
|
|
300
|
+
var DefaultPushNotificationSender = class {
|
|
301
|
+
pushNotificationStore;
|
|
302
|
+
options;
|
|
303
|
+
constructor(pushNotificationStore, options = {}) {
|
|
304
|
+
this.pushNotificationStore = pushNotificationStore;
|
|
305
|
+
this.options = {
|
|
306
|
+
timeout: 5e3,
|
|
307
|
+
tokenHeaderName: "X-A2A-Notification-Token",
|
|
308
|
+
...options
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
async send(task) {
|
|
312
|
+
const pushConfigs = await this.pushNotificationStore.load(task.id);
|
|
313
|
+
if (!pushConfigs || pushConfigs.length === 0) {
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
pushConfigs.forEach((pushConfig) => {
|
|
317
|
+
this._dispatchNotification(task, pushConfig).catch((error) => {
|
|
318
|
+
console.error(`Error sending push notification for task_id=${task.id} to URL: ${pushConfig.url}. Error:`, error);
|
|
319
|
+
});
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
async _dispatchNotification(task, pushConfig) {
|
|
323
|
+
const url = pushConfig.url;
|
|
324
|
+
const controller = new AbortController();
|
|
325
|
+
const timeoutId = setTimeout(() => controller.abort(), this.options.timeout);
|
|
326
|
+
try {
|
|
327
|
+
const headers = {
|
|
328
|
+
"Content-Type": "application/json"
|
|
329
|
+
};
|
|
330
|
+
if (pushConfig.token) {
|
|
331
|
+
headers[this.options.tokenHeaderName] = pushConfig.token;
|
|
332
|
+
}
|
|
333
|
+
const response = await fetch(url, {
|
|
334
|
+
method: "POST",
|
|
335
|
+
headers,
|
|
336
|
+
body: JSON.stringify(task),
|
|
337
|
+
signal: controller.signal
|
|
338
|
+
});
|
|
339
|
+
if (!response.ok) {
|
|
340
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
341
|
+
}
|
|
342
|
+
console.info(`Push notification sent for task_id=${task.id} to URL: ${url}`);
|
|
343
|
+
} catch (error) {
|
|
344
|
+
console.error(`Error sending push notification for task_id=${task.id} to URL: ${url}. Error:`, error);
|
|
345
|
+
} finally {
|
|
346
|
+
clearTimeout(timeoutId);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
};
|
|
350
|
+
|
|
260
351
|
// src/server/request_handler/default_request_handler.ts
|
|
261
352
|
var terminalStates = ["completed", "failed", "canceled", "rejected"];
|
|
262
353
|
var DefaultRequestHandler = class {
|
|
@@ -265,14 +356,18 @@ var DefaultRequestHandler = class {
|
|
|
265
356
|
taskStore;
|
|
266
357
|
agentExecutor;
|
|
267
358
|
eventBusManager;
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
constructor(agentCard, taskStore, agentExecutor, eventBusManager = new DefaultExecutionEventBusManager(), extendedAgentCard) {
|
|
359
|
+
pushNotificationStore;
|
|
360
|
+
pushNotificationSender;
|
|
361
|
+
constructor(agentCard, taskStore, agentExecutor, eventBusManager = new DefaultExecutionEventBusManager(), pushNotificationStore, pushNotificationSender, extendedAgentCard) {
|
|
271
362
|
this.agentCard = agentCard;
|
|
272
363
|
this.taskStore = taskStore;
|
|
273
364
|
this.agentExecutor = agentExecutor;
|
|
274
365
|
this.eventBusManager = eventBusManager;
|
|
275
366
|
this.extendedAgentCard = extendedAgentCard;
|
|
367
|
+
if (agentCard.capabilities.pushNotifications) {
|
|
368
|
+
this.pushNotificationStore = pushNotificationStore || new InMemoryPushNotificationStore();
|
|
369
|
+
this.pushNotificationSender = pushNotificationSender || new DefaultPushNotificationSender(this.pushNotificationStore);
|
|
370
|
+
}
|
|
276
371
|
}
|
|
277
372
|
async getAgentCard() {
|
|
278
373
|
return this.agentCard;
|
|
@@ -324,6 +419,7 @@ var DefaultRequestHandler = class {
|
|
|
324
419
|
try {
|
|
325
420
|
for await (const event of eventQueue.events()) {
|
|
326
421
|
await resultManager.processEvent(event);
|
|
422
|
+
await this._sendPushNotificationIfNeeded(event);
|
|
327
423
|
if (options?.firstResultResolver && !firstResultSent) {
|
|
328
424
|
if (event.kind === "message" || event.kind === "task") {
|
|
329
425
|
options.firstResultResolver(event);
|
|
@@ -355,6 +451,9 @@ var DefaultRequestHandler = class {
|
|
|
355
451
|
resultManager.setContext(incomingMessage);
|
|
356
452
|
const requestContext = await this._createRequestContext(incomingMessage, taskId, false);
|
|
357
453
|
const finalMessageForAgent = requestContext.userMessage;
|
|
454
|
+
if (params.configuration?.pushNotificationConfig && this.agentCard.capabilities.pushNotifications) {
|
|
455
|
+
await this.pushNotificationStore?.save(taskId, params.configuration.pushNotificationConfig);
|
|
456
|
+
}
|
|
358
457
|
const eventBus = this.eventBusManager.createOrGetByTaskId(taskId);
|
|
359
458
|
const eventQueue = new ExecutionEventQueue(eventBus);
|
|
360
459
|
this.agentExecutor.execute(requestContext, eventBus).catch((err) => {
|
|
@@ -422,6 +521,9 @@ var DefaultRequestHandler = class {
|
|
|
422
521
|
const finalMessageForAgent = requestContext.userMessage;
|
|
423
522
|
const eventBus = this.eventBusManager.createOrGetByTaskId(taskId);
|
|
424
523
|
const eventQueue = new ExecutionEventQueue(eventBus);
|
|
524
|
+
if (params.configuration?.pushNotificationConfig && this.agentCard.capabilities.pushNotifications) {
|
|
525
|
+
await this.pushNotificationStore?.save(taskId, params.configuration.pushNotificationConfig);
|
|
526
|
+
}
|
|
425
527
|
this.agentExecutor.execute(requestContext, eventBus).catch((err) => {
|
|
426
528
|
console.error(`Agent execution failed for stream message ${finalMessageForAgent.messageId}:`, err);
|
|
427
529
|
const errorTaskStatus = {
|
|
@@ -449,6 +551,7 @@ var DefaultRequestHandler = class {
|
|
|
449
551
|
try {
|
|
450
552
|
for await (const event of eventQueue.events()) {
|
|
451
553
|
await resultManager.processEvent(event);
|
|
554
|
+
await this._sendPushNotificationIfNeeded(event);
|
|
452
555
|
yield event;
|
|
453
556
|
}
|
|
454
557
|
} finally {
|
|
@@ -513,10 +616,7 @@ var DefaultRequestHandler = class {
|
|
|
513
616
|
if (!pushNotificationConfig.id) {
|
|
514
617
|
pushNotificationConfig.id = taskId;
|
|
515
618
|
}
|
|
516
|
-
|
|
517
|
-
const updatedConfigs = configs.filter((c) => c.id !== pushNotificationConfig.id);
|
|
518
|
-
updatedConfigs.push(pushNotificationConfig);
|
|
519
|
-
this.pushNotificationConfigs.set(taskId, updatedConfigs);
|
|
619
|
+
await this.pushNotificationStore?.save(taskId, pushNotificationConfig);
|
|
520
620
|
return params;
|
|
521
621
|
}
|
|
522
622
|
async getTaskPushNotificationConfig(params) {
|
|
@@ -527,7 +627,7 @@ var DefaultRequestHandler = class {
|
|
|
527
627
|
if (!task) {
|
|
528
628
|
throw A2AError.taskNotFound(params.id);
|
|
529
629
|
}
|
|
530
|
-
const configs = this.
|
|
630
|
+
const configs = await this.pushNotificationStore?.load(params.id) || [];
|
|
531
631
|
if (configs.length === 0) {
|
|
532
632
|
throw A2AError.internalError(`Push notification config not found for task ${params.id}.`);
|
|
533
633
|
}
|
|
@@ -551,7 +651,7 @@ var DefaultRequestHandler = class {
|
|
|
551
651
|
if (!task) {
|
|
552
652
|
throw A2AError.taskNotFound(params.id);
|
|
553
653
|
}
|
|
554
|
-
const configs = this.
|
|
654
|
+
const configs = await this.pushNotificationStore?.load(params.id) || [];
|
|
555
655
|
return configs.map((config) => ({
|
|
556
656
|
taskId: params.id,
|
|
557
657
|
pushNotificationConfig: config
|
|
@@ -566,16 +666,7 @@ var DefaultRequestHandler = class {
|
|
|
566
666
|
throw A2AError.taskNotFound(params.id);
|
|
567
667
|
}
|
|
568
668
|
const { id: taskId, pushNotificationConfigId } = params;
|
|
569
|
-
|
|
570
|
-
if (!configs) {
|
|
571
|
-
return;
|
|
572
|
-
}
|
|
573
|
-
const updatedConfigs = configs.filter((c) => c.id !== pushNotificationConfigId);
|
|
574
|
-
if (updatedConfigs.length === 0) {
|
|
575
|
-
this.pushNotificationConfigs.delete(taskId);
|
|
576
|
-
} else if (updatedConfigs.length < configs.length) {
|
|
577
|
-
this.pushNotificationConfigs.set(taskId, updatedConfigs);
|
|
578
|
-
}
|
|
669
|
+
await this.pushNotificationStore?.delete(taskId, pushNotificationConfigId);
|
|
579
670
|
}
|
|
580
671
|
async *resubscribe(params) {
|
|
581
672
|
if (!this.agentCard.capabilities.streaming) {
|
|
@@ -610,6 +701,28 @@ var DefaultRequestHandler = class {
|
|
|
610
701
|
eventQueue.stop();
|
|
611
702
|
}
|
|
612
703
|
}
|
|
704
|
+
async _sendPushNotificationIfNeeded(event) {
|
|
705
|
+
if (!this.agentCard.capabilities.pushNotifications) {
|
|
706
|
+
return;
|
|
707
|
+
}
|
|
708
|
+
let taskId = "";
|
|
709
|
+
if (event.kind == "task") {
|
|
710
|
+
const task2 = event;
|
|
711
|
+
taskId = task2.id;
|
|
712
|
+
} else {
|
|
713
|
+
taskId = event.taskId;
|
|
714
|
+
}
|
|
715
|
+
if (!taskId) {
|
|
716
|
+
console.error(`Task ID not found for event ${event.kind}.`);
|
|
717
|
+
return;
|
|
718
|
+
}
|
|
719
|
+
const task = await this.taskStore.load(taskId);
|
|
720
|
+
if (!task) {
|
|
721
|
+
console.error(`Task ${taskId} not found.`);
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
724
|
+
this.pushNotificationSender?.send(task);
|
|
725
|
+
}
|
|
613
726
|
};
|
|
614
727
|
|
|
615
728
|
// src/server/store.ts
|
|
@@ -627,8 +740,10 @@ export {
|
|
|
627
740
|
A2AError,
|
|
628
741
|
DefaultExecutionEventBus,
|
|
629
742
|
DefaultExecutionEventBusManager,
|
|
743
|
+
DefaultPushNotificationSender,
|
|
630
744
|
DefaultRequestHandler,
|
|
631
745
|
ExecutionEventQueue,
|
|
746
|
+
InMemoryPushNotificationStore,
|
|
632
747
|
InMemoryTaskStore,
|
|
633
748
|
JsonRpcTransportHandler,
|
|
634
749
|
RequestContext,
|