Repository navigation
feat(notifications): desktop and mobile notifications with Web Push - #218
Conversation
…ession can follow
The pruning that bounds the job store deletes a `gone` tombstone with no client-visible signal, so a browser that adopted another browser's recording could get a 404 and raise an error toast for a job that had in fact been delivered elsewhere. Only the browser that recorded (or retried) a job holds the audio to fall back on, so only it may report it as a failure; a follower that is locked out of the transcript is standing down by design. The attached-messages toast also blamed the agent for a rule that has nothing to do with it: `sendQueued` refuses attachments whether or not a run is active, and `followUp` is dispatched immediately when the agent is idle. The rule and its explanation are now one predicate, `queueAllowsAttachments`, used by both `sendQueued` and the dictation branch, so they cannot drift apart.
Stop withdrew queued messages one by one from this client's queue snapshot before aborting. A steer missing from that snapshot (promoted after the last queue_update) or claimed by the run but not yet recorded was never withdrawn, and omp drained it into a new turn right after the abort: the user pressed Stop and the steer ran anyway. Stop now sends abort_and_restore_queue, omp's Esc in one step (clearQueue forInterrupt, then abort), and restores the returned texts to the draft. omp without the command falls back to the per-entry withdrawal.
Review of the atomic Stop: - Capture the run fence at the click; a failed request is retried once and only while that run is current, so it can never abort a newer run. - Fall back to per-entry withdrawal only on "Unknown command" (omp without abort_and_restore_queue); any other failure retries the same command, and warns (new localized queueRestoreUncertain) when nothing came back. - Narrow the try to the request; drop an image-only "[Image]" label. - Tests: retry restores, lost response warns, no retry into a newer run, overlapping Stops share one request; tidy the server abort branch.
Prepare ompweb for publisher-default Auto effort in can1357/oh-my-pi#14114. Persist the choice through native config, preserve provider settings, and show the control and search result only when Reasoning is auto.
…in browser code Older browsers lack these APIs: Settings crashed on open, session catch-up stalled, and transcription polling failed. Use AbortController timers and plain promises, keeping the same timeouts and cancellation. Fixes kahme247#196.
Reuse the workspace refresh control and success checkmark. Bypass the server usage cache only for manual refreshes while retaining the existing five-minute automatic polling schedule.
Keep background polling silent, preserve refresh queries on older browsers, and ensure manual refresh is not satisfied by a concurrent background fetch. Cover persisted caching and hook behavior with regression checks.
A manual refresh must attempt cache invalidation even when the automatic fetch it waited behind rejects. Extend the CLI-backed regression to cover this failure path.
The reasoning trigger shows the terminal status line's level glyph instead of the level name (chevron hidden in narrow toolbars), so the model name keeps the room on phones. The menu pairs each glyph with its name. Slow was wired only for saved sessions, so a new session never showed it even after Fast had spawned omp. Offer it in new sessions too, and refresh live state after a new-session model change so support follows the model.
Without live omp state (new or idle session), predict omp's slowModeTarget from the catalog: /api/models marks supportsSlowMode by provider and reports providers.anthropic.slowMode, read fresh outside the models cache. Claude shows the shared setting (global scope); flex starts off (session). Live get_state wins as soon as omp runs, and clicking the toggle spawns omp like Fast does.
…t code Older mobile browsers lack these APIs, so calling them crashed the whole tree into the unexpected-error screen. Use browser-safe helpers. Fixes kahme247#196 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011RZdyVoycH4WVVDWJNctDR
… again Handle the session-persistence notice: re-read identity, keep the run state, re-key the registry (old id stays as an alias) and reuse a live wrapper that already reports the requested session file. Fixes kahme247#202 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011RZdyVoycH4WVVDWJNctDR
- auto-name asks omp (generate_title, else /rename) and only falls back to the derived title when omp cannot (Fixes kahme247#203) - provider detail lists the accounts omp reports for the provider (Refs kahme247#197) - tests and AGENTS.md notes Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011RZdyVoycH4WVVDWJNctDR
fix(queue): take the queue back on Stop through omp's atomic Esc
feat: add a Slow toggle and provider-neutral usage-limit badge
…urce feat(settings): add Auto thinking source selector
…efresh feat(usage): add manual provider usage refresh
…-compatibility fix(client): avoid AbortSignal.timeout/any and Promise.withResolvers
Take main's kahme247#199 client fix instead of the duplicate abort-signal helper. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011RZdyVoycH4WVVDWJNctDR
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011RZdyVoycH4WVVDWJNctDR
…edes-297gxo Support omp session moves and native title generation
Show the branch below the workspace name, keep the activity indicator beside the name, and preserve space for rename and branch controls.
Use OMP live resolution instead of duplicating discovery. Keep the native notice preference and never resume stopped sessions for inspection.
Add an icon-only dismiss button that hides the current report until its diagnostics change, and shorten the disable action to "Turn this off" so the notice text keeps its width on phones.
…s with Web Push Squashed from origin/feat/notifications (02ab6e6) onto upstream/main.
Squashed from origin/feat/notification-center (f988972) onto upstream/main. Semantic fixup vs PR kahme247#218: drop the removed completion notifier's record call; log OS-shown notifications from useNotifications in toastHistory.
…s with Web Push Squashed from origin/feat/notifications (02ab6e6) onto upstream/main.
Squashed from origin/feat/notification-center (a3da881) onto upstream/main. Semantic fixup vs PR kahme247#218: log OS-shown notifications from useNotifications in toastHistory (reapply on scratch rebuilds).
…s with Web Push Squashed from origin/feat/notifications (02ab6e6) onto upstream/main.
Squashed from origin/feat/notification-center (a3da881) onto upstream/main. Semantic fixup vs PR kahme247#218: log OS-shown notifications from useNotifications in toastHistory (reapply on scratch rebuilds).
…s with Web Push Squashed from origin/feat/notifications (a5899f0) onto upstream/main.
Squashed from origin/feat/notification-center (5df0463) onto upstream/main. Semantic fixup vs PR kahme247#218 (reapply on scratch rebuilds): useNotifications logs OS-shown notifications in toastHistory with the session onClick; history entries carry the toast onClick; NotificationList rows run it on click (with a test).
…s with Web Push Squashed from origin/feat/notifications (4955035) onto upstream/main.
Squashed from origin/feat/notification-center (5df0463) onto upstream/main. Semantic fixup vs PR kahme247#218 (reapply on scratch rebuilds): useNotifications logs OS-shown notifications in toastHistory with the session onClick; history entries carry the toast onClick; NotificationList rows run it on click (with a test).
…s with Web Push Squashed from origin/feat/notifications (8c66efd) onto upstream/main.
Squashed from origin/feat/notification-center (93acbe7) onto upstream/main. Semantic fixup vs PR kahme247#218 (reapply on scratch rebuilds): useNotifications logs OS-shown notifications in toastHistory with the session onClick; history entries carry the toast onClick; NotificationList rows run it on click (with a test).
…s with Web Push Squashed from origin/feat/notifications (8c66efd) onto upstream/main.
Squashed from origin/feat/notification-center (93acbe7) onto upstream/main. Semantic fixup vs PR kahme247#218 (reapply on scratch rebuilds): useNotifications logs OS-shown notifications in toastHistory with the session onClick; history entries carry the toast onClick; NotificationList rows run it on click (with a test).
…s with Web Push Squashed from origin/feat/notifications (8f99c19) onto upstream/main.
Squashed from origin/feat/notification-center (93acbe7) onto upstream/main. Semantic fixup vs PR kahme247#218 (reapply on scratch rebuilds): useNotifications logs OS-shown notifications in toastHistory with the session onClick; history entries carry the toast onClick; NotificationList rows run it on click or Enter (focusable when they have one, since there is no Open link), with a test.
kahme247
left a comment
There was a problem hiding this comment.
Review — approve (SHIP)
Verified by independent review in a scratch worktree plus lead checks. All claims hold.
Web Push (#218). VAPID private key never leaves the server (0600 store file; only {publicKey, subscribed} crosses the wire). All four endpoints sit behind the proxy.ts session-cookie gate; the two new matcher entries (/sw.js, /badge-96.png) are static and data-free. Stores bounded (MAX_DEVICES 50, presence pruned on read, zero server timers). Typecheck clean, targeted suites 93/93, mutations killed. The one real item is the #230 collision (below) — clean in isolation.
Coordinated merge note for #218 + #230: exactly one textual hunk (AppShell.handleAgentEnd) plus two silent breakages — #218 deletes lib/browser-notifications.ts that #230 still imports, and the appShell.sessionComplete/taskFinished keys #230 still translates. Resolution: land #230 first, resolve the hunk in favor of #218's useNotifications delivery, drop #230's handleAgentEnd record calls. History coverage then comes free (#218's showToast calls carry {id: tag}, which #230 auto-records with dedup). No duplicate centers, no unrenderable shapes.
3f1dbea to
42b3c29
Compare
Summary
Adds Settings → Notifications: desktop and mobile (PWA) notifications for
session_settled). Subagents never notify.askquestion, a confirmation, or any other blocking dialog.prompt_resultwithstatus: "error"after omp's retries and fallbacks, or the omp process crashing mid-run.retry_fallback_applied(refusal, rate limit, usage limit; for example Fable → Opus) and prewalk / plan hand-offs. The reason comes from the retry error omp sends right after the fallback.Each browser picks its own event types and what happens while you use omp-web in another tab: an in-app toast (default) or always a system notification. Nothing is shown for the session you are viewing, and clicking a notification opens its session.
How it works
AgentSessionWrapper.handleFrame, so sessions no tab is watching still notify.web-push, VAPID keys generated on first use in~/.omp/agent/omp-web/notifications.json, mode 0600)./api/agent/running/eventsstream, so a tab opens no extra connection.public/sw.jsshows pushes with our icon and a monochrome status-bar badge, and opens the session on click.The previous foreground-only completion notification is removed (noted in the CHANGELOG). The
notifyhost tool now goes through the service worker, so it also works on Android.Design spec:
docs/specs/2026-10-06-notifications-design.md.Verification
npm run typecheck,npm run lint(no new warnings),npm test: 1,252 tests, 0 failures. New tests cover the detector, the routing rules, push storage and failure handling, and therpc-managerwiring.askcall;Not done:
pushsubscriptionchangehandler: a browser-rotated subscription is repaired on the next app load.https:but not to public hosts (authenticated users already run agents with shell access).