Module: Miniswen::Testing

Defined in:
lib/miniswen/testing.rb

Overview

Test support for callers driving Miniswen::Agent without a real provider: a "test" model family resolving through ruby_llm's real path, an in-process FakeEnv shell, and stub_llm/llm_answer helpers on top of RubyLLM::Test's response queue. Include into a Minitest case; stubs reset before each test.

Defined Under Namespace

Modules: FindTestModels Classes: FakeEnv, Provider, RawResponse

Constant Summary collapse

PRICED_MODEL =

$20/M input (fresh and cached) and $400/M output price the default answer (95 fresh + 5 cached input tokens, 20 output tokens) at exactly $0.01.

RubyLLM::Model::Info.new(
  id: "test", name: "Test", provider: "test",
  capabilities: %w[function_calling],
  modalities: { input: %w[text], output: %w[text] },
  pricing: { text_tokens: { standard: {
    input_per_million: 20.0, cached_input_per_million: 20.0, output_per_million: 400.0
  } } }
)
UNPRICED_MODEL =
RubyLLM::Model::Info.new(
  id: "test-unpriced", name: "Test unpriced", provider: "test",
  capabilities: %w[function_calling],
  modalities: { input: %w[text], output: %w[text] }
)
MODELS =
{ PRICED_MODEL.id => PRICED_MODEL, UNPRICED_MODEL.id => UNPRICED_MODEL }.freeze
SUBMIT =
{ content: "Done.", cmd: "echo #{Agent::SUBMIT_MARKER}" }.freeze

Instance Method Summary collapse

Instance Method Details

#before_setupObject



81
82
83
84
# File 'lib/miniswen/testing.rb', line 81

def before_setup
  super
  RubyLLM::Test.reset
end

#llm_answer(answer, **overrides) ⇒ Object

Raises:

  • (ArgumentError)


93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/miniswen/testing.rb', line 93

def llm_answer(answer, **overrides)
  answer = { cmd: answer } if answer.is_a?(String)
  answer = answer.merge(overrides)
  raise ArgumentError, "an answer needs :cmd or :content" unless answer[:cmd] || answer[:content]

  calls = tool_calls_for(answer)
  RubyLLM::Message.new(
    role: :assistant,
    content: answer.fetch(:content, "Let me try."),
    tool_calls: calls,
    thinking: answer[:thinking] && RubyLLM::Thinking.new(text: answer[:thinking],
                                                         signature: answer[:thinking_signature]),
    input_tokens: answer.fetch(:input_tokens, 95),
    output_tokens: answer.fetch(:output_tokens, 20),
    cached_tokens: answer.fetch(:cached_tokens, 5),
    thinking_tokens: answer[:thinking] && 40,
    raw: RawResponse.new(body: raw_body_for(answer, calls))
  )
end

#stub_llm(*answers, **overrides) ⇒ Object

Each answer is a command string, or a hash with :cmd (one command or many) and/or :content, plus optional overrides (:tool_calls, :finish_reason, :thinking, token counts). Overrides given here apply to every answer.



89
90
91
# File 'lib/miniswen/testing.rb', line 89

def stub_llm(*answers, **overrides)
  RubyLLM::Test.stub_responses(*answers.map { llm_answer(_1, **overrides) })
end