#Inter agent communication does not work.

1 messages · Page 1 of 1 (latest)

hallow wren
#

Agents kan send messages to each other just fine, but when the agent is finished with the tasks and reports back that its done then this message arrives, but does not trigger response. If I then ask status the agent is able to read the signoff.

primal garnetBOT
#

To help others find answers, you can mark your question as solved via Right click solution message -> Apps -> ✅ Mark Solution

tawny voidBOT
#

What you’re seeing is (usually) expected on Discord:

  1. Discord bot-authored messages are ignored by default, so a “done” message coming from another bot/agent won’t start a new agent turn unless you opt in.
  2. Even if you opt in, OpenClaw still filters the bot’s own messages (loop prevention), so an agent can’t “trigger itself” by posting a message in the channel.

From the config reference (Discord section): bot-authored messages are ignored by default; allowBots enables them, but “own messages still filtered”.
https://docs.openclaw.ai/gateway/configuration-reference (search for allowBots)

Fix / options

A) If “done” is coming from a different Discord bot

Enable bot inbound messages:

{
  channels: {
#
    discord: {
      allowBots: "mentions", // or true
    },
  },
}

Then make sure the “done” message mentions the receiving bot if you use "mentions".

Docs: https://docs.openclaw.ai/channels/discord

B) If “done” is coming from the same bot identity

That will never trigger a new run (it’ll show up as context next time you talk, which matches your “ask status → it can read the signoff” observation).

In that case you need to either:

  • use two Discord bots/accounts (one per agent) and route them via multi-agent bindings, or
#
  • don’t use Discord messages as the signaling mechanism—use internal session messaging/orchestration instead.

Multi-agent doc (one bot per agent is the recommended pattern): https://docs.openclaw.ai/concepts/multi-agent

Quick questions to confirm

  • Is the “done” message posted by the same Discord bot user as the one you expect to respond?
  • What’s your openclaw --version and your channels.discord + guild/channel requireMention settings (token removed)?
hallow wren
#

I do not use discort, I use telegram, I talk to my main agent who deligates to an orchistrator agent, the orchistrator agent has a team

#

the innitial send command works, the agents receive this direct and answers or start doing whatever they need to do. but when a task is completed the confirmation that its done does not get picked up

tawny voidBOT
#

On Telegram (and really for all channels), an agent run only starts when either:

  • the gateway receives a real inbound message from the channel (you typing in Telegram), or
  • another agent explicitly triggers it via session tools (e.g. sessions_send), not by posting a “done” message back into Telegram.

So the behavior you described matches this exactly:

  • Orchestrator/team finishes → OpenClaw posts a signoff/announce message into Telegram
  • That message is outbound, and Telegram bots don’t receive their own outbound messages as new inbound updates
  • Therefore it cannot trigger your main agent to run
  • Next time you type “status”, that does trigger a run, and the main agent can now “see” the signoff in history/pending context

This is also why sessions_spawn completions (and the “announce step” in sessions_send) feel like “they arrive but don’t wake anything up”.

Docs that describe the announce behavior: https://docs.openclaw.ai/concepts/session-tool

What to do instead (2 workable patterns)

#

Pattern A (simplest): make the main agent wait for the orchestrator
Have main delegate using sessions_send with a non-zero timeoutSeconds that’s long enough. Then main continues in the same turn and replies to you.

Pattern B (async): orchestrator calls back into the main session
When orchestrator is done, it should call sessions_send to the main sessionKey (not message.send to Telegram) with “done + results”. That will trigger a main-agent run internally, and the main agent can then message you.

Quick clarifier so I can point to the exact fix

In your current setup, is the main→orchestrator delegation implemented with:

  • sessions_spawn, or
  • sessions_send (and if so, are you using timeoutSeconds: 0 fire-and-forget), or
  • just message.send back into Telegram?

If you paste the relevant snippet of your agent’s tool call (redact any secrets), I can tell you which pattern fits best.

#

That’s the key detail: the “task completed / done” message you’re seeing is an outbound announce, not an inbound message into the other agent’s session — so nothing “picks it up” automatically.

In OpenClaw terms, this almost always happens when you delegate with one of these patterns:

1) sessions_send with timeoutSeconds: 0 (fire-and-forget)

  • Initial send works → target agent starts immediately (you observe this)
  • When target finishes, OpenClaw may post an announce to your Telegram chat
  • But the requester agent is not waiting, so it never gets a tool result to continue from
  • And the announce message in Telegram does not trigger an agent run

Fix: don’t fire-and-forget if you expect the “done” to be picked up by the delegating agent. Use a non-zero timeout:

  • timeoutSeconds: 60/300/900 depending on how long the delegated task typically takes.

(Ref: sessions_send behavior + announce step: https://docs.openclaw.ai/concepts/session-tool)

2) sessions_spawn (always non-blocking)

#

sessions_spawn is explicitly non-blocking and only posts results back as an announce when done. Same outcome: you’ll see a “done” message, but it won’t wake another agent.

Fix: either (a) have the parent poll / follow up, or (b) use sessions_send when you need a synchronous “delegate → wait → continue” flow.


Quick diagnostic question

When your main agent delegates to the orchestrator, is it using:

  • sessions_send with timeoutSeconds: 0 (or a very small value), or
  • sessions_spawn?

If you paste the exact tool call JSON your main agent is making (just that block; redact nothing sensitive), I can tell you precisely which branch you’re on and what to change.

hallow wren
#

when discussing the issue with the (main) agent should this not be known?

tawny voidBOT
#

No — the Gateway “knows” (because it implements the behavior), but your (main) agent is just an LLM that only knows what’s in:

  • its system prompt + workspace files (AGENTS.md/SOUL.md/etc),
  • the current conversation context,
  • and any docs it explicitly reads.

The key gotcha here is: the thing you’re calling a “confirmation that it’s done” is typically an announce/outbound delivery step (from sessions_spawn, or from the announce phase of sessions_send). Outbound deliveries don’t come back in as inbound events, so they can’t “trigger” another agent turn.

Unless you’ve taught your main agent “never rely on announce messages to wake another agent; use sessions_send with a real timeout (wait) or implement an explicit callback”, it will often assume chat behaves like an event bus — which it isn’t.

Practical fix: put a rule in your main agent’s AGENTS.md like:

  • “If you need to act on completion, don’t use fire-and-forget. Use sessions_send with timeoutSeconds > 0 (wait), or have the worker sessions_send back into the main sessionKey. Do not assume a ‘done’ Telegram message will wake anyone up.”

If you paste the actual tool call your main agent is using for delegation (sessions_send/sessions_spawn + params), I can tell you exactly what to change (it’s usually just timeoutSeconds).

hallow wren
#

I have full agents, I do not want to use session_spawn. So main agent talks to Orchistrator, then orchistrator talks to B, (B can spawn itself) ben then needs to report back to orchistrator that then reports back to main.

#

how does the timeoutSeconds work, and how would it work if my main agents is deligating task to multiple agents?

tawny voidBOT
#

If you’re not using sessions_spawn, then the rule is pretty strict:

A “done” only gets picked up by the parent agent if the parent is either

  1. still waiting inside the sessions_send call (timeoutSeconds > 0), or
  2. the child explicitly triggers the parent with another sessions_send (a real inter-session send), not by posting an outbound “done” message to Telegram.

Right now your chain sounds like it’s doing this somewhere:

  • Main → Orchestrator: sessions_send(..., timeoutSeconds: 0) (fire-and-forget)
  • Orchestrator → B: sessions_send(..., timeoutSeconds: 0) (fire-and-forget)
  • B finishes → you see a “done” message in Telegram
  • But Orchestrator is not waiting, so it doesn’t “pick up” anything.
  • And the Telegram “done” message is outbound, so it doesn’t wake Orchestrator/Main.

Two ways to make your Main → Orchestrator → B → Orchestrator → Main chain work (without sessions_spawn)

Option A (simple + robust): make each hop wait

#
  • Main calls Orchestrator with timeoutSeconds > 0
  • Orchestrator calls B with timeoutSeconds > 0
  • B replies → Orchestrator continues and replies → Main continues and replies to you

This is the “RPC” style. It works reliably, but Main will be “busy” until done.

Option B (async): B must sessions_send back to Orchestrator, then Orchestrator back to Main

This is the “event/callback” style. It only works if B actually uses sessions_send targeting Orchestrator’s session, and Orchestrator then sessions_sends to Main’s session.

Key gotcha: for callbacks, the agent needs a real sessionKey to send to (and must be allowed to send to it). A Telegram message is not a callback.

The question that decides everything

In your current setup, when B “reports back that it’s done”, is B doing:

  • (good) sessions_send({ sessionKey: "<orchestrator session key>", message: "done ..." })
    or
  • (won’t wake anyone) message.send / normal chat output to Telegram / relying on an “announce” message?
#

If you paste one real example of the tool call B uses when it “reports back”, I can tell you exactly what to change (it’s usually either timeoutSeconds being 0, or B using message.send instead of sessions_send).

hallow wren
#

Is there a way to change the inter agent communication to Event-based (Registry-backed).

tawny voidBOT
#

timeoutSeconds is only about how long the caller waits for the other session to finish. It’s not a “kill switch” and it’s not the worker’s runtime limit.

From the Session Tools docs: https://docs.openclaw.ai/concepts/session-tool

What timeoutSeconds does in sessions_send

When agent A calls:

sessions_send({ sessionKey: B, message: "...", timeoutSeconds: N })

OpenClaw kicks off a run in session B. Then:

  • timeoutSeconds: 0
    “Fire-and-forget”
    → returns immediately with { status: "accepted", runId }
#

→ B keeps running in the background
→ A does not get a result to continue from in that same turn.

  • timeoutSeconds > 0
    “Wait for completion (up to N seconds)”
    → if B finishes within N seconds: { status: "ok", reply: ... }
    → if B takes longer than N seconds: { status: "timeout" } (B still continues running)
    → you can then use sessions_history later to see what happened.

So if your orchestration expects “B finished → orchestrator reacts”, then the orchestrator must either:

  • be waiting (timeoutSeconds > 0) on that sessions_send, or
  • be explicitly messaged by B (a callback sessions_send into the orchestrator session).

An outbound “done” message showing up in Telegram isn’t a callback and won’t wake anyone.


#

How this works with “main delegates to multiple agents”

You basically have 3 patterns:

Pattern 1 — Serial (simplest, no extra plumbing)

Main/Orchestrator does:

  1. sessions_send to agent B with timeoutSeconds: 300
  2. then sessions_send to agent C with timeoutSeconds: 300
  3. etc.

Downside: it’s sequential (B then C), not parallel.

Pattern 2 — Parallel start, then gather later (no sessions_spawn, but needs a “join” step)

Orchestrator does:

  • Start all workers with timeoutSeconds: 0:
#
sessions_send({ sessionKey: B, message: "...", timeoutSeconds: 0 })
sessions_send({ sessionKey: C, message: "...", timeoutSeconds: 0 })
sessions_send({ sessionKey: D, message: "...", timeoutSeconds: 0 })
  • Later, orchestrator either:
    • polls with sessions_history until each has replied, or
    • has each worker callback into orchestrator via sessions_send when done (best if you want push instead of polling).

This is the closest to “fan out / fan in” without sessions_spawn.

Pattern 3 — Main waits on Orchestrator (recommended shape)

Let the orchestrator handle the multi-worker complexity. Then:

  • Main → Orchestrator: sessions_send(..., timeoutSeconds: big_enough)
  • Orchestrator does Pattern 1 or 2 internally
#
  • Orchestrator returns one final summary to Main
  • Main replies to you

This keeps your “user-facing brain” (Main) clean.


One more practical gotcha

Parallelism only helps if your gateway is allowed to run multiple sessions at once (config agents.defaults.maxConcurrent). If it’s 1, you’ll still be effectively serialized even if you fire-and-forget multiple runs.


If you tell me which pattern you want (serial vs parallel fan-out), I can suggest the cleanest prompt/AGENTS.md rules for Main/Orchestrator/B so the “done” signals actually wake the next layer.

hallow wren
#

I think I will ask for a new feature, there should be a "secret" channel where agents can talk between each other, like a different channel.

tawny voidBOT
#

Not as a built-in “mode switch”, no.

OpenClaw’s inter-agent mechanism is fundamentally message-driven:

  • sessions run when they receive an inbound message (from a channel) or an internal send (sessions_send / agent RPC)
  • there isn’t a native “subscribe to completion events from other sessions” registry/event-bus that automatically wakes other agents when some run ends

What you can do (event-driven-ish options)

1) Use sessions_send as the event (callback)

This is the simplest in-process “event” model today:

  • Orchestrator → B: sessions_send(... timeoutSeconds: 0) (kick off)
  • When B is done: B must sessions_send back to Orchestrator (that’s the event)
  • When Orchestrator has all results: Orchestrator sessions_sends back to Main

That gives you true “done wakes parent” behavior without relying on Telegram messages.

#

2) Use Gateway Hooks/Webhooks to build a registry-backed event system (custom)

If by “registry-backed” you mean “durable event log / queue”, OpenClaw gives you the plumbing:

A common pattern is:

  • workers write an event to Redis/DB/file (your registry)
  • then hit POST /hooks/wake or POST /hooks/agent to wake the main/orchestrator session to consume events


but that requires you to implement the registry + handler logic (TypeScript hook or external service). It’s not just a config flip for agent-to-agent comms.

If you want this as a first-class feature

That’s a legit feature request (“session completion events that can route to other sessions/agents”). Best path is to open an issue: https://github.com/openclaw/openclaw/issues

#

If you tell me whether your agents are in the same agentId (multiple sessions) or truly different agentIds, I can recommend the cleanest callback approach with the least config friction.

#

That’s a totally reasonable feature request — and you can frame it as:

  • “Give agents an internal mailbox/bus” (durable, not tied to Telegram/Discord)
  • with explicit semantics: emit(event) / subscribe(filter) / ack()
  • and no accidental delivery into the user-facing chat.

Worth knowing: you already kind of have a “secret channel” today

Inter-agent messages sent via sessions_send are already persisted as inter_session provenance (they’re not normal user chat messages).

The part that leaks into your Telegram chat is the announce step (the “done” message you see). If you want “agents talk privately, only Main talks to me”, you can get close today by adopting a rule like:

  • Workers + orchestrator must respond with ANNOUNCE_SKIP during the announce step unless explicitly told to speak to the user.

(That won’t give you event subscriptions, but it fixes the “confirmation arrives but nobody picks it up” spam/confusion.)

For the feature request, I’d suggest asking for one (or both) of these

  1. A real internal agent bus / mailbox tool, e.g. events_emit, events_poll, events_subscribe (registry-backed, ackable).
#
  1. A smaller change: add a switch to session tools so they never “announce” unless requested, e.g.:
    • sessions_send(..., announce: false) or deliverMode: "silent"

Because right now, without a wait/callback, the only “completion signal” you see is that announce — which can’t wake other agents.

What to put in the GitHub issue

Include:

  • openclaw --version
  • your desired flow: Main → Orchestrator → workers (fan-out) → Orchestrator (fan-in) → Main
  • what you want to avoid: “done” messages in Telegram that don’t trigger anything
  • what you want instead: event-based callback without needing sessions_spawn

Issue link: https://github.com/openclaw/openclaw/issues

If you paste a sanitized example of the “done” message you see (and whether it’s coming from sessions_send announce), I can help you word the issue so it’s crisp and implementable.

hallow wren
#

Is there a way to make the agents talk in a rountable like way? Maybe through an external hub?

tawny voidBOT
#

Yes — if what you want is “routable” agent-to-agent messaging (publish to a hub, hub routes to the right agent/session, no need to keep sessionKeys in prompts), the clean way today is to put an external hub in the middle and use OpenClaw’s webhook ingress as the entry point back into the gateway.

Recommended architecture (hub + OpenClaw webhooks)

  1. Enable OpenClaw webhooks on the gateway
    Docs + exact config: https://docs.openclaw.ai/automation/webhook

At minimum:

{
  hooks: {
    enabled: true,
    token: "shared-secret",
    path: "/hooks",
    allowedAgentIds: ["main", "orchestrator"] // tighten this
#
  }
}
  1. Have agents POST events to your hub (HTTP endpoint / queue)
  • e.g. POST /events { from:"B", type:"task_done", correlationId:"..." , payload:{...} }
  1. Hub routes and wakes the right OpenClaw agent by calling:
  • POST /hooks/agent (run an agent turn) or
  • POST /hooks/wake (wake main heartbeat)

This is the part that turns “event emitted” into “agent actually runs now”.

Why this helps your exact problem

Your current “done” messages are outbound to Telegram, so they don’t wake other sessions. A hub → /hooks/agent call is a real inbound trigger into the gateway, so the orchestrator/main will actually run when the event arrives.

#

Caveats / design choices (important)

  • /hooks/agent by default runs in an isolated hook session and posts a summary into the main session (good for “event processing”).
  • If you try to route directly into existing long-lived sessions, you’ll run into sessionKey policy/security tradeoffs (the webhook docs cover defaultSessionKey and allowRequestSessionKey—be careful with that).

Quick question so I can suggest the simplest routing setup

Do you want the hub to:

  1. always wake Main (and Main decides what to do), or
  2. wake Orchestrator directly (so Main stays clean/user-facing)?

If you answer that, I can outline a minimal “event envelope” format and the safest webhook config knobs to use.

hallow wren
#

Gave this conversation to my agent and she will implement it and test. Thank you

tawny voidBOT
#

Nice — if it works out, please mark the solution in this thread (right-click the solution message → Apps → “Mark Solution”). That helps Answer Overflow index it for the next person.

If your agent hits anything weird during testing, paste:

  • the exact tool call it used (sessions_send params / timeoutSeconds)
  • and the resulting status (ok / timeout / etc.)
    and we can zero in quickly.
hallow wren
#

✅ Works as you described it... But I went further. I did find the sequential "roundtable" not wat I wanted... so I created a app within my command center that can be used to sent messages to everyone part of a roundtable. A sents message to Conference room.. and Conference rooms sends message to all participating Agents with istructions how to answer and were etc. when a agent answers it sends again the answer to everyone. Need to see long term if that works but first tests were promising. App also creates a transcript of the meeting who said what... Now working on the frontend part.