Module: Legion::LLM::Inference::Steps::Metering

Extended by:
Legion::Logging::Helper
Included in:
Executor
Defined in:
lib/legion/llm/inference/steps/metering.rb

Class Method Summary collapse

Class Method Details

.build_event(**opts) ⇒ Object



14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/legion/llm/inference/steps/metering.rb', line 14

def build_event(**opts)
  log.debug(
    "[metering][build_event] action=build request_id=#{opts[:request_id]} " \
    "conversation_id=#{opts[:conversation_id] || 'none'} provider=#{opts[:provider]} " \
    "instance=#{opts[:provider_instance] || 'default'} model=#{opts[:model_id]}"
  )
  identity_fields(opts)
    .merge(token_fields(opts))
    .merge(timing_and_context(opts))
    .merge(content_fields(opts))
    .merge(operational_fields(opts))
end

.content_fields(opts) ⇒ Object



91
92
93
94
95
96
97
98
99
# File 'lib/legion/llm/inference/steps/metering.rb', line 91

def content_fields(opts)
  fields = {
    messages:          opts[:messages],
    response_content:  opts[:response_content],
    response_thinking: opts[:response_thinking]
  }
  fields[:context_accounting] = opts[:context_accounting] if opts[:context_accounting]
  fields.compact
end

.flush_spoolObject



42
43
44
45
# File 'lib/legion/llm/inference/steps/metering.rb', line 42

def flush_spool
  log.debug('[metering][flush_spool] action=flush')
  Legion::LLM::Metering.flush_spool
end

.identity_fields(opts) ⇒ Object



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/legion/llm/inference/steps/metering.rb', line 47

def identity_fields(opts)
  {
    node_id:         opts[:node_id],
    worker_id:       opts[:worker_id],
    agent_id:        opts[:agent_id],
    task_id:         opts[:task_id],
    request_id:      opts[:request_id],
    conversation_id: opts[:conversation_id],
    correlation_id:  opts[:correlation_id],
    caller:          opts[:caller],
    identity:        opts[:identity],
    billing:         opts[:billing],
    request_type:    opts[:request_type],
    tier:            opts[:tier],
    provider:        opts[:provider],
    model_id:        opts[:model_id],
    offering_id:     opts[:offering_id]
  }.compact
end

.operational_fields(opts) ⇒ Object



101
102
103
104
105
106
107
# File 'lib/legion/llm/inference/steps/metering.rb', line 101

def operational_fields(opts)
  {
    status:             opts[:status],
    error:              opts[:error],
    provider_submitted: opts[:provider_submitted]
  }.compact
end

.publish_event(event) ⇒ Object



109
110
111
112
113
114
115
# File 'lib/legion/llm/inference/steps/metering.rb', line 109

def publish_event(event)
  log.debug(
    "[metering][publish_event] action=emit request_id=#{event[:request_id]} " \
    "conversation_id=#{event[:conversation_id] || 'none'}"
  )
  Legion::LLM::Metering.emit(event)
end

.publish_or_spool(event) ⇒ Object



27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/legion/llm/inference/steps/metering.rb', line 27

def publish_or_spool(event)
  log.debug(
    "[metering][publish_or_spool] action=publish request_id=#{event[:request_id]} " \
    "provider=#{event[:provider]} model=#{event[:model_id]} total_tokens=#{event[:total_tokens]}"
  )
  result = publish_event(event)
  if result == :dropped
    log.warn(
      "[metering][publish_or_spool] action=dropped request_id=#{event[:request_id]} " \
      "provider=#{event[:provider]} model=#{event[:model_id]}"
    )
  end
  result
end

.timing_and_context(opts) ⇒ Object



80
81
82
83
84
85
86
87
88
89
# File 'lib/legion/llm/inference/steps/metering.rb', line 80

def timing_and_context(opts)
  {
    latency_ms:        opts.fetch(:latency_ms, 0),
    wall_clock_ms:     opts.fetch(:wall_clock_ms, 0),
    cost_usd:          opts[:cost_usd],
    routing_reason:    opts[:routing_reason],
    offering_metadata: opts[:offering_metadata],
    recorded_at:       Time.now.utc.iso8601
  }.compact
end

.token_fields(opts) ⇒ Object



67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/legion/llm/inference/steps/metering.rb', line 67

def token_fields(opts)
  input    = opts.fetch(:input_tokens, 0)
  output   = opts.fetch(:output_tokens, 0)
  thinking = opts.fetch(:thinking_tokens, 0)
  total    = input + output + thinking
  log.debug(
    "[llm][steps][metering] action=token_summary request_id=#{opts[:request_id]} " \
    "input=#{input} output=#{output} thinking=#{thinking} total=#{total}"
  )
  { input_tokens: input, output_tokens: output, thinking_tokens: thinking,
    total_tokens: total }
end