122 lines
3.3 KiB
Python
122 lines
3.3 KiB
Python
import json
|
|
import os
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
|
|
class Config:
|
|
"""Configuration Manager for Strix."""
|
|
|
|
# LLM Configuration
|
|
strix_llm = None
|
|
llm_api_key = None
|
|
llm_api_base = None
|
|
openai_api_base = None
|
|
litellm_base_url = None
|
|
ollama_api_base = None
|
|
strix_reasoning_effort = "high"
|
|
llm_timeout = "300"
|
|
llm_rate_limit_delay = "4.0"
|
|
llm_rate_limit_concurrent = "1"
|
|
|
|
# Tool & Feature Configuration
|
|
perplexity_api_key = None
|
|
strix_disable_browser = "false"
|
|
|
|
# Runtime Configuration
|
|
strix_image = "ghcr.io/usestrix/strix-sandbox:0.1.10"
|
|
strix_runtime_backend = "docker"
|
|
strix_sandbox_execution_timeout = "500"
|
|
strix_sandbox_connect_timeout = "10"
|
|
|
|
# Telemetry
|
|
strix_telemetry = "1"
|
|
|
|
@classmethod
|
|
def _tracked_names(cls) -> list[str]:
|
|
return [
|
|
k
|
|
for k, v in vars(cls).items()
|
|
if not k.startswith("_") and k[0].islower() and (v is None or isinstance(v, str))
|
|
]
|
|
|
|
@classmethod
|
|
def tracked_vars(cls) -> list[str]:
|
|
return [name.upper() for name in cls._tracked_names()]
|
|
|
|
@classmethod
|
|
def get(cls, name: str) -> str | None:
|
|
env_name = name.upper()
|
|
default = getattr(cls, name, None)
|
|
return os.getenv(env_name, default)
|
|
|
|
@classmethod
|
|
def config_dir(cls) -> Path:
|
|
return Path.home() / ".strix"
|
|
|
|
@classmethod
|
|
def config_file(cls) -> Path:
|
|
return cls.config_dir() / "cli-config.json"
|
|
|
|
@classmethod
|
|
def load(cls) -> dict[str, Any]:
|
|
path = cls.config_file()
|
|
if not path.exists():
|
|
return {}
|
|
try:
|
|
with path.open("r", encoding="utf-8") as f:
|
|
data: dict[str, Any] = json.load(f)
|
|
return data
|
|
except (json.JSONDecodeError, OSError):
|
|
return {}
|
|
|
|
@classmethod
|
|
def save(cls, config: dict[str, Any]) -> bool:
|
|
try:
|
|
cls.config_dir().mkdir(parents=True, exist_ok=True)
|
|
config_path = cls.config_file()
|
|
with config_path.open("w", encoding="utf-8") as f:
|
|
json.dump(config, f, indent=2)
|
|
config_path.chmod(0o600)
|
|
except OSError:
|
|
return False
|
|
else:
|
|
return True
|
|
|
|
@classmethod
|
|
def apply_saved(cls) -> dict[str, str]:
|
|
saved = cls.load()
|
|
env_vars = saved.get("env", {})
|
|
applied = {}
|
|
|
|
for var_name, var_value in env_vars.items():
|
|
if var_name in cls.tracked_vars() and not os.getenv(var_name):
|
|
os.environ[var_name] = var_value
|
|
applied[var_name] = var_value
|
|
|
|
return applied
|
|
|
|
@classmethod
|
|
def capture_current(cls) -> dict[str, Any]:
|
|
env_vars = {}
|
|
for var_name in cls.tracked_vars():
|
|
value = os.getenv(var_name)
|
|
if value:
|
|
env_vars[var_name] = value
|
|
return {"env": env_vars}
|
|
|
|
@classmethod
|
|
def save_current(cls) -> bool:
|
|
existing = cls.load().get("env", {})
|
|
current = cls.capture_current().get("env", {})
|
|
merged = {**existing, **current}
|
|
return cls.save({"env": merged})
|
|
|
|
|
|
def apply_saved_config() -> dict[str, str]:
|
|
return Config.apply_saved()
|
|
|
|
|
|
def save_current_config() -> bool:
|
|
return Config.save_current()
|