UNPKG

@mastra/core

Version:
1 lines • 66.3 kB
{"version":3,"file":"index.cjs","names":["convertMessages","MessageList","MastraA2AError","#url","#description","#headers","#fetch","#retries","#backoffMs","#maxBackoffMs","#credentials","#abortSignal","#timeoutMs","#verifyAgentCard","#runState","#getBootstrap","#memory","RequestContext","#mastra","#sendAndResolve","#getTask","#resolveTaskToGenerateResult","#createBufferedStreamResult","#runRemoteStream","#resubscribeToRemoteStream","#cachedBootstrap","#resolveCardUrl","#request","#sendMessage","#evaluateTask","#delay","#consumeA2AStream","#collectStreamEvents","#streamEvents","#resolveRequestSignal"],"sources":["../../src/a2a/a2a-agent.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\nimport type { AgentCard, Message, Task, TaskArtifactUpdateEvent, TaskStatusUpdateEvent } from '@a2a-js/sdk';\nimport type { AgentExecutionOptionsBase } from '../agent/agent.types';\nimport { MessageList } from '../agent/message-list';\nimport type { MastraDBMessage, MessageListInput } from '../agent/message-list';\nimport { convertMessages } from '../agent/message-list/utils/convert-messages';\nimport type { SubAgent } from '../agent/subagent';\nimport type { Mastra } from '../mastra';\nimport type { MastraMemory } from '../memory/memory';\nimport { RequestContext } from '../request-context';\nimport type { ChunkType } from '../stream/types';\nimport type { DynamicArgument } from '../types';\nimport { MastraA2AError } from './error';\nimport type {\n A2AAgentCardVerificationContext,\n A2AAgentGenerateResult,\n A2AAgentOptions,\n A2AAgentResumePayload,\n A2AAgentRunState,\n A2AAgentStreamResult,\n JSONRPCResponse,\n RequestCredentialsMode,\n} from './types';\n\ntype FetchLike = typeof fetch;\n\ntype JSONRPCRequestBody = {\n jsonrpc: '2.0';\n id: string;\n method: string;\n params?: Record<string, unknown>;\n};\n\ntype RequestOptions = {\n method?: string;\n headers?: Record<string, string>;\n body?: unknown;\n stream?: boolean;\n credentials?: RequestCredentialsMode;\n signal?: AbortSignal;\n};\n\ntype AgentBootstrap = {\n card: AgentCard;\n cardUrl: string;\n executionUrl: string;\n streamingSupported: boolean;\n};\n\ntype TerminalEvaluation =\n | {\n kind: 'completed';\n text: string;\n task?: Task;\n message?: Message;\n }\n | {\n kind: 'suspended';\n text: string;\n task: Task;\n resumePayload: A2AAgentResumePayload;\n resumeSchema?: string;\n };\n\ntype StreamConsumptionResult = {\n text: string;\n task?: Task;\n suspended?: {\n payload: A2AAgentResumePayload;\n resumeSchema?: string;\n };\n};\n\ntype A2AStreamEventData = Message | Task | TaskStatusUpdateEvent | TaskArtifactUpdateEvent;\ntype A2AAgentFullStreamChunkBase =\n | { type: 'start'; payload: { id: string } }\n | { type: 'text-start'; payload: { id: string } }\n | { type: 'text-delta'; payload: { id: string; text: string } }\n | { type: 'text-end'; payload: { id: string } }\n | {\n type: 'tool-call-suspended';\n payload: {\n toolCallId: string;\n toolName: string;\n args: Record<string, never>;\n suspendPayload: A2AAgentResumePayload;\n resumeSchema: string;\n };\n }\n | {\n type: 'finish';\n payload: A2AAgentFinishPayload;\n };\n\ntype AgentFinishPayload = Extract<ChunkType, { type: 'finish' }>['payload'];\n\ntype A2AAgentFinishPayload = AgentFinishPayload & {\n /** @deprecated Use `stepResult.reason`. Kept for consumers of the previous flat payload shape. */\n finishReason: 'stop';\n /** @deprecated Use `output.usage`. Kept for consumers of the previous flat payload shape. */\n usage: typeof EMPTY_USAGE;\n};\ntype A2AAgentFullStreamChunk = A2AAgentFullStreamChunkBase & {\n runId: string;\n from: 'AGENT';\n};\n\ntype Deferred<T> = {\n promise: Promise<T>;\n resolve: (value: T | PromiseLike<T>) => void;\n reject: (reason?: unknown) => void;\n};\n\nconst EMPTY_USAGE = {\n inputTokens: undefined,\n outputTokens: undefined,\n totalTokens: undefined,\n};\n\nfunction toAgentStreamChunk(runId: string, chunk: A2AAgentFullStreamChunkBase): A2AAgentFullStreamChunk {\n return {\n ...chunk,\n runId,\n from: 'AGENT',\n };\n}\n\nfunction createFinishPayload(): A2AAgentFinishPayload {\n return {\n stepResult: {\n reason: 'stop',\n },\n output: {\n usage: EMPTY_USAGE,\n },\n metadata: {},\n messages: {\n all: [],\n user: [],\n nonUser: [],\n },\n finishReason: 'stop',\n usage: EMPTY_USAGE,\n };\n}\n\nfunction isTask(result: Message | Task | TaskStatusUpdateEvent | TaskArtifactUpdateEvent): result is Task {\n return typeof result === 'object' && result !== null && 'status' in result && 'id' in result && 'kind' in result;\n}\n\nfunction isMessage(result: Message | Task | TaskStatusUpdateEvent | TaskArtifactUpdateEvent): result is Message {\n return typeof result === 'object' && result !== null && 'messageId' in result && 'parts' in result;\n}\n\nfunction isTerminalTaskState(state: Task['status']['state'] | undefined) {\n return state === 'completed' || state === 'failed' || state === 'canceled' || state === 'rejected';\n}\n\nfunction splitNextEvent(buffer: string): { eventBlock?: string; rest: string } {\n const normalizedBuffer = buffer.replace(/\\x1E/g, '\\n\\n');\n const match = normalizedBuffer.match(/\\r?\\n\\r?\\n/);\n\n if (!match || match.index === undefined) {\n return { rest: normalizedBuffer };\n }\n\n return {\n eventBlock: normalizedBuffer.slice(0, match.index),\n rest: normalizedBuffer.slice(match.index + match[0].length),\n };\n}\n\nfunction parseEventBlock(eventBlock: string): { done: true } | { event?: A2AStreamEventData } {\n const trimmedBlock = eventBlock.trim();\n\n if (!trimmedBlock) {\n return {};\n }\n\n const lines = trimmedBlock.split(/\\r?\\n/);\n const dataLines = lines.filter(line => line.startsWith('data:')).map(line => line.slice(5).trimStart());\n const payload = dataLines.length > 0 ? dataLines.join('\\n') : trimmedBlock;\n\n if (payload === '[DONE]') {\n return { done: true };\n }\n\n let parsed: JSONRPCResponse<A2AStreamEventData> | A2AStreamEventData;\n\n try {\n parsed = JSON.parse(payload) as JSONRPCResponse<A2AStreamEventData> | A2AStreamEventData;\n } catch {\n return {};\n }\n\n if ('result' in parsed && parsed.result) {\n return { event: parsed.result };\n }\n\n return { event: parsed as A2AStreamEventData };\n}\n\nfunction extractTextParts(parts: { kind: string; text?: string }[] | undefined): string {\n return (parts ?? [])\n .filter((part): part is { kind: string; text: string } => part.kind === 'text' && typeof part.text === 'string')\n .map(part => part.text)\n .join('\\n');\n}\n\nfunction extractTaskText(task: Task): string {\n const artifactText = (task.artifacts ?? [])\n .flatMap(\n artifact =>\n artifact.parts?.flatMap(part => {\n if (part.kind === 'text' && 'text' in part && typeof part.text === 'string') {\n return [part.text];\n }\n\n return [];\n }) ?? [],\n )\n .join('\\n');\n const statusText = task.status.message ? extractMessageText(task.status.message) : '';\n return [artifactText, statusText].filter(Boolean).join('\\n').trim();\n}\n\nfunction extractTaskArtifactText(task: Task): string {\n return (task.artifacts ?? [])\n .flatMap(\n artifact =>\n artifact.parts?.flatMap(part => {\n if (part.kind === 'text' && 'text' in part && typeof part.text === 'string') {\n return [part.text];\n }\n\n return [];\n }) ?? [],\n )\n .join('');\n}\n\nfunction extractMessageText(message: Message): string {\n return extractTextParts(message.parts as { kind: string; text?: string }[] | undefined).trim();\n}\n\nfunction messagesToPrompt<OUTPUT>(messages: MessageListInput, options?: AgentExecutionOptionsBase<OUTPUT>): string {\n if (typeof messages === 'string') {\n return messages;\n }\n\n const converted = convertMessages(messages).to('AIV5.Model');\n const lines: string[] = [];\n\n if (options?.instructions) {\n lines.push(`Instructions:\\n${options.instructions}`);\n }\n\n const contextMessages = options?.context as Array<{ role?: string; content?: unknown }> | undefined;\n if (contextMessages?.length) {\n lines.push(\n 'Context:\\n' +\n contextMessages\n .map(message => {\n const role = message.role ?? 'unknown';\n const content = typeof message.content === 'string' ? message.content : JSON.stringify(message.content);\n return `${role}: ${content}`;\n })\n .join('\\n'),\n );\n }\n\n for (const message of converted) {\n if (message.role === 'system') {\n const content = Array.isArray(message.content)\n ? message.content\n .map((part: { type: string; text?: string }) => {\n if ('type' in part && part.type === 'text') {\n return part.text;\n }\n\n return '';\n })\n .filter(Boolean)\n .join('\\n')\n : typeof message.content === 'string'\n ? message.content\n : '';\n\n if (content) {\n lines.push(`system: ${content}`);\n }\n continue;\n }\n\n const content = Array.isArray(message.content)\n ? message.content\n .map((part: { type: string; text?: string; filename?: string }) => {\n if ('type' in part && part.type === 'text') {\n return part.text;\n }\n\n if ('type' in part && part.type === 'file') {\n return `[file:${part.filename ?? 'attachment'}]`;\n }\n\n return '';\n })\n .filter(Boolean)\n .join('\\n')\n : typeof message.content === 'string'\n ? message.content\n : '';\n\n lines.push(`${message.role}: ${content}`);\n }\n\n return lines.join('\\n\\n').trim();\n}\n\nfunction resumeDataToPrompt(resumeData: unknown): string {\n if (typeof resumeData === 'string') {\n return resumeData;\n }\n\n if (resumeData == null) {\n return '';\n }\n\n return JSON.stringify(resumeData, null, 2);\n}\n\nfunction createResumeSchema(): string {\n return JSON.stringify({\n type: 'object',\n additionalProperties: true,\n description: 'Data to continue the remote A2A task.',\n });\n}\n\nfunction resolveStreamTextId(candidateIds: Array<string | undefined>): string {\n for (const candidate of candidateIds) {\n if (candidate) {\n return candidate;\n }\n }\n\n return 'text-1';\n}\n\nfunction resolveMemoryInfo<OUTPUT>(options?: AgentExecutionOptionsBase<OUTPUT>) {\n const threadId = typeof options?.memory?.thread === 'string' ? options.memory.thread : options?.memory?.thread?.id;\n\n return {\n threadId,\n resourceId: options?.memory?.resource,\n };\n}\n\nfunction createResponseMessages(\n text: string,\n memoryInfo: { threadId?: string; resourceId?: string } = {},\n): MastraDBMessage[] {\n if (!text) {\n return [];\n }\n\n return new MessageList(memoryInfo)\n .add(\n {\n role: 'assistant',\n content: text,\n },\n 'response',\n )\n .get.response.db();\n}\n\nfunction createGenerateResult({\n runId,\n text,\n task,\n message,\n resumePayload,\n resumeSchema,\n threadId,\n resourceId,\n}: {\n runId: string;\n text: string;\n task?: Task;\n message?: Message;\n resumePayload?: A2AAgentResumePayload;\n resumeSchema?: string;\n threadId?: string;\n resourceId?: string;\n}): A2AAgentGenerateResult {\n const responseMessages = createResponseMessages(text, { threadId, resourceId });\n\n return {\n text,\n usage: EMPTY_USAGE,\n steps: [],\n finishReason: resumePayload ? 'suspended' : 'stop',\n warnings: [],\n providerMetadata: undefined,\n request: {},\n reasoning: [],\n reasoningText: undefined,\n toolCalls: [],\n toolResults: [],\n sources: [],\n files: [],\n response: {\n id: message?.messageId ?? task?.id ?? runId,\n timestamp: new Date(),\n modelId: 'a2a/remote-agent',\n messages: [],\n uiMessages: [],\n dbMessages: responseMessages,\n },\n totalUsage: EMPTY_USAGE,\n object: undefined,\n error: undefined,\n tripwire: undefined,\n traceId: undefined,\n spanId: undefined,\n runId,\n suspendPayload: resumePayload,\n resumeSchema,\n messages: responseMessages,\n rememberedMessages: [],\n task,\n message,\n resumePayload,\n };\n}\n\nfunction unwrapA2AResult(result: unknown): Message | Task {\n if (!result || typeof result !== 'object') {\n throw MastraA2AError.invalidAgentResponse('Remote A2A agent returned an invalid response.');\n }\n\n if ('result' in result && result.result && typeof result.result === 'object') {\n return result.result as Message | Task;\n }\n\n return result as Message | Task;\n}\n\nfunction createDeferred<T>(): Deferred<T> {\n let resolve!: Deferred<T>['resolve'];\n let reject!: Deferred<T>['reject'];\n\n const promise = new Promise<T>((res, rej) => {\n resolve = res;\n reject = rej;\n });\n\n return { promise, resolve, reject };\n}\n\nasync function requireResponseBody(response: Response, operation: string) {\n if (!response.body) {\n throw MastraA2AError.invalidAgentResponse(`Remote A2A agent returned an empty stream for ${operation}.`);\n }\n\n return response.body;\n}\n\nexport class A2AAgent implements SubAgent {\n readonly id: string;\n readonly name: string;\n\n readonly #url: string;\n readonly #description: string;\n readonly #headers: Record<string, string>;\n readonly #fetch: FetchLike;\n readonly #retries: number;\n readonly #backoffMs: number;\n readonly #maxBackoffMs: number;\n readonly #credentials?: RequestCredentialsMode;\n readonly #abortSignal?: AbortSignal;\n readonly #timeoutMs?: number;\n readonly #verifyAgentCard?: A2AAgentOptions['verifyAgentCard'];\n\n #cachedBootstrap?: AgentBootstrap;\n readonly #runState = new Map<string, A2AAgentRunState>();\n #memory?: DynamicArgument<MastraMemory>;\n #mastra?: Mastra;\n\n constructor(options: A2AAgentOptions) {\n this.#url = options.url.replace(/\\/$/, '');\n this.#description = options.description ?? `Remote A2A agent at ${this.#url}`;\n this.#headers = options.headers ?? {};\n this.#fetch = options.fetch ?? fetch;\n this.#retries = options.retries ?? 0;\n this.#backoffMs = options.backoffMs ?? 250;\n this.#maxBackoffMs = options.maxBackoffMs ?? 1_000;\n this.#credentials = options.credentials;\n this.#abortSignal = options.abortSignal;\n this.#timeoutMs = options.timeoutMs;\n this.#verifyAgentCard = options.verifyAgentCard;\n this.id = options.id ?? `a2a-${randomUUID()}`;\n this.name = options.name ?? options.description ?? 'A2A Agent';\n }\n\n async getAgentCard({ forceRefresh = false }: { forceRefresh?: boolean } = {}): Promise<AgentCard> {\n return (await this.#getBootstrap({ forceRefresh })).card;\n }\n\n getDescription(): string {\n return this.#description;\n }\n\n getModel: SubAgent['getModel'] = async () =>\n ({ specificationVersion: 'v2' }) as Awaited<ReturnType<SubAgent['getModel']>>;\n\n hasOwnMemory(): boolean {\n return Boolean(this.#memory);\n }\n\n __setMemory(memory: DynamicArgument<MastraMemory>): void {\n this.#memory = memory;\n }\n\n async getMemory({ requestContext = new RequestContext() }: { requestContext?: RequestContext } = {}) {\n if (!this.#memory) {\n return undefined;\n }\n\n if (typeof this.#memory !== 'function') {\n return this.#memory;\n }\n\n return await this.#memory({\n requestContext,\n mastra: this.#mastra,\n });\n }\n\n getInstructions: SubAgent['getInstructions'] = async () => '';\n\n __registerMastra(mastra: Mastra): void {\n this.#mastra = mastra;\n }\n\n async generate(\n messages: MessageListInput,\n options?: AgentExecutionOptionsBase<unknown>,\n ): Promise<A2AAgentGenerateResult> {\n const bootstrap = await this.#getBootstrap();\n const runId = options?.runId ?? randomUUID();\n const prompt = messagesToPrompt(messages, options);\n const memoryInfo = resolveMemoryInfo(options);\n\n return this.#sendAndResolve({\n bootstrap,\n runId,\n prompt,\n signal: options?.abortSignal,\n ...memoryInfo,\n });\n }\n\n async resumeGenerate(\n resumeData: unknown,\n options?: AgentExecutionOptionsBase<unknown>,\n ): Promise<A2AAgentGenerateResult> {\n const runId = options?.runId;\n if (!runId) {\n throw MastraA2AError.invalidParams('A2AAgent.resumeGenerate requires a runId.');\n }\n\n const state = this.#runState.get(runId);\n if (!state) {\n throw MastraA2AError.invalidParams(`No resumable A2A run state found for runId \"${runId}\".`);\n }\n\n const bootstrap = await this.#getBootstrap();\n const memoryInfo = resolveMemoryInfo(options);\n\n if (state.waitingForInput) {\n const prompt = resumeDataToPrompt(resumeData);\n return this.#sendAndResolve({\n bootstrap,\n runId,\n prompt,\n signal: options?.abortSignal,\n contextId: state.contextId,\n referenceTaskIds: state.taskId ? [state.taskId] : undefined,\n ...memoryInfo,\n });\n }\n\n if (!state.taskId) {\n throw MastraA2AError.invalidParams(`A2AAgent resume state for \"${runId}\" is missing a taskId.`);\n }\n\n const task = await this.#getTask({\n bootstrap,\n taskId: state.taskId,\n signal: options?.abortSignal,\n });\n\n return this.#resolveTaskToGenerateResult({\n bootstrap,\n runId,\n task,\n signal: options?.abortSignal,\n ...memoryInfo,\n });\n }\n\n async stream(\n messages: MessageListInput,\n options?: AgentExecutionOptionsBase<unknown>,\n ): Promise<A2AAgentStreamResult> {\n const bootstrap = await this.#getBootstrap();\n const runId = options?.runId ?? randomUUID();\n const prompt = messagesToPrompt(messages, options);\n const memoryInfo = resolveMemoryInfo(options);\n\n if (!bootstrap.streamingSupported) {\n const result = await this.generate(messages, { ...options, runId });\n return this.#createBufferedStreamResult({ runId, result, emitStart: true, ...memoryInfo });\n }\n\n return this.#runRemoteStream({\n bootstrap,\n runId,\n prompt,\n signal: options?.abortSignal,\n emitStart: true,\n ...memoryInfo,\n });\n }\n\n async resumeStream(resumeData: unknown, options?: AgentExecutionOptionsBase<unknown>): Promise<A2AAgentStreamResult> {\n const runId = options?.runId;\n if (!runId) {\n throw MastraA2AError.invalidParams('A2AAgent.resumeStream requires a runId.');\n }\n\n const state = this.#runState.get(runId);\n if (!state) {\n throw MastraA2AError.invalidParams(`No resumable A2A run state found for runId \"${runId}\".`);\n }\n\n const bootstrap = await this.#getBootstrap();\n const memoryInfo = resolveMemoryInfo(options);\n\n if (state.waitingForInput) {\n const prompt = resumeDataToPrompt(resumeData);\n\n if (!bootstrap.streamingSupported) {\n const result = await this.resumeGenerate(resumeData, options);\n return this.#createBufferedStreamResult({ runId, result, emitStart: false, ...memoryInfo });\n }\n\n return this.#runRemoteStream({\n bootstrap,\n runId,\n prompt,\n signal: options?.abortSignal,\n contextId: state.contextId,\n referenceTaskIds: state.taskId ? [state.taskId] : undefined,\n // Resumed runs skip the `start` chunk, mirroring the regular Agent loop.\n emitStart: false,\n ...memoryInfo,\n });\n }\n\n if (!state.taskId) {\n throw MastraA2AError.invalidParams(`A2AAgent resume state for \"${runId}\" is missing a taskId.`);\n }\n\n if (!bootstrap.streamingSupported) {\n const result = await this.resumeGenerate(resumeData, options);\n return this.#createBufferedStreamResult({ runId, result, emitStart: false, ...memoryInfo });\n }\n\n return this.#resubscribeToRemoteStream({\n bootstrap,\n runId,\n taskId: state.taskId,\n initialTask: state.lastTask,\n signal: options?.abortSignal,\n ...memoryInfo,\n });\n }\n\n async #getBootstrap({ forceRefresh = false }: { forceRefresh?: boolean } = {}): Promise<AgentBootstrap> {\n if (!forceRefresh && this.#cachedBootstrap) {\n return this.#cachedBootstrap;\n }\n\n const cardUrl = this.#resolveCardUrl();\n const response = await this.#request(cardUrl, {\n method: 'GET',\n signal: this.#abortSignal,\n });\n\n const card = (await response.json()) as AgentCard;\n const fetchedAt = new Date();\n\n if (this.#verifyAgentCard) {\n const context: A2AAgentCardVerificationContext = { cardUrl, fetchedAt };\n await this.#verifyAgentCard.verify(card, context);\n }\n\n const bootstrap: AgentBootstrap = {\n card,\n cardUrl,\n executionUrl: card.url,\n streamingSupported: card.capabilities?.streaming ?? false,\n };\n\n this.#cachedBootstrap = bootstrap;\n return bootstrap;\n }\n\n #resolveCardUrl() {\n return this.#url.endsWith('/agent-card.json') ? this.#url : `${this.#url}/.well-known/agent-card.json`;\n }\n\n async #sendMessage({\n bootstrap,\n prompt,\n signal,\n contextId,\n referenceTaskIds,\n }: {\n bootstrap: AgentBootstrap;\n prompt: string;\n signal?: AbortSignal;\n contextId?: string;\n referenceTaskIds?: string[];\n }): Promise<Message | Task> {\n const response = await this.#request(bootstrap.executionUrl, {\n method: 'POST',\n signal,\n body: {\n jsonrpc: '2.0',\n id: randomUUID(),\n method: 'message/send',\n params: {\n message: {\n role: 'user',\n kind: 'message',\n messageId: randomUUID(),\n parts: [{ kind: 'text', text: prompt }],\n ...(contextId ? { contextId } : {}),\n ...(referenceTaskIds?.length ? { referenceTaskIds } : {}),\n },\n },\n } satisfies JSONRPCRequestBody,\n });\n\n const json = await response.json();\n return unwrapA2AResult(json);\n }\n\n async #sendAndResolve({\n bootstrap,\n runId,\n prompt,\n signal,\n contextId,\n referenceTaskIds,\n threadId,\n resourceId,\n }: {\n bootstrap: AgentBootstrap;\n runId: string;\n prompt: string;\n signal?: AbortSignal;\n contextId?: string;\n referenceTaskIds?: string[];\n threadId?: string;\n resourceId?: string;\n }): Promise<A2AAgentGenerateResult> {\n const response = await this.#sendMessage({\n bootstrap,\n prompt,\n signal,\n contextId,\n referenceTaskIds,\n });\n\n if (isMessage(response)) {\n this.#runState.delete(runId);\n return createGenerateResult({\n runId,\n text: extractMessageText(response),\n message: response,\n threadId,\n resourceId,\n });\n }\n\n return this.#resolveTaskToGenerateResult({\n bootstrap,\n runId,\n task: response,\n signal,\n threadId,\n resourceId,\n });\n }\n\n async #getTask({\n bootstrap,\n taskId,\n signal,\n }: {\n bootstrap: AgentBootstrap;\n taskId: string;\n signal?: AbortSignal;\n }): Promise<Task> {\n const response = await this.#request(bootstrap.executionUrl, {\n method: 'POST',\n signal,\n body: {\n jsonrpc: '2.0',\n id: randomUUID(),\n method: 'tasks/get',\n params: { id: taskId },\n } satisfies JSONRPCRequestBody,\n });\n\n const json = await response.json();\n const result = unwrapA2AResult(json);\n\n if (!isTask(result)) {\n throw MastraA2AError.invalidAgentResponse('Remote A2A agent returned a non-task response for tasks/get.');\n }\n\n return result;\n }\n\n async #resolveTaskToGenerateResult({\n bootstrap,\n runId,\n task,\n signal,\n threadId,\n resourceId,\n }: {\n bootstrap: AgentBootstrap;\n runId: string;\n task: Task;\n signal?: AbortSignal;\n threadId?: string;\n resourceId?: string;\n }): Promise<A2AAgentGenerateResult> {\n let currentTask = task;\n\n while (true) {\n const evaluation = this.#evaluateTask({\n bootstrap,\n task: currentTask,\n });\n\n if (evaluation.kind === 'completed') {\n this.#runState.delete(runId);\n\n return createGenerateResult({\n runId,\n text: evaluation.text,\n task: evaluation.task,\n message: evaluation.message,\n threadId,\n resourceId,\n });\n }\n\n this.#runState.set(runId, {\n runId,\n contextId: evaluation.task.contextId,\n taskId: evaluation.task.id,\n executionUrl: bootstrap.executionUrl,\n cardUrl: bootstrap.cardUrl,\n streamingSupported: bootstrap.streamingSupported,\n waitingForInput: evaluation.resumePayload.waitingForInput,\n lastTask: evaluation.task,\n });\n\n if (evaluation.task.status.state === 'input-required') {\n return createGenerateResult({\n runId,\n text: evaluation.text,\n task: evaluation.task,\n resumePayload: evaluation.resumePayload,\n resumeSchema: evaluation.resumeSchema,\n threadId,\n resourceId,\n });\n }\n\n await this.#delay();\n\n currentTask = await this.#getTask({\n bootstrap,\n taskId: evaluation.task.id,\n signal,\n });\n }\n }\n\n #evaluateTask({ bootstrap, task }: { bootstrap: AgentBootstrap; task: Task }): TerminalEvaluation {\n const text = extractTaskText(task);\n\n if (task.status.state === 'input-required') {\n return {\n kind: 'suspended',\n text,\n task,\n resumePayload: {\n taskId: task.id,\n contextId: task.contextId,\n executionUrl: bootstrap.executionUrl,\n cardUrl: bootstrap.cardUrl,\n waitingForInput: true,\n task: structuredClone(task),\n },\n resumeSchema: createResumeSchema(),\n };\n }\n\n if (isTerminalTaskState(task.status.state)) {\n return {\n kind: 'completed',\n text,\n task,\n };\n }\n\n return {\n kind: 'suspended',\n text,\n task,\n resumePayload: {\n taskId: task.id,\n contextId: task.contextId,\n executionUrl: bootstrap.executionUrl,\n cardUrl: bootstrap.cardUrl,\n waitingForInput: false,\n task: structuredClone(task),\n },\n };\n }\n\n async #runRemoteStream({\n bootstrap,\n runId,\n prompt,\n signal,\n contextId,\n referenceTaskIds,\n threadId,\n resourceId,\n emitStart,\n }: {\n bootstrap: AgentBootstrap;\n runId: string;\n prompt: string;\n signal?: AbortSignal;\n contextId?: string;\n referenceTaskIds?: string[];\n threadId?: string;\n resourceId?: string;\n emitStart: boolean;\n }): Promise<A2AAgentStreamResult> {\n const response = await this.#request(bootstrap.executionUrl, {\n method: 'POST',\n signal,\n stream: true,\n body: {\n jsonrpc: '2.0',\n id: randomUUID(),\n method: 'message/stream',\n params: {\n message: {\n role: 'user',\n kind: 'message',\n messageId: randomUUID(),\n parts: [{ kind: 'text', text: prompt }],\n ...(contextId ? { contextId } : {}),\n ...(referenceTaskIds?.length ? { referenceTaskIds } : {}),\n },\n },\n } satisfies JSONRPCRequestBody,\n });\n\n return this.#consumeA2AStream({\n bootstrap,\n runId,\n stream: await requireResponseBody(response, 'message/stream'),\n threadId,\n resourceId,\n emitStart,\n });\n }\n\n async #resubscribeToRemoteStream({\n bootstrap,\n runId,\n taskId,\n initialTask,\n signal,\n threadId,\n resourceId,\n }: {\n bootstrap: AgentBootstrap;\n runId: string;\n taskId: string;\n initialTask?: Task;\n signal?: AbortSignal;\n threadId?: string;\n resourceId?: string;\n }): Promise<A2AAgentStreamResult> {\n const response = await this.#request(bootstrap.executionUrl, {\n method: 'POST',\n signal,\n stream: true,\n body: {\n jsonrpc: '2.0',\n id: randomUUID(),\n method: 'tasks/resubscribe',\n params: { id: taskId },\n } satisfies JSONRPCRequestBody,\n });\n\n return this.#consumeA2AStream({\n bootstrap,\n runId,\n initialTask,\n stream: await requireResponseBody(response, 'tasks/resubscribe'),\n threadId,\n resourceId,\n // Resubscribing continues an existing run; `start` is only emitted for fresh runs,\n // mirroring the regular Agent loop which skips `start` when resuming.\n emitStart: false,\n });\n }\n\n async #consumeA2AStream({\n bootstrap,\n runId,\n initialTask,\n stream,\n threadId,\n resourceId,\n emitStart,\n }: {\n bootstrap: AgentBootstrap;\n runId: string;\n initialTask?: Task;\n stream: ReadableStream<Uint8Array>;\n threadId?: string;\n resourceId?: string;\n emitStart: boolean;\n }): Promise<A2AAgentStreamResult> {\n const [consumerStream, accumulatorStream] = stream.tee();\n const resultDeferred = createDeferred<A2AAgentGenerateResult>();\n const textDeferred = createDeferred<string>();\n const taskDeferred = createDeferred<Task | undefined>();\n const suspendPayloadDeferred = createDeferred<A2AAgentResumePayload | undefined>();\n const resumeSchemaDeferred = createDeferred<string | undefined>();\n const messageList = new MessageList({ threadId, resourceId });\n\n void this.#collectStreamEvents({\n bootstrap,\n initialTask,\n stream: accumulatorStream,\n })\n .then(consumed => {\n if (consumed.task && consumed.suspended) {\n this.#runState.set(runId, {\n runId,\n contextId: consumed.task.contextId,\n taskId: consumed.task.id,\n executionUrl: bootstrap.executionUrl,\n cardUrl: bootstrap.cardUrl,\n streamingSupported: bootstrap.streamingSupported,\n waitingForInput: consumed.suspended.payload.waitingForInput,\n lastTask: consumed.task,\n });\n } else {\n this.#runState.delete(runId);\n }\n\n textDeferred.resolve(consumed.text);\n taskDeferred.resolve(consumed.task);\n suspendPayloadDeferred.resolve(consumed.suspended?.payload);\n resumeSchemaDeferred.resolve(consumed.suspended?.resumeSchema);\n if (consumed.text) {\n messageList.add(\n {\n role: 'assistant',\n content: consumed.text,\n },\n 'response',\n );\n }\n resultDeferred.resolve(\n createGenerateResult({\n runId,\n text: consumed.text,\n task: consumed.task,\n threadId,\n resourceId,\n ...(consumed.suspended\n ? {\n resumePayload: consumed.suspended.payload,\n resumeSchema: consumed.suspended.resumeSchema,\n }\n : {}),\n }),\n );\n })\n .catch(error => {\n textDeferred.reject(error);\n taskDeferred.reject(error);\n suspendPayloadDeferred.reject(error);\n resumeSchemaDeferred.reject(error);\n resultDeferred.reject(error);\n });\n\n const streamResult = {\n runId,\n fullStream: this.#streamEvents({ bootstrap, runId, stream: consumerStream, emitStart }),\n text: textDeferred.promise,\n toolResults: Promise.resolve([]),\n messageList,\n task: taskDeferred.promise,\n suspendPayload: suspendPayloadDeferred.promise,\n resumeSchema: resumeSchemaDeferred.promise,\n getResult: async () => resultDeferred.promise,\n };\n\n return streamResult as unknown as A2AAgentStreamResult;\n }\n\n async *#streamEvents({\n bootstrap,\n runId,\n stream,\n emitStart,\n }: {\n bootstrap: AgentBootstrap;\n runId: string;\n stream: ReadableStream<Uint8Array>;\n emitStart: boolean;\n }): AsyncIterable<A2AAgentFullStreamChunk> {\n if (emitStart) {\n yield toAgentStreamChunk(runId, { type: 'start', payload: { id: this.id } });\n }\n\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n let textId: string | undefined;\n let textStarted = false;\n let task: Task | undefined;\n let suspended: A2AAgentResumePayload | undefined;\n let receivedDone = false;\n\n while (true) {\n const { done, value } = await reader.read();\n\n if (done) {\n buffer += decoder.decode();\n } else if (value) {\n buffer += decoder.decode(value, { stream: true });\n }\n\n let next = splitNextEvent(buffer);\n while (next.eventBlock !== undefined) {\n const parsed = parseEventBlock(next.eventBlock);\n if ('done' in parsed && parsed.done) {\n receivedDone = true;\n buffer = next.rest;\n break;\n }\n\n if ('event' in parsed && parsed.event) {\n const event = parsed.event;\n\n if (isTask(event)) {\n task = event;\n if (event.status.state === 'input-required') {\n suspended = {\n taskId: event.id,\n contextId: event.contextId,\n executionUrl: bootstrap.executionUrl,\n cardUrl: bootstrap.cardUrl,\n waitingForInput: true,\n task: structuredClone(event),\n };\n }\n } else if (isMessage(event)) {\n const text = extractMessageText(event);\n if (text) {\n textId ??= resolveStreamTextId([event.messageId, task?.id]);\n if (textId) {\n if (!textStarted) {\n yield toAgentStreamChunk(runId, { type: 'text-start', payload: { id: textId } });\n textStarted = true;\n }\n yield toAgentStreamChunk(runId, { type: 'text-delta', payload: { id: textId, text } });\n }\n }\n } else if (event.kind === 'artifact-update') {\n const text = event.artifact.parts\n ?.flatMap(part =>\n part.kind === 'text' && 'text' in part && typeof part.text === 'string' ? [part.text] : [],\n )\n .join('');\n if (text) {\n textId ??= resolveStreamTextId([event.artifact.artifactId, task?.id]);\n if (textId) {\n if (!textStarted) {\n yield toAgentStreamChunk(runId, { type: 'text-start', payload: { id: textId } });\n textStarted = true;\n }\n yield toAgentStreamChunk(runId, { type: 'text-delta', payload: { id: textId, text } });\n }\n }\n } else if (event.kind === 'status-update') {\n task = task\n ? {\n ...task,\n status: event.status,\n }\n : task;\n if (event.status.state === 'input-required' && task) {\n suspended = {\n taskId: task.id,\n contextId: task.contextId,\n executionUrl: bootstrap.executionUrl,\n cardUrl: bootstrap.cardUrl,\n waitingForInput: true,\n task: structuredClone(task),\n };\n }\n }\n }\n\n buffer = next.rest;\n next = splitNextEvent(buffer);\n }\n\n if (done || receivedDone) {\n if (textId && textStarted) {\n yield toAgentStreamChunk(runId, { type: 'text-end', payload: { id: textId } });\n }\n\n if (!suspended && task && !isTerminalTaskState(task.status.state)) {\n suspended = {\n taskId: task.id,\n contextId: task.contextId,\n executionUrl: bootstrap.executionUrl,\n cardUrl: bootstrap.cardUrl,\n waitingForInput: false,\n task: structuredClone(task),\n };\n }\n\n if (suspended) {\n yield toAgentStreamChunk(runId, {\n type: 'tool-call-suspended',\n payload: {\n toolCallId: runId,\n toolName: this.id,\n args: {},\n suspendPayload: suspended,\n resumeSchema: createResumeSchema(),\n },\n });\n } else {\n yield toAgentStreamChunk(runId, {\n type: 'finish',\n payload: createFinishPayload(),\n });\n }\n return;\n }\n }\n }\n\n async #collectStreamEvents({\n bootstrap,\n initialTask,\n stream,\n }: {\n bootstrap: AgentBootstrap;\n initialTask?: Task;\n stream: ReadableStream<Uint8Array>;\n }): Promise<StreamConsumptionResult> {\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n let textBuffer = '';\n let task: Task | undefined = initialTask ? structuredClone(initialTask) : undefined;\n let suspended: StreamConsumptionResult['suspended'];\n\n while (true) {\n const { done, value } = await reader.read();\n\n if (done) {\n buffer += decoder.decode();\n } else if (value) {\n buffer += decoder.decode(value, { stream: true });\n }\n\n let next = splitNextEvent(buffer);\n while (next.eventBlock !== undefined) {\n const parsed = parseEventBlock(next.eventBlock);\n if ('done' in parsed && parsed.done) {\n break;\n }\n\n if ('event' in parsed && parsed.event) {\n const event = parsed.event;\n\n if (isTask(event)) {\n task = event;\n textBuffer = extractTaskArtifactText(event) || textBuffer;\n\n if (event.status.state === 'input-required') {\n suspended = {\n payload: {\n taskId: event.id,\n contextId: event.contextId,\n executionUrl: bootstrap.executionUrl,\n cardUrl: bootstrap.cardUrl,\n waitingForInput: true,\n task: structuredClone(event),\n },\n resumeSchema: createResumeSchema(),\n };\n }\n } else if (isMessage(event)) {\n const messageText = extractMessageText(event);\n if (messageText) {\n textBuffer = messageText;\n }\n } else if (event.kind === 'artifact-update') {\n task = task\n ? {\n ...task,\n artifacts: [\n ...(task.artifacts ?? []).filter(artifact => artifact.artifactId !== event.artifact.artifactId),\n event.artifact,\n ],\n }\n : task;\n\n const artifactText = event.artifact.parts\n ?.flatMap(part =>\n part.kind === 'text' && 'text' in part && typeof part.text === 'string' ? [part.text] : [],\n )\n .join('');\n if (artifactText) {\n textBuffer += artifactText;\n }\n } else if (event.kind === 'status-update') {\n task = task\n ? {\n ...task,\n status: event.status,\n }\n : task;\n\n if (event.status.state === 'input-required' && task) {\n suspended = {\n payload: {\n taskId: task.id,\n contextId: task.contextId,\n executionUrl: bootstrap.executionUrl,\n cardUrl: bootstrap.cardUrl,\n waitingForInput: true,\n task: structuredClone(task),\n },\n resumeSchema: createResumeSchema(),\n };\n }\n }\n }\n\n buffer = next.rest;\n next = splitNextEvent(buffer);\n }\n\n if (done) {\n break;\n }\n }\n\n if (!suspended && task && !isTerminalTaskState(task.status.state)) {\n suspended = {\n payload: {\n taskId: task.id,\n contextId: task.contextId,\n executionUrl: bootstrap.executionUrl,\n cardUrl: bootstrap.cardUrl,\n waitingForInput: false,\n task: structuredClone(task),\n },\n };\n }\n\n return {\n text: textBuffer,\n task,\n suspended,\n };\n }\n\n #createBufferedStreamResult({\n runId,\n result,\n threadId,\n resourceId,\n emitStart,\n }: {\n runId: string;\n result: A2AAgentGenerateResult;\n threadId?: string;\n resourceId?: string;\n emitStart: boolean;\n }): A2AAgentStreamResult {\n const messageList = new MessageList({ threadId, resourceId });\n const toolName = this.id;\n const agentId = this.id;\n const textId = resolveStreamTextId([result.message?.messageId, result.task?.id]);\n if (result.text) {\n messageList.add(\n {\n role: 'assistant',\n content: result.text,\n },\n 'response',\n );\n }\n\n const fullStream = (async function* (): AsyncIterable<A2AAgentFullStreamChunk> {\n if (emitStart) {\n yield toAgentStreamChunk(runId, { type: 'start', payload: { id: agentId } });\n }\n\n if (result.text) {\n yield toAgentStreamChunk(runId, { type: 'text-start', payload: { id: textId } });\n yield toAgentStreamChunk(runId, { type: 'text-delta', payload: { id: textId, text: result.text } });\n yield toAgentStreamChunk(runId, { type: 'text-end', payload: { id: textId } });\n }\n\n if (result.resumePayload) {\n yield toAgentStreamChunk(runId, {\n type: 'tool-call-suspended',\n payload: {\n toolCallId: runId,\n toolName,\n args: {},\n suspendPayload: result.resumePayload,\n resumeSchema: result.resumeSchema ?? createResumeSchema(),\n },\n });\n return;\n }\n\n yield toAgentStreamChunk(runId, {\n type: 'finish',\n payload: createFinishPayload(),\n });\n })();\n\n const streamResult = {\n runId,\n fullStream,\n text: Promise.resolve(result.text),\n toolResults: Promise.resolve([]),\n messageList,\n task: Promise.resolve(result.task),\n suspendPayload: Promise.resolve(result.resumePayload),\n resumeSchema: Promise.resolve(result.resumeSchema),\n getResult: async () => result,\n };\n\n return streamResult as unknown as A2AAgentStreamResult;\n }\n\n async #request(\n url: string,\n { method = 'POST', headers = {}, body, stream = false, credentials, signal }: RequestOptions = {},\n ): Promise<Response> {\n let attempts = 0;\n let lastError: unknown;\n\n const finalHeaders = {\n accept: stream ? 'text/event-stream' : 'application/json',\n ...this.#headers,\n ...headers,\n };\n\n while (attempts <= this.#retries) {\n try {\n const requestSignal = this.#resolveRequestSignal(signal);\n const response = await this.#fetch(url, {\n method,\n headers: {\n ...finalHeaders,\n ...(body ? { 'content-type': 'application/json' } : {}),\n },\n body: body ? JSON.stringify(body) : undefined,\n credentials: credentials ?? this.#credentials,\n signal: requestSignal,\n });\n\n if (!response.ok) {\n throw MastraA2AError.invalidAgentResponse(`Remote A2A request failed with status ${response.status}.`, {\n status: response.status,\n url,\n });\n }\n\n return response;\n } catch (error) {\n lastError = error;\n\n if (!shouldRetryRequest(error)) {\n throw lastError;\n }\n\n if (attempts === this.#retries) {\n break;\n }\n\n attempts += 1;\n await this.#delay(attempts);\n }\n }\n\n throw lastError;\n }\n\n async #delay(attempt: number = 0) {\n const delayMs = Math.min(this.#backoffMs * Math.max(1, attempt), this.#maxBackoffMs);\n if (delayMs <= 0) {\n return;\n }\n\n await new Promise(resolve => setTimeout(resolve, delayMs));\n }\n\n #resolveRequestSignal(signal?: AbortSignal) {\n if (this.#timeoutMs == null) {\n return signal ?? this.#abortSignal;\n }\n\n const timeoutSignal = AbortSignal.timeout(this.#timeoutMs);\n const signals = [signal, this.#abortSignal, timeoutSignal].filter(Boolean) as AbortSignal[];\n\n if (signals.length === 0) {\n return undefined;\n }\n\n return signals.length === 1 ? signals[0] : AbortSignal.any(signals);\n }\n}\n\nfunction shouldRetryRequest(error: unknown): boolean {\n if (error instanceof TypeError) {\n return true;\n }\n\n if (error instanceof DOMException && error.name === 'AbortError') {\n return true;\n }\n\n if (error instanceof Error && error.name === 'AbortError') {\n return true;\n }\n\n const status =\n typeof error === 'object' && error !== null && 'status' in error && typeof error.status === 'number'\n ? error.status\n : typeof error === 'object' &&\n error !== null &&\n 'data' in error &&\n typeof error.data === 'object' &&\n error.data !== null &&\n 'status' in error.data &&\n typeof error.data.status === 'number'\n ? error.data.status\n : undefined;\n\n if (status === undefined) {\n return true;\n }\n\n return status === 408 || status === 429 || status >= 500;\n}\n"],"mappings":"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