Class: Insika::LLMProviderStore

Inherits:
Object
  • Object
show all
Includes:
Coercion
Defined in:
lib/insika/llm_provider_store.rb

Overview

LLM providers authored at runtime. One record per provider in the ConfigStore (scope "llm_providers"), keyed by the API slug (deepseek, openai, ...). Holds base_url/auth_header/models and the api_key.

The api_key NEVER leaves here in plaintext to the UI: the display reads (get/all) mask it with the __OCULTO__ sentinel. Only all_raw/get_raw (consumed by the LLMConfigurator, never by the screen) return the real key. On write, the sentinel coming back preserves the key; a new string replaces it; "" clears it (see Insika::SecretMasking).

Constant Summary collapse

SCOPE =
"llm_providers"

Instance Method Summary collapse

Methods included from Coercion

blank?, deep_stringify, presence, present?, utf8

Constructor Details

#initialize(config_store:) ⇒ LLMProviderStore

Returns a new instance of LLMProviderStore.



18
19
20
# File 'lib/insika/llm_provider_store.rb', line 18

def initialize(config_store:)
  @cs = config_store
end

Instance Method Details

#allObject

-> [Hash] all MASKED (for the UI).



36
37
38
# File 'lib/insika/llm_provider_store.rb', line 36

def all
  apis.filter_map { |a| get(a) }
end

#all_rawObject

-> [Hash] all with REAL api_key (for the configurator). Never goes to the screen.



41
42
43
# File 'lib/insika/llm_provider_store.rb', line 41

def all_raw
  apis.filter_map { |a| raw(a) }
end

#apisObject

-> [String] slugs, lexicographic order.



33
# File 'lib/insika/llm_provider_store.rb', line 33

def apis = @cs.keys(SCOPE)

#delete(api) ⇒ Object

-> bool (did it exist?).



66
# File 'lib/insika/llm_provider_store.rb', line 66

def delete(api) = @cs.delete(SCOPE, api.to_s)

#get(api) ⇒ Object

-> MASKED Hash | nil.



23
24
25
# File 'lib/insika/llm_provider_store.rb', line 23

def get(api)
  mask(raw(api))
end

#get_raw(api) ⇒ Object

-> Hash with REAL api_key | nil. Internal use (LLMConfigurator).



28
29
30
# File 'lib/insika/llm_provider_store.rb', line 28

def get_raw(api)
  raw(api)
end

#upsert(attrs) ⇒ Object

Upsert with secret reconciliation. attrs (string|symbol keys):

api (required), base_url, auth_header, api_key (sentinel-aware), models[]

-> MASKED Hash (the stored record).



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/insika/llm_provider_store.rb', line 48

def upsert(attrs)
  h = symbolize(attrs)
  api = presence(h[:api])
  raise Insika::ValidationError, "api is required" if api.nil?

  existing = raw(api)
  record = {
    "api" => api,
    "base_url" => presence(h[:base_url]),
    "auth_header" => presence(h[:auth_header]),
    "api_key" => SecretMasking.reconcile(h[:api_key], existing&.fetch("api_key", nil)),
    "models" => Array(h[:models]).map(&:to_s)
  }
  @cs.put(SCOPE, api, record)
  mask(record)
end