Providers · 08
Mock Provider
The Mock provider is a mock provider for testing agents without making real API calls.
Usage
No additional gems required. Use the mock provider identifier:
class TestableAgent < Riffer::Agent
model 'mock/any' # The model name doesn't matter for mock provider
instructions 'You are helpful.'
uses_tools [MyTool]
end
Stubbing Responses
Use stub_response to queue responses:
# Get the provider instance from the agent
agent = TestableAgent.new
provider = agent.send(:provider_instance)
# Stub a simple text response
provider.stub_response("Hello, I'm here to help!")
# Now generate will return the stubbed response
response = agent.generate("Hi")
# => "Hello, I'm here to help!"
Stubbing Tool Calls
Stub responses that trigger tool execution:
provider.stub_response("", tool_calls: [
{name: "my_tool", arguments: '{"query":"test"}'}
])
# Queue the response after tool execution
provider.stub_response("Based on the tool result, here's my answer.")
response = agent.generate("Use the tool")
Queueing Multiple Responses
Responses are consumed in order:
provider.stub_response("First response")
provider.stub_response("Second response")
provider.stub_response("Third response")
agent.generate("Message 1") # => "First response"
agent.generate("Message 2") # => "Second response"
agent.generate("Message 3") # => "Third response"
agent.generate("Message 4") # => "Mock response" (default)
Inspecting Calls
Access recorded calls for assertions:
provider.calls
# => [
# {messages: [...], model: "any", tools: [...], ...},
# {messages: [...], model: "any", tools: [...], ...}
# ]
# Check what was sent
expect(provider.calls.last[:messages].last[:content]).to eq("Hi")
Clearing State
Reset stubbed responses:
provider.clear_stubs
Example Test
require 'minitest/autorun'
class MyAgentTest < Minitest::Test
def setup
@agent = TestableAgent.new
@provider = @agent.send(:provider_instance)
end
def test_generates_response
@provider.stub_response("Hello!")
response = @agent.generate("Hi")
assert_equal "Hello!", response.content
end
def test_executes_tool
@provider.stub_response("", tool_calls: [
{name: "weather_tool", arguments: '{"city":"Tokyo"}'}
])
@provider.stub_response("The weather is sunny.")
response = @agent.generate("What's the weather?")
assert_equal "The weather is sunny.", response.content
assert_equal 2, @provider.calls.length
end
def test_passes_context_to_tools
@provider.stub_response("", tool_calls: [
{name: "user_tool", arguments: '{}'}
])
@provider.stub_response("Done.")
agent = TestableAgent.new(context: {user_id: 123})
agent.generate("Do something")
# Tool receives the context
end
end
Streaming
The mock provider also supports streaming:
provider.stub_response("Hello world.")
events = []
agent.stream("Hi").each { |e| events << e }
# Events include TextDelta and TextDone
text_deltas = events.select { |e| e.is_a?(Riffer::StreamEvents::TextDelta) }
text_done = events.find { |e| e.is_a?(Riffer::StreamEvents::TextDone) }
Web Search
The test provider emits web search events when web_search: true is passed to the stream call:
provider.stub_response("Here are the latest results.")
events = []
agent.stream("What's new in Ruby?", web_search: true).each { |e| events << e }
# Events include WebSearchStatus and WebSearchDone before text events
search_deltas = events.select { |e| e.is_a?(Riffer::StreamEvents::WebSearchStatus) }
search_done = events.find { |e| e.is_a?(Riffer::StreamEvents::WebSearchDone) }
search_done.query # => "test search query"
search_done.sources # => [{title: "Example", url: "https://example.com"}]
Initial Responses
Pass responses during initialization:
provider = Riffer::Providers::Mock.new(responses: [
{content: "First"},
{content: "Second"}
])
Default Response
When no stubs are queued and initial responses are exhausted, the provider returns:
{role: "assistant", content: "Mock response"}