active_genie 0.30.3 → 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.
- checksums.yaml +4 -4
- data/README.md +7 -5
- data/VERSION +1 -1
- data/lib/active_genie/comparator/debate.rb +13 -36
- data/lib/active_genie/comparator/fight.rb +3 -3
- data/lib/active_genie/comparator.rb +0 -2
- data/lib/active_genie/configs/base_config.rb +25 -0
- data/lib/active_genie/configs/extractor_config.rb +6 -14
- data/lib/active_genie/configs/lister_config.rb +6 -10
- data/lib/active_genie/configs/llm_config.rb +12 -26
- data/lib/active_genie/configs/log_config.rb +19 -16
- data/lib/active_genie/configs/providers/anthropic_config.rb +16 -1
- data/lib/active_genie/configs/providers/deepseek_config.rb +8 -2
- data/lib/active_genie/configs/providers/google_config.rb +8 -2
- data/lib/active_genie/configs/providers/openai_config.rb +8 -2
- data/lib/active_genie/configs/providers/provider_base.rb +22 -31
- data/lib/active_genie/configs/providers_config.rb +35 -16
- data/lib/active_genie/configs/ranker_config.rb +6 -12
- data/lib/active_genie/configuration.rb +23 -60
- data/lib/active_genie/{ranker/entities → entities}/player.rb +4 -0
- data/lib/active_genie/{ranker/entities → entities}/players.rb +1 -1
- data/lib/active_genie/entities/result.rb +29 -0
- data/lib/active_genie/errors/provider_server_error.rb +8 -5
- data/lib/active_genie/errors/without_available_provider_error.rb +39 -0
- data/lib/active_genie/extractor/data.json +9 -0
- data/lib/active_genie/extractor/data.prompt.md +12 -0
- data/lib/active_genie/extractor/data.rb +71 -0
- data/lib/active_genie/extractor/explanation.rb +19 -47
- data/lib/active_genie/extractor/litote.rb +8 -14
- data/lib/active_genie/extractor.rb +5 -0
- data/lib/active_genie/lister/feud.json +5 -1
- data/lib/active_genie/lister/feud.rb +10 -24
- data/lib/active_genie/lister/juries.rb +14 -20
- data/lib/active_genie/logger.rb +16 -28
- data/lib/active_genie/providers/anthropic_provider.rb +11 -5
- data/lib/active_genie/providers/base_provider.rb +15 -17
- data/lib/active_genie/providers/deepseek_provider.rb +17 -9
- data/lib/active_genie/providers/google_provider.rb +10 -4
- data/lib/active_genie/providers/openai_provider.rb +6 -4
- data/lib/active_genie/providers/unified_provider.rb +47 -17
- data/lib/active_genie/ranker/elo.rb +41 -36
- data/lib/active_genie/ranker/free_for_all.rb +45 -28
- data/lib/active_genie/ranker/scoring.rb +20 -11
- data/lib/active_genie/ranker/tournament.rb +23 -35
- data/lib/active_genie/scorer/jury_bench.rb +15 -29
- data/lib/active_genie/utils/base_module.rb +34 -0
- data/lib/active_genie/utils/call_wrapper.rb +20 -0
- data/lib/active_genie/utils/deep_merge.rb +12 -0
- data/lib/active_genie/utils/fiber_by_batch.rb +2 -2
- data/lib/active_genie/utils/text_case.rb +18 -0
- data/lib/active_genie.rb +16 -18
- data/lib/tasks/test.rake +61 -3
- metadata +19 -8
- data/lib/active_genie/configs/comparator_config.rb +0 -10
- data/lib/active_genie/configs/scorer_config.rb +0 -10
|
@@ -12,14 +12,12 @@ module ActiveGenie
|
|
|
12
12
|
def initialize(players, criteria, juries: [], config: nil)
|
|
13
13
|
@players = Entities::Players.new(players)
|
|
14
14
|
@criteria = criteria
|
|
15
|
-
@
|
|
15
|
+
@initial_config = config
|
|
16
16
|
@juries = Array(juries).compact.uniq
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def call
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
ActiveGenie::FiberByBatch.call(players_without_score, config: @config) do |player|
|
|
20
|
+
ActiveGenie::FiberByBatch.call(players_without_score, config:) do |player|
|
|
23
21
|
player.score = generate_score(player)
|
|
24
22
|
end
|
|
25
23
|
end
|
|
@@ -31,14 +29,16 @@ module ActiveGenie
|
|
|
31
29
|
end
|
|
32
30
|
|
|
33
31
|
def generate_score(player)
|
|
34
|
-
|
|
32
|
+
result = ActiveGenie::Scorer.by_jury_bench(
|
|
35
33
|
player.content,
|
|
36
34
|
@criteria,
|
|
37
35
|
@juries,
|
|
38
|
-
config:
|
|
39
|
-
)
|
|
36
|
+
config:
|
|
37
|
+
)
|
|
38
|
+
score = result.data.to_i
|
|
39
|
+
reasoning = result.reasoning
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
ActiveGenie.logger.call({ code: :new_score, player_id: player.id, score:, reasoning: }, config:)
|
|
42
42
|
|
|
43
43
|
score
|
|
44
44
|
end
|
|
@@ -48,9 +48,9 @@ module ActiveGenie
|
|
|
48
48
|
response = ActiveGenie::Lister.juries(
|
|
49
49
|
[@players.sample.content, @players.sample.content].join("\n\n"),
|
|
50
50
|
@criteria,
|
|
51
|
-
config:
|
|
51
|
+
config:
|
|
52
52
|
)
|
|
53
|
-
|
|
53
|
+
ActiveGenie.logger.call({ code: :new_juries, juries: response }, config:)
|
|
54
54
|
response
|
|
55
55
|
end
|
|
56
56
|
end
|
|
@@ -58,11 +58,20 @@ module ActiveGenie
|
|
|
58
58
|
def ranker_scoring_id
|
|
59
59
|
@ranker_scoring_id ||= begin
|
|
60
60
|
player_ids = players_without_score.map(&:id).join(',')
|
|
61
|
-
ranker_unique_key = [player_ids, @criteria
|
|
61
|
+
ranker_unique_key = [player_ids, @criteria].join('-')
|
|
62
62
|
|
|
63
63
|
"#{Digest::MD5.hexdigest(ranker_unique_key)}-scoring"
|
|
64
64
|
end
|
|
65
65
|
end
|
|
66
|
+
|
|
67
|
+
def config
|
|
68
|
+
@config ||= ActiveGenie.new_configuration(
|
|
69
|
+
DeepMerge.call(
|
|
70
|
+
@initial_config,
|
|
71
|
+
{ log: { additional_context: { ranker_scoring_id: } } }
|
|
72
|
+
)
|
|
73
|
+
)
|
|
74
|
+
end
|
|
66
75
|
end
|
|
67
76
|
end
|
|
68
77
|
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative 'entities/players'
|
|
3
|
+
require_relative '../entities/players'
|
|
4
4
|
require_relative 'free_for_all'
|
|
5
5
|
require_relative 'elo'
|
|
6
6
|
require_relative 'scoring'
|
|
@@ -30,33 +30,30 @@ require_relative 'scoring'
|
|
|
30
30
|
# @return [Hash] Final ranked player results
|
|
31
31
|
module ActiveGenie
|
|
32
32
|
module Ranker
|
|
33
|
-
class Tournament
|
|
34
|
-
def self.call(...)
|
|
35
|
-
new(...).call
|
|
36
|
-
end
|
|
37
|
-
|
|
33
|
+
class Tournament < ActiveGenie::BaseModule
|
|
38
34
|
def initialize(players, criteria, juries: [], config: {})
|
|
39
35
|
@players = Entities::Players.new(players)
|
|
40
36
|
@criteria = criteria
|
|
41
37
|
@juries = Array(juries).compact.uniq
|
|
42
|
-
|
|
38
|
+
super(config:)
|
|
43
39
|
end
|
|
44
40
|
|
|
45
41
|
def call
|
|
46
|
-
@config.log.additional_context = { ranker_id: }
|
|
47
|
-
|
|
48
42
|
set_initial_player_scores!
|
|
49
43
|
eliminate_obvious_bad_players!
|
|
50
44
|
|
|
51
45
|
while @players.elo_eligible?
|
|
52
|
-
|
|
46
|
+
elo_result = run_elo_round!
|
|
53
47
|
eliminate_lower_tier_players!
|
|
54
|
-
rebalance_players!(
|
|
48
|
+
rebalance_players!(elo_result)
|
|
55
49
|
end
|
|
56
50
|
|
|
57
51
|
run_free_for_all!
|
|
58
52
|
|
|
59
|
-
|
|
53
|
+
ActiveGenie::Result.new(
|
|
54
|
+
data: sorted_players.map(&:content),
|
|
55
|
+
metadata: @players.map(&:to_h)
|
|
56
|
+
)
|
|
60
57
|
end
|
|
61
58
|
|
|
62
59
|
ELIMINATION_VARIATION = 'variation_too_high'
|
|
@@ -65,12 +62,7 @@ module ActiveGenie
|
|
|
65
62
|
private
|
|
66
63
|
|
|
67
64
|
def set_initial_player_scores!
|
|
68
|
-
Scoring.call(
|
|
69
|
-
@players,
|
|
70
|
-
@criteria,
|
|
71
|
-
juries: @juries,
|
|
72
|
-
config: @config
|
|
73
|
-
)
|
|
65
|
+
Scoring.call(@players, @criteria, juries: @juries, config:)
|
|
74
66
|
end
|
|
75
67
|
|
|
76
68
|
def eliminate_obvious_bad_players!
|
|
@@ -80,50 +72,46 @@ module ActiveGenie
|
|
|
80
72
|
end
|
|
81
73
|
|
|
82
74
|
def run_elo_round!
|
|
83
|
-
Elo.call(
|
|
84
|
-
@players,
|
|
85
|
-
@criteria,
|
|
86
|
-
config: @config
|
|
87
|
-
)
|
|
75
|
+
Elo.call(@players, @criteria, config:)
|
|
88
76
|
end
|
|
89
77
|
|
|
90
78
|
def eliminate_lower_tier_players!
|
|
91
79
|
@players.calc_lower_tier.each { |player| player.eliminated = ELIMINATION_RELEGATION }
|
|
92
80
|
end
|
|
93
81
|
|
|
94
|
-
def rebalance_players!(
|
|
95
|
-
return if
|
|
82
|
+
def rebalance_players!(elo_result)
|
|
83
|
+
return if elo_result.metadata[:highest_elo_diff].negative?
|
|
96
84
|
|
|
97
85
|
@players.eligible.each do |player|
|
|
98
|
-
next if
|
|
86
|
+
next if elo_result.metadata[:players_in_round].include?(player.id)
|
|
99
87
|
|
|
100
|
-
player.elo +=
|
|
88
|
+
player.elo += elo_result.metadata[:highest_elo_diff]
|
|
101
89
|
end
|
|
102
90
|
end
|
|
103
91
|
|
|
104
92
|
def run_free_for_all!
|
|
105
|
-
FreeForAll.call(
|
|
106
|
-
@players,
|
|
107
|
-
@criteria,
|
|
108
|
-
config: @config
|
|
109
|
-
)
|
|
93
|
+
FreeForAll.call(@players, @criteria, config:)
|
|
110
94
|
end
|
|
111
95
|
|
|
112
96
|
def sorted_players
|
|
113
97
|
players = @players.sorted
|
|
114
|
-
|
|
98
|
+
ActiveGenie.logger.call({ ranker_id:, code: :ranker_final, players: players.map(&:to_h) }, config:)
|
|
115
99
|
|
|
116
|
-
players
|
|
100
|
+
players
|
|
117
101
|
end
|
|
118
102
|
|
|
119
103
|
def ranker_id
|
|
120
104
|
@ranker_id ||= begin
|
|
121
105
|
player_ids = @players.map(&:id).join(',')
|
|
122
|
-
ranker_unique_key = [player_ids, @criteria
|
|
106
|
+
ranker_unique_key = [player_ids, @criteria].join('-')
|
|
123
107
|
|
|
124
108
|
Digest::MD5.hexdigest(ranker_unique_key)
|
|
125
109
|
end
|
|
126
110
|
end
|
|
111
|
+
|
|
112
|
+
def module_config
|
|
113
|
+
{ log: { additional_context: { ranker_id: } } }
|
|
114
|
+
end
|
|
127
115
|
end
|
|
128
116
|
end
|
|
129
117
|
end
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative '../providers/unified_provider'
|
|
4
|
+
require_relative '../utils/text_case'
|
|
4
5
|
|
|
5
6
|
module ActiveGenie
|
|
6
7
|
module Scorer
|
|
@@ -17,7 +18,7 @@ module ActiveGenie
|
|
|
17
18
|
# @example Usage with automatic jury recommendation
|
|
18
19
|
# JuryBench.call("Sample text", "Evaluate technical accuracy")
|
|
19
20
|
#
|
|
20
|
-
class JuryBench
|
|
21
|
+
class JuryBench < ActiveGenie::BaseModule
|
|
21
22
|
# @param text [String] The text content to be evaluated
|
|
22
23
|
# @param criteria [String] The evaluation criteria or rubric to assess against
|
|
23
24
|
# @param juries [Array<String>] Optional list of specific juries. If empty,
|
|
@@ -26,15 +27,11 @@ module ActiveGenie
|
|
|
26
27
|
# @return [Hash] The evaluation result containing the scores and reasoning
|
|
27
28
|
# @return [Number] :final_score The final score of the text based on the criteria and juries
|
|
28
29
|
# @return [String] :final_reasoning Detailed explanation of why the final score was reached
|
|
29
|
-
def self.call(...)
|
|
30
|
-
new(...).call
|
|
31
|
-
end
|
|
32
|
-
|
|
33
30
|
def initialize(text, criteria, juries = [], config: {})
|
|
34
31
|
@text = text
|
|
35
32
|
@criteria = criteria
|
|
36
33
|
@param_juries = Array(juries).compact.uniq
|
|
37
|
-
|
|
34
|
+
super(config:)
|
|
38
35
|
end
|
|
39
36
|
|
|
40
37
|
def call
|
|
@@ -44,24 +41,17 @@ module ActiveGenie
|
|
|
44
41
|
{ role: 'user', content: "Text to score: #{@text}" }
|
|
45
42
|
]
|
|
46
43
|
|
|
47
|
-
|
|
44
|
+
provider_response = ::ActiveGenie::Providers::UnifiedProvider.function_calling(
|
|
48
45
|
messages,
|
|
49
46
|
build_function,
|
|
50
47
|
config:
|
|
51
48
|
)
|
|
52
49
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
criteria: @criteria[0..30],
|
|
59
|
-
juries: juries,
|
|
60
|
-
score: result['final_score'],
|
|
61
|
-
reasoning: result['final_reasoning']
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
result
|
|
50
|
+
ActiveGenie::Result.new(
|
|
51
|
+
data: provider_response['final_score'] || 0,
|
|
52
|
+
reasoning: provider_response['final_reasoning'],
|
|
53
|
+
metadata: provider_response
|
|
54
|
+
)
|
|
65
55
|
end
|
|
66
56
|
|
|
67
57
|
PROMPT = File.read(File.join(__dir__, 'jury_bench.prompt.md'))
|
|
@@ -84,11 +74,12 @@ module ActiveGenie
|
|
|
84
74
|
@properties ||= begin
|
|
85
75
|
tmp = {}
|
|
86
76
|
juries.each do |jury|
|
|
87
|
-
|
|
77
|
+
jury_key = ActiveGenie::TextCase.underscore(jury)
|
|
78
|
+
tmp["#{jury_key}_reasoning"] = {
|
|
88
79
|
type: 'string',
|
|
89
80
|
description: "The reasoning of the Scorer process by #{jury}."
|
|
90
81
|
}
|
|
91
|
-
tmp["#{
|
|
82
|
+
tmp["#{jury_key}_score"] = {
|
|
92
83
|
type: 'number',
|
|
93
84
|
description: "The score given by #{jury}.",
|
|
94
85
|
min: 0,
|
|
@@ -113,17 +104,12 @@ module ActiveGenie
|
|
|
113
104
|
@juries ||= if @param_juries.any?
|
|
114
105
|
@param_juries
|
|
115
106
|
else
|
|
116
|
-
::ActiveGenie::Lister::Juries.call(@text, @criteria, config:)
|
|
107
|
+
::ActiveGenie::Lister::Juries.call(@text, @criteria, config:).data
|
|
117
108
|
end
|
|
118
109
|
end
|
|
119
110
|
|
|
120
|
-
def
|
|
121
|
-
|
|
122
|
-
c = ActiveGenie.configuration.merge(@initial_config)
|
|
123
|
-
c.llm.recommended_model = 'deepseek-chat' unless c.llm.recommended_model
|
|
124
|
-
|
|
125
|
-
c
|
|
126
|
-
end
|
|
111
|
+
def module_config
|
|
112
|
+
{ llm: { recommended_model: 'deepseek-chat' } }
|
|
127
113
|
end
|
|
128
114
|
end
|
|
129
115
|
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'call_wrapper'
|
|
4
|
+
|
|
5
|
+
module ActiveGenie
|
|
6
|
+
class BaseModule
|
|
7
|
+
prepend CallWrapper
|
|
8
|
+
|
|
9
|
+
def self.call(...)
|
|
10
|
+
new(...).call
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def initialize(config: {})
|
|
14
|
+
@initial_config = config || {}
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def call
|
|
18
|
+
raise NotImplementedError, 'Subclasses must implement the `call` method'
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def config
|
|
22
|
+
@config ||= ActiveGenie.new_configuration(
|
|
23
|
+
ActiveGenie::DeepMerge.call(
|
|
24
|
+
@initial_config.to_h,
|
|
25
|
+
module_config
|
|
26
|
+
)
|
|
27
|
+
)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def module_config
|
|
31
|
+
{}
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveGenie
|
|
4
|
+
module CallWrapper
|
|
5
|
+
def call(*, &)
|
|
6
|
+
response = super # Call the original method
|
|
7
|
+
|
|
8
|
+
if defined?(config)
|
|
9
|
+
ActiveGenie.logger.call(
|
|
10
|
+
{
|
|
11
|
+
code: self.class.name,
|
|
12
|
+
response: response.to_h
|
|
13
|
+
}, config:
|
|
14
|
+
)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
response
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveGenie
|
|
4
|
+
module DeepMerge
|
|
5
|
+
module_function
|
|
6
|
+
|
|
7
|
+
def call(first_hash, second_hash)
|
|
8
|
+
merger = proc { |_key, v1, v2| v1.is_a?(Hash) && v2.is_a?(Hash) ? v1.merge(v2, &merger) : v2 }
|
|
9
|
+
first_hash.to_h.merge(second_hash.to_h, &merger)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -8,9 +8,9 @@ module ActiveGenie
|
|
|
8
8
|
|
|
9
9
|
def call(items, config:, &block)
|
|
10
10
|
items.each_slice(config.llm.max_fibers).to_a.each do |batch|
|
|
11
|
-
Async do
|
|
11
|
+
Async do |task|
|
|
12
12
|
tasks = batch.map do |item|
|
|
13
|
-
|
|
13
|
+
task.async { block.call(item) }
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
tasks.each(&:wait)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveGenie
|
|
4
|
+
module TextCase
|
|
5
|
+
module_function
|
|
6
|
+
|
|
7
|
+
def underscore(camel_cased_word)
|
|
8
|
+
return camel_cased_word.to_s.dup unless /[A-Z-]|::/.match?(camel_cased_word)
|
|
9
|
+
|
|
10
|
+
word = camel_cased_word.to_s.gsub('::', '/')
|
|
11
|
+
word.gsub!(/(?<=[A-Z])(?=[A-Z][a-z])|(?<=[a-z\d])(?=[A-Z])/, '_')
|
|
12
|
+
word.tr!('-', '_')
|
|
13
|
+
word.tr!(' ', '_')
|
|
14
|
+
word.downcase!
|
|
15
|
+
word
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
data/lib/active_genie.rb
CHANGED
|
@@ -3,10 +3,9 @@
|
|
|
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/configs/providers/deepseek_config'
|
|
6
|
+
require_relative 'active_genie/entities/result'
|
|
7
|
+
require_relative 'active_genie/utils/base_module'
|
|
8
|
+
require_relative 'active_genie/utils/deep_merge'
|
|
10
9
|
|
|
11
10
|
module ActiveGenie
|
|
12
11
|
autoload :Extractor, File.join(__dir__, 'active_genie/extractor')
|
|
@@ -23,27 +22,26 @@ module ActiveGenie
|
|
|
23
22
|
end
|
|
24
23
|
|
|
25
24
|
def configuration
|
|
26
|
-
@configuration ||=
|
|
25
|
+
@configuration ||= Configuration.new
|
|
27
26
|
end
|
|
28
27
|
|
|
29
|
-
def
|
|
30
|
-
return
|
|
28
|
+
def new_configuration(new_config)
|
|
29
|
+
return new_config if new_config.instance_of?(Configuration)
|
|
31
30
|
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
Configuration.new(
|
|
32
|
+
DeepMerge.call(@configuration.to_h, new_config)
|
|
33
|
+
)
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
config = Configuration.new
|
|
36
|
+
def logger
|
|
37
|
+
@logger ||= Logger.new
|
|
38
|
+
end
|
|
40
39
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
config.providers.add(Config::Providers::AnthropicConfig)
|
|
44
|
-
config.providers.add(Config::Providers::DeepseekConfig)
|
|
40
|
+
def load_tasks
|
|
41
|
+
return unless defined?(Rake)
|
|
45
42
|
|
|
46
|
-
|
|
43
|
+
Rake::Task.define_task(:environment)
|
|
44
|
+
Dir.glob(File.join(__dir__, 'tasks', '*.rake')).each { |r| load r }
|
|
47
45
|
end
|
|
48
46
|
end
|
|
49
47
|
end
|
data/lib/tasks/test.rake
CHANGED
|
@@ -6,13 +6,71 @@ namespace :test do
|
|
|
6
6
|
Rake::TestTask.new(:unit) do |t|
|
|
7
7
|
t.pattern = 'test/unit/**/*_test.rb'
|
|
8
8
|
end
|
|
9
|
+
desc 'Run unit tests'
|
|
10
|
+
task unit: :reset_env
|
|
9
11
|
|
|
10
12
|
Rake::TestTask.new(:integration) do |t|
|
|
11
|
-
t.pattern = 'test/integration/**/*_test.rb'
|
|
13
|
+
t.pattern = 'test/integration/**/*_test.rb'
|
|
12
14
|
end
|
|
15
|
+
desc 'Run integration tests like install rails'
|
|
16
|
+
task integration: :reset_env
|
|
13
17
|
|
|
18
|
+
desc 'Run all tests (unit and integration)'
|
|
14
19
|
task default: %i[unit integration]
|
|
20
|
+
|
|
21
|
+
desc 'Reset environment variables for API keys'
|
|
22
|
+
task :reset_env do
|
|
23
|
+
reset_environment_variables
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
desc 'Run all tests (unit and integration) or a specific test file'
|
|
28
|
+
task :test, [:file_path] do |_t, args|
|
|
29
|
+
reset_environment_variables
|
|
30
|
+
|
|
31
|
+
if args[:file_path]
|
|
32
|
+
file_path, line_number = args[:file_path].split(':')
|
|
33
|
+
|
|
34
|
+
if line_number
|
|
35
|
+
test_name = find_test_name_at_line(file_path, line_number.to_i)
|
|
36
|
+
|
|
37
|
+
if test_name
|
|
38
|
+
sh "ruby -Itest #{file_path} --name #{test_name}"
|
|
39
|
+
else
|
|
40
|
+
puts "Warning: Could not find test method at line #{line_number}"
|
|
41
|
+
ruby "-Itest #{file_path}"
|
|
42
|
+
end
|
|
43
|
+
else
|
|
44
|
+
ruby "-Itest #{file_path}"
|
|
45
|
+
end
|
|
46
|
+
else
|
|
47
|
+
Rake::Task['test:unit'].invoke
|
|
48
|
+
Rake::Task['test:integration'].invoke
|
|
49
|
+
end
|
|
15
50
|
end
|
|
16
51
|
|
|
17
|
-
|
|
18
|
-
|
|
52
|
+
def find_test_name_at_line(file_path, line_number)
|
|
53
|
+
return nil unless File.exist?(file_path)
|
|
54
|
+
|
|
55
|
+
lines = File.readlines(file_path)
|
|
56
|
+
return nil if line_number > lines.length
|
|
57
|
+
|
|
58
|
+
(line_number - 1).downto(0) do |i|
|
|
59
|
+
line = lines[i]
|
|
60
|
+
if line =~ /^\s*def\s+(test_\w+)/
|
|
61
|
+
return Regexp.last_match(1)
|
|
62
|
+
elsif line =~ /^\s*test\s+['"](.+?)['"]\s+do/
|
|
63
|
+
test_desc = Regexp.last_match(1)
|
|
64
|
+
return "/#{test_desc}/"
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
nil
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def reset_environment_variables
|
|
72
|
+
ENV['OPENAI_API_KEY'] = nil
|
|
73
|
+
ENV['GEMINI_API_KEY'] = nil
|
|
74
|
+
ENV['ANTHROPIC_API_KEY'] = nil
|
|
75
|
+
ENV['DEEPSEEK_API_KEY'] = nil
|
|
76
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: active_genie
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.30.
|
|
4
|
+
version: 0.30.8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Radamés Roriz
|
|
@@ -24,8 +24,11 @@ dependencies:
|
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
25
|
version: '2.0'
|
|
26
26
|
description: |
|
|
27
|
-
ActiveGenie is
|
|
28
|
-
|
|
27
|
+
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.
|
|
28
|
+
This reliability is built on three core pillars:
|
|
29
|
+
- Custom Benchmarking: Testing for consistency with every new version and model update.
|
|
30
|
+
- Reasoning Prompting: Utilizing human reasoning techniques (like debate and jury review) to control a model's reasoning.
|
|
31
|
+
- Overfitting Prompts: Highly specialized, and potentially model-specific, prompt for each module's purpose.
|
|
29
32
|
email:
|
|
30
33
|
- radames@roriz.dev
|
|
31
34
|
executables: []
|
|
@@ -43,7 +46,7 @@ files:
|
|
|
43
46
|
- lib/active_genie/comparator/fight.json
|
|
44
47
|
- lib/active_genie/comparator/fight.prompt.md
|
|
45
48
|
- lib/active_genie/comparator/fight.rb
|
|
46
|
-
- lib/active_genie/configs/
|
|
49
|
+
- lib/active_genie/configs/base_config.rb
|
|
47
50
|
- lib/active_genie/configs/extractor_config.rb
|
|
48
51
|
- lib/active_genie/configs/lister_config.rb
|
|
49
52
|
- lib/active_genie/configs/llm_config.rb
|
|
@@ -55,13 +58,19 @@ files:
|
|
|
55
58
|
- lib/active_genie/configs/providers/provider_base.rb
|
|
56
59
|
- lib/active_genie/configs/providers_config.rb
|
|
57
60
|
- lib/active_genie/configs/ranker_config.rb
|
|
58
|
-
- lib/active_genie/configs/scorer_config.rb
|
|
59
61
|
- lib/active_genie/configuration.rb
|
|
62
|
+
- lib/active_genie/entities/player.rb
|
|
63
|
+
- lib/active_genie/entities/players.rb
|
|
64
|
+
- lib/active_genie/entities/result.rb
|
|
60
65
|
- lib/active_genie/errors/invalid_log_output_error.rb
|
|
61
66
|
- lib/active_genie/errors/invalid_model_error.rb
|
|
62
67
|
- lib/active_genie/errors/invalid_provider_error.rb
|
|
63
68
|
- lib/active_genie/errors/provider_server_error.rb
|
|
69
|
+
- lib/active_genie/errors/without_available_provider_error.rb
|
|
64
70
|
- lib/active_genie/extractor.rb
|
|
71
|
+
- lib/active_genie/extractor/data.json
|
|
72
|
+
- lib/active_genie/extractor/data.prompt.md
|
|
73
|
+
- lib/active_genie/extractor/data.rb
|
|
65
74
|
- lib/active_genie/extractor/explanation.json
|
|
66
75
|
- lib/active_genie/extractor/explanation.prompt.md
|
|
67
76
|
- lib/active_genie/extractor/explanation.rb
|
|
@@ -82,15 +91,17 @@ files:
|
|
|
82
91
|
- lib/active_genie/providers/unified_provider.rb
|
|
83
92
|
- lib/active_genie/ranker.rb
|
|
84
93
|
- lib/active_genie/ranker/elo.rb
|
|
85
|
-
- lib/active_genie/ranker/entities/player.rb
|
|
86
|
-
- lib/active_genie/ranker/entities/players.rb
|
|
87
94
|
- lib/active_genie/ranker/free_for_all.rb
|
|
88
95
|
- lib/active_genie/ranker/scoring.rb
|
|
89
96
|
- lib/active_genie/ranker/tournament.rb
|
|
90
97
|
- lib/active_genie/scorer.rb
|
|
91
98
|
- lib/active_genie/scorer/jury_bench.prompt.md
|
|
92
99
|
- lib/active_genie/scorer/jury_bench.rb
|
|
100
|
+
- lib/active_genie/utils/base_module.rb
|
|
101
|
+
- lib/active_genie/utils/call_wrapper.rb
|
|
102
|
+
- lib/active_genie/utils/deep_merge.rb
|
|
93
103
|
- lib/active_genie/utils/fiber_by_batch.rb
|
|
104
|
+
- lib/active_genie/utils/text_case.rb
|
|
94
105
|
- lib/tasks/benchmark.rake
|
|
95
106
|
- lib/tasks/install.rake
|
|
96
107
|
- lib/tasks/templates/active_genie.rb
|
|
@@ -120,5 +131,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
120
131
|
requirements: []
|
|
121
132
|
rubygems_version: 3.6.9
|
|
122
133
|
specification_version: 4
|
|
123
|
-
summary: 'The Lodash for GenAI:
|
|
134
|
+
summary: 'The Lodash for GenAI: Consistent + Model-Agnostic'
|
|
124
135
|
test_files: []
|