Module: LlmCostTracker::Integrations::RubyLlm

Extended by:
Base
Defined in:
lib/llm_cost_tracker/integrations/ruby_llm.rb

Defined Under Namespace

Modules: ProviderPatch

Class Method Summary collapse

Methods included from Base

active?, constant, elapsed_ms, enforce_budget!, install, minimum_version, patch_target, patch_targets, record_safely, request_params, status, version_constant

Class Method Details

.integration_nameObject



11
# File 'lib/llm_cost_tracker/integrations/ruby_llm.rb', line 11

def integration_name = :ruby_llm

.minimum_versionObject



13
# File 'lib/llm_cost_tracker/integrations/ruby_llm.rb', line 13

def minimum_version = "1.14.1"

.model_id(object) ⇒ Object



104
105
106
107
108
109
110
# File 'lib/llm_cost_tracker/integrations/ruby_llm.rb', line 104

def model_id(object)
  return nil if object.nil?

  value = ObjectReader.first(object, :id, :model_id, :model)
  value ||= object if object.is_a?(String) || object.is_a?(Symbol)
  value&.to_s
end

.patch_targetsObject



17
18
19
20
21
22
23
24
25
# File 'lib/llm_cost_tracker/integrations/ruby_llm.rb', line 17

def patch_targets
  [
    patch_target(
      "RubyLLM::Provider",
      with: ProviderPatch,
      methods: %i[slug complete embed transcribe]
    )
  ]
end

.provider_response_id(response) ⇒ Object



117
118
119
# File 'lib/llm_cost_tracker/integrations/ruby_llm.rb', line 117

def provider_response_id(response)
  ObjectReader.first(response, :id, :provider_response_id) || ObjectReader.nested(response, :raw, :id)
end

.provider_slug(provider) ⇒ Object



100
101
102
# File 'lib/llm_cost_tracker/integrations/ruby_llm.rb', line 100

def provider_slug(provider)
  ObjectReader.first(provider, :slug).to_s
end

.record_completion(provider, response, request:, latency_ms:, stream:) ⇒ Object



27
28
29
30
31
32
33
34
35
# File 'lib/llm_cost_tracker/integrations/ruby_llm.rb', line 27

def record_completion(provider, response, request:, latency_ms:, stream:)
  record_usage(
    provider: provider_slug(provider),
    model: response_model_id(response) || model_id(request[:model]),
    response: response,
    latency_ms: latency_ms,
    stream: stream
  )
end

.record_embedding(provider, response, request:, latency_ms:) ⇒ Object



41
42
43
44
45
46
47
48
49
50
# File 'lib/llm_cost_tracker/integrations/ruby_llm.rb', line 41

def record_embedding(provider, response, request:, latency_ms:)
  record_usage(
    provider: provider_slug(provider),
    model: response_model_id(response) || model_id(request[:model]),
    response: response,
    latency_ms: latency_ms,
    stream: false,
    output_tokens: 0
  )
end

.record_transcription(provider, response, request:, latency_ms:) ⇒ Object



52
53
54
55
56
57
58
59
60
# File 'lib/llm_cost_tracker/integrations/ruby_llm.rb', line 52

def record_transcription(provider, response, request:, latency_ms:)
  record_usage(
    provider: provider_slug(provider),
    model: response_model_id(response) || model_id(request[:model]),
    response: response,
    latency_ms: latency_ms,
    stream: false
  )
end

.record_usage(provider:, model:, response:, latency_ms:, stream:, output_tokens: nil) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/llm_cost_tracker/integrations/ruby_llm.rb', line 62

def record_usage(provider:, model:, response:, latency_ms:, stream:, output_tokens: nil)
  return unless active?

  record_safely do
    input_tokens = ObjectReader.first(response, :input_tokens)
    output_tokens = ObjectReader.first(response, :output_tokens) if output_tokens.nil?
    next if input_tokens.nil? && output_tokens.nil?

    cache_read = ObjectReader.integer(ObjectReader.first(response, :cached_tokens))

    LlmCostTracker::Tracker.record(
      provider: provider,
      model: model,
      input_tokens: regular_input_tokens(input_tokens, cache_read),
      output_tokens: ObjectReader.integer(output_tokens),
      latency_ms: latency_ms,
      stream: stream,
      usage_source: :ruby_llm,
      provider_response_id: provider_response_id(response),
      metadata: (response, cache_read)
    )
  end
end

.regular_input_tokens(input_tokens, cache_read) ⇒ Object



96
97
98
# File 'lib/llm_cost_tracker/integrations/ruby_llm.rb', line 96

def regular_input_tokens(input_tokens, cache_read)
  [ObjectReader.integer(input_tokens) - cache_read.to_i, 0].max
end

.response_model_id(object) ⇒ Object



112
113
114
115
# File 'lib/llm_cost_tracker/integrations/ruby_llm.rb', line 112

def response_model_id(object)
  value = ObjectReader.first(object, :model_id, :model)
  value&.to_s
end

.streaming_request?(request, has_block:) ⇒ Boolean

Returns:

  • (Boolean)


37
38
39
# File 'lib/llm_cost_tracker/integrations/ruby_llm.rb', line 37

def streaming_request?(request, has_block:)
  has_block || request[:stream] == true
end

.usage_metadata(response, cache_read) ⇒ Object



86
87
88
89
90
91
92
93
94
# File 'lib/llm_cost_tracker/integrations/ruby_llm.rb', line 86

def (response, cache_read)
  {
    cache_read_input_tokens: cache_read,
    cache_write_input_tokens: ObjectReader.integer(ObjectReader.first(response, :cache_creation_tokens)),
    hidden_output_tokens: ObjectReader.integer(
      ObjectReader.first(response, :thinking_tokens, :reasoning_tokens)
    )
  }
end

.version_constantObject



15
# File 'lib/llm_cost_tracker/integrations/ruby_llm.rb', line 15

def version_constant = "RubyLLM::VERSION"