riffer 0.31.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 +18 -0
- data/docs/08_MESSAGES.md +1 -1
- data/docs/14_MCP.md +50 -5
- 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 +22 -81
- 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 +74 -192
- 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 +21 -80
- 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 +57 -186
- 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
|
@@ -3,16 +3,10 @@
|
|
|
3
3
|
|
|
4
4
|
require "json"
|
|
5
5
|
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
# params = Riffer::Params.new
|
|
10
|
-
# params.required(:sentiment, String)
|
|
11
|
-
# so = Riffer::Agent::StructuredOutput.new(params)
|
|
12
|
-
# result = so.parse_and_validate('{"sentiment":"positive","score":0.9}')
|
|
13
|
-
# result.object #=> {sentiment: "positive", score: 0.9}
|
|
14
|
-
#
|
|
6
|
+
# Parses and validates structured JSON responses against a Riffer::Params
|
|
7
|
+
# schema.
|
|
15
8
|
class Riffer::Agent::StructuredOutput
|
|
9
|
+
# The schema parameters.
|
|
16
10
|
attr_reader :params #: Riffer::Params
|
|
17
11
|
|
|
18
12
|
#--
|
|
@@ -29,10 +23,8 @@ class Riffer::Agent::StructuredOutput
|
|
|
29
23
|
@params.to_json_schema(strict: strict)
|
|
30
24
|
end
|
|
31
25
|
|
|
32
|
-
# Parses a JSON string and validates it against the schema
|
|
33
|
-
#
|
|
34
|
-
# Returns a Result with the validated object on success, or an error message on failure.
|
|
35
|
-
#
|
|
26
|
+
# Parses a JSON string and validates it against the schema, returning a
|
|
27
|
+
# Result carrying either the validated object or an error message.
|
|
36
28
|
#--
|
|
37
29
|
#: (String) -> Riffer::Agent::StructuredOutput::Result
|
|
38
30
|
def parse_and_validate(json_string)
|
data/lib/riffer/agent.rb
CHANGED
|
@@ -3,12 +3,8 @@
|
|
|
3
3
|
|
|
4
4
|
require "json"
|
|
5
5
|
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
# Provides orchestration for LLM calls, tool use, and message management.
|
|
9
|
-
# Subclass this to create your own agents.
|
|
10
|
-
#
|
|
11
|
-
# See Riffer::Messages and Riffer::Providers.
|
|
6
|
+
# Base class for all agents in the Riffer framework. Subclass it to define an
|
|
7
|
+
# agent's model, instructions, tools, and guardrails.
|
|
12
8
|
#
|
|
13
9
|
# class MyAgent < Riffer::Agent
|
|
14
10
|
# model 'openai/gpt-4o'
|
|
@@ -21,14 +17,9 @@ require "json"
|
|
|
21
17
|
class Riffer::Agent
|
|
22
18
|
# @rbs self.@config: Riffer::Agent::Config?
|
|
23
19
|
|
|
24
|
-
include Riffer::Messages::Converter
|
|
25
|
-
extend Riffer::Helpers::ClassNameConverter
|
|
26
|
-
|
|
27
20
|
INTERRUPT_MAX_STEPS = :max_steps #: Symbol
|
|
28
21
|
|
|
29
|
-
# Returns the per-class Riffer::Agent::Config
|
|
30
|
-
# DSL setting. Lazily initialized on first read; each subclass has its own.
|
|
31
|
-
#
|
|
22
|
+
# Returns the per-class Riffer::Agent::Config holding every DSL setting.
|
|
32
23
|
#--
|
|
33
24
|
#: () -> Riffer::Agent::Config
|
|
34
25
|
def self.config
|
|
@@ -40,10 +31,10 @@ class Riffer::Agent
|
|
|
40
31
|
#--
|
|
41
32
|
#: (?String?) -> String
|
|
42
33
|
def self.identifier(value = nil)
|
|
43
|
-
value.nil? ? (config.identifier ||
|
|
34
|
+
value.nil? ? (config.identifier || Riffer::Helpers::ClassNameConverter.convert(name)) : (config.identifier = value)
|
|
44
35
|
end
|
|
45
36
|
|
|
46
|
-
# Gets or sets the model string (e.g., "openai/gpt-4o")
|
|
37
|
+
# Gets or sets the model string (e.g., "openai/gpt-4o").
|
|
47
38
|
#
|
|
48
39
|
#--
|
|
49
40
|
#: (?(String | Proc)?) -> (String | Proc)?
|
|
@@ -51,10 +42,7 @@ class Riffer::Agent
|
|
|
51
42
|
value.nil? ? config.model : (config.model = value)
|
|
52
43
|
end
|
|
53
44
|
|
|
54
|
-
# Gets or sets the agent instructions.
|
|
55
|
-
#
|
|
56
|
-
# Accepts a static string or a Proc for dynamic instructions.
|
|
57
|
-
# When a Proc is given, it is called at generate time and receives
|
|
45
|
+
# Gets or sets the agent instructions. A Proc is called at generate time with
|
|
58
46
|
# the +context+ hash (which may be +nil+).
|
|
59
47
|
#
|
|
60
48
|
# instructions "You are a helpful assistant."
|
|
@@ -86,9 +74,6 @@ class Riffer::Agent
|
|
|
86
74
|
end
|
|
87
75
|
|
|
88
76
|
# Gets or sets the structured output schema for this agent.
|
|
89
|
-
#
|
|
90
|
-
# Accepts a Riffer::Params instance or a block evaluated against a new Params.
|
|
91
|
-
#
|
|
92
77
|
#--
|
|
93
78
|
#: (?Riffer::Params?) ?{ (Riffer::Params) [self: Riffer::Params] -> void } -> Riffer::Params?
|
|
94
79
|
def self.structured_output(params = nil, &block)
|
|
@@ -101,10 +86,8 @@ class Riffer::Agent
|
|
|
101
86
|
end
|
|
102
87
|
|
|
103
88
|
# Gets or sets the maximum number of LLM call steps in the tool-use loop.
|
|
104
|
-
#
|
|
105
|
-
#
|
|
106
|
-
# for unlimited steps. The splat distinguishes a getter call (no argument)
|
|
107
|
-
# from setting the limit to +nil+.
|
|
89
|
+
# The splat distinguishes a getter (no argument) from setting the limit to
|
|
90
|
+
# +nil+ (unlimited); it defaults to Riffer::Agent::Config::DEFAULT_MAX_STEPS.
|
|
108
91
|
#
|
|
109
92
|
# max_steps # reads the current limit
|
|
110
93
|
# max_steps 8 # cap the loop at 8 steps
|
|
@@ -125,14 +108,12 @@ class Riffer::Agent
|
|
|
125
108
|
value.nil? ? config.tools_config : (config.tools_config = value)
|
|
126
109
|
end
|
|
127
110
|
|
|
128
|
-
# Opts this agent into tools from
|
|
129
|
-
#
|
|
130
|
-
#
|
|
131
|
-
# +tag+ - a String or Symbol; matched against registration manifest tags.
|
|
111
|
+
# Opts this agent into MCP tools from registrations matching the given tag.
|
|
112
|
+
# Progressive registrations expose +mcp_search+ instead of every schema up front.
|
|
132
113
|
#
|
|
133
|
-
#: (String | Symbol) -> void
|
|
134
|
-
def self.use_mcp(tag)
|
|
135
|
-
config.add_mcp(tag)
|
|
114
|
+
#: (String | Symbol, ?progressive: bool) -> void
|
|
115
|
+
def self.use_mcp(tag, progressive: true)
|
|
116
|
+
config.add_mcp(tag, progressive: progressive)
|
|
136
117
|
end
|
|
137
118
|
|
|
138
119
|
# Returns the accumulated +use_mcp+ configurations for this agent class.
|
|
@@ -142,20 +123,16 @@ class Riffer::Agent
|
|
|
142
123
|
config.mcp_configs
|
|
143
124
|
end
|
|
144
125
|
|
|
145
|
-
# Gets or sets the tool runtime for this agent
|
|
146
|
-
#
|
|
147
|
-
# Accepts a Riffer::Tools::Runtime subclass, a Riffer::Tools::Runtime instance,
|
|
148
|
-
# or a Proc. Defaults to <tt>Riffer.config.tool_runtime</tt> when unset.
|
|
149
|
-
#
|
|
126
|
+
# Gets or sets the tool runtime for this agent; defaults to
|
|
127
|
+
# <tt>Riffer.config.tool_runtime</tt> when unset.
|
|
150
128
|
#--
|
|
151
129
|
#: (?(singleton(Riffer::Tools::Runtime) | Riffer::Tools::Runtime | Proc)?) -> (singleton(Riffer::Tools::Runtime) | Riffer::Tools::Runtime | Proc)
|
|
152
130
|
def self.tool_runtime(value = nil)
|
|
153
131
|
value.nil? ? config.tool_runtime : (config.tool_runtime = value)
|
|
154
132
|
end
|
|
155
133
|
|
|
156
|
-
# Configures skills for this agent via a block DSL
|
|
157
|
-
#
|
|
158
|
-
# Returns the current Riffer::Skills::Config when called without a block.
|
|
134
|
+
# Configures skills for this agent via a block DSL, or returns the current
|
|
135
|
+
# Riffer::Skills::Config when called without a block.
|
|
159
136
|
#
|
|
160
137
|
# skills do
|
|
161
138
|
# backend Riffer::Skills::FilesystemBackend.new(".skills")
|
|
@@ -191,10 +168,6 @@ class Riffer::Agent
|
|
|
191
168
|
end
|
|
192
169
|
|
|
193
170
|
# Generates a response using a new agent instance.
|
|
194
|
-
#
|
|
195
|
-
# +context:+ is threaded into +new+; +prompt+ and +files:+ are forwarded
|
|
196
|
-
# to +#generate+.
|
|
197
|
-
#
|
|
198
171
|
#--
|
|
199
172
|
#: (?String?, ?files: Array[Hash[Symbol, untyped] | Riffer::Messages::FilePart]?, ?context: Hash[Symbol, untyped]?) -> Riffer::Agent::Response
|
|
200
173
|
def self.generate(prompt = nil, files: nil, context: nil)
|
|
@@ -202,10 +175,6 @@ class Riffer::Agent
|
|
|
202
175
|
end
|
|
203
176
|
|
|
204
177
|
# Streams a response using a new agent instance.
|
|
205
|
-
#
|
|
206
|
-
# +context:+ is threaded into +new+; +prompt+ and +files:+ are forwarded
|
|
207
|
-
# to +#stream+.
|
|
208
|
-
#
|
|
209
178
|
#--
|
|
210
179
|
#: (?String?, ?files: Array[Hash[Symbol, untyped] | Riffer::Messages::FilePart]?, ?context: Hash[Symbol, untyped]?) -> Enumerator[Riffer::StreamEvents::Base, void]
|
|
211
180
|
def self.stream(prompt = nil, files: nil, context: nil)
|
|
@@ -213,11 +182,6 @@ class Riffer::Agent
|
|
|
213
182
|
end
|
|
214
183
|
|
|
215
184
|
# Reconstructs a runnable agent from a wire hash produced by +#to_h+.
|
|
216
|
-
#
|
|
217
|
-
# Delegates to Riffer::Agent::Serializer.from_h. See it for the +session+
|
|
218
|
-
# seed, the +tool_resolver+ / +tool_runtime+ injection points, and what does
|
|
219
|
-
# not transfer.
|
|
220
|
-
#
|
|
221
185
|
#--
|
|
222
186
|
#: (Hash[Symbol, untyped], ?context: Hash[Symbol, untyped]?, ?session: Riffer::Agent::Session?, ?tool_resolver: ^(Hash[Symbol, untyped]) -> singleton(Riffer::Tool), ?tool_runtime: (singleton(Riffer::Tools::Runtime) | Riffer::Tools::Runtime | Proc)?) -> Riffer::Agent
|
|
223
187
|
def self.from_h(hash, context: nil, session: nil, tool_resolver: Riffer::Agent::Serializer::DEFAULT_TOOL_RESOLVER, tool_runtime: nil)
|
|
@@ -225,24 +189,14 @@ class Riffer::Agent
|
|
|
225
189
|
end
|
|
226
190
|
|
|
227
191
|
# Reconstructs a runnable agent from a JSON string produced by +#to_json+.
|
|
228
|
-
#
|
|
229
|
-
# Delegates to Riffer::Agent::Serializer.from_json, which parses the JSON
|
|
230
|
-
# (with symbol keys) for you. See Riffer::Agent::Serializer.from_h for the
|
|
231
|
-
# +session+ seed and the +tool_resolver+ / +tool_runtime+ injection points.
|
|
232
|
-
#
|
|
233
192
|
#--
|
|
234
193
|
#: (String, ?context: Hash[Symbol, untyped]?, ?session: Riffer::Agent::Session?, ?tool_resolver: ^(Hash[Symbol, untyped]) -> singleton(Riffer::Tool), ?tool_runtime: (singleton(Riffer::Tools::Runtime) | Riffer::Tools::Runtime | Proc)?) -> Riffer::Agent
|
|
235
194
|
def self.from_json(json, context: nil, session: nil, tool_resolver: Riffer::Agent::Serializer::DEFAULT_TOOL_RESOLVER, tool_runtime: nil)
|
|
236
195
|
Riffer::Agent::Serializer.from_json(json, context: context, session: session, tool_resolver: tool_resolver, tool_runtime: tool_runtime)
|
|
237
196
|
end
|
|
238
197
|
|
|
239
|
-
# Registers a guardrail for input, output, or both phases.
|
|
240
|
-
#
|
|
241
|
-
# [phase] :before, :after, or :around.
|
|
242
|
-
# [with] the guardrail class (must be subclass of Riffer::Guardrail).
|
|
243
|
-
# [options] additional options passed to the guardrail.
|
|
244
|
-
#
|
|
245
|
-
# Raises Riffer::ArgumentError if phase is invalid or guardrail is not a Guardrail class.
|
|
198
|
+
# Registers a guardrail for input, output, or both phases. Raises
|
|
199
|
+
# Riffer::ArgumentError unless +phase+ is :before, :after, or :around.
|
|
246
200
|
#--
|
|
247
201
|
#: (Symbol, with: singleton(Riffer::Guardrail), **untyped) -> void
|
|
248
202
|
def self.guardrail(phase, with:, **options)
|
|
@@ -250,92 +204,60 @@ class Riffer::Agent
|
|
|
250
204
|
end
|
|
251
205
|
|
|
252
206
|
# Returns the registered guardrail configs for a given phase.
|
|
253
|
-
#
|
|
254
|
-
# [phase] :before or :after.
|
|
255
|
-
#
|
|
256
207
|
#--
|
|
257
208
|
#: (Symbol) -> Array[Hash[Symbol, untyped]]
|
|
258
209
|
def self.guardrails_for(phase)
|
|
259
210
|
config.guardrails_for(phase)
|
|
260
211
|
end
|
|
261
212
|
|
|
262
|
-
# The conversation handle.
|
|
213
|
+
# The conversation handle.
|
|
263
214
|
attr_reader :session #: Riffer::Agent::Session
|
|
264
215
|
|
|
265
|
-
# The per-instance Riffer::Agent::Config.
|
|
266
|
-
# an explicit Config passed to +Agent.new(config:)+.
|
|
216
|
+
# The per-instance Riffer::Agent::Config.
|
|
267
217
|
attr_reader :config #: Riffer::Agent::Config
|
|
268
218
|
|
|
269
|
-
# The system message built from the configured +instructions+, or +nil+
|
|
270
|
-
#
|
|
271
|
-
# constructor +context:+ and cached. Useful for persistence flows.
|
|
219
|
+
# The system message built from the configured +instructions+, or +nil+ when
|
|
220
|
+
# none are configured.
|
|
272
221
|
attr_reader :instruction_message #: Riffer::Messages::System?
|
|
273
222
|
|
|
274
|
-
# The system message describing the configured skills catalog, or +nil+
|
|
275
|
-
#
|
|
276
|
-
# +Agent.new+ and cached.
|
|
223
|
+
# The system message describing the configured skills catalog, or +nil+ when
|
|
224
|
+
# skills are unconfigured or the catalog is empty.
|
|
277
225
|
attr_reader :skills_message #: Riffer::Messages::System?
|
|
278
226
|
|
|
279
|
-
# The mutable runtime context
|
|
280
|
-
# threaded
|
|
281
|
-
# and skills resolution, and shared with every +Riffer::Agent::Run+
|
|
282
|
-
# this agent executes. Exposes:
|
|
283
|
-
#
|
|
284
|
-
# - +context.skills+ — the resolved +Riffer::Skills::Context+ (when
|
|
285
|
-
# skills are configured), set at +Agent.new+ time.
|
|
286
|
-
# - +context.token_usage+ — the cumulative +Riffer::Providers::TokenUsage+,
|
|
287
|
-
# updated by each Run as the loop progresses.
|
|
288
|
-
# - +context[:key]+ / <tt>context.dig(:key)</tt> — Hash-style reads for
|
|
289
|
-
# caller-provided keys (e.g. <tt>context[:agent]</tt>,
|
|
290
|
-
# <tt>context[:tenant]</tt>). +:skills+ and +:token_usage+ are
|
|
291
|
-
# reserved and cannot be passed by the caller.
|
|
227
|
+
# The mutable runtime context shared with every +Riffer::Agent::Run+ this
|
|
228
|
+
# agent executes and threaded through all Proc-based settings.
|
|
292
229
|
attr_reader :context #: Riffer::Agent::Context
|
|
293
230
|
|
|
294
|
-
# The resolved provider name (the part before "
|
|
295
|
-
#
|
|
296
|
-
# form the provider-neutral model identifier the agent serializes.
|
|
231
|
+
# The resolved provider name (the part before "/" in the model string),
|
|
232
|
+
# e.g. +"openai"+.
|
|
297
233
|
attr_reader :provider_name #: String
|
|
298
234
|
|
|
299
|
-
# The resolved model name (the part after "
|
|
300
|
-
# argument on every LLM call.
|
|
235
|
+
# The resolved model name (the part after "/" in the model string), used as
|
|
236
|
+
# the model argument on every LLM call.
|
|
301
237
|
attr_reader :model_name #: String
|
|
302
238
|
|
|
303
|
-
# The provider client.
|
|
304
|
-
#
|
|
305
|
-
# +Riffer::Agent::Run+ this agent executes. Public so tests can pre-queue
|
|
306
|
-
# responses on +Riffer::Providers::Mock+ before calling +#generate+.
|
|
239
|
+
# The provider client. Public so tests can pre-queue responses on
|
|
240
|
+
# +Riffer::Providers::Mock+ before calling +#generate+.
|
|
307
241
|
attr_reader :provider #: Riffer::Providers::Base
|
|
308
242
|
|
|
309
|
-
# The +Riffer::Agent::StructuredOutput+ wrapping the configured schema, or
|
|
310
|
-
# when
|
|
243
|
+
# The +Riffer::Agent::StructuredOutput+ wrapping the configured schema, or
|
|
244
|
+
# +nil+ when not configured.
|
|
311
245
|
attr_reader :structured_output #: Riffer::Agent::StructuredOutput?
|
|
312
246
|
|
|
313
|
-
# The tool classes the LLM sees on every call this agent makes.
|
|
314
|
-
# eagerly at +Agent.new+ (Proc-form +uses_tools+ is called against
|
|
315
|
-
# +context+ once; MCP tools and the skill_activate tool are merged in).
|
|
247
|
+
# The tool classes the LLM sees on every call this agent makes.
|
|
316
248
|
attr_reader :tools #: Array[singleton(Riffer::Tool)]
|
|
317
249
|
|
|
318
|
-
# The tool runtime instance used to execute tool calls.
|
|
319
|
-
# at +Agent.new+ (Proc-form +tool_runtime+ is called against +context+ once).
|
|
250
|
+
# The tool runtime instance used to execute tool calls.
|
|
320
251
|
attr_reader :tool_runtime #: Riffer::Tools::Runtime
|
|
321
252
|
|
|
322
253
|
# Initializes a new agent.
|
|
323
254
|
#
|
|
324
|
-
#
|
|
325
|
-
#
|
|
326
|
-
#
|
|
327
|
-
# the caller is responsible for the session's contents (typical use case:
|
|
328
|
-
# cross-process resume from persisted history). With
|
|
329
|
-
# +Riffer.config.experimental_history_healing+ on, a provided session is
|
|
330
|
-
# healed at construction time so the +tool_use+ ↔ +tool_result+ invariant
|
|
331
|
-
# holds before the next inference call.
|
|
255
|
+
# A provided +session:+ is used as-is — the caller owns its contents (e.g.
|
|
256
|
+
# cross-process resume from persisted history); an omitted one is seeded with
|
|
257
|
+
# the instruction and skills messages.
|
|
332
258
|
#
|
|
333
|
-
#
|
|
334
|
-
#
|
|
335
|
-
# lifetime of the agent.
|
|
336
|
-
#
|
|
337
|
-
# Raises Riffer::ArgumentError if the configured model string is invalid
|
|
338
|
-
# (must be "provider/model" format).
|
|
259
|
+
# Raises Riffer::ArgumentError unless the configured model string is
|
|
260
|
+
# "provider/model" format.
|
|
339
261
|
#
|
|
340
262
|
#--
|
|
341
263
|
#: (?session: Riffer::Agent::Session?, ?context: Hash[Symbol, untyped]?, ?config: Riffer::Agent::Config?) -> void
|
|
@@ -361,15 +283,10 @@ class Riffer::Agent
|
|
|
361
283
|
|
|
362
284
|
# Generates a response from the agent.
|
|
363
285
|
#
|
|
364
|
-
#
|
|
365
|
-
#
|
|
366
|
-
#
|
|
367
|
-
#
|
|
368
|
-
# session — useful for resuming a persisted conversation whose last turn
|
|
369
|
-
# is already a user message, or for picking up pending tool calls after
|
|
370
|
-
# an interrupt.
|
|
371
|
-
#
|
|
372
|
-
# +files:+ requires +prompt+. Pass files to attach to the new user message.
|
|
286
|
+
# With +prompt+, a new user message is appended (silently — +on_message+ does
|
|
287
|
+
# not fire for user inputs) before the loop runs. Without it, the loop runs
|
|
288
|
+
# against the current session, resuming a persisted conversation or pending
|
|
289
|
+
# tool calls. +files:+ requires +prompt+.
|
|
373
290
|
#
|
|
374
291
|
#--
|
|
375
292
|
#: (?String?, ?files: Array[Hash[Symbol, untyped] | Riffer::Messages::FilePart]?) -> Riffer::Agent::Response
|
|
@@ -377,15 +294,11 @@ class Riffer::Agent
|
|
|
377
294
|
Riffer::Agent::Run.generate(agent: self, prompt: prompt, files: files)
|
|
378
295
|
end
|
|
379
296
|
|
|
380
|
-
# Streams a response from the agent
|
|
381
|
-
#
|
|
382
|
-
# Runs the inference loop via +Riffer::Agent::Run.stream+, returning an
|
|
383
|
-
# +Enumerator+ of +Riffer::StreamEvents+.
|
|
297
|
+
# Streams a response from the agent, returning an +Enumerator+ of
|
|
298
|
+
# +Riffer::StreamEvents+. See +#generate+ for prompt/files semantics.
|
|
384
299
|
#
|
|
385
300
|
# Raises Riffer::ArgumentError if structured output is configured.
|
|
386
301
|
#
|
|
387
|
-
# See +#generate+ for prompt/files semantics.
|
|
388
|
-
#
|
|
389
302
|
#--
|
|
390
303
|
#: (?String?, ?files: Array[Hash[Symbol, untyped] | Riffer::Messages::FilePart]?) -> Enumerator[Riffer::StreamEvents::Base, void]
|
|
391
304
|
def stream(prompt = nil, files: nil)
|
|
@@ -393,37 +306,24 @@ class Riffer::Agent
|
|
|
393
306
|
Riffer::Agent::Run.stream(agent: self, prompt: prompt, files: files)
|
|
394
307
|
end
|
|
395
308
|
|
|
396
|
-
# Interrupts the agent loop.
|
|
397
|
-
#
|
|
398
|
-
# Call from an +on_message+ callback to cleanly interrupt the loop.
|
|
399
|
-
# Equivalent to <tt>throw :riffer_interrupt, reason</tt>.
|
|
400
|
-
#
|
|
401
|
-
# When +Riffer.config.experimental_history_healing+ is enabled, riffer
|
|
402
|
-
# fills any orphaned +tool_use+ on the way out with a placeholder
|
|
403
|
-
# +Riffer::Messages::Tool+ carrying +error_type: :interrupted+. The
|
|
404
|
-
# filled call_ids are exposed on
|
|
405
|
-
# +Riffer::Agent::Response#healed_tool_call_ids+ (and the streaming
|
|
406
|
-
# +Riffer::StreamEvents::Interrupt+ event).
|
|
407
|
-
#
|
|
309
|
+
# Interrupts the agent loop from an +on_message+ callback. Equivalent to
|
|
310
|
+
# <tt>throw :riffer_interrupt, reason</tt>.
|
|
408
311
|
#--
|
|
409
312
|
#: (?(String | Symbol)?) -> void
|
|
410
313
|
def interrupt!(reason = nil)
|
|
411
314
|
throw :riffer_interrupt, reason
|
|
412
315
|
end
|
|
413
316
|
|
|
414
|
-
# Snapshots this resolved agent into a self-contained, provider-neutral
|
|
415
|
-
#
|
|
416
|
-
#
|
|
317
|
+
# Snapshots this resolved agent into a self-contained, provider-neutral wire
|
|
318
|
+
# hash.
|
|
417
319
|
#--
|
|
418
320
|
#: () -> Hash[Symbol, untyped]
|
|
419
321
|
def to_h
|
|
420
322
|
Riffer::Agent::Serializer.to_h(agent: self)
|
|
421
323
|
end
|
|
422
324
|
|
|
423
|
-
# Snapshots this resolved agent into a wire JSON string.
|
|
424
|
-
#
|
|
425
|
-
# state argument so <tt>JSON.generate(agent)</tt> works too.
|
|
426
|
-
#
|
|
325
|
+
# Snapshots this resolved agent into a wire JSON string. The +*+ absorbs the
|
|
326
|
+
# JSON generator state argument so <tt>JSON.generate(agent)</tt> works too.
|
|
427
327
|
#--
|
|
428
328
|
#: (*untyped) -> String
|
|
429
329
|
def to_json(*)
|
|
@@ -448,12 +348,6 @@ class Riffer::Agent
|
|
|
448
348
|
Riffer::Messages::System.new(skills.system_prompt)
|
|
449
349
|
end
|
|
450
350
|
|
|
451
|
-
# Resolves +Config#model+ to a "provider/model" string (calling the Proc
|
|
452
|
-
# form against +@context+) and parses it.
|
|
453
|
-
#
|
|
454
|
-
# Returns +[provider_name, model_name]+. Raises Riffer::ArgumentError on an
|
|
455
|
-
# invalid model string.
|
|
456
|
-
#
|
|
457
351
|
#--
|
|
458
352
|
#: () -> [String, String]
|
|
459
353
|
def resolve_provider_and_model
|
|
@@ -469,11 +363,6 @@ class Riffer::Agent
|
|
|
469
363
|
[provider_name, model_name]
|
|
470
364
|
end
|
|
471
365
|
|
|
472
|
-
# Builds the provider client from the resolved +@provider_name+ and the
|
|
473
|
-
# configured +provider_options+.
|
|
474
|
-
#
|
|
475
|
-
# Raises Riffer::ArgumentError on an unregistered provider.
|
|
476
|
-
#
|
|
477
366
|
#--
|
|
478
367
|
#: () -> Riffer::Providers::Base
|
|
479
368
|
def build_provider
|
|
@@ -482,9 +371,6 @@ class Riffer::Agent
|
|
|
482
371
|
provider_class.new(**@config.provider_options)
|
|
483
372
|
end
|
|
484
373
|
|
|
485
|
-
# Resolves the skills backend, lists skills, and selects an adapter.
|
|
486
|
-
# Returns nil if skills are unconfigured or the backend is empty.
|
|
487
|
-
#
|
|
488
374
|
#--
|
|
489
375
|
#: () -> Riffer::Skills::Context?
|
|
490
376
|
def resolve_skills
|
|
@@ -522,19 +408,6 @@ class Riffer::Agent
|
|
|
522
408
|
params ? Riffer::Agent::StructuredOutput.new(params) : nil
|
|
523
409
|
end
|
|
524
410
|
|
|
525
|
-
# Resolves the full tool catalog for the agent:
|
|
526
|
-
#
|
|
527
|
-
# - The configured +uses_tools+ value (Proc-form resolved against +context+).
|
|
528
|
-
# - The skill activation tool, when a +skills+ block is configured. The
|
|
529
|
-
# activation tool class comes from the per-agent +skills do; activate_tool ...; end+
|
|
530
|
-
# override when set, otherwise from +Riffer.config.skills.default_activate_tool+.
|
|
531
|
-
# - All MCP tools matching any +use_mcp+ tag, optionally wrapped in
|
|
532
|
-
# AuthenticatedTool when +Riffer.config.mcp.credentials+ is configured.
|
|
533
|
-
#
|
|
534
|
-
# Raises Riffer::ArgumentError on tool name conflicts with the skill
|
|
535
|
-
# activation tool, on duplicate tool names across sources, or on tool
|
|
536
|
-
# classes missing required metadata (description, params).
|
|
537
|
-
#
|
|
538
411
|
#--
|
|
539
412
|
#: () -> Array[singleton(Riffer::Tool)]
|
|
540
413
|
def resolve_tools
|
|
@@ -573,25 +446,35 @@ class Riffer::Agent
|
|
|
573
446
|
|
|
574
447
|
cred = Riffer.config.mcp.credentials
|
|
575
448
|
ctx = @context
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
449
|
+
|
|
450
|
+
regular_reg_tags, progressive_reg_tags = gather_mcp_registrations_with_tags(configs)
|
|
451
|
+
|
|
452
|
+
regular_tools = regular_reg_tags.flat_map { |reg, tag_accum| mcp_tools_for_registration(reg, tag_accum.uniq, cred, ctx) }
|
|
453
|
+
progressive_tools = progressive_reg_tags.flat_map { |reg, tag_accum| mcp_tools_for_registration(reg, tag_accum.uniq, cred, ctx) }
|
|
454
|
+
|
|
455
|
+
if progressive_tools.any?
|
|
456
|
+
@context.mcp_progressive_tools = progressive_tools.freeze
|
|
457
|
+
regular_tools + [Riffer::Mcp::SearchTool]
|
|
458
|
+
else
|
|
459
|
+
regular_tools
|
|
579
460
|
end
|
|
580
461
|
end
|
|
581
462
|
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
#: (Array[Hash[Symbol, untyped]]) -> Hash[Riffer::Mcp::Registration, Array[Symbol]]
|
|
463
|
+
#--
|
|
464
|
+
#: (Array[Hash[Symbol, untyped]]) -> [Hash[Riffer::Mcp::Registration, Array[Symbol]], Hash[Riffer::Mcp::Registration, Array[Symbol]]]
|
|
585
465
|
def gather_mcp_registrations_with_tags(configs)
|
|
586
|
-
|
|
466
|
+
regular = {} #: Hash[Riffer::Mcp::Registration, Array[Symbol]]
|
|
467
|
+
progressive = {} #: Hash[Riffer::Mcp::Registration, Array[Symbol]]
|
|
587
468
|
configs.each do |cfg|
|
|
469
|
+
target = cfg[:progressive] ? progressive : regular
|
|
588
470
|
Riffer::Mcp::Registry.find_by_tags(cfg[:tags]).each do |reg|
|
|
589
|
-
(
|
|
471
|
+
(target[reg] ||= []).concat(cfg[:tags] & reg.manifest.tags)
|
|
590
472
|
end
|
|
591
473
|
end
|
|
592
|
-
|
|
474
|
+
[regular, progressive]
|
|
593
475
|
end
|
|
594
476
|
|
|
477
|
+
#--
|
|
595
478
|
#: (Riffer::Mcp::Registration, Array[Symbol], (^(manifest: Riffer::Mcp::Manifest, matched_tags: Array[Symbol], context: Riffer::Agent::Context) -> Hash[Symbol, untyped]?)?, Riffer::Agent::Context) -> Array[singleton(Riffer::Tool)]
|
|
596
479
|
def mcp_tools_for_registration(reg, matched_tags, cred, ctx)
|
|
597
480
|
return reg.tools unless cred
|
|
@@ -599,8 +482,7 @@ class Riffer::Agent
|
|
|
599
482
|
Riffer::Mcp::AuthenticatedTool.wrap_all(reg.tools, reg.manifest, matched_tags)
|
|
600
483
|
end
|
|
601
484
|
|
|
602
|
-
|
|
603
|
-
#
|
|
485
|
+
#--
|
|
604
486
|
#: (Array[singleton(Riffer::Tool)]) -> void
|
|
605
487
|
def assert_distinct_tool_names!(tool_classes)
|
|
606
488
|
tally = Hash.new(0) #: Hash[String, Integer]
|