fix(model): require confirmation for expensive model selections
Rebased onto current main and re-ported across the restructured surfaces: model flows now thread confirm_provider/base_url/api_key through hermes_cli/model_setup_flows.py, the Discord picker lives in plugins/platforms/discord/adapter.py, and the web dashboard picker applies chat-mode switches via config.set so the expensive-model confirmation can ride the response. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
committed by
Teknium
co-authored by
Claude Fable 5
parent
4eadef18a9
commit
af978ecb17
+56
-4
@@ -6175,6 +6175,40 @@ def _reset_config_provider() -> Path:
|
||||
return config_path
|
||||
|
||||
|
||||
def _confirm_expensive_model_selection(
|
||||
model_id: str,
|
||||
*,
|
||||
provider: str = "",
|
||||
base_url: str = "",
|
||||
api_key: str = "",
|
||||
) -> bool:
|
||||
"""Prompt before saving a model whose known pricing exceeds guardrails."""
|
||||
try:
|
||||
from hermes_cli.model_cost_guard import expensive_model_warning
|
||||
|
||||
warning = expensive_model_warning(
|
||||
model_id,
|
||||
provider=provider,
|
||||
base_url=base_url,
|
||||
api_key=api_key,
|
||||
)
|
||||
except Exception:
|
||||
warning = None
|
||||
if warning is None:
|
||||
return True
|
||||
|
||||
print()
|
||||
print("=" * 72)
|
||||
print(warning.message)
|
||||
print("=" * 72)
|
||||
try:
|
||||
response = input("Switch anyway? [y/N]: ").strip().lower()
|
||||
except (KeyboardInterrupt, EOFError):
|
||||
print()
|
||||
return False
|
||||
return response in {"y", "yes"}
|
||||
|
||||
|
||||
def _prompt_model_selection(
|
||||
model_ids: List[str],
|
||||
current_model: str = "",
|
||||
@@ -6182,6 +6216,9 @@ def _prompt_model_selection(
|
||||
unavailable_models: Optional[List[str]] = None,
|
||||
portal_url: str = "",
|
||||
unavailable_message: str = "",
|
||||
confirm_provider: str = "",
|
||||
confirm_base_url: str = "",
|
||||
confirm_api_key: str = "",
|
||||
) -> Optional[str]:
|
||||
"""Interactive model selection. Puts current_model first with a marker. Returns chosen model ID or None.
|
||||
|
||||
@@ -6195,6 +6232,18 @@ def _prompt_model_selection(
|
||||
|
||||
_unavailable = unavailable_models or []
|
||||
|
||||
def _confirmed_selection(mid: str) -> Optional[str]:
|
||||
if not mid:
|
||||
return None
|
||||
if confirm_provider and not _confirm_expensive_model_selection(
|
||||
mid,
|
||||
provider=confirm_provider,
|
||||
base_url=confirm_base_url,
|
||||
api_key=confirm_api_key,
|
||||
):
|
||||
return None
|
||||
return mid
|
||||
|
||||
# Reorder: current model first, then the rest (deduplicated)
|
||||
ordered = []
|
||||
if current_model and current_model in model_ids:
|
||||
@@ -6310,13 +6359,13 @@ def _prompt_model_selection(
|
||||
return None
|
||||
print()
|
||||
if idx < len(ordered):
|
||||
return ordered[idx]
|
||||
return _confirmed_selection(ordered[idx])
|
||||
elif idx == len(ordered):
|
||||
try:
|
||||
custom = input("Enter model name: ").strip()
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
return None
|
||||
return custom if custom else None
|
||||
return _confirmed_selection(custom) if custom else None
|
||||
return None
|
||||
except (ImportError, NotImplementedError, OSError, subprocess.SubprocessError):
|
||||
pass
|
||||
@@ -6348,10 +6397,10 @@ def _prompt_model_selection(
|
||||
return None
|
||||
idx = int(choice)
|
||||
if 1 <= idx <= n:
|
||||
return ordered[idx - 1]
|
||||
return _confirmed_selection(ordered[idx - 1])
|
||||
elif idx == n + 1:
|
||||
custom = input("Enter model name: ").strip()
|
||||
return custom if custom else None
|
||||
return _confirmed_selection(custom) if custom else None
|
||||
elif idx == n + 2:
|
||||
return None
|
||||
print(f"Please enter 1-{n + 2}")
|
||||
@@ -7730,6 +7779,9 @@ def _login_nous(args, pconfig: ProviderConfig) -> None:
|
||||
unavailable_models=unavailable_models,
|
||||
portal_url=_portal,
|
||||
unavailable_message=unavailable_message,
|
||||
confirm_provider="nous",
|
||||
confirm_base_url=inference_base_url,
|
||||
confirm_api_key=runtime_key,
|
||||
)
|
||||
elif unavailable_models:
|
||||
_url = (_portal or DEFAULT_NOUS_PORTAL_URL).rstrip("/")
|
||||
|
||||
Reference in New Issue
Block a user