UNPKG

@dexwox-labs/a2a-server

Version:

TypeScript server implementation for Google's Agent-to-Agent (A2A) protocol - includes Express/WebSocket handlers, request validation and queue management

314 lines 12 kB
"use strict"; /** * @module DefaultJsonRpcRequestHandler * @description Default implementation of the JSON-RPC request handler for the A2A protocol * * This module provides the default implementation of the JSON-RPC request handler * interface for the A2A protocol server. It includes middleware for request validation, * error handling, and response formatting, as well as methods for handling various * JSON-RPC requests. */ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __asyncValues = (this && this.__asyncValues) || function (o) { if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); var m = o[Symbol.asyncIterator], i; return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } }; Object.defineProperty(exports, "__esModule", { value: true }); exports.DefaultJsonRpcRequestHandler = void 0; const express_1 = require("express"); /** * Default implementation of the JSON-RPC request handler * * This class provides a standard implementation of the JSON-RPC request handler * interface for the A2A protocol server. It includes middleware for request * validation, error handling, and response formatting, as well as methods for * handling various JSON-RPC requests. * * @example * ```typescript * // Create a JSON-RPC request handler * const jsonRpcHandler = new DefaultJsonRpcRequestHandler(); * * // Add middleware * jsonRpcHandler.use(jsonRpcHandler.handleErrors()); * jsonRpcHandler.use(jsonRpcHandler.formatResponse()); * * // Use in an Express app * app.use('/jsonrpc', jsonRpcHandler.router); * ``` */ class DefaultJsonRpcRequestHandler { constructor() { /** Express router for handling HTTP requests */ this.router = (0, express_1.Router)(); /** Array of middleware functions to apply to requests */ this.middlewares = []; } /** * Adds middleware to the request handler * * This method adds a middleware function to the request handler's middleware * stack. Middleware functions are executed in the order they are added. * * @param middleware - Middleware function to add * * @example * ```typescript * // Add error handling middleware * jsonRpcHandler.use(jsonRpcHandler.handleErrors()); * * // Add custom logging middleware * jsonRpcHandler.use(async (req, res, next) => { * console.log(`${req.method} ${req.path}`); * await next(); * }); * ``` */ use(middleware) { this.middlewares.push(middleware); } /** * Creates middleware for validating request body against a schema * * This method returns a middleware function that validates the request body * against a Zod schema. If validation fails, it responds with a 400 Bad Request * and a JSON-RPC error response. * * @param schema - Zod schema to validate against * @returns Middleware function that validates requests * * @example * ```typescript * // Create a schema for validating sendMessage requests * const sendMessageSchema = z.object({ * jsonrpc: z.literal('2.0'), * method: z.literal('sendMessage'), * params: z.object({ * parts: z.array(z.object({ * type: z.string(), * content: z.string() * })), * agentId: z.string() * }), * id: z.string().optional() * }); * * // Add validation middleware * jsonRpcHandler.use(jsonRpcHandler.validateRequest(sendMessageSchema)); * ``` */ validateRequest(schema) { return (req, res, next) => __awaiter(this, void 0, void 0, function* () { var _a; try { schema.parse(req.body); next(); } catch (err) { res.status(400).json(this.buildErrorResponse((_a = req.body) === null || _a === void 0 ? void 0 : _a.id, err)); } }); } /** * Creates middleware for handling errors * * This method returns a middleware function that catches any errors thrown * during request processing and responds with a 500 Internal Server Error * and a JSON-RPC error response. * * @returns Middleware function that catches and processes errors * * @example * ```typescript * // Add error handling middleware * jsonRpcHandler.use(jsonRpcHandler.handleErrors()); * ``` */ handleErrors() { return (req, res, next) => __awaiter(this, void 0, void 0, function* () { var _a; try { yield next(); } catch (err) { res.status(500).json(this.buildErrorResponse((_a = req.body) === null || _a === void 0 ? void 0 : _a.id, err)); } }); } /** * Creates middleware for formatting responses * * This method returns a middleware function that formats responses as JSON-RPC * success responses. If the response already has a jsonrpc property, it is * left unchanged. * * @returns Middleware function that formats responses * * @example * ```typescript * // Add response formatting middleware * jsonRpcHandler.use(jsonRpcHandler.formatResponse()); * ``` */ formatResponse() { return (req, res, next) => __awaiter(this, void 0, void 0, function* () { const originalJson = res.json; res.json = (body) => { var _a; if ((body === null || body === void 0 ? void 0 : body.jsonrpc) === '2.0') { return originalJson.call(res, body); } return originalJson.call(res, this.buildSuccessResponse((_a = req.body) === null || _a === void 0 ? void 0 : _a.id, body)); }; next(); }); } /** * Builds a JSON-RPC success response * * This method creates a properly formatted JSON-RPC 2.0 success response * with the provided result data. * * @param id - Request ID from the original JSON-RPC request * @param result - Result data to include in the response * @returns Properly formatted JSON-RPC success response * * @example * ```typescript * // Create a success response * const response = jsonRpcHandler.buildSuccessResponse('request-123', { * taskId: 'task-456' * }); * * // Send the response * res.json(response); * ``` */ buildSuccessResponse(id, result) { return { jsonrpc: '2.0', id, result }; } buildErrorResponse(id, error) { return { jsonrpc: '2.0', id, error: this.normalizeError(error) }; } handleJsonRpcSendMessage(req, res) { return __awaiter(this, void 0, void 0, function* () { try { const { parts, agentId } = req.body; const messageId = yield this.handleSendMessage(parts, agentId); res.json(this.buildSuccessResponse(req.body.id, messageId)); } catch (err) { res.status(400).json(this.buildErrorResponse(req.body.id, err)); } }); } handleJsonRpcStreamMessage(req, res) { return __awaiter(this, void 0, void 0, function* () { try { const { parts, agentId } = req.body; const stream = this.handleStreamMessage(parts, agentId); // Start consuming the stream in background (() => __awaiter(this, void 0, void 0, function* () { var _a, e_1, _b, _c; try { for (var _d = true, stream_1 = __asyncValues(stream), stream_1_1; stream_1_1 = yield stream_1.next(), _a = stream_1_1.done, !_a; _d = true) { _c = stream_1_1.value; _d = false; const _ = _c; } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (!_d && !_a && (_b = stream_1.return)) yield _b.call(stream_1); } finally { if (e_1) throw e_1.error; } } }))(); res.json(this.buildSuccessResponse(req.body.id, 'Stream started')); } catch (err) { res.status(400).json(this.buildErrorResponse(req.body.id, err)); } }); } handleJsonRpcGetTaskStatus(req, res) { return __awaiter(this, void 0, void 0, function* () { try { const task = yield this.handleGetTaskStatus(req.params.taskId); res.json(this.buildSuccessResponse(undefined, { task })); } catch (err) { res.status(400).json(this.buildErrorResponse(undefined, err)); } }); } handleJsonRpcCancelTask(req, res) { return __awaiter(this, void 0, void 0, function* () { try { yield this.handleCancelTask(req.params.taskId); res.json(this.buildSuccessResponse(undefined, 'Cancellation requested')); } catch (err) { res.status(400).json(this.buildErrorResponse(undefined, err)); } }); } handleJsonRpcDiscoverAgents(req, res) { return __awaiter(this, void 0, void 0, function* () { try { const { capability } = req.query; const agents = yield this.handleDiscoverAgents(capability); res.json(this.buildSuccessResponse(undefined, { agents })); } catch (err) { res.status(400).json(this.buildErrorResponse(undefined, err)); } }); } // Implement BaseRequestHandler methods handleSendMessage(parts, agentId) { throw new Error('Method not implemented.'); } handleStreamMessage(parts, agentId) { throw new Error('Method not implemented.'); } handleGetTaskStatus(taskId) { throw new Error('Method not implemented.'); } handleCancelTask(taskId) { throw new Error('Method not implemented.'); } handleTaskResubscription(taskId) { throw new Error('Method not implemented.'); } handleDiscoverAgents(capability) { return __awaiter(this, void 0, void 0, function* () { throw new Error('Method not implemented.'); }); } normalizeError(err) { throw new Error('Method not implemented.'); } } exports.DefaultJsonRpcRequestHandler = DefaultJsonRpcRequestHandler; //# sourceMappingURL=default-jsonrpc-handler.js.map