Merge pull request #729 from clawdbot/fix/telegram-command-mentions
fix: normalize telegram command mentions
This commit is contained in:
@@ -71,4 +71,17 @@ describe("control command parsing", () => {
|
||||
expect(hasControlCommand("prefix /send on")).toBe(false);
|
||||
expect(hasControlCommand("/send on")).toBe(true);
|
||||
});
|
||||
|
||||
it("ignores telegram commands addressed to other bots", () => {
|
||||
expect(
|
||||
hasControlCommand("/help@otherbot", undefined, {
|
||||
botUsername: "clawdbot",
|
||||
}),
|
||||
).toBe(false);
|
||||
expect(
|
||||
hasControlCommand("/help@clawdbot", undefined, {
|
||||
botUsername: "clawdbot",
|
||||
}),
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { ClawdbotConfig } from "../config/types.js";
|
||||
import {
|
||||
type CommandNormalizeOptions,
|
||||
listChatCommands,
|
||||
listChatCommandsForConfig,
|
||||
normalizeCommandBody,
|
||||
@@ -8,11 +9,12 @@ import {
|
||||
export function hasControlCommand(
|
||||
text?: string,
|
||||
cfg?: ClawdbotConfig,
|
||||
options?: CommandNormalizeOptions,
|
||||
): boolean {
|
||||
if (!text) return false;
|
||||
const trimmed = text.trim();
|
||||
if (!trimmed) return false;
|
||||
const normalizedBody = normalizeCommandBody(trimmed);
|
||||
const normalizedBody = normalizeCommandBody(trimmed, options);
|
||||
if (!normalizedBody) return false;
|
||||
const lowered = normalizedBody.toLowerCase();
|
||||
const commands = cfg ? listChatCommandsForConfig(cfg) : listChatCommands();
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
listChatCommandsForConfig,
|
||||
listNativeCommandSpecs,
|
||||
listNativeCommandSpecsForConfig,
|
||||
normalizeCommandBody,
|
||||
shouldHandleTextCommands,
|
||||
} from "./commands-registry.js";
|
||||
|
||||
@@ -92,4 +93,26 @@ describe("commands registry", () => {
|
||||
}),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("normalizes telegram-style command mentions for the current bot", () => {
|
||||
expect(
|
||||
normalizeCommandBody("/help@clawdbot", { botUsername: "clawdbot" }),
|
||||
).toBe("/help");
|
||||
expect(
|
||||
normalizeCommandBody("/help@clawdbot args", {
|
||||
botUsername: "clawdbot",
|
||||
}),
|
||||
).toBe("/help args");
|
||||
expect(
|
||||
normalizeCommandBody("/help@clawdbot: args", {
|
||||
botUsername: "clawdbot",
|
||||
}),
|
||||
).toBe("/help args");
|
||||
});
|
||||
|
||||
it("keeps telegram-style command mentions for other bots", () => {
|
||||
expect(
|
||||
normalizeCommandBody("/help@otherbot", { botUsername: "clawdbot" }),
|
||||
).toBe("/help@otherbot");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -361,7 +361,14 @@ export function buildCommandText(commandName: string, args?: string): string {
|
||||
return trimmedArgs ? `/${commandName} ${trimmedArgs}` : `/${commandName}`;
|
||||
}
|
||||
|
||||
export function normalizeCommandBody(raw: string): string {
|
||||
export type CommandNormalizeOptions = {
|
||||
botUsername?: string;
|
||||
};
|
||||
|
||||
export function normalizeCommandBody(
|
||||
raw: string,
|
||||
options?: CommandNormalizeOptions,
|
||||
): string {
|
||||
const trimmed = raw.trim();
|
||||
if (!trimmed.startsWith("/")) return trimmed;
|
||||
|
||||
@@ -378,17 +385,26 @@ export function normalizeCommandBody(raw: string): string {
|
||||
})()
|
||||
: singleLine;
|
||||
|
||||
const lowered = normalized.toLowerCase();
|
||||
const normalizedBotUsername = options?.botUsername?.trim().toLowerCase();
|
||||
const mentionMatch = normalizedBotUsername
|
||||
? normalized.match(/^\/([^\s@]+)@([^\s]+)(.*)$/)
|
||||
: null;
|
||||
const commandBody =
|
||||
mentionMatch && mentionMatch[2].toLowerCase() === normalizedBotUsername
|
||||
? `/${mentionMatch[1]}${mentionMatch[3] ?? ""}`
|
||||
: normalized;
|
||||
|
||||
const lowered = commandBody.toLowerCase();
|
||||
const exact = TEXT_ALIAS_MAP.get(lowered);
|
||||
if (exact) return exact.canonical;
|
||||
|
||||
const tokenMatch = normalized.match(/^\/([^\s]+)(?:\s+([\s\S]+))?$/);
|
||||
if (!tokenMatch) return normalized;
|
||||
const tokenMatch = commandBody.match(/^\/([^\s]+)(?:\s+([\s\S]+))?$/);
|
||||
if (!tokenMatch) return commandBody;
|
||||
const [, token, rest] = tokenMatch;
|
||||
const tokenKey = `/${token.toLowerCase()}`;
|
||||
const tokenSpec = TEXT_ALIAS_MAP.get(tokenKey);
|
||||
if (!tokenSpec) return normalized;
|
||||
if (rest && !tokenSpec.acceptsArgs) return normalized;
|
||||
if (!tokenSpec) return commandBody;
|
||||
if (rest && !tokenSpec.acceptsArgs) return commandBody;
|
||||
const normalizedRest = rest?.trimStart();
|
||||
return normalizedRest
|
||||
? `${tokenSpec.canonical} ${normalizedRest}`
|
||||
|
||||
@@ -17,6 +17,7 @@ import { hasControlCommand } from "../auto-reply/command-detection.js";
|
||||
import {
|
||||
buildCommandText,
|
||||
listNativeCommandSpecsForConfig,
|
||||
normalizeCommandBody,
|
||||
} from "../auto-reply/commands-registry.js";
|
||||
import { formatAgentEnvelope } from "../auto-reply/envelope.js";
|
||||
import {
|
||||
@@ -557,7 +558,7 @@ export function createTelegramBot(opts: TelegramBotOptions) {
|
||||
!wasMentioned &&
|
||||
!hasAnyMention &&
|
||||
commandAuthorized &&
|
||||
hasControlCommand(msg.text ?? msg.caption ?? "", cfg);
|
||||
hasControlCommand(msg.text ?? msg.caption ?? "", cfg, { botUsername });
|
||||
const effectiveWasMentioned = wasMentioned || shouldBypassMention;
|
||||
const canDetectMention = Boolean(botUsername) || mentionRegexes.length > 0;
|
||||
if (isGroup && requireMention && canDetectMention) {
|
||||
@@ -682,10 +683,11 @@ export function createTelegramBot(opts: TelegramBotOptions) {
|
||||
].filter((entry): entry is string => Boolean(entry));
|
||||
const groupSystemPrompt =
|
||||
systemPromptParts.length > 0 ? systemPromptParts.join("\n\n") : undefined;
|
||||
const commandBody = normalizeCommandBody(rawBody, { botUsername });
|
||||
const ctxPayload = {
|
||||
Body: combinedBody,
|
||||
RawBody: rawBody,
|
||||
CommandBody: rawBody,
|
||||
CommandBody: commandBody,
|
||||
From: isGroup
|
||||
? buildTelegramGroupFrom(chatId, messageThreadId)
|
||||
: `telegram:${chatId}`,
|
||||
|
||||
Reference in New Issue
Block a user