refactor(fal): render the managed billing message once in fal_common

Image and video callers were each formatting the same four-field dict into
the same sentence. Return the rendered tail from _managed_fal_billing_error
so the wording lives in one place; output is byte-identical.
This commit is contained in:
teknium1
2026-09-09 05:12:07 -07:00
committed by Teknium
parent acf9177c70
commit 3dc3809d07
3 changed files with 20 additions and 28 deletions
+2 -8
View File
@@ -224,16 +224,10 @@ def _submit_fal_video_request(endpoint: str, arguments: Dict[str, Any]):
from tools.fal_common import _extract_http_status, _managed_fal_billing_error
status = _extract_http_status(exc)
if status is not None and 400 <= status < 500:
billing = _managed_fal_billing_error(exc)
billing = _managed_fal_billing_error(exc, "endpoint")
if billing is not None:
raise ValueError(
f"Nous Subscription gateway rejected endpoint '{endpoint}' (HTTP {status}): "
f"{billing['message']} ({billing['error_code']}; "
f"{billing['code']}: {billing['detail']}). "
"This is a Nous Portal billing configuration issue, not a missing local API key. "
"The managed route cannot run this endpoint until Nous enables its billing meter; "
"a direct FAL_KEY is an optional bypass."
) from exc
f"Nous Subscription gateway rejected endpoint '{endpoint}' (HTTP {status}): {billing}") from exc
raise ValueError(f"Nous Subscription gateway rejected endpoint '{endpoint}' (HTTP {status}). This model may not yet be enabled "
f"on the Nous Portal's FAL proxy. Either:\n • Set FAL_KEY in your environment to use FAL.ai directly, or\n"
f" • Pick a different model via `hermes tools` → Video Generation.") from exc
+16 -12
View File
@@ -46,8 +46,12 @@ def _extract_http_status(exc: BaseException) -> Optional[int]:
return status if isinstance(status, int) else None
def _managed_fal_billing_error(exc: BaseException) -> Optional[Dict[str, str]]:
"""Return normalized Nous billing details from a managed-gateway error."""
def _managed_fal_billing_error(exc: BaseException, what: str) -> Optional[str]:
"""Human-readable tail for a Nous managed-gateway ``BILLING_ERROR`` response, else None.
``what`` names the rejected thing ("model", "endpoint"); the wording is shared by the image
and video callers so the two surfaces never drift.
"""
response = getattr(exc, "response", None)
if response is None:
return None
@@ -58,16 +62,16 @@ def _managed_fal_billing_error(exc: BaseException) -> Optional[Dict[str, str]]:
error = payload.get("error") if isinstance(payload, dict) else None
if not isinstance(error, dict) or error.get("code") != "BILLING_ERROR":
return None
raw_details = error.get("details")
details = raw_details if isinstance(raw_details, dict) else {}
raw_upstream = details.get("upstreamPayload")
upstream = raw_upstream if isinstance(raw_upstream, dict) else {}
return {
"message": str(error.get("message") or "Charge authorization failed"),
"error_code": str(error.get("code") or "BILLING_ERROR"),
"code": str(upstream.get("code") or details.get("chargeIntentErrorCode") or "billing_error"),
"detail": str(upstream.get("error") or "Nous Portal rejected the charge authorization"),
}
details = error.get("details") if isinstance(error.get("details"), dict) else {}
upstream = details.get("upstreamPayload") if isinstance(details.get("upstreamPayload"), dict) else {}
code = upstream.get("code") or details.get("chargeIntentErrorCode") or "billing_error"
detail = upstream.get("error") or "Nous Portal rejected the charge authorization"
return (
f"{error.get('message') or 'Charge authorization failed'} (BILLING_ERROR; {code}: {detail}). "
"This is a Nous Portal billing configuration issue, not a missing local API key. "
f"The managed route cannot run this {what} until Nous enables its billing meter; "
"a direct FAL_KEY is an optional bypass."
)
def _require(value: Any, what: str) -> Any:
+2 -8
View File
@@ -134,16 +134,10 @@ def _submit_fal_request(model: str, arguments: Dict[str, Any]):
# (allowlist miss, billing gate): give remediation instead of a raw httpx error.
status = _extract_http_status(exc)
if status is not None and 400 <= status < 500:
billing = _managed_fal_billing_error(exc)
billing = _managed_fal_billing_error(exc, "model")
if billing is not None:
raise ValueError(
f"Nous Subscription gateway rejected model '{model}' (HTTP {status}): "
f"{billing['message']} ({billing['error_code']}; "
f"{billing['code']}: {billing['detail']}). "
"This is a Nous Portal billing configuration issue, not a missing local API key. "
"The managed route cannot run this model until Nous enables its billing meter; "
"a direct FAL_KEY is an optional bypass."
) from exc
f"Nous Subscription gateway rejected model '{model}' (HTTP {status}): {billing}") from exc
gateway_message = ""
if status in {401, 402, 403}:
gateway_message = "\n\n" + nous_tool_gateway_unavailable_message(