active_genie 0.25.1 → 0.26.0

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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -5
  3. data/VERSION +1 -1
  4. data/lib/active_genie/battle/README.md +7 -7
  5. data/lib/active_genie/battle/generalist.json +36 -0
  6. data/lib/active_genie/battle/generalist.md +16 -0
  7. data/lib/active_genie/battle/generalist.rb +16 -69
  8. data/lib/active_genie/clients/providers/anthropic_client.rb +61 -40
  9. data/lib/active_genie/clients/providers/base_client.rb +44 -57
  10. data/lib/active_genie/clients/providers/deepseek_client.rb +57 -52
  11. data/lib/active_genie/clients/providers/google_client.rb +58 -60
  12. data/lib/active_genie/clients/providers/openai_client.rb +52 -55
  13. data/lib/active_genie/clients/unified_client.rb +4 -4
  14. data/lib/active_genie/config/battle_config.rb +2 -0
  15. data/lib/active_genie/config/llm_config.rb +3 -1
  16. data/lib/active_genie/config/log_config.rb +38 -14
  17. data/lib/active_genie/config/providers/anthropic_config.rb +2 -2
  18. data/lib/active_genie/config/providers/deepseek_config.rb +2 -2
  19. data/lib/active_genie/config/providers/google_config.rb +2 -2
  20. data/lib/active_genie/config/providers/openai_config.rb +2 -2
  21. data/lib/active_genie/config/providers_config.rb +4 -4
  22. data/lib/active_genie/config/scoring_config.rb +2 -0
  23. data/lib/active_genie/configuration.rb +14 -8
  24. data/lib/active_genie/data_extractor/from_informal.json +11 -0
  25. data/lib/active_genie/data_extractor/from_informal.rb +5 -13
  26. data/lib/active_genie/data_extractor/generalist.json +9 -0
  27. data/lib/active_genie/data_extractor/generalist.rb +12 -11
  28. data/lib/active_genie/errors/invalid_log_output_error.rb +19 -0
  29. data/lib/active_genie/logger.rb +13 -5
  30. data/lib/active_genie/{concerns → ranking/concerns}/loggable.rb +2 -5
  31. data/lib/active_genie/ranking/elo_round.rb +30 -28
  32. data/lib/active_genie/ranking/free_for_all.rb +30 -22
  33. data/lib/active_genie/ranking/player.rb +53 -19
  34. data/lib/active_genie/ranking/players_collection.rb +17 -13
  35. data/lib/active_genie/ranking/ranking.rb +21 -20
  36. data/lib/active_genie/ranking/ranking_scoring.rb +2 -20
  37. data/lib/active_genie/scoring/generalist.json +9 -0
  38. data/lib/active_genie/scoring/generalist.md +46 -0
  39. data/lib/active_genie/scoring/generalist.rb +13 -65
  40. data/lib/active_genie/scoring/recommended_reviewers.rb +2 -2
  41. metadata +11 -4
@@ -3,88 +3,93 @@
3
3
  require 'json'
4
4
  require 'net/http'
5
5
 
6
- require_relative './base_client'
6
+ require_relative 'base_client'
7
7
 
8
8
  module ActiveGenie
9
9
  module Clients
10
10
  class DeepseekClient < BaseClient
11
- class DeepseekError < ClientError; end
12
- class RateLimitError < DeepseekError; end
13
11
  class InvalidResponseError < StandardError; end
14
12
 
15
- # Requests structured JSON output from the DeepSeek model based on a schema.
13
+ # Requests structured JSON output from the Deepseek model based on a schema.
16
14
  #
17
15
  # @param messages [Array<Hash>] A list of messages representing the conversation history.
18
16
  # Each hash should have :role ('user', 'assistant', or 'system') and :content (String).
19
17
  # @param function [Hash] A JSON schema definition describing the desired output format.
20
18
  # @return [Hash, nil] The parsed JSON object matching the schema, or nil if parsing fails or content is empty.
21
19
  def function_calling(messages, function)
22
- model = @config.llm.model || @config.providers.deepseek.tier_to_model(@config.llm.model_tier)
23
-
24
20
  payload = {
25
21
  messages:,
26
- tools: [{
27
- type: 'function',
28
- function: {
29
- **function,
30
- parameters: {
31
- **function[:parameters],
32
- additionalProperties: false
33
- },
34
- strict: true
35
- }.compact
36
- }],
22
+ tools: [function_to_tool(function)],
37
23
  tool_choice: { type: 'function', function: { name: function[:name] } },
38
24
  stream: false,
39
25
  model:
40
26
  }
41
27
 
42
- headers = {
43
- 'Authorization': "Bearer #{@config.providers.deepseek.api_key}"
44
- }.compact
45
-
46
- retry_with_backoff do
47
- response = request_deepseek(payload, headers)
28
+ response = request(payload)
48
29
 
49
- parsed_response = JSON.parse(response.dig('choices', 0, 'message', 'tool_calls', 0, 'function', 'arguments'))
50
- parsed_response = parsed_response['message'] || parsed_response
51
-
52
- if parsed_response.nil? || parsed_response.keys.empty?
53
- raise InvalidResponseError,
54
- "Invalid response: #{parsed_response}"
55
- end
30
+ if response.nil? || response.keys.empty?
31
+ raise InvalidResponseError,
32
+ "Invalid response: #{response}"
33
+ end
56
34
 
57
- ActiveGenie::Logger.call({ code: :function_calling, payload:, parsed_response: })
35
+ ActiveGenie::Logger.call({ code: :function_calling, fine_tune: true, payload:, response: })
58
36
 
59
- parsed_response
60
- end
37
+ response
61
38
  end
62
39
 
63
40
  private
64
41
 
65
- # Make a request to the DeepSeek API
66
- #
67
- # @param payload [Hash] The request payload
68
- # @param headers [Hash] Additional headers
69
- # @return [Hash] The parsed response
70
- def request_deepseek(payload, headers)
71
- start_time = Time.now
72
- url = "#{@config.providers.deepseek.api_url}/chat/completions"
73
-
42
+ def request(payload)
74
43
  response = post(url, payload, headers: headers)
44
+
75
45
  return nil if response.nil?
76
46
 
77
- ActiveGenie::Logger.call({
78
- code: :llm_usage,
79
- input_tokens: response.dig('usage', 'prompt_tokens'),
80
- output_tokens: response.dig('usage', 'completion_tokens'),
81
- total_tokens: response.dig('usage', 'total_tokens'),
82
- model: payload[:model],
83
- duration: Time.now - start_time,
84
- usage: response['usage']
85
- })
47
+ ActiveGenie::Logger.call(
48
+ {
49
+ code: :llm_usage,
50
+ input_tokens: response.dig('usage', 'prompt_tokens'),
51
+ output_tokens: response.dig('usage', 'completion_tokens'),
52
+ total_tokens: response.dig('usage', 'total_tokens'),
53
+ model:,
54
+ usage: response['usage']
55
+ }
56
+ )
57
+
58
+ parsed_response = JSON.parse(response.dig('choices', 0, 'message', 'tool_calls', 0, 'function', 'arguments'))
59
+ parsed_response['message'] || parsed_response
60
+ end
61
+
62
+ def function_to_tool(function)
63
+ {
64
+ type: 'function',
65
+ function: {
66
+ **function,
67
+ parameters: {
68
+ **function[:parameters],
69
+ additionalProperties: false
70
+ },
71
+ strict: true
72
+ }.compact
73
+ }
74
+ end
75
+
76
+ def model
77
+ @config.llm.model || provider_config.tier_to_model(@config.llm.model_tier)
78
+ end
86
79
 
87
- response
80
+ def url
81
+ "#{provider_config.api_url}/chat/completions"
82
+ end
83
+
84
+ def headers
85
+ {
86
+ Authorization: "Bearer #{provider_config.api_key}",
87
+ 'Content-Type': 'application/json'
88
+ }.compact
89
+ end
90
+
91
+ def provider_config
92
+ @config.providers.deepseek
88
93
  end
89
94
  end
90
95
  end
@@ -3,17 +3,12 @@
3
3
  require 'json'
4
4
  require 'net/http'
5
5
  require 'uri'
6
- require_relative './base_client'
6
+ require_relative 'base_client'
7
7
 
8
8
  module ActiveGenie
9
9
  module Clients
10
10
  # Client for interacting with the Google Generative Language API.
11
11
  class GoogleClient < BaseClient
12
- class GoogleError < ClientError; end
13
- class RateLimitError < GoogleError; end
14
-
15
- API_VERSION_PATH = '/v1beta/models'
16
-
17
12
  # Requests structured JSON output from the Google Generative Language model based on a schema.
18
13
  #
19
14
  # @param messages [Array<Hash>] A list of messages representing the conversation history.
@@ -22,81 +17,72 @@ module ActiveGenie
22
17
  # @param function [Hash] A JSON schema definition describing the desired output format.
23
18
  # @return [Hash, nil] The parsed JSON object matching the schema, or nil if parsing fails or content is empty.
24
19
  def function_calling(messages, function)
25
- model = @config.llm.model || provider_config.tier_to_model(@config.llm.model_tier)
26
-
27
20
  contents = convert_messages_to_contents(messages, function)
28
21
  contents << output_as_json_schema(function)
29
22
 
30
23
  payload = {
31
- contents: contents,
24
+ contents:,
32
25
  generationConfig: {
33
26
  response_mime_type: 'application/json',
34
27
  temperature: 0.1
35
28
  }
36
29
  }
37
-
38
- endpoint = "#{API_VERSION_PATH}/#{model}:generateContent"
39
30
  params = { key: provider_config.api_key }
40
- headers = DEFAULT_HEADERS
41
-
42
- retry_with_backoff do
43
- start_time = Time.now
44
- url = "#{provider_config.api_url}#{endpoint}"
45
-
46
- response = post(url, payload, headers:, params:)
47
-
48
- json_string = response&.dig('candidates', 0, 'content', 'parts', 0, 'text')
49
- return nil if json_string.nil? || json_string.empty?
50
-
51
- begin
52
- parsed_response = JSON.parse(json_string)
53
-
54
- # Log usage metrics
55
- usage_metadata = response['usageMetadata'] || {}
56
- prompt_tokens = usage_metadata['promptTokenCount'] || 0
57
- candidates_tokens = usage_metadata['candidatesTokenCount'] || 0
58
- total_tokens = usage_metadata['totalTokenCount'] || (prompt_tokens + candidates_tokens)
59
-
60
- ActiveGenie::Logger.call({
61
- code: :llm_usage,
62
- input_tokens: prompt_tokens,
63
- output_tokens: candidates_tokens,
64
- total_tokens: total_tokens,
65
- model: model,
66
- duration: Time.now - start_time,
67
- usage: usage_metadata
68
- })
69
-
70
- ActiveGenie::Logger.call({ code: :function_calling, payload:, parsed_response: })
71
-
72
- normalize_function_output(parsed_response)
73
- rescue JSON::ParserError => e
74
- raise GoogleError, "Failed to parse Google API response: #{e.message} - Content: #{json_string}"
75
- end
76
- end
77
- end
78
31
 
79
- def provider_config
80
- @config.providers.google
32
+ response = request(payload, params)
33
+
34
+ json_string = response&.dig('candidates', 0, 'content', 'parts', 0, 'text')
35
+ return nil if json_string.nil? || json_string.empty?
36
+
37
+ normalize_response(json_string)
81
38
  end
82
39
 
40
+ API_VERSION_PATH = 'v1beta/models'
41
+ ROLE_TO_GOOGLE_ROLE = {
42
+ user: 'user',
43
+ assistant: 'model'
44
+ }.freeze
45
+
83
46
  private
84
47
 
85
- def normalize_function_output(output)
86
- output = if output.is_a?(Array)
87
- output.dig(0, 'properties') || output[0]
48
+ def request(payload, params)
49
+ response = post(url, payload, headers: DEFAULT_HEADERS, params:)
50
+
51
+ ActiveGenie::Logger.call(
52
+ {
53
+ code: :llm_usage,
54
+ input_tokens: response['usageMetadata']['promptTokenCount'] || 0,
55
+ output_tokens: response['usageMetadata']['candidatesTokenCount'] || 0,
56
+ total_tokens: response['usageMetadata']['totalTokenCount'] || (prompt_tokens + candidates_tokens),
57
+ model:,
58
+ usage: response['usageMetadata'] || {}
59
+ }
60
+ )
61
+
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
+ response
72
+ end
73
+
74
+ def normalize_response(json_string)
75
+ parsed_response = JSON.parse(json_string)
76
+
77
+ output = if parsed_response.is_a?(Array)
78
+ parsed_response.dig(0, 'properties') || parsed_response[0]
88
79
  else
89
- output
80
+ parsed_response
90
81
  end
91
82
 
92
83
  output.dig('input_schema', 'properties') || output
93
84
  end
94
85
 
95
- ROLE_TO_GOOGLE_ROLE = {
96
- user: 'user',
97
- assistant: 'model'
98
- }.freeze
99
-
100
86
  # Converts standard message format to Google's 'contents' format
101
87
  # and injects JSON schema instructions.
102
88
  # @param messages [Array<Hash>] Array of { role: 'user'/'assistant'/'system', content: '...' }
@@ -127,6 +113,18 @@ module ActiveGenie
127
113
  parts: [{ text: json_instruction }]
128
114
  }
129
115
  end
116
+
117
+ def model
118
+ @config.llm.model || provider_config.tier_to_model(@config.llm.model_tier)
119
+ end
120
+
121
+ def url
122
+ "#{provider_config.api_url}/#{API_VERSION_PATH}/#{model}:generateContent"
123
+ end
124
+
125
+ def provider_config
126
+ @config.providers.google
127
+ end
130
128
  end
131
129
  end
132
130
  end
@@ -3,13 +3,11 @@
3
3
  require 'json'
4
4
  require 'net/http'
5
5
 
6
- require_relative './base_client'
6
+ require_relative 'base_client'
7
7
 
8
8
  module ActiveGenie
9
9
  module Clients
10
10
  class OpenaiClient < BaseClient
11
- class OpenaiError < ClientError; end
12
- class RateLimitError < OpenaiError; end
13
11
  class InvalidResponseError < StandardError; end
14
12
 
15
13
  # Requests structured JSON output from the OpenAI model based on a schema.
@@ -19,77 +17,76 @@ module ActiveGenie
19
17
  # @param function [Hash] A JSON schema definition describing the desired output format.
20
18
  # @return [Hash, nil] The parsed JSON object matching the schema, or nil if parsing fails or content is empty.
21
19
  def function_calling(messages, function)
22
- model = @config.llm.model || provider_config.tier_to_model(@config.llm.model_tier)
23
-
24
20
  payload = {
25
21
  messages:,
26
- tools: [{
27
- type: 'function',
28
- function: {
29
- **function,
30
- parameters: {
31
- **function[:parameters],
32
- additionalProperties: false
33
- },
34
- strict: true
35
- }.compact
36
- }],
22
+ tools: [function_to_tool(function)],
37
23
  tool_choice: { type: 'function', function: { name: function[:name] } },
38
24
  stream: false,
39
25
  model:
40
26
  }
41
27
 
42
- headers = {
43
- 'Authorization': "Bearer #{provider_config.api_key}"
44
- }.compact
45
-
46
- retry_with_backoff do
47
- response = request_openai(payload, headers)
48
-
49
- parsed_response = JSON.parse(response.dig('choices', 0, 'message', 'tool_calls', 0, 'function', 'arguments'))
50
- parsed_response = parsed_response['message'] || parsed_response
28
+ response = request(payload)
51
29
 
52
- if parsed_response.nil? || parsed_response.keys.empty?
53
- raise InvalidResponseError,
54
- "Invalid response: #{parsed_response}"
55
- end
30
+ raise InvalidResponseError, "Invalid response: #{response}" if response.nil? || response.keys.empty?
56
31
 
57
- ActiveGenie::Logger.call({ code: :function_calling, payload:, parsed_response: })
32
+ ActiveGenie::Logger.call({ code: :function_calling, fine_tune: true, payload:, response: })
58
33
 
59
- parsed_response
60
- end
61
- end
62
-
63
- def provider_config
64
- @config.providers.openai
34
+ response
65
35
  end
66
36
 
67
37
  private
68
38
 
69
- # Make a request to the OpenAI API
70
- #
71
- # @param payload [Hash] The request payload
72
- # @param headers [Hash] Additional headers
73
- # @return [Hash] The parsed response
74
- def request_openai(payload, headers)
75
- start_time = Time.now
76
- url = "#{provider_config.api_url}/chat/completions"
77
-
39
+ def request(payload)
78
40
  response = post(url, payload, headers: headers)
79
41
 
80
42
  return nil if response.nil?
81
43
 
82
- ActiveGenie::Logger.call({
83
- code: :llm_usage,
84
- input_tokens: response.dig('usage', 'prompt_tokens'),
85
- output_tokens: response.dig('usage', 'completion_tokens'),
86
- total_tokens: response.dig('usage', 'total_tokens'),
87
- model: payload[:model],
88
- duration: Time.now - start_time,
89
- usage: response['usage']
90
- })
44
+ ActiveGenie::Logger.call(
45
+ {
46
+ code: :llm_usage,
47
+ input_tokens: response.dig('usage', 'prompt_tokens'),
48
+ output_tokens: response.dig('usage', 'completion_tokens'),
49
+ total_tokens: response.dig('usage', 'total_tokens'),
50
+ model:,
51
+ usage: response['usage']
52
+ }
53
+ )
54
+
55
+ parsed_response = JSON.parse(response.dig('choices', 0, 'message', 'tool_calls', 0, 'function', 'arguments'))
56
+ parsed_response['message'] || parsed_response
57
+ end
91
58
 
92
- response
59
+ def function_to_tool(function)
60
+ {
61
+ type: 'function',
62
+ function: {
63
+ **function,
64
+ parameters: {
65
+ **function[:parameters],
66
+ additionalProperties: false
67
+ },
68
+ strict: true
69
+ }.compact
70
+ }
71
+ end
72
+
73
+ def model
74
+ @config.llm.model || provider_config.tier_to_model(@config.llm.model_tier)
75
+ end
76
+
77
+ def url
78
+ "#{provider_config.api_url}/chat/completions"
79
+ end
80
+
81
+ def headers
82
+ {
83
+ Authorization: "Bearer #{provider_config.api_key}",
84
+ 'Content-Type': 'application/json'
85
+ }.compact
86
+ end
87
+
88
+ def provider_config
89
+ @config.providers.openai
93
90
  end
94
91
  end
95
92
  end
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative './providers/openai_client'
4
- require_relative './providers/anthropic_client'
5
- require_relative './providers/google_client'
6
- require_relative './providers/deepseek_client'
3
+ require_relative 'providers/openai_client'
4
+ require_relative 'providers/anthropic_client'
5
+ require_relative 'providers/google_client'
6
+ require_relative 'providers/deepseek_client'
7
7
  require_relative '../errors/invalid_provider_error'
8
8
 
9
9
  module ActiveGenie
@@ -2,7 +2,9 @@
2
2
 
3
3
  module ActiveGenie
4
4
  module Config
5
+ # rubocop:disable Lint/EmptyClass
5
6
  class BattleConfig
6
7
  end
8
+ # rubocop:enable Lint/EmptyClass
7
9
  end
8
10
  end
@@ -21,7 +21,9 @@ module ActiveGenie
21
21
  end
22
22
 
23
23
  def provider=(provider)
24
- @provider = provider&.to_s&.downcase&.strip&.to_sym
24
+ return if provider.nil? || provider.empty?
25
+
26
+ @provider = provider.to_s.downcase.strip.to_sym
25
27
  end
26
28
 
27
29
  def merge(config_params = {})
@@ -3,14 +3,48 @@
3
3
  module ActiveGenie
4
4
  module Config
5
5
  class LogConfig
6
- def add_observer(observers: [], scope: nil, &block)
6
+ attr_writer :file_path, :fine_tune_file_path
7
+
8
+ def file_path
9
+ @file_path || 'log/active_genie.log'
10
+ end
11
+
12
+ def fine_tune_file_path
13
+ @fine_tune_file_path || 'log/active_genie_fine_tune.log'
14
+ end
15
+
16
+ def output
17
+ @output || ->(log) { $stdout.puts log }
18
+ end
19
+
20
+ def output=(output)
21
+ raise InvalidLogOutputError, output unless output.respond_to?(:call)
22
+
23
+ @output = output
24
+ end
25
+
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
+ def add_observer(observers: [], scope: {}, &block)
7
39
  @observers ||= []
8
40
 
9
- raise ArgumentError, 'Scope must be a hash' if !scope.nil? && !scope.is_a?(Hash)
41
+ raise ArgumentError, 'Scope must be a hash' if scope && !scope.is_a?(Hash)
10
42
 
11
- @observers << { observer: block, scope: scope || {} } if block_given?
43
+ @observers << { observer: block, scope: } if block_given?
12
44
  Array(observers).each do |observer|
13
- @observers << { observer:, scope: scope || {} }
45
+ next unless observer.respond_to?(:call)
46
+
47
+ @observers << { observer:, scope: }
14
48
  end
15
49
  end
16
50
 
@@ -24,16 +58,6 @@ module ActiveGenie
24
58
  @observers = []
25
59
  end
26
60
 
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
61
  def merge(config_params = {})
38
62
  dup.tap do |config|
39
63
  config.add_observer(config_params[:observers]) if config_params[:observers]
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative './provider_base'
3
+ require_relative 'provider_base'
4
4
 
5
5
  module ActiveGenie
6
6
  module Config
@@ -14,7 +14,7 @@ module ActiveGenie
14
14
  # Falls back to the ANTHROPIC_API_KEY environment variable if not set.
15
15
  # @return [String, nil] The API key.
16
16
  def api_key
17
- @api_key || ENV['ANTHROPIC_API_KEY']
17
+ @api_key || ENV.fetch('ANTHROPIC_API_KEY', nil)
18
18
  end
19
19
 
20
20
  # Retrieves the base API URL for Anthropic API.
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative './provider_base'
3
+ require_relative 'provider_base'
4
4
 
5
5
  module ActiveGenie
6
6
  module Config
@@ -14,7 +14,7 @@ module ActiveGenie
14
14
  # Falls back to the DEEPSEEK_API_KEY environment variable if not set.
15
15
  # @return [String, nil] The API key.
16
16
  def api_key
17
- @api_key || ENV['DEEPSEEK_API_KEY']
17
+ @api_key || ENV.fetch('DEEPSEEK_API_KEY', nil)
18
18
  end
19
19
 
20
20
  # Retrieves the base API URL for DeepSeek API.
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative './provider_base'
3
+ require_relative 'provider_base'
4
4
 
5
5
  module ActiveGenie
6
6
  module Config
@@ -14,7 +14,7 @@ module ActiveGenie
14
14
  # Falls back to the GENERATIVE_LANGUAGE_GOOGLE_API_KEY environment variable if not set.
15
15
  # @return [String, nil] The API key.
16
16
  def api_key
17
- @api_key || ENV['GENERATIVE_LANGUAGE_GOOGLE_API_KEY'] || ENV['GEMINI_API_KEY']
17
+ @api_key || ENV['GENERATIVE_LANGUAGE_GOOGLE_API_KEY'] || ENV.fetch('GEMINI_API_KEY', nil)
18
18
  end
19
19
 
20
20
  # Retrieves the base API URL for Google Generative Language API.
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative './provider_base'
3
+ require_relative 'provider_base'
4
4
 
5
5
  module ActiveGenie
6
6
  module Config
@@ -14,7 +14,7 @@ module ActiveGenie
14
14
  # Falls back to the OPENAI_API_KEY environment variable if not set.
15
15
  # @return [String, nil] The API key.
16
16
  def api_key
17
- @api_key || ENV['OPENAI_API_KEY']
17
+ @api_key || ENV.fetch('OPENAI_API_KEY', nil)
18
18
  end
19
19
 
20
20
  # Retrieves the base API URL for OpenAI API.
@@ -51,12 +51,12 @@ module ActiveGenie
51
51
  end
52
52
  end
53
53
 
54
- def method_missing(m, *args, &block)
55
- @all[m] || super
54
+ def method_missing(method_name, *args, &)
55
+ @all[method_name] || super
56
56
  end
57
57
 
58
- def respond_to_missing?(m, include_private = false)
59
- @all.key?(m) || super
58
+ def respond_to_missing?(method_name, include_private = false)
59
+ @all.key?(method_name) || super
60
60
  end
61
61
  end
62
62
  end
@@ -2,7 +2,9 @@
2
2
 
3
3
  module ActiveGenie
4
4
  module Config
5
+ # rubocop:disable Lint/EmptyClass
5
6
  class ScoringConfig
6
7
  end
8
+ # rubocop:enable Lint/EmptyClass
7
9
  end
8
10
  end