active_genie 0.26.5 → 0.26.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ad223ae84ac62d9375af07ba18dca9152296cac5e7c432a6fd07118107c4ab6e
4
- data.tar.gz: 5faa2d7ad89cf2200296f94892470248a544d86cd37880191777226f121d9cf4
3
+ metadata.gz: 47ad459a3acb6b1e37b8cc9d30e072fb1a699177a628212a2b33406c7d019ace
4
+ data.tar.gz: 9ce87f41aa773aae74fa0a822e492263e95d7c4f63aac26eb77a8385351eaa6b
5
5
  SHA512:
6
- metadata.gz: 2a6bd702967d5948e37fed48a9b92d0c2061b4893579e67d526cb3bf9b71b44889b7a5a457d5c78a768f74d6cc650beb17a52c1ce00bf1a5c7d2dc553d88b866
7
- data.tar.gz: 845fecdb4f036ce4a97b99ea54d0f5600544d6ce0b052da99e4533e4555d774ce09bff1dc037d3752f30aabe69acc5b9362ab77eaf17c62b8ebb5244e02b5df8
6
+ metadata.gz: 3a15a6742977c8f1a38f1eab5e5d9a5ef30d79cfd9db8ba630775f7629cd25486e00b63a2122a01281a303e396a0d5faefdcb4b399a65b4eaaf9aeb50ddac116
7
+ data.tar.gz: 4f24bee6532d2251e9051067582bc4bcd1e9ef685996ff34eff15416976774387731917f66482c62efc9d205c552fcd3aacb8b73f869005585fd66fd86b89d12
data/README.md CHANGED
@@ -204,18 +204,22 @@ bundle exec rake active_genie:benchmark[data_extractor]
204
204
 
205
205
  See the [Benchmark README](benchmark/README.md) for detailed results, methodology, and how to contribute to our test suite.
206
206
 
207
- ## Configuration
208
-
209
- | Config | Description | Default |
210
- |--------|-------------|---------|
211
- | `provider` | LLM provider (openai, anthropic, etc) | `nil` |
212
- | `model` | Model to use | `nil` |
213
- | `api_key` | Provider API key | `nil` |
214
- | `timeout` | Request timeout in seconds | `5` |
215
- | `max_retries` | Maximum retry attempts | `3` |
207
+ ## Basic Configuration
208
+
209
+ | Config | Type | Description | Default |
210
+ |--------|------|-------------|---------|
211
+ | `llm.provider` | Symbol | LLM provider (openai, anthropic, etc) | `nil` |
212
+ | `llm.model` | String | Model to use | `nil` |
213
+ | `llm.temperature` | Float | Temperature to use | `0` |
214
+ | `llm.max_tokens` | Integer | Maximum tokens to use | `4096` |
215
+ | `llm.max_retries` | Integer | Maximum retry attempts | `3` |
216
+ | `log.output` | Proc | Log output | `->(log) { $stdout.puts log }` |
217
+ | `ranking.score_variation_threshold` | Integer | Score variation threshold | `30` |
216
218
 
217
219
  > **Note:** Each module can append its own set of configuration, see the individual module documentation for details.
218
220
 
221
+ Read all [configuration](lib/active_genie/config/README.md) for all available options.
222
+
219
223
  ## How to create a new provider
220
224
 
221
225
  ActiveGenie supports adding custom providers to integrate with different LLM services. To create a new provider:
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.26.5
1
+ 0.26.6
@@ -48,14 +48,14 @@ module ActiveGenie
48
48
  config: @config
49
49
  )
50
50
 
51
- ActiveGenie::Logger.call({
52
- code: :battle,
53
- player_a: @player_a[0..30],
54
- player_b: @player_b[0..30],
55
- criteria: @criteria[0..30],
56
- winner: response['impartial_judge_winner'],
57
- reasoning: response['impartial_judge_winner_reasoning']
58
- })
51
+ @config.logger.call({
52
+ code: :battle,
53
+ player_a: @player_a[0..30],
54
+ player_b: @player_b[0..30],
55
+ criteria: @criteria[0..30],
56
+ winner: response['impartial_judge_winner'],
57
+ reasoning: response['impartial_judge_winner_reasoning']
58
+ })
59
59
 
60
60
  response_formatted(response)
61
61
  end
@@ -55,7 +55,7 @@ module ActiveGenie
55
55
  def request(payload)
56
56
  response = post(url, payload, headers:)
57
57
 
58
- ActiveGenie::Logger.call(
58
+ @config.logger.call(
59
59
  {
60
60
  code: :llm_usage,
61
61
  input_tokens: response.dig('usage', 'input_tokens'),
@@ -67,7 +67,7 @@ module ActiveGenie
67
67
  usage: response['usage']
68
68
  }
69
69
  )
70
- ActiveGenie::Logger.call(
70
+ @config.logger.call(
71
71
  {
72
72
  code: :function_calling,
73
73
  fine_tune: true,
@@ -151,7 +151,7 @@ module ActiveGenie
151
151
  #
152
152
  # @param details [Hash] Request and response details
153
153
  def log_request_details(uri:, request:, response:, start_time:, parsed_response:)
154
- ActiveGenie::Logger.call(
154
+ @config.logger.call(
155
155
  {
156
156
  code: :http_request,
157
157
  uri: uri.to_s,
@@ -176,7 +176,7 @@ module ActiveGenie
176
176
  sleep_time = retry_delay * (2**retries)
177
177
  retries += 1
178
178
 
179
- ActiveGenie::Logger.call(
179
+ @config.logger.call(
180
180
  code: :retry_attempt,
181
181
  attempt: retries,
182
182
  max_retries: max_retries,
@@ -32,7 +32,7 @@ module ActiveGenie
32
32
  "Invalid response: #{response}"
33
33
  end
34
34
 
35
- ActiveGenie::Logger.call({ code: :function_calling, fine_tune: true, payload:, response: })
35
+ @config.logger.call({ code: :function_calling, fine_tune: true, payload:, response: })
36
36
 
37
37
  response
38
38
  end
@@ -44,7 +44,7 @@ module ActiveGenie
44
44
 
45
45
  return nil if response.nil?
46
46
 
47
- ActiveGenie::Logger.call(
47
+ @config.logger.call(
48
48
  {
49
49
  code: :llm_usage,
50
50
  input_tokens: response.dig('usage', 'prompt_tokens'),
@@ -34,6 +34,8 @@ module ActiveGenie
34
34
  json_string = response&.dig('candidates', 0, 'content', 'parts', 0, 'text')
35
35
  return nil if json_string.nil? || json_string.empty?
36
36
 
37
+ @config.logger.call({ code: :function_calling, fine_tune: true, payload:, parsed_response: json_string })
38
+
37
39
  normalize_response(json_string)
38
40
  end
39
41
 
@@ -48,7 +50,7 @@ module ActiveGenie
48
50
  def request(payload, params)
49
51
  response = post(url, payload, headers: DEFAULT_HEADERS, params:)
50
52
 
51
- ActiveGenie::Logger.call(
53
+ @config.logger.call(
52
54
  {
53
55
  code: :llm_usage,
54
56
  input_tokens: response['usageMetadata']['promptTokenCount'] || 0,
@@ -59,15 +61,6 @@ module ActiveGenie
59
61
  }
60
62
  )
61
63
 
62
- ActiveGenie::Logger.call(
63
- {
64
- code: :function_calling,
65
- fine_tune: true,
66
- payload:,
67
- parsed_response: response&.dig('candidates', 0, 'content', 'parts', 0, 'text')
68
- }
69
- )
70
-
71
64
  response
72
65
  end
73
66
 
@@ -29,7 +29,7 @@ module ActiveGenie
29
29
 
30
30
  raise InvalidResponseError, "Invalid response: #{response}" if response.nil? || response.keys.empty?
31
31
 
32
- ActiveGenie::Logger.call({ code: :function_calling, fine_tune: true, payload:, response: })
32
+ @config.logger.call({ code: :function_calling, fine_tune: true, payload:, response: })
33
33
 
34
34
  response
35
35
  end
@@ -41,7 +41,7 @@ module ActiveGenie
41
41
 
42
42
  return nil if response.nil?
43
43
 
44
- ActiveGenie::Logger.call(
44
+ @config.logger.call(
45
45
  {
46
46
  code: :llm_usage,
47
47
  input_tokens: response.dig('usage', 'prompt_tokens'),
@@ -0,0 +1,235 @@
1
+ # ActiveGenie Configuration
2
+
3
+ ActiveGenie provides a flexible configuration system that can be customized to suit your needs. This document details all available configuration options.
4
+
5
+ ## Initial Configuration
6
+
7
+ To configure ActiveGenie, use the `ActiveGenie.configure` block in your application's initialization:
8
+
9
+ ```ruby
10
+ ActiveGenie.configure do |config|
11
+ # Provider configurations
12
+ config.providers.openai.api_key = ENV['OPENAI_API_KEY']
13
+
14
+ # Log configurations
15
+ config.log.file_path = 'log/custom_genie.log'
16
+ config.log.fine_tune_file_path = 'log/fine_tune_genie.log'
17
+
18
+ # Other configurations can be added here
19
+ end
20
+ ```
21
+
22
+ ## Configuration Sections
23
+
24
+ ### 1. Log Configuration (`config.log`)
25
+
26
+ The log configuration controls how ActiveGenie handles logging of its operations.
27
+
28
+ #### Available Settings:
29
+
30
+ | Setting | Type | Default | Description |
31
+ |---------|------|---------|-------------|
32
+ | `file_path` | String | `'log/active_genie.log'` | Path to the main log file where all logs will be written. |
33
+ | `fine_tune_file_path` | String | `'log/active_genie_fine_tune.log'` | Path to the fine-tuning specific log file. |
34
+ | `output` | Proc | `->(log) { $stdout.puts log }` | Custom output handler for logs. Must respond to `call`. |
35
+ | `additional_context` | Hash | `{}` | Additional context to be added to each log entry. |
36
+
37
+ #### Methods:
38
+
39
+ - `add_observer(observers: [], scope: {}, &block)`
40
+ - Adds log observers that will be notified of log events.
41
+ - `observers`: An array of callable objects or a single callable object.
42
+ - `scope`: A hash to filter which logs the observer receives.
43
+ - `block`: A block that will be called for matching logs.
44
+
45
+ - `remove_observer(observers)`
46
+ - Removes the specified observers.
47
+
48
+ #### Example:
49
+
50
+ ```ruby
51
+ ActiveGenie.configure do |config|
52
+ config.log.file_path = 'log/my_app/genie.log'
53
+ config.log.fine_tune_file_path = 'log/my_app/fine_tune.log'
54
+
55
+ # Add a custom output handler
56
+ config.log.output = ->(log) { MyLogger.info(log) }
57
+
58
+ # Add an observer for specific log events
59
+ config.log.add_observer(scope: { event: :api_call }) do |log|
60
+ StatsD.increment("genie.api_calls")
61
+ end
62
+ end
63
+ ```
64
+
65
+ ### 2. LLM Configuration (`config.llm`)
66
+
67
+ The LLM configuration is used to define settings for interacting with Large Language Models.
68
+
69
+ #### Available Settings:
70
+
71
+ | Setting | Type | Default | Description |
72
+ |-----------------|---------------------|------------------------------|------------------------------------------------------------------------------------------------------------|
73
+ | `model` | String / nil | `nil` | The specific LLM model to use (e.g., 'gpt-4', 'claude-2'). |
74
+ | `provider` | Symbol / nil | `nil` | The LLM provider (e.g., `:openai`, `:anthropic`). Set as a string, stored as a symbol. |
75
+ | `client` | Object / nil | `nil` | A pre-configured client instance for the LLM provider. If set, other settings might be ignored. |
76
+ | `temperature` | Numeric | `0` | Controls randomness. Higher values (e.g., 0.8) = more random, lower (e.g., 0.2) = more deterministic. |
77
+ | `max_tokens` | Integer | `4096` | Maximum number of tokens to generate in the LLM response. |
78
+ | `max_retries` | Integer / nil | `nil` | Maximum number of times to retry a failed API call to the LLM. |
79
+ | `retry_delay` | Numeric / nil | `nil` | Delay (in seconds) between retries for failed API calls. |
80
+ | `model_tier` | Enum [lower_tier, middle_tier, higher_tier] | `'lower_tier'` | Specifies the model tier, potentially affecting cost/performance. Will be used if `model` is not set. |
81
+ | `read_timeout` | Numeric / nil | `nil` | Timeout (in seconds) for reading data from the LLM API. |
82
+ | `open_timeout` | Numeric / nil | `nil` | Timeout (in seconds) for establishing a connection to the LLM API. |
83
+
84
+ #### Example:
85
+
86
+ ```ruby
87
+ ActiveGenie.configure do |config|
88
+ config.llm.provider = :openai
89
+ config.llm.model = 'gpt-999'
90
+ config.llm.temperature = 0.1
91
+ config.llm.max_tokens = 8000
92
+ config.llm.max_retries = 1
93
+ config.llm.retry_delay = 5 # seconds
94
+ config.llm.model_tier = 'higher_tier' # If model is not set, will use the model tier to select a model
95
+ end
96
+ ```
97
+
98
+ ### 4. Providers Configuration (`config.providers`)
99
+
100
+ The Providers configuration (`config.providers`) manages settings for various Large Language Model (LLM) providers. It allows you to configure multiple providers, set a default, and access individual provider settings. Active Genie automatically loads configurations for supported providers (OpenAI, Anthropic, DeepSeek, Google).
101
+
102
+ #### Main Provider Settings:
103
+
104
+ | Setting | Type | Default | Description |
105
+ |-----------|---------------------|--------------------------------|-----------------------------------------------------------------------------|
106
+ | `default` | String / Symbol | First validly configured provider (often `:openai` if its API key is set) | The name of the default LLM provider to use (e.g., `:openai`, `:anthropic`). You can set this to your preferred provider. |
107
+
108
+ #### Methods for `config.providers`:
109
+
110
+ - `add(provider_classes)`
111
+ - Adds one or more custom provider configuration classes. `provider_classes` can be a single class or an array of classes. (Typically not needed for built-in providers).
112
+ - `remove(provider_classes)`
113
+ - Removes one or more provider configurations based on their classes.
114
+
115
+ #### Example for Main Provider Settings:
116
+
117
+ ```ruby
118
+ ActiveGenie.configure do |config|
119
+ # Set the default provider to use if not specifying one explicitly in operations
120
+ config.providers.default = :anthropic
121
+
122
+ # Configure individual providers (API keys are often set via ENV variables)
123
+ config.providers.openai.api_key = ENV['OPENAI_API_KEY']
124
+ config.providers.anthropic.api_key = ENV['ANTHROPIC_API_KEY']
125
+ # config.providers.deepseek.api_key = ENV['DEEPSEEK_API_KEY']
126
+ # config.providers.google.api_key = ENV['GEMINI_API_KEY']
127
+ end
128
+ ```
129
+
130
+ #### Individual Provider Configurations:
131
+
132
+ The following subsections detail the configurations for each supported LLM provider. Each provider configuration (e.g., `config.providers.openai`) allows setting an `api_key`, `api_url`, and specific model names for `lower_tier_model`, `middle_tier_model`, and `higher_tier_model`.
133
+
134
+ ##### a. OpenAI (`config.providers.openai`)
135
+
136
+ Internal Name: `:openai`
137
+
138
+ | Setting | Type | Default | Description |
139
+ |---------------------|--------|---------------------------------------|-----------------------------------------------------------------------------|
140
+ | `api_key` | String | `ENV['OPENAI_API_KEY']` | Your OpenAI API key. |
141
+ | `api_url` | String | `'https://api.openai.com/v1'` | Base URL for the OpenAI API. |
142
+ | `lower_tier_model` | String | `'gpt-4.1-mini'` | Model for lower-tier usage (cost-effective, faster). |
143
+ | `middle_tier_model` | String | `'gpt-4.1'` | Model for middle-tier usage (balanced performance). |
144
+ | `higher_tier_model` | String | `'o3-mini'` | Model for higher-tier usage (most capable). |
145
+
146
+ ##### b. Anthropic (`config.providers.anthropic`)
147
+
148
+ Internal Name: `:anthropic`
149
+
150
+ | Setting | Type | Default | Description |
151
+ |---------------------|--------|------------------------------------------|-----------------------------------------------------------------------------|
152
+ | `api_key` | String | `ENV['ANTHROPIC_API_KEY']` | Your Anthropic API key. |
153
+ | `api_url` | String | `'https://api.anthropic.com'` | Base URL for the Anthropic API. |
154
+ | `anthropic_version` | String | `'2023-06-01'` | The API version for Anthropic. |
155
+ | `lower_tier_model` | String | `'claude-3-5-haiku-20241022'` | Model for lower-tier usage. |
156
+ | `middle_tier_model` | String | `'claude-3-7-sonnet-20250219'` | Model for middle-tier usage. |
157
+ | `higher_tier_model` | String | `'claude-3-opus-20240229'` | Model for higher-tier usage. |
158
+
159
+ ##### c. DeepSeek (`config.providers.deepseek`)
160
+
161
+ Internal Name: `:deepseek`
162
+
163
+ | Setting | Type | Default | Description |
164
+ |---------------------|--------|---------------------------------------|-----------------------------------------------------------------------------|
165
+ | `api_key` | String | `ENV['DEEPSEEK_API_KEY']` | Your DeepSeek API key. |
166
+ | `api_url` | String | `'https://api.deepseek.com/v1'` | Base URL for the DeepSeek API. |
167
+ | `lower_tier_model` | String | `'deepseek-chat'` | Model for lower-tier usage. |
168
+ | `middle_tier_model` | String | `'deepseek-chat'` | Model for middle-tier usage. |
169
+ | `higher_tier_model` | String | `'deepseek-reasoner'` | Model for higher-tier usage. |
170
+
171
+ ##### d. Google (`config.providers.google`)
172
+
173
+ Internal Name: `:google`
174
+
175
+ | Setting | Type | Default | Description |
176
+ |---------------------|--------|---------------------------------------------------------------|-----------------------------------------------------------------------------|
177
+ | `api_key` | String | `ENV['GENERATIVE_LANGUAGE_GOOGLE_API_KEY']` or `ENV['GEMINI_API_KEY']` | Your Google API key for Gemini. |
178
+ | `api_url` | String | `'https://generativelanguage.googleapis.com'` | Base URL for the Google Generative Language API. |
179
+ | `lower_tier_model` | String | `'gemini-2.0-flash-lite'` | Model for lower-tier usage. |
180
+ | `middle_tier_model` | String | `'gemini-2.0-flash'` | Model for middle-tier usage. |
181
+ | `higher_tier_model` | String | `'gemini-2.5-pro-experimental'` | Model for higher-tier usage. |
182
+
183
+ #### Example for Overriding Individual Provider Settings:
184
+
185
+ ```ruby
186
+ ActiveGenie.configure do |config|
187
+ config.providers.openai.api_key = 'sk-yourOpenAiKey...'
188
+ config.providers.openai.middle_tier_model = 'gpt-4o' # Override default middle tier for OpenAI
189
+
190
+ config.providers.anthropic.api_key = 'sk-ant-yourAnthropicKey...'
191
+ config.providers.anthropic.anthropic_version = '2024-02-15' # Override Anthropic API version
192
+
193
+ config.providers.google.higher_tier_model = 'gemini-1.5-pro-latest' # Use a specific Google model
194
+ end
195
+ ```
196
+
197
+ ### 5. Ranking Configuration (`config.ranking`)
198
+
199
+ The Ranking configuration (`config.ranking`) deals with settings related to how results or items are ranked.
200
+
201
+ #### Available Settings:
202
+
203
+ | Setting | Type | Default | Description |
204
+ |-----------------------------|---------|---------|------------------------------------------------------------------------------------------------------------|
205
+ | `score_variation_threshold` | Integer | `30` | A threshold (percentage) used to determine significant variations in scores when ranking or comparing items. |
206
+
207
+ #### Example:
208
+
209
+ ```ruby
210
+ ActiveGenie.configure do |config|
211
+ config.ranking.score_variation_threshold = 25 # Set to 25%
212
+ end
213
+ ```
214
+
215
+ ### 6. Data Extractor Configuration (`config.data_extractor`)
216
+
217
+ The Data Extractor configuration (`config.data_extractor`) provides settings for how data is extracted and processed, likely from text or other sources using LLMs.
218
+
219
+ #### Available Settings:
220
+
221
+ | Setting | Type | Default | Description |
222
+ |--------------------|---------|---------|---------------------------------------------------------------------------------------------------------|
223
+ | `with_explanation` | Boolean | `true` | Whether the data extraction process should also attempt to provide an explanation for the extracted data. |
224
+ | `min_accuracy` | Integer | `70` | The minimum accuracy (percentage) required for extracted data to be considered valid or useful. |
225
+ | `verbose` | Boolean | `false` | If true, enables more detailed logging or output from the data extraction process. |
226
+
227
+ #### Example:
228
+
229
+ ```ruby
230
+ ActiveGenie.configure do |config|
231
+ config.data_extractor.with_explanation = false
232
+ config.data_extractor.min_accuracy = 85
233
+ config.data_extractor.verbose = true
234
+ end
235
+ ```
@@ -4,6 +4,7 @@ module ActiveGenie
4
4
  module Config
5
5
  class LogConfig
6
6
  attr_writer :file_path, :fine_tune_file_path
7
+ attr_reader :output, :observers
7
8
 
8
9
  def file_path
9
10
  @file_path || 'log/active_genie.log'
@@ -13,8 +14,12 @@ module ActiveGenie
13
14
  @fine_tune_file_path || 'log/active_genie_fine_tune.log'
14
15
  end
15
16
 
16
- def output
17
- @output || ->(log) { $stdout.puts log }
17
+ def additional_context
18
+ @additional_context || {}
19
+ end
20
+
21
+ def additional_context=(context)
22
+ @additional_context = additional_context.merge(context).compact
18
23
  end
19
24
 
20
25
  def output=(output)
@@ -23,29 +28,17 @@ module ActiveGenie
23
28
  @output = output
24
29
  end
25
30
 
26
- def output_call(log)
27
- output&.call(log)
28
-
29
- Array(@observers).each do |obs|
30
- next unless obs[:scope].all? { |key, value| log[key.to_sym] == value }
31
-
32
- obs[:observer]&.call(log)
33
- rescue StandardError => e
34
- ActiveGenie::Logger.call(code: :observer_error, **obs, error: e.message)
35
- end
36
- end
37
-
38
31
  def add_observer(observers: [], scope: {}, &block)
39
32
  @observers ||= []
40
33
 
41
34
  raise ArgumentError, 'Scope must be a hash' if scope && !scope.is_a?(Hash)
42
35
 
43
- @observers << { observer: block, scope: } if block_given?
44
36
  Array(observers).each do |observer|
45
37
  next unless observer.respond_to?(:call)
46
38
 
47
39
  @observers << { observer:, scope: }
48
40
  end
41
+ @observers << { observer: block, scope: } if block_given?
49
42
  end
50
43
 
51
44
  def remove_observer(observers)
@@ -60,6 +53,10 @@ module ActiveGenie
60
53
 
61
54
  def merge(config_params = {})
62
55
  dup.tap do |config|
56
+ config_params.compact.each do |key, value|
57
+ config.send("#{key}=", value) if config.respond_to?("#{key}=")
58
+ end
59
+
63
60
  config.add_observer(config_params[:observers]) if config_params[:observers]
64
61
  end
65
62
  end
@@ -48,8 +48,8 @@ module ActiveGenie
48
48
  # Retrieves the model name designated for the upper tier (e.g., most capable).
49
49
  # Defaults to 'claude-3-opus'.
50
50
  # @return [String] The upper tier model name.
51
- def upper_tier_model
52
- @upper_tier_model || 'claude-3-opus-20240229'
51
+ def higher_tier_model
52
+ @higher_tier_model || 'claude-3-opus-20240229'
53
53
  end
54
54
  end
55
55
  end
@@ -41,8 +41,8 @@ module ActiveGenie
41
41
  # Retrieves the model name designated for the upper tier (e.g., most capable).
42
42
  # Defaults to 'deepseek-reasoner'.
43
43
  # @return [String] The upper tier model name.
44
- def upper_tier_model
45
- @upper_tier_model || 'deepseek-reasoner'
44
+ def higher_tier_model
45
+ @higher_tier_model || 'deepseek-reasoner'
46
46
  end
47
47
  end
48
48
  end
@@ -43,8 +43,8 @@ module ActiveGenie
43
43
  # Retrieves the model name designated for the upper tier (e.g., most capable).
44
44
  # Defaults to 'gemini-2.5-pro-experimental'.
45
45
  # @return [String] The upper tier model name.
46
- def upper_tier_model
47
- @upper_tier_model || 'gemini-2.5-pro-experimental'
46
+ def higher_tier_model
47
+ @higher_tier_model || 'gemini-2.5-pro-experimental'
48
48
  end
49
49
  end
50
50
  end
@@ -41,8 +41,8 @@ module ActiveGenie
41
41
  # Retrieves the model name designated for the upper tier (e.g., most capable).
42
42
  # Defaults to 'o1-preview'.
43
43
  # @return [String] The upper tier model name.
44
- def upper_tier_model
45
- @upper_tier_model || 'o3-mini'
44
+ def higher_tier_model
45
+ @higher_tier_model || 'o3-mini'
46
46
  end
47
47
  end
48
48
  end
@@ -7,7 +7,7 @@ module ActiveGenie
7
7
  NAME = :unknown
8
8
 
9
9
  attr_writer :api_key, :organization, :api_url, :client,
10
- :lower_tier_model, :middle_tier_model, :upper_tier_model
10
+ :lower_tier_model, :middle_tier_model, :higher_tier_model
11
11
 
12
12
  # Maps a symbolic tier (:lower_tier, :middle_tier, :upper_tier) to a specific model name.
13
13
  # Falls back to the lower_tier_model if the tier is nil or unrecognized.
@@ -17,7 +17,7 @@ module ActiveGenie
17
17
  {
18
18
  lower_tier: lower_tier_model,
19
19
  middle_tier: middle_tier_model,
20
- upper_tier: upper_tier_model
20
+ upper_tier: higher_tier_model
21
21
  }[tier&.to_sym] || lower_tier_model
22
22
  end
23
23
 
@@ -31,7 +31,7 @@ module ActiveGenie
31
31
  api_url:,
32
32
  lower_tier_model:,
33
33
  middle_tier_model:,
34
- upper_tier_model:,
34
+ higher_tier_model:,
35
35
  **config
36
36
  }
37
37
  end
@@ -80,7 +80,7 @@ module ActiveGenie
80
80
  # Retrieves the model name designated for the upper tier (e.g., most capable).
81
81
  # Defaults to 'o1-preview'.
82
82
  # @return [String] The upper tier model name.
83
- def upper_tier_model
83
+ def higher_tier_model
84
84
  raise NotImplementedError, 'Subclasses must implement this method'
85
85
  end
86
86
  end
@@ -38,6 +38,10 @@ module ActiveGenie
38
38
  @llm ||= Config::LlmConfig.new
39
39
  end
40
40
 
41
+ def logger
42
+ @logger ||= ActiveGenie::Logger.new(log_config: log)
43
+ end
44
+
41
45
  SUB_CONFIGS = %w[log providers llm ranking scoring data_extractor battle].freeze
42
46
 
43
47
  def merge(config_params = {})
@@ -54,20 +58,28 @@ module ActiveGenie
54
58
 
55
59
  new_configuration.send("#{key}=", new_config)
56
60
  end
61
+ @logger = nil
57
62
 
58
63
  new_configuration
59
64
  end
60
65
 
66
+ # Merges a sub config with the config_params.
67
+ # Examples:
68
+ # config.merge({ 'log' => { file_path: 'log/active_genie.log' } })
69
+ # config.merge({ log: { file_path: 'log/active_genie.log' } })
70
+ # config.merge({ file_path: 'log/active_genie.log' })
71
+ # these are all the same
72
+
61
73
  def sub_config_merge(config, key, config_params)
62
- if config_params.key?(key.to_s)
74
+ if config_params&.key?(key.to_s)
63
75
  config.merge(config_params[key.to_s])
64
- elsif config_params.key?(key.to_sym)
76
+ elsif config_params&.key?(key.to_sym)
65
77
  config.merge(config_params[key.to_sym])
66
78
  else
67
- config.merge(config_params)
79
+ config.merge(config_params || {})
68
80
  end
69
81
  end
70
82
 
71
- attr_writer :log, :providers, :ranking, :scoring, :data_extractor, :battle, :llm
83
+ attr_writer :log, :providers, :ranking, :scoring, :data_extractor, :battle, :llm, :logger
72
84
  end
73
85
  end
@@ -87,7 +87,7 @@ module ActiveGenie
87
87
  config: @config
88
88
  )
89
89
 
90
- ActiveGenie::Logger.call(
90
+ @config.logger.call(
91
91
  {
92
92
  code: :data_extractor,
93
93
  text: @text[0..30],
@@ -4,47 +4,65 @@ require 'json'
4
4
  require 'fileutils'
5
5
 
6
6
  module ActiveGenie
7
- module Logger
8
- module_function
7
+ class Logger
8
+ def initialize(log_config: nil)
9
+ @log_config = log_config || ActiveGenie.configuration.log
10
+ end
9
11
 
10
12
  def call(data)
11
- log = {
12
- **(@context || {}),
13
- **(data || {}),
14
- timestamp: Time.now,
15
- process_id: Process.pid
16
- }
13
+ log = data.merge(@log_config.additional_context)
14
+ .merge(
15
+ timestamp: Time.now,
16
+ process_id: Process.pid
17
+ )
17
18
 
18
19
  persist!(log)
19
- config.output_call(log)
20
+ output_call(log)
21
+ call_observers(log)
20
22
 
21
23
  log
22
24
  end
23
25
 
24
- def with_context(context, observer: nil)
25
- @context ||= {}
26
- begin
27
- @context = @context.merge(context)
28
- config.add_observer(observers: [observer])
29
- yield if block_given?
30
- ensure
31
- @context.delete_if { |key, _| context.key?(key) }
32
- config.remove_observer([observer])
26
+ def merge(log_config = nil)
27
+ new(log_config:)
28
+ end
29
+
30
+ private
31
+
32
+ def call_observers(log)
33
+ Array(@log_config.observers).each do |observer|
34
+ next unless observer[:scope].all? { |key, value| log[key.to_sym] == value }
35
+
36
+ observer[:observer]&.call(log)
37
+ rescue StandardError => e
38
+ call(code: :observer_error, **observer, error: e.message)
33
39
  end
34
40
  end
35
41
 
36
- attr_accessor :context
42
+ def output_call(log)
43
+ if @log_config.output
44
+ @log_config.output&.call(log)
45
+ else
46
+ $stdout.puts log
47
+ end
48
+ rescue StandardError => e
49
+ call(code: :output_error, error: e.message)
50
+ end
37
51
 
38
52
  def persist!(log)
39
- file_path = log.key?(:fine_tune) && log[:fine_tune] ? config.fine_tune_file_path : config.file_path
53
+ file_path = log_to_file_path(log)
40
54
  folder_path = File.dirname(file_path)
41
55
 
42
56
  FileUtils.mkdir_p(folder_path)
43
57
  File.write(file_path, "#{JSON.generate(log)}\n", mode: 'a')
44
58
  end
45
59
 
46
- def config
47
- ActiveGenie.configuration.log
60
+ def log_to_file_path(log)
61
+ if log.key?(:fine_tune) && log[:fine_tune]
62
+ @log_config.fine_tune_file_path
63
+ else
64
+ @log_config.file_path
65
+ end
48
66
  end
49
67
  end
50
68
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../battle/generalist'
4
-
5
3
  module ActiveGenie
6
4
  module Ranking
7
5
  class EloRound
@@ -9,27 +7,26 @@ module ActiveGenie
9
7
  new(...).call
10
8
  end
11
9
 
12
- def initialize(players, criteria, config: {})
10
+ def initialize(players, criteria, config: nil)
13
11
  @players = players
14
12
  @relegation_tier = players.calc_relegation_tier
15
13
  @defender_tier = players.calc_defender_tier
16
14
  @criteria = criteria
17
- @config = config
15
+ @config = ActiveGenie.configuration.merge(config)
18
16
  @tmp_defenders = []
19
17
  @total_tokens = 0
20
- @previous_elo = {}
18
+ @previous_elo = @players.to_h { |player| [player.id, player.elo] }
21
19
  @previous_highest_elo = @defender_tier.max_by(&:elo).elo
22
20
  end
23
21
 
24
22
  def call
25
- @previous_elo = @players.to_h { |player| [player.id, player.elo] }
23
+ @config.log.add_observer(observers: ->(log) { log_observer(log) })
24
+ @config.log.additional_context = { elo_round_id: }
26
25
 
27
- ActiveGenie::Logger.with_context(log_context) do
28
- matches.each do |player_a, player_b|
29
- # TODO: battle can take a while, can be parallelized
30
- winner, loser = battle(player_a, player_b)
31
- update_players_elo(winner, loser)
32
- end
26
+ matches.each do |player_a, player_b|
27
+ # TODO: battle can take a while, can be parallelized
28
+ winner, loser = battle(player_a, player_b)
29
+ update_players_elo(winner, loser)
33
30
  end
34
31
 
35
32
  build_report
@@ -62,22 +59,20 @@ module ActiveGenie
62
59
  end
63
60
 
64
61
  def battle(player_a, player_b)
65
- ActiveGenie::Logger.with_context({ player_a_id: player_a.id, player_b_id: player_b.id }) do
66
- result = ActiveGenie::Battle.call(
67
- player_a.content,
68
- player_b.content,
69
- @criteria,
70
- config: @config
71
- )
72
-
73
- winner, loser = case result['winner']
74
- when 'player_a' then [player_a, player_b]
75
- when 'player_b' then [player_b, player_a]
76
- when 'draw' then [nil, nil]
77
- end
78
-
79
- [winner, loser]
80
- end
62
+ result = ActiveGenie::Battle.call(
63
+ player_a.content,
64
+ player_b.content,
65
+ @criteria,
66
+ config: @config.merge(additional_context: { player_a_id: player_a.id, player_b_id: player_b.id })
67
+ )
68
+
69
+ winner, loser = case result['winner']
70
+ when 'player_a' then [player_a, player_b]
71
+ when 'player_b' then [player_b, player_a]
72
+ when 'draw' then [nil, nil]
73
+ end
74
+
75
+ [winner, loser]
81
76
  end
82
77
 
83
78
  def update_players_elo(winner, loser)
@@ -94,16 +89,14 @@ module ActiveGenie
94
89
  player_rating + (K * (score - expected_score)).round
95
90
  end
96
91
 
97
- def log_context
98
- { elo_round_id: }
99
- end
100
-
101
92
  def elo_round_id
102
- relegation_tier_ids = @relegation_tier.map(&:id).join(',')
103
- defender_tier_ids = @defender_tier.map(&:id).join(',')
93
+ @elo_round_id ||= begin
94
+ relegation_tier_ids = @relegation_tier.map(&:id).join(',')
95
+ defender_tier_ids = @defender_tier.map(&:id).join(',')
104
96
 
105
- ranking_unique_key = [relegation_tier_ids, defender_tier_ids, @criteria, @config.to_json].join('-')
106
- Digest::MD5.hexdigest(ranking_unique_key)
97
+ ranking_unique_key = [relegation_tier_ids, defender_tier_ids, @criteria, @config.to_json].join('-')
98
+ Digest::MD5.hexdigest(ranking_unique_key)
99
+ end
107
100
  end
108
101
 
109
102
  def build_report
@@ -118,7 +111,7 @@ module ActiveGenie
118
111
  players_elo_diff:
119
112
  }
120
113
 
121
- ActiveGenie::Logger.call({ code: :elo_round_report, **report })
114
+ @config.logger.call({ elo_round_id:, code: :elo_round_report, **report })
122
115
 
123
116
  report
124
117
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../battle/generalist'
4
-
5
3
  module ActiveGenie
6
4
  module Ranking
7
5
  class FreeForAll
@@ -9,21 +7,22 @@ module ActiveGenie
9
7
  new(...).call
10
8
  end
11
9
 
12
- def initialize(players, criteria, config: {})
10
+ def initialize(players, criteria, config: nil)
13
11
  @players = players
14
12
  @criteria = criteria
15
- @config = config
13
+ @config = config || ActiveGenie.configuration
16
14
  @start_time = Time.now
17
15
  @total_tokens = 0
18
16
  end
19
17
 
20
18
  def call
21
- ActiveGenie::Logger.with_context(log_context, observer: ->(log) { log_observer(log) }) do
22
- matches.each do |player_a, player_b|
23
- winner, loser = battle(player_a, player_b)
19
+ @config.log.add_observer(observers: ->(log) { log_observer(log) })
20
+ @config.log.additional_context = { free_for_all_id: }
21
+
22
+ matches.each do |player_a, player_b|
23
+ winner, loser = battle(player_a, player_b)
24
24
 
25
- update_players_score(winner, loser)
26
- end
25
+ update_players_score(winner, loser)
27
26
  end
28
27
 
29
28
  build_report
@@ -38,26 +37,30 @@ module ActiveGenie
38
37
  end
39
38
 
40
39
  def battle(player_a, player_b)
40
+ log_context = { player_a_id: player_a.id, player_b_id: player_b.id }
41
+
41
42
  result = ActiveGenie::Battle.call(
42
43
  player_a.content,
43
44
  player_b.content,
44
45
  @criteria,
45
- config: @config
46
+ config: @config.merge(additional_context: log_context)
46
47
  )
47
48
 
48
49
  winner, loser = case result['winner']
49
- when 'player_a' then [player_a, player_b, result['reasoning']]
50
- when 'player_b' then [player_b, player_a, result['reasoning']]
51
- when 'draw' then [nil, nil, result['reasoning']]
50
+ when 'player_a' then [player_a, player_b]
51
+ when 'player_b' then [player_b, player_a]
52
+ when 'draw' then [nil, nil]
52
53
  end
53
54
 
54
- ActiveGenie::Logger.call({
55
- code: :free_for_all_battle,
56
- player_ids: [player_a.id, player_b.id],
57
- winner_id: winner&.id,
58
- loser_id: loser&.id,
59
- reasoning: result['reasoning']
60
- })
55
+ @config.logger.call(
56
+ {
57
+ **log_context,
58
+ code: :free_for_all_battle,
59
+ winner_id: winner&.id,
60
+ loser_id: loser&.id,
61
+ reasoning: result['reasoning']
62
+ }
63
+ )
61
64
 
62
65
  [winner, loser]
63
66
  end
@@ -74,14 +77,12 @@ module ActiveGenie
74
77
  end
75
78
  end
76
79
 
77
- def log_context
78
- { free_for_all_id: }
79
- end
80
-
81
80
  def free_for_all_id
82
- eligible_ids = @players.eligible.map(&:id).join(',')
83
- ranking_unique_key = [eligible_ids, @criteria, @config.to_json].join('-')
84
- Digest::MD5.hexdigest(ranking_unique_key)
81
+ @free_for_all_id ||= begin
82
+ eligible_ids = @players.eligible.map(&:id).join(',')
83
+ ranking_unique_key = [eligible_ids, @criteria, @config.to_json].join('-')
84
+ Digest::MD5.hexdigest(ranking_unique_key)
85
+ end
85
86
  end
86
87
 
87
88
  def build_report
@@ -92,7 +93,7 @@ module ActiveGenie
92
93
  total_tokens: @total_tokens
93
94
  }
94
95
 
95
- ActiveGenie::Logger.call({ code: :free_for_all_report, **report })
96
+ @config.logger.call({ code: :free_for_all_report, **report })
96
97
 
97
98
  report
98
99
  end
@@ -47,34 +47,26 @@ module ActiveGenie
47
47
  end
48
48
 
49
49
  def score=(value)
50
- ActiveGenie::Logger.call({ code: :new_score, player_id: id, score: value }) if value != @score
51
50
  @score = value
52
51
  @elo = generate_elo_by_score
53
52
  end
54
53
 
55
54
  def elo=(value)
56
- ActiveGenie::Logger.call({ code: :new_elo, player_id: id, elo: value }) if value != @elo
57
55
  @elo = value || BASE_ELO
58
56
  end
59
57
 
60
- def eliminated=(value)
61
- ActiveGenie::Logger.call({ code: :new_eliminated, player_id: id, eliminated: value }) if value != @eliminated
62
- @eliminated = value
63
- end
58
+ attr_writer :eliminated
64
59
 
65
60
  def draw!
66
61
  @ffa_draw_count += 1
67
- ActiveGenie::Logger.call({ code: :new_ffa_score, player_id: id, result: 'draw', ffa_score: })
68
62
  end
69
63
 
70
64
  def win!
71
65
  @ffa_win_count += 1
72
- ActiveGenie::Logger.call({ code: :new_ffa_score, player_id: id, result: 'win', ffa_score: })
73
66
  end
74
67
 
75
68
  def lose!
76
69
  @ffa_lose_count += 1
77
- ActiveGenie::Logger.call({ code: :new_ffa_score, player_id: id, result: 'lose', ffa_score: })
78
70
  end
79
71
 
80
72
  def ffa_score
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'concerns/loggable'
4
3
  require_relative 'players_collection'
5
4
  require_relative 'free_for_all'
6
5
  require_relative 'elo_round'
@@ -32,8 +31,6 @@ require_relative 'ranking_scoring'
32
31
  module ActiveGenie
33
32
  module Ranking
34
33
  class Ranking
35
- include ActiveGenie::Concerns::Loggable
36
-
37
34
  def self.call(...)
38
35
  new(...).call
39
36
  end
@@ -48,20 +45,19 @@ module ActiveGenie
48
45
 
49
46
  def call
50
47
  @players = create_players
48
+ @config.log.additional_context = { ranking_id: }
51
49
 
52
- ActiveGenie::Logger.with_context(log_context) do
53
- set_initial_player_scores!
54
- eliminate_obvious_bad_players!
55
-
56
- while @players.elo_eligible?
57
- elo_report = run_elo_round!
58
- eliminate_relegation_players!
59
- rebalance_players!(elo_report)
60
- end
50
+ set_initial_player_scores!
51
+ eliminate_obvious_bad_players!
61
52
 
62
- run_free_for_all!
53
+ while @players.elo_eligible?
54
+ elo_report = run_elo_round!
55
+ eliminate_relegation_players!
56
+ rebalance_players!(elo_report)
63
57
  end
64
58
 
59
+ run_free_for_all!
60
+
65
61
  sorted_players
66
62
  end
67
63
 
@@ -72,13 +68,18 @@ module ActiveGenie
72
68
 
73
69
  def create_players
74
70
  players = PlayersCollection.new(@param_players)
75
- players.each { |p| ActiveGenie::Logger.call({ code: :new_player, player: p.to_h }) }
71
+ players.each { |p| @config.logger.call({ code: :new_player, player: p.to_h }) }
76
72
 
77
73
  players
78
74
  end
79
75
 
80
76
  def set_initial_player_scores!
81
- RankingScoring.call(@players, @criteria, reviewers: @reviewers, config: @config)
77
+ RankingScoring.call(
78
+ @players,
79
+ @criteria,
80
+ reviewers: @reviewers,
81
+ config: @config
82
+ )
82
83
  end
83
84
 
84
85
  def eliminate_obvious_bad_players!
@@ -88,7 +89,11 @@ module ActiveGenie
88
89
  end
89
90
 
90
91
  def run_elo_round!
91
- EloRound.call(@players, @criteria, config: @config)
92
+ EloRound.call(
93
+ @players,
94
+ @criteria,
95
+ config: @config
96
+ )
92
97
  end
93
98
 
94
99
  def eliminate_relegation_players!
@@ -106,25 +111,27 @@ module ActiveGenie
106
111
  end
107
112
 
108
113
  def run_free_for_all!
109
- FreeForAll.call(@players, @criteria, config: @config)
114
+ FreeForAll.call(
115
+ @players,
116
+ @criteria,
117
+ config: @config
118
+ )
110
119
  end
111
120
 
112
121
  def sorted_players
113
122
  players = @players.sorted
114
- ActiveGenie::Logger.call({ code: :ranking_final, players: players.map(&:to_h) })
123
+ @config.logger.call({ ranking_id:, code: :ranking_final, players: players.map(&:to_h) })
115
124
 
116
125
  players.map(&:to_h)
117
126
  end
118
127
 
119
- def log_context
120
- { ranking_id: }
121
- end
122
-
123
128
  def ranking_id
124
- player_ids = @players.map(&:id).join(',')
125
- ranking_unique_key = [player_ids, @criteria, @config.to_json].join('-')
129
+ @ranking_id ||= begin
130
+ player_ids = @players.map(&:id).join(',')
131
+ ranking_unique_key = [player_ids, @criteria, @config.to_json].join('-')
126
132
 
127
- Digest::MD5.hexdigest(ranking_unique_key)
133
+ Digest::MD5.hexdigest(ranking_unique_key)
134
+ end
128
135
  end
129
136
  end
130
137
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../scoring/recommended_reviewers'
4
-
5
3
  module ActiveGenie
6
4
  module Ranking
7
5
  class RankingScoring
@@ -9,7 +7,7 @@ module ActiveGenie
9
7
  new(...).call
10
8
  end
11
9
 
12
- def initialize(players, criteria, reviewers: [], config: {})
10
+ def initialize(players, criteria, reviewers: [], config: nil)
13
11
  @players = players
14
12
  @criteria = criteria
15
13
  @config = ActiveGenie.configuration.merge(config)
@@ -17,12 +15,11 @@ module ActiveGenie
17
15
  end
18
16
 
19
17
  def call
20
- ActiveGenie::Logger.with_context(log_context) do
21
- @reviewers = generate_reviewers
18
+ @config.log.additional_context = { ranking_scoring_id: }
19
+ @reviewers = generate_reviewers
22
20
 
23
- players_without_score.each do |player|
24
- player.score = generate_score(player)
25
- end
21
+ players_without_score.each do |player|
22
+ player.score = generate_score(player)
26
23
  end
27
24
  end
28
25
 
@@ -40,7 +37,7 @@ module ActiveGenie
40
37
  config: @config
41
38
  ).values_at('final_score', 'final_reasoning')
42
39
 
43
- ActiveGenie::Logger.call({ code: :new_score, player_id: player.id, score:, reasoning: })
40
+ @config.logger.call({ code: :new_score, player_id: player.id, score:, reasoning: })
44
41
 
45
42
  score
46
43
  end
@@ -54,20 +51,18 @@ module ActiveGenie
54
51
  config: @config
55
52
  ).values_at('reviewer1', 'reviewer2', 'reviewer3')
56
53
 
57
- ActiveGenie::Logger.call({ code: :new_reviewers, reviewers: [reviewer1, reviewer2, reviewer3] })
54
+ @config.logger.call({ code: :new_reviewers, reviewers: [reviewer1, reviewer2, reviewer3] })
58
55
 
59
56
  [reviewer1, reviewer2, reviewer3]
60
57
  end
61
58
 
62
- def log_context
63
- { ranking_scoring_id: }
64
- end
65
-
66
59
  def ranking_scoring_id
67
- player_ids = players_without_score.map(&:id).join(',')
68
- ranking_unique_key = [player_ids, @criteria, @config.to_json].join('-')
60
+ @ranking_scoring_id ||= begin
61
+ player_ids = players_without_score.map(&:id).join(',')
62
+ ranking_unique_key = [player_ids, @criteria, @config.to_json].join('-')
69
63
 
70
- "#{Digest::MD5.hexdigest(ranking_unique_key)}-scoring"
64
+ "#{Digest::MD5.hexdigest(ranking_unique_key)}-scoring"
65
+ end
71
66
  end
72
67
  end
73
68
  end
@@ -52,14 +52,14 @@ module ActiveGenie
52
52
 
53
53
  result['final_score'] = 0 if result['final_score'].nil?
54
54
 
55
- ActiveGenie::Logger.call({
56
- code: :scoring,
57
- text: @text[0..30],
58
- criteria: @criteria[0..30],
59
- reviewers: reviewers,
60
- score: result['final_score'],
61
- reasoning: result['final_reasoning']
62
- })
55
+ @config.logger.call({
56
+ code: :scoring,
57
+ text: @text[0..30],
58
+ criteria: @criteria[0..30],
59
+ reviewers: reviewers,
60
+ score: result['final_score'],
61
+ reasoning: result['final_reasoning']
62
+ })
63
63
 
64
64
  result
65
65
  end
@@ -7,7 +7,7 @@ ActiveGenie.configure do |config|
7
7
  # config.providers.openai.api_url = 'https://api.openai.com/v1'
8
8
  # config.providers.openai.lower_tier_model = 'gpt-4.1-mini'
9
9
  # config.providers.openai.middle_tier_model = 'gpt-4.1'
10
- # config.providers.openai.upper_tier_model = 'o3-mini'
10
+ # config.providers.openai.higher_tier_model = 'o3-mini'
11
11
  # config.providers.openai.client = ActiveGenie::Providers::Openai::Client.new(config)
12
12
 
13
13
  # example how add a new provider
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_genie
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.26.5
4
+ version: 0.26.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Radamés Roriz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-06-03 00:00:00.000000000 Z
11
+ date: 2025-06-09 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |
14
14
  The lodash for GenAI, stop reinventing the wheel
@@ -35,6 +35,7 @@ files:
35
35
  - lib/active_genie/clients/providers/google_client.rb
36
36
  - lib/active_genie/clients/providers/openai_client.rb
37
37
  - lib/active_genie/clients/unified_client.rb
38
+ - lib/active_genie/config/README.md
38
39
  - lib/active_genie/config/battle_config.rb
39
40
  - lib/active_genie/config/data_extractor_config.rb
40
41
  - lib/active_genie/config/llm_config.rb
@@ -60,7 +61,6 @@ files:
60
61
  - lib/active_genie/logger.rb
61
62
  - lib/active_genie/ranking.rb
62
63
  - lib/active_genie/ranking/README.md
63
- - lib/active_genie/ranking/concerns/loggable.rb
64
64
  - lib/active_genie/ranking/elo_round.rb
65
65
  - lib/active_genie/ranking/free_for_all.rb
66
66
  - lib/active_genie/ranking/player.rb
@@ -1,29 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ActiveGenie
4
- module Concerns
5
- module Loggable
6
- def self.included(base)
7
- base.extend(ClassMethods)
8
- end
9
-
10
- module ClassMethods
11
- def call_with_log_context(context_method)
12
- original_method = instance_method(:call)
13
-
14
- define_method(:call) do |*args, **kwargs, &block|
15
- context = send(context_method, *args, **kwargs)
16
-
17
- ActiveGenie::Logger.with_context(context) do
18
- original_method.bind(self).call(*args, **kwargs, &block)
19
- end
20
- end
21
- end
22
-
23
- def logger(...)
24
- ActiveGenie::Logger.call(...)
25
- end
26
- end
27
- end
28
- end
29
- end