UNPKG

@tehreet/conduit

Version:

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

268 lines 10.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.testRouting = testRouting; exports.formatTestResult = formatTestResult; const router_1 = require("./router"); const plugins_1 = require("../plugins"); const context_extractor_1 = require("./context-extractor"); const config_validator_1 = require("./config-validator"); const constants_1 = require("../constants"); async function testRouting(options) { const result = { selectedModel: '', routingSource: '', tokenCount: 0, synapseContext: null, pluginResults: [], fallbackChain: [], metadata: {}, }; try { // Initialize plugins await (0, router_1.initializePlugins)(constants_1.PLUGINS_DIR); // Calculate token count if (options.tokenCount !== undefined) { result.tokenCount = options.tokenCount; } else if (options.message) { result.tokenCount = (0, config_validator_1.countTokens)(options.message); } else { result.tokenCount = (0, config_validator_1.estimateTokensFromContext)({ projectConfig: options.projectConfig ? JSON.parse(options.projectConfig) : undefined, agentConfig: options.agentConfig ? JSON.parse(options.agentConfig) : undefined, messageContent: options.message, }); } // Create test environment const testEnv = createTestEnvironment(options); // Extract Synapse context const synapseContext = context_extractor_1.ContextExtractor.extractSynapseContext(testEnv); result.synapseContext = synapseContext; // Create mock request const mockRequest = { body: { model: options.model || 'claude-3-5-sonnet-20241022', thinking: options.thinking || false, messages: options.message ? [{ role: 'user', content: options.message }] : [], }, }; // Create routing context const routingContext = { request: mockRequest, tokenCount: result.tokenCount, config: { Router: { default: 'claude-3-5-sonnet-20241022', longContext: 'claude-3-5-sonnet-20241022', background: 'claude-3-5-haiku-20241022', think: 'claude-3-5-sonnet-20241022', }, }, env: testEnv, synapseContext, }; // Test plugin routing await testPluginRouting(routingContext, result, options.verbose); // Test fallback routing if no plugin provided a result if (!result.selectedModel) { await testFallbackRouting(routingContext, result); } return result; } catch (error) { result.selectedModel = 'error'; result.routingSource = 'error'; result.metadata.error = error instanceof Error ? error.message : String(error); return result; } } function createTestEnvironment(options) { const env = {}; // Copy only string values from process.env Object.keys(process.env).forEach(key => { const value = process.env[key]; if (typeof value === 'string') { env[key] = value; } }); if (options.projectConfig) { env.SYNAPSE_PROJECT_MODEL_CONFIG = options.projectConfig; env.SYNAPSE_PROJECT_ID = 'test-project-id'; } if (options.agentConfig) { env.SYNAPSE_AGENT_MODEL_CONFIG = options.agentConfig; env.SYNAPSE_AGENT_ID = 'test-agent-id'; env.SYNAPSE_AGENT_TYPE = 'test-agent'; } return env; } async function testPluginRouting(context, result, verbose) { try { const manager = new plugins_1.DefaultPluginManager(); await manager.loadPlugins(constants_1.PLUGINS_DIR); const pluginResults = []; // Test each plugin individually if verbose mode if (verbose) { const plugins = manager.getRegisteredPlugins(); for (const pluginName of plugins) { try { const plugin = manager.getPlugin(pluginName); if (plugin?.customRouter) { const pluginResult = await plugin.customRouter(context); pluginResults.push({ pluginName, result: pluginResult ? pluginResult.model : null }); if (pluginResult && !result.selectedModel) { result.selectedModel = pluginResult.model; result.routingSource = `plugin:${pluginName}`; result.fallbackChain.push(`plugin:${pluginName}`); } } else { pluginResults.push({ pluginName, result: null }); } } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); pluginResults.push({ pluginName, result: null, error: errorMsg, }); } } } else { // Test all plugins together (normal execution) const pluginModel = await manager.executeCustomRouting(context); if (pluginModel) { result.selectedModel = pluginModel.model; result.routingSource = 'plugins'; result.fallbackChain.push('plugins'); } } result.pluginResults = pluginResults; } catch (error) { result.metadata.pluginError = error instanceof Error ? error.message : String(error); } } async function testFallbackRouting(context, result) { // Test Synapse context routing if (context.synapseContext?.projectId || context.synapseContext?.agentId) { const synapseModel = await testSynapseContextRouting(context); if (synapseModel) { result.selectedModel = synapseModel; result.routingSource = 'synapse-context'; result.fallbackChain.push('synapse-context'); return; } result.fallbackChain.push('synapse-context (no match)'); } // Test standard Conduit routing const standardModel = testStandardRouting(context); if (standardModel) { result.selectedModel = standardModel; result.routingSource = 'standard-routing'; result.fallbackChain.push('standard-routing'); return; } // Final fallback result.selectedModel = context.config.Router?.default || 'claude-3-5-sonnet-20241022'; result.routingSource = 'default-fallback'; result.fallbackChain.push('default-fallback'); } async function testSynapseContextRouting(context) { const { synapseContext } = context; // Test agent config if (synapseContext.agentModelConfig) { try { const agentConfig = JSON.parse(synapseContext.agentModelConfig); if (!agentConfig.useProjectDefaults && agentConfig.overrideModel) { return agentConfig.overrideModel; } } catch (error) { // Ignore parsing errors } } // Test project config if (synapseContext.projectModelConfig) { try { const projectConfig = JSON.parse(synapseContext.projectModelConfig); if (projectConfig.enabled && projectConfig.defaultModel) { return projectConfig.defaultModel; } } catch (error) { // Ignore parsing errors } } return null; } function testStandardRouting(context) { const { request, tokenCount, config } = context; // Long context model if (tokenCount > 60000 && config.Router?.longContext) { return config.Router.longContext; } // Background model for Haiku if (request.body.model?.startsWith('claude-3-5-haiku') && config.Router?.background) { return config.Router.background; } // Thinking model if (request.body.thinking && config.Router?.think) { return config.Router.think; } return null; } function formatTestResult(result, verbose = false) { const lines = []; lines.push(`🎯 Selected Model: ${result.selectedModel}`); lines.push(`📍 Routing Source: ${result.routingSource}`); lines.push(`🔢 Token Count: ${result.tokenCount}`); if (result.fallbackChain.length > 0) { lines.push(`🔄 Fallback Chain: ${result.fallbackChain.join(' → ')}`); } if (result.synapseContext && (result.synapseContext.projectId || result.synapseContext.agentId)) { lines.push(`🔧 Synapse Context:`); if (result.synapseContext.projectId) { lines.push(` Project ID: ${result.synapseContext.projectId}`); } if (result.synapseContext.agentId) { lines.push(` Agent ID: ${result.synapseContext.agentId}`); } } if (verbose && result.pluginResults && result.pluginResults.length > 0) { lines.push(`🔌 Plugin Results:`); for (const pluginResult of result.pluginResults) { if (pluginResult.error) { lines.push(` ${pluginResult.pluginName}: ❌ ${pluginResult.error}`); } else if (pluginResult.result) { lines.push(` ${pluginResult.pluginName}: ✅ ${pluginResult.result}`); } else { lines.push(` ${pluginResult.pluginName}: ⏭️ no result`); } } } if (result.metadata.error) { lines.push(`❌ Error: ${result.metadata.error}`); } if (result.metadata.pluginError) { lines.push(`🔌 Plugin Error: ${result.metadata.pluginError}`); } return lines.join('\n'); } //# sourceMappingURL=routing-tester.js.map