UNPKG

@tehreet/conduit

Version:

LLM API gateway with intelligent routing, robust process management, and health monitoring

285 lines 9.37 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ConduitServer = void 0; const events_1 = require("events"); const ConduitRouter_1 = require("../router/ConduitRouter"); const EnhancedPluginManager_1 = require("../plugins/EnhancedPluginManager"); const HealthMonitor_1 = require("../monitoring/HealthMonitor"); const serverWrapper_1 = require("../serverWrapper"); const log_1 = require("../utils/log"); const deepseek_1 = require("../transformers/deepseek"); /** * Enhanced ConduitServer with full programmatic API */ class ConduitServer extends events_1.EventEmitter { constructor(config) { super(); this.isStarted = false; this.config = config; this.startTime = new Date(); // Initialize components this.pluginManager = new EnhancedPluginManager_1.PluginManager(); this.router = new ConduitRouter_1.ConduitRouter(config, this.pluginManager); this.healthMonitor = new HealthMonitor_1.HealthMonitor(); // Set up event forwarding this.setupEventForwarding(); } /** * Start the server */ async start() { if (this.isStarted) { (0, log_1.log)('Server is already started'); return; } try { (0, log_1.log)('Starting ConduitServer...'); // Load plugins if (this.config.plugins && this.config.plugins.length > 0) { await this.pluginManager.loadPlugins(this.config.plugins); (0, log_1.log)(`Loaded ${this.pluginManager.getPluginCount()} plugins`); } // Initialize router await this.router.initialize(); (0, log_1.log)('Router initialized'); // Start health monitoring if (this.config.monitoring?.health?.enabled !== false) { this.healthMonitor.start(); (0, log_1.log)('Health monitoring started'); } // Create and start legacy server for HTTP handling this.legacyServer = (0, serverWrapper_1.createConduitServer)({ initialConfig: { ...this.config, PORT: this.config.server?.port || 3456, HOST: this.config.server?.host || '127.0.0.1' }, gracefulShutdownTimeout: this.config.server?.timeout || 30000, onShutdown: async () => { await this.cleanup(); } }); // Register custom transformers this.legacyServer.getServer().transformerService.registerTransformer('deepseek', new deepseek_1.DeepseekTransformer()); // Add our enhanced routing middleware this.legacyServer.addHook('preHandler', async (req, reply) => { await this.handleRequest(req, reply); }); // Start the legacy server await this.legacyServer.start(); this.isStarted = true; this.emit('started'); const port = this.config.server?.port || 3456; (0, log_1.log)(`ConduitServer started on port ${port}`); } catch (error) { (0, log_1.log)('Failed to start ConduitServer:', error); this.emit('error', error); throw error; } } /** * Stop the server */ async stop() { if (!this.isStarted) { (0, log_1.log)('Server is not started'); return; } try { (0, log_1.log)('Stopping ConduitServer...'); this.isStarted = false; this.emit('stopping'); // Stop health monitoring this.healthMonitor.stop(); // Stop legacy server if (this.legacyServer) { await this.legacyServer.getServer().close(); } // Cleanup plugins await this.pluginManager.cleanup(); // Cleanup router await this.router.cleanup(); this.emit('stopped'); (0, log_1.log)('ConduitServer stopped'); } catch (error) { (0, log_1.log)('Error stopping ConduitServer:', error); this.emit('error', error); throw error; } } /** * Route a single request programmatically */ async route(context) { if (!this.isStarted) { throw new Error('Server is not started'); } return await this.router.route(context); } /** * Get server health status */ getHealth() { return this.healthMonitor.getStatus(); } /** * Update server configuration */ async updateConfig(config) { (0, log_1.log)('Updating server configuration'); this.config = { ...this.config, ...config, server: { ...this.config.server, ...config.server }, Router: { ...this.config.Router, ...config.Router } }; // Update router configuration await this.router.updateConfig(this.config); // Reload plugins if plugin config changed if (config.plugins) { await this.pluginManager.cleanup(); await this.pluginManager.loadPlugins(config.plugins); } this.emit('config-updated', this.config); } /** * Get current configuration */ getConfig() { return { ...this.config }; } /** * Check if server is running */ isRunning() { return this.isStarted; } /** * Get server uptime in milliseconds */ getUptime() { return Date.now() - this.startTime.getTime(); } /** * Get plugin manager instance */ getPluginManager() { return this.pluginManager; } /** * Get router instance */ getRouter() { return this.router; } /** * Get health monitor instance */ getHealthMonitor() { return this.healthMonitor; } /** * Add a custom health check */ addHealthCheck(name, check) { this.healthMonitor.registerCheck(name, check); } /** * Add middleware hook */ addHook(event, handler) { if (this.legacyServer) { this.legacyServer.addHook(event, handler); } } /** * Handle incoming HTTP requests */ async handleRequest(req, reply) { try { // Skip health endpoints - they're handled by the legacy server if (req.url === '/health' || req.url === '/ready' || req.url === '/alive') { return; } // Skip non-routing requests if (req.method !== 'POST' || !req.url.startsWith('/v1/')) { return; } // Create routing context const context = { request: req, tokenCount: 0, // Will be calculated by router config: this.config, env: process.env, requestBody: req.body, // Add request body for plugins synapseContext: req.body?.synapseContext, // Add synapse context directly }; // Route the request const decision = await this.router.route(context); // Emit routing event this.emit('routing-decision', { context, decision }); // Apply routing decision to request if (req.body && decision.model) { req.body.model = decision.model; } } catch (error) { (0, log_1.log)('Error handling request:', error); this.emit('request-error', error); // Continue with request processing even if routing fails } } /** * Set up event forwarding from components */ setupEventForwarding() { // Forward router events this.router.on('routing-decision', (data) => { this.emit('routing-decision', data); }); this.router.on('error', (error) => { this.emit('router-error', error); }); // Forward plugin events this.pluginManager.on('plugin-loaded', (plugin) => { this.emit('plugin-loaded', plugin); }); this.pluginManager.on('plugin-error', (error) => { this.emit('plugin-error', error); }); // Forward health events this.healthMonitor.on('health-check', (status) => { this.emit('health-check', status); }); this.healthMonitor.on('health-warning', (warning) => { this.emit('health-warning', warning); }); } /** * Cleanup resources */ async cleanup() { (0, log_1.log)('Cleaning up ConduitServer resources'); try { // Stop health monitoring this.healthMonitor.stop(); // Cleanup plugins await this.pluginManager.cleanup(); // Cleanup router await this.router.cleanup(); } catch (error) { (0, log_1.log)('Error during cleanup:', error); } } } exports.ConduitServer = ConduitServer; //# sourceMappingURL=ConduitServer.js.map