Module: RubyLLM::Providers::OpenRouter::Streaming

Included in:
RubyLLM::Providers::OpenRouter
Defined in:
lib/ruby_llm/providers/openrouter/streaming.rb

Overview

Streaming methods of the OpenRouter API integration

Class Method Summary collapse

Class Method Details

.build_chunk(data) ⇒ Object



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/ruby_llm/providers/openrouter/streaming.rb', line 14

def build_chunk(data)
  usage = data['usage'] || {}
  cached_tokens = usage.dig('prompt_tokens_details', 'cached_tokens')
  delta = data.dig('choices', 0, 'delta') || {}

  Chunk.new(
    role: :assistant,
    model_id: data['model'],
    content: delta['content'],
    thinking: Thinking.build(
      text: extract_thinking_text(delta),
      signature: extract_thinking_signature(delta)
    ),
    tool_calls: OpenAI::Tools.parse_tool_calls(delta['tool_calls'], parse_arguments: false),
    input_tokens: usage['prompt_tokens'],
    output_tokens: usage['completion_tokens'],
    cached_tokens: cached_tokens,
    cache_creation_tokens: 0,
    thinking_tokens: usage.dig('completion_tokens_details', 'reasoning_tokens')
  )
end

.extract_thinking_signature(delta) ⇒ Object



59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/ruby_llm/providers/openrouter/streaming.rb', line 59

def extract_thinking_signature(delta)
  details = delta['reasoning_details']
  return nil unless details.is_a?(Array)

  signature = details.filter_map do |detail|
    detail['signature'] if detail['signature'].is_a?(String)
  end.first
  return signature if signature

  encrypted = details.find { |detail| detail['type'] == 'reasoning.encrypted' && detail['data'].is_a?(String) }
  encrypted&.dig('data')
end

.extract_thinking_text(delta) ⇒ Object



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/ruby_llm/providers/openrouter/streaming.rb', line 40

def extract_thinking_text(delta)
  candidate = delta['reasoning']
  return candidate if candidate.is_a?(String)

  details = delta['reasoning_details']
  return nil unless details.is_a?(Array)

  text = details.filter_map do |detail|
    case detail['type']
    when 'reasoning.text'
      detail['text']
    when 'reasoning.summary'
      detail['summary']
    end
  end.join

  text.empty? ? nil : text
end

.parse_streaming_error(data) ⇒ Object



36
37
38
# File 'lib/ruby_llm/providers/openrouter/streaming.rb', line 36

def parse_streaming_error(data)
  OpenAI::Streaming.parse_streaming_error(data)
end

.stream_urlObject



10
11
12
# File 'lib/ruby_llm/providers/openrouter/streaming.rb', line 10

def stream_url
  completion_url
end