Skip to content

Conversations

Use conversations for non-linear flows

Conversation handlers stay readable because waits, validation, branching, and timeouts live in normal async code.

Typed wait helpers

Wait for text, media, callback queries, contacts, locations, or mixed input.

Validation and retries

Re-prompt users when input does not match your validation rules.

Branching logic

Use normal if/else, loops, and try/catch for complex support or order flows.

Conversation.waitForAny

returns Promise<ConversationAnyResult>
const input = await c.waitForAny(options)
ParameterTypeRequiredDescription
optionsWaitOptions
no
Timeout, validation, and validation error message.

Conversations provide a fluent, await-based API for building multi-step dialogues. Unlike Wizards (which use sequential step arrays), Conversations let you write natural async/await code with branching, loops, and validation.

Quick Start

typescript
import { Bot, session, Conversation } from 'vibegram';

const bot = new Bot('YOUR_BOT_TOKEN');
bot.use(session());

const conv = new Conversation();

conv.define('order', async (ctx, c) => {
    await ctx.reply('What product do you want?');
    const product = await c.waitForText();

    await ctx.reply('How many?');
    const qty = await c.waitForText({
        validate: ctx => !isNaN(parseInt(ctx.message?.text || '')),
        validationError: 'Please enter a valid number.',
    });

    await ctx.reply(`Order confirmed: ${parseInt(qty)}x ${product}`);
});

bot.use(conv.middleware());
bot.command('order', ctx => conv.enter('order', ctx));

Wait Methods

MethodReturnsWaits for
conv.waitForText(opts?)stringText message
conv.waitForPhoto(opts?)PhotoSize[]Photo message
conv.waitForCallbackQuery(opts?)stringInline button press
conv.waitForContact(opts?)ContactShared contact
conv.waitForLocation(opts?)LocationShared location
conv.waitForAny(opts?)discriminated unionText, callback data, or common media
conv.wait(opts?)ContextAny update (raw)

Mixed Input

Use waitForAny() when one step accepts several input types:

typescript
const input = await c.waitForAny({
    validationError: 'Send text, press a button, or attach media.',
});

if (input.type === 'text') {
    await ctx.reply(`Text: ${input.text}`);
} else if (input.type === 'callback') {
    await ctx.reply(`Button: ${input.data}`);
} else if (input.mediaType === 'photo') {
    await ctx.reply(`Photo variants: ${input.media.length}`);
} else {
    await ctx.reply(`Media type: ${input.mediaType}`);
}

Validation

If validation fails, the user is re-prompted automatically:

typescript
const email = await c.waitForText({
    validate: ctx => /\S+@\S+\.\S+/.test(ctx.message?.text || ''),
    validationError: 'Please enter a valid email address.',
});

Timeouts

typescript
try {
    const answer = await c.waitForText({ timeout: 30000 }); // 30 seconds
    await ctx.reply(`You said: ${answer}`);
} catch (err) {
    if (err instanceof ConversationTimeout) {
        await ctx.reply('Time is up! Conversation cancelled.');
    }
}

Branching

Because conversations are plain async functions, you can use any control flow:

typescript
conv.define('support', async (ctx, c) => {
    await ctx.reply('What do you need help with?\n1. Billing\n2. Technical');
    const choice = await c.waitForText();

    if (choice === '1') {
        await ctx.reply('Describe your billing issue:');
        const issue = await c.waitForText();
        await ctx.reply(`Billing ticket created: "${issue}"`);
    } else {
        await ctx.reply('Describe the technical problem:');
        const issue = await c.waitForText();
        await ctx.reply('Attach a screenshot if possible:');
        try {
            const photo = await c.waitForPhoto({ timeout: 60000 });
            await ctx.reply('Screenshot received. Ticket created.');
        } catch {
            await ctx.reply('No screenshot provided. Ticket created without attachment.');
        }
    }
});

Conversation vs Wizard

FeatureWizardConversation
Code styleArray of step functionsSingle async function
BranchingManual cursor jumpingNative if/else
ValidationManual (don't call next)Built-in validate/retry
TimeoutsNot built-inBuilt-in
Input typesText onlyText, photo, callback, contact, location

TIP

Use Wizards for simple linear forms. Use Conversations for complex flows with branching, validation, and multiple input types.

Released under the ISC License.