Module: LlmCostTracker::Pricing::Registry

Defined in:
lib/llm_cost_tracker/pricing/registry.rb

Constant Summary collapse

DEFAULT_PRICES_PATH =
File.expand_path("../prices.json", __dir__)
EMPTY_PRICES =
{}.freeze
PRICE_KEYS =
Pricing::COMPONENTS.map { |component| component.price_key.to_s }.freeze
METADATA_KEYS =
%w[
  _source _source_version _fetched_at _updated _notes _validator_override
  _context_price_threshold_tokens
].freeze
MAX_FILE_BYTES =
2_097_152
MUTEX =
Mutex.new

Class Method Summary collapse

Class Method Details

.builtin_pricesObject



23
24
25
26
27
28
29
# File 'lib/llm_cost_tracker/pricing/registry.rb', line 23

def builtin_prices
  cached = @builtin_prices
  return cached if cached

  value = normalize_price_table(raw_registry.fetch("models", {})).freeze
  MUTEX.synchronize { @builtin_prices ||= value }
end

.file_metadata(path) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/llm_cost_tracker/pricing/registry.rb', line 39

def (path)
  return {} unless path

  registry = load_price_file(path.to_s)
  raise ArgumentError, "prices_file must be a hash" unless registry.is_a?(Hash)

   = registry.fetch("metadata", {})
  raise ArgumentError, "prices_file metadata must be a hash" unless .is_a?(Hash)

  
rescue Errno::ENOENT, JSON::ParserError, Psych::Exception, ArgumentError, TypeError => e
  raise Error, "Unable to load prices_file #{path.inspect}: #{e.message}"
end

.file_prices(path) ⇒ Object



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/llm_cost_tracker/pricing/registry.rb', line 57

def file_prices(path)
  return EMPTY_PRICES unless path

  path = path.to_s
  cache_key = [path, File.mtime(path).to_f]
  cached = @file_prices_cache
  return cached[:value] if cached && cached[:key] == cache_key

  MUTEX.synchronize do
    cached = @file_prices_cache
    return cached[:value] if cached && cached[:key] == cache_key

    value = normalize_price_entries(price_file_models(load_price_file(path)), context: path).freeze
    @file_prices_cache = { key: cache_key, value: value }.freeze
    value
  end
rescue Errno::ENOENT, JSON::ParserError, Psych::Exception, ArgumentError, TypeError => e
  raise Error, "Unable to load prices_file #{path.inspect}: #{e.message}"
end

.metadataObject



31
32
33
34
35
36
37
# File 'lib/llm_cost_tracker/pricing/registry.rb', line 31

def 
  cached = @metadata
  return cached if cached

  value = raw_registry.fetch("metadata", {}).freeze
  MUTEX.synchronize { @metadata ||= value }
end

.normalize_price_table(table) ⇒ Object



53
54
55
# File 'lib/llm_cost_tracker/pricing/registry.rb', line 53

def normalize_price_table(table)
  normalize_price_entries(table, context: "price table")
end