Class: Pikuri::Testing::Script
- Inherits:
-
Object
- Object
- Pikuri::Testing::Script
- Defined in:
- lib/pikuri/testing.rb
Overview
Collects the scripted conversation: each verb appends one OpenAI-wire response body to #responses, in call order. You don't build these directly — fake_transport yields one to your block.
fake_transport do |llm|
llm.reply('hi') # plain answer
llm.tool_call('calculator', expression: '2+2') # a tool turn
llm.stream('The ', 'answer ', 'is ', '4.') # a streamed answer
end
Instance Attribute Summary collapse
-
#responses ⇒ Array<Hash>
readonly
Queued response entries in call order.
Instance Method Summary collapse
-
#initialize ⇒ Script
constructor
A new instance of Script.
-
#reply(text) ⇒ self
Queue a plain assistant-text turn (the model's final answer for that step).
-
#stream(*deltas) ⇒ self
Queue a streamed assistant-text turn: each
deltabecomes one SSE chunk, so astreaming: trueagent emits a matching sequence of Agent::Event::AssistantDeltas and a final assembled Agent::Event::Assistant. -
#tool_batch(*calls) ⇒ self
Queue an assistant turn that calls several tools at once — one
tool_callsarray, the shape a provider sends when the model batches. -
#tool_call(name, **arguments) ⇒ self
Queue an assistant turn that calls one tool.
Constructor Details
#initialize ⇒ Script
Returns a new instance of Script.
145 146 147 148 |
# File 'lib/pikuri/testing.rb', line 145 def initialize @responses = [] @tool_call_seq = 0 end |
Instance Attribute Details
#responses ⇒ Array<Hash> (readonly)
Returns queued response entries in call order.
143 144 145 |
# File 'lib/pikuri/testing.rb', line 143 def responses @responses end |
Instance Method Details
#reply(text) ⇒ self
Queue a plain assistant-text turn (the model's final answer for that step).
155 156 157 158 |
# File 'lib/pikuri/testing.rb', line 155 def reply(text) @responses << { json: assistant_body(content: text) } self end |
#stream(*deltas) ⇒ self
Queue a streamed assistant-text turn: each delta becomes one SSE
chunk, so a streaming: true agent emits a matching sequence of
Agent::Event::AssistantDeltas and a final assembled
Agent::Event::Assistant. Text only — tool-call streaming is not
modelled.
209 210 211 212 213 214 215 216 217 218 |
# File 'lib/pikuri/testing.rb', line 209 def stream(*deltas) chunks = deltas.map do |d| "data: #{JSON.generate('model' => 'fake', 'choices' => [{ 'delta' => { 'content' => d } }])}\n\n" end chunks << "data: #{JSON.generate('model' => 'fake', 'choices' => [{ 'delta' => {} }], 'usage' => usage)}\n\n" chunks << "data: [DONE]\n\n" @responses << { sse: chunks } self end |
#tool_batch(*calls) ⇒ self
Queue an assistant turn that calls several tools at once — one
tool_calls array, the shape a provider sends when the model batches.
ruby_llm runs them in order, each answered by its own :tool message.
llm.tool_batch(['calculator', { expression: '1 + 1' }],
['calculator', { expression: '2 + 2' }])
What a spec needs to exercise anything treating a batch as a unit — the interloper's drain boundary, or which call a mid-batch unwind blames.
188 189 190 191 192 193 194 195 196 |
# File 'lib/pikuri/testing.rb', line 188 def tool_batch(*calls) wire = calls.map do |name, arguments| @tool_call_seq += 1 { 'id' => "call_#{@tool_call_seq}", 'type' => 'function', 'function' => { 'name' => name, 'arguments' => JSON.generate(arguments || {}) } } end @responses << { json: assistant_body(content: nil, tool_calls: wire) } self end |
#tool_call(name, **arguments) ⇒ self
Queue an assistant turn that calls one tool. The real ruby_llm loop parses it, runs the real registered tool, appends the observation, and re-requests — so the next queued entry is the model's follow-up.
171 172 173 |
# File 'lib/pikuri/testing.rb', line 171 def tool_call(name, **arguments) tool_batch([name, arguments]) end |