Summary
await_replies(correlation_id) subscribes to device-connect.<zone>.*.event.async_reply.<correlation_id> only when it is called (tools.py, await_replies → subscribe("correlation:...")). Devices answer a broadcast within milliseconds, so every reply published before that subscription exists is lost. Any agent that issues broadcast and await_replies as two separate tool calls (every LLM tool loop does) sees zero replies whenever the gap between the calls exceeds the devices' response time.
Repro (real broker, 20 candidate devices, 10 elected)
b = broadcast("device(model_id:X,location:area-05).function(observe_battery_function)", {}, where="status.battery_function == 1")
await_replies(b["correlation_id"], timeout=8) # immediately: 10 replies
# ... same with time.sleep(1.0) between the two calls: 0 replies
Devices executed and published 10 replies in both cases (fixture receipts confirm). Observed in an LLM-agent benchmark: Codex Astra lost all replies on a tier-100 state-filtered action (its reasoning gap between the two tool calls was about a second); Claude Sonnet 5 hit it intermittently at 10k ("broadcast appears non-responsive").
Proposal
broadcast() should open the reply subscription (or register the correlation id with a session-wide async_reply.> capture) before publishing the envelope, and await_replies() should drain that buffer. The correlation id is generated inside broadcast, so it can subscribe first and publish second.
- Keep
await_replies semantics (timeout / until) unchanged; only the buffering start moves.
- Regression: broadcast, sleep 1 s, await_replies → all replies present.
Relates to the broadcast/where path added in #64. Workaround in our harness: a session-wide wildcard subscription opened at connect time.
Summary
await_replies(correlation_id)subscribes todevice-connect.<zone>.*.event.async_reply.<correlation_id>only when it is called (tools.py,await_replies→subscribe("correlation:...")). Devices answer abroadcastwithin milliseconds, so every reply published before that subscription exists is lost. Any agent that issuesbroadcastandawait_repliesas two separate tool calls (every LLM tool loop does) sees zero replies whenever the gap between the calls exceeds the devices' response time.Repro (real broker, 20 candidate devices, 10 elected)
Devices executed and published 10 replies in both cases (fixture receipts confirm). Observed in an LLM-agent benchmark: Codex Astra lost all replies on a tier-100 state-filtered action (its reasoning gap between the two tool calls was about a second); Claude Sonnet 5 hit it intermittently at 10k ("broadcast appears non-responsive").
Proposal
broadcast()should open the reply subscription (or register the correlation id with a session-wideasync_reply.>capture) before publishing the envelope, andawait_replies()should drain that buffer. The correlation id is generated insidebroadcast, so it can subscribe first and publish second.await_repliessemantics (timeout / until) unchanged; only the buffering start moves.Relates to the broadcast/
wherepath added in #64. Workaround in our harness: a session-wide wildcard subscription opened at connect time.