Class: Chocomint::Config

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

Overview

設定ファイルを読み込み、環境変数オーバーライドを適用する。

設定は XDG Base Directory 準拠のユーザーパス (~/.config/chocomint/config.yaml。$XDG_CONFIG_HOME があればそちらを優先) に置く。 ユーザー設定がまだ無い場合は、gem 同梱の既定 config をそこへコピーして雛形にする (初回起動時)。読み込み・保存 (モデル切り替えの persist) はいずれもこのユーザーパスを使う。

Constant Summary collapse

BUNDLED_PATH =

gem 同梱の既定 config (初回のコピー元。読み取り専用として扱う)。

File.expand_path("../../config/config.yml", __dir__)
OPENROUTER_BASE_URL =

---- LLM プロバイダ / モデル設定 (AI エディタのモデル切り替え用) ----------

provider は base_url から推定する: openrouter.ai を含めば "openrouter"、 それ以外 (localhost:11434 等) は "ollama" とみなす。UI での表示・選択に使う。

"https://openrouter.ai/api/v1"
OLLAMA_BASE_URL =
"http://localhost:11434/v1"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(data, path = self.class.user_config_path) ⇒ Config

Returns a new instance of Config.



57
58
59
60
61
# File 'lib/chocomint/config.rb', line 57

def initialize(data, path = self.class.user_config_path)
  @data = deep_stringify(data)
  @path = path
  apply_env_overrides!
end

Instance Attribute Details

#dataObject (readonly)

Returns the value of attribute data.



18
19
20
# File 'lib/chocomint/config.rb', line 18

def data
  @data
end

#pathObject (readonly)

読み込み元パス。llm モデル設定を書き戻す (persist_llm!) のにも使う。 path は第 2 引数 (キーワードにすると Config.new("k" => v) が keyword 誤認で壊れるため)。



55
56
57
# File 'lib/chocomint/config.rb', line 55

def path
  @path
end

Class Method Details

.ensure_user_configObject

user_config_path を用意する。無ければ同梱 config をコピーして作る。 戻り値: 実際に読み込むべきパス (コピー成功時はユーザーパス、失敗時は同梱パス)。



39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/chocomint/config.rb', line 39

def self.ensure_user_config
  dest = user_config_path
  return dest if File.exist?(dest)

  begin
    FileUtils.mkdir_p(File.dirname(dest))
    FileUtils.cp(BUNDLED_PATH, dest) if File.exist?(BUNDLED_PATH)
    File.exist?(dest) ? dest : BUNDLED_PATH
  rescue SystemCallError
    # 書き込み不可などでコピーできないときは同梱 config を読む。
    BUNDLED_PATH
  end
end

.load(path = nil) ⇒ Object

設定を読み込む。明示的な path が無ければ user_config_path を使い、そこに まだファイルが無ければ gem 同梱の既定 config をコピーして作成する。 コピーできない (書き込み不可など) 場合は同梱 config をそのまま読み、 保存先だけユーザーパスに向ける (persist 時に改めて作成を試みる)。



31
32
33
34
35
# File 'lib/chocomint/config.rb', line 31

def self.load(path = nil)
  path ||= ensure_user_config
  raw = File.exist?(path) ? YAML.safe_load(File.read(path)) : {}
  new(raw || {}, path)
end

.user_config_pathObject

XDG 準拠のユーザー設定ファイルパス (~/.config/chocomint/config.yaml)。



21
22
23
24
25
# File 'lib/chocomint/config.rb', line 21

def self.user_config_path
  base = ENV["XDG_CONFIG_HOME"]
  base = File.join(Dir.home, ".config") if base.nil? || base.empty?
  File.join(base, "chocomint", "config.yaml")
end

Instance Method Details

#allow_all_commands?Boolean

true なら run_command で allowed_commands の whitelist チェックを行わず任意コマンドを実行する。

Returns:

  • (Boolean)


91
# File 'lib/chocomint/config.rb', line 91

def allow_all_commands? = security.fetch("allow_all_commands", false)

#allowed_commandsObject



89
90
# File 'lib/chocomint/config.rb', line 89

def allowed_commands = security.fetch("allowed_commands", [])
# true なら run_command で allowed_commands の whitelist チェックを行わず任意コマンドを実行する。

#allowed_dirsObject



87
# File 'lib/chocomint/config.rb', line 87

def allowed_dirs    = security.fetch("allowed_dirs", ["."])

#console_ws_portObject

AI エディタのコンソール (WebSocket) 用ポート。既定は HTTP ポート+1。



73
74
# File 'lib/chocomint/config.rb', line 73

def console_ws_port = ENV.fetch("CHOCOMINT_WS_PORT", server.fetch("ws_port", server_port + 1)).to_i
# コンソール接続に要求する共有トークン。未設定なら nil (ローカル限定運用向け)。

#console_ws_tokenObject

コンソール接続に要求する共有トークン。未設定なら nil (ローカル限定運用向け)。



75
# File 'lib/chocomint/config.rb', line 75

def console_ws_token = ENV.fetch("CHOCOMINT_WS_TOKEN", server.fetch("ws_token", nil))

#executionObject



65
# File 'lib/chocomint/config.rb', line 65

def execution = @data.fetch("execution", {})

#llmObject



63
# File 'lib/chocomint/config.rb', line 63

def llm      = @data.fetch("llm", {})

#llm_base_urlObject



104
# File 'lib/chocomint/config.rb', line 104

def llm_base_url = llm.fetch("base_url", OLLAMA_BASE_URL)

#llm_modelObject



105
# File 'lib/chocomint/config.rb', line 105

def llm_model    = llm.fetch("model", nil)

#llm_providerObject



107
108
109
# File 'lib/chocomint/config.rb', line 107

def llm_provider
  llm_base_url.to_s.include?("openrouter.ai") ? "openrouter" : "ollama"
end

#llm_timeout_secObject

LLM への HTTP リクエストのタイムアウト (秒)。ツール実行の timeout_sec とは分離する: ローカル LLM は 1 応答に数分かかることがあり、暴走コマンド用の短い timeout_sec を 流用すると Net::ReadTimeout で失敗するため。未設定なら余裕を持たせた既定にする。



84
# File 'lib/chocomint/config.rb', line 84

def llm_timeout_sec = llm.fetch("timeout_sec", 300)

#loggingObject



67
# File 'lib/chocomint/config.rb', line 67

def logging  = @data.fetch("logging", {})

#max_file_bytesObject



88
# File 'lib/chocomint/config.rb', line 88

def max_file_bytes  = security.fetch("max_file_bytes", 10_485_760)

#max_output_bytesObject



85
# File 'lib/chocomint/config.rb', line 85

def max_output_bytes = execution.fetch("max_output_bytes", 1_048_576)

#max_retryObject



77
78
# File 'lib/chocomint/config.rb', line 77

def max_retry       = execution.fetch("max_retry", 10)
# マルチステップ実行のステップ数上限。未設定なら max_retry を流用する (暴走防止)。

#max_stepsObject

マルチステップ実行のステップ数上限。未設定なら max_retry を流用する (暴走防止)。



79
# File 'lib/chocomint/config.rb', line 79

def max_steps       = execution.fetch("max_steps", max_retry)

#ollama_api_baseObject

Ollama の API ベース URL (末尾に /v1 を含まない)。インストール済みモデル一覧 (/api/tags) の取得に使う。provider が OpenRouter でも Ollama タブのモデルは ここから取るため、現在の provider に依存させない。

優先順位: (1) OLLAMA_HOST 環境変数 (Ollama 標準の設定) → (2) 現在の base_url が Ollama を指していればその親 → (3) 既定 (http://localhost:11434)。



118
119
120
121
122
123
124
# File 'lib/chocomint/config.rb', line 118

def ollama_api_base
  if (host = ENV["OLLAMA_HOST"]) && !host.to_s.empty?
    return normalize_ollama_host(host)
  end
  base = llm_provider == "ollama" ? llm_base_url : OLLAMA_BASE_URL
  base.to_s.sub(%r{/v1/?\z}, "").chomp("/")
end

#persist_llm!Object

現在の llm 設定 (provider / model / base_url / api_key_env) をユーザー設定へ 書き戻す。llm セクションだけを更新し、他セクションは元のファイル内容を保つ。

保存先は常にユーザーパス (~/.config/chocomint/config.yaml)。読み込み元が gem 同梱 config だった場合 (初回コピーに失敗したケース) でも、gem ディレクトリ には書かず、ベースは @path (同梱) の内容を引き継いでユーザーパスへ書き出す。



149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/chocomint/config.rb', line 149

def persist_llm!
  dest = self.class.user_config_path
  raw = begin
    (File.exist?(@path) && YAML.safe_load(File.read(@path))) || {}
  rescue Psych::SyntaxError
    {}
  end
  raw = deep_stringify(raw)
  raw["llm"] = @data["llm"]
  FileUtils.mkdir_p(File.dirname(dest))
  File.write(dest, YAML.dump(raw))
  @path = dest
end

#securityObject



66
# File 'lib/chocomint/config.rb', line 66

def security = @data.fetch("security", {})

#serverObject



68
# File 'lib/chocomint/config.rb', line 68

def server   = @data.fetch("server", {})

#server_hostObject



70
# File 'lib/chocomint/config.rb', line 70

def server_host = ENV.fetch("CHOCOMINT_HOST", server.fetch("host", "127.0.0.1"))

#server_portObject



71
72
# File 'lib/chocomint/config.rb', line 71

def server_port = ENV.fetch("CHOCOMINT_PORT", server.fetch("port", 9210)).to_i
# AI エディタのコンソール (WebSocket) 用ポート。既定は HTTP ポート+1。

#set_llm!(provider:, model:) ⇒ Object

実行時にモデル (と provider) を差し替える。Factory がここを参照して Planner / chat_client を再構築する。api_key_env は provider ごとに固定する (Ollama: OLLAMA_API_KEY / OpenRouter: OPENROUTER_API_KEY)。



129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/chocomint/config.rb', line 129

def set_llm!(provider:, model:)
  llm_cfg = (@data["llm"] ||= {})
  llm_cfg["model"] = model
  case provider.to_s
  when "openrouter"
    llm_cfg["base_url"] = OPENROUTER_BASE_URL
    llm_cfg["api_key_env"] = "OPENROUTER_API_KEY"
  else
    llm_cfg["base_url"] = OLLAMA_BASE_URL
    llm_cfg["api_key_env"] = "OLLAMA_API_KEY"
  end
  self
end

#sqlite_pathObject



93
# File 'lib/chocomint/config.rb', line 93

def sqlite_path     = logging.fetch("sqlite_path", "./logs/execution.db")

#timeout_secObject



80
81
82
83
# File 'lib/chocomint/config.rb', line 80

def timeout_sec     = execution.fetch("timeout_sec", 30)
# LLM への HTTP リクエストのタイムアウト (秒)。ツール実行の timeout_sec とは分離する:
# ローカル LLM は 1 応答に数分かかることがあり、暴走コマンド用の短い timeout_sec を
# 流用すると Net::ReadTimeout で失敗するため。未設定なら余裕を持たせた既定にする。

#verifierObject



64
# File 'lib/chocomint/config.rb', line 64

def verifier = @data.fetch("verifier", {})

#verifier_enabled?Boolean

Returns:

  • (Boolean)


95
# File 'lib/chocomint/config.rb', line 95

def verifier_enabled? = verifier.fetch("enabled", false)