UNPKG

@dexwox-labs/a2a-client

Version:

TypeScript client implementation for Google's Agent-to-Agent (A2A) protocol - includes HTTP/WebSocket communication, circuit breakers and error handling

430 lines 18.3 kB
"use strict"; /** * @module TaskClient * @description Client for managing tasks in the A2A protocol */ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; } var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); var _, done = false; for (var i = decorators.length - 1; i >= 0; i--) { var context = {}; for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; for (var p in contextIn.access) context.access[p] = contextIn.access[p]; context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); }; var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context); if (kind === "accessor") { if (result === void 0) continue; if (result === null || typeof result !== "object") throw new TypeError("Object expected"); if (_ = accept(result.get)) descriptor.get = _; if (_ = accept(result.set)) descriptor.set = _; if (_ = accept(result.init)) initializers.unshift(_); } else if (_ = accept(result)) { if (kind === "field") initializers.unshift(_); else descriptor[key] = _; } } if (target) Object.defineProperty(target, contextIn.name, descriptor); done = true; }; var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) { var useValue = arguments.length > 2; for (var i = 0; i < initializers.length; i++) { value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); } return useValue ? value : void 0; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.TaskClient = void 0; const a2a_core_1 = require("@dexwox-labs/a2a-core"); const error_handler_1 = require("./utils/error-handler"); const http_utils_1 = require("./utils/http-utils"); const events_1 = require("events"); const types_1 = require("./types"); /** * Client for managing tasks in the A2A protocol * * The TaskClient provides methods for creating, monitoring, and managing tasks * with support for real-time status updates and push notifications. * * @example * ```typescript * const taskClient = new TaskClient({ baseUrl: 'https://a2a-server.example.com' }); * * // Get task status * const task = await taskClient.getTaskStatus('task-123'); * console.log(`Task status: ${task.status}`); * * // Cancel a task * await taskClient.cancelTask('task-123'); * ``` */ let TaskClient = (() => { let _classDecorators = [(0, a2a_core_1.TraceClass)()]; let _classDescriptor; let _classExtraInitializers = []; let _classThis; let _classSuper = events_1.EventEmitter; var TaskClient = class extends _classSuper { static { _classThis = this; } static { const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0; __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers); TaskClient = _classThis = _classDescriptor.value; if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); __runInitializers(_classThis, _classExtraInitializers); } options; /** @private Cache of push notification configurations by task ID */ pushConfigs = new Map(); /** @private Map of task ID to callback functions for task updates */ taskCallbacks = new Map(); /** * Creates a new TaskClient instance * @param options - Configuration options for the client */ constructor(options) { super(); this.options = options; } /** * Gets the current status of a task * * Retrieves the current state and details of a task by its ID. This method * fetches the complete task object including status, input, output, and any * error information. * * @param taskId - The ID of the task to check * @returns Promise resolving to the complete task object * @throws {A2ANetworkError} If there's a network issue contacting the server * @throws {A2AValidationError} If the task ID is invalid or not found * * @example * ```typescript * try { * const task = await taskClient.getTaskStatus('task-123'); * console.log(`Task status: ${task.status}`); * * if (task.status === 'completed') { * console.log('Task output:', task.output); * } else if (task.status === 'failed') { * console.error('Task failed:', task.error); * } * } catch (error) { * console.error('Error checking task status:', error.message); * } * ``` */ async getTaskStatus(taskId) { const request = { jsonrpc: '2.0', method: 'getTaskStatus', params: { taskId } }; try { const response = await (0, http_utils_1.sendRequest)(this.options, request); return response.result.task; } catch (err) { if (err instanceof Error && err.message.includes('Network')) { throw new error_handler_1.A2ANetworkError('Failed to get task status', { originalError: err, taskId }); } throw (0, error_handler_1.normalizeError)(err); } } /** * Cancels a running task * * Attempts to cancel a task that is currently in progress. This will transition * the task to the 'canceled' state if successful. Tasks that have already * completed or failed cannot be canceled. * * @param taskId - The ID of the task to cancel * @returns Promise resolving when cancellation is complete * @throws {A2ANetworkError} If there's a network issue contacting the server * @throws {A2AValidationError} If the task cannot be canceled (e.g., already completed) * * @example * ```typescript * try { * await taskClient.cancelTask('task-123'); * console.log('Task canceled successfully'); * } catch (error) { * if (error.code === 'VALIDATION_ERROR') { * console.error('Cannot cancel task:', error.message); * } else { * console.error('Error canceling task:', error.message); * } * } * ``` */ async cancelTask(taskId) { const request = { jsonrpc: '2.0', method: 'cancelTask', params: { taskId } }; try { await (0, http_utils_1.sendRequest)(this.options, request); } catch (err) { if (err instanceof Error && err.message.includes('Network')) { throw new error_handler_1.A2ANetworkError('Failed to cancel task', { originalError: err, taskId }); } throw (0, error_handler_1.normalizeError)(err); } } /** * Lists all tasks for the current session * @param options Optional filters for the task list * @returns Promise resolving to an array of tasks * @throws A2AError if the request fails */ /** * Sets push notification configuration for a task * * Configures server-side push notifications for task status updates. This allows * your application to receive real-time updates about task progress without polling. * * @param taskId - The task ID to configure notifications for * @param config - Push notification settings including endpoint and events to subscribe to * @returns Promise resolving when configuration is complete * @throws {A2ANetworkError} If there's a network issue contacting the server * @throws {A2ATimeoutError} If the request times out * @throws {A2AValidationError} If the configuration is invalid * * @example * ```typescript * await taskClient.setPushConfig('task-123', { * enabled: true, * endpoint: 'https://my-app.example.com/webhooks/tasks', * authToken: 'secret-token-123', * events: ['task.updated', 'task.completed', 'task.failed'] * }); * * console.log('Push notifications configured for task'); * ``` */ async setPushConfig(taskId, config) { const request = { jsonrpc: '2.0', method: 'setPushConfig', params: { taskId, config } }; try { await (0, http_utils_1.sendRequest)(this.options, request); this.pushConfigs.set(taskId, config); } catch (err) { if (err instanceof Error && err.message.includes('timeout')) { throw new error_handler_1.A2ATimeoutError('Task operation timed out', { originalError: err, taskId }); } throw (0, error_handler_1.normalizeError)(err); } } /** * Gets push notification configuration for a task * * Retrieves the current push notification settings for a task. This method * first checks the local cache and only makes a server request if needed. * * @param taskId - The task ID to check * @returns Promise resolving to the push notification configuration * @throws {A2ANetworkError} If there's a network issue contacting the server * @throws {A2AValidationError} If the task ID is invalid or not found * * @example * ```typescript * const config = await taskClient.getPushConfig('task-123'); * * console.log('Push notifications enabled:', config.enabled); * console.log('Subscribed events:', config.events); * console.log('Webhook endpoint:', config.endpoint); * ``` */ async getPushConfig(taskId) { // Return cached config if available if (this.pushConfigs.has(taskId)) { return this.pushConfigs.get(taskId); } const request = { jsonrpc: '2.0', method: 'getPushConfig', params: { taskId } }; try { const response = await (0, http_utils_1.sendRequest)(this.options, request); this.pushConfigs.set(taskId, response.result.config); return response.result.config; } catch (err) { throw (0, error_handler_1.normalizeError)(err); } } /** * Updates the status of a task * * Changes a task's status from one state to another. The transition is validated * to ensure it follows the allowed state machine transitions in the A2A protocol. * * @param taskId - The ID of the task to update * @param status - Object containing the current state and target state * @param status.from - The current state of the task * @param status.to - The desired new state of the task * @returns Promise resolving when the status update is complete * @throws {A2ANetworkError} If there's a network issue contacting the server * @throws {A2AValidationError} If the state transition is invalid * * @example * ```typescript * // Mark a task as completed * await taskClient.updateTaskStatus('task-123', { * from: 'working', * to: 'completed' * }); * * // Mark a task as failed * await taskClient.updateTaskStatus('task-456', { * from: 'working', * to: 'failed' * }); * ``` */ async updateTaskStatus(taskId, status) { (0, a2a_core_1.validateTransition)(status.from, status.to); const request = { jsonrpc: '2.0', method: 'updateTaskStatus', params: { taskId, status } }; try { await (0, http_utils_1.sendRequest)(this.options, request); } catch (err) { if (err instanceof Error && err.message.includes('Network')) { throw new error_handler_1.A2ANetworkError('Failed to update task status', { originalError: err, taskId }); } throw (0, error_handler_1.normalizeError)(err); } } /** * Lists tasks matching the specified criteria * * Retrieves a list of tasks from the server, with optional filtering by status, * limiting the number of results, and filtering by creation date. * * @param options - Optional filter criteria for the task list * @param options.status - Optional filter by task status * @param options.limit - Optional maximum number of tasks to return * @param options.since - Optional ISO timestamp to filter tasks created after this time * @returns Promise resolving to an array of tasks matching the criteria * @throws {A2ANetworkError} If there's a network issue contacting the server * * @example * ```typescript * // Get all tasks * const allTasks = await taskClient.listTasks(); * * // Get only completed tasks * const completedTasks = await taskClient.listTasks({ status: 'completed' }); * * // Get the 10 most recent tasks * const recentTasks = await taskClient.listTasks({ limit: 10 }); * * // Get tasks created in the last hour * const oneHourAgo = new Date(Date.now() - 3600000).toISOString(); * const recentTasks = await taskClient.listTasks({ since: oneHourAgo }); * ``` */ async listTasks(options) { const request = { jsonrpc: '2.0', method: 'listTasks', params: options || {} }; try { const response = await (0, http_utils_1.sendRequest)(this.options, request); return response.result.tasks; } catch (err) { throw (0, error_handler_1.normalizeError)(err); } } /** * Registers a callback for task updates * * Sets up a callback function to be called whenever a specific task is updated. * This provides a way to monitor task progress in real-time without polling. * * @param taskId - The ID of the task to monitor * @param callback - Function to call when the task is updated * * @example * ```typescript * // Monitor a specific task * taskClient.onTaskUpdate('task-123', (task) => { * console.log(`Task ${task.id} updated:`, task.status); * * if (task.status === 'completed') { * console.log('Task completed with result:', task.output); * } else if (task.status === 'failed') { * console.error('Task failed with error:', task.error); * } * }); * ``` */ onTaskUpdate(taskId, callback) { this.taskCallbacks.set(taskId, callback); this.on(types_1.TASK_UPDATED, (updatedTask) => { if (updatedTask.id === taskId) { callback(updatedTask); } }); } /** * Handles incoming task updates and triggers callbacks * * This internal method processes task updates received from the server and * triggers the appropriate callbacks and events. It's typically called by * the MessageClient when streaming updates. * * @param task - The updated task object * @internal */ handleTaskUpdate(task) { // Trigger specific callback if registered const callback = this.taskCallbacks.get(task.id); if (callback) { callback(task); } // Emit appropriate event based on task state this.emit(types_1.TASK_UPDATED, task); if (task.status === 'completed') { this.emit(types_1.TASK_COMPLETED, task); this.taskCallbacks.delete(task.id); } else if (task.status === 'failed' || task.status === 'canceled') { this.emit(types_1.TASK_FAILED, task); this.taskCallbacks.delete(task.id); } } }; return TaskClient = _classThis; })(); exports.TaskClient = TaskClient; //# sourceMappingURL=task-client.js.map