Module: RubyLLM::Pollinations::Provider::Chat

Included in:
Pollinations
Defined in:
lib/ruby_llm/pollinations/provider/chat.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.extract_content_and_thinking(content) ⇒ Object



94
95
96
97
98
99
100
101
102
# File 'lib/ruby_llm/pollinations/provider/chat.rb', line 94

def extract_content_and_thinking(content)
  return extract_think_tag_content(content) if content.is_a?(String)
  return [content, nil] unless content.is_a?(Array)

  text = extract_text_from_blocks(content)
  thinking = extract_thinking_from_blocks(content)

  [text.empty? ? nil : text, thinking.empty? ? nil : thinking]
end

.extract_text_from_blocks(blocks) ⇒ Object



104
105
106
107
108
# File 'lib/ruby_llm/pollinations/provider/chat.rb', line 104

def extract_text_from_blocks(blocks)
  blocks.filter_map do |block|
    block['text'] if block['type'] == 'text' && block['text'].is_a?(String)
  end.join
end

.extract_think_tag_content(text) ⇒ Object



116
117
118
119
120
121
122
123
# File 'lib/ruby_llm/pollinations/provider/chat.rb', line 116

def extract_think_tag_content(text)
  return [text, nil] unless text.include?('<think>')

  thinking = text.scan(%r{<think>(.*?)</think>}m).join
  content = text.gsub(%r{<think>.*?</think>}m, '').strip

  [content.empty? ? nil : content, thinking.empty? ? nil : thinking]
end

.extract_thinking_from_blocks(blocks) ⇒ Object



110
111
112
113
114
# File 'lib/ruby_llm/pollinations/provider/chat.rb', line 110

def extract_thinking_from_blocks(blocks)
  blocks.filter_map do |block|
    block['thinking'] if block['type'] == 'thinking' && block['thinking'].is_a?(String)
  end.join
end

.extract_thinking_text(message_data) ⇒ Object



89
90
91
92
# File 'lib/ruby_llm/pollinations/provider/chat.rb', line 89

def extract_thinking_text(message_data)
  candidate = message_data['reasoning_content'] || message_data['reasoning'] || message_data['thinking']
  candidate.is_a?(String) ? candidate : nil
end

.format_messages(messages) ⇒ Object



72
73
74
75
76
77
78
79
80
81
# File 'lib/ruby_llm/pollinations/provider/chat.rb', line 72

def format_messages(messages)
  messages.map do |msg|
    {
      role: msg.role.to_s,
      content: Media.format_content(msg.content),
      tool_calls: Tools.format_tool_calls(msg.tool_calls),
      tool_call_id: msg.tool_call_id
    }.compact
  end
end

.parse_completion_response(response) ⇒ Object

Raises:

  • (RubyLLM::Error)


42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/ruby_llm/pollinations/provider/chat.rb', line 42

def parse_completion_response(response)
  data = response.body
  return if data.nil? || data.empty?

  raise RubyLLM::Error.new(response, data.dig('error', 'message')) if data.dig('error', 'message')

  message_data = data.dig('choices', 0, 'message')
  return unless message_data

  usage = data['usage'] || {}
  cached_tokens = usage.dig('prompt_tokens_details', 'cached_tokens')
  thinking_tokens = usage.dig('completion_tokens_details', 'reasoning_tokens')
  content, thinking_from_blocks = extract_content_and_thinking(message_data['content'])
  thinking_text = thinking_from_blocks || extract_thinking_text(message_data)

  RubyLLM::Message.new(
    role: :assistant,
    content: content,
    thinking: RubyLLM::Thinking.build(text: thinking_text),
    tool_calls: Tools.parse_tool_calls(message_data['tool_calls']),
    input_tokens: usage['prompt_tokens'],
    output_tokens: usage['completion_tokens'],
    cached_tokens: cached_tokens,
    cache_creation_tokens: 0,
    thinking_tokens: thinking_tokens,
    model_id: data['model'],
    raw: response
  )
end

.render_payload(messages, tools:, temperature:, model:, stream: false, schema: nil, thinking: nil) ⇒ Object

rubocop:disable Metrics/ParameterLists



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/ruby_llm/pollinations/provider/chat.rb', line 13

def render_payload(messages, tools:, temperature:, model:, stream: false, schema: nil, thinking: nil) # rubocop:disable Metrics/ParameterLists
  payload = {
    model: model.id,
    messages: format_messages(messages),
    stream: stream
  }

  payload[:temperature] = temperature unless temperature.nil?
  payload[:tools] = tools.map { |_, tool| Tools.tool_for(tool) } if tools.any?

  if schema
    strict = schema[:strict] != false
    payload[:response_format] = {
      type: 'json_schema',
      json_schema: {
        name: 'response',
        schema: schema,
        strict: strict
      }
    }
  end

  effort = resolve_effort(thinking)
  payload[:reasoning_effort] = effort if effort

  payload[:stream_options] = { include_usage: true } if stream
  payload
end

.resolve_effort(thinking) ⇒ Object



83
84
85
86
87
# File 'lib/ruby_llm/pollinations/provider/chat.rb', line 83

def resolve_effort(thinking)
  return nil unless thinking

  thinking.respond_to?(:effort) ? thinking.effort : thinking
end

Instance Method Details

#completion_url ⇒ Object



7
8
9
# File 'lib/ruby_llm/pollinations/provider/chat.rb', line 7

def completion_url
  'v1/chat/completions'
end