Module: Legion::LLM::Inventory::Discovery

Extended by:
Legion::Logging::Helper
Defined in:
lib/legion/llm/inventory/discovery.rb,
lib/legion/llm/inventory/discovery/system.rb,
lib/legion/llm/inventory/discovery/memory_gate.rb

Defined Under Namespace

Modules: MemoryGate, System

Constant Summary collapse

DISCOVERABLE_PROVIDERS =

Providers that populate lanes via live discovery (::Every actor polling local endpoints). These are distinguished from static-catalog providers (bedrock, anthropic, openai) which write lanes on boot and don’t need runtime probing.

%i[ollama mlx vllm].freeze
EMBEDDING_TIER_ORDER =
%w[local direct fleet cloud frontier].freeze
MODEL_FAMILY_DELIMITERS =

Version/tag delimiters that separate a model family base from its concrete discovered id (Ollama “model:tag”, Bedrock “family-YYYYMMDD-v1:0” / “family-6”).

%w[: -].freeze
MODEL_DIVERGENCE_SAMPLE_SIZE =

Cap how many discovered ids a divergence warning prints — multi-model cloud providers (Bedrock lists ~90) otherwise dump an unreadable single log line.

10

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.embedding_fallback_chainObject (readonly)

Returns the value of attribute embedding_fallback_chain.



33
34
35
# File 'lib/legion/llm/inventory/discovery.rb', line 33

def embedding_fallback_chain
  @embedding_fallback_chain
end

.embedding_instanceObject (readonly)

Returns the value of attribute embedding_instance.



33
34
35
# File 'lib/legion/llm/inventory/discovery.rb', line 33

def embedding_instance
  @embedding_instance
end

.embedding_modelObject (readonly)

Returns the value of attribute embedding_model.



33
34
35
# File 'lib/legion/llm/inventory/discovery.rb', line 33

def embedding_model
  @embedding_model
end

.embedding_providerObject (readonly)

Returns the value of attribute embedding_provider.



33
34
35
# File 'lib/legion/llm/inventory/discovery.rb', line 33

def embedding_provider
  @embedding_provider
end

Class Method Details

.can_embed?Boolean

Returns:

  • (Boolean)


35
36
37
# File 'lib/legion/llm/inventory/discovery.rb', line 35

def can_embed?
  @can_embed == true
end

.detect_embedding_capabilityObject



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/legion/llm/inventory/discovery.rb', line 56

def detect_embedding_capability
  log.debug '[llm][discovery] action=detect_embedding_capability.enter'

  if detect_embedding_from_registry
    log.debug '[llm][discovery] action=detect_embedding_capability registry_hit=true'
    return
  end

  embedding_settings = self.embedding_settings
  found = find_embedding_provider(embedding_settings)
  if found
    @can_embed = true
    @embedding_provider = found[:provider]
    @embedding_model = found[:model]
    @embedding_fallback_chain = build_embedding_fallback_chain(embedding_settings)
    log.info "[llm][discovery] embedding available provider=#{@embedding_provider} model=#{@embedding_model}"
  else
    @can_embed = false
    @embedding_fallback_chain = []
    log.info '[llm][discovery] no embedding provider available'
  end
rescue StandardError => e
  @can_embed = false
  @embedding_fallback_chain = []
  handle_exception(e, level: :warn, operation: 'llm.discovery.detect_embedding_capability')
end

.discovery_status(provider:, instance: nil) ⇒ Object



39
40
41
# File 'lib/legion/llm/inventory/discovery.rb', line 39

def discovery_status(provider:, instance: nil)
  @discovery_status[discovery_status_key(provider, instance)] || :unknown
end

.fetch_offering_models(entry) ⇒ Object



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/legion/llm/inventory/discovery.rb', line 103

def fetch_offering_models(entry)
  adapter = entry[:adapter]
  return [] unless adapter.respond_to?(:offerings)

  begin
    models = Array(adapter.offerings(live: true)).map do |offering|
      data = normalize_offering(offering)
      report_discovery_health(entry, data)
      {
        model:              (data[:id] || data[:name] || data[:model]).to_s,
        provider:           entry[:provider],
        instance:           normalize_instance_id(data[:instance_id] || data[:provider_instance] || entry[:instance]),
        tier:               data[:tier] || entry.dig(:metadata, :tier),
        size_bytes:         data[:size_bytes] || data[:size],
        capabilities:       source_aware_capabilities(data, entry),
        capability_sources: data[:capability_sources],
        context_length:     data[:context_length] || data[:max_model_len] || data.dig(:limits, :context_window),
        parameter_count:    data[:parameter_count] || data.dig(:metadata, :parameter_count),
        health:             data[:health] || data['health'] || data.dig(:metadata, :health),
        loaded:             extract_loaded_field(data)
      }
    end

    record_discovery_status(
      provider: entry[:provider],
      instance: entry[:instance],
      status:   models.empty? ? :empty : :ok
    )
    warn_on_model_divergence(entry, models)
    models
  rescue StandardError => e
    report_discovery_failure(entry, e)
    []
  end
end

.model_available?(model, provider: nil, instance: nil) ⇒ Boolean

Check whether a specific model is available from any registered provider. Reads the live Inventory lane store — no discovery cache.

Returns:

  • (Boolean)


85
86
87
88
89
90
91
92
93
94
95
# File 'lib/legion/llm/inventory/discovery.rb', line 85

def model_available?(model, provider: nil, instance: nil)
  return false unless defined?(Legion::LLM::Inventory)

  psym = provider&.to_sym
  isym = instance&.to_sym
  Legion::LLM::Inventory.lanes.any? do |l|
    name_matches?(l[:model].to_s, model.to_s) &&
      (psym.nil? || l[:provider_family].to_sym == psym) &&
      (isym.nil? || l[:instance_id].to_sym == isym)
  end
end

.model_size(_model, provider: nil, instance: nil) ⇒ Object

Return the size in bytes for a discovered model, or nil if unknown. After P3, size_bytes is not stored on lanes; always nil.



99
100
101
# File 'lib/legion/llm/inventory/discovery.rb', line 99

def model_size(_model, provider: nil, instance: nil) # rubocop:disable Lint/UnusedMethodArgument
  nil
end

.record_discovery_status(provider:, status:, instance: nil) ⇒ Object



43
44
45
# File 'lib/legion/llm/inventory/discovery.rb', line 43

def record_discovery_status(provider:, status:, instance: nil)
  @discovery_status[discovery_status_key(provider, instance)] = status.to_sym
end

.reset!Object



139
140
141
142
143
144
145
146
147
# File 'lib/legion/llm/inventory/discovery.rb', line 139

def reset!
  log.debug '[llm][discovery] reset'
  @can_embed = nil
  @embedding_provider = nil
  @embedding_model = nil
  @embedding_instance = nil
  @embedding_fallback_chain = nil
  @discovery_status = Concurrent::Map.new
end

.runObject



47
48
49
50
51
52
53
54
# File 'lib/legion/llm/inventory/discovery.rb', line 47

def run
  log.debug '[llm][discovery] run.enter'
  Legion::LLM::Inventory::Discovery::System.refresh! if discovery_enabled?
  log.info "[llm][discovery] system total_mb=#{Legion::LLM::Inventory::Discovery::System.total_memory_mb} " \
           "available_mb=#{Legion::LLM::Inventory::Discovery::System.available_memory_mb}"
rescue StandardError => e
  handle_exception(e, level: :warn, operation: 'llm.discovery.run')
end