#115400·OpenClaw

sessions_send: no synchronous wait option + duplicate delivery via async announce after sync tool result already returned

Author: Toopac7Created Jul 28, 2026Updated Oct 2, 2026
LabelsP2impact:session-stateimpact:message-lossclawsweeper:not-repro-on-mainissue-rating: 🦪 silver shellfish

We use sessions_send heavily for a gatekeeper-agent pattern: a "front" agent (rep-facing) calls a specialized "back" agent (CRM-lookup agent) via sessions_send, then sessions_yields to end its own turn while the back agent's session runs independently and its answer arrives later via the framework's async inter-session announce delivery.

This creates two structural problems that have caused repeated production incidents on our side (5 rounds of incident/fix since 2026-07-08, all symptoms of the same root cause):

1. No synchronous "send and truly wait for reply" primitive

sessions_send returns as soon as the target session accepts the message; it does not block until that session produces a substantive reply. Any caller that needs the real answer within the same synchronous request/response cycle (e.g. a webhook handler serving a chat client over HTTP, where the HTTP response must contain the real answer) has no supported way to actually wait for it — the calling agent's own turn ends at sessions_yield, before the async reply exists.

Workaround we've built: read the target session's own transcript file directly by its sessionKey (captured from the sessions_send tool-call result) and poll it for a substantive assistant message. This works, but it's an out-of-band filesystem read of implementation details (~/.openclaw/agents/<agentId>/sessions/sessions.json → transcript JSONL) that we shouldn't have to rely on — it broke once before when an internal compaction/format change altered our assumptions about the transcript layout, and is fragile by construction.

Ask: either (a) a sessions_send mode/flag that blocks the calling turn until the target session produces its next substantive reply (with a caller-specified timeout), returning that reply's text directly to the caller instead of only an "accepted" acknowledgment; or (b) a supported polling API (not raw transcript-file reads) for "has session X replied to message Y yet, and what did it say" that doesn't require re-implementing transcript parsing/control-token filtering ourselves.

2. Duplicate delivery: async announce fires even when a synchronous result already existed

When the calling agent's sessions_send tool call itself already returns a result (e.g. an acceptance/ack payload) within the same turn, the target session's eventual real reply is also delivered asynchronously via announce to the calling session later — as a second, separate inter-session message. If the calling session already ended its turn (e.g. moved on to other work, or a subsequent request started a new turn), this second delivery can land mid-way through unrelated work, confusing prompt state, or in our case, get silently buried when multiple retries have stacked overlapping async deliveries in flight at once.

Ask: a sessions_send option to suppress the async announce delivery when the caller doesn't want a second later delivery — e.g. delivery: { mode: "none" } equivalent already exists for cron jobs per this framework's own conventions; parity for sessions_send inter-agent calls would let us opt out of the duplicate-delivery pattern cleanly instead of filtering it out after the fact on our side.

Supporting evidence (our internal incident history, available on request)

  • 2026-07-08: async relay/announce delivery for a sessions_send call sat undelivered 8+ minutes in one observed case; a separate case showed the relay layer erroring outright ("Unknown target ... for Telegram"). Never root-caused on our end since it's framework-internal.
  • 2026-06-03: documented as a known, currently-unfixable-from-userland issue in our own internal runbook: "OpenClaw's delivery.mode: announce fires async AFTER the synchronous tool result is returned, injecting the same CRM data as a second inter-session message. This is framework-level behavior — cannot be suppressed via agent instructions."
  • 2026-07-22: retry pileup — when a caller doesn't wait long enough and retries with a fresh session, multiple concurrent target sessions' delayed async announces land back-to-back and can bury the real answer in the caller's turn ordering.

What we are NOT asking for

  • We are not asking OpenClaw to change the underlying agent-isolation model (separate sessions, separate workspaces) — that's working as intended and is valuable for our use case.
  • We are not asking for a change to how sessions_spawn/subagent completion events work — those already have sessions_yield as a supported wait primitive; this ask is specifically about the same-tier sessions_send (session-to-session messaging) pattern, which currently has no equivalent supported wait primitive.