Class: RubynCode::Config::Settings

Inherits:
Object
  • Object
show all
Defined in:
lib/rubyn_code/config/settings.rb

Defined Under Namespace

Classes: LoadError

Constant Summary collapse

CONFIGURABLE_KEYS =
%i[
  provider model model_mode max_iterations max_sub_agent_iterations max_output_chars
  context_threshold_tokens micro_compact_keep_recent
  poll_interval idle_timeout
  session_budget_usd daily_budget_usd
  oauth_client_id oauth_redirect_uri oauth_authorize_url
  oauth_token_url oauth_scopes
].freeze
DEFAULT_MAP =
{
  provider: Defaults::DEFAULT_PROVIDER,
  model: Defaults::DEFAULT_MODEL,
  model_mode: Defaults::MODEL_MODE,
  max_iterations: Defaults::MAX_ITERATIONS,
  max_sub_agent_iterations: Defaults::MAX_SUB_AGENT_ITERATIONS,
  max_output_chars: Defaults::MAX_OUTPUT_CHARS,
  context_threshold_tokens: Defaults::CONTEXT_THRESHOLD_TOKENS,
  micro_compact_keep_recent: Defaults::MICRO_COMPACT_KEEP_RECENT,
  poll_interval: Defaults::POLL_INTERVAL,
  idle_timeout: Defaults::IDLE_TIMEOUT,
  session_budget_usd: Defaults::SESSION_BUDGET_USD,
  daily_budget_usd: Defaults::DAILY_BUDGET_USD,
  oauth_client_id: Defaults::OAUTH_CLIENT_ID,
  oauth_redirect_uri: Defaults::OAUTH_REDIRECT_URI,
  oauth_authorize_url: Defaults::OAUTH_AUTHORIZE_URL,
  oauth_token_url: Defaults::OAUTH_TOKEN_URL,
  oauth_scopes: Defaults::OAUTH_SCOPES
}.freeze
DEFAULT_PROVIDER_MODELS =

Default model tiers per built-in provider. Used by seed_config! and backfill_provider_models! so new and existing configs stay in sync.

{
  'anthropic' => {
    'env_key' => 'ANTHROPIC_API_KEY',
    'models' => { 'cheap' => 'claude-haiku-4-5', 'mid' => 'claude-sonnet-4-6', 'top' => 'claude-opus-4-6' }
  },
  'openai' => {
    'env_key' => 'OPENAI_API_KEY',
    'models' => { 'cheap' => 'gpt-5.4-nano', 'mid' => 'gpt-5.4-mini', 'top' => 'gpt-5.4' }
  }
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config_path: Defaults::CONFIG_FILE) ⇒ Settings

Returns a new instance of Settings.



43
44
45
46
47
48
49
50
# File 'lib/rubyn_code/config/settings.rb', line 43

def initialize(config_path: Defaults::CONFIG_FILE)
  @config_path = config_path
  @data = {}
  ensure_home_directory!
  seed_config! unless File.exist?(@config_path)
  load!
  backfill_provider_models!
end

Instance Attribute Details

#config_pathObject (readonly)

Returns the value of attribute config_path.



41
42
43
# File 'lib/rubyn_code/config/settings.rb', line 41

def config_path
  @config_path
end

#dataObject (readonly)

Returns the value of attribute data.



41
42
43
# File 'lib/rubyn_code/config/settings.rb', line 41

def data
  @data
end

Instance Method Details

#add_provider(name, base_url:, env_key: nil, models: [], pricing: {}, api_format: nil) ⇒ Object

Add or update a provider in the config and persist to disk.

Parameters:

  • name (String)

    provider name (e.g., ‘groq’)

  • base_url (String)

    API base URL

  • env_key (String, nil) (defaults to: nil)

    environment variable for the API key

  • models (Array<String>) (defaults to: [])

    available model names

  • pricing (Hash) (defaults to: {})

    model => [input_rate, output_rate]

  • api_format (String, nil) (defaults to: nil)

    API format (‘openai’ or ‘anthropic’)



119
120
121
122
123
124
125
# File 'lib/rubyn_code/config/settings.rb', line 119

def add_provider(name, base_url:, env_key: nil, models: [], pricing: {}, api_format: nil) # rubocop:disable Metrics/ParameterLists -- all optional kwargs with defaults
  @data['providers'] ||= {}
  @data['providers'][name.to_s] = build_provider_hash(
    base_url: base_url, env_key: env_key, models: models, pricing: pricing, api_format: api_format
  )
  save!
end

#custom_pricingObject

Returns all user-configured pricing as { model => [input, output] }



128
129
130
131
132
133
134
135
# File 'lib/rubyn_code/config/settings.rb', line 128

def custom_pricing
  providers = @data['providers']
  return {} unless providers.is_a?(Hash)

  providers.each_with_object({}) do |(_, cfg), acc|
    merge_provider_pricing(cfg, acc)
  end
end

#dangerous_patternsObject



96
# File 'lib/rubyn_code/config/settings.rb', line 96

def dangerous_patterns = Defaults::DANGEROUS_PATTERNS

#db_fileObject



91
# File 'lib/rubyn_code/config/settings.rb', line 91

def db_file = Defaults::DB_FILE

#get(key, default = nil) ⇒ Object



63
64
65
66
# File 'lib/rubyn_code/config/settings.rb', line 63

def get(key, default = nil)
  sym = key.to_sym
  @data.fetch(key.to_s) { DEFAULT_MAP.fetch(sym, default) }
end

#home_dirObject



90
# File 'lib/rubyn_code/config/settings.rb', line 90

def home_dir = Defaults::HOME_DIR

#memories_dirObject



94
# File 'lib/rubyn_code/config/settings.rb', line 94

def memories_dir = Defaults::MEMORIES_DIR

#provider_config(name) ⇒ Object

Returns config hash for a custom provider, or nil if not configured. Reads from ‘providers.<name>` in config.yml.

Expected keys: base_url, env_key, models, pricing pricing is a hash of model_name => [input_rate, output_rate]



104
105
106
107
108
109
# File 'lib/rubyn_code/config/settings.rb', line 104

def provider_config(name)
  providers = @data.dig('providers', name.to_s)
  return nil unless providers.is_a?(Hash)

  providers.transform_keys(&:to_s)
end

#reload!Object



82
83
84
# File 'lib/rubyn_code/config/settings.rb', line 82

def reload!
  load!
end

#save!Object



72
73
74
75
76
77
78
79
80
# File 'lib/rubyn_code/config/settings.rb', line 72

def save!
  ensure_home_directory!
  File.write(@config_path, YAML.dump(@data))
  File.chmod(0o600, @config_path)
rescue Errno::EACCES => e
  raise LoadError, "Permission denied writing config to #{@config_path}: #{e.message}"
rescue SystemCallError => e
  raise LoadError, "Failed to save config to #{@config_path}: #{e.message}"
end

#scrub_env_varsObject



97
# File 'lib/rubyn_code/config/settings.rb', line 97

def scrub_env_vars = Defaults::SCRUB_ENV_VARS

#sessions_dirObject



93
# File 'lib/rubyn_code/config/settings.rb', line 93

def sessions_dir = Defaults::SESSIONS_DIR

#set(key, value) ⇒ Object



68
69
70
# File 'lib/rubyn_code/config/settings.rb', line 68

def set(key, value)
  @data[key.to_s] = value
end

#to_hObject



86
87
88
# File 'lib/rubyn_code/config/settings.rb', line 86

def to_h
  DEFAULT_MAP.transform_keys(&:to_s).merge(@data)
end

#tokens_fileObject



92
# File 'lib/rubyn_code/config/settings.rb', line 92

def tokens_file = Defaults::TOKENS_FILE