v3.6.0
A reply finds the exact agent that asked
Headline: same-workspace agents now reply to the exact pane that asked. A task's reply returns to its originating pane instead of the workspace's active one, same-workspace history finally tells the two agents apart (sender vs receiver, per pane), and a status update is restricted to the addressed pane — completing the pane-level multi-agent mesh that #239 and #242 began. Plus a fix for the terminal+browser split that blanked its unfocused side.
Added
- A2A symmetric reply — a reply returns to the exact pane that sent the task, and same-workspace history is told apart per pane (S-C2, #248). Follow-up to same-workspace agent messaging (#239). The task address model was asymmetric:
tocarried a pane anchor (#235) butfromdid not — so a reply had no pane to return to (it fell back to the workspace's active pane, or was suppressed same-workspace), and same-workspace history role collapsed touserfor both parties, making the two panes' messages indistinguishable. The hardening in #242 already captured and validated the sender's pane id on the send path, then discarded it; persisting it intometadata.fromopens three things with no new trust surface. (1) Symmetric reply pinning — a reply destined for the original sender now returns to that exact pane instead of the active-pane fallback, so a sender workspace running more than one agent gets the reply on the right pane (fail-closed if that pane has since closed — never a wrong-agent paste). (2) Per-pane history role — the role is computed from the caller's verified pane (userfor the sender pane,agentfor the receiver pane) instead of collapsing same-workspace. (3) Pane-granular status authz — a status update (a2a_task_update) on a pane-addressed task is restricted to the addressed receiver pane, not any pane in its workspace. A same-workspace reply is delivered as a one-line nudge to the addressed sibling — never a full-body paste into a live agent's prompt — and is suppressed entirely when it can't be proven a non-self target, so the #239 self-loop guard is preserved. The headlessexecute:trueworker (which carries no sender pane id) is never locked out: an absent caller pane always falls back to workspace-level authz. Cross-workspace delivery and role are unchanged.
Fixed
- Terminal + browser split no longer blanks the unfocused side (#247). A pane holding both a terminal and a browser surface renders them in a side-by-side split, but each surface gated its visibility on the pane's single active-surface id — so focusing one side hid the other (
display:none) and the unfocused pane went blank, toggling as you switched. Visibility is now decoupled from focus: both sides stay rendered, and the active-surface id only drives keyboard focus.