feat(desktop): native OS notifications for background process completions#44213
Open
AIalliAI wants to merge 1 commit into
Open
feat(desktop): native OS notifications for background process completions#44213AIalliAI wants to merge 1 commit into
AIalliAI wants to merge 1 commit into
Conversation
…ions When a background process started with notify_on_complete=true finishes, the desktop app now fires a native OS notification (Windows toast / macOS notification center) so the user doesn't have to keep the chat window open to learn the result. Gateway side: the notification poller's status.update (kind=process) event now carries the structured fields (event_type, command, exit_code) alongside the agent-facing formatted text, so GUI clients can render their own surfaces without parsing the [IMPORTANT: ...] prose. Desktop side: a new process-notifications store mirrors the gateway's display.background_process_notifications semantics (all/result/error/off, false → off, unknown → all) and builds the toast content; the message stream hook routes the event through the existing hermes:notify IPC bridge. The toast only fires when the user can't see the in-chat message — window hidden, or the process belongs to a non-active chat. Watch matches never toast (they can fire many times per process). Fixes NousResearch#44201 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contributor
Author
|
Requesting maintainer review — this is ready to land from my side. Standalone fork CI is pending first-run approval here; the rollup branch in #44061 carrying this session's batch is fully green on upstream CI (all test shards, typecheck, e2e). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When a background process started with
terminal(background=true, notify_on_complete=true)finishes, the desktop app now fires a native OS notification (Windows toast / macOS notification center), so hands-off background execution no longer requires keeping the chat window open.Fixes #44201
How it works
The pieces were mostly already there — this PR connects them:
hermes:notifyinelectron/main.cjs, surfaced aswindow.hermesDesktop.notify).tui_gateway/server.py) already emits astatus.update(kind=process) WS event on completion — but the renderer ignored it, and the payload carried only the agent-facing[IMPORTANT: ...]prose.Gateway: the
status.updatepayload now also carries the structured fields (event_type,command,exit_code) via a small_process_status_payload()helper, so GUI clients don't parse prose. Backward compatible —kindandtextare unchanged.Desktop: a new
store/process-notifications.tsmirrors the gateway'sdisplay.background_process_notificationssemantics fromgateway/run.py(all/result/error/off,false→off, unknown →all, env-independent) and builds the toast content;use-message-stream.tsroutes the event through the existing IPC bridge. The mode is synced from hermes config inuse-hermes-config.ts, so the same config key the messaging gateways honor now governs OS toasts — exactly what the issue asked for.Behavior decisions
document.hidden, same gate as the existing "Hermes finished" toast) or the process belongs to a non-active chat session.completionevents toast. Watch matches (watch_match) stay in-chat — they can legitimately fire many times per process and would spam the notification center.errormode toasts only non-zero exit codes;offdisables;all/resulttoast every completion.Known overlap
In the hidden + active-session case the user may get this toast and then the existing "Hermes finished" toast a few seconds later when the chained agent turn (which the poller injects) completes. They carry different information (immediate process result vs. agent's follow-up), so I left both rather than adding suppression heuristics; happy to gate one on the other if maintainers prefer. Related: #43255 adds a settings toggle for the agent-finished toast — this PR is independent of it but composes fine (different store, different event).
Testing
tests/test_tui_gateway_server.pypoller test extended to assert the enriched payload (event_type/command/exit_code) — 4 poller tests pass; the one failing test in that file (test_browser_manage_connect_default_local_reports_launch_hint) fails identically on pristinemain.process-notifications.test.ts(10 cases: mode normalization incl.false→off, error-mode gating, watch-match suppression, body truncation/fallback) — passes.main(verified on a clean worktree at the same commit); no new failures.tsc --noEmitandeslintclean on all touched files.🤖 Generated with Claude Code