Module: SwarmSDK::Agent::ChatHelpers::LoggingHelpers

Included in:
SwarmSDK::Agent::Chat, ContextTracker
Defined in:
lib/swarm_sdk/agent/chat_helpers/logging_helpers.rb

Overview

Helper methods for logging and serialization of tool calls and results

Responsibilities:

  • Format tool calls for logging
  • Serialize tool results (handling different types)
  • Calculate LLM costs based on token usage

These are stateless utility methods that operate on data structures.

Instance Method Summary collapse

Instance Method Details

#calculate_cost(message) ⇒ Hash

Calculate LLM cost for a message

Uses RubyLLM's model registry to get pricing information. Returns zero cost if pricing is unavailable.

Parameters:

  • Message with token counts

Returns:

  • Cost breakdown { input_cost:, output_cost:, total_cost: }



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/swarm_sdk/agent/chat_helpers/logging_helpers.rb', line 70

def calculate_cost(message)
  return zero_cost unless message.input_tokens && message.output_tokens

  # Use SwarmSDK's model registry (not RubyLLM's) for up-to-date pricing
  model_info = SwarmSDK::Models.find(message.model_id)
  return zero_cost unless model_info

  # Extract pricing from SwarmSDK's ModelInfo (method access for top-level, Hash for nested)
  pricing = model_info.pricing
  return zero_cost unless pricing

  text_pricing = pricing["text_tokens"] || pricing[:text_tokens]
  return zero_cost unless text_pricing

  standard_pricing = text_pricing["standard"] || text_pricing[:standard]
  return zero_cost unless standard_pricing

  input_price = standard_pricing["input_per_million"] || standard_pricing[:input_per_million]
  output_price = standard_pricing["output_per_million"] || standard_pricing[:output_per_million]

  return zero_cost unless input_price && output_price

  # Calculate costs (prices are per million tokens in USD)
  input_cost = (message.input_tokens / 1_000_000.0) * input_price
  output_cost = (message.output_tokens / 1_000_000.0) * output_price

  {
    input_cost: input_cost,
    output_cost: output_cost,
    total_cost: input_cost + output_cost,
  }
rescue StandardError => e
  # Model not found in registry or pricing not available
  RubyLLM.logger.debug("Cost calculation failed for #{message.model_id}: #{e.message}")
  zero_cost
end

#format_tool_calls(tool_calls_hash) ⇒ Array<Hash>?

Format tool calls for logging

Parameters:

  • Tool calls from message

Returns:

  • Formatted tool calls



19
20
21
22
23
24
25
26
27
28
29
# File 'lib/swarm_sdk/agent/chat_helpers/logging_helpers.rb', line 19

def format_tool_calls(tool_calls_hash)
  return unless tool_calls_hash

  tool_calls_hash.map do |_id, tc|
    {
      id: tc.id,
      name: tc.name,
      arguments: tc.arguments,
    }
  end
end

#serialize_result(result) ⇒ String, ...

Serialize a tool result for logging

Handles multiple result types:

  • String: pass through
  • Hash/Array: pass through
  • RubyLLM::Content: extract text and attachment info
  • Other: convert to string

Parameters:

  • Tool result

Returns:

  • Serialized result



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/swarm_sdk/agent/chat_helpers/logging_helpers.rb', line 41

def serialize_result(result)
  case result
  when String then result
  when Hash, Array then result
  when RubyLLM::Content
    # Format Content objects to show text and attachment info
    parts = []
    parts << result.text if result.text && !result.text.empty?

    if result.attachments.any?
      attachment_info = result.attachments.map do |att|
        "#{att.source} (#{att.mime_type})"
      end.join(", ")
      parts << "[Attachments: #{attachment_info}]"
    end

    parts.join(" ")
  else
    result.to_s
  end
end

#zero_costHash

Zero cost fallback

Returns:

  • Zero cost breakdown



110
111
112
# File 'lib/swarm_sdk/agent/chat_helpers/logging_helpers.rb', line 110

def zero_cost
  { input_cost: 0.0, output_cost: 0.0, total_cost: 0.0 }
end