Class: Aidp::Harness::CapabilityRegistry

Inherits:
Object
  • Object
show all
Defined in:
lib/aidp/harness/capability_registry.rb

Overview

Stores and queries model capability metadata from the catalog Provides information about model tiers, features, costs, and context windows

Constant Summary collapse

VALID_TIERS =

Valid thinking depth tiers

%w[mini standard thinking pro max].freeze
TIER_PRIORITY =

Tier priority for escalation (lower index = lower tier)

{
  "mini" => 0,
  "standard" => 1,
  "thinking" => 2,
  "pro" => 3,
  "max" => 4
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(catalog_path: nil, root_dir: nil) ⇒ CapabilityRegistry

Returns a new instance of CapabilityRegistry.



25
26
27
28
29
30
# File 'lib/aidp/harness/capability_registry.rb', line 25

def initialize(catalog_path: nil, root_dir: nil)
  @root_dir = root_dir || Dir.pwd
  @catalog_path = catalog_path || default_catalog_path
  @catalog_data = nil
  @loaded_at = nil
end

Instance Attribute Details

#catalog_pathObject (readonly)

Returns the value of attribute catalog_path.



23
24
25
# File 'lib/aidp/harness/capability_registry.rb', line 23

def catalog_path
  @catalog_path
end

Instance Method Details

#best_model_for_tier(tier, provider_name) ⇒ Object

Find best model for a tier and provider Returns [model_name, model_data] or nil



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/aidp/harness/capability_registry.rb', line 152

def best_model_for_tier(tier, provider_name)
  validate_tier!(tier)
  models = models_for_provider(provider_name)

  # Find all models matching tier
  tier_models = models.select { |_name, data| data["tier"] == tier }
  return nil if tier_models.empty?

  # Prefer newer models (higher in the list)
  # Sort by cost (cheaper first) as tiebreaker
  tier_models.min_by do |_name, data|
    cost = data["cost_per_mtok_input"] || 0
    [cost]
  end
end

#catalogObject

Get catalog data (lazy load if needed)



53
54
55
56
# File 'lib/aidp/harness/capability_registry.rb', line 53

def catalog
  load_catalog if @catalog_data.nil?
  @catalog_data || default_empty_catalog
end

#compare_tiers(tier1, tier2) ⇒ Object

Compare two tiers (returns -1, 0, 1 like <=>)



126
127
128
129
130
# File 'lib/aidp/harness/capability_registry.rb', line 126

def compare_tiers(tier1, tier2)
  priority1 = tier_priority(tier1) || -1
  priority2 = tier_priority(tier2) || -1
  priority1 <=> priority2
end

#export_for_displayObject

Export catalog as structured data for display



206
207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/aidp/harness/capability_registry.rb', line 206

def export_for_display
  {
    schema_version: catalog["schema_version"],
    providers: provider_names.map do |provider_name|
      {
        name: provider_name,
        display_name: provider_display_name(provider_name),
        tiers: supported_tiers(provider_name),
        models: models_for_provider(provider_name)
      }
    end,
    tier_order: VALID_TIERS
  }
end

#load_catalogObject

Load catalog from YAML file



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/aidp/harness/capability_registry.rb', line 33

def load_catalog
  return false unless File.exist?(@catalog_path)

  @catalog_data = YAML.safe_load_file(
    @catalog_path,
    permitted_classes: [Symbol],
    symbolize_names: false
  )
  @loaded_at = Time.now

  validate_catalog(@catalog_data)
  Aidp.log_debug("capability_registry", "Loaded catalog", path: @catalog_path, providers: provider_names.size)
  true
rescue => e
  Aidp.log_error("capability_registry", "Failed to load catalog", error: e.message, path: @catalog_path)
  @catalog_data = nil
  false
end

#model_info(provider_name, model_name) ⇒ Object

Get complete info for a specific model



99
100
101
# File 'lib/aidp/harness/capability_registry.rb', line 99

def model_info(provider_name, model_name)
  catalog.dig("providers", provider_name, "models", model_name)
end

#models_by_tier(tier, provider: nil) ⇒ Object

Get all models matching a specific tier Returns hash: { provider_name => [model_name, …] }



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/aidp/harness/capability_registry.rb', line 81

def models_by_tier(tier, provider: nil)
  validate_tier!(tier)

  results = {}
  providers_to_search = provider ? [provider] : provider_names

  providers_to_search.each do |provider_name|
    matching_models = []
    models_for_provider(provider_name).each do |model_name, model_data|
      matching_models << model_name if model_data["tier"] == tier
    end
    results[provider_name] = matching_models unless matching_models.empty?
  end

  results
end

#models_for_provider(provider_name) ⇒ Object

Get all models for a provider



64
65
66
67
68
69
# File 'lib/aidp/harness/capability_registry.rb', line 64

def models_for_provider(provider_name)
  provider_data = catalog.dig("providers", provider_name)
  return {} unless provider_data

  provider_data["models"] || {}
end

#next_tier(tier) ⇒ Object

Get next higher tier (or nil if already at max)



133
134
135
136
137
138
139
# File 'lib/aidp/harness/capability_registry.rb', line 133

def next_tier(tier)
  validate_tier!(tier)
  current_priority = tier_priority(tier)
  return nil if current_priority >= TIER_PRIORITY["max"]

  TIER_PRIORITY.key(current_priority + 1)
end

#previous_tier(tier) ⇒ Object

Get next lower tier (or nil if already at mini)



142
143
144
145
146
147
148
# File 'lib/aidp/harness/capability_registry.rb', line 142

def previous_tier(tier)
  validate_tier!(tier)
  current_priority = tier_priority(tier)
  return nil if current_priority <= TIER_PRIORITY["mini"]

  TIER_PRIORITY.key(current_priority - 1)
end

#provider_display_name(provider_name) ⇒ Object

Get display name for a provider



104
105
106
# File 'lib/aidp/harness/capability_registry.rb', line 104

def provider_display_name(provider_name)
  catalog.dig("providers", provider_name, "display_name") || provider_name
end

#provider_namesObject

Get all provider names in catalog



59
60
61
# File 'lib/aidp/harness/capability_registry.rb', line 59

def provider_names
  catalog.dig("providers")&.keys || []
end

#recommend_tier_for_complexity(complexity_score) ⇒ Object

Recommend tier based on complexity score (0.0-1.0)



174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/aidp/harness/capability_registry.rb', line 174

def recommend_tier_for_complexity(complexity_score)
  return "mini" if complexity_score <= 0.0

  recommendations = tier_recommendations.sort_by do |_name, data|
    data["complexity_threshold"] || 0.0
  end

  # Find first recommendation where complexity exceeds threshold
  recommendation = recommendations.find do |_name, data|
    complexity_score <= (data["complexity_threshold"] || 0.0)
  end

  recommendation ? recommendation[1]["recommended_tier"] : "max"
end

#reloadObject

Reload catalog from disk



190
191
192
193
194
# File 'lib/aidp/harness/capability_registry.rb', line 190

def reload
  @catalog_data = nil
  @loaded_at = nil
  load_catalog
end

#stale?(max_age_seconds = 3600) ⇒ Boolean

Check if catalog needs reload (based on file modification time)

Returns:

  • (Boolean)


197
198
199
200
201
202
203
# File 'lib/aidp/harness/capability_registry.rb', line 197

def stale?(max_age_seconds = 3600)
  return true unless @loaded_at
  return true unless File.exist?(@catalog_path)

  file_mtime = File.mtime(@catalog_path)
  file_mtime > @loaded_at || (Time.now - @loaded_at) > max_age_seconds
end

#supported_tiers(provider_name) ⇒ Object

Get all tiers supported by a provider



109
110
111
112
113
# File 'lib/aidp/harness/capability_registry.rb', line 109

def supported_tiers(provider_name)
  models = models_for_provider(provider_name)
  tiers = models.values.map { |m| m["tier"] }.compact.uniq
  tiers.sort_by { |t| TIER_PRIORITY[t] || 999 }
end

#tier_for_model(provider_name, model_name) ⇒ Object

Get tier for a specific model



72
73
74
75
76
77
# File 'lib/aidp/harness/capability_registry.rb', line 72

def tier_for_model(provider_name, model_name)
  model_data = model_info(provider_name, model_name)
  return nil unless model_data

  model_data["tier"]
end

#tier_priority(tier) ⇒ Object

Get tier priority (0 = lowest, 4 = highest)



121
122
123
# File 'lib/aidp/harness/capability_registry.rb', line 121

def tier_priority(tier)
  TIER_PRIORITY[tier]
end

#tier_recommendationsObject

Get tier recommendations from catalog



169
170
171
# File 'lib/aidp/harness/capability_registry.rb', line 169

def tier_recommendations
  catalog["tier_recommendations"] || {}
end

#valid_tier?(tier) ⇒ Boolean

Check if a tier is valid

Returns:

  • (Boolean)


116
117
118
# File 'lib/aidp/harness/capability_registry.rb', line 116

def valid_tier?(tier)
  VALID_TIERS.include?(tier)
end