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