fix(discord): make always-on auto replies more robust#73046
Conversation
Greptile SummaryThis PR adds
Confidence Score: 4/5Safe to merge; no P0/P1 defects found — remaining issues are a misleading log, a weakened test assertion, and a system-prompt instruction that may confuse agents in auto mode. All three findings are P2: none produce wrong data, security issues, or guaranteed runtime failures. The plugin-binding log stale message is misleading but the behavior change is likely low-impact for Discord. Score stays at 4 given P2s only. src/auto-reply/reply/dispatch-from-config.ts (plugin-binding skip comment/log), src/auto-reply/reply.triggers.group-intro-prompts.cases.ts (WhatsApp expected value), src/agents/system-prompt.ts (target instruction in auto mode)
|
| expected: [ | ||
| "You are in a WhatsApp group chat. Your replies are automatically sent to this group chat. Do not use the message tool to send to this same group - just reply normally.", | ||
| "You are in a WhatsApp group chat. Your replies are automatically sent to this group chat.", | ||
| `Activation: trigger-only (you are invoked only when explicitly mentioned; recent context may be included). ${groupParticipationNote} Address the specific sender noted in the message context.`, | ||
| ], |
There was a problem hiding this comment.
WhatsApp test expectation weakened but function output unchanged
buildGroupChatContext still produces "…Do not use the message tool to send to this same group - just reply normally." for legacy mode (confirmed by the unchanged assertion in groups.test.ts). Removing that phrase from the expected value here drops coverage of the instruction without explanation — if the intent is to eventually remove that guidance, the function itself should be updated first; if not, restoring the full expected string keeps the integration test properly pinned.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/auto-reply/reply.triggers.group-intro-prompts.cases.ts
Line: 46-49
Comment:
**WhatsApp test expectation weakened but function output unchanged**
`buildGroupChatContext` still produces `"…Do not use the message tool to send to this same group - just reply normally."` for legacy mode (confirmed by the unchanged assertion in `groups.test.ts`). Removing that phrase from the expected value here drops coverage of the instruction without explanation — if the intent is to eventually remove that guidance, the function itself should be updated first; if not, restoring the full expected string keeps the integration test properly pinned.
How can I resolve this? If you propose a fix, please make it concise.5398057 to
a3c14b0
Compare
🔒 Aisle Security AnalysisWe found 3 potential security issue(s) in this PR:
1. 🟠 Cross-context message tool sends allowed within provider by default (prompt-injection exfiltration risk)
Description
Vulnerable logic: // default: allowWithinProvider === true
if (allowWithinProvider) {
return;
}This is especially risky in group contexts where untrusted users can influence the assistant and where the new message-tool-only mode makes tool sends the primary way to produce visible output. RecommendationHarden cross-context messaging defaults and require explicit opt-in. Suggested changes:
const allowWithinProvider =
params.cfg.tools?.message?.crossContext?.allowWithinProvider === true;
if (!allowWithinProvider) {
// enforce same-target unless explicitly allowed
}
2. 🟠 sendPolicy: deny does not prevent outbound messaging via `message` tool (policy bypass)
Description
This creates a policy bypass if
Vulnerable logic (policy narrowed to automatic delivery only): // blocked; explicit message tool sends remain available.
const sendPolicyDenied = sendPolicy === "deny";
...
const suppressDelivery = sendPolicyDenied || suppressAutomaticSourceDelivery;Because RecommendationTreat Options:
Example (tool-level guard): // inside message tool handler
if (options?.sendPolicy === "deny" && action !== "read") {
throw new Error("Outbound messaging is blocked by sendPolicy: deny");
}Ensure the enforcement covers all outbound actions ( 3. 🔵 Discord "message_tool_only" mode still sends typing indicators (visible side-channel)
DescriptionIn Discord guild/group privacy mode (
This leaks that the bot is actively processing a message, which can undermine the intended “no visible output unless message tool is used” privacy guarantee. Vulnerable code (typing is unconditional): const { onModelSelected, ...replyPipeline } = createChannelReplyPipeline({
...
typing: {
start: () => sendTyping({ rest: feedbackRest, channelId: typingChannelId }),
...
},
});RecommendationGate typing indicators behind Example: const typingEnabled = sourceReplyDeliveryMode !== "message_tool_only";
const { onModelSelected, ...replyPipeline } = createChannelReplyPipeline({
cfg,
agentId: route.agentId,
channel: "discord",
accountId: route.accountId,
typing: typingEnabled
? {
start: () => sendTyping({ rest: feedbackRest, channelId: typingChannelId }),
onStartError: (err) => { /* ... */ },
maxDurationMs: DISCORD_TYPING_MAX_DURATION_MS,
}
: undefined,
});This prevents any Discord-visible activity in tool-only mode unless explicitly requested via a tool action. Analyzed PR: #73046 at commit Last updated on: 2026-04-28T06:40:13Z |
d30a9fc to
0a63cd8
Compare
|
Landed via squash after rewriting the delivery mode into the shared group-room config.
Thanks @scoootscooob! |
Summary
messagetool sends for visible channel outputmessage(action=send)fall back to the current channel target when the agent chooses to send visiblyBehavior
requireMention: falseremains the switch for always-on Discord guild channels.messagetool sends.Validation
pnpm test extensions/discord/src/monitor/message-handler.process.test.ts extensions/discord/src/config-schema.test.ts extensions/discord/src/monitor.test.ts src/auto-reply/reply/groups.test.ts src/agents/prompt-composition.test.tspnpm test src/auto-reply/reply/groups.test.ts src/agents/prompt-composition.test.tspnpm test src/auto-reply/reply/groups.test.ts src/auto-reply/reply/dispatch-from-config.test.ts src/auto-reply/reply.triggers.test.ts extensions/discord/src/monitor.test.ts extensions/discord/src/config-schema.test.ts extensions/discord/src/monitor/message-handler.process.test.ts extensions/slack/src/monitor.tool-result.test.tspnpm config:channels:checkpnpm config:docs:checkpnpm buildNotes
pnpm check:changedwas attempted and reached all-lanes because this local branch has broad comparison-base divergence; typecheck, lint, and import-cycle checks passed, then unrelated pre-existing test failures appeared insrc/infra/diagnostic-events.test.ts, Windows/Jiti loader tests, and plugin ledger tests.pnpm test src/auto-reply/reply.triggers.test.tsselector did not map to a test file under this repo's project routing; the broader earlier run selected that suite successfully.