Merge branch 'main' of github.com:NousResearch/hermes-agent into feat/ink-refactor
This commit is contained in:
@@ -10,7 +10,7 @@ import requests
|
||||
|
||||
from tools.browser_providers.base import CloudBrowserProvider
|
||||
from tools.managed_tool_gateway import resolve_managed_tool_gateway
|
||||
from tools.tool_backend_helpers import managed_nous_tools_enabled
|
||||
from tools.tool_backend_helpers import managed_nous_tools_enabled, prefers_gateway
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
_pending_create_keys: Dict[str, str] = {}
|
||||
@@ -75,7 +75,7 @@ class BrowserUseProvider(CloudBrowserProvider):
|
||||
|
||||
def _get_config_or_none(self) -> Optional[Dict[str, Any]]:
|
||||
api_key = os.environ.get("BROWSER_USE_API_KEY")
|
||||
if api_key:
|
||||
if api_key and not prefers_gateway("browser"):
|
||||
return {
|
||||
"api_key": api_key,
|
||||
"base_url": _BASE_URL,
|
||||
|
||||
@@ -39,7 +39,7 @@ from urllib.parse import urlencode
|
||||
import fal_client
|
||||
from tools.debug_helpers import DebugSession
|
||||
from tools.managed_tool_gateway import resolve_managed_tool_gateway
|
||||
from tools.tool_backend_helpers import managed_nous_tools_enabled
|
||||
from tools.tool_backend_helpers import managed_nous_tools_enabled, prefers_gateway
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -87,8 +87,9 @@ _managed_fal_client_lock = threading.Lock()
|
||||
|
||||
|
||||
def _resolve_managed_fal_gateway():
|
||||
"""Return managed fal-queue gateway config when direct FAL credentials are absent."""
|
||||
if os.getenv("FAL_KEY"):
|
||||
"""Return managed fal-queue gateway config when the user prefers the gateway
|
||||
or direct FAL credentials are absent."""
|
||||
if os.getenv("FAL_KEY") and not prefers_gateway("image_gen"):
|
||||
return None
|
||||
return resolve_managed_tool_gateway("fal-queue")
|
||||
|
||||
|
||||
@@ -762,8 +762,8 @@ def _create_environment(env_type: str, image: str, cwd: str, timeout: int,
|
||||
if modal_state["managed_mode_blocked"]:
|
||||
raise ValueError(
|
||||
"Modal backend is configured for managed mode, but "
|
||||
"HERMES_ENABLE_NOUS_MANAGED_TOOLS is not enabled and no direct "
|
||||
"Modal credentials/config were found. Enable the feature flag or "
|
||||
"a paid Nous subscription is required for the Tool Gateway and no direct "
|
||||
"Modal credentials/config were found. Log in with `hermes model` or "
|
||||
"choose TERMINAL_MODAL_MODE=direct/auto."
|
||||
)
|
||||
if modal_state["mode"] == "managed":
|
||||
@@ -1577,8 +1577,8 @@ def check_terminal_requirements() -> bool:
|
||||
if modal_state["managed_mode_blocked"]:
|
||||
logger.error(
|
||||
"Modal backend selected with TERMINAL_MODAL_MODE=managed, but "
|
||||
"HERMES_ENABLE_NOUS_MANAGED_TOOLS is not enabled and no direct "
|
||||
"Modal credentials/config were found. Enable the feature flag "
|
||||
"a paid Nous subscription is required for the Tool Gateway and no direct "
|
||||
"Modal credentials/config were found. Log in with `hermes model` "
|
||||
"or choose TERMINAL_MODAL_MODE=direct/auto."
|
||||
)
|
||||
return False
|
||||
|
||||
@@ -6,7 +6,6 @@ import os
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict
|
||||
|
||||
from utils import env_var_enabled
|
||||
|
||||
_DEFAULT_BROWSER_PROVIDER = "local"
|
||||
_DEFAULT_MODAL_MODE = "auto"
|
||||
@@ -14,8 +13,26 @@ _VALID_MODAL_MODES = {"auto", "direct", "managed"}
|
||||
|
||||
|
||||
def managed_nous_tools_enabled() -> bool:
|
||||
"""Return True when the hidden Nous-managed tools feature flag is enabled."""
|
||||
return env_var_enabled("HERMES_ENABLE_NOUS_MANAGED_TOOLS")
|
||||
"""Return True when the user has an active paid Nous subscription.
|
||||
|
||||
The Tool Gateway is available to any Nous subscriber who is NOT on
|
||||
the free tier. We intentionally catch all exceptions and return
|
||||
False — never block the agent startup path.
|
||||
"""
|
||||
try:
|
||||
from hermes_cli.auth import get_nous_auth_status
|
||||
|
||||
status = get_nous_auth_status()
|
||||
if not status.get("logged_in"):
|
||||
return False
|
||||
|
||||
from hermes_cli.models import check_nous_free_tier
|
||||
|
||||
if check_nous_free_tier():
|
||||
return False # free-tier users don't get gateway access
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def normalize_browser_cloud_provider(value: object | None) -> str:
|
||||
@@ -87,3 +104,18 @@ def resolve_openai_audio_api_key() -> str:
|
||||
os.getenv("VOICE_TOOLS_OPENAI_KEY", "")
|
||||
or os.getenv("OPENAI_API_KEY", "")
|
||||
).strip()
|
||||
|
||||
|
||||
def prefers_gateway(config_section: str) -> bool:
|
||||
"""Return True when the user opted into the Tool Gateway for this tool.
|
||||
|
||||
Reads ``<section>.use_gateway`` from config.yaml. Never raises.
|
||||
"""
|
||||
try:
|
||||
from hermes_cli.config import load_config
|
||||
section = (load_config() or {}).get(config_section)
|
||||
if isinstance(section, dict):
|
||||
return bool(section.get("use_gateway"))
|
||||
except Exception:
|
||||
pass
|
||||
return False
|
||||
|
||||
@@ -44,7 +44,7 @@ from hermes_constants import display_hermes_home
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
from tools.managed_tool_gateway import resolve_managed_tool_gateway
|
||||
from tools.tool_backend_helpers import managed_nous_tools_enabled, resolve_openai_audio_api_key
|
||||
from tools.tool_backend_helpers import managed_nous_tools_enabled, prefers_gateway, resolve_openai_audio_api_key
|
||||
from tools.xai_http import hermes_xai_user_agent
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -823,9 +823,13 @@ def check_tts_requirements() -> bool:
|
||||
|
||||
|
||||
def _resolve_openai_audio_client_config() -> tuple[str, str]:
|
||||
"""Return direct OpenAI audio config or a managed gateway fallback."""
|
||||
"""Return direct OpenAI audio config or a managed gateway fallback.
|
||||
|
||||
When ``tts.use_gateway`` is set in config, the Tool Gateway is preferred
|
||||
even if direct OpenAI credentials are present.
|
||||
"""
|
||||
direct_api_key = resolve_openai_audio_api_key()
|
||||
if direct_api_key:
|
||||
if direct_api_key and not prefers_gateway("tts"):
|
||||
return direct_api_key, DEFAULT_OPENAI_BASE_URL
|
||||
|
||||
managed_gateway = resolve_managed_tool_gateway("openai-audio")
|
||||
|
||||
@@ -59,7 +59,7 @@ from tools.managed_tool_gateway import (
|
||||
read_nous_access_token as _read_nous_access_token,
|
||||
resolve_managed_tool_gateway,
|
||||
)
|
||||
from tools.tool_backend_helpers import managed_nous_tools_enabled
|
||||
from tools.tool_backend_helpers import managed_nous_tools_enabled, prefers_gateway
|
||||
from tools.url_safety import is_safe_url
|
||||
from tools.website_policy import check_website_access
|
||||
|
||||
@@ -165,8 +165,8 @@ def _raise_web_backend_configuration_error() -> None:
|
||||
)
|
||||
if managed_nous_tools_enabled():
|
||||
message += (
|
||||
" If you have the hidden Nous-managed tools flag enabled, you can also login to Nous "
|
||||
"(`hermes model`) and provide FIRECRAWL_GATEWAY_URL or TOOL_GATEWAY_DOMAIN."
|
||||
" With your Nous subscription you can also use the Tool Gateway — "
|
||||
"run `hermes tools` and select Nous Subscription as the web provider."
|
||||
)
|
||||
raise ValueError(message)
|
||||
|
||||
@@ -176,8 +176,8 @@ def _firecrawl_backend_help_suffix() -> str:
|
||||
if not managed_nous_tools_enabled():
|
||||
return ""
|
||||
return (
|
||||
", or, if you have the hidden Nous-managed tools flag enabled, login to Nous and use "
|
||||
"FIRECRAWL_GATEWAY_URL or TOOL_GATEWAY_DOMAIN"
|
||||
", or use the Nous Tool Gateway via your subscription "
|
||||
"(FIRECRAWL_GATEWAY_URL or TOOL_GATEWAY_DOMAIN)"
|
||||
)
|
||||
|
||||
|
||||
@@ -205,13 +205,14 @@ def _web_requires_env() -> list[str]:
|
||||
def _get_firecrawl_client():
|
||||
"""Get or create Firecrawl client.
|
||||
|
||||
Direct Firecrawl takes precedence when explicitly configured. Otherwise
|
||||
Hermes falls back to the Firecrawl tool-gateway for logged-in Nous Subscribers.
|
||||
When ``web.use_gateway`` is set in config, the Tool Gateway is preferred
|
||||
even if direct Firecrawl credentials are present. Otherwise direct
|
||||
Firecrawl takes precedence when explicitly configured.
|
||||
"""
|
||||
global _firecrawl_client, _firecrawl_client_config
|
||||
|
||||
direct_config = _get_direct_firecrawl_config()
|
||||
if direct_config is not None:
|
||||
if direct_config is not None and not prefers_gateway("web"):
|
||||
kwargs, client_config = direct_config
|
||||
else:
|
||||
managed_gateway = resolve_managed_tool_gateway(
|
||||
|
||||
Reference in New Issue
Block a user