active_genie 0.0.24 → 0.0.25

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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +35 -50
  3. data/VERSION +1 -1
  4. data/lib/active_genie/battle/README.md +5 -5
  5. data/lib/active_genie/battle/generalist.rb +132 -0
  6. data/lib/active_genie/battle.rb +6 -5
  7. data/lib/active_genie/clients/providers/anthropic_client.rb +77 -0
  8. data/lib/active_genie/clients/{base_client.rb → providers/base_client.rb} +74 -100
  9. data/lib/active_genie/clients/providers/deepseek_client.rb +91 -0
  10. data/lib/active_genie/clients/providers/google_client.rb +132 -0
  11. data/lib/active_genie/clients/providers/openai_client.rb +96 -0
  12. data/lib/active_genie/clients/unified_client.rb +42 -12
  13. data/lib/active_genie/concerns/loggable.rb +11 -23
  14. data/lib/active_genie/config/battle_config.rb +8 -0
  15. data/lib/active_genie/config/data_extractor_config.rb +23 -0
  16. data/lib/active_genie/config/llm_config.rb +36 -0
  17. data/lib/active_genie/config/log_config.rb +44 -0
  18. data/lib/active_genie/config/providers/anthropic_config.rb +57 -0
  19. data/lib/active_genie/config/providers/deepseek_config.rb +50 -0
  20. data/lib/active_genie/config/providers/google_config.rb +52 -0
  21. data/lib/active_genie/config/providers/openai_config.rb +50 -0
  22. data/lib/active_genie/config/providers/provider_base.rb +89 -0
  23. data/lib/active_genie/config/providers_config.rb +62 -0
  24. data/lib/active_genie/config/ranking_config.rb +21 -0
  25. data/lib/active_genie/config/scoring_config.rb +8 -0
  26. data/lib/active_genie/configuration.rb +51 -28
  27. data/lib/active_genie/data_extractor/README.md +13 -13
  28. data/lib/active_genie/data_extractor/from_informal.rb +54 -48
  29. data/lib/active_genie/data_extractor/generalist.md +12 -0
  30. data/lib/active_genie/data_extractor/generalist.rb +125 -0
  31. data/lib/active_genie/data_extractor.rb +7 -5
  32. data/lib/active_genie/errors/invalid_provider_error.rb +41 -0
  33. data/lib/active_genie/logger.rb +17 -66
  34. data/lib/active_genie/ranking/README.md +31 -1
  35. data/lib/active_genie/ranking/elo_round.rb +107 -104
  36. data/lib/active_genie/ranking/free_for_all.rb +78 -74
  37. data/lib/active_genie/ranking/player.rb +79 -71
  38. data/lib/active_genie/ranking/players_collection.rb +83 -71
  39. data/lib/active_genie/ranking/ranking.rb +71 -94
  40. data/lib/active_genie/ranking/ranking_scoring.rb +71 -50
  41. data/lib/active_genie/ranking.rb +2 -0
  42. data/lib/active_genie/scoring/README.md +4 -4
  43. data/lib/active_genie/scoring/generalist.rb +171 -0
  44. data/lib/active_genie/scoring/recommended_reviewers.rb +70 -71
  45. data/lib/active_genie/scoring.rb +8 -5
  46. data/lib/active_genie.rb +23 -1
  47. data/lib/tasks/benchmark.rake +10 -9
  48. data/lib/tasks/install.rake +3 -1
  49. data/lib/tasks/templates/active_genie.rb +11 -6
  50. metadata +31 -22
  51. data/lib/active_genie/battle/basic.rb +0 -129
  52. data/lib/active_genie/clients/anthropic_client.rb +0 -84
  53. data/lib/active_genie/clients/google_client.rb +0 -135
  54. data/lib/active_genie/clients/helpers/retry.rb +0 -29
  55. data/lib/active_genie/clients/openai_client.rb +0 -98
  56. data/lib/active_genie/configuration/log_config.rb +0 -14
  57. data/lib/active_genie/configuration/providers/anthropic_config.rb +0 -54
  58. data/lib/active_genie/configuration/providers/base_config.rb +0 -85
  59. data/lib/active_genie/configuration/providers/deepseek_config.rb +0 -54
  60. data/lib/active_genie/configuration/providers/google_config.rb +0 -56
  61. data/lib/active_genie/configuration/providers/internal_company_api_config.rb +0 -54
  62. data/lib/active_genie/configuration/providers/openai_config.rb +0 -54
  63. data/lib/active_genie/configuration/providers_config.rb +0 -40
  64. data/lib/active_genie/configuration/runtime_config.rb +0 -35
  65. data/lib/active_genie/data_extractor/basic.rb +0 -101
  66. data/lib/active_genie/scoring/basic.rb +0 -170
@@ -1,129 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../clients/unified_client'
4
-
5
- module ActiveGenie::Battle
6
- # The Basic class provides a foundation for evaluating battles between two players
7
- # using AI-powered evaluation. It determines a winner based on specified criteria,
8
- # analyzing how well each player meets the requirements.
9
- #
10
- # The battle evaluation process compares two players' content against given criteria
11
- # and returns detailed feedback including the winner and reasoning for the decision.
12
- #
13
- # @example Basic usage with two players and criteria
14
- # Basic.call("Player A content", "Player B content", "Evaluate keyword usage and pattern matching")
15
- #
16
- class Basic
17
- def self.call(...)
18
- new(...).call
19
- end
20
-
21
- # @param player_1 [String] The content or submission from the first player
22
- # @param player_2 [String] The content or submission from the second player
23
- # @param criteria [String] The evaluation criteria or rules to assess against
24
- # @param config [Hash] Additional configuration options that modify the battle evaluation behavior
25
- # @return [Hash] The evaluation result containing the winner and reasoning
26
- # @return [String] :winner The winner, either player_1 or player_2
27
- # @return [String] :reasoning Detailed explanation of why the winner was chosen
28
- # @return [String] :what_could_be_changed_to_avoid_draw A suggestion on how to avoid a draw
29
- def initialize(player_1, player_2, criteria, config: {})
30
- @player_1 = player_1
31
- @player_2 = player_2
32
- @criteria = criteria
33
- @config = ActiveGenie::Configuration.to_h(config)
34
- end
35
-
36
- def call
37
- messages = [
38
- { role: 'system', content: PROMPT },
39
- { role: 'user', content: "criteria: #{@criteria}" },
40
- { role: 'user', content: "player_1: #{@player_1}" },
41
- { role: 'user', content: "player_2: #{@player_2}" },
42
- ]
43
-
44
- response = ::ActiveGenie::Clients::UnifiedClient.function_calling(
45
- messages,
46
- FUNCTION,
47
- model_tier: 'lower_tier',
48
- config: @config
49
- )
50
-
51
- ActiveGenie::Logger.debug({
52
- code: :battle,
53
- player_1: @player_1[0..30],
54
- player_2: @player_2[0..30],
55
- criteria: @criteria[0..30],
56
- winner: response['impartial_judge_winner'],
57
- reasoning: response['impartial_judge_winner_reasoning']
58
- })
59
-
60
- response_formatted(response)
61
- end
62
-
63
- private
64
-
65
- def response_formatted(response)
66
- winner = response['impartial_judge_winner']
67
- loser = case response['impartial_judge_winner']
68
- when 'player_1' then 'player_2'
69
- when 'player_2' then 'player_1'
70
- end
71
-
72
- { 'winner' => winner, 'loser' => loser, 'reasoning' => response['impartial_judge_winner_reasoning'] }
73
- end
74
-
75
- PROMPT = <<~PROMPT
76
- Based on two players, player_1 and player_2, they will battle against each other based on criteria. Criteria are vital as they provide a clear metric to compare the players. Follow these criteria strictly.
77
-
78
- # Steps
79
- 1. player_1 presents their strengths and how they meet the criteria. Max of 100 words.
80
- 2. player_2 presents their strengths and how they meet the criteria. Max of 100 words.
81
- 3. player_1 argues why they should be the winner compared to player_2. Max of 100 words.
82
- 4. player_2 counter-argues why they should be the winner compared to player_1. Max of 100 words.
83
- 5. The impartial judge chooses the winner.
84
-
85
- # Output Format
86
- - The impartial judge chooses this player as the winner.
87
-
88
- # Notes
89
- - Avoid resulting in a draw. Use reasoning or make fair assumptions if needed.
90
- - Critically assess each player's adherence to the criteria.
91
- - Clearly communicate the reasoning behind your decision.
92
- PROMPT
93
-
94
- FUNCTION = {
95
- name: 'battle_evaluation',
96
- description: 'Evaluate a battle between player_1 and player_2 using predefined criteria and identify the winner.',
97
- parameters: {
98
- type: "object",
99
- properties: {
100
- player_1_sell_himself: {
101
- type: 'string',
102
- description: 'player_1 presents their strengths and how they meet the criteria. Max of 100 words.',
103
- },
104
- player_2_sell_himself: {
105
- type: 'string',
106
- description: 'player_2 presents their strengths and how they meet the criteria. Max of 100 words.',
107
- },
108
- player_1_arguments: {
109
- type: 'string',
110
- description: 'player_1 arguments for why they should be the winner compared to player_2. Max of 100 words.',
111
- },
112
- player_2_counter: {
113
- type: 'string',
114
- description: 'player_2 counter arguments for why they should be the winner compared to player_1. Max of 100 words.',
115
- },
116
- impartial_judge_winner_reasoning: {
117
- type: 'string',
118
- description: 'The detailed reasoning about why the impartial judge chose the winner. Max of 100 words.',
119
- },
120
- impartial_judge_winner: {
121
- type: 'string',
122
- description: 'Who is the winner based on the impartial judge reasoning?',
123
- enum: ['player_1', 'player_2']
124
- },
125
- }
126
- }
127
- }
128
- end
129
- end
@@ -1,84 +0,0 @@
1
- require 'json'
2
- require 'net/http'
3
- require 'uri'
4
- require_relative './helpers/retry'
5
- require_relative './base_client'
6
-
7
- module ActiveGenie::Clients
8
- # Client for interacting with the Anthropic (Claude) API with json response
9
- class AnthropicClient < BaseClient
10
- class AnthropicError < ClientError; end
11
- class RateLimitError < AnthropicError; end
12
-
13
- ANTHROPIC_VERSION = '2023-06-01'
14
- ANTHROPIC_ENDPOINT = '/v1/messages'
15
-
16
- def initialize(config)
17
- super(config)
18
- end
19
-
20
- # Requests structured JSON output from the Anthropic Claude model based on a schema.
21
- #
22
- # @param messages [Array<Hash>] A list of messages representing the conversation history.
23
- # Each hash should have :role ('user', 'assistant', or 'system') and :content (String).
24
- # Claude uses 'user', 'assistant', and 'system' roles.
25
- # @param function [Hash] A JSON schema definition describing the desired output format.
26
- # @param model_tier [Symbol, nil] A symbolic representation of the model quality/size tier.
27
- # @param config [Hash] Optional configuration overrides:
28
- # - :api_key [String] Override the default API key.
29
- # - :model [String] Override the model name directly.
30
- # - :max_retries [Integer] Max retries for the request.
31
- # - :retry_delay [Integer] Initial delay for retries.
32
- # - :anthropic_version [String] Override the default Anthropic API version.
33
- # @return [Hash, nil] The parsed JSON object matching the schema, or nil if parsing fails or content is empty.
34
- def function_calling(messages, function, model_tier: nil, config: {})
35
- model = config[:runtime][:model] || @app_config.tier_to_model(model_tier)
36
-
37
- system_message = messages.find { |m| m[:role] == 'system' }&.dig(:content) || ''
38
- user_messages = messages.select { |m| m[:role] == 'user' || m[:role] == 'assistant' }
39
- .map { |m| { role: m[:role], content: m[:content] } }
40
-
41
- anthropic_function = function.dup
42
- anthropic_function[:input_schema] = function[:parameters]
43
- anthropic_function.delete(:parameters)
44
-
45
- payload = {
46
- model:,
47
- system: system_message,
48
- messages: user_messages,
49
- tools: [anthropic_function],
50
- tool_choice: { name: anthropic_function[:name], type: 'tool' },
51
- max_tokens: config[:runtime][:max_tokens],
52
- temperature: config[:runtime][:temperature] || 0,
53
- }
54
-
55
- api_key = config[:runtime][:api_key] || @app_config.api_key
56
- headers = {
57
- 'x-api-key': api_key,
58
- 'anthropic-version': config[:anthropic_version] || ANTHROPIC_VERSION
59
- }.compact
60
-
61
- retry_with_backoff(config:) do
62
- start_time = Time.now
63
-
64
- response = post(ANTHROPIC_ENDPOINT, payload, headers: headers, config: config)
65
-
66
- content = response.dig('content', 0, 'input')
67
-
68
- ActiveGenie::Logger.trace({
69
- code: :llm_usage,
70
- input_tokens: response.dig('usage', 'input_tokens'),
71
- output_tokens: response.dig('usage', 'output_tokens'),
72
- total_tokens: response.dig('usage', 'input_tokens') + response.dig('usage', 'output_tokens'),
73
- model: payload[:model],
74
- duration: Time.now - start_time,
75
- usage: response.dig('usage')
76
- })
77
-
78
- ActiveGenie::Logger.trace({code: :function_calling, payload:, parsed_response: content})
79
-
80
- content
81
- end
82
- end
83
- end
84
- end
@@ -1,135 +0,0 @@
1
- require 'json'
2
- require 'net/http'
3
- require 'uri'
4
- require_relative './helpers/retry'
5
- require_relative './base_client'
6
-
7
- module ActiveGenie::Clients
8
- # Client for interacting with the Google Generative Language API.
9
- class GoogleClient < BaseClient
10
- class GoogleError < ClientError; end
11
- class RateLimitError < GoogleError; end
12
-
13
- API_VERSION_PATH = '/v1beta/models'.freeze
14
-
15
- def initialize(config)
16
- super(config)
17
- end
18
-
19
- # Requests structured JSON output from the Google Generative Language model based on a schema.
20
- #
21
- # @param messages [Array<Hash>] A list of messages representing the conversation history.
22
- # Each hash should have :role ('user' or 'model') and :content (String).
23
- # Google Generative Language uses 'user' and 'model' roles.
24
- # @param function [Hash] A JSON schema definition describing the desired output format.
25
- # @param model_tier [Symbol, nil] A symbolic representation of the model quality/size tier.
26
- # @param config [Hash] Optional configuration overrides:
27
- # - :api_key [String] Override the default API key.
28
- # - :model [String] Override the model name directly.
29
- # - :max_retries [Integer] Max retries for the request.
30
- # - :retry_delay [Integer] Initial delay for retries.
31
- # @return [Hash, nil] The parsed JSON object matching the schema, or nil if parsing fails or content is empty.
32
- def function_calling(messages, function, model_tier: nil, config: {})
33
- model = config[:runtime][:model] || @app_config.tier_to_model(model_tier)
34
- api_key = config[:runtime][:api_key] || @app_config.api_key
35
-
36
- contents = convert_messages_to_contents(messages, function)
37
- contents << output_as_json_schema(function)
38
-
39
- payload = {
40
- contents: contents,
41
- generationConfig: {
42
- response_mime_type: "application/json",
43
- temperature: 0.1
44
- }
45
- }
46
-
47
- endpoint = "#{API_VERSION_PATH}/#{model}:generateContent"
48
- params = { key: api_key }
49
- headers = DEFAULT_HEADERS
50
-
51
- retry_with_backoff(config:) do
52
- start_time = Time.now
53
-
54
- response = post(endpoint, payload, headers:, params:, config: config)
55
-
56
- json_string = response&.dig('candidates', 0, 'content', 'parts', 0, 'text')
57
- return nil if json_string.nil? || json_string.empty?
58
-
59
- begin
60
- parsed_response = JSON.parse(json_string)
61
-
62
- # Log usage metrics
63
- usage_metadata = response['usageMetadata'] || {}
64
- prompt_tokens = usage_metadata['promptTokenCount'] || 0
65
- candidates_tokens = usage_metadata['candidatesTokenCount'] || 0
66
- total_tokens = usage_metadata['totalTokenCount'] || (prompt_tokens + candidates_tokens)
67
-
68
- ActiveGenie::Logger.trace({
69
- code: :llm_usage,
70
- input_tokens: prompt_tokens,
71
- output_tokens: candidates_tokens,
72
- total_tokens: total_tokens,
73
- model: model,
74
- duration: Time.now - start_time,
75
- usage: usage_metadata
76
- })
77
-
78
- ActiveGenie::Logger.trace({ code: :function_calling, payload:, parsed_response: })
79
-
80
- normalize_function_output(parsed_response)
81
- rescue JSON::ParserError => e
82
- raise GoogleError, "Failed to parse Google API response: #{e.message} - Content: #{json_string}"
83
- end
84
- end
85
- end
86
-
87
- private
88
-
89
- def normalize_function_output(output)
90
- output = if output.is_a?(Array)
91
- output.dig(0, 'properties') || output.dig(0)
92
- else
93
- output
94
- end
95
-
96
- output.dig('input_schema', 'properties') || output
97
- end
98
-
99
- ROLE_TO_GOOGLE_ROLE = {
100
- user: 'user',
101
- assistant: 'model',
102
- }.freeze
103
-
104
- # Converts standard message format to Google's 'contents' format
105
- # and injects JSON schema instructions.
106
- # @param messages [Array<Hash>] Array of { role: 'user'/'assistant'/'system', content: '...' }
107
- # @param function_schema [Hash] The JSON schema for the desired output.
108
- # @return [Array<Hash>] Array formatted for Google's 'contents' field.
109
- def convert_messages_to_contents(messages, function_schema)
110
- messages.map do |message|
111
- {
112
- role: ROLE_TO_GOOGLE_ROLE[message[:role].to_sym] || 'user',
113
- parts: [{ text: message[:content] }]
114
- }
115
- end
116
- end
117
-
118
- def output_as_json_schema(function_schema)
119
- json_instruction = <<~PROMPT
120
- Generate a JSON object that strictly adheres to the following JSON schema:
121
-
122
- ```json
123
- #{JSON.pretty_generate(function_schema[:parameters])}
124
- ```
125
-
126
- IMPORTANT: Only output the raw JSON object. Do not include any other text, explanations, or markdown formatting like ```json ... ``` wrappers around the final output.
127
- PROMPT
128
-
129
- {
130
- role: 'user',
131
- parts: [{ text: json_instruction }]
132
- }
133
- end
134
- end
135
- end
@@ -1,29 +0,0 @@
1
- MAX_RETRIES = 3
2
- BASE_DELAY = 0.5
3
-
4
- def retry_with_backoff(config: {})
5
- retries = config[:runtime][:max_retries] || MAX_RETRIES
6
-
7
- begin
8
- yield
9
- rescue => e
10
- if retries > 0
11
- ActiveGenie::Logger.warn({ code: :retry_with_backoff, message: "Retrying request after error: #{e.message}. Attempts remaining: #{retries}" })
12
-
13
- retries -= 1
14
- backoff_time = calculate_backoff(MAX_RETRIES - retries)
15
- sleep(backoff_time)
16
- retry
17
- else
18
- raise
19
- end
20
- end
21
- end
22
-
23
- def calculate_backoff(retry_count)
24
- # Exponential backoff with jitter: 2^retry_count + random jitter
25
- # Base delay is 0.5 seconds, doubles each retry, plus up to 0.5 seconds of random jitter
26
- # Simplified example: 0.5, 1, 2, 4, 8, 12, 16, 20, 24, 28, 30 seconds
27
- jitter = rand * BASE_DELAY
28
- [BASE_DELAY * (2 ** retry_count) + jitter, 30].min # Cap at 30 seconds
29
- end
@@ -1,98 +0,0 @@
1
- require 'json'
2
- require 'net/http'
3
-
4
- require_relative './helpers/retry'
5
- require_relative './base_client'
6
-
7
- module ActiveGenie::Clients
8
- class OpenaiClient < BaseClient
9
- class OpenaiError < ClientError; end
10
- class RateLimitError < OpenaiError; end
11
- class InvalidResponseError < StandardError; end
12
-
13
- def initialize(config)
14
- super(config)
15
- end
16
-
17
- # Requests structured JSON output from the OpenAI model based on a schema.
18
- #
19
- # @param messages [Array<Hash>] A list of messages representing the conversation history.
20
- # Each hash should have :role ('user', 'assistant', or 'system') and :content (String).
21
- # @param function [Hash] A JSON schema definition describing the desired output format.
22
- # @param model_tier [Symbol, nil] A symbolic representation of the model quality/size tier.
23
- # @param config [Hash] Optional configuration overrides:
24
- # - :api_key [String] Override the default API key.
25
- # - :model [String] Override the model name directly.
26
- # - :max_retries [Integer] Max retries for the request.
27
- # - :retry_delay [Integer] Initial delay for retries.
28
- # @return [Hash, nil] The parsed JSON object matching the schema, or nil if parsing fails or content is empty.
29
- def function_calling(messages, function, model_tier: nil, config: {})
30
- model = config[:runtime][:model] || @app_config.tier_to_model(model_tier)
31
-
32
- payload = {
33
- messages:,
34
- tools: [{
35
- type: 'function',
36
- function: {
37
- **function,
38
- parameters: {
39
- **function[:parameters],
40
- additionalProperties: false
41
- },
42
- strict: true
43
- }.compact
44
- }],
45
- tool_choice: { type: 'function', function: { name: function[:name] } },
46
- stream: false,
47
- model:,
48
- }
49
-
50
- api_key = config[:runtime][:api_key] || @app_config.api_key
51
- headers = {
52
- 'Authorization': "Bearer #{api_key}"
53
- }.compact
54
-
55
- retry_with_backoff(config:) do
56
- response = request_openai(payload, headers, config:)
57
-
58
- parsed_response = JSON.parse(response.dig('choices', 0, 'message', 'tool_calls', 0, 'function', 'arguments'))
59
- parsed_response = parsed_response.dig('message') || parsed_response
60
-
61
- raise InvalidResponseError, "Invalid response: #{parsed_response}" if parsed_response.nil? || parsed_response.keys.size.zero?
62
-
63
- ActiveGenie::Logger.trace({code: :function_calling, payload:, parsed_response: })
64
-
65
- parsed_response
66
- end
67
- end
68
-
69
-
70
- private
71
-
72
- # Make a request to the OpenAI API
73
- #
74
- # @param payload [Hash] The request payload
75
- # @param headers [Hash] Additional headers
76
- # @param config [Hash] Configuration options
77
- # @return [Hash] The parsed response
78
- def request_openai(payload, headers, config:)
79
- start_time = Time.now
80
-
81
- response = post("/chat/completions", payload, headers: headers, config: config)
82
-
83
- return nil if response.nil?
84
-
85
- ActiveGenie::Logger.trace({
86
- code: :llm_usage,
87
- input_tokens: response.dig('usage', 'prompt_tokens'),
88
- output_tokens: response.dig('usage', 'completion_tokens'),
89
- total_tokens: response.dig('usage', 'total_tokens'),
90
- model: payload[:model],
91
- duration: Time.now - start_time,
92
- usage: response.dig('usage')
93
- })
94
-
95
- response
96
- end
97
- end
98
- end
@@ -1,14 +0,0 @@
1
-
2
- module ActiveGenie::Configuration
3
- class LogConfig
4
- attr_writer :log_level
5
-
6
- def log_level
7
- @log_level ||= :info
8
- end
9
-
10
- def to_h(config = {})
11
- { log_level: }.merge(config)
12
- end
13
- end
14
- end
@@ -1,54 +0,0 @@
1
- require_relative '../../clients/anthropic_client'
2
- require_relative './base_config'
3
-
4
- module ActiveGenie
5
- module Configuration::Providers
6
- # Configuration class for the Anthropic API client.
7
- # Manages API keys, URLs, model selections, and client instantiation.
8
- class AnthropicConfig < BaseConfig
9
- NAME = :anthropic
10
-
11
- # Retrieves the API key.
12
- # Falls back to the ANTHROPIC_API_KEY environment variable if not set.
13
- # @return [String, nil] The API key.
14
- def api_key
15
- @api_key || ENV['ANTHROPIC_API_KEY']
16
- end
17
-
18
- # Retrieves the base API URL for Anthropic API.
19
- # Defaults to 'https://api.anthropic.com'.
20
- # @return [String] The API base URL.
21
- def api_url
22
- @api_url || 'https://api.anthropic.com'
23
- end
24
-
25
- # Lazily initializes and returns an instance of the AnthropicClient.
26
- # Passes itself (the config object) to the client's constructor.
27
- # @return [ActiveGenie::Clients::AnthropicClient] The client instance.
28
- def client
29
- @client ||= ::ActiveGenie::Clients::AnthropicClient.new(self)
30
- end
31
-
32
- # Retrieves the model name designated for the lower tier (e.g., cost-effective, faster).
33
- # Defaults to 'claude-3-haiku'.
34
- # @return [String] The lower tier model name.
35
- def lower_tier_model
36
- @lower_tier_model || 'claude-3-5-haiku-20241022'
37
- end
38
-
39
- # Retrieves the model name designated for the middle tier (e.g., balanced performance).
40
- # Defaults to 'claude-3-sonnet'.
41
- # @return [String] The middle tier model name.
42
- def middle_tier_model
43
- @middle_tier_model || 'claude-3-7-sonnet-20250219'
44
- end
45
-
46
- # Retrieves the model name designated for the upper tier (e.g., most capable).
47
- # Defaults to 'claude-3-opus'.
48
- # @return [String] The upper tier model name.
49
- def upper_tier_model
50
- @upper_tier_model || 'claude-3-opus-20240229'
51
- end
52
- end
53
- end
54
- end
@@ -1,85 +0,0 @@
1
- module ActiveGenie
2
- module Configuration::Providers
3
- class BaseConfig
4
- NAME = :unknown
5
-
6
- attr_writer :api_key, :organization, :api_url, :client,
7
- :lower_tier_model, :middle_tier_model, :upper_tier_model
8
-
9
- # Maps a symbolic tier (:lower_tier, :middle_tier, :upper_tier) to a specific model name.
10
- # Falls back to the lower_tier_model if the tier is nil or unrecognized.
11
- # @param tier [Symbol, String, nil] The symbolic tier name.
12
- # @return [String] The corresponding model name.
13
- def tier_to_model(tier)
14
- {
15
- lower_tier: lower_tier_model,
16
- middle_tier: middle_tier_model,
17
- upper_tier: upper_tier_model
18
- }[tier&.to_sym] || lower_tier_model
19
- end
20
-
21
- # Returns a hash representation of the configuration.
22
- # @param config [Hash] Additional key-value pairs to merge into the hash.
23
- # @return [Hash] The configuration settings as a hash.
24
- def to_h(config = {})
25
- {
26
- name: NAME,
27
- api_key:,
28
- api_url:,
29
- lower_tier_model:,
30
- middle_tier_model:,
31
- upper_tier_model:,
32
- **config
33
- }
34
- end
35
-
36
- # Validates the configuration.
37
- # @return [Boolean] True if the configuration is valid, false otherwise.
38
- def valid?
39
- api_key && api_url
40
- end
41
-
42
- # Retrieves the API key.
43
- # Falls back to the OPENAI_API_KEY environment variable if not set.
44
- # @return [String, nil] The API key.
45
- def api_key
46
- raise NotImplementedError, "Subclasses must implement this method"
47
- end
48
-
49
- # Retrieves the base API URL for OpenAI API.
50
- # Defaults to 'https://api.openai.com/v1'.
51
- # @return [String] The API base URL.
52
- def api_url
53
- raise NotImplementedError, "Subclasses must implement this method"
54
- end
55
-
56
- # Lazily initializes and returns an instance of the OpenaiClient.
57
- # Passes itself (the config object) to the client's constructor.
58
- # @return [ActiveGenie::Clients::OpenaiClient] The client instance.
59
- def client
60
- raise NotImplementedError, "Subclasses must implement this method"
61
- end
62
-
63
- # Retrieves the model name designated for the lower tier (e.g., cost-effective, faster).
64
- # Defaults to 'gpt-4o-mini'.
65
- # @return [String] The lower tier model name.
66
- def lower_tier_model
67
- raise NotImplementedError, "Subclasses must implement this method"
68
- end
69
-
70
- # Retrieves the model name designated for the middle tier (e.g., balanced performance).
71
- # Defaults to 'gpt-4o'.
72
- # @return [String] The middle tier model name.
73
- def middle_tier_model
74
- raise NotImplementedError, "Subclasses must implement this method"
75
- end
76
-
77
- # Retrieves the model name designated for the upper tier (e.g., most capable).
78
- # Defaults to 'o1-preview'.
79
- # @return [String] The upper tier model name.
80
- def upper_tier_model
81
- raise NotImplementedError, "Subclasses must implement this method"
82
- end
83
- end
84
- end
85
- end
@@ -1,54 +0,0 @@
1
- require_relative '../../clients/openai_client'
2
- require_relative './base_config'
3
-
4
- module ActiveGenie
5
- module Configuration::Providers
6
- # Configuration class for the DeepSeek API client.
7
- # Manages API keys, organization IDs, URLs, model selections, and client instantiation.
8
- class DeepseekConfig < BaseConfig
9
- NAME = :deepseek
10
-
11
- # Retrieves the API key.
12
- # Falls back to the DEEPSEEK_API_KEY environment variable if not set.
13
- # @return [String, nil] The API key.
14
- def api_key
15
- @api_key || ENV['DEEPSEEK_API_KEY']
16
- end
17
-
18
- # Retrieves the base API URL for DeepSeek API.
19
- # Defaults to 'https://api.deepseek.com/v1'.
20
- # @return [String] The API base URL.
21
- def api_url
22
- @api_url || 'https://api.deepseek.com/v1'
23
- end
24
-
25
- # Lazily initializes and returns an instance of the OpenaiClient.
26
- # Passes itself (the config object) to the client's constructor.
27
- # @return [ActiveGenie::Clients::OpenaiClient] The client instance.
28
- def client
29
- @client ||= ::ActiveGenie::Clients::OpenaiClient.new(self)
30
- end
31
-
32
- # Retrieves the model name designated for the lower tier (e.g., cost-effective, faster).
33
- # Defaults to 'deepseek-chat'.
34
- # @return [String] The lower tier model name.
35
- def lower_tier_model
36
- @lower_tier_model || 'deepseek-chat'
37
- end
38
-
39
- # Retrieves the model name designated for the middle tier (e.g., balanced performance).
40
- # Defaults to 'deepseek-chat'.
41
- # @return [String] The middle tier model name.
42
- def middle_tier_model
43
- @middle_tier_model || 'deepseek-chat'
44
- end
45
-
46
- # Retrieves the model name designated for the upper tier (e.g., most capable).
47
- # Defaults to 'deepseek-reasoner'.
48
- # @return [String] The upper tier model name.
49
- def upper_tier_model
50
- @upper_tier_model || 'deepseek-reasoner'
51
- end
52
- end
53
- end
54
- end