Class: Verica::RubyOpenAIWrapper::StreamAccumulator

Inherits:
Object
  • Object
show all
Defined in:
lib/verica/ruby_openai_wrapper.rb

Overview

Drains a ruby-openai stream (parsed Hashes, string keys) into the pieces the span needs: the joined assistant text, the first non-nil model, the assistant role from the first delta that carries one, the usage Hash from the final chunk (present only when the caller asks for it), and the reassembled tool calls. Tool-call deltas carry an index: id/type/ function.name come from the first fragment that has them; the argument fragments concatenate in arrival order into one JSON string per index.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeStreamAccumulator

Returns a new instance of StreamAccumulator.



227
228
229
230
231
232
233
# File 'lib/verica/ruby_openai_wrapper.rb', line 227

def initialize
  @content = +''
  @model = nil
  @role = nil
  @usage = nil
  @tool_call_parts = {}
end

Instance Attribute Details

#contentObject (readonly)

Returns the value of attribute content.



225
226
227
# File 'lib/verica/ruby_openai_wrapper.rb', line 225

def content
  @content
end

#modelObject (readonly)

Returns the value of attribute model.



225
226
227
# File 'lib/verica/ruby_openai_wrapper.rb', line 225

def model
  @model
end

#roleObject (readonly)

Returns the value of attribute role.



225
226
227
# File 'lib/verica/ruby_openai_wrapper.rb', line 225

def role
  @role
end

#usageObject (readonly)

Returns the value of attribute usage.



225
226
227
# File 'lib/verica/ruby_openai_wrapper.rb', line 225

def usage
  @usage
end

Instance Method Details

#add(chunk) ⇒ Object



235
236
237
238
239
240
241
242
243
244
245
246
247
248
# File 'lib/verica/ruby_openai_wrapper.rb', line 235

def add(chunk)
  return unless chunk.is_a?(Hash)

  @model ||= chunk['model']
  delta = chunk.dig('choices', 0, 'delta')
  if delta.is_a?(Hash)
    @role ||= delta['role']
    fragment = delta['content']
    @content << fragment if fragment.is_a?(String)
    add_tool_call_fragments(delta['tool_calls'])
  end
  usage = chunk['usage']
  @usage = usage if usage.is_a?(Hash)
end

#tool_callsObject

The reassembled tool calls, ordered by index, in the pinned semconv shape ({function: {name, arguments}}, arguments as one JSON string). Indexes that never produced a function name are dropped.



253
254
255
256
257
258
259
260
261
# File 'lib/verica/ruby_openai_wrapper.rb', line 253

def tool_calls
  @tool_call_parts.keys.sort.filter_map do |index|
    part = @tool_call_parts[index]
    name = part['name']
    next unless name.is_a?(String) && !name.empty?

    { function: { name: name, arguments: part['arguments'] } }
  end
end