From b7044bbba77ba0fd55de615e19f1d66041152648 Mon Sep 17 00:00:00 2001 From: worldmozara Date: Sat, 24 Oct 2026 01:48:04 +0800 Subject: [PATCH] core/cli: keep a prompt notification on screen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A prompt notification went out with the library defaults: the notification server's own expiry. A desktop server drops such a notification after a few seconds, so the announcement of a blocked turn had usually slid into the notification tray by the time the human looked back. It now goes out without expiry (`timeout=0`, the freedesktop value for "until dismissed"). Urgency is left alone: measured on KDE Plasma, `critical` keeps the notification up just the same, but paints it as urgent and asks the platform's Focus mode to let it through — decoration a prompt does not need. Dismissing is already the prompt's own job once it is answered, so nothing lingers. --- src/plyngent/cli/notify.py | 13 +++++++++++++ typings/desktop_notifier/__init__.pyi | 7 ++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/plyngent/cli/notify.py b/src/plyngent/cli/notify.py index 6c6d6c5..619e832 100644 --- a/src/plyngent/cli/notify.py +++ b/src/plyngent/cli/notify.py @@ -60,6 +60,14 @@ _BUTTONS: tuple[tuple[str, str], ...] = ( _MAX_TITLE = 80 _MAX_MESSAGE = 200 +#: Seconds a desktop notification may stay up; ``0`` is the freedesktop value +#: for "until dismissed" (``-1`` would hand the notification server's default +#: back, which is a few seconds — after that the notification collapses into +#: the tray, where nobody waiting on a prompt looks). Urgency stays at the +#: library default: ``critical`` keeps the notification up just the same, but +#: paints it as urgent and asks the platform's Focus mode to let it through. +_NO_EXPIRY = 0 + def _clean(text: str, limit: int) -> str: """One line, no control characters, truncated to *limit* characters.""" @@ -171,6 +179,11 @@ class DesktopNotifierChannel: send( title=request.title, message=request.message, + # A prompt holds the turn until it is answered, so the + # notification must still be on screen when the human looks + # back. Dismissing is the prompt's own job once it is + # answered, so nothing lingers. + timeout=_NO_EXPIRY, buttons=buttons, reply_field=reply, ) diff --git a/typings/desktop_notifier/__init__.pyi b/typings/desktop_notifier/__init__.pyi index 10e2cd3..54b1b30 100644 --- a/typings/desktop_notifier/__init__.pyi +++ b/typings/desktop_notifier/__init__.pyi @@ -22,6 +22,11 @@ class Capability(Enum): THREAD = ... TIMEOUT = ... +class Urgency(Enum): + Critical = ... + Normal = ... + Low = ... + class Button: def __init__( self, @@ -50,7 +55,7 @@ class DesktopNotifier: self, title: str, message: str, - urgency: Any = ..., + urgency: Urgency = ..., icon: Any = ..., buttons: Sequence[Button] = ..., reply_field: ReplyField | None = None,