Module: Legion::Extensions::Llm::SettingsCascade
- Defined in:
- lib/legion/extensions/llm/settings_cascade.rb
Overview
The shared 3-level settings cascade: provider -> instance -> model, most-specific-first. Single home for resolving operator config (enable_* overrides, weight, preferred_min/max_context_tokens, model_whitelist/blacklist, ...) for a (provider_family, instance, model, key) request.
instance is the operator's CONFIG NAME — the same identity
Identity::InstanceKey#instance_id and the router key settings lookups
by — never a derived host:port/credential value.
Lookup order (first meaningful value wins):
1. model: extensions.llm.<provider>.instances.<instance>.models.<model>.<key>
then extensions.llm.<provider>.models.<model>.<key>
2. instance: extensions.llm.<provider>.instances.<instance>.<key>
3. provider: extensions.llm.<provider>.<key>
Empty values (nil, blank String, empty Array) never resolve; the cascade falls through to the next scope and returns nil when no scope carries a meaningful value.
The cascade READS config only. It never publishes evidence: config and
- override sources remain unknown-only (Taxonomies
UNKNOWN_ONLY_EVIDENCE_SOURCES), and enable_* overrides are consumed router-side, not published as capability evidence.
Class Method Summary collapse
-
.lookup(scope, name) ⇒ Object
Tries the name as-given, as a Symbol, then as a String, preserving meaningful falsy values (false, 0) when the key is present.
- .meaningful?(value) ⇒ Boolean
-
.merge_model_scopes(provider_conf:, instance_cfg:, model:) ⇒ Object
The merged model-scope config hash for one model: the provider's models.
entry with the instance's models. entry overriding it (the merge the capability feeders use). - .model_scope(scope_conf, model) ⇒ Object
-
.resolve(provider_family:, instance:, key:, model: nil) ⇒ Object
Resolve
keyfor (provider_family, instance, model) from the live Legion::Settings[:llm][] path. -
.resolve_from(llm_conf:, provider_family:, instance:, key:, model: nil) ⇒ Object
Resolve against a pre-fetched extensions.llm subtree (plain Hash), e.g.
-
.resolve_value(provider_conf:, instance_cfg:, key:, model: nil) ⇒ Object
The pure 3-level cascade over pre-fetched scope hashes: model scopes (instance-scoped first, then provider-scoped) > instance > provider.
- .text_name!(name, field) ⇒ Object
Class Method Details
.lookup(scope, name) ⇒ Object
Tries the name as-given, as a Symbol, then as a String, preserving meaningful falsy values (false, 0) when the key is present.
103 104 105 106 107 108 109 110 |
# File 'lib/legion/extensions/llm/settings_cascade.rb', line 103 def lookup(scope, name) return nil unless scope.is_a?(::Hash) return scope[name] if scope.key?(name) return scope[name.to_sym] if scope.key?(name.to_sym) scope[name.to_s] end |
.meaningful?(value) ⇒ Boolean
97 98 99 |
# File 'lib/legion/extensions/llm/settings_cascade.rb', line 97 def meaningful?(value) !value.nil? && !value.to_s.empty? && (!value.is_a?(::Array) || value.any?) end |
.merge_model_scopes(provider_conf:, instance_cfg:, model:) ⇒ Object
The merged model-scope config hash for one model: the provider's
models.
83 84 85 86 87 |
# File 'lib/legion/extensions/llm/settings_cascade.rb', line 83 def merge_model_scopes(provider_conf:, instance_cfg:, model:) text_name!(model, :model) model_scope(provider_conf, model).merge(model_scope(instance_cfg, model)) end |
.model_scope(scope_conf, model) ⇒ Object
89 90 91 92 93 94 95 |
# File 'lib/legion/extensions/llm/settings_cascade.rb', line 89 def model_scope(scope_conf, model) models = lookup(scope_conf, :models) return {} unless models.is_a?(::Hash) entry = lookup(models, model) entry.is_a?(::Hash) ? entry : {} end |
.resolve(provider_family:, instance:, key:, model: nil) ⇒ Object
Resolve key for (provider_family, instance, model) from the live
Legion::Settings[:llm][
35 36 37 38 39 40 41 42 43 |
# File 'lib/legion/extensions/llm/settings_cascade.rb', line 35 def resolve(provider_family:, instance:, key:, model: nil) text_name!(provider_family, :provider_family) text_name!(instance, :instance) text_name!(key, :key) text_name!(model, :model) if model llm_conf = Legion::Settings.dig(:extensions, :llm) resolve_from(llm_conf: llm_conf, provider_family: provider_family, instance: instance, key: key, model: model) end |
.resolve_from(llm_conf:, provider_family:, instance:, key:, model: nil) ⇒ Object
Resolve against a pre-fetched extensions.llm subtree (plain Hash), e.g. a router settings snapshot. Same cascade as .resolve.
47 48 49 50 51 52 53 54 55 56 |
# File 'lib/legion/extensions/llm/settings_cascade.rb', line 47 def resolve_from(llm_conf:, provider_family:, instance:, key:, model: nil) text_name!(provider_family, :provider_family) text_name!(instance, :instance) text_name!(key, :key) provider_conf = lookup(llm_conf, provider_family) instances = lookup(provider_conf, :instances) instance_cfg = lookup(instances, instance) resolve_value(provider_conf: provider_conf, instance_cfg: instance_cfg, key: key, model: model) end |
.resolve_value(provider_conf:, instance_cfg:, key:, model: nil) ⇒ Object
The pure 3-level cascade over pre-fetched scope hashes: model scopes (instance-scoped first, then provider-scoped) > instance
provider.
model: nilskips the model leg. Returns the first meaningful value or nil.
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/legion/extensions/llm/settings_cascade.rb', line 62 def resolve_value(provider_conf:, instance_cfg:, key:, model: nil) text_name!(key, :key) text_name!(model, :model) if model scopes = [] scopes << model_scope(instance_cfg, model) if model scopes << model_scope(provider_conf, model) if model scopes << instance_cfg scopes << provider_conf scopes.each do |scope| value = lookup(scope, key) return value if meaningful?(value) end nil end |
.text_name!(name, field) ⇒ Object
112 113 114 115 116 |
# File 'lib/legion/extensions/llm/settings_cascade.rb', line 112 def text_name!(name, field) return if name.is_a?(::String) || name.is_a?(::Symbol) raise ::ArgumentError, "#{field} must be a String or Symbol" end |