active_genie 0.25.1 → 0.26.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 +4 -4
- data/README.md +5 -5
- data/VERSION +1 -1
- data/lib/active_genie/battle/README.md +7 -7
- data/lib/active_genie/battle/generalist.json +36 -0
- data/lib/active_genie/battle/generalist.md +16 -0
- data/lib/active_genie/battle/generalist.rb +16 -69
- data/lib/active_genie/clients/providers/anthropic_client.rb +61 -40
- data/lib/active_genie/clients/providers/base_client.rb +44 -57
- data/lib/active_genie/clients/providers/deepseek_client.rb +57 -52
- data/lib/active_genie/clients/providers/google_client.rb +58 -60
- data/lib/active_genie/clients/providers/openai_client.rb +52 -55
- data/lib/active_genie/clients/unified_client.rb +4 -4
- data/lib/active_genie/config/battle_config.rb +2 -0
- data/lib/active_genie/config/llm_config.rb +3 -1
- data/lib/active_genie/config/log_config.rb +38 -14
- data/lib/active_genie/config/providers/anthropic_config.rb +2 -2
- data/lib/active_genie/config/providers/deepseek_config.rb +2 -2
- data/lib/active_genie/config/providers/google_config.rb +2 -2
- data/lib/active_genie/config/providers/openai_config.rb +2 -2
- data/lib/active_genie/config/providers_config.rb +4 -4
- data/lib/active_genie/config/scoring_config.rb +2 -0
- data/lib/active_genie/configuration.rb +14 -8
- data/lib/active_genie/data_extractor/from_informal.json +11 -0
- data/lib/active_genie/data_extractor/from_informal.rb +5 -13
- data/lib/active_genie/data_extractor/generalist.json +9 -0
- data/lib/active_genie/data_extractor/generalist.rb +12 -11
- data/lib/active_genie/errors/invalid_log_output_error.rb +19 -0
- data/lib/active_genie/logger.rb +13 -5
- data/lib/active_genie/{concerns → ranking/concerns}/loggable.rb +2 -5
- data/lib/active_genie/ranking/elo_round.rb +30 -28
- data/lib/active_genie/ranking/free_for_all.rb +30 -22
- data/lib/active_genie/ranking/player.rb +53 -19
- data/lib/active_genie/ranking/players_collection.rb +17 -13
- data/lib/active_genie/ranking/ranking.rb +21 -20
- data/lib/active_genie/ranking/ranking_scoring.rb +2 -20
- data/lib/active_genie/scoring/generalist.json +9 -0
- data/lib/active_genie/scoring/generalist.md +46 -0
- data/lib/active_genie/scoring/generalist.rb +13 -65
- data/lib/active_genie/scoring/recommended_reviewers.rb +2 -2
- metadata +11 -4
@@ -3,88 +3,93 @@
|
|
3
3
|
require 'json'
|
4
4
|
require 'net/http'
|
5
5
|
|
6
|
-
require_relative '
|
6
|
+
require_relative 'base_client'
|
7
7
|
|
8
8
|
module ActiveGenie
|
9
9
|
module Clients
|
10
10
|
class DeepseekClient < BaseClient
|
11
|
-
class DeepseekError < ClientError; end
|
12
|
-
class RateLimitError < DeepseekError; end
|
13
11
|
class InvalidResponseError < StandardError; end
|
14
12
|
|
15
|
-
# Requests structured JSON output from the
|
13
|
+
# Requests structured JSON output from the Deepseek model based on a schema.
|
16
14
|
#
|
17
15
|
# @param messages [Array<Hash>] A list of messages representing the conversation history.
|
18
16
|
# Each hash should have :role ('user', 'assistant', or 'system') and :content (String).
|
19
17
|
# @param function [Hash] A JSON schema definition describing the desired output format.
|
20
18
|
# @return [Hash, nil] The parsed JSON object matching the schema, or nil if parsing fails or content is empty.
|
21
19
|
def function_calling(messages, function)
|
22
|
-
model = @config.llm.model || @config.providers.deepseek.tier_to_model(@config.llm.model_tier)
|
23
|
-
|
24
20
|
payload = {
|
25
21
|
messages:,
|
26
|
-
tools: [
|
27
|
-
type: 'function',
|
28
|
-
function: {
|
29
|
-
**function,
|
30
|
-
parameters: {
|
31
|
-
**function[:parameters],
|
32
|
-
additionalProperties: false
|
33
|
-
},
|
34
|
-
strict: true
|
35
|
-
}.compact
|
36
|
-
}],
|
22
|
+
tools: [function_to_tool(function)],
|
37
23
|
tool_choice: { type: 'function', function: { name: function[:name] } },
|
38
24
|
stream: false,
|
39
25
|
model:
|
40
26
|
}
|
41
27
|
|
42
|
-
|
43
|
-
'Authorization': "Bearer #{@config.providers.deepseek.api_key}"
|
44
|
-
}.compact
|
45
|
-
|
46
|
-
retry_with_backoff do
|
47
|
-
response = request_deepseek(payload, headers)
|
28
|
+
response = request(payload)
|
48
29
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
raise InvalidResponseError,
|
54
|
-
"Invalid response: #{parsed_response}"
|
55
|
-
end
|
30
|
+
if response.nil? || response.keys.empty?
|
31
|
+
raise InvalidResponseError,
|
32
|
+
"Invalid response: #{response}"
|
33
|
+
end
|
56
34
|
|
57
|
-
|
35
|
+
ActiveGenie::Logger.call({ code: :function_calling, fine_tune: true, payload:, response: })
|
58
36
|
|
59
|
-
|
60
|
-
end
|
37
|
+
response
|
61
38
|
end
|
62
39
|
|
63
40
|
private
|
64
41
|
|
65
|
-
|
66
|
-
#
|
67
|
-
# @param payload [Hash] The request payload
|
68
|
-
# @param headers [Hash] Additional headers
|
69
|
-
# @return [Hash] The parsed response
|
70
|
-
def request_deepseek(payload, headers)
|
71
|
-
start_time = Time.now
|
72
|
-
url = "#{@config.providers.deepseek.api_url}/chat/completions"
|
73
|
-
|
42
|
+
def request(payload)
|
74
43
|
response = post(url, payload, headers: headers)
|
44
|
+
|
75
45
|
return nil if response.nil?
|
76
46
|
|
77
|
-
ActiveGenie::Logger.call(
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
47
|
+
ActiveGenie::Logger.call(
|
48
|
+
{
|
49
|
+
code: :llm_usage,
|
50
|
+
input_tokens: response.dig('usage', 'prompt_tokens'),
|
51
|
+
output_tokens: response.dig('usage', 'completion_tokens'),
|
52
|
+
total_tokens: response.dig('usage', 'total_tokens'),
|
53
|
+
model:,
|
54
|
+
usage: response['usage']
|
55
|
+
}
|
56
|
+
)
|
57
|
+
|
58
|
+
parsed_response = JSON.parse(response.dig('choices', 0, 'message', 'tool_calls', 0, 'function', 'arguments'))
|
59
|
+
parsed_response['message'] || parsed_response
|
60
|
+
end
|
61
|
+
|
62
|
+
def function_to_tool(function)
|
63
|
+
{
|
64
|
+
type: 'function',
|
65
|
+
function: {
|
66
|
+
**function,
|
67
|
+
parameters: {
|
68
|
+
**function[:parameters],
|
69
|
+
additionalProperties: false
|
70
|
+
},
|
71
|
+
strict: true
|
72
|
+
}.compact
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
def model
|
77
|
+
@config.llm.model || provider_config.tier_to_model(@config.llm.model_tier)
|
78
|
+
end
|
86
79
|
|
87
|
-
|
80
|
+
def url
|
81
|
+
"#{provider_config.api_url}/chat/completions"
|
82
|
+
end
|
83
|
+
|
84
|
+
def headers
|
85
|
+
{
|
86
|
+
Authorization: "Bearer #{provider_config.api_key}",
|
87
|
+
'Content-Type': 'application/json'
|
88
|
+
}.compact
|
89
|
+
end
|
90
|
+
|
91
|
+
def provider_config
|
92
|
+
@config.providers.deepseek
|
88
93
|
end
|
89
94
|
end
|
90
95
|
end
|
@@ -3,17 +3,12 @@
|
|
3
3
|
require 'json'
|
4
4
|
require 'net/http'
|
5
5
|
require 'uri'
|
6
|
-
require_relative '
|
6
|
+
require_relative 'base_client'
|
7
7
|
|
8
8
|
module ActiveGenie
|
9
9
|
module Clients
|
10
10
|
# Client for interacting with the Google Generative Language API.
|
11
11
|
class GoogleClient < BaseClient
|
12
|
-
class GoogleError < ClientError; end
|
13
|
-
class RateLimitError < GoogleError; end
|
14
|
-
|
15
|
-
API_VERSION_PATH = '/v1beta/models'
|
16
|
-
|
17
12
|
# Requests structured JSON output from the Google Generative Language model based on a schema.
|
18
13
|
#
|
19
14
|
# @param messages [Array<Hash>] A list of messages representing the conversation history.
|
@@ -22,81 +17,72 @@ module ActiveGenie
|
|
22
17
|
# @param function [Hash] A JSON schema definition describing the desired output format.
|
23
18
|
# @return [Hash, nil] The parsed JSON object matching the schema, or nil if parsing fails or content is empty.
|
24
19
|
def function_calling(messages, function)
|
25
|
-
model = @config.llm.model || provider_config.tier_to_model(@config.llm.model_tier)
|
26
|
-
|
27
20
|
contents = convert_messages_to_contents(messages, function)
|
28
21
|
contents << output_as_json_schema(function)
|
29
22
|
|
30
23
|
payload = {
|
31
|
-
contents
|
24
|
+
contents:,
|
32
25
|
generationConfig: {
|
33
26
|
response_mime_type: 'application/json',
|
34
27
|
temperature: 0.1
|
35
28
|
}
|
36
29
|
}
|
37
|
-
|
38
|
-
endpoint = "#{API_VERSION_PATH}/#{model}:generateContent"
|
39
30
|
params = { key: provider_config.api_key }
|
40
|
-
headers = DEFAULT_HEADERS
|
41
|
-
|
42
|
-
retry_with_backoff do
|
43
|
-
start_time = Time.now
|
44
|
-
url = "#{provider_config.api_url}#{endpoint}"
|
45
|
-
|
46
|
-
response = post(url, payload, headers:, params:)
|
47
|
-
|
48
|
-
json_string = response&.dig('candidates', 0, 'content', 'parts', 0, 'text')
|
49
|
-
return nil if json_string.nil? || json_string.empty?
|
50
|
-
|
51
|
-
begin
|
52
|
-
parsed_response = JSON.parse(json_string)
|
53
|
-
|
54
|
-
# Log usage metrics
|
55
|
-
usage_metadata = response['usageMetadata'] || {}
|
56
|
-
prompt_tokens = usage_metadata['promptTokenCount'] || 0
|
57
|
-
candidates_tokens = usage_metadata['candidatesTokenCount'] || 0
|
58
|
-
total_tokens = usage_metadata['totalTokenCount'] || (prompt_tokens + candidates_tokens)
|
59
|
-
|
60
|
-
ActiveGenie::Logger.call({
|
61
|
-
code: :llm_usage,
|
62
|
-
input_tokens: prompt_tokens,
|
63
|
-
output_tokens: candidates_tokens,
|
64
|
-
total_tokens: total_tokens,
|
65
|
-
model: model,
|
66
|
-
duration: Time.now - start_time,
|
67
|
-
usage: usage_metadata
|
68
|
-
})
|
69
|
-
|
70
|
-
ActiveGenie::Logger.call({ code: :function_calling, payload:, parsed_response: })
|
71
|
-
|
72
|
-
normalize_function_output(parsed_response)
|
73
|
-
rescue JSON::ParserError => e
|
74
|
-
raise GoogleError, "Failed to parse Google API response: #{e.message} - Content: #{json_string}"
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
31
|
|
79
|
-
|
80
|
-
|
32
|
+
response = request(payload, params)
|
33
|
+
|
34
|
+
json_string = response&.dig('candidates', 0, 'content', 'parts', 0, 'text')
|
35
|
+
return nil if json_string.nil? || json_string.empty?
|
36
|
+
|
37
|
+
normalize_response(json_string)
|
81
38
|
end
|
82
39
|
|
40
|
+
API_VERSION_PATH = 'v1beta/models'
|
41
|
+
ROLE_TO_GOOGLE_ROLE = {
|
42
|
+
user: 'user',
|
43
|
+
assistant: 'model'
|
44
|
+
}.freeze
|
45
|
+
|
83
46
|
private
|
84
47
|
|
85
|
-
def
|
86
|
-
|
87
|
-
|
48
|
+
def request(payload, params)
|
49
|
+
response = post(url, payload, headers: DEFAULT_HEADERS, params:)
|
50
|
+
|
51
|
+
ActiveGenie::Logger.call(
|
52
|
+
{
|
53
|
+
code: :llm_usage,
|
54
|
+
input_tokens: response['usageMetadata']['promptTokenCount'] || 0,
|
55
|
+
output_tokens: response['usageMetadata']['candidatesTokenCount'] || 0,
|
56
|
+
total_tokens: response['usageMetadata']['totalTokenCount'] || (prompt_tokens + candidates_tokens),
|
57
|
+
model:,
|
58
|
+
usage: response['usageMetadata'] || {}
|
59
|
+
}
|
60
|
+
)
|
61
|
+
|
62
|
+
ActiveGenie::Logger.call(
|
63
|
+
{
|
64
|
+
code: :function_calling,
|
65
|
+
fine_tune: true,
|
66
|
+
payload:,
|
67
|
+
parsed_response: response&.dig('candidates', 0, 'content', 'parts', 0, 'text')
|
68
|
+
}
|
69
|
+
)
|
70
|
+
|
71
|
+
response
|
72
|
+
end
|
73
|
+
|
74
|
+
def normalize_response(json_string)
|
75
|
+
parsed_response = JSON.parse(json_string)
|
76
|
+
|
77
|
+
output = if parsed_response.is_a?(Array)
|
78
|
+
parsed_response.dig(0, 'properties') || parsed_response[0]
|
88
79
|
else
|
89
|
-
|
80
|
+
parsed_response
|
90
81
|
end
|
91
82
|
|
92
83
|
output.dig('input_schema', 'properties') || output
|
93
84
|
end
|
94
85
|
|
95
|
-
ROLE_TO_GOOGLE_ROLE = {
|
96
|
-
user: 'user',
|
97
|
-
assistant: 'model'
|
98
|
-
}.freeze
|
99
|
-
|
100
86
|
# Converts standard message format to Google's 'contents' format
|
101
87
|
# and injects JSON schema instructions.
|
102
88
|
# @param messages [Array<Hash>] Array of { role: 'user'/'assistant'/'system', content: '...' }
|
@@ -127,6 +113,18 @@ module ActiveGenie
|
|
127
113
|
parts: [{ text: json_instruction }]
|
128
114
|
}
|
129
115
|
end
|
116
|
+
|
117
|
+
def model
|
118
|
+
@config.llm.model || provider_config.tier_to_model(@config.llm.model_tier)
|
119
|
+
end
|
120
|
+
|
121
|
+
def url
|
122
|
+
"#{provider_config.api_url}/#{API_VERSION_PATH}/#{model}:generateContent"
|
123
|
+
end
|
124
|
+
|
125
|
+
def provider_config
|
126
|
+
@config.providers.google
|
127
|
+
end
|
130
128
|
end
|
131
129
|
end
|
132
130
|
end
|
@@ -3,13 +3,11 @@
|
|
3
3
|
require 'json'
|
4
4
|
require 'net/http'
|
5
5
|
|
6
|
-
require_relative '
|
6
|
+
require_relative 'base_client'
|
7
7
|
|
8
8
|
module ActiveGenie
|
9
9
|
module Clients
|
10
10
|
class OpenaiClient < BaseClient
|
11
|
-
class OpenaiError < ClientError; end
|
12
|
-
class RateLimitError < OpenaiError; end
|
13
11
|
class InvalidResponseError < StandardError; end
|
14
12
|
|
15
13
|
# Requests structured JSON output from the OpenAI model based on a schema.
|
@@ -19,77 +17,76 @@ module ActiveGenie
|
|
19
17
|
# @param function [Hash] A JSON schema definition describing the desired output format.
|
20
18
|
# @return [Hash, nil] The parsed JSON object matching the schema, or nil if parsing fails or content is empty.
|
21
19
|
def function_calling(messages, function)
|
22
|
-
model = @config.llm.model || provider_config.tier_to_model(@config.llm.model_tier)
|
23
|
-
|
24
20
|
payload = {
|
25
21
|
messages:,
|
26
|
-
tools: [
|
27
|
-
type: 'function',
|
28
|
-
function: {
|
29
|
-
**function,
|
30
|
-
parameters: {
|
31
|
-
**function[:parameters],
|
32
|
-
additionalProperties: false
|
33
|
-
},
|
34
|
-
strict: true
|
35
|
-
}.compact
|
36
|
-
}],
|
22
|
+
tools: [function_to_tool(function)],
|
37
23
|
tool_choice: { type: 'function', function: { name: function[:name] } },
|
38
24
|
stream: false,
|
39
25
|
model:
|
40
26
|
}
|
41
27
|
|
42
|
-
|
43
|
-
'Authorization': "Bearer #{provider_config.api_key}"
|
44
|
-
}.compact
|
45
|
-
|
46
|
-
retry_with_backoff do
|
47
|
-
response = request_openai(payload, headers)
|
48
|
-
|
49
|
-
parsed_response = JSON.parse(response.dig('choices', 0, 'message', 'tool_calls', 0, 'function', 'arguments'))
|
50
|
-
parsed_response = parsed_response['message'] || parsed_response
|
28
|
+
response = request(payload)
|
51
29
|
|
52
|
-
|
53
|
-
raise InvalidResponseError,
|
54
|
-
"Invalid response: #{parsed_response}"
|
55
|
-
end
|
30
|
+
raise InvalidResponseError, "Invalid response: #{response}" if response.nil? || response.keys.empty?
|
56
31
|
|
57
|
-
|
32
|
+
ActiveGenie::Logger.call({ code: :function_calling, fine_tune: true, payload:, response: })
|
58
33
|
|
59
|
-
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def provider_config
|
64
|
-
@config.providers.openai
|
34
|
+
response
|
65
35
|
end
|
66
36
|
|
67
37
|
private
|
68
38
|
|
69
|
-
|
70
|
-
#
|
71
|
-
# @param payload [Hash] The request payload
|
72
|
-
# @param headers [Hash] Additional headers
|
73
|
-
# @return [Hash] The parsed response
|
74
|
-
def request_openai(payload, headers)
|
75
|
-
start_time = Time.now
|
76
|
-
url = "#{provider_config.api_url}/chat/completions"
|
77
|
-
|
39
|
+
def request(payload)
|
78
40
|
response = post(url, payload, headers: headers)
|
79
41
|
|
80
42
|
return nil if response.nil?
|
81
43
|
|
82
|
-
ActiveGenie::Logger.call(
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
44
|
+
ActiveGenie::Logger.call(
|
45
|
+
{
|
46
|
+
code: :llm_usage,
|
47
|
+
input_tokens: response.dig('usage', 'prompt_tokens'),
|
48
|
+
output_tokens: response.dig('usage', 'completion_tokens'),
|
49
|
+
total_tokens: response.dig('usage', 'total_tokens'),
|
50
|
+
model:,
|
51
|
+
usage: response['usage']
|
52
|
+
}
|
53
|
+
)
|
54
|
+
|
55
|
+
parsed_response = JSON.parse(response.dig('choices', 0, 'message', 'tool_calls', 0, 'function', 'arguments'))
|
56
|
+
parsed_response['message'] || parsed_response
|
57
|
+
end
|
91
58
|
|
92
|
-
|
59
|
+
def function_to_tool(function)
|
60
|
+
{
|
61
|
+
type: 'function',
|
62
|
+
function: {
|
63
|
+
**function,
|
64
|
+
parameters: {
|
65
|
+
**function[:parameters],
|
66
|
+
additionalProperties: false
|
67
|
+
},
|
68
|
+
strict: true
|
69
|
+
}.compact
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
def model
|
74
|
+
@config.llm.model || provider_config.tier_to_model(@config.llm.model_tier)
|
75
|
+
end
|
76
|
+
|
77
|
+
def url
|
78
|
+
"#{provider_config.api_url}/chat/completions"
|
79
|
+
end
|
80
|
+
|
81
|
+
def headers
|
82
|
+
{
|
83
|
+
Authorization: "Bearer #{provider_config.api_key}",
|
84
|
+
'Content-Type': 'application/json'
|
85
|
+
}.compact
|
86
|
+
end
|
87
|
+
|
88
|
+
def provider_config
|
89
|
+
@config.providers.openai
|
93
90
|
end
|
94
91
|
end
|
95
92
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
4
|
-
require_relative '
|
5
|
-
require_relative '
|
6
|
-
require_relative '
|
3
|
+
require_relative 'providers/openai_client'
|
4
|
+
require_relative 'providers/anthropic_client'
|
5
|
+
require_relative 'providers/google_client'
|
6
|
+
require_relative 'providers/deepseek_client'
|
7
7
|
require_relative '../errors/invalid_provider_error'
|
8
8
|
|
9
9
|
module ActiveGenie
|
@@ -3,14 +3,48 @@
|
|
3
3
|
module ActiveGenie
|
4
4
|
module Config
|
5
5
|
class LogConfig
|
6
|
-
|
6
|
+
attr_writer :file_path, :fine_tune_file_path
|
7
|
+
|
8
|
+
def file_path
|
9
|
+
@file_path || 'log/active_genie.log'
|
10
|
+
end
|
11
|
+
|
12
|
+
def fine_tune_file_path
|
13
|
+
@fine_tune_file_path || 'log/active_genie_fine_tune.log'
|
14
|
+
end
|
15
|
+
|
16
|
+
def output
|
17
|
+
@output || ->(log) { $stdout.puts log }
|
18
|
+
end
|
19
|
+
|
20
|
+
def output=(output)
|
21
|
+
raise InvalidLogOutputError, output unless output.respond_to?(:call)
|
22
|
+
|
23
|
+
@output = output
|
24
|
+
end
|
25
|
+
|
26
|
+
def output_call(log)
|
27
|
+
output&.call(log)
|
28
|
+
|
29
|
+
Array(@observers).each do |obs|
|
30
|
+
next unless obs[:scope].all? { |key, value| log[key.to_sym] == value }
|
31
|
+
|
32
|
+
obs[:observer]&.call(log)
|
33
|
+
rescue StandardError => e
|
34
|
+
ActiveGenie::Logger.call(code: :observer_error, **obs, error: e.message)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def add_observer(observers: [], scope: {}, &block)
|
7
39
|
@observers ||= []
|
8
40
|
|
9
|
-
raise ArgumentError, 'Scope must be a hash' if
|
41
|
+
raise ArgumentError, 'Scope must be a hash' if scope && !scope.is_a?(Hash)
|
10
42
|
|
11
|
-
@observers << { observer: block, scope:
|
43
|
+
@observers << { observer: block, scope: } if block_given?
|
12
44
|
Array(observers).each do |observer|
|
13
|
-
|
45
|
+
next unless observer.respond_to?(:call)
|
46
|
+
|
47
|
+
@observers << { observer:, scope: }
|
14
48
|
end
|
15
49
|
end
|
16
50
|
|
@@ -24,16 +58,6 @@ module ActiveGenie
|
|
24
58
|
@observers = []
|
25
59
|
end
|
26
60
|
|
27
|
-
def call_observers(log)
|
28
|
-
Array(@observers).each do |obs|
|
29
|
-
next unless obs[:scope].all? { |key, value| log[key.to_sym] == value }
|
30
|
-
|
31
|
-
obs[:observer].call(log)
|
32
|
-
rescue StandardError => e
|
33
|
-
ActiveGenie::Logger.call(code: :observer_error, **obs, error: e.message)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
61
|
def merge(config_params = {})
|
38
62
|
dup.tap do |config|
|
39
63
|
config.add_observer(config_params[:observers]) if config_params[:observers]
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
3
|
+
require_relative 'provider_base'
|
4
4
|
|
5
5
|
module ActiveGenie
|
6
6
|
module Config
|
@@ -14,7 +14,7 @@ module ActiveGenie
|
|
14
14
|
# Falls back to the ANTHROPIC_API_KEY environment variable if not set.
|
15
15
|
# @return [String, nil] The API key.
|
16
16
|
def api_key
|
17
|
-
@api_key || ENV
|
17
|
+
@api_key || ENV.fetch('ANTHROPIC_API_KEY', nil)
|
18
18
|
end
|
19
19
|
|
20
20
|
# Retrieves the base API URL for Anthropic API.
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
3
|
+
require_relative 'provider_base'
|
4
4
|
|
5
5
|
module ActiveGenie
|
6
6
|
module Config
|
@@ -14,7 +14,7 @@ module ActiveGenie
|
|
14
14
|
# Falls back to the DEEPSEEK_API_KEY environment variable if not set.
|
15
15
|
# @return [String, nil] The API key.
|
16
16
|
def api_key
|
17
|
-
@api_key || ENV
|
17
|
+
@api_key || ENV.fetch('DEEPSEEK_API_KEY', nil)
|
18
18
|
end
|
19
19
|
|
20
20
|
# Retrieves the base API URL for DeepSeek API.
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
3
|
+
require_relative 'provider_base'
|
4
4
|
|
5
5
|
module ActiveGenie
|
6
6
|
module Config
|
@@ -14,7 +14,7 @@ module ActiveGenie
|
|
14
14
|
# Falls back to the GENERATIVE_LANGUAGE_GOOGLE_API_KEY environment variable if not set.
|
15
15
|
# @return [String, nil] The API key.
|
16
16
|
def api_key
|
17
|
-
@api_key || ENV['GENERATIVE_LANGUAGE_GOOGLE_API_KEY'] || ENV
|
17
|
+
@api_key || ENV['GENERATIVE_LANGUAGE_GOOGLE_API_KEY'] || ENV.fetch('GEMINI_API_KEY', nil)
|
18
18
|
end
|
19
19
|
|
20
20
|
# Retrieves the base API URL for Google Generative Language API.
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
3
|
+
require_relative 'provider_base'
|
4
4
|
|
5
5
|
module ActiveGenie
|
6
6
|
module Config
|
@@ -14,7 +14,7 @@ module ActiveGenie
|
|
14
14
|
# Falls back to the OPENAI_API_KEY environment variable if not set.
|
15
15
|
# @return [String, nil] The API key.
|
16
16
|
def api_key
|
17
|
-
@api_key || ENV
|
17
|
+
@api_key || ENV.fetch('OPENAI_API_KEY', nil)
|
18
18
|
end
|
19
19
|
|
20
20
|
# Retrieves the base API URL for OpenAI API.
|
@@ -51,12 +51,12 @@ module ActiveGenie
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
-
def method_missing(
|
55
|
-
@all[
|
54
|
+
def method_missing(method_name, *args, &)
|
55
|
+
@all[method_name] || super
|
56
56
|
end
|
57
57
|
|
58
|
-
def respond_to_missing?(
|
59
|
-
@all.key?(
|
58
|
+
def respond_to_missing?(method_name, include_private = false)
|
59
|
+
@all.key?(method_name) || super
|
60
60
|
end
|
61
61
|
end
|
62
62
|
end
|