Module: LLM::OpenWebUIMethods

Includes:
OpenAIMethods
Included in:
OpenWebUI
Defined in:
lib/scout/llm/backends/openwebui.rb

Overview

OpenWebUI backend.

OpenWebUI exposes an OpenAI-compatible Chat Completions API, but it is not accessed through the OpenAI ruby client.

Historically we copied singleton methods from LLM::OpenAI via hooks. That binds self to the original module and breaks internal dispatch.

Instead, we reuse behaviour by including OpenAIMethods in our own methods module, and compose via prepend.

Instance Method Summary collapse

Methods included from OpenAIMethods

#format_tool_call, #format_tool_definitions, #format_tool_output, #process_response

Instance Method Details

#client(options, messages = nil) ⇒ Object



19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/scout/llm/backends/openwebui.rb', line 19

def client(options, messages = nil)
  url, key, model, request_timeout = IndiferentHash.process_options options,
    :url, :key, :model, :request_timeout, 
    request_timeout: 12000

  {
    base_url: url,
    key: key,
    model: model,
    method: :post,
    request_timeout: request_timeout,
    action: 'chat/completions'
  }
end

#parse_tool_call(info) ⇒ Object



64
65
66
67
68
69
70
# File 'lib/scout/llm/backends/openwebui.rb', line 64

def parse_tool_call(info)
  IndiferentHash.setup info
  arguments, name = IndiferentHash.process_options info['function'], :arguments, :name
  arguments = JSON.parse arguments
  id = info[:id] || name + '_' + Misc.digest(arguments)
  { arguments: arguments, id: id, name: name }
end

#query(client, messages, tools = [], parameters = {}) ⇒ Object



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/scout/llm/backends/openwebui.rb', line 34

def query(client, messages, tools = [], parameters = {})
  base_url, key, model, method, action, timeout = IndiferentHash.process_options client.dup, :base_url, :key, :model, :method, :action, :request_timeout
  url = File.join(base_url, action.to_s)

  parameters = parameters.dup
  parameters[:model] ||= model
  parameters[:tools] = format_tool_definitions(tools) if tools && tools.any?
  parameters[:messages] = messages
  parameters[:verify_ssl] = false
  parameters[:timeout] = timeout.to_i if timeout
  parameters[:read_timeout] = timeout.to_i if timeout
  parameters[:open_timeout] = timeout.to_i if timeout

  headers = IndiferentHash.setup({ 'Authorization' => "Bearer #{key}", 'Content-Type' => 'application/json' })
  Misc.insist do
    response = case method.to_sym
               when :post
                 RestClient.post(url, parameters.to_json, headers)
               else
                 raise 'Get not supported'
               end

    if response.body.nil? || response.body == 'null'
      raise "No response body: #{JSON.pretty_generate(response)}"
    else
      JSON.parse(response.body)
    end
  end
end