from __future__ import annotations from runtime.planner_config import ( DEFAULT_MODEL_BY_PROVIDER, DEFAULT_PROVIDER, DEFAULT_TIMEOUT_SECONDS, PlannerConfig, load_config, ) _NO_RELEVANT_VARS = {"UNRELATED": "1"} def test_load_config_defaults_when_unset() -> None: config = load_config(_NO_RELEVANT_VARS) assert config == PlannerConfig( enabled=False, provider=DEFAULT_PROVIDER, model="", timeout=DEFAULT_TIMEOUT_SECONDS, ) assert config.resolved_model() == DEFAULT_MODEL_BY_PROVIDER[DEFAULT_PROVIDER] def test_load_config_parses_enabled_truthy_values() -> None: for value in ["1", "true", "True", "yes", "on", "enabled"]: assert load_config({"AI_PLANNER_ENABLED": value}).enabled is True def test_load_config_parses_enabled_falsy_values() -> None: for value in ["0", "false", "no", "off", ""]: assert load_config({"AI_PLANNER_ENABLED": value}).enabled is False def test_load_config_selects_provider_and_resolves_default_model() -> None: config = load_config({"AI_PLANNER_PROVIDER": "openai"}) assert config.provider == "openai" assert config.resolved_model() == "gpt-5.6" def test_load_config_anthropic_default_model() -> None: config = load_config({"AI_PLANNER_PROVIDER": "anthropic"}) assert config.resolved_model() == "claude-sonnet-5" def test_load_config_falls_back_to_default_provider_when_unsupported() -> None: config = load_config({"AI_PLANNER_PROVIDER": "not-a-real-provider"}) assert config.provider == DEFAULT_PROVIDER def test_load_config_model_override_wins_regardless_of_provider() -> None: config = load_config( {"AI_PLANNER_PROVIDER": "openai", "AI_PLANNER_MODEL": "custom-model"} ) assert config.resolved_model() == "custom-model" def test_load_config_parses_valid_timeout() -> None: config = load_config({"AI_PLANNER_TIMEOUT_SECONDS": "12.5"}) assert config.timeout == 12.5 def test_load_config_falls_back_to_default_timeout_when_invalid_or_non_positive() -> None: for value in ["not-a-number", "0", "-5"]: config = load_config({"AI_PLANNER_TIMEOUT_SECONDS": value, **_NO_RELEVANT_VARS}) assert config.timeout == DEFAULT_TIMEOUT_SECONDS