Skip to main content
Glama

mcp-github-project-manager

AIServiceFactory.ts7.79 kB
import { anthropic } from '@ai-sdk/anthropic'; import { openai } from '@ai-sdk/openai'; import { google } from '@ai-sdk/google'; import { perplexity } from '@ai-sdk/perplexity'; import { LanguageModel } from 'ai'; import { ANTHROPIC_API_KEY, OPENAI_API_KEY, GOOGLE_API_KEY, PERPLEXITY_API_KEY, AI_MAIN_MODEL, AI_RESEARCH_MODEL, AI_FALLBACK_MODEL, AI_PRD_MODEL } from '../../env'; /** * AI Provider Types */ export type AIProvider = 'anthropic' | 'openai' | 'google' | 'perplexity'; /** * AI Model Configuration */ export interface AIModelConfig { provider: AIProvider; model: string; apiKey: string; } /** * AI Service Configuration */ export interface AIServiceConfig { main: AIModelConfig | null; research: AIModelConfig | null; fallback: AIModelConfig | null; prd: AIModelConfig | null; } /** * Factory for creating AI service instances with Vercel AI SDK */ export class AIServiceFactory { private static instance: AIServiceFactory; private config: AIServiceConfig; private constructor() { this.config = this.buildConfiguration(); } /** * Get singleton instance */ public static getInstance(): AIServiceFactory { if (!AIServiceFactory.instance) { AIServiceFactory.instance = new AIServiceFactory(); } return AIServiceFactory.instance; } /** * Build AI service configuration from environment variables */ private buildConfiguration(): AIServiceConfig { return { main: this.parseModelConfig(AI_MAIN_MODEL), research: this.parseModelConfig(AI_RESEARCH_MODEL), fallback: this.parseModelConfig(AI_FALLBACK_MODEL), prd: this.parseModelConfig(AI_PRD_MODEL) }; } /** * Parse model configuration from model string */ private parseModelConfig(modelString: string): AIModelConfig | null { // Extract provider from model name let provider: AIProvider; let model: string; let apiKey: string; if (modelString.startsWith('claude-')) { provider = 'anthropic'; model = modelString; apiKey = ANTHROPIC_API_KEY; } else if (modelString.startsWith('gpt-') || modelString.startsWith('o1')) { provider = 'openai'; model = modelString; apiKey = OPENAI_API_KEY; } else if (modelString.startsWith('gemini-')) { provider = 'google'; model = modelString; apiKey = GOOGLE_API_KEY; } else if (modelString.includes('perplexity') || modelString.includes('llama') || modelString.includes('sonar')) { provider = 'perplexity'; model = modelString; apiKey = PERPLEXITY_API_KEY; } else { // Default to anthropic for unknown models provider = 'anthropic'; model = 'claude-3-5-sonnet-20241022'; apiKey = ANTHROPIC_API_KEY; } if (!apiKey) { process.stderr.write(`⚠️ AI Provider Warning: No API key found for ${provider} provider. AI features using this provider will be disabled.\n`); return null; } return { provider, model, apiKey }; } /** * Get AI model instance for specific use case */ public getModel(type: 'main' | 'research' | 'fallback' | 'prd'): LanguageModel | null { const config = this.config[type]; if (!config) { process.stderr.write(`⚠️ AI Model Warning: ${type} model is not available due to missing API key.\n`); return null; } switch (config.provider) { case 'anthropic': return anthropic(config.model); case 'openai': return openai(config.model); case 'google': return google(config.model); case 'perplexity': return perplexity(config.model); default: throw new Error(`Unsupported AI provider: ${config.provider}`); } } /** * Get main AI model (for general task generation) */ public getMainModel(): LanguageModel | null { return this.getModel('main'); } /** * Get research AI model (for enhanced analysis) */ public getResearchModel(): LanguageModel | null { return this.getModel('research'); } /** * Get fallback AI model (when main model fails) */ public getFallbackModel(): LanguageModel | null { return this.getModel('fallback'); } /** * Get PRD AI model (for PRD generation) */ public getPRDModel(): LanguageModel | null { return this.getModel('prd'); } /** * Get the best available model with fallback logic * Tries models in order of preference: main -> fallback -> any available */ public getBestAvailableModel(): LanguageModel | null { // Try main model first const mainModel = this.getMainModel(); if (mainModel) return mainModel; // Try fallback model const fallbackModel = this.getFallbackModel(); if (fallbackModel) return fallbackModel; // Try PRD model const prdModel = this.getPRDModel(); if (prdModel) return prdModel; // Try research model const researchModel = this.getResearchModel(); if (researchModel) return researchModel; // No models available return null; } /** * Check if any AI functionality is available */ public isAIAvailable(): boolean { return this.getBestAvailableModel() !== null; } /** * Get configuration for debugging */ public getConfiguration(): AIServiceConfig { return { ...this.config }; } /** * Check AI provider availability and configuration status */ public validateConfiguration(): { hasAnyProvider: boolean; available: string[]; missing: string[]; availableModels: string[]; unavailableModels: string[]; } { const missing: string[] = []; const available: string[] = []; const availableModels: string[] = []; const unavailableModels: string[] = []; // Check each provider if (!ANTHROPIC_API_KEY) { missing.push('ANTHROPIC_API_KEY'); } else { available.push('anthropic'); } if (!OPENAI_API_KEY) { missing.push('OPENAI_API_KEY'); } else { available.push('openai'); } if (!GOOGLE_API_KEY) { missing.push('GOOGLE_API_KEY'); } else { available.push('google'); } if (!PERPLEXITY_API_KEY) { missing.push('PERPLEXITY_API_KEY'); } else { available.push('perplexity'); } // Check which models are available if (this.config.main) availableModels.push('main'); else unavailableModels.push('main'); if (this.config.research) availableModels.push('research'); else unavailableModels.push('research'); if (this.config.fallback) availableModels.push('fallback'); else unavailableModels.push('fallback'); if (this.config.prd) availableModels.push('prd'); else unavailableModels.push('prd'); return { hasAnyProvider: available.length > 0, available, missing, availableModels, unavailableModels }; } /** * Test connection to AI providers */ public async testConnections(): Promise<{ [key in AIProvider]: boolean }> { const results: { [key in AIProvider]: boolean } = { anthropic: false, openai: false, google: false, perplexity: false }; // Test each provider if API key is available if (ANTHROPIC_API_KEY) { try { const model = this.getModel('main'); if (model) { // Simple test generation using generateText from ai package const { generateText } = await import('ai'); await generateText({ model, prompt: 'Test connection', maxTokens: 10 }); results.anthropic = true; } } catch (error) { process.stderr.write(`Anthropic connection test failed: ${error}\n`); } } // Add similar tests for other providers as needed return results; } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/kunwarVivek/mcp-github-project-manager'

If you have feedback or need assistance with the MCP directory API, please join our Discord server