DEV Community

Cover image for Mistral Basic AI Agent Using NextJS with TypeScript
Arfatur Rahman
Arfatur Rahman

Posted on

Mistral Basic AI Agent Using NextJS with TypeScript

Image description
In this tutorial, I will guide you step-by-step on how to use Mistral AI's powerful mistral-large-latest model to build a custom agent that can track and respond to payment statuses and transaction dates. This tutorial assumes you have a basic understanding of JavaScript, Next.js, and how to work with APIs. By the end of this guide, you will know how to create a responsive agent that integrates with real-time data fetching functions.

Prerequisites

Before you begin, make sure you have:

  • Basic knowledge of JavaScript, Node.js, and Next.js.
  • A Mistral AI account for API access.
  • Installed Next.js, Zod, and the Mistral client.

If you haven't installed these yet, you can do so by running:

npx create-next-app@latest arfat
cd arfat
npm i @mistralai/mistralai zod

Enter fullscreen mode Exit fullscreen mode

Important links

Get API key

Mistral Free Tier Limitations

  • 1 request per second: You can make one API request per second.
  • 500,000 tokens per minute: The total number of tokens you can use in one minute.
  • 1 billion tokens per month: The maximum token limit you can use in a month.

These limitations are important to keep in mind while developing, so you can optimize how frequently you call the API to avoid exceeding the free tier limits.

Schema and Input Validation

We'll begin by validating the user input to ensure that the data passed to the Mistral AI model is in the correct format. Using Zod for validation, here's how you can ensure that the input text is a non-empty string:

const inputSchema = z.object({
  inputText: z
    .string({
      invalid_type_error: "Input text must be a string", // Error message if the input is not a string
      required_error: "Input text is required", // Error message if the input is missing
    })
    .min(1, { message: "Input text cannot be empty" }), // Ensures the string is not empty
});

Enter fullscreen mode Exit fullscreen mode

Defining Mistral Messages

To interact with Mistral AI, we need to define a message interface that structures the conversation. The messages will have different roles such as system, user, assistant, and tool.

export interface MistralMessage {
  role: "system" | "user" | "assistant" | "tool";
  content: string;
  name?: string; // Optional name field
  toolCallId?: string; // Optional name field
}

Enter fullscreen mode Exit fullscreen mode

This allows Mistral AI to process incoming data and respond with human-like messages.

Setting Up the Mistral Client

Mistral's client is an interface that allows you to send requests to the API. You'll need to set up the Mistral client with your API key and initialize the client in your code:

import { Mistral } from "@mistralai/mistralai";

const apiKey = process.env.MISTRAL_API_KEY;
export const mistralClient = new Mistral({ apiKey: apiKey });

Enter fullscreen mode Exit fullscreen mode

Fetching Payment Data: Creating Helper Functions

We'll simulate payment data for testing by creating a mock database. The transactionData array contains payment information, and we’ll use two functions to retrieve the payment status and date based on a transaction ID.

const transactionData = [
  {
    transaction_id: "T1001",
    customer_id: "C001",
    payment_amount: 125.5,
    payment_date: "2021-10-05",
    payment_status: "Paid",
  },
];

export function getPaymentStatus({ transactionId }: { transactionId: string }) {
  const transaction = transactionData.find(
    (row) => row.transaction_id === transactionId
  );
  if (transaction) return JSON.stringify({ status: transaction.payment_status });
  return JSON.stringify({ error: "Transaction ID not found." });
}

export function getPaymentDate({ transactionId }: { transactionId: string }) {
  const transaction = transactionData.find(
    (row) => row.transaction_id === transactionId
  );
  if (transaction) return JSON.stringify({ date: transaction.payment_date });
  return JSON.stringify({ error: "Transaction ID not found." });
}

Enter fullscreen mode Exit fullscreen mode

These functions will serve as "tools" for the assistant to fetch the required payment data.


Mistral Tools: Connecting Functions with the AI Model

Mistral AI can call external functions (tools) to fetch data. Here, we define two tools: getPaymentStatus and getPaymentDate.

import { Tool } from "@mistralai/mistralai/models/components";

const mistralTools: Tool[] = [
  {
    type: "function",
    function: {
      name: "getPaymentStatus",
      description: "Get the payment status of a transaction",
      parameters: {
        type: "object",
        properties: {
          transactionId: {
            type: "string",
            description: "The transaction ID.",
          },
        },
        required: ["transactionId"],
      },
    },
  },
  {
    type: "function",
    function: {
      name: "getPaymentDate",
      description: "Get the payment date of a transaction",
      parameters: {
        type: "object",
        properties: {
          transactionId: {
            type: "string",
            description: "The transaction ID.",
          },
        },
        required: ["transactionId"],
      },
    },
  },
];

Enter fullscreen mode Exit fullscreen mode

These tools will allow Mistral to call these functions when needed.

The Main POST Handler

In the main POST request handler, we process the user’s query and send it to Mistral AI. If Mistral determines that a tool is needed (e.g., to fetch the payment status or date), it will invoke the appropriate function.

export async function POST(request: Request) {
  try {
    const body = await request.json();
    const { inputText } = inputSchema.parse(body);

    const messages: MistralMessage[] = [
      { role: "system", content: "You are a friendly assistant" },
      { role: "user", content: inputText },
    ];

    const response = await mistralClient.chat.complete({
      model: "mistral-large-latest",
      messages,
      toolChoice: "any",
      tools: mistralTools,
      temperature: 0.7,
      responseFormat: { type: "text" },
    });

    if (response?.choices && response.choices[0]?.message?.role === "assistant") {
      if (response?.choices[0].finishReason === "stop") {
        return formatResponse(
          { finalAnswer: response?.choices[0].message.content, ...response },
          "Data fetched successfully"
        );
      }

      if (response?.choices[0]?.finishReason === "tool_calls") {
        const toolCalls = response.choices[0]?.message?.toolCalls;
        if (toolCalls && toolCalls.length > 0) {
          const functionName = toolCalls[0]?.function?.name as keyof typeof availableFunctions;
          const functionArgs = JSON.parse(toolCalls[0]?.function?.arguments as string);

          const functionResponse = availableFunctions[functionName](functionArgs);

          messages.push({
            role: "tool",
            name: functionName,
            content: functionResponse,
            toolCallId: toolCalls[0].id,
          });

          await delay(3000);

          const functionREs = await mistralClient.chat.complete({
            model: "mistral-large-latest",
            messages,
          });

          return formatResponse(functionREs, "Data fetched successfully");
        }
      }
    }
  } catch (error) {
    console.log("Error", { error });
    return routeErrorHandler(error);
  }
}

Enter fullscreen mode Exit fullscreen mode

Top comments (0)

11 Tips That Make You a Better Typescript Programmer

typescript

1 Think in {Set}

Type is an everyday concept to programmers, but it’s surprisingly difficult to define it succinctly. I find it helpful to use Set as a conceptual model instead.

#2 Understand declared type and narrowed type

One extremely powerful typescript feature is automatic type narrowing based on control flow. This means a variable has two types associated with it at any specific point of code location: a declaration type and a narrowed type.

#3 Use discriminated union instead of optional fields

...

Read the whole post now!

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay