Skip to content

Reasoning

Agents can handle complex conversations by managing multiple steps in sequence, maintaining context, and waiting for user responses. This creates a more natural interaction flow.

Overview

For full reasoning we need to combine the following skills:

  • Scenarios: Train your agent for reliable responses.
  • Prompting: System prompt to teach available skills to the agent.
  • Processing: Handle multiple skills in a single conversation.
  • Parsing: Interpret user intent and translate it into a defined skill.
  • Definition: Define skills, parameters and handlers.

Example: Ens domain registration

Now let's put all these powerfull pieces together to create a more complex interaction.

Let's walk through a complete ENS domain registration flow:

User initiates the conversation

let's register humanagent.eth

Agent creates a response

The agent processes the natural language input "let's register fabriethsf.eth" and breaks it down into sequential steps:

[
  "Hello! I'll help you get your domain.",
  "Let's start by checking your ENS domain. Give me a moment.",
  "/check humanagent.eth",
]

Skills

These are some of the skills the agent can use with its definition and handler implementation:

src/handlers/check.ts
import { ensUrl } from "../index.js";
import { XMTPContext, getUserInfo } from "@xmtp/message-kit";
import type { skillAction } from "@xmtp/message-kit";
 
export const registerSkill: skillAction[] = [
  {
    skill: "/check [domain]",
    handler: handleCheck,
    examples: ["/check vitalik.eth", "/check fabri.base.eth"],
    description: "Check if a domain is available.",
    params: {
      domain: {
        type: "string",
      },
    },
  },
];
 
export async function handleCheck(context: XMTPContext) {
  const {
    message: {
      content: {
        params: { domain },
      },
    },
  } = context;
 
  const data = await getUserInfo(domain);
 
  if (!data?.address) {
    let message = `Looks like ${domain} is available! Here you can register it: ${ensUrl}${domain} or would you like to see some cool alternatives?`;
    return {
      code: 200,
      message,
    };
  } else {
    let message = `Looks like ${domain} is already registered!`;
    await context.executeSkill("/cool " + domain);
    return {
      code: 404,
      message,
    };
  }
}

Skills declaration

The agent processes the natural language input "let's register fabriethsf.eth" and breaks it down into sequential steps:

src/index.ts
export const skills = [
  {
    name: "Ens Domain Bot",
    tag: "@ens",
    description: "Register ENS domains.",
    skills: [
      ...checkSkill,
      ...coolSkill,
      ...infoSkill,
      ...registerSkill,
      ...renewSkill,
      ...resetSkill,
      ...tipSkill,
    ],
  },
];

Return a resposonse

The agent returns a response to the user:

src/index.ts
run(
  async (context: XMTPContext) => {
    const {
      message: { sender },
      skills,
    } = context;
 
    let prompt = await replaceVariables(
      systemPrompt,
      sender.address,
      skills,
      "@ens",
    );
    fs.writeFileSync("example_prompt.md", prompt);
    await agentReply(context, prompt);
  },
  { skills },
);

This is a very simple example, but it shows how the agent can handle complex interactions by managing multiple steps in sequence, maintaining context, and waiting for user responses.