def test_config_service_defaults_llm_timeout_seconds(): from landppt.services.config_service import ConfigService service = ConfigService(env_file=".env.example") assert service.config_schema["llm_timeout_seconds"]["default"] == "600" def test_db_config_service_defaults_llm_timeout_seconds(): from landppt.services.db_config_service import DatabaseConfigService service = DatabaseConfigService() assert service.config_schema["llm_timeout_seconds"]["default"] == "600" def test_get_user_ai_provider_config_sync_includes_llm_timeout_seconds(monkeypatch): class FakeDBConfigService: def get_all_config_sync(self, user_id=None): assert user_id == 7 return { "default_ai_provider": "openai", "openai_api_key": "sync-openai-key", "openai_base_url": "https://api.example.com/v1", "openai_model": "gpt-sync", "llm_timeout_seconds": "900", } import landppt.services.db_config_service as db_mod monkeypatch.setattr(db_mod, "get_db_config_service", lambda: FakeDBConfigService(), raising=True) config = db_mod.get_user_ai_provider_config_sync(7) assert config["provider_name"] == "openai" assert config["llm_timeout_seconds"] == "900" def test_openai_compatible_timeout_uses_unified_llm_timeout(): from landppt.ai.providers import _get_httpx_timeout_seconds assert _get_httpx_timeout_seconds({}) == 600.0 assert _get_httpx_timeout_seconds({"llm_timeout_seconds": "900"}) == 900.0 assert _get_httpx_timeout_seconds({"timeout": 45}) == 45.0 def test_ai_provider_factory_reuses_provider_for_same_config(): from landppt.ai.base import AIProvider from landppt.ai.providers import AIProviderFactory class DummyProvider(AIProvider): async def chat_completion(self, messages, **kwargs): raise NotImplementedError async def text_completion(self, prompt, **kwargs): raise NotImplementedError old_provider = AIProviderFactory._providers.get("dummy") AIProviderFactory._providers["dummy"] = DummyProvider AIProviderFactory.clear_cache() try: first = AIProviderFactory.create_provider("dummy", {"model": "m1", "api_key": "k"}) second = AIProviderFactory.create_provider("dummy", {"api_key": "k", "model": "m1"}) third = AIProviderFactory.create_provider("dummy", {"api_key": "other", "model": "m1"}) assert second is first assert third is not first finally: AIProviderFactory.clear_cache() if old_provider is None: AIProviderFactory._providers.pop("dummy", None) else: AIProviderFactory._providers["dummy"] = old_provider