feat: add centralized Config class with auto-save to ~/.strix/cli-config.json

- Add Config class with all env var defaults in one place
- Auto-load saved config on startup (env vars take precedence)
- Auto-save config after successful LLM warm-up
- Replace scattered os.getenv() calls with Config.get()
This commit is contained in:
0xallam
2026-01-10 15:49:03 -08:00
committed by Ahmed Allam
parent 2d35a4e0bd
commit 543b785d1a
13 changed files with 184 additions and 45 deletions
+3 -3
View File
@@ -1,4 +1,4 @@
import os
from strix.config import Config
class LLMConfig:
@@ -10,7 +10,7 @@ class LLMConfig:
timeout: int | None = None,
scan_mode: str = "deep",
):
self.model_name = model_name or os.getenv("STRIX_LLM", "openai/gpt-5")
self.model_name = model_name or Config.get("strix_llm")
if not self.model_name:
raise ValueError("STRIX_LLM environment variable must be set and not empty")
@@ -18,6 +18,6 @@ class LLMConfig:
self.enable_prompt_caching = enable_prompt_caching
self.skills = skills or []
self.timeout = timeout or int(os.getenv("LLM_TIMEOUT", "300"))
self.timeout = timeout or int(Config.get("llm_timeout")) # type: ignore[arg-type]
self.scan_mode = scan_mode if scan_mode in ["quick", "standard", "deep"] else "deep"
+8 -7
View File
@@ -1,11 +1,12 @@
import json
import logging
import os
import re
from typing import Any
import litellm
from strix.config import Config
logger = logging.getLogger(__name__)
@@ -154,13 +155,13 @@ def check_duplicate(
comparison_data = {"candidate": candidate_cleaned, "existing_reports": existing_cleaned}
model_name = os.getenv("STRIX_LLM", "openai/gpt-5")
api_key = os.getenv("LLM_API_KEY")
model_name = Config.get("strix_llm")
api_key = Config.get("llm_api_key")
api_base = (
os.getenv("LLM_API_BASE")
or os.getenv("OPENAI_API_BASE")
or os.getenv("LITELLM_BASE_URL")
or os.getenv("OLLAMA_API_BASE")
Config.get("llm_api_base")
or Config.get("openai_api_base")
or Config.get("litellm_base_url")
or Config.get("ollama_api_base")
)
messages = [
+7 -9
View File
@@ -1,6 +1,5 @@
import asyncio
import logging
import os
from collections.abc import AsyncIterator
from dataclasses import dataclass
from enum import Enum
@@ -16,6 +15,7 @@ from jinja2 import (
from litellm import completion_cost, stream_chunk_builder, supports_reasoning
from litellm.utils import supports_prompt_caching, supports_vision
from strix.config import Config
from strix.llm.config import LLMConfig
from strix.llm.memory_compressor import MemoryCompressor
from strix.llm.request_queue import get_global_queue
@@ -46,16 +46,14 @@ logger = logging.getLogger(__name__)
litellm.drop_params = True
litellm.modify_params = True
_LLM_API_KEY = os.getenv("LLM_API_KEY")
_LLM_API_KEY = Config.get("llm_api_key")
_LLM_API_BASE = (
os.getenv("LLM_API_BASE")
or os.getenv("OPENAI_API_BASE")
or os.getenv("LITELLM_BASE_URL")
or os.getenv("OLLAMA_API_BASE")
Config.get("llm_api_base")
or Config.get("openai_api_base")
or Config.get("litellm_base_url")
or Config.get("ollama_api_base")
)
_STRIX_REASONING_EFFORT = os.getenv(
"STRIX_REASONING_EFFORT"
) # "none", "minimal", "low", "medium", "high", or "xhigh"
_STRIX_REASONING_EFFORT = Config.get("strix_reasoning_effort")
class LLMRequestFailedError(Exception):
+3 -2
View File
@@ -1,9 +1,10 @@
import logging
import os
from typing import Any
import litellm
from strix.config import Config
logger = logging.getLogger(__name__)
@@ -150,7 +151,7 @@ class MemoryCompressor:
timeout: int = 600,
):
self.max_images = max_images
self.model_name = model_name or os.getenv("STRIX_LLM", "openai/gpt-5")
self.model_name = model_name or Config.get("strix_llm")
self.timeout = timeout
if not self.model_name:
+4 -8
View File
@@ -1,5 +1,4 @@
import asyncio
import os
import threading
import time
from collections.abc import AsyncIterator
@@ -8,16 +7,13 @@ from typing import Any
from litellm import acompletion
from litellm.types.utils import ModelResponseStream
from strix.config import Config
class LLMRequestQueue:
def __init__(self, max_concurrent: int = 1, delay_between_requests: float = 4.0):
rate_limit_delay = os.getenv("LLM_RATE_LIMIT_DELAY")
if rate_limit_delay:
delay_between_requests = float(rate_limit_delay)
rate_limit_concurrent = os.getenv("LLM_RATE_LIMIT_CONCURRENT")
if rate_limit_concurrent:
max_concurrent = int(rate_limit_concurrent)
delay_between_requests = float(Config.get("llm_rate_limit_delay")) # type: ignore[arg-type]
max_concurrent = int(Config.get("llm_rate_limit_concurrent")) # type: ignore[arg-type]
self.max_concurrent = max_concurrent
self.delay_between_requests = delay_between_requests