Skip to content

Intent

MessageKit Intent allows bots to interpret and execute commands internally, giving them the ability to process user requests in a conversational manner.

Explicit commands

Explicit commands are directly handled by the bot through a well-defined structure. The bot uses the parameters provided to trigger specific actions.

Example:

A user wants to swap tokens:

/swap 1 eth usdc

MessageKit directly processes the parameters from the command and handles the parameters to return a Frame URL.

Declaring commands

import { HandlerContext } from "@xmtp/message-kit";
import { handleSwap } from "./handler/swap.js";
 
export const commands: CommandGroup[] = [
  {
    name: "Swap Bot",
    description: "Swap bot for base.",
    triggers: ["/swap", "@swap", "@swapbot"],
    commands: [
      {
        command: "/swap [amount] [token_from] [token_to]",
        handler: handleSwap,
        description: "Exchange one cryptocurrency for another.",
        params: {
          amount: { type: "number", default: 1 },
          token_from: { type: "string", values: ["eth", "usdc", "dai"] },
          token_to: { type: "string", values: ["eth", "usdc", "dai"] },
        },
      },
    ],
  },
];

Handling command responses

MessageKit will automatically handle the command parameters allowing you to focus on handling the command logic.

import { HandlerContext } from "@xmtp/message-kit";
 
export async function handleSwap(context: HandlerContext) {
  const {
    message: {
      content: { command, params }, 
    },
  } = context;
  const baseUrl = "https://{url}";
 
  if (command === "swap") {
    const { amount, token_from, token_to } = params; 
 
    if (!amount || !token_from || !token_to) {
      context.reply(
        "Missing required parameters. Please provide amount, token_from, and token_to.",
      );
      return;
    }
    // Generate URL for the swap transaction
    let url_swap = generateFrameURL(baseUrl, "swap", {
      amount,
      token_from,
      token_to,
    });
    context.reply(`${url_swap}`);
  }
}

The bot will reply with the URL to the swap transaction.

{baseUrl}/swap?amount=1&token_from=eth&token_to=usdc

Natural language

Bots can also understand natural language prompts, allowing users to interact with the bot more conversationally. The bot translates the user's natural language input into a command and executes it.

Example:

A user types:

@swap 1 usdc to eth please

The message will trigger an AI text generation model to convert the natural language to a command.

You are a helpful and playful betting bot that lives inside a web3 messaging group.
 
Users can start a swap by tagging you in a prompt like "@swap 1 eth to usdc"
 
You then have an internal command to create a swap: "/swap [amount] [token_from] [token_to]"
 
Format examples:
/swap 1 eth usdc
/swap 100 dai usdc
/swap 0.1 eth usdt

The AI model will return this command:

/swap 1 usdc eth

And then the bot using intent will execute the command. Internally MessageKit will execute the handler handleSwap for the command as defined in the commands file seen before.

const { reply } = await textGeneration(userPrompt, systemPrompt);
if (reply.startsWith("/")) {
  // Execute the command if it's a slash command
  await context.intent(reply);
}

Reasoning (Multiple Commands)

Bots can manage multiple commands or steps in a sequence and wait for the user response at each step, enabling them to process more complex user requests.

Example:

A user interacts with the ENS bot:

lets register fabriethsf.eth

We already have the commands defined:

{
  name: "ENS Bot",
  commands: [
    {
      command: "/check [domain]",
      handler: handleEns,
      description: "Check if a domain is available.",
    },
    {
      command: "/register [domain]",
      handler: handleEns,
      description: "Register a domain.",
    },
    {
      command: "/info [domain]",
      handler: handleEns,
      description: "Get information about a domain.",
    }
  ],
 
}

Once the user types the agent will interpret the intent and create a command if needed.

You are a helpful and playful ens domain register bot that lives inside a web3 messaging app.
- Only provide answers based on verified information.
- Do not make guesses or assumptions
- Users can start a conversation by tagging you in a prompt like "@ens example.eth" or chatting 1:1
- You can respond with multiple messages if needed. Each message should be separated by a newline character.
- You can execute commands by sending the command as a message.
 
## Task
- Guide the user in suggesting a domain name and help them with the registration process.  You can trigger commands by only sending the command as a message.
- To trigger registration mini-app: "/register [domain]".
- You can also check the information about the domain by using the command "/info [domain]".
- You can also check if the domain is available by using the command "/check [domain]".
 
## Commands
- /help: Show the list of commands
- /check [domain]: Check if a domain is available
- /register [domain]: Register a domain
 
Format examples:
/register vitalik.eth
/check vitalik.eth
/info vitalik.eth
/help

In this case the agent creates 2 messages:

[
  "Let's first check if the domain is available.  ",
  '/check fabriethsf.eth'
]

The check handler can return an api response:

return {
  code: 200,
  message: `Looks like ${domain} is available! Do you want to register it? https://ens.steer.fun/frames/manage?name=${domain}`,
};

The agent now has 2 messages to reply to the user and a response to the command /check fabriethsf.eth.

for (const message of messages) {
  if (message.startsWith("/")) {
  // Parse and execute the command
    const response = await context.intent(message);
    await context.send((response as ApiResponse)?.message);
  } else {
    // Send the message as a text response
    await context.send(message);
  }
}

Short-Term Memory

Bots can maintain short-term memory, which allows them to remember recent interactions. This feature helps bots continue conversations and complete actions based on previous inputs without needing the user to repeat information.

const chatHistories: Record<string, any[]> = {};
 
let userPrompt = params?.prompt ?? content;
 
const { reply, history } = await textGeneration(
  userPrompt,
  systemPrompt,
  chatHistories[sender.address],
);
chatHistories[sender.address] = history;

In summary, MessageKit provides a way to handle commands and natural language in a conversational manner allowing for infinite use cases. Can't wait to see what you build!