fix(web): use get_env_value for Firecrawl config resolution

The Firecrawl provider used os.getenv() to read FIRECRAWL_API_KEY and
FIRECRAWL_API_URL, which only checks the process environment.  When
values are supplied through Hermes's ~/.hermes/.env config mechanism
(via hermes_cli.config.get_env_value), they are not guaranteed to be
present in os.environ for every gateway/tool execution path.

Switch to get_env_value() which checks both os.environ and the .env
file, matching the pattern used by other providers (nous_subscription,
setup, discord adapter).

Fixes #40190
This commit is contained in:
liuhao1024 2026-06-06 08:17:40 +08:00 committed by Teknium
parent 3ba5ba89c2
commit 026ab4737d
3 changed files with 49 additions and 5 deletions

View file

@ -122,8 +122,10 @@ Firecrawl = _FirecrawlProxy()
def _get_direct_firecrawl_config() -> Optional[tuple]:
"""Return explicit direct Firecrawl kwargs + cache key, or None when unset."""
api_key = os.getenv("FIRECRAWL_API_KEY", "").strip()
api_url = os.getenv("FIRECRAWL_API_URL", "").strip().rstrip("/")
from hermes_cli.config import get_env_value
api_key = (get_env_value("FIRECRAWL_API_KEY") or "").strip()
api_url = (get_env_value("FIRECRAWL_API_URL") or "").strip().rstrip("/")
if not api_key and not api_url:
return None

View file

@ -787,3 +787,44 @@ class TestNonBuiltinProviderAvailability:
"web_search tool was filtered out despite custom provider being available"
assert web_extract_entry is not None, \
"web_extract tool was filtered out despite custom provider being available"
class TestFirecrawlEnvResolution:
"""Verify Firecrawl reads env values from hermes_cli.config.get_env_value,
not just os.getenv. This catches the regression reported in #40190 where
values stored in ~/.hermes/.env were invisible to the provider."""
def test_direct_config_reads_via_get_env_value(self, monkeypatch: pytest.MonkeyPatch) -> None:
"""_get_direct_firecrawl_config() must use get_env_value, not os.getenv."""
# Ensure os.environ does NOT carry the key
monkeypatch.delenv("FIRECRAWL_API_KEY", raising=False)
monkeypatch.delenv("FIRECRAWL_API_URL", raising=False)
fake_key = "fc-test-key-from-dotenv"
with patch(
"hermes_cli.config.get_env_value",
side_effect=lambda k: fake_key if k == "FIRECRAWL_API_KEY" else None,
):
from plugins.web.firecrawl.provider import _get_direct_firecrawl_config
result = _get_direct_firecrawl_config()
assert result is not None, "get_env_value fallback should find the key"
kwargs, _cache_key = result
assert kwargs["api_key"] == fake_key
def test_direct_config_reads_url_via_get_env_value(self, monkeypatch: pytest.MonkeyPatch) -> None:
"""Self-hosted URL from .env must be picked up."""
monkeypatch.delenv("FIRECRAWL_API_KEY", raising=False)
monkeypatch.delenv("FIRECRAWL_API_URL", raising=False)
fake_url = "https://firecrawl.internal.example.com"
with patch(
"hermes_cli.config.get_env_value",
side_effect=lambda k: fake_url if k == "FIRECRAWL_API_URL" else None,
):
from plugins.web.firecrawl.provider import _get_direct_firecrawl_config
result = _get_direct_firecrawl_config()
assert result is not None
kwargs, _cache_key = result
assert kwargs["api_url"] == fake_url.rstrip("/")

View file

@ -1001,8 +1001,9 @@ if __name__ == "__main__":
# Check if API keys are available
web_available = check_web_api_key()
tool_gateway_available = _is_tool_gateway_ready()
firecrawl_key_available = bool(os.getenv("FIRECRAWL_API_KEY", "").strip())
firecrawl_url_available = bool(os.getenv("FIRECRAWL_API_URL", "").strip())
from hermes_cli.config import get_env_value as _gev
firecrawl_key_available = bool((_gev("FIRECRAWL_API_KEY") or "").strip())
firecrawl_url_available = bool((_gev("FIRECRAWL_API_URL") or "").strip())
if web_available:
backend = _get_backend()
@ -1020,7 +1021,7 @@ if __name__ == "__main__":
elif backend == "ddgs":
print(" Using DuckDuckGo via ddgs package (search only)")
elif firecrawl_url_available:
print(f" Using self-hosted Firecrawl: {os.getenv('FIRECRAWL_API_URL').strip().rstrip('/')}")
print(f" Using self-hosted Firecrawl: {(_gev('FIRECRAWL_API_URL') or '').strip().rstrip('/')}")
elif firecrawl_key_available:
print(" Using direct Firecrawl cloud API")
elif tool_gateway_available: