Skip to content

Discord: ThreadStarterBody re-injected on every turn (echo contamination) #41355

Description

@p3nchan

Bug Description

Discord thread starter context (ThreadStarterBody) is re-injected into the agent's input on every turn of a thread conversation, causing echo contamination. The agent receives [Thread starter - for context] repeatedly, which can leak into outbound messages.

Root Cause

The Discord adapter in finalizeInboundContext sets ThreadStarterBody: threadStarterBody unconditionally on every inbound message. Unlike Slack (fixed in #32133) and iMessage (fixed in #33295), Discord has no guard to limit this to the first turn.

Layer 1 — Discord Adapter (no guard):

// Current (broken):
ThreadStarterBody: threadStarterBody,

// Fixed (matches Slack pattern):
ThreadStarterBody: !previousTimestamp ? threadStarterBody : void 0,

Layer 2 — Session Handler (no guard):

// Current (broken):
const threadStarterBody = ctx.ThreadStarterBody?.trim();

// Fixed:
const threadStarterBody = isNewSession ? ctx.ThreadStarterBody?.trim() : void 0;

Impact

  • Thread starter text is prepended to every agent turn
  • Agent may echo back metadata markers like [Thread starter - for context]
  • Increases token usage on every turn
  • Affects all Discord thread conversations

Affected Files

All compiled bundles containing the Discord adapter and session handler:

  • dist/reply-*.js
  • dist/pi-embedded-*.js
  • dist/compact-*.js
  • dist/plugin-sdk/reply-*.js
  • dist/plugin-sdk/dispatch-*.js

Workaround

Set includeThreadStarter: false per-channel in config:

{
  "channels": {
    "discord": {
      "guilds": {
        "<guild-id>": {
          "channels": {
            "*": {
              "includeThreadStarter": false
            }
          }
        }
      }
    }
  }
}

This disables thread starter context entirely (including the useful first-turn context).

Related PRs

Suggested Fix

Apply the same !previousTimestamp guard pattern from the Slack fix (#32133) to the Discord adapter, and add a redundant isNewSession guard in the session handler.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions