route-claudecode
Version:
Advanced routing and transformation system for Claude Code outputs to multiple AI providers
450 lines • 17 kB
JavaScript
"use strict";
/**
* 动态模型配置管理器
* 集成模型发现系统并管理模型配置更新
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.DEFAULT_MODEL_CONFIG_MANAGER_CONFIG = exports.DynamicModelConfigManager = void 0;
exports.createDynamicModelConfigManager = createDynamicModelConfigManager;
const logger_1 = require("@/utils/logger");
const dynamic_model_discovery_1 = require("./dynamic-model-discovery");
/**
* 动态模型配置管理器
*/
class DynamicModelConfigManager {
config;
discoveries = new Map();
providerConfigs = new Map();
updateListeners = new Set();
discoveryIntervalId;
constructor(config) {
this.config = config;
logger_1.logger.info('Dynamic Model Config Manager initialized', { config }, 'model-config-manager');
}
/**
* 注册提供商
*/
async registerProvider(providerId, providerConfig) {
logger_1.logger.info('Registering provider for model discovery', { providerId }, 'model-config-manager');
// 创建模型发现实例
const discoveryConfig = {
provider: providerConfig,
providerId,
maxRetries: this.config.testRetries,
retryDelay: 1000,
requestTimeout: this.config.testTimeout,
testPrompt: 'Hello, please respond briefly.',
maxTokens: 50
};
const discovery = (0, dynamic_model_discovery_1.createDynamicModelDiscovery)(discoveryConfig);
this.discoveries.set(providerId, discovery);
// 初始化提供商配置
this.providerConfigs.set(providerId, {
providerId,
models: [],
lastUpdated: 0,
isHealthy: false
});
// 如果启用自动发现,立即执行第一次发现
if (this.config.autoDiscovery) {
await this.discoverProviderModels(providerId);
}
logger_1.logger.info('Provider registered successfully', { providerId }, 'model-config-manager');
}
/**
* 注销提供商
*/
unregisterProvider(providerId) {
logger_1.logger.info('Unregistering provider', { providerId }, 'model-config-manager');
this.discoveries.delete(providerId);
this.providerConfigs.delete(providerId);
logger_1.logger.info('Provider unregistered successfully', { providerId }, 'model-config-manager');
}
/**
* 手动触发提供商模型发现
*/
async discoverProviderModels(providerId) {
logger_1.logger.info('Starting manual model discovery', { providerId }, 'model-config-manager');
const discovery = this.discoveries.get(providerId);
if (!discovery) {
throw new Error(`Provider ${providerId} not registered`);
}
// 执行模型发现
const result = await discovery.discoverModels();
// 更新提供商配置
await this.updateProviderModelConfig(providerId, result);
// 触发更新事件
this.notifyModelUpdateListeners(providerId, result);
logger_1.logger.info('Manual model discovery completed', {
providerId,
totalModels: result.totalModels,
availableModels: result.availableModels.length,
unavailableModels: result.unavailableModels.length
}, 'model-config-manager');
return result;
}
/**
* 测试特定模型可用性
*/
async testModelAvailability(providerId, modelId) {
logger_1.logger.debug('Testing model availability', { providerId, modelId }, 'model-config-manager');
const discovery = this.discoveries.get(providerId);
if (!discovery) {
throw new Error(`Provider ${providerId} not registered`);
}
try {
const result = await discovery.testModelAvailability(modelId, 3);
// 更新模型配置
const providerConfig = this.providerConfigs.get(providerId);
if (providerConfig) {
const modelConfig = providerConfig.models.find(m => m.id === modelId);
if (modelConfig) {
const oldAvailability = modelConfig.isAvailable;
modelConfig.isAvailable = result.isAvailable;
modelConfig.lastChecked = result.testTimestamp;
modelConfig.responseTime = result.responseTime;
// 如果可用性发生变化,触发事件
if (oldAvailability !== result.isAvailable) {
this.notifySingleModelUpdate(providerId, {
type: result.isAvailable ? 'model_became_available' : 'model_became_unavailable',
providerId,
modelId,
timestamp: Date.now(),
details: { result }
});
}
}
}
logger_1.logger.debug('Model availability test completed', {
providerId,
modelId,
isAvailable: result.isAvailable,
responseTime: result.responseTime
}, 'model-config-manager');
return result.isAvailable;
}
catch (error) {
logger_1.logger.error('Model availability test failed', {
providerId,
modelId,
error: error instanceof Error ? error.message : String(error)
}, 'model-config-manager');
return false;
}
}
/**
* 获取提供商的模型配置
*/
getProviderModels(providerId) {
const providerConfig = this.providerConfigs.get(providerId);
return providerConfig ? providerConfig.models : [];
}
/**
* 获取所有提供商的模型配置
*/
getAllModels() {
const allModels = [];
for (const providerConfig of this.providerConfigs.values()) {
allModels.push(...providerConfig.models);
}
return allModels;
}
/**
* 获取可用的模型(按类别筛选)
*/
getAvailableModels(category) {
let models = this.getAllModels().filter(m => m.isAvailable);
if (category) {
models = models.filter(m => m.category === category);
}
// 按优先级排序
return models.sort((a, b) => b.priority - a.priority);
}
/**
* 获取模型配置
*/
getModelConfig(providerId, modelId) {
const providerConfig = this.providerConfigs.get(providerId);
return providerConfig?.models.find(m => m.id === modelId);
}
/**
* 开始自动发现循环
*/
startAutoDiscovery() {
if (this.discoveryIntervalId) {
logger_1.logger.warn('Auto discovery already started', {}, 'model-config-manager');
return;
}
logger_1.logger.info('Starting auto discovery loop', {
interval: this.config.discoveryInterval + ' minutes'
}, 'model-config-manager');
this.discoveryIntervalId = setInterval(async () => {
await this.runAutoDiscoveryCycle();
}, this.config.discoveryInterval * 60 * 1000);
// 立即执行第一次循环
this.runAutoDiscoveryCycle().catch(error => {
logger_1.logger.error('Auto discovery cycle failed', error, 'model-config-manager');
});
}
/**
* 停止自动发现循环
*/
stopAutoDiscovery() {
if (this.discoveryIntervalId) {
clearInterval(this.discoveryIntervalId);
this.discoveryIntervalId = undefined;
logger_1.logger.info('Auto discovery stopped', {}, 'model-config-manager');
}
}
/**
* 添加模型更新监听器
*/
addModelUpdateListener(listener) {
this.updateListeners.add(listener);
}
/**
* 移除模型更新监听器
*/
removeModelUpdateListener(listener) {
this.updateListeners.delete(listener);
}
/**
* 获取管理器状态
*/
getStatus() {
const cacheStats = Array.from(this.discoveries.values()).map(d => d.getCacheStats());
return {
registeredProviders: Array.from(this.discoveries.keys()),
totalModels: this.getAllModels().length,
availableModels: this.getAllModels().filter(m => m.isAvailable).length,
isAutoDiscoveryRunning: !!this.discoveryIntervalId,
cacheStats,
lastUpdateTime: Math.max(...Array.from(this.providerConfigs.values()).map(c => c.lastUpdated))
};
}
/**
* 清除所有缓存
*/
clearAllCaches() {
for (const discovery of this.discoveries.values()) {
discovery.clearCache();
}
logger_1.logger.info('All model discovery caches cleared', {}, 'model-config-manager');
}
/**
* 自动发现循环
*/
async runAutoDiscoveryCycle() {
logger_1.logger.debug('Running auto discovery cycle', {}, 'model-config-manager');
const providers = Array.from(this.discoveries.keys());
for (const providerId of providers) {
try {
await this.discoverProviderModels(providerId);
}
catch (error) {
logger_1.logger.error('Auto discovery cycle failed for provider', {
providerId,
error: error instanceof Error ? error.message : String(error)
}, 'model-config-manager');
}
// 提供商发现间隔
await this.delay(5000);
}
}
/**
* 更新提供商模型配置
*/
async updateProviderModelConfig(providerId, result) {
const discovery = this.discoveries.get(providerId);
const providerConfig = this.providerConfigs.get(providerId);
// 获取现有模型配置
const existingModels = new Map(providerConfig.models.map(m => [m.id, m]));
const newModels = [];
const updatedModels = [];
// 处理可用模型
for (const modelId of result.availableModels) {
const existingModel = existingModels.get(modelId);
if (existingModel) {
// 更新现有模型
existingModel.isAvailable = true;
existingModel.lastChecked = result.discoveryTimestamp;
updatedModels.push(existingModel);
existingModels.delete(modelId);
}
else {
// 添加新模型
const modelConfig = await this.createModelConfigFromDiscovery(providerId, modelId, discovery);
newModels.push(modelConfig);
}
}
// 处理不可用模型
for (const modelId of result.unavailableModels) {
const existingModel = existingModels.get(modelId);
if (existingModel) {
// 更新现有模型为不可用
existingModel.isAvailable = false;
existingModel.lastChecked = result.discoveryTimestamp;
updatedModels.push(existingModel);
existingModels.delete(modelId);
}
}
// 处理不再存在的模型(标记为不可用)
for (const existingModel of existingModels.values()) {
existingModel.isAvailable = false;
existingModel.lastChecked = result.discoveryTimestamp;
updatedModels.push(existingModel);
}
// 限制模型数量
const finalModels = [...newModels, ...updatedModels]
.slice(0, this.config.maxModelsPerProvider)
.sort((a, b) => b.priority - a.priority);
// 更新提供商配置
providerConfig.models = finalModels;
providerConfig.lastUpdated = result.discoveryTimestamp;
providerConfig.isHealthy = result.availableModels.length > 0;
logger_1.logger.info('Provider model config updated', {
providerId,
totalModels: finalModels.length,
newModels: newModels.length,
updatedModels: updatedModels.length,
availableModels: result.availableModels.length,
averageResponseTime: result.averageResponseTime
}, 'model-config-manager');
}
/**
* 从发现结果创建模型配置
*/
async createModelConfigFromDiscovery(providerId, modelId, discovery) {
// 测试模型可用性以获取响应时间
const availabilityResult = await discovery.testModelAvailability(modelId, 1);
// 推断模型类别
const category = this.inferModelCategory(modelId);
// 推断模型优先级
const priority = this.inferModelPriority(modelId);
return {
id: modelId,
name: modelId,
description: `Discovered model: ${modelId}`,
capabilities: {
text: true,
vision: false, // 需要通过测试确定
tools: false, // 需要通过测试确定
streaming: true
},
isAvailable: availabilityResult.isAvailable,
lastChecked: availabilityResult.testTimestamp,
responseTime: availabilityResult.responseTime,
category,
priority
};
}
/**
* 推断模型类别
*/
inferModelCategory(modelId) {
const lowerId = modelId.toLowerCase();
if (lowerId.includes('haiku') || lowerId.includes('fast') || lowerId.includes('quick')) {
return 'background';
}
if (lowerId.includes('thinking') || lowerId.includes('reasoning') || lowerId.includes('chain')) {
return 'thinking';
}
if (lowerId.includes('long') || lowerId.includes('context') || lowerId.includes('128k')) {
return 'longcontext';
}
if (lowerId.includes('search') || lowerId.includes('rag') || lowerId.includes('retrieval')) {
return 'search';
}
return 'default';
}
/**
* 推断模型优先级
*/
inferModelPriority(modelId) {
const lowerId = modelId.toLowerCase();
// 最新模型优先级最高
if (lowerId.includes('claude-3-5') || lowerId.includes('gpt-4-turbo') || lowerId.includes('gemini-1.5-pro')) {
return 100;
}
if (lowerId.includes('claude-3') || lowerId.includes('gpt-4') || lowerId.includes('gemini-pro')) {
return 80;
}
if (lowerId.includes('claude-2') || lowerId.includes('gpt-3.5') || lowerId.includes('gemini-1.0')) {
return 60;
}
// 开源模型
if (lowerId.includes('llama') || lowerId.includes('mistral') || lowerId.includes('qwen')) {
return 40;
}
// 未知模型默认优先级
return 20;
}
/**
* 通知模型更新监听器
*/
notifyModelUpdateListeners(providerId, result) {
const providerConfig = this.providerConfigs.get(providerId);
if (!providerConfig)
return;
const existingModels = new Set(this.providerConfigs.get(providerId)?.models.map(m => m.id) || []);
// 检测新添加的模型
for (const modelId of result.availableModels) {
if (!existingModels.has(modelId)) {
this.notifySingleModelUpdate(providerId, {
type: 'model_added',
providerId,
modelId,
timestamp: Date.now(),
details: { result }
});
}
}
}
/**
* 通知单个模型更新
*/
notifySingleModelUpdate(providerId, event) {
const fullEvent = {
...event,
providerId
};
for (const listener of this.updateListeners) {
try {
listener(fullEvent);
}
catch (error) {
logger_1.logger.error('Model update listener error', {
providerId,
eventId: `${event.type}-${event.modelId}`,
error: error instanceof Error ? error.message : String(error)
}, 'model-config-manager');
}
}
}
/**
* 延迟函数
*/
delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
exports.DynamicModelConfigManager = DynamicModelConfigManager;
/**
* 工厂函数创建动态模型配置管理器
*/
function createDynamicModelConfigManager(config) {
return new DynamicModelConfigManager(config);
}
/**
* 默认配置
*/
exports.DEFAULT_MODEL_CONFIG_MANAGER_CONFIG = {
autoDiscovery: true,
discoveryInterval: 30, // 30分钟
maxModelsPerProvider: 10,
testRetries: 3,
testTimeout: 30000,
enableCaching: true,
cacheExpiry: 60 // 60分钟
};
//# sourceMappingURL=dynamic-model-config-manager.js.map