Summary
The Slack adapter strips the receiving bot's own <@UID> from the message
body before handing it to the agent (resolve_slack_mentions,
crates/openab-core/src/slack.rs:1553-1584, called at :1258). This is
correct on its own — it lets the LLM @-mention other users in its reply.
But in a multi-agent deployment it removes the only per-recipient signal
each bot has to tell whether it was explicitly mentioned, which breaks any
"should I respond or defer?" logic when one message @-mentions two or more
bots.
Environment
- openab version: 0.9.0
- Adapter: Slack (Socket Mode). The stripping is in shared
openab_core::slack, so it affects every agent backend
(claude-agent-acp, codex-acp, agy/Antigravity, hermes-acp) equally.
- Deployment: 4 team bots in one Slack workspace, each in each other's
trustedBotIds.
Repro (minimal)
- Run two OpenAB bots (say
@bot-a = <@UAAA>, @bot-b = <@UBBB>) in the
same Slack channel.
- A human posts one message mentioning both:
<@UAAA>, <@UBBB> please tell me X.
- Inspect the trigger body each bot actually receives (agent session
transcript):
bot-a receives , <@UBBB> please tell me X ← its own <@UAAA> stripped
bot-b receives <@UAAA>, please tell me X ← its own <@UBBB> stripped
Each bot's body now contains only the other bot's UID. Any agent
instruction of the form "respond iff the trigger contains your own UID" is
structurally unsatisfiable, and the natural failure mode is mutual
deferral: each bot sees the other's mention, concludes "the other one is the
target", and both stay silent — so a message that explicitly addressed both
gets no answer.
We hit exactly this in production (both bots silent to a direct two-bot
question; separately, one bot leaked its "should I stay silent?" deliberation
as the visible reply, and that leak re-quoted the other bot's raw <@UID>,
re-triggering it). We've worked around it in our steering docs by telling the
bots not to gate on their own UID, but that's a heuristic — the bot can no
longer reliably know it was addressed.
Why the body alone can't be worked around cleanly
sender_context (schema openab.sender.v1) exposes channel, channel_id,
sender_id, receiver_id, thread_ts, etc., but no field says whether the
receiving bot was explicitly @-mentioned vs woken by the
multibot-mentions "involved" fallback. receiver_id is always the bot
itself, so it can't distinguish the two. The stripped body was the only
mention signal, and it's gone by the time the agent sees it.
Requested fix (either is sufficient)
- Preferred: add a reliable per-recipient signal to
sender_context,
e.g. "mentioned": true|false (was this bot's own UID present in the
original body before stripping), and optionally "mentioned_bots": ["UAAA", "UBBB"] (all bot UIDs the human addressed). Then multi-agent steering can
decide correctly without depending on the mutated body.
- Alternative: keep the stripped body for readability, but stop stripping
(or re-surface) the self-mention when the message addresses 2+ known bots,
so each recipient can still see it was among those addressed.
Happy to send a PR for option 1 (small addition to the sender-context builder
around slack.rs:1258) if the maintainers agree on the field shape.
Summary
The Slack adapter strips the receiving bot's own
<@UID>from the messagebody before handing it to the agent (
resolve_slack_mentions,crates/openab-core/src/slack.rs:1553-1584, called at:1258). This iscorrect on its own — it lets the LLM
@-mention other users in its reply.But in a multi-agent deployment it removes the only per-recipient signal
each bot has to tell whether it was explicitly mentioned, which breaks any
"should I respond or defer?" logic when one message
@-mentions two or morebots.
Environment
openab_core::slack, so it affects every agent backend(
claude-agent-acp,codex-acp,agy/Antigravity,hermes-acp) equally.trustedBotIds.Repro (minimal)
@bot-a=<@UAAA>,@bot-b=<@UBBB>) in thesame Slack channel.
<@UAAA>, <@UBBB> please tell me X.transcript):
bot-areceives, <@UBBB> please tell me X← its own<@UAAA>strippedbot-breceives<@UAAA>, please tell me X← its own<@UBBB>strippedEach bot's body now contains only the other bot's UID. Any agent
instruction of the form "respond iff the trigger contains your own UID" is
structurally unsatisfiable, and the natural failure mode is mutual
deferral: each bot sees the other's mention, concludes "the other one is the
target", and both stay silent — so a message that explicitly addressed both
gets no answer.
We hit exactly this in production (both bots silent to a direct two-bot
question; separately, one bot leaked its "should I stay silent?" deliberation
as the visible reply, and that leak re-quoted the other bot's raw
<@UID>,re-triggering it). We've worked around it in our steering docs by telling the
bots not to gate on their own UID, but that's a heuristic — the bot can no
longer reliably know it was addressed.
Why the body alone can't be worked around cleanly
sender_context(schemaopenab.sender.v1) exposeschannel,channel_id,sender_id,receiver_id,thread_ts, etc., but no field says whether thereceiving bot was explicitly
@-mentioned vs woken by themultibot-mentions"involved" fallback.receiver_idis always the botitself, so it can't distinguish the two. The stripped body was the only
mention signal, and it's gone by the time the agent sees it.
Requested fix (either is sufficient)
sender_context,e.g.
"mentioned": true|false(was this bot's own UID present in theoriginal body before stripping), and optionally
"mentioned_bots": ["UAAA", "UBBB"](all bot UIDs the human addressed). Then multi-agent steering candecide correctly without depending on the mutated body.
(or re-surface) the self-mention when the message addresses 2+ known bots,
so each recipient can still see it was among those addressed.
Happy to send a PR for option 1 (small addition to the sender-context builder
around
slack.rs:1258) if the maintainers agree on the field shape.