UNPKG

@hivetechs/hive-ai

Version:

Real-time streaming AI consensus platform with HTTP+SSE MCP integration for Claude Code, VS Code, Cursor, and Windsurf - powered by OpenRouter's unified API

145 lines 5.79 kB
/** * OpenRouter API Client * Provides unified access to 200+ models from 50+ providers */ export class OpenRouterClient { baseUrl = 'https://openrouter.ai/api/v1'; userAgent = 'hive-tools/1.0.0'; async fetchAllModels() { try { const response = await fetch(`${this.baseUrl}/models`, { method: 'GET', headers: { 'User-Agent': this.userAgent, 'Content-Type': 'application/json', }, }); if (!response.ok) { throw new Error(`OpenRouter API error: ${response.status} ${response.statusText}`); } const data = await response.json(); return this.transformModels(data.data); } catch (error) { throw new Error(`Failed to fetch models from OpenRouter: ${error instanceof Error ? error.message : 'Unknown error'}`); } } transformModels(rawModels) { return rawModels.map(model => { // Extract provider from model ID (format: provider/model-name) const provider = this.extractProvider(model.id); // Convert pricing from per-token to per-1k-tokens const inputCost = parseFloat(model.pricing.prompt) * 1000; const outputCost = parseFloat(model.pricing.completion) * 1000; // Determine capabilities based on modalities const capabilities = this.determineCapabilities(model.architecture); return { id: model.id, name: model.name, provider, description: model.description || '', capabilities, pricing: { input: inputCost, output: outputCost, image: model.pricing.image ? parseFloat(model.pricing.image) : undefined, request: model.pricing.request ? parseFloat(model.pricing.request) : undefined, }, contextWindow: model.context_length, created: model.created, modalities: { input: model.architecture.input_modalities || ['text'], output: model.architecture.output_modalities || ['text'], }, }; }); } extractProvider(modelId) { // Model IDs follow format: "provider/model-name" or just "model-name" const parts = modelId.split('/'); if (parts.length > 1) { return parts[0]; } // Fallback: try to detect provider from common patterns if (modelId.includes('gpt')) return 'openai'; if (modelId.includes('claude')) return 'anthropic'; if (modelId.includes('gemini')) return 'google'; if (modelId.includes('grok')) return 'xai'; if (modelId.includes('llama')) return 'meta'; return 'unknown'; } determineCapabilities(architecture) { const capabilities = []; // All models support chat by default capabilities.push('chat'); // Check for image input if (architecture.input_modalities?.includes('image')) { capabilities.push('vision'); } // Check for other capabilities based on modalities if (architecture.input_modalities?.includes('audio')) { capabilities.push('audio'); } return capabilities; } async getProviderSummary() { const models = await this.fetchAllModels(); const providerMap = new Map(); // Group models by provider models.forEach(model => { if (!providerMap.has(model.provider)) { providerMap.set(model.provider, []); } providerMap.get(model.provider).push(model); }); // Create provider summaries return Array.from(providerMap.entries()).map(([provider, providerModels]) => { const averageCost = this.calculateAverageCost(providerModels); const allCapabilities = new Set(); providerModels.forEach(model => { model.capabilities.forEach(cap => allCapabilities.add(cap)); }); return { name: provider, modelCount: providerModels.length, averageCost, capabilities: Array.from(allCapabilities), models: providerModels, }; }).sort((a, b) => b.modelCount - a.modelCount); // Sort by model count descending } calculateAverageCost(models) { const costs = models.map(model => (model.pricing.input + model.pricing.output) / 2); return costs.reduce((sum, cost) => sum + cost, 0) / costs.length; } searchModels(models, filters) { return models.filter(model => { if (filters.capability && !model.capabilities.includes(filters.capability)) { return false; } if (filters.maxCost) { const avgCost = (model.pricing.input + model.pricing.output) / 2; if (avgCost > filters.maxCost) { return false; } } if (filters.provider && model.provider !== filters.provider) { return false; } if (filters.contextWindow && model.contextWindow < filters.contextWindow) { return false; } return true; }); } compareModels(models, modelIds) { return models.filter(model => modelIds.includes(model.id)); } } export const openRouterClient = new OpenRouterClient(); //# sourceMappingURL=openrouter-client.js.map