Class: Riffer::Providers::Mock
- Defined in:
- lib/riffer/providers/mock.rb,
sig/generated/riffer/providers/mock.rbs
Overview
Mock provider for mocking LLM responses in tests; no external gems required.
Constant Summary
Constants inherited from Base
Base::REQUEST_PARAM_ATTRIBUTES, Base::WIRE_SEPARATOR
Instance Attribute Summary collapse
-
#calls ⇒ Array[Hash[Symbol, untyped]]
readonly
Array of recorded method calls for assertions.
Class Method Summary collapse
-
.semconv_provider_name ⇒ String
The GenAI semconv well-known provider name.
-
.skills_adapter(model = nil) ⇒ singleton(Riffer::Skills::Adapter)
Returns the skill adapter for the mock model — XML when the model name contains
claude(mirroring a real Claude provider), else Markdown.
Instance Method Summary collapse
-
#build_request_params(messages, model, options) ⇒ Hash[Symbol, untyped]
-- : (Array, String?, Hash[Symbol, untyped]) -> Hash[Symbol, untyped].
-
#clear_stubs ⇒ void
Clears all stubbed responses.
-
#execute_generate(params) ⇒ Hash[Symbol, untyped]
-- : (Hash[Symbol, untyped]) -> Hash[Symbol, untyped].
-
#execute_stream(params, yielder) ⇒ void
-- : (Hash[Symbol, untyped], Riffer::Providers::_EventSink) -> void.
-
#extract_content(response) ⇒ String
-- : (untyped) -> String.
-
#extract_finish_reason(response) ⇒ Riffer::Providers::FinishReason?
-- : (untyped) -> Riffer::Providers::FinishReason?.
-
#extract_token_usage(response) ⇒ Riffer::Providers::TokenUsage?
-- : (untyped) -> Riffer::Providers::TokenUsage?.
-
#extract_tool_calls(response) ⇒ Array[Riffer::Messages::Assistant::ToolCall]
-- : (untyped) -> Array.
-
#initialize(responses: []) ⇒ Mock
constructor
responses:pre-configures canned responses (same shape as#stub_response) for standalone use; agent tests queue responses on agent.provider via#stub_responseinstead. -
#next_response ⇒ Hash[Symbol, untyped]
-- : () -> Hash[Symbol, untyped].
-
#normalize_response(response) ⇒ Hash[Symbol, untyped]
-- : (Hash[Symbol, untyped]) -> Hash[Symbol, untyped].
-
#stub_response(content, tool_calls: [], token_usage: nil, finish_reason: nil) ⇒ void
Stubs the next response; call repeatedly to queue several.
Methods inherited from Base
#apply_pricing, #build_client, #capture_input, #capture_messages?, #capture_output, #chat_span_attributes, #client, #decode_tool_name, #depends_on, #encode_tool_name, #generate_text, #global_client, #in_chat_span, #merge_consecutive_messages, #normalize_messages, #parse_structured_output, #parse_tool_arguments, #pricing_rates, #record_finish_reason, #record_stream_outcome, #stream_text, #tag_attributes, #validate_input!, #validate_normalized_messages!, #yield_finish_reason
Constructor Details
#initialize(responses: []) ⇒ Mock
responses: pre-configures canned responses (same shape as
#stub_response) for standalone use; agent tests queue responses on
agent.provider via #stub_response instead.
Riffer::Providers::Mock.new(responses: [
{content: "", tool_calls: [{name: "tool_a", arguments: "{}"}]},
{content: "Final answer"}
])
-- : (?responses: Array[Hash[Symbol, untyped]]) -> void
41 42 43 44 45 46 47 |
# File 'lib/riffer/providers/mock.rb', line 41 def initialize(responses: []) super() @responses = responses.map { |r| normalize_response(r) } @current_index = 0 @calls = [] @stubbed_responses = [] end |
Instance Attribute Details
#calls ⇒ Array[Hash[Symbol, untyped]] (readonly)
Array of recorded method calls for assertions.
28 29 30 |
# File 'lib/riffer/providers/mock.rb', line 28 def calls @calls end |
Class Method Details
.semconv_provider_name ⇒ String
The GenAI semconv well-known provider name.
: () -> String
23 24 25 |
# File 'lib/riffer/providers/mock.rb', line 23 def self.semconv_provider_name "mock" end |
.skills_adapter(model = nil) ⇒ singleton(Riffer::Skills::Adapter)
Returns the skill adapter for the mock model — XML when the model name
contains claude (mirroring a real Claude provider), else Markdown.
: (?String?) -> singleton(Riffer::Skills::Adapter)
14 15 16 17 18 |
# File 'lib/riffer/providers/mock.rb', line 14 def self.skills_adapter(model = nil) return Riffer::Skills::XmlAdapter if model&.include?("claude") Riffer::Skills::MarkdownAdapter end |
Instance Method Details
#build_request_params(messages, model, options) ⇒ Hash[Symbol, untyped]
-- : (Array, String?, Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
102 103 104 105 106 107 108 |
# File 'lib/riffer/providers/mock.rb', line 102 def build_request_params(, model, ) web_search = [:web_search] @calls << { messages: .map(&:to_h), model: model, **.except(:web_search) } response = next_response response[:web_search] = web_search if web_search { response: response } end |
#clear_stubs ⇒ void
This method returns an undefined value.
Clears all stubbed responses.
-- : () -> void
73 74 75 |
# File 'lib/riffer/providers/mock.rb', line 73 def clear_stubs @stubbed_responses = [] end |
#execute_generate(params) ⇒ Hash[Symbol, untyped]
-- : (Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
112 113 114 |
# File 'lib/riffer/providers/mock.rb', line 112 def execute_generate(params) params[:response] end |
#execute_stream(params, yielder) ⇒ void
This method returns an undefined value.
-- : (Hash[Symbol, untyped], Riffer::Providers::_EventSink) -> void
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/riffer/providers/mock.rb', line 146 def execute_stream(params, yielder) response = params[:response] full_content = response[:content] || "" tool_calls = response[:tool_calls] || [] token_usage = response[:token_usage] web_search = response[:web_search] if web_search yielder << Riffer::StreamEvents::WebSearchStatus.new("in_progress") yielder << Riffer::StreamEvents::WebSearchStatus.new("searching", query: "mock search query") yielder << Riffer::StreamEvents::WebSearchStatus.new("open_page", url: "https://example.com") yielder << Riffer::StreamEvents::WebSearchStatus.new("completed") yielder << Riffer::StreamEvents::WebSearchDone.new( "mock search query", sources: [{ title: "Example", url: "https://example.com" }], ) end unless full_content.empty? content_parts = full_content.split(". ").map { |part| part + (part.end_with?(".") ? "" : ".") } content_parts.each do |part| yielder << Riffer::StreamEvents::TextDelta.new("#{part} ") end end tool_calls.each do |tc| yielder << Riffer::StreamEvents::ToolCallDelta.new( item_id: tc.call_id, name: tc.name, arguments_delta: tc.arguments, ) yielder << Riffer::StreamEvents::ToolCallDone.new( item_id: tc.call_id, call_id: tc.call_id, name: tc.name, arguments: tc.arguments, ) end yielder << Riffer::StreamEvents::TextDone.new(full_content) yield_finish_reason(yielder, extract_finish_reason(response)) yielder << Riffer::StreamEvents::TokenUsageDone.new(token_usage: apply_pricing(token_usage)) if token_usage end |
#extract_content(response) ⇒ String
-- : (untyped) -> String
134 135 136 |
# File 'lib/riffer/providers/mock.rb', line 134 def extract_content(response) response.is_a?(Hash) ? (response[:content] || "") : response.content end |
#extract_finish_reason(response) ⇒ Riffer::Providers::FinishReason?
-- : (untyped) -> Riffer::Providers::FinishReason?
125 126 127 128 129 130 |
# File 'lib/riffer/providers/mock.rb', line 125 def extract_finish_reason(response) return nil unless response.is_a?(Hash) reason = response[:finish_reason] reason ? Riffer::Providers::FinishReason.new(reason: reason) : nil end |
#extract_token_usage(response) ⇒ Riffer::Providers::TokenUsage?
-- : (untyped) -> Riffer::Providers::TokenUsage?
118 119 120 121 |
# File 'lib/riffer/providers/mock.rb', line 118 def extract_token_usage(response) usage = response[:token_usage] usage && apply_pricing(usage) end |
#extract_tool_calls(response) ⇒ Array[Riffer::Messages::Assistant::ToolCall]
-- : (untyped) -> Array
140 141 142 |
# File 'lib/riffer/providers/mock.rb', line 140 def extract_tool_calls(response) response.is_a?(Hash) ? (response[:tool_calls] || []) : response.tool_calls end |
#next_response ⇒ Hash[Symbol, untyped]
-- : () -> Hash[Symbol, untyped]
192 193 194 195 196 197 198 199 200 201 202 |
# File 'lib/riffer/providers/mock.rb', line 192 def next_response if @stubbed_responses.any? @stubbed_responses.shift elsif @current_index < @responses.size response = @responses[@current_index] @current_index += 1 response else normalize_response(content: "Mock response") end end |
#normalize_response(response) ⇒ Hash[Symbol, untyped]
-- : (Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/riffer/providers/mock.rb', line 81 def normalize_response(response) formatted_tool_calls = (response[:tool_calls] || []).map.with_index do |tc, idx| next tc if tc.is_a?(Riffer::Messages::Assistant::ToolCall) Riffer::Messages::Assistant::ToolCall.new( call_id: tc[:call_id] || tc[:id] || "mock_call_#{idx}", name: tc[:name], arguments: tc[:arguments].is_a?(String) ? tc[:arguments] : tc[:arguments].to_json, ) end { role: response[:role] || "assistant", content: response[:content] || "", tool_calls: formatted_tool_calls, token_usage: response[:token_usage], finish_reason: response[:finish_reason] || (formatted_tool_calls.empty? ? :stop : :tool_calls), } end |
#stub_response(content, tool_calls: [], token_usage: nil, finish_reason: nil) ⇒ void
This method returns an undefined value.
Stubs the next response; call repeatedly to queue several. finish_reason
defaults to :tool_calls when tool calls are present, else :stop.
provider.stub_response("Hello")
provider.stub_response("", tool_calls: [{name: "my_tool", arguments: '{"key":"value"}'}])
provider.stub_response("Final response",
token_usage: Riffer::Providers::TokenUsage.new(input_tokens: 10, output_tokens: 5))
provider.stub_response("Truncated...", finish_reason: :length)
-- : (String, ?tool_calls: Array[Hash[Symbol, untyped]], ?token_usage: Riffer::Providers::TokenUsage?, ?finish_reason: Symbol?) -> void
60 61 62 63 64 65 66 67 |
# File 'lib/riffer/providers/mock.rb', line 60 def stub_response(content, tool_calls: [], token_usage: nil, finish_reason: nil) @stubbed_responses << normalize_response( content: content, tool_calls: tool_calls, token_usage: token_usage, finish_reason: finish_reason, ) end |