Module: ActiveHarness::Pricing::OpenRouter

Defined in:
lib/active_harness/pricing/openrouter.rb

Overview

Fetches image-model pricing directly from the OpenRouter API.

models.dev only has generic prompt/completion rates for OpenRouter models. OpenRouter’s own /endpoints API exposes a separate ‘image_output` rate that reflects the real cost of image generation tokens.

Data flow:

1. GET /api/v1/models?output_modalities=image  → list of image models
2. GET /api/v1/models/{id}/endpoints           → per-model, picks first
   active endpoint to get image_output rate
3. Result cached to tmp/active_harness/pricing_openrouter.json for 24h

Usage:

Pricing::OpenRouter.find("openai/gpt-5-image-mini")  # → ModelPrice or nil
Pricing::OpenRouter.update                           # force refresh

Constant Summary collapse

API_BASE =
"https://openrouter.ai/api/v1/models"
CACHE_TTL =
86_400

Class Method Summary collapse

Class Method Details

.cache_fileObject



52
53
54
# File 'lib/active_harness/pricing/openrouter.rb', line 52

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

.find(model_id) ⇒ Object

Returns a ModelPrice for the given OpenRouter model id, or nil. Automatically refreshes the cache if missing or stale.



30
31
32
33
34
# File 'lib/active_harness/pricing/openrouter.rb', line 30

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

.reload!Object



48
49
50
# File 'lib/active_harness/pricing/openrouter.rb', line 48

def reload!
  @registry = nil
end

.updateObject

Fetches fresh data from OpenRouter and writes the cache. Returns the number of models saved.



38
39
40
41
42
43
44
45
46
# File 'lib/active_harness/pricing/openrouter.rb', line 38

def update
  image_models = fetch_image_models
  enriched = image_models.map { |m| enrich_with_endpoint(m) }

  FileUtils.mkdir_p(File.dirname(cache_file))
  File.write(cache_file, JSON.generate(enriched))
  reload!
  enriched.size
end