Skip to content

Cancelling Commands

If you have long-running command workflows (like waiting for a user to upload an image or type a long response), users can cancel them using specific cancel words.

By default, the cancel words are "cancel" (English) and "cancelar" (Spanish).

For example, if a bot is expecting the user to send an image msg via !forwardmsg, but the user changes their mind and sends "cancel", the command will immediately abort.

You can configure which words should act as global cancellation keywords when you first instantiate the bot:

import Whatsbotcord, { BaileysAdapter } from "whatsbotcord";
const bot = new Whatsbotcord({
commandPrefix: ["$", "!", "/", "."],
delayMilisecondsBetweenMsgs: 1,
// 1. Define global cancel keywords here
cancelKeywords: ["abort", "stop", "cancel"],
});

Now, any time your command is waiting for user input using a Wait* method, saying “abort”, “stop”, or “cancel” will exit the execution.

You can temporarily override the global cancel keywords just for a single Wait*() method. This is useful if a specific step requires different fallback words, or if “stop” might be a valid answer to a specific prompt!

const imgReceived = await chat.WaitMultimedia(MsgType.Image, {
timeoutSeconds: 60,
wrongTypeFeedbackMsg: "Hey, send me an img, try again!",
// 2. Override for this wait action only
cancelKeywords: ["cancelcustomword"],
});

In this specific call, only "cancelcustomword" will abort the flow. If you use another WaitMultimedia(...) or WaitMsg(...) method later down the line without providing cancelKeywords, it will fall back to the global bot config (e.g., ["abort", "stop", "cancel"]).

Here is a complete example of a command that asks for a profile photo. If the user decides they don’t want to change their photo anymore and replies with "cancel", the command halts automatically without executing any further code.

import { MsgType } from "whatsbotcord";
import type { AdditionalAPI, IChatContext, CommandArgs, ICommand } from "whatsbotcord/types";
export class UpdatePhotoCommand implements ICommand {
public name: string = "updatephoto";
public async run(ctx: IChatContext, api: AdditionalAPI, args: CommandArgs): Promise<void> {
await ctx.Loading();
await ctx.SendText("📸 Send me your new profile photo! (Or type 'cancel' to abort)");
// The command will pause here.
// If the user sends "cancel" (or any registered keyword), the command is killed instantly.
const imgBuffer = await ctx.WaitMultimedia(MsgType.Image, { timeoutSeconds: 60 });
if (!imgBuffer) {
await ctx.SendText("You took too long!");
return;
}
// This line will NEVER execute if the user sent "cancel".
await ctx.SendText("✅ Photo updated successfully!");
await ctx.Ok();
}
}

You can easily verify that your commands correctly abort using ChatMock:

import { test, expect } from "bun:test";
import { SenderType } from "whatsbotcord";
import { ChatMock } from "whatsbotcord/testing";
import { UpdatePhotoCommand } from "./UpdatePhotoCommand.js";
test("User cancels the photo update", async () => {
const chat = new ChatMock(new UpdatePhotoCommand(), { senderType: SenderType.Individual });
// Simulate the user sending the cancel keyword
chat.EnqueueIncoming_Text("cancel");
await chat.StartChatSimulation();
// Assert that the bot ONLY sent the initial prompt and nothing else!
expect(chat.SentFromCommand.Texts).toHaveLength(1);
expect(chat.SentFromCommand.Texts[0].text).toContain("Send me your new profile photo!");
// The "Photo updated successfully!" text is never sent because execution aborted.
});