Module: Legion::LLM::CodexConfigLoader

Extended by:
Legion::Logging::Helper
Defined in:
lib/legion/llm/codex_config_loader.rb

Constant Summary collapse

CODEX_AUTH =
File.expand_path('~/.codex/auth.json')

Class Method Summary collapse

Class Method Details

.apply_codex_config(config) ⇒ Object



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/legion/llm/codex_config_loader.rb', line 46

def apply_codex_config(config)
  return unless config[:auth_mode] == 'chatgpt'

  token = config.dig(:tokens, :access_token)
  return unless token.is_a?(String) && !token.empty?

  unless token_valid?(token)
    log.debug 'CodexConfigLoader: access token is expired, skipping'
    return
  end

  providers = Legion::LLM.settings[:providers]
  existing_raw = providers.dig(:openai, :api_key)
  resolved_existing = resolve_env_api_key(existing_raw)
  return unless resolved_existing.nil? || (resolved_existing.respond_to?(:empty?) && resolved_existing.empty?)

  providers[:openai][:api_key] = token
  log.debug 'Imported OpenAI API key from Codex auth config'
end

.loadObject



16
17
18
19
20
21
22
23
# File 'lib/legion/llm/codex_config_loader.rb', line 16

def load
  return unless File.exist?(CODEX_AUTH)

  config = read_json(CODEX_AUTH)
  return if config.empty?

  apply_codex_config(config)
end

.read_json(path) ⇒ Object



39
40
41
42
43
44
# File 'lib/legion/llm/codex_config_loader.rb', line 39

def read_json(path)
  ::JSON.parse(File.read(path), symbolize_names: true)
rescue StandardError => e
  handle_exception(e, level: :debug)
  {}
end

.read_tokenObject



25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/legion/llm/codex_config_loader.rb', line 25

def read_token
  return nil unless File.exist?(CODEX_AUTH)

  config = read_json(CODEX_AUTH)
  return nil if config.empty?
  return nil unless config[:auth_mode] == 'chatgpt'

  token = config.dig(:tokens, :access_token)
  return nil unless token.is_a?(String) && !token.empty?
  return nil unless token_valid?(token)

  token
end

.resolve_env_api_key(value) ⇒ Object



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/legion/llm/codex_config_loader.rb', line 66

def resolve_env_api_key(value)
  return nil if value.nil?

  if value.is_a?(String)
    return nil if value.empty?

    if value.start_with?('env://')
      env_name = value.sub('env://', '')
      env_value = ENV.fetch(env_name, nil)
      return nil if env_value.nil? || env_value.empty?

      return env_value
    end

    return value
  end

  if value.is_a?(Array)
    resolved = value.map { |v| resolve_env_api_key(v) }.compact
    return nil if resolved.empty?
    return resolved.first if resolved.length == 1

    return resolved
  end

  value
end

.token_valid?(token) ⇒ Boolean

Returns:

  • (Boolean)


94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/legion/llm/codex_config_loader.rb', line 94

def token_valid?(token)
  parts = token.split('.')
  return true unless parts.length == 3

  padded = parts[1] + ('=' * ((4 - (parts[1].length % 4)) % 4))
  payload = ::JSON.parse(Base64.urlsafe_decode64(padded), symbolize_names: true)
  exp = payload[:exp]
  return true unless exp.is_a?(Integer)

  exp > Time.now.to_i
rescue StandardError => e
  log.debug("CodexConfigLoader.token_valid? failed to parse access token: #{e.message}")
  handle_exception(e, level: :debug)
  true
end