feat(desktop): stream subagent activity into watch windows (#47060)
* feat(desktop): stream subagent replies into watch windows A desktop watch window resumes a child session lazily (no full agent) and mirrors the parent-relayed `subagent.*` events into native child-session stream events. The child's streamed reply text was never relayed, so the window sat blank while the subagent "talked". - delegate_tool: forward the child's `run_conversation` stream tokens up the progress relay as `subagent.text` (inert under CLI/TUI — their progress handlers ignore non-tool event types; only a gateway watch window mirrors it). - server: mirror `subagent.text` -> `message.delta` on the child sid only, and skip the parent emit (per-token frames are meaningless on the parent session, which shows the child via the spawn tree). Demote `subagent.start` to a one-time goal header and drop the noisy `subagent.progress` mirror — tools already mirror natively. - server: guard `_start_agent_build` so a lazy watch session spectating an in-flight child stays lazy; incidental RPCs were upgrading it to a full agent mid-stream and silently killing the mirror. * fix(desktop): keep watch-window chat clear of titlebar chrome Secondary windows (new-session scratch, subagent watch, cmd-click pop-out) hide the titlebar tool cluster + session header, so the transcript ran to the window's top edge and streamed text slid up under the OS traffic lights. - Gate the hidden chrome on `isSecondaryWindow()` everywhere (app-shell, chat header, thread list) instead of the narrower new-session flag. - Add a fixed opaque drag-strip at the top of the secondary-window transcript: content padding alone scrolls away with the text, so the strip masks anything behind it and keeps the window draggable like the main header. * fix: WSL subagent window * fix: subagent window top padding --------- Co-authored-by: Austin Pickett <pickett.austin@gmail.com> Co-authored-by: Teknium <127238744+teknium1@users.noreply.github.com>
This commit is contained in:
co-authored by
Austin Pickett
Teknium
parent
6ebc449915
commit
44e5848e74
@@ -867,6 +867,15 @@ def _build_child_progress_callback(
|
||||
_relay("subagent.complete", preview=preview, **kwargs)
|
||||
return
|
||||
|
||||
if event_type == "subagent.text":
|
||||
# Streamed assistant reply text from the child. Relay verbatim so a
|
||||
# gateway watch window can mirror the child "talking" as it streams.
|
||||
# No spinner echo — the CLI shows the child via the tree, and the
|
||||
# CLI/TUI progress handlers ignore non-tool event types, so this is
|
||||
# inert there; only a gateway watch window consumes it.
|
||||
_relay("subagent.text", preview=preview)
|
||||
return
|
||||
|
||||
# Normalise legacy strings, new-style "delegate.*" strings, and
|
||||
# DelegateEvent enum values all to a single DelegateEvent. The
|
||||
# original implementation only accepted the five legacy strings;
|
||||
@@ -1626,11 +1635,23 @@ def _run_single_child(
|
||||
# Python stack (see #14726 — 0-API-call hangs are opaque without it).
|
||||
_worker_thread_holder: Dict[str, Optional[threading.Thread]] = {"t": None}
|
||||
|
||||
def _relay_child_text(delta: str) -> None:
|
||||
# Forward the child's streamed reply text up the progress relay so
|
||||
# gateway watch windows mirror it live (subagent.text → message.delta).
|
||||
# Inert under CLI/TUI: their progress handlers ignore non-tool events.
|
||||
if not delta or not child_progress_cb:
|
||||
return
|
||||
try:
|
||||
child_progress_cb("subagent.text", preview=delta)
|
||||
except Exception as e:
|
||||
logger.debug("Child text relay failed: %s", e)
|
||||
|
||||
def _run_with_thread_capture():
|
||||
_worker_thread_holder["t"] = threading.current_thread()
|
||||
return child.run_conversation(
|
||||
user_message=goal,
|
||||
task_id=child_task_id,
|
||||
stream_callback=_relay_child_text,
|
||||
)
|
||||
|
||||
_child_future = _timeout_executor.submit(_run_with_thread_capture)
|
||||
|
||||
Reference in New Issue
Block a user