From 9329e06696c968b7a960541d0ee0167df6742f21 Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Fri, 15 May 2026 01:33:13 -0700 Subject: [PATCH] feat(image-gen): actionable setup message when no FAL backend is reachable (#26222) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the in-tree FAL path has no API key (and no managed gateway), the handler used to return a bare 'FAL_KEY environment variable not set' error. Users had no idea where to get a key, that a managed Nous gateway exists, or that plugin-registered providers are an option. Now `image_generate_tool` returns a structured multi-line message: - signup link (https://fal.ai) - managed-gateway status (if Nous tools are enabled) - pointer to `hermes tools` / `hermes plugins list` for alternate backends, so users on a stale `image_gen.provider` know where to look The schema is untouched — `check_fn` still gates the tool out of the schema when no backend is reachable at startup, consistent with every other conditional tool. This patch fixes the call-time failure modes: managed-gateway 5xx, plugin provider disappearing mid-session, etc. Inspired by #2546 / @Mibayy. The PR was ~5700 commits stale against the new plugin-aware image_gen architecture, so this is a forward port of the actionable-error idea rather than a cherry-pick. Closes #2543 Co-authored-by: Mibayy --- tests/tools/test_image_generation_env.py | 59 ++++++++++++++++++++++++ tools/image_generation_tool.py | 41 ++++++++++++++-- 2 files changed, 96 insertions(+), 4 deletions(-) diff --git a/tests/tools/test_image_generation_env.py b/tests/tools/test_image_generation_env.py index fc4e6553346..56c9741617f 100644 --- a/tests/tools/test_image_generation_env.py +++ b/tests/tools/test_image_generation_env.py @@ -37,3 +37,62 @@ def test_fal_key_empty_is_unset(monkeypatch): ) assert image_generation_tool.check_fal_api_key() is False + + +# --------------------------------------------------------------------------- +# Actionable setup message when no FAL backend is reachable. +# Regression for the silent-drop UX gap described in issue #2543. +# --------------------------------------------------------------------------- + + +def test_no_backend_message_mentions_fal_signup_and_plugins(monkeypatch): + from tools import image_generation_tool + + monkeypatch.setattr( + image_generation_tool, "managed_nous_tools_enabled", lambda: False + ) + + msg = image_generation_tool._build_no_backend_setup_message() + + assert "FAL_KEY" in msg + assert "https://fal.ai" in msg + # Plugin pointer so users on a stale image_gen.provider know where to look. + assert "hermes tools" in msg or "hermes plugins" in msg + + +def test_no_backend_message_mentions_managed_gateway_when_enabled(monkeypatch): + from tools import image_generation_tool + + monkeypatch.setattr( + image_generation_tool, "managed_nous_tools_enabled", lambda: True + ) + + msg = image_generation_tool._build_no_backend_setup_message() + + assert "managed FAL gateway" in msg + assert "Nous account" in msg or "hermes setup" in msg + + +def test_image_generate_tool_returns_actionable_error_when_no_backend(monkeypatch): + """End-to-end: handler must surface the actionable message, not a bare string.""" + import json + + from tools import image_generation_tool + + monkeypatch.setattr( + image_generation_tool, "fal_key_is_configured", lambda: False + ) + monkeypatch.setattr( + image_generation_tool, "_resolve_managed_fal_gateway", lambda: None + ) + monkeypatch.setattr( + image_generation_tool, "managed_nous_tools_enabled", lambda: False + ) + + result = json.loads( + image_generation_tool.image_generate_tool(prompt="a cat") + ) + + assert result["success"] is False + assert "https://fal.ai" in result["error"] + assert "FAL_KEY" in result["error"] diff --git a/tools/image_generation_tool.py b/tools/image_generation_tool.py index c496166ec98..3d171f093c9 100644 --- a/tools/image_generation_tool.py +++ b/tools/image_generation_tool.py @@ -698,10 +698,7 @@ def image_generate_tool( raise ValueError("Prompt is required and must be a non-empty string") if not (fal_key_is_configured() or _resolve_managed_fal_gateway()): - message = "FAL_KEY environment variable not set" - if managed_nous_tools_enabled(): - message += " and managed FAL gateway is unavailable" - raise ValueError(message) + raise ValueError(_build_no_backend_setup_message()) aspect_lc = (aspect_ratio or DEFAULT_ASPECT_RATIO).lower().strip() if aspect_lc not in VALID_ASPECT_RATIOS: @@ -811,6 +808,42 @@ def check_fal_api_key() -> bool: return bool(fal_key_is_configured() or _resolve_managed_fal_gateway()) +def _build_no_backend_setup_message() -> str: + """Build an actionable error string when no FAL backend is reachable. + + Used by the in-tree FAL path. Mentions: + - FAL_KEY signup link + - managed-gateway status (if Nous tools are enabled) + - plugin alternative pointer (so users on a stale ``image_gen.provider`` + know the registry exists and how to inspect it) + """ + lines = ["Image generation is unavailable in this environment.", ""] + lines.append("Missing requirements:") + if managed_nous_tools_enabled(): + lines.append( + " - FAL_KEY is not set and the managed FAL gateway is unreachable" + ) + else: + lines.append(" - FAL_KEY environment variable is not set") + lines.append("") + lines.append("To enable image generation, do one of:") + lines.append( + " 1. Get a free API key at https://fal.ai and set " + "FAL_KEY= (then restart the session)" + ) + if managed_nous_tools_enabled(): + lines.append( + " 2. Sign in to a Nous account that has the managed FAL " + "gateway enabled (`hermes setup`)" + ) + lines.append( + " 3. Configure a different image_gen provider via `hermes tools` " + "→ Image Generation (run `hermes plugins list` to see installed " + "backends)" + ) + return "\n".join(lines) + + def check_image_generation_requirements() -> bool: """True if any image gen backend is available.