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

197 lines 7.92 kB
"use strict"; /** * @module A2AServer * @description Server implementation for hosting A2A protocol agents */ 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); } }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.A2AServer = void 0; const express_1 = __importDefault(require("express")); const body_parser_1 = require("body-parser"); const cors_1 = __importDefault(require("cors")); const ws_1 = require("ws"); /** * Server implementation for hosting A2A protocol agents * * The A2AServer class provides a complete HTTP and WebSocket server implementation * for hosting agents that implement the A2A protocol. It handles request routing, * error handling, and WebSocket connections for streaming. * * @example * ```typescript * import { A2AServer, DefaultRequestHandler } from '@dexwox-labs/a2a-node'; * * // Define an agent * const agent = { * id: 'weather-agent', * name: 'Weather Agent', * description: 'Provides weather information', * capabilities: ['weather-forecasting'], * endpoint: 'http://localhost:3000' * }; * * // Create a request handler * const requestHandler = new DefaultRequestHandler([agent]); * * // Create and start the server * const server = new A2AServer(agent, requestHandler); * server.start(3000); * ``` */ class A2AServer { /** * Creates a new A2AServer instance * * @param agentCard - The agent card describing this server's capabilities * @param requestHandler - Handler for processing incoming requests * @param contextMiddleware - Optional custom middleware for request context */ constructor(agentCard, requestHandler, contextMiddleware) { this.contextMiddleware = contextMiddleware; /** WebSocket server instance */ this.wss = null; this.app = (0, express_1.default)(); this.agentCard = agentCard; this.requestHandler = requestHandler; this.configureMiddleware(); this.configureRoutes(); this.configureErrorHandling(); } /** * Configures Express middleware for the server * * Sets up JSON parsing, CORS, and request context middleware. * @private */ configureMiddleware() { this.app.use((0, body_parser_1.json)()); this.app.use((0, cors_1.default)({ origin: process.env.CORS_ORIGIN || '*', methods: ['GET', 'POST', 'OPTIONS'], allowedHeaders: ['Content-Type', 'Authorization'] })); // Add context middleware if provided, otherwise use default if (this.contextMiddleware) { this.app.use(this.contextMiddleware); } else { this.app.use(require('./agent-execution/context-middleware').contextMiddleware(this.agentCard.id)); } } /** * Configures HTTP routes for the server * * Sets up the agent card endpoint and API routes. * @private */ configureRoutes() { // Agent card endpoint this.app.get('/.well-known/agent.json', (_, res) => { res.json(this.agentCard); }); // API routes this.app.use('/api/v1', this.requestHandler.router); } /** * Configures global error handling for the server * * Sets up middleware to catch and format errors according to the A2A protocol. * @private */ configureErrorHandling() { const errorHandler = (err, req, res, next) => { if (err instanceof Error && 'code' in err && 'message' in err) { const a2aError = err; res.status(400).json({ jsonrpc: '2.0', error: Object.assign({ code: a2aError.code, message: a2aError.message }, (a2aError.data && { data: a2aError.data })) }); } console.error(err); res.status(500).json({ jsonrpc: '2.0', error: { code: -32603, message: 'Internal server error' } }); }; this.app.use(errorHandler); } /** * Starts the A2A server on the specified port * * This method starts both the HTTP server and WebSocket server for handling * A2A protocol requests. The WebSocket server is used for streaming messages. * * @param port - The port to listen on (default: 3000) * * @example * ```typescript * // Start on the default port (3000) * server.start(); * * // Start on a specific port * server.start(8080); * ``` */ start(port = 3000) { const server = this.app.listen(port, () => { console.log(`Server running on port ${port}`); }); // Create WebSocket server this.wss = new ws_1.WebSocketServer({ server }); this.wss.on('connection', (ws) => { console.log('New WebSocket connection'); ws.on('message', (data) => __awaiter(this, void 0, void 0, function* () { var _a, e_1, _b, _c; try { const message = JSON.parse(data.toString()); if (message.method === 'streamMessage') { try { for (var _d = true, _e = __asyncValues(this.requestHandler.handleStreamMessage(message.params.parts, message.params.agentId)), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) { _c = _f.value; _d = false; const part = _c; ws.send(JSON.stringify(part)); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (!_d && !_a && (_b = _e.return)) yield _b.call(_e); } finally { if (e_1) throw e_1.error; } } } } catch (err) { ws.send(JSON.stringify(this.requestHandler.normalizeError(err))); } })); ws.on('close', () => { console.log('WebSocket connection closed'); }); }); } } exports.A2AServer = A2AServer; //# sourceMappingURL=app.js.map