import type { ModelProvider, APIResponse, ChatMessage } from "@/types"; import OllamaCloudService from "./ollama-cloud"; import ZaiPlanService from "./zai-plan"; export interface ModelAdapterConfig { ollama?: { apiKey?: string; endpoint?: string; }; zai?: { apiKey?: string; generalEndpoint?: string; codingEndpoint?: string; }; } export class ModelAdapter { private ollamaService: OllamaCloudService; private zaiService: ZaiPlanService; private preferredProvider: ModelProvider; constructor(config: ModelAdapterConfig = {}, preferredProvider: ModelProvider = "ollama") { this.ollamaService = new OllamaCloudService(config.ollama); this.zaiService = new ZaiPlanService(config.zai); this.preferredProvider = preferredProvider; } setPreferredProvider(provider: ModelProvider): void { this.preferredProvider = provider; } updateOllamaApiKey(apiKey: string): void { this.ollamaService = new OllamaCloudService({ apiKey }); } updateZaiApiKey(apiKey: string): void { this.zaiService = new ZaiPlanService({ apiKey }); } private async callWithFallback( operation: (service: any) => Promise>, providers: ModelProvider[] ): Promise> { for (const provider of providers) { try { let service: any; switch (provider) { case "ollama": service = this.ollamaService; break; case "zai": service = this.zaiService; break; } const result = await operation(service); if (result.success) { return result; } } catch (error) { console.error(`Error with ${provider}:`, error); } } return { success: false, error: "All providers failed", }; } async enhancePrompt(prompt: string, provider?: ModelProvider, model?: string): Promise> { const providers: ModelProvider[] = provider ? [provider] : [this.preferredProvider, "ollama", "zai"]; return this.callWithFallback((service) => service.enhancePrompt(prompt, model), providers); } async generatePRD(idea: string, provider?: ModelProvider, model?: string): Promise> { const providers: ModelProvider[] = provider ? [provider] : ["ollama", "zai", this.preferredProvider]; return this.callWithFallback((service) => service.generatePRD(idea, model), providers); } async generateActionPlan(prd: string, provider?: ModelProvider, model?: string): Promise> { const providers: ModelProvider[] = provider ? [provider] : ["zai", "ollama", this.preferredProvider]; return this.callWithFallback((service) => service.generateActionPlan(prd, model), providers); } async generateUXDesignerPrompt(appDescription: string, provider?: ModelProvider, model?: string): Promise> { const providers: ModelProvider[] = provider ? [provider] : [this.preferredProvider, "ollama", "zai"]; return this.callWithFallback((service) => service.generateUXDesignerPrompt(appDescription, model), providers); } async chatCompletion( messages: ChatMessage[], model: string, provider: ModelProvider = this.preferredProvider ): Promise> { try { let service: any; switch (provider) { case "ollama": service = this.ollamaService; break; case "zai": service = this.zaiService; break; } return await service.chatCompletion(messages, model); } catch (error) { return { success: false, error: error instanceof Error ? error.message : "Chat completion failed", }; } } async listModels(provider?: ModelProvider): Promise>> { const fallbackModels: Record = { ollama: ["gpt-oss:120b", "llama3.1", "gemma3", "deepseek-r1", "qwen3"], zai: ["glm-4.7", "glm-4.5", "glm-4.5-air", "glm-4-flash", "glm-4-flashx"], }; const models: Record = { ...fallbackModels }; if (provider === "ollama" || !provider) { try { const ollamaModels = await this.ollamaService.listModels(); if (ollamaModels.success && ollamaModels.data && ollamaModels.data.length > 0) { models.ollama = ollamaModels.data; } } catch (error) { console.error("[ModelAdapter] Failed to load Ollama models, using fallback:", error); } } if (provider === "zai" || !provider) { try { const zaiModels = await this.zaiService.listModels(); if (zaiModels.success && zaiModels.data && zaiModels.data.length > 0) { models.zai = zaiModels.data; } } catch (error) { console.error("[ModelAdapter] Failed to load Z.AI models, using fallback:", error); } } return { success: true, data: models }; } getAvailableModels(provider: ModelProvider): string[] { switch (provider) { case "ollama": return this.ollamaService.getAvailableModels(); case "zai": return this.zaiService.getAvailableModels(); default: return []; } } } export default ModelAdapter;