Class: Legion::CLI::Chat::Tools::ProviderHealth

Inherits:
Tools::Base
  • Object
show all
Defined in:
lib/legion/cli/chat/tools/provider_health.rb

Class Method Summary collapse

Methods inherited from Tools::Base

deferred, deferred?, description, error_response, extension, handle_exception, input_schema, log, mcp_category, mcp_tier, runner, sticky, tags, text_response, tool_name, trigger_words

Class Method Details

.call(provider: nil) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/legion/cli/chat/tools/provider_health.rb', line 26

def self.call(provider: nil)
  return 'LLM provider inventory not available.' unless provider_stats_available?

  if provider
    format_detail(provider.strip)
  else
    format_report
  end
rescue StandardError => e
  Legion::Logging.warn("ProviderHealth#execute failed: #{e.message}") if defined?(Legion::Logging)
  "Error checking provider health: #{e.message}"
end

.format_circuit_summary(summary) ⇒ Object



64
65
66
67
68
# File 'lib/legion/cli/chat/tools/provider_health.rb', line 64

def self.format_circuit_summary(summary)
  format('  Circuits: %<closed>d closed, %<open>d open, %<half>d half-open (of %<total>d)',
         closed: summary[:closed], open: summary[:open],
         half: summary[:half_open], total: summary[:total])
end

.format_detail(provider) ⇒ Object



52
53
54
55
56
57
58
59
60
61
62
# File 'lib/legion/cli/chat/tools/provider_health.rb', line 52

def self.format_detail(provider)
  entry = provider_detail(provider)
  return "Router not available: #{entry[:error]}" if entry[:error]
  return "Provider not found: #{provider}" if entry.empty?

  lines = ["Provider: #{entry[:provider]}\n"]
  lines << "  Circuit:    #{entry[:circuit]}"
  lines << "  Healthy:    #{entry[:healthy] ? 'YES' : 'NO'}"
  lines << "  Adjustment: #{entry[:adjustment]}"
  lines.join("\n")
end

.format_entry(entry) ⇒ Object



70
71
72
73
74
75
76
77
78
# File 'lib/legion/cli/chat/tools/provider_health.rb', line 70

def self.format_entry(entry)
  icon = entry[:healthy] ? '+' : '!'
  suffix = +''
  suffix << " offerings=#{entry[:offerings]}" if entry.key?(:offerings)
  suffix << " models=#{entry[:models].length}" if entry[:models].respond_to?(:length)
  format('  [%<icon>s] %<name>-15s circuit=%<circuit>s adj=%<adj>d%<suffix>s',
         icon: icon, name: entry[:provider],
         circuit: entry[:circuit], adj: entry[:adjustment], suffix: suffix)
end

.format_reportObject



39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/legion/cli/chat/tools/provider_health.rb', line 39

def self.format_report
  report = provider_health_report
  return "Router not available: #{report[:error]}" if report.is_a?(Hash) && report[:error]
  return 'No providers configured.' if report.empty?

  summary = provider_circuit_summary(report)
  lines = ["Provider Health Report:\n"]
  lines << format_circuit_summary(summary) if summary.is_a?(Hash) && !summary[:error]
  lines << ''
  report.each { |entry| lines << format_entry(entry) }
  lines.join("\n")
end

.native_provider_health_reportObject



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/legion/cli/chat/tools/provider_health.rb', line 92

def self.native_provider_health_report
  groups = Legion::LLM::Inventory.providers
  return [] unless groups.respond_to?(:map)

  groups.map do |provider, offerings|
    provider_offerings = Array(offerings)
    health = provider_offerings.map { |offering| offering_value(offering, :health) }
                               .find { |entry| entry.is_a?(Hash) } || {}
    circuit = health[:circuit_state] || health['circuit_state'] || 'unknown'
    {
      provider:   provider.to_s,
      circuit:    circuit,
      adjustment: health[:adjustment] || health['adjustment'] || 0,
      healthy:    circuit.to_s != 'open',
      offerings:  provider_offerings.size,
      models:     provider_offerings.map { |offering| offering_value(offering, :model) }.compact.uniq,
      types:      provider_offerings.map { |offering| offering_value(offering, :type) }.compact.uniq,
      instances:  provider_offerings.map do |offering|
        offering_value(offering, :provider_instance) || offering_value(offering, :instance_id)
      end.compact.uniq
    }
  end
end

.native_provider_stats_available?Boolean

Returns:

  • (Boolean)


84
85
86
# File 'lib/legion/cli/chat/tools/provider_health.rb', line 84

def self.native_provider_stats_available?
  defined?(Legion::LLM::Inventory) && Legion::LLM::Inventory.respond_to?(:providers)
end

.offering_value(offering, key) ⇒ Object



131
132
133
134
135
# File 'lib/legion/cli/chat/tools/provider_health.rb', line 131

def self.offering_value(offering, key)
  return unless offering.respond_to?(:[])

  offering[key] || offering[key.to_s]
end

.provider_circuit_summary(report) ⇒ Object



116
117
118
119
120
121
122
123
124
# File 'lib/legion/cli/chat/tools/provider_health.rb', line 116

def self.provider_circuit_summary(report)
  circuits = report.map { |entry| entry[:circuit].to_s }
  {
    total:     report.size,
    closed:    circuits.count('closed'),
    open:      circuits.count('open'),
    half_open: circuits.count('half_open')
  }
end

.provider_detail(provider) ⇒ Object



126
127
128
129
# File 'lib/legion/cli/chat/tools/provider_health.rb', line 126

def self.provider_detail(provider)
  provider_name = provider.to_s
  provider_health_report.find { |entry| entry[:provider] == provider_name } || {}
end

.provider_health_reportObject



88
89
90
# File 'lib/legion/cli/chat/tools/provider_health.rb', line 88

def self.provider_health_report
  native_provider_health_report
end

.provider_stats_available?Boolean

Returns:

  • (Boolean)


80
81
82
# File 'lib/legion/cli/chat/tools/provider_health.rb', line 80

def self.provider_stats_available?
  native_provider_stats_available?
end