fix: honor mention-bypass for group commands
This commit is contained in:
@@ -56,6 +56,7 @@
|
||||
- Docs: expand parameter descriptions for agent/wake hooks. (#532) — thanks @mcinteerj
|
||||
- Docs: add community showcase entries from Discord. (#476) — thanks @gupsammy
|
||||
- TUI: refresh status bar after think/verbose/reasoning changes. (#519) — thanks @jdrhyne
|
||||
- Commands: treat mention-bypassed group command messages as mentioned so elevated directives respond.
|
||||
|
||||
## 2026.1.8
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ read_when:
|
||||
- **Global availability gate**: `agent.elevated` is global (not per-agent). If disabled or sender not allowlisted, elevated is unavailable everywhere.
|
||||
- **Per-session state**: `/elevated on|off` sets the elevated level for the current session key.
|
||||
- **Inline directive**: `/elevated on` inside a message applies to that message only.
|
||||
- **Groups**: In group chats, elevated directives are only honored when the agent is mentioned.
|
||||
- **Groups**: In group chats, elevated directives are only honored when the agent is mentioned. Command-only messages that bypass mention requirements are treated as mentioned.
|
||||
- **Host execution**: elevated runs `bash` on the host (bypasses sandbox).
|
||||
- **Unsandboxed agents**: when there is no sandbox to bypass, elevated does not change where `bash` runs.
|
||||
- **Tool policy still applies**: if `bash` is denied by tool policy, elevated cannot be used.
|
||||
|
||||
@@ -785,6 +785,7 @@ export function createDiscordMessageHandler(params: {
|
||||
!hasAnyMention &&
|
||||
commandAuthorized &&
|
||||
hasControlCommand(baseText);
|
||||
const effectiveWasMentioned = wasMentioned || shouldBypassMention;
|
||||
const canDetectMention = Boolean(botId) || mentionRegexes.length > 0;
|
||||
if (isGuildMessage && shouldRequireMention) {
|
||||
if (botId && !wasMentioned && !shouldBypassMention) {
|
||||
@@ -981,7 +982,7 @@ export function createDiscordMessageHandler(params: {
|
||||
: undefined,
|
||||
Provider: "discord" as const,
|
||||
Surface: "discord" as const,
|
||||
WasMentioned: wasMentioned,
|
||||
WasMentioned: effectiveWasMentioned,
|
||||
MessageSid: message.id,
|
||||
ParentSessionKey: threadKeys.parentSessionKey,
|
||||
ThreadStarterBody: threadStarterBody,
|
||||
|
||||
@@ -326,6 +326,7 @@ export async function monitorIMessageProvider(
|
||||
!mentioned &&
|
||||
commandAuthorized &&
|
||||
hasControlCommand(messageText);
|
||||
const effectiveWasMentioned = mentioned || shouldBypassMention;
|
||||
if (
|
||||
isGroup &&
|
||||
requireMention &&
|
||||
@@ -387,7 +388,7 @@ export async function monitorIMessageProvider(
|
||||
MediaPath: mediaPath,
|
||||
MediaType: mediaType,
|
||||
MediaUrl: mediaPath,
|
||||
WasMentioned: mentioned,
|
||||
WasMentioned: effectiveWasMentioned,
|
||||
CommandAuthorized: commandAuthorized,
|
||||
// Originating channel for reply routing.
|
||||
OriginatingChannel: "imessage" as const,
|
||||
|
||||
@@ -250,6 +250,39 @@ describe("monitorSlackProvider tool results", () => {
|
||||
expect(replyMock.mock.calls[0][0].WasMentioned).toBe(true);
|
||||
});
|
||||
|
||||
it("treats control commands as mentions for group bypass", async () => {
|
||||
replyMock.mockResolvedValue({ text: "ok" });
|
||||
|
||||
const controller = new AbortController();
|
||||
const run = monitorSlackProvider({
|
||||
botToken: "bot-token",
|
||||
appToken: "app-token",
|
||||
abortSignal: controller.signal,
|
||||
});
|
||||
|
||||
await waitForEvent("message");
|
||||
const handler = getSlackHandlers()?.get("message");
|
||||
if (!handler) throw new Error("Slack message handler not registered");
|
||||
|
||||
await handler({
|
||||
event: {
|
||||
type: "message",
|
||||
user: "U1",
|
||||
text: "/elevated off",
|
||||
ts: "123",
|
||||
channel: "C1",
|
||||
channel_type: "channel",
|
||||
},
|
||||
});
|
||||
|
||||
await flush();
|
||||
controller.abort();
|
||||
await run;
|
||||
|
||||
expect(replyMock).toHaveBeenCalledTimes(1);
|
||||
expect(replyMock.mock.calls[0][0].WasMentioned).toBe(true);
|
||||
});
|
||||
|
||||
it("threads replies when incoming message is in a thread", async () => {
|
||||
replyMock.mockResolvedValue({ text: "thread reply" });
|
||||
|
||||
|
||||
@@ -913,6 +913,7 @@ export async function monitorSlackProvider(opts: MonitorSlackOpts = {}) {
|
||||
!hasAnyMention &&
|
||||
commandAuthorized &&
|
||||
hasControlCommand(message.text ?? "");
|
||||
const effectiveWasMentioned = wasMentioned || shouldBypassMention;
|
||||
const canDetectMention = Boolean(botUserId) || mentionRegexes.length > 0;
|
||||
if (
|
||||
isRoom &&
|
||||
@@ -1058,7 +1059,7 @@ export async function monitorSlackProvider(opts: MonitorSlackOpts = {}) {
|
||||
ThreadStarterBody: threadStarterBody,
|
||||
ThreadLabel: threadLabel,
|
||||
Timestamp: message.ts ? Math.round(Number(message.ts) * 1000) : undefined,
|
||||
WasMentioned: isRoomish ? wasMentioned : undefined,
|
||||
WasMentioned: isRoomish ? effectiveWasMentioned : undefined,
|
||||
MediaPath: media?.path,
|
||||
MediaType: media?.contentType,
|
||||
MediaUrl: media?.path,
|
||||
|
||||
@@ -486,6 +486,7 @@ export function createTelegramBot(opts: TelegramBotOptions) {
|
||||
!hasAnyMention &&
|
||||
commandAuthorized &&
|
||||
hasControlCommand(msg.text ?? msg.caption ?? "");
|
||||
const effectiveWasMentioned = wasMentioned || shouldBypassMention;
|
||||
const canDetectMention = Boolean(botUsername) || mentionRegexes.length > 0;
|
||||
if (isGroup && requireMention && canDetectMention) {
|
||||
if (!wasMentioned && !shouldBypassMention) {
|
||||
@@ -592,7 +593,7 @@ export function createTelegramBot(opts: TelegramBotOptions) {
|
||||
ReplyToBody: replyTarget?.body,
|
||||
ReplyToSender: replyTarget?.sender,
|
||||
Timestamp: msg.date ? msg.date * 1000 : undefined,
|
||||
WasMentioned: isGroup ? wasMentioned : undefined,
|
||||
WasMentioned: isGroup ? effectiveWasMentioned : undefined,
|
||||
MediaPath: allMedia[0]?.path,
|
||||
MediaType: allMedia[0]?.contentType,
|
||||
MediaUrl: allMedia[0]?.path,
|
||||
|
||||
Reference in New Issue
Block a user