active_genie 0.29.1 → 0.30.1

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 (68) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/VERSION +1 -1
  4. data/lib/active_genie/{battle/generalist.json → comparator/debate.json} +2 -2
  5. data/lib/active_genie/{battle/generalist.prompt.md → comparator/debate.prompt.md} +1 -1
  6. data/lib/active_genie/{battle/generalist.rb → comparator/debate.rb} +20 -21
  7. data/lib/active_genie/{battle → comparator}/fight.rb +7 -7
  8. data/lib/active_genie/comparator.rb +24 -0
  9. data/lib/active_genie/{config/scoring_config.rb → configs/comparator_config.rb} +1 -1
  10. data/lib/active_genie/{config/data_extractor_config.rb → configs/extractor_config.rb} +1 -1
  11. data/lib/active_genie/{config/factory_config.rb → configs/lister_config.rb} +1 -1
  12. data/lib/active_genie/{config → configs}/llm_config.rb +7 -6
  13. data/lib/active_genie/{config → configs}/providers_config.rb +1 -1
  14. data/lib/active_genie/{config/ranking_config.rb → configs/ranker_config.rb} +1 -1
  15. data/lib/active_genie/{config/battle_config.rb → configs/scorer_config.rb} +1 -1
  16. data/lib/active_genie/configuration.rb +19 -19
  17. data/lib/active_genie/errors/invalid_provider_error.rb +1 -1
  18. data/lib/active_genie/{data_extractor/generalist.rb → extractor/explanation.rb} +11 -11
  19. data/lib/active_genie/{data_extractor/from_informal.rb → extractor/litote.rb} +8 -8
  20. data/lib/active_genie/extractor.rb +22 -0
  21. data/lib/active_genie/{factory → lister}/feud.rb +8 -8
  22. data/lib/active_genie/lister/juries.prompt.md +20 -0
  23. data/lib/active_genie/lister/juries.rb +82 -0
  24. data/lib/active_genie/{factory.rb → lister.rb} +7 -6
  25. data/lib/active_genie/{clients/providers/anthropic_client.rb → providers/anthropic_provider.rb} +4 -4
  26. data/lib/active_genie/{clients/providers/base_client.rb → providers/base_provider.rb} +14 -7
  27. data/lib/active_genie/{clients/providers/deepseek_client.rb → providers/deepseek_provider.rb} +3 -3
  28. data/lib/active_genie/{clients/providers/google_client.rb → providers/google_provider.rb} +6 -6
  29. data/lib/active_genie/{clients/providers/openai_client.rb → providers/openai_provider.rb} +3 -3
  30. data/lib/active_genie/providers/unified_provider.rb +44 -0
  31. data/lib/active_genie/{ranking/elo_round.rb → ranker/elo.rb} +37 -36
  32. data/lib/active_genie/ranker/entities/player.rb +124 -0
  33. data/lib/active_genie/ranker/entities/players.rb +102 -0
  34. data/lib/active_genie/{ranking → ranker}/free_for_all.rb +9 -9
  35. data/lib/active_genie/ranker/scoring.rb +68 -0
  36. data/lib/active_genie/{ranking/ranking.rb → ranker/tournament.rb} +22 -31
  37. data/lib/active_genie/ranker.rb +32 -0
  38. data/lib/active_genie/scorer/jury_bench.rb +121 -0
  39. data/lib/active_genie/scorer.rb +17 -0
  40. data/lib/active_genie/utils/fiber_by_batch.rb +21 -0
  41. data/lib/active_genie.rb +9 -9
  42. data/lib/tasks/test.rake +4 -0
  43. metadata +67 -52
  44. data/lib/active_genie/battle.rb +0 -31
  45. data/lib/active_genie/clients/unified_client.rb +0 -50
  46. data/lib/active_genie/data_extractor.rb +0 -23
  47. data/lib/active_genie/ranking/player.rb +0 -122
  48. data/lib/active_genie/ranking/players_collection.rb +0 -95
  49. data/lib/active_genie/ranking/ranking_scoring.rb +0 -69
  50. data/lib/active_genie/ranking.rb +0 -14
  51. data/lib/active_genie/scoring/generalist.json +0 -9
  52. data/lib/active_genie/scoring/generalist.rb +0 -119
  53. data/lib/active_genie/scoring/recommended_reviewers.rb +0 -87
  54. data/lib/active_genie/scoring.rb +0 -23
  55. /data/lib/active_genie/{battle → comparator}/fight.json +0 -0
  56. /data/lib/active_genie/{battle → comparator}/fight.prompt.md +0 -0
  57. /data/lib/active_genie/{config → configs}/log_config.rb +0 -0
  58. /data/lib/active_genie/{config → configs}/providers/anthropic_config.rb +0 -0
  59. /data/lib/active_genie/{config → configs}/providers/deepseek_config.rb +0 -0
  60. /data/lib/active_genie/{config → configs}/providers/google_config.rb +0 -0
  61. /data/lib/active_genie/{config → configs}/providers/openai_config.rb +0 -0
  62. /data/lib/active_genie/{config → configs}/providers/provider_base.rb +0 -0
  63. /data/lib/active_genie/{data_extractor/generalist.json → extractor/explanation.json} +0 -0
  64. /data/lib/active_genie/{data_extractor/generalist.prompt.md → extractor/explanation.prompt.md} +0 -0
  65. /data/lib/active_genie/{data_extractor/from_informal.json → extractor/litote.json} +0 -0
  66. /data/lib/active_genie/{factory → lister}/feud.json +0 -0
  67. /data/lib/active_genie/{factory → lister}/feud.prompt.md +0 -0
  68. /data/lib/active_genie/{scoring/generalist.prompt.md → scorer/jury_bench.prompt.md} +0 -0
@@ -1,14 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveGenie
4
- module Ranking
4
+ module Ranker
5
5
  class FreeForAll
6
6
  def self.call(...)
7
7
  new(...).call
8
8
  end
9
9
 
10
10
  def initialize(players, criteria, config: nil)
11
- @players = players
11
+ @players = Entities::Players.new(players)
12
12
  @criteria = criteria
13
13
  @config = config || ActiveGenie.configuration
14
14
  @start_time = Time.now
@@ -19,8 +19,8 @@ module ActiveGenie
19
19
  @config.log.add_observer(observers: ->(log) { log_observer(log) })
20
20
  @config.log.additional_context = { free_for_all_id: }
21
21
 
22
- matches.each do |player_a, player_b|
23
- winner, loser = battle(player_a, player_b)
22
+ ActiveGenie::FiberByBatch.call(matches, config: @config) do |player_a, player_b|
23
+ winner, loser = debate(player_a, player_b)
24
24
 
25
25
  update_players_score(winner, loser)
26
26
  end
@@ -31,15 +31,15 @@ module ActiveGenie
31
31
  private
32
32
 
33
33
  # TODO: reduce the number of matches based on transitivity.
34
- # For example, if A is better than B, and B is better than C, then battle between A and C should be auto win A
34
+ # For example, if A is better than B, and B is better than C, then debate between A and C should be auto win A
35
35
  def matches
36
36
  @players.eligible.combination(2).to_a
37
37
  end
38
38
 
39
- def battle(player_a, player_b)
39
+ def debate(player_a, player_b)
40
40
  log_context = { player_a_id: player_a.id, player_b_id: player_b.id }
41
41
 
42
- result = ActiveGenie::Battle.call(
42
+ result = ActiveGenie::Comparator.by_debate(
43
43
  player_a.content,
44
44
  player_b.content,
45
45
  @criteria,
@@ -55,7 +55,7 @@ module ActiveGenie
55
55
  @config.logger.call(
56
56
  {
57
57
  **log_context,
58
- code: :free_for_all_battle,
58
+ code: :free_for_all,
59
59
  winner_id: winner&.id,
60
60
  loser_id: loser&.id,
61
61
  reasoning: result['reasoning']
@@ -88,7 +88,7 @@ module ActiveGenie
88
88
  def build_report
89
89
  report = {
90
90
  free_for_all_id:,
91
- battles_count: matches.size,
91
+ debates_count: matches.size,
92
92
  duration_seconds: Time.now - @start_time,
93
93
  total_tokens: @total_tokens
94
94
  }
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../utils/fiber_by_batch'
4
+
5
+ module ActiveGenie
6
+ module Ranker
7
+ class Scoring
8
+ def self.call(...)
9
+ new(...).call
10
+ end
11
+
12
+ def initialize(players, criteria, juries: [], config: nil)
13
+ @players = Entities::Players.new(players)
14
+ @criteria = criteria
15
+ @config = ActiveGenie.configuration.merge(config)
16
+ @juries = Array(juries).compact.uniq
17
+ end
18
+
19
+ def call
20
+ @config.log.additional_context = { ranker_scoring_id: }
21
+
22
+ ActiveGenie::FiberByBatch.call(players_without_score, config: @config) do |player|
23
+ player.score = generate_score(player)
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def players_without_score
30
+ @players_without_score ||= @players.select { |player| player.score.nil? }
31
+ end
32
+
33
+ def generate_score(player)
34
+ score, reasoning = ActiveGenie::Scorer.by_jury_bench(
35
+ player.content,
36
+ @criteria,
37
+ @juries,
38
+ config: @config
39
+ ).values_at('final_score', 'final_reasoning')
40
+
41
+ @config.logger.call({ code: :new_score, player_id: player.id, score:, reasoning: })
42
+
43
+ score
44
+ end
45
+
46
+ def juries
47
+ @juries ||= begin
48
+ response = ActiveGenie::Lister.juries(
49
+ [@players.sample.content, @players.sample.content].join("\n\n"),
50
+ @criteria,
51
+ config: @config
52
+ )
53
+ @config.logger.call({ code: :new_juries, juries: response })
54
+ response
55
+ end
56
+ end
57
+
58
+ def ranker_scoring_id
59
+ @ranker_scoring_id ||= begin
60
+ player_ids = players_without_score.map(&:id).join(',')
61
+ ranker_unique_key = [player_ids, @criteria, @config.to_json].join('-')
62
+
63
+ "#{Digest::MD5.hexdigest(ranker_unique_key)}-scoring"
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'players_collection'
3
+ require_relative 'entities/players'
4
4
  require_relative 'free_for_all'
5
- require_relative 'elo_round'
6
- require_relative 'ranking_scoring'
5
+ require_relative 'elo'
6
+ require_relative 'scoring'
7
7
 
8
8
  # This class orchestrates player ranking through multiple evaluation stages
9
9
  # using Elo ranking and free-for-all match simulations.
@@ -13,7 +13,7 @@ require_relative 'ranking_scoring'
13
13
  # 4. Conducts free-for-all matches
14
14
  #
15
15
  # @example Basic usage
16
- # Ranking.call(players, criteria)
16
+ # Ranker.tournament(players, criteria)
17
17
  #
18
18
  # @param param_players [Array<Hash|String>] Collection of player objects to evaluate
19
19
  # Example: ["Circle", "Triangle", "Square"]
@@ -29,30 +29,28 @@ require_relative 'ranking_scoring'
29
29
  # Example: { model: "gpt-4o", api_key: ENV['OPENAI_API_KEY'] }
30
30
  # @return [Hash] Final ranked player results
31
31
  module ActiveGenie
32
- module Ranking
33
- class Ranking
32
+ module Ranker
33
+ class Tournament
34
34
  def self.call(...)
35
35
  new(...).call
36
36
  end
37
37
 
38
- def initialize(param_players, criteria, reviewers: [], config: {})
39
- @param_players = param_players
38
+ def initialize(players, criteria, juries: [], config: {})
39
+ @players = Entities::Players.new(players)
40
40
  @criteria = criteria
41
- @reviewers = Array(reviewers).compact.uniq
41
+ @juries = Array(juries).compact.uniq
42
42
  @config = ActiveGenie.configuration.merge(config)
43
- @players = nil
44
43
  end
45
44
 
46
45
  def call
47
- @players = create_players
48
- @config.log.additional_context = { ranking_id: }
46
+ @config.log.additional_context = { ranker_id: }
49
47
 
50
48
  set_initial_player_scores!
51
49
  eliminate_obvious_bad_players!
52
50
 
53
51
  while @players.elo_eligible?
54
52
  elo_report = run_elo_round!
55
- eliminate_relegation_players!
53
+ eliminate_lower_tier_players!
56
54
  rebalance_players!(elo_report)
57
55
  end
58
56
 
@@ -66,38 +64,31 @@ module ActiveGenie
66
64
 
67
65
  private
68
66
 
69
- def create_players
70
- players = PlayersCollection.new(@param_players)
71
- players.each { |p| @config.logger.call({ code: :new_player, player: p.to_h }) }
72
-
73
- players
74
- end
75
-
76
67
  def set_initial_player_scores!
77
- RankingScoring.call(
68
+ Scoring.call(
78
69
  @players,
79
70
  @criteria,
80
- reviewers: @reviewers,
71
+ juries: @juries,
81
72
  config: @config
82
73
  )
83
74
  end
84
75
 
85
76
  def eliminate_obvious_bad_players!
86
- while @players.coefficient_of_variation >= @config.ranking.score_variation_threshold
77
+ while @players.coefficient_of_variation >= @config.ranker.score_variation_threshold
87
78
  @players.eligible.last.eliminated = ELIMINATION_VARIATION
88
79
  end
89
80
  end
90
81
 
91
82
  def run_elo_round!
92
- EloRound.call(
83
+ Elo.call(
93
84
  @players,
94
85
  @criteria,
95
86
  config: @config
96
87
  )
97
88
  end
98
89
 
99
- def eliminate_relegation_players!
100
- @players.calc_relegation_tier.each { |player| player.eliminated = ELIMINATION_RELEGATION }
90
+ def eliminate_lower_tier_players!
91
+ @players.calc_lower_tier.each { |player| player.eliminated = ELIMINATION_RELEGATION }
101
92
  end
102
93
 
103
94
  def rebalance_players!(elo_report)
@@ -120,17 +111,17 @@ module ActiveGenie
120
111
 
121
112
  def sorted_players
122
113
  players = @players.sorted
123
- @config.logger.call({ ranking_id:, code: :ranking_final, players: players.map(&:to_h) })
114
+ @config.logger.call({ ranker_id:, code: :ranker_final, players: players.map(&:to_h) })
124
115
 
125
116
  players.map(&:to_h)
126
117
  end
127
118
 
128
- def ranking_id
129
- @ranking_id ||= begin
119
+ def ranker_id
120
+ @ranker_id ||= begin
130
121
  player_ids = @players.map(&:id).join(',')
131
- ranking_unique_key = [player_ids, @criteria, @config.to_json].join('-')
122
+ ranker_unique_key = [player_ids, @criteria, @config.to_json].join('-')
132
123
 
133
- Digest::MD5.hexdigest(ranking_unique_key)
124
+ Digest::MD5.hexdigest(ranker_unique_key)
134
125
  end
135
126
  end
136
127
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'ranker/tournament'
4
+ require_relative 'ranker/free_for_all'
5
+ require_relative 'ranker/elo'
6
+ require_relative 'ranker/scoring'
7
+
8
+ module ActiveGenie
9
+ module Ranker
10
+ module_function
11
+
12
+ def call(...)
13
+ Tournament.call(...)
14
+ end
15
+
16
+ def by_tournament(...)
17
+ Tournament.call(...)
18
+ end
19
+
20
+ def by_free_for_all(...)
21
+ FreeForAll.call(...)
22
+ end
23
+
24
+ def by_elo(...)
25
+ Elo.call(...)
26
+ end
27
+
28
+ def by_scoring(...)
29
+ Scoring.call(...)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../providers/unified_provider'
4
+
5
+ module ActiveGenie
6
+ module Scorer
7
+ # The JuryBench class provides a foundation for Scorer text content against specified criteria
8
+ # using AI-powered evaluation. It supports both single and multiple jury scenarios,
9
+ # with the ability to automatically recommend juries when none are specified.
10
+ #
11
+ # The Scorer process evaluates text based on given criteria and returns detailed feedback
12
+ # including individual jury scores, reasoning, and a final aggregated score.
13
+ #
14
+ # @example JuryBench usage with a single jury
15
+ # JuryBench.call("Sample text", "Evaluate grammar and clarity", ["Grammar Expert"])
16
+ #
17
+ # @example Usage with automatic jury recommendation
18
+ # JuryBench.call("Sample text", "Evaluate technical accuracy")
19
+ #
20
+ class JuryBench
21
+ # @param text [String] The text content to be evaluated
22
+ # @param criteria [String] The evaluation criteria or rubric to assess against
23
+ # @param juries [Array<String>] Optional list of specific juries. If empty,
24
+ # juries will be automatically recommended based on the content and criteria
25
+ # @param config [Hash] Additional configuration config that modify the Scorer behavior
26
+ # @return [Hash] The evaluation result containing the scores and reasoning
27
+ # @return [Number] :final_score The final score of the text based on the criteria and juries
28
+ # @return [String] :final_reasoning Detailed explanation of why the final score was reached
29
+ def self.call(...)
30
+ new(...).call
31
+ end
32
+
33
+ def initialize(text, criteria, juries = [], config: {})
34
+ @text = text
35
+ @criteria = criteria
36
+ @param_juries = Array(juries).compact.uniq
37
+ @config = ActiveGenie.configuration.merge(config)
38
+ end
39
+
40
+ def call
41
+ messages = [
42
+ { role: 'system', content: PROMPT },
43
+ { role: 'user', content: "Scorer criteria: #{@criteria}" },
44
+ { role: 'user', content: "Text to score: #{@text}" }
45
+ ]
46
+
47
+ result = ::ActiveGenie::Providers::UnifiedProvider.function_calling(
48
+ messages,
49
+ build_function,
50
+ config: @config
51
+ )
52
+
53
+ result['final_score'] = 0 if result['final_score'].nil?
54
+
55
+ @config.logger.call({
56
+ code: :Scorer,
57
+ text: @text[0..30],
58
+ criteria: @criteria[0..30],
59
+ juries: juries,
60
+ score: result['final_score'],
61
+ reasoning: result['final_reasoning']
62
+ })
63
+
64
+ result
65
+ end
66
+
67
+ PROMPT = File.read(File.join(__dir__, 'jury_bench.prompt.md'))
68
+
69
+ private
70
+
71
+ def build_function
72
+ {
73
+ name: 'scorer',
74
+ description: 'Score the text based on the given criteria.',
75
+ parameters: {
76
+ type: 'object',
77
+ properties: properties,
78
+ required: properties.keys
79
+ }
80
+ }
81
+ end
82
+
83
+ def properties
84
+ @properties ||= begin
85
+ tmp = {}
86
+ juries.each do |jury|
87
+ tmp["#{jury}_reasoning"] = {
88
+ type: 'string',
89
+ description: "The reasoning of the Scorer process by #{jury}."
90
+ }
91
+ tmp["#{jury}_score"] = {
92
+ type: 'number',
93
+ description: "The score given by #{jury}.",
94
+ min: 0,
95
+ max: 100
96
+ }
97
+ end
98
+
99
+ tmp[:final_score] = {
100
+ type: 'number',
101
+ description: 'The final score based on the previous juries'
102
+ }
103
+ tmp[:final_reasoning] = {
104
+ type: 'string',
105
+ description: 'The final reasoning based on the previous juries'
106
+ }
107
+
108
+ tmp
109
+ end
110
+ end
111
+
112
+ def juries
113
+ @juries ||= if @param_juries.any?
114
+ @param_juries
115
+ else
116
+ ::ActiveGenie::Lister::Juries.call(@text, @criteria, config: @config)
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'scorer/jury_bench'
4
+
5
+ module ActiveGenie
6
+ module Scorer
7
+ module_function
8
+
9
+ def call(...)
10
+ JuryBench.call(...)
11
+ end
12
+
13
+ def by_jury_bench(...)
14
+ JuryBench.call(...)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'async'
4
+
5
+ module ActiveGenie
6
+ module FiberByBatch
7
+ module_function
8
+
9
+ def call(items, config:, &block)
10
+ items.each_slice(config.llm.max_fibers).to_a.each do |batch|
11
+ Async do
12
+ tasks = batch.map do |item|
13
+ Async { block.call(item) }
14
+ end
15
+
16
+ tasks.each(&:wait)
17
+ end.wait
18
+ end
19
+ end
20
+ end
21
+ end
data/lib/active_genie.rb CHANGED
@@ -3,17 +3,17 @@
3
3
  require_relative 'active_genie/logger'
4
4
  require_relative 'active_genie/configuration'
5
5
 
6
- require_relative 'active_genie/config/providers/openai_config'
7
- require_relative 'active_genie/config/providers/google_config'
8
- require_relative 'active_genie/config/providers/anthropic_config'
9
- require_relative 'active_genie/config/providers/deepseek_config'
6
+ require_relative 'active_genie/configs/providers/openai_config'
7
+ require_relative 'active_genie/configs/providers/google_config'
8
+ require_relative 'active_genie/configs/providers/anthropic_config'
9
+ require_relative 'active_genie/configs/providers/deepseek_config'
10
10
 
11
11
  module ActiveGenie
12
- autoload :DataExtractor, File.join(__dir__, 'active_genie/data_extractor')
13
- autoload :Battle, File.join(__dir__, 'active_genie/battle')
14
- autoload :Scoring, File.join(__dir__, 'active_genie/scoring')
15
- autoload :Ranking, File.join(__dir__, 'active_genie/ranking')
16
- autoload :Factory, File.join(__dir__, 'active_genie/factory')
12
+ autoload :Extractor, File.join(__dir__, 'active_genie/extractor')
13
+ autoload :Comparator, File.join(__dir__, 'active_genie/comparator')
14
+ autoload :Scorer, File.join(__dir__, 'active_genie/scorer')
15
+ autoload :Ranker, File.join(__dir__, 'active_genie/ranker')
16
+ autoload :Lister, File.join(__dir__, 'active_genie/lister')
17
17
 
18
18
  VERSION = File.read(File.expand_path('../VERSION', __dir__)).strip
19
19
 
data/lib/tasks/test.rake CHANGED
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'rake/testtask'
4
+
3
5
  namespace :test do
4
6
  Rake::TestTask.new(:unit) do |t|
5
7
  t.pattern = 'test/unit/**/*_test.rb'
@@ -8,4 +10,6 @@ namespace :test do
8
10
  Rake::TestTask.new(:integration) do |t|
9
11
  t.pattern = 'test/integration/**/*_test.rb' # Or use _spec.rb for RSpec
10
12
  end
13
+
14
+ task default: %i[unit integration]
11
15
  end
metadata CHANGED
@@ -1,17 +1,31 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_genie
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.29.1
4
+ version: 0.30.1
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-08-05 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2025-08-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: async
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
13
27
  description: |
14
- ActiveGenie is a Ruby gem that helps developers build reliable, future-proof GenAI features without worrying about changing models, prompts, or providers. Like Lodash for GenAI, it offers simple, reusable modules for tasks like data extraction, scoring, and ranking, so you can focus on your app’s logic, not the shifting AI landscape.
28
+ ActiveGenie is a Ruby gem that helps developers build reliable, future-proof GenAI features without worrying about changing models, prompts, or providers. Like Lodash for GenAI, it offers simple, reusable modules for tasks like extractor, comparator, scorer, and ranker, so you can focus on your app’s logic, not the shifting AI landscape.
15
29
  Behind the scenes, a custom benchmarking system keeps everything consistent across LLM vendors and versions, release after release.
16
30
  email:
17
31
  - radames@roriz.dev
@@ -23,58 +37,59 @@ files:
23
37
  - README.md
24
38
  - VERSION
25
39
  - lib/active_genie.rb
26
- - lib/active_genie/battle.rb
27
- - lib/active_genie/battle/fight.json
28
- - lib/active_genie/battle/fight.prompt.md
29
- - lib/active_genie/battle/fight.rb
30
- - lib/active_genie/battle/generalist.json
31
- - lib/active_genie/battle/generalist.prompt.md
32
- - lib/active_genie/battle/generalist.rb
33
- - lib/active_genie/clients/providers/anthropic_client.rb
34
- - lib/active_genie/clients/providers/base_client.rb
35
- - lib/active_genie/clients/providers/deepseek_client.rb
36
- - lib/active_genie/clients/providers/google_client.rb
37
- - lib/active_genie/clients/providers/openai_client.rb
38
- - lib/active_genie/clients/unified_client.rb
39
- - lib/active_genie/config/battle_config.rb
40
- - lib/active_genie/config/data_extractor_config.rb
41
- - lib/active_genie/config/factory_config.rb
42
- - lib/active_genie/config/llm_config.rb
43
- - lib/active_genie/config/log_config.rb
44
- - lib/active_genie/config/providers/anthropic_config.rb
45
- - lib/active_genie/config/providers/deepseek_config.rb
46
- - lib/active_genie/config/providers/google_config.rb
47
- - lib/active_genie/config/providers/openai_config.rb
48
- - lib/active_genie/config/providers/provider_base.rb
49
- - lib/active_genie/config/providers_config.rb
50
- - lib/active_genie/config/ranking_config.rb
51
- - lib/active_genie/config/scoring_config.rb
40
+ - lib/active_genie/comparator.rb
41
+ - lib/active_genie/comparator/debate.json
42
+ - lib/active_genie/comparator/debate.prompt.md
43
+ - lib/active_genie/comparator/debate.rb
44
+ - lib/active_genie/comparator/fight.json
45
+ - lib/active_genie/comparator/fight.prompt.md
46
+ - lib/active_genie/comparator/fight.rb
47
+ - lib/active_genie/configs/comparator_config.rb
48
+ - lib/active_genie/configs/extractor_config.rb
49
+ - lib/active_genie/configs/lister_config.rb
50
+ - lib/active_genie/configs/llm_config.rb
51
+ - lib/active_genie/configs/log_config.rb
52
+ - lib/active_genie/configs/providers/anthropic_config.rb
53
+ - lib/active_genie/configs/providers/deepseek_config.rb
54
+ - lib/active_genie/configs/providers/google_config.rb
55
+ - lib/active_genie/configs/providers/openai_config.rb
56
+ - lib/active_genie/configs/providers/provider_base.rb
57
+ - lib/active_genie/configs/providers_config.rb
58
+ - lib/active_genie/configs/ranker_config.rb
59
+ - lib/active_genie/configs/scorer_config.rb
52
60
  - lib/active_genie/configuration.rb
53
- - lib/active_genie/data_extractor.rb
54
- - lib/active_genie/data_extractor/from_informal.json
55
- - lib/active_genie/data_extractor/from_informal.rb
56
- - lib/active_genie/data_extractor/generalist.json
57
- - lib/active_genie/data_extractor/generalist.prompt.md
58
- - lib/active_genie/data_extractor/generalist.rb
59
61
  - lib/active_genie/errors/invalid_log_output_error.rb
60
62
  - lib/active_genie/errors/invalid_provider_error.rb
61
- - lib/active_genie/factory.rb
62
- - lib/active_genie/factory/feud.json
63
- - lib/active_genie/factory/feud.prompt.md
64
- - lib/active_genie/factory/feud.rb
63
+ - lib/active_genie/extractor.rb
64
+ - lib/active_genie/extractor/explanation.json
65
+ - lib/active_genie/extractor/explanation.prompt.md
66
+ - lib/active_genie/extractor/explanation.rb
67
+ - lib/active_genie/extractor/litote.json
68
+ - lib/active_genie/extractor/litote.rb
69
+ - lib/active_genie/lister.rb
70
+ - lib/active_genie/lister/feud.json
71
+ - lib/active_genie/lister/feud.prompt.md
72
+ - lib/active_genie/lister/feud.rb
73
+ - lib/active_genie/lister/juries.prompt.md
74
+ - lib/active_genie/lister/juries.rb
65
75
  - lib/active_genie/logger.rb
66
- - lib/active_genie/ranking.rb
67
- - lib/active_genie/ranking/elo_round.rb
68
- - lib/active_genie/ranking/free_for_all.rb
69
- - lib/active_genie/ranking/player.rb
70
- - lib/active_genie/ranking/players_collection.rb
71
- - lib/active_genie/ranking/ranking.rb
72
- - lib/active_genie/ranking/ranking_scoring.rb
73
- - lib/active_genie/scoring.rb
74
- - lib/active_genie/scoring/generalist.json
75
- - lib/active_genie/scoring/generalist.prompt.md
76
- - lib/active_genie/scoring/generalist.rb
77
- - lib/active_genie/scoring/recommended_reviewers.rb
76
+ - lib/active_genie/providers/anthropic_provider.rb
77
+ - lib/active_genie/providers/base_provider.rb
78
+ - lib/active_genie/providers/deepseek_provider.rb
79
+ - lib/active_genie/providers/google_provider.rb
80
+ - lib/active_genie/providers/openai_provider.rb
81
+ - lib/active_genie/providers/unified_provider.rb
82
+ - lib/active_genie/ranker.rb
83
+ - lib/active_genie/ranker/elo.rb
84
+ - lib/active_genie/ranker/entities/player.rb
85
+ - lib/active_genie/ranker/entities/players.rb
86
+ - lib/active_genie/ranker/free_for_all.rb
87
+ - lib/active_genie/ranker/scoring.rb
88
+ - lib/active_genie/ranker/tournament.rb
89
+ - lib/active_genie/scorer.rb
90
+ - lib/active_genie/scorer/jury_bench.prompt.md
91
+ - lib/active_genie/scorer/jury_bench.rb
92
+ - lib/active_genie/utils/fiber_by_batch.rb
78
93
  - lib/tasks/benchmark.rake
79
94
  - lib/tasks/install.rake
80
95
  - lib/tasks/templates/active_genie.rb
@@ -1,31 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'battle/generalist'
4
- require_relative 'battle/fight'
5
-
6
- module ActiveGenie
7
- # See the [Battle README](lib/active_genie/battle/README.md) for more information.
8
- module Battle
9
- module_function
10
-
11
- def generalist(...)
12
- Generalist.call(...)
13
- end
14
-
15
- def call(...)
16
- Generalist.call(...)
17
- end
18
-
19
- def battle(...)
20
- Generalist.call(...)
21
- end
22
-
23
- def compare(...)
24
- Generalist.call(...)
25
- end
26
-
27
- def fight(...)
28
- Fight.call(...)
29
- end
30
- end
31
- end