From d0e1388ca928f984877a2a576b67cf0bdf362096 Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Fri, 17 Apr 2026 12:32:03 -0700 Subject: [PATCH] fix(tests): make AIAgent constructor calls self-contained (#11755) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(tests): make AIAgent constructor calls self-contained (no env leakage) Tests in tests/run_agent/ were constructing AIAgent() without passing both api_key and base_url, then relying on leaked state from other tests in the same xdist worker (or process-level env vars) to keep provider resolution happy. Under hermetic conftest + pytest-split, that state is gone and the tests fail with 'No LLM provider configured'. Fix: pass both api_key and base_url explicitly on 47 AIAgent() construction sites across 13 files. AIAgent.__init__ with both set takes the direct-construction path (line 960 in run_agent.py) and skips the resolver entirely. One call site (test_none_base_url_passed_as_none) left alone — that test asserts behavior for base_url=None specifically. This is a prerequisite for any future matrix-split or stricter isolation work, and lands cleanly on its own. Validation: - tests/run_agent/ full: 760 passed, 0 failed (local) - Previously relied on cross-test pollution; now self-contained * fix(tests): update opencode-go model order assertion to match kimi-k2.5-first commit 78a74bb promoted kimi-k2.5 to first position in model suggestion lists but didn't update this test, which has been failing on main since. Reorder expected list to match the new canonical order. --- .../test_opencode_go_in_model_list.py | 2 +- .../test_1630_context_overflow_loop.py | 1 + tests/run_agent/test_413_compression.py | 1 + tests/run_agent/test_860_dedup.py | 6 +++ .../run_agent/test_compression_persistence.py | 2 + ...t_create_openai_client_kwargs_isolation.py | 2 + .../test_create_openai_client_reuse.py | 2 + tests/run_agent/test_fallback_model.py | 1 + .../test_plugin_context_engine_init.py | 2 + tests/run_agent/test_provider_fallback.py | 1 + tests/run_agent/test_provider_parity.py | 3 ++ tests/run_agent/test_run_agent.py | 15 +++++- tests/run_agent/test_streaming.py | 48 +++++++++++++++++++ .../test_token_persistence_non_cli.py | 1 + 14 files changed, 85 insertions(+), 2 deletions(-) diff --git a/tests/hermes_cli/test_opencode_go_in_model_list.py b/tests/hermes_cli/test_opencode_go_in_model_list.py index cb8b3b142..a84701f09 100644 --- a/tests/hermes_cli/test_opencode_go_in_model_list.py +++ b/tests/hermes_cli/test_opencode_go_in_model_list.py @@ -15,7 +15,7 @@ def test_opencode_go_appears_when_api_key_set(): opencode_go = next((p for p in providers if p["slug"] == "opencode-go"), None) assert opencode_go is not None, "opencode-go should appear when OPENCODE_GO_API_KEY is set" - assert opencode_go["models"] == ["glm-5.1", "glm-5", "kimi-k2.5", "mimo-v2-pro", "mimo-v2-omni", "minimax-m2.7", "minimax-m2.5"] + assert opencode_go["models"] == ["kimi-k2.5", "glm-5.1", "glm-5", "mimo-v2-pro", "mimo-v2-omni", "minimax-m2.7", "minimax-m2.5"] # opencode-go can appear as "built-in" (from PROVIDER_TO_MODELS_DEV when # models.dev is reachable) or "hermes" (from HERMES_OVERLAYS fallback when # the API is unavailable, e.g. in CI). diff --git a/tests/run_agent/test_1630_context_overflow_loop.py b/tests/run_agent/test_1630_context_overflow_loop.py index c33aaa967..f69b01241 100644 --- a/tests/run_agent/test_1630_context_overflow_loop.py +++ b/tests/run_agent/test_1630_context_overflow_loop.py @@ -32,6 +32,7 @@ class TestGeneric400Heuristic: from run_agent import AIAgent a = AIAgent( api_key="test-key-12345", + base_url="https://openrouter.ai/api/v1", quiet_mode=True, skip_context_files=True, skip_memory=True, diff --git a/tests/run_agent/test_413_compression.py b/tests/run_agent/test_413_compression.py index 1d6f6cebb..e8835c641 100644 --- a/tests/run_agent/test_413_compression.py +++ b/tests/run_agent/test_413_compression.py @@ -69,6 +69,7 @@ def agent(): ): a = AIAgent( api_key="test-key-1234567890", + base_url="https://openrouter.ai/api/v1", quiet_mode=True, skip_context_files=True, skip_memory=True, diff --git a/tests/run_agent/test_860_dedup.py b/tests/run_agent/test_860_dedup.py index 350d2a21a..89f4c010b 100644 --- a/tests/run_agent/test_860_dedup.py +++ b/tests/run_agent/test_860_dedup.py @@ -29,6 +29,8 @@ class TestFlushDeduplication: with patch.dict(os.environ, {"OPENROUTER_API_KEY": "test-key"}): from run_agent import AIAgent agent = AIAgent( + api_key="test-key", + base_url="https://openrouter.ai/api/v1", model="test/model", quiet_mode=True, session_db=session_db, @@ -271,6 +273,8 @@ class TestFlushIdxInit: with patch.dict(os.environ, {"OPENROUTER_API_KEY": "test-key"}): from run_agent import AIAgent agent = AIAgent( + api_key="test-key", + base_url="https://openrouter.ai/api/v1", model="test/model", quiet_mode=True, skip_context_files=True, @@ -283,6 +287,8 @@ class TestFlushIdxInit: with patch.dict(os.environ, {"OPENROUTER_API_KEY": "test-key"}): from run_agent import AIAgent agent = AIAgent( + api_key="test-key", + base_url="https://openrouter.ai/api/v1", model="test/model", quiet_mode=True, skip_context_files=True, diff --git a/tests/run_agent/test_compression_persistence.py b/tests/run_agent/test_compression_persistence.py index 272b39bfe..46ab963d4 100644 --- a/tests/run_agent/test_compression_persistence.py +++ b/tests/run_agent/test_compression_persistence.py @@ -37,6 +37,8 @@ class TestFlushAfterCompression: with patch.dict(os.environ, {"OPENROUTER_API_KEY": "test-key"}): from run_agent import AIAgent agent = AIAgent( + api_key="test-key", + base_url="https://openrouter.ai/api/v1", model="test/model", quiet_mode=True, session_db=session_db, diff --git a/tests/run_agent/test_create_openai_client_kwargs_isolation.py b/tests/run_agent/test_create_openai_client_kwargs_isolation.py index 506e1486c..98b7ff480 100644 --- a/tests/run_agent/test_create_openai_client_kwargs_isolation.py +++ b/tests/run_agent/test_create_openai_client_kwargs_isolation.py @@ -19,6 +19,8 @@ from run_agent import AIAgent def test_create_openai_client_does_not_mutate_input_kwargs(mock_openai): mock_openai.return_value = MagicMock() agent = AIAgent( + api_key="test-key", + base_url="https://openrouter.ai/api/v1", model="test/model", quiet_mode=True, skip_context_files=True, diff --git a/tests/run_agent/test_create_openai_client_reuse.py b/tests/run_agent/test_create_openai_client_reuse.py index 8183e7eea..0eac567ae 100644 --- a/tests/run_agent/test_create_openai_client_reuse.py +++ b/tests/run_agent/test_create_openai_client_reuse.py @@ -23,6 +23,8 @@ from run_agent import AIAgent def _make_agent(): return AIAgent( + api_key="test-key", + base_url="https://openrouter.ai/api/v1", model="test/model", quiet_mode=True, skip_context_files=True, diff --git a/tests/run_agent/test_fallback_model.py b/tests/run_agent/test_fallback_model.py index ac693caf0..6491bd686 100644 --- a/tests/run_agent/test_fallback_model.py +++ b/tests/run_agent/test_fallback_model.py @@ -36,6 +36,7 @@ def _make_agent(fallback_model=None): ): agent = AIAgent( api_key="test-key", + base_url="https://openrouter.ai/api/v1", quiet_mode=True, skip_context_files=True, skip_memory=True, diff --git a/tests/run_agent/test_plugin_context_engine_init.py b/tests/run_agent/test_plugin_context_engine_init.py index 7583d9e75..60e898890 100644 --- a/tests/run_agent/test_plugin_context_engine_init.py +++ b/tests/run_agent/test_plugin_context_engine_init.py @@ -45,6 +45,7 @@ def test_plugin_engine_gets_context_length_on_init(): agent = AIAgent( api_key="test-key-1234567890", + base_url="https://openrouter.ai/api/v1", quiet_mode=True, skip_context_files=True, skip_memory=True, @@ -75,6 +76,7 @@ def test_plugin_engine_update_model_args(): agent = AIAgent( model="openrouter/auto", api_key="test-key-1234567890", + base_url="https://openrouter.ai/api/v1", quiet_mode=True, skip_context_files=True, skip_memory=True, diff --git a/tests/run_agent/test_provider_fallback.py b/tests/run_agent/test_provider_fallback.py index 2bb210955..e441bfd33 100644 --- a/tests/run_agent/test_provider_fallback.py +++ b/tests/run_agent/test_provider_fallback.py @@ -19,6 +19,7 @@ def _make_agent(fallback_model=None): ): agent = AIAgent( api_key="test-key", + base_url="https://openrouter.ai/api/v1", quiet_mode=True, skip_context_files=True, skip_memory=True, diff --git a/tests/run_agent/test_provider_parity.py b/tests/run_agent/test_provider_parity.py index 1817e44a6..bdbe89f3a 100644 --- a/tests/run_agent/test_provider_parity.py +++ b/tests/run_agent/test_provider_parity.py @@ -60,6 +60,9 @@ def _make_agent(monkeypatch, provider, api_mode="chat_completions", base_url="ht ) if model: kwargs["model"] = model + base_url="https://openrouter.ai/api/v1", + api_key="test-key", + base_url="https://openrouter.ai/api/v1", return AIAgent(**kwargs) diff --git a/tests/run_agent/test_run_agent.py b/tests/run_agent/test_run_agent.py index 46eec2cf7..86f95580f 100644 --- a/tests/run_agent/test_run_agent.py +++ b/tests/run_agent/test_run_agent.py @@ -55,6 +55,7 @@ def agent(): ): a = AIAgent( api_key="test-key-1234567890", + base_url="https://openrouter.ai/api/v1", quiet_mode=True, skip_context_files=True, skip_memory=True, @@ -76,6 +77,7 @@ def agent_with_memory_tool(): ): a = AIAgent( api_key="test-k...7890", + base_url="https://openrouter.ai/api/v1", quiet_mode=True, skip_context_files=True, skip_memory=True, @@ -112,12 +114,14 @@ def test_aiagent_reuses_existing_errors_log_handler(): ): AIAgent( api_key="test-k...7890", + base_url="https://openrouter.ai/api/v1", quiet_mode=True, skip_context_files=True, skip_memory=True, ) AIAgent( api_key="test-k...7890", + base_url="https://openrouter.ai/api/v1", quiet_mode=True, skip_context_files=True, skip_memory=True, @@ -491,6 +495,7 @@ class TestInit: ): a = AIAgent( api_key="test-key-1234567890", + base_url="https://openrouter.ai/api/v1", model="openai/gpt-4o", quiet_mode=True, skip_context_files=True, @@ -542,6 +547,7 @@ class TestInit: ): a = AIAgent( api_key="test-key-1234567890", + base_url="https://openrouter.ai/api/v1", quiet_mode=True, skip_context_files=True, skip_memory=True, @@ -557,6 +563,7 @@ class TestInit: ): a = AIAgent( api_key="test-key-1234567890", + base_url="https://openrouter.ai/api/v1", quiet_mode=True, skip_context_files=True, skip_memory=True, @@ -694,6 +701,7 @@ class TestBuildSystemPrompt: ): agent = AIAgent( api_key="test-k...7890", + base_url="https://openrouter.ai/api/v1", quiet_mode=True, skip_context_files=True, skip_memory=True, @@ -726,6 +734,7 @@ class TestToolUseEnforcementConfig: a = AIAgent( model=model, api_key="test-key-1234567890", + base_url="https://openrouter.ai/api/v1", quiet_mode=True, skip_context_files=True, skip_memory=True, @@ -822,6 +831,7 @@ class TestToolUseEnforcementConfig: ): a = AIAgent( api_key="test-key-1234567890", + base_url="https://openrouter.ai/api/v1", quiet_mode=True, skip_context_files=True, skip_memory=True, @@ -3433,7 +3443,7 @@ class TestAnthropicBaseUrlPassthrough: ): mock_build.return_value = MagicMock() a = AIAgent( - api_key="sk-ant-api03-test1234567890", + api_key="sk-ant...7890", api_mode="anthropic_messages", quiet_mode=True, skip_context_files=True, @@ -3457,6 +3467,7 @@ class TestAnthropicCredentialRefresh: mock_build.side_effect = [old_client, new_client] agent = AIAgent( api_key="sk-ant-oat01-stale-token", + base_url="https://openrouter.ai/api/v1", api_mode="anthropic_messages", quiet_mode=True, skip_context_files=True, @@ -3487,6 +3498,7 @@ class TestAnthropicCredentialRefresh: ): agent = AIAgent( api_key="sk-ant-oat01-same-token", + base_url="https://openrouter.ai/api/v1", api_mode="anthropic_messages", quiet_mode=True, skip_context_files=True, @@ -3514,6 +3526,7 @@ class TestAnthropicCredentialRefresh: ): agent = AIAgent( api_key="sk-ant-oat01-current-token", + base_url="https://openrouter.ai/api/v1", api_mode="anthropic_messages", quiet_mode=True, skip_context_files=True, diff --git a/tests/run_agent/test_streaming.py b/tests/run_agent/test_streaming.py index 97dcffc67..73a987202 100644 --- a/tests/run_agent/test_streaming.py +++ b/tests/run_agent/test_streaming.py @@ -80,6 +80,8 @@ class TestStreamingAccumulator: mock_create.return_value = mock_client agent = AIAgent( + api_key="test-key", + base_url="https://openrouter.ai/api/v1", model="test/model", quiet_mode=True, skip_context_files=True, @@ -120,6 +122,8 @@ class TestStreamingAccumulator: mock_create.return_value = mock_client agent = AIAgent( + api_key="test-key", + base_url="https://openrouter.ai/api/v1", model="test/model", quiet_mode=True, skip_context_files=True, @@ -167,6 +171,8 @@ class TestStreamingAccumulator: mock_create.return_value = mock_client agent = AIAgent( + api_key="test-key", + base_url="https://openrouter.ai/api/v1", model="test/model", quiet_mode=True, skip_context_files=True, @@ -205,6 +211,8 @@ class TestStreamingAccumulator: mock_create.return_value = mock_client agent = AIAgent( + api_key="test-key", + base_url="https://openrouter.ai/api/v1", model="test/model", quiet_mode=True, skip_context_files=True, @@ -245,6 +253,8 @@ class TestStreamingCallbacks: mock_create.return_value = mock_client agent = AIAgent( + api_key="test-key", + base_url="https://openrouter.ai/api/v1", model="test/model", quiet_mode=True, skip_context_files=True, @@ -277,6 +287,8 @@ class TestStreamingCallbacks: mock_create.return_value = mock_client agent = AIAgent( + api_key="test-key", + base_url="https://openrouter.ai/api/v1", model="test/model", quiet_mode=True, skip_context_files=True, @@ -308,6 +320,8 @@ class TestStreamingCallbacks: mock_create.return_value = mock_client agent = AIAgent( + api_key="test-key", + base_url="https://openrouter.ai/api/v1", model="test/model", quiet_mode=True, skip_context_files=True, @@ -346,6 +360,8 @@ class TestStreamingCallbacks: mock_create.return_value = mock_client agent = AIAgent( + api_key="test-key", + base_url="https://openrouter.ai/api/v1", model="test/model", quiet_mode=True, skip_context_files=True, @@ -381,6 +397,8 @@ class TestStreamingCallbacks: mock_create.return_value = mock_client agent = AIAgent( + api_key="test-key", + base_url="https://openrouter.ai/api/v1", model="test/model", quiet_mode=True, skip_context_files=True, @@ -428,6 +446,8 @@ class TestStreamingFallback: mock_create.return_value = mock_client agent = AIAgent( + api_key="test-key", + base_url="https://openrouter.ai/api/v1", model="test/model", quiet_mode=True, skip_context_files=True, @@ -455,6 +475,8 @@ class TestStreamingFallback: mock_create.return_value = mock_client agent = AIAgent( + api_key="test-key", + base_url="https://openrouter.ai/api/v1", model="test/model", quiet_mode=True, skip_context_files=True, @@ -477,6 +499,8 @@ class TestStreamingFallback: mock_create.return_value = mock_client agent = AIAgent( + api_key="test-key", + base_url="https://openrouter.ai/api/v1", model="test/model", quiet_mode=True, skip_context_files=True, @@ -500,6 +524,8 @@ class TestStreamingFallback: mock_create.return_value = mock_client agent = AIAgent( + api_key="test-key", + base_url="https://openrouter.ai/api/v1", model="test/model", quiet_mode=True, skip_context_files=True, @@ -542,6 +568,8 @@ class TestStreamingFallback: mock_create.return_value = mock_client agent = AIAgent( + api_key="test-key", + base_url="https://openrouter.ai/api/v1", model="test/model", quiet_mode=True, skip_context_files=True, @@ -577,6 +605,8 @@ class TestStreamingFallback: mock_create.return_value = mock_client agent = AIAgent( + api_key="test-key", + base_url="https://openrouter.ai/api/v1", model="test/model", quiet_mode=True, skip_context_files=True, @@ -619,6 +649,8 @@ class TestReasoningStreaming: mock_create.return_value = mock_client agent = AIAgent( + api_key="test-key", + base_url="https://openrouter.ai/api/v1", model="test/model", quiet_mode=True, skip_context_files=True, @@ -646,6 +678,8 @@ class TestHasStreamConsumers: def test_no_consumers(self): from run_agent import AIAgent agent = AIAgent( + api_key="test-key", + base_url="https://openrouter.ai/api/v1", model="test/model", quiet_mode=True, skip_context_files=True, @@ -656,6 +690,8 @@ class TestHasStreamConsumers: def test_delta_callback_set(self): from run_agent import AIAgent agent = AIAgent( + api_key="test-key", + base_url="https://openrouter.ai/api/v1", model="test/model", quiet_mode=True, skip_context_files=True, @@ -667,6 +703,8 @@ class TestHasStreamConsumers: def test_stream_callback_set(self): from run_agent import AIAgent agent = AIAgent( + api_key="test-key", + base_url="https://openrouter.ai/api/v1", model="test/model", quiet_mode=True, skip_context_files=True, @@ -688,6 +726,8 @@ class TestCodexStreamCallbacks: deltas = [] agent = AIAgent( + api_key="test-key", + base_url="https://openrouter.ai/api/v1", model="test/model", quiet_mode=True, skip_context_files=True, @@ -729,6 +769,8 @@ class TestCodexStreamCallbacks: from run_agent import AIAgent agent = AIAgent( + api_key="test-key", + base_url="https://openrouter.ai/api/v1", model="test/model", quiet_mode=True, skip_context_files=True, @@ -792,6 +834,8 @@ class TestCodexStreamCallbacks: ) agent = AIAgent( + api_key="test-key", + base_url="https://openrouter.ai/api/v1", model="test/model", quiet_mode=True, skip_context_files=True, @@ -810,6 +854,8 @@ class TestCodexStreamCallbacks: from run_agent import AIAgent agent = AIAgent( + api_key="test-key", + base_url="https://openrouter.ai/api/v1", model="test/model", quiet_mode=True, skip_context_files=True, @@ -861,6 +907,8 @@ class TestAnthropicStreamCallbacks: from run_agent import AIAgent agent = AIAgent( + api_key="test-key", + base_url="https://openrouter.ai/api/v1", model="test/model", quiet_mode=True, skip_context_files=True, diff --git a/tests/run_agent/test_token_persistence_non_cli.py b/tests/run_agent/test_token_persistence_non_cli.py index d25cf07ab..044d8abb3 100644 --- a/tests/run_agent/test_token_persistence_non_cli.py +++ b/tests/run_agent/test_token_persistence_non_cli.py @@ -22,6 +22,7 @@ def _make_agent(session_db, *, platform: str): ): agent = AIAgent( api_key="test-key", + base_url="https://openrouter.ai/api/v1", quiet_mode=True, skip_context_files=True, skip_memory=True,