active_genie 0.30.1 → 0.30.8

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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +7 -5
  3. data/VERSION +1 -1
  4. data/lib/active_genie/comparator/debate.rb +13 -31
  5. data/lib/active_genie/comparator/fight.rb +3 -3
  6. data/lib/active_genie/comparator.rb +0 -2
  7. data/lib/active_genie/configs/base_config.rb +25 -0
  8. data/lib/active_genie/configs/extractor_config.rb +6 -14
  9. data/lib/active_genie/configs/lister_config.rb +6 -10
  10. data/lib/active_genie/configs/llm_config.rb +12 -25
  11. data/lib/active_genie/configs/log_config.rb +19 -16
  12. data/lib/active_genie/configs/providers/anthropic_config.rb +10 -16
  13. data/lib/active_genie/configs/providers/deepseek_config.rb +4 -19
  14. data/lib/active_genie/configs/providers/google_config.rb +4 -19
  15. data/lib/active_genie/configs/providers/openai_config.rb +4 -19
  16. data/lib/active_genie/configs/providers/provider_base.rb +21 -67
  17. data/lib/active_genie/configs/providers_config.rb +39 -20
  18. data/lib/active_genie/configs/ranker_config.rb +6 -12
  19. data/lib/active_genie/configuration.rb +23 -60
  20. data/lib/active_genie/{ranker/entities → entities}/player.rb +4 -0
  21. data/lib/active_genie/{ranker/entities → entities}/players.rb +1 -1
  22. data/lib/active_genie/entities/result.rb +29 -0
  23. data/lib/active_genie/errors/invalid_model_error.rb +42 -0
  24. data/lib/active_genie/errors/invalid_provider_error.rb +1 -1
  25. data/lib/active_genie/errors/provider_server_error.rb +26 -0
  26. data/lib/active_genie/errors/without_available_provider_error.rb +39 -0
  27. data/lib/active_genie/extractor/data.json +9 -0
  28. data/lib/active_genie/extractor/data.prompt.md +12 -0
  29. data/lib/active_genie/extractor/data.rb +71 -0
  30. data/lib/active_genie/extractor/explanation.rb +22 -41
  31. data/lib/active_genie/extractor/litote.rb +10 -9
  32. data/lib/active_genie/extractor.rb +5 -0
  33. data/lib/active_genie/lister/feud.json +5 -1
  34. data/lib/active_genie/lister/feud.rb +12 -17
  35. data/lib/active_genie/lister/juries.rb +18 -16
  36. data/lib/active_genie/logger.rb +16 -28
  37. data/lib/active_genie/providers/anthropic_provider.rb +12 -6
  38. data/lib/active_genie/providers/base_provider.rb +15 -18
  39. data/lib/active_genie/providers/deepseek_provider.rb +18 -10
  40. data/lib/active_genie/providers/google_provider.rb +11 -5
  41. data/lib/active_genie/providers/openai_provider.rb +8 -6
  42. data/lib/active_genie/providers/unified_provider.rb +58 -3
  43. data/lib/active_genie/ranker/elo.rb +41 -36
  44. data/lib/active_genie/ranker/free_for_all.rb +45 -28
  45. data/lib/active_genie/ranker/scoring.rb +20 -11
  46. data/lib/active_genie/ranker/tournament.rb +23 -35
  47. data/lib/active_genie/scorer/jury_bench.rb +18 -23
  48. data/lib/active_genie/utils/base_module.rb +34 -0
  49. data/lib/active_genie/utils/call_wrapper.rb +20 -0
  50. data/lib/active_genie/utils/deep_merge.rb +12 -0
  51. data/lib/active_genie/utils/fiber_by_batch.rb +2 -2
  52. data/lib/active_genie/utils/text_case.rb +18 -0
  53. data/lib/active_genie.rb +16 -18
  54. data/lib/tasks/benchmark.rake +1 -3
  55. data/lib/tasks/templates/active_genie.rb +0 -3
  56. data/lib/tasks/test.rake +62 -1
  57. metadata +25 -15
  58. data/lib/active_genie/configs/comparator_config.rb +0 -10
  59. data/lib/active_genie/configs/scorer_config.rb +0 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5673a34f1cd8c2b2a9a884a73ded1bf12e28f4d29ab5f351ecb3374bc9ca0617
4
- data.tar.gz: 7ca0bc8d8bdc8b6d3618bd5f22bd13f80a9ac4399fa0282e6b11a461beb1cc1d
3
+ metadata.gz: 02e46bc41ee34451323202588e8018cca0f7497529f9c7f6ce64c0e00e009f7e
4
+ data.tar.gz: 4a78b8402fee546b0fd6fef3352cd85d476399167edf051798ec71709c46bb7b
5
5
  SHA512:
6
- metadata.gz: f174076b72df558ef82d3834043ae3299ab1aa41d235d6b547cbee45d21804295b87729a92dda51910d37a076f954fb8b4e2460443c1814f73221b5663255d96
7
- data.tar.gz: 503840469d6a67206d67d3f5b27f73803cb736cd4c826e7ea4b4575f1f702b7875fdeb979a875c29e88d5b06d9d18b49c94ae4f957f13563289428bdc1d83cd0
6
+ metadata.gz: 2e606f1827f1b88e67dea196d56173a5dd4c5ff51861a77942faebef38fdd6f252e3077c9ca2bc8585769ab4f873344dea0abebb88d19af1f40493aac9e7374d
7
+ data.tar.gz: 4beac5e264438b7c9eb692669ff16940e140251cc8e87b35e61fbef8eb3fdf604acc2966ed021705bca63a9ff90cd63312abe25143b68364a67d92becd113d58
data/README.md CHANGED
@@ -1,12 +1,14 @@
1
1
  # ActiveGenie 🧞‍♂️
2
- > The Lodash for GenAI: Real Value + Consistent + Model-Agnostic
2
+ > The Lodash for GenAI: Consistent + Model-Agnostic
3
3
 
4
4
  [![Gem Version](https://badge.fury.io/rb/active_genie.svg?icon=si%3Arubygems)](https://badge.fury.io/rb/active_genie)
5
5
  [![Ruby](https://github.com/roriz/active_genie/actions/workflows/benchmark.yml/badge.svg)](https://github.com/roriz/active_genie/actions/workflows/benchmark.yml)
6
6
 
7
- ActiveGenie is a developer-first library for GenAI workflows, designed to help you extract, compare, score, and rank with consistency and model-agnostic. Think of it as the Lodash for GenAI: built for real value, consistent results, and freedom from vendor lock-in. It solves the biggest pain in GenAI today: getting predictable, trustworthy answers across use cases, models, and providers.
8
-
9
- Behind the scenes, a custom benchmarking system keeps everything consistent across LLM vendors and versions, release after release.
7
+ **ActiveGenie** is an **enabler for creating reliable GenAI features**, offering powerful, **model-agnostic tools** across any provider. It allows you to settle subjective comparisons with a `ActibeGenie::Comparator` module that stages a political debate, get accurate scores from an **AI jury** using `ActiveGenie::Scorer`, and **rank large datasets** using `ActiveGenie::Ranker`'s tournament-style system.
8
+ This reliability is built on three core pillars:
9
+ * **Custom Benchmarking:** Testing for consistency with every new version and model update.
10
+ * **Reasoning Prompting:** Utilizing human reasoning techniques (like debate and jury review) to control a model's reasoning.
11
+ * **Overfitting Prompts:** Highly specialized, and potentially model-specific, prompt for each module's purpose.
10
12
 
11
13
  For full documentation, visit [activegenie.ai](https://activegenie.ai).
12
14
 
@@ -57,7 +59,7 @@ schema = {
57
59
  }
58
60
  }
59
61
 
60
- result = ActiveGenie::DataExtractor.call(
62
+ result = ActiveGenie::Extractor.call(
61
63
  text,
62
64
  schema,
63
65
  config: { provider_name: :openai, model: 'gpt-4.1-mini' } # optional
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.30.1
1
+ 0.30.8
@@ -14,11 +14,7 @@ module ActiveGenie
14
14
  # @example Debate usage with two players and criteria
15
15
  # Debate.call("Player A content", "Player B content", "Evaluate keyword usage and pattern matching")
16
16
  #
17
- class Debate
18
- def self.call(...)
19
- new(...).call
20
- end
21
-
17
+ class Debate < ActiveGenie::BaseModule
22
18
  # @param player_a [String] The content or submission from the first player
23
19
  # @param player_b [String] The content or submission from the second player
24
20
  # @param criteria [String] The evaluation criteria or rules to assess against
@@ -31,7 +27,7 @@ module ActiveGenie
31
27
  @player_a = player_a
32
28
  @player_b = player_b
33
29
  @criteria = criteria
34
- @config = ActiveGenie.configuration.merge(config)
30
+ super(config:)
35
31
  end
36
32
 
37
33
  # @return [ComparatorResponse] The evaluation result containing the winner and reasoning
@@ -43,13 +39,9 @@ module ActiveGenie
43
39
  { role: 'user', content: "criteria: #{@criteria}" }
44
40
  ]
45
41
 
46
- response = ::ActiveGenie::Providers::UnifiedProvider.function_calling(
47
- messages,
48
- FUNCTION,
49
- config: @config
50
- )
42
+ provider_response = ::ActiveGenie::Providers::UnifiedProvider.function_calling(messages, FUNCTION, config:)
51
43
 
52
- response_formatted(response)
44
+ response_formatted(provider_response)
53
45
  end
54
46
 
55
47
  PROMPT = File.read(File.join(__dir__, 'debate.prompt.md'))
@@ -57,28 +49,18 @@ module ActiveGenie
57
49
 
58
50
  private
59
51
 
60
- def response_formatted(response)
61
- winner, loser = case response['impartial_judge_winner']
62
- when 'player_a' then [@player_a, @player_b]
63
- when 'player_b' then [@player_b, @player_a]
64
- end
65
- reasoning = response['impartial_judge_winner_reasoning']
66
-
67
- comparator_response = ActiveGenie::Comparator::ComparatorResponse.new(winner:, loser:, reasoning:,
68
- raw: response)
69
- log_comparator(comparator_response)
52
+ def response_formatted(provider_response)
53
+ winner, = case provider_response['impartial_judge_winner']
54
+ when 'player_a' then [@player_a, @player_b]
55
+ when 'player_b' then [@player_b, @player_a]
56
+ end
57
+ reasoning = provider_response['impartial_judge_winner_reasoning']
70
58
 
71
- comparator_response
59
+ ActiveGenie::Result.new(data: winner, reasoning:, metadata: provider_response)
72
60
  end
73
61
 
74
- def log_comparator(comparator_response)
75
- @config.logger.call(
76
- code: :comparator,
77
- player_a: @player_a[0..30],
78
- player_b: @player_b[0..30],
79
- criteria: @criteria[0..30],
80
- **comparator_response.to_h
81
- )
62
+ def module_config
63
+ { llm: { recommended_model: 'claude-haiku-4-5' } }
82
64
  end
83
65
  end
84
66
  end
@@ -21,13 +21,13 @@ module ActiveGenie
21
21
  { role: 'user', content: "criteria: #{@criteria}" }
22
22
  ]
23
23
 
24
- response = ::ActiveGenie::Providers::UnifiedProvider.function_calling(
24
+ provider_response = ::ActiveGenie::Providers::UnifiedProvider.function_calling(
25
25
  messages,
26
26
  FUNCTION,
27
- config: @config
27
+ config:
28
28
  )
29
29
 
30
- response_formatted(response)
30
+ response_formatted(provider_response)
31
31
  end
32
32
 
33
33
  PROMPT = File.read(File.join(__dir__, 'fight.prompt.md'))
@@ -7,8 +7,6 @@ module ActiveGenie
7
7
  module Comparator
8
8
  module_function
9
9
 
10
- ComparatorResponse = Struct.new(:winner, :loser, :reasoning, :raw, keyword_init: true)
11
-
12
10
  def call(...)
13
11
  Debate.call(...)
14
12
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveGenie
4
+ module Config
5
+ class BaseConfig
6
+ def initialize(**args)
7
+ attributes.each do |var|
8
+ send("#{var}=", args[var] || args[var.to_s])
9
+ end
10
+ end
11
+
12
+ def attributes
13
+ public_methods(false).grep(/=$/).map { |m| m.to_s.delete('=').to_sym }
14
+ end
15
+
16
+ def to_h
17
+ h = {}
18
+ attributes.each do |var|
19
+ h[var.to_sym] = send(var)
20
+ end
21
+ h
22
+ end
23
+ end
24
+ end
25
+ end
@@ -1,22 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'base_config'
4
+
3
5
  module ActiveGenie
4
6
  module Config
5
- class ExtractorConfig
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
7
+ class ExtractorConfig < BaseConfig
8
+ attr_writer :min_accuracy
13
9
 
14
- def merge(config_params = {})
15
- dup.tap do |config|
16
- config.with_explanation = config_params[:with_explanation] if config_params.key?(:with_explanation)
17
- config.min_accuracy = config_params[:min_accuracy] if config_params.key?(:min_accuracy)
18
- config.verbose = config_params[:verbose] if config_params.key?(:verbose)
19
- end
10
+ def min_accuracy
11
+ @min_accuracy ||= 70
20
12
  end
21
13
  end
22
14
  end
@@ -1,18 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'base_config'
4
+
3
5
  module ActiveGenie
4
6
  module Config
5
- class ListerConfig
6
- attr_accessor :number_of_items
7
-
8
- def initialize
9
- @number_of_items = 5
10
- end
7
+ class ListerConfig < BaseConfig
8
+ attr_writer :number_of_items
11
9
 
12
- def merge(config_params = {})
13
- dup.tap do |config|
14
- config.number_of_items = config_params[:number_of_items] if config_params.key?(:number_of_items)
15
- end
10
+ def number_of_items
11
+ @number_of_items ||= 5
16
12
  end
17
13
  end
18
14
  end
@@ -1,38 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'base_config'
4
+
3
5
  module ActiveGenie
4
6
  module Config
5
- class LlmConfig
6
- attr_accessor :model, :temperature, :max_tokens, :max_retries, :retry_delay,
7
- :model_tier, :read_timeout, :open_timeout, :provider, :max_fibers
7
+ class LlmConfig < BaseConfig
8
+ attr_accessor :model, :recommended_model, :max_retries, :retry_delay,
9
+ :read_timeout, :open_timeout
10
+ attr_writer :temperature, :max_fibers, :max_tokens
8
11
  attr_reader :provider_name
9
12
 
10
- def initialize
11
- @model = nil
12
- @provider_name = nil
13
- @provider = 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
- @max_fibers = 10
13
+ def temperature
14
+ @temperature ||= 0
22
15
  end
23
16
 
24
- def provider_name=(provider_name)
25
- return if provider_name.nil? || provider_name.empty?
26
-
27
- @provider_name = provider_name.to_s.downcase.strip.to_sym
17
+ def max_fibers
18
+ @max_fibers ||= 10
28
19
  end
29
20
 
30
- def merge(config_params = {})
31
- dup.tap do |config|
32
- config_params.each do |key, value|
33
- config.send("#{key}=", value) if config.respond_to?("#{key}=")
34
- end
35
- end
21
+ def max_tokens
22
+ @max_tokens ||= 4096
36
23
  end
37
24
  end
38
25
  end
@@ -1,28 +1,41 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'base_config'
4
+
3
5
  module ActiveGenie
4
6
  module Config
5
- class LogConfig
7
+ class LogConfig < BaseConfig
8
+ attr_reader :output
6
9
  attr_writer :file_path, :fine_tune_file_path
7
- attr_reader :output, :observers
8
10
 
9
11
  def file_path
10
- @file_path || 'log/active_genie.log'
12
+ @file_path ||= 'log/active_genie.log'
11
13
  end
12
14
 
13
15
  def fine_tune_file_path
14
- @fine_tune_file_path || 'log/active_genie_fine_tune.log'
16
+ @fine_tune_file_path ||= 'log/active_genie_fine_tune.log'
17
+ end
18
+
19
+ def observers=(observers)
20
+ Array(observers).each do |observer|
21
+ add_observer(observers: [observer[:observer]], scope: observer[:scope] || {})
22
+ end
23
+ end
24
+
25
+ def observers
26
+ @observers ||= []
15
27
  end
16
28
 
17
29
  def additional_context
18
- @additional_context || {}
30
+ @additional_context ||= {}
19
31
  end
20
32
 
21
33
  def additional_context=(context)
22
- @additional_context = additional_context.merge(context).compact
34
+ @additional_context = additional_context.merge(context || {}).compact
23
35
  end
24
36
 
25
37
  def output=(output)
38
+ return if output.nil?
26
39
  raise InvalidLogOutputError, output unless output.respond_to?(:call)
27
40
 
28
41
  @output = output
@@ -50,16 +63,6 @@ module ActiveGenie
50
63
  def clear_observers
51
64
  @observers = []
52
65
  end
53
-
54
- def merge(config_params = {})
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
-
60
- config.add_observer(config_params[:observers]) if config_params[:observers]
61
- end
62
- end
63
66
  end
64
67
  end
65
68
  end
@@ -8,7 +8,10 @@ module ActiveGenie
8
8
  # Configuration class for the Anthropic API client.
9
9
  # Manages API keys, URLs, model selections, and client instantiation.
10
10
  class AnthropicConfig < ProviderBase
11
- NAME = :anthropic
11
+ def initialize(anthropic_version: nil, **args)
12
+ @anthropic_version = anthropic_version
13
+ super(**args)
14
+ end
12
15
 
13
16
  # Retrieves the API key.
14
17
  # Falls back to the ANTHROPIC_API_KEY environment variable if not set.
@@ -31,25 +34,16 @@ module ActiveGenie
31
34
  @anthropic_version || '2023-06-01'
32
35
  end
33
36
 
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'
37
+ def default_model
38
+ @default_model || 'claude-3-5-haiku-20241022'
39
39
  end
40
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'
41
+ def valid_model?(model)
42
+ model.include?('claude')
46
43
  end
47
44
 
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 higher_tier_model
52
- @higher_tier_model || 'claude-3-opus-20240229'
45
+ def to_h
46
+ super.merge({ anthropic_version: })
53
47
  end
54
48
  end
55
49
  end
@@ -8,8 +8,6 @@ module ActiveGenie
8
8
  # Configuration class for the DeepSeek API client.
9
9
  # Manages API keys, organization IDs, URLs, model selections, and client instantiation.
10
10
  class DeepseekConfig < ProviderBase
11
- NAME = :deepseek
12
-
13
11
  # Retrieves the API key.
14
12
  # Falls back to the DEEPSEEK_API_KEY environment variable if not set.
15
13
  # @return [String, nil] The API key.
@@ -24,25 +22,12 @@ module ActiveGenie
24
22
  @api_url || 'https://api.deepseek.com/v1'
25
23
  end
26
24
 
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'
25
+ def default_model
26
+ @default_model || 'deepseek-chat'
39
27
  end
40
28
 
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 higher_tier_model
45
- @higher_tier_model || 'deepseek-reasoner'
29
+ def valid_model?(model)
30
+ model.include?('deepseek')
46
31
  end
47
32
  end
48
33
  end
@@ -8,8 +8,6 @@ module ActiveGenie
8
8
  # Configuration class for the Google Generative Language API client.
9
9
  # Manages API keys, URLs, model selections, and client instantiation.
10
10
  class GoogleConfig < ProviderBase
11
- NAME = :google
12
-
13
11
  # Retrieves the API key.
14
12
  # Falls back to the GENERATIVE_LANGUAGE_GOOGLE_API_KEY environment variable if not set.
15
13
  # @return [String, nil] The API key.
@@ -26,25 +24,12 @@ module ActiveGenie
26
24
  @api_url || 'https://generativelanguage.googleapis.com'
27
25
  end
28
26
 
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'
27
+ def default_model
28
+ @default_model || 'gemini-2.5-flash'
41
29
  end
42
30
 
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 higher_tier_model
47
- @higher_tier_model || 'gemini-2.5-pro-experimental'
31
+ def valid_model?(model)
32
+ model.include?('gemini')
48
33
  end
49
34
  end
50
35
  end
@@ -8,8 +8,6 @@ module ActiveGenie
8
8
  # Configuration class for the OpenAI API client.
9
9
  # Manages API keys, organization IDs, URLs, model selections, and client instantiation.
10
10
  class OpenaiConfig < ProviderBase
11
- NAME = :openai
12
-
13
11
  # Retrieves the API key.
14
12
  # Falls back to the OPENAI_API_KEY environment variable if not set.
15
13
  # @return [String, nil] The API key.
@@ -24,25 +22,12 @@ module ActiveGenie
24
22
  @api_url || 'https://api.openai.com/v1'
25
23
  end
26
24
 
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'
25
+ def default_model
26
+ @default_model || 'gpt-5-mini'
39
27
  end
40
28
 
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 higher_tier_model
45
- @higher_tier_model || 'o3-mini'
29
+ def valid_model?(model)
30
+ model.include?('gpt')
46
31
  end
47
32
  end
48
33
  end
@@ -4,37 +4,14 @@ module ActiveGenie
4
4
  module Config
5
5
  module Providers
6
6
  class ProviderBase
7
- NAME = :unknown
8
-
9
- attr_writer :api_key, :organization, :api_url, :client,
10
- :lower_tier_model, :middle_tier_model, :higher_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: higher_tier_model
21
- }[tier&.to_sym] || lower_tier_model
7
+ def initialize(api_key: nil, organization: nil, api_url: nil, default_model: nil)
8
+ @api_key = api_key
9
+ @organization = organization
10
+ @api_url = api_url
11
+ @default_model = default_model
22
12
  end
23
13
 
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
- higher_tier_model:,
35
- **config
36
- }
37
- end
14
+ attr_writer :api_key, :organization, :api_url, :default_model
38
15
 
39
16
  # Validates the configuration.
40
17
  # @return [Boolean] True if the configuration is valid, false otherwise.
@@ -42,46 +19,23 @@ module ActiveGenie
42
19
  api_key && api_url
43
20
  end
44
21
 
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'
22
+ # Checks if the given model is valid for this provider. Example provider.valid_model?('gpt-4') => true
23
+ # @param model [String, nil] The model name to validate.
24
+ # @return [Boolean] True if the model is valid, false otherwise.
25
+ def valid_model?(_model)
26
+ false
57
27
  end
58
28
 
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 higher_tier_model
84
- raise NotImplementedError, 'Subclasses must implement this method'
29
+ # Returns a hash representation of the configuration.
30
+ # @param config [Hash] Additional key-value pairs to merge into the hash.
31
+ # @return [Hash] The configuration settings as a hash.
32
+ def to_h
33
+ {
34
+ api_key: @api_key,
35
+ api_url: @api_url,
36
+ organization: @organization,
37
+ default_model: @default_model
38
+ }
85
39
  end
86
40
  end
87
41
  end