Module: RubyLLM::Agents::Pricing::DataStore
Overview
Centralized HTTP fetch + two-layer cache for all pricing sources.
Replaces the duplicated fetch_from_url / litellm_data / cache_expired? code previously copy-pasted across TranscriptionPricing, SpeechPricing, and ImageGenerator::Pricing.
Two-layer cache:
Layer 1: In-memory (per-process, instant)
Layer 2: Rails.cache (cross-process, survives restarts)
Thread-safety: All cache writes are protected by a Mutex.
Constant Summary collapse
- DEFAULT_CACHE_TTL =
24 hours
24 * 60 * 60
- LITELLM_URL =
"https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json"- OPENROUTER_URL =
"https://openrouter.ai/api/v1/models"- HELICONE_URL =
"https://www.helicone.ai/api/llm-costs"- PORTKEY_BASE_URL =
"https://api.portkey.ai/model-configs/pricing"- LLMPRICING_BASE_URL =
"https://llmpricing.ai/api"
Instance Method Summary collapse
-
#cache_stats ⇒ Hash
Cache statistics for each source.
-
#helicone_data ⇒ Array<Hash>
Array of cost entries.
-
#litellm_data ⇒ Hash
Model_id => { pricing fields }.
-
#llmpricing_data(provider, model, input_tokens, output_tokens) ⇒ Hash?
Pricing data.
-
#openrouter_data ⇒ Array<Hash>
Array of model entries with pricing.
-
#portkey_data(provider, model) ⇒ Hash?
Pricing data for this model.
-
#refresh!(source = :all) ⇒ Object
Clear caches and optionally re-fetch.
Instance Method Details
#cache_stats ⇒ Hash
Returns Cache statistics for each source.
126 127 128 129 130 131 132 133 134 |
# File 'lib/ruby_llm/agents/pricing/data_store.rb', line 126 def cache_stats { litellm: bulk_stats(:litellm), openrouter: bulk_stats(:openrouter), helicone: bulk_stats(:helicone), portkey: per_model_stats("portkey:"), llmpricing: per_model_stats("llmpricing:") } end |
#helicone_data ⇒ Array<Hash>
Returns Array of cost entries.
61 62 63 64 65 66 67 68 |
# File 'lib/ruby_llm/agents/pricing/data_store.rb', line 61 def helicone_data return nil unless source_enabled?(:helicone) fetch_bulk(:helicone, helicone_url) do |body| parsed = JSON.parse(body) parsed.is_a?(Array) ? parsed : (parsed["data"] || parsed["costs"] || []) end end |
#litellm_data ⇒ Hash
Returns model_id => { pricing fields }.
46 47 48 |
# File 'lib/ruby_llm/agents/pricing/data_store.rb', line 46 def litellm_data fetch_bulk(:litellm, litellm_url) { |body| JSON.parse(body) } end |
#llmpricing_data(provider, model, input_tokens, output_tokens) ⇒ Hash?
Returns Pricing data.
89 90 91 92 93 94 95 |
# File 'lib/ruby_llm/agents/pricing/data_store.rb', line 89 def llmpricing_data(provider, model, input_tokens, output_tokens) return nil unless source_enabled?(:llmpricing) cache_key = "llmpricing:#{provider}/#{model}" url = "#{llmpricing_base_url}/prices?provider=#{uri_encode(provider)}&model=#{uri_encode(model)}&input_tokens=#{input_tokens}&output_tokens=#{output_tokens}" fetch_per_model(cache_key, url) end |
#openrouter_data ⇒ Array<Hash>
Returns Array of model entries with pricing.
51 52 53 54 55 56 57 58 |
# File 'lib/ruby_llm/agents/pricing/data_store.rb', line 51 def openrouter_data return nil unless source_enabled?(:openrouter) fetch_bulk(:openrouter, openrouter_url) do |body| parsed = JSON.parse(body) parsed.is_a?(Hash) ? (parsed["data"] || []) : parsed end end |
#portkey_data(provider, model) ⇒ Hash?
Returns Pricing data for this model.
77 78 79 80 81 82 |
# File 'lib/ruby_llm/agents/pricing/data_store.rb', line 77 def portkey_data(provider, model) return nil unless source_enabled?(:portkey) cache_key = "portkey:#{provider}/#{model}" fetch_per_model(cache_key, "#{portkey_base_url}/#{provider}/#{model}") end |
#refresh!(source = :all) ⇒ Object
Clear caches and optionally re-fetch
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/ruby_llm/agents/pricing/data_store.rb', line 104 def refresh!(source = :all) mutex.synchronize do case source when :all @bulk_cache = {} @bulk_fetched_at = {} @per_model_cache = {} @per_model_fetched_at = {} when :litellm, :openrouter, :helicone @bulk_cache&.delete(source) @bulk_fetched_at&.delete(source) when :portkey @per_model_cache&.reject! { |k, _| k.start_with?("portkey:") } @per_model_fetched_at&.reject! { |k, _| k.start_with?("portkey:") } when :llmpricing @per_model_cache&.reject! { |k, _| k.start_with?("llmpricing:") } @per_model_fetched_at&.reject! { |k, _| k.start_with?("llmpricing:") } end end end |