class Riffer::Agent
Base class for all agents in the Riffer framework. Subclass it to define an agent’s model, instructions, tools, and guardrails.
class MyAgent < Riffer::Agent model 'openai/gpt-4o' instructions 'You are a helpful assistant.' end agent = MyAgent.new agent.generate('Hello!')
Constants
- INTERRUPT_MAX_STEPS
-
@rbs self.@config: Riffer::Agent::Config?
Attributes
The per-instance Riffer::Agent::Config.
The mutable runtime context shared with every Riffer::Agent::Run this agent executes and threaded through all Proc-based settings.
The system message built from the configured instructions, or nil when none are configured.
The resolved model name (the part after “/” in the model string), used as the model argument on every LLM call.
The provider client. Public so tests can pre-queue responses on Riffer::Providers::Mock before calling generate.
The resolved provider name (the part before “/” in the model string), e.g. +“openai”+.
The conversation handle.
The system message describing the configured skills catalog, or nil when skills are unconfigured or the catalog is empty.
The Riffer::Agent::StructuredOutput wrapping the configured schema, or nil when not configured.
The tool runtime instance used to execute tool calls.
The tool classes the LLM sees on every call this agent makes.
Public Class Methods
Source
# File lib/riffer/agent.rb, line 27 def self.config @config ||= Riffer::Agent::Config.new end
Returns the per-class Riffer::Agent::Config holding every DSL setting.
Source
# File lib/riffer/agent.rb, line 166 def self.from_h( hash, context: nil, session: nil, tool_resolver: Riffer::Agent::Serializer::DEFAULT_TOOL_RESOLVER, tool_runtime: nil ) Riffer::Agent::Serializer.from_h( hash, context: context, session: session, tool_resolver: tool_resolver, tool_runtime: tool_runtime, ) end
Reconstructs a runnable agent from a wire hash produced by to_h.
Source
# File lib/riffer/agent.rb, line 185 def self.from_json( json, context: nil, session: nil, tool_resolver: Riffer::Agent::Serializer::DEFAULT_TOOL_RESOLVER, tool_runtime: nil ) Riffer::Agent::Serializer.from_json( json, context: context, session: session, tool_resolver: tool_resolver, tool_runtime: tool_runtime, ) end
Reconstructs a runnable agent from a JSON string produced by to_json.
Source
# File lib/riffer/agent.rb, line 152 def self.generate(prompt = nil, files: nil, context: nil, tags: {}) new(context: context).generate(prompt, files: files, tags: tags) end
Generates a response using a new agent instance.
Source
# File lib/riffer/agent.rb, line 205 def self.guardrail(phase, with:, **options) config.add_guardrail(phase, klass: with, options: options) end
Registers a guardrail for input, output, or both phases. Raises Riffer::ArgumentError unless phase is :before, :after, or :around.
Source
# File lib/riffer/agent.rb, line 212 def self.guardrails_for(phase) config.guardrails_for(phase) end
Returns the registered guardrail configs for a given phase.
Source
# File lib/riffer/agent.rb, line 35 def self.identifier(value = nil) value.nil? ? (config.identifier || Riffer::Helpers::Identifier.for(self)) : (config.identifier = value) end
Gets or sets the agent identifier.
Source
# File lib/riffer/agent.rb, line 58 def self.instructions(value = nil) value.nil? ? config.instructions : (config.instructions = value) end
Gets or sets the agent instructions. A Proc is called at generate time with the context hash (which may be nil).
instructions "You are a helpful assistant." instructions -> (context) { "You are assisting #{context[:name]}" }
Source
# File lib/riffer/agent.rb, line 92 def self.max_steps(*value) return config.max_steps if value.empty? config.max_steps = value.first end
Gets or sets the maximum number of LLM call steps in the tool-use loop. The splat distinguishes a getter (no argument) from setting the limit to nil (unlimited); it defaults to Riffer::Agent::Config::DEFAULT_MAX_STEPS.
max_steps # reads the current limit max_steps 8 # cap the loop at 8 steps max_steps nil # unlimited
Source
# File lib/riffer/agent.rb, line 117 def self.mcp_configs config.mcp_configs end
Returns the accumulated +use_mcp+ configurations for this agent class.
: () -> Array[Hash[Symbol, untyped]]
Source
# File lib/riffer/agent.rb, line 43 def self.model(value = nil) value.nil? ? config.model : (config.model = value) end
Gets or sets the model string (e.g., “openai/gpt-4o”).
Source
# File lib/riffer/agent.rb, line 66 def self.model_options(options = nil) options.nil? ? config.model_options : (config.model_options = options) end
Gets or sets model options passed to generate_text/stream_text.
Source
# File lib/riffer/agent.rb, line 267 def initialize(session: nil, context: nil, config: nil) @config = config || self.class.config @context = Riffer::Agent::Context.new(context || {}) @provider_name, @model_name = resolve_provider_and_model @provider = build_provider @context.skills = resolve_skills @structured_output = resolve_structured_output @tools = resolve_tools @tool_runtime = resolve_tool_runtime @instruction_message = build_instruction_message @skills_message = build_skills_message @session = session || Riffer::Agent::Session.new(messages: [@instruction_message, @skills_message].compact) @session.set(Riffer::Agent::Session::Repair.prune_orphans(@session.messages)) end
Initializes a new agent.
A provided session: is used as-is — the caller owns its contents (e.g. cross-process resume from persisted history); an omitted one is seeded with the instruction and skills messages.
Raises Riffer::ArgumentError unless the configured model string is “provider/model” format.
Source
# File lib/riffer/agent.rb, line 140 def self.skills(&block) if block skills_config = Riffer::Skills::Config.new skills_config.instance_eval(&block) config.skills_config = skills_config end config.skills_config end
Configures skills for this agent via a block DSL, or returns the current Riffer::Skills::Config when called without a block.
skills do backend Riffer::Skills::FilesystemBackend.new(".skills") adapter Riffer::Skills::XmlAdapter activate ["code-review"] end
Source
# File lib/riffer/agent.rb, line 159 def self.stream(prompt = nil, files: nil, context: nil, tags: {}) new(context: context).stream(prompt, files: files, tags: tags) end
Streams a response using a new agent instance.
Source
# File lib/riffer/agent.rb, line 73 def self.structured_output(params = nil, &block) if block params = Riffer::Params.new params.instance_eval(&block) end config.structured_output = params if params config.structured_output end
Gets or sets the structured output schema for this agent.
Source
# File lib/riffer/agent.rb, line 125 def self.tool_runtime(value = nil) value.nil? ? config.tool_runtime : (config.tool_runtime = value) end
Gets or sets the tool runtime for this agent; defaults to Riffer.config.tool_runtime when unset.
Source
# File lib/riffer/agent.rb, line 110 def self.use_mcp(tag, progressive: true) config.add_mcp(tag, progressive: progressive) end
Opts this agent into MCP tools from registrations matching the given tag. Progressive registrations expose +mcp_search+ instead of every schema up front.
: (String | Symbol, ?progressive: bool) -> void
Source
# File lib/riffer/agent.rb, line 102 def self.uses_tools(value = nil) value.nil? ? config.tools_config : (config.tools_config = value) end
Gets or sets the tools used by this agent.
Public Instance Methods
Source
# File lib/riffer/agent.rb, line 303 def generate(prompt = nil, files: nil, tags: {}) Riffer::Agent::Run.generate(agent: self, prompt: prompt, files: files, tags: tags) end
Generates a response from the agent.
With prompt, a new user message is appended (silently — on_message does not fire for user inputs) before the loop runs. Without it, the loop runs against the current session, resuming a persisted conversation or pending tool calls. files: requires prompt.
tags: is an optional flat hash of attribution tags applied to this single call: they propagate to the provider’s native request-metadata field, and are stamped as riffer.tag.* on every span the call emits. See docs/AGENTS.md for the per-provider mapping. The reserved key user_id also maps to the provider’s native user identifier where one exists.
Source
# File lib/riffer/agent.rb, line 327 def interrupt!(reason = nil) throw :riffer_interrupt, reason end
Interrupts the agent loop from an on_message callback. Equivalent to throw :riffer_interrupt, reason.
Source
# File lib/riffer/agent.rb, line 314 def stream(prompt = nil, files: nil, tags: {}) if @structured_output raise Riffer::ArgumentError, "Structured output is not supported with streaming. Use #generate instead." end Riffer::Agent::Run.stream(agent: self, prompt: prompt, files: files, tags: tags) end
Streams a response from the agent, returning an Enumerator of Riffer::StreamEvents. See generate for prompt/files/tags semantics.
Raises Riffer::ArgumentError if structured output is configured.
Source
# File lib/riffer/agent.rb, line 335 def to_h Riffer::Agent::Serializer.to_h(agent: self) end
Snapshots this resolved agent into a self-contained, provider-neutral wire hash.
Source
# File lib/riffer/agent.rb, line 343 def to_json(*) Riffer::Agent::Serializer.to_json(agent: self) end
Snapshots this resolved agent into a wire JSON string. The +*+ absorbs the JSON generator state argument so JSON.generate(agent) works too.