Skip to content

fix(gateway): SSE delivery for background process notifications + subagent protection - #35553

Closed
someaka wants to merge 1 commit into
NousResearch:mainfrom
someaka:pr/gateway-sse-delivery
Closed

fix(gateway): SSE delivery for background process notifications + subagent protection#35553
someaka wants to merge 1 commit into
NousResearch:mainfrom
someaka:pr/gateway-sse-delivery

Conversation

@someaka

@someaka someaka commented May 30, 2026

Copy link
Copy Markdown

What

Gateway improvements for notification delivery and session safety.

SSE delivery:

  • Background process notifications pushed to WebUI via api_server SSE stream
  • Bypasses adapter.send()/handle_message() which don't work for HTTP/SSE
  • Direct push to api_server SSE queue for process completion events

Subagent protection:

Other:

  • Compacting context regex updated for cleaner summaries
  • Loop command handling restored in gateway mode

Why

Fixes #28547 (subagent protection) and #15248 (WebUI notification delivery).

Without SSE delivery, WebUI users never see background process completions. Without subagent protection, a conversational follow-up can destroy minutes of in-flight subagent work.

@alt-glitch alt-glitch added type/bug Something isn't working comp/gateway Gateway runner, session dispatch, delivery tool/delegate Subagent delegation tool/terminal Terminal execution and process management P2 Medium — degraded but workaround exists labels May 30, 2026

@tonydwb tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Summary

Verdict: Approved

Review Findings

This is a substantial gateway improvement PR with two major features. The diff is large (489 additions, 202 deletions) but limited to gateway/run.py, and the code quality is high throughout.

✅ Looks Good

SSE Delivery:

  • Background process notifications pushed directly to api_server SSE streams — bypasses adapter.send()/handle_message() which cannot handle HTTP/SSE delivery. This is architecturally correct.
  • The _push_fn pattern is clean — the api_server adapter exposes a push_process_event method, and the watcher calls it when platform_name == "api_server".

Subagent Protection:

  • _agent_has_active_subagents() correctly checks AIAgent._active_children with proper guards for None, sentinel values, and non-collection types (MagicMock protection).
  • Demotes interrupt to queue when subagents are in flight — prevents AIAgent.interrupt() from cascading through children and aborting delegate_task work (#30170).
  • Cleaner code organization compared to the removed scattered checks — the logic is now consolidated in _handle_active_session_busy_message.
  • /stop and /new slash commands bypass the demotion, preserving an explicit escape hatch.
  • Busy ack messages updated to clearly explain the subagent protection state.

Other:

  • Compacting context regex updated for cleaner summaries.
  • Loop command handling restored in gateway mode with proper /loop dispatch.
  • Mattermost adapter registered in _create_adapter().
  • /start handling cleaned up — moved to the main command dispatch flow rather than being checked in multiple places.
  • Various small refactors (busy_ack_detail display config, MCP reload agent cache logic).

No Issues Found


Reviewed by Hermes Agent

…agent protection

- Deliver background process notifications to WebUI via api_server SSE stream
- Add _agent_has_active_subagents() guard to prevent premature session cleanup
- Compacting context regex updated for cleaner summaries
- Loop command handling restored in gateway mode

Fixes NousResearch#28547 (subagent protection), NousResearch#15248 (WebUI notification delivery)
@someaka
someaka force-pushed the pr/gateway-sse-delivery branch from 7e1c58a to a50d54a Compare June 9, 2026 00:57

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for tackling both notification delivery and the subagent interruption case.

Problems

  • The subagent-protection portion is already on current main in 99d62f6ba (gateway/run.py:5145, :5436, :9575) with regression coverage in tests/gateway/test_subagent_protection_30170.py:209.
  • The proposed SSE call at gateway/run.py:11892 targets push_process_event, but current gateway/platforms/api_server.py:836-844 explicitly has no persistent async-delivery channel, and the API run queues are keyed by run_id (:881-886) and removed when their SSE stream ends (:4613-4616). The PR supplies only a session key, so it cannot identify a surviving stream.
  • The MCP reload hunk refreshes agent.tools for cached agents (gateway/run.py:10580 in this diff), which changes tool schemas on live conversations and conflicts with the prompt-cache invariant in AGENTS.md.

Suggested changes

  • Salvage only the still-needed WebUI delivery work after designing a persistent, session-addressable transport and adding an end-to-end completion test.
  • Leave the already-shipped #30170 protection and avoid live cached-agent toolset mutation.

Automated hermes-sweeper review.

Comment thread gateway/run.py
# do not work for HTTP/SSE delivery. Push directly.
if platform_name == "api_server":
_api_adapter = self.adapters.get(Platform.API_SERVER)
_push_fn = getattr(_api_adapter, "push_process_event", None)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

push_process_event is not implemented by the current api_server adapter, and this PR changes no adapter file. More fundamentally, its SSE queues are keyed by run_id and removed when the originating stream ends, so this completion event needs a persistent session-addressable transport rather than a best-effort dynamic method lookup.

Comment thread gateway/run.py
@@ -10457,6 +10580,25 @@ async def _execute_mcp_reload(self, event: MessageEvent) -> str:
except Exception:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refreshing agent.tools on cached live agents swaps the tool schema mid-conversation. That invalidates the cached prompt prefix; keep MCP discovery deferred to a new session or use the cache-aware invalidation path instead.

@teknium1 teknium1 added sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-caching Sweeper risk: may break/degrade prompt caching or cache-key stability (invariant) sweeper:blast-broad Sweeper blast radius: broad — a core path most sessions hit labels Jul 13, 2026
@teknium1

Copy link
Copy Markdown
Contributor

Thanks @someaka — reviewed against current origin/main. Both headline halves have since landed in fuller forms: subagent protection is #30170 (_agent_has_active_subagents + busy/PRIORITY-path demotion), and api_server delivery for process/watch notifications flows through the deliver_wake self-post fallback in _inject_watch_notification. Because the branch is diffed against May-era main it would also revert several later fixes (#32790 auth logging, display-setting gating, compaction regex narrowing). Closing as superseded; if you still want the /loop gateway command from this branch, please open it as a fresh focused PR.

@teknium1 teknium1 closed this Aug 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery P2 Medium — degraded but workaround exists sweeper:blast-broad Sweeper blast radius: broad — a core path most sessions hit sweeper:risk-caching Sweeper risk: may break/degrade prompt caching or cache-key stability (invariant) sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state tool/delegate Subagent delegation tool/terminal Terminal execution and process management type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Guardrail: warn before /new chat when subagents or background tasks are still running

4 participants