agent_core/loop_types.py keeps fire-and-forget observer tasks in a module-global set:
_background_tasks: set[asyncio.Task[None]] = set()
...
if method == "on_loop_end":
await drain_background_observers() # drains every loop's tasks
drain_background_observers() gathers all pending tasks, not the ones this loop created. With two agent loops in one process — the ordinary sub-agent case — loop A's on_loop_end waits on loop B's still-running passive hooks.
Observed: a passive on_turn_end sleeping 3s in one logical loop made an unrelated loop's on_loop_end return 3.0s late. A passive hook awaiting something that is never signalled turns this into an indefinite hang of an unrelated loop's shutdown.
Fix direction: a per-loop task registry, or scope the drain to the tasks this loop scheduled. Note the drain exists for a real reason (a caller reading the event sink right after run() would otherwise race pending writes), so it must stay — just be scoped.
Provenance: pre-existing in ApodexHarness/miroharness/core/loop_types.py, ported verbatim by #1 — not introduced by the refactor. Fixing it here is the source-of-truth fix; ApodexHarness carries the same code and needs the same change until it consumes AgentCore.
agent_core/loop_types.pykeeps fire-and-forget observer tasks in a module-global set:drain_background_observers()gathers all pending tasks, not the ones this loop created. With two agent loops in one process — the ordinary sub-agent case — loop A'son_loop_endwaits on loop B's still-running passive hooks.Observed: a passive
on_turn_endsleeping 3s in one logical loop made an unrelated loop'son_loop_endreturn 3.0s late. A passive hook awaiting something that is never signalled turns this into an indefinite hang of an unrelated loop's shutdown.Fix direction: a per-loop task registry, or scope the drain to the tasks this loop scheduled. Note the drain exists for a real reason (a caller reading the event sink right after
run()would otherwise race pending writes), so it must stay — just be scoped.Provenance: pre-existing in
ApodexHarness/miroharness/core/loop_types.py, ported verbatim by #1 — not introduced by the refactor. Fixing it here is the source-of-truth fix; ApodexHarness carries the same code and needs the same change until it consumes AgentCore.