Module: ActiveHarness::Pricing::PriceResolver
- Defined in:
- lib/active_harness/pricing/price_resolver.rb
Overview
Queries all pricing sources for a given model and calculates costs.
All cost methods accept either an agent/result object OR explicit keyword args:
PriceResolver.max_cost(result) # from ActiveHarness agent result
PriceResolver.max_cost(agent) # from ActiveHarness agent instance
PriceResolver.max_cost(model_id: "gpt-4o", tokens_input: 1000, tokens_output: 500)
Resolved keys are cached in memory (TTL: 24h) — in production only a handful of models are used, so the first lookup pays the search cost and every subsequent call returns instantly from cache.
Constant Summary collapse
- DATA_DIR =
File.("../../../data", __dir__)
- CACHE_TTL =
24 hours
86_400- SOURCES =
{ pricepertoken: Source.new(File.join(DATA_DIR, "pricepertoken.json"), :pricepertoken), modelsdev: Source.new(File.join(DATA_DIR, "modelsdev.json"), :modelsdev), openrouter: Source.new(File.join(DATA_DIR, "openrouter.json"), :openrouter) }.freeze
Class Method Summary collapse
-
.clear_cache! ⇒ Object
Clears the resolve cache.
-
.costs(subject = nil, model_id: nil, tokens_input: 0, tokens_output: 0) ⇒ Object
Returns { source_name => Float (USD) } — calculated cost per source.
-
.max_cost(subject = nil, model_id: nil, tokens_input: 0, tokens_output: 0, provider_cost: nil) ⇒ Object
Returns the highest cost estimate across all sources (conservative upper bound).
-
.min_cost(subject = nil, model_id: nil, tokens_input: 0, tokens_output: 0, provider_cost: nil) ⇒ Object
Returns the lowest cost estimate across all sources (optimistic lower bound).
-
.resolve(model_id) ⇒ Object
Returns { source_name => PricingData } for every source that has this model.
Class Method Details
.clear_cache! ⇒ Object
Clears the resolve cache. Useful in tests or after manually refreshing data files.
89 90 91 92 |
# File 'lib/active_harness/pricing/price_resolver.rb', line 89 def clear_cache! @resolve_cache = nil @cache_built_at = nil end |
.costs(subject = nil, model_id: nil, tokens_input: 0, tokens_output: 0) ⇒ Object
Returns { source_name => Float (USD) } — calculated cost per source. Accepts a result/agent object or keyword args.
44 45 46 47 48 49 50 51 52 |
# File 'lib/active_harness/pricing/price_resolver.rb', line 44 def costs(subject = nil, model_id: nil, tokens_input: 0, tokens_output: 0) args = extract_args(subject, model_id: model_id, tokens_input: tokens_input, tokens_output: tokens_output) tokens_in = args[:tokens_input].to_i tokens_out = args[:tokens_output].to_i resolve(args[:model_id]).transform_values do |p| (tokens_in * p.input_per_1m / 1_000_000.0) + (tokens_out * p.output_per_1m / 1_000_000.0) end end |
.max_cost(subject = nil, model_id: nil, tokens_input: 0, tokens_output: 0, provider_cost: nil) ⇒ Object
Returns the highest cost estimate across all sources (conservative upper bound). Accepts a result/agent object or keyword args. Returns nil when no pricing data found. Returns { cost: Float, source: Symbol, all: Hash } otherwise.
58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/active_harness/pricing/price_resolver.rb', line 58 def max_cost(subject = nil, model_id: nil, tokens_input: 0, tokens_output: 0, provider_cost: nil) args = extract_args(subject, model_id: model_id, tokens_input: tokens_input, tokens_output: tokens_output, provider_cost: provider_cost) return provider_result(args[:provider_cost], args[:model_id]) if args[:provider_cost].to_f > 0 all = costs(model_id: args[:model_id], tokens_input: args[:tokens_input], tokens_output: args[:tokens_output]) return nil if all.empty? src, cost = all.max_by { |_, v| v } { cost: cost, source: src, all: all } end |
.min_cost(subject = nil, model_id: nil, tokens_input: 0, tokens_output: 0, provider_cost: nil) ⇒ Object
Returns the lowest cost estimate across all sources (optimistic lower bound). Accepts a result/agent object or keyword args. Returns nil when no pricing data found. Returns { cost: Float, source: Symbol, all: Hash } otherwise.
75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/active_harness/pricing/price_resolver.rb', line 75 def min_cost(subject = nil, model_id: nil, tokens_input: 0, tokens_output: 0, provider_cost: nil) args = extract_args(subject, model_id: model_id, tokens_input: tokens_input, tokens_output: tokens_output, provider_cost: provider_cost) return provider_result(args[:provider_cost], args[:model_id]) if args[:provider_cost].to_f > 0 all = costs(model_id: args[:model_id], tokens_input: args[:tokens_input], tokens_output: args[:tokens_output]) return nil if all.empty? src, cost = all.min_by { |_, v| v } { cost: cost, source: src, all: all } end |
.resolve(model_id) ⇒ Object
Returns { source_name => PricingData } for every source that has this model. Result is cached by canonical key for CACHE_TTL seconds.
27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/active_harness/pricing/price_resolver.rb', line 27 def resolve(model_id) key = Normalizer.to_key(model_id) cached = resolve_cache[key] return cached unless cached.nil? result = SOURCES.each_with_object({}) do |(name, source), h| hit = source.find(key) h[name] = hit if hit&.input_per_1m && hit&.output_per_1m end resolve_cache[key] = result result end |