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