Module: ActiveHarness::Pricing::OpenRouter
- Defined in:
- lib/active_harness/pricing/openrouter.rb
Overview
Fetches complete pricing for all OpenRouter models across all modalities.
OpenRouter exposes models via several endpoints:
GET /api/v1/models → 337 text models (base)
GET /api/v1/models?output_modalities=image → 32 image-gen models (25 extra)
GET /api/v1/models?output_modalities=embeddings → 26 models (all extra)
GET /api/v1/models?output_modalities=speech → 9 models (all extra)
GET /api/v1/models?output_modalities=transcription → 10 models (all extra)
GET /api/v1/models?output_modalities=video → 14 models (all zero pricing)
GET /api/v1/models?output_modalities=rerank → 4 models (all zero pricing)
For image-output models, /api/v1/models/id/endpoints is also fetched to get the accurate ‘image_output` per-token rate.
All models are merged by id; pricing fields are populated per-modality:
text_input / text_output — text tokens
image_input — image tokens accepted as input (vision)
image_output — image generation tokens (from /endpoints)
audio_input — audio tokens as input
audio_output — audio tokens as output (TTS)
cache_read / cache_write — cache tokens
web_search — per web-search request
Usage:
Pricing::OpenRouter.find("openai/gpt-5-image-mini") # → ModelPrice or nil
Pricing::OpenRouter.all # → Array<ModelPrice>
Pricing::OpenRouter.update # force refresh
Constant Summary collapse
- API_BASE =
"https://openrouter.ai/api/v1/models"- MEMORY_TTL =
3 days
3 * 86_400
- EXTRA_MODALITIES =
Modalities that have models outside the base text-337 set.
%w[image embeddings speech transcription video rerank].freeze
Class Method Summary collapse
- .all ⇒ Object
- .cache_file ⇒ Object
- .find(model_id) ⇒ Object
- .preload! ⇒ Object
- .reload! ⇒ Object
- .update ⇒ Object
Class Method Details
.all ⇒ Object
49 50 51 52 |
# File 'lib/active_harness/pricing/openrouter.rb', line 49 def all ensure_fresh_registry registry.filter_map { |raw| build_price(raw) } end |
.cache_file ⇒ Object
75 76 77 |
# File 'lib/active_harness/pricing/openrouter.rb', line 75 def cache_file File.join(project_root, "tmp", "active_harness", "openrouter_pricing.json") end |
.find(model_id) ⇒ Object
43 44 45 46 47 |
# File 'lib/active_harness/pricing/openrouter.rb', line 43 def find(model_id) ensure_fresh_registry raw = registry.find { |m| m[:id] == model_id.to_s } raw ? build_price(raw) : nil end |
.preload! ⇒ Object
54 55 56 57 58 59 60 61 |
# File 'lib/active_harness/pricing/openrouter.rb', line 54 def preload! update rescue StandardError nil ensure @registry = load_registry @loaded_at = @registry.empty? ? nil : Time.now end |
.reload! ⇒ Object
70 71 72 73 |
# File 'lib/active_harness/pricing/openrouter.rb', line 70 def reload! @registry = nil @loaded_at = nil end |
.update ⇒ Object
63 64 65 66 67 68 |
# File 'lib/active_harness/pricing/openrouter.rb', line 63 def update entries = collect_all_models FileUtils.mkdir_p(File.dirname(cache_file)) File.write(cache_file, JSON.generate(entries)) entries.size end |