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,5 @@
1
1
  # Generated from lib/riffer/providers/base.rb with RBS::Inline
2
2
 
3
- # Base class for all LLM providers. A template-method flow: subclasses implement
4
- # the hooks (+build_request_params+, +execute_generate+, +execute_stream+,
5
- # +extract_token_usage+, +extract_content+, +extract_tool_calls+) and the base
6
- # class orchestrates them.
7
3
  class Riffer::Providers::Base
8
4
  self.@semconv_provider_name: String?
9
5
 
@@ -15,51 +11,35 @@ class Riffer::Providers::Base
15
11
 
16
12
  WIRE_SEPARATOR: String
17
13
 
18
- # Returns the preferred skill adapter for this provider; override in
19
- # subclasses (optionally introspecting +model+) for provider-specific formats.
20
14
  # --
21
15
  # : (?String?) -> singleton(Riffer::Skills::Adapter)
22
16
  def self.skills_adapter: (?String?) -> singleton(Riffer::Skills::Adapter)
23
17
 
24
- # Returns the provider name stamped as <tt>gen_ai.provider.name</tt> on trace
25
- # spans, ideally a GenAI semconv well-known value. Defaults to the snake_cased
26
- # class name rather than raising like the abstract provider methods, so
27
- # enabling tracing never breaks an otherwise-working custom provider.
28
18
  # --
29
19
  # : () -> String
30
20
  def self.semconv_provider_name: () -> String
31
21
 
32
- # Generates text using the provider.
33
- #
34
22
  # --
35
- # : (?prompt: String?, ?system: String?, ?messages: Array[Hash[Symbol, untyped] | Riffer::Messages::Base]?, ?model: String?, ?files: Array[Hash[Symbol, untyped] | Riffer::Messages::FilePart]?, **untyped) -> Riffer::Messages::Assistant
36
- def generate_text: (?prompt: String?, ?system: String?, ?messages: Array[Hash[Symbol, untyped] | Riffer::Messages::Base]?, ?model: String?, ?files: Array[Hash[Symbol, untyped] | Riffer::Messages::FilePart]?, **untyped) -> Riffer::Messages::Assistant
23
+ # : (?prompt: String?, ?system: String?, ?messages: Array[Hash[Symbol, untyped] | Riffer::Messages::Base]?, ?model: String?, ?files: Array[Hash[Symbol, untyped] | Riffer::Messages::User::FilePart]?, **untyped) -> Riffer::Messages::Assistant
24
+ def generate_text: (?prompt: String?, ?system: String?, ?messages: Array[Hash[Symbol, untyped] | Riffer::Messages::Base]?, ?model: String?, ?files: Array[Hash[Symbol, untyped] | Riffer::Messages::User::FilePart]?, **untyped) -> Riffer::Messages::Assistant
37
25
 
38
- # Streams text from the provider.
39
- #
40
26
  # --
41
- # : (?prompt: String?, ?system: String?, ?messages: Array[Hash[Symbol, untyped] | Riffer::Messages::Base]?, ?model: String?, ?files: Array[Hash[Symbol, untyped] | Riffer::Messages::FilePart]?, **untyped) -> Enumerator[Riffer::StreamEvents::Base, void]
42
- def stream_text: (?prompt: String?, ?system: String?, ?messages: Array[Hash[Symbol, untyped] | Riffer::Messages::Base]?, ?model: String?, ?files: Array[Hash[Symbol, untyped] | Riffer::Messages::FilePart]?, **untyped) -> Enumerator[Riffer::StreamEvents::Base, void]
27
+ # : (?prompt: String?, ?system: String?, ?messages: Array[Hash[Symbol, untyped] | Riffer::Messages::Base]?, ?model: String?, ?files: Array[Hash[Symbol, untyped] | Riffer::Messages::User::FilePart]?, **untyped) -> Enumerator[Riffer::StreamEvents::Base, void]
28
+ def stream_text: (?prompt: String?, ?system: String?, ?messages: Array[Hash[Symbol, untyped] | Riffer::Messages::Base]?, ?model: String?, ?files: Array[Hash[Symbol, untyped] | Riffer::Messages::User::FilePart]?, **untyped) -> Enumerator[Riffer::StreamEvents::Base, void]
43
29
 
44
30
  # --
45
- # : (Riffer::Messages::FilePart) -> Symbol
46
- def file_delivery: (Riffer::Messages::FilePart) -> Symbol
31
+ # : (Riffer::Messages::User::FilePart) -> Symbol
32
+ def file_delivery: (Riffer::Messages::User::FilePart) -> Symbol
47
33
 
48
34
  private
49
35
 
50
36
  # : (String) -> true
51
37
  def depends_on: (String) -> true
52
38
 
53
- # Returns the client for the current LLM call. A configured client wins,
54
- # resolved on every call so a Proc can vary the client by process or
55
- # credential lifetime; otherwise the provider builds one from the configured
56
- # credentials, memoized for the life of the provider.
57
39
  # --
58
40
  # : () -> untyped
59
41
  def client: () -> untyped
60
42
 
61
- # Returns the consumer-configured client for this provider; nil when none is
62
- # configured, and for providers that take no configuration at all.
63
43
  # --
64
44
  # : () -> untyped
65
45
  def global_client: () -> untyped
@@ -99,12 +79,14 @@ class Riffer::Providers::Base
99
79
  # : () -> Riffer::Config::Pricing::Rates?
100
80
  def pricing_rates: () -> Riffer::Config::Pricing::Rates?
101
81
 
102
- # Defaults to nil rather than raising — finish reasons are optional, so
103
- # providers that don't report one stay valid.
104
82
  # --
105
83
  # : (untyped) -> Riffer::Providers::FinishReason?
106
84
  def extract_finish_reason: (untyped) -> Riffer::Providers::FinishReason?
107
85
 
86
+ # --
87
+ # : (untyped) -> Array[Riffer::Messages::Assistant::ReasoningPart]
88
+ def extract_reasoning: (untyped) -> Array[Riffer::Messages::Assistant::ReasoningPart]
89
+
108
90
  # --
109
91
  # : (untyped) -> String
110
92
  def extract_content: (untyped) -> String
@@ -124,8 +106,6 @@ class Riffer::Providers::Base
124
106
  # : (String?, Hash[Symbol, untyped]) -> Hash[String, untyped]
125
107
  def chat_span_attributes: (String?, Hash[Symbol, untyped]) -> Hash[String, untyped]
126
108
 
127
- # Maps normalized tags to their namespaced span attribute form. An empty map
128
- # yields an empty hash, so merging it is a no-op.
129
109
  # --
130
110
  # : (Hash[String, String]) -> Hash[String, String]
131
111
  def tag_attributes: (Hash[String, String]) -> Hash[String, String]
@@ -150,6 +130,10 @@ class Riffer::Providers::Base
150
130
  # : ((Riffer::Tracing::Otel::Span | Riffer::Tracing::NoOp::Span)) -> bool
151
131
  def capture_messages?: (Riffer::Tracing::Otel::Span | Riffer::Tracing::NoOp::Span) -> bool
152
132
 
133
+ # --
134
+ # : (Riffer::Providers::_EventSink, String) -> void
135
+ def yield_reasoning_done: (Riffer::Providers::_EventSink, String) -> void
136
+
153
137
  # --
154
138
  # : (Riffer::Providers::_EventSink, Riffer::Providers::FinishReason?) -> void
155
139
  def yield_finish_reason: (Riffer::Providers::_EventSink, Riffer::Providers::FinishReason?) -> void
@@ -159,8 +143,8 @@ class Riffer::Providers::Base
159
143
  def parse_structured_output: (String) -> Hash[Symbol, untyped]?
160
144
 
161
145
  # --
162
- # : ((String | Hash[String, untyped])?) -> Hash[String, untyped]
163
- def parse_tool_arguments: ((String | Hash[String, untyped])?) -> Hash[String, untyped]
146
+ # : (String) -> Hash[String, untyped]
147
+ def parse_tool_arguments: (String) -> Hash[String, untyped]
164
148
 
165
149
  # --
166
150
  # : (Array[Riffer::Messages::Base]) -> Array[Riffer::Messages::Base]
@@ -171,8 +155,8 @@ class Riffer::Providers::Base
171
155
  def validate_input!: (prompt: String?, system: String?, messages: Array[Hash[Symbol | String, untyped] | Riffer::Messages::Base]?) -> void
172
156
 
173
157
  # --
174
- # : (prompt: String?, system: String?, messages: Array[Hash[Symbol, untyped] | Riffer::Messages::Base]?, ?files: Array[Hash[Symbol, untyped] | Riffer::Messages::FilePart]?) -> Array[Riffer::Messages::Base]
175
- def normalize_messages: (prompt: String?, system: String?, messages: Array[Hash[Symbol, untyped] | Riffer::Messages::Base]?, ?files: Array[Hash[Symbol, untyped] | Riffer::Messages::FilePart]?) -> Array[Riffer::Messages::Base]
158
+ # : (prompt: String?, system: String?, messages: Array[Hash[Symbol, untyped] | Riffer::Messages::Base]?, ?files: Array[Hash[Symbol, untyped] | Riffer::Messages::User::FilePart]?) -> Array[Riffer::Messages::Base]
159
+ def normalize_messages: (prompt: String?, system: String?, messages: Array[Hash[Symbol, untyped] | Riffer::Messages::Base]?, ?files: Array[Hash[Symbol, untyped] | Riffer::Messages::User::FilePart]?) -> Array[Riffer::Messages::Base]
176
160
 
177
161
  # --
178
162
  # : (Array[Riffer::Messages::Base]) -> void
@@ -1,18 +1,12 @@
1
1
  # Generated from lib/riffer/providers/finish_reason.rb with RBS::Inline
2
2
 
3
- # Normalized reason an LLM call finished, paired with the provider's raw
4
- # wire value. +reason+ carries the same meaning for every provider.
5
3
  class Riffer::Providers::FinishReason
6
- # The normalized vocabulary every provider maps into.
7
4
  VALUES: Array[Symbol]
8
5
 
9
- # The normalized reason.
10
6
  attr_reader reason: Symbol
11
7
 
12
- # The provider's raw finish-reason value, when one exists on the wire.
13
8
  attr_reader raw: String?
14
9
 
15
- # Raises Riffer::ArgumentError when +reason+ is outside VALUES.
16
10
  # --
17
11
  # : (reason: Symbol, ?raw: String?) -> void
18
12
  def initialize: (reason: Symbol, ?raw: String?) -> void
@@ -1,17 +1,7 @@
1
1
  # Generated from lib/riffer/providers/gemini/client.rb with RBS::Inline
2
2
 
3
- # HTTP transport for the Gemini REST API. Riffer builds one from the
4
- # configured +api_key+ by default; construct your own to tune the HTTP knobs
5
- # and assign it to <tt>Riffer.config.gemini.client</tt>. Any object
6
- # implementing +post+ and +post_stream+ with these contracts works there —
7
- # the class is a default implementation, not a required base.
8
- #
9
- # Riffer.configure do |config|
10
- # config.gemini.client = Riffer::Providers::Gemini::Client.new(
11
- # api_key: ENV["GEMINI_API_KEY"],
12
- # read_timeout: 120
13
- # )
14
- # end
3
+ # <tt>Riffer.config.gemini.client</tt> accepts any object implementing +post+ and +post_stream+
4
+ # with these contracts; this class is the default, not a required base.
15
5
  class Riffer::Providers::Gemini::Client
16
6
  @proxy_port: Integer?
17
7
 
@@ -36,15 +26,12 @@ class Riffer::Providers::Gemini::Client
36
26
  # : (?api_key: String?, ?base_url: String, ?open_timeout: Integer, ?read_timeout: Integer, ?write_timeout: Integer?, ?proxy_address: String?, ?proxy_port: Integer?) -> void
37
27
  def initialize: (?api_key: String?, ?base_url: String, ?open_timeout: Integer, ?read_timeout: Integer, ?write_timeout: Integer?, ?proxy_address: String?, ?proxy_port: Integer?) -> void
38
28
 
39
- # POSTs a JSON body to an API path and returns the parsed response hash.
40
- # Raises Riffer::Error when the API responds with a non-success status.
29
+ # Raises Riffer::Error on a non-success status.
41
30
  # --
42
31
  # : (String, Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
43
32
  def post: (String, Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
44
33
 
45
- # POSTs a JSON body to an API path, yielding raw response body chunks as
46
- # they arrive. Raises Riffer::Error when the API responds with a
47
- # non-success status.
34
+ # Raises Riffer::Error on a non-success status.
48
35
  # --
49
36
  # : (String, Hash[Symbol, untyped]) { (String) -> void } -> void
50
37
  def post_stream: (String, Hash[Symbol, untyped]) { (String) -> void } -> void
@@ -1,19 +1,17 @@
1
1
  # Generated from lib/riffer/providers/gemini.rb with RBS::Inline
2
2
 
3
- # Google Gemini provider for Gemini models via the Gemini REST API.
4
3
  class Riffer::Providers::Gemini < Riffer::Providers::Base
5
4
  VALID_MODEL_PATTERN: Regexp
6
5
 
7
6
  FINISH_REASONS: Hash[String, Symbol]
8
7
 
9
- # The GenAI semconv well-known provider name.
10
8
  # --
11
9
  # : () -> String
12
10
  def self.semconv_provider_name: () -> String
13
11
 
14
12
  # --
15
- # : (Riffer::Messages::FilePart) -> Symbol
16
- def file_delivery: (Riffer::Messages::FilePart) -> Symbol
13
+ # : (Riffer::Messages::User::FilePart) -> Symbol
14
+ def file_delivery: (Riffer::Messages::User::FilePart) -> Symbol
17
15
 
18
16
  private
19
17
 
@@ -49,14 +47,10 @@ class Riffer::Providers::Gemini < Riffer::Providers::Base
49
47
  # : (Hash[Symbol, untyped]) -> Riffer::Providers::FinishReason?
50
48
  def extract_finish_reason: (Hash[Symbol, untyped]) -> Riffer::Providers::FinishReason?
51
49
 
52
- # Gemini reports STOP even when the candidate carries functionCall parts,
53
- # so tool-call presence overrides the raw value.
54
50
  # --
55
51
  # : (String?, tool_calls: bool) -> Riffer::Providers::FinishReason?
56
52
  def build_finish_reason: (String?, tool_calls: bool) -> Riffer::Providers::FinishReason?
57
53
 
58
- # Gemini reports thinking tokens outside +candidatesTokenCount+;
59
- # TokenUsage's output includes them.
60
54
  # --
61
55
  # : (Hash[Symbol, untyped]) -> Riffer::Providers::TokenUsage
62
56
  def build_token_usage: (Hash[Symbol, untyped]) -> Riffer::Providers::TokenUsage
@@ -74,8 +68,8 @@ class Riffer::Providers::Gemini < Riffer::Providers::Base
74
68
  def convert_assistant_to_gemini_format: (Riffer::Messages::Assistant) -> Hash[Symbol, untyped]
75
69
 
76
70
  # --
77
- # : (Riffer::Messages::FilePart) -> Hash[Symbol, untyped]
78
- def convert_file_part_to_gemini_format: (Riffer::Messages::FilePart) -> Hash[Symbol, untyped]
71
+ # : (Riffer::Messages::User::FilePart) -> Hash[Symbol, untyped]
72
+ def convert_file_part_to_gemini_format: (Riffer::Messages::User::FilePart) -> Hash[Symbol, untyped]
79
73
 
80
74
  # --
81
75
  # : (singleton(Riffer::Tool)) -> Hash[Symbol, untyped]
@@ -1,6 +1,5 @@
1
1
  # Generated from lib/riffer/providers/mock.rb with RBS::Inline
2
2
 
3
- # Mock provider for mocking LLM responses in tests; no external gems required.
4
3
  class Riffer::Providers::Mock < Riffer::Providers::Base
5
4
  @stubbed_responses: Array[Hash[Symbol, untyped]]
6
5
 
@@ -8,48 +7,24 @@ class Riffer::Providers::Mock < Riffer::Providers::Base
8
7
 
9
8
  @responses: Array[Hash[Symbol, untyped]]
10
9
 
11
- # Returns the skill adapter for the mock model — XML when the model name
12
- # contains +claude+ (mirroring a real Claude provider), else Markdown.
13
10
  # --
14
11
  # : (?String?) -> singleton(Riffer::Skills::Adapter)
15
12
  def self.skills_adapter: (?String?) -> singleton(Riffer::Skills::Adapter)
16
13
 
17
- # The GenAI semconv well-known provider name.
18
14
  # --
19
15
  # : () -> String
20
16
  def self.semconv_provider_name: () -> String
21
17
 
22
- # Array of recorded method calls for assertions.
23
18
  attr_reader calls: Array[Hash[Symbol, untyped]]
24
19
 
25
- # +responses:+ pre-configures canned responses (same shape as
26
- # +#stub_response+) for standalone use; agent tests queue responses on
27
- # <tt>agent.provider</tt> via +#stub_response+ instead.
28
- #
29
- # Riffer::Providers::Mock.new(responses: [
30
- # {content: "", tool_calls: [{name: "tool_a", arguments: "{}"}]},
31
- # {content: "Final answer"}
32
- # ])
33
- #
34
20
  # --
35
21
  # : (?responses: Array[Hash[Symbol, untyped]]) -> void
36
22
  def initialize: (?responses: Array[Hash[Symbol, untyped]]) -> void
37
23
 
38
- # Stubs the next response; call repeatedly to queue several. +finish_reason+
39
- # defaults to +:tool_calls+ when tool calls are present, else +:stop+.
40
- #
41
- # provider.stub_response("Hello")
42
- # provider.stub_response("", tool_calls: [{name: "my_tool", arguments: '{"key":"value"}'}])
43
- # provider.stub_response("Final response",
44
- # token_usage: Riffer::Providers::TokenUsage.new(input_tokens: 10, output_tokens: 5))
45
- # provider.stub_response("Truncated...", finish_reason: :length)
46
- #
47
24
  # --
48
- # : (String, ?tool_calls: Array[Hash[Symbol, untyped]], ?token_usage: Riffer::Providers::TokenUsage?, ?finish_reason: Symbol?) -> void
49
- def stub_response: (String, ?tool_calls: Array[Hash[Symbol, untyped]], ?token_usage: Riffer::Providers::TokenUsage?, ?finish_reason: Symbol?) -> void
25
+ # : (String, ?tool_calls: Array[Hash[Symbol, untyped]], ?token_usage: Riffer::Providers::TokenUsage?, ?finish_reason: Symbol?, ?reasoning: Array[Hash[Symbol, untyped] | Riffer::Messages::Assistant::ReasoningPart]) -> void
26
+ def stub_response: (String, ?tool_calls: Array[Hash[Symbol, untyped]], ?token_usage: Riffer::Providers::TokenUsage?, ?finish_reason: Symbol?, ?reasoning: Array[Hash[Symbol, untyped] | Riffer::Messages::Assistant::ReasoningPart]) -> void
50
27
 
51
- # Clears all stubbed responses.
52
- #
53
28
  # --
54
29
  # : () -> void
55
30
  def clear_stubs: () -> void
@@ -76,6 +51,10 @@ class Riffer::Providers::Mock < Riffer::Providers::Base
76
51
  # : (untyped) -> Riffer::Providers::FinishReason?
77
52
  def extract_finish_reason: (untyped) -> Riffer::Providers::FinishReason?
78
53
 
54
+ # --
55
+ # : (untyped) -> Array[Riffer::Messages::Assistant::ReasoningPart]
56
+ def extract_reasoning: (untyped) -> Array[Riffer::Messages::Assistant::ReasoningPart]
57
+
79
58
  # --
80
59
  # : (untyped) -> String
81
60
  def extract_content: (untyped) -> String
@@ -1,15 +1,12 @@
1
1
  # Generated from lib/riffer/providers/open_ai.rb with RBS::Inline
2
2
 
3
- # OpenAI provider for GPT models. Requires the +openai+ gem.
4
3
  class Riffer::Providers::OpenAI < Riffer::Providers::Base
5
4
  WEB_SEARCH_TOOL_TYPE: String
6
5
 
7
- # The Responses API has no finish_reason field. The response +status+ is
8
- # the primary signal; an +incomplete+ status is only meaningful together
9
- # with <tt>incomplete_details.reason</tt>, so that branch nests one level.
6
+ # The Responses API has no finish_reason field, and an +incomplete+ status is only meaningful
7
+ # together with <tt>incomplete_details.reason</tt>.
10
8
  FINISH_REASONS: Hash[String, Symbol | Hash[String, Symbol]]
11
9
 
12
- # The GenAI semconv well-known provider name.
13
10
  # --
14
11
  # : () -> String
15
12
  def self.semconv_provider_name: () -> String
@@ -19,8 +16,8 @@ class Riffer::Providers::OpenAI < Riffer::Providers::Base
19
16
  def initialize: () -> void
20
17
 
21
18
  # --
22
- # : (Riffer::Messages::FilePart) -> Symbol
23
- def file_delivery: (Riffer::Messages::FilePart) -> Symbol
19
+ # : (Riffer::Messages::User::FilePart) -> Symbol
20
+ def file_delivery: (Riffer::Messages::User::FilePart) -> Symbol
24
21
 
25
22
  private
26
23
 
@@ -28,9 +25,6 @@ class Riffer::Providers::OpenAI < Riffer::Providers::Base
28
25
  # : () -> untyped
29
26
  def global_client: () -> untyped
30
27
 
31
- # Compacted so an unset value stays absent: the SDK reads +OPENAI_API_KEY+ /
32
- # +OPENAI_BASE_URL+ only for a missing argument, and an explicit nil would
33
- # suppress that fallback.
34
28
  # --
35
29
  # : () -> untyped
36
30
  def build_client: () -> untyped
@@ -59,7 +53,6 @@ class Riffer::Providers::OpenAI < Riffer::Providers::Base
59
53
  # : (untyped) -> Riffer::Providers::FinishReason?
60
54
  def build_finish_reason: (untyped) -> Riffer::Providers::FinishReason?
61
55
 
62
- # The nested field that names the cause behind an ambiguous status.
63
56
  # --
64
57
  # : (untyped, String) -> String?
65
58
  def finish_detail: (untyped, String) -> String?
@@ -125,8 +118,8 @@ class Riffer::Providers::OpenAI < Riffer::Providers::Base
125
118
  def convert_assistant_to_openai_format: (Riffer::Messages::Assistant) -> (Hash[Symbol, untyped] | Array[Hash[Symbol, untyped]])
126
119
 
127
120
  # --
128
- # : (Riffer::Messages::FilePart) -> Hash[Symbol, untyped]
129
- def convert_file_part_to_openai_format: (Riffer::Messages::FilePart) -> Hash[Symbol, untyped]
121
+ # : (Riffer::Messages::User::FilePart) -> Hash[Symbol, untyped]
122
+ def convert_file_part_to_openai_format: (Riffer::Messages::User::FilePart) -> Hash[Symbol, untyped]
130
123
 
131
124
  # --
132
125
  # : (singleton(Riffer::Tool)) -> Hash[Symbol, untyped]
@@ -1,15 +1,17 @@
1
1
  # Generated from lib/riffer/providers/open_router.rb with RBS::Inline
2
2
 
3
- # OpenRouter provider (https://openrouter.ai). Requires the +openai+ gem —
4
- # OpenRouter exposes an OpenAI-compatible endpoint, so this reuses the OpenAI
5
- # SDK with a +base_url+ override. +api_key+ resolves from config, then
6
- # +OPENROUTER_API_KEY+.
7
3
  class Riffer::Providers::OpenRouter < Riffer::Providers::Base
8
4
  BASE_URL: String
9
5
 
10
6
  FINISH_REASONS: Hash[String, Symbol]
11
7
 
12
- # The GenAI semconv well-known provider name.
8
+ REASONING_TYPES: Hash[String, Symbol]
9
+
10
+ # The +reasoning_details+ formats OpenRouter documents. Only parts tagged with
11
+ # one of them are replayed, so parts from other adapters, or with no format,
12
+ # never reach the request.
13
+ REASONING_FORMATS: Array[String]
14
+
13
15
  # --
14
16
  # : () -> String
15
17
  def self.semconv_provider_name: () -> String
@@ -19,8 +21,8 @@ class Riffer::Providers::OpenRouter < Riffer::Providers::Base
19
21
  def initialize: () -> void
20
22
 
21
23
  # --
22
- # : (Riffer::Messages::FilePart) -> Symbol
23
- def file_delivery: (Riffer::Messages::FilePart) -> Symbol
24
+ # : (Riffer::Messages::User::FilePart) -> Symbol
25
+ def file_delivery: (Riffer::Messages::User::FilePart) -> Symbol
24
26
 
25
27
  private
26
28
 
@@ -28,11 +30,6 @@ class Riffer::Providers::OpenRouter < Riffer::Providers::Base
28
30
  # : () -> untyped
29
31
  def global_client: () -> untyped
30
32
 
31
- # Deliberately not compacted: this borrows the OpenAI SDK to talk to a
32
- # different vendor, so omitting an unset +api_key+ would let the SDK fall
33
- # back to +OPENAI_API_KEY+ and send an OpenAI credential to OpenRouter.
34
- # Passing nil raises in the SDK instead. +OPENROUTER_API_KEY+ is read here
35
- # rather than left to the SDK for the same reason.
36
33
  # --
37
34
  # : () -> untyped
38
35
  def build_client: () -> untyped
@@ -57,14 +54,10 @@ class Riffer::Providers::OpenRouter < Riffer::Providers::Base
57
54
  # : (untyped) -> Riffer::Providers::FinishReason?
58
55
  def extract_finish_reason: (untyped) -> Riffer::Providers::FinishReason?
59
56
 
60
- # +native+ is the upstream model's own finish reason, which OpenRouter
61
- # reports alongside its normalized one; it wins as +raw+ when present.
62
57
  # --
63
58
  # : (untyped, ?native: untyped) -> Riffer::Providers::FinishReason?
64
59
  def build_finish_reason: (untyped, ?native: untyped) -> Riffer::Providers::FinishReason?
65
60
 
66
- # +native_finish_reason+ is outside the OpenAI schema, so it is only
67
- # reachable through the SDK model's raw data hash.
68
61
  # --
69
62
  # : (untyped) -> untyped
70
63
  def native_finish_reason: (untyped) -> untyped
@@ -77,6 +70,20 @@ class Riffer::Providers::OpenRouter < Riffer::Providers::Base
77
70
  # : (untyped) -> Array[Riffer::Messages::Assistant::ToolCall]
78
71
  def extract_tool_calls: (untyped) -> Array[Riffer::Messages::Assistant::ToolCall]
79
72
 
73
+ # --
74
+ # : (untyped) -> Array[Riffer::Messages::Assistant::ReasoningPart]
75
+ def extract_reasoning: (untyped) -> Array[Riffer::Messages::Assistant::ReasoningPart]
76
+
77
+ # The openai gem's typed models strip fields outside OpenAI's spec, so
78
+ # +reasoning_details+ is only reachable through the model's raw data hash.
79
+ # --
80
+ # : (untyped) -> Array[Hash[Symbol, untyped]]?
81
+ def reasoning_details: (untyped) -> Array[Hash[Symbol, untyped]]?
82
+
83
+ # --
84
+ # : (Hash[Symbol, untyped]) -> Riffer::Messages::Assistant::ReasoningPart?
85
+ def build_reasoning_part: (Hash[Symbol, untyped]) -> Riffer::Messages::Assistant::ReasoningPart?
86
+
80
87
  # --
81
88
  # : (Hash[Symbol, untyped], Riffer::Providers::_EventSink) -> void
82
89
  def execute_stream: (Hash[Symbol, untyped], Riffer::Providers::_EventSink) -> void
@@ -93,6 +100,14 @@ class Riffer::Providers::OpenRouter < Riffer::Providers::Base
93
100
  # : (untyped, state: Hash[Symbol, untyped], yielder: Riffer::Providers::_EventSink) -> void
94
101
  def handle_reasoning_delta: (untyped, state: Hash[Symbol, untyped], yielder: Riffer::Providers::_EventSink) -> void
95
102
 
103
+ # OpenRouter streams one reasoning block as many fragments sharing an
104
+ # +index+: prose and payload arrive in pieces to concatenate, while the
105
+ # signature, id, and format arrive once, often on the last fragment. Keying
106
+ # on +type+ as well keeps index-less fragments of different kinds apart.
107
+ # --
108
+ # : (Hash[untyped, Hash[Symbol, untyped]], Hash[Symbol, untyped]) -> void
109
+ def accumulate_reasoning_detail: (Hash[untyped, Hash[Symbol, untyped]], Hash[Symbol, untyped]) -> void
110
+
96
111
  # --
97
112
  # : (untyped, state: Hash[Symbol, untyped], yielder: Riffer::Providers::_EventSink) -> void
98
113
  def handle_tool_call_deltas: (untyped, state: Hash[Symbol, untyped], yielder: Riffer::Providers::_EventSink) -> void
@@ -114,8 +129,12 @@ class Riffer::Providers::OpenRouter < Riffer::Providers::Base
114
129
  def convert_assistant_to_chat_completions_format: (Riffer::Messages::Assistant) -> Hash[Symbol, untyped]
115
130
 
116
131
  # --
117
- # : (Riffer::Messages::FilePart) -> Hash[Symbol, untyped]
118
- def convert_file_part_to_chat_completions_format: (Riffer::Messages::FilePart) -> Hash[Symbol, untyped]
132
+ # : (Riffer::Messages::Assistant::ReasoningPart) -> Hash[Symbol, untyped]
133
+ def convert_reasoning_part_to_detail: (Riffer::Messages::Assistant::ReasoningPart) -> Hash[Symbol, untyped]
134
+
135
+ # --
136
+ # : (Riffer::Messages::User::FilePart) -> Hash[Symbol, untyped]
137
+ def convert_file_part_to_chat_completions_format: (Riffer::Messages::User::FilePart) -> Hash[Symbol, untyped]
119
138
 
120
139
  # --
121
140
  # : (singleton(Riffer::Tool)) -> Hash[Symbol, untyped]
@@ -1,8 +1,5 @@
1
1
  # Generated from lib/riffer/providers/repository.rb with RBS::Inline
2
2
 
3
- # Resolves provider classes by identifier, combining the built-in REPO with
4
- # consumer registrations added through +register+. Registration is not
5
- # synchronized — register during boot, before concurrent generation begins.
6
3
  module Riffer::Providers::Repository
7
4
  @registrations: Hash[Symbol, ^() -> singleton(Riffer::Providers::Base)]
8
5
 
@@ -10,29 +7,20 @@ module Riffer::Providers::Repository
10
7
 
11
8
  REPO: Hash[Symbol, ^() -> singleton(Riffer::Providers::Base)]
12
9
 
13
- # Registers a custom provider under +identifier+, resolved lazily by the block.
14
- # Takes precedence over a built-in sharing the identifier.
15
- #
16
- # Riffer::Providers::Repository.register(:jane) { MyApp::JaneProvider }
17
- #
10
+ # Not synchronized — register during boot, before concurrent generation
11
+ # begins.
18
12
  # --
19
13
  # : ((String | Symbol)) { () -> singleton(Riffer::Providers::Base) } -> void
20
14
  def register: (String | Symbol) { () -> singleton(Riffer::Providers::Base) } -> void
21
15
 
22
- # Removes a custom registration by identifier, leaving any built-in of the
23
- # same name intact.
24
16
  # --
25
17
  # : ((String | Symbol)) -> void
26
18
  def unregister: (String | Symbol) -> void
27
19
 
28
- # Finds a provider class by identifier, preferring a custom registration over
29
- # a built-in of the same name.
30
- #
31
20
  # --
32
21
  # : ((String | Symbol)) -> singleton(Riffer::Providers::Base)?
33
22
  def find: (String | Symbol) -> singleton(Riffer::Providers::Base)?
34
23
 
35
- # Returns the registry identifier for a provider class, or nil when unregistered.
36
24
  # --
37
25
  # : (singleton(Riffer::Providers::Base)) -> Symbol?
38
26
  def key_for: (singleton(Riffer::Providers::Base)) -> Symbol?
@@ -1,40 +1,37 @@
1
1
  # Generated from lib/riffer/providers/token_usage.rb with RBS::Inline
2
2
 
3
- # Normalized token usage for an LLM API call. Buckets carry the same
4
- # meaning for every provider.
5
3
  class Riffer::Providers::TokenUsage
6
- # Number of tokens entering the context window, including cache reads and writes.
4
+ # --
5
+ # : ((Hash[Symbol, untyped] | Riffer::Providers::TokenUsage)) -> Riffer::Providers::TokenUsage
6
+ def self.from_hash: (Hash[Symbol, untyped] | Riffer::Providers::TokenUsage) -> Riffer::Providers::TokenUsage
7
+
8
+ # Normalized across providers: includes cache reads and writes.
7
9
  attr_reader input_tokens: Integer
8
10
 
9
- # Number of tokens generated by the model, including reasoning/thinking tokens.
11
+ # Includes reasoning/thinking tokens.
10
12
  attr_reader output_tokens: Integer
11
13
 
12
- # Subset of +input_tokens+ written to the provider's prompt cache, when the provider reports it.
14
+ # Subset of +input_tokens+.
13
15
  attr_reader cache_write_tokens: Integer?
14
16
 
15
- # Subset of +input_tokens+ read from the provider's prompt cache, when the provider reports it.
17
+ # Subset of +input_tokens+.
16
18
  attr_reader cache_read_tokens: Integer?
17
19
 
18
- # Cost of the call, set when the model is priced. For observability, not billing.
20
+ # For observability, not billing.
19
21
  attr_reader cost: Float?
20
22
 
21
23
  # --
22
24
  # : (input_tokens: Integer, output_tokens: Integer, ?cache_write_tokens: Integer?, ?cache_read_tokens: Integer?, ?cost: Float?) -> void
23
25
  def initialize: (input_tokens: Integer, output_tokens: Integer, ?cache_write_tokens: Integer?, ?cache_read_tokens: Integer?, ?cost: Float?) -> void
24
26
 
25
- # Returns the total number of tokens (input + output).
26
- #
27
27
  # --
28
28
  # : () -> Integer
29
29
  def total_tokens: () -> Integer
30
30
 
31
- # Combines two TokenUsage objects for cumulative tracking.
32
- #
33
31
  # --
34
32
  # : (Riffer::Providers::TokenUsage) -> Riffer::Providers::TokenUsage
35
33
  def +: (Riffer::Providers::TokenUsage) -> Riffer::Providers::TokenUsage
36
34
 
37
- # Converts the token usage to a hash; cache tokens and cost are omitted when nil.
38
35
  # --
39
36
  # : () -> Hash[Symbol, (Integer | Float)]
40
37
  def to_h: () -> Hash[Symbol, Integer | Float]
@@ -1,68 +1,29 @@
1
1
  # Generated from lib/riffer/registrable.rb with RBS::Inline
2
2
 
3
- # Registry of a class's direct subclasses, keyed by identifier. Extend it
4
- # onto a base class to look up subclasses in constant time via +find+ and +all+.
5
- # Subclasses join implicitly by inheriting; +register+ adds one explicitly, for
6
- # ephemeral classes a test suite builds and tears down. Registration is not
7
- # synchronized — register during boot or from a single-threaded test, before
8
- # concurrent lookups begin.
9
- #
10
- # class Riffer::Tool
11
- # extend Riffer::Registrable
12
- # end
13
- #
14
- # Riffer::Tool.find("weather_tool") # => WeatherTool
15
- #
16
3
  # @rbs module-self Class
17
4
  module Riffer::Registrable : Class
18
5
  @identifier_registry: Hash[String, Class]?
19
6
 
20
7
  @explicit_registrations: Hash[String, Class]?
21
8
 
22
- # Finds a registered subclass by identifier, or +nil+ when none matches.
23
- # Implicit registration covers only *named direct* subclasses: grandchildren
24
- # are not visible to a grandparent's +find+ (call +find+ on their direct
25
- # parent instead), anonymous classes are never registered implicitly, and a
26
- # subclass whose name no longer resolves back to it is dropped at the next
27
- # registry rebuild. Duplicate identifiers raise
28
- # Riffer::DuplicateIdentifierError at first lookup.
29
- #
30
9
  # --
31
10
  # : (String | Symbol) -> Class?
32
11
  def find: (String | Symbol) -> Class?
33
12
 
34
- # Returns all registered subclasses, implicit and explicit. Carries the same
35
- # registration rules as +find+.
36
- #
37
13
  # --
38
14
  # : () -> Array[Class]
39
15
  def all: () -> Array[Class]
40
16
 
41
- # Registers a direct subclass under its +identifier+, whether or not it is
42
- # named — unlike implicit registration, it survives a name that no longer
43
- # resolves, so an ephemeral class stays findable until +unregister+. Prefer
44
- # Riffer::Testing for ordinary test setup, which stubs and cleans up
45
- # automatically.
46
- #
47
- # Raises Riffer::ArgumentError when the identifier is blank or the class is
48
- # not a direct subclass, and Riffer::DuplicateIdentifierError when the
49
- # identifier is already taken — including by this same class.
50
- #
51
17
  # --
52
18
  # : (Class) -> void
53
19
  def register: (Class) -> void
54
20
 
55
- # Removes an explicit registration of +klass+, leaving implicit registrations
56
- # untouched.
57
21
  # --
58
22
  # : (Class) -> void
59
23
  def unregister: (Class) -> void
60
24
 
61
25
  private
62
26
 
63
- # Ruby invokes +inherited+ with +self+ bound to the direct superclass — the
64
- # only registry the new subclass joins — so busting self's memo is exactly
65
- # sufficient.
66
27
  # --
67
28
  # : (Class) -> void
68
29
  def inherited: (Class) -> void
@@ -79,12 +40,6 @@ module Riffer::Registrable : Class
79
40
  # : () -> Hash[String, Class]
80
41
  def build_identifier_registry: () -> Hash[String, Class]
81
42
 
82
- # Class#subclasses keeps returning superseded generations of a reloaded or
83
- # stubbed class, so a subclass counts only while its own name still resolves
84
- # back to it. An anonymous class has no name to resolve and is skipped even
85
- # with an explicit identifier — the MCP factory and serializer shells
86
- # synthesize short-lived anonymous classes whose registration would flake
87
- # with GC timing.
88
43
  # --
89
44
  # : (Class) -> bool
90
45
  def live?: (Class) -> bool
@@ -1,11 +1,5 @@
1
1
  # Generated from lib/riffer/runner/fibers.rb with RBS::Inline
2
2
 
3
- # Processes items concurrently using fibers via the +async+ gem.
4
- # +max_concurrency+ caps simultaneous fibers via an <tt>Async::Semaphore</tt>.
5
- # If multiple fibers raise, only the first exception is re-raised after all
6
- # finish.
7
- # Joins the current reactor task when one is already running, and otherwise
8
- # starts its own.
9
3
  class Riffer::Runner::Fibers < Riffer::Runner
10
4
  @max_concurrency: Integer?
11
5
 
@@ -1,6 +1,5 @@
1
1
  # Generated from lib/riffer/runner/sequential.rb with RBS::Inline
2
2
 
3
- # Processes items sequentially in the current thread — the default runner.
4
3
  class Riffer::Runner::Sequential < Riffer::Runner
5
4
  # --
6
5
  # : (Array[untyped], context: Riffer::Agent::Context?) { (untyped) -> untyped } -> Array[untyped]