77from typing import Optional
88
99import typer
10+ from dotenv import load_dotenv
1011from pydantic import BaseModel , Field
1112from rich .console import Console
12- from rich .prompt import Prompt , Confirm
13- from dotenv import load_dotenv
13+ from rich .prompt import Confirm , Prompt
1414
1515console = Console ()
1616
17+
1718class ClickHouseConfig (BaseModel ):
1819 """ClickHouse connection configuration"""
19-
20+
2021 host : str = Field (default = "localhost" , description = "ClickHouse host" )
2122 port : int = Field (default = 8123 , description = "ClickHouse HTTP port" )
2223 username : str = Field (default = "default" , description = "ClickHouse username" )
@@ -26,37 +27,50 @@ class ClickHouseConfig(BaseModel):
2627
2728 # Provider selection
2829 provider : str = Field (default = "local" , description = "LLM provider: local only" )
29-
30+
3031 # Local LLM (llama.cpp / llamafile / llama-cpp-python server) configuration
31- local_llm_base_url : str = Field (default = "http://127.0.0.1:8000/v1" , description = "Local LLM server base URL" )
32- local_llm_model : str = Field (default = "qwen3-1.7b" , description = "Local LLM model name" )
33-
32+ local_llm_base_url : str = Field (
33+ default = "http://127.0.0.1:8000/v1" , description = "Local LLM server base URL"
34+ )
35+ local_llm_model : str = Field (
36+ default = "qwen3-1.7b" , description = "Local LLM model name"
37+ )
38+
3439 # Legacy OpenRouter configuration (kept for backward compatibility)
3540 openrouter_api_key : str = Field (default = "" , description = "Legacy OpenRouter API key" )
36- openrouter_model : str = Field (default = "openai/gpt-4o-mini" , description = "Legacy OpenRouter model" )
37- openrouter_provider_only : str = Field (default = "openai" , description = "Legacy OpenRouter provider preference" )
38- openrouter_data_collection : str = Field (default = "deny" , description = "Legacy OpenRouter data collection setting" )
39-
41+ openrouter_model : str = Field (
42+ default = "openai/gpt-4o-mini" , description = "Legacy OpenRouter model"
43+ )
44+ openrouter_provider_only : str = Field (
45+ default = "openai" , description = "Legacy OpenRouter provider preference"
46+ )
47+ openrouter_data_collection : str = Field (
48+ default = "deny" , description = "Legacy OpenRouter data collection setting"
49+ )
50+
4051 # Agent configuration
41- max_tool_calls : int = Field (default = 35 , description = "Maximum tool calls per conversation" )
52+ max_tool_calls : int = Field (
53+ default = 35 , description = "Maximum tool calls per conversation"
54+ )
4255 temperature : float = Field (default = 0.1 , description = "LLM temperature" )
4356 max_tokens : int = Field (default = 4000 , description = "Maximum tokens per response" )
4457
58+
4559def load_config (
4660 config_file : Optional [Path ] = None ,
4761 host : Optional [str ] = None ,
4862 port : Optional [int ] = None ,
4963 username : Optional [str ] = None ,
5064 password : Optional [str ] = None ,
51- database : Optional [str ] = None
65+ database : Optional [str ] = None ,
5266) -> ClickHouseConfig :
5367 """Load configuration from file and command line arguments"""
54-
68+
5569 # Load environment variables from .env file
5670 load_dotenv ()
57-
71+
5872 config_data = {}
59-
73+
6074 # Determine default config file if not provided
6175 default_config_file = Path .home () / ".config" / "proto" / "proto-config.json"
6276 legacy_config_file = Path ("proto-config.json" )
@@ -71,6 +85,7 @@ def load_config(
7185 # Load from config file if found
7286 if candidate_config and candidate_config .exists ():
7387 import json
88+
7489 with open (candidate_config ) as f :
7590 config_data = json .load (f )
7691
@@ -86,27 +101,31 @@ def load_config(
86101 for old_key , new_key in key_mapping .items ():
87102 if old_key in config_data and new_key not in config_data :
88103 config_data [new_key ] = config_data [old_key ]
89-
104+
90105 # Load from environment variables
91- config_data .update ({
92- k .lower ().replace ("clickhouse_" , "" ): v
93- for k , v in os .environ .items ()
94- if k .startswith ("CLICKHOUSE_" )
95- })
96-
106+ config_data .update (
107+ {
108+ k .lower ().replace ("clickhouse_" , "" ): v
109+ for k , v in os .environ .items ()
110+ if k .startswith ("CLICKHOUSE_" )
111+ }
112+ )
113+
97114 # OpenRouter configuration from environment
98115 if "OPENROUTER_API_KEY" in os .environ :
99116 config_data ["openrouter_api_key" ] = os .environ ["OPENROUTER_API_KEY" ]
100-
117+
101118 if "OPENROUTER_MODEL" in os .environ :
102119 config_data ["openrouter_model" ] = os .environ ["OPENROUTER_MODEL" ]
103-
120+
104121 if "OPENROUTER_PROVIDER_ONLY" in os .environ :
105122 config_data ["openrouter_provider_only" ] = os .environ ["OPENROUTER_PROVIDER_ONLY" ]
106-
123+
107124 if "OPENROUTER_DATA_COLLECTION" in os .environ :
108- config_data ["openrouter_data_collection" ] = os .environ ["OPENROUTER_DATA_COLLECTION" ]
109-
125+ config_data ["openrouter_data_collection" ] = os .environ [
126+ "OPENROUTER_DATA_COLLECTION"
127+ ]
128+
110129 # Override with command line arguments
111130 if host :
112131 config_data ["host" ] = host
@@ -118,21 +137,22 @@ def load_config(
118137 config_data ["password" ] = password
119138 if database :
120139 config_data ["database" ] = database
121-
140+
122141 config = ClickHouseConfig (** config_data )
123-
142+
124143 # No interactive configuration needed for local provider
125144 if config .provider != "local" :
126145 console .print ("[yellow]⚠️ Only local provider is supported[/yellow]" )
127146 console .print ("[blue]ℹ️ Switching to local provider automatically[/blue]" )
128147 config .provider = "local"
129-
148+
130149 return config
131150
151+
132152def save_env_config (config : ClickHouseConfig ):
133153 """Save configuration to .env file"""
134154 env_path = Path (".env" )
135-
155+
136156 env_content = f"""# ClickHouse Configuration
137157CLICKHOUSE_HOST={ config .host }
138158CLICKHOUSE_PORT={ config .port }
@@ -147,12 +167,13 @@ def save_env_config(config: ClickHouseConfig):
147167OPENROUTER_PROVIDER_ONLY={ config .openrouter_provider_only }
148168OPENROUTER_DATA_COLLECTION={ config .openrouter_data_collection }
149169"""
150-
170+
151171 with open (env_path , "w" ) as f :
152172 f .write (env_content )
153-
173+
154174 console .print (f"[green]✓[/green] Configuration saved to { env_path } " )
155175
176+
156177def create_sample_config ():
157178 """Create a sample configuration file"""
158179 config_data = {
@@ -168,13 +189,14 @@ def create_sample_config():
168189 "openrouter_data_collection" : "deny" ,
169190 "max_tool_calls" : 35 ,
170191 "temperature" : 0.1 ,
171- "max_tokens" : 4000
192+ "max_tokens" : 4000 ,
172193 }
173-
194+
174195 config_path = Path ("proto-config.json" )
175-
196+
176197 import json
198+
177199 with open (config_path , "w" ) as f :
178200 json .dump (config_data , f , indent = 2 )
179-
180- console .print (f"[green]✓[/green] Sample configuration created at { config_path } " )
201+
202+ console .print (f"[green]✓[/green] Sample configuration created at { config_path } " )
0 commit comments