active_genie 0.26.5 → 0.27.1
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 +10 -193
- data/VERSION +1 -1
- data/lib/active_genie/battle/generalist.rb +9 -9
- data/lib/active_genie/clients/providers/anthropic_client.rb +2 -2
- data/lib/active_genie/clients/providers/base_client.rb +2 -2
- data/lib/active_genie/clients/providers/deepseek_client.rb +2 -2
- data/lib/active_genie/clients/providers/google_client.rb +3 -10
- data/lib/active_genie/clients/providers/openai_client.rb +2 -2
- data/lib/active_genie/config/log_config.rb +12 -15
- 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/provider_base.rb +4 -4
- data/lib/active_genie/configuration.rb +16 -4
- data/lib/active_genie/data_extractor/generalist.rb +2 -2
- data/lib/active_genie/logger.rb +40 -22
- data/lib/active_genie/ranking/elo_round.rb +30 -37
- data/lib/active_genie/ranking/free_for_all.rb +29 -28
- data/lib/active_genie/ranking/player.rb +1 -9
- data/lib/active_genie/ranking/ranking.rb +32 -25
- data/lib/active_genie/ranking/ranking_scoring.rb +12 -17
- data/lib/active_genie/scoring/generalist.rb +9 -9
- data/lib/tasks/templates/active_genie.rb +1 -1
- metadata +8 -13
- data/lib/active_genie/data_extractor/README.md +0 -131
- data/lib/active_genie/ranking/README.md +0 -73
- data/lib/active_genie/ranking/concerns/loggable.rb +0 -29
- data/lib/active_genie/scoring/README.md +0 -76
- /data/lib/active_genie/battle/{generalist.md → generalist.prompt.md} +0 -0
- /data/lib/active_genie/data_extractor/{generalist.md → generalist.prompt.md} +0 -0
- /data/lib/active_genie/scoring/{generalist.md → generalist.prompt.md} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 752b254545d62f5e618ca56935dca6e89dce29e0353af995f96f276ac2852662
|
4
|
+
data.tar.gz: 7df0c3373970c5da1cf12cea004839a17e8489bf52b2e3d14dedcd61c04f91cc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dd4d86d0bd8a8be3c44355d997883db01b424a070ab51b555e1f1b8a10c3c0fbc46f8afc4c5b8764b4462b9e1e5e711be38ad25a77a21e26b3ea55668fd61ccf
|
7
|
+
data.tar.gz: bb69781f7f05a339833e553ab7cb1dc805044cda7fb2615712c7fea3f5ce9f71dce82b38edd1b70aa6fca36d6ef6538c573b34058e80498a0a5a65bf6fd58821
|
data/README.md
CHANGED
@@ -1,13 +1,16 @@
|
|
1
1
|
# ActiveGenie 🧞♂️
|
2
|
-
> The
|
2
|
+
> The Lodash for GenAI: Real Value + Consistent + Model-Agnostic
|
3
3
|
|
4
4
|
[](https://badge.fury.io/rb/active_genie)
|
5
5
|
[](https://github.com/roriz/active_genie/actions/workflows/benchmark.yml)
|
6
6
|
|
7
|
-
ActiveGenie is a
|
8
|
-
ActiveGenie is backed by a custom benchmarking system that ensures consistent quality and performance across different models and providers in every release.
|
7
|
+
ActiveGenie is a developer-first library for GenAI workflows, designed to help you compare, rank, and score LLM outputs with consistency and model-agnostic flexibility. Think of it as the Lodash for GenAI: built for real value, consistent results, and freedom from vendor lock-in. It solves the biggest pain in GenAI today: getting predictable, trustworthy answers across use cases, models, and providers.
|
9
8
|
|
10
|
-
|
9
|
+
Behind the scenes, a custom benchmarking system keeps everything consistent across LLM vendors and versions, release after release.
|
10
|
+
|
11
|
+
For full documentation, visit [activegenie.ai](https://activegenie.ai).
|
12
|
+
|
13
|
+
# Installation
|
11
14
|
|
12
15
|
1. Add to your Gemfile:
|
13
16
|
```ruby
|
@@ -32,9 +35,7 @@ ActiveGenie.configure do |config|
|
|
32
35
|
end
|
33
36
|
```
|
34
37
|
|
35
|
-
## Quick
|
36
|
-
|
37
|
-
### Data Extractor
|
38
|
+
## Quick start example
|
38
39
|
|
39
40
|
Extract structured data from text using AI-powered analysis, handling informal language and complex expressions.
|
40
41
|
|
@@ -71,193 +72,9 @@ result = ActiveGenie::DataExtractor.call(
|
|
71
72
|
# }
|
72
73
|
```
|
73
74
|
|
74
|
-
|
75
|
-
|
76
|
-
Features:
|
77
|
-
- Structured data extraction with type validation
|
78
|
-
- Schema-based extraction with custom constraints
|
79
|
-
- Informal text analysis (litotes, hedging)
|
80
|
-
- Detailed explanations for extracted values
|
81
|
-
|
82
|
-
See the [Data Extractor README](lib/active_genie/data_extractor/README.md) for informal text processing, advanced schemas, and detailed interface documentation.
|
83
|
-
|
84
|
-
### Scoring
|
85
|
-
Text evaluation system that provides detailed scoring and feedback using multiple expert reviewers. Get balanced scoring through AI-powered expert reviewers that automatically adapt to your content.
|
86
|
-
|
87
|
-
```ruby
|
88
|
-
text = "The code implements a binary search algorithm with O(log n) complexity"
|
89
|
-
criteria = "Evaluate technical accuracy and clarity"
|
90
|
-
|
91
|
-
result = ActiveGenie::Scoring.call(
|
92
|
-
text,
|
93
|
-
criteria,
|
94
|
-
config: { provider: :anthropic, model: 'claude-3-5-haiku-20241022' } # optional
|
95
|
-
)
|
96
|
-
# => {
|
97
|
-
# algorithm_expert_score: 95,
|
98
|
-
# algorithm_expert_reasoning: "Accurately describes binary search and its complexity",
|
99
|
-
# technical_writer_score: 90,
|
100
|
-
# technical_writer_reasoning: "Clear and concise explanation of the algorithm",
|
101
|
-
# final_score: 92.5
|
102
|
-
# }
|
103
|
-
```
|
104
|
-
|
105
|
-
*Recommended model*: `claude-3-5-haiku-20241022`
|
106
|
-
|
107
|
-
Features:
|
108
|
-
- Multi-reviewer evaluation with automatic expert selection
|
109
|
-
- Detailed feedback with scoring reasoning
|
110
|
-
- Customizable reviewer weights
|
111
|
-
- Flexible evaluation criteria
|
112
|
-
|
113
|
-
See the [Scoring README](lib/active_genie/scoring/README.md) for advanced usage, custom reviewers, and detailed interface documentation.
|
114
|
-
|
115
|
-
### Battle
|
116
|
-
AI-powered battle evaluation system that determines winners between two players based on specified criteria.
|
117
|
-
|
118
|
-
```ruby
|
119
|
-
require 'active_genie'
|
120
|
-
|
121
|
-
player_a = "Implementation uses dependency injection for better testability"
|
122
|
-
player_b = "Code has high test coverage but tightly coupled components"
|
123
|
-
criteria = "Evaluate code quality and maintainability"
|
124
|
-
|
125
|
-
result = ActiveGenie::Battle.call(
|
126
|
-
player_a,
|
127
|
-
player_b,
|
128
|
-
criteria,
|
129
|
-
config: { provider: :google, model: 'gemini-2.0-flash-lite' } # optional
|
130
|
-
)
|
131
|
-
# => {
|
132
|
-
# winner_player: "Implementation uses dependency injection for better testability",
|
133
|
-
# reasoning: "Player 1 implementation demonstrates better maintainability through dependency injection,
|
134
|
-
# which allows for easier testing and component replacement. While Player 2 has good test coverage,
|
135
|
-
# the tight coupling makes the code harder to maintain and modify.",
|
136
|
-
# what_could_be_changed_to_avoid_draw: "Focus on specific architectural patterns and design principles"
|
137
|
-
# }
|
138
|
-
```
|
139
|
-
|
140
|
-
*Recommended model*: `claude-3-5-haiku`
|
141
|
-
|
142
|
-
Features:
|
143
|
-
- Multi-reviewer evaluation with automatic expert selection
|
144
|
-
- Detailed feedback with scoring reasoning
|
145
|
-
- Customizable reviewer weights
|
146
|
-
- Flexible evaluation criteria
|
147
|
-
|
148
|
-
See the [Battle README](lib/active_genie/battle/README.md) for advanced usage, custom reviewers, and detailed interface documentation.
|
149
|
-
|
150
|
-
### Ranking
|
151
|
-
The Ranking module provides competitive ranking through multi-stage evaluation:
|
152
|
-
|
153
|
-
```ruby
|
154
|
-
require 'active_genie'
|
155
|
-
|
156
|
-
players = ['REST API', 'GraphQL API', 'SOAP API', 'gRPC API', 'Websocket API']
|
157
|
-
criteria = "Best one to be used into a high changing environment"
|
158
|
-
|
159
|
-
result = ActiveGenie::Ranking.call(
|
160
|
-
players,
|
161
|
-
criteria,
|
162
|
-
config: { provider: :google, model: 'gemini-2.0-flash-lite' } # optional
|
163
|
-
)
|
164
|
-
# => {
|
165
|
-
# winner_player: "gRPC API",
|
166
|
-
# reasoning: "gRPC API is the best one to be used into a high changing environment",
|
167
|
-
# }
|
168
|
-
```
|
169
|
-
|
170
|
-
*Recommended model*: `gemini-2.0-flash-lite`
|
171
|
-
|
172
|
-
- **Multi-phase ranking system** combining expert scoring and ELO algorithms
|
173
|
-
- **Automatic elimination** of inconsistent performers using statistical analysis
|
174
|
-
- **Dynamic ranking adjustments** based on simulated pairwise battles, from bottom to top
|
175
|
-
|
176
|
-
See the [Ranking README](lib/active_genie/ranking/README.md) for implementation details, configuration, and advanced ranking strategies.
|
177
|
-
|
178
|
-
### Text Summarizer (Future)
|
179
|
-
### Categorizer (Future)
|
180
|
-
### Language detector (Future)
|
181
|
-
### Translator (Future)
|
182
|
-
### Sentiment analyzer (Future)
|
183
|
-
|
184
|
-
## Benchmarking 🧪
|
185
|
-
|
186
|
-
ActiveGenie includes a comprehensive benchmarking system to ensure consistent, high-quality outputs across different LLM models and providers.
|
187
|
-
|
188
|
-
```ruby
|
189
|
-
# Run all benchmarks
|
190
|
-
bundle exec rake active_genie:benchmark
|
191
|
-
|
192
|
-
# Run benchmarks for a specific module
|
193
|
-
bundle exec rake active_genie:benchmark[data_extractor]
|
194
|
-
```
|
195
|
-
|
196
|
-
### Latest Results
|
197
|
-
|
198
|
-
| Model | Overall Precision |
|
199
|
-
|-------|-------------------|
|
200
|
-
| claude-3-5-haiku-20241022 | 92.25% |
|
201
|
-
| gemini-2.0-flash-lite | 84.25% |
|
202
|
-
| gpt-4o-mini | 62.75% |
|
203
|
-
| deepseek-chat | 57.25% |
|
204
|
-
|
205
|
-
See the [Benchmark README](benchmark/README.md) for detailed results, methodology, and how to contribute to our test suite.
|
206
|
-
|
207
|
-
## Configuration
|
208
|
-
|
209
|
-
| Config | Description | Default |
|
210
|
-
|--------|-------------|---------|
|
211
|
-
| `provider` | LLM provider (openai, anthropic, etc) | `nil` |
|
212
|
-
| `model` | Model to use | `nil` |
|
213
|
-
| `api_key` | Provider API key | `nil` |
|
214
|
-
| `timeout` | Request timeout in seconds | `5` |
|
215
|
-
| `max_retries` | Maximum retry attempts | `3` |
|
75
|
+
## Documentation
|
216
76
|
|
217
|
-
|
218
|
-
|
219
|
-
## How to create a new provider
|
220
|
-
|
221
|
-
ActiveGenie supports adding custom providers to integrate with different LLM services. To create a new provider:
|
222
|
-
|
223
|
-
1. Create a configuration class for your provider in `lib/active_genie/configuration/providers/`:
|
224
|
-
2. Register your client
|
225
|
-
|
226
|
-
```ruby
|
227
|
-
class InternalCompanyApi
|
228
|
-
# @param messages [Array<Hash>] A list of messages representing the conversation history.
|
229
|
-
# Each hash should have :role ('user', 'assistant', or 'system') and :content (String).
|
230
|
-
# @param function [Hash] A JSON schema definition describing the desired output format.
|
231
|
-
# @return [Hash, nil] The parsed JSON object matching the schema, or nil if parsing fails or content is empty.
|
232
|
-
def function_calling(messages, function)
|
233
|
-
# ...
|
234
|
-
end
|
235
|
-
end
|
236
|
-
|
237
|
-
ActiveGenie.configure do |config|
|
238
|
-
config.llm.client = InternalCompanyApi
|
239
|
-
end
|
240
|
-
# or
|
241
|
-
ActiveGenie::Battle.call('player_a', 'player_b', 'criteria', { client: InternalCompanyApi })
|
242
|
-
```
|
243
|
-
|
244
|
-
## Observability
|
245
|
-
Fundamental to managing any production system, observability is crucial for GenAI features. At a minimum, track these key metrics:
|
246
|
-
|
247
|
-
- Usage Rate (e.g., uses_per_minute): Detect anomalies like sudden traffic spikes (potential DDoS) or drops (feature outage or declining usage).
|
248
|
-
- Failure/Retry Rate (e.g., retry_count, fail_count): Monitor the frequency of errors. Exceeding a defined threshold should trigger downtime or degradation alerts.
|
249
|
-
- Token Consumption (e.g., tokens_used): Track usage to monitor costs. Set alerts if tokens_used * price_per_token exceeds budget thresholds.
|
250
|
-
|
251
|
-
```ruby
|
252
|
-
ActiveGenie.configure do |config|
|
253
|
-
config.log.add_observer(scope: { code: :llm_usage }) do |log|
|
254
|
-
puts "LLM Usage: #{log[:model]} - #{log[:total_tokens]} tokens"
|
255
|
-
end
|
256
|
-
config.log.add_observer(scope: { code: :retry_attempt }) do |log|
|
257
|
-
puts "Retry Attempt: #{log[:attempt]} of #{log[:max_retries]}"
|
258
|
-
end
|
259
|
-
end
|
260
|
-
```
|
77
|
+
For full documentation, visit [activegenie.ai](https://activegenie.ai).
|
261
78
|
|
262
79
|
## Contributing
|
263
80
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.27.1
|
@@ -48,19 +48,19 @@ module ActiveGenie
|
|
48
48
|
config: @config
|
49
49
|
)
|
50
50
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
51
|
+
@config.logger.call({
|
52
|
+
code: :battle,
|
53
|
+
player_a: @player_a[0..30],
|
54
|
+
player_b: @player_b[0..30],
|
55
|
+
criteria: @criteria[0..30],
|
56
|
+
winner: response['impartial_judge_winner'],
|
57
|
+
reasoning: response['impartial_judge_winner_reasoning']
|
58
|
+
})
|
59
59
|
|
60
60
|
response_formatted(response)
|
61
61
|
end
|
62
62
|
|
63
|
-
PROMPT = File.read(File.join(__dir__, 'generalist.md'))
|
63
|
+
PROMPT = File.read(File.join(__dir__, 'generalist.prompt.md'))
|
64
64
|
FUNCTION = JSON.parse(File.read(File.join(__dir__, 'generalist.json')), symbolize_names: true)
|
65
65
|
|
66
66
|
private
|
@@ -55,7 +55,7 @@ module ActiveGenie
|
|
55
55
|
def request(payload)
|
56
56
|
response = post(url, payload, headers:)
|
57
57
|
|
58
|
-
|
58
|
+
@config.logger.call(
|
59
59
|
{
|
60
60
|
code: :llm_usage,
|
61
61
|
input_tokens: response.dig('usage', 'input_tokens'),
|
@@ -67,7 +67,7 @@ module ActiveGenie
|
|
67
67
|
usage: response['usage']
|
68
68
|
}
|
69
69
|
)
|
70
|
-
|
70
|
+
@config.logger.call(
|
71
71
|
{
|
72
72
|
code: :function_calling,
|
73
73
|
fine_tune: true,
|
@@ -151,7 +151,7 @@ module ActiveGenie
|
|
151
151
|
#
|
152
152
|
# @param details [Hash] Request and response details
|
153
153
|
def log_request_details(uri:, request:, response:, start_time:, parsed_response:)
|
154
|
-
|
154
|
+
@config.logger.call(
|
155
155
|
{
|
156
156
|
code: :http_request,
|
157
157
|
uri: uri.to_s,
|
@@ -176,7 +176,7 @@ module ActiveGenie
|
|
176
176
|
sleep_time = retry_delay * (2**retries)
|
177
177
|
retries += 1
|
178
178
|
|
179
|
-
|
179
|
+
@config.logger.call(
|
180
180
|
code: :retry_attempt,
|
181
181
|
attempt: retries,
|
182
182
|
max_retries: max_retries,
|
@@ -32,7 +32,7 @@ module ActiveGenie
|
|
32
32
|
"Invalid response: #{response}"
|
33
33
|
end
|
34
34
|
|
35
|
-
|
35
|
+
@config.logger.call({ code: :function_calling, fine_tune: true, payload:, response: })
|
36
36
|
|
37
37
|
response
|
38
38
|
end
|
@@ -44,7 +44,7 @@ module ActiveGenie
|
|
44
44
|
|
45
45
|
return nil if response.nil?
|
46
46
|
|
47
|
-
|
47
|
+
@config.logger.call(
|
48
48
|
{
|
49
49
|
code: :llm_usage,
|
50
50
|
input_tokens: response.dig('usage', 'prompt_tokens'),
|
@@ -34,6 +34,8 @@ module ActiveGenie
|
|
34
34
|
json_string = response&.dig('candidates', 0, 'content', 'parts', 0, 'text')
|
35
35
|
return nil if json_string.nil? || json_string.empty?
|
36
36
|
|
37
|
+
@config.logger.call({ code: :function_calling, fine_tune: true, payload:, parsed_response: json_string })
|
38
|
+
|
37
39
|
normalize_response(json_string)
|
38
40
|
end
|
39
41
|
|
@@ -48,7 +50,7 @@ module ActiveGenie
|
|
48
50
|
def request(payload, params)
|
49
51
|
response = post(url, payload, headers: DEFAULT_HEADERS, params:)
|
50
52
|
|
51
|
-
|
53
|
+
@config.logger.call(
|
52
54
|
{
|
53
55
|
code: :llm_usage,
|
54
56
|
input_tokens: response['usageMetadata']['promptTokenCount'] || 0,
|
@@ -59,15 +61,6 @@ module ActiveGenie
|
|
59
61
|
}
|
60
62
|
)
|
61
63
|
|
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
64
|
response
|
72
65
|
end
|
73
66
|
|
@@ -29,7 +29,7 @@ module ActiveGenie
|
|
29
29
|
|
30
30
|
raise InvalidResponseError, "Invalid response: #{response}" if response.nil? || response.keys.empty?
|
31
31
|
|
32
|
-
|
32
|
+
@config.logger.call({ code: :function_calling, fine_tune: true, payload:, response: })
|
33
33
|
|
34
34
|
response
|
35
35
|
end
|
@@ -41,7 +41,7 @@ module ActiveGenie
|
|
41
41
|
|
42
42
|
return nil if response.nil?
|
43
43
|
|
44
|
-
|
44
|
+
@config.logger.call(
|
45
45
|
{
|
46
46
|
code: :llm_usage,
|
47
47
|
input_tokens: response.dig('usage', 'prompt_tokens'),
|
@@ -4,6 +4,7 @@ module ActiveGenie
|
|
4
4
|
module Config
|
5
5
|
class LogConfig
|
6
6
|
attr_writer :file_path, :fine_tune_file_path
|
7
|
+
attr_reader :output, :observers
|
7
8
|
|
8
9
|
def file_path
|
9
10
|
@file_path || 'log/active_genie.log'
|
@@ -13,8 +14,12 @@ module ActiveGenie
|
|
13
14
|
@fine_tune_file_path || 'log/active_genie_fine_tune.log'
|
14
15
|
end
|
15
16
|
|
16
|
-
def
|
17
|
-
@
|
17
|
+
def additional_context
|
18
|
+
@additional_context || {}
|
19
|
+
end
|
20
|
+
|
21
|
+
def additional_context=(context)
|
22
|
+
@additional_context = additional_context.merge(context).compact
|
18
23
|
end
|
19
24
|
|
20
25
|
def output=(output)
|
@@ -23,29 +28,17 @@ module ActiveGenie
|
|
23
28
|
@output = output
|
24
29
|
end
|
25
30
|
|
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
31
|
def add_observer(observers: [], scope: {}, &block)
|
39
32
|
@observers ||= []
|
40
33
|
|
41
34
|
raise ArgumentError, 'Scope must be a hash' if scope && !scope.is_a?(Hash)
|
42
35
|
|
43
|
-
@observers << { observer: block, scope: } if block_given?
|
44
36
|
Array(observers).each do |observer|
|
45
37
|
next unless observer.respond_to?(:call)
|
46
38
|
|
47
39
|
@observers << { observer:, scope: }
|
48
40
|
end
|
41
|
+
@observers << { observer: block, scope: } if block_given?
|
49
42
|
end
|
50
43
|
|
51
44
|
def remove_observer(observers)
|
@@ -60,6 +53,10 @@ module ActiveGenie
|
|
60
53
|
|
61
54
|
def merge(config_params = {})
|
62
55
|
dup.tap do |config|
|
56
|
+
config_params.compact.each do |key, value|
|
57
|
+
config.send("#{key}=", value) if config.respond_to?("#{key}=")
|
58
|
+
end
|
59
|
+
|
63
60
|
config.add_observer(config_params[:observers]) if config_params[:observers]
|
64
61
|
end
|
65
62
|
end
|
@@ -48,8 +48,8 @@ module ActiveGenie
|
|
48
48
|
# Retrieves the model name designated for the upper tier (e.g., most capable).
|
49
49
|
# Defaults to 'claude-3-opus'.
|
50
50
|
# @return [String] The upper tier model name.
|
51
|
-
def
|
52
|
-
@
|
51
|
+
def higher_tier_model
|
52
|
+
@higher_tier_model || 'claude-3-opus-20240229'
|
53
53
|
end
|
54
54
|
end
|
55
55
|
end
|
@@ -41,8 +41,8 @@ module ActiveGenie
|
|
41
41
|
# Retrieves the model name designated for the upper tier (e.g., most capable).
|
42
42
|
# Defaults to 'deepseek-reasoner'.
|
43
43
|
# @return [String] The upper tier model name.
|
44
|
-
def
|
45
|
-
@
|
44
|
+
def higher_tier_model
|
45
|
+
@higher_tier_model || 'deepseek-reasoner'
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
@@ -43,8 +43,8 @@ module ActiveGenie
|
|
43
43
|
# Retrieves the model name designated for the upper tier (e.g., most capable).
|
44
44
|
# Defaults to 'gemini-2.5-pro-experimental'.
|
45
45
|
# @return [String] The upper tier model name.
|
46
|
-
def
|
47
|
-
@
|
46
|
+
def higher_tier_model
|
47
|
+
@higher_tier_model || 'gemini-2.5-pro-experimental'
|
48
48
|
end
|
49
49
|
end
|
50
50
|
end
|
@@ -41,8 +41,8 @@ module ActiveGenie
|
|
41
41
|
# Retrieves the model name designated for the upper tier (e.g., most capable).
|
42
42
|
# Defaults to 'o1-preview'.
|
43
43
|
# @return [String] The upper tier model name.
|
44
|
-
def
|
45
|
-
@
|
44
|
+
def higher_tier_model
|
45
|
+
@higher_tier_model || 'o3-mini'
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
@@ -7,7 +7,7 @@ module ActiveGenie
|
|
7
7
|
NAME = :unknown
|
8
8
|
|
9
9
|
attr_writer :api_key, :organization, :api_url, :client,
|
10
|
-
:lower_tier_model, :middle_tier_model, :
|
10
|
+
:lower_tier_model, :middle_tier_model, :higher_tier_model
|
11
11
|
|
12
12
|
# Maps a symbolic tier (:lower_tier, :middle_tier, :upper_tier) to a specific model name.
|
13
13
|
# Falls back to the lower_tier_model if the tier is nil or unrecognized.
|
@@ -17,7 +17,7 @@ module ActiveGenie
|
|
17
17
|
{
|
18
18
|
lower_tier: lower_tier_model,
|
19
19
|
middle_tier: middle_tier_model,
|
20
|
-
upper_tier:
|
20
|
+
upper_tier: higher_tier_model
|
21
21
|
}[tier&.to_sym] || lower_tier_model
|
22
22
|
end
|
23
23
|
|
@@ -31,7 +31,7 @@ module ActiveGenie
|
|
31
31
|
api_url:,
|
32
32
|
lower_tier_model:,
|
33
33
|
middle_tier_model:,
|
34
|
-
|
34
|
+
higher_tier_model:,
|
35
35
|
**config
|
36
36
|
}
|
37
37
|
end
|
@@ -80,7 +80,7 @@ module ActiveGenie
|
|
80
80
|
# Retrieves the model name designated for the upper tier (e.g., most capable).
|
81
81
|
# Defaults to 'o1-preview'.
|
82
82
|
# @return [String] The upper tier model name.
|
83
|
-
def
|
83
|
+
def higher_tier_model
|
84
84
|
raise NotImplementedError, 'Subclasses must implement this method'
|
85
85
|
end
|
86
86
|
end
|
@@ -38,6 +38,10 @@ module ActiveGenie
|
|
38
38
|
@llm ||= Config::LlmConfig.new
|
39
39
|
end
|
40
40
|
|
41
|
+
def logger
|
42
|
+
@logger ||= ActiveGenie::Logger.new(log_config: log)
|
43
|
+
end
|
44
|
+
|
41
45
|
SUB_CONFIGS = %w[log providers llm ranking scoring data_extractor battle].freeze
|
42
46
|
|
43
47
|
def merge(config_params = {})
|
@@ -54,20 +58,28 @@ module ActiveGenie
|
|
54
58
|
|
55
59
|
new_configuration.send("#{key}=", new_config)
|
56
60
|
end
|
61
|
+
@logger = nil
|
57
62
|
|
58
63
|
new_configuration
|
59
64
|
end
|
60
65
|
|
66
|
+
# Merges a sub config with the config_params.
|
67
|
+
# Examples:
|
68
|
+
# config.merge({ 'log' => { file_path: 'log/active_genie.log' } })
|
69
|
+
# config.merge({ log: { file_path: 'log/active_genie.log' } })
|
70
|
+
# config.merge({ file_path: 'log/active_genie.log' })
|
71
|
+
# these are all the same
|
72
|
+
|
61
73
|
def sub_config_merge(config, key, config_params)
|
62
|
-
if config_params
|
74
|
+
if config_params&.key?(key.to_s)
|
63
75
|
config.merge(config_params[key.to_s])
|
64
|
-
elsif config_params
|
76
|
+
elsif config_params&.key?(key.to_sym)
|
65
77
|
config.merge(config_params[key.to_sym])
|
66
78
|
else
|
67
|
-
config.merge(config_params)
|
79
|
+
config.merge(config_params || {})
|
68
80
|
end
|
69
81
|
end
|
70
82
|
|
71
|
-
attr_writer :log, :providers, :ranking, :scoring, :data_extractor, :battle, :llm
|
83
|
+
attr_writer :log, :providers, :ranking, :scoring, :data_extractor, :battle, :llm, :logger
|
72
84
|
end
|
73
85
|
end
|
@@ -87,7 +87,7 @@ module ActiveGenie
|
|
87
87
|
config: @config
|
88
88
|
)
|
89
89
|
|
90
|
-
|
90
|
+
@config.logger.call(
|
91
91
|
{
|
92
92
|
code: :data_extractor,
|
93
93
|
text: @text[0..30],
|
@@ -119,7 +119,7 @@ module ActiveGenie
|
|
119
119
|
end
|
120
120
|
|
121
121
|
def prompt
|
122
|
-
File.read(File.join(__dir__, 'generalist.md'))
|
122
|
+
File.read(File.join(__dir__, 'generalist.prompt.md'))
|
123
123
|
end
|
124
124
|
end
|
125
125
|
end
|