Skip to content

Conversations

literallyfiro edited this page Feb 10, 2026 · 4 revisions

Conversation API

A conversation represents a structured interaction between a bot and a user. It typically follows a sequence of exchanges (messages) where the bot prompts the user for input, processes the response, and decides on the next step.

Imagine this example: a bot asks the user for their name, then asks for their age, and finally asks for their favorite color. Each of these steps is a conversation turn, and the entire sequence is a conversation.

Normally, you would have to listen for each message and keep track of the conversation state manually. However, with the Conversation API, you can define a conversation as workflow and let Teleight handle the conversation flow for you.

Creating a Conversation

To create a conversation, you need to implement the ConversationExecutor interface.

public class TestConversation implements ConversationExecutor {

    @Override
    public void execute(@NotNull ConversationContext context) {
        final Chat chat = context.chat();
        final String chatId = String.valueOf(chat.id());

        // Let's start the conversation by sending a message to the user
        SendMessage startMessage = SendMessage.ofBuilder(chatId, "Send me a message with the text \"hello\"").build();
        context.bot().execute(startMessage);

        // Now, let's wait for an update. We give the user 10 seconds to reply.
        // If the result is null, that means the bot did not receive an update in time
        final Update update = context.waitForUpdate(10, TimeUnit.SECONDS);

        if (update == null) {
            // And this is the case, so let's leave the conversation and send an error message to the user
            SendMessage resultToUser = SendMessage.ofBuilder(chatId, "You didn't send the message in time..").build();
            context.bot().execute(resultToUser);
            return;
        }

        // Let's get a message from the update
        final Message message = update.message();

        if (message == null) {
            // The message is null, and it's not what we want
            // This happens when the bot receives an update which does not contain a message.
            SendMessage resultToUser = SendMessage.ofBuilder(chatId, "You didn't send a message..").build();
            context.bot().execute(resultToUser);
            return;
        }

        // Now, check if the text equals hello or not and act appropriately
        String resultToUser;
        if (message.text() == null || !message.text().equals("hello")) {
            resultToUser = "You didn't send \"hello\"!";
        } else {
            resultToUser = "Good job!";
        }
        final SendMessage result = SendMessage.ofBuilder(chatId, resultToUser).build();
        context.bot().execute(result);
    }

}

The main method you will use for continuing the flow is the waitForUpdate method inside the ConversationContext class. This method will wait for an update from the user for a specified amount of time. If the user does not respond in time, the method will return null.

Registering the Conversation

To register a conversation, call the registerConversation method. Required parameters are the conversation name (which will be used as identifier) and the conversation instance.

final Conversation testConversation = Conversation.of("test", new TestConversation());
bot.getConversationManager().registerConversation(testConversation);

Joining a Conversation

To start a conversation, you need to call the startConversation method.

final JoinResult result = bot.getConversationManager().startConversation(user, chat, "test");

This will return a JoinResult object that contains the result of the operation.

if (result instanceof ConversationManager.JoinResult.AlreadyInConversation) {
    System.out.println("User is already in conversation");
} else if (result instanceof ConversationManager.JoinResult.ConversationNotFound) {
    System.out.println("Conversation not found");
} else {
    System.out.println("Conversation started");
}

Custom Properties in Conversations

In TeleightBots, custom properties allow you to define and manage additional data within a conversation. These properties can be used to store and retrieve information that is relevant to the conversation flow.

Required vs Optional Properties

Each property can be defined as required or optional. Required properties must be set when the conversation is created, while optional properties can be set in the join conversation operation.

Defining Custom Properties

Custom properties are defined using the Property class. Each property has a name, a value, and a flag indicating whether it is required or optional.

If you create a property with a default value, it will be considered optional:

Property<String> testProperty = Property.of("testProperty", "defaultValue");

If you instead create a property without a default value, it will be considered required:

Property<Integer> testProperty = Property.of("testProperty");

Property Methods

The Property class provides several methods to retrieve the value in different types:

  • asString(): Returns the value as a string.
  • asInt(): Returns the value as an integer.
  • asBool(): Returns the value as a boolean.
  • asLong(): Returns the value as a long.
  • asFloat(): Returns the value as a float.
  • as(Class<? extends A> type): Returns the value as a custom type.

Registering a Conversation with Custom Properties

To register a conversation with custom properties, you can use the ofBuilder method of the Conversation class and the property or properties method to add custom properties:

Conversation testConversation = Conversation.ofBuilder("testConversation", new TestConversation())
        .property(Property.of("isThisAProperty", true))
        .property(Property.of("isUserAdmin", false))
        .allowUnknownProperties(true)
        .build();

bot.getConversationManager().registerConversation(testConversation);

The allowUnknownProperties method allows you to specify whether unknown properties should be allowed in the conversation. Unknown properties are properties that are not explicitly defined when the conversation is registered, and can be applied later when you use the joinConversation method.

If this flag is set to false (default behavior), an exception will be thrown if an unknown property is passed to the conversation.

Example Usage

Here's an example of how to use custom properties in a conversation:

public class TestConversation implements ConversationExecutor {

    @Override
    public void execute(@NotNull ConversationContext context) {
        final Chat chat = context.chat();
        final String chatId = String.valueOf(chat.id());

        // Retrieve the custom property.
        // Be careful: getProperty() can return a null value if the property is not found
        // In this case, we can omit the null check because we know the property is defined directly in the conversation
        boolean testProperty = context.getProperty("isThisAProperty").asBool();

        // Use the property in the conversation logic
        if (testProperty) {
            SendMessage message = SendMessage.ofBuilder(chatId, "Property is true").build();
            context.bot().execute(message);
        } else {
            SendMessage message = SendMessage.ofBuilder(chatId, "Property is false").build();
            context.bot().execute(message);
        }
    }
}

Joining a Conversation with Properties

When a user joins a conversation, you can pass a map of properties to initialize the conversation with specific values:

Map<String, Object> properties = Map.of(
    "name", "John",
    "age", 25
);

ConversationManager.JoinResult result = context.bot().getConversationManager().joinConversation(
    sender, context.message().chat(), "testConversation", properties);

if (result instanceof ConversationManager.JoinResult.AlreadyInConversation) {
    System.out.println("User is already in conversation");
} else if (result instanceof ConversationManager.JoinResult.ConversationNotFound) {
    System.out.println("Conversation not found");
} else {
    System.out.println("Conversation started");
}

Warning

In this example, name and age are considered unknown properties because they were not defined when the conversation was registered. If allowUnknownProperties is set to false, an exception will be thrown when the user tries to join the conversation with unknown properties.

Clone this wiki locally