active_genie 0.0.24 → 0.0.25

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.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +35 -50
  3. data/VERSION +1 -1
  4. data/lib/active_genie/battle/README.md +5 -5
  5. data/lib/active_genie/battle/generalist.rb +132 -0
  6. data/lib/active_genie/battle.rb +6 -5
  7. data/lib/active_genie/clients/providers/anthropic_client.rb +77 -0
  8. data/lib/active_genie/clients/{base_client.rb → providers/base_client.rb} +74 -100
  9. data/lib/active_genie/clients/providers/deepseek_client.rb +91 -0
  10. data/lib/active_genie/clients/providers/google_client.rb +132 -0
  11. data/lib/active_genie/clients/providers/openai_client.rb +96 -0
  12. data/lib/active_genie/clients/unified_client.rb +42 -12
  13. data/lib/active_genie/concerns/loggable.rb +11 -23
  14. data/lib/active_genie/config/battle_config.rb +8 -0
  15. data/lib/active_genie/config/data_extractor_config.rb +23 -0
  16. data/lib/active_genie/config/llm_config.rb +36 -0
  17. data/lib/active_genie/config/log_config.rb +44 -0
  18. data/lib/active_genie/config/providers/anthropic_config.rb +57 -0
  19. data/lib/active_genie/config/providers/deepseek_config.rb +50 -0
  20. data/lib/active_genie/config/providers/google_config.rb +52 -0
  21. data/lib/active_genie/config/providers/openai_config.rb +50 -0
  22. data/lib/active_genie/config/providers/provider_base.rb +89 -0
  23. data/lib/active_genie/config/providers_config.rb +62 -0
  24. data/lib/active_genie/config/ranking_config.rb +21 -0
  25. data/lib/active_genie/config/scoring_config.rb +8 -0
  26. data/lib/active_genie/configuration.rb +51 -28
  27. data/lib/active_genie/data_extractor/README.md +13 -13
  28. data/lib/active_genie/data_extractor/from_informal.rb +54 -48
  29. data/lib/active_genie/data_extractor/generalist.md +12 -0
  30. data/lib/active_genie/data_extractor/generalist.rb +125 -0
  31. data/lib/active_genie/data_extractor.rb +7 -5
  32. data/lib/active_genie/errors/invalid_provider_error.rb +41 -0
  33. data/lib/active_genie/logger.rb +17 -66
  34. data/lib/active_genie/ranking/README.md +31 -1
  35. data/lib/active_genie/ranking/elo_round.rb +107 -104
  36. data/lib/active_genie/ranking/free_for_all.rb +78 -74
  37. data/lib/active_genie/ranking/player.rb +79 -71
  38. data/lib/active_genie/ranking/players_collection.rb +83 -71
  39. data/lib/active_genie/ranking/ranking.rb +71 -94
  40. data/lib/active_genie/ranking/ranking_scoring.rb +71 -50
  41. data/lib/active_genie/ranking.rb +2 -0
  42. data/lib/active_genie/scoring/README.md +4 -4
  43. data/lib/active_genie/scoring/generalist.rb +171 -0
  44. data/lib/active_genie/scoring/recommended_reviewers.rb +70 -71
  45. data/lib/active_genie/scoring.rb +8 -5
  46. data/lib/active_genie.rb +23 -1
  47. data/lib/tasks/benchmark.rake +10 -9
  48. data/lib/tasks/install.rake +3 -1
  49. data/lib/tasks/templates/active_genie.rb +11 -6
  50. metadata +31 -22
  51. data/lib/active_genie/battle/basic.rb +0 -129
  52. data/lib/active_genie/clients/anthropic_client.rb +0 -84
  53. data/lib/active_genie/clients/google_client.rb +0 -135
  54. data/lib/active_genie/clients/helpers/retry.rb +0 -29
  55. data/lib/active_genie/clients/openai_client.rb +0 -98
  56. data/lib/active_genie/configuration/log_config.rb +0 -14
  57. data/lib/active_genie/configuration/providers/anthropic_config.rb +0 -54
  58. data/lib/active_genie/configuration/providers/base_config.rb +0 -85
  59. data/lib/active_genie/configuration/providers/deepseek_config.rb +0 -54
  60. data/lib/active_genie/configuration/providers/google_config.rb +0 -56
  61. data/lib/active_genie/configuration/providers/internal_company_api_config.rb +0 -54
  62. data/lib/active_genie/configuration/providers/openai_config.rb +0 -54
  63. data/lib/active_genie/configuration/providers_config.rb +0 -40
  64. data/lib/active_genie/configuration/runtime_config.rb +0 -35
  65. data/lib/active_genie/data_extractor/basic.rb +0 -101
  66. data/lib/active_genie/scoring/basic.rb +0 -170
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveGenie
2
4
  module Concerns
3
5
  module Loggable
@@ -6,38 +8,24 @@ module ActiveGenie
6
8
  end
7
9
 
8
10
  module ClassMethods
9
- def with_logging_context(context_method, observer_proc = nil)
11
+ def call_with_log_context(context_method)
10
12
  original_method = instance_method(:call)
11
-
13
+
12
14
  define_method(:call) do |*args, **kwargs, &block|
13
15
  context = send(context_method, *args, **kwargs)
14
- bound_observer = observer_proc ? ->(log) { instance_exec(log, &observer_proc) } : nil
15
-
16
- ActiveGenie::Logger.with_context(context, observer: bound_observer) do
16
+
17
+ ActiveGenie::Logger.with_context(context) do
17
18
  original_method.bind(self).call(*args, **kwargs, &block)
18
19
  end
19
20
  end
20
21
  end
21
- end
22
-
23
- def info(log)
24
- ::ActiveGenie::Logger.info(log)
25
- end
26
22
 
27
- def error(log)
28
- ::ActiveGenie::Logger.error(log)
29
- end
30
-
31
- def warn(log)
32
- ::ActiveGenie::Logger.warn(log)
33
- end
23
+ def logger(data)
24
+ log = ActiveGenie::Logger.call(data)
25
+ @config&.log&.call_observers(log)
34
26
 
35
- def debug(log)
36
- ::ActiveGenie::Logger.debug(log)
37
- end
38
-
39
- def trace(log)
40
- ::ActiveGenie::Logger.trace(log)
27
+ log
28
+ end
41
29
  end
42
30
  end
43
31
  end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveGenie
4
+ module Config
5
+ class BattleConfig
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveGenie
4
+ module Config
5
+ class DataExtractorConfig
6
+ attr_accessor :with_explanation, :min_accuracy, :verbose
7
+
8
+ def initialize
9
+ @with_explanation = true
10
+ @min_accuracy = 70
11
+ @verbose = false
12
+ end
13
+
14
+ def merge(config_params = {})
15
+ dup.tap do |config|
16
+ config.with_explanation = config_params[:with_explanation] if config_params[:with_explanation]
17
+ config.min_accuracy = config_params[:min_accuracy] if config_params[:min_accuracy]
18
+ config.verbose = config_params[:verbose] if config_params[:verbose]
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveGenie
4
+ module Config
5
+ class LlmConfig
6
+ attr_accessor :model, :temperature, :max_tokens, :max_retries, :retry_delay,
7
+ :model_tier, :read_timeout, :open_timeout, :client
8
+ attr_reader :provider
9
+
10
+ def initialize
11
+ @model = nil
12
+ @provider = nil
13
+ @client = nil
14
+ @temperature = 0
15
+ @max_tokens = 4096
16
+ @max_retries = nil
17
+ @retry_delay = nil
18
+ @model_tier = 'lower_tier'
19
+ @read_timeout = nil
20
+ @open_timeout = nil
21
+ end
22
+
23
+ def provider=(provider)
24
+ @provider = provider&.to_s&.downcase&.strip&.to_sym
25
+ end
26
+
27
+ def merge(config_params = {})
28
+ dup.tap do |config|
29
+ config_params.each do |key, value|
30
+ config.send("#{key}=", value) if config.respond_to?("#{key}=")
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveGenie
4
+ module Config
5
+ class LogConfig
6
+ def add_observer(observers: [], scope: nil, &block)
7
+ @observers ||= []
8
+
9
+ raise ArgumentError, 'Scope must be a hash' if !scope.nil? && !scope.is_a?(Hash)
10
+
11
+ @observers << { observer: block, scope: scope || {} } if block_given?
12
+ Array(observers).each do |observer|
13
+ @observers << { observer:, scope: scope || {} }
14
+ end
15
+ end
16
+
17
+ def remove_observer(observers)
18
+ Array(observers).each do |observer|
19
+ @observers.delete_if { |obs| obs[:observer] == observer }
20
+ end
21
+ end
22
+
23
+ def clear_observers
24
+ @observers = []
25
+ end
26
+
27
+ def call_observers(log)
28
+ Array(@observers).each do |obs|
29
+ next unless obs[:scope].all? { |key, value| log[key.to_sym] == value }
30
+
31
+ obs[:observer].call(log)
32
+ rescue StandardError => e
33
+ ActiveGenie::Logger.call(code: :observer_error, **obs, error: e.message)
34
+ end
35
+ end
36
+
37
+ def merge(config_params = {})
38
+ dup.tap do |config|
39
+ config.add_observer(config_params[:observers]) if config_params[:observers]
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './provider_base'
4
+
5
+ module ActiveGenie
6
+ module Config
7
+ module Providers
8
+ # Configuration class for the Anthropic API client.
9
+ # Manages API keys, URLs, model selections, and client instantiation.
10
+ class AnthropicConfig < ProviderBase
11
+ NAME = :anthropic
12
+
13
+ # Retrieves the API key.
14
+ # Falls back to the ANTHROPIC_API_KEY environment variable if not set.
15
+ # @return [String, nil] The API key.
16
+ def api_key
17
+ @api_key || ENV['ANTHROPIC_API_KEY']
18
+ end
19
+
20
+ # Retrieves the base API URL for Anthropic API.
21
+ # Defaults to 'https://api.anthropic.com'.
22
+ # @return [String] The API base URL.
23
+ def api_url
24
+ @api_url || 'https://api.anthropic.com'
25
+ end
26
+
27
+ # Retrieves the Anthropic version.
28
+ # Defaults to '2023-06-01'.
29
+ # @return [String] The Anthropic version.
30
+ def anthropic_version
31
+ @anthropic_version || '2023-06-01'
32
+ end
33
+
34
+ # Retrieves the model name designated for the lower tier (e.g., cost-effective, faster).
35
+ # Defaults to 'claude-3-haiku'.
36
+ # @return [String] The lower tier model name.
37
+ def lower_tier_model
38
+ @lower_tier_model || 'claude-3-5-haiku-20241022'
39
+ end
40
+
41
+ # Retrieves the model name designated for the middle tier (e.g., balanced performance).
42
+ # Defaults to 'claude-3-sonnet'.
43
+ # @return [String] The middle tier model name.
44
+ def middle_tier_model
45
+ @middle_tier_model || 'claude-3-7-sonnet-20250219'
46
+ end
47
+
48
+ # Retrieves the model name designated for the upper tier (e.g., most capable).
49
+ # Defaults to 'claude-3-opus'.
50
+ # @return [String] The upper tier model name.
51
+ def upper_tier_model
52
+ @upper_tier_model || 'claude-3-opus-20240229'
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './provider_base'
4
+
5
+ module ActiveGenie
6
+ module Config
7
+ module Providers
8
+ # Configuration class for the DeepSeek API client.
9
+ # Manages API keys, organization IDs, URLs, model selections, and client instantiation.
10
+ class DeepseekConfig < ProviderBase
11
+ NAME = :deepseek
12
+
13
+ # Retrieves the API key.
14
+ # Falls back to the DEEPSEEK_API_KEY environment variable if not set.
15
+ # @return [String, nil] The API key.
16
+ def api_key
17
+ @api_key || ENV['DEEPSEEK_API_KEY']
18
+ end
19
+
20
+ # Retrieves the base API URL for DeepSeek API.
21
+ # Defaults to 'https://api.deepseek.com/v1'.
22
+ # @return [String] The API base URL.
23
+ def api_url
24
+ @api_url || 'https://api.deepseek.com/v1'
25
+ end
26
+
27
+ # Retrieves the model name designated for the lower tier (e.g., cost-effective, faster).
28
+ # Defaults to 'deepseek-chat'.
29
+ # @return [String] The lower tier model name.
30
+ def lower_tier_model
31
+ @lower_tier_model || 'deepseek-chat'
32
+ end
33
+
34
+ # Retrieves the model name designated for the middle tier (e.g., balanced performance).
35
+ # Defaults to 'deepseek-chat'.
36
+ # @return [String] The middle tier model name.
37
+ def middle_tier_model
38
+ @middle_tier_model || 'deepseek-chat'
39
+ end
40
+
41
+ # Retrieves the model name designated for the upper tier (e.g., most capable).
42
+ # Defaults to 'deepseek-reasoner'.
43
+ # @return [String] The upper tier model name.
44
+ def upper_tier_model
45
+ @upper_tier_model || 'deepseek-reasoner'
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './provider_base'
4
+
5
+ module ActiveGenie
6
+ module Config
7
+ module Providers
8
+ # Configuration class for the Google Generative Language API client.
9
+ # Manages API keys, URLs, model selections, and client instantiation.
10
+ class GoogleConfig < ProviderBase
11
+ NAME = :google
12
+
13
+ # Retrieves the API key.
14
+ # Falls back to the GENERATIVE_LANGUAGE_GOOGLE_API_KEY environment variable if not set.
15
+ # @return [String, nil] The API key.
16
+ def api_key
17
+ @api_key || ENV['GENERATIVE_LANGUAGE_GOOGLE_API_KEY'] || ENV['GEMINI_API_KEY']
18
+ end
19
+
20
+ # Retrieves the base API URL for Google Generative Language API.
21
+ # Defaults to 'https://generativelanguage.googleapis.com'.
22
+ # @return [String] The API base URL.
23
+ def api_url
24
+ # NOTE: Google Generative Language API uses a specific path structure like /v1beta/models/{model}:generateContent
25
+ # The base URL here should be just the domain part.
26
+ @api_url || 'https://generativelanguage.googleapis.com'
27
+ end
28
+
29
+ # Retrieves the model name designated for the lower tier (e.g., cost-effective, faster).
30
+ # Defaults to 'gemini-2.0-flash-lite'.
31
+ # @return [String] The lower tier model name.
32
+ def lower_tier_model
33
+ @lower_tier_model || 'gemini-2.0-flash-lite'
34
+ end
35
+
36
+ # Retrieves the model name designated for the middle tier (e.g., balanced performance).
37
+ # Defaults to 'gemini-2.0-flash'.
38
+ # @return [String] The middle tier model name.
39
+ def middle_tier_model
40
+ @middle_tier_model || 'gemini-2.0-flash'
41
+ end
42
+
43
+ # Retrieves the model name designated for the upper tier (e.g., most capable).
44
+ # Defaults to 'gemini-2.5-pro-experimental'.
45
+ # @return [String] The upper tier model name.
46
+ def upper_tier_model
47
+ @upper_tier_model || 'gemini-2.5-pro-experimental'
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './provider_base'
4
+
5
+ module ActiveGenie
6
+ module Config
7
+ module Providers
8
+ # Configuration class for the OpenAI API client.
9
+ # Manages API keys, organization IDs, URLs, model selections, and client instantiation.
10
+ class OpenaiConfig < ProviderBase
11
+ NAME = :openai
12
+
13
+ # Retrieves the API key.
14
+ # Falls back to the OPENAI_API_KEY environment variable if not set.
15
+ # @return [String, nil] The API key.
16
+ def api_key
17
+ @api_key || ENV['OPENAI_API_KEY']
18
+ end
19
+
20
+ # Retrieves the base API URL for OpenAI API.
21
+ # Defaults to 'https://api.openai.com/v1'.
22
+ # @return [String] The API base URL.
23
+ def api_url
24
+ @api_url || 'https://api.openai.com/v1'
25
+ end
26
+
27
+ # Retrieves the model name designated for the lower tier (e.g., cost-effective, faster).
28
+ # Defaults to 'gpt-4o-mini'.
29
+ # @return [String] The lower tier model name.
30
+ def lower_tier_model
31
+ @lower_tier_model || 'gpt-4.1-mini'
32
+ end
33
+
34
+ # Retrieves the model name designated for the middle tier (e.g., balanced performance).
35
+ # Defaults to 'gpt-4o'.
36
+ # @return [String] The middle tier model name.
37
+ def middle_tier_model
38
+ @middle_tier_model || 'gpt-4.1'
39
+ end
40
+
41
+ # Retrieves the model name designated for the upper tier (e.g., most capable).
42
+ # Defaults to 'o1-preview'.
43
+ # @return [String] The upper tier model name.
44
+ def upper_tier_model
45
+ @upper_tier_model || 'o3-mini'
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveGenie
4
+ module Config
5
+ module Providers
6
+ class ProviderBase
7
+ NAME = :unknown
8
+
9
+ attr_writer :api_key, :organization, :api_url, :client,
10
+ :lower_tier_model, :middle_tier_model, :upper_tier_model
11
+
12
+ # Maps a symbolic tier (:lower_tier, :middle_tier, :upper_tier) to a specific model name.
13
+ # Falls back to the lower_tier_model if the tier is nil or unrecognized.
14
+ # @param tier [Symbol, String, nil] The symbolic tier name.
15
+ # @return [String] The corresponding model name.
16
+ def tier_to_model(tier)
17
+ {
18
+ lower_tier: lower_tier_model,
19
+ middle_tier: middle_tier_model,
20
+ upper_tier: upper_tier_model
21
+ }[tier&.to_sym] || lower_tier_model
22
+ end
23
+
24
+ # Returns a hash representation of the configuration.
25
+ # @param config [Hash] Additional key-value pairs to merge into the hash.
26
+ # @return [Hash] The configuration settings as a hash.
27
+ def to_h(config = {})
28
+ {
29
+ name: NAME,
30
+ api_key:,
31
+ api_url:,
32
+ lower_tier_model:,
33
+ middle_tier_model:,
34
+ upper_tier_model:,
35
+ **config
36
+ }
37
+ end
38
+
39
+ # Validates the configuration.
40
+ # @return [Boolean] True if the configuration is valid, false otherwise.
41
+ def valid?
42
+ api_key && api_url
43
+ end
44
+
45
+ # Retrieves the API key.
46
+ # Falls back to the OPENAI_API_KEY environment variable if not set.
47
+ # @return [String, nil] The API key.
48
+ def api_key
49
+ raise NotImplementedError, 'Subclasses must implement this method'
50
+ end
51
+
52
+ # Retrieves the base API URL for OpenAI API.
53
+ # Defaults to 'https://api.openai.com/v1'.
54
+ # @return [String] The API base URL.
55
+ def api_url
56
+ raise NotImplementedError, 'Subclasses must implement this method'
57
+ end
58
+
59
+ # Lazily initializes and returns an instance of the OpenaiClient.
60
+ # Passes itself (the config object) to the client's constructor.
61
+ # @return [ActiveGenie::Clients::OpenaiClient] The client instance.
62
+ def client
63
+ raise NotImplementedError, 'Subclasses must implement this method'
64
+ end
65
+
66
+ # Retrieves the model name designated for the lower tier (e.g., cost-effective, faster).
67
+ # Defaults to 'gpt-4o-mini'.
68
+ # @return [String] The lower tier model name.
69
+ def lower_tier_model
70
+ raise NotImplementedError, 'Subclasses must implement this method'
71
+ end
72
+
73
+ # Retrieves the model name designated for the middle tier (e.g., balanced performance).
74
+ # Defaults to 'gpt-4o'.
75
+ # @return [String] The middle tier model name.
76
+ def middle_tier_model
77
+ raise NotImplementedError, 'Subclasses must implement this method'
78
+ end
79
+
80
+ # Retrieves the model name designated for the upper tier (e.g., most capable).
81
+ # Defaults to 'o1-preview'.
82
+ # @return [String] The upper tier model name.
83
+ def upper_tier_model
84
+ raise NotImplementedError, 'Subclasses must implement this method'
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveGenie
4
+ module Config
5
+ class ProvidersConfig
6
+ def initialize
7
+ @all = {}
8
+ @default = nil
9
+ end
10
+
11
+ attr_reader :all
12
+
13
+ def default
14
+ @default || valid.keys.first
15
+ end
16
+
17
+ def default=(provider)
18
+ normalized_provider = provider.to_s.downcase.strip
19
+ @default = normalized_provider.size > 0 ? normalized_provider : valid.keys.first
20
+ end
21
+
22
+ def valid
23
+ valid_provider_keys = @all.keys.select { |k| @all[k].valid? }
24
+ @all.slice(*valid_provider_keys)
25
+ end
26
+
27
+ def add(provider_classes)
28
+ @all ||= {}
29
+ Array(provider_classes).each do |provider|
30
+ name = provider::NAME
31
+ remove([name]) if @all.key?(name)
32
+
33
+ @all[name] = provider.new
34
+ end
35
+
36
+ self
37
+ end
38
+
39
+ def remove(provider_classes)
40
+ Array(provider_classes).each do |provider|
41
+ @all.delete(provider::NAME)
42
+ end
43
+
44
+ self
45
+ end
46
+
47
+ def merge(config_params = {})
48
+ dup.tap do |config|
49
+ config.add(config_params[:providers]) if config_params[:providers]
50
+ end
51
+ end
52
+
53
+ def method_missing(m, *args, &block)
54
+ @all[m] || super
55
+ end
56
+
57
+ def respond_to_missing?(m, include_private = false)
58
+ @all.key?(m) || super
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveGenie
4
+ module Config
5
+ class RankingConfig
6
+ attr_accessor :score_variation_threshold
7
+
8
+ def initialize
9
+ @score_variation_threshold = 30
10
+ end
11
+
12
+ def merge(config_params = {})
13
+ dup.tap do |config|
14
+ if config_params[:score_variation_threshold]
15
+ config.score_variation_threshold = config_params[:score_variation_threshold]
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveGenie
4
+ module Config
5
+ class ScoringConfig
6
+ end
7
+ end
8
+ end
@@ -1,42 +1,65 @@
1
- require_relative 'configuration/providers_config'
2
- require_relative 'configuration/providers/openai_config'
3
- require_relative 'configuration/providers/google_config'
4
- require_relative 'configuration/providers/anthropic_config'
5
- require_relative 'configuration/providers/deepseek_config'
6
- require_relative 'configuration/log_config'
7
- require_relative 'configuration/runtime_config'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'config/providers_config'
4
+ require_relative 'config/log_config'
5
+ require_relative 'config/ranking_config'
6
+ require_relative 'config/scoring_config'
7
+ require_relative 'config/data_extractor_config'
8
+ require_relative 'config/battle_config'
9
+ require_relative 'config/llm_config'
8
10
 
9
11
  module ActiveGenie
10
- module Configuration
11
- module_function
12
+ class Configuration
13
+ def log
14
+ @log ||= Config::LogConfig.new
15
+ end
12
16
 
13
17
  def providers
14
- @providers ||= begin
15
- p = ProvidersConfig.new
16
- p.register(ActiveGenie::Configuration::Providers::OpenaiConfig)
17
- p.register(ActiveGenie::Configuration::Providers::GoogleConfig)
18
- p.register(ActiveGenie::Configuration::Providers::AnthropicConfig)
19
- p.register(ActiveGenie::Configuration::Providers::DeepseekConfig)
20
- p
21
- end
18
+ @providers ||= Config::ProvidersConfig.new
22
19
  end
23
20
 
24
- def log
25
- @log ||= LogConfig.new
21
+ def ranking
22
+ @ranking ||= Config::RankingConfig.new
23
+ end
24
+
25
+ def scoring
26
+ @scoring ||= Config::ScoringConfig.new
27
+ end
28
+
29
+ def data_extractor
30
+ @data_extractor ||= Config::DataExtractorConfig.new
26
31
  end
27
32
 
28
- def runtime
29
- @runtime ||= RuntimeConfig.new
33
+ def battle
34
+ @battle ||= Config::BattleConfig.new
30
35
  end
31
36
 
32
- def to_h(configs = {})
33
- normalized_configs = configs.dig(:runtime) ? configs : { runtime: configs }
37
+ def llm
38
+ @llm ||= Config::LlmConfig.new
39
+ end
40
+
41
+ def merge(config_params = {})
42
+ return config_params if config_params.is_a?(Configuration)
43
+
44
+ new_configuration = dup
45
+
46
+ %w[log providers llm ranking scoring data_extractor battle].each do |key|
47
+ config = new_configuration.send(key)
48
+
49
+ next unless config.respond_to?(:merge)
34
50
 
35
- {
36
- providers: providers.to_h(normalized_configs.dig(:providers) || {}),
37
- log: log.to_h(normalized_configs.dig(:log) || {}),
38
- runtime: runtime.to_h(normalized_configs.dig(:runtime) || {})
39
- }
51
+ new_config = if config_params.key?(key)
52
+ config.merge(config_params[key])
53
+ else
54
+ config.merge(config_params)
55
+ end
56
+
57
+ new_configuration.send("#{key}=", new_config)
58
+ end
59
+
60
+ new_configuration
40
61
  end
62
+
63
+ attr_writer :log, :providers, :ranking, :scoring, :data_extractor, :battle, :llm
41
64
  end
42
65
  end