Docs
CodeRabbit
Cloudflare
AG Grid
SerpAPI
Netlify
OpenRouter
Neon
WorkOS
Clerk
Electric
PowerSync
Sentry
Railway
Prisma
Strapi
Unkey
CodeRabbit
Cloudflare
AG Grid
SerpAPI
Netlify
OpenRouter
Neon
WorkOS
Clerk
Electric
PowerSync
Sentry
Railway
Prisma
Strapi
Unkey
Class References
Function References
Interface References
Type Alias References
Variable References
Adapters

Mistral

The Mistral adapter provides access to Mistral's chat models, including Mistral Large, the multimodal Pixtral family, the Magistral reasoning models, and the Codestral code-specialized model.

Installation

sh
npm install @tanstack/ai-mistral
npm install @tanstack/ai-mistral

Basic Usage

typescript
import { chat } from "@tanstack/ai";
import { mistralText } from "@tanstack/ai-mistral";

const stream = chat({
  adapter: mistralText("mistral-large-latest"),
  messages: [{ role: "user", content: "Hello!" }],
});
import { chat } from "@tanstack/ai";
import { mistralText } from "@tanstack/ai-mistral";

const stream = chat({
  adapter: mistralText("mistral-large-latest"),
  messages: [{ role: "user", content: "Hello!" }],
});

Basic Usage - Custom API Key

typescript
import { chat } from "@tanstack/ai";
import { createMistralText } from "@tanstack/ai-mistral";

const adapter = createMistralText(
  "mistral-large-latest",
  process.env.MISTRAL_API_KEY!,
);

const stream = chat({
  adapter,
  messages: [{ role: "user", content: "Hello!" }],
});
import { chat } from "@tanstack/ai";
import { createMistralText } from "@tanstack/ai-mistral";

const adapter = createMistralText(
  "mistral-large-latest",
  process.env.MISTRAL_API_KEY!,
);

const stream = chat({
  adapter,
  messages: [{ role: "user", content: "Hello!" }],
});

Configuration

typescript
import {
  createMistralText,
  type MistralTextConfig,
} from "@tanstack/ai-mistral";

const config: Omit<MistralTextConfig, "apiKey"> = {
  serverURL: "https://api.mistral.ai", // Optional, this is the default
  defaultHeaders: {
    "X-Custom-Header": "value",
  },
};

const adapter = createMistralText(
  "mistral-large-latest",
  process.env.MISTRAL_API_KEY!,
  config,
);
import {
  createMistralText,
  type MistralTextConfig,
} from "@tanstack/ai-mistral";

const config: Omit<MistralTextConfig, "apiKey"> = {
  serverURL: "https://api.mistral.ai", // Optional, this is the default
  defaultHeaders: {
    "X-Custom-Header": "value",
  },
};

const adapter = createMistralText(
  "mistral-large-latest",
  process.env.MISTRAL_API_KEY!,
  config,
);

Example: Chat Completion

typescript
import { chat, toServerSentEventsResponse } from "@tanstack/ai";
import { mistralText } from "@tanstack/ai-mistral";

export async function POST(request: Request) {
  const { messages } = await request.json();

  const stream = chat({
    adapter: mistralText("mistral-large-latest"),
    messages,
  });

  return toServerSentEventsResponse(stream);
}
import { chat, toServerSentEventsResponse } from "@tanstack/ai";
import { mistralText } from "@tanstack/ai-mistral";

export async function POST(request: Request) {
  const { messages } = await request.json();

  const stream = chat({
    adapter: mistralText("mistral-large-latest"),
    messages,
  });

  return toServerSentEventsResponse(stream);
}

Example: With Tools

typescript
import { chat, toolDefinition } from "@tanstack/ai";
import { mistralText } from "@tanstack/ai-mistral";
import { z } from "zod";

const getWeatherDef = toolDefinition({
  name: "get_weather",
  description: "Get the current weather for a location",
  inputSchema: z.object({
    location: z.string(),
  }),
});

const getWeather = getWeatherDef.server(async ({ location }) => {
  return { temperature: 72, conditions: "sunny" };
});

const stream = chat({
  adapter: mistralText("mistral-large-latest"),
  messages: [{ role: "user", content: "What's the weather in Paris?" }],
  tools: [getWeather],
});
import { chat, toolDefinition } from "@tanstack/ai";
import { mistralText } from "@tanstack/ai-mistral";
import { z } from "zod";

const getWeatherDef = toolDefinition({
  name: "get_weather",
  description: "Get the current weather for a location",
  inputSchema: z.object({
    location: z.string(),
  }),
});

const getWeather = getWeatherDef.server(async ({ location }) => {
  return { temperature: 72, conditions: "sunny" };
});

const stream = chat({
  adapter: mistralText("mistral-large-latest"),
  messages: [{ role: "user", content: "What's the weather in Paris?" }],
  tools: [getWeather],
});

Example: Multimodal (Vision)

Use a vision-capable model — pixtral-large-latest, pixtral-12b-2409, mistral-medium-latest, or mistral-small-latest — to send images alongside text:

typescript
import { chat } from "@tanstack/ai";
import { mistralText } from "@tanstack/ai-mistral";

const stream = chat({
  adapter: mistralText("pixtral-large-latest"),
  messages: [
    {
      role: "user",
      content: [
        { type: "text", content: "What's in this image?" },
        {
          type: "image",
          source: {
            type: "url",
            value: "https://example.com/photo.jpg",
          },
        },
      ],
    },
  ],
});
import { chat } from "@tanstack/ai";
import { mistralText } from "@tanstack/ai-mistral";

const stream = chat({
  adapter: mistralText("pixtral-large-latest"),
  messages: [
    {
      role: "user",
      content: [
        { type: "text", content: "What's in this image?" },
        {
          type: "image",
          source: {
            type: "url",
            value: "https://example.com/photo.jpg",
          },
        },
      ],
    },
  ],
});

For data-URL or base64 images, set source.type to "data" and provide mimeType:

typescript
import { chat } from "@tanstack/ai";
import { mistralText } from "@tanstack/ai-mistral";

const base64String = "..."; // your base64-encoded image bytes

const stream = chat({
  adapter: mistralText("pixtral-large-latest"),
  messages: [
    {
      role: "user",
      content: [
        { type: "text", content: "What's in this image?" },
        {
          type: "image",
          source: {
            type: "data",
            mimeType: "image/png",
            value: base64String,
          },
        },
      ],
    },
  ],
});
import { chat } from "@tanstack/ai";
import { mistralText } from "@tanstack/ai-mistral";

const base64String = "..."; // your base64-encoded image bytes

const stream = chat({
  adapter: mistralText("pixtral-large-latest"),
  messages: [
    {
      role: "user",
      content: [
        { type: "text", content: "What's in this image?" },
        {
          type: "image",
          source: {
            type: "data",
            mimeType: "image/png",
            value: base64String,
          },
        },
      ],
    },
  ],
});

See Multimodal Content for the full content-part shape.

Example: Reasoning (Magistral)

Magistral models (magistral-medium-latest, magistral-small-latest) stream their reasoning as separate events before the final answer. The adapter emits AG-UI REASONING_* chunks for the thinking content and TEXT_MESSAGE_* chunks for the answer:

typescript
// ignore: narrowing the raw AG-UI stream by `chunk.type` relies on @ag-ui/core's
// discriminated-union `type` field, which kiira can't resolve in a source-only
// check. The runtime behaviour is exactly as shown.
import { chat } from "@tanstack/ai";
import { mistralText } from "@tanstack/ai-mistral";

const stream = chat({
  adapter: mistralText("magistral-medium-latest"),
  messages: [{ role: "user", content: "Why is the sky blue?" }],
});

for await (const chunk of stream) {
  if (chunk.type === "REASONING_MESSAGE_CONTENT") {
    process.stdout.write(`[thinking] ${chunk.delta}`);
  } else if (chunk.type === "TEXT_MESSAGE_CONTENT") {
    process.stdout.write(chunk.delta);
  }
}
// ignore: narrowing the raw AG-UI stream by `chunk.type` relies on @ag-ui/core's
// discriminated-union `type` field, which kiira can't resolve in a source-only
// check. The runtime behaviour is exactly as shown.
import { chat } from "@tanstack/ai";
import { mistralText } from "@tanstack/ai-mistral";

const stream = chat({
  adapter: mistralText("magistral-medium-latest"),
  messages: [{ role: "user", content: "Why is the sky blue?" }],
});

for await (const chunk of stream) {
  if (chunk.type === "REASONING_MESSAGE_CONTENT") {
    process.stdout.write(`[thinking] ${chunk.delta}`);
  } else if (chunk.type === "TEXT_MESSAGE_CONTENT") {
    process.stdout.write(chunk.delta);
  }
}

Reasoning events are always closed before any text or tool output begins, so consumers see a complete REASONING_START → REASONING_MESSAGE_START → REASONING_MESSAGE_CONTENT* → REASONING_MESSAGE_END → REASONING_END sequence first.

See Thinking & Reasoning for the cross-provider event spec.

Example: Structured Output

Generate JSON that conforms to a Zod schema using Mistral's json_schema response format:

typescript
import { chat } from "@tanstack/ai";
import { mistralText } from "@tanstack/ai-mistral";
import { z } from "zod";

const recipeSchema = z.object({
  name: z.string(),
  ingredients: z.array(z.string()),
  steps: z.array(z.string()),
});

const recipe = await chat({
  adapter: mistralText("mistral-large-latest"),
  messages: [
    { role: "user", content: "Give me a chocolate chip cookie recipe." },
  ],
  outputSchema: recipeSchema,
});

console.log(recipe.name); // typed as z.infer<typeof recipeSchema>
import { chat } from "@tanstack/ai";
import { mistralText } from "@tanstack/ai-mistral";
import { z } from "zod";

const recipeSchema = z.object({
  name: z.string(),
  ingredients: z.array(z.string()),
  steps: z.array(z.string()),
});

const recipe = await chat({
  adapter: mistralText("mistral-large-latest"),
  messages: [
    { role: "user", content: "Give me a chocolate chip cookie recipe." },
  ],
  outputSchema: recipeSchema,
});

console.log(recipe.name); // typed as z.infer<typeof recipeSchema>

See Structured Outputs for the full guide.

Model Options

Mistral exposes provider-specific options via modelOptions:

typescript
import { chat } from "@tanstack/ai";
import { mistralText } from "@tanstack/ai-mistral";

const stream = chat({
  adapter: mistralText("mistral-large-latest"),
  messages: [{ role: "user", content: "Hello!" }],
  modelOptions: {
    temperature: 0.7,
    top_p: 0.9,
    max_tokens: 1024,
    random_seed: 42,
    stop: ["END"],
    safe_prompt: true,
    frequency_penalty: 0.5,
    presence_penalty: 0.5,
    parallel_tool_calls: true,
    tool_choice: "auto",
  },
});
import { chat } from "@tanstack/ai";
import { mistralText } from "@tanstack/ai-mistral";

const stream = chat({
  adapter: mistralText("mistral-large-latest"),
  messages: [{ role: "user", content: "Hello!" }],
  modelOptions: {
    temperature: 0.7,
    top_p: 0.9,
    max_tokens: 1024,
    random_seed: 42,
    stop: ["END"],
    safe_prompt: true,
    frequency_penalty: 0.5,
    presence_penalty: 0.5,
    parallel_tool_calls: true,
    tool_choice: "auto",
  },
});

All sampling parameters — including temperature, top_p, and max_tokens — go inside modelOptions using Mistral's native (snake_case) names.

Environment Variables

Set your API key in environment variables:

sh
MISTRAL_API_KEY=...
MISTRAL_API_KEY=...

Get a key from the Mistral Console.

Supported Models

Chat

  • mistral-large-latest — Flagship general-purpose model (128k context)
  • mistral-medium-latest — Multimodal mid-tier model with vision
  • mistral-small-latest — Fast, affordable multimodal model with vision
  • ministral-8b-latest — 8B edge model
  • ministral-3b-latest — 3B edge model
  • open-mistral-nemo — Open 12B model

Code

  • codestral-latest — Code-specialized model (256k context)

Vision

  • pixtral-large-latest — Large vision model
  • pixtral-12b-2409 — 12B vision model

Reasoning

Reasoning content is streamed as REASONING_* events before the final answer.

  • magistral-medium-latest — Mid-tier reasoning model
  • magistral-small-latest — Small reasoning model

See Mistral's model comparison for full details.

API Reference

mistralText(model, config?)

Creates a Mistral text adapter using the MISTRAL_API_KEY environment variable.

Parameters:

  • model — The model name (e.g., 'mistral-large-latest')
  • config.serverURL? — Custom base URL (optional)
  • config.defaultHeaders? — Headers to attach to every request (optional)

Returns: A Mistral text adapter instance.

createMistralText(model, apiKey, config?)

Creates a Mistral text adapter with an explicit API key.

Parameters:

  • model — The model name
  • apiKey — Your Mistral API key
  • config.serverURL? — Custom base URL (optional)
  • config.defaultHeaders? — Headers to attach to every request (optional)

Returns: A Mistral text adapter instance.

Limitations

  • Embeddings: Use the Mistral SDK directly for mistral-embed.
  • Image / Audio / Video Generation: Mistral does not provide these endpoints. Use OpenAI, Gemini, or fal.ai.
  • Text-to-Speech / Transcription: Not supported. Use OpenAI or ElevenLabs.

Next Steps

Provider Tools

Mistral does not currently expose provider-specific tool factories. Define your own tools with toolDefinition() from @tanstack/ai.

See Tools for the general tool-definition flow, or Provider Tools for other providers' native-tool offerings.