@mastra/server 1.32.1-alpha.0 → 1.33.0-alpha.0

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.
@@ -7,6 +7,10 @@ import { __export } from './chunk-PR4QN5HX.js';
7
7
  import { isDeepStrictEqual } from 'util';
8
8
  import { MastraA2AError } from '@mastra/core/a2a';
9
9
  import { z } from 'zod/v4';
10
+ import { lookup } from 'dns/promises';
11
+ import { request as request$1 } from 'http';
12
+ import { request } from 'https';
13
+ import { isIP } from 'net';
10
14
 
11
15
  // src/server/handlers/a2a.ts
12
16
  var a2a_exports = {};
@@ -15,8 +19,12 @@ __export(a2a_exports, {
15
19
  GET_AGENT_CARD_ROUTE: () => GET_AGENT_CARD_ROUTE,
16
20
  getAgentCardByIdHandler: () => getAgentCardByIdHandler,
17
21
  getAgentExecutionHandler: () => getAgentExecutionHandler,
22
+ handleDeleteTaskPushNotificationConfig: () => handleDeleteTaskPushNotificationConfig,
23
+ handleGetTaskPushNotificationConfig: () => handleGetTaskPushNotificationConfig,
24
+ handleListTaskPushNotificationConfig: () => handleListTaskPushNotificationConfig,
18
25
  handleMessageSend: () => handleMessageSend,
19
26
  handleMessageStream: () => handleMessageStream,
27
+ handleSetTaskPushNotificationConfig: () => handleSetTaskPushNotificationConfig,
20
28
  handleTaskCancel: () => handleTaskCancel,
21
29
  handleTaskGet: () => handleTaskGet,
22
30
  handleTaskResubscribe: () => handleTaskResubscribe
@@ -77,6 +85,231 @@ function convertToCoreMessagePart(part) {
77
85
  throw new Error("Data parts are not supported in core messages");
78
86
  }
79
87
  }
88
+ var DEFAULT_PUSH_NOTIFICATION_TOKEN_HEADER = "X-A2A-Notification-Token";
89
+ function isDisallowedHostname(hostname) {
90
+ const normalized = hostname.toLowerCase();
91
+ return normalized === "localhost" || normalized.endsWith(".localhost") || normalized.endsWith(".local") || normalized.endsWith(".internal") || !normalized.includes(".");
92
+ }
93
+ function isDisallowedIpv4(address) {
94
+ const [first = -1, second = -1] = address.split(".").map(Number);
95
+ return first === 10 || first === 127 || first === 169 && second === 254 || first === 172 && second >= 16 && second <= 31 || first === 192 && second === 168;
96
+ }
97
+ function isDisallowedIpv6(address) {
98
+ const normalized = address.toLowerCase();
99
+ return normalized === "::1" || normalized.startsWith("fe8") || normalized.startsWith("fe9") || normalized.startsWith("fea") || normalized.startsWith("feb") || normalized.startsWith("fc") || normalized.startsWith("fd");
100
+ }
101
+ function isDisallowedIpAddress(address) {
102
+ const version = isIP(address);
103
+ if (version === 4) {
104
+ return isDisallowedIpv4(address);
105
+ }
106
+ if (version === 6) {
107
+ return isDisallowedIpv6(address);
108
+ }
109
+ return false;
110
+ }
111
+ var DefaultPushNotificationSender = class {
112
+ constructor(pushNotificationStore, options = {}) {
113
+ this.pushNotificationStore = pushNotificationStore;
114
+ this.options = options;
115
+ }
116
+ pushNotificationStore;
117
+ options;
118
+ getStore() {
119
+ return this.pushNotificationStore;
120
+ }
121
+ async resolveValidatedDestination(rawUrl) {
122
+ const url = new URL(rawUrl);
123
+ if (url.protocol !== "https:" && url.protocol !== "http:") {
124
+ throw new Error(`Push notification URL must use http or https: ${url.protocol}`);
125
+ }
126
+ const hostname = url.hostname.toLowerCase();
127
+ if (this.options.allowedHosts && !this.options.allowedHosts.includes(hostname)) {
128
+ throw new Error(`Push notification host is not allowed: ${hostname}`);
129
+ }
130
+ if (isDisallowedHostname(hostname)) {
131
+ throw new Error(`Push notification URL must not target local or internal hosts: ${hostname}`);
132
+ }
133
+ if (isDisallowedIpAddress(hostname)) {
134
+ throw new Error(`Push notification URL must not target local or private IPs: ${hostname}`);
135
+ }
136
+ const resolvedAddresses = isIP(hostname) === 0 ? await (this.options.lookup ?? lookup)(hostname, { all: true, verbatim: true }) : [{ address: hostname, family: isIP(hostname) }];
137
+ if (resolvedAddresses.some((result) => isDisallowedIpAddress(result.address))) {
138
+ throw new Error(`Push notification URL resolved to a local or private IP: ${hostname}`);
139
+ }
140
+ const requestUrl = new URL(url.toString());
141
+ requestUrl.hostname = resolvedAddresses[0].address;
142
+ return {
143
+ originalUrl: url,
144
+ requestUrl,
145
+ hostHeader: url.host,
146
+ servername: isIP(hostname) === 0 ? hostname : void 0
147
+ };
148
+ }
149
+ async postTaskSnapshot({
150
+ requestUrl,
151
+ hostHeader,
152
+ servername,
153
+ headers,
154
+ body,
155
+ timeout
156
+ }) {
157
+ headers.set("host", hostHeader);
158
+ const signal = typeof AbortSignal.timeout === "function" ? AbortSignal.timeout(timeout) : void 0;
159
+ if (this.options.fetch) {
160
+ return this.options.fetch(requestUrl.toString(), {
161
+ method: "POST",
162
+ headers,
163
+ body,
164
+ signal
165
+ });
166
+ }
167
+ const transport = requestUrl.protocol === "https:" ? request : request$1;
168
+ return await new Promise((resolve, reject) => {
169
+ const request = transport(
170
+ {
171
+ protocol: requestUrl.protocol,
172
+ hostname: requestUrl.hostname,
173
+ port: requestUrl.port || void 0,
174
+ path: `${requestUrl.pathname}${requestUrl.search}`,
175
+ method: "POST",
176
+ headers: Object.fromEntries(headers.entries()),
177
+ servername
178
+ },
179
+ (response) => {
180
+ response.resume();
181
+ response.on("end", () => {
182
+ resolve({
183
+ ok: !!response.statusCode && response.statusCode >= 200 && response.statusCode < 300,
184
+ status: response.statusCode ?? 0,
185
+ statusText: response.statusMessage ?? ""
186
+ });
187
+ });
188
+ }
189
+ );
190
+ request.on("error", reject);
191
+ if (signal) {
192
+ signal.addEventListener(
193
+ "abort",
194
+ () => {
195
+ request.destroy(signal.reason instanceof Error ? signal.reason : new Error("Push notification timed out"));
196
+ },
197
+ { once: true }
198
+ );
199
+ }
200
+ request.end(body);
201
+ });
202
+ }
203
+ async sendNotifications({
204
+ agentId,
205
+ task,
206
+ logger
207
+ }) {
208
+ const configs = this.pushNotificationStore.list({
209
+ agentId,
210
+ params: { id: task.id }
211
+ });
212
+ if (configs.length === 0) {
213
+ return;
214
+ }
215
+ await Promise.allSettled(
216
+ configs.map(async (config) => {
217
+ const headers = new Headers({
218
+ "content-type": "application/json"
219
+ });
220
+ if (config.pushNotificationConfig.token) {
221
+ headers.set(
222
+ this.options.tokenHeaderName ?? DEFAULT_PUSH_NOTIFICATION_TOKEN_HEADER,
223
+ config.pushNotificationConfig.token
224
+ );
225
+ }
226
+ const auth = config.pushNotificationConfig.authentication;
227
+ if (auth?.credentials) {
228
+ if (auth.schemes.includes("Bearer")) {
229
+ headers.set("authorization", `Bearer ${auth.credentials}`);
230
+ } else if (auth.schemes.includes("Basic")) {
231
+ headers.set("authorization", `Basic ${auth.credentials}`);
232
+ }
233
+ }
234
+ const { requestUrl, hostHeader, servername } = await this.resolveValidatedDestination(
235
+ config.pushNotificationConfig.url
236
+ );
237
+ const response = await this.postTaskSnapshot({
238
+ requestUrl,
239
+ hostHeader,
240
+ servername,
241
+ headers,
242
+ body: JSON.stringify(task),
243
+ timeout: this.options.timeout ?? 5e3
244
+ });
245
+ if (!response.ok) {
246
+ throw new Error(
247
+ `Push notification failed with status ${response.status} ${response.statusText ?? ""}`.trim()
248
+ );
249
+ }
250
+ })
251
+ ).then((results) => {
252
+ for (const result of results) {
253
+ if (result.status === "rejected") {
254
+ logger?.error("Failed to deliver A2A push notification", result.reason);
255
+ }
256
+ }
257
+ });
258
+ }
259
+ };
260
+
261
+ // src/server/a2a/push-notification-store.ts
262
+ function normalizeConfigId(taskId, configId) {
263
+ return configId || taskId;
264
+ }
265
+ var InMemoryPushNotificationStore = class {
266
+ store = /* @__PURE__ */ new Map();
267
+ getKey(agentId, taskId) {
268
+ return JSON.stringify([agentId, taskId]);
269
+ }
270
+ set({ agentId, config }) {
271
+ const key = this.getKey(agentId, config.taskId);
272
+ const configs = this.store.get(key) ?? /* @__PURE__ */ new Map();
273
+ const normalizedConfig = {
274
+ taskId: config.taskId,
275
+ pushNotificationConfig: {
276
+ ...config.pushNotificationConfig,
277
+ id: normalizeConfigId(config.taskId, config.pushNotificationConfig.id)
278
+ }
279
+ };
280
+ configs.set(normalizedConfig.pushNotificationConfig.id, structuredClone(normalizedConfig));
281
+ this.store.set(key, configs);
282
+ return structuredClone(normalizedConfig);
283
+ }
284
+ get({
285
+ agentId,
286
+ params
287
+ }) {
288
+ const key = this.getKey(agentId, params.id);
289
+ const configId = normalizeConfigId(params.id, params.pushNotificationConfigId);
290
+ const config = this.store.get(key)?.get(configId);
291
+ return config ? structuredClone(config) : null;
292
+ }
293
+ list({
294
+ agentId,
295
+ params
296
+ }) {
297
+ const key = this.getKey(agentId, params.id);
298
+ return Array.from(this.store.get(key)?.values() ?? []).map((config) => structuredClone(config));
299
+ }
300
+ delete({ agentId, params }) {
301
+ const key = this.getKey(agentId, params.id);
302
+ const configs = this.store.get(key);
303
+ if (!configs) {
304
+ return false;
305
+ }
306
+ const deleted = configs.delete(params.pushNotificationConfigId);
307
+ if (configs.size === 0) {
308
+ this.store.delete(key);
309
+ }
310
+ return deleted;
311
+ }
312
+ };
80
313
 
81
314
  // src/server/a2a/tasks.ts
82
315
  function isTaskStatusUpdate(update) {
@@ -204,9 +437,27 @@ var messageSendParamsSchema = z.object({
204
437
  referenceTaskIds: z.array(z.string()).optional(),
205
438
  extensions: z.array(z.string()).optional(),
206
439
  metadata: z.record(z.string(), z.any()).optional()
207
- })
440
+ }),
441
+ configuration: z.object({
442
+ acceptedOutputModes: z.array(z.string()).optional(),
443
+ blocking: z.boolean().optional(),
444
+ historyLength: z.number().optional(),
445
+ pushNotificationConfig: z.object({
446
+ url: z.string(),
447
+ id: z.string().optional(),
448
+ token: z.string().optional(),
449
+ authentication: z.object({
450
+ schemes: z.array(z.string()),
451
+ credentials: z.string().optional()
452
+ }).optional()
453
+ }).optional()
454
+ }).optional()
208
455
  });
209
- function createAgentCardDefaults() {
456
+ var defaultPushNotificationStore = new InMemoryPushNotificationStore();
457
+ var defaultPushNotificationSender = new DefaultPushNotificationSender(defaultPushNotificationStore);
458
+ function createAgentCardDefaults({
459
+ pushNotifications = false
460
+ } = {}) {
210
461
  return {
211
462
  protocolVersion: "0.3.0",
212
463
  additionalInterfaces: [],
@@ -215,7 +466,7 @@ function createAgentCardDefaults() {
215
466
  securitySchemes: {},
216
467
  capabilities: {
217
468
  streaming: true,
218
- pushNotifications: false,
469
+ pushNotifications,
219
470
  stateTransitionHistory: false,
220
471
  extensions: []
221
472
  },
@@ -232,6 +483,7 @@ async function getAgentCardByIdHandler({
232
483
  url: "https://mastra.ai"
233
484
  },
234
485
  version = "1.0",
486
+ pushNotifications = false,
235
487
  requestContext
236
488
  }) {
237
489
  const agent = await getAgentFromSystem({ mastra, agentId });
@@ -242,7 +494,7 @@ async function getAgentCardByIdHandler({
242
494
  url: executionUrl,
243
495
  provider,
244
496
  version,
245
- ...createAgentCardDefaults(),
497
+ ...createAgentCardDefaults({ pushNotifications }),
246
498
  // Convert agent tools to skills format for A2A protocol
247
499
  skills: Object.entries(tools).map(([toolId, tool]) => ({
248
500
  id: toolId,
@@ -338,6 +590,63 @@ function createDataArtifactUpdate({
338
590
  }
339
591
  };
340
592
  }
593
+ function resolvePushNotificationPair({
594
+ pushNotificationStore,
595
+ pushNotificationSender
596
+ }) {
597
+ if (pushNotificationSender) {
598
+ return {
599
+ pushNotificationStore: pushNotificationSender.getStore(),
600
+ pushNotificationSender
601
+ };
602
+ }
603
+ if (pushNotificationStore) {
604
+ return {
605
+ pushNotificationStore,
606
+ pushNotificationSender: new DefaultPushNotificationSender(pushNotificationStore)
607
+ };
608
+ }
609
+ return {
610
+ pushNotificationStore: defaultPushNotificationStore,
611
+ pushNotificationSender: defaultPushNotificationSender
612
+ };
613
+ }
614
+ function createTaskPushNotificationConfig(taskId, pushNotificationConfig) {
615
+ return {
616
+ taskId,
617
+ pushNotificationConfig: {
618
+ ...pushNotificationConfig,
619
+ id: pushNotificationConfig.id ?? taskId
620
+ }
621
+ };
622
+ }
623
+ function shouldSendPushNotification(previousTask, nextTask) {
624
+ const pushTriggerStates = ["completed", "failed", "canceled", "input-required"];
625
+ if (!pushTriggerStates.includes(nextTask.status.state)) {
626
+ return false;
627
+ }
628
+ return previousTask?.status.state !== nextTask.status.state;
629
+ }
630
+ async function saveTaskAndMaybeSendPushNotification({
631
+ taskStore,
632
+ pushNotificationSender,
633
+ previousTask,
634
+ nextTask,
635
+ agentId,
636
+ logger
637
+ }) {
638
+ await taskStore.save({ agentId, data: nextTask });
639
+ if (!shouldSendPushNotification(previousTask, nextTask)) {
640
+ return;
641
+ }
642
+ void pushNotificationSender.sendNotifications({
643
+ agentId,
644
+ task: nextTask,
645
+ logger
646
+ }).catch((error) => {
647
+ logger?.error("Failed to schedule A2A push notification", error);
648
+ });
649
+ }
341
650
  function extractFullStreamTextDelta(value) {
342
651
  if (typeof value !== "object" || value === null || !("type" in value)) {
343
652
  return null;
@@ -442,6 +751,8 @@ async function handleMessageSend({
442
751
  requestId,
443
752
  params,
444
753
  taskStore,
754
+ pushNotificationStore,
755
+ pushNotificationSender,
445
756
  agent,
446
757
  agentId,
447
758
  logger,
@@ -451,6 +762,13 @@ async function handleMessageSend({
451
762
  const { message, metadata } = params;
452
763
  const { contextId } = message;
453
764
  const taskId = message.taskId || crypto.randomUUID();
765
+ const {
766
+ pushNotificationStore: resolvedPushNotificationStore,
767
+ pushNotificationSender: resolvedPushNotificationSender
768
+ } = resolvePushNotificationPair({
769
+ pushNotificationStore,
770
+ pushNotificationSender
771
+ });
454
772
  let currentData = await loadOrCreateTask({
455
773
  taskId,
456
774
  taskStore,
@@ -459,7 +777,13 @@ async function handleMessageSend({
459
777
  contextId,
460
778
  metadata
461
779
  });
462
- createTaskContext({
780
+ if (params.configuration?.pushNotificationConfig) {
781
+ resolvedPushNotificationStore.set({
782
+ agentId,
783
+ config: createTaskPushNotificationConfig(taskId, params.configuration.pushNotificationConfig)
784
+ });
785
+ }
786
+ const context = createTaskContext({
463
787
  task: currentData,
464
788
  userMessage: message,
465
789
  history: currentData.history || [],
@@ -494,7 +818,15 @@ async function handleMessageSend({
494
818
  finishReason: result.finishReason
495
819
  }
496
820
  };
497
- await taskStore.save({ agentId, data: currentData });
821
+ await saveTaskAndMaybeSendPushNotification({
822
+ taskStore,
823
+ pushNotificationSender: resolvedPushNotificationSender,
824
+ previousTask: context.task,
825
+ nextTask: currentData,
826
+ agentId,
827
+ logger
828
+ });
829
+ context.task = currentData;
498
830
  } catch (handlerError) {
499
831
  const failureStatusUpdate = {
500
832
  state: "failed",
@@ -512,7 +844,14 @@ async function handleMessageSend({
512
844
  };
513
845
  currentData = applyUpdateToTask(currentData, failureStatusUpdate);
514
846
  try {
515
- await taskStore.save({ agentId, data: currentData });
847
+ await saveTaskAndMaybeSendPushNotification({
848
+ taskStore,
849
+ pushNotificationSender: resolvedPushNotificationSender,
850
+ previousTask: context.task,
851
+ nextTask: currentData,
852
+ agentId,
853
+ logger
854
+ });
516
855
  } catch (saveError) {
517
856
  logger?.error(`Failed to save task ${currentData.id} after handler error:`, saveError?.message);
518
857
  }
@@ -532,10 +871,115 @@ async function handleTaskGet({
532
871
  }
533
872
  return createSuccessResponse(requestId, task);
534
873
  }
874
+ async function loadTaskOrThrow({
875
+ taskStore,
876
+ agentId,
877
+ taskId
878
+ }) {
879
+ const task = await taskStore.load({ agentId, taskId });
880
+ if (!task) {
881
+ throw MastraA2AError.taskNotFound(taskId);
882
+ }
883
+ return task;
884
+ }
885
+ async function handleSetTaskPushNotificationConfig({
886
+ requestId,
887
+ taskStore,
888
+ pushNotificationStore,
889
+ agentId,
890
+ params
891
+ }) {
892
+ await loadTaskOrThrow({
893
+ taskStore,
894
+ agentId,
895
+ taskId: params.taskId
896
+ });
897
+ const { pushNotificationStore: resolvedPushNotificationStore } = resolvePushNotificationPair({
898
+ pushNotificationStore
899
+ });
900
+ const config = resolvedPushNotificationStore.set({
901
+ agentId,
902
+ config: createTaskPushNotificationConfig(params.taskId, params.pushNotificationConfig)
903
+ });
904
+ return createSuccessResponse(requestId, config);
905
+ }
906
+ async function handleGetTaskPushNotificationConfig({
907
+ requestId,
908
+ taskStore,
909
+ pushNotificationStore,
910
+ agentId,
911
+ params
912
+ }) {
913
+ await loadTaskOrThrow({
914
+ taskStore,
915
+ agentId,
916
+ taskId: params.id
917
+ });
918
+ const { pushNotificationStore: resolvedPushNotificationStore } = resolvePushNotificationPair({
919
+ pushNotificationStore
920
+ });
921
+ const config = resolvedPushNotificationStore.get({
922
+ agentId,
923
+ params
924
+ });
925
+ if (!config) {
926
+ throw MastraA2AError.invalidParams(
927
+ `Push notification config not found: ${params.pushNotificationConfigId ?? params.id}`
928
+ );
929
+ }
930
+ return createSuccessResponse(requestId, config);
931
+ }
932
+ async function handleListTaskPushNotificationConfig({
933
+ requestId,
934
+ taskStore,
935
+ pushNotificationStore,
936
+ agentId,
937
+ params
938
+ }) {
939
+ await loadTaskOrThrow({
940
+ taskStore,
941
+ agentId,
942
+ taskId: params.id
943
+ });
944
+ const { pushNotificationStore: resolvedPushNotificationStore } = resolvePushNotificationPair({
945
+ pushNotificationStore
946
+ });
947
+ const configs = resolvedPushNotificationStore.list({
948
+ agentId,
949
+ params
950
+ });
951
+ return createSuccessResponse(requestId, configs);
952
+ }
953
+ async function handleDeleteTaskPushNotificationConfig({
954
+ requestId,
955
+ taskStore,
956
+ pushNotificationStore,
957
+ agentId,
958
+ params
959
+ }) {
960
+ await loadTaskOrThrow({
961
+ taskStore,
962
+ agentId,
963
+ taskId: params.id
964
+ });
965
+ const { pushNotificationStore: resolvedPushNotificationStore } = resolvePushNotificationPair({
966
+ pushNotificationStore
967
+ });
968
+ const deleted = resolvedPushNotificationStore.delete({
969
+ agentId,
970
+ params
971
+ });
972
+ if (!deleted) {
973
+ throw MastraA2AError.invalidParams(`Push notification config not found: ${params.pushNotificationConfigId}`);
974
+ }
975
+ return createSuccessResponse(requestId, null);
976
+ }
535
977
  async function* handleMessageStream({
536
978
  requestId,
537
979
  params,
538
980
  taskStore,
981
+ pushNotificationStore,
982
+ pushNotificationSender,
539
983
  agent,
540
984
  agentId,
541
985
  logger,
@@ -545,6 +989,13 @@ async function* handleMessageStream({
545
989
  const { message, metadata } = params;
546
990
  const { contextId } = message;
547
991
  const taskId = message.taskId || crypto.randomUUID();
992
+ const {
993
+ pushNotificationStore: resolvedPushNotificationStore,
994
+ pushNotificationSender: resolvedPushNotificationSender
995
+ } = resolvePushNotificationPair({
996
+ pushNotificationStore,
997
+ pushNotificationSender
998
+ });
548
999
  let currentData = await loadOrCreateTask({
549
1000
  taskId,
550
1001
  taskStore,
@@ -553,6 +1004,12 @@ async function* handleMessageStream({
553
1004
  contextId,
554
1005
  metadata
555
1006
  });
1007
+ if (params.configuration?.pushNotificationConfig) {
1008
+ resolvedPushNotificationStore.set({
1009
+ agentId,
1010
+ config: createTaskPushNotificationConfig(taskId, params.configuration.pushNotificationConfig)
1011
+ });
1012
+ }
556
1013
  currentData = applyUpdateToTask(currentData, {
557
1014
  state: "working",
558
1015
  message: {
@@ -562,7 +1019,13 @@ async function* handleMessageStream({
562
1019
  parts: [{ kind: "text", text: "Generating response..." }]
563
1020
  }
564
1021
  });
565
- await taskStore.save({ agentId, data: currentData });
1022
+ await saveTaskAndMaybeSendPushNotification({
1023
+ taskStore,
1024
+ pushNotificationSender: resolvedPushNotificationSender,
1025
+ nextTask: currentData,
1026
+ agentId,
1027
+ logger
1028
+ });
566
1029
  yield createSuccessResponse(requestId, currentData);
567
1030
  try {
568
1031
  const resourceId = metadata?.resourceId ?? message.metadata?.resourceId ?? agentId;
@@ -589,7 +1052,13 @@ async function* handleMessageStream({
589
1052
  lastChunk: false
590
1053
  });
591
1054
  currentData = applyUpdateToTask(currentData, textUpdate);
592
- await taskStore.save({ agentId, data: currentData });
1055
+ await saveTaskAndMaybeSendPushNotification({
1056
+ taskStore,
1057
+ pushNotificationSender: resolvedPushNotificationSender,
1058
+ nextTask: currentData,
1059
+ agentId,
1060
+ logger
1061
+ });
593
1062
  yield createSuccessResponse(requestId, textUpdate);
594
1063
  sawTextArtifact = true;
595
1064
  pendingTextChunk = textDelta;
@@ -616,7 +1085,13 @@ async function* handleMessageStream({
616
1085
  lastChunk: !structuredData
617
1086
  });
618
1087
  currentData = applyUpdateToTask(currentData, textUpdate);
619
- await taskStore.save({ agentId, data: currentData });
1088
+ await saveTaskAndMaybeSendPushNotification({
1089
+ taskStore,
1090
+ pushNotificationSender: resolvedPushNotificationSender,
1091
+ nextTask: currentData,
1092
+ agentId,
1093
+ logger
1094
+ });
620
1095
  yield createSuccessResponse(requestId, textUpdate);
621
1096
  sawTextArtifact = true;
622
1097
  pendingTextChunk = void 0;
@@ -629,15 +1104,22 @@ async function* handleMessageStream({
629
1104
  lastChunk: true
630
1105
  });
631
1106
  currentData = applyUpdateToTask(currentData, dataUpdate);
632
- await taskStore.save({ agentId, data: currentData });
1107
+ await saveTaskAndMaybeSendPushNotification({
1108
+ taskStore,
1109
+ pushNotificationSender: resolvedPushNotificationSender,
1110
+ nextTask: currentData,
1111
+ agentId,
1112
+ logger
1113
+ });
633
1114
  yield createSuccessResponse(requestId, dataUpdate);
634
1115
  }
635
- currentData = applyUpdateToTask(currentData, {
1116
+ const previousTask = currentData;
1117
+ const completedTask = applyUpdateToTask(currentData, {
636
1118
  state: "completed",
637
1119
  message: void 0
638
1120
  });
639
- currentData.metadata = {
640
- ...currentData.metadata,
1121
+ completedTask.metadata = {
1122
+ ...completedTask.metadata,
641
1123
  execution: {
642
1124
  toolCalls: await result.toolCalls,
643
1125
  toolResults: await result.toolResults,
@@ -645,8 +1127,17 @@ async function* handleMessageStream({
645
1127
  finishReason: await result.finishReason
646
1128
  }
647
1129
  };
648
- await taskStore.save({ agentId, data: currentData });
1130
+ currentData = completedTask;
1131
+ await saveTaskAndMaybeSendPushNotification({
1132
+ taskStore,
1133
+ pushNotificationSender: resolvedPushNotificationSender,
1134
+ previousTask,
1135
+ nextTask: currentData,
1136
+ agentId,
1137
+ logger
1138
+ });
649
1139
  } catch (handlerError) {
1140
+ const previousTask = currentData;
650
1141
  currentData = applyUpdateToTask(currentData, {
651
1142
  state: "failed",
652
1143
  message: {
@@ -662,7 +1153,14 @@ async function* handleMessageStream({
662
1153
  }
663
1154
  });
664
1155
  try {
665
- await taskStore.save({ agentId, data: currentData });
1156
+ await saveTaskAndMaybeSendPushNotification({
1157
+ taskStore,
1158
+ pushNotificationSender: resolvedPushNotificationSender,
1159
+ previousTask,
1160
+ nextTask: currentData,
1161
+ agentId,
1162
+ logger
1163
+ });
666
1164
  } catch (saveError) {
667
1165
  logger?.error(`Failed to save task ${currentData.id} after handler error:`, saveError?.message);
668
1166
  }
@@ -769,6 +1267,7 @@ function createA2ASSEResponse(payload) {
769
1267
  async function handleTaskCancel({
770
1268
  requestId,
771
1269
  taskStore,
1270
+ pushNotificationSender,
772
1271
  agentId,
773
1272
  taskId,
774
1273
  logger
@@ -795,8 +1294,16 @@ async function handleTaskCancel({
795
1294
  messageId: crypto.randomUUID()
796
1295
  }
797
1296
  };
1297
+ const previousTask = data;
798
1298
  data = applyUpdateToTask(data, cancelUpdate);
799
- await taskStore.save({ agentId, data });
1299
+ await saveTaskAndMaybeSendPushNotification({
1300
+ taskStore,
1301
+ pushNotificationSender: resolvePushNotificationPair({ pushNotificationSender }).pushNotificationSender,
1302
+ previousTask,
1303
+ nextTask: data,
1304
+ agentId,
1305
+ logger
1306
+ });
800
1307
  taskStore.activeCancellations.delete(taskId);
801
1308
  return createSuccessResponse(requestId, data);
802
1309
  }
@@ -808,10 +1315,19 @@ async function getAgentExecutionHandler({
808
1315
  method,
809
1316
  params,
810
1317
  taskStore,
1318
+ pushNotificationStore,
1319
+ pushNotificationSender,
811
1320
  logger,
812
1321
  abortSignal
813
1322
  }) {
814
1323
  const agent = await getAgentFromSystem({ mastra, agentId });
1324
+ const {
1325
+ pushNotificationStore: resolvedPushNotificationStore,
1326
+ pushNotificationSender: resolvedPushNotificationSender
1327
+ } = resolvePushNotificationPair({
1328
+ pushNotificationStore,
1329
+ pushNotificationSender
1330
+ });
815
1331
  let taskId;
816
1332
  try {
817
1333
  taskId = getTaskIdFromParams(params);
@@ -821,8 +1337,11 @@ async function getAgentExecutionHandler({
821
1337
  requestId,
822
1338
  params,
823
1339
  taskStore,
1340
+ pushNotificationStore: resolvedPushNotificationStore,
1341
+ pushNotificationSender: resolvedPushNotificationSender,
824
1342
  agent,
825
1343
  agentId,
1344
+ logger,
826
1345
  requestContext
827
1346
  });
828
1347
  return result;
@@ -832,8 +1351,11 @@ async function getAgentExecutionHandler({
832
1351
  requestId,
833
1352
  taskStore,
834
1353
  params,
1354
+ pushNotificationStore: resolvedPushNotificationStore,
1355
+ pushNotificationSender: resolvedPushNotificationSender,
835
1356
  agent,
836
1357
  agentId,
1358
+ logger,
837
1359
  requestContext
838
1360
  });
839
1361
  return result;
@@ -851,8 +1373,10 @@ async function getAgentExecutionHandler({
851
1373
  const result = await handleTaskCancel({
852
1374
  requestId,
853
1375
  taskStore,
1376
+ pushNotificationSender: resolvedPushNotificationSender,
854
1377
  agentId,
855
- taskId: taskId || "No task ID provided"
1378
+ taskId: taskId || "No task ID provided",
1379
+ logger
856
1380
  });
857
1381
  return result;
858
1382
  }
@@ -865,10 +1389,37 @@ async function getAgentExecutionHandler({
865
1389
  abortSignal
866
1390
  });
867
1391
  case "tasks/pushNotificationConfig/set":
1392
+ return await handleSetTaskPushNotificationConfig({
1393
+ requestId,
1394
+ taskStore,
1395
+ pushNotificationStore: resolvedPushNotificationStore,
1396
+ agentId,
1397
+ params
1398
+ });
868
1399
  case "tasks/pushNotificationConfig/get":
1400
+ return await handleGetTaskPushNotificationConfig({
1401
+ requestId,
1402
+ taskStore,
1403
+ pushNotificationStore: resolvedPushNotificationStore,
1404
+ agentId,
1405
+ params
1406
+ });
869
1407
  case "tasks/pushNotificationConfig/list":
1408
+ return await handleListTaskPushNotificationConfig({
1409
+ requestId,
1410
+ taskStore,
1411
+ pushNotificationStore: resolvedPushNotificationStore,
1412
+ agentId,
1413
+ params
1414
+ });
870
1415
  case "tasks/pushNotificationConfig/delete":
871
- throw MastraA2AError.pushNotificationNotSupported();
1416
+ return await handleDeleteTaskPushNotificationConfig({
1417
+ requestId,
1418
+ taskStore,
1419
+ pushNotificationStore: resolvedPushNotificationStore,
1420
+ agentId,
1421
+ params
1422
+ });
872
1423
  case "agent/getAuthenticatedExtendedCard":
873
1424
  throw MastraA2AError.extendedAgentCardNotConfigured();
874
1425
  default:
@@ -901,7 +1452,8 @@ var GET_AGENT_CARD_ROUTE = createRoute({
901
1452
  mastra: ctx.mastra,
902
1453
  requestContext: ctx.requestContext,
903
1454
  agentId: ctx.agentId,
904
- executionUrl
1455
+ executionUrl,
1456
+ pushNotifications: true
905
1457
  });
906
1458
  }
907
1459
  });
@@ -936,6 +1488,6 @@ var AGENT_EXECUTION_ROUTE = createRoute({
936
1488
  }
937
1489
  });
938
1490
 
939
- export { AGENT_EXECUTION_ROUTE, GET_AGENT_CARD_ROUTE, a2a_exports, getAgentCardByIdHandler, getAgentExecutionHandler, handleMessageSend, handleMessageStream, handleTaskCancel, handleTaskGet, handleTaskResubscribe };
940
- //# sourceMappingURL=chunk-ALUAG74N.js.map
941
- //# sourceMappingURL=chunk-ALUAG74N.js.map
1491
+ export { AGENT_EXECUTION_ROUTE, GET_AGENT_CARD_ROUTE, a2a_exports, getAgentCardByIdHandler, getAgentExecutionHandler, handleDeleteTaskPushNotificationConfig, handleGetTaskPushNotificationConfig, handleListTaskPushNotificationConfig, handleMessageSend, handleMessageStream, handleSetTaskPushNotificationConfig, handleTaskCancel, handleTaskGet, handleTaskResubscribe };
1492
+ //# sourceMappingURL=chunk-3KIFZFY7.js.map
1493
+ //# sourceMappingURL=chunk-3KIFZFY7.js.map