riffer 0.12.0 → 0.13.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/.release-please-manifest.json +1 -1
- data/CHANGELOG.md +7 -0
- data/docs/08_EVALS.md +12 -14
- data/docs/09_GUARDRAILS.md +3 -23
- data/lib/riffer/evals/evaluator.rb +1 -22
- data/lib/riffer/evals/evaluators/answer_relevancy.rb +0 -1
- data/lib/riffer/evals/evaluators.rb +1 -54
- data/lib/riffer/evals/metric.rb +13 -14
- data/lib/riffer/evals/profile.rb +4 -5
- data/lib/riffer/evals/result.rb +6 -6
- data/lib/riffer/evals/runner.rb +1 -4
- data/lib/riffer/guardrail.rb +0 -25
- data/lib/riffer/guardrails/max_length.rb +0 -2
- data/lib/riffer/guardrails/modification.rb +11 -7
- data/lib/riffer/guardrails/runner.rb +2 -2
- data/lib/riffer/guardrails/tripwire.rb +8 -8
- data/lib/riffer/stream_events/guardrail_modification.rb +3 -3
- data/lib/riffer/stream_events/guardrail_tripwire.rb +4 -4
- data/lib/riffer/version.rb +1 -1
- data/sig/generated/riffer/evals/evaluator.rbs +0 -11
- data/sig/generated/riffer/evals/evaluators.rbs +1 -38
- data/sig/generated/riffer/evals/metric.rbs +6 -9
- data/sig/generated/riffer/evals/profile.rbs +3 -4
- data/sig/generated/riffer/evals/result.rbs +6 -6
- data/sig/generated/riffer/guardrail.rbs +0 -18
- data/sig/generated/riffer/guardrails/modification.rbs +5 -5
- data/sig/generated/riffer/guardrails/tripwire.rbs +6 -6
- data/sig/generated/riffer/stream_events/guardrail_modification.rbs +3 -3
- data/sig/generated/riffer/stream_events/guardrail_tripwire.rbs +3 -3
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a7a4f27800f9f5a266d408a1b8b8d6d96f6c59307b4761d34d3a1365b9b71bb8
|
|
4
|
+
data.tar.gz: 6719e5013f8d83c78f2647808dd0d27a024ec432085311af02b1dc7cfbdaacfb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 24356e56e024eaf5223c91c97b72bf4e90a9dd74721d12dac6b5d0f294bea305914d6f074467e915dfd64adbf3eea5a07484147a394f51613f7fe16e828e4c36
|
|
7
|
+
data.tar.gz: 6c8b8d464d94b56f044196f81ec298b01824dea114aca266b82de020c82521ce975451c643c5307d532c23f6fb85e2d38f4931f931cf13dee5e54b53ba5e8211
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.13.0](https://github.com/janeapp/riffer/compare/riffer/v0.12.0...riffer/v0.13.0) (2026-02-12)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* remove identifiers from evals and guardrails ([#112](https://github.com/janeapp/riffer/issues/112)) ([7b60707](https://github.com/janeapp/riffer/commit/7b60707206e53451f5bee2faf1c12a75eaf26d98))
|
|
14
|
+
|
|
8
15
|
## [0.12.0](https://github.com/janeapp/riffer/compare/riffer/v0.11.0...riffer/v0.12.0) (2026-02-11)
|
|
9
16
|
|
|
10
17
|
|
data/docs/08_EVALS.md
CHANGED
|
@@ -24,7 +24,7 @@ module QualityEvals
|
|
|
24
24
|
include Riffer::Evals::Profile
|
|
25
25
|
|
|
26
26
|
ai_evals do
|
|
27
|
-
metric
|
|
27
|
+
metric Riffer::Evals::Evaluators::AnswerRelevancy, min: 0.85
|
|
28
28
|
end
|
|
29
29
|
end
|
|
30
30
|
|
|
@@ -53,7 +53,7 @@ The judge model is the LLM that evaluates agent outputs. You can use any configu
|
|
|
53
53
|
|
|
54
54
|
## Built-in Evaluators
|
|
55
55
|
|
|
56
|
-
###
|
|
56
|
+
### AnswerRelevancy
|
|
57
57
|
|
|
58
58
|
Evaluates how well a response addresses the input question.
|
|
59
59
|
|
|
@@ -67,7 +67,7 @@ Evaluates how well a response addresses the input question.
|
|
|
67
67
|
|
|
68
68
|
```ruby
|
|
69
69
|
ai_evals do
|
|
70
|
-
metric
|
|
70
|
+
metric Riffer::Evals::Evaluators::AnswerRelevancy, min: 0.85
|
|
71
71
|
end
|
|
72
72
|
```
|
|
73
73
|
|
|
@@ -82,7 +82,7 @@ module QualityEvals
|
|
|
82
82
|
include Riffer::Evals::Profile
|
|
83
83
|
|
|
84
84
|
ai_evals do
|
|
85
|
-
metric
|
|
85
|
+
metric Riffer::Evals::Evaluators::AnswerRelevancy, min: 0.85
|
|
86
86
|
end
|
|
87
87
|
end
|
|
88
88
|
```
|
|
@@ -95,7 +95,7 @@ end
|
|
|
95
95
|
|
|
96
96
|
```ruby
|
|
97
97
|
ai_evals do
|
|
98
|
-
metric
|
|
98
|
+
metric Riffer::Evals::Evaluators::AnswerRelevancy, min: 0.85, weight: 2.0 # Weighted more heavily
|
|
99
99
|
end
|
|
100
100
|
```
|
|
101
101
|
|
|
@@ -138,7 +138,7 @@ result.to_h # => Hash representation
|
|
|
138
138
|
Individual evaluation results:
|
|
139
139
|
|
|
140
140
|
```ruby
|
|
141
|
-
result.results.first.evaluator # =>
|
|
141
|
+
result.results.first.evaluator # => Riffer::Evals::Evaluators::AnswerRelevancy
|
|
142
142
|
result.results.first.score # => 0.92
|
|
143
143
|
result.results.first.reason # => "The response directly addresses..."
|
|
144
144
|
result.results.first.higher_is_better # => true
|
|
@@ -151,7 +151,6 @@ Create evaluators by subclassing `Riffer::Evals::Evaluator`:
|
|
|
151
151
|
```ruby
|
|
152
152
|
# app/evals/medical_accuracy_evaluator.rb
|
|
153
153
|
class MedicalAccuracyEvaluator < Riffer::Evals::Evaluator
|
|
154
|
-
identifier "medical_accuracy"
|
|
155
154
|
description "Evaluates medical information accuracy"
|
|
156
155
|
higher_is_better true
|
|
157
156
|
judge_model "anthropic/claude-opus-4-5-20251101" # Optional override
|
|
@@ -179,20 +178,20 @@ class MedicalAccuracyEvaluator < Riffer::Evals::Evaluator
|
|
|
179
178
|
end
|
|
180
179
|
```
|
|
181
180
|
|
|
182
|
-
###
|
|
181
|
+
### Using Custom Evaluators
|
|
183
182
|
|
|
184
|
-
|
|
183
|
+
Reference your custom evaluator class directly in eval profiles:
|
|
185
184
|
|
|
186
185
|
```ruby
|
|
187
|
-
|
|
188
|
-
|
|
186
|
+
ai_evals do
|
|
187
|
+
metric MedicalAccuracyEvaluator, min: 0.9
|
|
188
|
+
end
|
|
189
189
|
```
|
|
190
190
|
|
|
191
191
|
### Evaluator DSL
|
|
192
192
|
|
|
193
193
|
Class methods:
|
|
194
194
|
|
|
195
|
-
- `identifier(value)` - Set the evaluator identifier (defaults to snake_case class name)
|
|
196
195
|
- `description(value)` - Human-readable description
|
|
197
196
|
- `higher_is_better(value)` - Whether higher scores are better (default: true)
|
|
198
197
|
- `judge_model(value)` - Override the global judge model
|
|
@@ -231,7 +230,6 @@ Evaluators don't have to use LLM-as-judge:
|
|
|
231
230
|
|
|
232
231
|
```ruby
|
|
233
232
|
class LengthEvaluator < Riffer::Evals::Evaluator
|
|
234
|
-
identifier "response_length"
|
|
235
233
|
description "Checks response is within expected length"
|
|
236
234
|
higher_is_better true
|
|
237
235
|
|
|
@@ -289,7 +287,7 @@ module QualityEvals
|
|
|
289
287
|
include Riffer::Evals::Profile
|
|
290
288
|
|
|
291
289
|
ai_evals do
|
|
292
|
-
metric
|
|
290
|
+
metric Riffer::Evals::Evaluators::AnswerRelevancy, min: 0.85, weight: 2.0
|
|
293
291
|
end
|
|
294
292
|
end
|
|
295
293
|
|
data/docs/09_GUARDRAILS.md
CHANGED
|
@@ -41,20 +41,6 @@ class ContentFilterGuardrail < Riffer::Guardrail
|
|
|
41
41
|
end
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
## Configuration Methods
|
|
45
|
-
|
|
46
|
-
### identifier
|
|
47
|
-
|
|
48
|
-
Sets a custom identifier (defaults to snake_case class name):
|
|
49
|
-
|
|
50
|
-
```ruby
|
|
51
|
-
class MyGuardrail < Riffer::Guardrail
|
|
52
|
-
identifier "my_custom_guardrail"
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
MyGuardrail.identifier # => "my_custom_guardrail"
|
|
56
|
-
```
|
|
57
|
-
|
|
58
44
|
## Processing Methods
|
|
59
45
|
|
|
60
46
|
### process_input
|
|
@@ -186,7 +172,7 @@ response = MyAgent.generate("Hello")
|
|
|
186
172
|
if response.blocked?
|
|
187
173
|
puts "Blocked: #{response.tripwire.reason}"
|
|
188
174
|
puts "Phase: #{response.tripwire.phase}"
|
|
189
|
-
puts "Guardrail: #{response.tripwire.
|
|
175
|
+
puts "Guardrail: #{response.tripwire.guardrail}"
|
|
190
176
|
else
|
|
191
177
|
puts response.content
|
|
192
178
|
end
|
|
@@ -201,7 +187,7 @@ response = MyAgent.generate("Hello")
|
|
|
201
187
|
|
|
202
188
|
if response.modified?
|
|
203
189
|
response.modifications.each do |mod|
|
|
204
|
-
puts "Guardrail: #{mod.
|
|
190
|
+
puts "Guardrail: #{mod.guardrail}"
|
|
205
191
|
puts "Phase: #{mod.phase}"
|
|
206
192
|
puts "Changed indices: #{mod.message_indices}"
|
|
207
193
|
end
|
|
@@ -214,7 +200,7 @@ During streaming, `GuardrailModification` events are emitted when transforms occ
|
|
|
214
200
|
MyAgent.stream("Hello").each do |event|
|
|
215
201
|
case event
|
|
216
202
|
when Riffer::StreamEvents::GuardrailModification
|
|
217
|
-
puts "Modified by: #{event.
|
|
203
|
+
puts "Modified by: #{event.guardrail} (#{event.phase})"
|
|
218
204
|
when Riffer::StreamEvents::TextDelta
|
|
219
205
|
print event.content
|
|
220
206
|
end
|
|
@@ -264,8 +250,6 @@ end
|
|
|
264
250
|
|
|
265
251
|
```ruby
|
|
266
252
|
class UnicodeNormalizer < Riffer::Guardrail
|
|
267
|
-
identifier "unicode_normalizer"
|
|
268
|
-
|
|
269
253
|
def process_input(messages, context:)
|
|
270
254
|
normalized = messages.map do |msg|
|
|
271
255
|
if msg.respond_to?(:content) && msg.content
|
|
@@ -296,8 +280,6 @@ end
|
|
|
296
280
|
|
|
297
281
|
```ruby
|
|
298
282
|
class TokenLimiter < Riffer::Guardrail
|
|
299
|
-
identifier "token_limiter"
|
|
300
|
-
|
|
301
283
|
def initialize(limit:, strategy: :truncate)
|
|
302
284
|
super()
|
|
303
285
|
@limit = limit
|
|
@@ -339,8 +321,6 @@ end
|
|
|
339
321
|
|
|
340
322
|
```ruby
|
|
341
323
|
class ContentPolicyFilter < Riffer::Guardrail
|
|
342
|
-
identifier "content_policy"
|
|
343
|
-
|
|
344
324
|
BLOCKED_PATTERNS = [
|
|
345
325
|
/pattern1/i,
|
|
346
326
|
/pattern2/i
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
# See Riffer::Evals::Evaluators.
|
|
10
10
|
#
|
|
11
11
|
# class MyEvaluator < Riffer::Evals::Evaluator
|
|
12
|
-
# identifier "my_evaluator"
|
|
13
12
|
# description "Evaluates response quality"
|
|
14
13
|
# higher_is_better true
|
|
15
14
|
# judge_model "anthropic/claude-opus-4-5-20251101"
|
|
@@ -25,16 +24,6 @@
|
|
|
25
24
|
#
|
|
26
25
|
class Riffer::Evals::Evaluator
|
|
27
26
|
class << self
|
|
28
|
-
include Riffer::Helpers::ClassNameConverter
|
|
29
|
-
|
|
30
|
-
# Gets or sets the evaluator identifier.
|
|
31
|
-
#
|
|
32
|
-
#: (?String?) -> String
|
|
33
|
-
def identifier(value = nil)
|
|
34
|
-
return @identifier || class_name_to_identifier(name) if value.nil?
|
|
35
|
-
@identifier = value.to_s
|
|
36
|
-
end
|
|
37
|
-
|
|
38
27
|
# Gets or sets the evaluator description.
|
|
39
28
|
#
|
|
40
29
|
#: (?String?) -> String?
|
|
@@ -58,16 +47,6 @@ class Riffer::Evals::Evaluator
|
|
|
58
47
|
return @judge_model if value.nil?
|
|
59
48
|
@judge_model = value.to_s
|
|
60
49
|
end
|
|
61
|
-
|
|
62
|
-
private
|
|
63
|
-
|
|
64
|
-
#: (String?) -> String?
|
|
65
|
-
def class_name_to_identifier(name)
|
|
66
|
-
return nil if name.nil?
|
|
67
|
-
class_name = name.split("::").last
|
|
68
|
-
return nil if class_name.nil?
|
|
69
|
-
class_name_to_path(class_name).sub(/_evaluator$/, "")
|
|
70
|
-
end
|
|
71
50
|
end
|
|
72
51
|
|
|
73
52
|
# Evaluates an input/output pair.
|
|
@@ -97,7 +76,7 @@ class Riffer::Evals::Evaluator
|
|
|
97
76
|
#: (score: Float, ?reason: String?, ?metadata: Hash[Symbol, untyped]) -> Riffer::Evals::Result
|
|
98
77
|
def result(score:, reason: nil, metadata: {})
|
|
99
78
|
Riffer::Evals::Result.new(
|
|
100
|
-
evaluator: self.class
|
|
79
|
+
evaluator: self.class,
|
|
101
80
|
score: score,
|
|
102
81
|
reason: reason,
|
|
103
82
|
metadata: metadata,
|
|
@@ -1,59 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
# rbs_inline: enabled
|
|
3
3
|
|
|
4
|
-
# Namespace for built-in evaluators
|
|
5
|
-
#
|
|
6
|
-
# See Riffer::Evals::Evaluators::Repository for registering custom evaluators.
|
|
4
|
+
# Namespace for built-in evaluators.
|
|
7
5
|
module Riffer::Evals::Evaluators
|
|
8
|
-
# Repository for looking up evaluators by identifier.
|
|
9
|
-
#
|
|
10
|
-
# Built-in evaluators are always available. Custom evaluators
|
|
11
|
-
# can be registered using Repository.register in your app initialization.
|
|
12
|
-
#
|
|
13
|
-
# # Register a custom evaluator (config/initializers/riffer.rb)
|
|
14
|
-
# Riffer::Evals::Evaluators::Repository.register(:my_evaluator, MyEvaluator)
|
|
15
|
-
#
|
|
16
|
-
# # Find an evaluator
|
|
17
|
-
# Riffer::Evals::Evaluators::Repository.find(:answer_relevancy)
|
|
18
|
-
# # => Riffer::Evals::Evaluators::AnswerRelevancy
|
|
19
|
-
#
|
|
20
|
-
class Repository
|
|
21
|
-
# Built-in evaluators (always available).
|
|
22
|
-
BUILT_IN = {
|
|
23
|
-
answer_relevancy: -> { Riffer::Evals::Evaluators::AnswerRelevancy }
|
|
24
|
-
}.freeze #: Hash[Symbol, ^() -> singleton(Riffer::Evals::Evaluator)]
|
|
25
|
-
|
|
26
|
-
@custom = {}
|
|
27
|
-
|
|
28
|
-
class << self
|
|
29
|
-
# Registers a custom evaluator class with an identifier.
|
|
30
|
-
#
|
|
31
|
-
#: ((String | Symbol), singleton(Riffer::Evals::Evaluator)) -> void
|
|
32
|
-
def register(identifier, evaluator_class)
|
|
33
|
-
@custom[identifier.to_sym] = -> { evaluator_class }
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
# Finds an evaluator class by identifier.
|
|
37
|
-
#
|
|
38
|
-
#: ((String | Symbol)) -> singleton(Riffer::Evals::Evaluator)?
|
|
39
|
-
def find(identifier)
|
|
40
|
-
id = identifier.to_sym
|
|
41
|
-
(@custom[id] || BUILT_IN[id])&.call
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
# Returns all registered evaluators (built-in and custom).
|
|
45
|
-
#
|
|
46
|
-
#: () -> Hash[Symbol, singleton(Riffer::Evals::Evaluator)]
|
|
47
|
-
def all
|
|
48
|
-
BUILT_IN.merge(@custom).transform_values(&:call)
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
# Clears custom registrations (for testing). Built-ins remain.
|
|
52
|
-
#
|
|
53
|
-
#: () -> void
|
|
54
|
-
def clear
|
|
55
|
-
@custom = {}
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
6
|
end
|
data/lib/riffer/evals/metric.rb
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
# Metrics define which evaluator to use and what thresholds determine pass/fail.
|
|
7
7
|
#
|
|
8
8
|
# metric = Riffer::Evals::Metric.new(
|
|
9
|
-
#
|
|
9
|
+
# evaluator_class: Riffer::Evals::Evaluators::AnswerRelevancy,
|
|
10
10
|
# min: 0.85,
|
|
11
11
|
# weight: 1.0
|
|
12
12
|
# )
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
# metric.passes?(result) # => true/false based on thresholds
|
|
15
15
|
#
|
|
16
16
|
class Riffer::Evals::Metric
|
|
17
|
-
# The
|
|
18
|
-
attr_reader :
|
|
17
|
+
# The evaluator class to use.
|
|
18
|
+
attr_reader :evaluator_class #: singleton(Riffer::Evals::Evaluator)
|
|
19
19
|
|
|
20
20
|
# Minimum acceptable score (for higher_is_better evaluators).
|
|
21
21
|
attr_reader :min #: Float?
|
|
@@ -28,21 +28,20 @@ class Riffer::Evals::Metric
|
|
|
28
28
|
|
|
29
29
|
# Initializes a new metric.
|
|
30
30
|
#
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
# Raises Riffer::ArgumentError if evaluator_class is not a subclass of Riffer::Evals::Evaluator.
|
|
32
|
+
#
|
|
33
|
+
#: (evaluator_class: singleton(Riffer::Evals::Evaluator), ?min: Float?, ?max: Float?, ?weight: Float) -> void
|
|
34
|
+
def initialize(evaluator_class:, min: nil, max: nil, weight: 1.0)
|
|
35
|
+
unless evaluator_class.is_a?(Class) && evaluator_class < Riffer::Evals::Evaluator
|
|
36
|
+
raise Riffer::ArgumentError, "evaluator_class must be a subclass of Riffer::Evals::Evaluator, got #{evaluator_class.inspect}"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
@evaluator_class = evaluator_class
|
|
34
40
|
@min = min&.to_f
|
|
35
41
|
@max = max&.to_f
|
|
36
42
|
@weight = weight.to_f
|
|
37
43
|
end
|
|
38
44
|
|
|
39
|
-
# Returns the evaluator class for this metric.
|
|
40
|
-
#
|
|
41
|
-
#: () -> singleton(Riffer::Evals::Evaluator)?
|
|
42
|
-
def evaluator_class
|
|
43
|
-
Riffer::Evals::Evaluators::Repository.find(evaluator_identifier)
|
|
44
|
-
end
|
|
45
|
-
|
|
46
45
|
# Checks if a result passes this metric's thresholds.
|
|
47
46
|
#
|
|
48
47
|
#: (Riffer::Evals::Result) -> bool
|
|
@@ -57,7 +56,7 @@ class Riffer::Evals::Metric
|
|
|
57
56
|
#: () -> Hash[Symbol, untyped]
|
|
58
57
|
def to_h
|
|
59
58
|
{
|
|
60
|
-
|
|
59
|
+
evaluator_class: evaluator_class,
|
|
61
60
|
min: min,
|
|
62
61
|
max: max,
|
|
63
62
|
weight: weight
|
data/lib/riffer/evals/profile.rb
CHANGED
|
@@ -10,8 +10,7 @@
|
|
|
10
10
|
# include Riffer::Evals::Profile
|
|
11
11
|
#
|
|
12
12
|
# ai_evals do
|
|
13
|
-
# metric
|
|
14
|
-
# metric :hallucination, max: 0.10
|
|
13
|
+
# metric Riffer::Evals::Evaluators::AnswerRelevancy, min: 0.85
|
|
15
14
|
# end
|
|
16
15
|
# end
|
|
17
16
|
#
|
|
@@ -49,10 +48,10 @@ module Riffer::Evals::Profile
|
|
|
49
48
|
|
|
50
49
|
# Defines a metric with thresholds.
|
|
51
50
|
#
|
|
52
|
-
#: ((
|
|
53
|
-
def metric(
|
|
51
|
+
#: (singleton(Riffer::Evals::Evaluator), ?min: Float?, ?max: Float?, ?weight: Float) -> void
|
|
52
|
+
def metric(evaluator_class, min: nil, max: nil, weight: 1.0)
|
|
54
53
|
metrics << Riffer::Evals::Metric.new(
|
|
55
|
-
|
|
54
|
+
evaluator_class: evaluator_class,
|
|
56
55
|
min: min,
|
|
57
56
|
max: max,
|
|
58
57
|
weight: weight
|
data/lib/riffer/evals/result.rb
CHANGED
|
@@ -6,19 +6,19 @@
|
|
|
6
6
|
# Contains the score, reason, and metadata from running an evaluator.
|
|
7
7
|
#
|
|
8
8
|
# result = Riffer::Evals::Result.new(
|
|
9
|
-
# evaluator:
|
|
9
|
+
# evaluator: Riffer::Evals::Evaluators::AnswerRelevancy,
|
|
10
10
|
# score: 0.85,
|
|
11
11
|
# reason: "The response addresses the question directly.",
|
|
12
12
|
# higher_is_better: true
|
|
13
13
|
# )
|
|
14
14
|
#
|
|
15
15
|
# result.score # => 0.85
|
|
16
|
-
# result.evaluator # =>
|
|
16
|
+
# result.evaluator # => Riffer::Evals::Evaluators::AnswerRelevancy
|
|
17
17
|
# result.higher_is_better # => true
|
|
18
18
|
#
|
|
19
19
|
class Riffer::Evals::Result
|
|
20
|
-
# The
|
|
21
|
-
attr_reader :evaluator #:
|
|
20
|
+
# The evaluator class that produced this result.
|
|
21
|
+
attr_reader :evaluator #: singleton(Riffer::Evals::Evaluator)
|
|
22
22
|
|
|
23
23
|
# The evaluation score (0.0 to 1.0).
|
|
24
24
|
attr_reader :score #: Float
|
|
@@ -36,7 +36,7 @@ class Riffer::Evals::Result
|
|
|
36
36
|
#
|
|
37
37
|
# Raises Riffer::ArgumentError if score is not between 0.0 and 1.0.
|
|
38
38
|
#
|
|
39
|
-
#: (evaluator:
|
|
39
|
+
#: (evaluator: singleton(Riffer::Evals::Evaluator), score: Float, ?reason: String?, ?metadata: Hash[Symbol, untyped], ?higher_is_better: bool) -> void
|
|
40
40
|
def initialize(evaluator:, score:, reason: nil, metadata: {}, higher_is_better: true)
|
|
41
41
|
@evaluator = evaluator
|
|
42
42
|
@score = score.to_f
|
|
@@ -51,7 +51,7 @@ class Riffer::Evals::Result
|
|
|
51
51
|
#: () -> Hash[Symbol, untyped]
|
|
52
52
|
def to_h
|
|
53
53
|
{
|
|
54
|
-
evaluator: evaluator,
|
|
54
|
+
evaluator: evaluator.name,
|
|
55
55
|
score: score,
|
|
56
56
|
reason: reason,
|
|
57
57
|
metadata: metadata,
|
data/lib/riffer/evals/runner.rb
CHANGED
|
@@ -29,10 +29,7 @@ class Riffer::Evals::Runner
|
|
|
29
29
|
#: (input: String, output: String, ?context: Hash[Symbol, untyped]?) -> Riffer::Evals::RunResult
|
|
30
30
|
def run(input:, output:, context: nil)
|
|
31
31
|
results = metrics.map do |metric|
|
|
32
|
-
|
|
33
|
-
raise Riffer::ArgumentError, "Evaluator not found: #{metric.evaluator_identifier}" unless evaluator_class
|
|
34
|
-
|
|
35
|
-
evaluator = evaluator_class.new
|
|
32
|
+
evaluator = metric.evaluator_class.new
|
|
36
33
|
evaluator.evaluate(input: input, output: output, context: context)
|
|
37
34
|
end
|
|
38
35
|
|
data/lib/riffer/guardrail.rb
CHANGED
|
@@ -6,8 +6,6 @@
|
|
|
6
6
|
# Subclass this to create custom guardrails:
|
|
7
7
|
#
|
|
8
8
|
# class MyGuardrail < Riffer::Guardrail
|
|
9
|
-
# identifier "my_guardrail"
|
|
10
|
-
#
|
|
11
9
|
# def process_input(messages, context:)
|
|
12
10
|
# # Return pass(messages), transform(modified_messages), or block(reason)
|
|
13
11
|
# pass(messages)
|
|
@@ -19,29 +17,6 @@
|
|
|
19
17
|
# end
|
|
20
18
|
# end
|
|
21
19
|
class Riffer::Guardrail
|
|
22
|
-
include Riffer::Helpers::ClassNameConverter
|
|
23
|
-
|
|
24
|
-
class << self
|
|
25
|
-
include Riffer::Helpers::ClassNameConverter
|
|
26
|
-
|
|
27
|
-
# Gets or sets the guardrail identifier.
|
|
28
|
-
#
|
|
29
|
-
# +value+ - the identifier to set, or nil to get.
|
|
30
|
-
#
|
|
31
|
-
#: (?String?) -> String
|
|
32
|
-
def identifier(value = nil)
|
|
33
|
-
return @identifier || class_name_to_path(name) if value.nil?
|
|
34
|
-
@identifier = value.to_s
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
# Returns the instance's identifier.
|
|
39
|
-
#
|
|
40
|
-
#: () -> String
|
|
41
|
-
def identifier
|
|
42
|
-
self.class.identifier
|
|
43
|
-
end
|
|
44
|
-
|
|
45
20
|
# Processes input messages before they are sent to the LLM.
|
|
46
21
|
#
|
|
47
22
|
# Override this method in subclasses to implement input processing.
|
|
@@ -8,8 +8,6 @@
|
|
|
8
8
|
# guardrail :before, with: Riffer::Guardrails::MaxLength, max: 1000
|
|
9
9
|
# guardrail :after, with: Riffer::Guardrails::MaxLength, max: 5000
|
|
10
10
|
class Riffer::Guardrails::MaxLength < Riffer::Guardrail
|
|
11
|
-
identifier "riffer/guardrails/max_length"
|
|
12
|
-
|
|
13
11
|
DEFAULT_MAX = 10_000 #: Integer
|
|
14
12
|
|
|
15
13
|
# The maximum allowed character length.
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
# created to record which guardrail made the change, in which phase, and
|
|
8
8
|
# which message indices were affected.
|
|
9
9
|
class Riffer::Guardrails::Modification
|
|
10
|
-
# The
|
|
11
|
-
attr_reader :
|
|
10
|
+
# The guardrail class that transformed data.
|
|
11
|
+
attr_reader :guardrail #: singleton(Riffer::Guardrail)
|
|
12
12
|
|
|
13
13
|
# The phase when the transformation occurred (:before or :after).
|
|
14
14
|
attr_reader :phase #: Symbol
|
|
@@ -18,13 +18,13 @@ class Riffer::Guardrails::Modification
|
|
|
18
18
|
|
|
19
19
|
# Creates a new modification record.
|
|
20
20
|
#
|
|
21
|
-
# +
|
|
21
|
+
# +guardrail+ - the guardrail class that transformed.
|
|
22
22
|
# +phase+ - :before or :after.
|
|
23
23
|
# +message_indices+ - indices of changed messages.
|
|
24
24
|
#
|
|
25
|
-
#: (
|
|
26
|
-
def initialize(
|
|
27
|
-
@
|
|
25
|
+
#: (guardrail: singleton(Riffer::Guardrail), phase: Symbol, message_indices: Array[Integer]) -> void
|
|
26
|
+
def initialize(guardrail:, phase:, message_indices:)
|
|
27
|
+
@guardrail = guardrail
|
|
28
28
|
@phase = phase
|
|
29
29
|
@message_indices = message_indices
|
|
30
30
|
end
|
|
@@ -33,6 +33,10 @@ class Riffer::Guardrails::Modification
|
|
|
33
33
|
#
|
|
34
34
|
#: () -> Hash[Symbol, untyped]
|
|
35
35
|
def to_h
|
|
36
|
-
{
|
|
36
|
+
{
|
|
37
|
+
guardrail: guardrail.name,
|
|
38
|
+
phase: phase,
|
|
39
|
+
message_indices: message_indices
|
|
40
|
+
}
|
|
37
41
|
end
|
|
38
42
|
end
|
|
@@ -52,7 +52,7 @@ class Riffer::Guardrails::Runner
|
|
|
52
52
|
if result.block?
|
|
53
53
|
tripwire = Riffer::Guardrails::Tripwire.new(
|
|
54
54
|
reason: result.data,
|
|
55
|
-
|
|
55
|
+
guardrail: guardrail.class,
|
|
56
56
|
phase: phase,
|
|
57
57
|
metadata: result.metadata
|
|
58
58
|
)
|
|
@@ -61,7 +61,7 @@ class Riffer::Guardrails::Runner
|
|
|
61
61
|
|
|
62
62
|
if result.transform?
|
|
63
63
|
modifications << Riffer::Guardrails::Modification.new(
|
|
64
|
-
|
|
64
|
+
guardrail: guardrail.class,
|
|
65
65
|
phase: phase,
|
|
66
66
|
message_indices: detect_changed_indices(current_data, result.data)
|
|
67
67
|
)
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
#
|
|
9
9
|
# tripwire = Tripwire.new(
|
|
10
10
|
# reason: "PII detected in input",
|
|
11
|
-
#
|
|
11
|
+
# guardrail: PiiRedactor,
|
|
12
12
|
# phase: :before,
|
|
13
13
|
# metadata: { detected_types: [:email, :phone] }
|
|
14
14
|
# )
|
|
@@ -18,8 +18,8 @@ class Riffer::Guardrails::Tripwire
|
|
|
18
18
|
# The reason for blocking.
|
|
19
19
|
attr_reader :reason #: String
|
|
20
20
|
|
|
21
|
-
# The
|
|
22
|
-
attr_reader :
|
|
21
|
+
# The guardrail class that triggered the block.
|
|
22
|
+
attr_reader :guardrail #: singleton(Riffer::Guardrail)
|
|
23
23
|
|
|
24
24
|
# The phase when the block occurred (:before or :after).
|
|
25
25
|
attr_reader :phase #: Symbol
|
|
@@ -30,18 +30,18 @@ class Riffer::Guardrails::Tripwire
|
|
|
30
30
|
# Creates a new tripwire.
|
|
31
31
|
#
|
|
32
32
|
# +reason+ - the reason for blocking.
|
|
33
|
-
# +
|
|
33
|
+
# +guardrail+ - the guardrail class that blocked.
|
|
34
34
|
# +phase+ - :before or :after.
|
|
35
35
|
# +metadata+ - optional additional information.
|
|
36
36
|
#
|
|
37
37
|
# Raises Riffer::ArgumentError if the phase is invalid.
|
|
38
38
|
#
|
|
39
|
-
#: (reason: String,
|
|
40
|
-
def initialize(reason:,
|
|
39
|
+
#: (reason: String, guardrail: singleton(Riffer::Guardrail), phase: Symbol, ?metadata: Hash[Symbol, untyped]?) -> void
|
|
40
|
+
def initialize(reason:, guardrail:, phase:, metadata: nil)
|
|
41
41
|
raise Riffer::ArgumentError, "Invalid phase: #{phase}" unless PHASES.include?(phase)
|
|
42
42
|
|
|
43
43
|
@reason = reason
|
|
44
|
-
@
|
|
44
|
+
@guardrail = guardrail
|
|
45
45
|
@phase = phase
|
|
46
46
|
@metadata = metadata
|
|
47
47
|
end
|
|
@@ -52,7 +52,7 @@ class Riffer::Guardrails::Tripwire
|
|
|
52
52
|
def to_h
|
|
53
53
|
{
|
|
54
54
|
reason: reason,
|
|
55
|
-
|
|
55
|
+
guardrail: guardrail.name,
|
|
56
56
|
phase: phase,
|
|
57
57
|
metadata: metadata
|
|
58
58
|
}
|
|
@@ -19,10 +19,10 @@ class Riffer::StreamEvents::GuardrailModification < Riffer::StreamEvents::Base
|
|
|
19
19
|
@modification = modification
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
# The guardrail
|
|
22
|
+
# The guardrail class that made the transformation.
|
|
23
23
|
#
|
|
24
|
-
#: () ->
|
|
25
|
-
def
|
|
24
|
+
#: () -> singleton(Riffer::Guardrail)
|
|
25
|
+
def guardrail = modification.guardrail
|
|
26
26
|
|
|
27
27
|
# The phase when the transformation occurred.
|
|
28
28
|
#
|
|
@@ -33,11 +33,11 @@ class Riffer::StreamEvents::GuardrailTripwire < Riffer::StreamEvents::Base
|
|
|
33
33
|
tripwire.phase
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
-
# The guardrail
|
|
36
|
+
# The guardrail class that triggered the block.
|
|
37
37
|
#
|
|
38
|
-
#: () ->
|
|
39
|
-
def
|
|
40
|
-
tripwire.
|
|
38
|
+
#: () -> singleton(Riffer::Guardrail)
|
|
39
|
+
def guardrail
|
|
40
|
+
tripwire.guardrail
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
# Converts the event to a hash.
|
data/lib/riffer/version.rb
CHANGED
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
# See Riffer::Evals::Evaluators.
|
|
9
9
|
#
|
|
10
10
|
# class MyEvaluator < Riffer::Evals::Evaluator
|
|
11
|
-
# identifier "my_evaluator"
|
|
12
11
|
# description "Evaluates response quality"
|
|
13
12
|
# higher_is_better true
|
|
14
13
|
# judge_model "anthropic/claude-opus-4-5-20251101"
|
|
@@ -22,13 +21,6 @@
|
|
|
22
21
|
# end
|
|
23
22
|
# end
|
|
24
23
|
class Riffer::Evals::Evaluator
|
|
25
|
-
include Riffer::Helpers::ClassNameConverter
|
|
26
|
-
|
|
27
|
-
# Gets or sets the evaluator identifier.
|
|
28
|
-
#
|
|
29
|
-
# : (?String?) -> String
|
|
30
|
-
def self.identifier: (?String?) -> String
|
|
31
|
-
|
|
32
24
|
# Gets or sets the evaluator description.
|
|
33
25
|
#
|
|
34
26
|
# : (?String?) -> String?
|
|
@@ -44,9 +36,6 @@ class Riffer::Evals::Evaluator
|
|
|
44
36
|
# : (?String?) -> String?
|
|
45
37
|
def self.judge_model: (?String?) -> String?
|
|
46
38
|
|
|
47
|
-
# : (String?) -> String?
|
|
48
|
-
private def self.class_name_to_identifier: (String?) -> String?
|
|
49
|
-
|
|
50
39
|
# Evaluates an input/output pair.
|
|
51
40
|
#
|
|
52
41
|
# Raises NotImplementedError if not implemented by subclass.
|
|
@@ -1,42 +1,5 @@
|
|
|
1
1
|
# Generated from lib/riffer/evals/evaluators.rb with RBS::Inline
|
|
2
2
|
|
|
3
|
-
# Namespace for built-in evaluators
|
|
4
|
-
#
|
|
5
|
-
# See Riffer::Evals::Evaluators::Repository for registering custom evaluators.
|
|
3
|
+
# Namespace for built-in evaluators.
|
|
6
4
|
module Riffer::Evals::Evaluators
|
|
7
|
-
# Repository for looking up evaluators by identifier.
|
|
8
|
-
#
|
|
9
|
-
# Built-in evaluators are always available. Custom evaluators
|
|
10
|
-
# can be registered using Repository.register in your app initialization.
|
|
11
|
-
#
|
|
12
|
-
# # Register a custom evaluator (config/initializers/riffer.rb)
|
|
13
|
-
# Riffer::Evals::Evaluators::Repository.register(:my_evaluator, MyEvaluator)
|
|
14
|
-
#
|
|
15
|
-
# # Find an evaluator
|
|
16
|
-
# Riffer::Evals::Evaluators::Repository.find(:answer_relevancy)
|
|
17
|
-
# # => Riffer::Evals::Evaluators::AnswerRelevancy
|
|
18
|
-
class Repository
|
|
19
|
-
# Built-in evaluators (always available).
|
|
20
|
-
BUILT_IN: Hash[Symbol, ^() -> singleton(Riffer::Evals::Evaluator)]
|
|
21
|
-
|
|
22
|
-
# Registers a custom evaluator class with an identifier.
|
|
23
|
-
#
|
|
24
|
-
# : ((String | Symbol), singleton(Riffer::Evals::Evaluator)) -> void
|
|
25
|
-
def self.register: (String | Symbol, singleton(Riffer::Evals::Evaluator)) -> void
|
|
26
|
-
|
|
27
|
-
# Finds an evaluator class by identifier.
|
|
28
|
-
#
|
|
29
|
-
# : ((String | Symbol)) -> singleton(Riffer::Evals::Evaluator)?
|
|
30
|
-
def self.find: (String | Symbol) -> singleton(Riffer::Evals::Evaluator)?
|
|
31
|
-
|
|
32
|
-
# Returns all registered evaluators (built-in and custom).
|
|
33
|
-
#
|
|
34
|
-
# : () -> Hash[Symbol, singleton(Riffer::Evals::Evaluator)]
|
|
35
|
-
def self.all: () -> Hash[Symbol, singleton(Riffer::Evals::Evaluator)]
|
|
36
|
-
|
|
37
|
-
# Clears custom registrations (for testing). Built-ins remain.
|
|
38
|
-
#
|
|
39
|
-
# : () -> void
|
|
40
|
-
def self.clear: () -> void
|
|
41
|
-
end
|
|
42
5
|
end
|
|
@@ -5,15 +5,15 @@
|
|
|
5
5
|
# Metrics define which evaluator to use and what thresholds determine pass/fail.
|
|
6
6
|
#
|
|
7
7
|
# metric = Riffer::Evals::Metric.new(
|
|
8
|
-
#
|
|
8
|
+
# evaluator_class: Riffer::Evals::Evaluators::AnswerRelevancy,
|
|
9
9
|
# min: 0.85,
|
|
10
10
|
# weight: 1.0
|
|
11
11
|
# )
|
|
12
12
|
#
|
|
13
13
|
# metric.passes?(result) # => true/false based on thresholds
|
|
14
14
|
class Riffer::Evals::Metric
|
|
15
|
-
# The
|
|
16
|
-
attr_reader
|
|
15
|
+
# The evaluator class to use.
|
|
16
|
+
attr_reader evaluator_class: singleton(Riffer::Evals::Evaluator)
|
|
17
17
|
|
|
18
18
|
# Minimum acceptable score (for higher_is_better evaluators).
|
|
19
19
|
attr_reader min: Float?
|
|
@@ -26,13 +26,10 @@ class Riffer::Evals::Metric
|
|
|
26
26
|
|
|
27
27
|
# Initializes a new metric.
|
|
28
28
|
#
|
|
29
|
-
#
|
|
30
|
-
def initialize: (evaluator_identifier: String, ?min: Float?, ?max: Float?, ?weight: Float) -> void
|
|
31
|
-
|
|
32
|
-
# Returns the evaluator class for this metric.
|
|
29
|
+
# Raises Riffer::ArgumentError if evaluator_class is not a subclass of Riffer::Evals::Evaluator.
|
|
33
30
|
#
|
|
34
|
-
# : (
|
|
35
|
-
def
|
|
31
|
+
# : (evaluator_class: singleton(Riffer::Evals::Evaluator), ?min: Float?, ?max: Float?, ?weight: Float) -> void
|
|
32
|
+
def initialize: (evaluator_class: singleton(Riffer::Evals::Evaluator), ?min: Float?, ?max: Float?, ?weight: Float) -> void
|
|
36
33
|
|
|
37
34
|
# Checks if a result passes this metric's thresholds.
|
|
38
35
|
#
|
|
@@ -9,8 +9,7 @@
|
|
|
9
9
|
# include Riffer::Evals::Profile
|
|
10
10
|
#
|
|
11
11
|
# ai_evals do
|
|
12
|
-
# metric
|
|
13
|
-
# metric :hallucination, max: 0.10
|
|
12
|
+
# metric Riffer::Evals::Evaluators::AnswerRelevancy, min: 0.85
|
|
14
13
|
# end
|
|
15
14
|
# end
|
|
16
15
|
#
|
|
@@ -35,8 +34,8 @@ module Riffer::Evals::Profile
|
|
|
35
34
|
|
|
36
35
|
# Defines a metric with thresholds.
|
|
37
36
|
#
|
|
38
|
-
# : ((
|
|
39
|
-
def metric: (
|
|
37
|
+
# : (singleton(Riffer::Evals::Evaluator), ?min: Float?, ?max: Float?, ?weight: Float) -> void
|
|
38
|
+
def metric: (singleton(Riffer::Evals::Evaluator), ?min: Float?, ?max: Float?, ?weight: Float) -> void
|
|
40
39
|
end
|
|
41
40
|
|
|
42
41
|
module ClassMethods
|
|
@@ -5,18 +5,18 @@
|
|
|
5
5
|
# Contains the score, reason, and metadata from running an evaluator.
|
|
6
6
|
#
|
|
7
7
|
# result = Riffer::Evals::Result.new(
|
|
8
|
-
# evaluator:
|
|
8
|
+
# evaluator: Riffer::Evals::Evaluators::AnswerRelevancy,
|
|
9
9
|
# score: 0.85,
|
|
10
10
|
# reason: "The response addresses the question directly.",
|
|
11
11
|
# higher_is_better: true
|
|
12
12
|
# )
|
|
13
13
|
#
|
|
14
14
|
# result.score # => 0.85
|
|
15
|
-
# result.evaluator # =>
|
|
15
|
+
# result.evaluator # => Riffer::Evals::Evaluators::AnswerRelevancy
|
|
16
16
|
# result.higher_is_better # => true
|
|
17
17
|
class Riffer::Evals::Result
|
|
18
|
-
# The
|
|
19
|
-
attr_reader evaluator:
|
|
18
|
+
# The evaluator class that produced this result.
|
|
19
|
+
attr_reader evaluator: singleton(Riffer::Evals::Evaluator)
|
|
20
20
|
|
|
21
21
|
# The evaluation score (0.0 to 1.0).
|
|
22
22
|
attr_reader score: Float
|
|
@@ -34,8 +34,8 @@ class Riffer::Evals::Result
|
|
|
34
34
|
#
|
|
35
35
|
# Raises Riffer::ArgumentError if score is not between 0.0 and 1.0.
|
|
36
36
|
#
|
|
37
|
-
# : (evaluator:
|
|
38
|
-
def initialize: (evaluator:
|
|
37
|
+
# : (evaluator: singleton(Riffer::Evals::Evaluator), score: Float, ?reason: String?, ?metadata: Hash[Symbol, untyped], ?higher_is_better: bool) -> void
|
|
38
|
+
def initialize: (evaluator: singleton(Riffer::Evals::Evaluator), score: Float, ?reason: String?, ?metadata: Hash[Symbol, untyped], ?higher_is_better: bool) -> void
|
|
39
39
|
|
|
40
40
|
# Returns a hash representation of the result.
|
|
41
41
|
#
|
|
@@ -5,8 +5,6 @@
|
|
|
5
5
|
# Subclass this to create custom guardrails:
|
|
6
6
|
#
|
|
7
7
|
# class MyGuardrail < Riffer::Guardrail
|
|
8
|
-
# identifier "my_guardrail"
|
|
9
|
-
#
|
|
10
8
|
# def process_input(messages, context:)
|
|
11
9
|
# # Return pass(messages), transform(modified_messages), or block(reason)
|
|
12
10
|
# pass(messages)
|
|
@@ -18,22 +16,6 @@
|
|
|
18
16
|
# end
|
|
19
17
|
# end
|
|
20
18
|
class Riffer::Guardrail
|
|
21
|
-
include Riffer::Helpers::ClassNameConverter
|
|
22
|
-
|
|
23
|
-
include Riffer::Helpers::ClassNameConverter
|
|
24
|
-
|
|
25
|
-
# Gets or sets the guardrail identifier.
|
|
26
|
-
#
|
|
27
|
-
# +value+ - the identifier to set, or nil to get.
|
|
28
|
-
#
|
|
29
|
-
# : (?String?) -> String
|
|
30
|
-
def self.identifier: (?String?) -> String
|
|
31
|
-
|
|
32
|
-
# Returns the instance's identifier.
|
|
33
|
-
#
|
|
34
|
-
# : () -> String
|
|
35
|
-
def identifier: () -> String
|
|
36
|
-
|
|
37
19
|
# Processes input messages before they are sent to the LLM.
|
|
38
20
|
#
|
|
39
21
|
# Override this method in subclasses to implement input processing.
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
# created to record which guardrail made the change, in which phase, and
|
|
7
7
|
# which message indices were affected.
|
|
8
8
|
class Riffer::Guardrails::Modification
|
|
9
|
-
# The
|
|
10
|
-
attr_reader
|
|
9
|
+
# The guardrail class that transformed data.
|
|
10
|
+
attr_reader guardrail: singleton(Riffer::Guardrail)
|
|
11
11
|
|
|
12
12
|
# The phase when the transformation occurred (:before or :after).
|
|
13
13
|
attr_reader phase: Symbol
|
|
@@ -17,12 +17,12 @@ class Riffer::Guardrails::Modification
|
|
|
17
17
|
|
|
18
18
|
# Creates a new modification record.
|
|
19
19
|
#
|
|
20
|
-
# +
|
|
20
|
+
# +guardrail+ - the guardrail class that transformed.
|
|
21
21
|
# +phase+ - :before or :after.
|
|
22
22
|
# +message_indices+ - indices of changed messages.
|
|
23
23
|
#
|
|
24
|
-
# : (
|
|
25
|
-
def initialize: (
|
|
24
|
+
# : (guardrail: singleton(Riffer::Guardrail), phase: Symbol, message_indices: Array[Integer]) -> void
|
|
25
|
+
def initialize: (guardrail: singleton(Riffer::Guardrail), phase: Symbol, message_indices: Array[Integer]) -> void
|
|
26
26
|
|
|
27
27
|
# Converts the modification to a hash.
|
|
28
28
|
#
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
#
|
|
8
8
|
# tripwire = Tripwire.new(
|
|
9
9
|
# reason: "PII detected in input",
|
|
10
|
-
#
|
|
10
|
+
# guardrail: PiiRedactor,
|
|
11
11
|
# phase: :before,
|
|
12
12
|
# metadata: { detected_types: [:email, :phone] }
|
|
13
13
|
# )
|
|
@@ -17,8 +17,8 @@ class Riffer::Guardrails::Tripwire
|
|
|
17
17
|
# The reason for blocking.
|
|
18
18
|
attr_reader reason: String
|
|
19
19
|
|
|
20
|
-
# The
|
|
21
|
-
attr_reader
|
|
20
|
+
# The guardrail class that triggered the block.
|
|
21
|
+
attr_reader guardrail: singleton(Riffer::Guardrail)
|
|
22
22
|
|
|
23
23
|
# The phase when the block occurred (:before or :after).
|
|
24
24
|
attr_reader phase: Symbol
|
|
@@ -29,14 +29,14 @@ class Riffer::Guardrails::Tripwire
|
|
|
29
29
|
# Creates a new tripwire.
|
|
30
30
|
#
|
|
31
31
|
# +reason+ - the reason for blocking.
|
|
32
|
-
# +
|
|
32
|
+
# +guardrail+ - the guardrail class that blocked.
|
|
33
33
|
# +phase+ - :before or :after.
|
|
34
34
|
# +metadata+ - optional additional information.
|
|
35
35
|
#
|
|
36
36
|
# Raises Riffer::ArgumentError if the phase is invalid.
|
|
37
37
|
#
|
|
38
|
-
# : (reason: String,
|
|
39
|
-
def initialize: (reason: String,
|
|
38
|
+
# : (reason: String, guardrail: singleton(Riffer::Guardrail), phase: Symbol, ?metadata: Hash[Symbol, untyped]?) -> void
|
|
39
|
+
def initialize: (reason: String, guardrail: singleton(Riffer::Guardrail), phase: Symbol, ?metadata: Hash[Symbol, untyped]?) -> void
|
|
40
40
|
|
|
41
41
|
# Converts the tripwire to a hash.
|
|
42
42
|
#
|
|
@@ -15,10 +15,10 @@ class Riffer::StreamEvents::GuardrailModification < Riffer::StreamEvents::Base
|
|
|
15
15
|
# : (Riffer::Guardrails::Modification, ?role: Symbol) -> void
|
|
16
16
|
def initialize: (Riffer::Guardrails::Modification, ?role: Symbol) -> void
|
|
17
17
|
|
|
18
|
-
# The guardrail
|
|
18
|
+
# The guardrail class that made the transformation.
|
|
19
19
|
#
|
|
20
|
-
# : () ->
|
|
21
|
-
def
|
|
20
|
+
# : () -> singleton(Riffer::Guardrail)
|
|
21
|
+
def guardrail: () -> singleton(Riffer::Guardrail)
|
|
22
22
|
|
|
23
23
|
# The phase when the transformation occurred.
|
|
24
24
|
#
|
|
@@ -25,10 +25,10 @@ class Riffer::StreamEvents::GuardrailTripwire < Riffer::StreamEvents::Base
|
|
|
25
25
|
# : () -> Symbol
|
|
26
26
|
def phase: () -> Symbol
|
|
27
27
|
|
|
28
|
-
# The guardrail
|
|
28
|
+
# The guardrail class that triggered the block.
|
|
29
29
|
#
|
|
30
|
-
# : () ->
|
|
31
|
-
def
|
|
30
|
+
# : () -> singleton(Riffer::Guardrail)
|
|
31
|
+
def guardrail: () -> singleton(Riffer::Guardrail)
|
|
32
32
|
|
|
33
33
|
# Converts the event to a hash.
|
|
34
34
|
#
|