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
# File 'lib/scout/llm/backends/openwebui.rb', line 19

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

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

#parse_tool_call(info) ⇒ Object



59
60
61
62
63
64
65
# File 'lib/scout/llm/backends/openwebui.rb', line 59

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



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

def query(client, messages, tools = [], parameters = {})
  base_url, key, model, method, action = IndiferentHash.process_options client.dup, :base_url, :key, :model, :method, :action
  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

  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