Module: LlmCostTracker::Integrations

Defined in:
lib/llm_cost_tracker/integrations.rb,
lib/llm_cost_tracker/integrations/base.rb,
lib/llm_cost_tracker/integrations/openai.rb,
lib/llm_cost_tracker/integrations/ruby_llm.rb,
lib/llm_cost_tracker/integrations/anthropic.rb,
lib/llm_cost_tracker/integrations/openai/patches.rb,
lib/llm_cost_tracker/integrations/openai/batch_capture.rb

Defined Under Namespace

Modules: Anthropic, Base, Openai, RubyLlm

Class Method Summary collapse

Class Method Details

.checks(names = LlmCostTracker.configuration.instrumented_integrations) ⇒ Object



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

def self.checks(names = LlmCostTracker.configuration.instrumented_integrations)
  return [Check.new(:ok, "integrations", "no SDK integrations enabled")] if names.empty?

  normalize(names).map do |name|
    integration = fetch(name)
    next integration.status if integration

    Check.new(:warn, name.to_s, "unknown integration; check your config.instrument(...) call")
  end
end

.fetch(name) ⇒ Object



57
58
59
60
61
62
63
# File 'lib/llm_cost_tracker/integrations.rb', line 57

def self.fetch(name)
  const_name = name.to_s.camelize
  return nil unless const_name.match?(/\A[A-Z]\w*\z/)
  return nil unless const_defined?(const_name, false)

  const_get(const_name, false)
end

.install!(names = LlmCostTracker.configuration.instrumented_integrations) ⇒ Object



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

def self.install!(names = LlmCostTracker.configuration.instrumented_integrations)
  normalized = normalize(names)
  warn_double_instrumentation(normalized)
  normalized.each do |name|
    integration = fetch(name)
    next integration.install if integration

    Logging.warn("Unknown integration: #{name.inspect}. Known: #{self.names.map(&:inspect).join(', ')}")
  end
end

.namesObject



65
66
67
# File 'lib/llm_cost_tracker/integrations.rb', line 65

def self.names
  constants(false).reject { |c| c == :Base }.map { |c| c.to_s.underscore.to_sym }.sort
end

.normalize(names) ⇒ Object



40
41
42
# File 'lib/llm_cost_tracker/integrations.rb', line 40

def self.normalize(names)
  Array(names).flatten.uniq
end

.warn_double_instrumentation(names) ⇒ Object



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

def self.warn_double_instrumentation(names)
  return unless names.include?(:ruby_llm)

  overlapping = names - [:ruby_llm]
  return if overlapping.empty?

  Logging.warn(
    ":ruby_llm is enabled together with #{overlapping.map(&:inspect).join(', ')}. " \
    "RubyLLM uses HTTP underneath, so calls routed to those providers may be recorded twice " \
    "(once via the SDK patch, once via the Faraday parser). Pick one path per provider."
  )
end