var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/client/index.ts var client_exports = {}; __export(client_exports, { A2AClient: () => A2AClient, AgentCardResolver: () => AgentCardResolver, AuthenticatedExtendedCardNotConfiguredError: () => AuthenticatedExtendedCardNotConfiguredError, Client: () => Client, ClientCallContext: () => ClientCallContext, ClientCallContextKey: () => ClientCallContextKey, ClientFactory: () => ClientFactory, ClientFactoryOptions: () => ClientFactoryOptions, ContentTypeNotSupportedError: () => ContentTypeNotSupportedError, DefaultAgentCardResolver: () => DefaultAgentCardResolver, InvalidAgentResponseError: () => InvalidAgentResponseError, JsonRpcTransport: () => JsonRpcTransport, JsonRpcTransportFactory: () => JsonRpcTransportFactory, PushNotificationNotSupportedError: () => PushNotificationNotSupportedError, RestTransport: () => RestTransport, RestTransportFactory: () => RestTransportFactory, ServiceParameters: () => ServiceParameters, TaskNotCancelableError: () => TaskNotCancelableError, TaskNotFoundError: () => TaskNotFoundError, UnsupportedOperationError: () => UnsupportedOperationError, createAuthenticatingFetchWithRetry: () => createAuthenticatingFetchWithRetry, withA2AExtensions: () => withA2AExtensions }); module.exports = __toCommonJS(client_exports); // src/constants.ts var AGENT_CARD_PATH = ".well-known/agent-card.json"; var HTTP_EXTENSION_HEADER = "X-A2A-Extensions"; // src/errors.ts var A2A_ERROR_CODE = { PARSE_ERROR: -32700, INVALID_REQUEST: -32600, METHOD_NOT_FOUND: -32601, INVALID_PARAMS: -32602, INTERNAL_ERROR: -32603, TASK_NOT_FOUND: -32001, TASK_NOT_CANCELABLE: -32002, PUSH_NOTIFICATION_NOT_SUPPORTED: -32003, UNSUPPORTED_OPERATION: -32004, CONTENT_TYPE_NOT_SUPPORTED: -32005, INVALID_AGENT_RESPONSE: -32006, AUTHENTICATED_EXTENDED_CARD_NOT_CONFIGURED: -32007 }; var TaskNotFoundError = class extends Error { constructor(message) { super(message ?? "Task not found"); this.name = "TaskNotFoundError"; } }; var TaskNotCancelableError = class extends Error { constructor(message) { super(message ?? "Task cannot be canceled"); this.name = "TaskNotCancelableError"; } }; var PushNotificationNotSupportedError = class extends Error { constructor(message) { super(message ?? "Push Notification is not supported"); this.name = "PushNotificationNotSupportedError"; } }; var UnsupportedOperationError = class extends Error { constructor(message) { super(message ?? "This operation is not supported"); this.name = "UnsupportedOperationError"; } }; var ContentTypeNotSupportedError = class extends Error { constructor(message) { super(message ?? "Incompatible content types"); this.name = "ContentTypeNotSupportedError"; } }; var InvalidAgentResponseError = class extends Error { constructor(message) { super(message ?? "Invalid agent response type"); this.name = "InvalidAgentResponseError"; } }; var AuthenticatedExtendedCardNotConfiguredError = class extends Error { constructor(message) { super(message ?? "Authenticated Extended Card not configured"); this.name = "AuthenticatedExtendedCardNotConfiguredError"; } }; // src/sse_utils.ts async function* parseSseStream(response) { if (!response.body) { throw new Error("SSE response body is undefined. Cannot read stream."); } let buffer = ""; let eventType = "message"; let eventData = ""; const stream = response.body.pipeThrough(new TextDecoderStream()); for await (const value of readFrom(stream)) { buffer += value; let lineEndIndex; while ((lineEndIndex = buffer.indexOf("\n")) >= 0) { const line = buffer.substring(0, lineEndIndex).trim(); buffer = buffer.substring(lineEndIndex + 1); if (line === "") { if (eventData) { yield { type: eventType, data: eventData }; eventData = ""; eventType = "message"; } } else if (line.startsWith("event:")) { eventType = line.substring("event:".length).trim(); } else if (line.startsWith("data:")) { eventData = line.substring("data:".length).trim(); } } } if (eventData) { yield { type: eventType, data: eventData }; } } async function* readFrom(stream) { const reader = stream.getReader(); try { while (true) { const { done, value } = await reader.read(); if (done) { break; } yield value; } } finally { reader.releaseLock(); } } // src/client/transports/json_rpc_transport.ts var JsonRpcTransport = class _JsonRpcTransport { customFetchImpl; endpoint; requestIdCounter = 1; constructor(options) { this.endpoint = options.endpoint; this.customFetchImpl = options.fetchImpl; } async getExtendedAgentCard(options, idOverride) { const rpcResponse = await this._sendRpcRequest("agent/getAuthenticatedExtendedCard", void 0, idOverride, options); return rpcResponse.result; } async sendMessage(params, options, idOverride) { const rpcResponse = await this._sendRpcRequest( "message/send", params, idOverride, options ); return rpcResponse.result; } async *sendMessageStream(params, options) { yield* this._sendStreamingRequest("message/stream", params, options); } async setTaskPushNotificationConfig(params, options, idOverride) { const rpcResponse = await this._sendRpcRequest("tasks/pushNotificationConfig/set", params, idOverride, options); return rpcResponse.result; } async getTaskPushNotificationConfig(params, options, idOverride) { const rpcResponse = await this._sendRpcRequest("tasks/pushNotificationConfig/get", params, idOverride, options); return rpcResponse.result; } async listTaskPushNotificationConfig(params, options, idOverride) { const rpcResponse = await this._sendRpcRequest("tasks/pushNotificationConfig/list", params, idOverride, options); return rpcResponse.result; } async deleteTaskPushNotificationConfig(params, options, idOverride) { await this._sendRpcRequest("tasks/pushNotificationConfig/delete", params, idOverride, options); } async getTask(params, options, idOverride) { const rpcResponse = await this._sendRpcRequest( "tasks/get", params, idOverride, options ); return rpcResponse.result; } async cancelTask(params, options, idOverride) { const rpcResponse = await this._sendRpcRequest( "tasks/cancel", params, idOverride, options ); return rpcResponse.result; } async *resubscribeTask(params, options) { yield* this._sendStreamingRequest("tasks/resubscribe", params, options); } async callExtensionMethod(method, params, idOverride, options) { return await this._sendRpcRequest( method, params, idOverride, options ); } _fetch(...args) { if (this.customFetchImpl) { return this.customFetchImpl(...args); } if (typeof fetch === "function") { return fetch(...args); } throw new Error( "A `fetch` implementation was not provided and is not available in the global scope. Please provide a `fetchImpl` in the A2ATransportOptions. " ); } async _sendRpcRequest(method, params, idOverride, options) { const requestId = idOverride ?? this.requestIdCounter++; const rpcRequest = { jsonrpc: "2.0", method, params, id: requestId }; const httpResponse = await this._fetchRpc(rpcRequest, "application/json", options); if (!httpResponse.ok) { let errorBodyText = "(empty or non-JSON response)"; let errorJson; try { errorBodyText = await httpResponse.text(); errorJson = JSON.parse(errorBodyText); } catch (e) { throw new Error( `HTTP error for ${method}! Status: ${httpResponse.status} ${httpResponse.statusText}. Response: ${errorBodyText}`, { cause: e } ); } if (errorJson.jsonrpc && errorJson.error) { throw _JsonRpcTransport.mapToError(errorJson); } else { throw new Error( `HTTP error for ${method}! Status: ${httpResponse.status} ${httpResponse.statusText}. Response: ${errorBodyText}` ); } } const rpcResponse = await httpResponse.json(); if (rpcResponse.id !== requestId) { throw new Error( `JSON-RPC response ID mismatch for method ${method}. Expected ${requestId}, got ${rpcResponse.id}.` ); } if ("error" in rpcResponse) { throw _JsonRpcTransport.mapToError(rpcResponse); } return rpcResponse; } async _fetchRpc(rpcRequest, acceptHeader = "application/json", options) { const requestInit = { method: "POST", headers: { ...options?.serviceParameters, "Content-Type": "application/json", Accept: acceptHeader }, body: JSON.stringify(rpcRequest), signal: options?.signal }; return this._fetch(this.endpoint, requestInit); } async *_sendStreamingRequest(method, params, options) { const clientRequestId = this.requestIdCounter++; const rpcRequest = { jsonrpc: "2.0", method, params, id: clientRequestId }; const response = await this._fetchRpc(rpcRequest, "text/event-stream", options); if (!response.ok) { let errorBody = ""; let errorJson; try { errorBody = await response.text(); errorJson = JSON.parse(errorBody); } catch (e) { throw new Error( `HTTP error establishing stream for ${method}: ${response.status} ${response.statusText}. Response: ${errorBody || "(empty)"}`, { cause: e } ); } if (errorJson.error) { throw new Error( `HTTP error establishing stream for ${method}: ${response.status} ${response.statusText}. RPC Error: ${errorJson.error.message} (Code: ${errorJson.error.code})` ); } throw new Error( `HTTP error establishing stream for ${method}: ${response.status} ${response.statusText}` ); } if (!response.headers.get("Content-Type")?.startsWith("text/event-stream")) { throw new Error( `Invalid response Content-Type for SSE stream for ${method}. Expected 'text/event-stream'.` ); } for await (const event of parseSseStream(response)) { yield this._processSseEventData(event.data, clientRequestId); } } _processSseEventData(jsonData, originalRequestId) { if (!jsonData.trim()) { throw new Error("Attempted to process empty SSE event data."); } let a2aStreamResponse; try { a2aStreamResponse = JSON.parse(jsonData); } catch (e) { throw new Error( `Failed to parse SSE event data: "${jsonData.substring(0, 100)}...". Original error: ${e instanceof Error && e.message || "Unknown error"}`, { cause: e } ); } if (a2aStreamResponse.id !== originalRequestId) { throw new Error( `JSON-RPC response ID mismatch in SSE event. Expected ${originalRequestId}, got ${a2aStreamResponse.id}.` ); } if ("error" in a2aStreamResponse) { const err = a2aStreamResponse.error; throw new Error( `SSE event contained an error: ${err.message} (Code: ${err.code}) Data: ${JSON.stringify(err.data || {})}`, { cause: _JsonRpcTransport.mapToError(a2aStreamResponse) } ); } if (!("result" in a2aStreamResponse) || typeof a2aStreamResponse.result === "undefined") { throw new Error(`SSE event JSON-RPC response is missing 'result' field. Data: ${jsonData}`); } return a2aStreamResponse.result; } static mapToError(response) { switch (response.error.code) { case -32001: return new TaskNotFoundJSONRPCError(response); case -32002: return new TaskNotCancelableJSONRPCError(response); case -32003: return new PushNotificationNotSupportedJSONRPCError(response); case -32004: return new UnsupportedOperationJSONRPCError(response); case -32005: return new ContentTypeNotSupportedJSONRPCError(response); case -32006: return new InvalidAgentResponseJSONRPCError(response); case -32007: return new AuthenticatedExtendedCardNotConfiguredJSONRPCError(response); default: return new JSONRPCTransportError(response); } } }; var JsonRpcTransportFactory = class _JsonRpcTransportFactory { constructor(options) { this.options = options; } static name = "JSONRPC"; get protocolName() { return _JsonRpcTransportFactory.name; } async create(url, _agentCard) { return new JsonRpcTransport({ endpoint: url, fetchImpl: this.options?.fetchImpl }); } }; var JSONRPCTransportError = class extends Error { constructor(errorResponse) { super( `JSON-RPC error: ${errorResponse.error.message} (Code: ${errorResponse.error.code}) Data: ${JSON.stringify(errorResponse.error.data || {})}` ); this.errorResponse = errorResponse; } }; var TaskNotFoundJSONRPCError = class extends TaskNotFoundError { constructor(errorResponse) { super(); this.errorResponse = errorResponse; } }; var TaskNotCancelableJSONRPCError = class extends TaskNotCancelableError { constructor(errorResponse) { super(); this.errorResponse = errorResponse; } }; var PushNotificationNotSupportedJSONRPCError = class extends PushNotificationNotSupportedError { constructor(errorResponse) { super(); this.errorResponse = errorResponse; } }; var UnsupportedOperationJSONRPCError = class extends UnsupportedOperationError { constructor(errorResponse) { super(); this.errorResponse = errorResponse; } }; var ContentTypeNotSupportedJSONRPCError = class extends ContentTypeNotSupportedError { constructor(errorResponse) { super(); this.errorResponse = errorResponse; } }; var InvalidAgentResponseJSONRPCError = class extends InvalidAgentResponseError { constructor(errorResponse) { super(); this.errorResponse = errorResponse; } }; var AuthenticatedExtendedCardNotConfiguredJSONRPCError = class extends AuthenticatedExtendedCardNotConfiguredError { constructor(errorResponse) { super(); this.errorResponse = errorResponse; } }; // src/client/client.ts var A2AClient = class _A2AClient { static emptyOptions = void 0; agentCardPromise; customFetchImpl; serviceEndpointUrl; // To be populated from AgentCard after fetchin // A2AClient is built around JSON-RPC types, so it will only support JSON-RPC transport, new client with transport agnostic interface is going to be created for multi-transport. // New transport abstraction isn't going to expose individual transport specific fields, so to keep returning JSON-RPC IDs here for compatibility, // keep counter here and pass it to JsonRpcTransport via an optional idOverride parameter (which is not visible via transport-agnostic A2ATransport interface). transport; requestIdCounter = 1; /** * Constructs an A2AClient instance from an AgentCard. * @param agentCard The AgentCard object. * @param options Optional. The options for the A2AClient including the fetch/auth implementation. */ constructor(agentCard, options) { this.customFetchImpl = options?.fetchImpl; if (typeof agentCard === "string") { console.warn( "Warning: Constructing A2AClient with a URL is deprecated. Please use A2AClient.fromCardUrl() instead." ); this.agentCardPromise = this._fetchAndCacheAgentCard(agentCard, options?.agentCardPath); } else { if (!agentCard.url) { throw new Error( "Provided Agent Card does not contain a valid 'url' for the service endpoint." ); } this.serviceEndpointUrl = agentCard.url; this.agentCardPromise = Promise.resolve(agentCard); } } /** * Dynamically resolves the fetch implementation to use for requests. * Prefers a custom implementation if provided, otherwise falls back to the global fetch. * @returns The fetch implementation. * @param args Arguments to pass to the fetch implementation. * @throws If no fetch implementation is available. */ _fetch(...args) { if (this.customFetchImpl) { return this.customFetchImpl(...args); } if (typeof fetch === "function") { return fetch(...args); } throw new Error( "A `fetch` implementation was not provided and is not available in the global scope. Please provide a `fetchImpl` in the A2AClientOptions. For earlier Node.js versions (pre-v18), you can use a library like `node-fetch`." ); } /** * Creates an A2AClient instance by fetching the AgentCard from a URL then constructing the A2AClient. * @param agentCardUrl The URL of the agent card. * @param options Optional. The options for the A2AClient including the fetch/auth implementation. * @returns A Promise that resolves to a new A2AClient instance. */ static async fromCardUrl(agentCardUrl, options) { const fetchImpl = options?.fetchImpl; const requestInit = { headers: { Accept: "application/json" } }; let response; if (fetchImpl) { response = await fetchImpl(agentCardUrl, requestInit); } else if (typeof fetch === "function") { response = await fetch(agentCardUrl, requestInit); } else { throw new Error( "A `fetch` implementation was not provided and is not available in the global scope. Please provide a `fetchImpl` in the A2AClientOptions. For earlier Node.js versions (pre-v18), you can use a library like `node-fetch`." ); } if (!response.ok) { throw new Error( `Failed to fetch Agent Card from ${agentCardUrl}: ${response.status} ${response.statusText}` ); } let agentCard; try { agentCard = await response.json(); } catch (error) { console.error("Failed to parse Agent Card JSON:", error); throw new Error( `Failed to parse Agent Card JSON from ${agentCardUrl}. Original error: ${error.message}` ); } return new _A2AClient(agentCard, options); } /** * Sends a message to the agent. * The behavior (blocking/non-blocking) and push notification configuration * are specified within the `params.configuration` object. * Optionally, `params.message.contextId` or `params.message.taskId` can be provided. * @param params The parameters for sending the message, including the message content and configuration. * @returns A Promise resolving to SendMessageResponse, which can be a Message, Task, or an error. */ async sendMessage(params) { return await this.invokeJsonRpc( (t, p, id) => t.sendMessage(p, _A2AClient.emptyOptions, id), params ); } /** * Sends a message to the agent and streams back responses using Server-Sent Events (SSE). * Push notification configuration can be specified in `params.configuration`. * Optionally, `params.message.contextId` or `params.message.taskId` can be provided. * Requires the agent to support streaming (`capabilities.streaming: true` in AgentCard). * @param params The parameters for sending the message. * @returns An AsyncGenerator yielding A2AStreamEventData (Message, Task, TaskStatusUpdateEvent, or TaskArtifactUpdateEvent). * The generator throws an error if streaming is not supported or if an HTTP/SSE error occurs. */ async *sendMessageStream(params) { const agentCard = await this.agentCardPromise; if (!agentCard.capabilities?.streaming) { throw new Error( "Agent does not support streaming (AgentCard.capabilities.streaming is not true)." ); } const transport = await this._getOrCreateTransport(); yield* transport.sendMessageStream(params); } /** * Sets or updates the push notification configuration for a given task. * Requires the agent to support push notifications (`capabilities.pushNotifications: true` in AgentCard). * @param params Parameters containing the taskId and the TaskPushNotificationConfig. * @returns A Promise resolving to SetTaskPushNotificationConfigResponse. */ async setTaskPushNotificationConfig(params) { const agentCard = await this.agentCardPromise; if (!agentCard.capabilities?.pushNotifications) { throw new Error( "Agent does not support push notifications (AgentCard.capabilities.pushNotifications is not true)." ); } return await this.invokeJsonRpc((t, p, id) => t.setTaskPushNotificationConfig(p, _A2AClient.emptyOptions, id), params); } /** * Gets the push notification configuration for a given task. * @param params Parameters containing the taskId. * @returns A Promise resolving to GetTaskPushNotificationConfigResponse. */ async getTaskPushNotificationConfig(params) { return await this.invokeJsonRpc( (t, p, id) => t.getTaskPushNotificationConfig(p, _A2AClient.emptyOptions, id), params ); } /** * Lists the push notification configurations for a given task. * @param params Parameters containing the taskId. * @returns A Promise resolving to ListTaskPushNotificationConfigResponse. */ async listTaskPushNotificationConfig(params) { return await this.invokeJsonRpc((t, p, id) => t.listTaskPushNotificationConfig(p, _A2AClient.emptyOptions, id), params); } /** * Deletes the push notification configuration for a given task. * @param params Parameters containing the taskId and push notification configuration ID. * @returns A Promise resolving to DeleteTaskPushNotificationConfigResponse. */ async deleteTaskPushNotificationConfig(params) { return await this.invokeJsonRpc((t, p, id) => t.deleteTaskPushNotificationConfig(p, _A2AClient.emptyOptions, id), params); } /** * Retrieves a task by its ID. * @param params Parameters containing the taskId and optional historyLength. * @returns A Promise resolving to GetTaskResponse, which contains the Task object or an error. */ async getTask(params) { return await this.invokeJsonRpc( (t, p, id) => t.getTask(p, _A2AClient.emptyOptions, id), params ); } /** * Cancels a task by its ID. * @param params Parameters containing the taskId. * @returns A Promise resolving to CancelTaskResponse, which contains the updated Task object or an error. */ async cancelTask(params) { return await this.invokeJsonRpc( (t, p, id) => t.cancelTask(p, _A2AClient.emptyOptions, id), params ); } /** * @template TExtensionParams The type of parameters for the custom extension method. * @template TExtensionResponse The type of response expected from the custom extension method. * This should extend JSONRPCResponse. This ensures the extension response is still a valid A2A response. * @param method Custom JSON-RPC method defined in the AgentCard's extensions. * @param params Extension paramters defined in the AgentCard's extensions. * @returns A Promise that resolves to the RPC response. */ async callExtensionMethod(method, params) { const transport = await this._getOrCreateTransport(); try { return await transport.callExtensionMethod( method, params, this.requestIdCounter++ ); } catch (e) { const errorResponse = extractJSONRPCError(e); if (errorResponse) { return errorResponse; } throw e; } } /** * Resubscribes to a task's event stream using Server-Sent Events (SSE). * This is used if a previous SSE connection for an active task was broken. * Requires the agent to support streaming (`capabilities.streaming: true` in AgentCard). * @param params Parameters containing the taskId. * @returns An AsyncGenerator yielding A2AStreamEventData (Message, Task, TaskStatusUpdateEvent, or TaskArtifactUpdateEvent). */ async *resubscribeTask(params) { const agentCard = await this.agentCardPromise; if (!agentCard.capabilities?.streaming) { throw new Error("Agent does not support streaming (required for tasks/resubscribe)."); } const transport = await this._getOrCreateTransport(); yield* transport.resubscribeTask(params); } //////////////////////////////////////////////////////////////////////////////// // Functions used to support old A2AClient Constructor to be deprecated soon // TODOs: // * remove `agentCardPromise`, and just use agentCard initialized // * _getServiceEndpoint can be made synchronous or deleted and accessed via // agentCard.url // * getAgentCard changed to this.agentCard // * delete resolveAgentCardUrl(), _fetchAndCacheAgentCard(), // agentCardPath from A2AClientOptions // * delete _getOrCreateTransport //////////////////////////////////////////////////////////////////////////////// async _getOrCreateTransport() { if (this.transport) { return this.transport; } const endpoint = await this._getServiceEndpoint(); this.transport = new JsonRpcTransport({ fetchImpl: this.customFetchImpl, endpoint }); return this.transport; } /** * Fetches the Agent Card from the agent's well-known URI and caches its service endpoint URL. * This method is called by the constructor. * @param agentBaseUrl The base URL of the A2A agent (e.g., https://agent.example.com) * @param agentCardPath path to the agent card, defaults to .well-known/agent-card.json * @returns A Promise that resolves to the AgentCard. */ async _fetchAndCacheAgentCard(agentBaseUrl, agentCardPath) { try { const agentCardUrl = this.resolveAgentCardUrl(agentBaseUrl, agentCardPath); const response = await this._fetch(agentCardUrl, { headers: { Accept: "application/json" } }); if (!response.ok) { throw new Error( `Failed to fetch Agent Card from ${agentCardUrl}: ${response.status} ${response.statusText}` ); } const agentCard = await response.json(); if (!agentCard.url) { throw new Error( "Fetched Agent Card does not contain a valid 'url' for the service endpoint." ); } this.serviceEndpointUrl = agentCard.url; return agentCard; } catch (error) { console.error("Error fetching or parsing Agent Card:", error); throw error; } } /** * Retrieves the Agent Card. * If an `agentBaseUrl` is provided, it fetches the card from that specific URL. * Otherwise, it returns the card fetched and cached during client construction. * @param agentBaseUrl Optional. The base URL of the agent to fetch the card from. * @param agentCardPath path to the agent card, defaults to .well-known/agent-card.json * If provided, this will fetch a new card, not use the cached one from the constructor's URL. * @returns A Promise that resolves to the AgentCard. */ async getAgentCard(agentBaseUrl, agentCardPath) { if (agentBaseUrl) { const agentCardUrl = this.resolveAgentCardUrl(agentBaseUrl, agentCardPath); const response = await this._fetch(agentCardUrl, { headers: { Accept: "application/json" } }); if (!response.ok) { throw new Error( `Failed to fetch Agent Card from ${agentCardUrl}: ${response.status} ${response.statusText}` ); } return await response.json(); } return this.agentCardPromise; } /** * Determines the agent card URL based on the agent URL. * @param agentBaseUrl The agent URL. * @param agentCardPath Optional relative path to the agent card, defaults to .well-known/agent-card.json */ resolveAgentCardUrl(agentBaseUrl, agentCardPath = AGENT_CARD_PATH) { return `${agentBaseUrl.replace(/\/$/, "")}/${agentCardPath.replace(/^\//, "")}`; } /** * Gets the RPC service endpoint URL. Ensures the agent card has been fetched first. * @returns A Promise that resolves to the service endpoint URL string. */ async _getServiceEndpoint() { if (this.serviceEndpointUrl) { return this.serviceEndpointUrl; } await this.agentCardPromise; if (!this.serviceEndpointUrl) { throw new Error( "Agent Card URL for RPC endpoint is not available. Fetching might have failed." ); } return this.serviceEndpointUrl; } async invokeJsonRpc(caller, params) { const transport = await this._getOrCreateTransport(); const requestId = this.requestIdCounter++; try { const result = await caller(transport, params, requestId); return { id: requestId, jsonrpc: "2.0", result: result ?? null // JSON-RPC requires result property on success, it will be null for "void" methods. }; } catch (e) { const errorResponse = extractJSONRPCError(e); if (errorResponse) { return errorResponse; } throw e; } } }; function extractJSONRPCError(error) { if (error instanceof Object && "errorResponse" in error && error.errorResponse instanceof Object && "jsonrpc" in error.errorResponse && error.errorResponse.jsonrpc === "2.0" && "error" in error.errorResponse && error.errorResponse.error !== null) { return error.errorResponse; } else { return void 0; } } // src/client/auth-handler.ts function createAuthenticatingFetchWithRetry(fetchImpl, authHandler) { async function authFetch(url, init) { const authHeaders = await authHandler.headers() || {}; const mergedInit = { ...init || {}, headers: { ...authHeaders, ...init?.headers || {} } }; let response = await fetchImpl(url, mergedInit); const updatedHeaders = await authHandler.shouldRetryWithHeaders(mergedInit, response); if (updatedHeaders) { const retryInit = { ...init || {}, headers: { ...updatedHeaders, ...init?.headers || {} } }; response = await fetchImpl(url, retryInit); if (response.ok && authHandler.onSuccessfulRetry) { await authHandler.onSuccessfulRetry(updatedHeaders); } } return response; } Object.setPrototypeOf(authFetch, Object.getPrototypeOf(fetchImpl)); Object.defineProperties(authFetch, Object.getOwnPropertyDescriptors(fetchImpl)); return authFetch; } // src/types/pb/a2a_types.ts function taskStateFromJSON(object) { switch (object) { case 0: case "TASK_STATE_UNSPECIFIED": return 0 /* TASK_STATE_UNSPECIFIED */; case 1: case "TASK_STATE_SUBMITTED": return 1 /* TASK_STATE_SUBMITTED */; case 2: case "TASK_STATE_WORKING": return 2 /* TASK_STATE_WORKING */; case 3: case "TASK_STATE_COMPLETED": return 3 /* TASK_STATE_COMPLETED */; case 4: case "TASK_STATE_FAILED": return 4 /* TASK_STATE_FAILED */; case 5: case "TASK_STATE_CANCELLED": return 5 /* TASK_STATE_CANCELLED */; case 6: case "TASK_STATE_INPUT_REQUIRED": return 6 /* TASK_STATE_INPUT_REQUIRED */; case 7: case "TASK_STATE_REJECTED": return 7 /* TASK_STATE_REJECTED */; case 8: case "TASK_STATE_AUTH_REQUIRED": return 8 /* TASK_STATE_AUTH_REQUIRED */; case -1: case "UNRECOGNIZED": default: return -1 /* UNRECOGNIZED */; } } function taskStateToJSON(object) { switch (object) { case 0 /* TASK_STATE_UNSPECIFIED */: return "TASK_STATE_UNSPECIFIED"; case 1 /* TASK_STATE_SUBMITTED */: return "TASK_STATE_SUBMITTED"; case 2 /* TASK_STATE_WORKING */: return "TASK_STATE_WORKING"; case 3 /* TASK_STATE_COMPLETED */: return "TASK_STATE_COMPLETED"; case 4 /* TASK_STATE_FAILED */: return "TASK_STATE_FAILED"; case 5 /* TASK_STATE_CANCELLED */: return "TASK_STATE_CANCELLED"; case 6 /* TASK_STATE_INPUT_REQUIRED */: return "TASK_STATE_INPUT_REQUIRED"; case 7 /* TASK_STATE_REJECTED */: return "TASK_STATE_REJECTED"; case 8 /* TASK_STATE_AUTH_REQUIRED */: return "TASK_STATE_AUTH_REQUIRED"; case -1 /* UNRECOGNIZED */: default: return "UNRECOGNIZED"; } } function roleFromJSON(object) { switch (object) { case 0: case "ROLE_UNSPECIFIED": return 0 /* ROLE_UNSPECIFIED */; case 1: case "ROLE_USER": return 1 /* ROLE_USER */; case 2: case "ROLE_AGENT": return 2 /* ROLE_AGENT */; case -1: case "UNRECOGNIZED": default: return -1 /* UNRECOGNIZED */; } } function roleToJSON(object) { switch (object) { case 0 /* ROLE_UNSPECIFIED */: return "ROLE_UNSPECIFIED"; case 1 /* ROLE_USER */: return "ROLE_USER"; case 2 /* ROLE_AGENT */: return "ROLE_AGENT"; case -1 /* UNRECOGNIZED */: default: return "UNRECOGNIZED"; } } var SendMessageConfiguration = { fromJSON(object) { return { acceptedOutputModes: globalThis.Array.isArray(object?.acceptedOutputModes) ? object.acceptedOutputModes.map((e) => globalThis.String(e)) : globalThis.Array.isArray(object?.accepted_output_modes) ? object.accepted_output_modes.map( (e) => globalThis.String(e) ) : [], pushNotification: isSet(object.pushNotification) ? PushNotificationConfig.fromJSON(object.pushNotification) : isSet(object.push_notification) ? PushNotificationConfig.fromJSON(object.push_notification) : void 0, historyLength: isSet(object.historyLength) ? globalThis.Number(object.historyLength) : isSet(object.history_length) ? globalThis.Number(object.history_length) : 0, blocking: isSet(object.blocking) ? globalThis.Boolean(object.blocking) : false }; }, toJSON(message) { const obj = {}; if (message.acceptedOutputModes?.length) { obj.acceptedOutputModes = message.acceptedOutputModes; } if (message.pushNotification !== void 0) { obj.pushNotification = PushNotificationConfig.toJSON(message.pushNotification); } if (message.historyLength !== 0) { obj.historyLength = Math.round(message.historyLength); } if (message.blocking !== false) { obj.blocking = message.blocking; } return obj; } }; var Task = { fromJSON(object) { return { id: isSet(object.id) ? globalThis.String(object.id) : "", contextId: isSet(object.contextId) ? globalThis.String(object.contextId) : isSet(object.context_id) ? globalThis.String(object.context_id) : "", status: isSet(object.status) ? TaskStatus.fromJSON(object.status) : void 0, artifacts: globalThis.Array.isArray(object?.artifacts) ? object.artifacts.map((e) => Artifact.fromJSON(e)) : [], history: globalThis.Array.isArray(object?.history) ? object.history.map((e) => Message.fromJSON(e)) : [], metadata: isObject(object.metadata) ? object.metadata : void 0 }; }, toJSON(message) { const obj = {}; if (message.id !== "") { obj.id = message.id; } if (message.contextId !== "") { obj.contextId = message.contextId; } if (message.status !== void 0) { obj.status = TaskStatus.toJSON(message.status); } if (message.artifacts?.length) { obj.artifacts = message.artifacts.map((e) => Artifact.toJSON(e)); } if (message.history?.length) { obj.history = message.history.map((e) => Message.toJSON(e)); } if (message.metadata !== void 0) { obj.metadata = message.metadata; } return obj; } }; var TaskStatus = { fromJSON(object) { return { state: isSet(object.state) ? taskStateFromJSON(object.state) : 0, update: isSet(object.message) ? Message.fromJSON(object.message) : isSet(object.update) ? Message.fromJSON(object.update) : void 0, timestamp: isSet(object.timestamp) ? globalThis.String(object.timestamp) : void 0 }; }, toJSON(message) { const obj = {}; if (message.state !== 0) { obj.state = taskStateToJSON(message.state); } if (message.update !== void 0) { obj.message = Message.toJSON(message.update); } if (message.timestamp !== void 0) { obj.timestamp = message.timestamp; } return obj; } }; var Part = { fromJSON(object) { return { part: isSet(object.text) ? { $case: "text", value: globalThis.String(object.text) } : isSet(object.file) ? { $case: "file", value: FilePart.fromJSON(object.file) } : isSet(object.data) ? { $case: "data", value: DataPart.fromJSON(object.data) } : void 0 }; }, toJSON(message) { const obj = {}; if (message.part?.$case === "text") { obj.text = message.part.value; } else if (message.part?.$case === "file") { obj.file = FilePart.toJSON(message.part.value); } else if (message.part?.$case === "data") { obj.data = DataPart.toJSON(message.part.value); } return obj; } }; var FilePart = { fromJSON(object) { return { file: isSet(object.fileWithUri) ? { $case: "fileWithUri", value: globalThis.String(object.fileWithUri) } : isSet(object.file_with_uri) ? { $case: "fileWithUri", value: globalThis.String(object.file_with_uri) } : isSet(object.fileWithBytes) ? { $case: "fileWithBytes", value: Buffer.from(bytesFromBase64(object.fileWithBytes)) } : isSet(object.file_with_bytes) ? { $case: "fileWithBytes", value: Buffer.from(bytesFromBase64(object.file_with_bytes)) } : void 0, mimeType: isSet(object.mimeType) ? globalThis.String(object.mimeType) : isSet(object.mime_type) ? globalThis.String(object.mime_type) : "" }; }, toJSON(message) { const obj = {}; if (message.file?.$case === "fileWithUri") { obj.fileWithUri = message.file.value; } else if (message.file?.$case === "fileWithBytes") { obj.fileWithBytes = base64FromBytes(message.file.value); } if (message.mimeType !== "") { obj.mimeType = message.mimeType; } return obj; } }; var DataPart = { fromJSON(object) { return { data: isObject(object.data) ? object.data : void 0 }; }, toJSON(message) { const obj = {}; if (message.data !== void 0) { obj.data = message.data; } return obj; } }; var Message = { fromJSON(object) { return { messageId: isSet(object.messageId) ? globalThis.String(object.messageId) : isSet(object.message_id) ? globalThis.String(object.message_id) : "", contextId: isSet(object.contextId) ? globalThis.String(object.contextId) : isSet(object.context_id) ? globalThis.String(object.context_id) : "", taskId: isSet(object.taskId) ? globalThis.String(object.taskId) : isSet(object.task_id) ? globalThis.String(object.task_id) : "", role: isSet(object.role) ? roleFromJSON(object.role) : 0, content: globalThis.Array.isArray(object?.content) ? object.content.map((e) => Part.fromJSON(e)) : [], metadata: isObject(object.metadata) ? object.metadata : void 0, extensions: globalThis.Array.isArray(object?.extensions) ? object.extensions.map((e) => globalThis.String(e)) : [] }; }, toJSON(message) { const obj = {}; if (message.messageId !== "") { obj.messageId = message.messageId; } if (message.contextId !== "") { obj.contextId = message.contextId; } if (message.taskId !== "") { obj.taskId = message.taskId; } if (message.role !== 0) { obj.role = roleToJSON(message.role); } if (message.content?.length) { obj.content = message.content.map((e) => Part.toJSON(e)); } if (message.metadata !== void 0) { obj.metadata = message.metadata; } if (message.extensions?.length) { obj.extensions = message.extensions; } return obj; } }; var Artifact = { fromJSON(object) { return { artifactId: isSet(object.artifactId) ? globalThis.String(object.artifactId) : isSet(object.artifact_id) ? globalThis.String(object.artifact_id) : "", name: isSet(object.name) ? globalThis.String(object.name) : "", description: isSet(object.description) ? globalThis.String(object.description) : "", parts: globalThis.Array.isArray(object?.parts) ? object.parts.map((e) => Part.fromJSON(e)) : [], metadata: isObject(object.metadata) ? object.metadata : void 0, extensions: globalThis.Array.isArray(object?.extensions) ? object.extensions.map((e) => globalThis.String(e)) : [] }; }, toJSON(message) { const obj = {}; if (message.artifactId !== "") { obj.artifactId = message.artifactId; } if (message.name !== "") { obj.name = message.name; } if (message.description !== "") { obj.description = message.description; } if (message.parts?.length) { obj.parts = message.parts.map((e) => Part.toJSON(e)); } if (message.metadata !== void 0) { obj.metadata = message.metadata; } if (message.extensions?.length) { obj.extensions = message.extensions; } return obj; } }; var TaskStatusUpdateEvent = { fromJSON(object) { return { taskId: isSet(object.taskId) ? globalThis.String(object.taskId) : isSet(object.task_id) ? globalThis.String(object.task_id) : "", contextId: isSet(object.contextId) ? globalThis.String(object.contextId) : isSet(object.context_id) ? globalThis.String(object.context_id) : "", status: isSet(object.status) ? TaskStatus.fromJSON(object.status) : void 0, final: isSet(object.final) ? globalThis.Boolean(object.final) : false, metadata: isObject(object.metadata) ? object.metadata : void 0 }; }, toJSON(message) { const obj = {}; if (message.taskId !== "") { obj.taskId = message.taskId; } if (message.contextId !== "") { obj.contextId = message.contextId; } if (message.status !== void 0) { obj.status = TaskStatus.toJSON(message.status); } if (message.final !== false) { obj.final = message.final; } if (message.metadata !== void 0) { obj.metadata = message.metadata; } return obj; } }; var TaskArtifactUpdateEvent = { fromJSON(object) { return { taskId: isSet(object.taskId) ? globalThis.String(object.taskId) : isSet(object.task_id) ? globalThis.String(object.task_id) : "", contextId: isSet(object.contextId) ? globalThis.String(object.contextId) : isSet(object.context_id) ? globalThis.String(object.context_id) : "", artifact: isSet(object.artifact) ? Artifact.fromJSON(object.artifact) : void 0, append: isSet(object.append) ? globalThis.Boolean(object.append) : false, lastChunk: isSet(object.lastChunk) ? globalThis.Boolean(object.lastChunk) : isSet(object.last_chunk) ? globalThis.Boolean(object.last_chunk) : false, metadata: isObject(object.metadata) ? object.metadata : void 0 }; }, toJSON(message) { const obj = {}; if (message.taskId !== "") { obj.taskId = message.taskId; } if (message.contextId !== "") { obj.contextId = message.contextId; } if (message.artifact !== void 0) { obj.artifact = Artifact.toJSON(message.artifact); } if (message.append !== false) { obj.append = message.append; } if (message.lastChunk !== false) { obj.lastChunk = message.lastChunk; } if (message.metadata !== void 0) { obj.metadata = message.metadata; } return obj; } }; var PushNotificationConfig = { fromJSON(object) { return { id: isSet(object.id) ? globalThis.String(object.id) : "", url: isSet(object.url) ? globalThis.String(object.url) : "", token: isSet(object.token) ? globalThis.String(object.token) : "", authentication: isSet(object.authentication) ? AuthenticationInfo.fromJSON(object.authentication) : void 0 }; }, toJSON(message) { const obj = {}; if (message.id !== "") { obj.id = message.id; } if (message.url !== "") { obj.url = message.url; } if (message.token !== "") { obj.token = message.token; } if (message.authentication !== void 0) { obj.authentication = AuthenticationInfo.toJSON(message.authentication); } return obj; } }; var AuthenticationInfo = { fromJSON(object) { return { schemes: globalThis.Array.isArray(object?.schemes) ? object.schemes.map((e) => globalThis.String(e)) : [], credentials: isSet(object.credentials) ? globalThis.String(object.credentials) : "" }; }, toJSON(message) { const obj = {}; if (message.schemes?.length) { obj.schemes = message.schemes; } if (message.credentials !== "") { obj.credentials = message.credentials; } return obj; } }; var AgentInterface = { fromJSON(object) { return { url: isSet(object.url) ? globalThis.String(object.url) : "", transport: isSet(object.transport) ? globalThis.String(object.transport) : "" }; }, toJSON(message) { const obj = {}; if (message.url !== "") { obj.url = message.url; } if (message.transport !== "") { obj.transport = message.transport; } return obj; } }; var AgentCard = { fromJSON(object) { return { protocolVersion: isSet(object.protocolVersion) ? globalThis.String(object.protocolVersion) : isSet(object.protocol_version) ? globalThis.String(object.protocol_version) : "", name: isSet(object.name) ? globalThis.String(object.name) : "", description: isSet(object.description) ? globalThis.String(object.description) : "", url: isSet(object.url) ? globalThis.String(object.url) : "", preferredTransport: isSet(object.preferredTransport) ? globalThis.String(object.preferredTransport) : isSet(object.preferred_transport) ? globalThis.String(object.preferred_transport) : "", additionalInterfaces: globalThis.Array.isArray(object?.additionalInterfaces) ? object.additionalInterfaces.map((e) => AgentInterface.fromJSON(e)) : globalThis.Array.isArray(object?.additional_interfaces) ? object.additional_interfaces.map((e) => AgentInterface.fromJSON(e)) : [], provider: isSet(object.provider) ? AgentProvider.fromJSON(object.provider) : void 0, version: isSet(object.version) ? globalThis.String(object.version) : "", documentationUrl: isSet(object.documentationUrl) ? globalThis.String(object.documentationUrl) : isSet(object.documentation_url) ? globalThis.String(object.documentation_url) : "", capabilities: isSet(object.capabilities) ? AgentCapabilities.fromJSON(object.capabilities) : void 0, securitySchemes: isObject(object.securitySchemes) ? globalThis.Object.entries(object.securitySchemes).reduce( (acc, [key, value]) => { acc[key] = SecurityScheme.fromJSON(value); return acc; }, {} ) : isObject(object.security_schemes) ? globalThis.Object.entries(object.security_schemes).reduce( (acc, [key, value]) => { acc[key] = SecurityScheme.fromJSON(value); return acc; }, {} ) : {}, security: globalThis.Array.isArray(object?.security) ? object.security.map((e) => Security.fromJSON(e)) : [], defaultInputModes: globalThis.Array.isArray(object?.defaultInputModes) ? object.defaultInputModes.map((e) => globalThis.String(e)) : globalThis.Array.isArray(object?.default_input_modes) ? object.default_input_modes.map((e) => globalThis.String(e)) : [], defaultOutputModes: globalThis.Array.isArray(object?.defaultOutputModes) ? object.defaultOutputModes.map((e) => globalThis.String(e)) : globalThis.Array.isArray(object?.default_output_modes) ? object.default_output_modes.map((e) => globalThis.String(e)) : [], skills: globalThis.Array.isArray(object?.skills) ? object.skills.map((e) => AgentSkill.fromJSON(e)) : [], supportsAuthenticatedExtendedCard: isSet(object.supportsAuthenticatedExtendedCard) ? globalThis.Boolean(object.supportsAuthenticatedExtendedCard) : isSet(object.supports_authenticated_extended_card) ? globalThis.Boolean(object.supports_authenticated_extended_card) : false, signatures: globalThis.Array.isArray(object?.signatures) ? object.signatures.map((e) => AgentCardSignature.fromJSON(e)) : [] }; }, toJSON(message) { const obj = {}; if (message.protocolVersion !== "") { obj.protocolVersion = message.protocolVersion; } if (message.name !== "") { obj.name = message.name; } if (message.description !== "") { obj.description = message.description; } if (message.url !== "") { obj.url = message.url; } if (message.preferredTransport !== "") { obj.preferredTransport = message.preferredTransport; } if (message.additionalInterfaces?.length) { obj.additionalInterfaces = message.additionalInterfaces.map((e) => AgentInterface.toJSON(e)); } if (message.provider !== void 0) { obj.provider = AgentProvider.toJSON(message.provider); } if (message.version !== "") { obj.version = message.version; } if (message.documentationUrl !== "") { obj.documentationUrl = message.documentationUrl; } if (message.capabilities !== void 0) { obj.capabilities = AgentCapabilities.toJSON(message.capabilities); } if (message.securitySchemes) { const entries = globalThis.Object.entries(message.securitySchemes); if (entries.length > 0) { obj.securitySchemes = {}; entries.forEach(([k, v]) => { obj.securitySchemes[k] = SecurityScheme.toJSON(v); }); } } if (message.security?.length) { obj.security = message.security.map((e) => Security.toJSON(e)); } if (message.defaultInputModes?.length) { obj.defaultInputModes = message.defaultInputModes; } if (message.defaultOutputModes?.length) { obj.defaultOutputModes = message.defaultOutputModes; } if (message.skills?.length) { obj.skills = message.skills.map((e) => AgentSkill.toJSON(e)); } if (message.supportsAuthenticatedExtendedCard !== false) { obj.supportsAuthenticatedExtendedCard = message.supportsAuthenticatedExtendedCard; } if (message.signatures?.length) { obj.signatures = message.signatures.map((e) => AgentCardSignature.toJSON(e)); } return obj; } }; var AgentProvider = { fromJSON(object) { return { url: isSet(object.url) ? globalThis.String(object.url) : "", organization: isSet(object.organization) ? globalThis.String(object.organization) : "" }; }, toJSON(message) { const obj = {}; if (message.url !== "") { obj.url = message.url; } if (message.organization !== "") { obj.organization = message.organization; } return obj; } }; var AgentCapabilities = { fromJSON(object) { return { streaming: isSet(object.streaming) ? globalThis.Boolean(object.streaming) : false, pushNotifications: isSet(object.pushNotifications) ? globalThis.Boolean(object.pushNotifications) : isSet(object.push_notifications) ? globalThis.Boolean(object.push_notifications) : false, extensions: globalThis.Array.isArray(object?.extensions) ? object.extensions.map((e) => AgentExtension.fromJSON(e)) : [] }; }, toJSON(message) { const obj = {}; if (message.streaming !== false) { obj.streaming = message.streaming; } if (message.pushNotifications !== false) { obj.pushNotifications = message.pushNotifications; } if (message.extensions?.length) { obj.extensions = message.extensions.map((e) => AgentExtension.toJSON(e)); } return obj; } }; var AgentExtension = { fromJSON(object) { return { uri: isSet(object.uri) ? globalThis.String(object.uri) : "", description: isSet(object.description) ? globalThis.String(object.description) : "", required: isSet(object.required) ? globalThis.Boolean(object.required) : false, params: isObject(object.params) ? object.params : void 0 }; }, toJSON(message) { const obj = {}; if (message.uri !== "") { obj.uri = message.uri; } if (message.description !== "") { obj.description = message.description; } if (message.required !== false) { obj.required = message.required; } if (message.params !== void 0) { obj.params = message.params; } return obj; } }; var AgentSkill = { fromJSON(object) { return { id: isSet(object.id) ? globalThis.String(object.id) : "", name: isSet(object.name) ? globalThis.String(object.name) : "", description: isSet(object.description) ? globalThis.String(object.description) : "", tags: globalThis.Array.isArray(object?.tags) ? object.tags.map((e) => globalThis.String(e)) : [], examples: globalThis.Array.isArray(object?.examples) ? object.examples.map((e) => globalThis.String(e)) : [], inputModes: globalThis.Array.isArray(object?.inputModes) ? object.inputModes.map((e) => globalThis.String(e)) : globalThis.Array.isArray(object?.input_modes) ? object.input_modes.map((e) => globalThis.String(e)) : [], outputModes: globalThis.Array.isArray(object?.outputModes) ? object.outputModes.map((e) => globalThis.String(e)) : globalThis.Array.isArray(object?.output_modes) ? object.output_modes.map((e) => globalThis.String(e)) : [], security: globalThis.Array.isArray(object?.security) ? object.security.map((e) => Security.fromJSON(e)) : [] }; }, toJSON(message) { const obj = {}; if (message.id !== "") { obj.id = message.id; } if (message.name !== "") { obj.name = message.name; } if (message.description !== "") { obj.description = message.description; } if (message.tags?.length) { obj.tags = message.tags; } if (message.examples?.length) { obj.examples = message.examples; } if (message.inputModes?.length) { obj.inputModes = message.inputModes; } if (message.outputModes?.length) { obj.outputModes = message.outputModes; } if (message.security?.length) { obj.security = message.security.map((e) => Security.toJSON(e)); } return obj; } }; var AgentCardSignature = { fromJSON(object) { return { protected: isSet(object.protected) ? globalThis.String(object.protected) : "", signature: isSet(object.signature) ? globalThis.String(object.signature) : "", header: isObject(object.header) ? object.header : void 0 }; }, toJSON(message) { const obj = {}; if (message.protected !== "") { obj.protected = message.protected; } if (message.signature !== "") { obj.signature = message.signature; } if (message.header !== void 0) { obj.header = message.header; } return obj; } }; var TaskPushNotificationConfig = { fromJSON(object) { return { name: isSet(object.name) ? globalThis.String(object.name) : "", pushNotificationConfig: isSet(object.pushNotificationConfig) ? PushNotificationConfig.fromJSON(object.pushNotificationConfig) : isSet(object.push_notification_config) ? PushNotificationConfig.fromJSON(object.push_notification_config) : void 0 }; }, toJSON(message) { const obj = {}; if (message.name !== "") { obj.name = message.name; } if (message.pushNotificationConfig !== void 0) { obj.pushNotificationConfig = PushNotificationConfig.toJSON(message.pushNotificationConfig); } return obj; } }; var StringList = { fromJSON(object) { return { list: globalThis.Array.isArray(object?.list) ? object.list.map((e) => globalThis.String(e)) : [] }; }, toJSON(message) { const obj = {}; if (message.list?.length) { obj.list = message.list; } return obj; } }; var Security = { fromJSON(object) { return { schemes: isObject(object.schemes) ? globalThis.Object.entries(object.schemes).reduce( (acc, [key, value]) => { acc[key] = StringList.fromJSON(value); return acc; }, {} ) : {} }; }, toJSON(message) { const obj = {}; if (message.schemes) { const entries = globalThis.Object.entries(message.schemes); if (entries.length > 0) { obj.schemes = {}; entries.forEach(([k, v]) => { obj.schemes[k] = StringList.toJSON(v); }); } } return obj; } }; var SecurityScheme = { fromJSON(object) { return { scheme: isSet(object.apiKeySecurityScheme) ? { $case: "apiKeySecurityScheme", value: APIKeySecurityScheme.fromJSON(object.apiKeySecurityScheme) } : isSet(object.api_key_security_scheme) ? { $case: "apiKeySecurityScheme", value: APIKeySecurityScheme.fromJSON(object.api_key_security_scheme) } : isSet(object.httpAuthSecurityScheme) ? { $case: "httpAuthSecurityScheme", value: HTTPAuthSecurityScheme.fromJSON(object.httpAuthSecurityScheme) } : isSet(object.http_auth_security_scheme) ? { $case: "httpAuthSecurityScheme", value: HTTPAuthSecurityScheme.fromJSON(object.http_auth_security_scheme) } : isSet(object.oauth2SecurityScheme) ? { $case: "oauth2SecurityScheme", value: OAuth2SecurityScheme.fromJSON(object.oauth2SecurityScheme) } : isSet(object.oauth2_security_scheme) ? { $case: "oauth2SecurityScheme", value: OAuth2SecurityScheme.fromJSON(object.oauth2_security_scheme) } : isSet(object.openIdConnectSecurityScheme) ? { $case: "openIdConnectSecurityScheme", value: OpenIdConnectSecurityScheme.fromJSON(object.openIdConnectSecurityScheme) } : isSet(object.open_id_connect_security_scheme) ? { $case: "openIdConnectSecurityScheme", value: OpenIdConnectSecurityScheme.fromJSON(object.open_id_connect_security_scheme) } : isSet(object.mtlsSecurityScheme) ? { $case: "mtlsSecurityScheme", value: MutualTlsSecurityScheme.fromJSON(object.mtlsSecurityScheme) } : isSet(object.mtls_security_scheme) ? { $case: "mtlsSecurityScheme", value: MutualTlsSecurityScheme.fromJSON(object.mtls_security_scheme) } : void 0 }; }, toJSON(message) { const obj = {}; if (message.scheme?.$case === "apiKeySecurityScheme") { obj.apiKeySecurityScheme = APIKeySecurityScheme.toJSON(message.scheme.value); } else if (message.scheme?.$case === "httpAuthSecurityScheme") { obj.httpAuthSecurityScheme = HTTPAuthSecurityScheme.toJSON(message.scheme.value); } else if (message.scheme?.$case === "oauth2SecurityScheme") { obj.oauth2SecurityScheme = OAuth2SecurityScheme.toJSON(message.scheme.value); } else if (message.scheme?.$case === "openIdConnectSecurityScheme") { obj.openIdConnectSecurityScheme = OpenIdConnectSecurityScheme.toJSON(message.scheme.value); } else if (message.scheme?.$case === "mtlsSecurityScheme") { obj.mtlsSecurityScheme = MutualTlsSecurityScheme.toJSON(message.scheme.value); } return obj; } }; var APIKeySecurityScheme = { fromJSON(object) { return { description: isSet(object.description) ? globalThis.String(object.description) : "", location: isSet(object.location) ? globalThis.String(object.location) : "", name: isSet(object.name) ? globalThis.String(object.name) : "" }; }, toJSON(message) { const obj = {}; if (message.description !== "") { obj.description = message.description; } if (message.location !== "") { obj.location = message.location; } if (message.name !== "") { obj.name = message.name; } return obj; } }; var HTTPAuthSecurityScheme = { fromJSON(object) { return { description: isSet(object.description) ? globalThis.String(object.description) : "", scheme: isSet(object.scheme) ? globalThis.String(object.scheme) : "", bearerFormat: isSet(object.bearerFormat) ? globalThis.String(object.bearerFormat) : isSet(object.bearer_format) ? globalThis.String(object.bearer_format) : "" }; }, toJSON(message) { const obj = {}; if (message.description !== "") { obj.description = message.description; } if (message.scheme !== "") { obj.scheme = message.scheme; } if (message.bearerFormat !== "") { obj.bearerFormat = message.bearerFormat; } return obj; } }; var OAuth2SecurityScheme = { fromJSON(object) { return { description: isSet(object.description) ? globalThis.String(object.description) : "", flows: isSet(object.flows) ? OAuthFlows.fromJSON(object.flows) : void 0, oauth2MetadataUrl: isSet(object.oauth2MetadataUrl) ? globalThis.String(object.oauth2MetadataUrl) : isSet(object.oauth2_metadata_url) ? globalThis.String(object.oauth2_metadata_url) : "" }; }, toJSON(message) { const obj = {}; if (message.description !== "") { obj.description = message.description; } if (message.flows !== void 0) { obj.flows = OAuthFlows.toJSON(message.flows); } if (message.oauth2MetadataUrl !== "") { obj.oauth2MetadataUrl = message.oauth2MetadataUrl; } return obj; } }; var OpenIdConnectSecurityScheme = { fromJSON(object) { return { description: isSet(object.description) ? globalThis.String(object.description) : "", openIdConnectUrl: isSet(object.openIdConnectUrl) ? globalThis.String(object.openIdConnectUrl) : isSet(object.open_id_connect_url) ? globalThis.String(object.open_id_connect_url) : "" }; }, toJSON(message) { const obj = {}; if (message.description !== "") { obj.description = message.description; } if (message.openIdConnectUrl !== "") { obj.openIdConnectUrl = message.openIdConnectUrl; } return obj; } }; var MutualTlsSecurityScheme = { fromJSON(object) { return { description: isSet(object.description) ? globalThis.String(object.description) : "" }; }, toJSON(message) { const obj = {}; if (message.description !== "") { obj.description = message.description; } return obj; } }; var OAuthFlows = { fromJSON(object) { return { flow: isSet(object.authorizationCode) ? { $case: "authorizationCode", value: AuthorizationCodeOAuthFlow.fromJSON(object.authorizationCode) } : isSet(object.authorization_code) ? { $case: "authorizationCode", value: AuthorizationCodeOAuthFlow.fromJSON(object.authorization_code) } : isSet(object.clientCredentials) ? { $case: "clientCredentials", value: ClientCredentialsOAuthFlow.fromJSON(object.clientCredentials) } : isSet(object.client_credentials) ? { $case: "clientCredentials", value: ClientCredentialsOAuthFlow.fromJSON(object.client_credentials) } : isSet(object.implicit) ? { $case: "implicit", value: ImplicitOAuthFlow.fromJSON(object.implicit) } : isSet(object.password) ? { $case: "password", value: PasswordOAuthFlow.fromJSON(object.password) } : void 0 }; }, toJSON(message) { const obj = {}; if (message.flow?.$case === "authorizationCode") { obj.authorizationCode = AuthorizationCodeOAuthFlow.toJSON(message.flow.value); } else if (message.flow?.$case === "clientCredentials") { obj.clientCredentials = ClientCredentialsOAuthFlow.toJSON(message.flow.value); } else if (message.flow?.$case === "implicit") { obj.implicit = ImplicitOAuthFlow.toJSON(message.flow.value); } else if (message.flow?.$case === "password") { obj.password = PasswordOAuthFlow.toJSON(message.flow.value); } return obj; } }; var AuthorizationCodeOAuthFlow = { fromJSON(object) { return { authorizationUrl: isSet(object.authorizationUrl) ? globalThis.String(object.authorizationUrl) : isSet(object.authorization_url) ? globalThis.String(object.authorization_url) : "", tokenUrl: isSet(object.tokenUrl) ? globalThis.String(object.tokenUrl) : isSet(object.token_url) ? globalThis.String(object.token_url) : "", refreshUrl: isSet(object.refreshUrl) ? globalThis.String(object.refreshUrl) : isSet(object.refresh_url) ? globalThis.String(object.refresh_url) : "", scopes: isObject(object.scopes) ? globalThis.Object.entries(object.scopes).reduce( (acc, [key, value]) => { acc[key] = globalThis.String(value); return acc; }, {} ) : {} }; }, toJSON(message) { const obj = {}; if (message.authorizationUrl !== "") { obj.authorizationUrl = message.authorizationUrl; } if (message.tokenUrl !== "") { obj.tokenUrl = message.tokenUrl; } if (message.refreshUrl !== "") { obj.refreshUrl = message.refreshUrl; } if (message.scopes) { const entries = globalThis.Object.entries(message.scopes); if (entries.length > 0) { obj.scopes = {}; entries.forEach(([k, v]) => { obj.scopes[k] = v; }); } } return obj; } }; var ClientCredentialsOAuthFlow = { fromJSON(object) { return { tokenUrl: isSet(object.tokenUrl) ? globalThis.String(object.tokenUrl) : isSet(object.token_url) ? globalThis.String(object.token_url) : "", refreshUrl: isSet(object.refreshUrl) ? globalThis.String(object.refreshUrl) : isSet(object.refresh_url) ? globalThis.String(object.refresh_url) : "", scopes: isObject(object.scopes) ? globalThis.Object.entries(object.scopes).reduce( (acc, [key, value]) => { acc[key] = globalThis.String(value); return acc; }, {} ) : {} }; }, toJSON(message) { const obj = {}; if (message.tokenUrl !== "") { obj.tokenUrl = message.tokenUrl; } if (message.refreshUrl !== "") { obj.refreshUrl = message.refreshUrl; } if (message.scopes) { const entries = globalThis.Object.entries(message.scopes); if (entries.length > 0) { obj.scopes = {}; entries.forEach(([k, v]) => { obj.scopes[k] = v; }); } } return obj; } }; var ImplicitOAuthFlow = { fromJSON(object) { return { authorizationUrl: isSet(object.authorizationUrl) ? globalThis.String(object.authorizationUrl) : isSet(object.authorization_url) ? globalThis.String(object.authorization_url) : "", refreshUrl: isSet(object.refreshUrl) ? globalThis.String(object.refreshUrl) : isSet(object.refresh_url) ? globalThis.String(object.refresh_url) : "", scopes: isObject(object.scopes) ? globalThis.Object.entries(object.scopes).reduce( (acc, [key, value]) => { acc[key] = globalThis.String(value); return acc; }, {} ) : {} }; }, toJSON(message) { const obj = {}; if (message.authorizationUrl !== "") { obj.authorizationUrl = message.authorizationUrl; } if (message.refreshUrl !== "") { obj.refreshUrl = message.refreshUrl; } if (message.scopes) { const entries = globalThis.Object.entries(message.scopes); if (entries.length > 0) { obj.scopes = {}; entries.forEach(([k, v]) => { obj.scopes[k] = v; }); } } return obj; } }; var PasswordOAuthFlow = { fromJSON(object) { return { tokenUrl: isSet(object.tokenUrl) ? globalThis.String(object.tokenUrl) : isSet(object.token_url) ? globalThis.String(object.token_url) : "", refreshUrl: isSet(object.refreshUrl) ? globalThis.String(object.refreshUrl) : isSet(object.refresh_url) ? globalThis.String(object.refresh_url) : "", scopes: isObject(object.scopes) ? globalThis.Object.entries(object.scopes).reduce( (acc, [key, value]) => { acc[key] = globalThis.String(value); return acc; }, {} ) : {} }; }, toJSON(message) { const obj = {}; if (message.tokenUrl !== "") { obj.tokenUrl = message.tokenUrl; } if (message.refreshUrl !== "") { obj.refreshUrl = message.refreshUrl; } if (message.scopes) { const entries = globalThis.Object.entries(message.scopes); if (entries.length > 0) { obj.scopes = {}; entries.forEach(([k, v]) => { obj.scopes[k] = v; }); } } return obj; } }; var SendMessageRequest = { fromJSON(object) { return { request: isSet(object.message) ? Message.fromJSON(object.message) : isSet(object.request) ? Message.fromJSON(object.request) : void 0, configuration: isSet(object.configuration) ? SendMessageConfiguration.fromJSON(object.configuration) : void 0, metadata: isObject(object.metadata) ? object.metadata : void 0 }; }, toJSON(message) { const obj = {}; if (message.request !== void 0) { obj.message = Message.toJSON(message.request); } if (message.configuration !== void 0) { obj.configuration = SendMessageConfiguration.toJSON(message.configuration); } if (message.metadata !== void 0) { obj.metadata = message.metadata; } return obj; } }; var SendMessageResponse = { fromJSON(object) { return { payload: isSet(object.task) ? { $case: "task", value: Task.fromJSON(object.task) } : isSet(object.message) ? { $case: "msg", value: Message.fromJSON(object.message) } : isSet(object.msg) ? { $case: "msg", value: Message.fromJSON(object.msg) } : void 0 }; }, toJSON(message) { const obj = {}; if (message.payload?.$case === "task") { obj.task = Task.toJSON(message.payload.value); } else if (message.payload?.$case === "msg") { obj.message = Message.toJSON(message.payload.value); } return obj; } }; var StreamResponse = { fromJSON(object) { return { payload: isSet(object.task) ? { $case: "task", value: Task.fromJSON(object.task) } : isSet(object.message) ? { $case: "msg", value: Message.fromJSON(object.message) } : isSet(object.msg) ? { $case: "msg", value: Message.fromJSON(object.msg) } : isSet(object.statusUpdate) ? { $case: "statusUpdate", value: TaskStatusUpdateEvent.fromJSON(object.statusUpdate) } : isSet(object.status_update) ? { $case: "statusUpdate", value: TaskStatusUpdateEvent.fromJSON(object.status_update) } : isSet(object.artifactUpdate) ? { $case: "artifactUpdate", value: TaskArtifactUpdateEvent.fromJSON(object.artifactUpdate) } : isSet(object.artifact_update) ? { $case: "artifactUpdate", value: TaskArtifactUpdateEvent.fromJSON(object.artifact_update) } : void 0 }; }, toJSON(message) { const obj = {}; if (message.payload?.$case === "task") { obj.task = Task.toJSON(message.payload.value); } else if (message.payload?.$case === "msg") { obj.message = Message.toJSON(message.payload.value); } else if (message.payload?.$case === "statusUpdate") { obj.statusUpdate = TaskStatusUpdateEvent.toJSON(message.payload.value); } else if (message.payload?.$case === "artifactUpdate") { obj.artifactUpdate = TaskArtifactUpdateEvent.toJSON(message.payload.value); } return obj; } }; var ListTaskPushNotificationConfigResponse = { fromJSON(object) { return { configs: globalThis.Array.isArray(object?.configs) ? object.configs.map((e) => TaskPushNotificationConfig.fromJSON(e)) : [], nextPageToken: isSet(object.nextPageToken) ? globalThis.String(object.nextPageToken) : isSet(object.next_page_token) ? globalThis.String(object.next_page_token) : "" }; }, toJSON(message) { const obj = {}; if (message.configs?.length) { obj.configs = message.configs.map((e) => TaskPushNotificationConfig.toJSON(e)); } if (message.nextPageToken !== "") { obj.nextPageToken = message.nextPageToken; } return obj; } }; function bytesFromBase64(b64) { return Uint8Array.from(globalThis.Buffer.from(b64, "base64")); } function base64FromBytes(arr) { return globalThis.Buffer.from(arr).toString("base64"); } function isObject(value) { return typeof value === "object" && value !== null; } function isSet(value) { return value !== null && value !== void 0; } // src/server/error.ts var A2AError = class _A2AError extends Error { code; data; taskId; // Optional task ID context constructor(code, message, data, taskId) { super(message); this.name = "A2AError"; this.code = code; this.data = data; this.taskId = taskId; } /** * Formats the error into a standard JSON-RPC error object structure. */ toJSONRPCError() { const errorObject = { code: this.code, message: this.message }; if (this.data !== void 0) { errorObject.data = this.data; } return errorObject; } // Static factory methods for common errors static parseError(message, data) { return new _A2AError(-32700, message, data); } static invalidRequest(message, data) { return new _A2AError(-32600, message, data); } static methodNotFound(method) { return new _A2AError(-32601, `Method not found: ${method}`); } static invalidParams(message, data) { return new _A2AError(-32602, message, data); } static internalError(message, data) { return new _A2AError(-32603, message, data); } static taskNotFound(taskId) { return new _A2AError(-32001, `Task not found: ${taskId}`, void 0, taskId); } static taskNotCancelable(taskId) { return new _A2AError(-32002, `Task not cancelable: ${taskId}`, void 0, taskId); } static pushNotificationNotSupported() { return new _A2AError(-32003, "Push Notification is not supported"); } static unsupportedOperation(operation) { return new _A2AError(-32004, `Unsupported operation: ${operation}`); } static authenticatedExtendedCardNotConfigured() { return new _A2AError(-32007, `Extended card not configured.`); } }; // src/types/converters/id_decoding.ts var CONFIG_REGEX = /^tasks\/([^/]+)\/pushNotificationConfigs\/([^/]+)$/; var TASK_ONLY_REGEX = /^tasks\/([^/]+)(?:\/|$)/; var extractTaskId = (name) => { const match = name.match(TASK_ONLY_REGEX); if (!match) { throw A2AError.invalidParams(`Invalid or missing task ID in: "${name}"`); } return match[1]; }; var generateTaskName = (taskId) => { return `tasks/${taskId}`; }; var extractTaskAndPushNotificationConfigId = (name) => { const match = name.match(CONFIG_REGEX); if (!match) { throw A2AError.invalidParams(`Invalid or missing config ID in: "${name}"`); } return { taskId: match[1], configId: match[2] }; }; var generatePushNotificationConfigName = (taskId, configId) => { return `tasks/${taskId}/pushNotificationConfigs/${configId}`; }; // src/types/converters/from_proto.ts var FromProto = class _FromProto { static taskQueryParams(request) { return { id: extractTaskId(request.name), historyLength: request.historyLength }; } static taskIdParams(request) { return { id: extractTaskId(request.name) }; } static getTaskPushNotificationConfigParams(request) { const { taskId, configId } = extractTaskAndPushNotificationConfigId(request.name); return { id: taskId, pushNotificationConfigId: configId }; } static listTaskPushNotificationConfigParams(request) { return { id: extractTaskId(request.parent) }; } static createTaskPushNotificationConfig(request) { if (!request.config?.pushNotificationConfig) { throw A2AError.invalidParams( "Request must include a `config` object with a `pushNotificationConfig`" ); } return { taskId: extractTaskId(request.parent), pushNotificationConfig: _FromProto.pushNotificationConfig( request.config.pushNotificationConfig ) }; } static deleteTaskPushNotificationConfigParams(request) { const { taskId, configId } = extractTaskAndPushNotificationConfigId(request.name); return { id: taskId, pushNotificationConfigId: configId }; } static message(message) { if (!message) { return void 0; } return { kind: "message", messageId: message.messageId, parts: message.content.map((p) => _FromProto.part(p)), contextId: message.contextId || void 0, taskId: message.taskId || void 0, role: _FromProto.role(message.role), metadata: message.metadata, extensions: message.extensions }; } static role(role) { switch (role) { case 2 /* ROLE_AGENT */: return "agent"; case 1 /* ROLE_USER */: return "user"; default: throw A2AError.invalidParams(`Invalid role: ${role}`); } } static messageSendConfiguration(configuration) { if (!configuration) { return void 0; } return { blocking: configuration.blocking, acceptedOutputModes: configuration.acceptedOutputModes, pushNotificationConfig: _FromProto.pushNotificationConfig(configuration.pushNotification) }; } static pushNotificationConfig(config) { if (!config) { return void 0; } return { id: config.id, url: config.url, token: config.token || void 0, authentication: _FromProto.pushNotificationAuthenticationInfo(config.authentication) }; } static pushNotificationAuthenticationInfo(authInfo) { if (!authInfo) { return void 0; } return { schemes: authInfo.schemes, credentials: authInfo.credentials }; } static part(part) { if (part.part?.$case === "text") { return { kind: "text", text: part.part.value }; } if (part.part?.$case === "file") { const filePart = part.part.value; if (filePart.file?.$case === "fileWithUri") { return { kind: "file", file: { uri: filePart.file.value, mimeType: filePart.mimeType } }; } else if (filePart.file?.$case === "fileWithBytes") { return { kind: "file", file: { bytes: filePart.file.value.toString("base64"), mimeType: filePart.mimeType } }; } throw A2AError.invalidParams("Invalid file part type"); } if (part.part?.$case === "data") { return { kind: "data", data: part.part.value.data }; } throw A2AError.invalidParams("Invalid part type"); } static messageSendParams(request) { return { message: _FromProto.message(request.request), configuration: _FromProto.messageSendConfiguration(request.configuration), metadata: request.metadata }; } static sendMessageResult(response) { if (response.payload?.$case === "task") { return _FromProto.task(response.payload.value); } else if (response.payload?.$case === "msg") { return _FromProto.message(response.payload.value); } throw A2AError.invalidParams("Invalid SendMessageResponse: missing result"); } static task(task) { return { kind: "task", id: task.id, status: _FromProto.taskStatus(task.status), contextId: task.contextId, artifacts: task.artifacts?.map((a) => _FromProto.artifact(a)), history: task.history?.map((h) => _FromProto.message(h)), metadata: task.metadata }; } static taskStatus(status) { return { message: _FromProto.message(status.update), state: _FromProto.taskState(status.state), timestamp: status.timestamp }; } static taskState(state) { switch (state) { case 1 /* TASK_STATE_SUBMITTED */: return "submitted"; case 2 /* TASK_STATE_WORKING */: return "working"; case 6 /* TASK_STATE_INPUT_REQUIRED */: return "input-required"; case 3 /* TASK_STATE_COMPLETED */: return "completed"; case 5 /* TASK_STATE_CANCELLED */: return "canceled"; case 4 /* TASK_STATE_FAILED */: return "failed"; case 7 /* TASK_STATE_REJECTED */: return "rejected"; case 8 /* TASK_STATE_AUTH_REQUIRED */: return "auth-required"; case 0 /* TASK_STATE_UNSPECIFIED */: return "unknown"; default: throw A2AError.invalidParams(`Invalid task state: ${state}`); } } static artifact(artifact) { return { artifactId: artifact.artifactId, name: artifact.name || void 0, description: artifact.description || void 0, parts: artifact.parts.map((p) => _FromProto.part(p)), metadata: artifact.metadata }; } static taskPushNotificationConfig(request) { return { taskId: extractTaskId(request.name), pushNotificationConfig: _FromProto.pushNotificationConfig(request.pushNotificationConfig) }; } static listTaskPushNotificationConfig(request) { return request.configs.map((c) => _FromProto.taskPushNotificationConfig(c)); } static agentCard(agentCard) { return { additionalInterfaces: agentCard.additionalInterfaces?.map((i) => _FromProto.agentInterface(i)), capabilities: agentCard.capabilities ? _FromProto.agentCapabilities(agentCard.capabilities) : {}, defaultInputModes: agentCard.defaultInputModes, defaultOutputModes: agentCard.defaultOutputModes, description: agentCard.description, documentationUrl: agentCard.documentationUrl || void 0, name: agentCard.name, preferredTransport: agentCard.preferredTransport, provider: agentCard.provider ? _FromProto.agentProvider(agentCard.provider) : void 0, protocolVersion: agentCard.protocolVersion, security: agentCard.security?.map((s) => _FromProto.security(s)), securitySchemes: agentCard.securitySchemes ? Object.fromEntries( Object.entries(agentCard.securitySchemes).map(([key, value]) => [ key, _FromProto.securityScheme(value) ]) ) : {}, skills: agentCard.skills.map((s) => _FromProto.skills(s)), signatures: agentCard.signatures?.map((s) => _FromProto.agentCardSignature(s)), supportsAuthenticatedExtendedCard: agentCard.supportsAuthenticatedExtendedCard, url: agentCard.url, version: agentCard.version }; } static agentCapabilities(capabilities) { return { extensions: capabilities.extensions?.map((e) => _FromProto.agentExtension(e)), pushNotifications: capabilities.pushNotifications, streaming: capabilities.streaming }; } static agentExtension(extension) { return { uri: extension.uri, description: extension.description || void 0, required: extension.required, params: extension.params }; } static agentInterface(intf) { return { transport: intf.transport, url: intf.url }; } static agentProvider(provider) { return { organization: provider.organization, url: provider.url }; } static security(security) { return Object.fromEntries( Object.entries(security.schemes)?.map(([key, value]) => [key, value.list]) ); } static securityScheme(securitySchemes) { switch (securitySchemes.scheme?.$case) { case "apiKeySecurityScheme": return { type: "apiKey", name: securitySchemes.scheme.value.name, in: securitySchemes.scheme.value.location, description: securitySchemes.scheme.value.description || void 0 }; case "httpAuthSecurityScheme": return { type: "http", scheme: securitySchemes.scheme.value.scheme, bearerFormat: securitySchemes.scheme.value.bearerFormat || void 0, description: securitySchemes.scheme.value.description || void 0 }; case "mtlsSecurityScheme": return { type: "mutualTLS", description: securitySchemes.scheme.value.description || void 0 }; case "oauth2SecurityScheme": return { type: "oauth2", description: securitySchemes.scheme.value.description || void 0, flows: _FromProto.oauthFlows(securitySchemes.scheme.value.flows), oauth2MetadataUrl: securitySchemes.scheme.value.oauth2MetadataUrl || void 0 }; case "openIdConnectSecurityScheme": return { type: "openIdConnect", description: securitySchemes.scheme.value.description || void 0, openIdConnectUrl: securitySchemes.scheme.value.openIdConnectUrl }; default: throw A2AError.internalError(`Unsupported security scheme type`); } } static oauthFlows(flows) { switch (flows.flow?.$case) { case "implicit": return { implicit: { authorizationUrl: flows.flow.value.authorizationUrl, scopes: flows.flow.value.scopes, refreshUrl: flows.flow.value.refreshUrl || void 0 } }; case "password": return { password: { refreshUrl: flows.flow.value.refreshUrl || void 0, scopes: flows.flow.value.scopes, tokenUrl: flows.flow.value.tokenUrl } }; case "authorizationCode": return { authorizationCode: { refreshUrl: flows.flow.value.refreshUrl || void 0, authorizationUrl: flows.flow.value.authorizationUrl, scopes: flows.flow.value.scopes, tokenUrl: flows.flow.value.tokenUrl } }; case "clientCredentials": return { clientCredentials: { refreshUrl: flows.flow.value.refreshUrl || void 0, scopes: flows.flow.value.scopes, tokenUrl: flows.flow.value.tokenUrl } }; default: throw A2AError.internalError(`Unsupported OAuth flows`); } } static skills(skill) { return { id: skill.id, name: skill.name, description: skill.description, tags: skill.tags, examples: skill.examples, inputModes: skill.inputModes, outputModes: skill.outputModes, security: skill.security?.map((s) => _FromProto.security(s)) }; } static agentCardSignature(signatures) { return { protected: signatures.protected, signature: signatures.signature, header: signatures.header }; } static taskStatusUpdateEvent(event) { return { kind: "status-update", taskId: event.taskId, status: _FromProto.taskStatus(event.status), contextId: event.contextId, metadata: event.metadata, final: event.final }; } static taskArtifactUpdateEvent(event) { return { kind: "artifact-update", taskId: event.taskId, artifact: _FromProto.artifact(event.artifact), contextId: event.contextId, metadata: event.metadata, lastChunk: event.lastChunk }; } static messageStreamResult(event) { switch (event.payload?.$case) { case "msg": return _FromProto.message(event.payload.value); case "task": return _FromProto.task(event.payload.value); case "statusUpdate": return _FromProto.taskStatusUpdateEvent(event.payload.value); case "artifactUpdate": return _FromProto.taskArtifactUpdateEvent(event.payload.value); default: throw A2AError.internalError("Invalid event type in StreamResponse"); } } }; // src/client/card-resolver.ts var DefaultAgentCardResolver = class { constructor(options) { this.options = options; } /** * Fetches the agent card based on provided base URL and path. * Path is selected in the following order: * 1) path parameter * 2) path from options * 3) .well-known/agent-card.json */ async resolve(baseUrl, path) { const agentCardUrl = new URL(path ?? this.options?.path ?? AGENT_CARD_PATH, baseUrl); const response = await this.fetchImpl(agentCardUrl); if (!response.ok) { throw new Error(`Failed to fetch Agent Card from ${agentCardUrl}: ${response.status}`); } const rawCard = await response.json(); return this.normalizeAgentCard(rawCard); } fetchImpl(...args) { if (this.options?.fetchImpl) { return this.options.fetchImpl(...args); } return fetch(...args); } /* * In the v0.3.0 specification, there was a structural drift between the JSON Schema data model * and the Protobuf-based data model for AgentCards. * The JSON Schema format uses a `"type"` discriminator (e.g., `{"type": "openIdConnect"}`), * while the Protobuf JSON representation uses the `oneof` field name as the discriminator * (e.g., `{"openIdConnectSecurityScheme": {...}}`). * * The A2A SDK internal logic expects the JSON Schema-based format. This fallback detection * allows us to parse cards served by endpoints returning the Protobuf JSON structure by * identifying the lack of the "type" field in security schemes or the presence of the * "schemes" wrapper in security entries, and normalizing it before use. */ normalizeAgentCard(card) { if (this.isProtoAgentCard(card)) { const parsedProto = AgentCard.fromJSON(card); return FromProto.agentCard(parsedProto); } return card; } isProtoAgentCard(card) { if (!card || typeof card !== "object") return false; const c = card; if (this.hasProtoSecurity(c.security)) return true; if (this.hasProtoSecuritySchemes(c.securitySchemes)) return true; if (Array.isArray(c.skills)) { return c.skills.some( (skill) => skill && typeof skill === "object" && this.hasProtoSecurity(skill.security) ); } return false; } hasProtoSecurity(securityArray) { if (Array.isArray(securityArray) && securityArray.length > 0) { const first = securityArray[0]; return first && typeof first === "object" && "schemes" in first; } return false; } hasProtoSecuritySchemes(securitySchemes) { if (securitySchemes && typeof securitySchemes === "object") { const schemes = Object.values(securitySchemes); if (schemes.length > 0) { const first = schemes[0]; return first && typeof first === "object" && !("type" in first); } } return false; } }; var AgentCardResolver = { default: new DefaultAgentCardResolver() }; // src/client/multitransport-client.ts var Client = class { constructor(transport, agentCard, config) { this.transport = transport; this.agentCard = agentCard; this.config = config; } /** * If the current agent card supports the extended feature, it will try to fetch the extended agent card from the server, * Otherwise it will return the current agent card value. */ async getAgentCard(options) { if (this.agentCard.supportsAuthenticatedExtendedCard) { this.agentCard = await this.executeWithInterceptors( { method: "getAgentCard" }, options, (_, options2) => this.transport.getExtendedAgentCard(options2) ); } return this.agentCard; } /** * Sends a message to an agent to initiate a new interaction or to continue an existing one. * Uses blocking mode by default. */ sendMessage(params, options) { params = this.applyClientConfig({ params, blocking: !(this.config?.polling ?? false) }); return this.executeWithInterceptors( { method: "sendMessage", value: params }, options, this.transport.sendMessage.bind(this.transport) ); } /** * Sends a message to an agent to initiate/continue a task AND subscribes the client to real-time updates for that task. * Performs fallback to non-streaming if not supported by the agent. */ async *sendMessageStream(params, options) { const method = "sendMessageStream"; params = this.applyClientConfig({ params, blocking: true }); const beforeArgs = { input: { method, value: params }, agentCard: this.agentCard, options }; const beforeResult = await this.interceptBefore(beforeArgs); if (beforeResult) { const earlyReturn = beforeResult.earlyReturn.value; const afterArgs = { result: { method, value: earlyReturn }, agentCard: this.agentCard, options: beforeArgs.options }; await this.interceptAfter(afterArgs, beforeResult.executed); yield afterArgs.result.value; return; } if (!this.agentCard.capabilities.streaming) { const result = await this.transport.sendMessage(beforeArgs.input.value, beforeArgs.options); const afterArgs = { result: { method, value: result }, agentCard: this.agentCard, options: beforeArgs.options }; await this.interceptAfter(afterArgs); yield afterArgs.result.value; return; } for await (const event of this.transport.sendMessageStream( beforeArgs.input.value, beforeArgs.options )) { const afterArgs = { result: { method, value: event }, agentCard: this.agentCard, options: beforeArgs.options }; await this.interceptAfter(afterArgs); yield afterArgs.result.value; if (afterArgs.earlyReturn) { return; } } } /** * Sets or updates the push notification configuration for a specified task. * Requires the server to have AgentCard.capabilities.pushNotifications: true. */ setTaskPushNotificationConfig(params, options) { if (!this.agentCard.capabilities.pushNotifications) { throw new PushNotificationNotSupportedError(); } return this.executeWithInterceptors( { method: "setTaskPushNotificationConfig", value: params }, options, this.transport.setTaskPushNotificationConfig.bind(this.transport) ); } /** * Retrieves the current push notification configuration for a specified task. * Requires the server to have AgentCard.capabilities.pushNotifications: true. */ getTaskPushNotificationConfig(params, options) { if (!this.agentCard.capabilities.pushNotifications) { throw new PushNotificationNotSupportedError(); } return this.executeWithInterceptors( { method: "getTaskPushNotificationConfig", value: params }, options, this.transport.getTaskPushNotificationConfig.bind(this.transport) ); } /** * Retrieves the associated push notification configurations for a specified task. * Requires the server to have AgentCard.capabilities.pushNotifications: true. */ listTaskPushNotificationConfig(params, options) { if (!this.agentCard.capabilities.pushNotifications) { throw new PushNotificationNotSupportedError(); } return this.executeWithInterceptors( { method: "listTaskPushNotificationConfig", value: params }, options, this.transport.listTaskPushNotificationConfig.bind(this.transport) ); } /** * Deletes an associated push notification configuration for a task. */ deleteTaskPushNotificationConfig(params, options) { return this.executeWithInterceptors( { method: "deleteTaskPushNotificationConfig", value: params }, options, this.transport.deleteTaskPushNotificationConfig.bind(this.transport) ); } /** * Retrieves the current state (including status, artifacts, and optionally history) of a previously initiated task. */ getTask(params, options) { return this.executeWithInterceptors( { method: "getTask", value: params }, options, this.transport.getTask.bind(this.transport) ); } /** * Requests the cancellation of an ongoing task. The server will attempt to cancel the task, * but success is not guaranteed (e.g., the task might have already completed or failed, or cancellation might not be supported at its current stage). */ cancelTask(params, options) { return this.executeWithInterceptors( { method: "cancelTask", value: params }, options, this.transport.cancelTask.bind(this.transport) ); } /** * Allows a client to reconnect to an updates stream for an ongoing task after a previous connection was interrupted. */ async *resubscribeTask(params, options) { const method = "resubscribeTask"; const beforeArgs = { input: { method, value: params }, agentCard: this.agentCard, options }; const beforeResult = await this.interceptBefore(beforeArgs); if (beforeResult) { const earlyReturn = beforeResult.earlyReturn.value; const afterArgs = { result: { method, value: earlyReturn }, agentCard: this.agentCard, options: beforeArgs.options }; await this.interceptAfter(afterArgs, beforeResult.executed); yield afterArgs.result.value; return; } for await (const event of this.transport.resubscribeTask( beforeArgs.input.value, beforeArgs.options )) { const afterArgs = { result: { method, value: event }, agentCard: this.agentCard, options: beforeArgs.options }; await this.interceptAfter(afterArgs); yield afterArgs.result.value; if (afterArgs.earlyReturn) { return; } } } applyClientConfig({ params, blocking }) { const result = { ...params, configuration: params.configuration ?? {} }; if (!result.configuration.acceptedOutputModes && this.config?.acceptedOutputModes) { result.configuration.acceptedOutputModes = this.config.acceptedOutputModes; } if (!result.configuration.pushNotificationConfig && this.config?.pushNotificationConfig) { result.configuration.pushNotificationConfig = this.config.pushNotificationConfig; } result.configuration.blocking ??= blocking; return result; } async executeWithInterceptors(input, options, transportCall) { const beforeArgs = { input, agentCard: this.agentCard, options }; const beforeResult = await this.interceptBefore(beforeArgs); if (beforeResult) { const afterArgs2 = { result: { method: input.method, value: beforeResult.earlyReturn.value }, agentCard: this.agentCard, options: beforeArgs.options }; await this.interceptAfter(afterArgs2, beforeResult.executed); return afterArgs2.result.value; } const result = await transportCall(beforeArgs.input.value, beforeArgs.options); const afterArgs = { result: { method: input.method, value: result }, agentCard: this.agentCard, options: beforeArgs.options }; await this.interceptAfter(afterArgs); return afterArgs.result.value; } async interceptBefore(args) { if (!this.config?.interceptors || this.config.interceptors.length === 0) { return; } const executed = []; for (const interceptor of this.config.interceptors) { await interceptor.before(args); executed.push(interceptor); if (args.earlyReturn) { return { earlyReturn: args.earlyReturn, executed }; } } } async interceptAfter(args, interceptors) { const reversedInterceptors = [...interceptors ?? this.config?.interceptors ?? []].reverse(); for (const interceptor of reversedInterceptors) { await interceptor.after(args); if (args.earlyReturn) { return; } } } }; // src/types/converters/to_proto.ts var ToProto = class _ToProto { static agentCard(agentCard) { return { protocolVersion: agentCard.protocolVersion, name: agentCard.name, description: agentCard.description, url: agentCard.url, preferredTransport: agentCard.preferredTransport ?? "", additionalInterfaces: agentCard.additionalInterfaces?.map((i) => _ToProto.agentInterface(i)) ?? [], provider: _ToProto.agentProvider(agentCard.provider), version: agentCard.version, documentationUrl: agentCard.documentationUrl ?? "", capabilities: _ToProto.agentCapabilities(agentCard.capabilities), securitySchemes: agentCard.securitySchemes ? Object.fromEntries( Object.entries(agentCard.securitySchemes).map(([key, value]) => [ key, _ToProto.securityScheme(value) ]) ) : {}, security: agentCard.security?.map((s) => _ToProto.security(s)) ?? [], defaultInputModes: agentCard.defaultInputModes, defaultOutputModes: agentCard.defaultOutputModes, skills: agentCard.skills.map((s) => _ToProto.agentSkill(s)), supportsAuthenticatedExtendedCard: agentCard.supportsAuthenticatedExtendedCard, signatures: agentCard.signatures?.map((s) => _ToProto.agentCardSignature(s)) ?? [] }; } static agentCardSignature(signatures) { return { protected: signatures.protected, signature: signatures.signature, header: signatures.header }; } static agentSkill(skill) { return { id: skill.id, name: skill.name, description: skill.description, tags: skill.tags ?? [], examples: skill.examples ?? [], inputModes: skill.inputModes ?? [], outputModes: skill.outputModes ?? [], security: skill.security ? skill.security.map((s) => _ToProto.security(s)) : [] }; } static security(security) { return { schemes: Object.fromEntries( Object.entries(security).map(([key, value]) => { return [key, { list: value }]; }) ) }; } static securityScheme(scheme) { switch (scheme.type) { case "apiKey": return { scheme: { $case: "apiKeySecurityScheme", value: { name: scheme.name, location: scheme.in, description: scheme.description ?? "" } } }; case "http": return { scheme: { $case: "httpAuthSecurityScheme", value: { description: scheme.description ?? "", scheme: scheme.scheme, bearerFormat: scheme.bearerFormat ?? "" } } }; case "mutualTLS": return { scheme: { $case: "mtlsSecurityScheme", value: { description: scheme.description ?? "" } } }; case "oauth2": return { scheme: { $case: "oauth2SecurityScheme", value: { description: scheme.description ?? "", flows: _ToProto.oauthFlows(scheme.flows), oauth2MetadataUrl: scheme.oauth2MetadataUrl ?? "" } } }; case "openIdConnect": return { scheme: { $case: "openIdConnectSecurityScheme", value: { description: scheme.description ?? "", openIdConnectUrl: scheme.openIdConnectUrl } } }; default: throw A2AError.internalError(`Unsupported security scheme type`); } } static oauthFlows(flows) { if (flows.implicit) { return { flow: { $case: "implicit", value: { authorizationUrl: flows.implicit.authorizationUrl, scopes: flows.implicit.scopes, refreshUrl: flows.implicit.refreshUrl ?? "" } } }; } else if (flows.password) { return { flow: { $case: "password", value: { tokenUrl: flows.password.tokenUrl, scopes: flows.password.scopes, refreshUrl: flows.password.refreshUrl ?? "" } } }; } else if (flows.clientCredentials) { return { flow: { $case: "clientCredentials", value: { tokenUrl: flows.clientCredentials.tokenUrl, scopes: flows.clientCredentials.scopes, refreshUrl: flows.clientCredentials.refreshUrl ?? "" } } }; } else if (flows.authorizationCode) { return { flow: { $case: "authorizationCode", value: { authorizationUrl: flows.authorizationCode.authorizationUrl, tokenUrl: flows.authorizationCode.tokenUrl, scopes: flows.authorizationCode.scopes, refreshUrl: flows.authorizationCode.refreshUrl ?? "" } } }; } else { throw A2AError.internalError(`Unsupported OAuth flows`); } } static agentInterface(agentInterface) { return { transport: agentInterface.transport, url: agentInterface.url }; } static agentProvider(agentProvider) { if (!agentProvider) { return void 0; } return { url: agentProvider.url, organization: agentProvider.organization }; } static agentCapabilities(capabilities) { return { streaming: capabilities.streaming, pushNotifications: capabilities.pushNotifications, extensions: capabilities.extensions ? capabilities.extensions.map((e) => _ToProto.agentExtension(e)) : [] }; } static agentExtension(extension) { return { uri: extension.uri, description: extension.description ?? "", required: extension.required ?? false, params: extension.params }; } static listTaskPushNotificationConfig(config) { return { configs: config.map((c) => _ToProto.taskPushNotificationConfig(c)), nextPageToken: "" }; } static getTaskPushNotificationConfigParams(config) { return { name: generatePushNotificationConfigName(config.id, config.pushNotificationConfigId) }; } static listTaskPushNotificationConfigParams(config) { return { parent: generateTaskName(config.id), pageToken: "", pageSize: 0 }; } static deleteTaskPushNotificationConfigParams(config) { return { name: generatePushNotificationConfigName(config.id, config.pushNotificationConfigId) }; } static taskPushNotificationConfig(config) { return { name: generatePushNotificationConfigName( config.taskId, config.pushNotificationConfig.id ?? "" ), pushNotificationConfig: _ToProto.pushNotificationConfig(config.pushNotificationConfig) }; } static taskPushNotificationConfigCreate(config) { return { parent: generateTaskName(config.taskId), config: _ToProto.taskPushNotificationConfig(config), configId: config.pushNotificationConfig.id }; } static pushNotificationConfig(config) { if (!config) { return void 0; } return { id: config.id ?? "", url: config.url, token: config.token ?? "", authentication: _ToProto.pushNotificationAuthenticationInfo(config.authentication) }; } static pushNotificationAuthenticationInfo(authInfo) { if (!authInfo) { return void 0; } return { schemes: authInfo.schemes, credentials: authInfo.credentials ?? "" }; } static messageStreamResult(event) { if (event.kind === "message") { return { payload: { $case: "msg", value: _ToProto.message(event) } }; } else if (event.kind === "task") { return { payload: { $case: "task", value: _ToProto.task(event) } }; } else if (event.kind === "status-update") { return { payload: { $case: "statusUpdate", value: _ToProto.taskStatusUpdateEvent(event) } }; } else if (event.kind === "artifact-update") { return { payload: { $case: "artifactUpdate", value: _ToProto.taskArtifactUpdateEvent(event) } }; } else { throw A2AError.internalError("Invalid event type"); } } static taskStatusUpdateEvent(event) { return { taskId: event.taskId, status: _ToProto.taskStatus(event.status), contextId: event.contextId, metadata: event.metadata, final: event.final }; } static taskArtifactUpdateEvent(event) { return { taskId: event.taskId, artifact: _ToProto.artifact(event.artifact), contextId: event.contextId, metadata: event.metadata, append: event.append, lastChunk: event.lastChunk }; } static messageSendResult(params) { if (params.kind === "message") { return { payload: { $case: "msg", value: _ToProto.message(params) } }; } else if (params.kind === "task") { return { payload: { $case: "task", value: _ToProto.task(params) } }; } } static message(message) { if (!message) { return void 0; } return { messageId: message.messageId, content: message.parts.map((p) => _ToProto.part(p)), contextId: message.contextId ?? "", taskId: message.taskId ?? "", role: _ToProto.role(message.role), metadata: message.metadata, extensions: message.extensions ?? [] }; } static role(role) { switch (role) { case "agent": return 2 /* ROLE_AGENT */; case "user": return 1 /* ROLE_USER */; default: throw A2AError.internalError(`Invalid role`); } } static task(task) { return { id: task.id, contextId: task.contextId, status: _ToProto.taskStatus(task.status), artifacts: task.artifacts?.map((a) => _ToProto.artifact(a)) ?? [], history: task.history?.map((m) => _ToProto.message(m)) ?? [], metadata: task.metadata }; } static taskStatus(status) { return { state: _ToProto.taskState(status.state), update: _ToProto.message(status.message), timestamp: status.timestamp }; } static artifact(artifact) { return { artifactId: artifact.artifactId, name: artifact.name ?? "", description: artifact.description ?? "", parts: artifact.parts.map((p) => _ToProto.part(p)), metadata: artifact.metadata, extensions: artifact.extensions ? artifact.extensions : [] }; } static taskState(state) { switch (state) { case "submitted": return 1 /* TASK_STATE_SUBMITTED */; case "working": return 2 /* TASK_STATE_WORKING */; case "input-required": return 6 /* TASK_STATE_INPUT_REQUIRED */; case "rejected": return 7 /* TASK_STATE_REJECTED */; case "auth-required": return 8 /* TASK_STATE_AUTH_REQUIRED */; case "completed": return 3 /* TASK_STATE_COMPLETED */; case "failed": return 4 /* TASK_STATE_FAILED */; case "canceled": return 5 /* TASK_STATE_CANCELLED */; case "unknown": return 0 /* TASK_STATE_UNSPECIFIED */; default: return -1 /* UNRECOGNIZED */; } } static part(part) { if (part.kind === "text") { return { part: { $case: "text", value: part.text } }; } if (part.kind === "file") { let filePart; if ("uri" in part.file) { filePart = { file: { $case: "fileWithUri", value: part.file.uri }, mimeType: part.file.mimeType }; } else if ("bytes" in part.file) { filePart = { file: { $case: "fileWithBytes", value: Buffer.from(part.file.bytes, "base64") }, mimeType: part.file.mimeType }; } else { throw A2AError.internalError("Invalid file part"); } return { part: { $case: "file", value: filePart } }; } if (part.kind === "data") { return { part: { $case: "data", value: { data: part.data } } }; } throw A2AError.internalError("Invalid part type"); } static messageSendParams(params) { return { request: _ToProto.message(params.message), configuration: _ToProto.configuration(params.configuration), metadata: params.metadata }; } static configuration(configuration) { if (!configuration) { return void 0; } return { blocking: configuration.blocking, acceptedOutputModes: configuration.acceptedOutputModes ?? [], pushNotification: _ToProto.pushNotificationConfig(configuration.pushNotificationConfig), historyLength: configuration.historyLength ?? 0 }; } static taskQueryParams(params) { return { name: generateTaskName(params.id), historyLength: params.historyLength ?? 0 }; } static cancelTaskRequest(params) { return { name: generateTaskName(params.id) }; } static taskIdParams(params) { return { name: generateTaskName(params.id) }; } static getAgentCardRequest() { return {}; } }; // src/client/transports/rest_transport.ts var RestTransport = class _RestTransport { customFetchImpl; endpoint; constructor(options) { this.endpoint = options.endpoint.replace(/\/+$/, ""); this.customFetchImpl = options.fetchImpl; } async getExtendedAgentCard(options) { const response = await this._sendRequest( "GET", "/v1/card", void 0, options, void 0, AgentCard ); return FromProto.agentCard(response); } async sendMessage(params, options) { const requestBody = ToProto.messageSendParams(params); const response = await this._sendRequest( "POST", "/v1/message:send", requestBody, options, SendMessageRequest, SendMessageResponse ); return FromProto.sendMessageResult(response); } async *sendMessageStream(params, options) { const protoParams = ToProto.messageSendParams(params); const requestBody = SendMessageRequest.toJSON(protoParams); yield* this._sendStreamingRequest("/v1/message:stream", requestBody, options); } async setTaskPushNotificationConfig(params, options) { const requestBody = ToProto.taskPushNotificationConfig(params); const response = await this._sendRequest( "POST", `/v1/tasks/${encodeURIComponent(params.taskId)}/pushNotificationConfigs`, requestBody, options, TaskPushNotificationConfig, TaskPushNotificationConfig ); return FromProto.taskPushNotificationConfig(response); } async getTaskPushNotificationConfig(params, options) { const { pushNotificationConfigId } = params; if (!pushNotificationConfigId) { throw new Error( "pushNotificationConfigId is required for getTaskPushNotificationConfig with REST transport." ); } const response = await this._sendRequest( "GET", `/v1/tasks/${encodeURIComponent(params.id)}/pushNotificationConfigs/${encodeURIComponent(pushNotificationConfigId)}`, void 0, options, void 0, TaskPushNotificationConfig ); return FromProto.taskPushNotificationConfig(response); } async listTaskPushNotificationConfig(params, options) { const response = await this._sendRequest( "GET", `/v1/tasks/${encodeURIComponent(params.id)}/pushNotificationConfigs`, void 0, options, void 0, ListTaskPushNotificationConfigResponse ); return FromProto.listTaskPushNotificationConfig(response); } async deleteTaskPushNotificationConfig(params, options) { await this._sendRequest( "DELETE", `/v1/tasks/${encodeURIComponent(params.id)}/pushNotificationConfigs/${encodeURIComponent(params.pushNotificationConfigId)}`, void 0, options, void 0, void 0 ); } async getTask(params, options) { const queryParams = new URLSearchParams(); if (params.historyLength !== void 0) { queryParams.set("historyLength", String(params.historyLength)); } const queryString = queryParams.toString(); const path = `/v1/tasks/${encodeURIComponent(params.id)}${queryString ? `?${queryString}` : ""}`; const response = await this._sendRequest( "GET", path, void 0, options, void 0, Task ); return FromProto.task(response); } async cancelTask(params, options) { const response = await this._sendRequest( "POST", `/v1/tasks/${encodeURIComponent(params.id)}:cancel`, void 0, options, void 0, Task ); return FromProto.task(response); } async *resubscribeTask(params, options) { yield* this._sendStreamingRequest( `/v1/tasks/${encodeURIComponent(params.id)}:subscribe`, void 0, options ); } _fetch(...args) { if (this.customFetchImpl) { return this.customFetchImpl(...args); } if (typeof fetch === "function") { return fetch(...args); } throw new Error( "A `fetch` implementation was not provided and is not available in the global scope. Please provide a `fetchImpl` in the RestTransportOptions." ); } _buildHeaders(options, acceptHeader = "application/json") { return { ...options?.serviceParameters, "Content-Type": "application/json", Accept: acceptHeader }; } async _sendRequest(method, path, body, options, requestType, responseType) { const url = `${this.endpoint}${path}`; const requestInit = { method, headers: this._buildHeaders(options), signal: options?.signal }; if (body !== void 0 && method !== "GET") { if (!requestType) { throw new Error( `Bug: Request body provided for ${method} ${path} but no toJson serializer provided.` ); } requestInit.body = JSON.stringify(requestType.toJSON(body)); } const response = await this._fetch(url, requestInit); if (!response.ok) { await this._handleErrorResponse(response, path); } if (response.status === 204 || !responseType) { return void 0; } const result = await response.json(); return responseType.fromJSON(result); } async _handleErrorResponse(response, path) { let errorBodyText = "(empty or non-JSON response)"; let errorBody; try { errorBodyText = await response.text(); if (errorBodyText) { errorBody = JSON.parse(errorBodyText); } } catch (e) { throw new Error( `HTTP error for ${path}! Status: ${response.status} ${response.statusText}. Response: ${errorBodyText}`, { cause: e } ); } if (errorBody && typeof errorBody.code === "number") { throw _RestTransport.mapToError(errorBody); } throw new Error( `HTTP error for ${path}! Status: ${response.status} ${response.statusText}. Response: ${errorBodyText}` ); } async *_sendStreamingRequest(path, body, options) { const url = `${this.endpoint}${path}`; const requestInit = { method: "POST", headers: this._buildHeaders(options, "text/event-stream"), signal: options?.signal }; if (body !== void 0) { requestInit.body = JSON.stringify(body); } const response = await this._fetch(url, requestInit); if (!response.ok) { await this._handleErrorResponse(response, path); } const contentType = response.headers.get("Content-Type"); if (!contentType?.startsWith("text/event-stream")) { throw new Error( `Invalid response Content-Type for SSE stream. Expected 'text/event-stream', got '${contentType}'.` ); } for await (const event of parseSseStream(response)) { if (event.type === "error") { const errorData = JSON.parse(event.data); throw _RestTransport.mapToError(errorData); } yield this._processSseEventData(event.data); } } _processSseEventData(jsonData) { if (!jsonData.trim()) { throw new Error("Attempted to process empty SSE event data."); } try { const response = JSON.parse(jsonData); const protoResponse = StreamResponse.fromJSON(response); return FromProto.messageStreamResult(protoResponse); } catch (e) { console.error("Failed to parse SSE event data:", jsonData, e); throw new Error( `Failed to parse SSE event data: "${jsonData.substring(0, 100)}...". Original error: ${e instanceof Error && e.message || "Unknown error"}` ); } } static mapToError(error) { switch (error.code) { case A2A_ERROR_CODE.TASK_NOT_FOUND: return new TaskNotFoundError(error.message); case A2A_ERROR_CODE.TASK_NOT_CANCELABLE: return new TaskNotCancelableError(error.message); case A2A_ERROR_CODE.PUSH_NOTIFICATION_NOT_SUPPORTED: return new PushNotificationNotSupportedError(error.message); case A2A_ERROR_CODE.UNSUPPORTED_OPERATION: return new UnsupportedOperationError(error.message); case A2A_ERROR_CODE.CONTENT_TYPE_NOT_SUPPORTED: return new ContentTypeNotSupportedError(error.message); case A2A_ERROR_CODE.INVALID_AGENT_RESPONSE: return new InvalidAgentResponseError(error.message); case A2A_ERROR_CODE.AUTHENTICATED_EXTENDED_CARD_NOT_CONFIGURED: return new AuthenticatedExtendedCardNotConfiguredError(error.message); default: return new Error( `REST error: ${error.message} (Code: ${error.code})${error.data ? ` Data: ${JSON.stringify(error.data)}` : ""}` ); } } }; var RestTransportFactory = class _RestTransportFactory { constructor(options) { this.options = options; } static name = "HTTP+JSON"; get protocolName() { return _RestTransportFactory.name; } async create(url, _agentCard) { return new RestTransport({ endpoint: url, fetchImpl: this.options?.fetchImpl }); } }; // src/client/factory.ts var ClientFactoryOptions = { /** * SDK default options for {@link ClientFactory}. */ default: { transports: [new JsonRpcTransportFactory(), new RestTransportFactory()] }, /** * Creates new options by merging an original and an override object. * Transports are merged based on `TransportFactory.protocolName`, * interceptors are concatenated, other fields are overriden. * * @example * ```ts * const options = ClientFactoryOptions.createFrom(ClientFactoryOptions.default, { * transports: [new MyCustomTransportFactory()], // adds a custom transport * clientConfig: { interceptors: [new MyInterceptor()] }, // adds a custom interceptor * }); * ``` */ createFrom(original, overrides) { return { ...original, ...overrides, transports: mergeTransports(original.transports, overrides.transports), clientConfig: { ...original.clientConfig ?? {}, ...overrides.clientConfig ?? {}, interceptors: mergeArrays( original.clientConfig?.interceptors, overrides.clientConfig?.interceptors ), acceptedOutputModes: overrides.clientConfig?.acceptedOutputModes ?? original.clientConfig?.acceptedOutputModes }, preferredTransports: overrides.preferredTransports ?? original.preferredTransports }; } }; var ClientFactory = class { constructor(options = ClientFactoryOptions.default) { this.options = options; if (!options.transports || options.transports.length === 0) { throw new Error("No transports provided"); } this.transportsByName = transportsByName(options.transports); for (const transport of options.preferredTransports ?? []) { if (!this.transportsByName.has(transport)) { throw new Error( `Unknown preferred transport: ${transport}, available transports: ${[...this.transportsByName.keys()].join()}` ); } } this.agentCardResolver = options.cardResolver ?? AgentCardResolver.default; } transportsByName; agentCardResolver; /** * Creates a new client from the provided agent card. */ async createFromAgentCard(agentCard) { const agentCardPreferred = agentCard.preferredTransport ?? JsonRpcTransportFactory.name; const additionalInterfaces = agentCard.additionalInterfaces ?? []; const urlsPerAgentTransports = new CaseInsensitiveMap([ [agentCardPreferred, agentCard.url], ...additionalInterfaces.map((i) => [i.transport, i.url]) ]); const transportsByPreference = [ ...this.options.preferredTransports ?? [], agentCardPreferred, ...additionalInterfaces.map((i) => i.transport) ]; for (const transport of transportsByPreference) { const url = urlsPerAgentTransports.get(transport); const factory = this.transportsByName.get(transport); if (factory && url) { return new Client( await factory.create(url, agentCard), agentCard, this.options.clientConfig ); } } throw new Error( "No compatible transport found, available transports: " + [...this.transportsByName.keys()].join() ); } /** * Downloads agent card using AgentCardResolver from options * and creates a new client from the downloaded card. * * @example * ```ts * const factory = new ClientFactory(); // use default options and default {@link AgentCardResolver}. * const client1 = await factory.createFromUrl('https://example.com'); // /.well-known/agent-card.json is used by default * const client2 = await factory.createFromUrl('https://example.com', '/my-agent-card.json'); // specify custom path * const client3 = await factory.createFromUrl('https://example.com/my-agent-card.json', ''); // specify full URL and set path to empty * ``` */ async createFromUrl(baseUrl, path) { const agentCard = await this.agentCardResolver.resolve(baseUrl, path); return this.createFromAgentCard(agentCard); } }; function mergeTransports(original, overrides) { if (!overrides) { return original; } const result = transportsByName(original); const overridesByName = transportsByName(overrides); for (const [name, factory] of overridesByName) { result.set(name, factory); } return Array.from(result.values()); } function transportsByName(transports) { const result = new CaseInsensitiveMap(); if (!transports) { return result; } for (const t of transports) { if (result.has(t.protocolName)) { throw new Error(`Duplicate protocol name: ${t.protocolName}`); } result.set(t.protocolName, t); } return result; } function mergeArrays(a1, a2) { if (!a1 && !a2) { return void 0; } return [...a1 ?? [], ...a2 ?? []]; } var CaseInsensitiveMap = class extends Map { normalizeKey(key) { return key.toUpperCase(); } set(key, value) { return super.set(this.normalizeKey(key), value); } get(key) { return super.get(this.normalizeKey(key)); } has(key) { return super.has(this.normalizeKey(key)); } delete(key) { return super.delete(this.normalizeKey(key)); } }; // src/extensions.ts var Extensions = { /** * Creates new {@link Extensions} from `current` and `additional`. * If `current` already contains `additional` it is returned unmodified. */ createFrom: (current, additional) => { if (current?.includes(additional)) { return current; } return [...current ?? [], additional]; }, /** * Creates {@link Extensions} from comma separated extensions identifiers as per * https://a2a-protocol.org/latest/specification/#326-service-parameters. * Parses the output of `toServiceParameter`. */ parseServiceParameter: (value) => { if (!value) { return []; } const unique = new Set( value.split(",").map((ext) => ext.trim()).filter((ext) => ext.length > 0) ); return Array.from(unique); }, /** * Converts {@link Extensions} to comma separated extensions identifiers as per * https://a2a-protocol.org/latest/specification/#326-service-parameters. */ toServiceParameter: (value) => { return value.join(","); } }; // src/client/service-parameters.ts var ServiceParameters = { create(...updates) { return ServiceParameters.createFrom(void 0, ...updates); }, createFrom: (serviceParameters, ...updates) => { const result = serviceParameters ? { ...serviceParameters } : {}; for (const update of updates) { update(result); } return result; } }; function withA2AExtensions(...extensions) { return (parameters) => { parameters[HTTP_EXTENSION_HEADER] = Extensions.toServiceParameter(extensions); }; } // src/client/context.ts var ClientCallContext = { /** * Create a new {@link ClientCallContext} with optional updates applied. */ create: (...updates) => { return ClientCallContext.createFrom(void 0, ...updates); }, /** * Create a new {@link ClientCallContext} based on an existing one with updates applied. */ createFrom: (context, ...updates) => { const result = context ? { ...context } : {}; for (const update of updates) { update(result); } return result; } }; var ClientCallContextKey = class { symbol; constructor(description) { this.symbol = Symbol(description); } set(value) { return (context) => { context[this.symbol] = value; }; } get(context) { return context[this.symbol]; } }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { A2AClient, AgentCardResolver, AuthenticatedExtendedCardNotConfiguredError, Client, ClientCallContext, ClientCallContextKey, ClientFactory, ClientFactoryOptions, ContentTypeNotSupportedError, DefaultAgentCardResolver, InvalidAgentResponseError, JsonRpcTransport, JsonRpcTransportFactory, PushNotificationNotSupportedError, RestTransport, RestTransportFactory, ServiceParameters, TaskNotCancelableError, TaskNotFoundError, UnsupportedOperationError, createAuthenticatingFetchWithRetry, withA2AExtensions });