agent-evals 0.1.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 +7 -0
- data/CHANGELOG.md +16 -0
- data/LICENSE.txt +21 -0
- data/README.md +635 -0
- data/exe/agent-evals +9 -0
- data/lib/agent/evals/adapter.rb +47 -0
- data/lib/agent/evals/case.rb +36 -0
- data/lib/agent/evals/cli/cases.rb +48 -0
- data/lib/agent/evals/cli/command.rb +163 -0
- data/lib/agent/evals/cli/compare.rb +33 -0
- data/lib/agent/evals/cli/model_command.rb +393 -0
- data/lib/agent/evals/cli/progress_bars.rb +90 -0
- data/lib/agent/evals/cli/run.rb +61 -0
- data/lib/agent/evals/cli/verify.rb +24 -0
- data/lib/agent/evals/cli/version.rb +15 -0
- data/lib/agent/evals/cli.rb +40 -0
- data/lib/agent/evals/completion.rb +11 -0
- data/lib/agent/evals/config.rb +146 -0
- data/lib/agent/evals/configuration.rb +172 -0
- data/lib/agent/evals/contender.rb +31 -0
- data/lib/agent/evals/discovery.rb +95 -0
- data/lib/agent/evals/experiment.rb +133 -0
- data/lib/agent/evals/helper.rb +98 -0
- data/lib/agent/evals/launcher.rb +37 -0
- data/lib/agent/evals/metric.rb +26 -0
- data/lib/agent/evals/model.rb +55 -0
- data/lib/agent/evals/providers/base.rb +93 -0
- data/lib/agent/evals/providers/catalog.rb +32 -0
- data/lib/agent/evals/providers/open_router.rb +64 -0
- data/lib/agent/evals/providers/registry.rb +112 -0
- data/lib/agent/evals/providers/type_safe.rb +53 -0
- data/lib/agent/evals/reply.rb +18 -0
- data/lib/agent/evals/run_result.rb +14 -0
- data/lib/agent/evals/runtime.rb +74 -0
- data/lib/agent/evals/schema_validator.rb +84 -0
- data/lib/agent/evals/score.rb +26 -0
- data/lib/agent/evals/scorer.rb +45 -0
- data/lib/agent/evals/testing/echo_adapter.rb +29 -0
- data/lib/agent/evals/testing/fake_model.rb +18 -0
- data/lib/agent/evals/testing/fake_provider.rb +67 -0
- data/lib/agent/evals/tracker.rb +80 -0
- data/lib/agent/evals/trackers/braintrust.rb +91 -0
- data/lib/agent/evals/trackers/local.rb +78 -0
- data/lib/agent/evals/trackers/logfire.rb +143 -0
- data/lib/agent/evals/trackers/registry.rb +82 -0
- data/lib/agent/evals/usage.rb +33 -0
- data/lib/agent/evals/verify.rb +49 -0
- data/lib/agent/evals/version.rb +7 -0
- data/lib/agent/evals/warnings.rb +89 -0
- data/lib/agent/evals.rb +82 -0
- metadata +257 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Agent
|
|
4
|
+
module Evals
|
|
5
|
+
# What one call cost, as the provider counted it. Summed over a run.
|
|
6
|
+
Usage = Data.define(:input_tokens, :output_tokens, :cost_usd) do
|
|
7
|
+
# @return [Usage] zero of everything
|
|
8
|
+
def self.zero = new(input_tokens: 0, output_tokens: 0, cost_usd: 0.0)
|
|
9
|
+
|
|
10
|
+
# Reads a Hash with Symbol or String keys, missing keys as zero.
|
|
11
|
+
#
|
|
12
|
+
# @param hash [Hash, Usage, nil]
|
|
13
|
+
# @return [Usage]
|
|
14
|
+
def self.from(hash)
|
|
15
|
+
return hash if hash.is_a?(Usage)
|
|
16
|
+
return zero if hash.nil?
|
|
17
|
+
|
|
18
|
+
h = hash.transform_keys(&:to_sym)
|
|
19
|
+
new(input_tokens: h.fetch(:input_tokens, 0).to_i,
|
|
20
|
+
output_tokens: h.fetch(:output_tokens, 0).to_i,
|
|
21
|
+
cost_usd: h.fetch(:cost_usd, 0.0).to_f)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# @param other [Usage]
|
|
25
|
+
# @return [Usage]
|
|
26
|
+
def +(other)
|
|
27
|
+
with(input_tokens: input_tokens + other.input_tokens,
|
|
28
|
+
output_tokens: output_tokens + other.output_tokens,
|
|
29
|
+
cost_usd: cost_usd + other.cost_usd)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Agent
|
|
4
|
+
module Evals
|
|
5
|
+
# Offline consistency checks over every case, so a typo in the suite is
|
|
6
|
+
# caught before it is billed as a model's mistake. The gem checks what
|
|
7
|
+
# every suite has: an input and a parsable expected answer. The adapter
|
|
8
|
+
# checks each dataset's shared files, and the scorer each case against
|
|
9
|
+
# what it will demand of it.
|
|
10
|
+
class Verify
|
|
11
|
+
# @param configuration [Configuration]
|
|
12
|
+
def initialize(configuration = Agent::Evals.configuration)
|
|
13
|
+
@configuration = configuration
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# @return [Hash{String => Array<String>}] problems by "dataset/id"; empty when all is sound
|
|
17
|
+
def problems
|
|
18
|
+
discovery = @configuration.discovery
|
|
19
|
+
failures = {}
|
|
20
|
+
discovery.datasets.each do |dataset|
|
|
21
|
+
Array(adapter.verify(dataset)).each { (failures[dataset.to_s] ||= []) << it }
|
|
22
|
+
discovery.cases(dataset: dataset).each do |kase|
|
|
23
|
+
list = case_problems(kase)
|
|
24
|
+
failures[kase.key] = list unless list.empty?
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
failures
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @param kase [Case]
|
|
31
|
+
# @return [Array<String>]
|
|
32
|
+
def case_problems(kase)
|
|
33
|
+
problems = []
|
|
34
|
+
problems << "input is empty" if kase.input.empty?
|
|
35
|
+
problems << kase.metadata[:expected_error] if kase.metadata[:expected_error]
|
|
36
|
+
return problems unless kase.expected?
|
|
37
|
+
|
|
38
|
+
problems.concat(Array(scorer.verify(kase, context: adapter.context(kase))))
|
|
39
|
+
rescue StandardError => e
|
|
40
|
+
problems << "#{e.class}: #{e.message}"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def adapter = @configuration.adapter
|
|
46
|
+
def scorer = @configuration.scorer
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "logger"
|
|
4
|
+
|
|
5
|
+
module Agent
|
|
6
|
+
module Evals
|
|
7
|
+
# Everything a run would otherwise print as a warning while its progress
|
|
8
|
+
# bars redraw: cases that failed, and what Braintrust, RubyLLM and Ruby
|
|
9
|
+
# itself log. Printed among the bars, each one breaks the redraw; collected
|
|
10
|
+
# here, they are saved to one file, and the run prints only how many.
|
|
11
|
+
#
|
|
12
|
+
# It quacks as an IO, so a Logger, and $stderr, can write to it. Threads
|
|
13
|
+
# share it.
|
|
14
|
+
class Warnings
|
|
15
|
+
def initialize
|
|
16
|
+
@lines = []
|
|
17
|
+
@lock = Mutex.new
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# @param text [#to_s]
|
|
21
|
+
# @return [self]
|
|
22
|
+
def record(text)
|
|
23
|
+
text = text.to_s.chomp
|
|
24
|
+
@lock.synchronize { @lines << text } unless text.strip.empty?
|
|
25
|
+
self
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# @return [Integer] the bytes "written", as IO#write does
|
|
29
|
+
def write(*texts)
|
|
30
|
+
texts.each { record(it) }
|
|
31
|
+
texts.sum { it.to_s.bytesize }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def puts(*texts) = texts.each { record(it) } && nil
|
|
35
|
+
def print(*texts) = write(*texts) && nil
|
|
36
|
+
def <<(text) = record(text)
|
|
37
|
+
def flush = self
|
|
38
|
+
def sync = true
|
|
39
|
+
def sync=(_value); end
|
|
40
|
+
def close = nil
|
|
41
|
+
def tty? = false
|
|
42
|
+
|
|
43
|
+
# @return [Integer]
|
|
44
|
+
def count = @lock.synchronize { @lines.size }
|
|
45
|
+
|
|
46
|
+
# @return [Array<String>]
|
|
47
|
+
def to_a = @lock.synchronize { @lines.dup }
|
|
48
|
+
|
|
49
|
+
# @return [Boolean] whether nothing was recorded
|
|
50
|
+
def none? = count.zero?
|
|
51
|
+
|
|
52
|
+
# @param path [String]
|
|
53
|
+
# @return [String] the path
|
|
54
|
+
def save(path)
|
|
55
|
+
File.write(path, "#{to_a.join("\n\n")}\n")
|
|
56
|
+
path
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Runs the block with $stderr, Ruby's own warnings, and the loggers of
|
|
60
|
+
# whichever optional gems are loaded writing here, and puts them back after.
|
|
61
|
+
#
|
|
62
|
+
# @return [Object] what the block returns
|
|
63
|
+
def capture
|
|
64
|
+
logger = Logger.new(self, level: Logger::WARN)
|
|
65
|
+
stderr = $stderr
|
|
66
|
+
restore = redirect_loggers(logger)
|
|
67
|
+
$stderr = self
|
|
68
|
+
yield
|
|
69
|
+
ensure
|
|
70
|
+
restore&.call
|
|
71
|
+
$stderr = stderr
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
private
|
|
75
|
+
|
|
76
|
+
# @return [Proc] puts the loggers back
|
|
77
|
+
def redirect_loggers(logger)
|
|
78
|
+
braintrust = defined?(Braintrust::Log) ? Braintrust::Log.logger : nil
|
|
79
|
+
ruby_llm = defined?(RubyLLM) ? RubyLLM.instance_variable_get(:@logger) : nil
|
|
80
|
+
Braintrust::Log.logger = logger if defined?(Braintrust::Log)
|
|
81
|
+
RubyLLM.instance_variable_set(:@logger, logger) if defined?(RubyLLM)
|
|
82
|
+
lambda do
|
|
83
|
+
Braintrust::Log.logger = braintrust if defined?(Braintrust::Log)
|
|
84
|
+
RubyLLM.instance_variable_set(:@logger, ruby_llm) if defined?(RubyLLM)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
data/lib/agent/evals.rb
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "dry/cli"
|
|
5
|
+
require "dry/cli/help"
|
|
6
|
+
require "dry/cli/ui"
|
|
7
|
+
require "dry/cli/autocomplete/command"
|
|
8
|
+
require "zeitwerk"
|
|
9
|
+
|
|
10
|
+
module Agent
|
|
11
|
+
# A generic evaluation runner with a one-way boundary. The consumer suite
|
|
12
|
+
# registers an {Adapter}, which runs one {Case} against a {Model} and
|
|
13
|
+
# returns a {Reply} without scoring it, and a {Scorer}, which turns a reply
|
|
14
|
+
# into a {Score} without calling anything. Everything else, from discovery
|
|
15
|
+
# to the leaderboard, is this gem's, and none of it knows what is being
|
|
16
|
+
# evaluated.
|
|
17
|
+
module Evals
|
|
18
|
+
class Error < StandardError; end
|
|
19
|
+
|
|
20
|
+
# Raised by a command that needs an optional gem the bundle does not hold.
|
|
21
|
+
class MissingDependency < Error; end
|
|
22
|
+
|
|
23
|
+
class << self
|
|
24
|
+
# The suite's settings, filled in by {.configure} from `evals/eval_helper.rb`.
|
|
25
|
+
#
|
|
26
|
+
# @return [Configuration]
|
|
27
|
+
def configuration
|
|
28
|
+
@configuration ||= Configuration.new
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Builds the suite's configuration. Called once from the eval helper.
|
|
32
|
+
#
|
|
33
|
+
# @example evals/eval_helper.rb
|
|
34
|
+
# Agent::Evals.configure do |c|
|
|
35
|
+
# c.suite "extract", root: __dir__, env_files: ["../.env"]
|
|
36
|
+
# c.cases "datasets/*/cases/**/input.txt"
|
|
37
|
+
# c.adapter ExtractAdapter.new
|
|
38
|
+
# c.scorer ExtractScorer.new
|
|
39
|
+
# c.before_run { MyGem.reset_configuration! }
|
|
40
|
+
# end
|
|
41
|
+
#
|
|
42
|
+
# @yieldparam configuration [Configuration]
|
|
43
|
+
# @return [Configuration]
|
|
44
|
+
def configure
|
|
45
|
+
yield configuration
|
|
46
|
+
configuration
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Forgets the configuration, so a spec that loads a second helper starts clean.
|
|
50
|
+
#
|
|
51
|
+
# @return [void]
|
|
52
|
+
def reset!
|
|
53
|
+
@configuration = nil
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# @return [Boolean] whether a helper has registered an adapter and a scorer
|
|
57
|
+
def configured? = configuration.complete?
|
|
58
|
+
|
|
59
|
+
# Requires an optional gem the moment a command needs it, and names it
|
|
60
|
+
# when it is missing, instead of letting a bare LoadError surface three
|
|
61
|
+
# frames deep in a provider.
|
|
62
|
+
#
|
|
63
|
+
# @param feature [String] what to require, e.g. "ruby_llm"
|
|
64
|
+
# @param gem_name [String] the gem to add to the Gemfile; the feature when they agree
|
|
65
|
+
# @param needed_for [String] what the user was doing
|
|
66
|
+
# @return [void]
|
|
67
|
+
# @raise [MissingDependency]
|
|
68
|
+
def optional!(feature, gem_name = feature, needed_for:)
|
|
69
|
+
require feature
|
|
70
|
+
rescue LoadError
|
|
71
|
+
raise MissingDependency, "#{needed_for} needs the #{gem_name} gem: add `gem \"#{gem_name}\"` to your Gemfile"
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
require_relative "evals/version"
|
|
78
|
+
|
|
79
|
+
loader = Zeitwerk::Loader.for_gem_extension(Agent)
|
|
80
|
+
loader.inflector.inflect("cli" => "CLI")
|
|
81
|
+
loader.ignore(File.expand_path("evals/version.rb", __dir__))
|
|
82
|
+
loader.setup
|
metadata
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: agent-evals
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Konstantin Gredeskoul
|
|
8
|
+
bindir: exe
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: dotenv
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
-
|
|
17
|
+
- ~>
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: "3.2"
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
-
|
|
25
|
+
- ~>
|
|
26
|
+
- !ruby/object:Gem::Version
|
|
27
|
+
version: "3.2"
|
|
28
|
+
- !ruby/object:Gem::Dependency
|
|
29
|
+
name: dry-cli
|
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
|
31
|
+
requirements:
|
|
32
|
+
-
|
|
33
|
+
- ~>
|
|
34
|
+
- !ruby/object:Gem::Version
|
|
35
|
+
version: "1.4"
|
|
36
|
+
type: :runtime
|
|
37
|
+
prerelease: false
|
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
39
|
+
requirements:
|
|
40
|
+
-
|
|
41
|
+
- ~>
|
|
42
|
+
- !ruby/object:Gem::Version
|
|
43
|
+
version: "1.4"
|
|
44
|
+
- !ruby/object:Gem::Dependency
|
|
45
|
+
name: dry-cli-autocomplete
|
|
46
|
+
requirement: !ruby/object:Gem::Requirement
|
|
47
|
+
requirements:
|
|
48
|
+
-
|
|
49
|
+
- ~>
|
|
50
|
+
- !ruby/object:Gem::Version
|
|
51
|
+
version: "0.6"
|
|
52
|
+
type: :runtime
|
|
53
|
+
prerelease: false
|
|
54
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
55
|
+
requirements:
|
|
56
|
+
-
|
|
57
|
+
- ~>
|
|
58
|
+
- !ruby/object:Gem::Version
|
|
59
|
+
version: "0.6"
|
|
60
|
+
- !ruby/object:Gem::Dependency
|
|
61
|
+
name: dry-cli-help
|
|
62
|
+
requirement: !ruby/object:Gem::Requirement
|
|
63
|
+
requirements:
|
|
64
|
+
-
|
|
65
|
+
- ~>
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: "0.6"
|
|
68
|
+
type: :runtime
|
|
69
|
+
prerelease: false
|
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
-
|
|
73
|
+
- ~>
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: "0.6"
|
|
76
|
+
- !ruby/object:Gem::Dependency
|
|
77
|
+
name: dry-cli-ui
|
|
78
|
+
requirement: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
-
|
|
81
|
+
- ~>
|
|
82
|
+
- !ruby/object:Gem::Version
|
|
83
|
+
version: "0.7"
|
|
84
|
+
type: :runtime
|
|
85
|
+
prerelease: false
|
|
86
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
87
|
+
requirements:
|
|
88
|
+
-
|
|
89
|
+
- ~>
|
|
90
|
+
- !ruby/object:Gem::Version
|
|
91
|
+
version: "0.7"
|
|
92
|
+
- !ruby/object:Gem::Dependency
|
|
93
|
+
name: zeitwerk
|
|
94
|
+
requirement: !ruby/object:Gem::Requirement
|
|
95
|
+
requirements:
|
|
96
|
+
-
|
|
97
|
+
- ~>
|
|
98
|
+
- !ruby/object:Gem::Version
|
|
99
|
+
version: "2.8"
|
|
100
|
+
type: :runtime
|
|
101
|
+
prerelease: false
|
|
102
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
103
|
+
requirements:
|
|
104
|
+
-
|
|
105
|
+
- ~>
|
|
106
|
+
- !ruby/object:Gem::Version
|
|
107
|
+
version: "2.8"
|
|
108
|
+
- !ruby/object:Gem::Dependency
|
|
109
|
+
name: pastel
|
|
110
|
+
requirement: !ruby/object:Gem::Requirement
|
|
111
|
+
requirements:
|
|
112
|
+
-
|
|
113
|
+
- ~>
|
|
114
|
+
- !ruby/object:Gem::Version
|
|
115
|
+
version: "0.8"
|
|
116
|
+
type: :runtime
|
|
117
|
+
prerelease: false
|
|
118
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
119
|
+
requirements:
|
|
120
|
+
-
|
|
121
|
+
- ~>
|
|
122
|
+
- !ruby/object:Gem::Version
|
|
123
|
+
version: "0.8"
|
|
124
|
+
- !ruby/object:Gem::Dependency
|
|
125
|
+
name: tty-box
|
|
126
|
+
requirement: !ruby/object:Gem::Requirement
|
|
127
|
+
requirements:
|
|
128
|
+
-
|
|
129
|
+
- ~>
|
|
130
|
+
- !ruby/object:Gem::Version
|
|
131
|
+
version: "0.7"
|
|
132
|
+
type: :runtime
|
|
133
|
+
prerelease: false
|
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
135
|
+
requirements:
|
|
136
|
+
-
|
|
137
|
+
- ~>
|
|
138
|
+
- !ruby/object:Gem::Version
|
|
139
|
+
version: "0.7"
|
|
140
|
+
- !ruby/object:Gem::Dependency
|
|
141
|
+
name: tty-table
|
|
142
|
+
requirement: !ruby/object:Gem::Requirement
|
|
143
|
+
requirements:
|
|
144
|
+
-
|
|
145
|
+
- ~>
|
|
146
|
+
- !ruby/object:Gem::Version
|
|
147
|
+
version: "0.12"
|
|
148
|
+
type: :runtime
|
|
149
|
+
prerelease: false
|
|
150
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
151
|
+
requirements:
|
|
152
|
+
-
|
|
153
|
+
- ~>
|
|
154
|
+
- !ruby/object:Gem::Version
|
|
155
|
+
version: "0.12"
|
|
156
|
+
- !ruby/object:Gem::Dependency
|
|
157
|
+
name: logger
|
|
158
|
+
requirement: !ruby/object:Gem::Requirement
|
|
159
|
+
requirements:
|
|
160
|
+
-
|
|
161
|
+
- ~>
|
|
162
|
+
- !ruby/object:Gem::Version
|
|
163
|
+
version: "1.6"
|
|
164
|
+
type: :runtime
|
|
165
|
+
prerelease: false
|
|
166
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
167
|
+
requirements:
|
|
168
|
+
-
|
|
169
|
+
- ~>
|
|
170
|
+
- !ruby/object:Gem::Version
|
|
171
|
+
version: "1.6"
|
|
172
|
+
description: "Runs a suite of cases against one or more models through an adapter the consumer writes, scores each reply with a scorer the consumer writes, and prints leaderboards, per-case breakdowns and Braintrust experiments. The gem knows nothing about what is being evaluated: it owns discovery, the model lineup, providers, parallel execution, reporting and the command line."
|
|
173
|
+
email:
|
|
174
|
+
- kigster@gmail.com
|
|
175
|
+
executables:
|
|
176
|
+
- agent-evals
|
|
177
|
+
extensions: []
|
|
178
|
+
extra_rdoc_files: []
|
|
179
|
+
files:
|
|
180
|
+
- CHANGELOG.md
|
|
181
|
+
- LICENSE.txt
|
|
182
|
+
- README.md
|
|
183
|
+
- exe/agent-evals
|
|
184
|
+
- lib/agent/evals.rb
|
|
185
|
+
- lib/agent/evals/adapter.rb
|
|
186
|
+
- lib/agent/evals/case.rb
|
|
187
|
+
- lib/agent/evals/cli.rb
|
|
188
|
+
- lib/agent/evals/cli/cases.rb
|
|
189
|
+
- lib/agent/evals/cli/command.rb
|
|
190
|
+
- lib/agent/evals/cli/compare.rb
|
|
191
|
+
- lib/agent/evals/cli/model_command.rb
|
|
192
|
+
- lib/agent/evals/cli/progress_bars.rb
|
|
193
|
+
- lib/agent/evals/cli/run.rb
|
|
194
|
+
- lib/agent/evals/cli/verify.rb
|
|
195
|
+
- lib/agent/evals/cli/version.rb
|
|
196
|
+
- lib/agent/evals/completion.rb
|
|
197
|
+
- lib/agent/evals/config.rb
|
|
198
|
+
- lib/agent/evals/configuration.rb
|
|
199
|
+
- lib/agent/evals/contender.rb
|
|
200
|
+
- lib/agent/evals/discovery.rb
|
|
201
|
+
- lib/agent/evals/experiment.rb
|
|
202
|
+
- lib/agent/evals/helper.rb
|
|
203
|
+
- lib/agent/evals/launcher.rb
|
|
204
|
+
- lib/agent/evals/metric.rb
|
|
205
|
+
- lib/agent/evals/model.rb
|
|
206
|
+
- lib/agent/evals/providers/base.rb
|
|
207
|
+
- lib/agent/evals/providers/catalog.rb
|
|
208
|
+
- lib/agent/evals/providers/open_router.rb
|
|
209
|
+
- lib/agent/evals/providers/registry.rb
|
|
210
|
+
- lib/agent/evals/providers/type_safe.rb
|
|
211
|
+
- lib/agent/evals/reply.rb
|
|
212
|
+
- lib/agent/evals/run_result.rb
|
|
213
|
+
- lib/agent/evals/runtime.rb
|
|
214
|
+
- lib/agent/evals/schema_validator.rb
|
|
215
|
+
- lib/agent/evals/score.rb
|
|
216
|
+
- lib/agent/evals/scorer.rb
|
|
217
|
+
- lib/agent/evals/testing/echo_adapter.rb
|
|
218
|
+
- lib/agent/evals/testing/fake_model.rb
|
|
219
|
+
- lib/agent/evals/testing/fake_provider.rb
|
|
220
|
+
- lib/agent/evals/tracker.rb
|
|
221
|
+
- lib/agent/evals/trackers/braintrust.rb
|
|
222
|
+
- lib/agent/evals/trackers/local.rb
|
|
223
|
+
- lib/agent/evals/trackers/logfire.rb
|
|
224
|
+
- lib/agent/evals/trackers/registry.rb
|
|
225
|
+
- lib/agent/evals/usage.rb
|
|
226
|
+
- lib/agent/evals/verify.rb
|
|
227
|
+
- lib/agent/evals/version.rb
|
|
228
|
+
- lib/agent/evals/warnings.rb
|
|
229
|
+
homepage: "https://github.com/kigster/agent-evals"
|
|
230
|
+
licenses:
|
|
231
|
+
- MIT
|
|
232
|
+
metadata:
|
|
233
|
+
allowed_push_host: "https://rubygems.org"
|
|
234
|
+
homepage_uri: "https://github.com/kigster/agent-evals"
|
|
235
|
+
source_code_uri: "https://github.com/kigster/agent-evals"
|
|
236
|
+
changelog_uri: "https://github.com/kigster/agent-evals/blob/main/CHANGELOG.md"
|
|
237
|
+
rubygems_mfa_required: "true"
|
|
238
|
+
rdoc_options: []
|
|
239
|
+
require_paths:
|
|
240
|
+
- lib
|
|
241
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
242
|
+
requirements:
|
|
243
|
+
-
|
|
244
|
+
- ">="
|
|
245
|
+
- !ruby/object:Gem::Version
|
|
246
|
+
version: 3.4.0
|
|
247
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
248
|
+
requirements:
|
|
249
|
+
-
|
|
250
|
+
- ">="
|
|
251
|
+
- !ruby/object:Gem::Version
|
|
252
|
+
version: "0"
|
|
253
|
+
requirements: []
|
|
254
|
+
rubygems_version: 4.1.0.beta2
|
|
255
|
+
specification_version: 4
|
|
256
|
+
summary: "A generic evaluation runner for LLM-backed code: adapters run, scorers score, the CLI reports"
|
|
257
|
+
test_files: []
|