Files
ai/gateway/src/llm/provider.ts
2026-03-27 16:33:40 -04:00

141 lines
3.1 KiB
TypeScript

import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
import { ChatAnthropic } from '@langchain/anthropic';
import type { FastifyBaseLogger } from 'fastify';
/**
* Supported LLM providers
*/
export enum LLMProvider {
ANTHROPIC = 'anthropic',
}
/**
* Model configuration
*/
export interface ModelConfig {
provider: LLMProvider;
model: string;
temperature?: number;
maxTokens?: number;
}
/**
* License tier model configuration
*/
export interface LicenseTierModels {
default: string;
cost_optimized: string;
complex: string;
allowed_models?: string[];
blocked_models?: string[];
}
/**
* License models configuration
*/
export interface LicenseModelsConfig {
free: LicenseTierModels;
pro: LicenseTierModels;
enterprise: LicenseTierModels;
}
/**
* Provider configuration with API keys
*/
export interface ProviderConfig {
anthropicApiKey?: string;
defaultModel?: ModelConfig;
licenseModels?: LicenseModelsConfig;
}
/**
* LLM Provider factory
* Creates model instances with unified interface across providers
*/
export class LLMProviderFactory {
private config: ProviderConfig;
private logger: FastifyBaseLogger;
constructor(config: ProviderConfig, logger: FastifyBaseLogger) {
this.config = config;
this.logger = logger;
}
/**
* Create a chat model instance
*/
createModel(modelConfig: ModelConfig): BaseChatModel {
this.logger.debug(
{ provider: modelConfig.provider, model: modelConfig.model },
'Creating LLM model'
);
switch (modelConfig.provider) {
case LLMProvider.ANTHROPIC:
return this.createAnthropicModel(modelConfig);
default:
throw new Error(`Unsupported provider: ${modelConfig.provider}`);
}
}
/**
* Create Anthropic Claude model
*/
private createAnthropicModel(config: ModelConfig): ChatAnthropic {
if (!this.config.anthropicApiKey) {
throw new Error('Anthropic API key not configured');
}
return new ChatAnthropic({
model: config.model,
temperature: config.temperature ?? 0.7,
maxTokens: config.maxTokens ?? 4096,
anthropicApiKey: this.config.anthropicApiKey,
});
}
/**
* Get default model based on environment
*/
getDefaultModel(): ModelConfig {
if (this.config.defaultModel) {
return this.config.defaultModel;
}
if (!this.config.anthropicApiKey) {
throw new Error('Anthropic API key not configured');
}
return {
provider: LLMProvider.ANTHROPIC,
model: 'claude-sonnet-4-6',
};
}
/**
* Get license models configuration
*/
getLicenseModelsConfig(): LicenseModelsConfig | undefined {
return this.config.licenseModels;
}
}
/**
* Predefined model configurations
*/
export const MODELS = {
CLAUDE_SONNET: {
provider: LLMProvider.ANTHROPIC,
model: 'claude-sonnet-4-6',
},
CLAUDE_HAIKU: {
provider: LLMProvider.ANTHROPIC,
model: 'claude-haiku-4-5-20251001',
},
CLAUDE_OPUS: {
provider: LLMProvider.ANTHROPIC,
model: 'claude-opus-4-6',
},
} as const satisfies Record<string, ModelConfig>;