diff --git a/run_agent.py b/run_agent.py index cc7603fae..2b022c892 100644 --- a/run_agent.py +++ b/run_agent.py @@ -6260,6 +6260,10 @@ class AIAgent: # falling through to OpenRouter defaults. fb_base_url_hint = (fb.get("base_url") or "").strip() or None fb_api_key_hint = (fb.get("api_key") or "").strip() or None + if not fb_api_key_hint: + fb_key_env = (fb.get("key_env") or "").strip() + if fb_key_env: + fb_api_key_hint = os.getenv(fb_key_env, "").strip() or None # For Ollama Cloud endpoints, pull OLLAMA_API_KEY from env # when no explicit key is in the fallback config. Host match # (not substring) — see GHSA-76xc-57q6-vm5m. diff --git a/tests/run_agent/test_provider_fallback.py b/tests/run_agent/test_provider_fallback.py index e441bfd33..88982437e 100644 --- a/tests/run_agent/test_provider_fallback.py +++ b/tests/run_agent/test_provider_fallback.py @@ -155,3 +155,29 @@ class TestFallbackChainAdvancement: ] assert agent._try_activate_fallback() is True assert agent.model == "gpt-4o" + + def test_resolves_key_env_for_fallback_provider(self): + fbs = [ + { + "provider": "custom", + "model": "fallback-model", + "base_url": "https://fallback.example/v1", + "key_env": "MY_FALLBACK_KEY", + } + ] + agent = _make_agent(fallback_model=fbs) + with ( + patch.dict("os.environ", {"MY_FALLBACK_KEY": "env-secret"}, clear=False), + patch( + "agent.auxiliary_client.resolve_provider_client", + return_value=( + _mock_client( + base_url="https://fallback.example/v1", + api_key="env-secret", + ), + "fallback-model", + ), + ) as mock_rpc, + ): + assert agent._try_activate_fallback() is True + assert mock_rpc.call_args.kwargs["explicit_api_key"] == "env-secret"