Class: Aireview::Config
Overview
Answers questions about the merged settings: values, their source
(layer), the routing plan, provider keys. How settings are read from
files and the environment is ConfigLoader's business.
Constant Summary
collapse
- DEFAULT_SECRET_FILES =
[
'.env',
'.env.*',
'config/secrets.yml',
'config/credentials/*.key',
'spec/fixtures/cassettes/*.yml',
'spec/fixtures/cassettes/**/*.yml',
'spec/cassettes/*.yml',
'spec/cassettes/**/*.yml',
'test/fixtures/cassettes/*.yml',
'test/fixtures/cassettes/**/*.yml'
].freeze
- REVIEW_MODES =
%w[update once].freeze
- DEFAULTS =
{
'review_language' => 'en',
'review_mode' => 'update',
'ignore_paths' => [],
'secret_patterns' => [],
'secret_files' => DEFAULT_SECRET_FILES,
'review_instructions' => nil,
'llm_api_base' => nil,
'ollama_api_base' => 'http://localhost:11434/v1',
'llm_http_proxy' => nil,
'llm' => {
'provider' => 'gemini',
'temperature' => 0,
'timeout' => 60,
'max_prompt_chars' => ConfigLimits::DEFAULT_MAX_PROMPT_CHARS,
'time_budget' => ConfigFallbacks::DEFAULT_TIME_BUDGET,
'overloaded_quarantine' => ConfigFallbacks::DEFAULT_OVERLOADED_QUARANTINE
},
'context' => ConfigLimits::CONTEXT_DEFAULTS
}.freeze
Aireview::ConfigLayers::BUILT_IN_LAYER, Aireview::ConfigLayers::CLI_LAYER, Aireview::ConfigLayers::DATA_LAYER, Aireview::ConfigLayers::ENV_LAYER, Aireview::ConfigLayers::FILE_LAYER, Aireview::ConfigLayers::IMAGE_LAYER
Constants included
from ConfigJev
Aireview::ConfigJev::CRITIQUE_ENGINES, Aireview::ConfigJev::DEFAULT_JEV_MODEL, Aireview::ConfigJev::DEFAULT_JEV_TIMEOUT, Aireview::ConfigJev::JEV_ALIASES, Aireview::ConfigJev::JEV_FALLBACKS, Aireview::ConfigJev::JEV_THRESHOLD_DEFAULTS
Aireview::ConfigFallbacks::DEFAULT_OVERLOADED_QUARANTINE, Aireview::ConfigFallbacks::DEFAULT_TIME_BUDGET, Aireview::ConfigFallbacks::KEYLESS_PROVIDERS, Aireview::ConfigFallbacks::SELF_HOSTED_PLACEHOLDER_KEY
Aireview::ConfigLimits::CONTEXT_DEFAULTS, Aireview::ConfigLimits::DEFAULT_MAX_PROMPT_CHARS
Instance Attribute Summary collapse
Class Method Summary
collapse
Instance Method Summary
collapse
-
#critique_model ⇒ Object
nil when no LLM Critique can run (see llm_stages).
-
#critique_provider ⇒ Object
-
#critique_temperature ⇒ Object
-
#generate_model ⇒ Object
The primary model of a stage is the first in its chain: the start for Generate, the first of the pool for Critique.
-
#generate_provider ⇒ Object
-
#generate_temperature ⇒ Object
-
#gitlab_token ⇒ Object
-
#gitlab_url ⇒ Object
-
#ignore_paths ⇒ Object
-
#initialize(data = nil, config_path: nil, logger: Logger.new($stderr), layers: nil) ⇒ Config
constructor
The layers are the single source of truth: the merged data is computed from them.
-
#jira_configured? ⇒ Boolean
-
#jira_login ⇒ Object
-
#jira_password ⇒ Object
-
#jira_url ⇒ Object
-
#llm_api_base ⇒ Object
-
#llm_api_key ⇒ Object
-
#llm_http_proxy ⇒ Object
-
#llm_provider ⇒ Object
-
#llm_temperature ⇒ Object
-
#llm_timeout ⇒ Object
-
#ollama_api_base ⇒ Object
-
#provider_api_key(provider = llm_provider) ⇒ Object
-
#require_gitlab_token! ⇒ Object
-
#result_signature ⇒ Object
Everything besides the prompt that affects the review result goes into the note key (see ReviewMarker): provider, model and temperature of the stages, Jev as the critique engine, the shared pool with its critique policy.
-
#review_instructions ⇒ Object
-
#review_language ⇒ Object
-
#review_mode ⇒ Object
update — our note is updated when the diff or the settings changed, once — one automatic review; a job Retry updates the review on changes.
-
#secret_files ⇒ Object
-
#secret_patterns ⇒ Object
-
#stage_signature(stage, temperature) ⇒ Object
The primary of a stage on a server of your own goes into the review key with its address; without one the signature is what it was.
-
#with_overrides(generate_model: nil, critique_model: nil, generate_temperature: nil, critique_temperature: nil, critique_engine: nil, no_fallbacks: false, no_critique: false) ⇒ Object
CLI overrides change only the primary model of a stage, the reserves from the config stay; no_fallbacks leaves one model and one key.
#layer_paths, #source_of, #stage_fallbacks_source, #stage_model_source, #stage_provider_source, #stage_provider_warnings, #stage_setting, #stage_setting_layer, #start_inherited?, #warnings
Methods included from ConfigJev
#critique_disabled?, #critique_engine, #jev_api_key, #jev_critique?, #jev_fallback, #jev_model, #jev_shadow?, #jev_signature, #jev_thresholds, #jev_timeout, #jev_warnings, #llm_stages, #require_jev!
#api_key_counts, #candidate_api_keys, #fallback_names, #fallbacks_disabled?, #llm_time_budget, #overloaded_quarantine, #provider_api_keys, #require_llm_configuration!, #require_models!, #routing, #stage_chain
#max_diff_chars, #max_jira_comment_chars, #max_jira_description_chars, #max_mr_description_chars, #max_prompt_chars
Constructor Details
#initialize(data = nil, config_path: nil, logger: Logger.new($stderr), layers: nil) ⇒ Config
The layers are the single source of truth: the merged data is computed
from them. A config built from a hash (without ConfigLoader) is one
layer, otherwise the CLI layer from with_overrides would be the only
one and the stage settings of the original hash would be lost.
72
73
74
75
76
77
|
# File 'lib/aireview/config.rb', line 72
def initialize(data = nil, config_path: nil, logger: Logger.new($stderr), layers: nil)
@layers = layers || [ConfigLayers::Layer.new(name: ConfigLayers::DATA_LAYER, data: Utils.normalize_hash(data))]
@data = @layers.map(&:data).reduce({}) { |merged, layer_data| Utils.deep_merge(merged, layer_data) }
@config_path = config_path
@logger = logger
end
|
Instance Attribute Details
#config_path ⇒ Object
Returns the value of attribute config_path.
58
59
60
|
# File 'lib/aireview/config.rb', line 58
def config_path
@config_path
end
|
#layers ⇒ Object
Returns the value of attribute layers.
58
59
60
|
# File 'lib/aireview/config.rb', line 58
def layers
@layers
end
|
Class Method Details
.load(**options) ⇒ Object
60
61
62
|
# File 'lib/aireview/config.rb', line 60
def self.load(**options)
ConfigLoader.load(**options)
end
|
Instance Method Details
#critique_model ⇒ Object
nil when no LLM Critique can run (see llm_stages).
150
151
152
|
# File 'lib/aireview/config.rb', line 150
def critique_model
routing.stage?('critique') ? routing.primary('critique').model : nil
end
|
#critique_provider ⇒ Object
171
172
173
|
# File 'lib/aireview/config.rb', line 171
def critique_provider
routing.stage?('critique') ? routing.primary('critique').provider : nil
end
|
#critique_temperature ⇒ Object
186
187
188
|
# File 'lib/aireview/config.rb', line 186
def critique_temperature
stage_setting('critique', 'temperature') || DEFAULTS.dig('llm', 'temperature')
end
|
#generate_model ⇒ Object
The primary model of a stage is the first in its chain: the start for
Generate, the first of the pool for Critique. These go into the review key.
145
146
147
|
# File 'lib/aireview/config.rb', line 145
def generate_model
routing.primary('generate').model
end
|
#generate_provider ⇒ Object
154
155
156
|
# File 'lib/aireview/config.rb', line 154
def generate_provider
routing.primary('generate').provider
end
|
#generate_temperature ⇒ Object
182
183
184
|
# File 'lib/aireview/config.rb', line 182
def generate_temperature
stage_setting('generate', 'temperature') || DEFAULTS.dig('llm', 'temperature')
end
|
#gitlab_token ⇒ Object
115
116
117
|
# File 'lib/aireview/config.rb', line 115
def gitlab_token
@data['gitlab_token']
end
|
#gitlab_url ⇒ Object
111
112
113
|
# File 'lib/aireview/config.rb', line 111
def gitlab_url
@data['gitlab_url']
end
|
#ignore_paths ⇒ Object
216
217
218
|
# File 'lib/aireview/config.rb', line 216
def ignore_paths
Array(@data['ignore_paths']).compact
end
|
#jira_login ⇒ Object
123
124
125
|
# File 'lib/aireview/config.rb', line 123
def jira_login
@data['jira_login']
end
|
#jira_password ⇒ Object
127
128
129
|
# File 'lib/aireview/config.rb', line 127
def jira_password
@data['jira_password']
end
|
#jira_url ⇒ Object
119
120
121
|
# File 'lib/aireview/config.rb', line 119
def jira_url
@data['jira_url']
end
|
#llm_api_base ⇒ Object
190
191
192
|
# File 'lib/aireview/config.rb', line 190
def llm_api_base
@data['llm_api_base']
end
|
#llm_api_key ⇒ Object
232
233
234
|
# File 'lib/aireview/config.rb', line 232
def llm_api_key
@data['llm_api_key']
end
|
#llm_http_proxy ⇒ Object
198
199
200
|
# File 'lib/aireview/config.rb', line 198
def llm_http_proxy
@data['llm_http_proxy'] || dig('llm', 'http_proxy')
end
|
#llm_provider ⇒ Object
131
132
133
|
# File 'lib/aireview/config.rb', line 131
def llm_provider
dig('llm', 'provider') || DEFAULTS.dig('llm', 'provider')
end
|
#llm_temperature ⇒ Object
135
136
137
|
# File 'lib/aireview/config.rb', line 135
def llm_temperature
dig('llm', 'temperature') || DEFAULTS.dig('llm', 'temperature')
end
|
#llm_timeout ⇒ Object
139
140
141
|
# File 'lib/aireview/config.rb', line 139
def llm_timeout
dig('llm', 'timeout') || DEFAULTS.dig('llm', 'timeout')
end
|
#ollama_api_base ⇒ Object
194
195
196
|
# File 'lib/aireview/config.rb', line 194
def ollama_api_base
@data['ollama_api_base'] || DEFAULTS['ollama_api_base']
end
|
#provider_api_key(provider = llm_provider) ⇒ Object
236
237
238
|
# File 'lib/aireview/config.rb', line 236
def provider_api_key(provider = llm_provider)
@data["#{provider}_api_key"] || llm_api_key
end
|
#require_gitlab_token! ⇒ Object
246
247
248
249
250
|
# File 'lib/aireview/config.rb', line 246
def require_gitlab_token!
return gitlab_token if Aireview::Utils.present?(gitlab_token)
raise ConfigError, 'GITLAB_TOKEN is required'
end
|
#result_signature ⇒ Object
Everything besides the prompt that affects the review result goes into
the note key (see ReviewMarker): provider, model and temperature of the
stages, Jev as the critique engine, the shared pool with its critique
policy. Reserves of per-stage chains do not change the result.
162
163
164
165
166
167
168
169
|
# File 'lib/aireview/config.rb', line 162
def result_signature
{
'generate' => stage_signature('generate', generate_temperature),
'critique' => (routing.stage?('critique') ? stage_signature('critique', critique_temperature) : nil),
'critique_engine' => jev_signature,
'pool' => routing.signature
}
end
|
#review_instructions ⇒ Object
228
229
230
|
# File 'lib/aireview/config.rb', line 228
def review_instructions
@data['review_instructions']
end
|
#review_language ⇒ Object
202
203
204
|
# File 'lib/aireview/config.rb', line 202
def review_language
@data['review_language'] || DEFAULTS['review_language']
end
|
#review_mode ⇒ Object
update — our note is updated when the diff or the settings changed,
once — one automatic review; a job Retry updates the review on changes.
208
209
210
211
212
213
214
|
# File 'lib/aireview/config.rb', line 208
def review_mode
mode = (@data['review_mode'] || DEFAULTS['review_mode']).to_s
return mode if REVIEW_MODES.include?(mode)
@logger.warn("Unknown review_mode #{mode.inspect}, using #{DEFAULTS['review_mode']}")
DEFAULTS['review_mode']
end
|
#secret_files ⇒ Object
224
225
226
|
# File 'lib/aireview/config.rb', line 224
def secret_files
(DEFAULT_SECRET_FILES + Array(@data['secret_files']).compact).uniq
end
|
#secret_patterns ⇒ Object
220
221
222
|
# File 'lib/aireview/config.rb', line 220
def secret_patterns
Array(@data['secret_patterns']).compact
end
|
#stage_signature(stage, temperature) ⇒ Object
The primary of a stage on a server of your own goes into the review key
with its address; without one the signature is what it was.
177
178
179
180
|
# File 'lib/aireview/config.rb', line 177
def stage_signature(stage, temperature)
primary = routing.primary(stage)
[primary.provider, primary.model, temperature, *primary.api_base]
end
|
#with_overrides(generate_model: nil, critique_model: nil, generate_temperature: nil, critique_temperature: nil, critique_engine: nil, no_fallbacks: false, no_critique: false) ⇒ Object
CLI overrides change only the primary model of a stage, the reserves
from the config stay; no_fallbacks leaves one model and one key.
no_critique — --no-critique: the run has no Critique, so its settings
are neither routed nor validated (see llm_stages).
Seven named flags of the CLI read better than a struct for its own sake.
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
# File 'lib/aireview/config.rb', line 84
def with_overrides( generate_model: nil,
critique_model: nil,
generate_temperature: nil,
critique_temperature: nil,
critique_engine: nil,
no_fallbacks: false,
no_critique: false
)
llm_config = {
'generate' => stage_overrides(model: generate_model, temperature: generate_temperature),
'critique' => stage_overrides(model: critique_model, temperature: critique_temperature)
.merge({'engine' => critique_engine}.compact)
}.reject { |_, overrides| overrides.empty? }
overrides = {}
overrides['llm'] = llm_config unless llm_config.empty?
overrides['fallbacks_disabled'] = true if no_fallbacks
overrides['critique_disabled'] = true if no_critique
return self if overrides.empty?
self.class.new(
config_path: config_path,
logger: @logger,
layers: @layers + [ConfigLayers::Layer.new(name: ConfigLayers::CLI_LAYER, data: overrides)]
)
end
|