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.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/VERSION +1 -1
- data/lib/active_genie/{battle/generalist.json → comparator/debate.json} +2 -2
- data/lib/active_genie/{battle/generalist.prompt.md → comparator/debate.prompt.md} +1 -1
- data/lib/active_genie/{battle/generalist.rb → comparator/debate.rb} +20 -21
- data/lib/active_genie/{battle → comparator}/fight.rb +7 -7
- data/lib/active_genie/comparator.rb +24 -0
- data/lib/active_genie/{config/scoring_config.rb → configs/comparator_config.rb} +1 -1
- data/lib/active_genie/{config/data_extractor_config.rb → configs/extractor_config.rb} +1 -1
- data/lib/active_genie/{config/factory_config.rb → configs/lister_config.rb} +1 -1
- data/lib/active_genie/{config → configs}/llm_config.rb +7 -6
- data/lib/active_genie/{config → configs}/providers_config.rb +1 -1
- data/lib/active_genie/{config/ranking_config.rb → configs/ranker_config.rb} +1 -1
- data/lib/active_genie/{config/battle_config.rb → configs/scorer_config.rb} +1 -1
- data/lib/active_genie/configuration.rb +19 -19
- data/lib/active_genie/errors/invalid_provider_error.rb +1 -1
- data/lib/active_genie/{data_extractor/generalist.rb → extractor/explanation.rb} +11 -11
- data/lib/active_genie/{data_extractor/from_informal.rb → extractor/litote.rb} +8 -8
- data/lib/active_genie/extractor.rb +22 -0
- data/lib/active_genie/{factory → lister}/feud.rb +8 -8
- data/lib/active_genie/lister/juries.prompt.md +20 -0
- data/lib/active_genie/lister/juries.rb +82 -0
- data/lib/active_genie/{factory.rb → lister.rb} +7 -6
- data/lib/active_genie/{clients/providers/anthropic_client.rb → providers/anthropic_provider.rb} +4 -4
- data/lib/active_genie/{clients/providers/base_client.rb → providers/base_provider.rb} +14 -7
- data/lib/active_genie/{clients/providers/deepseek_client.rb → providers/deepseek_provider.rb} +3 -3
- data/lib/active_genie/{clients/providers/google_client.rb → providers/google_provider.rb} +6 -6
- data/lib/active_genie/{clients/providers/openai_client.rb → providers/openai_provider.rb} +3 -3
- data/lib/active_genie/providers/unified_provider.rb +44 -0
- data/lib/active_genie/{ranking/elo_round.rb → ranker/elo.rb} +37 -36
- data/lib/active_genie/ranker/entities/player.rb +124 -0
- data/lib/active_genie/ranker/entities/players.rb +102 -0
- data/lib/active_genie/{ranking → ranker}/free_for_all.rb +9 -9
- data/lib/active_genie/ranker/scoring.rb +68 -0
- data/lib/active_genie/{ranking/ranking.rb → ranker/tournament.rb} +22 -31
- data/lib/active_genie/ranker.rb +32 -0
- data/lib/active_genie/scorer/jury_bench.rb +121 -0
- data/lib/active_genie/scorer.rb +17 -0
- data/lib/active_genie/utils/fiber_by_batch.rb +21 -0
- data/lib/active_genie.rb +9 -9
- data/lib/tasks/test.rake +4 -0
- metadata +67 -52
- data/lib/active_genie/battle.rb +0 -31
- data/lib/active_genie/clients/unified_client.rb +0 -50
- data/lib/active_genie/data_extractor.rb +0 -23
- data/lib/active_genie/ranking/player.rb +0 -122
- data/lib/active_genie/ranking/players_collection.rb +0 -95
- data/lib/active_genie/ranking/ranking_scoring.rb +0 -69
- data/lib/active_genie/ranking.rb +0 -14
- data/lib/active_genie/scoring/generalist.json +0 -9
- data/lib/active_genie/scoring/generalist.rb +0 -119
- data/lib/active_genie/scoring/recommended_reviewers.rb +0 -87
- data/lib/active_genie/scoring.rb +0 -23
- /data/lib/active_genie/{battle → comparator}/fight.json +0 -0
- /data/lib/active_genie/{battle → comparator}/fight.prompt.md +0 -0
- /data/lib/active_genie/{config → configs}/log_config.rb +0 -0
- /data/lib/active_genie/{config → configs}/providers/anthropic_config.rb +0 -0
- /data/lib/active_genie/{config → configs}/providers/deepseek_config.rb +0 -0
- /data/lib/active_genie/{config → configs}/providers/google_config.rb +0 -0
- /data/lib/active_genie/{config → configs}/providers/openai_config.rb +0 -0
- /data/lib/active_genie/{config → configs}/providers/provider_base.rb +0 -0
- /data/lib/active_genie/{data_extractor/generalist.json → extractor/explanation.json} +0 -0
- /data/lib/active_genie/{data_extractor/generalist.prompt.md → extractor/explanation.prompt.md} +0 -0
- /data/lib/active_genie/{data_extractor/from_informal.json → extractor/litote.json} +0 -0
- /data/lib/active_genie/{factory → lister}/feud.json +0 -0
- /data/lib/active_genie/{factory → lister}/feud.prompt.md +0 -0
- /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
|
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
|
23
|
-
winner, loser =
|
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
|
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
|
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::
|
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: :
|
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
|
-
|
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 '
|
3
|
+
require_relative 'entities/players'
|
4
4
|
require_relative 'free_for_all'
|
5
|
-
require_relative '
|
6
|
-
require_relative '
|
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
|
-
#
|
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
|
33
|
-
class
|
32
|
+
module Ranker
|
33
|
+
class Tournament
|
34
34
|
def self.call(...)
|
35
35
|
new(...).call
|
36
36
|
end
|
37
37
|
|
38
|
-
def initialize(
|
39
|
-
@
|
38
|
+
def initialize(players, criteria, juries: [], config: {})
|
39
|
+
@players = Entities::Players.new(players)
|
40
40
|
@criteria = criteria
|
41
|
-
@
|
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
|
-
@
|
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
|
-
|
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
|
-
|
68
|
+
Scoring.call(
|
78
69
|
@players,
|
79
70
|
@criteria,
|
80
|
-
|
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.
|
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
|
-
|
83
|
+
Elo.call(
|
93
84
|
@players,
|
94
85
|
@criteria,
|
95
86
|
config: @config
|
96
87
|
)
|
97
88
|
end
|
98
89
|
|
99
|
-
def
|
100
|
-
@players.
|
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({
|
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
|
129
|
-
@
|
119
|
+
def ranker_id
|
120
|
+
@ranker_id ||= begin
|
130
121
|
player_ids = @players.map(&:id).join(',')
|
131
|
-
|
122
|
+
ranker_unique_key = [player_ids, @criteria, @config.to_json].join('-')
|
132
123
|
|
133
|
-
Digest::MD5.hexdigest(
|
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/
|
7
|
-
require_relative 'active_genie/
|
8
|
-
require_relative 'active_genie/
|
9
|
-
require_relative 'active_genie/
|
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 :
|
13
|
-
autoload :
|
14
|
-
autoload :
|
15
|
-
autoload :
|
16
|
-
autoload :
|
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.
|
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-
|
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
|
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/
|
27
|
-
- lib/active_genie/
|
28
|
-
- lib/active_genie/
|
29
|
-
- lib/active_genie/
|
30
|
-
- lib/active_genie/
|
31
|
-
- lib/active_genie/
|
32
|
-
- lib/active_genie/
|
33
|
-
- lib/active_genie/
|
34
|
-
- lib/active_genie/
|
35
|
-
- lib/active_genie/
|
36
|
-
- lib/active_genie/
|
37
|
-
- lib/active_genie/
|
38
|
-
- lib/active_genie/
|
39
|
-
- lib/active_genie/
|
40
|
-
- lib/active_genie/
|
41
|
-
- lib/active_genie/
|
42
|
-
- lib/active_genie/
|
43
|
-
- lib/active_genie/
|
44
|
-
- lib/active_genie/
|
45
|
-
- lib/active_genie/
|
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/
|
62
|
-
- lib/active_genie/
|
63
|
-
- lib/active_genie/
|
64
|
-
- lib/active_genie/
|
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/
|
67
|
-
- lib/active_genie/
|
68
|
-
- lib/active_genie/
|
69
|
-
- lib/active_genie/
|
70
|
-
- lib/active_genie/
|
71
|
-
- lib/active_genie/
|
72
|
-
- lib/active_genie/
|
73
|
-
- lib/active_genie/
|
74
|
-
- lib/active_genie/
|
75
|
-
- lib/active_genie/
|
76
|
-
- lib/active_genie/
|
77
|
-
- lib/active_genie/scoring
|
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
|
data/lib/active_genie/battle.rb
DELETED
@@ -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
|