@a2a-js/sdk 0.3.2 → 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.
@@ -3,94 +3,80 @@ import {
3
3
  } from "../chunk-67JNQ6TZ.js";
4
4
 
5
5
  // src/client/client.ts
6
- var A2AClient = class {
6
+ var A2AClient = class _A2AClient {
7
7
  agentCardPromise;
8
8
  requestIdCounter = 1;
9
9
  serviceEndpointUrl;
10
10
  // To be populated from AgentCard after fetching
11
- fetchImpl;
11
+ customFetchImpl;
12
12
  /**
13
- * Constructs an A2AClient instance.
14
- * It initiates fetching the agent card from the provided agent baseUrl.
15
- * The Agent Card is fetched from a path relative to the agentBaseUrl, which defaults to '.well-known/agent-card.json'.
16
- * The `url` field from the Agent Card will be used as the RPC service endpoint.
17
- * @param agentBaseUrl The base URL of the A2A agent (e.g., https://agent.example.com)
18
- * @param options Optional. The options for the A2AClient including the fetch implementation, agent card path, and authentication handler.
19
- */
20
- constructor(agentBaseUrl, options) {
21
- this.fetchImpl = options?.fetchImpl ?? fetch;
22
- this.agentCardPromise = this._fetchAndCacheAgentCard(agentBaseUrl, options?.agentCardPath);
23
- }
24
- /**
25
- * Fetches the Agent Card from the agent's well-known URI and caches its service endpoint URL.
26
- * This method is called by the constructor.
27
- * @param agentBaseUrl The base URL of the A2A agent (e.g., https://agent.example.com)
28
- * @param agentCardPath path to the agent card, defaults to .well-known/agent-card.json
29
- * @returns A Promise that resolves to the AgentCard.
13
+ * Constructs an A2AClient instance from an AgentCard.
14
+ * @param agentCard The AgentCard object.
15
+ * @param options Optional. The options for the A2AClient including the fetch/auth implementation.
30
16
  */
31
- async _fetchAndCacheAgentCard(agentBaseUrl, agentCardPath) {
32
- try {
33
- const agentCardUrl = this.resolveAgentCardUrl(agentBaseUrl, agentCardPath);
34
- const response = await this.fetchImpl(agentCardUrl, {
35
- headers: { "Accept": "application/json" }
36
- });
37
- if (!response.ok) {
38
- throw new Error(`Failed to fetch Agent Card from ${agentCardUrl}: ${response.status} ${response.statusText}`);
39
- }
40
- const agentCard = await response.json();
17
+ constructor(agentCard, options) {
18
+ this.customFetchImpl = options?.fetchImpl;
19
+ if (typeof agentCard === "string") {
20
+ console.warn("Warning: Constructing A2AClient with a URL is deprecated. Please use A2AClient.fromCardUrl() instead.");
21
+ this.agentCardPromise = this._fetchAndCacheAgentCard(agentCard, options?.agentCardPath);
22
+ } else {
41
23
  if (!agentCard.url) {
42
- throw new Error("Fetched Agent Card does not contain a valid 'url' for the service endpoint.");
24
+ throw new Error("Provided Agent Card does not contain a valid 'url' for the service endpoint.");
43
25
  }
44
26
  this.serviceEndpointUrl = agentCard.url;
45
- return agentCard;
46
- } catch (error) {
47
- console.error("Error fetching or parsing Agent Card:", error);
48
- throw error;
27
+ this.agentCardPromise = Promise.resolve(agentCard);
49
28
  }
50
29
  }
51
30
  /**
52
- * Retrieves the Agent Card.
53
- * If an `agentBaseUrl` is provided, it fetches the card from that specific URL.
54
- * Otherwise, it returns the card fetched and cached during client construction.
55
- * @param agentBaseUrl Optional. The base URL of the agent to fetch the card from.
56
- * @param agentCardPath path to the agent card, defaults to .well-known/agent-card.json
57
- * If provided, this will fetch a new card, not use the cached one from the constructor's URL.
58
- * @returns A Promise that resolves to the AgentCard.
31
+ * Dynamically resolves the fetch implementation to use for requests.
32
+ * Prefers a custom implementation if provided, otherwise falls back to the global fetch.
33
+ * @returns The fetch implementation.
34
+ * @param args Arguments to pass to the fetch implementation.
35
+ * @throws If no fetch implementation is available.
59
36
  */
60
- async getAgentCard(agentBaseUrl, agentCardPath) {
61
- if (agentBaseUrl) {
62
- const agentCardUrl = this.resolveAgentCardUrl(agentBaseUrl, agentCardPath);
63
- const response = await this.fetchImpl(agentCardUrl, {
64
- headers: { "Accept": "application/json" }
65
- });
66
- if (!response.ok) {
67
- throw new Error(`Failed to fetch Agent Card from ${agentCardUrl}: ${response.status} ${response.statusText}`);
68
- }
69
- return await response.json();
37
+ _fetch(...args) {
38
+ if (this.customFetchImpl) {
39
+ return this.customFetchImpl(...args);
70
40
  }
71
- return this.agentCardPromise;
72
- }
73
- /**
74
- * Determines the agent card URL based on the agent URL.
75
- * @param agentBaseUrl The agent URL.
76
- * @param agentCardPath Optional relative path to the agent card, defaults to .well-known/agent-card.json
77
- */
78
- resolveAgentCardUrl(agentBaseUrl, agentCardPath = AGENT_CARD_PATH) {
79
- return `${agentBaseUrl.replace(/\/$/, "")}/${agentCardPath.replace(/^\//, "")}`;
41
+ if (typeof fetch === "function") {
42
+ return fetch(...args);
43
+ }
44
+ throw new Error(
45
+ "A `fetch` implementation was not provided and is not available in the global scope. Please provide a `fetchImpl` in the A2AClientOptions. For earlier Node.js versions (pre-v18), you can use a library like `node-fetch`."
46
+ );
80
47
  }
81
48
  /**
82
- * Gets the RPC service endpoint URL. Ensures the agent card has been fetched first.
83
- * @returns A Promise that resolves to the service endpoint URL string.
49
+ * Creates an A2AClient instance by fetching the AgentCard from a URL then constructing the A2AClient.
50
+ * @param agentCardUrl The URL of the agent card.
51
+ * @param options Optional. The options for the A2AClient including the fetch/auth implementation.
52
+ * @returns A Promise that resolves to a new A2AClient instance.
84
53
  */
85
- async _getServiceEndpoint() {
86
- if (this.serviceEndpointUrl) {
87
- return this.serviceEndpointUrl;
54
+ static async fromCardUrl(agentCardUrl, options) {
55
+ const fetchImpl = options?.fetchImpl;
56
+ const requestInit = {
57
+ headers: { "Accept": "application/json" }
58
+ };
59
+ let response;
60
+ if (fetchImpl) {
61
+ response = await fetchImpl(agentCardUrl, requestInit);
62
+ } else if (typeof fetch === "function") {
63
+ response = await fetch(agentCardUrl, requestInit);
64
+ } else {
65
+ throw new Error(
66
+ "A `fetch` implementation was not provided and is not available in the global scope. Please provide a `fetchImpl` in the A2AClientOptions. For earlier Node.js versions (pre-v18), you can use a library like `node-fetch`."
67
+ );
88
68
  }
89
- await this.agentCardPromise;
90
- if (!this.serviceEndpointUrl) {
91
- throw new Error("Agent Card URL for RPC endpoint is not available. Fetching might have failed.");
69
+ if (!response.ok) {
70
+ throw new Error(`Failed to fetch Agent Card from ${agentCardUrl}: ${response.status} ${response.statusText}`);
92
71
  }
93
- return this.serviceEndpointUrl;
72
+ let agentCard;
73
+ try {
74
+ agentCard = await response.json();
75
+ } catch (error) {
76
+ console.error("Failed to parse Agent Card JSON:", error);
77
+ throw new Error(`Failed to parse Agent Card JSON from ${agentCardUrl}. Original error: ${error.message}`);
78
+ }
79
+ return new _A2AClient(agentCard, options);
94
80
  }
95
81
  /**
96
82
  * Helper method to make a generic JSON-RPC POST request.
@@ -149,7 +135,7 @@ var A2AClient = class {
149
135
  },
150
136
  body: JSON.stringify(rpcRequest)
151
137
  };
152
- return this.fetchImpl(url, requestInit);
138
+ return this._fetch(url, requestInit);
153
139
  }
154
140
  /**
155
141
  * Sends a message to the agent.
@@ -232,6 +218,28 @@ var A2AClient = class {
232
218
  params
233
219
  );
234
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
+ }
235
243
  /**
236
244
  * Retrieves a task by its ID.
237
245
  * @param params Parameters containing the taskId and optional historyLength.
@@ -248,6 +256,17 @@ var A2AClient = class {
248
256
  async cancelTask(params) {
249
257
  return this._postRpcRequest("tasks/cancel", params);
250
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
+ }
251
270
  /**
252
271
  * Resubscribes to a task's event stream using Server-Sent Events (SSE).
253
272
  * This is used if a previous SSE connection for an active task was broken.
@@ -269,7 +288,7 @@ var A2AClient = class {
269
288
  params,
270
289
  id: clientRequestId
271
290
  };
272
- const response = await this.fetchImpl(endpoint, {
291
+ const response = await this._fetch(endpoint, {
273
292
  method: "POST",
274
293
  headers: {
275
294
  "Content-Type": "application/json",
@@ -384,6 +403,87 @@ var A2AClient = class {
384
403
  isErrorResponse(response) {
385
404
  return "error" in response;
386
405
  }
406
+ ////////////////////////////////////////////////////////////////////////////////
407
+ // Functions used to support old A2AClient Constructor to be deprecated soon
408
+ // TODOs:
409
+ // * remove `agentCardPromise`, and just use agentCard initialized
410
+ // * _getServiceEndpoint can be made synchronous or deleted and accessed via
411
+ // agentCard.url
412
+ // * getAgentCard changed to this.agentCard
413
+ // * delete resolveAgentCardUrl(), _fetchAndCacheAgentCard(),
414
+ // agentCardPath from A2AClientOptions
415
+ ////////////////////////////////////////////////////////////////////////////////
416
+ /**
417
+ * Fetches the Agent Card from the agent's well-known URI and caches its service endpoint URL.
418
+ * This method is called by the constructor.
419
+ * @param agentBaseUrl The base URL of the A2A agent (e.g., https://agent.example.com)
420
+ * @param agentCardPath path to the agent card, defaults to .well-known/agent-card.json
421
+ * @returns A Promise that resolves to the AgentCard.
422
+ */
423
+ async _fetchAndCacheAgentCard(agentBaseUrl, agentCardPath) {
424
+ try {
425
+ const agentCardUrl = this.resolveAgentCardUrl(agentBaseUrl, agentCardPath);
426
+ const response = await this._fetch(agentCardUrl, {
427
+ headers: { "Accept": "application/json" }
428
+ });
429
+ if (!response.ok) {
430
+ throw new Error(`Failed to fetch Agent Card from ${agentCardUrl}: ${response.status} ${response.statusText}`);
431
+ }
432
+ const agentCard = await response.json();
433
+ if (!agentCard.url) {
434
+ throw new Error("Fetched Agent Card does not contain a valid 'url' for the service endpoint.");
435
+ }
436
+ this.serviceEndpointUrl = agentCard.url;
437
+ return agentCard;
438
+ } catch (error) {
439
+ console.error("Error fetching or parsing Agent Card:", error);
440
+ throw error;
441
+ }
442
+ }
443
+ /**
444
+ * Retrieves the Agent Card.
445
+ * If an `agentBaseUrl` is provided, it fetches the card from that specific URL.
446
+ * Otherwise, it returns the card fetched and cached during client construction.
447
+ * @param agentBaseUrl Optional. The base URL of the agent to fetch the card from.
448
+ * @param agentCardPath path to the agent card, defaults to .well-known/agent-card.json
449
+ * If provided, this will fetch a new card, not use the cached one from the constructor's URL.
450
+ * @returns A Promise that resolves to the AgentCard.
451
+ */
452
+ async getAgentCard(agentBaseUrl, agentCardPath) {
453
+ if (agentBaseUrl) {
454
+ const agentCardUrl = this.resolveAgentCardUrl(agentBaseUrl, agentCardPath);
455
+ const response = await this._fetch(agentCardUrl, {
456
+ headers: { "Accept": "application/json" }
457
+ });
458
+ if (!response.ok) {
459
+ throw new Error(`Failed to fetch Agent Card from ${agentCardUrl}: ${response.status} ${response.statusText}`);
460
+ }
461
+ return await response.json();
462
+ }
463
+ return this.agentCardPromise;
464
+ }
465
+ /**
466
+ * Determines the agent card URL based on the agent URL.
467
+ * @param agentBaseUrl The agent URL.
468
+ * @param agentCardPath Optional relative path to the agent card, defaults to .well-known/agent-card.json
469
+ */
470
+ resolveAgentCardUrl(agentBaseUrl, agentCardPath = AGENT_CARD_PATH) {
471
+ return `${agentBaseUrl.replace(/\/$/, "")}/${agentCardPath.replace(/^\//, "")}`;
472
+ }
473
+ /**
474
+ * Gets the RPC service endpoint URL. Ensures the agent card has been fetched first.
475
+ * @returns A Promise that resolves to the service endpoint URL string.
476
+ */
477
+ async _getServiceEndpoint() {
478
+ if (this.serviceEndpointUrl) {
479
+ return this.serviceEndpointUrl;
480
+ }
481
+ await this.agentCardPromise;
482
+ if (!this.serviceEndpointUrl) {
483
+ throw new Error("Agent Card URL for RPC endpoint is not available. Fetching might have failed.");
484
+ }
485
+ return this.serviceEndpointUrl;
486
+ }
387
487
  };
388
488
 
389
489
  // src/client/auth-handler.ts
@@ -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
- // Store for push notification configurations (could be part of TaskStore or separate)
378
- pushNotificationConfigs = /* @__PURE__ */ new Map();
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
- const configs = this.pushNotificationConfigs.get(taskId) || [];
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.pushNotificationConfigs.get(params.id) || [];
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.pushNotificationConfigs.get(params.id) || [];
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
- const configs = this.pushNotificationConfigs.get(taskId);
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,
@@ -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 pushNotificationConfigs;
129
- constructor(agentCard: AgentCard, taskStore: TaskStore, agentExecutor: AgentExecutor, eventBusManager?: ExecutionEventBusManager, extendedAgentCard?: AgentCard);
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
- export { A2AError, A2ARequestHandler, type AgentExecutionEvent, type AgentExecutor, DefaultExecutionEventBus, DefaultExecutionEventBusManager, DefaultRequestHandler, type ExecutionEventBus, type ExecutionEventBusManager, ExecutionEventQueue, InMemoryTaskStore, JsonRpcTransportHandler, RequestContext, ResultManager, type TaskStore };
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 };