riffer 0.40.0 → 0.42.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 (78) hide show
  1. checksums.yaml +4 -4
  2. data/{AGENTS.md → .claude/CLAUDE.md} +0 -8
  3. data/.claude/rules/comments.md +13 -0
  4. data/.claude/rules/rbs-inline.md +93 -0
  5. data/.release-please-manifest.json +1 -1
  6. data/CHANGELOG.md +22 -0
  7. data/README.md +20 -24
  8. data/docs/AGENTS.md +24 -14
  9. data/docs/AGENT_LIFECYCLE.md +2 -2
  10. data/docs/CONFIGURATION.md +105 -21
  11. data/docs/SERIALIZATION.md +4 -3
  12. data/docs/TOOLS.md +18 -1
  13. data/docs/providers/AMAZON_BEDROCK.md +14 -8
  14. data/docs/providers/ANTHROPIC.md +9 -7
  15. data/docs/providers/AZURE_OPENAI.md +12 -12
  16. data/docs/providers/CUSTOM_PROVIDERS.md +32 -16
  17. data/docs/providers/GEMINI.md +28 -5
  18. data/docs/providers/OPENAI.md +21 -5
  19. data/docs/providers/OPENROUTER.md +11 -6
  20. data/docs/providers/PROVIDERS.md +16 -1
  21. data/lib/riffer/agent/config.rb +0 -6
  22. data/lib/riffer/agent/run.rb +2 -4
  23. data/lib/riffer/agent/serializer.rb +0 -2
  24. data/lib/riffer/agent.rb +4 -26
  25. data/lib/riffer/config.rb +6 -6
  26. data/lib/riffer/evals/judge.rb +3 -5
  27. data/lib/riffer/guardrail.rb +1 -1
  28. data/lib/riffer/helpers/identifier.rb +41 -0
  29. data/lib/riffer/providers/amazon_bedrock.rb +31 -19
  30. data/lib/riffer/providers/anthropic.rb +23 -8
  31. data/lib/riffer/providers/azure_open_ai.rb +19 -11
  32. data/lib/riffer/providers/base.rb +32 -1
  33. data/lib/riffer/providers/gemini/client.rb +120 -0
  34. data/lib/riffer/providers/gemini.rb +13 -62
  35. data/lib/riffer/providers/mock.rb +5 -4
  36. data/lib/riffer/providers/open_ai.rb +23 -8
  37. data/lib/riffer/providers/open_router.rb +23 -9
  38. data/lib/riffer/registrable.rb +81 -0
  39. data/lib/riffer/tool.rb +1 -0
  40. data/lib/riffer/tools/toolable.rb +2 -3
  41. data/lib/riffer/version.rb +1 -1
  42. data/lib/riffer.rb +3 -0
  43. data/sig/_private/riffer/providers/amazon_bedrock.rbs +4 -2
  44. data/sig/_private/riffer/providers/anthropic.rbs +4 -2
  45. data/sig/_private/riffer/providers/gemini.rbs +7 -0
  46. data/sig/_private/riffer/providers/open_ai.rbs +4 -2
  47. data/sig/_private/riffer/providers/open_router.rbs +4 -2
  48. data/sig/generated/riffer/agent/config.rbs +1 -5
  49. data/sig/generated/riffer/agent.rbs +2 -18
  50. data/sig/generated/riffer/config.rbs +25 -15
  51. data/sig/generated/riffer/evals/judge.rbs +2 -4
  52. data/sig/generated/riffer/helpers/identifier.rbs +19 -0
  53. data/sig/generated/riffer/providers/amazon_bedrock.rbs +13 -2
  54. data/sig/generated/riffer/providers/anthropic.rbs +13 -2
  55. data/sig/generated/riffer/providers/azure_open_ai.rbs +14 -4
  56. data/sig/generated/riffer/providers/base.rbs +22 -0
  57. data/sig/generated/riffer/providers/gemini/client.rbs +65 -0
  58. data/sig/generated/riffer/providers/gemini.rbs +7 -23
  59. data/sig/generated/riffer/providers/mock.rbs +4 -3
  60. data/sig/generated/riffer/providers/open_ai.rbs +13 -2
  61. data/sig/generated/riffer/providers/open_router.rbs +16 -3
  62. data/sig/generated/riffer/registrable.rbs +51 -0
  63. data/sig/generated/riffer/tool.rbs +2 -0
  64. data/sig/generated/riffer/tools/toolable.rbs +3 -1
  65. data/sig/generated/riffer.rbs +4 -0
  66. data/sig/manual/riffer/agent.rbs +7 -0
  67. data/sig/manual/riffer/helpers/identifier.rbs +5 -0
  68. data/sig/manual/riffer/tool.rbs +7 -0
  69. metadata +14 -11
  70. data/.agents/architecture.md +0 -265
  71. data/.agents/code-style.md +0 -110
  72. data/.agents/providers.md +0 -45
  73. data/.agents/rbs-inline.md +0 -169
  74. data/.agents/testing.md +0 -60
  75. data/CLAUDE.md +0 -1
  76. data/lib/riffer/helpers/class_name_converter.rb +0 -22
  77. data/sig/generated/riffer/helpers/class_name_converter.rbs +0 -12
  78. data/sig/manual/riffer/helpers/class_name_converter.rbs +0 -5
@@ -1,169 +0,0 @@
1
- # RBS Inline
2
-
3
- Type annotations are added directly in Ruby source files using [rbs-inline](https://github.com/soutaro/rbs-inline).
4
-
5
- ## Magic Comment
6
-
7
- rbs-inline only processes a file when `rbs_inline: enabled` is present on line 2. It ships as part of the required header on every `lib/**/*.rb` file — see [Required Header](code-style.md#required-header).
8
-
9
- ## Annotation Syntax
10
-
11
- The **`#:`** prefix is used — standalone lines above methods (type signatures) or inline on the same line (attributes, constants).
12
-
13
- ### Method Parameters and Return Types
14
-
15
- Use a single `#:` line above the method with the RBS method signature:
16
-
17
- ```ruby
18
- #: (String, Integer) -> bool
19
- def valid?(name, age)
20
- ```
21
-
22
- #### Parameter Mapping
23
-
24
- | Ruby param | RBS signature |
25
- | ---------------------------- | ------------------------ |
26
- | `def foo(x)` | `(Type)` |
27
- | `def foo(x = nil)` | `(?Type?)` |
28
- | `def foo(x = val)` | `(?Type)` |
29
- | `def foo(x:)` | `(x: Type)` |
30
- | `def foo(x: nil)` | `(?x: Type?)` |
31
- | `def foo(x: val)` | `(?x: Type)` |
32
- | `def foo(*args)` | `(*untyped)` |
33
- | `def foo(**kwargs)` | `(**untyped)` |
34
- | `def foo(&block)` (required) | `() { (Type) -> void }` |
35
- | `def foo(&block)` (optional) | `() ?{ (Type) -> void }` |
36
- | `def foo(...)` | `(*untyped, **untyped)` |
37
-
38
- #### Examples
39
-
40
- ```ruby
41
- # No parameters
42
- #: () -> String
43
- def name
44
-
45
- # Positional parameters
46
- #: (String, Integer) -> bool
47
- def valid?(name, age)
48
-
49
- # Optional positional parameter
50
- #: (?String?) -> String
51
- def self.identifier(value = nil)
52
-
53
- # Required keyword parameters
54
- #: (input: String, output: String) -> Riffer::Evals::Result
55
- def evaluate(input:, output:)
56
-
57
- # Mixed keyword parameters (required + optional)
58
- #: (input: String, output: String, ?context: Hash[Symbol, untyped]?) -> Riffer::Evals::Result
59
- def evaluate(input:, output:, context: nil)
60
-
61
- # Positional + keyword parameters
62
- #: (String, ?context: Hash[Symbol, untyped]?) -> String
63
- def generate(prompt, context: nil)
64
-
65
- # Splat/double-splat
66
- #: (**untyped) -> void
67
- def initialize(**options)
68
-
69
- # Forward arguments
70
- #: (*untyped, **untyped) -> String
71
- def self.generate(...)
72
-
73
- # Block parameter (required)
74
- #: () { (Riffer::Messages::Base) -> void } -> self
75
- def on_message(&block)
76
-
77
- # Block parameter (optional)
78
- #: () ?{ (Riffer::Config) -> void } -> void
79
- def configure(&block)
80
- ```
81
-
82
- ### Attributes
83
-
84
- ```ruby
85
- attr_reader :name #: String
86
- attr_reader :items #: Array[String]
87
- ```
88
-
89
- ### Constants
90
-
91
- ```ruby
92
- VERSION = "1.0.0" #: String
93
- DEFAULTS = {}.freeze #: Hash[Symbol, untyped]
94
- ```
95
-
96
- ### Instance variables
97
-
98
- The `#:` shorthand on an assignment is a Steep _assertion_ — it types the expression but does
99
- **not declare the ivar**. To declare an ivar's type, use a `# @rbs` comment inside the class
100
- body. `# @rbs` is used **only** for ivar declarations in this codebase; everything else uses
101
- `#:`.
102
-
103
- ```ruby
104
- class Riffer::Agent::Session
105
- # @rbs @callbacks: Array[^(Riffer::Messages::Base) -> void] # instance ivar
106
- end
107
-
108
- module Riffer
109
- # @rbs self.@config: Riffer::Config? # class/module-level ivar
110
- end
111
- ```
112
-
113
- ## Common Type Patterns
114
-
115
- | Pattern | Meaning |
116
- | ------------------------- | --------------------------- |
117
- | `String?` | Optional (String or nil) |
118
- | `(String \| Integer)` | Union type |
119
- | `Array[String]` | Typed array |
120
- | `Hash[Symbol, untyped]` | Typed hash |
121
- | `^(String) -> void` | Block/proc type |
122
- | `singleton(Riffer::Tool)` | Class object (not instance) |
123
- | `bool` | Boolean (true or false) |
124
- | `untyped` | Any type |
125
- | `void` | No meaningful return |
126
-
127
- ## Optional-dependency types (consumer-safe signatures)
128
-
129
- `sig/generated/` ships with the gem and is loaded by downstream projects (`rbs collection` / `rbs -r riffer`). rbs-inline copies a method's `#:` signature **verbatim** into the shipped sig, so **never name an optional-dependency type in a `#:` signature** — `OpenAI::*`, `Anthropic::*`, `Aws::*`, `MCP::*`, `Async::*`, `Zeitwerk::*`, etc. A consumer who installs riffer without that gem would hit `Cannot find type`, because those providers are pluggable and the gems ship no usable RBS of their own.
130
-
131
- **Workaround — assert the type inside the method body instead.** An inline assertion (`local = arg #: OpenAI::Models::…`) is a Steep-only hint that rbs-inline does **not** emit into the signature. Leave the SDK param/return `untyped` in the `#:` line, keep every riffer/stdlib param and return typed, and recover the SDK type with a body assertion:
132
-
133
- ```ruby
134
- #: (untyped) -> String
135
- def extract_content(response)
136
- message = response #: Anthropic::Models::Message
137
- message.content&.first&.text || "" # fully type-checked against the SDK type
138
- end
139
-
140
- #: (untyped, state: Hash[Symbol, untyped], yielder: Enumerator::Yielder) -> void
141
- def handle_stream_chunk(chunk, state:, yielder:)
142
- typed = chunk #: OpenAI::Models::Chat::ChatCompletionChunk
143
- # ...
144
- end
145
-
146
- # When the return value IS the SDK object, type the return `untyped` (no body assertion needed):
147
- #: (Hash[Symbol, untyped]) -> untyped
148
- def execute_generate(params)
149
- @client.messages.create(**params)
150
- end
151
- ```
152
-
153
- `test/shipped_signatures_test.rb` enforces this — it fails if any optional-dependency type appears in `sig/generated/` or `sig/manual/`.
154
-
155
- ### Where stubs and stdlib deps live
156
-
157
- - `sig/_private/` — signatures that must **not** ship. RBS **skips** `_`-prefixed directories in library mode, so consumers never load them; riffer's own `steep check` does (via the `Steepfile`). Two kinds, by predictable path: external-gem signatures are named by gem at the top level (`async.rbs`, `mcp.rbs`, `zeitwerk.rbs`, `openai.rbs`, `anthropic.rbs`, `aws-sdk-core/*` — full stubs for RBS-less gems plus arity patches for the provider SDKs); riffer's own hidden stubs mirror `lib/` under `riffer/` (e.g. `riffer/providers/anthropic.rbs` declares the SDK-typed `@client` ivar).
158
- - `sig/manual/` — hand-written riffer-only signatures that are **safe to ship**, for the few things rbs-inline can't generate _at all_ (mirroring `lib/`). In practice that's `extend self` modules (`riffer/agent/run.rbs`, `riffer/helpers/call_or_value.rbs`) and modeling an include applied dynamically (`riffer/tools/toolable.rbs`). SDK-free ivars are **not** hand-written here — declare them inline with `# @rbs` (see "Instance variables"). SDK-typed ivars can't ship, so they go in `_private/riffer/providers/` (`@client`).
159
- - `sig/manifest.yaml` — declares the **stdlib** RBS the shipped sigs reference (`uri`, `net-http`) so `rbs -r riffer` resolves them.
160
-
161
- ## Workflow
162
-
163
- After changing type annotations:
164
-
165
- 1. Run `bin/rbs` to regenerate `sig/generated/` files
166
- 2. Commit both the source changes and the generated `.rbs` files
167
- 3. CI checks for drift between source annotations and committed `.rbs` files
168
-
169
- Use `bin/rbs-watch` during development to auto-regenerate on file changes.
data/.agents/testing.md DELETED
@@ -1,60 +0,0 @@
1
- # Testing
2
-
3
- ## Framework
4
-
5
- Use Minitest with the spec DSL for all tests.
6
-
7
- ## Test Structure
8
-
9
- ```ruby
10
- # frozen_string_literal: true
11
-
12
- require "test_helper"
13
-
14
- describe Riffer::Feature do
15
- describe "#method_name" do
16
- before do
17
- # setup code
18
- end
19
-
20
- it "does something expected" do
21
- result = Riffer::Feature.method_name(args)
22
- assert_equal expected, result
23
- end
24
-
25
- it "handles edge case" do
26
- result = Riffer::Feature.method_name(edge_case_args)
27
- assert_equal edge_case_expected, result
28
- end
29
- end
30
- end
31
- ```
32
-
33
- ## Guidelines
34
-
35
- - Test files go in `test/` directory with `*_test.rb` suffix
36
- - Use `before`/`after` blocks for setup and cleanup
37
- - Stick to the single assertion rule where possible
38
- - Test edge cases and error conditions
39
- - Use Minitest assertions: `assert_equal`, `assert_instance_of`, `refute_nil`, etc.
40
-
41
- ## VCR Cassettes
42
-
43
- Record external API interactions in `test/fixtures/vcr_cassettes/`.
44
-
45
- ## Running Tests
46
-
47
- ```bash
48
- # Run all tests
49
- bin/test
50
-
51
- # Run a single test file (or multiple files)
52
- bin/test test/riffer/agent_test.rb
53
- bin/test test/riffer/agent_test.rb test/riffer/config_test.rb
54
-
55
- # Filter by test name (regex or substring)
56
- bin/test test/riffer/agent_test.rb --name /generates/
57
-
58
- # Filter across the whole suite
59
- bin/test --name /generates/
60
- ```
data/CLAUDE.md DELETED
@@ -1 +0,0 @@
1
- AGENTS.md
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
- # rbs_inline: enabled
3
-
4
- # Helper module for converting class names.
5
- module Riffer::Helpers::ClassNameConverter
6
- extend self
7
-
8
- DEFAULT_SEPARATOR = "/" #: String
9
-
10
- # Converts a class name to snake_case identifier format.
11
- #
12
- #--
13
- #: (String, ?separator: String) -> String
14
- def convert(class_name, separator: DEFAULT_SEPARATOR)
15
- class_name.
16
- to_s.
17
- gsub("::", separator).
18
- gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').
19
- gsub(/([a-z\d])([A-Z])/, '\1_\2').
20
- downcase
21
- end
22
- end
@@ -1,12 +0,0 @@
1
- # Generated from lib/riffer/helpers/class_name_converter.rb with RBS::Inline
2
-
3
- # Helper module for converting class names.
4
- module Riffer::Helpers::ClassNameConverter
5
- DEFAULT_SEPARATOR: String
6
-
7
- # Converts a class name to snake_case identifier format.
8
- #
9
- # --
10
- # : (String, ?separator: String) -> String
11
- def convert: (String, ?separator: String) -> String
12
- end
@@ -1,5 +0,0 @@
1
- # `Riffer::Helpers::ClassNameConverter` uses `extend self`; rbs-inline doesn't
2
- # emit that, so re-extend here to expose its instance methods as singleton methods.
3
- module Riffer::Helpers::ClassNameConverter
4
- extend ::Riffer::Helpers::ClassNameConverter
5
- end