active_genie 0.25.2 → 0.26.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a47b22f8cc9f75c2538e99ea16e5116970651e93d7e085ac224e0c7cb5b94131
4
- data.tar.gz: c516cb0b89906f21d29c6be507b1fde213bf3c0cd0d4b303af2d5297636f0f7f
3
+ metadata.gz: ad223ae84ac62d9375af07ba18dca9152296cac5e7c432a6fd07118107c4ab6e
4
+ data.tar.gz: 5faa2d7ad89cf2200296f94892470248a544d86cd37880191777226f121d9cf4
5
5
  SHA512:
6
- metadata.gz: ca01c7dc21605c869147aa07c4fc3104da04d0bf0d22ac37e0e0040047d74e3d1a1a843fa5b18592c5f641783cd4c1962cad5dc71c38d408f12d05368362d144
7
- data.tar.gz: bd3377cfe1a2452ba4e838306c11405c73e57bf437281a5d0888fe0482aa0efbe2f8b381ec1b8e22d09221b6d67b582be9a2ccaf853ac7b20727783646e4e29f
6
+ metadata.gz: 2a6bd702967d5948e37fed48a9b92d0c2061b4893579e67d526cb3bf9b71b44889b7a5a457d5c78a768f74d6cc650beb17a52c1ce00bf1a5c7d2dc553d88b866
7
+ data.tar.gz: 845fecdb4f036ce4a97b99ea54d0f5600544d6ce0b052da99e4533e4555d774ce09bff1dc037d3752f30aabe69acc5b9362ab77eaf17c62b8ebb5244e02b5df8
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.25.2
1
+ 0.26.5
@@ -30,9 +30,7 @@ module ActiveGenie
30
30
  temperature: @config.llm.temperature || 0
31
31
  }
32
32
 
33
- retry_with_backoff do
34
- request(payload).dig('content', 0, 'input')
35
- end
33
+ request(payload).dig('content', 0, 'input')
36
34
  end
37
35
 
38
36
  ANTHROPIC_ENDPOINT = '/v1/messages'
@@ -81,16 +81,13 @@ module ActiveGenie
81
81
 
82
82
  response = http_request(request, uri)
83
83
 
84
- case response
85
- when Net::HTTPSuccess
86
- parsed_response = parse_response(response)
84
+ raise ClientError, "Unexpected response: #{response.code} - #{response.body}" unless response.is_a?(Net::HTTPSuccess)
87
85
 
88
- log_request_details(uri:, request:, response:, start_time:, parsed_response:)
86
+ parsed_response = parse_response(response)
89
87
 
90
- parsed_response
91
- else
92
- raise ClientError, "Unexpected response: #{response.code} - #{response.body}"
93
- end
88
+ log_request_details(uri:, request:, response:, start_time:, parsed_response:)
89
+
90
+ parsed_response
94
91
  end
95
92
 
96
93
  # Create and configure an HTTP client
@@ -103,7 +100,10 @@ module ActiveGenie
103
100
  http.verify_mode = OpenSSL::SSL::VERIFY_PEER
104
101
  http.read_timeout = @config.llm.read_timeout || DEFAULT_TIMEOUT
105
102
  http.open_timeout = @config.llm.open_timeout || DEFAULT_OPEN_TIMEOUT
106
- http.request(request)
103
+
104
+ retry_with_backoff do
105
+ http.request(request)
106
+ end
107
107
  end
108
108
 
109
109
  # Apply headers to the request
@@ -170,7 +170,7 @@ module ActiveGenie
170
170
 
171
171
  begin
172
172
  yield
173
- rescue Net::HTTPError, ClientError => e
173
+ rescue Net::OpenTimeout, Net::ReadTimeout, ClientError => e
174
174
  raise if retries > max_retries
175
175
 
176
176
  sleep_time = retry_delay * (2**retries)
@@ -25,18 +25,16 @@ module ActiveGenie
25
25
  model:
26
26
  }
27
27
 
28
- retry_with_backoff do
29
- response = request(payload)
28
+ response = request(payload)
30
29
 
31
- if response.nil? || response.keys.empty?
32
- raise InvalidResponseError,
33
- "Invalid response: #{response}"
34
- end
30
+ if response.nil? || response.keys.empty?
31
+ raise InvalidResponseError,
32
+ "Invalid response: #{response}"
33
+ end
35
34
 
36
- ActiveGenie::Logger.call({ code: :function_calling, fine_tune: true, payload:, response: })
35
+ ActiveGenie::Logger.call({ code: :function_calling, fine_tune: true, payload:, response: })
37
36
 
38
- response
39
- end
37
+ response
40
38
  end
41
39
 
42
40
  private
@@ -29,14 +29,12 @@ module ActiveGenie
29
29
  }
30
30
  params = { key: provider_config.api_key }
31
31
 
32
- retry_with_backoff do
33
- response = request(payload, params)
32
+ response = request(payload, params)
34
33
 
35
- json_string = response&.dig('candidates', 0, 'content', 'parts', 0, 'text')
36
- return nil if json_string.nil? || json_string.empty?
34
+ json_string = response&.dig('candidates', 0, 'content', 'parts', 0, 'text')
35
+ return nil if json_string.nil? || json_string.empty?
37
36
 
38
- normalize_response(json_string)
39
- end
37
+ normalize_response(json_string)
40
38
  end
41
39
 
42
40
  API_VERSION_PATH = 'v1beta/models'
@@ -25,15 +25,13 @@ module ActiveGenie
25
25
  model:
26
26
  }
27
27
 
28
- retry_with_backoff do
29
- response = request(payload)
28
+ response = request(payload)
30
29
 
31
- raise InvalidResponseError, "Invalid response: #{response}" if response.nil? || response.keys.empty?
30
+ raise InvalidResponseError, "Invalid response: #{response}" if response.nil? || response.keys.empty?
32
31
 
33
- ActiveGenie::Logger.call({ code: :function_calling, fine_tune: true, payload:, response: })
32
+ ActiveGenie::Logger.call({ code: :function_calling, fine_tune: true, payload:, response: })
34
33
 
35
- response
36
- end
34
+ response
37
35
  end
38
36
 
39
37
  private
@@ -24,25 +24,27 @@ module ActiveGenie
24
24
  end
25
25
 
26
26
  def output_call(log)
27
- output.call(log)
27
+ output&.call(log)
28
28
 
29
29
  Array(@observers).each do |obs|
30
30
  next unless obs[:scope].all? { |key, value| log[key.to_sym] == value }
31
31
 
32
- obs[:observer].call(log)
32
+ obs[:observer]&.call(log)
33
33
  rescue StandardError => e
34
34
  ActiveGenie::Logger.call(code: :observer_error, **obs, error: e.message)
35
35
  end
36
36
  end
37
37
 
38
- def add_observer(observers: [], scope: nil, &block)
38
+ def add_observer(observers: [], scope: {}, &block)
39
39
  @observers ||= []
40
40
 
41
- raise ArgumentError, 'Scope must be a hash' unless scope.is_a?(Hash)
41
+ raise ArgumentError, 'Scope must be a hash' if scope && !scope.is_a?(Hash)
42
42
 
43
- @observers << { observer: block, scope: scope || {} } if block_given?
43
+ @observers << { observer: block, scope: } if block_given?
44
44
  Array(observers).each do |observer|
45
- @observers << { observer:, scope: scope || {} }
45
+ next unless observer.respond_to?(:call)
46
+
47
+ @observers << { observer:, scope: }
46
48
  end
47
49
  end
48
50
 
@@ -37,8 +37,8 @@ module ActiveGenie
37
37
  def call
38
38
  response = Generalist.call(@text, data_to_extract_with_litote, config: @config)
39
39
 
40
- if response['message_litote']
41
- response = Generalist.call(response['litote_rephrased'], @data_to_extract, config: @config)
40
+ if response[:message_litote]
41
+ response = Generalist.call(response[:litote_rephrased], @data_to_extract, config: @config)
42
42
  end
43
43
 
44
44
  response
@@ -21,13 +21,15 @@ module ActiveGenie
21
21
  log
22
22
  end
23
23
 
24
- def with_context(context)
24
+ def with_context(context, observer: nil)
25
25
  @context ||= {}
26
26
  begin
27
27
  @context = @context.merge(context)
28
+ config.add_observer(observers: [observer])
28
29
  yield if block_given?
29
30
  ensure
30
31
  @context.delete_if { |key, _| context.key?(key) }
32
+ config.remove_observer([observer])
31
33
  end
32
34
  end
33
35
 
@@ -17,11 +17,13 @@ module ActiveGenie
17
17
  @config = config
18
18
  @tmp_defenders = []
19
19
  @total_tokens = 0
20
- @previous_elo = players.to_h { |player| [player.id, player.elo] }
20
+ @previous_elo = {}
21
21
  @previous_highest_elo = @defender_tier.max_by(&:elo).elo
22
22
  end
23
23
 
24
24
  def call
25
+ @previous_elo = @players.to_h { |player| [player.id, player.elo] }
26
+
25
27
  ActiveGenie::Logger.with_context(log_context) do
26
28
  matches.each do |player_a, player_b|
27
29
  # TODO: battle can take a while, can be parallelized
@@ -38,14 +40,17 @@ module ActiveGenie
38
40
 
39
41
  private
40
42
 
41
- def save_previous_elo
42
- @previous_elo = @players.to_h { |player| [player.id, player.elo] }
43
- end
44
-
45
43
  def matches
44
+ match_keys = {}
45
+
46
46
  @relegation_tier.each_with_object([]) do |attack_player, matches|
47
47
  BATTLE_PER_PLAYER.times do
48
- matches << [attack_player, next_defense_player].shuffle
48
+ defense_player = next_defense_player
49
+
50
+ next if match_keys["#{attack_player.id}_#{defense_player.id}"]
51
+
52
+ match_keys["#{attack_player.id}_#{defense_player.id}"] = true
53
+ matches << [attack_player, defense_player]
49
54
  end
50
55
  end
51
56
  end
@@ -130,7 +135,7 @@ module ActiveGenie
130
135
  elo_diffs = players_in_round.map do |player|
131
136
  [player.id, player.elo - @previous_elo[player.id]]
132
137
  end
133
- elo_diffs.sort_by { |_, diff| -diff }.to_h
138
+ elo_diffs.sort_by { |_, diff| -(diff || 0) }.to_h
134
139
  end
135
140
 
136
141
  def log_observer(log)
@@ -18,7 +18,7 @@ module ActiveGenie
18
18
  end
19
19
 
20
20
  def call
21
- ActiveGenie::Logger.with_context(log_context, observer: method(:log_observer)) do
21
+ ActiveGenie::Logger.with_context(log_context, observer: ->(log) { log_observer(log) }) do
22
22
  matches.each do |player_a, player_b|
23
23
  winner, loser = battle(player_a, player_b)
24
24
 
@@ -10,8 +10,6 @@ module ActiveGenie
10
10
  @params[:content] ||= @params
11
11
  end
12
12
 
13
- attr_accessor :rank
14
-
15
13
  def content
16
14
  @content ||= @params[:content]
17
15
  end
@@ -29,7 +27,7 @@ module ActiveGenie
29
27
  end
30
28
 
31
29
  def elo
32
- @elo ||= @params[:elo]
30
+ @elo = @elo || @params[:elo] || generate_elo_by_score
33
31
  end
34
32
 
35
33
  def ffa_win_count
@@ -56,7 +54,7 @@ module ActiveGenie
56
54
 
57
55
  def elo=(value)
58
56
  ActiveGenie::Logger.call({ code: :new_elo, player_id: id, elo: value }) if value != @elo
59
- @elo = value
57
+ @elo = value || BASE_ELO
60
58
  end
61
59
 
62
60
  def eliminated=(value)
@@ -80,7 +78,7 @@ module ActiveGenie
80
78
  end
81
79
 
82
80
  def ffa_score
83
- (@ffa_win_count * 3) + @ffa_draw_count
81
+ (ffa_win_count * 3) + ffa_draw_count
84
82
  end
85
83
 
86
84
  def sort_value
@@ -93,7 +91,9 @@ module ActiveGenie
93
91
 
94
92
  def to_h
95
93
  {
96
- id:, name:, content:, score:, elo:,
94
+ id:, name:, content:,
95
+
96
+ score:, elo:,
97
97
  ffa_win_count:, ffa_lose_count:, ffa_draw_count:,
98
98
  eliminated:, ffa_score:, sort_value:
99
99
  }
@@ -121,7 +121,9 @@ module ActiveGenie
121
121
  private
122
122
 
123
123
  def generate_elo_by_score
124
- BASE_ELO + ((@score || 0) - 50)
124
+ return BASE_ELO if @score.nil?
125
+
126
+ BASE_ELO + (@score - 50)
125
127
  end
126
128
  end
127
129
  end
@@ -52,17 +52,11 @@ module ActiveGenie
52
52
  end
53
53
 
54
54
  def sorted
55
- sorted_players = @players.sort_by { |p| -p.sort_value }
56
- sorted_players.each_with_index { |p, i| p.rank = i + 1 }
57
- sorted_players
55
+ @players.sort_by { |p| -p.sort_value }
58
56
  end
59
57
 
60
58
  def to_json(*_args)
61
- to_h.to_json
62
- end
63
-
64
- def to_h
65
- sorted.map(&:to_h)
59
+ @players.map(&:to_h).to_json
66
60
  end
67
61
 
68
62
  def method_missing(...)
@@ -90,7 +84,11 @@ module ActiveGenie
90
84
  def tier_size
91
85
  size = (eligible_size / 3).ceil
92
86
 
93
- size.clamp(10, eligible_size - 10)
87
+ if eligible_size < 10
88
+ (eligible_size / 2).ceil
89
+ else
90
+ size.clamp(10, eligible_size - 10)
91
+ end
94
92
  end
95
93
  end
96
94
  end
@@ -20,8 +20,7 @@ module ActiveGenie
20
20
  ActiveGenie::Logger.with_context(log_context) do
21
21
  @reviewers = generate_reviewers
22
22
 
23
- players_to_score = players_without_score
24
- players_to_score.each do |player|
23
+ players_without_score.each do |player|
25
24
  player.score = generate_score(player)
26
25
  end
27
26
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_genie
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.25.2
4
+ version: 0.26.5
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-06-01 00:00:00.000000000 Z
11
+ date: 2025-06-03 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |
14
14
  The lodash for GenAI, stop reinventing the wheel