Class: RSpec::LLM::Adapters::Fake

Inherits:
Base
  • Object
show all
Defined in:
lib/rspec/llm/adapters/fake.rb

Overview

In-memory programmable adapter. Use in unit-style specs to avoid hitting a real LLM while still exercising matcher and DSL behavior.

fake = RSpec::LLM::Adapters::Fake.new
fake.respond_to("Summarize: foo").with("foo summary")
fake.respond_to_pattern(/^Summarize/).with { |prompt| "summary of #{prompt}" }
fake.default("I don't know")
fake.embed_with { |text| [text.length.to_f, 0.0, 0.0] }

Defined Under Namespace

Classes: Stub, UnstubbedPromptError

Instance Attribute Summary collapse

Attributes inherited from Base

#client

Instance Method Summary collapse

Methods inherited from Base

wrap

Constructor Details

#initialize(client = nil) ⇒ Fake

Returns a new instance of Fake.



35
36
37
38
39
40
41
# File 'lib/rspec/llm/adapters/fake.rb', line 35

def initialize(client = nil)
  super
  @stubs = []
  @default = nil
  @embedder = nil
  @call_log = []
end

Instance Attribute Details

#call_logObject (readonly)

Returns the value of attribute call_log.



43
44
45
# File 'lib/rspec/llm/adapters/fake.rb', line 43

def call_log
  @call_log
end

Instance Method Details

#chat(messages) ⇒ Object



65
66
67
68
69
70
# File 'lib/rspec/llm/adapters/fake.rb', line 65

def chat(messages)
  prompt = last_user_message(normalize_messages(messages))
  @call_log << prompt
  response = lookup(prompt)
  response.is_a?(Proc) ? response.call(prompt) : response
end

#chat_structured(messages, schema: nil) ⇒ Object

Extends #chat with structured-output support for tests. When schema is provided the raw stub value is JSON-parsed; if it produces a Hash it is returned directly so callers receive the same shape that a real structured adapter would deliver. Stubs that are already a Hash are returned unchanged. Non-JSON strings fall back to the plain string so existing YES/NO-style tests continue to work.

When no schema is given the adapter still attempts JSON parsing — this lets tests stub structured JSON responses without needing the RubyLLM::Schema gem loaded.



82
83
84
85
86
87
88
89
90
# File 'lib/rspec/llm/adapters/fake.rb', line 82

def chat_structured(messages, schema: nil) # rubocop:disable Lint/UnusedMethodArgument
  response = chat(messages)
  return response if response.is_a?(Hash)

  parsed = JSON.parse(response.to_s, symbolize_names: true)
  parsed.is_a?(Hash) ? parsed : response
rescue JSON::ParserError
  response
end

#default(text = nil, &block) ⇒ Object

Raises:

  • (ArgumentError)


53
54
55
56
57
58
# File 'lib/rspec/llm/adapters/fake.rb', line 53

def default(text = nil, &block)
  raise ArgumentError, "pass text or a block" if text.nil? && block.nil?

  @default = text || block
  self
end

#embed(text) ⇒ Object

Raises:

  • (NotImplementedError)


92
93
94
95
96
# File 'lib/rspec/llm/adapters/fake.rb', line 92

def embed(text)
  raise NotImplementedError, "configure with #embed_with { |text| vector }" unless @embedder

  @embedder.call(text)
end

#embed_with(&block) ⇒ Object



60
61
62
63
# File 'lib/rspec/llm/adapters/fake.rb', line 60

def embed_with(&block)
  @embedder = block
  self
end

#reset!Object



98
99
100
101
102
103
104
# File 'lib/rspec/llm/adapters/fake.rb', line 98

def reset!
  @stubs.clear
  @default = nil
  @embedder = nil
  @call_log.clear
  self
end

#respond_to(prompt) ⇒ Object



45
46
47
# File 'lib/rspec/llm/adapters/fake.rb', line 45

def respond_to(prompt)
  Stub.new(self, prompt)
end

#respond_to_pattern(regex) ⇒ Object



49
50
51
# File 'lib/rspec/llm/adapters/fake.rb', line 49

def respond_to_pattern(regex)
  Stub.new(self, regex)
end