Skip to content

feat(desktop): native OS notifications for background process completions#44213

Open
AIalliAI wants to merge 1 commit into
NousResearch:mainfrom
AIalliAI:fix/44201-desktop-process-native-notifications
Open

feat(desktop): native OS notifications for background process completions#44213
AIalliAI wants to merge 1 commit into
NousResearch:mainfrom
AIalliAI:fix/44201-desktop-process-native-notifications

Conversation

@AIalliAI

Copy link
Copy Markdown
Contributor

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:

  • The Electron main process already exposes a native-notification IPC bridge (hermes:notify in electron/main.cjs, surfaced as window.hermesDesktop.notify).
  • The gateway's notification poller (tui_gateway/server.py) already emits a status.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.update payload 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 — kind and text are unchanged.

Desktop: a new store/process-notifications.ts mirrors the gateway's display.background_process_notifications semantics from gateway/run.py (all/result/error/off, falseoff, unknown → all, env-independent) and builds the toast content; use-message-stream.ts routes the event through the existing IPC bridge. The mode is synced from hermes config in use-hermes-config.ts, so the same config key the messaging gateways honor now governs OS toasts — exactly what the issue asked for.

Behavior decisions

  • The toast fires only when the user can't see the in-chat message: window hidden (document.hidden, same gate as the existing "Hermes finished" toast) or the process belongs to a non-active chat session.
  • Only completion events toast. Watch matches (watch_match) stay in-chat — they can legitimately fire many times per process and would spam the notification center.
  • error mode toasts only non-zero exit codes; off disables; all/result toast every completion.
  • Failure toasts surface the exit code in the title: "Background process failed (exit 2)"; body is the command line (truncated to 140 chars).

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.py poller 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 pristine main.
  • New process-notifications.test.ts (10 cases: mode normalization incl. falseoff, error-mode gating, watch-match suppression, body truncation/fallback) — passes.
  • Full desktop vitest suite: the 6 failures present are identical on pristine main (verified on a clean worktree at the same commit); no new failures.
  • tsc --noEmit and eslint clean on all touched files.

🤖 Generated with Claude Code

…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>
@alt-glitch alt-glitch added type/feature New feature or request comp/tui Terminal UI (ui-tui/ + tui_gateway/) P3 Low — cosmetic, nice to have labels Jun 11, 2026
@AIalliAI

Copy link
Copy Markdown
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).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/tui Terminal UI (ui-tui/ + tui_gateway/) P3 Low — cosmetic, nice to have type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Desktop App native OS notifications for background process completions

2 participants