diff --git a/src/config/schema.ts b/src/config/schema.ts index bb8d8c0bb..319c93a86 100644 --- a/src/config/schema.ts +++ b/src/config/schema.ts @@ -604,6 +604,8 @@ const FIELD_HELP: Record = { "channels.telegram.commands.native": 'Override native commands for Telegram (bool or "auto").', "channels.telegram.commands.nativeSkills": 'Override native skill commands for Telegram (bool or "auto").', + "channels.telegram.commands.customFirst": + "If true, custom commands appear before native commands in the Telegram menu (default: false).", "channels.slack.commands.native": 'Override native commands for Slack (bool or "auto").', "channels.slack.commands.nativeSkills": 'Override native skill commands for Slack (bool or "auto").', diff --git a/src/config/types.messages.ts b/src/config/types.messages.ts index 37ef4e942..889c11a45 100644 --- a/src/config/types.messages.ts +++ b/src/config/types.messages.ts @@ -114,4 +114,6 @@ export type ProviderCommandsConfig = { native?: NativeCommandsSetting; /** Override native skill command registration for this provider (bool or "auto"). */ nativeSkills?: NativeCommandsSetting; + /** If true, custom commands appear before native commands in the menu. Default: false (native first). */ + customFirst?: boolean; }; diff --git a/src/config/zod-schema.core.ts b/src/config/zod-schema.core.ts index 4a8c80bcc..87adc7363 100644 --- a/src/config/zod-schema.core.ts +++ b/src/config/zod-schema.core.ts @@ -497,6 +497,7 @@ export const ProviderCommandsSchema = z .object({ native: NativeCommandsSettingSchema.optional(), nativeSkills: NativeCommandsSettingSchema.optional(), + customFirst: z.boolean().optional(), }) .strict() .optional(); diff --git a/src/telegram/bot-native-commands.ts b/src/telegram/bot-native-commands.ts index 0f1cc1cb7..81f7c719d 100644 --- a/src/telegram/bot-native-commands.ts +++ b/src/telegram/bot-native-commands.ts @@ -56,6 +56,7 @@ type RegisterTelegramNativeCommandsParams = { nativeEnabled: boolean; nativeSkillsEnabled: boolean; nativeDisabledExplicit: boolean; + customFirst: boolean; resolveGroupPolicy: (chatId: string | number) => ChannelGroupPolicy; resolveTelegramGroupConfig: ( chatId: string | number, @@ -79,6 +80,7 @@ export const registerTelegramNativeCommands = ({ nativeEnabled, nativeSkillsEnabled, nativeDisabledExplicit, + customFirst, resolveGroupPolicy, resolveTelegramGroupConfig, shouldSkipUpdate, @@ -103,13 +105,13 @@ export const registerTelegramNativeCommands = ({ runtime.error?.(danger(issue.message)); } const customCommands = customResolution.commands; - const allCommands: Array<{ command: string; description: string }> = [ - ...nativeCommands.map((command) => ({ - command: command.name, - description: command.description, - })), - ...customCommands, - ]; + const nativeCommandItems = nativeCommands.map((command) => ({ + command: command.name, + description: command.description, + })); + const allCommands: Array<{ command: string; description: string }> = customFirst + ? [...customCommands, ...nativeCommandItems] + : [...nativeCommandItems, ...customCommands]; if (allCommands.length > 0) { bot.api.setMyCommands(allCommands).catch((err) => { diff --git a/src/telegram/bot.ts b/src/telegram/bot.ts index d958d5616..d90d3959a 100644 --- a/src/telegram/bot.ts +++ b/src/telegram/bot.ts @@ -236,6 +236,7 @@ export function createTelegramBot(opts: TelegramBotOptions) { providerSetting: telegramCfg.commands?.native, globalSetting: cfg.commands?.native, }); + const customFirst = telegramCfg.commands?.customFirst === true; const useAccessGroups = cfg.commands?.useAccessGroups !== false; const ackReactionScope = cfg.messages?.ackReactionScope ?? "group-mentions"; const mediaMaxBytes = (opts.mediaMaxMb ?? telegramCfg.mediaMaxMb ?? 5) * 1024 * 1024; @@ -341,6 +342,7 @@ export function createTelegramBot(opts: TelegramBotOptions) { nativeEnabled, nativeSkillsEnabled, nativeDisabledExplicit, + customFirst, resolveGroupPolicy, resolveTelegramGroupConfig, shouldSkipUpdate,