Commit graph

1 commit

Author SHA1 Message Date
ouroboros-agent
72c3747acb feat(v7.3.0): notifications pull the owner back to a question or a finished task
While a client runs, Ouroboros can now reach the owner who left the window.
Settings -> Appearance gains a notification block beside the theme: a master
switch, the two required categories (a question or decision is waiting for you,
a task finished or stopped), a model-chosen category for messages Ouroboros
sends while it works, a separate off-by-default toggle for ordinary replies in
Main, sound, an off-by-default show-the-text choice, and a test notification.
The choices are stored per client exactly like the appearance choice, never
reach the server, and are excluded from the settings-dirty tracker so a
client-local toggle never offers to discard unsaved server settings.

Delivery is page-level: a system banner where this client exposes one and
permission is granted, otherwise the in-app surface plus one short tone, with
the status line stating which surface this client actually has. Either way a
click opens the source. No OS permission, Do Not Disturb or platform limit is
bypassed, and no native launcher path is added in this version.

web/modules/notifications.js keeps classification and the delivery gate pure
over one live frame plus the stored preferences, and takes ONE subscription per
client on the shared socket. It is deliberately NOT wired inside a chat
instance: an instance dies with its room, so a Project the owner never opened
would never have rung - the case notifications exist for. web/modules/chat.js is
byte-identical to before. Only live frames reach the notifier, so a reload
cannot re-notify without storing any notification state.

A finished task is recognised on the shape it actually arrives in (the live
task_done log frame) as well as the authored summary, and a conversation turn's
own ending stays the ordinary-reply category instead of claiming a task
finished; all of them collapse to one key per task. A child task never notifies
the owner: it escalates to its parent, and lineage is read from the delegation
facts frames carry because the terminal frame carries none. Importance needs no
new host field and no second model call - the existing proactive-message
discriminator is the signal.

Policy has one canonical home in docs/DESIGN.md section 9, including its
disclosed limits; docs/DEVELOPMENT.md carries the engineering invariant and the
architecture chapter names the owner. Two chapter byte budgets are raised with
stated reasons.

Verification: 1506 node tests; four browser journeys driving real socket frames
through ws.js (defaults off, one notification per event, silence on reload,
child conclusion withheld, unopened Project room reached, machine traffic
refused, click moves to the source); the deterministic repository gates (size
ratchet, generated manifests, README history limit, chapter budgets, docs sync)
pass. Three failures in the full battery are proven pre-existing by running the
same tests on the unmodified base commit.

Review-driven corrections in this commit, each with its own regression: a
`task_done` frame counts as an ending only with a SETTLED status, because an
update or restart teardown reports `interrupted` and requeues the same task id
(ringing there would also have burned that task's key and silenced its real
completion); a bare `task_terminal_status` chat row belongs to a DIRECT turn and
stays the ordinary-reply category instead of claiming a task finished; a child's
chat row is dropped whatever else it carries; the room gate mirrors
`mainThreadAccepts`, so an external owner transport notifies while the hidden
partition and A2A ids never do; and the client-level listener absorbs its own
errors, because it runs before the chat instances' handlers and `ws.emit` does
not isolate them.
2026-09-20 01:33:19 +03:00