riffer 0.11.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.
Files changed (133) hide show
  1. checksums.yaml +4 -4
  2. data/.agents/code-style.md +2 -1
  3. data/.agents/rbs-inline.md +123 -0
  4. data/.agents/rdoc.md +14 -8
  5. data/.release-please-manifest.json +1 -1
  6. data/AGENTS.md +3 -0
  7. data/CHANGELOG.md +31 -0
  8. data/CLAUDE.md +1 -0
  9. data/Guardfile +7 -0
  10. data/Rakefile +23 -1
  11. data/Steepfile +14 -0
  12. data/docs/03_AGENTS.md +24 -1
  13. data/docs/06_STREAM_EVENTS.md +34 -0
  14. data/docs/08_EVALS.md +314 -0
  15. data/docs/09_GUARDRAILS.md +366 -0
  16. data/lib/riffer/agent/response.rb +51 -0
  17. data/lib/riffer/agent.rb +205 -116
  18. data/lib/riffer/config.rb +19 -13
  19. data/lib/riffer/core.rb +5 -6
  20. data/lib/riffer/evals/evaluator.rb +86 -0
  21. data/lib/riffer/evals/evaluators/answer_relevancy.rb +59 -0
  22. data/lib/riffer/evals/evaluators.rb +6 -0
  23. data/lib/riffer/evals/judge.rb +110 -0
  24. data/lib/riffer/evals/metric.rb +65 -0
  25. data/lib/riffer/evals/profile.rb +99 -0
  26. data/lib/riffer/evals/result.rb +70 -0
  27. data/lib/riffer/evals/run_result.rb +99 -0
  28. data/lib/riffer/evals/runner.rb +44 -0
  29. data/lib/riffer/evals.rb +11 -0
  30. data/lib/riffer/guardrail.rb +74 -0
  31. data/lib/riffer/guardrails/max_length.rb +67 -0
  32. data/lib/riffer/guardrails/modification.rb +42 -0
  33. data/lib/riffer/guardrails/result.rb +94 -0
  34. data/lib/riffer/guardrails/runner.rb +104 -0
  35. data/lib/riffer/guardrails/tripwire.rb +60 -0
  36. data/lib/riffer/guardrails.rb +10 -0
  37. data/lib/riffer/helpers/class_name_converter.rb +3 -5
  38. data/lib/riffer/helpers/dependencies.rb +3 -5
  39. data/lib/riffer/helpers/validations.rb +3 -5
  40. data/lib/riffer/helpers.rb +11 -0
  41. data/lib/riffer/messages/assistant.rb +9 -16
  42. data/lib/riffer/messages/base.rb +6 -7
  43. data/lib/riffer/messages/converter.rb +4 -4
  44. data/lib/riffer/messages/system.rb +2 -1
  45. data/lib/riffer/messages/tool.rb +9 -22
  46. data/lib/riffer/messages/user.rb +2 -1
  47. data/lib/riffer/messages.rb +1 -0
  48. data/lib/riffer/providers/amazon_bedrock.rb +16 -8
  49. data/lib/riffer/providers/anthropic.rb +15 -7
  50. data/lib/riffer/providers/base.rb +8 -14
  51. data/lib/riffer/providers/open_ai.rb +19 -9
  52. data/lib/riffer/providers/repository.rb +9 -10
  53. data/lib/riffer/providers/test.rb +17 -22
  54. data/lib/riffer/providers.rb +1 -0
  55. data/lib/riffer/stream_events/base.rb +5 -6
  56. data/lib/riffer/stream_events/guardrail_modification.rb +43 -0
  57. data/lib/riffer/stream_events/guardrail_tripwire.rb +52 -0
  58. data/lib/riffer/stream_events/reasoning_delta.rb +4 -10
  59. data/lib/riffer/stream_events/reasoning_done.rb +4 -10
  60. data/lib/riffer/stream_events/text_delta.rb +4 -10
  61. data/lib/riffer/stream_events/text_done.rb +4 -10
  62. data/lib/riffer/stream_events/token_usage_done.rb +4 -10
  63. data/lib/riffer/stream_events/tool_call_delta.rb +6 -12
  64. data/lib/riffer/stream_events/tool_call_done.rb +7 -14
  65. data/lib/riffer/stream_events.rb +1 -0
  66. data/lib/riffer/token_usage.rb +10 -23
  67. data/lib/riffer/tool.rb +58 -76
  68. data/lib/riffer/tools/param.rb +12 -15
  69. data/lib/riffer/tools/params.rb +8 -19
  70. data/lib/riffer/tools/response.rb +14 -20
  71. data/lib/riffer/tools.rb +1 -0
  72. data/lib/riffer/version.rb +2 -1
  73. data/lib/riffer.rb +22 -26
  74. data/sig/generated/riffer/agent/response.rbs +42 -0
  75. data/sig/generated/riffer/agent.rbs +175 -0
  76. data/sig/generated/riffer/config.rbs +60 -0
  77. data/sig/generated/riffer/core.rbs +17 -0
  78. data/sig/generated/riffer/evals/evaluator.rbs +55 -0
  79. data/sig/generated/riffer/evals/evaluators/answer_relevancy.rbs +24 -0
  80. data/sig/generated/riffer/evals/evaluators.rbs +5 -0
  81. data/sig/generated/riffer/evals/judge.rbs +52 -0
  82. data/sig/generated/riffer/evals/metric.rbs +43 -0
  83. data/sig/generated/riffer/evals/profile.rbs +59 -0
  84. data/sig/generated/riffer/evals/result.rbs +49 -0
  85. data/sig/generated/riffer/evals/run_result.rbs +62 -0
  86. data/sig/generated/riffer/evals/runner.rbs +27 -0
  87. data/sig/generated/riffer/evals.rbs +10 -0
  88. data/sig/generated/riffer/guardrail.rbs +61 -0
  89. data/sig/generated/riffer/guardrails/max_length.rbs +38 -0
  90. data/sig/generated/riffer/guardrails/modification.rbs +31 -0
  91. data/sig/generated/riffer/guardrails/result.rbs +73 -0
  92. data/sig/generated/riffer/guardrails/runner.rbs +51 -0
  93. data/sig/generated/riffer/guardrails/tripwire.rbs +45 -0
  94. data/sig/generated/riffer/guardrails.rbs +9 -0
  95. data/sig/generated/riffer/helpers/class_name_converter.rbs +11 -0
  96. data/sig/generated/riffer/helpers/dependencies.rbs +25 -0
  97. data/sig/generated/riffer/helpers/validations.rbs +11 -0
  98. data/sig/generated/riffer/helpers.rbs +10 -0
  99. data/sig/generated/riffer/messages/assistant.rbs +41 -0
  100. data/sig/generated/riffer/messages/base.rbs +24 -0
  101. data/sig/generated/riffer/messages/converter.rbs +18 -0
  102. data/sig/generated/riffer/messages/system.rbs +11 -0
  103. data/sig/generated/riffer/messages/tool.rbs +41 -0
  104. data/sig/generated/riffer/messages/user.rbs +11 -0
  105. data/sig/generated/riffer/messages.rbs +11 -0
  106. data/sig/generated/riffer/providers/amazon_bedrock.rbs +42 -0
  107. data/sig/generated/riffer/providers/anthropic.rbs +39 -0
  108. data/sig/generated/riffer/providers/base.rbs +37 -0
  109. data/sig/generated/riffer/providers/open_ai.rbs +46 -0
  110. data/sig/generated/riffer/providers/repository.rbs +12 -0
  111. data/sig/generated/riffer/providers/test.rbs +41 -0
  112. data/sig/generated/riffer/providers.rbs +10 -0
  113. data/sig/generated/riffer/stream_events/base.rbs +19 -0
  114. data/sig/generated/riffer/stream_events/guardrail_modification.rbs +37 -0
  115. data/sig/generated/riffer/stream_events/guardrail_tripwire.rbs +37 -0
  116. data/sig/generated/riffer/stream_events/reasoning_delta.rbs +16 -0
  117. data/sig/generated/riffer/stream_events/reasoning_done.rbs +16 -0
  118. data/sig/generated/riffer/stream_events/text_delta.rbs +15 -0
  119. data/sig/generated/riffer/stream_events/text_done.rbs +15 -0
  120. data/sig/generated/riffer/stream_events/token_usage_done.rbs +19 -0
  121. data/sig/generated/riffer/stream_events/tool_call_delta.rbs +21 -0
  122. data/sig/generated/riffer/stream_events/tool_call_done.rbs +24 -0
  123. data/sig/generated/riffer/stream_events.rbs +13 -0
  124. data/sig/generated/riffer/token_usage.rbs +48 -0
  125. data/sig/generated/riffer/tool.rbs +92 -0
  126. data/sig/generated/riffer/tools/param.rbs +39 -0
  127. data/sig/generated/riffer/tools/params.rbs +38 -0
  128. data/sig/generated/riffer/tools/response.rbs +62 -0
  129. data/sig/generated/riffer/tools.rbs +10 -0
  130. data/sig/generated/riffer/version.rbs +5 -0
  131. data/sig/generated/riffer.rbs +36 -0
  132. metadata +118 -6
  133. data/sig/riffer.rbs +0 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f5f2d3838897b17320d17d3cc95b1db37ae8af023d6dcac8c5c9ce0fa5a6e847
4
- data.tar.gz: e7e75acdd198f147747d06bcaaddeba27f3491bcc12edd2ac0e35f464d47e2f0
3
+ metadata.gz: a7a4f27800f9f5a266d408a1b8b8d6d96f6c59307b4761d34d3a1365b9b71bb8
4
+ data.tar.gz: 6719e5013f8d83c78f2647808dd0d27a024ec432085311af02b1dc7cfbdaacfb
5
5
  SHA512:
6
- metadata.gz: 557d945daf22b6a45cb838532a5df0c811d2ac73377b2a5c445efb0dc06a8a2e9c234d14691333d699c6d0dddda7299a5e3bb5a676e4ae72d32b1f631c9694b4
7
- data.tar.gz: aa35cbff64ef8c11e72e76c3c931589e8163f751b96c066cfef74a5f7779fabb8891565c4d215b2ea9b29fca45fb991ebd49260462c203aa9b73328f39d913ca
6
+ metadata.gz: 24356e56e024eaf5223c91c97b72bf4e90a9dd74721d12dac6b5d0f294bea305914d6f074467e915dfd64adbf3eea5a07484147a394f51613f7fe16e828e4c36
7
+ data.tar.gz: 6c8b8d464d94b56f044196f81ec298b01824dea114aca266b82de020c82521ce975451c643c5307d532c23f6fb85e2d38f4931f931cf13dee5e54b53ba5e8211
@@ -8,10 +8,11 @@
8
8
 
9
9
  ## Required Header
10
10
 
11
- All Ruby files must include:
11
+ All Ruby files in `lib/` must include:
12
12
 
13
13
  ```ruby
14
14
  # frozen_string_literal: true
15
+ # rbs_inline: enabled
15
16
  ```
16
17
 
17
18
  ## Error Handling
@@ -0,0 +1,123 @@
1
+ # RBS Inline
2
+
3
+ Type annotations are added directly in Ruby source files using [rbs-inline](https://github.com/soutaro/rbs-inline).
4
+
5
+ ## Magic Comment
6
+
7
+ Every `lib/**/*.rb` file must include the `rbs_inline: enabled` comment on line 2:
8
+
9
+ ```ruby
10
+ # frozen_string_literal: true
11
+ # rbs_inline: enabled
12
+ ```
13
+
14
+ ## Annotation Syntax
15
+
16
+ The **`#:`** prefix is used — standalone lines above methods (type signatures) or inline on the same line (attributes, constants).
17
+
18
+ ### Method Parameters and Return Types
19
+
20
+ Use a single `#:` line above the method with the RBS method signature:
21
+
22
+ ```ruby
23
+ #: (String, Integer) -> bool
24
+ def valid?(name, age)
25
+ ```
26
+
27
+ #### Parameter Mapping
28
+
29
+ | Ruby param | RBS signature |
30
+ | ---------------------------- | ------------------------ |
31
+ | `def foo(x)` | `(Type)` |
32
+ | `def foo(x = nil)` | `(?Type?)` |
33
+ | `def foo(x = val)` | `(?Type)` |
34
+ | `def foo(x:)` | `(x: Type)` |
35
+ | `def foo(x: nil)` | `(?x: Type?)` |
36
+ | `def foo(x: val)` | `(?x: Type)` |
37
+ | `def foo(*args)` | `(*untyped)` |
38
+ | `def foo(**kwargs)` | `(**untyped)` |
39
+ | `def foo(&block)` (required) | `() { (Type) -> void }` |
40
+ | `def foo(&block)` (optional) | `() ?{ (Type) -> void }` |
41
+ | `def foo(...)` | `(*untyped, **untyped)` |
42
+
43
+ #### Examples
44
+
45
+ ```ruby
46
+ # No parameters
47
+ #: () -> String
48
+ def name
49
+
50
+ # Positional parameters
51
+ #: (String, Integer) -> bool
52
+ def valid?(name, age)
53
+
54
+ # Optional positional parameter
55
+ #: (?String?) -> String
56
+ def self.identifier(value = nil)
57
+
58
+ # Required keyword parameters
59
+ #: (input: String, output: String) -> Riffer::Evals::Result
60
+ def evaluate(input:, output:)
61
+
62
+ # Mixed keyword parameters (required + optional)
63
+ #: (input: String, output: String, ?context: Hash[Symbol, untyped]?) -> Riffer::Evals::Result
64
+ def evaluate(input:, output:, context: nil)
65
+
66
+ # Positional + keyword parameters
67
+ #: (String, ?tool_context: Hash[Symbol, untyped]?) -> String
68
+ def generate(prompt, tool_context: nil)
69
+
70
+ # Splat/double-splat
71
+ #: (**untyped) -> void
72
+ def initialize(**options)
73
+
74
+ # Forward arguments
75
+ #: (*untyped, **untyped) -> String
76
+ def self.generate(...)
77
+
78
+ # Block parameter (required)
79
+ #: () { (Riffer::Messages::Base) -> void } -> self
80
+ def on_message(&block)
81
+
82
+ # Block parameter (optional)
83
+ #: () ?{ (Riffer::Config) -> void } -> void
84
+ def configure(&block)
85
+ ```
86
+
87
+ ### Attributes
88
+
89
+ ```ruby
90
+ attr_reader :name #: String
91
+ attr_reader :items #: Array[String]
92
+ ```
93
+
94
+ ### Constants
95
+
96
+ ```ruby
97
+ VERSION = "1.0.0" #: String
98
+ DEFAULTS = {}.freeze #: Hash[Symbol, untyped]
99
+ ```
100
+
101
+ ## Common Type Patterns
102
+
103
+ | Pattern | Meaning |
104
+ | ------------------------- | --------------------------- |
105
+ | `String?` | Optional (String or nil) |
106
+ | `(String \| Integer)` | Union type |
107
+ | `Array[String]` | Typed array |
108
+ | `Hash[Symbol, untyped]` | Typed hash |
109
+ | `^(String) -> void` | Block/proc type |
110
+ | `singleton(Riffer::Tool)` | Class object (not instance) |
111
+ | `bool` | Boolean (true or false) |
112
+ | `untyped` | Any type |
113
+ | `void` | No meaningful return |
114
+
115
+ ## Workflow
116
+
117
+ After changing type annotations:
118
+
119
+ 1. Run `bundle exec rake rbs:generate` to regenerate `sig/generated/` files
120
+ 2. Commit both the source changes and the generated `.rbs` files
121
+ 3. CI checks for drift between source annotations and committed `.rbs` files
122
+
123
+ Use `bundle exec rake rbs:watch` during development to auto-regenerate on file changes.
data/.agents/rdoc.md CHANGED
@@ -1,24 +1,30 @@
1
1
  # RDoc Documentation
2
2
 
3
- Use pure RDoc comments for public APIs (not YARD).
3
+ Use RDoc prose comments for public API descriptions and RBS inline annotations for types.
4
4
 
5
- ## Parameters
5
+ ## Parameters and Return Types
6
6
 
7
- Use definition list syntax (`::`):
7
+ Describe parameters in the RDoc prose comment. Use a single `#:` line for the RBS method signature (see [rbs-inline.md](rbs-inline.md) for the full type annotation syntax):
8
8
 
9
9
  ```ruby
10
10
  # Creates a new agent.
11
11
  #
12
- # name:: String - the agent name
13
- # options:: Hash - optional configuration
12
+ # +name+ - the agent name.
13
+ # +options+ - optional configuration.
14
+ #
15
+ #: (String, ?options: Hash[Symbol, untyped]) -> void
16
+ def initialize(name, options: {})
14
17
  ```
15
18
 
16
- ## Return Values
19
+ ## Attributes and Constants
17
20
 
18
- Document with prose:
21
+ Use `#:` inline syntax (on the same line) for attribute and constant types:
19
22
 
20
23
  ```ruby
21
- # Returns String - the agent identifier.
24
+ # The agent name.
25
+ attr_reader :name #: String
26
+
27
+ DEFAULT_TIMEOUT = 10 #: Integer
22
28
  ```
23
29
 
24
30
  ## Exceptions
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "0.11.0"
2
+ ".": "0.13.0"
3
3
  }
data/AGENTS.md CHANGED
@@ -16,6 +16,7 @@ Ruby gem framework for building AI-powered agents with LLM provider adapters.
16
16
  - [Code Style](.agents/code-style.md) - StandardRB and comment conventions
17
17
  - [RDoc](.agents/rdoc.md) - Documentation format for public APIs
18
18
  - [Providers](.agents/providers.md) - Adding new LLM provider adapters
19
+ - [RBS Inline](.agents/rbs-inline.md) - Type annotations with rbs-inline
19
20
 
20
21
  ## Commands
21
22
 
@@ -25,4 +26,6 @@ Ruby gem framework for building AI-powered agents with LLM provider adapters.
25
26
  | `bundle exec rake test` | Run tests only |
26
27
  | `bundle exec rake standard` | Check code style |
27
28
  | `bundle exec rake standard:fix` | Auto-fix style issues |
29
+ | `bundle exec rake rbs:generate` | Generate RBS type signatures |
30
+ | `bundle exec rake rbs:watch` | Watch and regenerate RBS files |
28
31
  | `bin/console` | Interactive console |
data/CHANGELOG.md CHANGED
@@ -5,6 +5,37 @@ 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
+
15
+ ## [0.12.0](https://github.com/janeapp/riffer/compare/riffer/v0.11.0...riffer/v0.12.0) (2026-02-11)
16
+
17
+
18
+ ### ⚠ BREAKING CHANGES
19
+
20
+ * Agent#generate now returns Riffer::Agent::Response instead of String. Use response.content or response.to_s for the text.
21
+
22
+ ### Features
23
+
24
+ * add Claude Code Review GitHub Action ([#108](https://github.com/janeapp/riffer/issues/108)) ([f4b281c](https://github.com/janeapp/riffer/commit/f4b281c43e6ad50430c38323bcb876b60efc994a))
25
+ * add evals primitive for LLM-as-judge evaluations ([#101](https://github.com/janeapp/riffer/issues/101)) ([8fd7b36](https://github.com/janeapp/riffer/commit/8fd7b369f2bd0236ea4c7d30cc12e71b960211dd))
26
+ * add guardrails primitive for input/output processing ([#100](https://github.com/janeapp/riffer/issues/100)) ([48d8bad](https://github.com/janeapp/riffer/commit/48d8badce98c0bf9110bafebd3097e25f46c8444))
27
+ * add inline RBS type annotations with Steep type checking ([#103](https://github.com/janeapp/riffer/issues/103)) ([02ae559](https://github.com/janeapp/riffer/commit/02ae559fa580ef4353bd969f2e50e056ab538e2d))
28
+
29
+
30
+ ### Bug Fixes
31
+
32
+ * correct RBS inline annotations and remove ivar declarations ([#109](https://github.com/janeapp/riffer/issues/109)) ([d59076d](https://github.com/janeapp/riffer/commit/d59076d40b88f581b51ddbb9ee3d50ed57e84451))
33
+
34
+
35
+ ### Miscellaneous Chores
36
+
37
+ * set next version ([#111](https://github.com/janeapp/riffer/issues/111)) ([faf41b9](https://github.com/janeapp/riffer/commit/faf41b92032e302c3f0d2d06ab93140137c1b199))
38
+
8
39
  ## [0.11.0](https://github.com/janeapp/riffer/compare/riffer/v0.10.0...riffer/v0.11.0) (2026-02-04)
9
40
 
10
41
 
data/CLAUDE.md ADDED
@@ -0,0 +1 @@
1
+ AGENTS.md
data/Guardfile ADDED
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ guard :shell do
4
+ watch(%r{^lib/.*\.rb$}) do
5
+ system("bundle exec rake rbs:generate")
6
+ end
7
+ end
data/Rakefile CHANGED
@@ -23,4 +23,26 @@ end
23
23
 
24
24
  task docs: :rdoc
25
25
 
26
- task default: %i[test standard]
26
+ namespace :rbs do
27
+ desc "Generate RBS type signatures from inline annotations"
28
+ task :generate do
29
+ sh "bundle exec rbs-inline --output sig/generated lib"
30
+ end
31
+
32
+ desc "Watch lib/ for changes and regenerate RBS files"
33
+ task :watch do
34
+ require "guard"
35
+ require "guard/commander"
36
+
37
+ Guard.start(no_interactions: true)
38
+ end
39
+ end
40
+
41
+ namespace :steep do
42
+ desc "Run Steep type checker"
43
+ task :check do
44
+ sh "bundle exec steep check"
45
+ end
46
+ end
47
+
48
+ task default: %i[test standard steep:check]
data/Steepfile ADDED
@@ -0,0 +1,14 @@
1
+ D = Steep::Diagnostic
2
+
3
+ target :lib do
4
+ signature "sig/generated"
5
+
6
+ check "lib"
7
+
8
+ library "logger"
9
+ library "anthropic"
10
+ library "openai"
11
+ library "aws-sdk-bedrockruntime"
12
+
13
+ configure_code_diagnostics(D::Ruby.lenient)
14
+ end
data/docs/03_AGENTS.md CHANGED
@@ -100,15 +100,38 @@ class MyAgent < Riffer::Agent
100
100
  end
101
101
  ```
102
102
 
103
+ ### guardrail
104
+
105
+ Registers guardrails for pre/post processing of messages. Pass the guardrail class and any options:
106
+
107
+ ```ruby
108
+ class MyAgent < Riffer::Agent
109
+ model 'openai/gpt-4o'
110
+
111
+ # Input-only guardrail
112
+ guardrail :before, with: InputValidator
113
+
114
+ # Output-only guardrail
115
+ guardrail :after, with: ResponseFilter
116
+
117
+ # Both input and output, with options
118
+ guardrail :around, with: Riffer::Guardrails::MaxLength, max: 1000
119
+ end
120
+ ```
121
+
122
+ See [Guardrails](09_GUARDRAILS.md) for detailed documentation.
123
+
103
124
  ## Instance Methods
104
125
 
105
126
  ### generate
106
127
 
107
- Generates a response synchronously:
128
+ Generates a response synchronously. Returns a `Riffer::Agent::Response` object:
108
129
 
109
130
  ```ruby
110
131
  # Class method (recommended for simple calls)
111
132
  response = MyAgent.generate('Hello')
133
+ puts response.content # Access the response text
134
+ puts response.blocked? # Check if guardrail blocked (always false without guardrails)
112
135
 
113
136
  # Instance method (when you need message history or callbacks)
114
137
  agent = MyAgent.new
@@ -109,6 +109,40 @@ event.role # => "assistant"
109
109
  event.content # => "Let me think about this step by step..."
110
110
  ```
111
111
 
112
+ ### GuardrailTripwire
113
+
114
+ Emitted when a guardrail blocks execution during streaming:
115
+
116
+ ```ruby
117
+ agent.stream("Hello").each do |event|
118
+ case event
119
+ when Riffer::StreamEvents::GuardrailTripwire
120
+ puts "Blocked by: #{event.guardrail_id}"
121
+ puts "Reason: #{event.reason}"
122
+ puts "Phase: #{event.phase}" # :before or :after
123
+ end
124
+ end
125
+ ```
126
+
127
+ See [Guardrails](09_GUARDRAILS.md) for more information.
128
+
129
+ ### GuardrailModification
130
+
131
+ Emitted when a guardrail transforms data during streaming:
132
+
133
+ ```ruby
134
+ agent.stream("Hello").each do |event|
135
+ case event
136
+ when Riffer::StreamEvents::GuardrailModification
137
+ puts "Modified by: #{event.guardrail_id}"
138
+ puts "Phase: #{event.phase}" # :before or :after
139
+ puts "Changed: #{event.message_indices}" # Array of affected indices
140
+ end
141
+ end
142
+ ```
143
+
144
+ See [Guardrails](09_GUARDRAILS.md) for more information.
145
+
112
146
  ### TokenUsageDone
113
147
 
114
148
  Emitted when token usage data is available at the end of a response: