@tehreet/conduit
Version:
LLM API gateway with intelligent routing, robust process management, and health monitoring
285 lines • 9.37 kB
JavaScript
"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