riffer 0.13.0 → 0.14.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/architecture.md +43 -8
- data/.agents/providers.md +166 -14
- data/.release-please-manifest.json +1 -1
- data/CHANGELOG.md +22 -0
- data/docs/01_OVERVIEW.md +22 -1
- data/docs/03_AGENTS.md +280 -5
- data/docs/05_MESSAGES.md +62 -0
- data/docs/06_STREAM_EVENTS.md +89 -0
- data/docs/07_CONFIGURATION.md +9 -7
- data/docs/08_EVALS.md +116 -156
- data/docs/09_GUARDRAILS.md +3 -22
- data/docs_providers/01_PROVIDERS.md +13 -13
- data/docs_providers/02_AMAZON_BEDROCK.md +15 -22
- data/docs_providers/03_ANTHROPIC.md +39 -0
- data/docs_providers/04_OPENAI.md +41 -0
- data/docs_providers/{05_TEST_PROVIDER.md → 05_MOCK_PROVIDER.md} +25 -8
- data/docs_providers/06_CUSTOM_PROVIDERS.md +159 -81
- data/lib/riffer/agent/response.rb +22 -2
- data/lib/riffer/agent.rb +297 -79
- data/lib/riffer/evals/evaluator.rb +48 -19
- data/lib/riffer/evals/evaluator_runner.rb +80 -0
- data/lib/riffer/evals/judge.rb +39 -13
- data/lib/riffer/evals/result.rb +2 -2
- data/lib/riffer/evals/run_result.rb +26 -70
- data/lib/riffer/evals/scenario_result.rb +61 -0
- data/lib/riffer/evals.rb +2 -2
- data/lib/riffer/file_part.rb +116 -0
- data/lib/riffer/messages/converter.rb +33 -1
- data/lib/riffer/messages/user.rb +21 -0
- data/lib/riffer/{tools/param.rb → param.rb} +2 -2
- data/lib/riffer/{tools/params.rb → params.rb} +7 -6
- data/lib/riffer/providers/amazon_bedrock.rb +183 -140
- data/lib/riffer/providers/anthropic.rb +226 -131
- data/lib/riffer/providers/base.rb +62 -20
- data/lib/riffer/providers/mock.rb +136 -0
- data/lib/riffer/providers/open_ai.rb +195 -111
- data/lib/riffer/providers/repository.rb +1 -1
- data/lib/riffer/providers.rb +1 -1
- data/lib/riffer/stream_events/interrupt.rb +25 -0
- data/lib/riffer/stream_events/web_search_done.rb +25 -0
- data/lib/riffer/stream_events/web_search_status.rb +32 -0
- data/lib/riffer/structured_output/result.rb +35 -0
- data/lib/riffer/structured_output.rb +39 -0
- data/lib/riffer/tool.rb +2 -2
- data/lib/riffer/tools.rb +0 -2
- data/lib/riffer/version.rb +1 -1
- data/sig/generated/riffer/agent/response.rbs +17 -2
- data/sig/generated/riffer/agent.rbs +90 -11
- data/sig/generated/riffer/evals/evaluator.rbs +27 -16
- data/sig/generated/riffer/evals/evaluator_runner.rbs +41 -0
- data/sig/generated/riffer/evals/judge.rbs +16 -6
- data/sig/generated/riffer/evals/result.rbs +2 -2
- data/sig/generated/riffer/evals/run_result.rbs +11 -43
- data/sig/generated/riffer/evals/scenario_result.rbs +42 -0
- data/sig/generated/riffer/evals.rbs +2 -2
- data/sig/generated/riffer/file_part.rbs +70 -0
- data/sig/generated/riffer/messages/converter.rbs +12 -0
- data/sig/generated/riffer/messages/user.rbs +14 -0
- data/sig/generated/riffer/{tools/param.rbs → param.rbs} +3 -3
- data/sig/generated/riffer/{tools/params.rbs → params.rbs} +6 -5
- data/sig/generated/riffer/providers/amazon_bedrock.rbs +39 -13
- data/sig/generated/riffer/providers/anthropic.rbs +50 -12
- data/sig/generated/riffer/providers/base.rbs +32 -11
- data/sig/generated/riffer/providers/{test.rbs → mock.rbs} +19 -10
- data/sig/generated/riffer/providers/open_ai.rbs +46 -20
- data/sig/generated/riffer/providers.rbs +1 -1
- data/sig/generated/riffer/stream_events/interrupt.rbs +17 -0
- data/sig/generated/riffer/stream_events/web_search_done.rbs +18 -0
- data/sig/generated/riffer/stream_events/web_search_status.rbs +21 -0
- data/sig/generated/riffer/structured_output/result.rbs +31 -0
- data/sig/generated/riffer/structured_output.rbs +25 -0
- data/sig/generated/riffer/tool.rbs +2 -2
- data/sig/generated/riffer/tools.rbs +0 -2
- metadata +28 -24
- data/lib/riffer/evals/evaluators/answer_relevancy.rb +0 -59
- data/lib/riffer/evals/evaluators.rb +0 -6
- data/lib/riffer/evals/metric.rb +0 -65
- data/lib/riffer/evals/profile.rb +0 -99
- data/lib/riffer/evals/runner.rb +0 -44
- data/lib/riffer/guardrails/max_length.rb +0 -67
- data/lib/riffer/providers/test.rb +0 -114
- data/sig/generated/riffer/evals/evaluators/answer_relevancy.rbs +0 -24
- data/sig/generated/riffer/evals/evaluators.rbs +0 -5
- data/sig/generated/riffer/evals/metric.rbs +0 -43
- data/sig/generated/riffer/evals/profile.rbs +0 -59
- data/sig/generated/riffer/evals/runner.rbs +0 -27
- data/sig/generated/riffer/guardrails/max_length.rbs +0 -38
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ae2818fb04f43e8b5bd3a4a2ecfc2302af15ac073985e08f3fd36c461bafdf8c
|
|
4
|
+
data.tar.gz: e5ec190ea0c927eb38604849798b44fc96a03ba80510376d1d0e2eb2f5138fd0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c841653977d2277537ae2930a874d32748f874a4995fa058fd2abdff798d70f99cecdc4e75058179194f7b78502e209c4c97d916b4f568cab5935b9f4d470e84
|
|
7
|
+
data.tar.gz: 383682e8b929bc8f164c9bce1ae0b6bbec9a6ea7a30a5282bde79becfe886b22e7177f45ac5421ec97aad7fdfd2adf0150d649d0791c14f931c59ab737b36940
|
data/.agents/architecture.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
### Agent (`lib/riffer/agent.rb`)
|
|
6
6
|
|
|
7
|
-
Base class for AI agents. Subclass and use DSL methods `model` and `
|
|
7
|
+
Base class for AI agents. Subclass and use DSL methods `model`, `instructions`, and `structured_output` to configure. Orchestrates message flow, LLM calls, tool execution, and structured output parsing via a generate/stream loop.
|
|
8
8
|
|
|
9
9
|
```ruby
|
|
10
10
|
class EchoAgent < Riffer::Agent
|
|
@@ -18,10 +18,13 @@ puts agent.generate('Hello world')
|
|
|
18
18
|
|
|
19
19
|
### Providers (`lib/riffer/providers/`)
|
|
20
20
|
|
|
21
|
-
Adapters for LLM APIs.
|
|
21
|
+
Adapters for LLM APIs. The base class uses a template-method pattern — `generate_text` and `stream_text` orchestrate the flow, delegating to five hook methods each provider implements:
|
|
22
22
|
|
|
23
|
-
- `
|
|
24
|
-
- `
|
|
23
|
+
- `build_request_params(messages, model, options)` — convert messages, tools, and options into SDK params
|
|
24
|
+
- `execute_generate(params)` — call the SDK and return the raw response
|
|
25
|
+
- `execute_stream(params, yielder)` — call the streaming SDK, mapping events to the yielder
|
|
26
|
+
- `extract_token_usage(response)` — pull token counts from the SDK response
|
|
27
|
+
- `extract_assistant_message(response, token_usage)` — parse the SDK response into an `Assistant` message
|
|
25
28
|
|
|
26
29
|
Providers are registered in `Riffer::Providers::Repository::REPO` with identifiers (e.g., `openai`, `amazon_bedrock`).
|
|
27
30
|
|
|
@@ -30,11 +33,13 @@ Providers are registered in `Riffer::Providers::Repository::REPO` with identifie
|
|
|
30
33
|
Typed message objects that extend `Riffer::Messages::Base`:
|
|
31
34
|
|
|
32
35
|
- `System` - system instructions
|
|
33
|
-
- `User` - user input
|
|
36
|
+
- `User` - user input (supports file attachments via `Riffer::FilePart`)
|
|
34
37
|
- `Assistant` - AI responses
|
|
35
38
|
- `Tool` - tool execution results
|
|
36
39
|
|
|
37
|
-
|
|
40
|
+
`Riffer::FilePart` represents file attachments (images and documents) that can be included with User messages. Supports file paths, URLs, and raw base64 data.
|
|
41
|
+
|
|
42
|
+
The `Converter` module handles hash-to-object conversion, including file hash-to-`FilePart` conversion.
|
|
38
43
|
|
|
39
44
|
### StreamEvents (`lib/riffer/stream_events/`)
|
|
40
45
|
|
|
@@ -44,10 +49,27 @@ Structured events for streaming responses:
|
|
|
44
49
|
- `TextDone` - completion signals
|
|
45
50
|
- `ReasoningDelta` - reasoning process chunks
|
|
46
51
|
- `ReasoningDone` - reasoning completion
|
|
52
|
+
- `WebSearchStatus` - web search status updates
|
|
53
|
+
- `WebSearchDone` - web search completion with query and sources
|
|
54
|
+
- `Interrupt` - callback interrupted the agent loop
|
|
55
|
+
|
|
56
|
+
### Stopping the Loop Early
|
|
57
|
+
|
|
58
|
+
Two mechanisms can stop the agent loop before the LLM finishes naturally:
|
|
59
|
+
|
|
60
|
+
**Guardrail tripwires** — declarative policy enforcement registered at class level. A `:before` guardrail can block the request before the LLM is called; an `:after` guardrail can block the response. Tripwires are not resumable — the caller must change the input and start over. `Response#blocked?` returns `true`.
|
|
61
|
+
|
|
62
|
+
**Callback interrupts** — imperative flow control via `on_message` callbacks. Use `throw :riffer_interrupt` to pause the loop at any point. `Response#interrupted?` returns `true`. In streaming, yields an `Interrupt` event.
|
|
63
|
+
|
|
64
|
+
### Resuming After an Interrupt
|
|
65
|
+
|
|
66
|
+
`agent.resume` or `agent.resume_stream` continues an interrupted loop. Both accept `messages:` for cross-process resume from persisted data.
|
|
67
|
+
|
|
68
|
+
On resume, `execute_pending_tool_calls` detects tool calls from the last assistant message that lack corresponding tool result messages and executes them before entering the LLM loop. This handles the case where an interrupt fired mid-way through tool execution.
|
|
47
69
|
|
|
48
70
|
## Key Patterns
|
|
49
71
|
|
|
50
|
-
- Model
|
|
72
|
+
- Model config accepts a `provider/model` string (e.g., `openai/gpt-4`) or a Proc/lambda that returns one
|
|
51
73
|
- Configuration via `Riffer.configure { |c| c.openai.api_key = "..." }`
|
|
52
74
|
- Providers use `depends_on` helper for runtime dependency checking
|
|
53
75
|
- Zeitwerk for autoloading - file structure must match module/class names
|
|
@@ -55,6 +77,9 @@ Structured events for streaming responses:
|
|
|
55
77
|
## Project Structure
|
|
56
78
|
|
|
57
79
|
```
|
|
80
|
+
examples/
|
|
81
|
+
evaluators/ # Reference evaluator implementations (copy-paste)
|
|
82
|
+
guardrails/ # Reference guardrail implementations (copy-paste)
|
|
58
83
|
lib/
|
|
59
84
|
riffer.rb # Main entry point, uses Zeitwerk for autoloading
|
|
60
85
|
riffer/
|
|
@@ -64,11 +89,17 @@ lib/
|
|
|
64
89
|
agent.rb # Agent class
|
|
65
90
|
messages.rb # Messages namespace/module
|
|
66
91
|
providers.rb # Providers namespace/module
|
|
92
|
+
param.rb # Single parameter definition (shared by tools and structured output)
|
|
93
|
+
params.rb # Parameter collection with DSL and validation
|
|
94
|
+
structured_output.rb # Structured output schema wrapper
|
|
67
95
|
stream_events.rb # Stream events namespace/module
|
|
96
|
+
structured_output/
|
|
97
|
+
result.rb # Parse/validation result object
|
|
68
98
|
helpers/
|
|
69
99
|
class_name_converter.rb # Class name conversion utilities
|
|
70
100
|
dependencies.rb # Dependency management
|
|
71
101
|
validations.rb # Validation helpers
|
|
102
|
+
file_part.rb # File attachment (images and documents)
|
|
72
103
|
messages/
|
|
73
104
|
base.rb # Base message class
|
|
74
105
|
assistant.rb # Assistant message
|
|
@@ -80,14 +111,18 @@ lib/
|
|
|
80
111
|
base.rb # Base provider class
|
|
81
112
|
open_ai.rb # OpenAI provider
|
|
82
113
|
amazon_bedrock.rb # Amazon Bedrock provider
|
|
114
|
+
anthropic.rb # Anthropic provider
|
|
83
115
|
repository.rb # Provider registry
|
|
84
|
-
|
|
116
|
+
mock.rb # Mock provider
|
|
85
117
|
stream_events/
|
|
86
118
|
base.rb # Base stream event
|
|
119
|
+
interrupt.rb # Interrupt event
|
|
87
120
|
text_delta.rb # Text delta event
|
|
88
121
|
text_done.rb # Text done event
|
|
89
122
|
reasoning_delta.rb # Reasoning delta event
|
|
90
123
|
reasoning_done.rb # Reasoning done event
|
|
124
|
+
web_search_status.rb # Web search status event
|
|
125
|
+
web_search_done.rb # Web search done event
|
|
91
126
|
test/
|
|
92
127
|
test_helper.rb # Minitest configuration with VCR
|
|
93
128
|
riffer_test.rb # Main module tests
|
data/.agents/providers.md
CHANGED
|
@@ -3,33 +3,185 @@
|
|
|
3
3
|
## Steps
|
|
4
4
|
|
|
5
5
|
1. Create `lib/riffer/providers/your_provider.rb` extending `Riffer::Providers::Base`
|
|
6
|
-
2. Implement required methods (see below)
|
|
6
|
+
2. Implement the required hook methods (see below)
|
|
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`
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Architecture
|
|
12
|
+
|
|
13
|
+
The base class uses the **template method** pattern. The public methods `generate_text` and `stream_text` orchestrate the flow, delegating to five hook methods that each provider implements:
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
generate_text
|
|
17
|
+
├─ build_request_params
|
|
18
|
+
├─ execute_generate
|
|
19
|
+
├─ extract_token_usage
|
|
20
|
+
└─ extract_assistant_message
|
|
21
|
+
|
|
22
|
+
stream_text
|
|
23
|
+
├─ build_request_params
|
|
24
|
+
└─ execute_stream
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Required Hook Methods
|
|
12
28
|
|
|
13
29
|
```ruby
|
|
14
30
|
# frozen_string_literal: true
|
|
31
|
+
# rbs_inline: enabled
|
|
32
|
+
|
|
33
|
+
class Riffer::Providers::YourProvider < Riffer::Providers::Base
|
|
34
|
+
def initialize(**options)
|
|
35
|
+
depends_on "your-sdk-gem"
|
|
36
|
+
@client = YourSDK::Client.new(**options)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
# Convert messages, tools, and options into SDK-specific params.
|
|
42
|
+
# If supporting web search, extract `web_search` from options and convert
|
|
43
|
+
# it to a provider-native tool format (e.g., OpenAI's `web_search_preview`
|
|
44
|
+
# or Anthropic's `web_search_20250305` server tool).
|
|
45
|
+
#
|
|
46
|
+
#: (Array[Riffer::Messages::Base], String?, Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
47
|
+
def build_request_params(messages, model, options)
|
|
48
|
+
# Return a hash that can be passed to both execute_generate and execute_stream
|
|
49
|
+
end
|
|
15
50
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
51
|
+
# Call the SDK and return the raw response object.
|
|
52
|
+
#
|
|
53
|
+
#: (Hash[Symbol, untyped]) -> untyped
|
|
54
|
+
def execute_generate(params)
|
|
55
|
+
@client.create(**params)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Call the streaming SDK, mapping provider events to Riffer stream events.
|
|
59
|
+
#
|
|
60
|
+
#: (Hash[Symbol, untyped], Enumerator::Yielder) -> void
|
|
61
|
+
def execute_stream(params, yielder)
|
|
62
|
+
@client.stream(**params) do |event|
|
|
63
|
+
# Map SDK events to Riffer::StreamEvents::* and yield them
|
|
64
|
+
# yielder << Riffer::StreamEvents::TextDelta.new(event.text)
|
|
28
65
|
end
|
|
29
66
|
end
|
|
67
|
+
|
|
68
|
+
# Extract token usage from the SDK response.
|
|
69
|
+
#
|
|
70
|
+
#: (untyped) -> Riffer::TokenUsage?
|
|
71
|
+
def extract_token_usage(response)
|
|
72
|
+
usage = response.usage
|
|
73
|
+
return nil unless usage
|
|
74
|
+
|
|
75
|
+
Riffer::TokenUsage.new(
|
|
76
|
+
input_tokens: usage.input_tokens,
|
|
77
|
+
output_tokens: usage.output_tokens
|
|
78
|
+
)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Parse the SDK response into an Assistant message.
|
|
82
|
+
#
|
|
83
|
+
#: (untyped, ?Riffer::TokenUsage?) -> Riffer::Messages::Assistant
|
|
84
|
+
def extract_assistant_message(response, token_usage = nil)
|
|
85
|
+
# Extract text and tool_calls from the response
|
|
86
|
+
Riffer::Messages::Assistant.new(text, tool_calls: tool_calls, token_usage: token_usage)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Structured Output
|
|
92
|
+
|
|
93
|
+
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.
|
|
94
|
+
|
|
95
|
+
### Extracting from options
|
|
96
|
+
|
|
97
|
+
All providers follow the same pattern:
|
|
98
|
+
|
|
99
|
+
```ruby
|
|
100
|
+
def build_request_params(messages, model, options)
|
|
101
|
+
structured_output = options[:structured_output]
|
|
102
|
+
|
|
103
|
+
params = {
|
|
104
|
+
# ...
|
|
105
|
+
**options.except(:tools, :structured_output)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
# Convert to provider-specific format (see below)
|
|
109
|
+
end
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Provider-specific formats
|
|
113
|
+
|
|
114
|
+
**OpenAI** — uses `params[:text][:format]`:
|
|
115
|
+
|
|
116
|
+
```ruby
|
|
117
|
+
if structured_output
|
|
118
|
+
params[:text] = {
|
|
119
|
+
format: {
|
|
120
|
+
type: "json_schema",
|
|
121
|
+
name: "response",
|
|
122
|
+
schema: structured_output.json_schema,
|
|
123
|
+
strict: true
|
|
124
|
+
}
|
|
125
|
+
}
|
|
30
126
|
end
|
|
31
127
|
```
|
|
32
128
|
|
|
129
|
+
**Anthropic** — uses `params[:output_config]`:
|
|
130
|
+
|
|
131
|
+
```ruby
|
|
132
|
+
if structured_output
|
|
133
|
+
params[:output_config] = {
|
|
134
|
+
format: {
|
|
135
|
+
type: "json_schema",
|
|
136
|
+
schema: structured_output.json_schema
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
end
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**Amazon Bedrock** — uses `params[:output_config][:text_format]` with stringified schema:
|
|
143
|
+
|
|
144
|
+
```ruby
|
|
145
|
+
if structured_output
|
|
146
|
+
params[:output_config] = {
|
|
147
|
+
text_format: {
|
|
148
|
+
type: "json_schema",
|
|
149
|
+
structure: {
|
|
150
|
+
json_schema: {
|
|
151
|
+
schema: structured_output.json_schema.to_json,
|
|
152
|
+
name: "response"
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
end
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Key details
|
|
161
|
+
|
|
162
|
+
- `structured_output.json_schema` returns a Hash with `type`, `properties`, `required`, and `additionalProperties` keys
|
|
163
|
+
- Bedrock requires the schema as a JSON string (`.to_json`), others use the Hash directly
|
|
164
|
+
- The agent handles parsing and validation of the response — providers only need to pass the schema to the SDK
|
|
165
|
+
|
|
166
|
+
## File Handling
|
|
167
|
+
|
|
168
|
+
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:
|
|
169
|
+
|
|
170
|
+
- **OpenAI**: `input_image` (URLs or data URIs) and `input_file` (data URIs)
|
|
171
|
+
- **Anthropic**: `image` and `document` blocks with `url` or `base64` source
|
|
172
|
+
- **Bedrock**: `image` and `document` blocks with `bytes` source (always base64, URLs are resolved)
|
|
173
|
+
|
|
174
|
+
## Shared Utilities
|
|
175
|
+
|
|
176
|
+
The base class provides `parse_tool_arguments` for converting tool call arguments from JSON strings to hashes:
|
|
177
|
+
|
|
178
|
+
```ruby
|
|
179
|
+
# Available in all providers via the base class
|
|
180
|
+
parse_tool_arguments('{"key":"value"}') # => {"key" => "value"}
|
|
181
|
+
parse_tool_arguments({"key" => "value"}) # => {"key" => "value"}
|
|
182
|
+
parse_tool_arguments(nil) # => {}
|
|
183
|
+
```
|
|
184
|
+
|
|
33
185
|
## Registration
|
|
34
186
|
|
|
35
187
|
Add to `Riffer::Providers::Repository::REPO`:
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,28 @@ 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.14.0](https://github.com/janeapp/riffer/compare/riffer/v0.13.0...riffer/v0.14.0) (2026-02-24)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* add file attachment support for user messages ([#129](https://github.com/janeapp/riffer/issues/129)) ([0d08eb1](https://github.com/janeapp/riffer/commit/0d08eb140e4094a729b1da5e3fddb57b251bf6f3))
|
|
14
|
+
* add max_steps option to Agent ([#121](https://github.com/janeapp/riffer/issues/121)) ([fbc0391](https://github.com/janeapp/riffer/commit/fbc0391d157db587c0293255587a70141a7b588f))
|
|
15
|
+
* add structured output support for agents ([#128](https://github.com/janeapp/riffer/issues/128)) ([99be155](https://github.com/janeapp/riffer/commit/99be15567747427830fdb75b585715f013857f6f))
|
|
16
|
+
* add web_search option for OpenAI and Anthropic providers ([#126](https://github.com/janeapp/riffer/issues/126)) ([7e7e793](https://github.com/janeapp/riffer/commit/7e7e793a4ff746d7238074a21b9cd62a846e7c99))
|
|
17
|
+
* interruptible callbacks via throw/catch ([#119](https://github.com/janeapp/riffer/issues/119)) ([f5985e6](https://github.com/janeapp/riffer/commit/f5985e627737b28ebbf7ed7262e62496836acf1f))
|
|
18
|
+
* replace eval prompt API with semantic fields ([#132](https://github.com/janeapp/riffer/issues/132)) ([5d99d5a](https://github.com/janeapp/riffer/commit/5d99d5af408e4e70ae66c975d1b40d60a209f5a6))
|
|
19
|
+
* replace Profile/Metric eval system with EvaluatorRunner ([#138](https://github.com/janeapp/riffer/issues/138)) ([ebf2696](https://github.com/janeapp/riffer/commit/ebf2696dfce814be43278aa9857285c21b3894bf))
|
|
20
|
+
* support dynamic model selection via lambda ([#127](https://github.com/janeapp/riffer/issues/127)) ([c59cf96](https://github.com/janeapp/riffer/commit/c59cf96efb5a4f5d0bc947441fa3aeeea3b4e5f3))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
### Bug Fixes
|
|
24
|
+
|
|
25
|
+
* add --comment flag to claude code review prompt ([#122](https://github.com/janeapp/riffer/issues/122)) ([534bd59](https://github.com/janeapp/riffer/commit/534bd59c389233466824090b7bdfed976870d9f1))
|
|
26
|
+
* add RBS annotations to web search constants and fix test provider docs ([#130](https://github.com/janeapp/riffer/issues/130)) ([7cebe05](https://github.com/janeapp/riffer/commit/7cebe0506eafaa35abe2de74997af479a3776a7d))
|
|
27
|
+
* correct Amazon Bedrock model options to use Converse API structure ([#133](https://github.com/janeapp/riffer/issues/133)) ([3af4562](https://github.com/janeapp/riffer/commit/3af45620fc47d1b98961eb45d79a905a7d2cac82))
|
|
28
|
+
* widen run_eval input type to accept String or messages array ([#124](https://github.com/janeapp/riffer/issues/124)) ([f96214c](https://github.com/janeapp/riffer/commit/f96214c5b602c3469edca2ac9d0b856d1e23c630))
|
|
29
|
+
|
|
8
30
|
## [0.13.0](https://github.com/janeapp/riffer/compare/riffer/v0.12.0...riffer/v0.13.0) (2026-02-12)
|
|
9
31
|
|
|
10
32
|
|
data/docs/01_OVERVIEW.md
CHANGED
|
@@ -37,13 +37,32 @@ end
|
|
|
37
37
|
|
|
38
38
|
See [Tools](04_TOOLS.md) for details.
|
|
39
39
|
|
|
40
|
+
### Structured Output
|
|
41
|
+
|
|
42
|
+
Agents can return structured JSON responses that conform to a schema. The response is automatically parsed and validated:
|
|
43
|
+
|
|
44
|
+
```ruby
|
|
45
|
+
class SentimentAgent < Riffer::Agent
|
|
46
|
+
model 'openai/gpt-4o'
|
|
47
|
+
structured_output do
|
|
48
|
+
required :sentiment, String
|
|
49
|
+
required :score, Float
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
response = SentimentAgent.generate('Analyze: "I love this!"')
|
|
54
|
+
response.structured_output # => {sentiment: "positive", score: 0.95}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
See the [structured output section in Agents](03_AGENTS.md#structured_output) for details.
|
|
58
|
+
|
|
40
59
|
### Provider
|
|
41
60
|
|
|
42
61
|
Providers are adapters that connect to LLM services. Riffer supports:
|
|
43
62
|
|
|
44
63
|
- **OpenAI** - GPT models via the OpenAI API
|
|
45
64
|
- **Amazon Bedrock** - Claude and other models via AWS Bedrock
|
|
46
|
-
- **
|
|
65
|
+
- **Mock** - Mock provider for testing
|
|
47
66
|
|
|
48
67
|
See [Providers](providers/01_PROVIDERS.md) for details.
|
|
49
68
|
|
|
@@ -66,6 +85,8 @@ When streaming responses, Riffer emits typed events:
|
|
|
66
85
|
- `TextDone` - Complete text
|
|
67
86
|
- `ToolCallDelta` - Incremental tool call arguments
|
|
68
87
|
- `ToolCallDone` - Complete tool call
|
|
88
|
+
- `WebSearchStatus` - Web search progress updates
|
|
89
|
+
- `WebSearchDone` - Web search completion with sources
|
|
69
90
|
|
|
70
91
|
See [Stream Events](06_STREAM_EVENTS.md) for details.
|
|
71
92
|
|