Skip to content

Introduction

MessageKit's Skill framework is a GPT wrapper built on top of XMTP. It allows you to process natural language and perform agentic interactions.

User request

who holds vitalik.eth

Parsing

The agent processes the natural language input and breaks it down into sequential steps:

[
  "Let's check who holds vitalik.eth",
  "/info vitalik.eth",
]

This is the parameters extracted from the user request and available to the handler:

{
  "skill": "info",
  "params": {
    "domain": "vitalik.eth"
  }
}

This happens in the processMultilineResponse in the GPT plugin.

Skill declaration

The handler function to process check skill requests:

src/skills/info.ts
export const info: Skill[] = [
  {
    skill: "info",
    handler: handler,
    description:
      "Get detailed information about an ENS domain including owner, expiry date, and resolver.",
    examples: [
      "/info humanagent.eth",
      "/info fabri.base.eth",
      "/info @fabri",
      "/info fabri.converse.xyz",
      "/info vitalik.eth",
    ],
    params: {
      domain: {
        type: "string",
      },
    },
  },
];

Handler

The handler function to process info skill requests to fetch information about an ENS domain:

src/skills/info.ts
export async function handler(context: Context) {
  const {
    message: {
      sender,
      content: {
        params: { domain },
      },
    },
  } = context;
 
  const data = await getUserInfo(domain);
  if (!data?.address) {
    return {
      code: 404,
      message: "Domain not found.",
    };
  }
  let message = `Information:\n\n`;
  if (data?.ensDomain)
    message += `URL: https://app.ens.domains/${data?.ensDomain}\n`;
  if (data?.converseUsername)
    message += `Converse: https://converse.xyz/dm/${data?.converseUsername}\n`;
  if (data?.address) message += `Address: ${data?.address}\n`;
  if (data?.ensInfo?.avatar) message += `Avatar: ${data?.ensInfo?.avatar}\n`;
  if (data?.ensInfo?.description)
    message += `Description: ${data?.ensInfo?.description}\n`;
  if (data?.ensInfo?.ens_primary)
    message += `Primary ENS: ${data?.ensInfo?.ens_primary}\n`;
  if (data?.ensInfo?.github) message += `GitHub: ${data?.ensInfo?.github}\n`;
  if (data?.ensInfo?.twitter) message += `Twitter: ${data?.ensInfo?.twitter}\n`;
  message += `\n\nWould you like to tip the domain owner for getting there first 🤣?`;
  message = message.trim();
  return { code: 200, message };
}

System prompt

Here is the default prompt for the agent. You don't need to define it, but you can override it.

src/prompt.ts
export const systemPrompt = `{intro}
 
{vibe}
 
{rules}
 
{user_context}
 
{skills}
`;

Agent

This is the main function that runs the listener.

import { Agent, run, type Context } from "@xmtp/message-kit";
 
const agent: Agent = {
  name: "ENS Info Bot",
  tag: "@bot",
  description: "Agent Description",
  skills: [skill1, skill2],
};
 
//starts the agent
run(agent);

End result

The end result is a prompt that the model can understand and use to respond to the user.

example_prompt.md
You are a helpful agent called @bot that lives inside a web3 messaging app called
 
 
# Rules
- You can respond with multiple messages if needed. Each message should be separated by a newline character.
- You can trigger skills by only sending the command in a newline message.
- Each command starts with a slash (/).
- Check that you are not missing a command
- If you are going to use a command, make sure to preceed the command with "One moment:". i.e "Sure! ill check that for you. One moment:
/check humanagent.eth"
- Never announce actions without using a command separated by a newline character.
- Never use markdown in your responses or even ```
- Do not make guesses or assumptions
- Only answer if the verified information is in the prompt.
- Focus only on helping users with operations detailed below.
- Date: Sun, 15 Dec 2024 18:09:17 GMT,
 
 
## User context
- Start by fetch their domain from or Converse username
- Call the user by their name or domain, in case they have one
- Ask for a name (if they don't have one) so you can suggest domains.
- Message sent date: 2024-12-15T18:09:34.050Z
- Users address is: 0x40f08f0f853d1c42c61815652b7ccd5a50f0be09
- Users name is: ArizonaOregon
- Converse username is: ArizonaOregon
 
## Commands
/check [domain] - Check if a domain is available.
/cool [domain] - Get cool alternatives for a .eth domain.
/info [domain] - Get detailed information about an ENS domain including owner, expiry date, and resolver.
/register [domain] - Register a new ENS domain. Returns a URL to complete the registration process.
/renew [domain] - Extend the registration period of your ENS domain. Returns a URL to complete the renewal.
/pay [amount] [token] [username] [address] - Send a specified amount of a cryptocurrency to a destination address. 
When tipping, you can asume its 1 usdc.
/tip [username] - Send 1 usdc.
 
## Examples
/check vitalik.eth
/check fabri.base.eth
/cool vitalik.eth
/info humanagent.eth
/info fabri.base.eth
/info @fabri
/info fabri.converse.xyz
/info vitalik.eth
/register vitalik.eth
/renew fabri.base.eth
/pay 10 vitalik.eth
/pay 1 usdc to 0xC60E6Bb79322392761BFe3081E302aEB79B30B03
/tip vitalik.eth