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.
- checksums.yaml +4 -4
- data/{AGENTS.md → .claude/CLAUDE.md} +0 -8
- data/.claude/rules/comments.md +13 -0
- data/.claude/rules/rbs-inline.md +93 -0
- data/.release-please-manifest.json +1 -1
- data/CHANGELOG.md +22 -0
- data/README.md +20 -24
- data/docs/AGENTS.md +24 -14
- data/docs/AGENT_LIFECYCLE.md +2 -2
- data/docs/CONFIGURATION.md +105 -21
- data/docs/SERIALIZATION.md +4 -3
- data/docs/TOOLS.md +18 -1
- data/docs/providers/AMAZON_BEDROCK.md +14 -8
- data/docs/providers/ANTHROPIC.md +9 -7
- data/docs/providers/AZURE_OPENAI.md +12 -12
- data/docs/providers/CUSTOM_PROVIDERS.md +32 -16
- data/docs/providers/GEMINI.md +28 -5
- data/docs/providers/OPENAI.md +21 -5
- data/docs/providers/OPENROUTER.md +11 -6
- data/docs/providers/PROVIDERS.md +16 -1
- data/lib/riffer/agent/config.rb +0 -6
- data/lib/riffer/agent/run.rb +2 -4
- data/lib/riffer/agent/serializer.rb +0 -2
- data/lib/riffer/agent.rb +4 -26
- data/lib/riffer/config.rb +6 -6
- data/lib/riffer/evals/judge.rb +3 -5
- data/lib/riffer/guardrail.rb +1 -1
- data/lib/riffer/helpers/identifier.rb +41 -0
- data/lib/riffer/providers/amazon_bedrock.rb +31 -19
- data/lib/riffer/providers/anthropic.rb +23 -8
- data/lib/riffer/providers/azure_open_ai.rb +19 -11
- data/lib/riffer/providers/base.rb +32 -1
- data/lib/riffer/providers/gemini/client.rb +120 -0
- data/lib/riffer/providers/gemini.rb +13 -62
- data/lib/riffer/providers/mock.rb +5 -4
- data/lib/riffer/providers/open_ai.rb +23 -8
- data/lib/riffer/providers/open_router.rb +23 -9
- data/lib/riffer/registrable.rb +81 -0
- data/lib/riffer/tool.rb +1 -0
- data/lib/riffer/tools/toolable.rb +2 -3
- data/lib/riffer/version.rb +1 -1
- data/lib/riffer.rb +3 -0
- data/sig/_private/riffer/providers/amazon_bedrock.rbs +4 -2
- data/sig/_private/riffer/providers/anthropic.rbs +4 -2
- data/sig/_private/riffer/providers/gemini.rbs +7 -0
- data/sig/_private/riffer/providers/open_ai.rbs +4 -2
- data/sig/_private/riffer/providers/open_router.rbs +4 -2
- data/sig/generated/riffer/agent/config.rbs +1 -5
- data/sig/generated/riffer/agent.rbs +2 -18
- data/sig/generated/riffer/config.rbs +25 -15
- data/sig/generated/riffer/evals/judge.rbs +2 -4
- data/sig/generated/riffer/helpers/identifier.rbs +19 -0
- data/sig/generated/riffer/providers/amazon_bedrock.rbs +13 -2
- data/sig/generated/riffer/providers/anthropic.rbs +13 -2
- data/sig/generated/riffer/providers/azure_open_ai.rbs +14 -4
- data/sig/generated/riffer/providers/base.rbs +22 -0
- data/sig/generated/riffer/providers/gemini/client.rbs +65 -0
- data/sig/generated/riffer/providers/gemini.rbs +7 -23
- data/sig/generated/riffer/providers/mock.rbs +4 -3
- data/sig/generated/riffer/providers/open_ai.rbs +13 -2
- data/sig/generated/riffer/providers/open_router.rbs +16 -3
- data/sig/generated/riffer/registrable.rbs +51 -0
- data/sig/generated/riffer/tool.rbs +2 -0
- data/sig/generated/riffer/tools/toolable.rbs +3 -1
- data/sig/generated/riffer.rbs +4 -0
- data/sig/manual/riffer/agent.rbs +7 -0
- data/sig/manual/riffer/helpers/identifier.rbs +5 -0
- data/sig/manual/riffer/tool.rbs +7 -0
- metadata +14 -11
- data/.agents/architecture.md +0 -265
- data/.agents/code-style.md +0 -110
- data/.agents/providers.md +0 -45
- data/.agents/rbs-inline.md +0 -169
- data/.agents/testing.md +0 -60
- data/CLAUDE.md +0 -1
- data/lib/riffer/helpers/class_name_converter.rb +0 -22
- data/sig/generated/riffer/helpers/class_name_converter.rbs +0 -12
- data/sig/manual/riffer/helpers/class_name_converter.rbs +0 -5
data/.agents/rbs-inline.md
DELETED
|
@@ -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
|