Keep older daemons usable and let clients choose timeline recovery (#4737)

* fix(subscriptions): preserve older-host workflows and explicit timeline recovery

Keep established app and SDK workflows available on older daemons without emulating independent directory filters. Restore live timeline membership without choosing the consumer's history recovery policy. Preserve daemon filesystem paths separately from legacy workspace IDs.

* fix(client): keep legacy workspace replies scoped to the requested page
This commit is contained in:
Mohamed Boudra
2026-09-12 08:50:16 +02:00
committed by GitHub
parent d0e1edca7f
commit 03a54a171d
27 changed files with 1560 additions and 395 deletions
+4 -2
View File
@@ -356,8 +356,10 @@ query, and toast providers inside the surface content, including overflow pages
plugins. Providers only around the trigger do not reach those bodies.
Request observation with `client.paseo.agents.list({ subscribe: {} })` and consume the returned
`subscription` handle. Plain `list()` and local `.subscribe(handler)` listeners create no daemon
demand. Each list-and-subscribe call has its own server ID, even for the same query. Handle snapshots
`subscription` handle. Plain `list()` and agent/workspace directory `.subscribe(handler)` listeners create no daemon
demand. Provider and project `subscribe()` calls establish their own demand. On capable daemons, each
list-and-subscribe call has its own server ID, even for the same query. Older daemons retain
[shared delivery behavior](protocol-compatibility.md#owned-observations). Handle snapshots
also run after reconnect; replace your view before applying its subsequent updates. The installation
owns every observation created through its API and releases them on unload, including setup failure.
Mounted surfaces and command invocations have shorter API lifetimes.
+15 -4
View File
@@ -46,15 +46,26 @@ The app, CLI, and plugins inherit those defaults; they supply only host resource
automation, or explicit overrides. A schema accepting a message does not establish support for
its delivery semantics.
Connecting creates no timeline or event demand. Client subscriptions own their network membership,
On capable daemons, connecting creates no timeline or event demand. Client subscriptions own their network membership,
release it on unsubscribe, and restore it after reconnect. Raw message observers inspect traffic
without requesting streams. Application caches and which agents are visible remain caller-owned.
## Owned observations
`owned_subscriptions` and `server_info.features.ownedSubscriptions` negotiate the entire source-owned
contract described in [architecture](architecture.md#websocket-protocol). The client gates observation
once and tells users to update an older host. It does not emulate independent handles over legacy slots.
`owned_subscriptions` and `server_info.features.ownedSubscriptions` negotiate the source-owned
contract described in [architecture](architecture.md#websocket-protocol). The client selects delivery
behavior once at its connection boundary. App workflows use the same observation interface on both.
With an older daemon, the client uses the existing connection and legacy RPCs. Directory subscriptions
remain shared and last-query-wins. Local handle IDs identify listeners; they do not promise independent
server filters. Timeline and event membership retain their existing shared behavior. Releasing a handle
detaches its listener and uses the old unsubscribe operation where one exists. Broadcast-only hosts keep
broadcasting; readiness there means local attachment, not a daemon acknowledgement. No extra sockets
or multiplexing emulation are introduced.
Preserve established workflows when changing delivery internals. Independent filters and quiet
connections require a capable daemon; opening the app, reading history and using terminals do not.
Pre-registry workspace grouping and legacy event normalization belong inside the client boundary.
Old clients keep their existing wire shapes and slot behavior at the daemon's source boundary.
The adapter keys legacy slots by physical socket, so an old connection cannot replace a modern