fix: --config flag now fully overrides ~/.strix/cli-config.json (#457)
* fix: --config flag now fully overrides ~/.strix/cli-config.json (fixes #377) Previously, env vars applied from the default config at module import time were not cleared when --config was later processed, causing settings from ~/.strix/cli-config.json to leak into runs that specified a custom config. Track which vars were applied by the initial default-config load in Config._applied_from_default. In apply_config_override, clear those vars before applying the custom config so only the custom file's settings take effect. * Add config override regression test * Make config override test setup explicit --------- Co-authored-by: octo-patch <octo-patch@github.com> Co-authored-by: bearsyankees <bearsyankees@gmail.com>
This commit is contained in:
+10
-1
@@ -2,7 +2,7 @@ import contextlib
|
|||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any, ClassVar
|
||||||
|
|
||||||
|
|
||||||
STRIX_API_BASE = "https://models.strix.ai/api/v1"
|
STRIX_API_BASE = "https://models.strix.ai/api/v1"
|
||||||
@@ -56,6 +56,10 @@ class Config:
|
|||||||
# Config file override (set via --config CLI arg)
|
# Config file override (set via --config CLI arg)
|
||||||
_config_file_override: Path | None = None
|
_config_file_override: Path | None = None
|
||||||
|
|
||||||
|
# Tracks env vars set by the initial default-config load so they can be
|
||||||
|
# cleared when a --config override is later applied (avoids leakage).
|
||||||
|
_applied_from_default: ClassVar[dict[str, str]] = {}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _tracked_names(cls) -> list[str]:
|
def _tracked_names(cls) -> list[str]:
|
||||||
return [
|
return [
|
||||||
@@ -151,6 +155,11 @@ class Config:
|
|||||||
os.environ[var_name] = var_value
|
os.environ[var_name] = var_value
|
||||||
applied[var_name] = var_value
|
applied[var_name] = var_value
|
||||||
|
|
||||||
|
# Record what was applied from the default config so it can be cleared
|
||||||
|
# if a --config override is later provided (prevents leakage).
|
||||||
|
if cls._config_file_override is None and not force:
|
||||||
|
cls._applied_from_default = applied
|
||||||
|
|
||||||
return applied
|
return applied
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ Strix Agent Interface
|
|||||||
import argparse
|
import argparse
|
||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@@ -528,6 +529,12 @@ def pull_docker_image() -> None:
|
|||||||
|
|
||||||
|
|
||||||
def apply_config_override(config_path: str) -> None:
|
def apply_config_override(config_path: str) -> None:
|
||||||
|
# Clear env vars that were automatically applied from the default config file
|
||||||
|
# so they don't leak into the custom config context.
|
||||||
|
for var_name in Config._applied_from_default:
|
||||||
|
os.environ.pop(var_name, None)
|
||||||
|
Config._applied_from_default = {}
|
||||||
|
|
||||||
Config._config_file_override = validate_config_file(config_path)
|
Config._config_file_override = validate_config_file(config_path)
|
||||||
apply_saved_config(force=True)
|
apply_saved_config(force=True)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import json
|
||||||
|
import os
|
||||||
|
|
||||||
|
from strix.config.config import Config, apply_saved_config
|
||||||
|
|
||||||
|
|
||||||
|
def test_apply_config_override_clears_default_only_vars(monkeypatch, tmp_path) -> None:
|
||||||
|
from strix.interface.main import apply_config_override
|
||||||
|
|
||||||
|
default_cfg = tmp_path / "cli-config.json"
|
||||||
|
default_cfg.write_text(
|
||||||
|
json.dumps({"env": {"LLM_API_BASE": "https://default.api", "STRIX_LLM": "default-model"}}),
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
custom_cfg = tmp_path / "custom.json"
|
||||||
|
custom_cfg.write_text(json.dumps({"env": {"STRIX_LLM": "custom-model"}}), encoding="utf-8")
|
||||||
|
|
||||||
|
monkeypatch.setattr(Config, "_config_file_override", None)
|
||||||
|
monkeypatch.setattr(Config, "_applied_from_default", {})
|
||||||
|
monkeypatch.setattr(Config, "config_dir", classmethod(lambda cls: tmp_path))
|
||||||
|
for var_name in Config._llm_env_vars():
|
||||||
|
monkeypatch.delenv(var_name, raising=False)
|
||||||
|
|
||||||
|
apply_saved_config()
|
||||||
|
|
||||||
|
assert os.environ.get("LLM_API_BASE") == "https://default.api"
|
||||||
|
|
||||||
|
apply_config_override(str(custom_cfg))
|
||||||
|
|
||||||
|
assert os.environ.get("STRIX_LLM") == "custom-model"
|
||||||
|
assert "LLM_API_BASE" not in os.environ
|
||||||
Reference in New Issue
Block a user