core/cli: keep a prompt notification on screen

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.
This commit is contained in:
2026-10-24 01:48:04 +08:00
parent d4485aff7a
commit b7044bbba7
2 changed files with 19 additions and 1 deletions
+13
View File
@@ -60,6 +60,14 @@ _BUTTONS: tuple[tuple[str, str], ...] = (
_MAX_TITLE = 80 _MAX_TITLE = 80
_MAX_MESSAGE = 200 _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: def _clean(text: str, limit: int) -> str:
"""One line, no control characters, truncated to *limit* characters.""" """One line, no control characters, truncated to *limit* characters."""
@@ -171,6 +179,11 @@ class DesktopNotifierChannel:
send( send(
title=request.title, title=request.title,
message=request.message, 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, buttons=buttons,
reply_field=reply, reply_field=reply,
) )
+6 -1
View File
@@ -22,6 +22,11 @@ class Capability(Enum):
THREAD = ... THREAD = ...
TIMEOUT = ... TIMEOUT = ...
class Urgency(Enum):
Critical = ...
Normal = ...
Low = ...
class Button: class Button:
def __init__( def __init__(
self, self,
@@ -50,7 +55,7 @@ class DesktopNotifier:
self, self,
title: str, title: str,
message: str, message: str,
urgency: Any = ..., urgency: Urgency = ...,
icon: Any = ..., icon: Any = ...,
buttons: Sequence[Button] = ..., buttons: Sequence[Button] = ...,
reply_field: ReplyField | None = None, reply_field: ReplyField | None = None,