riffer 0.45.0 → 0.46.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.
@@ -1,29 +1,28 @@
1
1
  # Generated from lib/riffer/agent/response.rb with RBS::Inline
2
2
 
3
- # Wraps an agent generation response. When a guardrail blocks execution,
4
- # +content+ is empty and +tripwire+ carries the block details.
3
+ # Wraps an agent generation response. +outcome+ says how the run ended; when a
4
+ # guardrail blocks execution, +content+ is empty and +tripwire+ carries the
5
+ # block details.
5
6
  #
6
7
  # response = agent.generate("Hello")
7
- # if response.blocked?
8
- # puts "Blocked: #{response.tripwire.reason}"
9
- # else
8
+ # if response.outcome.success?
10
9
  # puts response.content
10
+ # else
11
+ # puts "#{response.outcome.reason}: #{response.outcome.detail}"
11
12
  # end
12
13
  class Riffer::Agent::Response
13
- @interrupted: bool
14
-
15
14
  # The response content.
16
15
  attr_reader content: String
17
16
 
17
+ # How the run ended.
18
+ attr_reader outcome: Riffer::Agent::Outcome
19
+
18
20
  # The tripwire if execution was blocked.
19
21
  attr_reader tripwire: Riffer::Guardrails::Tripwire?
20
22
 
21
23
  # The modifications made by guardrails during processing.
22
24
  attr_reader modifications: Array[Riffer::Guardrails::Modification]
23
25
 
24
- # The reason provided with the interrupt, if any.
25
- attr_reader interrupt_reason: (String | Symbol)?
26
-
27
26
  # The parsed structured output, if structured output was configured.
28
27
  attr_reader structured_output: Hash[Symbol, untyped]?
29
28
 
@@ -44,34 +43,20 @@ class Riffer::Agent::Response
44
43
  # --
45
44
  # : (
46
45
  # String,
46
+ # outcome: Riffer::Agent::Outcome,
47
47
  # ?tripwire: Riffer::Guardrails::Tripwire?,
48
48
  # ?modifications: Array[Riffer::Guardrails::Modification],
49
- # ?interrupted: bool,
50
- # ?interrupt_reason: (String | Symbol)?,
51
49
  # ?structured_output: Hash[Symbol, untyped]?,
52
50
  # ?messages: Array[Riffer::Messages::Base],
53
51
  # ?healed_tool_call_ids: Array[String],
54
52
  # ?token_usage: Riffer::Providers::TokenUsage?,
55
53
  # ?steps: Integer
56
54
  # ) -> void
57
- def initialize: (String, ?tripwire: Riffer::Guardrails::Tripwire?, ?modifications: Array[Riffer::Guardrails::Modification], ?interrupted: bool, ?interrupt_reason: (String | Symbol)?, ?structured_output: Hash[Symbol, untyped]?, ?messages: Array[Riffer::Messages::Base], ?healed_tool_call_ids: Array[String], ?token_usage: Riffer::Providers::TokenUsage?, ?steps: Integer) -> void
58
-
59
- # Returns true if the response was blocked by a guardrail.
60
- #
61
- # --
62
- # : () -> bool
63
- def blocked?: () -> bool
55
+ def initialize: (String, outcome: Riffer::Agent::Outcome, ?tripwire: Riffer::Guardrails::Tripwire?, ?modifications: Array[Riffer::Guardrails::Modification], ?structured_output: Hash[Symbol, untyped]?, ?messages: Array[Riffer::Messages::Base], ?healed_tool_call_ids: Array[String], ?token_usage: Riffer::Providers::TokenUsage?, ?steps: Integer) -> void
64
56
 
65
57
  # Returns true if any guardrail modified data during processing.
66
58
  #
67
59
  # --
68
60
  # : () -> bool
69
61
  def modified?: () -> bool
70
-
71
- # Returns true if the agent loop was interrupted by a callback
72
- # via <tt>throw :riffer_interrupt</tt>.
73
- #
74
- # --
75
- # : () -> bool
76
- def interrupted?: () -> bool
77
62
  end
@@ -14,8 +14,8 @@ module Riffer::Agent::Run
14
14
  # for prompt/files semantics.
15
15
  #
16
16
  # --
17
- # : (agent: Riffer::Agent, ?prompt: String?, ?files: Array[Hash[Symbol, untyped] | Riffer::Messages::FilePart]?, ?tags: Hash[(String | Symbol), untyped]) -> Enumerator[Riffer::StreamEvents::Base, void]
18
- def stream: (agent: Riffer::Agent, ?prompt: String?, ?files: Array[Hash[Symbol, untyped] | Riffer::Messages::FilePart]?, ?tags: Hash[String | Symbol, untyped]) -> Enumerator[Riffer::StreamEvents::Base, void]
17
+ # : (agent: Riffer::Agent, ?prompt: String?, ?files: Array[Hash[Symbol, untyped] | Riffer::Messages::FilePart]?, ?tags: Hash[(String | Symbol), untyped]) -> Enumerator[Riffer::StreamEvents::Base, Riffer::Agent::Response]
18
+ def stream: (agent: Riffer::Agent, ?prompt: String?, ?files: Array[Hash[Symbol, untyped] | Riffer::Messages::FilePart]?, ?tags: Hash[String | Symbol, untyped]) -> Enumerator[Riffer::StreamEvents::Base, Riffer::Agent::Response]
19
19
 
20
20
  private
21
21
 
@@ -45,8 +45,16 @@ module Riffer::Agent::Run
45
45
  def tripwire_response: (Riffer::Agent, Enumerator::Yielder?, Riffer::Guardrails::Tripwire, Array[Riffer::Guardrails::Modification], ?token_usage: Riffer::Providers::TokenUsage?, ?steps: Integer) -> Riffer::Agent::Response
46
46
 
47
47
  # --
48
- # : (Riffer::Agent, Array[Riffer::Guardrails::Modification], **untyped) -> Riffer::Agent::Response
49
- def final_response: (Riffer::Agent, Array[Riffer::Guardrails::Modification], **untyped) -> Riffer::Agent::Response
48
+ # : (Riffer::Agent, Array[Riffer::Guardrails::Modification], ?interrupted: bool, ?interrupt_reason: (String | Symbol)?, **untyped) -> Riffer::Agent::Response
49
+ def final_response: (Riffer::Agent, Array[Riffer::Guardrails::Modification], ?interrupted: bool, ?interrupt_reason: (String | Symbol)?, **untyped) -> Riffer::Agent::Response
50
+
51
+ # Checked in the order things happened. The loop being stopped (max_steps or
52
+ # an interrupt) beats the provider's finish reason, which beats riffer's own
53
+ # validation of the content. A truncated response that also fails the schema
54
+ # therefore reports :length, not :invalid_structured_output.
55
+ # --
56
+ # : (Riffer::Messages::Assistant?, Riffer::Agent::StructuredOutput::Result?, interrupted: bool, interrupt_reason: (String | Symbol)?) -> Riffer::Agent::Outcome
57
+ def final_outcome: (Riffer::Messages::Assistant?, Riffer::Agent::StructuredOutput::Result?, interrupted: bool, interrupt_reason: (String | Symbol)?) -> Riffer::Agent::Outcome
50
58
 
51
59
  # --
52
60
  # : (Riffer::Agent, ?Hash[String, String]) -> Riffer::Messages::Assistant
@@ -77,8 +85,8 @@ module Riffer::Agent::Run
77
85
  def run_after_guardrails: (Riffer::Agent, Riffer::Messages::Assistant, Enumerator::Yielder?, Array[Riffer::Guardrails::Modification], ?Hash[String, String]) { (Riffer::Guardrails::Tripwire) -> void } -> untyped
78
86
 
79
87
  # --
80
- # : (Riffer::Agent, Riffer::Messages::Assistant?) -> Hash[Symbol, untyped]?
81
- def validate_structured_output: (Riffer::Agent, Riffer::Messages::Assistant?) -> Hash[Symbol, untyped]?
88
+ # : (Riffer::Agent, Riffer::Messages::Assistant?) -> Riffer::Agent::StructuredOutput::Result?
89
+ def structured_output_result: (Riffer::Agent, Riffer::Messages::Assistant?) -> Riffer::Agent::StructuredOutput::Result?
82
90
 
83
91
  # --
84
92
  # : (Riffer::Agent) -> Array[singleton(Riffer::Tool)]
@@ -96,16 +104,15 @@ module Riffer::Agent::Run
96
104
  # : (
97
105
  # Riffer::Agent,
98
106
  # String,
107
+ # outcome: Riffer::Agent::Outcome,
99
108
  # ?tripwire: Riffer::Guardrails::Tripwire?,
100
109
  # ?modifications: Array[Riffer::Guardrails::Modification],
101
- # ?interrupted: bool,
102
- # ?interrupt_reason: (String | Symbol)?,
103
110
  # ?structured_output: Hash[Symbol, untyped]?,
104
111
  # ?healed_tool_call_ids: Array[String],
105
112
  # ?token_usage: Riffer::Providers::TokenUsage?,
106
113
  # ?steps: Integer
107
114
  # ) -> Riffer::Agent::Response
108
- def build_response: (Riffer::Agent, String, ?tripwire: Riffer::Guardrails::Tripwire?, ?modifications: Array[Riffer::Guardrails::Modification], ?interrupted: bool, ?interrupt_reason: (String | Symbol)?, ?structured_output: Hash[Symbol, untyped]?, ?healed_tool_call_ids: Array[String], ?token_usage: Riffer::Providers::TokenUsage?, ?steps: Integer) -> Riffer::Agent::Response
115
+ def build_response: (Riffer::Agent, String, outcome: Riffer::Agent::Outcome, ?tripwire: Riffer::Guardrails::Tripwire?, ?modifications: Array[Riffer::Guardrails::Modification], ?structured_output: Hash[Symbol, untyped]?, ?healed_tool_call_ids: Array[String], ?token_usage: Riffer::Providers::TokenUsage?, ?steps: Integer) -> Riffer::Agent::Response
109
116
 
110
117
  # Raises when +files+ are supplied without a +prompt+ — the provider needs
111
118
  # text to anchor the attachments.
@@ -136,4 +143,8 @@ module Riffer::Agent::Run
136
143
  # --
137
144
  # : (Riffer::Tracing::Otel::Span | Riffer::Tracing::NoOp::Span, Riffer::Agent::Response) -> void
138
145
  def record_run_outcome: (Riffer::Tracing::Otel::Span | Riffer::Tracing::NoOp::Span, Riffer::Agent::Response) -> void
146
+
147
+ # --
148
+ # : (Riffer::Agent::Outcome) -> String?
149
+ def interrupt_reason_attribute: (Riffer::Agent::Outcome) -> String?
139
150
  end
@@ -113,8 +113,8 @@ class Riffer::Agent
113
113
 
114
114
  # Streams a response using a new agent instance.
115
115
  # --
116
- # : (?String?, ?files: Array[Hash[Symbol, untyped] | Riffer::Messages::FilePart]?, ?context: Hash[Symbol, untyped]?, ?tags: Hash[(String | Symbol), untyped]) -> Enumerator[Riffer::StreamEvents::Base, void]
117
- def self.stream: (?String?, ?files: Array[Hash[Symbol, untyped] | Riffer::Messages::FilePart]?, ?context: Hash[Symbol, untyped]?, ?tags: Hash[String | Symbol, untyped]) -> Enumerator[Riffer::StreamEvents::Base, void]
116
+ # : (?String?, ?files: Array[Hash[Symbol, untyped] | Riffer::Messages::FilePart]?, ?context: Hash[Symbol, untyped]?, ?tags: Hash[(String | Symbol), untyped]) -> Enumerator[Riffer::StreamEvents::Base, Riffer::Agent::Response]
117
+ def self.stream: (?String?, ?files: Array[Hash[Symbol, untyped] | Riffer::Messages::FilePart]?, ?context: Hash[Symbol, untyped]?, ?tags: Hash[String | Symbol, untyped]) -> Enumerator[Riffer::StreamEvents::Base, Riffer::Agent::Response]
118
118
 
119
119
  # Reconstructs a runnable agent from a wire hash produced by +#to_h+.
120
120
  # --
@@ -208,14 +208,15 @@ class Riffer::Agent
208
208
  # : (?String?, ?files: Array[Hash[Symbol, untyped] | Riffer::Messages::FilePart]?, ?tags: Hash[(String | Symbol), untyped]) -> Riffer::Agent::Response
209
209
  def generate: (?String?, ?files: Array[Hash[Symbol, untyped] | Riffer::Messages::FilePart]?, ?tags: Hash[String | Symbol, untyped]) -> Riffer::Agent::Response
210
210
 
211
- # Streams a response from the agent, returning an +Enumerator+ of
212
- # +Riffer::StreamEvents+. See +#generate+ for prompt/files/tags semantics.
211
+ # Streams a response from the agent as an +Enumerator+ of
212
+ # +Riffer::StreamEvents+ whose block-form +each+ returns the final
213
+ # Riffer::Agent::Response. See +#generate+ for prompt/files/tags semantics.
213
214
  #
214
215
  # Raises Riffer::ArgumentError if structured output is configured.
215
216
  #
216
217
  # --
217
- # : (?String?, ?files: Array[Hash[Symbol, untyped] | Riffer::Messages::FilePart]?, ?tags: Hash[(String | Symbol), untyped]) -> Enumerator[Riffer::StreamEvents::Base, void]
218
- def stream: (?String?, ?files: Array[Hash[Symbol, untyped] | Riffer::Messages::FilePart]?, ?tags: Hash[String | Symbol, untyped]) -> Enumerator[Riffer::StreamEvents::Base, void]
218
+ # : (?String?, ?files: Array[Hash[Symbol, untyped] | Riffer::Messages::FilePart]?, ?tags: Hash[(String | Symbol), untyped]) -> Enumerator[Riffer::StreamEvents::Base, Riffer::Agent::Response]
219
+ def stream: (?String?, ?files: Array[Hash[Symbol, untyped] | Riffer::Messages::FilePart]?, ?tags: Hash[String | Symbol, untyped]) -> Enumerator[Riffer::StreamEvents::Base, Riffer::Agent::Response]
219
220
 
220
221
  # Interrupts the agent loop from an +on_message+ callback. Equivalent to
221
222
  # <tt>throw :riffer_interrupt, reason</tt>.
@@ -27,11 +27,23 @@ class Riffer::Messages::Assistant < Riffer::Messages::Base
27
27
  # <tt>Riffer::Providers::FinishReason::VALUES</tt>).
28
28
  attr_reader finish_reason: Symbol?
29
29
 
30
+ # The provider's raw finish-reason value behind +finish_reason+, when one
31
+ # exists on the wire.
32
+ attr_reader finish_reason_raw: String?
33
+
30
34
  # Raises Riffer::ArgumentError when +finish_reason+ is outside the
31
35
  # normalized vocabulary.
32
36
  # --
33
- # : (String, ?id: String?, ?tool_calls: Array[Riffer::Messages::Assistant::ToolCall], ?token_usage: Riffer::Providers::TokenUsage?, ?structured_output: Hash[Symbol, untyped]?, ?finish_reason: Symbol?) -> void
34
- def initialize: (String, ?id: String?, ?tool_calls: Array[Riffer::Messages::Assistant::ToolCall], ?token_usage: Riffer::Providers::TokenUsage?, ?structured_output: Hash[Symbol, untyped]?, ?finish_reason: Symbol?) -> void
37
+ # : (
38
+ # String,
39
+ # ?id: String?,
40
+ # ?tool_calls: Array[Riffer::Messages::Assistant::ToolCall],
41
+ # ?token_usage: Riffer::Providers::TokenUsage?,
42
+ # ?structured_output: Hash[Symbol, untyped]?,
43
+ # ?finish_reason: Symbol?,
44
+ # ?finish_reason_raw: String?
45
+ # ) -> void
46
+ def initialize: (String, ?id: String?, ?tool_calls: Array[Riffer::Messages::Assistant::ToolCall], ?token_usage: Riffer::Providers::TokenUsage?, ?structured_output: Hash[Symbol, untyped]?, ?finish_reason: Symbol?, ?finish_reason_raw: String?) -> void
35
47
 
36
48
  # --
37
49
  # : () -> Symbol
@@ -40,6 +40,11 @@ class Riffer::Params
40
40
 
41
41
  # Validates arguments against parameter definitions.
42
42
  #
43
+ # A Float param accepts an Integer (JSON Schema <tt>"number"</tt> covers
44
+ # integers) and its value is coerced with +to_f+, so callers always get a
45
+ # Float. The same holds for the items of an <tt>of: Float</tt> array. No other
46
+ # type is coerced.
47
+ #
43
48
  # Raises Riffer::ValidationError if validation fails.
44
49
  #
45
50
  # --
@@ -71,7 +76,16 @@ class Riffer::Params
71
76
  # : (Riffer::Params::Param, Array[untyped], Array[String]) -> Array[untyped]
72
77
  def validate_nested_array_of_objects: (Riffer::Params::Param, Array[untyped], Array[String]) -> Array[untyped]
73
78
 
79
+ # Returns the array with its valid items coerced by +coerce_value+.
80
+ # --
81
+ # : (Riffer::Params::Param, Array[untyped], Array[String]) -> Array[untyped]
82
+ def validate_typed_array: (Riffer::Params::Param, Array[untyped], Array[String]) -> Array[untyped]
83
+
84
+ # Coerces an already-validated value to the Ruby type its param declares.
85
+ # Only Float coerces today, because JSON Schema "number" accepts integers and
86
+ # callers should not get a type that depends on whether the model wrote a
87
+ # decimal point. Add a branch here rather than inline at a call site.
74
88
  # --
75
- # : (Riffer::Params::Param, Array[untyped], Array[String]) -> void
76
- def validate_typed_array: (Riffer::Params::Param, Array[untyped], Array[String]) -> void
89
+ # : (Module, untyped) -> untyped
90
+ def coerce_value: (Module, untyped) -> untyped
77
91
  end
@@ -4,6 +4,8 @@
4
4
  # +max_concurrency+ caps simultaneous fibers via an <tt>Async::Semaphore</tt>.
5
5
  # If multiple fibers raise, only the first exception is re-raised after all
6
6
  # finish.
7
+ # Joins the current reactor task when one is already running, and otherwise
8
+ # starts its own.
7
9
  class Riffer::Runner::Fibers < Riffer::Runner
8
10
  @max_concurrency: Integer?
9
11
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: riffer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.45.0
4
+ version: 0.46.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jake Bottrall
@@ -110,6 +110,7 @@ files:
110
110
  - lib/riffer/agent.rb
111
111
  - lib/riffer/agent/config.rb
112
112
  - lib/riffer/agent/context.rb
113
+ - lib/riffer/agent/outcome.rb
113
114
  - lib/riffer/agent/response.rb
114
115
  - lib/riffer/agent/run.rb
115
116
  - lib/riffer/agent/serializer.rb
@@ -239,6 +240,7 @@ files:
239
240
  - sig/generated/riffer/agent.rbs
240
241
  - sig/generated/riffer/agent/config.rbs
241
242
  - sig/generated/riffer/agent/context.rbs
243
+ - sig/generated/riffer/agent/outcome.rbs
242
244
  - sig/generated/riffer/agent/response.rbs
243
245
  - sig/generated/riffer/agent/run.rbs
244
246
  - sig/generated/riffer/agent/serializer.rbs