Bind the node emitter's session into its durable events - #25
Closed
Parad0x-Labs wants to merge 1 commit into
Closed
Parad0x-Labs wants to merge 1 commit into
Parad0x-Labs wants to merge 1 commit into
Conversation
_agent_node_emitter takes session_id as its documented per-session parameter, but the closure never used it: the streaming seam persists only what the source context names, so a turn whose context carries no session key (the conductor hands the raw ask context) wrote its node rows nowhere -- the blank-Agents-panel regression this emitter exists to prevent. The emitter now captures a sink context once at creation, defaulting session_id to the session it was built for, additive and never overriding a session the caller already named. The client-turn-id suite drove this seam through a bare object(), which predates the streaming route and died with AttributeError; its emitter helper now binds the factory to a carrier of exactly the two production mixins the streaming route reads, so the real emission code still runs without booting an agent. 4 CI failures (main run 35570948370, every PR run since) -> 7 passed; the twelve node-event neighbor suites are identical to clean main.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What failed
tests/test_runtime_events_carry_the_client_turn_id.py— 4 of 7 cases red in the main CIcensus (run 35570948370) and in every PR run since; failing since the public root
(
78f818b), reproducing locally 4/4 deterministic:AttributeError: 'object' object has no attribute '_emit_runtime_event'atcore/agent_runtime/agent.py:3681(raised inside worker threads)test_node_events_carry_the_client_turn_id_through_the_real_runner: 0 events where 4were asserted
Root cause (product defect, not just a stale test rig)
Two layers:
_agent_node_emitter(session_id, source_context)documents itself as the per-session durable emitter ("A per-turn emitter putting node
lifecycle on the durable stream the UI polls") and accepts
session_idas its firstparameter — but the closure never uses it. The streaming seam it routes through
(
_emit_runtime_event→orchestrator.emit_runtime_event→core.runtime_task_events.emit_runtime_event) persists only what the source contextnames (
runtime_session_id/session_id). A turn whose context carries no session key —e.g. the conductor handing the raw ask context — wrote its
agent_node_*rows nowhere:the blank-Agents-panel regression class this emitter exists to prevent (its own docstring
cites the 2026-08-29 IDLE-companion incident).
bare
object()("It reads nothing offself" — true when the emitter wrote through amodule-level append; false since the streaming seam reads
self._emit_runtime_event).Repair
core/agent_runtime/agent.py: the emitter captures asink_contextonce at creation(same concurrency law as the tags it already captures on the turn's thread) with
setdefault("session_id", session_id)— additive, never overrides a session the caller'scontext already names; the per-emit call routes through the streaming seam with it.
tests/test_runtime_events_carry_the_client_turn_id.py: the helper binds the factory to acarrier of exactly the two production mixins the streaming route reads
(
ToolResultWorkflowSurfaceMixinfor_emit_runtime_event,RuntimeCheckpointSupportMixinfor the checkpoint resolver) — both stateless adapters, sothe real emission code still runs without booting an agent. No assertion changed.
Validation
node events, no duplicates, when the context already names a session — the setdefault
no-op path).
(
test_a_running_node_is_visible_while_it_runs,test_agent_node_events_reach_companion,test_node_events_reach_the_pollable_stream,test_chat_companion_laws,test_the_agents_panel_shows_work_while_it_happens,test_worker_effect_context_p0, …):178 passed, 3 failed — byte-identical result on clean main (the 3 are pre-existing:
2 × worker_effect served weather + 1 × event_log untagged grouping; stash-verified A/B).
ruff check .clean (pinned 0.16.7).Base: main
8153a96. Head:3b19e6b. Files:core/agent_runtime/agent.py(+10),tests/test_runtime_events_carry_the_client_turn_id.py(helper only, assertions unchanged).