mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-22 10:32:00 +00:00
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:
parent
4eadef18a9
commit
af978ecb17
27 changed files with 1354 additions and 111 deletions
54
cli.py
54
cli.py
|
|
@ -6516,6 +6516,47 @@ class HermesCLI(CLIAgentSetupMixin, CLICommandsMixin):
|
|||
}
|
||||
self._invalidate(min_interval=0.0)
|
||||
|
||||
def _confirm_expensive_model_switch(self, result) -> bool:
|
||||
"""Ask for explicit confirmation before applying costly model switches."""
|
||||
if not getattr(result, "success", False):
|
||||
return True
|
||||
try:
|
||||
from hermes_cli.model_cost_guard import expensive_model_warning
|
||||
|
||||
warning = expensive_model_warning(
|
||||
result.new_model,
|
||||
provider=result.target_provider,
|
||||
base_url=result.base_url or self.base_url or "",
|
||||
api_key=result.api_key or self.api_key or "",
|
||||
model_info=result.model_info,
|
||||
)
|
||||
except Exception:
|
||||
warning = None
|
||||
if warning is None:
|
||||
return True
|
||||
|
||||
choices = [
|
||||
("once", "Switch anyway", "Use this model for the current Hermes session."),
|
||||
("cancel", "Cancel", "Keep the current model."),
|
||||
]
|
||||
raw = self._prompt_text_input_modal(
|
||||
title="!!! Expensive Model Warning !!!",
|
||||
detail=warning.message,
|
||||
choices=choices,
|
||||
timeout=120,
|
||||
)
|
||||
choice = self._normalize_slash_confirm_choice(raw, choices)
|
||||
return choice == "once"
|
||||
|
||||
def _confirm_and_apply_model_switch_result(self, result, persist_global: bool) -> None:
|
||||
try:
|
||||
if result.success and not self._confirm_expensive_model_switch(result):
|
||||
_cprint(" Model switch cancelled.")
|
||||
return
|
||||
self._apply_model_switch_result(result, persist_global)
|
||||
except Exception as exc:
|
||||
_cprint(f" ✗ Model selection failed: {exc}")
|
||||
|
||||
def _close_model_picker(self) -> None:
|
||||
self._model_picker_state = None
|
||||
self._restore_modal_input_snapshot()
|
||||
|
|
@ -6692,7 +6733,14 @@ class HermesCLI(CLIAgentSetupMixin, CLICommandsMixin):
|
|||
custom_providers=state.get("custom_provs"),
|
||||
)
|
||||
self._close_model_picker()
|
||||
self._apply_model_switch_result(result, persist_global)
|
||||
if getattr(self, "_app", None):
|
||||
threading.Thread(
|
||||
target=self._confirm_and_apply_model_switch_result,
|
||||
args=(result, persist_global),
|
||||
daemon=True,
|
||||
).start()
|
||||
else:
|
||||
self._confirm_and_apply_model_switch_result(result, persist_global)
|
||||
return
|
||||
self._close_model_picker()
|
||||
|
||||
|
|
@ -6793,6 +6841,10 @@ class HermesCLI(CLIAgentSetupMixin, CLICommandsMixin):
|
|||
_cprint(f" ✗ {result.error_message}")
|
||||
return
|
||||
|
||||
if not self._confirm_expensive_model_switch(result):
|
||||
_cprint(" Model switch cancelled.")
|
||||
return
|
||||
|
||||
# Apply to CLI state.
|
||||
# Update requested_provider so _ensure_runtime_credentials() doesn't
|
||||
# overwrite the switch on the next turn (it re-resolves from this).
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue