142 lines
3.7 KiB
TypeScript
142 lines
3.7 KiB
TypeScript
/**
|
|
* Model validation and configuration for LLM providers
|
|
*/
|
|
|
|
export type Provider = 'openai' | 'anthropic' | 'groq';
|
|
|
|
export interface ModelConfig {
|
|
provider: Provider;
|
|
modelName: string;
|
|
isValid: boolean;
|
|
error?: string;
|
|
}
|
|
|
|
/**
|
|
* Supported models by provider (MCP-compatible only)
|
|
* These models support MCP through their respective APIs:
|
|
* - OpenAI: Responses API
|
|
* - Anthropic: Messages API with MCP beta
|
|
* - Groq: Responses API (OpenAI-compatible)
|
|
*/
|
|
export const SUPPORTED_MODELS = {
|
|
openai: [
|
|
// OpenAI models that support Responses API
|
|
'gpt-4o',
|
|
'gpt-4o-mini',
|
|
],
|
|
anthropic: [
|
|
// Claude 4 models that support Messages API with MCP
|
|
'claude-sonnet-4-5-20250929',
|
|
'claude-haiku-4-5', // Latest Haiku 4.5
|
|
],
|
|
groq: [
|
|
// Only Groq models that support Responses API (per Groq docs)
|
|
'gpt-oss-120b',
|
|
],
|
|
} as const;
|
|
|
|
/**
|
|
* Default models for each provider
|
|
*/
|
|
export const DEFAULT_MODELS = {
|
|
openai: 'gpt-4o',
|
|
anthropic: 'claude-sonnet-4-5-20250929', // Claude 4.5 Sonnet
|
|
groq: 'gpt-oss-120b', // Using Responses API model for better MCP support
|
|
} as const;
|
|
|
|
/**
|
|
* Parse a model string into provider and model name
|
|
* Supports formats:
|
|
* - "provider/model-name" (e.g., "openai/gpt-4o")
|
|
* - "model-name" (defaults to openai provider)
|
|
*/
|
|
export function parseModelString(modelString?: string): { provider: Provider; modelName: string } {
|
|
if (!modelString) {
|
|
return { provider: 'openai', modelName: DEFAULT_MODELS.openai };
|
|
}
|
|
|
|
if (modelString.includes('/')) {
|
|
const [provider, modelName] = modelString.split('/', 2) as [string, string];
|
|
|
|
// Validate provider
|
|
if (provider !== 'openai' && provider !== 'anthropic' && provider !== 'groq') {
|
|
// Default to openai if provider is unknown
|
|
return { provider: 'openai', modelName: DEFAULT_MODELS.openai };
|
|
}
|
|
|
|
return { provider, modelName };
|
|
}
|
|
|
|
// No provider prefix, default to openai
|
|
return { provider: 'openai', modelName: modelString };
|
|
}
|
|
|
|
/**
|
|
* Validate a model configuration
|
|
*/
|
|
export function validateModel(modelString?: string): ModelConfig {
|
|
const { provider, modelName } = parseModelString(modelString);
|
|
|
|
// Check if model is in supported list
|
|
const supportedModels = SUPPORTED_MODELS[provider];
|
|
const isValid = (supportedModels as readonly string[]).includes(modelName);
|
|
|
|
if (!isValid) {
|
|
return {
|
|
provider,
|
|
modelName,
|
|
isValid: false,
|
|
error: `Model '${modelName}' is not supported for provider '${provider}'. Supported models: ${supportedModels.join(', ')}`,
|
|
};
|
|
}
|
|
|
|
return {
|
|
provider,
|
|
modelName,
|
|
isValid: true,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get the default model for a provider
|
|
*/
|
|
export function getDefaultModel(provider: Provider): string {
|
|
return DEFAULT_MODELS[provider];
|
|
}
|
|
|
|
/**
|
|
* Check if a provider is supported
|
|
*/
|
|
export function isSupportedProvider(provider: string): provider is Provider {
|
|
return provider === 'openai' || provider === 'anthropic' || provider === 'groq';
|
|
}
|
|
|
|
/**
|
|
* Get model string with provider prefix
|
|
*/
|
|
export function getModelString(provider: Provider, modelName: string): string {
|
|
return `${provider}/${modelName}`;
|
|
}
|
|
|
|
/**
|
|
* Ensure model string is compatible with OpenAI Responses API
|
|
* (only OpenAI models work with the Responses API)
|
|
*/
|
|
export function ensureOpenAIModel(modelString?: string): string {
|
|
const { provider, modelName } = parseModelString(modelString);
|
|
|
|
// If it's already an OpenAI model, return it
|
|
if (provider === 'openai') {
|
|
// Validate it's a supported OpenAI model
|
|
const validation = validateModel(modelString);
|
|
if (validation.isValid) {
|
|
return modelName;
|
|
}
|
|
// Fall back to default if invalid
|
|
return DEFAULT_MODELS.openai;
|
|
}
|
|
|
|
// For non-OpenAI providers, return default OpenAI model
|
|
return DEFAULT_MODELS.openai;
|
|
}
|