riffer 0.30.0 → 0.32.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/code-style.md +63 -4
- data/.agents/rbs-inline.md +1 -6
- data/.release-please-manifest.json +1 -1
- data/AGENTS.md +1 -2
- data/CHANGELOG.md +25 -0
- data/docs/08_MESSAGES.md +1 -1
- data/docs/14_MCP.md +50 -5
- data/docs/15_SERIALIZATION.md +23 -12
- data/docs/providers/02_AMAZON_BEDROCK.md +14 -0
- data/lib/riffer/agent/config.rb +42 -47
- data/lib/riffer/agent/context.rb +70 -50
- data/lib/riffer/agent/response.rb +4 -20
- data/lib/riffer/agent/run.rb +28 -67
- data/lib/riffer/agent/serializer.rb +36 -85
- data/lib/riffer/agent/session/repair.rb +14 -40
- data/lib/riffer/agent/session.rb +25 -67
- data/lib/riffer/agent/structured_output/result.rb +3 -11
- data/lib/riffer/agent/structured_output.rb +5 -13
- data/lib/riffer/agent.rb +81 -199
- data/lib/riffer/config.rb +34 -101
- data/lib/riffer/evals/evaluator.rb +7 -27
- data/lib/riffer/evals/evaluator_runner.rb +11 -19
- data/lib/riffer/evals/judge.rb +4 -25
- data/lib/riffer/evals/result.rb +1 -18
- data/lib/riffer/evals/run_result.rb +0 -11
- data/lib/riffer/evals/scenario_result.rb +0 -14
- data/lib/riffer/evals.rb +0 -6
- data/lib/riffer/guardrail.rb +4 -27
- data/lib/riffer/guardrails/modification.rb +0 -10
- data/lib/riffer/guardrails/result.rb +3 -30
- data/lib/riffer/guardrails/runner.rb +5 -22
- data/lib/riffer/guardrails/tripwire.rb +1 -19
- data/lib/riffer/guardrails.rb +2 -4
- data/lib/riffer/helpers/call_or_value.rb +4 -3
- data/lib/riffer/helpers/class_name_converter.rb +3 -1
- data/lib/riffer/helpers/dependencies.rb +5 -7
- data/lib/riffer/helpers.rb +0 -5
- data/lib/riffer/mcp/authenticated_tool.rb +9 -9
- data/lib/riffer/mcp/client.rb +12 -17
- data/lib/riffer/mcp/manifest.rb +13 -10
- data/lib/riffer/mcp/registration.rb +2 -11
- data/lib/riffer/mcp/registry.rb +44 -52
- data/lib/riffer/mcp/search_tool.rb +53 -0
- data/lib/riffer/mcp/tool_factory.rb +13 -18
- data/lib/riffer/mcp.rb +12 -17
- data/lib/riffer/messages/assistant.rb +2 -9
- data/lib/riffer/messages/base.rb +46 -16
- data/lib/riffer/messages/file_part.rb +32 -24
- data/lib/riffer/messages/system.rb +0 -5
- data/lib/riffer/messages/tool.rb +0 -10
- data/lib/riffer/messages/user.rb +0 -10
- data/lib/riffer/messages.rb +0 -7
- data/lib/riffer/params/boolean.rb +2 -4
- data/lib/riffer/params/param.rb +28 -39
- data/lib/riffer/params.rb +9 -21
- data/lib/riffer/providers/amazon_bedrock.rb +42 -28
- data/lib/riffer/providers/anthropic.rb +4 -9
- data/lib/riffer/providers/azure_open_ai.rb +3 -19
- data/lib/riffer/providers/base.rb +13 -26
- data/lib/riffer/providers/gemini.rb +4 -4
- data/lib/riffer/providers/mock.rb +6 -26
- data/lib/riffer/providers/open_ai.rb +6 -8
- data/lib/riffer/providers/open_router.rb +4 -10
- data/lib/riffer/providers/repository.rb +4 -3
- data/lib/riffer/providers/token_usage.rb +9 -20
- data/lib/riffer/providers.rb +0 -8
- data/lib/riffer/runner/fibers.rb +10 -16
- data/lib/riffer/runner/sequential.rb +1 -4
- data/lib/riffer/runner/threaded.rb +3 -14
- data/lib/riffer/runner.rb +2 -15
- data/lib/riffer/skills/activate_tool.rb +2 -11
- data/lib/riffer/skills/adapter.rb +4 -22
- data/lib/riffer/skills/backend.rb +7 -21
- data/lib/riffer/skills/config.rb +10 -31
- data/lib/riffer/skills/context.rb +5 -20
- data/lib/riffer/skills/filesystem_backend.rb +7 -25
- data/lib/riffer/skills/frontmatter.rb +10 -28
- data/lib/riffer/skills/markdown_adapter.rb +2 -9
- data/lib/riffer/skills/xml_adapter.rb +2 -8
- data/lib/riffer/stream_events/base.rb +1 -6
- data/lib/riffer/stream_events/guardrail_modification.rb +1 -8
- data/lib/riffer/stream_events/guardrail_tripwire.rb +1 -8
- data/lib/riffer/stream_events/interrupt.rb +4 -7
- data/lib/riffer/stream_events/reasoning_delta.rb +2 -4
- data/lib/riffer/stream_events/reasoning_done.rb +2 -4
- data/lib/riffer/stream_events/skill_activation.rb +2 -4
- data/lib/riffer/stream_events/text_delta.rb +0 -2
- data/lib/riffer/stream_events/text_done.rb +1 -3
- data/lib/riffer/stream_events/token_usage_done.rb +1 -8
- data/lib/riffer/stream_events/tool_call_delta.rb +2 -3
- data/lib/riffer/stream_events/tool_call_done.rb +1 -3
- data/lib/riffer/stream_events/web_search_done.rb +1 -3
- data/lib/riffer/stream_events/web_search_status.rb +2 -3
- data/lib/riffer/stream_events.rb +0 -10
- data/lib/riffer/tool.rb +6 -13
- data/lib/riffer/tools/response.rb +8 -4
- data/lib/riffer/tools/runtime/fibers.rb +0 -3
- data/lib/riffer/tools/runtime/inline.rb +1 -4
- data/lib/riffer/tools/runtime/threaded.rb +0 -2
- data/lib/riffer/tools/runtime.rb +5 -38
- data/lib/riffer/tools/toolable.rb +5 -16
- data/lib/riffer/tools.rb +0 -4
- data/lib/riffer/version.rb +1 -1
- data/lib/riffer.rb +7 -8
- data/sig/generated/riffer/agent/config.rbs +29 -46
- data/sig/generated/riffer/agent/context.rbs +40 -48
- data/sig/generated/riffer/agent/response.rbs +4 -20
- data/sig/generated/riffer/agent/run.rbs +12 -61
- data/sig/generated/riffer/agent/serializer.rbs +28 -81
- data/sig/generated/riffer/agent/session/repair.rbs +12 -40
- data/sig/generated/riffer/agent/session.rbs +25 -67
- data/sig/generated/riffer/agent/structured_output/result.rbs +2 -10
- data/sig/generated/riffer/agent/structured_output.rbs +5 -12
- data/sig/generated/riffer/agent.rbs +62 -191
- data/sig/generated/riffer/config.rbs +34 -100
- data/sig/generated/riffer/evals/evaluator.rbs +7 -27
- data/sig/generated/riffer/evals/evaluator_runner.rbs +9 -19
- data/sig/generated/riffer/evals/judge.rbs +4 -24
- data/sig/generated/riffer/evals/result.rbs +1 -17
- data/sig/generated/riffer/evals/run_result.rbs +0 -10
- data/sig/generated/riffer/evals/scenario_result.rbs +0 -13
- data/sig/generated/riffer/evals.rbs +0 -6
- data/sig/generated/riffer/guardrail.rbs +4 -27
- data/sig/generated/riffer/guardrails/modification.rbs +0 -10
- data/sig/generated/riffer/guardrails/result.rbs +3 -30
- data/sig/generated/riffer/guardrails/runner.rbs +5 -22
- data/sig/generated/riffer/guardrails/tripwire.rbs +1 -19
- data/sig/generated/riffer/guardrails.rbs +2 -4
- data/sig/generated/riffer/helpers/call_or_value.rbs +4 -3
- data/sig/generated/riffer/helpers/class_name_converter.rbs +1 -1
- data/sig/generated/riffer/helpers/dependencies.rbs +3 -7
- data/sig/generated/riffer/helpers.rbs +0 -5
- data/sig/generated/riffer/mcp/authenticated_tool.rbs +5 -4
- data/sig/generated/riffer/mcp/client.rbs +10 -16
- data/sig/generated/riffer/mcp/manifest.rbs +9 -9
- data/sig/generated/riffer/mcp/registration.rbs +2 -10
- data/sig/generated/riffer/mcp/registry.rbs +11 -18
- data/sig/generated/riffer/mcp/search_tool.rbs +26 -0
- data/sig/generated/riffer/mcp/tool_factory.rbs +10 -15
- data/sig/generated/riffer/mcp.rbs +10 -17
- data/sig/generated/riffer/messages/assistant.rbs +2 -8
- data/sig/generated/riffer/messages/base.rbs +11 -16
- data/sig/generated/riffer/messages/file_part.rbs +13 -23
- data/sig/generated/riffer/messages/system.rbs +0 -4
- data/sig/generated/riffer/messages/tool.rbs +0 -9
- data/sig/generated/riffer/messages/user.rbs +0 -9
- data/sig/generated/riffer/messages.rbs +0 -7
- data/sig/generated/riffer/params/boolean.rbs +2 -4
- data/sig/generated/riffer/params/param.rbs +21 -39
- data/sig/generated/riffer/params.rbs +9 -21
- data/sig/generated/riffer/providers/amazon_bedrock.rbs +21 -25
- data/sig/generated/riffer/providers/anthropic.rbs +2 -7
- data/sig/generated/riffer/providers/azure_open_ai.rbs +3 -18
- data/sig/generated/riffer/providers/base.rbs +9 -25
- data/sig/generated/riffer/providers/gemini.rbs +0 -2
- data/sig/generated/riffer/providers/mock.rbs +6 -26
- data/sig/generated/riffer/providers/open_ai.rbs +1 -5
- data/sig/generated/riffer/providers/open_router.rbs +4 -10
- data/sig/generated/riffer/providers/repository.rbs +2 -3
- data/sig/generated/riffer/providers/token_usage.rbs +6 -16
- data/sig/generated/riffer/providers.rbs +0 -8
- data/sig/generated/riffer/runner/fibers.rbs +8 -15
- data/sig/generated/riffer/runner/sequential.rbs +1 -3
- data/sig/generated/riffer/runner/threaded.rbs +3 -13
- data/sig/generated/riffer/runner.rbs +2 -14
- data/sig/generated/riffer/skills/activate_tool.rbs +2 -11
- data/sig/generated/riffer/skills/adapter.rbs +4 -22
- data/sig/generated/riffer/skills/backend.rbs +7 -21
- data/sig/generated/riffer/skills/config.rbs +10 -31
- data/sig/generated/riffer/skills/context.rbs +5 -20
- data/sig/generated/riffer/skills/filesystem_backend.rbs +7 -24
- data/sig/generated/riffer/skills/frontmatter.rbs +10 -27
- data/sig/generated/riffer/skills/markdown_adapter.rbs +2 -9
- data/sig/generated/riffer/skills/xml_adapter.rbs +2 -8
- data/sig/generated/riffer/stream_events/base.rbs +1 -6
- data/sig/generated/riffer/stream_events/guardrail_modification.rbs +1 -8
- data/sig/generated/riffer/stream_events/guardrail_tripwire.rbs +1 -8
- data/sig/generated/riffer/stream_events/interrupt.rbs +4 -7
- data/sig/generated/riffer/stream_events/reasoning_delta.rbs +2 -4
- data/sig/generated/riffer/stream_events/reasoning_done.rbs +2 -4
- data/sig/generated/riffer/stream_events/skill_activation.rbs +2 -4
- data/sig/generated/riffer/stream_events/text_delta.rbs +0 -2
- data/sig/generated/riffer/stream_events/text_done.rbs +1 -3
- data/sig/generated/riffer/stream_events/token_usage_done.rbs +1 -7
- data/sig/generated/riffer/stream_events/tool_call_delta.rbs +2 -3
- data/sig/generated/riffer/stream_events/tool_call_done.rbs +1 -3
- data/sig/generated/riffer/stream_events/web_search_done.rbs +1 -3
- data/sig/generated/riffer/stream_events/web_search_status.rbs +2 -3
- data/sig/generated/riffer/stream_events.rbs +0 -10
- data/sig/generated/riffer/tool.rbs +5 -12
- data/sig/generated/riffer/tools/response.rbs +6 -4
- data/sig/generated/riffer/tools/runtime/fibers.rbs +0 -3
- data/sig/generated/riffer/tools/runtime/inline.rbs +1 -3
- data/sig/generated/riffer/tools/runtime/threaded.rbs +0 -2
- data/sig/generated/riffer/tools/runtime.rbs +5 -37
- data/sig/generated/riffer/tools/toolable.rbs +4 -14
- data/sig/generated/riffer/tools.rbs +0 -4
- data/sig/generated/riffer.rbs +5 -4
- data/sig/manual/riffer/agent/session/repair.rbs +5 -0
- data/sig/manual/riffer/evals/evaluator_runner.rbs +5 -0
- data/sig/manual/riffer/helpers/class_name_converter.rbs +5 -0
- data/sig/manual/riffer/helpers/dependencies.rbs +5 -0
- data/sig/manual/riffer/mcp/authenticated_tool.rbs +5 -0
- data/sig/manual/riffer/mcp/registry.rbs +5 -0
- data/sig/manual/riffer/mcp/tool_factory.rbs +5 -0
- data/sig/manual/riffer/mcp.rbs +5 -0
- data/sig/manual/riffer/providers/repository.rbs +5 -0
- data/sig/manual/riffer.rbs +5 -0
- metadata +17 -9
- data/.agents/rdoc.md +0 -69
- data/lib/riffer/messages/converter.rb +0 -90
- data/sig/generated/riffer/messages/converter.rbs +0 -33
- data/sig/manual/riffer/tools/toolable.rbs +0 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0cddafa66f3f24980037c23be5e8584ec888b93c40b2b780c99e7205558d2593
|
|
4
|
+
data.tar.gz: 5aea2edfeb9d47a4246b15d3f4e16a7a3c1d7941a473355495267b9eb93bc3cc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fad79dcfd8036c3249ea17be785cb6acb193e3a1677f23ee052c89daf39fe97840369a4718e65ebb515bbddeb866608a532b8076a89e2f6c724ddd74d2131e85
|
|
7
|
+
data.tar.gz: 0c7b1bdb7383c6f9a2b053d2d811a7c4aa29142f8a44aa3fd07071d88b0dac722268f036c9f45887bbf3b10591cb3067193540c2cff766d6ab91aa4644f0dcb8
|
data/.agents/code-style.md
CHANGED
|
@@ -24,11 +24,66 @@ class MyCustomError < Riffer::Error
|
|
|
24
24
|
end
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
## Comments
|
|
27
|
+
## Comments & Documentation
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
-
|
|
29
|
+
A comment exists to explain a **why** the code itself cannot — never a **how**, and never a restatement of what the code already says. This bar governs all prose, from inline `#` comments to RDoc descriptions on the public API. Types are not prose's job: parameters, return values, and attribute/constant types live in rbs-inline `#:` annotations (see [rbs-inline.md](rbs-inline.md)).
|
|
30
|
+
|
|
31
|
+
**What's a comment (in scope):** RDoc descriptions and inline `#` explanations. **Not comments (never touched):** rbs-inline `#:` annotations, magic comments (`frozen_string_literal`, `rbs_inline`), and RDoc directives (`:nodoc:`, `:nocov:`).
|
|
32
|
+
|
|
33
|
+
### Public surface
|
|
34
|
+
|
|
35
|
+
Everything public — classes, modules, constants, attributes, public methods, and `protected` subclass-contract methods (e.g. the `pass` / `transform` / `block` helpers a custom `Riffer::Guardrail` calls) — gets **at minimum a very brief description**:
|
|
36
|
+
|
|
37
|
+
- **One verb-first sentence, one line.** `Creates a new agent.`, `Serializes the definition to JSON.`
|
|
38
|
+
- An optional **second sentence is reserved strictly for a "why"** — a non-obvious constraint or rationale the code can't convey. Never a second sentence of "how".
|
|
39
|
+
- If a description needs more than one sentence to say _what_ it does, that's a smell the method does too much.
|
|
40
|
+
- **Exempt:** a constant whose name and value already carry the full meaning (`VERSION = "0.30.0"`, `PHASES = %i[before after]`) — describe a constant only when its name doesn't; an empty namespace module (a Zeitwerk placeholder with no usable members of its own, e.g. `module Riffer::Messages; end`) — its children are documented individually; and a constructor (`initialize`) — the class doc and RDoc's `::new` already cover plain construction, so describe it only when it carries a contract or non-obvious construction behavior (a raise, a dup guard).
|
|
41
|
+
|
|
42
|
+
Do not document parameters or return values in prose — the `#:` line is the single source of truth for types. Attributes and constants still carry a brief description on the line above their inline `#:`.
|
|
43
|
+
|
|
44
|
+
```ruby
|
|
45
|
+
# Serializes the agent definition to a transferable JSON payload.
|
|
46
|
+
#--
|
|
47
|
+
#: (Riffer::Agent) -> String
|
|
48
|
+
def serialize(agent)
|
|
49
|
+
|
|
50
|
+
# The agent's display name.
|
|
51
|
+
attr_reader :name #: String
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Private methods
|
|
55
|
+
|
|
56
|
+
A comment survives on a private method **only** if it explains a why a competent reader cannot recover from the code and names alone — a non-local constraint, an external-system quirk, a deliberate non-obvious tradeoff. A description of what it does, or a why that's evident from the code, gets cut.
|
|
57
|
+
|
|
58
|
+
### Inline comments
|
|
59
|
+
|
|
60
|
+
Same bar: kept only to explain the why of something genuinely ambiguous. `TODO` / `FIXME` / `HACK` markers are tracked work and stay; `NOTE` / `REVIEW` are subject to the why-rule.
|
|
61
|
+
|
|
62
|
+
### No history
|
|
63
|
+
|
|
64
|
+
A comment describes the present, never how the code got there. Change narration — "was X, now Y", "previously used Z" — has no place; the reader cares about what is, not what was. The one thing worth stating is a still-true constraint, and it belongs in the present tense ("the API returns null for empty results — guard"), never told as the story of the bug that revealed it.
|
|
65
|
+
|
|
66
|
+
### RDoc mechanics
|
|
67
|
+
|
|
68
|
+
**The `#--` stop directive.** Place `#--` on the line immediately before a **standalone** `#:` type annotation. Without it, RDoc treats `#:` as a label-list marker and corrupts the preceding description into a `<pre>` block. Inline `#:` on the same line as code (attributes, constants) does not need it.
|
|
69
|
+
|
|
70
|
+
**Raises.** Document a raise **only when it's part of the caller's contract** — something a caller should reasonably anticipate and handle. Skip programmer-error guards and "should never happen" assertions. Reserved for public methods. When the raise condition merely restates the declared `#:` type, phrase it by intent ("Raises Riffer::ArgumentError on an invalid value") rather than re-listing the type union — but keep the runtime constraints a type can't express (enum value sets, coercion rules, validation failure).
|
|
71
|
+
|
|
72
|
+
```ruby
|
|
73
|
+
# Builds a param from a schema hash.
|
|
74
|
+
# Raises Riffer::ArgumentError if the schema is missing a +type+.
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Examples.** Include an example only when a **consumer is likely to use the thing themselves** — a public entry point they construct, subclass, or call (an `Agent` subclass, `Riffer::Mcp.register`, the `params` DSL). Skip examples on framework-internal types even though they're technically public (value objects the framework constructs and hands back, internal engines). When included, keep them sparing — only when they teach something the signature can't — and write them as indented code blocks (2 extra spaces of indent). Usage walkthroughs belong in `docs/`.
|
|
78
|
+
|
|
79
|
+
**Inline code formatting.** Use `+word+` for single-word inline code; for multi-word expressions (spaces, colons, brackets) use `<tt>multi word expression</tt>`, e.g. `Equivalent to <tt>throw :riffer_interrupt, reason</tt>`.
|
|
80
|
+
|
|
81
|
+
**Internal APIs.** Mark with `:nodoc:` to exclude from generated documentation:
|
|
82
|
+
|
|
83
|
+
```ruby
|
|
84
|
+
def internal_method # :nodoc:
|
|
85
|
+
end
|
|
86
|
+
```
|
|
32
87
|
|
|
33
88
|
## Hash Key Convention
|
|
34
89
|
|
|
@@ -37,6 +92,10 @@ end
|
|
|
37
92
|
- String keys are only used at serialization boundaries (JSON Schema output, external API payloads)
|
|
38
93
|
- Do not write dual-access patterns like `hash[:key] || hash["key"]` — normalize to symbol keys at the boundary instead
|
|
39
94
|
|
|
95
|
+
## Reserved Tool Identifiers
|
|
96
|
+
|
|
97
|
+
- Internal-use-only tools use plain descriptive names without a prefix (e.g. `mcp_search`, `mcp_call`, `evaluation`, `skill_activate`)
|
|
98
|
+
|
|
40
99
|
## Module Structure
|
|
41
100
|
|
|
42
101
|
```ruby
|
data/.agents/rbs-inline.md
CHANGED
|
@@ -4,12 +4,7 @@ Type annotations are added directly in Ruby source files using [rbs-inline](http
|
|
|
4
4
|
|
|
5
5
|
## Magic Comment
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
```ruby
|
|
10
|
-
# frozen_string_literal: true
|
|
11
|
-
# rbs_inline: enabled
|
|
12
|
-
```
|
|
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).
|
|
13
8
|
|
|
14
9
|
## Annotation Syntax
|
|
15
10
|
|
data/AGENTS.md
CHANGED
|
@@ -14,8 +14,7 @@ Ruby gem framework for building AI-powered agents with LLM provider adapters.
|
|
|
14
14
|
|
|
15
15
|
- [Architecture](.agents/architecture.md) - Core components and project structure
|
|
16
16
|
- [Testing](.agents/testing.md) - Minitest spec DSL and VCR cassettes
|
|
17
|
-
- [Code Style](.agents/code-style.md) - StandardRB and
|
|
18
|
-
- [RDoc](.agents/rdoc.md) - Documentation format for public APIs
|
|
17
|
+
- [Code Style](.agents/code-style.md) - StandardRB, comment, and RDoc conventions
|
|
19
18
|
- [Providers](.agents/providers.md) - Adding new LLM provider adapters
|
|
20
19
|
- [RBS Inline](.agents/rbs-inline.md) - Type annotations with rbs-inline
|
|
21
20
|
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,31 @@ 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.32.0](https://github.com/janeapp/riffer/compare/riffer/v0.31.0...riffer/v0.32.0) (2026-06-08)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### ⚠ BREAKING CHANGES
|
|
12
|
+
|
|
13
|
+
* `TokenUsage#cache_creation_tokens` is renamed to `cache_write_tokens` (also reflected in `TokenUsage#to_h`). Update any code reading that attribute or hash key.
|
|
14
|
+
* apply module/class conventions consistently ([#298](https://github.com/janeapp/riffer/issues/298))
|
|
15
|
+
|
|
16
|
+
### Features
|
|
17
|
+
|
|
18
|
+
* add Bedrock prompt caching and surface cached tokens ([#300](https://github.com/janeapp/riffer/issues/300)) ([407390b](https://github.com/janeapp/riffer/commit/407390b505a3af6b881c5204d856a8e9ceddbed9))
|
|
19
|
+
* add progressive discovery for MCP tools by default ([0a37485](https://github.com/janeapp/riffer/commit/0a37485dd59e08a0ba0ca8d1046e3313914f72a5))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### Code Refactoring
|
|
23
|
+
|
|
24
|
+
* apply module/class conventions consistently ([#298](https://github.com/janeapp/riffer/issues/298)) ([76a3131](https://github.com/janeapp/riffer/commit/76a3131f800ba026c07cc194ab2879279134e865))
|
|
25
|
+
|
|
26
|
+
## [0.31.0](https://github.com/janeapp/riffer/compare/riffer/v0.30.0...riffer/v0.31.0) (2026-06-03)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
### Features
|
|
30
|
+
|
|
31
|
+
* forward session: through Agent.from_h/from_json for history seeding ([#295](https://github.com/janeapp/riffer/issues/295)) ([0b2eaa2](https://github.com/janeapp/riffer/commit/0b2eaa27f5154bfd61891d4e93b8938f7dce2ce6))
|
|
32
|
+
|
|
8
33
|
## [0.30.0](https://github.com/janeapp/riffer/compare/riffer/v0.29.1...riffer/v0.30.0) (2026-06-03)
|
|
9
34
|
|
|
10
35
|
|
data/docs/08_MESSAGES.md
CHANGED
|
@@ -196,7 +196,7 @@ agent = MyAgent.new(session: session)
|
|
|
196
196
|
response = agent.generate # session already carries the last user turn
|
|
197
197
|
```
|
|
198
198
|
|
|
199
|
-
`Riffer::Agent::Session.new(messages:)` accepts `Riffer::Messages::Base` objects. If your persistence layer hands back hashes, normalize them first via `Riffer::Messages::
|
|
199
|
+
`Riffer::Agent::Session.new(messages:)` accepts `Riffer::Messages::Base` objects. If your persistence layer hands back hashes, normalize them first via `Riffer::Messages::Base.from_hash` or your own adapter.
|
|
200
200
|
|
|
201
201
|
### Accessing Message History
|
|
202
202
|
|
data/docs/14_MCP.md
CHANGED
|
@@ -36,8 +36,9 @@ When **`Riffer.config.mcp.credentials`** is set to a Proc, each MCP `tools/call`
|
|
|
36
36
|
```ruby
|
|
37
37
|
Riffer.configure do |config|
|
|
38
38
|
config.mcp.credentials = lambda do |manifest:, matched_tags:, context:|
|
|
39
|
-
# return nil to omit this server's tools for this
|
|
40
|
-
#
|
|
39
|
+
# when caller does not have an integration, return nil to omit this server's tools for this run
|
|
40
|
+
# when server is unauthenticated or local, return {} to include this server's tools with no extra headers
|
|
41
|
+
# when authorization headers are required, return Hash<String,String> headers
|
|
41
42
|
end
|
|
42
43
|
end
|
|
43
44
|
```
|
|
@@ -46,9 +47,9 @@ end
|
|
|
46
47
|
- **`matched_tags`** — intersection of the agent's `use_mcp` tags and `manifest.tags` for this registration (unioned across multiple `use_mcp` lines).
|
|
47
48
|
- **`context`** — the same hash passed to `generate` / `stream` for this run.
|
|
48
49
|
|
|
49
|
-
**Resolve time:**
|
|
50
|
+
**Resolve time:** The proc is invoked once per matching registration before tools are exposed to the model.
|
|
50
51
|
|
|
51
|
-
**Call time:** Authenticated tool wrappers invoke the proc again for each execution. If it returns
|
|
52
|
+
**Call time:** Authenticated tool wrappers invoke the proc again for each execution. If it returns `nil`, then `Riffer::Mcp::CredentialsDeniedError` is raised.
|
|
52
53
|
|
|
53
54
|
If **`credentials` is unset**, discovery and `tools/call` share one client built from `discovery_headers` (same behaviour as a single static token for both list and call).
|
|
54
55
|
|
|
@@ -71,6 +72,8 @@ class ResearchAgent < Riffer::Agent
|
|
|
71
72
|
end
|
|
72
73
|
```
|
|
73
74
|
|
|
75
|
+
By default, `use_mcp` uses **progressive discovery**. The agent receives `mcp_search` rather than every schema up front. See [Progressive Tool Discovery](#progressive-tool-discovery).
|
|
76
|
+
|
|
74
77
|
`use_mcp` accepts any tag registered via `Riffer::Mcp.register`. Multiple calls accumulate — the agent receives tools from all matching servers:
|
|
75
78
|
|
|
76
79
|
```ruby
|
|
@@ -90,6 +93,48 @@ Tool names must be unique across `uses_tools` and all included MCP servers; dupl
|
|
|
90
93
|
|
|
91
94
|
Like [`uses_tools`](03_AGENTS.md#uses_tools), **`use_mcp` is not inherited** from the superclass. Declare `use_mcp` on each agent class that should load MCP tools.
|
|
92
95
|
|
|
96
|
+
## Progressive Tool Discovery
|
|
97
|
+
|
|
98
|
+
Progressive discovery is the default. The `use_mcp` instruction exposes **`mcp_search`** instead of flooding the context with every tool schema up front.
|
|
99
|
+
|
|
100
|
+
```ruby
|
|
101
|
+
class ResearchAgent < Riffer::Agent
|
|
102
|
+
model "openai/gpt-4o"
|
|
103
|
+
|
|
104
|
+
use_mcp :github # default: tools discoverable on demand
|
|
105
|
+
use_mcp :jira, progressive: false # opt-out: all Jira tools injected directly
|
|
106
|
+
end
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Only use `progressive: false` when the server has a small, stable set of tools you always want available.
|
|
110
|
+
|
|
111
|
+
**`mcp_search`** — Search for available tools by name or description.
|
|
112
|
+
- `query` (required, non-empty) — filter by name or description substring.
|
|
113
|
+
|
|
114
|
+
On a successful search, matching tools are injected into the agent's active tool list. The model calls them natively on the next turn — no proxy or JSON-encoded arguments.
|
|
115
|
+
|
|
116
|
+
**Example flow:**
|
|
117
|
+
|
|
118
|
+
1. Agent starts — only `mcp_search` appears in the tool list.
|
|
119
|
+
2. LLM calls `mcp_search` with `query: "create pull request"`.
|
|
120
|
+
3. Riffer injects `github__create_pr` into the active tool list and returns an acknowledgment.
|
|
121
|
+
4. LLM calls `github__create_pr` directly with its real schema (e.g. `title:`, `body:`, `base:`).
|
|
122
|
+
5. The provider validates the arguments; the tool executes with all credential handling intact.
|
|
123
|
+
|
|
124
|
+
Injected tools accumulate across turns — tools discovered in one search remain available for subsequent calls without re-searching.
|
|
125
|
+
|
|
126
|
+
**Multiple progressive `use_mcp` calls:** All matching registrations are combined into one `mcp_search`:
|
|
127
|
+
|
|
128
|
+
```ruby
|
|
129
|
+
use_mcp :connectors_a # both default to progressive
|
|
130
|
+
use_mcp :connectors_b
|
|
131
|
+
# → one mcp_search exposing tools from both registrations
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**Credential handling:** Progressive tools follow the same credential rules as regular tools — see [Session credentials callback](#session-credentials-callback).
|
|
135
|
+
|
|
136
|
+
**Tool access in tools:** The full discovery pool is available via `context[:mcp_progressive_tools]` and injected tools via `context[:injected_tools]` (both `Array[Riffer::Tool subclass]`). These keys are framework-managed — treat them as read-only from application code.
|
|
137
|
+
|
|
93
138
|
## Unregistering a Server
|
|
94
139
|
|
|
95
140
|
```ruby
|
|
@@ -130,7 +175,7 @@ All inherit from `Riffer::Mcp::Error < Riffer::Error`.
|
|
|
130
175
|
|
|
131
176
|
- **Tool results:** `tools/call` responses are reduced to joined **text** content from MCP `content` items. Non-text parts (e.g. images, embedded resources) are not surfaced in this release.
|
|
132
177
|
- **Session credentials:** When `Riffer.config.mcp.credentials` is set, authenticated tool wrappers may build a **new HTTP client per tool invocation** so headers stay fresh; there is no connection pooling in this release.
|
|
133
|
-
- **Context window / progressive disclosure:**
|
|
178
|
+
- **Context window / progressive disclosure:** `use_mcp` defaults to progressive mode — tools are discovered via `mcp_search` and injected natively for subsequent calls. Use `progressive: false` to inject all schemas directly. See [Progressive Tool Discovery](#progressive-tool-discovery).
|
|
134
179
|
|
|
135
180
|
## Requirements
|
|
136
181
|
|
data/docs/15_SERIALIZATION.md
CHANGED
|
@@ -1,28 +1,39 @@
|
|
|
1
1
|
# Serialization
|
|
2
2
|
|
|
3
|
-
`Riffer::Agent::Serializer` turns a **resolved agent** into a self-contained, provider-neutral data
|
|
3
|
+
`Riffer::Agent::Serializer` turns a **resolved agent** into a self-contained, provider-neutral data hash (`to_h`) and reconstructs a **runnable agent** from that hash (`from_h`). Use it to persist agent definitions outside of code, or to transfer them across a process/service boundary.
|
|
4
4
|
|
|
5
5
|
You normally reach it through the delegators on `Riffer::Agent`:
|
|
6
6
|
|
|
7
7
|
```ruby
|
|
8
|
-
|
|
9
|
-
rebuilt = Riffer::Agent.from_h(
|
|
8
|
+
data = agent.to_h # snapshot
|
|
9
|
+
rebuilt = Riffer::Agent.from_h(data) # reconstruct
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
-
The
|
|
12
|
+
The hash is plain data — symbol-keyed, JSON-safe. For the wire, use the JSON helpers, which handle generating and parsing for you:
|
|
13
13
|
|
|
14
14
|
```ruby
|
|
15
15
|
json = agent.to_json # or Riffer::Agent::Serializer.to_json(agent:)
|
|
16
16
|
rebuilt = Riffer::Agent.from_json(json)
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
The hash forms (`to_h` / `from_h`) are public too, if you want to embed the
|
|
19
|
+
The hash forms (`to_h` / `from_h`) are public too, if you want to embed the hash in a larger payload. `from_h` expects symbol keys, so parse with `JSON.parse(str, symbolize_names: true)` — or just use `from_json`, which does that for you.
|
|
20
20
|
|
|
21
21
|
### Runtime context
|
|
22
22
|
|
|
23
23
|
`from_h` / `from_json` accept an optional `context:` — the rebuilt agent's **runtime** context, exactly the value you'd pass to `Agent.new(context:)`. It is **not** used to re-resolve the serialized definition (that's already resolved); it's threaded into tool dispatch and read by tools/runtimes at call time. Pass it when a tool or a remote runtime needs per-call data — e.g. `context: { tenant: "acme" }` for multi-tenant dispatch, or Maestro passing `context: { agent: self }` so its runtime can call back. Omit it (defaults to empty) when nothing downstream reads context.
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
### Seeding conversation history
|
|
26
|
+
|
|
27
|
+
The hash carries the agent **definition**, not its conversation history (see [What does not transfer](#what-does-not-transfer)). To resume a persisted conversation, pass a `session:` — exactly the value you'd pass to `Agent.new(session:)`:
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
rebuilt = Riffer::Agent.from_h(data, session: persisted_session)
|
|
31
|
+
rebuilt.generate # continues from the seeded history
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The session is used **as-is**: the rebuilt agent does not prepend anything to it, so the caller owns its full contents — **including the system instruction message**. Omit `session:` and the rebuilt agent builds a fresh session, seeded with the hash's `instructions` and an empty history. Because a supplied session is authoritative, the hash's `instructions` are not re-injected into it — make sure your persisted session already contains the system message.
|
|
35
|
+
|
|
36
|
+
## What the hash carries
|
|
26
37
|
|
|
27
38
|
```ruby
|
|
28
39
|
{
|
|
@@ -41,7 +52,7 @@ The hash forms (`to_h` / `from_h`) are public too, if you want to embed the dict
|
|
|
41
52
|
|
|
42
53
|
### Resolved snapshot
|
|
43
54
|
|
|
44
|
-
`to_h` reads the agent's **resolved** state, not its raw configuration. By the time you call it, `Agent.new` has already evaluated any `Proc`-based `model`, `instructions`, or `uses_tools` against the agent's own context — so the
|
|
55
|
+
`to_h` reads the agent's **resolved** state, not its raw configuration. By the time you call it, `Agent.new` has already evaluated any `Proc`-based `model`, `instructions`, or `uses_tools` against the agent's own context — so the hash carries plain strings and data, never Procs. The receiver's `context:` drives runtime behavior (tool dispatch); it does **not** re-evaluate baked-in fields.
|
|
45
56
|
|
|
46
57
|
### Structured output
|
|
47
58
|
|
|
@@ -56,7 +67,7 @@ Tools cross as `{name, description, parameters_schema, timeout}` descriptors —
|
|
|
56
67
|
When the rebuilt agent runs in the **same** codebase that defined the tools (e.g. persisting an agent definition and rehydrating it later), resolve each descriptor back to its real class:
|
|
57
68
|
|
|
58
69
|
```ruby
|
|
59
|
-
rebuilt = Riffer::Agent.from_h(
|
|
70
|
+
rebuilt = Riffer::Agent.from_h(data,
|
|
60
71
|
tool_resolver: ->(descriptor) { MyToolRegistry.fetch(descriptor[:name]) })
|
|
61
72
|
```
|
|
62
73
|
|
|
@@ -67,7 +78,7 @@ The real classes carry their `#call` bodies, so the agent runs on the default `I
|
|
|
67
78
|
When the receiver holds **only the Riffer gem**, the default `tool_resolver` synthesizes body-less **tool shells**. A shell advertises the tool's schema to the LLM but has no `#call` — invoking it in-process raises. Pair the default resolver with a remote `Riffer::Tools::Runtime` that forwards each call back to the origin:
|
|
68
79
|
|
|
69
80
|
```ruby
|
|
70
|
-
rebuilt = Riffer::Agent.from_h(
|
|
81
|
+
rebuilt = Riffer::Agent.from_h(data,
|
|
71
82
|
tool_runtime: MyRemoteToolRuntime.new(client: rpc_client))
|
|
72
83
|
```
|
|
73
84
|
|
|
@@ -77,12 +88,12 @@ You own what a resolved tool does: a resolver may return real in-process classes
|
|
|
77
88
|
|
|
78
89
|
## `max_steps`
|
|
79
90
|
|
|
80
|
-
Unlimited steps are `nil` at the agent level — set it with `max_steps nil`. On the wire, the serializer encodes that as **`-1`** (and decodes `-1` back to `nil`), so the
|
|
91
|
+
Unlimited steps are `nil` at the agent level — set it with `max_steps nil`. On the wire, the serializer encodes that as **`-1`** (and decodes `-1` back to `nil`), so the hash stays portable across transports where JSON `null` is awkward — proto3, for one, can't distinguish `null` from an absent field. The `-1` is purely a wire detail: the DSL and your code only ever see `nil`, and the encode/decode handles the translation at the boundary.
|
|
81
92
|
|
|
82
93
|
- **DSL** — integer = bounded, `nil` = unlimited, omitted = `Config`'s default (16).
|
|
83
94
|
- **Wire** — integer = bounded, `-1` = unlimited, omitted = default (16).
|
|
84
95
|
|
|
85
|
-
A finite integer round-trips as-is; a
|
|
96
|
+
A finite integer round-trips as-is; a hash missing the key falls back to the default rather than running unbounded.
|
|
86
97
|
|
|
87
98
|
## Versioning
|
|
88
99
|
|
|
@@ -90,7 +101,7 @@ A finite integer round-trips as-is; a dict missing the key falls back to the def
|
|
|
90
101
|
|
|
91
102
|
## Secrets
|
|
92
103
|
|
|
93
|
-
`provider_options` and `model_options` **ride on the wire as plain data** — they are part of the
|
|
104
|
+
`provider_options` and `model_options` **ride on the wire as plain data** — they are part of the hash and _will_ transfer. Prefer configuring API keys via environment/global provider configuration rather than `provider_options`. **Never serialize an agent whose options carry sensitive values** — and if a serialized definition ever does, handle it as a secret (encrypt it, keep it out of logs).
|
|
94
105
|
|
|
95
106
|
## What does **not** transfer
|
|
96
107
|
|
|
@@ -83,6 +83,20 @@ model_options additional_model_request_fields: {
|
|
|
83
83
|
}
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
+
### cache_control
|
|
87
|
+
|
|
88
|
+
Enable prompt caching for models that support it (Claude, Nova). Riffer appends a single Converse `cachePoint` to the stable prefix — after the system array, or after the tools when there is no system prompt — so system instructions and tool definitions are reused across the calls in an agent loop and across conversation turns. The volatile message tail is never cached.
|
|
89
|
+
|
|
90
|
+
```ruby
|
|
91
|
+
# 5-minute TTL (default)
|
|
92
|
+
model_options cache_control: {type: "ephemeral"}
|
|
93
|
+
|
|
94
|
+
# 1-hour TTL (model-dependent; Bedrock validates support)
|
|
95
|
+
model_options cache_control: {type: "ephemeral", ttl: "1h"}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Caching is opt-in: omit `cache_control` and no cachePoint is sent. The breakpoint is only honored once the prefix clears the model's minimum token count; on models that don't support `cachePoint`, the Converse request errors. Verify hits via `response.token_usage.cache_read_tokens`.
|
|
99
|
+
|
|
86
100
|
## Example
|
|
87
101
|
|
|
88
102
|
```ruby
|
data/lib/riffer/agent/config.rb
CHANGED
|
@@ -2,38 +2,49 @@
|
|
|
2
2
|
# rbs_inline: enabled
|
|
3
3
|
|
|
4
4
|
# Typed configuration object holding every class-level DSL setting on a
|
|
5
|
-
# Riffer::Agent subclass.
|
|
6
|
-
#
|
|
7
|
-
# Each subclass of Riffer::Agent owns one Config, accessible via the class
|
|
8
|
-
# method <tt>config</tt>. The class-level DSL (+model+, +instructions+, +uses_tools+,
|
|
9
|
-
# etc.) reads and mutates this Config in place. Append-style DSL methods
|
|
10
|
-
# (+use_mcp+, +guardrail+) are handled by the +add_mcp+ and +add_guardrail+
|
|
11
|
-
# helpers below.
|
|
12
|
-
#
|
|
13
|
-
# Config stores Procs unresolved. Per-instance resolution happens elsewhere
|
|
14
|
-
# (instructions, model, tools, tool runtime, skills).
|
|
5
|
+
# Riffer::Agent subclass. Procs are stored unresolved and resolved per-instance
|
|
6
|
+
# later.
|
|
15
7
|
class Riffer::Agent::Config
|
|
16
8
|
DEFAULT_MAX_STEPS = 16 #: Integer
|
|
17
9
|
|
|
10
|
+
# The configured agent identifier.
|
|
18
11
|
attr_reader :identifier #: String?
|
|
12
|
+
|
|
13
|
+
# The configured model.
|
|
19
14
|
attr_reader :model #: (String | Proc)?
|
|
15
|
+
|
|
16
|
+
# The configured instructions.
|
|
20
17
|
attr_reader :instructions #: (String | Proc)?
|
|
18
|
+
|
|
19
|
+
# Options passed to the provider client.
|
|
21
20
|
attr_accessor :provider_options #: Hash[Symbol, untyped]
|
|
21
|
+
|
|
22
|
+
# Options passed to generate_text/stream_text.
|
|
22
23
|
attr_accessor :model_options #: Hash[Symbol, untyped]
|
|
24
|
+
|
|
25
|
+
# The configured structured-output schema.
|
|
23
26
|
attr_reader :structured_output #: Riffer::Params?
|
|
27
|
+
|
|
28
|
+
# The maximum number of LLM call steps in the tool-use loop.
|
|
24
29
|
attr_accessor :max_steps #: Numeric?
|
|
30
|
+
|
|
31
|
+
# The configured tools.
|
|
25
32
|
attr_accessor :tools_config #: (Array[singleton(Riffer::Tool)] | Proc)?
|
|
33
|
+
|
|
34
|
+
# The accumulated +use_mcp+ tag configurations.
|
|
26
35
|
attr_reader :mcp_configs #: Array[Hash[Symbol, untyped]]
|
|
36
|
+
|
|
37
|
+
# The configured tool runtime.
|
|
27
38
|
attr_reader :tool_runtime #: (singleton(Riffer::Tools::Runtime) | Riffer::Tools::Runtime | Proc)
|
|
39
|
+
|
|
40
|
+
# The configured skills.
|
|
28
41
|
attr_accessor :skills_config #: Riffer::Skills::Config?
|
|
42
|
+
|
|
43
|
+
# Registered guardrail entries keyed by phase.
|
|
29
44
|
attr_reader :guardrails #: Hash[Symbol, Array[Hash[Symbol, untyped]]]
|
|
30
45
|
|
|
31
|
-
# Builds a new Config.
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
# Raises Riffer::ArgumentError if +model+ or +instructions+ is provided
|
|
35
|
-
# as a non-String, non-Proc value (or as an empty String).
|
|
36
|
-
#
|
|
46
|
+
# Builds a new Config. Raises Riffer::ArgumentError if +model+ or
|
|
47
|
+
# +instructions+ is invalid (e.g. an empty string).
|
|
37
48
|
#--
|
|
38
49
|
#: (?identifier: String?, ?model: (String | Proc)?, ?instructions: (String | Proc)?, ?provider_options: Hash[Symbol, untyped], ?model_options: Hash[Symbol, untyped], ?structured_output: Riffer::Params?, ?max_steps: Numeric?, ?tools_config: (Array[singleton(Riffer::Tool)] | Proc)?, ?mcp_configs: Array[Hash[Symbol, untyped]], ?tool_runtime: (singleton(Riffer::Tools::Runtime) | Riffer::Tools::Runtime | Proc), ?skills_config: Riffer::Skills::Config?, ?guardrails: Hash[Symbol, Array[Hash[Symbol, untyped]]]) -> void
|
|
39
50
|
def initialize(
|
|
@@ -64,18 +75,14 @@ class Riffer::Agent::Config
|
|
|
64
75
|
self.tool_runtime = tool_runtime
|
|
65
76
|
end
|
|
66
77
|
|
|
67
|
-
# Sets +identifier
|
|
68
|
-
#
|
|
78
|
+
# Sets +identifier+, coercing the value to String.
|
|
69
79
|
#--
|
|
70
80
|
#: (untyped) -> String?
|
|
71
81
|
def identifier=(value)
|
|
72
82
|
@identifier = value&.to_s
|
|
73
83
|
end
|
|
74
84
|
|
|
75
|
-
# Sets +structured_output+.
|
|
76
|
-
#
|
|
77
|
-
# Raises Riffer::ArgumentError on any other type.
|
|
78
|
-
#
|
|
85
|
+
# Sets +structured_output+. Raises Riffer::ArgumentError on an invalid value.
|
|
79
86
|
#--
|
|
80
87
|
#: (Riffer::Params?) -> Riffer::Params?
|
|
81
88
|
def structured_output=(value)
|
|
@@ -83,11 +90,7 @@ class Riffer::Agent::Config
|
|
|
83
90
|
@structured_output = value
|
|
84
91
|
end
|
|
85
92
|
|
|
86
|
-
# Sets +tool_runtime+.
|
|
87
|
-
# Riffer::Tools::Runtime instance, or a Proc.
|
|
88
|
-
#
|
|
89
|
-
# Raises Riffer::ArgumentError on any other type.
|
|
90
|
-
#
|
|
93
|
+
# Sets +tool_runtime+. Raises Riffer::ArgumentError on an invalid value.
|
|
91
94
|
#--
|
|
92
95
|
#: ((singleton(Riffer::Tools::Runtime) | Riffer::Tools::Runtime | Proc)) -> (singleton(Riffer::Tools::Runtime) | Riffer::Tools::Runtime | Proc)
|
|
93
96
|
def tool_runtime=(value)
|
|
@@ -96,10 +99,8 @@ class Riffer::Agent::Config
|
|
|
96
99
|
@tool_runtime = value
|
|
97
100
|
end
|
|
98
101
|
|
|
99
|
-
# Sets +model+.
|
|
100
|
-
#
|
|
101
|
-
# Raises Riffer::ArgumentError on non-String, non-Proc, or empty-String values.
|
|
102
|
-
#
|
|
102
|
+
# Sets +model+. Raises Riffer::ArgumentError on an invalid value (e.g. an
|
|
103
|
+
# empty string).
|
|
103
104
|
#--
|
|
104
105
|
#: ((String | Proc)?) -> (String | Proc)?
|
|
105
106
|
def model=(value)
|
|
@@ -107,10 +108,8 @@ class Riffer::Agent::Config
|
|
|
107
108
|
@model = value
|
|
108
109
|
end
|
|
109
110
|
|
|
110
|
-
# Sets +instructions+.
|
|
111
|
-
#
|
|
112
|
-
# Raises Riffer::ArgumentError on non-String, non-Proc, or empty-String values.
|
|
113
|
-
#
|
|
111
|
+
# Sets +instructions+. Raises Riffer::ArgumentError on an invalid value (e.g.
|
|
112
|
+
# an empty string).
|
|
114
113
|
#--
|
|
115
114
|
#: ((String | Proc)?) -> (String | Proc)?
|
|
116
115
|
def instructions=(value)
|
|
@@ -121,20 +120,15 @@ class Riffer::Agent::Config
|
|
|
121
120
|
# Appends an MCP tag entry to +mcp_configs+.
|
|
122
121
|
#
|
|
123
122
|
#--
|
|
124
|
-
#: (String | Symbol) -> Array[Hash[Symbol, untyped]]
|
|
125
|
-
def add_mcp(tag)
|
|
126
|
-
|
|
123
|
+
#: (String | Symbol, ?progressive: bool) -> Array[Hash[Symbol, untyped]]
|
|
124
|
+
def add_mcp(tag, progressive: true)
|
|
125
|
+
raise Riffer::ArgumentError, "progressive must be a boolean" unless progressive == true || progressive == false
|
|
126
|
+
@mcp_configs << {tags: [tag.to_sym], progressive: progressive}
|
|
127
127
|
end
|
|
128
128
|
|
|
129
|
-
# Appends a guardrail entry to +guardrails+ for the given phase
|
|
130
|
-
#
|
|
131
|
-
#
|
|
132
|
-
# +:before+ and +:after+.
|
|
133
|
-
# [klass] the Riffer::Guardrail subclass to register.
|
|
134
|
-
# [options] options forwarded to the guardrail at runtime.
|
|
135
|
-
#
|
|
136
|
-
# Raises Riffer::ArgumentError on an invalid phase or non-Guardrail class.
|
|
137
|
-
#
|
|
129
|
+
# Appends a guardrail entry to +guardrails+ for the given phase; +:around+
|
|
130
|
+
# appends to both +:before+ and +:after+. Raises Riffer::ArgumentError unless
|
|
131
|
+
# +phase+ is :before, :after, or :around.
|
|
138
132
|
#--
|
|
139
133
|
#: (Symbol, klass: singleton(Riffer::Guardrail), ?options: Hash[Symbol, untyped]) -> void
|
|
140
134
|
def add_guardrail(phase, klass:, options: {})
|
|
@@ -164,6 +158,7 @@ class Riffer::Agent::Config
|
|
|
164
158
|
|
|
165
159
|
private
|
|
166
160
|
|
|
161
|
+
#--
|
|
167
162
|
#: (untyped, String) -> void
|
|
168
163
|
def validate_string_or_proc!(value, name)
|
|
169
164
|
return if value.nil? || value.is_a?(Proc)
|