Class: Mistri::Usage

Inherits:
Object
  • Object
show all
Defined in:
lib/mistri/usage.rb

Overview

Token accounting for an assistant turn, and the dollar cost of those tokens.

input counts only prompt tokens billed at the full rate: cache reads and writes are separate fields, so a cached token is never double-billed. reasoning is the thinking slice of output. cache_write_1h is the slice of cache_write held for an hour, which bills at twice the input rate.

Defined Under Namespace

Classes: Cost

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(input: 0, output: 0, cache_read: 0, cache_write: 0, cache_write_1h: 0, reasoning: 0, cost: Cost.unknown) ⇒ Usage

Returns a new instance of Usage.



59
60
61
62
# File 'lib/mistri/usage.rb', line 59

def initialize(input: 0, output: 0, cache_read: 0, cache_write: 0,
               cache_write_1h: 0, reasoning: 0, cost: Cost.unknown)
  super
end

Class Method Details

.from_h(hash) ⇒ Object



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/mistri/usage.rb', line 66

def self.from_h(hash)
  h = (hash || {}).transform_keys(&:to_s)
  c = (h["cost"] || {}).transform_keys(&:to_s)
  counts = { input: h.fetch("input", 0).to_i, output: h.fetch("output", 0).to_i,
             cache_read: h.fetch("cache_read", 0).to_i,
             cache_write: h.fetch("cache_write", 0).to_i,
             cache_write_1h: h.fetch("cache_write_1h", 0).to_i,
             reasoning: h.fetch("reasoning", 0).to_i }
  amounts = { input: c.fetch("input", 0).to_f, output: c.fetch("output", 0).to_f,
              cache_read: c.fetch("cache_read", 0).to_f,
              cache_write: c.fetch("cache_write", 0).to_f,
              total: c.fetch("total", 0).to_f }
  known = c.fetch("known", false) == true
  known ||= !c.key?("known") && counts.values.all?(&:zero?) && amounts.values.all?(&:zero?)
  new(**counts, cost: Cost.new(**amounts, known:))
end

.zeroObject



64
# File 'lib/mistri/usage.rb', line 64

def self.zero = new(cost: Cost.zero)

Instance Method Details

#+(other) ⇒ Object



104
105
106
107
108
109
110
111
# File 'lib/mistri/usage.rb', line 104

def +(other)
  self.class.new(input: input + other.input, output: output + other.output,
                 cache_read: cache_read + other.cache_read,
                 cache_write: cache_write + other.cache_write,
                 cache_write_1h: cache_write_1h + other.cache_write_1h,
                 reasoning: reasoning + other.reasoning,
                 cost: cost + other.cost)
end

#prompt_tokensObject



83
# File 'lib/mistri/usage.rb', line 83

def prompt_tokens = input + cache_read + cache_write

#to_hObject



113
# File 'lib/mistri/usage.rb', line 113

def to_h = super.merge(cost: cost.to_h)

#total_tokensObject



85
# File 'lib/mistri/usage.rb', line 85

def total_tokens = input + output + cache_read + cache_write

#with_cost(rates) ⇒ Object

A copy with cost computed from per-million-token rates. The 1h cache-write slice bills at the :cache_write_1h rate when given, else at twice the input rate, matching extended-retention pricing.



90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/mistri/usage.rb', line 90

def with_cost(rates)
  long = [cache_write_1h, cache_write].min
  short = cache_write - long
  computed = {
    input: rate(rates, :input) * input,
    output: rate(rates, :output) * output,
    cache_read: rate(rates, :cache_read) * cache_read,
    cache_write: (rate(rates, :cache_write) * short) + (long_write_rate(rates) * long)
  }
  with(cost: Cost.new(**computed,
                      total: computed.values.sum,
                      known: rates_cover?(rates, short, long)))
end