Class: Kernai::Providers::Ollama

Inherits:
Kernai::Provider show all
Defined in:
lib/kernai/providers/ollama.rb

Overview

Kernai::Provider adapter for the Ollama chat API.

Supports streaming, multimodal image input (when the model declares ‘:vision`; only inline-bytes images are accepted — Ollama does not fetch URLs). GenerationOptions are routed under Ollama’s ‘options` map, with `max_tokens` surfaced as `num_predict`.

Zero runtime dependencies beyond the Ruby stdlib. Points at ‘localhost:11434` by default; override with `base_url:` for remote deployments.

Constant Summary collapse

DEFAULT_BASE_URL =
'http://localhost:11434'

Instance Method Summary collapse

Methods inherited from Kernai::Provider

#encode, #fallback_for

Constructor Details

#initialize(api_key: ENV.fetch('OLLAMA_API_KEY', nil), base_url: ENV.fetch('OLLAMA_BASE_URL', DEFAULT_BASE_URL)) ⇒ Ollama

Returns a new instance of Ollama.



22
23
24
25
26
27
# File 'lib/kernai/providers/ollama.rb', line 22

def initialize(api_key: ENV.fetch('OLLAMA_API_KEY', nil),
               base_url: ENV.fetch('OLLAMA_BASE_URL', DEFAULT_BASE_URL))
  super()
  @api_key = api_key
  @base_url = base_url.chomp('/')
end

Instance Method Details

#call(messages:, model:, generation: nil, &block) ⇒ Object



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/kernai/providers/ollama.rb', line 29

def call(messages:, model:, generation: nil, &block)
  uri = URI("#{@base_url}/api/chat")
  payload = build_payload(messages, model, stream: block_given?, generation: generation)

  started = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  content, usage = if block
                     stream_request(uri, payload, &block)
                   else
                     non_stream_request(uri, payload)
                   end

  Kernai::LlmResponse.new(
    content: content,
    latency_ms: elapsed_ms(started),
    prompt_tokens: usage['prompt_eval_count'],
    completion_tokens: usage['eval_count']
  )
end

#encode_part(part, model:) ⇒ Object

Strings become text parts; inline base64 images become image parts when the model declares ‘:vision`. URL-backed images and non-image media fall back to the base class placeholder, which re-enters this method and is wrapped as a text part.



52
53
54
55
56
57
58
# File 'lib/kernai/providers/ollama.rb', line 52

def encode_part(part, model:)
  return { type: :text, text: part } if part.is_a?(String)
  return nil unless part.is_a?(Kernai::Media) && part.kind == :image && model.supports?(:vision)
  return nil if part.url?

  { type: :image, data: part.to_base64 }
end