Multi-level orchestration: pull-based remote grandchild visibility - #14763
Multi-level orchestration: pull-based remote grandchild visibility#14763danielpeng2 wants to merge 2 commits into
Conversation
Cloud runs that orchestrate children of their own have no push channel to this client in v1, so nothing surfaced their subtrees. This adds pull-based discovery: a new RemoteSubtreeModel reads the children list on watched remote runs' public-API run items, materializes local placeholder conversations for them (the shared-session viewer's pattern), and refreshes statuses on a slow 30s poll. Placeholders flow through the regular parent/child topology, so the drill-down pill bar, navigation, and rollups need no remote-specific handling. Polling goes dormant only after a "final sweep" — a successful fetch issued after the watched run terminated — so children spawned by fast-completing runs (between the last fetch and termination) are still discovered. Also fixes hidden remote-child pane hydration for RUNNING runs: the LiveAttach arm only flipped view-model state and never connected the pane's deferred shared-session viewer, leaving an empty pane. It now attaches the live session explicitly. This was a latent pre-existing bug too: a still-running level-1 remote child opened after an app restart showed an empty pane. Co-Authored-By: Warp Agent <agent@warp.dev>
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
|
I'm starting a first review of this pull request. You can view the conversation on Warp. I completed the review and no human review was requested for this pull request. Comment Powered by Oz |
There was a problem hiding this comment.
Overview
This PR adds pull-based discovery for remote orchestration subtrees and updates remote-child hydration so attachable running sessions connect explicitly. The implementation is directionally scoped to the attached diff, but there are lifecycle gaps in the new polling model and the PR lacks the visual evidence required for this user-facing behavior change.
Concerns
- The remote subtree watches are only synced from later history/controller events. A restored or already-active orchestration view can mount with remote children already visible but never start pull discovery until some unrelated event fires, leaving grandchildren hidden.
- Bulk terminal-surface clears are ignored by
RemoteSubtreeModel, so entries for cleared conversations can keep issuing remote task fetches after the pane/history surface is gone. - For this user-facing change, please include screenshots or a screen recording demonstrating nested remote children and live attach working end to end.
Verdict
Found: 0 critical, 3 important, 0 suggestions
Request changes
Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).
Powered by Oz
| /// Registers the conversations rendered by this bar with | ||
| /// [`RemoteSubtreeModel`] so cloud-side children of any remote node are | ||
| /// discovered via pull and rollup badges refresh on its slow poll. | ||
| fn sync_remote_subtree_watches(&self, ctx: &mut ViewContext<Self>) { |
There was a problem hiding this comment.
sync_remote_subtree_watches only runs from later event handlers, so a pill bar that mounts around an already-restored orchestration tree can display remote nodes without ever starting pull discovery until another history/controller event happens. Invoke the sync once during initialization or from the render/spec path so existing remote children are watched immediately.
There was a problem hiding this comment.
Looked into this — I don't think the gap is reachable, so leaving as-is:
- The pill bar is constructed eagerly in
TerminalView::newalongside a freshAgentViewControllerthat always startsInactive, and the controller handle isn't reachable externally until the view is built, so the bar can't miss an activation event. - The bar renders nothing unless the controller is fullscreen, and every path into fullscreen goes through
enter_agent_view_internal, which emitsEnteredAgentView— the pill bar's controller subscription runssync_remote_subtree_watcheson every controller event (thematches!gate only clears mouse states). - All restore paths hydrate conversations before entering agent view, and
restore_conversationsunconditionally emitsUpdatedConversationStatusper restored conversation (another sync trigger, with no surface filter). Startup restore doesn't auto-enter agent view at all, so nothing displays until an entry that triggers the sync with the tree already in history.
So any pill bar that displays remote nodes has necessarily had a sync run after the tree was present. A construction-time sync would also be a no-op there since the controller is always Inactive at that point (and render can't do it — it takes &AppContext).
| | BlocklistAIHistoryEvent::UpdatedStreamingExchange { .. } | ||
| | BlocklistAIHistoryEvent::SetActiveConversation { .. } | ||
| | BlocklistAIHistoryEvent::ClearedActiveConversation { .. } | ||
| | BlocklistAIHistoryEvent::ClearedConversationsForTerminalSurface { .. } |
There was a problem hiding this comment.
/agent/runs/{id} every 30s after the surface is gone; remove all cleared_conversation_ids here and prune them from child maps.
There was a problem hiding this comment.
Fixed in 5c5d632: ClearedConversationsForTerminalSurface now unwatches every id in cleared_conversation_ids and prunes child references from the remaining entries (shared unwatch helper with the remove/delete path), with a unit test covering both.
One correction on the mechanism: the bulk clear does not remove conversations from conversations_by_id, so they aren't missing from history. The actual leak is that a cleared conversation loses its surface association, so register_or_update_child bails and the watched node's status freezes — a node frozen in a non-terminal status keeps subtree_may_still_change true forever. The missing-conversation/final-sweep loop only arises downstream (e.g. a cleared conversation later deleted with no surface emits no event). Either way, dropping the entries on clear fixes it; restore/reopen re-watches via the existing sync triggers.
ClearedConversationsForTerminalSurface emits no per-conversation remove events, and a cleared conversation loses its surface, freezing its local status. RemoteSubtreeModel previously ignored the event, so watched entries could keep polling the runs endpoint every 30s indefinitely. Drop cleared conversations from the watch set and prune child references; restore/reopen re-watches via the existing sync triggers. Co-Authored-By: Warp Agent <agent@warp.dev>

Description
Stacked on the multi-level orchestration client core. Makes the subtrees of REMOTE (cloud) children visible at depth, and fixes hidden remote-child pane hydration for running runs.
Pull-based remote grandchild discovery. A cloud run that orchestrates children of its own has no push channel to this client in v1 (root-keyed SSE fan-out is deferred), so nothing surfaced its subtree. A new
RemoteSubtreeModelwatches the remote nodes the pill bar displays, reads thechildrenlist on their public-API run items one level at a time, and materializes local placeholder conversations for them — the same pattern the shared-session viewer uses. Placeholders join the regular parent/child topology, so the drill-down bar, group-pill badges, navigation, and root-card rollups need no remote-specific handling; clicking a discovered grandchild opens it through the existing hidden-pane machinery.Statuses refresh on a slow 30s poll. Polling goes dormant only after a final sweep — a successful fetch issued after the watched run terminated — which guarantees children spawned by fast-completing runs (between the last fetch and termination) are still discovered; failed fetches keep retrying instead of stranding the subtree.
Hydration live-attach fix. Hidden remote-child panes are built on a deferred shared-session viewer that shows nothing until it connects to a session. The hydration path's live-attach arm only flipped view-model state and never connected, so clicking a RUNNING remote child whose pane was created after the fact showed an empty conversation view. The hydration decision now carries the attachable session id and the pane attaches it explicitly, mirroring the attach-to-running flow used by the agents panel. Note this also fixes a latent pre-existing bug: a still-RUNNING level-1 remote child opened after an app restart showed an empty pane.
Linked Issue
Part of the multi-level orchestration work (client side); pairs with the warp-server
OrchestrationMaxDepthchanges.Testing
cargo clippy -p warp --all-targets --tests -- -D warnings,./script/format, and the full targeted orchestration test suite (109 tests) are clean at the stack tip../script/run(nested cloud children in depth-2 trees)https://www.loom.com/share/e253b7c77bb044448fa98e4a5b2af960
Agent Mode
Co-Authored-By: Warp Agent agent@warp.dev