from __future__ import annotations import json import pytest from world_simulator.config import apply_runtime_env_overrides, load_game_config, parse_game_config def test_parse_game_config() -> None: config = parse_game_config( { "world": {"width": 80, "depth": 60, "terrain": "plain_green", "seed": 7}, "npcs": {"count": 3}, "simulation": {"tick_ms": 500}, "server": {"host": "127.0.0.1", "port": 8000}, } ) assert config.world.width == 80 assert config.world.depth == 60 assert config.npcs.count == 3 assert config.world.seed == 7 assert config.connector.type == "deterministic" def test_parse_openai_compatible_connector() -> None: config = parse_game_config( { "world": {"width": 80, "depth": 60, "terrain": "plain_green", "seed": 7}, "npcs": {"count": 3}, "simulation": {"tick_ms": 500}, "server": {"host": "127.0.0.1", "port": 8000}, "connector": { "type": "openai_compatible", "base_url": "http://llm.local/v1", "model": "test-model", "max_tokens": 256, "temperature": 0.6, "top_p": 0.95, "tool_choice": "required", "max_parallel_npc_calls": 3, }, "god_console": { "type": "openai_compatible", "base_url": "https://georgij-sawin--world-simulator-qwen36-27b-h100-serve.modal.run/v1", "model": "qwen3.6-27b-h100-fp8", "max_tokens": 1200, "tool_choice": "required", }, } ) assert config.connector.type == "openai_compatible" assert config.connector.base_url == "http://llm.local/v1" assert config.connector.model == "test-model" assert config.connector.max_tokens == 256 assert config.connector.temperature == 0.6 assert config.connector.top_p == 0.95 assert config.connector.tool_choice == "required" assert config.connector.max_parallel_npc_calls == 3 assert config.god_console is not None assert ( config.god_console.base_url == "https://georgij-sawin--world-simulator-qwen36-27b-h100-serve.modal.run/v1" ) assert config.god_console.model == "qwen3.6-27b-h100-fp8" assert config.god_console.max_tokens == 1200 assert config.god_console.tool_choice == "required" def test_rejects_negative_npc_count() -> None: with pytest.raises(ValueError, match="count"): parse_game_config( { "world": {"width": 80, "depth": 60, "terrain": "plain_green", "seed": 7}, "npcs": {"count": -1}, "simulation": {"tick_ms": 500}, "server": {"host": "127.0.0.1", "port": 8000}, } ) def test_load_game_config_reads_dotenv(tmp_path, monkeypatch: pytest.MonkeyPatch) -> None: monkeypatch.chdir(tmp_path) config_dir = tmp_path / "config" config_dir.mkdir() config_path = config_dir / "game.json" config_path.write_text( json.dumps( { "world": {"width": 80, "depth": 60, "terrain": "plain_green", "seed": 7}, "npcs": {"count": 3}, "simulation": {"tick_ms": 500}, "server": {"host": "127.0.0.1", "port": 8000}, "connector": { "type": "openai_compatible", "base_url_env": "TEST_OPENAI_BASE_URL", "model_env": "TEST_OPENAI_MODEL", "api_key_env": "TEST_OPENAI_API_KEY", }, } ), encoding="utf-8", ) (tmp_path / ".env").write_text( "\n".join( [ "TEST_OPENAI_BASE_URL=https://api.openai.com/v1", "TEST_OPENAI_MODEL=your-tool-capable-model", "TEST_OPENAI_API_KEY=test-key", ] ), encoding="utf-8", ) config = load_game_config(config_path) assert config.connector.base_url == "https://api.openai.com/v1" assert config.connector.model == "your-tool-capable-model" assert config.connector.api_key_env == "TEST_OPENAI_API_KEY" def test_load_game_config_does_not_override_existing_env( tmp_path, monkeypatch: pytest.MonkeyPatch, ) -> None: monkeypatch.chdir(tmp_path) monkeypatch.setenv("TEST_OPENAI_BASE_URL", "https://already-set.example/v1") config_path = tmp_path / "game.json" config_path.write_text( json.dumps( { "world": {"width": 80, "depth": 60, "terrain": "plain_green", "seed": 7}, "npcs": {"count": 3}, "simulation": {"tick_ms": 500}, "server": {"host": "127.0.0.1", "port": 8000}, "connector": { "type": "openai_compatible", "base_url_env": "TEST_OPENAI_BASE_URL", "model": "test-model", }, } ), encoding="utf-8", ) (tmp_path / ".env").write_text( "TEST_OPENAI_BASE_URL=https://from-dotenv.example/v1", encoding="utf-8", ) config = load_game_config(config_path) assert config.connector.base_url == "https://already-set.example/v1" def test_force_deterministic_env_overrides_runtime_connectors( monkeypatch: pytest.MonkeyPatch, ) -> None: monkeypatch.setenv("WORLD_SIMULATOR_FORCE_DETERMINISTIC", "1") config = parse_game_config( { "world": {"width": 80, "depth": 60, "terrain": "plain_green", "seed": 7}, "npcs": {"count": 3}, "simulation": {"tick_ms": 500}, "server": {"host": "127.0.0.1", "port": 8000}, "connector": { "type": "openai_compatible", "base_url": "https://workspace--npc-serve.modal.run/v1", "model": "npc-model", }, "god_console": { "type": "openai_compatible", "base_url": "https://workspace--god-serve.modal.run/v1", "model": "god-model", }, "overseer": { "mode": "autopilot", "connector": { "type": "openai_compatible", "base_url": "https://workspace--overseer-serve.modal.run/v1", "model": "overseer-model", }, }, } ) config = apply_runtime_env_overrides(config) assert config.connector.type == "deterministic" assert config.god_console is None assert config.overseer.mode == "autopilot" assert config.overseer.connector.type == "deterministic"