feat: confirm prompt for destructive slash commands (#4069) (#22687)

/clear, /new, /reset, and /undo now ask the user to confirm before
discarding conversation state — three-option prompt routed through the
existing tools.slash_confirm primitive.

Native yes/no buttons render on Telegram, Discord, and Slack (their
adapters already implement send_slash_confirm); other platforms get a
text-fallback prompt and reply with /approve, /always, or /cancel.

The classic prompt_toolkit CLI uses the same three-option flow via the
established _prompt_text_input pattern (see _confirm_and_reload_mcp).
TUI keeps its existing modal overlay (#12312).

Gated by new config key approvals.destructive_slash_confirm (default
true). Picking 'Always Approve' flips the gate to false so subsequent
destructive commands run silently — matches the established
mcp_reload_confirm UX.

Out of scope: /cron remove (separate domain — scheduled jobs, not
session history). Existing TUI overlay env-var (HERMES_TUI_NO_CONFIRM)
left unchanged; cosmetic unification can come later.

Closes #4069.
This commit is contained in:
Teknium 2026-05-09 11:04:46 -07:00 committed by GitHub
parent 0cafe7d50d
commit b9c001116e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 730 additions and 3 deletions

View file

@ -144,6 +144,11 @@ def _make_runner(session_db=None):
runner._invalidate_session_run_generation = MagicMock()
runner._begin_session_run_generation = MagicMock(return_value=1)
runner._is_session_run_current = MagicMock(return_value=True)
# Bypass the destructive-slash confirm gate — these tests focus on
# /new topic-mode mechanics, not the confirm prompt itself.
runner._read_user_config = lambda: {
"approvals": {"destructive_slash_confirm": False}
}
runner._release_running_agent_state = MagicMock()
runner._evict_cached_agent = MagicMock()
runner._clear_session_boundary_security_state = MagicMock()