Module: LlmCostTracker::Integrations::Base

Included in:
Anthropic, Openai, RubyLlm
Defined in:
lib/llm_cost_tracker/integrations/base.rb

Constant Summary collapse

Result =
LlmCostTracker::Doctor::Check

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.object_dig(object, *path) ⇒ Object



112
113
114
115
116
117
118
# File 'lib/llm_cost_tracker/integrations/base.rb', line 112

def object_dig(object, *path)
  path.reduce(object) do |current, key|
    return nil if current.nil?

    read_object_value(current, key)
  end
end

.object_value(object, *keys) ⇒ Object



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

def object_value(object, *keys)
  keys.each do |key|
    value = read_object_value(object, key)
    return value unless value.nil?
  end
  nil
end

Instance Method Details

#active?Boolean

Returns:

  • (Boolean)


17
18
19
# File 'lib/llm_cost_tracker/integrations/base.rb', line 17

def active?
  LlmCostTracker.configuration.instrumented?(integration_name)
end

#enforce_budget!(request:) ⇒ Object



44
45
46
47
48
49
50
51
52
# File 'lib/llm_cost_tracker/integrations/base.rb', line 44

def enforce_budget!(request:)
  return unless active?

  LlmCostTracker::Tracker.enforce_budget!(
    provider: integration_name.to_s,
    model: request[:model],
    request: request
  )
end

#installObject



21
22
23
24
25
26
27
# File 'lib/llm_cost_tracker/integrations/base.rb', line 21

def install
  validate_contract!
  patch_targets.each do |target|
    target_class = target.fetch(:constant_name).to_s.safe_constantize
    install_patch(target_class, target.fetch(:patch)) if target_class
  end
end

#minimum_versionObject



120
# File 'lib/llm_cost_tracker/integrations/base.rb', line 120

def minimum_version = nil

#normalize_sdk_args(args, kwargs) ⇒ Object



74
75
76
77
78
# File 'lib/llm_cost_tracker/integrations/base.rb', line 74

def normalize_sdk_args(args, kwargs)
  return args if args.any? || kwargs.empty?

  [kwargs]
end

#patch_target(constant_name, with:, methods:, optional: false, skip_when_methods_missing: false) ⇒ Object



126
127
128
129
130
131
132
133
134
# File 'lib/llm_cost_tracker/integrations/base.rb', line 126

def patch_target(constant_name, with:, methods:, optional: false, skip_when_methods_missing: false)
  {
    constant_name: constant_name,
    patch: with,
    method_names: Array(methods),
    optional: optional,
    skip_when_methods_missing: skip_when_methods_missing
  }
end

#patch_targetsObject



124
# File 'lib/llm_cost_tracker/integrations/base.rb', line 124

def patch_targets = []

#record_safelyObject



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

def record_safely
  yield
rescue LlmCostTracker::Error
  raise
rescue StandardError => e
  Logging.warn("#{integration_name} integration failed to record usage: #{e.class}: #{e.message}")
end

#request_params(args, kwargs) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
# File 'lib/llm_cost_tracker/integrations/base.rb', line 62

def request_params(args, kwargs)
  params =
    case args.first
    when Hash then args.first
    when nil then {}
    else args.first.to_h
    end
  params.merge(kwargs).with_indifferent_access
rescue StandardError
  kwargs.to_h.with_indifferent_access
end

#statusObject



29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/llm_cost_tracker/integrations/base.rb', line 29

def status
  name = integration_name.to_s
  problems = version_problems + target_problems
  if problems.any?
    return Result.new(:warn, name, "#{name} integration cannot be installed: #{problems.join('; ')}")
  end

  installed = patch_targets.reject { |target| target.fetch(:optional) }.all? do |target|
    target.fetch(:constant_name).to_s.safe_constantize&.ancestors&.include?(target.fetch(:patch))
  end
  return Result.new(:ok, name, "#{name} integration installed") if installed

  Result.new(:warn, name, "#{name} integration is enabled but not installed")
end

#stream_collector(request) ⇒ Object



91
92
93
94
95
96
97
98
# File 'lib/llm_cost_tracker/integrations/base.rb', line 91

def stream_collector(request)
  LlmCostTracker::Capture::StreamCollector.new(
    provider: integration_name.to_s,
    model: request[:model],
    pricing_mode: stream_pricing_mode(request),
    request: request
  )
end

#stream_pricing_mode(_request) ⇒ Object



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

def stream_pricing_mode(_request)
  nil
end

#track_stream(stream, collector:) ⇒ Object



80
81
82
83
84
85
86
87
88
89
# File 'lib/llm_cost_tracker/integrations/base.rb', line 80

def track_stream(stream, collector:)
  return stream unless active?

  LlmCostTracker::Capture::StreamTracker.new(
    stream: stream,
    collector: collector,
    active: -> { active? },
    finish: ->(errored) { record_safely { collector.finish!(errored: errored) } }
  ).wrap
end

#version_constantObject



122
# File 'lib/llm_cost_tracker/integrations/base.rb', line 122

def version_constant = nil