riffer 0.20.0 → 0.21.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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/.agents/providers.md +5 -176
  3. data/.release-please-manifest.json +1 -1
  4. data/AGENTS.md +1 -1
  5. data/CHANGELOG.md +8 -0
  6. data/CODE_OF_CONDUCT.md +1 -1
  7. data/README.md +13 -7
  8. data/Rakefile +2 -4
  9. data/docs/01_OVERVIEW.md +11 -6
  10. data/docs/02_GETTING_STARTED.md +5 -35
  11. data/docs/03_AGENTS.md +18 -417
  12. data/docs/04_AGENT_LIFECYCLE.md +315 -0
  13. data/docs/05_AGENT_LOOP.md +104 -0
  14. data/docs/06_TOOLS.md +278 -0
  15. data/docs/{04_TOOLS.md → 07_TOOL_ADVANCED.md} +1 -274
  16. data/docs/{05_MESSAGES.md → 08_MESSAGES.md} +35 -1
  17. data/docs/{06_STREAM_EVENTS.md → 09_STREAM_EVENTS.md} +34 -12
  18. data/docs/{07_CONFIGURATION.md → 10_CONFIGURATION.md} +2 -40
  19. data/docs/{08_EVALS.md → 11_EVALS.md} +6 -2
  20. data/docs/{09_GUARDRAILS.md → 12_GUARDRAILS.md} +36 -1
  21. data/{docs_providers → docs/providers}/01_PROVIDERS.md +1 -1
  22. data/{docs_providers → docs/providers}/02_AMAZON_BEDROCK.md +1 -1
  23. data/{docs_providers → docs/providers}/03_ANTHROPIC.md +2 -2
  24. data/{docs_providers → docs/providers}/04_OPENAI.md +3 -2
  25. data/{docs_providers → docs/providers}/05_AZURE_OPENAI.md +3 -2
  26. data/{docs_providers → docs/providers}/06_MOCK_PROVIDER.md +2 -2
  27. data/lib/riffer/agent.rb +3 -4
  28. data/lib/riffer/helpers/dependencies.rb +5 -32
  29. data/lib/riffer/messages/assistant.rb +7 -1
  30. data/lib/riffer/messages/system.rb +6 -0
  31. data/lib/riffer/messages/user.rb +6 -0
  32. data/lib/riffer/providers/amazon_bedrock.rb +13 -7
  33. data/lib/riffer/providers/anthropic.rb +1 -2
  34. data/lib/riffer/providers/base.rb +12 -0
  35. data/lib/riffer/providers/mock.rb +2 -3
  36. data/lib/riffer/providers/open_ai.rb +1 -3
  37. data/lib/riffer/runner/fibers.rb +1 -1
  38. data/lib/riffer/version.rb +1 -1
  39. data/sig/generated/riffer/helpers/dependencies.rbs +4 -12
  40. data/sig/generated/riffer/messages/assistant.rbs +6 -4
  41. data/sig/generated/riffer/messages/system.rbs +4 -0
  42. data/sig/generated/riffer/messages/user.rbs +4 -0
  43. data/sig/generated/riffer/providers/base.rbs +4 -0
  44. metadata +27 -24
  45. /data/docs/{10_SKILLS.md → 13_SKILLS.md} +0 -0
  46. /data/{docs_providers → docs/providers}/07_CUSTOM_PROVIDERS.md +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '09506e8a2dfa346e49231fa598f1e899066a5597ddd5b6738758ca49594ca7c2'
4
- data.tar.gz: 684dc3caf2f6a59d052adb51a5c33bdf0a5542a2a375f188a1bc0a600a7df5ef
3
+ metadata.gz: 8975a79d79a073d1bca29cd43216049766975f010b74dbc6ba1dbaaf22f69982
4
+ data.tar.gz: 5473e7c42541581bf7ad3c2efd046a3f3e76201e8b0c1a9a5ef324cc8175ae47
5
5
  SHA512:
6
- metadata.gz: 2b1c4119f8afac1367aac6a7d9caddd656a598dab1ad44c921802864e73815d19c3a4f96e554483d9062c9e87864bd870e8af260b9d7f5922331bdcc714ccb52
7
- data.tar.gz: 5f8387e02a6b2638550e59265980c8de6ce9422b77f905dcc019360e039d59ffb5b8d76310ba90819f7f7b51a5af34588b0de40782255c57215d4bf32ca862c8
6
+ metadata.gz: a331b45d49617ffaa73b65df988d2b018fcc214c25480880bb9b420ac3415a5abf5a4703e2e1568d3982c7bebad77a3710b8d1f04a83b0f063117e35298bc485
7
+ data.tar.gz: 3ed3b7446ce0385cf0a70a795ac7c00c27dc786a815b66bf77fe3927e4cb9bbae806342835eeb0759a5b7dcf8eb3b04df8fad249a69040e8b7a48a88da7435fe
data/.agents/providers.md CHANGED
@@ -3,7 +3,7 @@
3
3
  ## Steps
4
4
 
5
5
  1. Create `lib/riffer/providers/your_provider.rb` extending `Riffer::Providers::Base`
6
- 2. Implement the required hook methods (see below)
6
+ 2. Implement the required hook methods (see [Custom Providers](../docs/providers/07_CUSTOM_PROVIDERS.md) for the full API)
7
7
  3. Register in `Riffer::Providers::Repository::REPO`
8
8
  4. Add provider config to `Riffer::Config` if needed
9
9
  5. Create tests in `test/riffer/providers/your_provider_test.rb`
@@ -25,181 +25,6 @@ stream_text
25
25
  └─ execute_stream
26
26
  ```
27
27
 
28
- ## Required Hook Methods
29
-
30
- ```ruby
31
- # frozen_string_literal: true
32
- # rbs_inline: enabled
33
-
34
- class Riffer::Providers::YourProvider < Riffer::Providers::Base
35
- def initialize(**options)
36
- depends_on "your-sdk-gem"
37
- @client = YourSDK::Client.new(**options)
38
- end
39
-
40
- private
41
-
42
- # Convert messages, tools, and options into SDK-specific params.
43
- # If supporting web search, extract `web_search` from options and convert
44
- # it to a provider-native tool format (e.g., OpenAI's `web_search_preview`
45
- # or Anthropic's `web_search_20250305` server tool).
46
- #
47
- #: (Array[Riffer::Messages::Base], String?, Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
48
- def build_request_params(messages, model, options)
49
- # Return a hash that can be passed to both execute_generate and execute_stream
50
- end
51
-
52
- # Call the SDK and return the raw response object.
53
- #
54
- #: (Hash[Symbol, untyped]) -> untyped
55
- def execute_generate(params)
56
- @client.create(**params)
57
- end
58
-
59
- # Call the streaming SDK, mapping provider events to Riffer stream events.
60
- #
61
- #: (Hash[Symbol, untyped], Enumerator::Yielder) -> void
62
- def execute_stream(params, yielder)
63
- @client.stream(**params) do |event|
64
- # Map SDK events to Riffer::StreamEvents::* and yield them
65
- # yielder << Riffer::StreamEvents::TextDelta.new(event.text)
66
- end
67
- end
68
-
69
- # Extract token usage from the SDK response.
70
- #
71
- #: (untyped) -> Riffer::TokenUsage?
72
- def extract_token_usage(response)
73
- usage = response.usage
74
- return nil unless usage
75
-
76
- Riffer::TokenUsage.new(
77
- input_tokens: usage.input_tokens,
78
- output_tokens: usage.output_tokens
79
- )
80
- end
81
-
82
- # Extract text content from the SDK response.
83
- #
84
- #: (untyped) -> String
85
- def extract_content(response)
86
- # Return the text content from the response
87
- end
88
-
89
- # Extract tool calls from the SDK response.
90
- #
91
- #: (untyped) -> Array[Riffer::Messages::Assistant::ToolCall]
92
- def extract_tool_calls(response)
93
- # Return an array of ToolCall structs
94
- end
95
- end
96
- ```
97
-
98
- ## Structured Output
99
-
100
- When structured output is configured, the agent passes a `Riffer::StructuredOutput` instance via `options[:structured_output]`. Providers must extract it from options (and exclude it from the splat) and convert it to their SDK-specific format.
101
-
102
- ### Extracting from options
103
-
104
- All providers follow the same pattern:
105
-
106
- ```ruby
107
- def build_request_params(messages, model, options)
108
- structured_output = options[:structured_output]
109
-
110
- params = {
111
- # ...
112
- **options.except(:tools, :structured_output)
113
- }
114
-
115
- # Convert to provider-specific format (see below)
116
- end
117
- ```
118
-
119
- ### Strict schema
120
-
121
- All providers apply `strict_schema` (defined in `Providers::Base`) to schemas sent to LLMs — both structured output and tool parameters. This transformation:
122
-
123
- - Moves all properties into `required`
124
- - Makes originally-optional properties nullable (`[type, "null"]`)
125
- - Recurses into nested objects and array items
126
-
127
- This ensures all providers return proper `null` for optional fields instead of empty strings or garbage.
128
-
129
- ### Provider-specific formats
130
-
131
- **OpenAI** — uses `params[:text][:format]` with `strict: true`:
132
-
133
- ```ruby
134
- if structured_output
135
- params[:text] = {
136
- format: {
137
- type: "json_schema",
138
- name: "response",
139
- schema: strict_schema(structured_output.json_schema),
140
- strict: true
141
- }
142
- }
143
- end
144
- ```
145
-
146
- **Anthropic** — uses `params[:output_config]`:
147
-
148
- ```ruby
149
- if structured_output
150
- params[:output_config] = {
151
- format: {
152
- type: "json_schema",
153
- schema: strict_schema(structured_output.json_schema)
154
- }
155
- }
156
- end
157
- ```
158
-
159
- **Amazon Bedrock** — uses `params[:output_config][:text_format]` with stringified schema:
160
-
161
- ```ruby
162
- if structured_output
163
- params[:output_config] = {
164
- text_format: {
165
- type: "json_schema",
166
- structure: {
167
- json_schema: {
168
- schema: strict_schema(structured_output.json_schema).to_json,
169
- name: "response"
170
- }
171
- }
172
- }
173
- }
174
- end
175
- ```
176
-
177
- ### Key details
178
-
179
- - `structured_output.json_schema` returns a Hash with `type`, `properties`, `required`, and `additionalProperties` keys
180
- - All providers wrap schemas with `strict_schema` to ensure proper null handling
181
- - Bedrock requires the schema as a JSON string (`.to_json`), others use the Hash directly
182
- - The agent handles parsing and validation of the response — providers only need to pass the schema to the SDK
183
-
184
- ## File Handling
185
-
186
- User messages may include `Riffer::FilePart` objects in their `files` array. Each provider's `build_request_params` (or its message conversion helpers) must convert these to provider-specific content blocks:
187
-
188
- - **OpenAI**: `input_image` (URLs or data URIs) and `input_file` (data URIs)
189
- - **Anthropic**: `image` and `document` blocks with `url` or `base64` source
190
- - **Bedrock**: `image` and `document` blocks with `bytes` source (always base64, URLs are resolved)
191
-
192
- ## Shared Utilities
193
-
194
- The base class provides `parse_tool_arguments` for converting tool call arguments from JSON strings to hashes:
195
-
196
- ```ruby
197
- # Available in all providers via the base class
198
- parse_tool_arguments('{"key":"value"}') # => {"key" => "value"}
199
- parse_tool_arguments({"key" => "value"}) # => {"key" => "value"}
200
- parse_tool_arguments(nil) # => {}
201
- ```
202
-
203
28
  ## Registration
204
29
 
205
30
  Add to `Riffer::Providers::Repository::REPO`:
@@ -214,3 +39,7 @@ REPO = {
214
39
  ## Dependencies
215
40
 
216
41
  Use `depends_on` helper for runtime dependency checking if your provider requires external gems.
42
+
43
+ ## Reference
44
+
45
+ For hook method signatures, structured output handling, file handling, and complete examples, see [Custom Providers](../docs/providers/07_CUSTOM_PROVIDERS.md).
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "0.20.0"
2
+ ".": "0.21.0"
3
3
  }
data/AGENTS.md CHANGED
@@ -4,7 +4,7 @@ Ruby gem framework for building AI-powered agents with LLM provider adapters.
4
4
 
5
5
  ## Quick Reference
6
6
 
7
- - **Ruby**: 3.2.0+
7
+ - **Ruby**: 3.3.0+
8
8
  - **Lint + Test**: `bundle exec rake`
9
9
  - **Autoloading**: Zeitwerk (file paths must match module/class names)
10
10
  - **Model format**: `provider/model` (e.g., `openai/gpt-4`)
data/CHANGELOG.md CHANGED
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.21.0](https://github.com/janeapp/riffer/compare/riffer/v0.20.0...riffer/v0.21.0) (2026-04-09)
9
+
10
+
11
+ ### Features
12
+
13
+ * **amazon_bedrock:** support S3 URI file sources ([#190](https://github.com/janeapp/riffer/issues/190)) ([243e5b1](https://github.com/janeapp/riffer/commit/243e5b12407cac800b6cf0968a24989924932c26))
14
+ * normalize consecutive same-role messages before provider serialization ([#201](https://github.com/janeapp/riffer/issues/201)) ([1ac986d](https://github.com/janeapp/riffer/commit/1ac986dd54a3fb9859ae05d57c49176e37704195))
15
+
8
16
  ## [0.20.0](https://github.com/janeapp/riffer/compare/riffer/v0.19.0...riffer/v0.20.0) (2026-03-26)
9
17
 
10
18
 
data/CODE_OF_CONDUCT.md CHANGED
@@ -60,7 +60,7 @@ representative at an online or offline event.
60
60
 
61
61
  Instances of abusive, harassing, or otherwise unacceptable behavior may be
62
62
  reported to the community leaders responsible for enforcement at
63
- [INSERT CONTACT METHOD].
63
+ [https://github.com/janeapp/riffer/issues](https://github.com/janeapp/riffer/issues) using the `conduct` label.
64
64
  All complaints will be reviewed and investigated promptly and fairly.
65
65
 
66
66
  All community leaders are obligated to respect the privacy and security of the
data/README.md CHANGED
@@ -6,7 +6,7 @@ The all-in-one Ruby framework for building AI-powered applications and agents.
6
6
 
7
7
  ## Requirements
8
8
 
9
- - Ruby 3.2 or later
9
+ - Ruby 3.3 or later
10
10
 
11
11
  ## Installation
12
12
 
@@ -49,12 +49,18 @@ For comprehensive documentation, see the [docs](docs/) directory:
49
49
 
50
50
  - [Overview](docs/01_OVERVIEW.md) - Core concepts and architecture
51
51
  - [Getting Started](docs/02_GETTING_STARTED.md) - Installation and first steps
52
- - [Agents](docs/03_AGENTS.md) - Building AI agents
53
- - [Tools](docs/04_TOOLS.md) - Creating tools for agents
54
- - [Messages](docs/05_MESSAGES.md) - Message types and formats
55
- - [Stream Events](docs/06_STREAM_EVENTS.md) - Streaming responses
56
- - [Configuration](docs/07_CONFIGURATION.md) - Framework configuration
57
- - [Providers](docs_providers/01_PROVIDERS.md) - LLM provider adapters
52
+ - [Agents](docs/03_AGENTS.md) - Defining and configuring agents
53
+ - [Agent Lifecycle](docs/04_AGENT_LIFECYCLE.md) - Generate, stream, and responses
54
+ - [Agent Loop](docs/05_AGENT_LOOP.md) - Tool execution flow and stopping
55
+ - [Tools](docs/06_TOOLS.md) - Creating tools for agents
56
+ - [Advanced Tools](docs/07_TOOL_ADVANCED.md) - Timeouts, runtime, and registration
57
+ - [Messages](docs/08_MESSAGES.md) - Message types and formats
58
+ - [Stream Events](docs/09_STREAM_EVENTS.md) - Streaming responses
59
+ - [Configuration](docs/10_CONFIGURATION.md) - Framework configuration
60
+ - [Evals](docs/11_EVALS.md) - Evaluating agent quality
61
+ - [Guardrails](docs/12_GUARDRAILS.md) - Input/output validation
62
+ - [Skills](docs/13_SKILLS.md) - Packaged agent capabilities
63
+ - [Providers](docs/providers/01_PROVIDERS.md) - LLM provider adapters
58
64
 
59
65
  ### API Reference
60
66
 
data/Rakefile CHANGED
@@ -12,12 +12,10 @@ RDoc::Task.new do |rdoc|
12
12
  rdoc.rdoc_dir = "doc"
13
13
  rdoc.title = "Riffer Documentation"
14
14
  rdoc.main = "README.md"
15
-
16
- # Explicitly include top-level docs and the library
17
- rdoc.rdoc_files.include("README.md", "CHANGELOG.md", "LICENSE.txt", "docs/**/*.md", "docs_providers/**/*.md")
15
+ rdoc.rdoc_files.include("README.md", "CHANGELOG.md", "LICENSE.txt")
18
16
  rdoc.rdoc_files.include("lib/**/*.rb")
19
-
20
17
  rdoc.options << "--charset" << "utf-8"
18
+ rdoc.options << "--page-dir" << "docs"
21
19
  end
22
20
 
23
21
  task docs: :rdoc
data/docs/01_OVERVIEW.md CHANGED
@@ -30,12 +30,12 @@ class WeatherTool < Riffer::Tool
30
30
  end
31
31
 
32
32
  def call(context:, city:)
33
- WeatherAPI.fetch(city)
33
+ text(WeatherAPI.fetch(city))
34
34
  end
35
35
  end
36
36
  ```
37
37
 
38
- See [Tools](04_TOOLS.md) for details.
38
+ See [Tools](06_TOOLS.md) for details.
39
39
 
40
40
  ### Structured Output
41
41
 
@@ -65,7 +65,9 @@ See the [structured output section in Agents](03_AGENTS.md#structured_output) fo
65
65
  Providers are adapters that connect to LLM services. Riffer supports:
66
66
 
67
67
  - **OpenAI** - GPT models via the OpenAI API
68
+ - **Azure OpenAI** - GPT models via Azure
68
69
  - **Amazon Bedrock** - Claude and other models via AWS Bedrock
70
+ - **Anthropic** - Claude models via the Anthropic API
69
71
  - **Mock** - Mock provider for testing
70
72
 
71
73
  See [Providers](providers/01_PROVIDERS.md) for details.
@@ -79,7 +81,7 @@ Messages represent the conversation between user and assistant. Riffer uses stro
79
81
  - `Riffer::Messages::Assistant` - LLM responses
80
82
  - `Riffer::Messages::Tool` - Tool execution results
81
83
 
82
- See [Messages](05_MESSAGES.md) for details.
84
+ See [Messages](08_MESSAGES.md) for details.
83
85
 
84
86
  ### Stream Events
85
87
 
@@ -92,7 +94,7 @@ When streaming responses, Riffer emits typed events:
92
94
  - `WebSearchStatus` - Web search progress updates
93
95
  - `WebSearchDone` - Web search completion with sources
94
96
 
95
- See [Stream Events](06_STREAM_EVENTS.md) for details.
97
+ See [Stream Events](09_STREAM_EVENTS.md) for details.
96
98
 
97
99
  ## Architecture
98
100
 
@@ -127,5 +129,8 @@ Response
127
129
 
128
130
  - [Getting Started](02_GETTING_STARTED.md) - Quick start guide
129
131
  - [Agents](03_AGENTS.md) - Agent configuration and usage
130
- - [Tools](04_TOOLS.md) - Creating tools
131
- - [Configuration](07_CONFIGURATION.md) - Global configuration
132
+ - [Tools](06_TOOLS.md) - Creating tools
133
+ - [Configuration](10_CONFIGURATION.md) - Global configuration
134
+ - [Evals](11_EVALS.md) - Evaluating agent quality
135
+ - [Guardrails](12_GUARDRAILS.md) - Input/output validation
136
+ - [Skills](13_SKILLS.md) - Packaged agent capabilities
@@ -24,37 +24,7 @@ gem install riffer
24
24
 
25
25
  ## Provider Setup
26
26
 
27
- Riffer requires an LLM provider. Install the provider gem for your chosen service:
28
-
29
- ### OpenAI
30
-
31
- ```ruby
32
- gem 'openai'
33
- ```
34
-
35
- Configure your API key:
36
-
37
- ```ruby
38
- Riffer.configure do |config|
39
- config.openai.api_key = ENV['OPENAI_API_KEY']
40
- end
41
- ```
42
-
43
- ### Amazon Bedrock
44
-
45
- ```ruby
46
- gem 'aws-sdk-bedrockruntime'
47
- ```
48
-
49
- Configure your credentials:
50
-
51
- ```ruby
52
- Riffer.configure do |config|
53
- config.amazon_bedrock.region = 'us-east-1'
54
- # Optional: Use bearer token auth instead of IAM
55
- config.amazon_bedrock.api_token = ENV['BEDROCK_API_TOKEN']
56
- end
57
- ```
27
+ Riffer requires an LLM provider. See [Providers](providers/01_PROVIDERS.md) for setup instructions for each supported provider.
58
28
 
59
29
  ## Creating Your First Agent
60
30
 
@@ -104,7 +74,7 @@ class TimeTool < Riffer::Tool
104
74
  description "Gets the current time"
105
75
 
106
76
  def call(context:)
107
- Time.now.strftime('%Y-%m-%d %H:%M:%S')
77
+ text(Time.now.strftime('%Y-%m-%d %H:%M:%S'))
108
78
  end
109
79
  end
110
80
 
@@ -122,7 +92,7 @@ puts agent.generate("What time is it?")
122
92
  ## Next Steps
123
93
 
124
94
  - [Agents](03_AGENTS.md) - Agent configuration options
125
- - [Tools](04_TOOLS.md) - Creating tools with parameters
126
- - [Messages](05_MESSAGES.md) - Message types and history
127
- - [Stream Events](06_STREAM_EVENTS.md) - Streaming event types
95
+ - [Tools](06_TOOLS.md) - Creating tools with parameters
96
+ - [Messages](08_MESSAGES.md) - Message types and history
97
+ - [Stream Events](09_STREAM_EVENTS.md) - Streaming event types
128
98
  - [Providers](providers/01_PROVIDERS.md) - Provider-specific guides