Class: Aidp::Harness::RubyLLMRegistry
- Inherits:
-
Object
- Object
- Aidp::Harness::RubyLLMRegistry
- Defined in:
- lib/aidp/harness/ruby_llm_registry.rb
Overview
RubyLLMRegistry wraps the ruby_llm gem’s model registry to provide AIDP-specific functionality while leveraging ruby_llm’s comprehensive and actively maintained model database
Defined Under Namespace
Classes: ModelNotFound, RegistryError
Constant Summary collapse
- PROVIDER_NAME_MAPPING =
Map AIDP provider names to RubyLLM provider names Some AIDP providers use different names than the upstream APIs
{ "codex" => "openai", # Codex is AIDP's OpenAI adapter "anthropic" => "anthropic", "gemini" => "gemini", # Gemini provider name matches "aider" => nil, # Aider aggregates multiple providers "cursor" => nil, # Cursor has its own models "openai" => "openai", "google" => "gemini", # Google's API uses gemini provider name "azure" => "bedrock", # Azure OpenAI uses bedrock in registry "bedrock" => "bedrock", "openrouter" => "openrouter" }.freeze
- TIER_CLASSIFICATION =
Tier classification based on model characteristics These are heuristics since ruby_llm doesn’t classify tiers
{ # Mini tier: fast, cost-effective models mini: ->(model) { return true if model.id.to_s.match?(/haiku|mini|flash|small/i) # Check pricing if available if model.pricing pricing_hash = model.pricing.to_h input_cost = pricing_hash.dig(:text_tokens, :standard, :input_per_million) return true if input_cost && input_cost < 1.0 end false }, # Advanced tier: high-capability, expensive models advanced: ->(model) { return true if model.id.to_s.match?(/opus|turbo|pro|preview|o1/i) # Check pricing if available if model.pricing pricing_hash = model.pricing.to_h input_cost = pricing_hash.dig(:text_tokens, :standard, :input_per_million) return true if input_cost && input_cost > 10.0 end false }, # Standard tier: everything else (default) standard: ->(model) { true } }.freeze
Instance Method Summary collapse
-
#classify_tier(model) ⇒ String
Classify a model’s tier.
-
#deprecation_cache ⇒ Object
Get deprecation cache instance (lazy loaded).
-
#find_replacement_model(deprecated_model, provider: nil) ⇒ String?
Find replacement for a deprecated model Returns the latest non-deprecated model in the same family/tier.
-
#get_model_info(model_id) ⇒ Hash?
Get model information.
-
#initialize(deprecation_cache: nil) ⇒ RubyLLMRegistry
constructor
A new instance of RubyLLMRegistry.
-
#model_deprecated?(model_id, provider = nil) ⇒ Boolean
Check if a model is deprecated.
-
#models_for_provider(provider) ⇒ Array<String>
Get all models for a provider.
-
#models_for_tier(tier, provider: nil, skip_deprecated: true) ⇒ Array<String>
Get all models for a specific tier.
-
#refresh! ⇒ Object
Refresh the model registry from ruby_llm.
-
#resolve_model(model_name, provider: nil, skip_deprecated: true) ⇒ String?
Resolve a model name (family or versioned) to the canonical API model.
Constructor Details
#initialize(deprecation_cache: nil) ⇒ RubyLLMRegistry
Returns a new instance of RubyLLMRegistry.
68 69 70 71 72 73 74 75 76 77 |
# File 'lib/aidp/harness/ruby_llm_registry.rb', line 68 def initialize(deprecation_cache: nil) @deprecation_cache = deprecation_cache @models = RubyLLM::Models.instance.instance_variable_get(:@models) @index_by_id = @models.to_h { |m| [m.id, m] } # Build family index for mapping versioned names to families @family_index = build_family_index Aidp.log_info("ruby_llm_registry", "initialized", models: @models.size) end |
Instance Method Details
#classify_tier(model) ⇒ String
Classify a model’s tier
206 207 208 209 210 |
# File 'lib/aidp/harness/ruby_llm_registry.rb', line 206 def classify_tier(model) return "advanced" if TIER_CLASSIFICATION[:advanced].call(model) return "mini" if TIER_CLASSIFICATION[:mini].call(model) "standard" end |
#deprecation_cache ⇒ Object
Get deprecation cache instance (lazy loaded)
31 32 33 |
# File 'lib/aidp/harness/ruby_llm_registry.rb', line 31 def deprecation_cache @deprecation_cache ||= Aidp::Harness::DeprecationCache.new end |
#find_replacement_model(deprecated_model, provider: nil) ⇒ String?
Find replacement for a deprecated model Returns the latest non-deprecated model in the same family/tier
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
# File 'lib/aidp/harness/ruby_llm_registry.rb', line 236 def find_replacement_model(deprecated_model, provider: nil) registry_provider = provider ? PROVIDER_NAME_MAPPING[provider] : nil return nil unless registry_provider # Determine tier of deprecated model deprecated_info = @index_by_id[deprecated_model] return nil unless deprecated_info tier = classify_tier(deprecated_info) # Get all non-deprecated models for this tier and provider candidates = models_for_tier(tier, provider: provider, skip_deprecated: true) # Prefer models in the same family (e.g., both "sonnet") family_keyword = extract_family_keyword(deprecated_model) same_family = candidates.select { |m| m.to_s.include?(family_keyword) } if family_keyword # Return first match from same family, or first candidate overall replacement = same_family&.first || candidates.first if replacement Aidp.log_info("ruby_llm_registry", "found replacement", deprecated: deprecated_model, replacement: replacement, tier: tier) end replacement end |
#get_model_info(model_id) ⇒ Hash?
Get model information
129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/aidp/harness/ruby_llm_registry.rb', line 129 def get_model_info(model_id) model = @index_by_id[model_id] return nil unless model { id: model.id, name: model.name || model.display_name, provider: model.provider.to_s, tier: classify_tier(model), context_window: model.context_window, capabilities: extract_capabilities(model), pricing: model.pricing } end |
#model_deprecated?(model_id, provider = nil) ⇒ Boolean
Check if a model is deprecated
225 226 227 228 229 |
# File 'lib/aidp/harness/ruby_llm_registry.rb', line 225 def model_deprecated?(model_id, provider = nil) return false unless provider deprecation_cache.deprecated?(provider: provider, model_id: model_id.to_s) end |
#models_for_provider(provider) ⇒ Array<String>
Get all models for a provider
192 193 194 195 196 197 198 199 200 |
# File 'lib/aidp/harness/ruby_llm_registry.rb', line 192 def models_for_provider(provider) # Map AIDP provider name to RubyLLM provider name registry_provider = PROVIDER_NAME_MAPPING[provider] # Return empty if provider doesn't map to a registry provider return [] if registry_provider.nil? @models.select { |m| m.provider.to_s == registry_provider }.map(&:id) end |
#models_for_tier(tier, provider: nil, skip_deprecated: true) ⇒ Array<String>
Get all models for a specific tier
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
# File 'lib/aidp/harness/ruby_llm_registry.rb', line 150 def models_for_tier(tier, provider: nil, skip_deprecated: true) tier_sym = tier.to_sym classifier = TIER_CLASSIFICATION[tier_sym] unless classifier Aidp.log_warn("ruby_llm_registry", "invalid tier", tier: tier) return [] end # Map AIDP provider to registry provider if filtering registry_provider = provider ? PROVIDER_NAME_MAPPING[provider] : nil return [] if provider && registry_provider.nil? models = @models.select do |model| (registry_provider.nil? || model.provider.to_s == registry_provider) && classifier.call(model) end # For mini and standard tiers, exclude if advanced classification matches if tier_sym == :mini models.reject! { |m| TIER_CLASSIFICATION[:advanced].call(m) } elsif tier_sym == :standard models.reject! do |m| TIER_CLASSIFICATION[:mini].call(m) || TIER_CLASSIFICATION[:advanced].call(m) end end # Filter out deprecated models if requested if skip_deprecated models.reject! { |m| deprecation_cache.deprecated?(provider: registry_provider, model_id: m.id.to_s) } end model_ids = models.map(&:id).uniq Aidp.log_debug("ruby_llm_registry", "found models for tier", tier: tier, provider: provider, count: model_ids.size) model_ids end |
#refresh! ⇒ Object
Refresh the model registry from ruby_llm
213 214 215 216 217 218 219 |
# File 'lib/aidp/harness/ruby_llm_registry.rb', line 213 def refresh! RubyLLM::Models.refresh! @models = RubyLLM::Models.instance.instance_variable_get(:@models) @index_by_id = @models.to_h { |m| [m.id, m] } @family_index = build_family_index Aidp.log_info("ruby_llm_registry", "refreshed", models: @models.size) end |
#resolve_model(model_name, provider: nil, skip_deprecated: true) ⇒ String?
Resolve a model name (family or versioned) to the canonical API model
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/aidp/harness/ruby_llm_registry.rb', line 85 def resolve_model(model_name, provider: nil, skip_deprecated: true) # Map AIDP provider to registry provider if filtering registry_provider = provider ? PROVIDER_NAME_MAPPING[provider] : nil # Check if model is deprecated if skip_deprecated && model_deprecated?(model_name, registry_provider) Aidp.log_warn("ruby_llm_registry", "skipping deprecated model", model: model_name, provider: provider) return nil end # Try exact match first model = @index_by_id[model_name] return model.id if model && (registry_provider.nil? || model.provider.to_s == registry_provider) # Try family mapping family_models = @family_index[model_name] if family_models # Filter by provider if specified family_models = family_models.select { |m| m.provider.to_s == registry_provider } if registry_provider # Filter out deprecated models if requested if skip_deprecated family_models = family_models.reject do |m| deprecation_cache.deprecated?(provider: registry_provider, model_id: m.id.to_s) end end # Return the latest version (first non-"latest" model, or the latest one) model = family_models.reject { |m| m.id.to_s.include?("-latest") }.first || family_models.first return model.id if model end # Try fuzzy matching for common patterns fuzzy_match = find_fuzzy_match(model_name, registry_provider, skip_deprecated: skip_deprecated) return fuzzy_match.id if fuzzy_match Aidp.log_warn("ruby_llm_registry", "model not found", model: model_name, provider: provider) nil end |