Keep action-required notifications visible
Make plugin frontend-reload and Agent Zero update notifications persistent until the user dismisses or acts on them. Reuse the existing zero-duration toast contract without changing ordinary notification timeouts.\n\nDocument the behavior and extend the persistent-toast regression coverage.
Alessandro committed
Jul 12, 2026 at 16:55 UTC
a55a76f62b9dbc22573b8697d53cb47e1bf731be
5 files changed
+10
-3
extensions/python/user_message_ui/AGENTS.md
+1
@@ -11,6 +11,7 @@
11
## Local Contracts
12
13
- Keep proactive UI messages relevant, non-spammy, and safe for display.
14
+- Keep update-available notifications visible until the user dismisses them.
15
- Do not expose local diagnostics or update data that should stay internal.
16
17
## Work Guidance
extensions/python/user_message_ui/_10_update_check.py
+1
-1
@@ -104,7 +104,7 @@ class UpdateCheck(Extension):
104
message=notif.get("message", "A newer version of Agent Zero is available. Please update to the latest version."),
105
type=notif.get("type", "info"),
106
detail=notif.get("detail", ""),
107
- display_time=notif.get("display_time", 10),
107
+ display_time=0,
108
group=notif.get("group", "update_check"),
109
priority=notif.get("priority", notification.NotificationPriority.NORMAL),
110
id=notif.get("id", "update_check_available"),
helpers/plugins.py
+1
-1
@@ -842,7 +842,7 @@ def send_frontend_reload_notification(plugin_names: list[str] | None = None):
842
title="Plugins with frontend extensions updated, page reload recommended",
843
message="""<button type="button" class="button confirm" onclick="window.location.reload()"><span class="icon material-symbols-outlined">refresh</span>Reload page</button>""",
844
detail="",
845
- display_time=display_time,
845
+ display_time=0,
846
group="plugins_changed",
847
id="plugins_frontend_reload",
848
)
helpers/plugins.py.dox.md
+1
-1
@@ -40,7 +40,7 @@
40
- `find_plugin_asset(plugin_name: str, *subpaths, project_name=..., agent_profile=...)`
41
- `find_plugin_assets(*subpaths, plugin_name: str=..., project_name: str=..., agent_profile: str=..., only_first: bool=...) -> list[PluginAssetFile]`
42
- `determine_plugin_asset_path(plugin_name: str, project_name: str, agent_profile: str, *subpaths)`
43
-- `send_frontend_reload_notification(plugin_names: list[str] | None=...)`: If the plugin changed has webui extensions, notify frontend to reload the page
43
+- `send_frontend_reload_notification(plugin_names: list[str] | None=...)`: If the plugin changed has webui extensions, show a persistent reload notification
44
- `call_plugin_hook(plugin_name: str, hook_name: str, default: Any=..., *args, **kwargs)`
45
- `_apply_defaults_from_env(plugin_name: str, config: dict[str, Any])`
46
- Notable constants/configuration names: `_META_TARGET_RE`, `META_FILE_NAME`, `CONFIG_FILE_NAME`, `CONFIG_DEFAULT_FILE_NAME`, `DISABLED_FILE_NAME`, `ENABLED_FILE_NAME`, `TOGGLE_FILE_PATTERN`, `HOOKS_SCRIPT`, `HOOKS_CACHE_AREA`, `PLUGINS_LIST_CACHE_AREA`, `ENABLED_PLUGINS_LIST_CACHE_AREA`, `ENABLED_PLUGINS_PATHS_CACHE_AREA`.
tests/test_download_toast_regressions.py
+6
@@ -89,6 +89,8 @@ def previous_non_space(source: str, index: int) -> str:
89
def test_notification_store_supports_persistent_grouped_toasts():
90
store = read("webui", "components", "notifications", "notification-store.js")
91
api = read("api", "notification_create.py")
92
+ plugins = read("helpers", "plugins.py")
93
+ update_check = read("extensions", "python", "user_message_ui", "_10_update_check.py")
94
95
assert "isPersistentToast(toast)" in store
96
assert "return this.getToastDisplayTime(toast) <= 0;" in store
@@ -97,6 +99,10 @@ def test_notification_store_supports_persistent_grouped_toasts():
99
assert "this.removeFromToastStack(existingToast.toastId);" in store
100
assert "if display_time < 0:" in api
101
assert "if display_time <= 0:" not in api
102
+ assert 'id="plugins_frontend_reload",' in plugins
103
+ assert 'id=notif.get("id", "update_check_available"),' in update_check
104
+ assert "display_time=0," in plugins
105
+ assert "display_time=0," in update_check
106
107
108
def test_backup_zip_downloads_emit_grouped_preparing_and_downloading_toasts():