Blocks messages entirely — the agent won't see them at all. To let the agent read all messages but only respond to commands, mentions, or replies, use Mention Only mode in Channels settings (cog icon).
Blocks messages entirely — the agent won't see them at all. To let the agent read all messages but only respond to commands, mentions, or replies, use Mention Only mode in Channels settings (cog icon).
)}
diff --git a/interface/src/components/ConversationSettingsPanel.tsx b/interface/src/components/ConversationSettingsPanel.tsx
index be511dd6d..dd1f44128 100644
--- a/interface/src/components/ConversationSettingsPanel.tsx
+++ b/interface/src/components/ConversationSettingsPanel.tsx
@@ -104,7 +104,7 @@ const RESPONSE_MODE_DESCRIPTIONS: Record = {
quiet:
"Observes and learns from the conversation, but only responds when @mentioned, replied to, or given a command.",
mention_only:
- "Only responds when explicitly @mentioned or replied to. No passive memory capture.",
+ "Messages are still visible to the agent for context, but it only responds when explicitly @mentioned, replied to, or given a command. To block messages entirely, use the binding-level require mention setting instead.",
};
const WORKER_HISTORY_OPTIONS = [
diff --git a/src/agent/channel.rs b/src/agent/channel.rs
index 637d959eb..84e7a3737 100644
--- a/src/agent/channel.rs
+++ b/src/agent/channel.rs
@@ -1428,12 +1428,29 @@ impl Channel {
response_mode = ?self.resolved_settings.response_mode,
"suppressing unsolicited coalesced batch"
);
- // In Quiet mode, keep passive memory capture.
- // In MentionOnly mode, skip memory persistence.
- if matches!(self.resolved_settings.response_mode, ResponseMode::Quiet) {
- self.message_count += message_count;
- self.check_memory_persistence().await;
+ // In MentionOnly mode, inject batch messages into in-memory history
+ // so the LLM retains channel context when eventually triggered.
+ if matches!(
+ self.resolved_settings.response_mode,
+ ResponseMode::MentionOnly
+ ) {
+ {
+ let mut history = self.state.history.write().await;
+ for (formatted_text, _, _) in &pending_batch_entries {
+ history.push(rig::message::Message::User {
+ content: OneOrMany::one(UserContent::text(formatted_text)),
+ });
+ }
+ }
+ // Compaction guard: suppressed messages accumulate in history
+ // without agent turns, so check compaction to prevent unbounded growth.
+ if let Err(error) = self.compactor.check_and_compact().await {
+ tracing::warn!(channel_id = %self.id, %error, "compaction check failed");
+ }
}
+ // Both Quiet and MentionOnly keep passive memory capture.
+ self.message_count += message_count;
+ self.check_memory_persistence().await;
return Ok(());
}
@@ -1846,12 +1863,27 @@ impl Channel {
response_mode = ?self.resolved_settings.response_mode,
"suppressing unsolicited reply"
);
- // In Quiet mode, keep passive memory capture.
- // In MentionOnly mode, skip memory persistence entirely.
- if matches!(self.resolved_settings.response_mode, ResponseMode::Quiet) {
- self.message_count += 1;
- self.check_memory_persistence().await;
+ // In MentionOnly mode, inject the message into in-memory history
+ // so the LLM retains channel context when eventually triggered.
+ if matches!(
+ self.resolved_settings.response_mode,
+ ResponseMode::MentionOnly
+ ) {
+ {
+ let mut history = self.state.history.write().await;
+ history.push(rig::message::Message::User {
+ content: OneOrMany::one(UserContent::text(&user_text)),
+ });
+ }
+ // Compaction guard: suppressed messages accumulate in history
+ // without agent turns, so check compaction to prevent unbounded growth.
+ if let Err(error) = self.compactor.check_and_compact().await {
+ tracing::warn!(channel_id = %self.id, %error, "compaction check failed");
+ }
}
+ // Both Quiet and MentionOnly keep passive memory capture.
+ self.message_count += 1;
+ self.check_memory_persistence().await;
return Ok(());
}
}
diff --git a/src/config/types.rs b/src/config/types.rs
index 9bd9073e7..1cbd07501 100644
--- a/src/config/types.rs
+++ b/src/config/types.rs
@@ -1638,6 +1638,11 @@ pub struct Binding {
/// Channel IDs this binding applies to. If empty, all channels in the guild/workspace are allowed.
pub channel_ids: Vec,
/// Require explicit @mention (or reply-to-bot) for inbound messages.
+ /// Messages that don't match are blocked at the routing level and never
+ /// reach the channel — the agent cannot see them at all.
+ /// For context-aware mention filtering (agent sees messages but only
+ /// responds to mentions), use the channel-level `MentionOnly` response
+ /// mode instead.
pub require_mention: bool,
/// User IDs allowed to DM the bot through this binding.
pub dm_allowed_users: Vec,
diff --git a/src/conversation/settings.rs b/src/conversation/settings.rs
index 1f7d62d7c..8e55ee1b8 100644
--- a/src/conversation/settings.rs
+++ b/src/conversation/settings.rs
@@ -119,9 +119,15 @@ pub enum ResponseMode {
/// Observe and learn (history + memory persistence) but only respond
/// to @mentions, replies-to-bot, and slash commands.
Quiet,
- /// Only respond when explicitly @mentioned or replied to.
- /// Messages that don't pass the mention check are recorded in history
- /// but receive no processing (no memory persistence, no LLM).
+ /// Only respond when explicitly @mentioned, replied to, or given a command.
+ /// Messages that don't pass the mention check are still ingested into
+ /// the in-memory context window (so the agent stays context-aware),
+ /// recorded in conversation history, and contribute to passive memory
+ /// capture — but do not trigger an LLM turn.
+ ///
+ /// This differs from the binding-level `require_mention` flag, which
+ /// blocks message routing entirely — unmentioned messages never reach
+ /// the channel and are invisible to the agent.
MentionOnly,
}