Files
teknium1 23036e20a6 fix(ux): plain-language, actionable user-facing messages (core)
Squashed integration of the user-facing message audit for this surface set.
Full per-finding receipts: /tmp/ux-audit/lanes/*-receipt.md (campaign artifacts).
2026-09-15 04:12:13 -07:00

44 lines
2.0 KiB
Python

"""Shared wording for the exec-approval prompt every messaging surface renders.
The button card (``BasePlatformAdapter._format_exec_approval``) and the plain-text
``/approve`` fallback (``gateway.run._format_exec_approval_fallback``) must tell the user
the same three things: what Hermes wants to run, why it was flagged, and that silence means
the command does NOT run once ``approvals.timeout`` elapses. Keeping the text here means one
edit changes every platform; adapters only wrap these strings in their own markup.
No imports from ``gateway.platforms.base`` or ``gateway.run`` — both import this module.
"""
from __future__ import annotations
# Bare strings; adapters add their own bold/HTML around them.
EA_HEADER_TEXT = "Hermes wants to run a command that needs your OK"
EA_REASON_LABEL_TEXT = "Why it was flagged"
# Timeout notice posted when nobody answered the prompt (``{window}`` = "5 minutes").
APPROVAL_TIMED_OUT_NOTICE = (
"⌛ Approval timed out after {window} — the command was NOT run. "
"Ask me to try again if you still want it, or raise approvals.timeout in config.yaml.")
def approval_timeout_seconds() -> int:
"""The configured ``approvals.timeout`` (default 300s); module attribute so tests can pin it."""
from tools.approval_context import _get_approval_timeout
return _get_approval_timeout()
def format_approval_window(seconds: int) -> str:
"""Human wording for a timeout (300 → "5 minutes"); one formatter shared with the CLI notice and
the tool result's ``user_summary`` — see ``tools.approval_context.format_approval_window``."""
from tools.approval_context import format_approval_window as _shared
return _shared(seconds)
def format_approval_deadline_line(timeout_s: int) -> str:
"""The last line of every approval prompt: doing nothing is a safe no."""
return f"If you don't answer within {format_approval_window(timeout_s)} it will NOT run."
def format_approval_timed_out_notice(timeout_s: int) -> str:
return APPROVAL_TIMED_OUT_NOTICE.format(window=format_approval_window(timeout_s))