-
-
Notifications
You must be signed in to change notification settings - Fork 69.5k
[Bug]: Discord thread-bound ACP session receives bot's own ⚙️ system messages, causing infinite turn loop #29325
Description
Summary
When an ACP session is bound to a Discord thread, OpenClaw's own system messages (⚙️ usage_update, available_commands_update, session active, etc.) are forwarded to the ACP session as user prompts. This causes the agent (Codex) to treat them as tasks, generating responses that are again posted to the thread — creating an infinite loop.
Environment
- OpenClaw (latest)
- ACP backend: acpx (v0.1.13)
- Agent: Codex (
gpt-5.3-codex,--full-auto) - Channel: Discord (thread-bound session via
/acp spawn+thread: true)
Steps to Reproduce
- Spawn an ACP session bound to a Discord thread (
sessions_spawn runtime="acp", thread=true) - Agent completes the assigned task and posts a result to the thread
- OpenClaw posts a system message (e.g.
⚙️ codex session active (auto-unfocus in 24h)...) to the thread - Observe: the system message is forwarded to the ACP session as a new user turn
- Codex processes it as a task → posts response → triggers more system messages → loop
Evidence
Session records in ~/.acpx/sessions/ show the pattern clearly:
# Turn 1 (expected — user task)
user: "cd ~/src/.../yoshikouki-com ## レイアウトシステムStep 1-3を実装..."
assistant: "実装完了。110テストpass。"
# Turn 2 (unexpected — system message treated as prompt)
user: "⚙️ codex session active (auto-unfocus in 24h). Messages here go directly to this session. cwd: /home/..."
assistant: "セッション初期化として、ワークスペースの必読ファイルを読み込んで..."
# Turn 3 (loop continues)
user: "⚙️ available_commands_update"
assistant: "依頼内容を実行するため、まずワークスペースの必読ファイルと available_commands_update に..."
# Turn 4+
user: "⚙️ usage_update"
assistant: "usage_update 実行完了..."
Result: 4,456 messages sent to the Discord thread before manual intervention.
Root Cause (Code Analysis)
The Discord channel-level inbound handler correctly filters bot's own messages:
// reply-Deht_wOB.js
if (params.botUserId && author.id === params.botUserId) return null; // ✅ filtered
if (author.bot) {
if (!allowBots && !sender.isPluralKit) { /* drop */ } // ✅ filtered
}However, tryDispatchAcpReply() — the function that forwards inbound messages to the bound ACP session — has no equivalent IsFromBot / IsSelf check. The ⚙️ system messages appear to reach tryDispatchAcpReply via a different code path (thread binding service), bypassing the channel-level bot filter entirely.
Expected Behavior
Bot's own system messages (⚙️ prefix) posted to a thread-bound ACP session's thread should not be forwarded to the ACP session as user prompts.
Actual Behavior
All messages in the bound thread — including OpenClaw's own ⚙️ system messages — are forwarded to the ACP session, causing infinite agent loops.
Workaround
Currently mitigating with acp.stream.coalesceIdleMs: 10000 to reduce flood impact, but this does not prevent the infinite loop itself.