diff --git a/.changeset/new-apples-raise.md b/.changeset/new-apples-raise.md
new file mode 100644
index 000000000000..a7a765686d7e
--- /dev/null
+++ b/.changeset/new-apples-raise.md
@@ -0,0 +1,5 @@
+---
+'@ai-sdk/mistral': patch
+---
+
+feat(provider/mistral): `response_format.type === 'json_schema'`
diff --git a/content/providers/01-ai-sdk-providers/20-mistral.mdx b/content/providers/01-ai-sdk-providers/20-mistral.mdx
index e272f499d349..2c1b1f5b68fb 100644
--- a/content/providers/01-ai-sdk-providers/20-mistral.mdx
+++ b/content/providers/01-ai-sdk-providers/20-mistral.mdx
@@ -111,6 +111,18 @@ The following optional provider options are available for Mistral models:
Maximum number of pages to process in a document.
+- **strictJsonSchema** _boolean_
+
+ Whether to use strict JSON schema validation for structured outputs. Only applies when a schema is provided and only sets the [`strict` flag](https://docs.mistral.ai/api/#tag/chat/operation/chat_completion_v1_chat_completions_post) in addition to using [Custom Structured Outputs](https://docs.mistral.ai/capabilities/structured-output/custom_structured_output/), which is used by default if a schema is provided.
+
+ Defaults to `false`.
+
+- **structuredOutputs** _boolean_
+
+ Whether to use [structured outputs](#structured-outputs). When enabled, tool calls and object generation will be strict and follow the provided schema.
+
+ Defaults to `true`.
+
### Document OCR
Mistral chat models support document OCR for PDF files.
@@ -200,6 +212,60 @@ const { text } = await generateText({
Mistral language models can also be used in the `streamText`, `generateObject`, and `streamObject` functions
(see [AI SDK Core](/docs/ai-sdk-core)).
+#### Structured Outputs
+
+Mistral chat models support structured outputs using JSON Schema. You can use `generateObject` or `streamObject`
+with Zod, Valibot, or raw JSON Schema. The SDK sends your schema via Mistral's `response_format: { type: 'json_schema' }`.
+
+```ts
+import { mistral } from '@ai-sdk/mistral';
+import { generateObject } from 'ai';
+import { z } from 'zod/v3';
+
+const result = await generateObject({
+ model: mistral('mistral-large-latest'),
+ schema: z.object({
+ recipe: z.object({
+ name: z.string(),
+ ingredients: z.array(z.string()),
+ instructions: z.array(z.string()),
+ }),
+ }),
+ prompt: 'Generate a simple pasta recipe.',
+});
+
+console.log(JSON.stringify(result.object, null, 2));
+```
+
+You can enable strict JSON Schema validation using a provider option:
+
+```ts highlight="7-11"
+import { mistral } from '@ai-sdk/mistral';
+import { generateObject } from 'ai';
+import { z } from 'zod/v3';
+
+const result = await generateObject({
+ model: mistral('mistral-large-latest'),
+ providerOptions: {
+ mistral: {
+ strictJsonSchema: true, // reject outputs that don't strictly match the schema
+ },
+ },
+ schema: z.object({
+ title: z.string(),
+ items: z.array(z.object({ id: z.string(), qty: z.number().int().min(1) })),
+ }),
+ prompt: 'Generate a small shopping list.',
+});
+```
+
+
+ When using structured outputs, the SDK no longer injects an extra "answer with
+ JSON" instruction. It relies on Mistral's native `json_schema`/`json_object`
+ response formats instead. You can customize the schema name/description via
+ the standard structured-output APIs.
+
+
### Model Capabilities
| Model | Image Input | Object Generation | Tool Usage | Tool Streaming |
diff --git a/examples/ai-core/src/generate-object/mistral.ts b/examples/ai-core/src/generate-object/mistral.ts
index 186ce5718824..5dbf095fc1ad 100644
--- a/examples/ai-core/src/generate-object/mistral.ts
+++ b/examples/ai-core/src/generate-object/mistral.ts
@@ -19,6 +19,14 @@ async function main() {
}),
}),
prompt: 'Generate a lasagna recipe.',
+ providerOptions: {
+ mistral: {
+ // `open-mistral-7b` model has problems with the `$schema` property
+ // in the JSON schema unless `strict` is set to true
+ // See https://github.com/vercel/ai/pull/8130#issuecomment-3213138032
+ strictJsonSchema: true,
+ },
+ },
});
console.log(JSON.stringify(result.object.recipe, null, 2));
diff --git a/packages/mistral/src/mistral-chat-language-model.test.ts b/packages/mistral/src/mistral-chat-language-model.test.ts
index 4a9fb19fa55a..28a21c11be31 100644
--- a/packages/mistral/src/mistral-chat-language-model.test.ts
+++ b/packages/mistral/src/mistral-chat-language-model.test.ts
@@ -571,12 +571,6 @@ describe('doGenerate', () => {
"document_page_limit": undefined,
"max_tokens": undefined,
"messages": [
- {
- "content": "JSON schema:
- {"type":"object","properties":{"name":{"type":"string"}}}
- You MUST answer with a JSON object that matches the JSON schema above.",
- "role": "system",
- },
{
"content": [
{
@@ -590,7 +584,20 @@ describe('doGenerate', () => {
"model": "mistral-small-latest",
"random_seed": undefined,
"response_format": {
- "type": "json_object",
+ "json_schema": {
+ "description": undefined,
+ "name": "response",
+ "schema": {
+ "properties": {
+ "name": {
+ "type": "string",
+ },
+ },
+ "type": "object",
+ },
+ "strict": false,
+ },
+ "type": "json_schema",
},
"safe_prompt": undefined,
"temperature": undefined,
diff --git a/packages/mistral/src/mistral-chat-language-model.ts b/packages/mistral/src/mistral-chat-language-model.ts
index 8af1cb4b3aa8..3d5f0148f6a4 100644
--- a/packages/mistral/src/mistral-chat-language-model.ts
+++ b/packages/mistral/src/mistral-chat-language-model.ts
@@ -110,22 +110,12 @@ export class MistralChatLanguageModel implements LanguageModelV2 {
});
}
- // TODO remove when we have JSON schema support (see OpenAI implementation)
- if (
- responseFormat != null &&
- responseFormat.type === 'json' &&
- responseFormat.schema != null
- ) {
- warnings.push({
- type: 'unsupported-setting',
- setting: 'responseFormat',
- details: 'JSON response format schema is not supported',
- });
- }
+ const structuredOutputs = options.structuredOutputs ?? true;
+ const strictJsonSchema = options.strictJsonSchema ?? false;
// For Mistral we need to need to instruct the model to return a JSON object.
// https://docs.mistral.ai/capabilities/structured-output/structured_output_overview/
- if (responseFormat?.type === 'json') {
+ if (responseFormat?.type === 'json' && !responseFormat?.schema) {
prompt = injectJsonInstructionIntoMessages({
messages: prompt,
schema: responseFormat.schema,
@@ -146,9 +136,20 @@ export class MistralChatLanguageModel implements LanguageModelV2 {
random_seed: seed,
// response format:
- // TODO add JSON schema support (see OpenAI implementation)
response_format:
- responseFormat?.type === 'json' ? { type: 'json_object' } : undefined,
+ responseFormat?.type === 'json'
+ ? structuredOutputs && responseFormat?.schema != null
+ ? {
+ type: 'json_schema',
+ json_schema: {
+ schema: responseFormat.schema,
+ strict: strictJsonSchema,
+ name: responseFormat.name ?? 'response',
+ description: responseFormat.description,
+ },
+ }
+ : { type: 'json_object' }
+ : undefined,
// mistral-specific provider options:
document_image_limit: options.documentImageLimit,
diff --git a/packages/mistral/src/mistral-chat-options.ts b/packages/mistral/src/mistral-chat-options.ts
index 6f5af4280d1b..58396171b319 100644
--- a/packages/mistral/src/mistral-chat-options.ts
+++ b/packages/mistral/src/mistral-chat-options.ts
@@ -34,6 +34,20 @@ Defaults to `false`.
documentImageLimit: z.number().optional(),
documentPageLimit: z.number().optional(),
+
+ /**
+ * Whether to use structured outputs.
+ *
+ * @default true
+ */
+ structuredOutputs: z.boolean().optional(),
+
+ /**
+ * Whether to use strict JSON schema validation.
+ *
+ * @default false
+ */
+ strictJsonSchema: z.boolean().optional(),
});
export type MistralProviderOptions = z.infer;