Class: Ask::Providers::OpenAICompatible

Inherits:
OpenAI
  • Object
show all
Defined in:
lib/ask/provider/openai_compatible.rb

Overview

Single class for all OpenAI-compatible providers.

Reads its behavior from LLM::OPENAI_COMPATIBLE via the class-level compat_config that gets set at registration time. Each registered provider is an anonymous subclass with its own compat_config.

This eliminates one subclass file per provider — adding a new OpenAI-compatible API is a one-line config entry.

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from OpenAI

#build_request, #chat, #embed, #format_message, #format_tools, #list_models, #parse_error, #parse_response, #parse_stream

Methods included from LLM::ProviderConfig

#build_request, #format_message, #format_tools, #parse_response, #parse_stream

Methods included from LLM::SSEBuffer

#each_sse_event, #init_sse_buffer

Constructor Details

#initialize(config = {}) ⇒ OpenAICompatible

Returns a new instance of OpenAICompatible.



43
44
45
46
47
# File 'lib/ask/provider/openai_compatible.rb', line 43

def initialize(config = {})
  @compat_cfg = self.class.compat_config || {}
  config = normalize_compat_config(config)
  super(config)
end

Class Attribute Details

.compat_configObject (readonly)

Returns the value of attribute compat_config.



15
16
17
# File 'lib/ask/provider/openai_compatible.rb', line 15

def compat_config
  @compat_config
end

Class Method Details

.capabilitiesObject



21
22
23
# File 'lib/ask/provider/openai_compatible.rb', line 21

def capabilities
  compat_config[:capabilities] || { chat: true, streaming: true, tool_calls: true }
end

.configuration_optionsObject



25
26
27
# File 'lib/ask/provider/openai_compatible.rb', line 25

def configuration_options
  %i[api_key base_url]
end

.configuration_requirementsObject



29
30
31
# File 'lib/ask/provider/openai_compatible.rb', line 29

def configuration_requirements
  %i[api_key]
end

.configured?(config) ⇒ Boolean

Returns:

  • (Boolean)


33
34
35
36
37
38
# File 'lib/ask/provider/openai_compatible.rb', line 33

def configured?(config)
  key = config.respond_to?(:api_key) ? config.api_key : nil
  key ||= ENV[compat_config[:api_key_env].to_s]
  key ||= ENV[compat_config[:alternate_env].to_s] if compat_config[:alternate_env]
  key.to_s.length > 0
end

.slugObject



17
18
19
# File 'lib/ask/provider/openai_compatible.rb', line 17

def slug
  compat_config[:slug].to_s
end

Instance Method Details

#api_baseObject



49
50
51
# File 'lib/ask/provider/openai_compatible.rb', line 49

def api_base
  @config.base_url || @compat_cfg[:api_base] || super
end

#format_messages(messages) ⇒ Object



63
64
65
66
67
68
69
# File 'lib/ask/provider/openai_compatible.rb', line 63

def format_messages(messages)
  result = super
  if @compat_cfg[:reasoning_content]
    result.each { |fm| fm[:reasoning_content] ||= "" if fm[:role] == "assistant" && fm[:tool_calls] }
  end
  result
end

#headersObject



53
54
55
56
57
58
59
60
61
# File 'lib/ask/provider/openai_compatible.rb', line 53

def headers
  h = { "Content-Type" => "application/json" }
  key = @config.api_key
  h["Authorization"] = "Bearer #{key}" if key
  if (extra = @compat_cfg[:extra_headers])
    extra.each { |k, v| h[k] = v }
  end
  h
end