From ad0247c2a84aa1f1fa6bedc26fad06d5814fda2c Mon Sep 17 00:00:00 2001 From: aaron <> Date: Mon, 8 Jun 2026 08:36:13 +0800 Subject: [PATCH] 1 --- app/config/system_config.py | 32 +++++++++++++++++++++++++++++++- tests/test_runtime_config.py | 23 +++++++++++++++-------- 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/app/config/system_config.py b/app/config/system_config.py index 0024a8f..1a45527 100644 --- a/app/config/system_config.py +++ b/app/config/system_config.py @@ -72,6 +72,35 @@ def default_llm_config(): } +def _llm_env_overrides(): + """Honor explicit LLM env vars even when DB runtime config exists.""" + overrides = {} + checks = { + "ALPHAX_LLM_ENABLED": ("enabled", lambda: _env_bool("ALPHAX_LLM_ENABLED", False)), + "ALPHAX_LLM_BASE_URL": ("base_url", lambda: _env_str("ALPHAX_LLM_BASE_URL", "https://api.openai.com/v1")), + "ALPHAX_LLM_API_KEY_ENV": ("api_key_env", lambda: _env_str("ALPHAX_LLM_API_KEY_ENV", "ALPHAX_LLM_API_KEY")), + "ALPHAX_LLM_MODEL": ("model", lambda: _env_str("ALPHAX_LLM_MODEL", "gpt-4o-mini")), + "ALPHAX_LLM_TIMEOUT": ("timeout", lambda: _env_int("ALPHAX_LLM_TIMEOUT", 20)), + "ALPHAX_LLM_MAX_TOKENS": ("max_tokens", lambda: _env_int("ALPHAX_LLM_MAX_TOKENS", 900)), + } + for env_name, (key, loader) in checks.items(): + if _env_present(env_name): + overrides[key] = loader() + module_overrides = {} + module_checks = { + "ALPHAX_LLM_RECOMMENDATIONS_ENABLED": ("recommendations", lambda: _env_bool("ALPHAX_LLM_RECOMMENDATIONS_ENABLED", True)), + "ALPHAX_LLM_SENTIMENT_ENABLED": ("sentiment", lambda: _env_bool("ALPHAX_LLM_SENTIMENT_ENABLED", True)), + "ALPHAX_LLM_REVIEW_ENABLED": ("review", lambda: _env_bool("ALPHAX_LLM_REVIEW_ENABLED", True)), + "ALPHAX_LLM_CHAT_ENABLED": ("chat", lambda: _env_bool("ALPHAX_LLM_CHAT_ENABLED", True)), + } + for env_name, (key, loader) in module_checks.items(): + if _env_present(env_name): + module_overrides[key] = loader() + if module_overrides: + overrides["modules"] = module_overrides + return overrides + + def default_paper_trading_config(): # One shared default keeps buy-now entries and wait-pullback orders from # drifting into two unrelated RR standards. The explicit entry/order envs @@ -457,7 +486,8 @@ def llm_config(): if cfg is None: _seed_one("llm", default_llm_config(), "LLM provider and module switches; API key remains in env") cfg = get_llm_config(default=None) - return cfg or default_llm_config() + merged = deep_merge(default_llm_config(), cfg or {}) + return deep_merge(merged, _llm_env_overrides()) def paper_trading_config(): diff --git a/tests/test_runtime_config.py b/tests/test_runtime_config.py index 8645d36..6582a20 100644 --- a/tests/test_runtime_config.py +++ b/tests/test_runtime_config.py @@ -216,13 +216,19 @@ def test_runtime_config_api_blocks_protected_system_config_updates(): assert delete_resp.status_code == 403 -def test_llm_system_config_overrides_env_defaults(monkeypatch): - monkeypatch.setenv("ALPHAX_LLM_ENABLED", "0") +def test_llm_explicit_env_overrides_stale_system_config(monkeypatch): + monkeypatch.setenv("ALPHAX_LLM_ENABLED", "1") + monkeypatch.setenv("ALPHAX_LLM_BASE_URL", "https://api.deepseek.com") + monkeypatch.setenv("ALPHAX_LLM_API_KEY_ENV", "DEEPSEEK_API_KEY") + monkeypatch.setenv("ALPHAX_LLM_MODEL", "deepseek-chat") + monkeypatch.setenv("ALPHAX_LLM_TIMEOUT", "45") + monkeypatch.setenv("ALPHAX_LLM_MAX_TOKENS", "1200") + monkeypatch.setenv("ALPHAX_LLM_SENTIMENT_ENABLED", "1") set_config("system", "llm", { "enabled": True, "base_url": "https://llm.example/v1", "api_key_env": "TEST_LLM_KEY", - "model": "test-model", + "model": "gpt-5.4", "timeout": 33, "max_tokens": 444, "modules": {"sentiment": False, "review": True}, @@ -231,11 +237,12 @@ def test_llm_system_config_overrides_env_defaults(monkeypatch): params = get_llm_params() assert params["enabled"] is True - assert params["base_url"] == "https://llm.example/v1" - assert params["model"] == "test-model" - assert params["timeout"] == 33 - assert params["max_tokens"] == 444 - assert get_llm_module_enabled("sentiment") is False + assert params["base_url"] == "https://api.deepseek.com" + assert params["api_key_env"] == "DEEPSEEK_API_KEY" + assert params["model"] == "deepseek-chat" + assert params["timeout"] == 45 + assert params["max_tokens"] == 1200 + assert get_llm_module_enabled("sentiment") is True assert get_llm_module_enabled("review") is True