/** * LLM provider factory. * * Creates an LLMProvider based on LLM_PROVIDER env var. * Auto-detects Azure vs OpenAI from endpoint URLs if not explicitly set. */ import { AzureOpenAIProvider } from './providers/azure-openai.js'; import { MockLLMProvider } from './providers/mock.js'; import { OpenAIProvider } from './providers/openai.js'; import type { LLMProvider, LLMProviderType } from './types.js'; let _provider: LLMProvider | null = null; /** * Resolve provider type from env vars. * Priority: LLM_PROVIDER > OPENAI_PROVIDER > auto-detect from endpoint URLs. */ function resolveProviderType(): LLMProviderType { const explicit = (process.env.LLM_PROVIDER || process.env.OPENAI_PROVIDER || '').toLowerCase(); if (explicit === 'azure') return 'azure'; if (explicit === 'openai') return 'openai'; if (explicit === 'mock') return 'mock'; const azureEndpoint = process.env.AZURE_OPENAI_ENDPOINT; const baseUrl = process.env.OPENAI_BASE_URL || ''; if (azureEndpoint && azureEndpoint.trim().length > 0) return 'azure'; if (baseUrl.includes('.cognitive.microsoft.com') || baseUrl.includes('.openai.azure.com')) return 'azure'; return 'openai'; } /** * Get the singleton LLM provider. */ export function getLLM(): LLMProvider { if (!_provider) { const type = resolveProviderType(); _provider = createLLMProvider(type); } return _provider; } /** * Create an LLM provider by type. */ export function createLLMProvider(type: LLMProviderType): LLMProvider { switch (type) { case 'azure': return new AzureOpenAIProvider(); case 'openai': return new OpenAIProvider(); case 'mock': return new MockLLMProvider(); default: throw new Error(`Unknown LLM_PROVIDER: '${type}'. Valid: azure, openai, mock`); } } /** * Set the singleton LLM provider (for testing). */ export function setLLM(provider: LLMProvider): void { _provider = provider; } /** * @internal */ export function _resetLLM(): void { _provider = null; }