riffer 0.47.2 → 0.49.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 (267) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/rules/comments.md +2 -4
  3. data/.claude/rules/rbs-inline.md +2 -12
  4. data/.release-please-manifest.json +1 -1
  5. data/.rubocop.yml +5 -0
  6. data/CHANGELOG.md +42 -0
  7. data/docs/AGENTS.md +39 -7
  8. data/docs/AGENT_LIFECYCLE.md +14 -16
  9. data/docs/CONFIGURATION.md +23 -34
  10. data/docs/EVALS.md +2 -1
  11. data/docs/MCP.md +0 -4
  12. data/docs/MESSAGES.md +85 -17
  13. data/docs/STREAM_EVENTS.md +8 -4
  14. data/docs/TOOL_ADVANCED.md +1 -3
  15. data/docs/TRACING.md +2 -2
  16. data/docs/providers/AMAZON_BEDROCK.md +32 -1
  17. data/docs/providers/CUSTOM_PROVIDERS.md +56 -4
  18. data/docs/providers/GEMINI.md +1 -1
  19. data/docs/providers/MOCK_PROVIDER.md +17 -0
  20. data/docs/providers/OPENROUTER.md +18 -1
  21. data/docs-site/build.rb +0 -6
  22. data/docs-site/check.rb +1 -5
  23. data/lib/riffer/agent/config.rb +27 -44
  24. data/lib/riffer/agent/context.rb +2 -26
  25. data/lib/riffer/agent/outcome.rb +0 -20
  26. data/lib/riffer/agent/response.rb +4 -35
  27. data/lib/riffer/agent/run.rb +32 -48
  28. data/lib/riffer/agent/serializer.rb +10 -39
  29. data/lib/riffer/agent/session/repair.rb +3 -15
  30. data/lib/riffer/agent/session.rb +26 -38
  31. data/lib/riffer/agent/structured_output/result.rb +0 -8
  32. data/lib/riffer/agent/structured_output.rb +0 -7
  33. data/lib/riffer/agent.rb +31 -127
  34. data/lib/riffer/config/amazon_bedrock.rb +30 -0
  35. data/lib/riffer/config/anthropic.rb +21 -0
  36. data/lib/riffer/config/azure_open_ai.rb +30 -0
  37. data/lib/riffer/config/evals.rb +18 -0
  38. data/lib/riffer/config/files.rb +61 -0
  39. data/lib/riffer/config/gemini.rb +21 -0
  40. data/lib/riffer/config/mcp.rb +31 -0
  41. data/lib/riffer/config/open_ai.rb +30 -0
  42. data/lib/riffer/config/open_router.rb +21 -0
  43. data/lib/riffer/config/pricing/rates.rb +36 -0
  44. data/lib/riffer/config/pricing.rb +64 -0
  45. data/lib/riffer/config/skills.rb +38 -0
  46. data/lib/riffer/config/tracing.rb +43 -0
  47. data/lib/riffer/config.rb +3 -362
  48. data/lib/riffer/evals/evaluator.rb +22 -23
  49. data/lib/riffer/evals/evaluator_runner.rb +0 -15
  50. data/lib/riffer/evals/judge.rb +9 -11
  51. data/lib/riffer/evals/result.rb +1 -11
  52. data/lib/riffer/evals/run_result.rb +0 -12
  53. data/lib/riffer/evals/scenario_result.rb +0 -19
  54. data/lib/riffer/files/downloader.rb +2 -3
  55. data/lib/riffer/files/resolver.rb +5 -10
  56. data/lib/riffer/guardrail.rb +2 -22
  57. data/lib/riffer/guardrails/modification.rb +0 -8
  58. data/lib/riffer/guardrails/result.rb +0 -17
  59. data/lib/riffer/guardrails/runner.rb +2 -11
  60. data/lib/riffer/guardrails/tripwire.rb +0 -8
  61. data/lib/riffer/guardrails.rb +0 -2
  62. data/lib/riffer/helpers/boolean.rb +0 -4
  63. data/lib/riffer/helpers/call_or_value.rb +0 -3
  64. data/lib/riffer/helpers/deep_dup.rb +37 -0
  65. data/lib/riffer/helpers/dependencies.rb +0 -4
  66. data/lib/riffer/helpers/identifier.rb +3 -12
  67. data/lib/riffer/helpers/validate.rb +42 -0
  68. data/lib/riffer/mcp/authenticated_tool.rb +4 -12
  69. data/lib/riffer/mcp/client.rb +0 -7
  70. data/lib/riffer/mcp/manifest.rb +3 -7
  71. data/lib/riffer/mcp/registration.rb +0 -10
  72. data/lib/riffer/mcp/registry.rb +0 -9
  73. data/lib/riffer/mcp/search_tool.rb +0 -4
  74. data/lib/riffer/mcp/tool.rb +1 -4
  75. data/lib/riffer/mcp/tool_factory.rb +3 -6
  76. data/lib/riffer/mcp.rb +2 -23
  77. data/lib/riffer/messages/assistant/reasoning_part.rb +73 -0
  78. data/lib/riffer/messages/assistant/tool_call.rb +55 -0
  79. data/lib/riffer/messages/assistant.rb +43 -15
  80. data/lib/riffer/messages/base.rb +5 -33
  81. data/lib/riffer/messages/system.rb +8 -1
  82. data/lib/riffer/messages/tool.rb +15 -13
  83. data/lib/riffer/messages/{file_part.rb → user/file_part.rb} +16 -40
  84. data/lib/riffer/messages/user.rb +11 -4
  85. data/lib/riffer/params/boolean.rb +1 -5
  86. data/lib/riffer/params/param.rb +15 -31
  87. data/lib/riffer/params.rb +15 -39
  88. data/lib/riffer/providers/amazon_bedrock.rb +104 -44
  89. data/lib/riffer/providers/anthropic.rb +11 -26
  90. data/lib/riffer/providers/azure_open_ai.rb +3 -8
  91. data/lib/riffer/providers/base.rb +30 -32
  92. data/lib/riffer/providers/finish_reason.rb +0 -6
  93. data/lib/riffer/providers/gemini/client.rb +4 -17
  94. data/lib/riffer/providers/gemini.rb +6 -12
  95. data/lib/riffer/providers/mock.rb +18 -27
  96. data/lib/riffer/providers/open_ai.rb +12 -21
  97. data/lib/riffer/providers/open_router.rb +109 -33
  98. data/lib/riffer/providers/repository.rb +2 -14
  99. data/lib/riffer/providers/token_usage.rb +19 -12
  100. data/lib/riffer/registrable.rb +11 -45
  101. data/lib/riffer/runner/fibers.rb +1 -6
  102. data/lib/riffer/runner/sequential.rb +0 -1
  103. data/lib/riffer/runner/threaded.rb +0 -3
  104. data/lib/riffer/runner.rb +0 -3
  105. data/lib/riffer/skills/activate_tool.rb +0 -3
  106. data/lib/riffer/skills/adapter.rb +0 -8
  107. data/lib/riffer/skills/backend.rb +2 -7
  108. data/lib/riffer/skills/config.rb +13 -17
  109. data/lib/riffer/skills/context.rb +0 -29
  110. data/lib/riffer/skills/filesystem_backend.rb +0 -7
  111. data/lib/riffer/skills/frontmatter.rb +2 -16
  112. data/lib/riffer/skills/markdown_adapter.rb +3 -6
  113. data/lib/riffer/skills/xml_adapter.rb +0 -3
  114. data/lib/riffer/stream_events/base.rb +0 -3
  115. data/lib/riffer/stream_events/finish_reason_done.rb +1 -6
  116. data/lib/riffer/stream_events/guardrail_modification.rb +0 -10
  117. data/lib/riffer/stream_events/guardrail_tripwire.rb +0 -10
  118. data/lib/riffer/stream_events/interrupt.rb +2 -12
  119. data/lib/riffer/stream_events/reasoning_delta.rb +0 -3
  120. data/lib/riffer/stream_events/reasoning_done.rb +6 -8
  121. data/lib/riffer/stream_events/skill_activation.rb +0 -3
  122. data/lib/riffer/stream_events/text_delta.rb +0 -2
  123. data/lib/riffer/stream_events/text_done.rb +0 -2
  124. data/lib/riffer/stream_events/token_usage_done.rb +0 -2
  125. data/lib/riffer/stream_events/tool_call_delta.rb +1 -5
  126. data/lib/riffer/stream_events/tool_call_done.rb +0 -5
  127. data/lib/riffer/stream_events/web_search_done.rb +0 -3
  128. data/lib/riffer/stream_events/web_search_status.rb +1 -5
  129. data/lib/riffer/testing/minitest.rb +4 -5
  130. data/lib/riffer/testing.rb +5 -38
  131. data/lib/riffer/tool.rb +2 -28
  132. data/lib/riffer/tools/response.rb +3 -32
  133. data/lib/riffer/tools/runtime/fibers.rb +0 -6
  134. data/lib/riffer/tools/runtime/inline.rb +0 -1
  135. data/lib/riffer/tools/runtime/threaded.rb +0 -6
  136. data/lib/riffer/tools/runtime.rb +8 -30
  137. data/lib/riffer/tools/toolable.rb +0 -37
  138. data/lib/riffer/tracing/capture.rb +5 -9
  139. data/lib/riffer/tracing/no_op.rb +0 -7
  140. data/lib/riffer/tracing/otel.rb +7 -16
  141. data/lib/riffer/tracing/stream_recorder.rb +0 -7
  142. data/lib/riffer/tracing.rb +4 -27
  143. data/lib/riffer/version.rb +1 -1
  144. data/lib/riffer.rb +2 -30
  145. data/sig/generated/riffer/agent/config.rbs +24 -46
  146. data/sig/generated/riffer/agent/context.rbs +2 -26
  147. data/sig/generated/riffer/agent/outcome.rbs +0 -20
  148. data/sig/generated/riffer/agent/response.rbs +4 -27
  149. data/sig/generated/riffer/agent/run.rbs +12 -31
  150. data/sig/generated/riffer/agent/serializer.rbs +2 -27
  151. data/sig/generated/riffer/agent/session/repair.rbs +2 -10
  152. data/sig/generated/riffer/agent/session.rbs +10 -36
  153. data/sig/generated/riffer/agent/structured_output/result.rbs +0 -7
  154. data/sig/generated/riffer/agent/structured_output.rbs +0 -7
  155. data/sig/generated/riffer/agent.rbs +25 -125
  156. data/sig/generated/riffer/config/amazon_bedrock.rbs +21 -0
  157. data/sig/generated/riffer/config/anthropic.rbs +15 -0
  158. data/sig/generated/riffer/config/azure_open_ai.rbs +21 -0
  159. data/sig/generated/riffer/config/evals.rbs +13 -0
  160. data/sig/generated/riffer/config/files.rbs +43 -0
  161. data/sig/generated/riffer/config/gemini.rbs +15 -0
  162. data/sig/generated/riffer/config/mcp.rbs +19 -0
  163. data/sig/generated/riffer/config/open_ai.rbs +21 -0
  164. data/sig/generated/riffer/config/open_router.rbs +15 -0
  165. data/sig/generated/riffer/config/pricing/rates.rbs +19 -0
  166. data/sig/generated/riffer/config/pricing.rbs +31 -0
  167. data/sig/generated/riffer/config/skills.rbs +19 -0
  168. data/sig/generated/riffer/config/tracing.rbs +25 -0
  169. data/sig/generated/riffer/config.rbs +2 -307
  170. data/sig/generated/riffer/evals/evaluator.rbs +12 -21
  171. data/sig/generated/riffer/evals/evaluator_runner.rbs +0 -14
  172. data/sig/generated/riffer/evals/judge.rbs +4 -8
  173. data/sig/generated/riffer/evals/result.rbs +1 -11
  174. data/sig/generated/riffer/evals/run_result.rbs +0 -12
  175. data/sig/generated/riffer/evals/scenario_result.rbs +0 -14
  176. data/sig/generated/riffer/files/resolver.rbs +6 -13
  177. data/sig/generated/riffer/guardrail.rbs +2 -22
  178. data/sig/generated/riffer/guardrails/modification.rbs +0 -6
  179. data/sig/generated/riffer/guardrails/result.rbs +0 -15
  180. data/sig/generated/riffer/guardrails/runner.rbs +0 -11
  181. data/sig/generated/riffer/guardrails/tripwire.rbs +0 -8
  182. data/sig/generated/riffer/guardrails.rbs +0 -2
  183. data/sig/generated/riffer/helpers/boolean.rbs +0 -4
  184. data/sig/generated/riffer/helpers/call_or_value.rbs +0 -3
  185. data/sig/generated/riffer/helpers/deep_dup.rbs +13 -0
  186. data/sig/generated/riffer/helpers/dependencies.rbs +0 -4
  187. data/sig/generated/riffer/helpers/identifier.rbs +0 -12
  188. data/sig/generated/riffer/helpers/validate.rbs +21 -0
  189. data/sig/generated/riffer/mcp/authenticated_tool.rbs +0 -5
  190. data/sig/generated/riffer/mcp/client.rbs +0 -7
  191. data/sig/generated/riffer/mcp/manifest.rbs +3 -7
  192. data/sig/generated/riffer/mcp/registration.rbs +0 -10
  193. data/sig/generated/riffer/mcp/registry.rbs +0 -9
  194. data/sig/generated/riffer/mcp/search_tool.rbs +0 -4
  195. data/sig/generated/riffer/mcp/tool.rbs +0 -4
  196. data/sig/generated/riffer/mcp/tool_factory.rbs +0 -6
  197. data/sig/generated/riffer/mcp.rbs +2 -22
  198. data/sig/generated/riffer/messages/assistant/reasoning_part.rbs +45 -0
  199. data/sig/generated/riffer/messages/assistant/tool_call.rbs +34 -0
  200. data/sig/generated/riffer/messages/assistant.rbs +25 -31
  201. data/sig/generated/riffer/messages/base.rbs +0 -12
  202. data/sig/generated/riffer/messages/system.rbs +4 -1
  203. data/sig/generated/riffer/messages/tool.rbs +4 -10
  204. data/sig/generated/riffer/messages/user/file_part.rbs +76 -0
  205. data/sig/generated/riffer/messages/user.rbs +7 -5
  206. data/sig/generated/riffer/params/boolean.rbs +1 -4
  207. data/sig/generated/riffer/params/param.rbs +7 -31
  208. data/sig/generated/riffer/params.rbs +8 -38
  209. data/sig/generated/riffer/providers/amazon_bedrock.rbs +33 -29
  210. data/sig/generated/riffer/providers/anthropic.rbs +2 -12
  211. data/sig/generated/riffer/providers/azure_open_ai.rbs +0 -8
  212. data/sig/generated/riffer/providers/base.rbs +18 -34
  213. data/sig/generated/riffer/providers/finish_reason.rbs +0 -6
  214. data/sig/generated/riffer/providers/gemini/client.rbs +4 -17
  215. data/sig/generated/riffer/providers/gemini.rbs +4 -10
  216. data/sig/generated/riffer/providers/mock.rbs +6 -27
  217. data/sig/generated/riffer/providers/open_ai.rbs +6 -13
  218. data/sig/generated/riffer/providers/open_router.rbs +37 -18
  219. data/sig/generated/riffer/providers/repository.rbs +2 -14
  220. data/sig/generated/riffer/providers/token_usage.rbs +9 -12
  221. data/sig/generated/riffer/registrable.rbs +0 -45
  222. data/sig/generated/riffer/runner/fibers.rbs +0 -6
  223. data/sig/generated/riffer/runner/sequential.rbs +0 -1
  224. data/sig/generated/riffer/runner/threaded.rbs +0 -3
  225. data/sig/generated/riffer/runner.rbs +0 -3
  226. data/sig/generated/riffer/skills/activate_tool.rbs +0 -3
  227. data/sig/generated/riffer/skills/adapter.rbs +0 -8
  228. data/sig/generated/riffer/skills/backend.rbs +2 -7
  229. data/sig/generated/riffer/skills/config.rbs +6 -17
  230. data/sig/generated/riffer/skills/context.rbs +0 -29
  231. data/sig/generated/riffer/skills/filesystem_backend.rbs +0 -7
  232. data/sig/generated/riffer/skills/frontmatter.rbs +2 -16
  233. data/sig/generated/riffer/skills/markdown_adapter.rbs +0 -6
  234. data/sig/generated/riffer/skills/xml_adapter.rbs +0 -3
  235. data/sig/generated/riffer/stream_events/base.rbs +0 -3
  236. data/sig/generated/riffer/stream_events/finish_reason_done.rbs +1 -6
  237. data/sig/generated/riffer/stream_events/guardrail_modification.rbs +0 -10
  238. data/sig/generated/riffer/stream_events/guardrail_tripwire.rbs +0 -10
  239. data/sig/generated/riffer/stream_events/interrupt.rbs +2 -10
  240. data/sig/generated/riffer/stream_events/reasoning_delta.rbs +0 -3
  241. data/sig/generated/riffer/stream_events/reasoning_done.rbs +4 -6
  242. data/sig/generated/riffer/stream_events/skill_activation.rbs +0 -3
  243. data/sig/generated/riffer/stream_events/text_delta.rbs +0 -2
  244. data/sig/generated/riffer/stream_events/text_done.rbs +0 -2
  245. data/sig/generated/riffer/stream_events/token_usage_done.rbs +0 -2
  246. data/sig/generated/riffer/stream_events/tool_call_delta.rbs +1 -5
  247. data/sig/generated/riffer/stream_events/tool_call_done.rbs +0 -5
  248. data/sig/generated/riffer/stream_events/web_search_done.rbs +0 -3
  249. data/sig/generated/riffer/stream_events/web_search_status.rbs +1 -5
  250. data/sig/generated/riffer/testing.rbs +0 -38
  251. data/sig/generated/riffer/tool.rbs +0 -27
  252. data/sig/generated/riffer/tools/response.rbs +3 -29
  253. data/sig/generated/riffer/tools/runtime/fibers.rbs +0 -5
  254. data/sig/generated/riffer/tools/runtime/inline.rbs +0 -1
  255. data/sig/generated/riffer/tools/runtime/threaded.rbs +0 -5
  256. data/sig/generated/riffer/tools/runtime.rbs +4 -26
  257. data/sig/generated/riffer/tools/toolable.rbs +0 -37
  258. data/sig/generated/riffer/tracing/capture.rbs +6 -9
  259. data/sig/generated/riffer/tracing/no_op.rbs +0 -7
  260. data/sig/generated/riffer/tracing/otel.rbs +7 -16
  261. data/sig/generated/riffer/tracing/stream_recorder.rbs +0 -2
  262. data/sig/generated/riffer/tracing.rbs +4 -23
  263. data/sig/generated/riffer.rbs +2 -29
  264. data/sig/manual/riffer/helpers/deep_dup.rbs +5 -0
  265. data/sig/manual/riffer/helpers/validate.rbs +5 -0
  266. metadata +39 -3
  267. data/sig/generated/riffer/messages/file_part.rbs +0 -101
@@ -1,9 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  # rbs_inline: enabled
3
3
 
4
- # Emitted when a guardrail transforms data during streaming.
5
4
  class Riffer::StreamEvents::GuardrailModification < Riffer::StreamEvents::Base
6
- # The modification record.
7
5
  attr_reader :modification #: Riffer::Guardrails::Modification # @dynamic modification
8
6
 
9
7
  #--
@@ -13,26 +11,18 @@ class Riffer::StreamEvents::GuardrailModification < Riffer::StreamEvents::Base
13
11
  @modification = modification
14
12
  end
15
13
 
16
- # The guardrail class that made the transformation.
17
- #
18
14
  #--
19
15
  #: () -> singleton(Riffer::Guardrail)
20
16
  def guardrail = modification.guardrail
21
17
 
22
- # The phase when the transformation occurred.
23
- #
24
18
  #--
25
19
  #: () -> Symbol
26
20
  def phase = modification.phase
27
21
 
28
- # The indices of messages that were changed.
29
- #
30
22
  #--
31
23
  #: () -> Array[Integer]
32
24
  def message_indices = modification.message_indices
33
25
 
34
- # Converts the event to a hash.
35
- #
36
26
  #--
37
27
  #: () -> Hash[Symbol, untyped]
38
28
  def to_h
@@ -1,9 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  # rbs_inline: enabled
3
3
 
4
- # Emitted when a guardrail blocks execution during streaming.
5
4
  class Riffer::StreamEvents::GuardrailTripwire < Riffer::StreamEvents::Base
6
- # The tripwire containing block details.
7
5
  attr_reader :tripwire #: Riffer::Guardrails::Tripwire # @dynamic tripwire
8
6
 
9
7
  #--
@@ -13,32 +11,24 @@ class Riffer::StreamEvents::GuardrailTripwire < Riffer::StreamEvents::Base
13
11
  @tripwire = tripwire
14
12
  end
15
13
 
16
- # The reason for blocking.
17
- #
18
14
  #--
19
15
  #: () -> String
20
16
  def reason
21
17
  tripwire.reason
22
18
  end
23
19
 
24
- # The phase when blocking occurred (:before or :after).
25
- #
26
20
  #--
27
21
  #: () -> Symbol
28
22
  def phase
29
23
  tripwire.phase
30
24
  end
31
25
 
32
- # The guardrail class that triggered the block.
33
- #
34
26
  #--
35
27
  #: () -> singleton(Riffer::Guardrail)
36
28
  def guardrail
37
29
  tripwire.guardrail
38
30
  end
39
31
 
40
- # Converts the event to a hash.
41
- #
42
32
  #--
43
33
  #: () -> Hash[Symbol, untyped]
44
34
  def to_h
@@ -1,31 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
  # rbs_inline: enabled
3
3
 
4
- # Represents an interrupt during streaming, fired when a callback throws
5
- # +:riffer_interrupt+.
6
4
  class Riffer::StreamEvents::Interrupt < Riffer::StreamEvents::Base
7
- # The reason provided with the interrupt, if any.
8
5
  attr_reader :reason #: (String | Symbol)? # @dynamic reason
9
6
 
10
- # Call ids of tool_use blocks riffer filled with placeholder results when the
11
- # interrupt fired (only when history healing is on).
12
- attr_reader :healed_tool_call_ids #: Array[String] # @dynamic healed_tool_call_ids
13
-
14
7
  #--
15
- #: (?reason: (String | Symbol)?, ?healed_tool_call_ids: Array[String]) -> void
16
- def initialize(reason: nil, healed_tool_call_ids: [])
8
+ #: (?reason: (String | Symbol)?) -> void
9
+ def initialize(reason: nil)
17
10
  super(role: :system)
18
11
  @reason = reason
19
- @healed_tool_call_ids = healed_tool_call_ids
20
12
  end
21
13
 
22
- # Converts the event to a hash.
23
14
  #--
24
15
  #: () -> Hash[Symbol, untyped]
25
16
  def to_h
26
17
  h = { role: @role, interrupt: true } #: Hash[Symbol, untyped]
27
18
  h[:reason] = @reason if @reason
28
- h[:healed_tool_call_ids] = @healed_tool_call_ids unless @healed_tool_call_ids.empty?
29
19
  h
30
20
  end
31
21
  end
@@ -1,10 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  # rbs_inline: enabled
3
3
 
4
- # Represents an incremental reasoning chunk during streaming; only emitted by
5
- # providers that support reasoning (e.g. OpenAI with the reasoning option).
6
4
  class Riffer::StreamEvents::ReasoningDelta < Riffer::StreamEvents::Base
7
- # The incremental reasoning content.
8
5
  attr_reader :content #: String # @dynamic content
9
6
 
10
7
  #--
@@ -1,22 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
  # rbs_inline: enabled
3
3
 
4
- # Represents completed reasoning during streaming; only emitted by providers
5
- # that support reasoning (e.g. OpenAI with the reasoning option).
6
4
  class Riffer::StreamEvents::ReasoningDone < Riffer::StreamEvents::Base
7
- # The complete reasoning content.
8
- attr_reader :content #: String # @dynamic content
5
+ # +text+ is the concatenation of the preceding ReasoningDelta events.
6
+ attr_reader :part #: Riffer::Messages::Assistant::ReasoningPart # @dynamic part
9
7
 
10
8
  #--
11
- #: (String, ?role: Symbol) -> void
12
- def initialize(content, role: :assistant)
9
+ #: (Riffer::Messages::Assistant::ReasoningPart, ?role: Symbol) -> void
10
+ def initialize(part, role: :assistant)
13
11
  super(role: role)
14
- @content = content
12
+ @part = part
15
13
  end
16
14
 
17
15
  #--
18
16
  #: () -> Hash[Symbol, untyped]
19
17
  def to_h
20
- { role: @role, content: @content }
18
+ { role: @role, part: part.to_h }
21
19
  end
22
20
  end
@@ -1,10 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  # rbs_inline: enabled
3
3
 
4
- # Emitted when a skill is activated during streaming, via the +on_activate+
5
- # callback when the LLM calls the activation tool.
6
4
  class Riffer::StreamEvents::SkillActivation < Riffer::StreamEvents::Base
7
- # The activated skill name.
8
5
  attr_reader :name #: String # @dynamic name
9
6
 
10
7
  #--
@@ -1,9 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  # rbs_inline: enabled
3
3
 
4
- # Represents an incremental text chunk during streaming.
5
4
  class Riffer::StreamEvents::TextDelta < Riffer::StreamEvents::Base
6
- # The incremental text content.
7
5
  attr_reader :content #: String # @dynamic content
8
6
 
9
7
  #--
@@ -1,9 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  # rbs_inline: enabled
3
3
 
4
- # Represents completed text generation during streaming.
5
4
  class Riffer::StreamEvents::TextDone < Riffer::StreamEvents::Base
6
- # The complete text content.
7
5
  attr_reader :content #: String # @dynamic content
8
6
 
9
7
  #--
@@ -1,9 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  # rbs_inline: enabled
3
3
 
4
- # Final token usage for the response, emitted when the LLM finishes.
5
4
  class Riffer::StreamEvents::TokenUsageDone < Riffer::StreamEvents::Base
6
- # The token usage data for this response.
7
5
  attr_reader :token_usage #: Riffer::Providers::TokenUsage # @dynamic token_usage
8
6
 
9
7
  #--
@@ -1,16 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
  # rbs_inline: enabled
3
3
 
4
- # Represents an incremental tool call chunk (partial argument data) during
5
- # streaming.
6
4
  class Riffer::StreamEvents::ToolCallDelta < Riffer::StreamEvents::Base
7
- # The tool call item identifier.
8
5
  attr_reader :item_id #: String # @dynamic item_id
9
6
 
10
- # The tool name (may only be present in first delta).
7
+ # Providers may send the name only on the first delta.
11
8
  attr_reader :name #: String? # @dynamic name
12
9
 
13
- # The incremental arguments JSON fragment.
14
10
  attr_reader :arguments_delta #: String # @dynamic arguments_delta
15
11
 
16
12
  #--
@@ -1,18 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
  # rbs_inline: enabled
3
3
 
4
- # Represents a completed tool call during streaming.
5
4
  class Riffer::StreamEvents::ToolCallDone < Riffer::StreamEvents::Base
6
- # The tool call item identifier.
7
5
  attr_reader :item_id #: String # @dynamic item_id
8
6
 
9
- # The call identifier for response matching.
10
7
  attr_reader :call_id #: String # @dynamic call_id
11
8
 
12
- # The tool name.
13
9
  attr_reader :name #: String # @dynamic name
14
10
 
15
- # The complete arguments JSON string.
16
11
  attr_reader :arguments #: String # @dynamic arguments
17
12
 
18
13
  #--
@@ -1,12 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
  # rbs_inline: enabled
3
3
 
4
- # The result of a completed server-side web search during streaming.
5
4
  class Riffer::StreamEvents::WebSearchDone < Riffer::StreamEvents::Base
6
- # The search query used.
7
5
  attr_reader :query #: String # @dynamic query
8
6
 
9
- # The search result sources with title and url.
10
7
  attr_reader :sources #: Array[Hash[Symbol, String?]] # @dynamic sources
11
8
 
12
9
  #--
@@ -1,16 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
  # rbs_inline: enabled
3
3
 
4
- # A web search status notification, emitted as a server-side web search
5
- # progresses.
6
4
  class Riffer::StreamEvents::WebSearchStatus < Riffer::StreamEvents::Base
7
- # The web search status ("in_progress", "searching", "completed", "open_page").
5
+ # One of "in_progress", "searching", "open_page", or "completed".
8
6
  attr_reader :status #: String # @dynamic status
9
7
 
10
- # The URL being fetched (present for "open_page" status).
11
8
  attr_reader :url #: String? # @dynamic url
12
9
 
13
- # The search query (present when available during status changes).
14
10
  attr_reader :query #: String? # @dynamic query
15
11
 
16
12
  #--
@@ -1,13 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # rbs-inline stays disabled here: the generated signature would name Minitest,
4
- # which a shipped signature must never reference. The hand-written stub lives in
5
- # sig/_private/riffer/testing/minitest.rbs.
3
+ # rbs-inline stays disabled: a shipped signature must never name Minitest. The
4
+ # stub lives in sig/_private/riffer/testing/minitest.rbs.
6
5
 
7
6
  require "riffer"
8
7
 
9
- # Wiring only — minitest is never a riffer dependency; a consumer requires this
10
- # file from a test_helper that has already loaded the framework.
8
+ # Minitest is never a riffer dependency; the consumer's test_helper loads it
9
+ # before requiring this file.
11
10
  module Riffer::Testing::MinitestCleanup
12
11
  # Minitest reserves +after_teardown+ for library extensions; +teardown+
13
12
  # belongs to the test author.
@@ -1,14 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  # rbs_inline: enabled
3
3
 
4
- # Builds throwaway agents and tools a test suite can resolve by identifier or
5
- # constant name, and removes them again. Require <tt>riffer/testing/rspec</tt>
6
- # or <tt>riffer/testing/minitest</tt> to get +stub_agent+/+stub_tool+ in every
7
- # example plus per-test cleanup; otherwise include this module and call +reset!+
8
- # from your own teardown, or call the methods on the module directly.
9
- #
10
- # Tracking is not synchronized — stub from a single-threaded test, before
11
- # concurrent lookups begin.
12
4
  module Riffer::Testing
13
5
  extend self
14
6
 
@@ -17,43 +9,18 @@ module Riffer::Testing
17
9
  CONST_NAME_PATTERN = /\A[A-Z][A-Za-z0-9_]*\z/ #: Regexp
18
10
  private_constant :CONST_NAME_PATTERN
19
11
 
20
- # Builds an agent class, evaluates the optional body in it, and makes it
21
- # resolvable until the next +reset!+. A +name+ assigns a top-level constant
22
- # and derives the identifier; the body may set +identifier+ like any other
23
- # agent config.
24
- #
25
- # agent = stub_agent("SupportAgent") { model "mock/gpt-5-mini" }
26
- #
27
- # Raises Riffer::ArgumentError when the constant is already defined or the
28
- # stub ends up with no identifier, and Riffer::DuplicateIdentifierError when
29
- # another agent already holds the identifier.
30
- #
31
12
  #--
32
13
  #: (?(String | Symbol)?, ?base: singleton(Riffer::Agent)) ?{ () [self: singleton(Riffer::Agent)] -> void } -> singleton(Riffer::Agent)
33
14
  def stub_agent(name = nil, base: Riffer::Agent, &body)
34
15
  build_stub(name, base: base, &body) #: singleton(Riffer::Agent)
35
16
  end
36
17
 
37
- # Builds a tool class, evaluates the optional body in it, and makes it
38
- # resolvable until the next +reset!+. A +name+ assigns a top-level constant
39
- # and derives the identifier; the body may set +identifier+ like any other
40
- # tool config.
41
- #
42
- # tool = stub_tool("KbSearch") { def call(context:, **) = text("stubbed") }
43
- #
44
- # Raises Riffer::ArgumentError when the constant is already defined or the
45
- # stub ends up with no identifier, and Riffer::DuplicateIdentifierError when
46
- # another tool already holds the identifier.
47
- #
48
18
  #--
49
19
  #: (?(String | Symbol)?, ?base: singleton(Riffer::Tool)) ?{ () [self: singleton(Riffer::Tool)] -> void } -> singleton(Riffer::Tool)
50
20
  def stub_tool(name = nil, base: Riffer::Tool, &body)
51
21
  build_stub(name, base: base, &body) #: singleton(Riffer::Tool)
52
22
  end
53
23
 
54
- # Removes every stub built since the last reset — its registration and any
55
- # constant it created — newest first, and forgets them. A no-op when nothing
56
- # has been stubbed.
57
24
  #--
58
25
  #: () -> void
59
26
  def reset!
@@ -66,12 +33,12 @@ module Riffer::Testing
66
33
  tracked.clear
67
34
  end
68
35
 
69
- # The stub classes awaiting cleanup. Lives on the module rather than the
70
- # caller so an including test case and a direct
71
- # <tt>Riffer::Testing.stub_*</tt> call share one list.
72
36
  #--
73
37
  #: () -> Array[[Class, String?]]
74
38
  def self.registrations # :nodoc:
39
+ # Lives on the module rather than the caller so an including test case and
40
+ # a direct <tt>Riffer::Testing.stub_*</tt> call share one list. Not
41
+ # synchronized: stub from a single-threaded test.
75
42
  @registrations ||= []
76
43
  end
77
44
 
@@ -118,11 +85,11 @@ module Riffer::Testing
118
85
  const_name
119
86
  end
120
87
 
121
- # A test may have removed or replaced the constant itself, so never clobber
122
- # one that no longer points at the stub.
123
88
  #--
124
89
  #: (String, Class) -> void
125
90
  def remove_stub_const(const_name, stub)
91
+ # A test may have removed or replaced the constant itself, so never clobber
92
+ # one that no longer points at the stub.
126
93
  return unless Object.const_defined?(const_name, false) && Object.const_get(const_name, false).equal?(stub)
127
94
 
128
95
  Object.send(:remove_const, const_name)
data/lib/riffer/tool.rb CHANGED
@@ -3,64 +3,36 @@
3
3
 
4
4
  require "timeout"
5
5
 
6
- # Base class for all tools in the Riffer framework. Subclasses must implement
7
- # the +call+ method.
8
- #
9
- # class WeatherLookupTool < Riffer::Tool
10
- # description "Provides current weather information for a specified city."
11
- #
12
- # params do
13
- # required :city, String, description: "The city to look up"
14
- # optional :units, String, default: "celsius"
15
- # end
16
- #
17
- # def call(context:, city:, units: nil)
18
- # # Implementation
19
- # end
20
- # end
21
- #
22
6
  class Riffer::Tool
23
7
  extend Riffer::Tools::Toolable
24
8
  extend Riffer::Registrable
25
9
 
26
10
  kind :tool
27
11
 
28
- # Executes the tool with the given arguments.
29
12
  #--
30
13
  #: (context: Riffer::Agent::Context?, **untyped) -> Riffer::Tools::Response
31
14
  def call(context:, **kwargs)
32
15
  raise NotImplementedError, "#{self.class} must implement #call"
33
16
  end
34
17
 
35
- # Creates a text response.
36
- #
37
18
  #--
38
19
  #: (untyped) -> Riffer::Tools::Response
39
20
  def text(result)
40
21
  Riffer::Tools::Response.text(result)
41
22
  end
42
23
 
43
- # Creates a JSON response.
44
- #
45
24
  #--
46
25
  #: (untyped) -> Riffer::Tools::Response
47
26
  def json(result)
48
27
  Riffer::Tools::Response.json(result)
49
28
  end
50
29
 
51
- # Creates an error response.
52
- #
53
30
  #--
54
31
  #: (String, ?type: Symbol) -> Riffer::Tools::Response
55
32
  def error(message, type: :execution_error)
56
33
  Riffer::Tools::Response.error(message, type: type)
57
34
  end
58
35
 
59
- # Executes the tool with validation and timeout, folding every +StandardError+
60
- # into an error Response. Anything outside +StandardError+ — an unimplemented
61
- # +#call+ above all — still propagates, because a broken tool is a broken
62
- # deploy rather than a bad request.
63
- #
64
36
  #--
65
37
  #: (context: Riffer::Agent::Context?, **untyped) -> Riffer::Tools::Response
66
38
  def call_with_validation(context:, **kwargs)
@@ -88,6 +60,8 @@ class Riffer::Tool
88
60
  )
89
61
  rescue Riffer::ToolExecutionError => e
90
62
  Riffer::Tools::Response.error(e.message, type: :execution_error)
63
+ # Anything outside StandardError — an unimplemented #call above all — still
64
+ # propagates: a broken tool is a broken deploy, not a bad request.
91
65
  rescue StandardError => e
92
66
  Riffer::Tools::Response.error(
93
67
  "Error executing tool: #{e.class}: #{e.message}",
@@ -3,39 +3,20 @@
3
3
 
4
4
  require "json"
5
5
 
6
- # Represents the result of a tool execution; every tool's +call+ must return one.
7
- #
8
- # class MyTool < Riffer::Tool
9
- # def call(context:, **kwargs)
10
- # result = perform_operation
11
- # Riffer::Tools::Response.success(result)
12
- # rescue MyError => e
13
- # Riffer::Tools::Response.error(e.message)
14
- # end
15
- # end
16
- #
6
+ # Every tool's +call+ must return one.
17
7
  class Riffer::Tools::Response
18
8
  # @rbs @success: bool
19
9
 
20
10
  VALID_FORMATS = %i[text json].freeze #: Array[Symbol]
21
11
 
22
- # The response content.
23
12
  attr_reader :content #: String # @dynamic content
24
-
25
- # The error message, or +nil+ on success.
26
13
  attr_reader :error_message #: String? # @dynamic error_message
27
-
28
- # The error type, or +nil+ on success.
29
14
  attr_reader :error_type #: Symbol? # @dynamic error_type
30
15
 
31
- # The exception an unhandled failure was folded from, or +nil+. Kept out of
32
- # every serialized form so it never reaches an LLM or a message payload.
16
+ # Kept out of every serialized form so it never reaches an LLM or a message
17
+ # payload.
33
18
  attr_reader :exception #: Exception? # @dynamic exception
34
19
 
35
- # Creates a success response.
36
- #
37
- # Raises Riffer::ArgumentError if format is invalid.
38
- #
39
20
  #--
40
21
  #: (untyped, ?format: Symbol) -> Riffer::Tools::Response
41
22
  def self.success(result, format: :text)
@@ -47,42 +28,32 @@ class Riffer::Tools::Response
47
28
  new(content: content, success: true)
48
29
  end
49
30
 
50
- # Creates a success response with text format.
51
- #
52
31
  #--
53
32
  #: (untyped) -> Riffer::Tools::Response
54
33
  def self.text(result)
55
34
  success(result, format: :text)
56
35
  end
57
36
 
58
- # Creates a success response with JSON format.
59
- #
60
37
  #--
61
38
  #: (untyped) -> Riffer::Tools::Response
62
39
  def self.json(result)
63
40
  success(result, format: :json)
64
41
  end
65
42
 
66
- # Creates an error response.
67
- #
68
43
  #--
69
44
  #: (String, ?type: Symbol, ?exception: Exception?) -> Riffer::Tools::Response
70
45
  def self.error(message, type: :execution_error, exception: nil)
71
46
  new(content: message, success: false, error_message: message, error_type: type, exception: exception)
72
47
  end
73
48
 
74
- # Returns true if the tool execution succeeded.
75
49
  #--
76
50
  #: () -> bool
77
51
  def success? = @success
78
52
 
79
- # Returns true if the tool execution failed.
80
53
  #--
81
54
  #: () -> bool
82
55
  def error? = !@success
83
56
 
84
- # Returns a hash representation of the response.
85
- #
86
57
  #--
87
58
  #: () -> Hash[Symbol, untyped]
88
59
  def to_h
@@ -1,12 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  # rbs_inline: enabled
3
3
 
4
- # Executes tool calls concurrently using fibers via the +async+ gem.
5
- #
6
- # class MyAgent < Riffer::Agent
7
- # tool_runtime Riffer::Tools::Runtime::Fibers
8
- # end
9
- #
10
4
  class Riffer::Tools::Runtime::Fibers < Riffer::Tools::Runtime
11
5
  #--
12
6
  #: (?max_concurrency: Integer?) -> void
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  # rbs_inline: enabled
3
3
 
4
- # Executes tool calls sequentially in the current thread — the default runtime.
5
4
  class Riffer::Tools::Runtime::Inline < Riffer::Tools::Runtime
6
5
  #--
7
6
  #: () -> void
@@ -1,12 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  # rbs_inline: enabled
3
3
 
4
- # Executes tool calls concurrently using threads.
5
- #
6
- # class MyAgent < Riffer::Agent
7
- # tool_runtime Riffer::Tools::Runtime::Threaded
8
- # end
9
- #
10
4
  class Riffer::Tools::Runtime::Threaded < Riffer::Tools::Runtime
11
5
  DEFAULT_MAX_CONCURRENCY = 5 #: Integer
12
6