active_genie 0.28.2 → 0.29.0

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: a2cb129cd0e5a4f5f0f1daf6ed3cb26a4dab4d10cb56bbfcc419656c2797347a
4
- data.tar.gz: df1fe343d28aeb72f8fe30dc53bdecd860e8bd44ae009a086c7ad502da77bfd8
3
+ metadata.gz: 9d304f581f4ebf42ba3fe4095d319c7d450b554b7af7c9a86ff4c34af1d6b771
4
+ data.tar.gz: 749952b6fcf70903b247987d739ab8d2a55e40fd70873ed65f9eedf64fde9abd
5
5
  SHA512:
6
- metadata.gz: 1449245c23bcc2c5f3c4266712c67b202e4e2c6724ee9f283bd81d76b2daedc4bc06ee524ed8d959d13f31062b393b5f7cfb7f46721888efb8d89bbd4d8a12b3
7
- data.tar.gz: 649a20ee71c55d8486d8264b641974c3222baa477133d6924ba039f2ef24f9185d2b60b2f37f7d2ff498b87aaed09b78815feb3bbc52c92613eb810de2c59c2c
6
+ metadata.gz: cb9fccff5748c42bdf51dbd4b57041bd6de75f69cafa10cf77246eb6e3e67c4204436187fb595afd70af610b841b103bfd79f5040019e58a779a6eae8b17802e
7
+ data.tar.gz: 1a958882621ce6a9f5d20b2383e8be76bee47e776d30a8f007f7d20516aefb01c936dd56f315cc3e1d1c0255d4eafc7ad9d80e477edf308b2acd5392489198db
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.28.2
1
+ 0.29.0
@@ -1,4 +1,5 @@
1
- Create a dynamic, back-and-forth verbal match between two fighters, given their names and preferred fighting styles. In this match, fighters do not physically battle, instead, they engage in a spoken confrontation, each describing and boasting about their fighting style, how their techniques would outmaneuver, counter, or overwhelm the other's approach. Ensure that each verbal exchange details:
1
+ Create a dynamic, back-and-forth verbal match between two fighters, given their names and preferred fighting styles. Criteria are vital as they provide a clear metric to compare the players. Follow these criteria strictly.
2
+ In this match, fighters do not physically battle, instead, they engage in a spoken confrontation, each describing and boasting about their fighting style, how their techniques would outmaneuver, counter, or overwhelm the other's approach. Each moviment must be focused in how it will help the fighter to reach the criteria as fully as possible. Ensure that each verbal exchange details:
2
3
  - The technique or strategy the speaker would use.
3
4
  - How that move is superior to the opponent’s last stated tactic.
4
5
  - How the opponent might respond, and what reply the speaker would have.
@@ -10,7 +11,8 @@ Explicit steps:
10
11
  - Alternate dialogue, with each fighter explaining their tactical move, then the intended counter or rebuttal, going at least two cycles each.
11
12
  - Ensure reasoning (the logic or explanation behind each technique and counter) always precedes the conclusion or actual "move" or taunt.
12
13
  - Close with a final statement or taunt from each fighter, maintaining the competitive tone.
13
- - Make the dialogue lively and imaginative, using language consistent with fighters boasting or challenging each other.
14
+ - Make the dialogue lively and imaginative.
15
+ - Make sure follow these criteria strictly.
14
16
 
15
17
  Output Format:
16
18
  - Structure as a script, with each turn labeled by the fighter’s name.
@@ -23,6 +25,7 @@ Example:
23
25
  Example Input:
24
26
  Fighter One: Master Crane, Style: Crane Kung Fu
25
27
  Fighter Two: Iron Ox, Style: Ox Bull Charge
28
+ Criteria: Fair fight 1v1 using only techniques from their style.
26
29
 
27
30
  Example Output:
28
31
  Master Crane: My Crane Kung Fu relies on lightness and precision, striking where your heavy blows simply can't reach. Your Ox Bull Charge is powerful, but too direct, I'd dance aside and tap your pressure points before you even turn.
@@ -38,4 +41,4 @@ Important Considerations:
38
41
  - Always have the reasoning/strategy before the actual attack or boast in each utterance.
39
42
  - Maintain the turn order and competitive dialogue style.
40
43
 
41
- *Reminder: The main objective is to script an imaginative, turn-based verbal contest between two stylized fighters, with detailed reasoning and taunts about their style advantages, as instructed above.*
44
+ *Reminder: The main objective is to script an imaginative, turn-based verbal contest between two fighters, with detailed reasoning and taunts about their style advantages until reach the criteria, as instructed above.*
@@ -16,9 +16,9 @@ module ActiveGenie
16
16
  def call
17
17
  messages = [
18
18
  { role: 'system', content: PROMPT },
19
- { role: 'user', content: "criteria: #{@criteria}" },
20
19
  { role: 'user', content: "player_a: #{@player_a}" },
21
- { role: 'user', content: "player_b: #{@player_b}" }
20
+ { role: 'user', content: "player_b: #{@player_b}" },
21
+ { role: 'user', content: "criteria: #{@criteria}" }
22
22
  ]
23
23
 
24
24
  response = ::ActiveGenie::Clients::UnifiedClient.function_calling(
@@ -40,9 +40,9 @@ module ActiveGenie
40
40
  def call
41
41
  messages = [
42
42
  { role: 'system', content: PROMPT },
43
- { role: 'user', content: "criteria: #{@criteria}" },
44
43
  { role: 'user', content: "player_a: #{@player_a}" },
45
- { role: 'user', content: "player_b: #{@player_b}" }
44
+ { role: 'user', content: "player_b: #{@player_b}" },
45
+ { role: 'user', content: "criteria: #{@criteria}" }
46
46
  ]
47
47
 
48
48
  response = ::ActiveGenie::Clients::UnifiedClient.function_calling(
@@ -16,6 +16,10 @@ module ActiveGenie
16
16
  Generalist.call(...)
17
17
  end
18
18
 
19
+ def battle(...)
20
+ Generalist.call(...)
21
+ end
22
+
19
23
  def compare(...)
20
24
  Generalist.call(...)
21
25
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveGenie
4
+ module Config
5
+ class FactoryConfig
6
+ attr_accessor :number_of_items
7
+
8
+ def initialize
9
+ @number_of_items = 5
10
+ end
11
+
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
16
+ end
17
+ end
18
+ end
19
+ end
@@ -7,6 +7,7 @@ require_relative 'config/scoring_config'
7
7
  require_relative 'config/data_extractor_config'
8
8
  require_relative 'config/battle_config'
9
9
  require_relative 'config/llm_config'
10
+ require_relative 'config/factory_config'
10
11
 
11
12
  module ActiveGenie
12
13
  class Configuration
@@ -34,6 +35,10 @@ module ActiveGenie
34
35
  @battle ||= Config::BattleConfig.new
35
36
  end
36
37
 
38
+ def factory
39
+ @factory ||= Config::FactoryConfig.new
40
+ end
41
+
37
42
  def llm
38
43
  @llm ||= Config::LlmConfig.new
39
44
  end
@@ -42,7 +47,7 @@ module ActiveGenie
42
47
  @logger ||= ActiveGenie::Logger.new(log_config: log)
43
48
  end
44
49
 
45
- SUB_CONFIGS = %w[log providers llm ranking scoring data_extractor battle].freeze
50
+ SUB_CONFIGS = %w[log providers llm ranking scoring data_extractor battle factory].freeze
46
51
 
47
52
  def merge(config_params = {})
48
53
  return config_params if config_params.is_a?(Configuration)
@@ -80,6 +85,6 @@ module ActiveGenie
80
85
  end
81
86
  end
82
87
 
83
- attr_writer :log, :providers, :ranking, :scoring, :data_extractor, :battle, :llm, :logger
88
+ attr_writer(*SUB_CONFIGS, :logger)
84
89
  end
85
90
  end
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "feud_items_generator",
3
+ "description": "Generate a list of items for a given theme.",
4
+ "parameters": {
5
+ "type": "object",
6
+ "properties": {
7
+ "theme": {
8
+ "type": "string",
9
+ "description": "The theme for the feud."
10
+ },
11
+ "items": {
12
+ "type": "array",
13
+ "description": "The list of items for the feud.",
14
+ "items": {
15
+ "type": "string"
16
+ }
17
+ }
18
+ },
19
+ "required": ["theme", "items"]
20
+ }
21
+ }
@@ -0,0 +1,20 @@
1
+ Emulate the game "Family Feud": For a given theme, reason about the general public's most common answers impersonating a survey of average people's opinions and generate an ordered, survey-style answer list.
2
+
3
+ - Before producing the answer list, internally consider: If a group of average people were surveyed on this theme, which answers would be mentioned most frequently?.
4
+
5
+ # Output Format
6
+
7
+ A numbered list in plain text
8
+
9
+ # Example
10
+
11
+ Example for the theme "Favorite Fast Foods":
12
+ 1. Pizza
13
+ 2. Hamburgers
14
+ 3. Hot Dogs
15
+ 4. French Fries
16
+
17
+ # Notes
18
+
19
+ - Always impersonate a "Family Feud" survey: order is critical most likely answers should come first.
20
+ - Judge each item by their general public reputation and cultural impact.
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../clients/unified_client'
4
+
5
+ module ActiveGenie
6
+ module Factory
7
+ # The Factory::Feud class provides a foundation for generating a list of items for a given theme
8
+ #
9
+ # @example Feud usage with two players and criteria
10
+ # Feud.call("Industries that are most likely to be affected by climate change")
11
+ #
12
+ class Feud
13
+ def self.call(...)
14
+ new(...).call
15
+ end
16
+
17
+ # @param theme [String] The theme for the feud
18
+ # @param config [Hash] Additional configuration options that modify the battle evaluation behavior
19
+ # @return [Array of strings] List of items
20
+ def initialize(theme, config: {})
21
+ @theme = theme
22
+ @config = ActiveGenie.configuration.merge(config)
23
+ end
24
+
25
+ # @return [Array] The list of items
26
+ def call
27
+ messages = [
28
+ { role: 'system', content: PROMPT },
29
+ { role: 'system', content: "List #{number_of_items} top items." },
30
+ { role: 'user', content: "theme: #{@theme}" }
31
+ ]
32
+
33
+ response = ::ActiveGenie::Clients::UnifiedClient.function_calling(
34
+ messages,
35
+ FUNCTION,
36
+ config: @config
37
+ )
38
+
39
+ log_feud(response)
40
+ response['items']
41
+ end
42
+
43
+ PROMPT = File.read(File.join(__dir__, 'feud.prompt.md'))
44
+ FUNCTION = JSON.parse(File.read(File.join(__dir__, 'feud.json')), symbolize_names: true)
45
+
46
+ private
47
+
48
+ def number_of_items
49
+ @config.factory.number_of_items
50
+ end
51
+
52
+ def log_feud(response)
53
+ @config.logger.call(
54
+ code: :feud,
55
+ theme: @theme[0..30],
56
+ items: response['items'].map { |item| item[0..30] }
57
+ )
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'factory/feud'
4
+
5
+ module ActiveGenie
6
+ module Factory
7
+ module_function
8
+
9
+ def feud(...)
10
+ Feud.call(...)
11
+ end
12
+
13
+ def list(...)
14
+ Feud.call(...)
15
+ end
16
+
17
+ def call(...)
18
+ Feud.call(...)
19
+ end
20
+ end
21
+ end
@@ -106,7 +106,7 @@ module ActiveGenie
106
106
  end
107
107
 
108
108
  def reviewers
109
- @reviewers ||= if @param_reviewers.count.positive?
109
+ @reviewers ||= if @param_reviewers.any?
110
110
  @param_reviewers
111
111
  else
112
112
  result = RecommendedReviewers.call(@text, @criteria, config: @config)
data/lib/active_genie.rb CHANGED
@@ -13,6 +13,7 @@ module ActiveGenie
13
13
  autoload :Battle, File.join(__dir__, 'active_genie/battle')
14
14
  autoload :Scoring, File.join(__dir__, 'active_genie/scoring')
15
15
  autoload :Ranking, File.join(__dir__, 'active_genie/ranking')
16
+ autoload :Factory, File.join(__dir__, 'active_genie/factory')
16
17
 
17
18
  VERSION = File.read(File.expand_path('../VERSION', __dir__)).strip
18
19
 
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.28.2
4
+ version: 0.29.0
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-07-12 00:00:00.000000000 Z
11
+ date: 2025-07-16 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |
14
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.
@@ -38,6 +38,7 @@ files:
38
38
  - lib/active_genie/clients/unified_client.rb
39
39
  - lib/active_genie/config/battle_config.rb
40
40
  - lib/active_genie/config/data_extractor_config.rb
41
+ - lib/active_genie/config/factory_config.rb
41
42
  - lib/active_genie/config/llm_config.rb
42
43
  - lib/active_genie/config/log_config.rb
43
44
  - lib/active_genie/config/providers/anthropic_config.rb
@@ -57,6 +58,10 @@ files:
57
58
  - lib/active_genie/data_extractor/generalist.rb
58
59
  - lib/active_genie/errors/invalid_log_output_error.rb
59
60
  - 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
60
65
  - lib/active_genie/logger.rb
61
66
  - lib/active_genie/ranking.rb
62
67
  - lib/active_genie/ranking/elo_round.rb