/** * CapabilityMatrixRegistry - Provider capability matrix lookup * * Implements DD §12.2. * Holds ProviderCapabilityMatrix rows with nested supports/conversion/quality/cost tiers. * * @module packages/llm/src/CapabilityMatrix */ export interface SupportsMap { text_input: boolean text_output: boolean streaming: boolean tool_use: boolean parallel_tool_use: boolean structured_output: boolean json_mode: boolean thinking: boolean prompt_cache: boolean system_prompt: boolean image_input: boolean image_output: boolean audio_input: boolean audio_output: boolean file_input: boolean computer_use: boolean long_context: boolean } export interface ConversionMap { from_anthropic_canonical?: boolean tool_schema?: 'native' | 'emulated' | 'none' image_input?: 'base64' | 'url' | 'none' thinking?: 'native' | 'emulated' | 'none' cache_control?: 'anthropic' | 'openai' | 'none' } export interface ProviderCapability { provider: string model: string max_tokens_output?: number max_tokens_input?: number supports: SupportsMap conversion?: ConversionMap quality_tier?: 'flagship' | 'balanced' | 'economy' cost_tier?: 'high' | 'medium' | 'low' } export interface ProviderCapabilityMatrix { provider: string model_pattern: string capabilities: Omit } // Capability matrix — loaded from provider-capability-matrix-v1.md const CAPABILITY_MATRIX: ProviderCapabilityMatrix[] = [ { provider: 'anthropic', model_pattern: '^claude-opus-4-.*', capabilities: { max_tokens_output: 200000, max_tokens_input: 200000, supports: { text_input: true, text_output: true, streaming: true, tool_use: true, parallel_tool_use: true, structured_output: true, json_mode: true, thinking: true, prompt_cache: true, system_prompt: true, image_input: true, image_output: false, audio_input: false, audio_output: false, file_input: true, computer_use: true, long_context: true }, conversion: { from_anthropic_canonical: true, tool_schema: 'native', image_input: 'base64', thinking: 'native', cache_control: 'anthropic' }, quality_tier: 'flagship', cost_tier: 'high' } }, { provider: 'anthropic', model_pattern: '^claude-sonnet-4-.*', capabilities: { max_tokens_output: 200000, max_tokens_input: 200000, supports: { text_input: true, text_output: true, streaming: true, tool_use: true, parallel_tool_use: true, structured_output: true, json_mode: true, thinking: true, prompt_cache: true, system_prompt: true, image_input: true, image_output: false, audio_input: false, audio_output: false, file_input: true, computer_use: true, long_context: true }, conversion: { from_anthropic_canonical: true, tool_schema: 'native', image_input: 'base64', thinking: 'native', cache_control: 'anthropic' }, quality_tier: 'balanced', cost_tier: 'medium' } }, { provider: 'anthropic', model_pattern: '^claude-haiku-4-.*', capabilities: { max_tokens_output: 200000, max_tokens_input: 200000, supports: { text_input: true, text_output: true, streaming: true, tool_use: true, parallel_tool_use: true, structured_output: true, json_mode: true, thinking: false, prompt_cache: true, system_prompt: true, image_input: true, image_output: false, audio_input: false, audio_output: false, file_input: true, computer_use: false, long_context: true }, conversion: { from_anthropic_canonical: true, tool_schema: 'native', image_input: 'base64', thinking: 'none', cache_control: 'anthropic' }, quality_tier: 'economy', cost_tier: 'low' } }, { provider: 'openai', model_pattern: '^gpt-5-.*', capabilities: { max_tokens_output: 128000, max_tokens_input: 128000, supports: { text_input: true, text_output: true, streaming: true, tool_use: true, parallel_tool_use: true, structured_output: true, json_mode: true, thinking: true, prompt_cache: true, system_prompt: true, image_input: true, image_output: false, audio_input: true, audio_output: true, file_input: true, computer_use: false, long_context: true }, conversion: { from_anthropic_canonical: true, tool_schema: 'native', image_input: 'url', thinking: 'native', cache_control: 'openai' }, quality_tier: 'flagship', cost_tier: 'high' } }, { provider: 'openai', model_pattern: '^gpt-4[ot]-.*', capabilities: { max_tokens_output: 128000, max_tokens_input: 128000, supports: { text_input: true, text_output: true, streaming: true, tool_use: true, parallel_tool_use: true, structured_output: true, json_mode: true, thinking: false, prompt_cache: false, system_prompt: true, image_input: true, image_output: false, audio_input: false, audio_output: false, file_input: true, computer_use: false, long_context: true }, conversion: { from_anthropic_canonical: true, tool_schema: 'native', image_input: 'url', thinking: 'none', cache_control: 'openai' }, quality_tier: 'balanced', cost_tier: 'medium' } }, { provider: 'openai-compatible', model_pattern: '.*', capabilities: { // Defaults for compatible providers - actual capability varies max_tokens_output: 4096, max_tokens_input: 128000, supports: { text_input: true, text_output: true, streaming: true, tool_use: true, parallel_tool_use: false, structured_output: false, json_mode: true, thinking: false, prompt_cache: false, system_prompt: true, image_input: false, image_output: false, audio_input: false, audio_output: false, file_input: false, computer_use: false, long_context: false }, conversion: { from_anthropic_canonical: true, tool_schema: 'emulated', image_input: 'none', thinking: 'none', cache_control: 'none' }, quality_tier: 'economy', cost_tier: 'low' } }, { provider: 'glm', model_pattern: '^glm-5-.*', capabilities: { max_tokens_output: 128000, max_tokens_input: 128000, supports: { text_input: true, text_output: true, streaming: true, tool_use: true, parallel_tool_use: false, structured_output: true, json_mode: true, thinking: true, prompt_cache: false, system_prompt: true, image_input: true, image_output: false, audio_input: false, audio_output: false, file_input: true, computer_use: false, long_context: true }, conversion: { from_anthropic_canonical: true, tool_schema: 'emulated', image_input: 'url', thinking: 'emulated', cache_control: 'none' }, quality_tier: 'balanced', cost_tier: 'medium' } } ] export class CapabilityMatrixRegistry { private matrix: ProviderCapabilityMatrix[] constructor(matrix?: ProviderCapabilityMatrix[]) { this.matrix = matrix || CAPABILITY_MATRIX } /** * Look up capabilities for a specific provider/model. */ lookup(provider: string, model: string): ProviderCapability | undefined { // Find matching entry for (const entry of this.matrix) { if (entry.provider !== provider) continue const regex = new RegExp(entry.model_pattern) if (regex.test(model)) { return { provider, model, ...entry.capabilities } } } return undefined } /** * List all models for a provider. */ list_models(provider: string): string[] { const models: string[] = [] for (const entry of this.matrix) { if (entry.provider === provider) { // Extract example model name from pattern const example = entry.model_pattern.replace(/^\^|\$.*$/g, '') models.push(example || entry.model_pattern) } } return models } /** * Check if a provider/model supports a specific capability. * Queries the nested `supports` object. */ supports(provider: string, model: string, capability: keyof SupportsMap): boolean { const caps = this.lookup(provider, model) if (!caps) return false return caps.supports[capability] === true } /** * Get the best model for a set of requirements. */ find_best( provider: string, requirements: { min_output_tokens?: number thinking?: boolean tool_use?: boolean } ): string | undefined { const entries = this.matrix.filter(e => e.provider === provider) for (const entry of entries) { const caps = entry.capabilities if (requirements.min_output_tokens && (!caps.max_tokens_output || caps.max_tokens_output < requirements.min_output_tokens)) { continue } if (requirements.thinking && !caps.supports.thinking) { continue } if (requirements.tool_use && !caps.supports.tool_use) { continue } // Return first matching model pattern return entry.model_pattern.replace(/[\^$]/g, '') } return undefined } } export function createCapabilityMatrixRegistry(): CapabilityMatrixRegistry { return new CapabilityMatrixRegistry() }