Module: PWN::Plugins::REPL::AIConsoleUsage

Defined in:
lib/pwn/plugins/repl/ai_console_usage.rb

Overview

Provider-reported token totals and explicitly configured USD estimates.

Defined Under Namespace

Classes: Tracker

Class Method Summary collapse

Class Method Details

.authors ⇒ Object



98
99
100
# File 'lib/pwn/plugins/repl/ai_console_usage.rb', line 98

public_class_method def self.authors
  'AUTHOR(S): 0day Inc. <[email protected]>'
end

.estimate(opts = {}) ⇒ Object

Price only when every used component has an explicit finite USD rate.



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/pwn/plugins/repl/ai_console_usage.rb', line 81

public_class_method def self.estimate(opts = {})
  usage = opts[:usage] || normalize(opts)
  rates = opts[:rates] || rates_for(engine: opts[:engine], model: opts[:model])
  return nil unless rates.is_a?(Hash)

  components = [
    [usage[:input_tokens] - usage[:cached_tokens] - usage[:cache_write_tokens], rates[:input_per_million]],
    [usage[:cached_tokens], rates[:cache_read_per_million] || rates[:input_per_million]],
    [usage[:cache_write_tokens], rates[:cache_write_per_million]],
    [usage[:output_tokens], rates[:output_per_million]]
  ]
  return nil if components.any? { |tokens, rate| tokens.to_i.positive? && !rate?(value: rate) }
  return nil if components.any? { |tokens, _rate| tokens.to_i.negative? }

  components.sum { |tokens, rate| tokens.to_i * rate.to_f / 1_000_000.0 }
end

.help ⇒ Object



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/pwn/plugins/repl/ai_console_usage.rb', line 102

public_class_method def self.help
  puts "USAGE:
    # Normalize one provider usage report. Cached tokens are included in input, not added again.
    #{self}.normalize(
      usage: 'required - provider usage hash'
    )

    # Estimate USD only from explicit nonnegative rates; nil means unavailable, never zero.
    #{self}.estimate(
      usage: 'required - normalized or provider usage hash',
      rates: 'optional - input_per_million, output_per_million, cache_read_per_million, cache_write_per_million',
      engine: 'optional - provider used to read configured rates',
      model: 'optional - model key under that provider pricing hash'
    )

    # Return module authors.
    #{self}.authors
  "
end

.normalize(opts = {}) ⇒ Object

Normalize a provider usage hash without double-counting cached tokens.



66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/pwn/plugins/repl/ai_console_usage.rb', line 66

public_class_method def self.normalize(opts = {})
  raw = opts[:usage].is_a?(Hash) ? opts[:usage] : opts
  details = raw[:input_tokens_details] || raw[:prompt_tokens_details] || {}
  cached = integer(value: details[:cached_tokens] || details[:cache_read_input_tokens] || raw[:cache_read_input_tokens])
  written = integer(value: details[:cache_creation_input_tokens] || raw[:cache_creation_input_tokens])
  input = integer(value: raw[:input_tokens] || raw[:prompt_tokens])
  output = integer(value: raw[:output_tokens] || raw[:completion_tokens])
  reasoning = integer(value: (raw[:output_tokens_details] || {})[:reasoning_tokens] || raw[:reasoning_tokens])
  output += reasoning if raw[:completion_tokens].nil? && raw[:output_tokens].nil?
  reported = raw[:total_tokens]
  total = reported.nil? ? input + output : integer(value: reported)
  { input_tokens: input, output_tokens: output, cached_tokens: cached, cache_write_tokens: written, total_tokens: total }
end