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 166 def self.all subclasses #: Array[singleton(Riffer::Agent)] end
Returns all agent subclasses.
Source
# File lib/riffer/agent.rb, line 25 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 158 def self.find(identifier) all.find { |agent_class| agent_class.identifier == identifier.to_s } end
Finds an agent class by identifier.
Source
# File lib/riffer/agent.rb, line 187 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 194 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 173 def self.generate(prompt = nil, files: nil, context: nil) new(context: context).generate(prompt, files: files) end
Generates a response using a new agent instance.
Source
# File lib/riffer/agent.rb, line 202 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 209 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 33 def self.identifier(value = nil) value.nil? ? (config.identifier || Riffer::Helpers::ClassNameConverter.convert(name)) : (config.identifier = value) end
Gets or sets the agent identifier.
Source
# File lib/riffer/agent.rb, line 56 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 98 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 122 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 41 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 72 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 264 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 64 def self.provider_options(options = nil) options.nil? ? config.provider_options : (config.provider_options = options) end
Gets or sets provider options passed to the provider client.
Source
# File lib/riffer/agent.rb, line 145 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 180 def self.stream(prompt = nil, files: nil, context: nil) new(context: context).stream(prompt, files: files) end
Streams a response using a new agent instance.
Source
# File lib/riffer/agent.rb, line 79 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 130 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 115 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 107 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 293 def generate(prompt = nil, files: nil) Riffer::Agent::Run.generate(agent: self, prompt: prompt, files: files) 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.
Source
# File lib/riffer/agent.rb, line 313 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 304 def stream(prompt = nil, files: nil) raise Riffer::ArgumentError, "Structured output is not supported with streaming. Use #generate instead." if @structured_output Riffer::Agent::Run.stream(agent: self, prompt: prompt, files: files) end
Streams a response from the agent, returning an Enumerator of Riffer::StreamEvents. See generate for prompt/files semantics.
Raises Riffer::ArgumentError if structured output is configured.
Source
# File lib/riffer/agent.rb, line 321 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 329 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.