'use strict'; var chunkCXAJPAJ2_cjs = require('./chunk-CXAJPAJ2.cjs'); var chunk4ZHHKMDQ_cjs = require('./chunk-4ZHHKMDQ.cjs'); var chunkDZD7RZYY_cjs = require('./chunk-DZD7RZYY.cjs'); var chunkGZ4HWZWE_cjs = require('./chunk-GZ4HWZWE.cjs'); var chunkG54X6VE6_cjs = require('./chunk-G54X6VE6.cjs'); var chunkO7I5CWRX_cjs = require('./chunk-O7I5CWRX.cjs'); var util = require('util'); var a2a = require('@mastra/core/a2a'); var v4 = require('zod/v4'); var crypto2 = require('crypto'); var promises = require('dns/promises'); var http = require('http'); var https = require('https'); var net = require('net'); function _interopNamespace(e) { if (e && e.__esModule) return e; var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n.default = e; return Object.freeze(n); } var crypto2__namespace = /*#__PURE__*/_interopNamespace(crypto2); // ../../../../../setup-pnpm/node_modules/.bin/store/v11/links/@/canonicalize/1.0.8/8d710dcf19a48d178b2fc853e16c59951fde29eb27b6037da6c3f4dbb968b03d/node_modules/canonicalize/lib/canonicalize.js var require_canonicalize = chunkO7I5CWRX_cjs.__commonJS({ "../../../../../setup-pnpm/node_modules/.bin/store/v11/links/@/canonicalize/1.0.8/8d710dcf19a48d178b2fc853e16c59951fde29eb27b6037da6c3f4dbb968b03d/node_modules/canonicalize/lib/canonicalize.js"(exports, module) { module.exports = function serialize(object) { if (object === null || typeof object !== "object" || object.toJSON != null) { return JSON.stringify(object); } if (Array.isArray(object)) { return "[" + object.reduce((t, cv, ci) => { const comma = ci === 0 ? "" : ","; const value = cv === void 0 || typeof cv === "symbol" ? null : cv; return t + comma + serialize(value); }, "") + "]"; } return "{" + Object.keys(object).sort().reduce((t, cv, ci) => { if (object[cv] === void 0 || typeof object[cv] === "symbol") { return t; } const comma = t.length === 0 ? "" : ","; return t + comma + serialize(cv) + ":" + serialize(object[cv]); }, "") + "}"; }; } }); // src/server/handlers/a2a.ts var a2a_exports = {}; chunkO7I5CWRX_cjs.__export(a2a_exports, { AGENT_EXECUTION_ROUTE: () => AGENT_EXECUTION_ROUTE, GET_AGENT_CARD_ROUTE: () => GET_AGENT_CARD_ROUTE, getAgentCardByIdHandler: () => getAgentCardByIdHandler, getAgentExecutionHandler: () => getAgentExecutionHandler, handleDeleteTaskPushNotificationConfig: () => handleDeleteTaskPushNotificationConfig, handleGetTaskPushNotificationConfig: () => handleGetTaskPushNotificationConfig, handleListTaskPushNotificationConfig: () => handleListTaskPushNotificationConfig, handleMessageSend: () => handleMessageSend, handleMessageStream: () => handleMessageStream, handleSetTaskPushNotificationConfig: () => handleSetTaskPushNotificationConfig, handleTaskCancel: () => handleTaskCancel, handleTaskGet: () => handleTaskGet, handleTaskResubscribe: () => handleTaskResubscribe }); // src/server/a2a/agent-card-signing.ts var import_canonicalize = chunkO7I5CWRX_cjs.__toESM(require_canonicalize(), 1); var SUPPORTED_JWS_ALGORITHMS = /* @__PURE__ */ new Set([ "ES256", "ES384", "ES512", "RS256", "RS384", "RS512", "PS256", "PS384", "PS512" ]); function stripAgentCardSignatures(agentCard) { const unsignedCard = structuredClone(agentCard); delete unsignedCard.signatures; return unsignedCard; } function importSigningKey(signing) { const { privateKey } = signing; if (typeof privateKey === "string") { return crypto2__namespace.createPrivateKey(privateKey); } return crypto2__namespace.createPrivateKey({ key: privateKey, format: "jwk" }); } function getProtectedHeader(signing) { const { alg, ...rest } = signing.protectedHeader; if (!SUPPORTED_JWS_ALGORITHMS.has(alg)) { throw new Error(`Unsupported JWS algorithm for A2A Agent Card signing: ${alg}`); } return { ...rest, alg }; } function getSignatureOptions(algorithm) { if (algorithm.startsWith("ES")) { return { dsaEncoding: "ieee-p1363" }; } if (algorithm.startsWith("PS")) { return { padding: crypto2__namespace.constants.RSA_PKCS1_PSS_PADDING, saltLength: crypto2__namespace.constants.RSA_PSS_SALTLEN_DIGEST }; } return {}; } function getDigestAlgorithm(algorithm) { if (algorithm.endsWith("256")) return "sha256"; if (algorithm.endsWith("384")) return "sha384"; if (algorithm.endsWith("512")) return "sha512"; throw new Error(`Unsupported JWS algorithm for A2A Agent Card signing: ${algorithm}`); } async function signAgentCard({ agentCard, signing }) { const canonicalPayload = (0, import_canonicalize.default)(stripAgentCardSignatures(agentCard)); if (!canonicalPayload) { throw new Error("Failed to canonicalize A2A Agent Card for signing"); } const key = importSigningKey(signing); const protectedHeader = getProtectedHeader(signing); const encodedHeader = Buffer.from(JSON.stringify(protectedHeader), "utf8").toString("base64url"); const encodedPayload = Buffer.from(canonicalPayload, "utf8").toString("base64url"); const signingInput = `${encodedHeader}.${encodedPayload}`; const signatureBuffer = crypto2__namespace.sign( getDigestAlgorithm(String(protectedHeader.alg)), Buffer.from(signingInput, "utf8"), { key, ...getSignatureOptions(String(protectedHeader.alg)) } ); const signatureValue = signatureBuffer.toString("base64url"); if (!encodedHeader || !signatureValue) { throw new Error("Failed to create compact JWS for A2A Agent Card"); } const signature = { protected: encodedHeader, signature: signatureValue, header: signing.header }; return { ...agentCard, signatures: [...agentCard.signatures ?? [], signature] }; } function normalizeError(error, reqId, taskId, logger) { let a2aError; if (error instanceof a2a.MastraA2AError) { a2aError = error; } else if (error instanceof Error) { a2aError = a2a.MastraA2AError.internalError(error.message, { stack: error.stack }); } else { a2aError = a2a.MastraA2AError.internalError("An unknown error occurred.", error); } if (taskId && !a2aError.taskId) { a2aError.taskId = taskId; } logger?.error(`Error processing request (Task: ${a2aError.taskId ?? "N/A"}, ReqID: ${reqId ?? "N/A"}):`, a2aError); return createErrorResponse(reqId, a2aError.toJSONRPCError()); } function createErrorResponse(id, error) { return { jsonrpc: "2.0", id, // Can be null if request ID was invalid/missing error }; } function createSuccessResponse(id, result) { if (!id) { throw a2a.MastraA2AError.internalError("Cannot create success response for null ID."); } return { jsonrpc: "2.0", id, result }; } function convertToCoreMessage(message) { return { role: message.role === "user" ? "user" : "assistant", content: message.parts.map((msg) => convertToCoreMessagePart(msg)) }; } function convertToCoreMessagePart(part) { switch (part.kind) { case "text": return { type: "text", text: part.text }; case "file": return { type: "file", data: "uri" in part.file ? new URL(part.file.uri) : part.file.bytes, mimeType: part.file.mimeType }; case "data": throw new Error("Data parts are not supported in core messages"); } } var DEFAULT_PUSH_NOTIFICATION_TOKEN_HEADER = "X-A2A-Notification-Token"; function isDisallowedHostname(hostname) { const normalized = hostname.toLowerCase(); return normalized === "localhost" || normalized.endsWith(".localhost") || normalized.endsWith(".local") || normalized.endsWith(".internal") || !normalized.includes("."); } function isDisallowedIpv4(address) { const [first = -1, second = -1] = address.split(".").map(Number); return first === 10 || first === 127 || first === 169 && second === 254 || first === 172 && second >= 16 && second <= 31 || first === 192 && second === 168; } function isDisallowedIpv6(address) { const normalized = address.toLowerCase(); return normalized === "::1" || normalized.startsWith("fe8") || normalized.startsWith("fe9") || normalized.startsWith("fea") || normalized.startsWith("feb") || normalized.startsWith("fc") || normalized.startsWith("fd"); } function isDisallowedIpAddress(address) { const version = net.isIP(address); if (version === 4) { return isDisallowedIpv4(address); } if (version === 6) { return isDisallowedIpv6(address); } return false; } var DefaultPushNotificationSender = class { constructor(pushNotificationStore, options = {}) { this.pushNotificationStore = pushNotificationStore; this.options = options; } pushNotificationStore; options; getStore() { return this.pushNotificationStore; } async resolveValidatedDestination(rawUrl) { const url = new URL(rawUrl); if (url.protocol !== "https:" && url.protocol !== "http:") { throw new Error(`Push notification URL must use http or https: ${url.protocol}`); } const hostname = url.hostname.toLowerCase(); if (this.options.allowedHosts && !this.options.allowedHosts.includes(hostname)) { throw new Error(`Push notification host is not allowed: ${hostname}`); } if (isDisallowedHostname(hostname)) { throw new Error(`Push notification URL must not target local or internal hosts: ${hostname}`); } if (isDisallowedIpAddress(hostname)) { throw new Error(`Push notification URL must not target local or private IPs: ${hostname}`); } const resolvedAddresses = net.isIP(hostname) === 0 ? await (this.options.lookup ?? promises.lookup)(hostname, { all: true, verbatim: true }) : [{ address: hostname, family: net.isIP(hostname) }]; if (resolvedAddresses.some((result) => isDisallowedIpAddress(result.address))) { throw new Error(`Push notification URL resolved to a local or private IP: ${hostname}`); } const requestUrl = new URL(url.toString()); requestUrl.hostname = resolvedAddresses[0].address; return { originalUrl: url, requestUrl, hostHeader: url.host, servername: net.isIP(hostname) === 0 ? hostname : void 0 }; } async postTaskSnapshot({ requestUrl, hostHeader, servername, headers, body, timeout }) { headers.set("host", hostHeader); const signal = typeof AbortSignal.timeout === "function" ? AbortSignal.timeout(timeout) : void 0; if (this.options.fetch) { return this.options.fetch(requestUrl.toString(), { method: "POST", headers, body, signal }); } const transport = requestUrl.protocol === "https:" ? https.request : http.request; return await new Promise((resolve, reject) => { const request = transport( { protocol: requestUrl.protocol, hostname: requestUrl.hostname, port: requestUrl.port || void 0, path: `${requestUrl.pathname}${requestUrl.search}`, method: "POST", headers: Object.fromEntries(headers.entries()), servername }, (response) => { response.resume(); response.on("end", () => { resolve({ ok: !!response.statusCode && response.statusCode >= 200 && response.statusCode < 300, status: response.statusCode ?? 0, statusText: response.statusMessage ?? "" }); }); } ); request.on("error", reject); if (signal) { signal.addEventListener( "abort", () => { request.destroy(signal.reason instanceof Error ? signal.reason : new Error("Push notification timed out")); }, { once: true } ); } request.end(body); }); } async sendNotifications({ agentId, task, logger }) { const configs = this.pushNotificationStore.list({ agentId, params: { id: task.id } }); if (configs.length === 0) { return; } await Promise.allSettled( configs.map(async (config) => { const headers = new Headers({ "content-type": "application/json" }); if (config.pushNotificationConfig.token) { headers.set( this.options.tokenHeaderName ?? DEFAULT_PUSH_NOTIFICATION_TOKEN_HEADER, config.pushNotificationConfig.token ); } const auth = config.pushNotificationConfig.authentication; if (auth?.credentials) { if (auth.schemes.includes("Bearer")) { headers.set("authorization", `Bearer ${auth.credentials}`); } else if (auth.schemes.includes("Basic")) { headers.set("authorization", `Basic ${auth.credentials}`); } } const { requestUrl, hostHeader, servername } = await this.resolveValidatedDestination( config.pushNotificationConfig.url ); const response = await this.postTaskSnapshot({ requestUrl, hostHeader, servername, headers, body: JSON.stringify(task), timeout: this.options.timeout ?? 5e3 }); if (!response.ok) { throw new Error( `Push notification failed with status ${response.status} ${response.statusText ?? ""}`.trim() ); } }) ).then((results) => { for (const result of results) { if (result.status === "rejected") { logger?.error("Failed to deliver A2A push notification", result.reason); } } }); } }; // src/server/a2a/push-notification-store.ts function normalizeConfigId(taskId, configId) { return configId || taskId; } var InMemoryPushNotificationStore = class { store = /* @__PURE__ */ new Map(); getKey(agentId, taskId) { return JSON.stringify([agentId, taskId]); } set({ agentId, config }) { const key = this.getKey(agentId, config.taskId); const configs = this.store.get(key) ?? /* @__PURE__ */ new Map(); const normalizedConfig = { taskId: config.taskId, pushNotificationConfig: { ...config.pushNotificationConfig, id: normalizeConfigId(config.taskId, config.pushNotificationConfig.id) } }; configs.set(normalizedConfig.pushNotificationConfig.id, structuredClone(normalizedConfig)); this.store.set(key, configs); return structuredClone(normalizedConfig); } get({ agentId, params }) { const key = this.getKey(agentId, params.id); const configId = normalizeConfigId(params.id, params.pushNotificationConfigId); const config = this.store.get(key)?.get(configId); return config ? structuredClone(config) : null; } list({ agentId, params }) { const key = this.getKey(agentId, params.id); return Array.from(this.store.get(key)?.values() ?? []).map((config) => structuredClone(config)); } delete({ agentId, params }) { const key = this.getKey(agentId, params.id); const configs = this.store.get(key); if (!configs) { return false; } const deleted = configs.delete(params.pushNotificationConfigId); if (configs.size === 0) { this.store.delete(key); } return deleted; } }; // src/server/a2a/tasks.ts function isTaskStatusUpdate(update) { return "state" in update && !("parts" in update); } function isArtifactUpdate(update) { return "kind" in update && update.kind === "artifact-update"; } function applyUpdateToTask(current, update) { let newTask = structuredClone(current); if (isTaskStatusUpdate(update)) { newTask.status = { ...newTask.status, // Keep existing properties if not overwritten ...update, // Apply updates timestamp: (/* @__PURE__ */ new Date()).toISOString() }; } else if (isArtifactUpdate(update)) { if (!newTask.artifacts) { newTask.artifacts = []; } else { newTask.artifacts = [...newTask.artifacts]; } const artifact = update.artifact; const existingIndex = newTask.artifacts.findIndex((a) => a.name === artifact.name); const existingArtifact = newTask.artifacts[existingIndex]; if (existingArtifact) { if (update.append) { const appendedArtifact = JSON.parse(JSON.stringify(existingArtifact)); appendedArtifact.parts.push(...artifact.parts); if (artifact.metadata) { appendedArtifact.metadata = { ...appendedArtifact.metadata || {}, ...artifact.metadata }; } if (artifact.description) appendedArtifact.description = artifact.description; newTask.artifacts[existingIndex] = appendedArtifact; } else { newTask.artifacts[existingIndex] = { ...artifact }; } } else { newTask.artifacts.push({ ...artifact }); } } return newTask; } async function loadOrCreateTask({ agentId, taskId, taskStore, message, contextId, metadata, logger }) { const data = await taskStore.load({ agentId, taskId }); if (!data) { const initialTask = { id: taskId, contextId: contextId || crypto.randomUUID(), status: { state: "submitted", timestamp: (/* @__PURE__ */ new Date()).toISOString(), message: void 0 }, artifacts: [], history: [message], metadata, kind: "task" }; logger?.info(`[Task ${taskId}] Created new task.`); await taskStore.save({ agentId, data: initialTask }); return initialTask; } logger?.info(`[Task ${taskId}] Loaded existing task.`); let updatedData = data; updatedData.history = [...data.history || [], message]; const { status } = data; const finalStates = ["completed", "failed", "canceled"]; if (finalStates.includes(status.state)) { logger?.warn(`[Task ${taskId}] Received message for task in final state ${status.state}. Restarting.`); updatedData = applyUpdateToTask(updatedData, { state: "submitted", message: void 0 }); } else if (status.state === "input-required") { logger?.info(`[Task ${taskId}] Changing state from 'input-required' to 'working'.`); updatedData = applyUpdateToTask(updatedData, { state: "working" }); } else if (status.state === "working") { logger?.warn(`[Task ${taskId}] Received message while already 'working'. Proceeding.`); } await taskStore.save({ agentId, data: updatedData }); return updatedData; } function createTaskContext({ task, userMessage, history, activeCancellations }) { return { task: structuredClone(task), userMessage, history: structuredClone(history), isCancelled: () => activeCancellations.has(task.id) }; } // src/server/handlers/a2a.ts var messagePartSchema = v4.z.discriminatedUnion("kind", [ v4.z.object({ kind: v4.z.literal("text"), text: v4.z.string(), metadata: v4.z.record(v4.z.string(), v4.z.any()).optional() }), v4.z.object({ kind: v4.z.literal("file"), file: v4.z.union([ v4.z.object({ bytes: v4.z.string(), mimeType: v4.z.string().optional(), name: v4.z.string().optional() }), v4.z.object({ uri: v4.z.string(), mimeType: v4.z.string().optional(), name: v4.z.string().optional() }) ]), metadata: v4.z.record(v4.z.string(), v4.z.any()).optional() }), v4.z.object({ kind: v4.z.literal("data"), data: v4.z.record(v4.z.string(), v4.z.any()), metadata: v4.z.record(v4.z.string(), v4.z.any()).optional() }) ]); var messageSendParamsSchema = v4.z.object({ message: v4.z.object({ role: v4.z.enum(["user", "agent"]), parts: v4.z.array(messagePartSchema), kind: v4.z.literal("message"), messageId: v4.z.string(), contextId: v4.z.string().optional(), taskId: v4.z.string().optional(), referenceTaskIds: v4.z.array(v4.z.string()).optional(), extensions: v4.z.array(v4.z.string()).optional(), metadata: v4.z.record(v4.z.string(), v4.z.any()).optional() }), configuration: v4.z.object({ acceptedOutputModes: v4.z.array(v4.z.string()).optional(), blocking: v4.z.boolean().optional(), historyLength: v4.z.number().optional(), pushNotificationConfig: v4.z.object({ url: v4.z.string(), id: v4.z.string().optional(), token: v4.z.string().optional(), authentication: v4.z.object({ schemes: v4.z.array(v4.z.string()), credentials: v4.z.string().optional() }).optional() }).optional() }).optional() }); var defaultPushNotificationStore = new InMemoryPushNotificationStore(); var defaultPushNotificationSender = new DefaultPushNotificationSender(defaultPushNotificationStore); function createAgentCardDefaults({ pushNotifications = false } = {}) { return { protocolVersion: "0.3.0", additionalInterfaces: [], supportsAuthenticatedExtendedCard: false, security: [], securitySchemes: {}, capabilities: { streaming: true, pushNotifications, stateTransitionHistory: false, extensions: [] }, defaultInputModes: ["text/plain"], defaultOutputModes: ["text/plain"] }; } async function getAgentCardByIdHandler({ mastra, agentId, executionUrl = `/a2a/${agentId}`, provider = { organization: "Mastra", url: "https://mastra.ai" }, version = "1.0", pushNotifications = false, requestContext }) { const agent = await chunkDZD7RZYY_cjs.getAgentFromSystem({ mastra, agentId }); const [instructions, tools] = await Promise.all([agent.getInstructions({ requestContext }), agent.listTools({ requestContext })]); const agentCard = { name: agent.id || agentId, description: chunkGZ4HWZWE_cjs.convertInstructionsToString(instructions), url: executionUrl, provider, version, ...createAgentCardDefaults({ pushNotifications }), // Convert agent tools to skills format for A2A protocol skills: Object.entries(tools).map(([toolId, tool]) => ({ id: toolId, name: toolId, description: tool.description || `Tool: ${toolId}`, // Optional fields tags: ["tool"] })) }; const signing = mastra.getServer?.()?.a2a?.agentCardSigning; if (!signing) { return agentCard; } return signAgentCard({ agentCard, signing }); } function getA2AExecutionUrl({ agentId, request, routePrefix }) { const executionPath = `${routePrefix ?? ""}/a2a/${agentId}`; if (!request) { return executionPath; } return `${chunk4ZHHKMDQ_cjs.getPublicOrigin(request)}${executionPath}`; } function validateMessageSendParams(params) { try { messageSendParamsSchema.parse(params); } catch (error) { if (error instanceof v4.z.ZodError) { throw a2a.MastraA2AError.invalidParams(error.issues[0].message); } throw error; } } function createArtifactUpdate({ taskId, contextId, text, data }) { const parts = [ ...text ? [{ kind: "text", text }] : [], ...data ? [{ kind: "data", data }] : [] ]; if (parts.length === 0) { return void 0; } return { kind: "artifact-update", taskId, contextId, lastChunk: true, artifact: { artifactId: `${taskId}:response`, name: data ? "response.json" : "response.txt", parts } }; } function createTextChunkArtifactUpdate({ taskId, contextId, text, append, lastChunk }) { return { kind: "artifact-update", taskId, contextId, ...append ? { append: true } : {}, ...lastChunk !== void 0 ? { lastChunk } : {}, artifact: { artifactId: `${taskId}:response:text`, name: "response.txt", parts: [{ kind: "text", text }] } }; } function createDataArtifactUpdate({ taskId, contextId, data, lastChunk }) { return { kind: "artifact-update", taskId, contextId, ...{ lastChunk } , artifact: { artifactId: `${taskId}:response:data`, name: "response.json", parts: [{ kind: "data", data }] } }; } function resolvePushNotificationPair({ pushNotificationStore, pushNotificationSender }) { if (pushNotificationSender) { return { pushNotificationStore: pushNotificationSender.getStore(), pushNotificationSender }; } if (pushNotificationStore) { return { pushNotificationStore, pushNotificationSender: new DefaultPushNotificationSender(pushNotificationStore) }; } return { pushNotificationStore: defaultPushNotificationStore, pushNotificationSender: defaultPushNotificationSender }; } function createTaskPushNotificationConfig(taskId, pushNotificationConfig) { return { taskId, pushNotificationConfig: { ...pushNotificationConfig, id: pushNotificationConfig.id ?? taskId } }; } function shouldSendPushNotification(previousTask, nextTask) { const pushTriggerStates = ["completed", "failed", "canceled", "input-required"]; if (!pushTriggerStates.includes(nextTask.status.state)) { return false; } return previousTask?.status.state !== nextTask.status.state; } async function saveTaskAndMaybeSendPushNotification({ taskStore, pushNotificationSender, previousTask, nextTask, agentId, logger }) { await taskStore.save({ agentId, data: nextTask }); if (!shouldSendPushNotification(previousTask, nextTask)) { return; } void pushNotificationSender.sendNotifications({ agentId, task: nextTask, logger }).catch((error) => { logger?.error("Failed to schedule A2A push notification", error); }); } function extractFullStreamTextDelta(value) { if (typeof value !== "object" || value === null || !("type" in value)) { return null; } const chunk = value; switch (chunk.type) { case "text-delta": if (typeof chunk.payload?.text === "string") { return chunk.payload.text; } if (typeof chunk.payload?.delta === "string") { return chunk.payload.delta; } if (typeof chunk.textDelta === "string") { return chunk.textDelta; } if (typeof chunk.delta === "string") { return chunk.delta; } if (typeof chunk.text === "string") { return chunk.text; } return null; default: return null; } } function extractFinalStructuredObject(value) { if (typeof value !== "object" || value === null || !("type" in value)) { return void 0; } const chunk = value; if (chunk.type !== "object-result") { return void 0; } const objectValue = chunk.payload?.object ?? chunk.object; return objectValue && typeof objectValue === "object" ? objectValue : void 0; } function isTerminalTaskState(state) { return ["completed", "failed", "canceled"].includes(state); } function artifactIdentity(artifact) { return artifact.artifactId || artifact.name; } function areArtifactPartsEqual(left, right) { if (left === right) { return true; } if (left.length !== right.length) { return false; } return left.every((part, index) => { const other = right[index]; if (!other || part.kind !== other.kind) { return false; } if (part.kind === "text" && other.kind === "text") { return part.text === other.text; } return part === other; }); } function areArtifactsEqual(left, right) { if (left === right) { return true; } if (!left || !right) { return left === right; } return left.artifactId === right.artifactId && left.name === right.name && left.description === right.description && left.metadata === right.metadata && areArtifactPartsEqual(left.parts, right.parts); } function areStatusMessagePartsEqual(left, right) { return left === right || util.isDeepStrictEqual(left, right); } function areStatusMessagesEqual(left, right) { if (left === right) { return true; } if (!left || !right) { return left === right; } return left.messageId === right.messageId && left.kind === right.kind && left.role === right.role && left.contextId === right.contextId && left.taskId === right.taskId && util.isDeepStrictEqual(left.referenceTaskIds, right.referenceTaskIds) && util.isDeepStrictEqual(left.extensions, right.extensions) && util.isDeepStrictEqual(left.metadata, right.metadata) && areStatusMessagePartsEqual(left.parts, right.parts); } function didTaskStatusChange(previous, next) { return previous.status.state !== next.status.state || previous.status.timestamp !== next.status.timestamp || !areStatusMessagesEqual(previous.status.message, next.status.message); } function getTaskArtifactUpdates({ previous, next }) { const previousArtifacts = new Map((previous.artifacts ?? []).map((artifact) => [artifactIdentity(artifact), artifact])); const changedArtifacts = (next.artifacts ?? []).filter((artifact) => { const priorArtifact = previousArtifacts.get(artifactIdentity(artifact)); return !priorArtifact || !areArtifactsEqual(priorArtifact, artifact); }); return changedArtifacts.map((artifact, index) => ({ kind: "artifact-update", taskId: next.id, contextId: next.contextId, lastChunk: isTerminalTaskState(next.status.state) && index === changedArtifacts.length - 1, artifact: structuredClone(artifact) })); } async function handleMessageSend({ requestId, params, taskStore, pushNotificationStore, pushNotificationSender, agent, agentId, logger, requestContext }) { validateMessageSendParams(params); const { message, metadata } = params; const { contextId } = message; const taskId = message.taskId || crypto.randomUUID(); const { pushNotificationStore: resolvedPushNotificationStore, pushNotificationSender: resolvedPushNotificationSender } = resolvePushNotificationPair({ pushNotificationStore, pushNotificationSender }); let currentData = await loadOrCreateTask({ taskId, taskStore, agentId, message, contextId, metadata }); if (params.configuration?.pushNotificationConfig) { resolvedPushNotificationStore.set({ agentId, config: createTaskPushNotificationConfig(taskId, params.configuration.pushNotificationConfig) }); } const context = createTaskContext({ task: currentData, userMessage: message, history: currentData.history || [], activeCancellations: taskStore.activeCancellations }); try { const resourceId = metadata?.resourceId ?? message.metadata?.resourceId ?? agentId; const result = await agent.generate([convertToCoreMessage(message)], { runId: taskId, requestContext, ...contextId ? { threadId: contextId, resourceId } : {} }); const artifactUpdate = createArtifactUpdate({ taskId: currentData.id, contextId: currentData.contextId, text: result.text, data: result.object }); if (artifactUpdate) { currentData = applyUpdateToTask(currentData, artifactUpdate); } currentData = applyUpdateToTask(currentData, { state: "completed", message: void 0 }); currentData.metadata = { ...currentData.metadata, execution: { toolCalls: result.toolCalls, toolResults: result.toolResults, usage: result.usage, finishReason: result.finishReason } }; await saveTaskAndMaybeSendPushNotification({ taskStore, pushNotificationSender: resolvedPushNotificationSender, previousTask: context.task, nextTask: currentData, agentId, logger }); context.task = currentData; } catch (handlerError) { const failureStatusUpdate = { state: "failed", message: { messageId: crypto.randomUUID(), role: "agent", parts: [ { kind: "text", text: `Handler failed: ${handlerError instanceof Error ? handlerError.message : String(handlerError)}` } ], kind: "message" } }; currentData = applyUpdateToTask(currentData, failureStatusUpdate); try { await saveTaskAndMaybeSendPushNotification({ taskStore, pushNotificationSender: resolvedPushNotificationSender, previousTask: context.task, nextTask: currentData, agentId, logger }); } catch (saveError) { logger?.error(`Failed to save task ${currentData.id} after handler error:`, saveError?.message); } return normalizeError(handlerError, requestId, currentData.id, logger); } return createSuccessResponse(requestId, currentData); } async function handleTaskGet({ requestId, taskStore, agentId, taskId }) { const task = await taskStore.load({ agentId, taskId }); if (!task) { throw a2a.MastraA2AError.taskNotFound(taskId); } return createSuccessResponse(requestId, task); } async function loadTaskOrThrow({ taskStore, agentId, taskId }) { const task = await taskStore.load({ agentId, taskId }); if (!task) { throw a2a.MastraA2AError.taskNotFound(taskId); } return task; } async function handleSetTaskPushNotificationConfig({ requestId, taskStore, pushNotificationStore, agentId, params }) { await loadTaskOrThrow({ taskStore, agentId, taskId: params.taskId }); const { pushNotificationStore: resolvedPushNotificationStore } = resolvePushNotificationPair({ pushNotificationStore }); const config = resolvedPushNotificationStore.set({ agentId, config: createTaskPushNotificationConfig(params.taskId, params.pushNotificationConfig) }); return createSuccessResponse(requestId, config); } async function handleGetTaskPushNotificationConfig({ requestId, taskStore, pushNotificationStore, agentId, params }) { await loadTaskOrThrow({ taskStore, agentId, taskId: params.id }); const { pushNotificationStore: resolvedPushNotificationStore } = resolvePushNotificationPair({ pushNotificationStore }); const config = resolvedPushNotificationStore.get({ agentId, params }); if (!config) { throw a2a.MastraA2AError.invalidParams( `Push notification config not found: ${params.pushNotificationConfigId ?? params.id}` ); } return createSuccessResponse(requestId, config); } async function handleListTaskPushNotificationConfig({ requestId, taskStore, pushNotificationStore, agentId, params }) { await loadTaskOrThrow({ taskStore, agentId, taskId: params.id }); const { pushNotificationStore: resolvedPushNotificationStore } = resolvePushNotificationPair({ pushNotificationStore }); const configs = resolvedPushNotificationStore.list({ agentId, params }); return createSuccessResponse(requestId, configs); } async function handleDeleteTaskPushNotificationConfig({ requestId, taskStore, pushNotificationStore, agentId, params }) { await loadTaskOrThrow({ taskStore, agentId, taskId: params.id }); const { pushNotificationStore: resolvedPushNotificationStore } = resolvePushNotificationPair({ pushNotificationStore }); const deleted = resolvedPushNotificationStore.delete({ agentId, params }); if (!deleted) { throw a2a.MastraA2AError.invalidParams(`Push notification config not found: ${params.pushNotificationConfigId}`); } return createSuccessResponse(requestId, null); } async function* handleMessageStream({ requestId, params, taskStore, pushNotificationStore, pushNotificationSender, agent, agentId, logger, requestContext }) { validateMessageSendParams(params); const { message, metadata } = params; const { contextId } = message; const taskId = message.taskId || crypto.randomUUID(); const { pushNotificationStore: resolvedPushNotificationStore, pushNotificationSender: resolvedPushNotificationSender } = resolvePushNotificationPair({ pushNotificationStore, pushNotificationSender }); let currentData = await loadOrCreateTask({ taskId, taskStore, agentId, message, contextId, metadata }); if (params.configuration?.pushNotificationConfig) { resolvedPushNotificationStore.set({ agentId, config: createTaskPushNotificationConfig(taskId, params.configuration.pushNotificationConfig) }); } currentData = applyUpdateToTask(currentData, { state: "working", message: { messageId: crypto.randomUUID(), kind: "message", role: "agent", parts: [{ kind: "text", text: "Generating response..." }] } }); await saveTaskAndMaybeSendPushNotification({ taskStore, pushNotificationSender: resolvedPushNotificationSender, nextTask: currentData, agentId, logger }); yield createSuccessResponse(requestId, currentData); try { const resourceId = metadata?.resourceId ?? message.metadata?.resourceId ?? agentId; const result = await agent.stream([convertToCoreMessage(message)], { runId: taskId, requestContext, ...contextId ? { threadId: contextId, resourceId } : {} }); let sawTextArtifact = false; let pendingTextChunk; let structuredData; for await (const chunk of result.fullStream) { const textDelta = extractFullStreamTextDelta(chunk); if (textDelta !== null) { if (!pendingTextChunk) { pendingTextChunk = textDelta; continue; } const textUpdate = createTextChunkArtifactUpdate({ taskId: currentData.id, contextId: currentData.contextId, text: pendingTextChunk, append: sawTextArtifact, lastChunk: false }); currentData = applyUpdateToTask(currentData, textUpdate); await saveTaskAndMaybeSendPushNotification({ taskStore, pushNotificationSender: resolvedPushNotificationSender, nextTask: currentData, agentId, logger }); yield createSuccessResponse(requestId, textUpdate); sawTextArtifact = true; pendingTextChunk = textDelta; continue; } const finalStructuredObject = extractFinalStructuredObject(chunk); if (finalStructuredObject) { structuredData = finalStructuredObject; } } structuredData ??= await result.object; if (!pendingTextChunk && !sawTextArtifact) { const finalText = await result.text; if (finalText) { pendingTextChunk = finalText; } } if (pendingTextChunk) { const textUpdate = createTextChunkArtifactUpdate({ taskId: currentData.id, contextId: currentData.contextId, text: pendingTextChunk, append: sawTextArtifact, lastChunk: !structuredData }); currentData = applyUpdateToTask(currentData, textUpdate); await saveTaskAndMaybeSendPushNotification({ taskStore, pushNotificationSender: resolvedPushNotificationSender, nextTask: currentData, agentId, logger }); yield createSuccessResponse(requestId, textUpdate); sawTextArtifact = true; pendingTextChunk = void 0; } if (structuredData) { const dataUpdate = createDataArtifactUpdate({ taskId: currentData.id, contextId: currentData.contextId, data: structuredData, lastChunk: true }); currentData = applyUpdateToTask(currentData, dataUpdate); await saveTaskAndMaybeSendPushNotification({ taskStore, pushNotificationSender: resolvedPushNotificationSender, nextTask: currentData, agentId, logger }); yield createSuccessResponse(requestId, dataUpdate); } const previousTask = currentData; const completedTask = applyUpdateToTask(currentData, { state: "completed", message: void 0 }); completedTask.metadata = { ...completedTask.metadata, execution: { toolCalls: await result.toolCalls, toolResults: await result.toolResults, usage: await result.usage, finishReason: await result.finishReason } }; currentData = completedTask; await saveTaskAndMaybeSendPushNotification({ taskStore, pushNotificationSender: resolvedPushNotificationSender, previousTask, nextTask: currentData, agentId, logger }); } catch (handlerError) { const previousTask = currentData; currentData = applyUpdateToTask(currentData, { state: "failed", message: { messageId: crypto.randomUUID(), role: "agent", parts: [ { kind: "text", text: `Handler failed: ${handlerError instanceof Error ? handlerError.message : String(handlerError)}` } ], kind: "message" } }); try { await saveTaskAndMaybeSendPushNotification({ taskStore, pushNotificationSender: resolvedPushNotificationSender, previousTask, nextTask: currentData, agentId, logger }); } catch (saveError) { logger?.error(`Failed to save task ${currentData.id} after handler error:`, saveError?.message); } } yield createSuccessResponse(requestId, { kind: "status-update", taskId: currentData.id, contextId: currentData.contextId, status: currentData.status, final: true }); } async function* handleTaskResubscribe({ requestId, taskStore, agentId, taskId, abortSignal }) { let snapshot = taskStore.loadWithVersion({ agentId, taskId }); if (!snapshot) { throw a2a.MastraA2AError.taskNotFound(taskId); } yield createSuccessResponse(requestId, snapshot.task); if (isTerminalTaskState(snapshot.task.status.state)) { return; } while (true) { const { task, version } = snapshot; const nextUpdate = await taskStore.waitForNextUpdate({ agentId, taskId, afterVersion: version, signal: abortSignal }); for (const artifactUpdate of getTaskArtifactUpdates({ previous: task, next: nextUpdate.task })) { yield createSuccessResponse(requestId, artifactUpdate); } if (didTaskStatusChange(task, nextUpdate.task)) { yield createSuccessResponse(requestId, { kind: "status-update", taskId: nextUpdate.task.id, contextId: nextUpdate.task.contextId, status: nextUpdate.task.status, final: isTerminalTaskState(nextUpdate.task.status.state) }); } if (isTerminalTaskState(nextUpdate.task.status.state)) { return; } snapshot = nextUpdate; } } function getTaskIdFromParams(params) { if (!params || typeof params !== "object") { return void 0; } if ("id" in params && typeof params.id === "string") { return params.id; } if ("taskId" in params && typeof params.taskId === "string") { return params.taskId; } if ("message" in params && params.message && typeof params.message === "object" && "taskId" in params.message) { return typeof params.message.taskId === "string" ? params.message.taskId : void 0; } return void 0; } function isAsyncIterable(value) { return !!value && typeof value === "object" && Symbol.asyncIterator in value; } function createA2AJsonResponse(payload) { return Response.json(payload); } function createA2ASSEResponse(payload) { const encoder = new TextEncoder(); const iterable = isAsyncIterable(payload) ? payload : (async function* () { yield payload; })(); const stream = new ReadableStream({ async start(controller) { try { for await (const chunk of iterable) { controller.enqueue(encoder.encode(`data: ${JSON.stringify(chunk)} `)); } } catch (error) { controller.error(error); return; } controller.close(); } }); return new Response(stream, { headers: { "Content-Type": "text/event-stream; charset=utf-8", "Cache-Control": "no-cache", Connection: "keep-alive", "X-Accel-Buffering": "no" } }); } async function handleTaskCancel({ requestId, taskStore, pushNotificationSender, agentId, taskId, logger }) { let data = await taskStore.load({ agentId, taskId }); if (!data) { throw a2a.MastraA2AError.taskNotFound(taskId); } const finalStates = ["completed", "failed", "canceled"]; if (finalStates.includes(data.status.state)) { logger?.info(`Task ${taskId} already in final state ${data.status.state}, cannot cancel.`); return createSuccessResponse(requestId, data); } taskStore.activeCancellations.add(taskId); const cancelUpdate = { state: "canceled", message: { role: "agent", parts: [{ kind: "text", text: "Task cancelled by request." }], kind: "message", messageId: crypto.randomUUID() } }; const previousTask = data; data = applyUpdateToTask(data, cancelUpdate); await saveTaskAndMaybeSendPushNotification({ taskStore, pushNotificationSender: resolvePushNotificationPair({ pushNotificationSender }).pushNotificationSender, previousTask, nextTask: data, agentId, logger }); taskStore.activeCancellations.delete(taskId); return createSuccessResponse(requestId, data); } async function getAgentExecutionHandler({ requestId, mastra, agentId, requestContext, method, params, taskStore, pushNotificationStore, pushNotificationSender, logger, abortSignal }) { const agent = await chunkDZD7RZYY_cjs.getAgentFromSystem({ mastra, agentId }); const { pushNotificationStore: resolvedPushNotificationStore, pushNotificationSender: resolvedPushNotificationSender } = resolvePushNotificationPair({ pushNotificationStore, pushNotificationSender }); let taskId; try { taskId = getTaskIdFromParams(params); switch (method) { case "message/send": { const result = await handleMessageSend({ requestId, params, taskStore, pushNotificationStore: resolvedPushNotificationStore, pushNotificationSender: resolvedPushNotificationSender, agent, agentId, logger, requestContext }); return result; } case "message/stream": { const result = await handleMessageStream({ requestId, taskStore, params, pushNotificationStore: resolvedPushNotificationStore, pushNotificationSender: resolvedPushNotificationSender, agent, agentId, logger, requestContext }); return result; } case "tasks/get": { const result = await handleTaskGet({ requestId, taskStore, agentId, taskId: taskId || "No task ID provided" }); return result; } case "tasks/cancel": { const result = await handleTaskCancel({ requestId, taskStore, pushNotificationSender: resolvedPushNotificationSender, agentId, taskId: taskId || "No task ID provided", logger }); return result; } case "tasks/resubscribe": return await handleTaskResubscribe({ requestId, taskStore, agentId, taskId: taskId || "No task ID provided", abortSignal }); case "tasks/pushNotificationConfig/set": return await handleSetTaskPushNotificationConfig({ requestId, taskStore, pushNotificationStore: resolvedPushNotificationStore, agentId, params }); case "tasks/pushNotificationConfig/get": return await handleGetTaskPushNotificationConfig({ requestId, taskStore, pushNotificationStore: resolvedPushNotificationStore, agentId, params }); case "tasks/pushNotificationConfig/list": return await handleListTaskPushNotificationConfig({ requestId, taskStore, pushNotificationStore: resolvedPushNotificationStore, agentId, params }); case "tasks/pushNotificationConfig/delete": return await handleDeleteTaskPushNotificationConfig({ requestId, taskStore, pushNotificationStore: resolvedPushNotificationStore, agentId, params }); case "agent/getAuthenticatedExtendedCard": throw a2a.MastraA2AError.extendedAgentCardNotConfigured(); default: throw a2a.MastraA2AError.methodNotFound(method); } } catch (error) { if (error instanceof a2a.MastraA2AError && taskId && !error.taskId) { error.taskId = taskId; } return normalizeError(error, requestId, taskId, logger); } } var GET_AGENT_CARD_ROUTE = chunkG54X6VE6_cjs.createRoute({ method: "GET", path: "/.well-known/:agentId/agent-card.json", responseType: "json", pathParamSchema: chunkCXAJPAJ2_cjs.a2aAgentIdPathParams, responseSchema: chunkCXAJPAJ2_cjs.agentCardResponseSchema, summary: "Get agent card", description: "Returns the agent card information for A2A protocol discovery", tags: ["Agent-to-Agent"], requiresAuth: true, handler: async (ctx) => { const executionUrl = getA2AExecutionUrl({ agentId: ctx.agentId, request: ctx.request, routePrefix: ctx.routePrefix }); return getAgentCardByIdHandler({ mastra: ctx.mastra, requestContext: ctx.requestContext, agentId: ctx.agentId, executionUrl, pushNotifications: true }); } }); var AGENT_EXECUTION_ROUTE = chunkG54X6VE6_cjs.createRoute({ method: "POST", path: "/a2a/:agentId", responseType: "datastream-response", pathParamSchema: chunkCXAJPAJ2_cjs.a2aAgentIdPathParams, bodySchema: chunkCXAJPAJ2_cjs.agentExecutionBodySchema, responseSchema: chunkCXAJPAJ2_cjs.agentExecutionResponseSchema, summary: "Execute agent", description: "Executes an agent action via JSON-RPC 2.0 over A2A protocol", tags: ["Agent-to-Agent"], requiresAuth: true, handler: async ({ mastra, agentId, requestContext, taskStore, abortSignal, ...bodyParams }) => { const { id: requestId, method } = bodyParams; const params = "params" in bodyParams ? bodyParams.params : void 0; const result = await getAgentExecutionHandler({ requestId, mastra, agentId, requestContext, method, params, taskStore, abortSignal }); if (method === "message/stream" || method === "tasks/resubscribe") { return createA2ASSEResponse(result); } return createA2AJsonResponse(result); } }); exports.AGENT_EXECUTION_ROUTE = AGENT_EXECUTION_ROUTE; exports.GET_AGENT_CARD_ROUTE = GET_AGENT_CARD_ROUTE; exports.a2a_exports = a2a_exports; exports.getAgentCardByIdHandler = getAgentCardByIdHandler; exports.getAgentExecutionHandler = getAgentExecutionHandler; exports.handleDeleteTaskPushNotificationConfig = handleDeleteTaskPushNotificationConfig; exports.handleGetTaskPushNotificationConfig = handleGetTaskPushNotificationConfig; exports.handleListTaskPushNotificationConfig = handleListTaskPushNotificationConfig; exports.handleMessageSend = handleMessageSend; exports.handleMessageStream = handleMessageStream; exports.handleSetTaskPushNotificationConfig = handleSetTaskPushNotificationConfig; exports.handleTaskCancel = handleTaskCancel; exports.handleTaskGet = handleTaskGet; exports.handleTaskResubscribe = handleTaskResubscribe; //# sourceMappingURL=chunk-HL75U57J.cjs.map //# sourceMappingURL=chunk-HL75U57J.cjs.map