Class: Terret::OpenRouter::Accumulator
- Inherits:
-
Object
- Object
- Terret::OpenRouter::Accumulator
- Defined in:
- lib/terret/openrouter/accumulator.rb
Overview
Accumulates parsed streaming chunks into vocabulary StreamEvents and the final assistant Message. Tool-call argument fragments are gathered per index; the calls close on finalize. Pure, no I/O.
Constant Summary collapse
- STOP_REASONS =
{ "stop" => :end_turn, "tool_calls" => :tool_use, "length" => :length, "error" => :error }.freeze
Instance Attribute Summary collapse
-
#error ⇒ Object
readonly
Returns the value of attribute error.
Instance Method Summary collapse
- #feed(chunk) ⇒ Object
- #finalize {|LLM::MessageStop.new(stop_reason: STOP_REASONS.fetch(@stop, :end_turn))| ... } ⇒ Object
-
#initialize ⇒ Accumulator
constructor
A new instance of Accumulator.
Constructor Details
#initialize ⇒ Accumulator
Returns a new instance of Accumulator.
18 19 20 21 22 23 |
# File 'lib/terret/openrouter/accumulator.rb', line 18 def initialize @text = +"" @calls = {} # index => { id:, name:, args: +"" } @stop = nil @error = nil end |
Instance Attribute Details
#error ⇒ Object (readonly)
Returns the value of attribute error.
16 17 18 |
# File 'lib/terret/openrouter/accumulator.rb', line 16 def error @error end |
Instance Method Details
#feed(chunk) ⇒ Object
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/terret/openrouter/accumulator.rb', line 25 def feed(chunk) if (err = chunk[:error]) @error = LLM::StreamError.new(message: err[:message], code: err[:code]) yield @error end if (usage = chunk[:usage]) yield LLM::Usage.new(prompt_tokens: usage[:prompt_tokens], completion_tokens: usage[:completion_tokens], cost: usage[:cost]) end choice = chunk[:choices]&.first or return @stop = choice[:finish_reason] if choice[:finish_reason] delta = choice[:delta] or return if (text = delta[:content]) && !text.empty? @text << text yield LLM::TextDelta.new(text: text) end Array(delta[:tool_calls]).each { |tc| accumulate_call(tc) } nil end |
#finalize {|LLM::MessageStop.new(stop_reason: STOP_REASONS.fetch(@stop, :end_turn))| ... } ⇒ Object
46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/terret/openrouter/accumulator.rb', line 46 def finalize parts = [] parts << LLM::Text.new(text: @text) unless @text.empty? @calls.keys.sort.each do |index| slot = @calls[index] args = slot[:args].empty? ? {} : JSON.parse(slot[:args], symbolize_names: true) call = LLM::ToolCall.new(id: slot[:id], name: slot[:name], args: args) yield LLM::ToolCallEnd.new(tool_call: call) parts << call end yield LLM::MessageStop.new(stop_reason: STOP_REASONS.fetch(@stop, :end_turn)) LLM::Message.new(role: :assistant, parts: parts) end |