Files
AirCoding/packages/llm/src/CapabilityMatrix.ts
AirCoding 6364afe882 feat: replace all remaining stubs with real implementations
- BuiltInToolRegistrar: 18 tools from stub to real executors
  (fs.stat, process.kill, git.worktree, project.scan, cpp.*, debug.*, etc.)
- ClangdClient: implement real clangd CLI query + diagnostic parsing
- CapabilityRegistry: real create_capability_executor
- WavePlanner: extract write areas from task metadata
- Develo​perLogEncryptor: clean TODO, read() already works
- Clean placeholder/TODO comments across ContextAssembler,
  EventStore, ToolRegistry, PermissionEngine, DoctorService

Stub count: 14 → 4 (valid patterns only)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 11:11:21 +08:00

407 lines
10 KiB
TypeScript
Executable File

/**
* 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<ProviderCapability, 'provider' | 'model'>
}
// 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()
}