Module: ActiveHarness::Costs

Defined in:
lib/active_harness/costs.rb

Overview

Provides access to AI model pricing data, filtered to providers supported by ActiveHarness (files present in lib/active_harness/providers/).

Data source priority:

1. {project_root}/tmp/active_harness/costs.json — fetched cache (refreshed once per day)
2. lib/active_harness/data/models.json           — bundled fallback (ships with gem)

Usage:

# Fetch fresh data and save to tmp cache (also called automatically when stale)
ActiveHarness::Costs.update

# All models (auto-updates cache if missing or older than 24h)
ActiveHarness::Costs.all

# Single model by ID
ActiveHarness::Costs.find("gpt-4o")

# By provider — method or bracket syntax
ActiveHarness::Costs.providers.openai
ActiveHarness::Costs.providers[:anthropic]

# List providers that have data
ActiveHarness::Costs.providers.list

Defined Under Namespace

Classes: ModelCost, ProvidersProxy

Constant Summary collapse

BUNDLED_DATA_FILE =
File.expand_path("data/models.json", __dir__).freeze
MODELS_DEV_URL =
"https://models.dev/api.json"
CACHE_TTL =

24 hours in seconds

86_400
MODELS_DEV_PROVIDER_MAP =

Maps models.dev provider keys → ActiveHarness provider names. Only entries whose value matches a file in providers/ will be kept.

{
  "openai"         => "openai",
  "anthropic"      => "anthropic",
  "google"         => "gemini",
  "google-vertex"  => "vertexai",
  "amazon-bedrock" => "bedrock",
  "deepseek"       => "deepseek",
  "mistral"        => "mistral",
  "openrouter"     => "openrouter",
  "perplexity"     => "perplexity",
  "xai"            => "xai",
  "groq"           => "groq",
  "azure"          => "azure"
}.freeze

Class Method Summary collapse

Class Method Details

.allObject

Returns pricing data for all models from supported providers. Automatically fetches fresh data if the cache is missing or older than 24h.



105
106
107
108
# File 'lib/active_harness/costs.rb', line 105

def all
  ensure_fresh_registry
  registry.map { |raw| build_cost(raw) }
end

.available_providersObject

Names of providers supported by ActiveHarness (derived from providers/ directory).



165
166
167
168
169
170
171
172
# File 'lib/active_harness/costs.rb', line 165

def available_providers
  @available_providers ||= begin
    providers_dir = File.expand_path("providers", __dir__)
    Dir.glob("#{providers_dir}/*.rb")
      .map { |f| File.basename(f, ".rb") }
      .reject { |n| %w[base custom].include?(n) }
  end
end

.cache_fileObject

Path to the per-project cache file.



160
161
162
# File 'lib/active_harness/costs.rb', line 160

def cache_file
  File.join(project_root, "tmp", "active_harness", "costs.json")
end

.find(model_id) ⇒ Object

Returns pricing data for a single model by ID, or nil if not found.



111
112
113
114
115
# File 'lib/active_harness/costs.rb', line 111

def find(model_id)
  ensure_fresh_registry
  raw = registry.find { |m| m[:id] == model_id.to_s }
  raw ? build_cost(raw) : nil
end

.for_provider(name) ⇒ Object

Returns pricing data for all models from the given provider.



123
124
125
126
127
128
# File 'lib/active_harness/costs.rb', line 123

def for_provider(name)
  ensure_fresh_registry
  registry
    .select { |m| m[:provider] == name.to_s }
    .map { |m| build_cost(m) }
end

.provider_namesObject

Returns a sorted list of provider names that have data.



131
132
133
134
135
136
# File 'lib/active_harness/costs.rb', line 131

def provider_names
  @provider_names ||= begin
    ensure_fresh_registry
    registry.map { |m| m[:provider] }.uniq.sort
  end
end

.providersObject

Returns a ProvidersProxy for provider-scoped access.



118
119
120
# File 'lib/active_harness/costs.rb', line 118

def providers
  @providers_proxy ||= ProvidersProxy.new
end

.reload!Object

Reloads registry from disk on next access.



153
154
155
156
157
# File 'lib/active_harness/costs.rb', line 153

def reload!
  @registry      = nil
  @provider_names = nil
  nil
end

.updateObject

Fetches fresh pricing data from models.dev, filters to supported providers, and writes the result to project_root/tmp/active_harness/costs.json. Returns the number of models saved, or raises on HTTP failure.



141
142
143
144
145
146
147
148
149
150
# File 'lib/active_harness/costs.rb', line 141

def update
  raw_api = fetch_models_dev
  models  = extract_models(raw_api)

  FileUtils.mkdir_p(File.dirname(cache_file))
  File.write(cache_file, JSON.generate(models))

  reload!
  models.size
end