Skip to content

fix(delegation): route async delegate_task results back to originating session - #58690

Closed
asimons81 wants to merge 1 commit into
NousResearch:mainfrom
asimons81:fix/async-delegation-session-routing
Closed

fix(delegation): route async delegate_task results back to originating session#58690
asimons81 wants to merge 1 commit into
NousResearch:mainfrom
asimons81:fix/async-delegation-session-routing

Conversation

@asimons81

Copy link
Copy Markdown
Contributor

Summary

Fixes #58684.

Background delegate_task results are delivered to whichever session happens to be active when the subagent finishes, not the session that dispatched it — causing cross-contamination between unrelated sessions.

Root cause: The completion event already carries the dispatching session's session_key (captured at delegate_tool.py:2798), but the delivery router ignored it. drain_notifications() consumed all events from the shared queue without filtering by session, and the CLI/TUI post-turn drains had no session awareness.

Changes

  • tools/process_registry.py: drain_notifications() now accepts an optional session_key parameter. When provided, async-delegation events whose session_key doesn't match are re-queued instead of consumed.
  • cli.py: The process_loop drain passes the active session key to drain_notifications()
  • tui_gateway/server.py: The post-turn drain passes the TUI session's session_key
  • gateway/run.py: _build_process_event_source logs a warning when routing metadata is unresolvable (previously a silent drop)
  • Tests: two new regression tests covering session-filtered and unfiltered drain behavior

Behavior

Scenario Before After
Dispatch from session A, result arrives while session A is active ✅ Works ✅ Unchanged
Dispatch from session A, switch to session B before result arrives ❌ Result goes to session B ✅ Result waits for session A's drain
No session_key (CLI default) ✅ All events consumed ✅ Unchanged (backward compatible)
Gateway event with unresolvable session key 🤫 Silently dropped ⚠️ Warning logged

Testing

  • test_drain_notifications_filters_async_delegation_by_session_key (new) — verifies events are correctly filtered and re-queued per session
  • test_drain_notifications_no_filter_passes_all_async_delegation (new) — backward compatibility: no filter = all events consumed
  • All 5 drain_notifications tests pass
  • 19/20 async_delegation tests pass (1 pre-existing unrelated failure in test_crashed_runner_produces_error_completion)
  • 35/35 notify_on_complete tests pass

…g session

The completion event already carries the dispatching session's session_key
(captured at dispatch time in delegate_tool.py:2798), but the delivery
router ignored it — results landed in whatever session was active at
completion time instead of the session that dispatched the subagent.

Changes:
- drain_notifications() in process_registry.py: optional session_key
  filter. Non-matching async_delegation events are re-queued instead of
  consumed, so they remain available for the correct session's drain.
- cli.py process_loop: passes active session_key to drain_notifications()
- tui_gateway/server.py post-turn drain: passes session_key from the
  TUI session dict
- gateway/run.py _build_process_event_source: logs warning when routing
  metadata is unresolvable (previously silent drop)
- Regression tests verifying session-scoped drain filtering

Fixes NousResearch#58684
@asimons81
asimons81 force-pushed the fix/async-delegation-session-routing branch from c5a034c to 7ffa632 Compare July 5, 2026 06:43
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/gateway Gateway runner, session dispatch, delivery comp/tui Terminal UI (ui-tui/ + tui_gateway/) comp/tools Tool registry, model_tools, toolsets comp/cli CLI entry point, hermes_cli/, setup wizard tool/delegate Subagent delegation 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 labels Jul 5, 2026
@teknium1

teknium1 commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Merged via PR #60869 — your commit was cherry-picked onto current main with your authorship preserved in git log, plus a follow-up commit extending your session_key filter with a positive-proof ownership callback (compression-chain aware, fail-closed) for the TUI drain path. Your two-session regression tests transferred cleanly and pinned the behavior. Thanks — the drain hole was the piece none of the poller-side fixes touched.

@teknium1 teknium1 closed this Jul 8, 2026
@asimons81
asimons81 deleted the fix/async-delegation-session-routing branch July 30, 2026 00:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard comp/gateway Gateway runner, session dispatch, delivery comp/tools Tool registry, model_tools, toolsets comp/tui Terminal UI (ui-tui/ + tui_gateway/) P2 Medium — degraded but workaround exists 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 type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: delegate_task async results delivered to wrong session/thread

3 participants