UNPKG

@ai-sdk/mistral

Version:
3,170 lines • 106 kB
import { InvalidArgumentError, NoSuchModelError, TooManyEmbeddingValuesForCallError, UnsupportedFunctionalityError } from "@ai-sdk/provider";
import { StreamingToolCallTracker, WORKFLOW_DESERIALIZE, WORKFLOW_SERIALIZE, combineHeaders, connectToWebSocket, convertBase64ToUint8Array, convertToBase64, convertUint8ArrayToBase64, createEventSourceResponseHandler, createJsonErrorResponseHandler, createJsonResponseHandler, createLanguageModelResponseMetadata as getResponseMetadata, createNullLanguageModelUsage, createProviderExecutedToolFactory, createToolNameMapping, deleteFromApi, generateId, getTopLevelMediaType, injectJsonInstructionIntoMessages, isCustomReasoning, lazySchema, loadApiKey, mapReasoningToProviderEffort, mediaTypeToExtension, parseProviderOptions, postFormDataToApi, postJsonToApi, postToApi, resolve, resolveFullMediaType, resolveWith, safeParseJSON, safeValidateTypes, secureJsonParse, serializeModelOptions, stringifyWithBigIntAndCycles, toWebSocketUrl, waitForWebSocketBufferDrain, withUserAgentSuffix, withoutTrailingSlash, zodSchema } from "@ai-sdk/provider-utils";
import { z } from "zod/v4";
//#region src/convert-mistral-usage.ts
const mistralPromptTokensDetailsSchema = z.object({
	messages: z.array(z.json()).nullish(),
	cached_tokens: z.number().nullish(),
	audio_tokens: z.number().nullish()
}).catchall(z.json());
const mistralCompletionTokensDetailsSchema = z.object({ reasoning_tokens: z.number().nullish() }).catchall(z.json());
const mistralUsageSchema = z.object({
	prompt_tokens: z.number(),
	completion_tokens: z.number(),
	total_tokens: z.number(),
	prompt_audio_seconds: z.number().nullish(),
	request_count: z.number().nullish(),
	service_tier: z.string().nullish(),
	num_cached_tokens: z.number().nullish(),
	prompt_tokens_details: mistralPromptTokensDetailsSchema.nullish(),
	prompt_token_details: mistralPromptTokensDetailsSchema.nullish(),
	completion_tokens_details: mistralCompletionTokensDetailsSchema.nullish()
}).catchall(z.json());
function convertMistralUsage(usage) {
	if (usage == null) return createNullLanguageModelUsage();
	const promptTokens = usage.prompt_tokens;
	const completionTokens = usage.completion_tokens;
	const cacheReadTokens = usage.num_cached_tokens ?? usage.prompt_tokens_details?.cached_tokens ?? usage.prompt_token_details?.cached_tokens ?? 0;
	return {
		inputTokens: {
			total: promptTokens,
			noCache: promptTokens - cacheReadTokens,
			cacheRead: cacheReadTokens || void 0,
			cacheWrite: void 0
		},
		outputTokens: {
			total: completionTokens,
			text: completionTokens,
			reasoning: void 0
		},
		raw: usage
	};
}
//#endregion
//#region src/convert-to-mistral-chat-messages.ts
function formatFileUrl({ part }) {
	if (part.data.type === "url") return part.data.url.toString();
	if (part.data.type === "data") return `data:${resolveFullMediaType({ part })};base64,${convertToBase64(part.data.data)}`;
	throw new UnsupportedFunctionalityError({ functionality: `file part data type ${part.data.type}` });
}
function serializeMistralToolCallArguments(input) {
	if (typeof input === "string") try {
		secureJsonParse(input);
		return input;
	} catch {
		return JSON.stringify(input);
	}
	return stringifyWithBigIntAndCycles(input);
}
function convertToMistralChatMessages(prompt) {
	const messages = [];
	for (let i = 0; i < prompt.length; i++) {
		const { role, content } = prompt[i];
		const isLastMessage = i === prompt.length - 1;
		switch (role) {
			case "system":
				messages.push({
					role: "system",
					content
				});
				break;
			case "user":
				messages.push({
					role: "user",
					content: content.map((part) => {
						switch (part.type) {
							case "text": return {
								type: "text",
								text: part.text
							};
							case "file": switch (part.data.type) {
								case "reference": throw new UnsupportedFunctionalityError({ functionality: "file parts with provider references" });
								case "text": throw new UnsupportedFunctionalityError({ functionality: "text file parts" });
								case "url":
								case "data": if (getTopLevelMediaType(part.mediaType) === "image") return {
									type: "image_url",
									image_url: formatFileUrl({ part })
								};
								else {
									if (part.data.type === "data") {
										if (resolveFullMediaType({ part }) !== "application/pdf") throw new UnsupportedFunctionalityError({ functionality: "Only images and PDF file parts are supported" });
									} else if (part.mediaType !== "application/pdf") throw new UnsupportedFunctionalityError({ functionality: "Only images and PDF file parts are supported" });
									return {
										type: "document_url",
										document_url: formatFileUrl({ part })
									};
								}
							}
						}
					})
				});
				break;
			case "assistant": {
				let text = "";
				let hasReasoning = false;
				const contentParts = [];
				const toolCalls = [];
				for (const part of content) switch (part.type) {
					case "text":
						text += part.text;
						contentParts.push({
							type: "text",
							text: part.text
						});
						break;
					case "tool-call":
						toolCalls.push({
							id: part.toolCallId,
							type: "function",
							function: {
								name: part.toolName,
								arguments: serializeMistralToolCallArguments(part.input)
							}
						});
						break;
					case "reasoning":
						hasReasoning = true;
						contentParts.push({
							type: "thinking",
							thinking: [{
								type: "text",
								text: part.text
							}],
							closed: true
						});
						break;
					default: throw new Error(`Unsupported content type in assistant message: ${part.type}`);
				}
				messages.push({
					role: "assistant",
					content: hasReasoning ? contentParts : text,
					prefix: isLastMessage ? true : void 0,
					tool_calls: toolCalls.length > 0 ? toolCalls : void 0
				});
				break;
			}
			case "tool":
				for (const toolResponse of content) {
					if (toolResponse.type === "tool-approval-response") continue;
					const output = toolResponse.output;
					let contentValue;
					switch (output.type) {
						case "text":
						case "error-text":
							contentValue = output.value;
							break;
						case "execution-denied":
							contentValue = output.reason ?? "Tool call execution denied.";
							break;
						case "content":
						case "json":
						case "error-json": contentValue = stringifyWithBigIntAndCycles(output.value);
					}
					messages.push({
						role: "tool",
						name: toolResponse.toolName,
						tool_call_id: toolResponse.toolCallId,
						content: contentValue
					});
				}
				break;
			default: throw new Error(`Unsupported role: ${role}`);
		}
	}
	return messages;
}
//#endregion
//#region src/map-mistral-finish-reason.ts
function mapMistralFinishReason(finishReason) {
	switch (finishReason) {
		case "stop": return "stop";
		case "length":
		case "model_length": return "length";
		case "tool_calls": return "tool-calls";
		case "error": return "error";
		default: return "other";
	}
}
//#endregion
//#region src/mistral-chat-language-model-options.ts
const mistralLanguageModelChatOptions = () => z.object({
	/**
	* Whether to inject a safety prompt before all conversations.
	*
	* Defaults to `false`.
	*/
	safePrompt: z.boolean().optional(),
	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(),
	/**
	* Whether to enable parallel function calling during tool use.
	* When set to false, the model will use at most one tool per response.
	*
	* @default true
	*/
	parallelToolCalls: z.boolean().optional(),
	/**
	* A stable identifier used to route requests with shared prompt prefixes to
	* the same cache.
	*/
	promptCacheKey: z.string().optional(),
	/**
	* Controls the reasoning effort for models that support adjustable reasoning.
	*
	* - `'high'`: Enable reasoning
	* - `'none'`: Disable reasoning
	* - `'medium'`: Medium reasoning effort for models that support it, e.g.
	*   `mistral-large-4`, which accepts `'low'`, `'medium'`, and `'high'`
	* - `'low'`, `'max'`: Lowest and highest reasoning effort for models that
	*   support them, e.g. `zai-glm-5-3`, which accepts `'low'`, `'high'`, and
	*   `'max'` but not `'none'`
	*/
	reasoningEffort: z.enum([
		"high",
		"none",
		"low",
		"medium",
		"max"
	]).optional()
});
const mistralLanguageModelChatOptionsValidator = lazySchema(() => zodSchema(mistralLanguageModelChatOptions()));
//#endregion
//#region src/mistral-error.ts
const mistralErrorDataSchema = lazySchema(() => zodSchema(z.object({
	object: z.literal("error"),
	message: z.string(),
	type: z.string(),
	param: z.string().nullable(),
	code: z.string().nullable()
})));
const mistralFailedResponseHandler = createJsonErrorResponseHandler({
	errorSchema: mistralErrorDataSchema,
	errorToMessage: (data) => data.message
});
//#endregion
//#region src/mistral-prepare-tools.ts
function prepareTools({ tools, toolChoice }) {
	tools = tools?.length ? tools : void 0;
	const toolWarnings = [];
	if (tools == null) return {
		tools: void 0,
		toolChoice: void 0,
		toolWarnings
	};
	const mistralTools = [];
	for (const tool of tools) if (tool.type === "provider") toolWarnings.push({
		type: "unsupported",
		feature: `provider-defined tool ${tool.id}`
	});
	else mistralTools.push({
		type: "function",
		function: {
			name: tool.name,
			description: tool.description,
			parameters: tool.inputSchema,
			...tool.strict != null ? { strict: tool.strict } : {}
		}
	});
	if (toolChoice == null) return {
		tools: mistralTools,
		toolChoice: void 0,
		toolWarnings
	};
	const type = toolChoice.type;
	switch (type) {
		case "auto":
		case "none": return {
			tools: mistralTools,
			toolChoice: type,
			toolWarnings
		};
		case "required": return {
			tools: mistralTools,
			toolChoice: "any",
			toolWarnings
		};
		case "tool": return {
			tools: mistralTools,
			toolChoice: {
				type: "function",
				function: { name: toolChoice.toolName }
			},
			toolWarnings
		};
		default: throw new UnsupportedFunctionalityError({ functionality: `tool choice type: ${type}` });
	}
}
//#endregion
//#region src/mistral-model-catalog.ts
const mistralProviderOptions = {
	language: {
		safePrompt: { description: "Inject a safety prompt. Chat API only." },
		documentImageLimit: { description: "Maximum document images. Chat API only." },
		documentPageLimit: { description: "Maximum document pages. Chat API only." },
		structuredOutputs: { description: "Whether to send a JSON response schema." },
		strictJsonSchema: { description: "Whether to use strict JSON schema validation." },
		parallelToolCalls: { description: "Allow parallel function calls. Chat API only." },
		promptCacheKey: { description: "Cache affinity key. Chat API only." },
		reasoningEffort: { description: "Reasoning effort for configurable reasoning models." }
	},
	embedding: {
		metadata: { description: "Metadata attached to the embedding request." },
		outputDimension: { description: "Output embedding dimensions." },
		outputDtype: { description: "Output embedding data type." }
	},
	transcription: {
		language: { description: "Language of the audio." },
		returnLanguage: { description: "Return the detected language." },
		temperature: { description: "Sampling temperature." },
		timestampGranularities: { description: "Timestamp granularities to return." },
		diarize: { description: "Identify speakers in the transcription." },
		contextBias: { description: "Vocabulary and context to guide transcription." },
		targetStreamingDelayMs: { description: "Target transcription delay in milliseconds. Realtime only." },
		speakerReferences: { description: "Named audio clips for known speakers. Realtime only." },
		turnDetection: { description: "Turn detection settings. Realtime only." }
	},
	speech: {
		refAudio: { description: "Reference audio for voice cloning, overriding voice." },
		expressiveness: { description: "Speech expressiveness, from 1 to 5." },
		phonemeHints: { description: "Pronunciation hints as IPA phonemes." }
	}
};
const languageModelDefinitions = {
	"labs-leanstral-1-5": true,
	"magistral-medium-latest": true,
	"magistral-small-latest": true,
	"ministral-14b-latest": true,
	"ministral-8b-latest": true,
	"mistral-large-latest": true,
	"mistral-medium-latest": true,
	"mistral-small-latest": true,
	"voxtral-small-latest": false,
	"zai-glm-5-2": false,
	"codestral-2508": void 0,
	"codestral-latest": void 0,
	"glm-5-2": void 0,
	"labs-leanstral-1-5-1": void 0,
	"ministral-14b-2512": void 0,
	"ministral-3b-2512": void 0,
	"ministral-3b-latest": void 0,
	"ministral-8b-2512": void 0,
	"mistral-code-fim-latest": void 0,
	"mistral-code-latest": void 0,
	"mistral-large-2512": void 0,
	"mistral-large-4": void 0,
	"mistral-large-4-0": void 0,
	"mistral-medium": void 0,
	"mistral-medium-2604": void 0,
	"mistral-medium-3": void 0,
	"mistral-medium-3-5": void 0,
	"mistral-medium-3.5": void 0,
	"mistral-small-2603": void 0,
	"mistral-vibe-cli-fast": void 0,
	"mistral-vibe-cli-latest": void 0,
	"mistral-vibe-cli-with-tools": void 0,
	"voxtral-small-2507": void 0,
	"zai-glm-5": void 0,
	"zai-glm-5-3": void 0,
	"zai-glm-5-3-flash": void 0,
	"zai-glm-latest": void 0
};
const modelsWithoutReasoningEffort = /* @__PURE__ */ new Set([
	"codestral-2508",
	"codestral-latest",
	"ministral-14b-2512",
	"ministral-14b-latest",
	"ministral-3b-2512",
	"ministral-3b-latest",
	"ministral-8b-2512",
	"ministral-8b-latest",
	"mistral-code-fim-latest",
	"mistral-code-latest",
	"mistral-large-latest",
	"mistral-large-2512",
	"voxtral-small-2507",
	"voxtral-small-latest"
]);
const modelsWithLowHighMaxReasoningEffort = /* @__PURE__ */ new Set([
	"zai-glm-5",
	"zai-glm-5-3",
	"zai-glm-5-3-flash",
	"zai-glm-latest"
]);
const modelsWithLowMediumHighReasoningEffort = /* @__PURE__ */ new Set(["mistral-large-4", "mistral-large-4-0"]);
const reasoningEffortModelIds = /* @__PURE__ */ new Set([
	"glm-5-2",
	"labs-leanstral-1-5",
	"labs-leanstral-1-5-1",
	"magistral-medium-latest",
	"magistral-small-latest",
	"mistral-large-4",
	"mistral-large-4-0",
	"mistral-medium",
	"mistral-medium-2604",
	"mistral-medium-3",
	"mistral-medium-3-5",
	"mistral-medium-3.5",
	"mistral-medium-latest",
	"mistral-small-2603",
	"mistral-small-latest",
	"mistral-vibe-cli-fast",
	"mistral-vibe-cli-latest",
	"mistral-vibe-cli-with-tools",
	"zai-glm-5-2"
]);
function reasoningCapabilities(efforts) {
	return {
		support: efforts.length > 0,
		efforts
	};
}
function createLanguageModelEntry(modelId, image) {
	const reasoning = reasoningCapabilities(modelsWithoutReasoningEffort.has(modelId) ? [] : modelsWithLowHighMaxReasoningEffort.has(modelId) ? [
		"low",
		"high",
		"max"
	] : modelsWithLowMediumHighReasoningEffort.has(modelId) ? [
		"low",
		"medium",
		"high"
	] : ["none", "high"]);
	const conversationReasoning = reasoningCapabilities(reasoningEffortModelIds.has(modelId) ? ["none", "high"] : []);
	const chatOnly = { condition: "Only supported on the Chat API." };
	return {
		capabilities: { language: {
			inputs: {
				image: image ?? "unknown",
				audio: "unknown"
			},
			objectGeneration: image != null ? true : "unknown",
			tools: {
				usage: image != null ? true : "unknown",
				streaming: image != null ? true : "unknown"
			},
			reasoning,
			sampling: {
				temperature: "unknown",
				topP: "unknown",
				logprobs: false
			},
			endpoints: { conversation: { reasoning: conversationReasoning } }
		} },
		providerOptions: { language: declareProviderOptions(mistralProviderOptions.language, image != null ? true : "unknown", {
			safePrompt: chatOnly,
			documentImageLimit: chatOnly,
			documentPageLimit: chatOnly,
			parallelToolCalls: chatOnly,
			promptCacheKey: chatOnly,
			reasoningEffort: reasoning.support && !conversationReasoning.support ? chatOnly : reasoning.support
		}) }
	};
}
function createTranscriptionModelEntry(modelId, declared) {
	const languageWithTimestamps = ![
		"voxtral-mini-2507",
		"voxtral-mini-2602",
		"voxtral-mini-latest"
	].includes(modelId);
	const support = declared ? true : "unknown";
	return {
		capabilities: { transcription: {
			transcription: support,
			streaming: false,
			duration: support,
			segments: support,
			language: support,
			languageWithTimestamps,
			timestamps: support,
			diarization: support,
			contextBias: support
		} },
		providerOptions: { transcription: declareProviderOptions(mistralProviderOptions.transcription, support, {
			targetStreamingDelayMs: false,
			speakerReferences: false,
			turnDetection: false,
			returnLanguage: { condition: "Only supported when language is not pinned." },
			timestampGranularities: languageWithTimestamps ? support : { condition: "Only supported when language is not pinned." }
		}) }
	};
}
function createSpeechModelEntry(declared) {
	const support = declared ? true : "unknown";
	return {
		capabilities: { speech: {
			instructions: false,
			savedVoices: support,
			referenceAudio: support,
			nonStreaming: true,
			outputFormats: [
				"pcm",
				"wav",
				"mp3",
				"flac",
				"opus"
			]
		} },
		providerOptions: { speech: declareProviderOptions(mistralProviderOptions.speech, support, {}) }
	};
}
function createEmbeddingModelEntry(defaultDimensions, customDimensions) {
	return {
		capabilities: { embedding: {
			defaultDimensions,
			customDimensions
		} },
		providerOptions: { embedding: declareProviderOptions(mistralProviderOptions.embedding, true, {
			outputDimension: customDimensions,
			outputDtype: customDimensions
		}) }
	};
}
const mistralEmbeddingModelEntries = {
	"mistral-embed": createEmbeddingModelEntry(1024, false),
	"codestral-embed": createEmbeddingModelEntry(1536, true),
	"codestral-embed-2505": void 0,
	"mistral-embed-2312": void 0
};
const mistralSpeechModelEntries = {
	"voxtral-mini-tts-3-0": createSpeechModelEntry(true),
	"voxtral-mini-tts-2603": createSpeechModelEntry(true),
	"voxtral-mini-tts-3": void 0,
	"voxtral-mini-tts-latest": void 0
};
const mistralTranscriptionModelEntries = {
	"voxtral-mini-transcribe-3-0": createTranscriptionModelEntry("voxtral-mini-transcribe-3-0", true),
	"voxtral-small-transcribe-3-0": createTranscriptionModelEntry("voxtral-small-transcribe-3-0", true),
	"voxtral-mini-latest": createTranscriptionModelEntry("voxtral-mini-latest", true),
	"voxtral-mini-2602": void 0,
	"voxtral-mini-transcribe-3": void 0,
	"voxtral-mini-transcribe-latest": void 0,
	"voxtral-mini-transcribe-realtime-3": void 0,
	"voxtral-mini-transcribe-realtime-3-0": void 0,
	"voxtral-small-transcribe-3": void 0,
	"voxtral-small-transcribe-latest": void 0
};
const mistralModelCatalog = Object.fromEntries(Object.entries({
	...Object.fromEntries(Object.entries(languageModelDefinitions).filter(([, definition]) => definition != null).map(([modelId, image]) => [modelId, createLanguageModelEntry(modelId, image)])),
	...mistralTranscriptionModelEntries,
	...mistralSpeechModelEntries,
	...mistralEmbeddingModelEntries
}).flatMap(([modelId, entry]) => entry != null ? [[modelId, entry]] : []));
function findModelEntry(modelId) {
	return Object.prototype.hasOwnProperty.call(mistralModelCatalog, modelId) ? mistralModelCatalog[modelId] : void 0;
}
function getMistralLanguageModelEntry(modelId) {
	const entry = findModelEntry(modelId);
	return entry?.capabilities.language != null && entry.providerOptions?.language != null ? {
		capabilities: { language: entry.capabilities.language },
		providerOptions: { language: entry.providerOptions.language }
	} : createLanguageModelEntry(modelId);
}
function getMistralTranscriptionModelEntry(modelId) {
	const capabilities = findModelEntry(modelId)?.capabilities.transcription;
	return capabilities != null ? { capabilities: { transcription: capabilities } } : createTranscriptionModelEntry(modelId, false);
}
function getMistralSpeechModelEntry(modelId) {
	const capabilities = findModelEntry(modelId)?.capabilities.speech;
	return capabilities != null ? { capabilities: { speech: capabilities } } : createSpeechModelEntry(false);
}
function declareProviderOptions(definitions, support, exceptions) {
	return Object.fromEntries(Object.keys(definitions).map((option) => [option, exceptions[option] ?? support]));
}
//#endregion
//#region src/mistral-chat-language-model.ts
var MistralChatLanguageModel = class MistralChatLanguageModel {
	static [WORKFLOW_SERIALIZE](model) {
		return serializeModelOptions({
			modelId: model.modelId,
			config: model.config
		});
	}
	static [WORKFLOW_DESERIALIZE](options) {
		return new MistralChatLanguageModel(options.modelId, options.config);
	}
	constructor(modelId, config) {
		this.specificationVersion = "v4";
		this.supportedUrls = { "application/pdf": [/^https:\/\/.*$/] };
		this.modelId = modelId;
		this.config = config;
		this.generateId = config.generateId ?? generateId;
	}
	get provider() {
		return this.config.provider;
	}
	async getArgs({ prompt, maxOutputTokens, temperature, topP, topK, frequencyPenalty, presencePenalty, reasoning, stopSequences, responseFormat, seed, providerOptions, tools, toolChoice }) {
		const warnings = [];
		const options = await parseProviderOptions({
			provider: "mistral",
			providerOptions,
			schema: mistralLanguageModelChatOptionsValidator
		}) ?? {};
		if (topK != null) warnings.push({
			type: "unsupported",
			feature: "topK"
		});
		const { reasoning: reasoningCapabilities } = getMistralLanguageModelEntry(this.modelId).capabilities.language;
		let resolvedReasoningEffort;
		if (reasoningCapabilities.support) resolvedReasoningEffort = mapReasoningToProviderEffort({
			reasoning,
			providerOptionsEffort: options.reasoningEffort,
			effortMap: Object.fromEntries(reasoningCapabilities.efforts.map((effort) => [effort, effort])),
			warnings
		});
		else if (isCustomReasoning(reasoning)) warnings.push({
			type: "unsupported",
			feature: "reasoning",
			details: "This model does not support reasoning configuration."
		});
		const structuredOutputs = options.structuredOutputs ?? true;
		const strictJsonSchema = options.strictJsonSchema ?? false;
		if (responseFormat?.type === "json" && (!structuredOutputs || responseFormat.schema == null)) prompt = injectJsonInstructionIntoMessages({
			messages: prompt,
			schema: responseFormat.schema
		});
		const baseArgs = {
			model: this.modelId,
			safe_prompt: options.safePrompt,
			max_tokens: maxOutputTokens,
			temperature,
			top_p: topP,
			...frequencyPenalty != null ? { frequency_penalty: frequencyPenalty } : {},
			...presencePenalty != null ? { presence_penalty: presencePenalty } : {},
			stop: stopSequences,
			random_seed: seed,
			reasoning_effort: resolvedReasoningEffort,
			response_format: 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" } : void 0,
			document_image_limit: options.documentImageLimit,
			document_page_limit: options.documentPageLimit,
			...options.promptCacheKey !== void 0 ? { prompt_cache_key: options.promptCacheKey } : {},
			messages: convertToMistralChatMessages(prompt)
		};
		const { tools: mistralTools, toolChoice: mistralToolChoice, toolWarnings } = prepareTools({
			tools,
			toolChoice
		});
		return {
			args: {
				...baseArgs,
				tools: mistralTools,
				tool_choice: mistralToolChoice,
				...mistralTools != null && options.parallelToolCalls !== void 0 ? { parallel_tool_calls: options.parallelToolCalls } : {}
			},
			warnings: [...warnings, ...toolWarnings]
		};
	}
	async doGenerate(options) {
		const { args: body, warnings } = await this.getArgs(options);
		const { responseHeaders, value: response, rawValue: rawResponse } = await postJsonToApi({
			url: `${this.config.baseURL}/chat/completions`,
			headers: combineHeaders(await resolve(this.config.headers), options.headers),
			body,
			failedResponseHandler: mistralFailedResponseHandler,
			successfulResponseHandler: createJsonResponseHandler(mistralChatResponseSchema),
			abortSignal: options.abortSignal,
			fetch: this.config.fetch
		});
		const choice = response.choices[0];
		const content = [];
		if (choice.message.content != null && Array.isArray(choice.message.content)) {
			for (const part of choice.message.content) if (part.type === "thinking") {
				const reasoningText = extractReasoningContent(part.thinking);
				if (reasoningText.length > 0) content.push({
					type: "reasoning",
					text: reasoningText
				});
			} else if (part.type === "text") {
				if (part.text.length > 0) content.push({
					type: "text",
					text: part.text
				});
			}
		} else {
			const text = extractTextContent(choice.message.content);
			if (text != null && text.length > 0) content.push({
				type: "text",
				text
			});
		}
		if (choice.message.tool_calls != null) for (const toolCall of choice.message.tool_calls) content.push({
			type: "tool-call",
			toolCallId: toolCall.id,
			toolName: toolCall.function.name,
			input: toolCall.function.arguments
		});
		return {
			content,
			finishReason: {
				unified: mapMistralFinishReason(choice.finish_reason),
				raw: choice.finish_reason ?? void 0
			},
			usage: convertMistralUsage(response.usage),
			request: { body },
			response: {
				...getResponseMetadata(response),
				headers: responseHeaders,
				body: rawResponse
			},
			warnings
		};
	}
	async doStream(options) {
		const { args, warnings } = await this.getArgs(options);
		const body = {
			...args,
			stream: true
		};
		const { responseHeaders, value: response } = await postJsonToApi({
			url: `${this.config.baseURL}/chat/completions`,
			headers: combineHeaders(await resolve(this.config.headers), options.headers),
			body,
			failedResponseHandler: mistralFailedResponseHandler,
			successfulResponseHandler: createEventSourceResponseHandler(mistralChatChunkSchema),
			abortSignal: options.abortSignal,
			fetch: this.config.fetch
		});
		let finishReason = {
			unified: "interrupted",
			raw: void 0
		};
		let usage = void 0;
		let isFirstChunk = true;
		let activeText = false;
		let activeReasoningId = null;
		let toolCallTracker;
		const generateId = this.generateId;
		return {
			stream: response.pipeThrough(new TransformStream({
				start(controller) {
					toolCallTracker = new StreamingToolCallTracker(controller, { generateId });
					controller.enqueue({
						type: "stream-start",
						warnings
					});
				},
				transform(chunk, controller) {
					if (options.includeRawChunks) controller.enqueue({
						type: "raw",
						rawValue: chunk.rawValue
					});
					if (!chunk.success) {
						finishReason = {
							unified: "error",
							raw: void 0
						};
						controller.enqueue({
							type: "error",
							error: chunk.error
						});
						return;
					}
					const value = chunk.value;
					if (isFirstChunk) {
						isFirstChunk = false;
						controller.enqueue({
							type: "response-metadata",
							...getResponseMetadata(value)
						});
					}
					if (value.usage != null) usage = value.usage;
					const choice = value.choices[0];
					const delta = choice.delta;
					const textContent = extractTextContent(delta.content);
					if (delta.content != null && Array.isArray(delta.content)) {
						for (const part of delta.content) if (part.type === "thinking") {
							const reasoningDelta = extractReasoningContent(part.thinking);
							if (reasoningDelta.length > 0) {
								if (activeReasoningId == null) {
									if (activeText) {
										controller.enqueue({
											type: "text-end",
											id: "0"
										});
										activeText = false;
									}
									activeReasoningId = generateId();
									controller.enqueue({
										type: "reasoning-start",
										id: activeReasoningId
									});
								}
								controller.enqueue({
									type: "reasoning-delta",
									id: activeReasoningId,
									delta: reasoningDelta
								});
							}
						}
					}
					if (textContent != null && textContent.length > 0) {
						if (!activeText) {
							if (activeReasoningId != null) {
								controller.enqueue({
									type: "reasoning-end",
									id: activeReasoningId
								});
								activeReasoningId = null;
							}
							controller.enqueue({
								type: "text-start",
								id: "0"
							});
							activeText = true;
						}
						controller.enqueue({
							type: "text-delta",
							id: "0",
							delta: textContent
						});
					}
					if (delta?.tool_calls != null) for (const toolCall of delta.tool_calls) toolCallTracker.processDelta(toolCall);
					if (choice.finish_reason != null) finishReason = {
						unified: mapMistralFinishReason(choice.finish_reason),
						raw: choice.finish_reason
					};
				},
				flush(controller) {
					if (activeReasoningId != null) controller.enqueue({
						type: "reasoning-end",
						id: activeReasoningId
					});
					if (activeText) controller.enqueue({
						type: "text-end",
						id: "0"
					});
					toolCallTracker.flush();
					controller.enqueue({
						type: "finish",
						finishReason,
						usage: convertMistralUsage(usage)
					});
				}
			})),
			request: { body },
			response: { headers: responseHeaders }
		};
	}
};
function extractReasoningContent(thinking) {
	return thinking.filter((chunk) => chunk.type === "text").map((chunk) => chunk.text).join("");
}
function extractTextContent(content) {
	if (typeof content === "string") return content;
	if (content == null) return;
	const textContent = [];
	for (const chunk of content) {
		const { type } = chunk;
		switch (type) {
			case "text":
				textContent.push(chunk.text);
				break;
			case "thinking":
			case "image_url":
			case "reference": break;
			default: throw new Error(`Unsupported type: ${type}`);
		}
	}
	return textContent.length ? textContent.join("") : void 0;
}
const mistralContentSchema = () => z.union([z.string(), z.array(z.discriminatedUnion("type", [
	z.object({
		type: z.literal("text"),
		text: z.string()
	}),
	z.object({
		type: z.literal("image_url"),
		image_url: z.union([z.string(), z.object({
			url: z.string(),
			detail: z.string().nullable()
		})])
	}),
	z.object({
		type: z.literal("reference"),
		reference_ids: z.array(z.union([z.string(), z.number()]))
	}),
	z.object({
		type: z.literal("thinking"),
		thinking: z.array(z.object({
			type: z.literal("text"),
			text: z.string()
		}))
	})
]))]).nullish();
const mistralChatResponseSchema = lazySchema(() => zodSchema(z.object({
	id: z.string().nullish(),
	created: z.number().nullish(),
	model: z.string().nullish(),
	choices: z.array(z.object({
		message: z.object({
			role: z.literal("assistant"),
			content: mistralContentSchema(),
			tool_calls: z.array(z.object({
				id: z.string(),
				function: z.object({
					name: z.string(),
					arguments: z.string()
				})
			})).nullish()
		}),
		index: z.number(),
		finish_reason: z.string().nullish()
	})),
	object: z.literal("chat.completion"),
	usage: mistralUsageSchema
})));
const mistralChatChunkSchema = lazySchema(() => zodSchema(z.object({
	id: z.string().nullish(),
	created: z.number().nullish(),
	model: z.string().nullish(),
	choices: z.array(z.object({
		delta: z.object({
			role: z.enum(["assistant"]).optional(),
			content: mistralContentSchema(),
			tool_calls: z.array(z.object({
				index: z.number().nullish(),
				id: z.string().nullish(),
				function: z.object({
					name: z.string().nullish(),
					arguments: z.string().nullish()
				})
			})).nullish()
		}),
		finish_reason: z.string().nullish(),
		index: z.number()
	})),
	usage: mistralUsageSchema.nullish()
})));
//#endregion
//#region src/convert-to-mistral-conversation-inputs.ts
function convertToMistralConversationInputs(prompt, toolNameMapping) {
	const inputs = [];
	const instructions = [];
	const executions = /* @__PURE__ */ new Set();
	const appendToolResult = (part) => {
		if (executions.has(part.toolCallId)) {
			let result = null;
			if (part.output.type === "json") {
				const value = part.output.value;
				const info = value != null && typeof value === "object" && "info" in value ? value.info : void 0;
				if (info != null && typeof info === "object" && !Array.isArray(info)) result = "result" in info ? info.result ?? info : info;
			}
			inputs.push({
				type: "function.result",
				tool_call_id: part.toolCallId,
				result: typeof result === "string" ? result : stringifyWithBigIntAndCycles(result)
			});
			return;
		}
		const converted = convertToMistralChatMessages([{
			role: "tool",
			content: [part]
		}])[0];
		inputs.push({
			type: "function.result",
			tool_call_id: part.toolCallId,
			result: converted.content
		});
	};
	for (const message of prompt) switch (message.role) {
		case "system":
			instructions.push(message.content);
			break;
		case "user": {
			const converted = convertToMistralChatMessages([message])[0];
			if (converted.role === "user") inputs.push({
				type: "message.input",
				role: "user",
				content: converted.content
			});
			break;
		}
		case "assistant": {
			let content = [];
			const flush = () => {
				if (content.length > 0) {
					inputs.push({
						type: "message.input",
						role: "assistant",
						content
					});
					content = [];
				}
			};
			for (const part of message.content) switch (part.type) {
				case "text":
					content.push({
						type: "text",
						text: part.text
					});
					break;
				case "reasoning":
					content.push({
						type: "thinking",
						thinking: [{
							type: "text",
							text: part.text
						}],
						closed: true
					});
					break;
				case "tool-call":
					flush();
					if (part.providerExecuted) {
						const name = part.providerOptions?.mistral?.function ?? part.providerOptions?.mistral?.name;
						const args = part.input;
						inputs.push({
							type: "function.call",
							tool_call_id: part.toolCallId,
							name: typeof name === "string" ? name : toolNameMapping.toProviderToolName(part.toolName),
							arguments: typeof args?.arguments === "string" ? args.arguments : serializeMistralToolCallArguments(part.input)
						});
						executions.add(part.toolCallId);
					} else inputs.push({
						type: "function.call",
						tool_call_id: part.toolCallId,
						name: part.toolName,
						arguments: serializeMistralToolCallArguments(part.input)
					});
					break;
				case "tool-result":
					flush();
					appendToolResult(part);
					break;
				default: throw new UnsupportedFunctionalityError({ functionality: `assistant content type: ${part.type}` });
			}
			flush();
			break;
		}
		case "tool": for (const part of message.content) {
			if (part.type === "tool-approval-response") continue;
			appendToolResult(part);
		}
	}
	return {
		inputs,
		instructions: instructions.length > 0 ? instructions.join("\n\n") : void 0
	};
}
//#endregion
//#region src/mistral-conversation-language-model-options.ts
const mistralLanguageModelConversationOptions = lazySchema(() => zodSchema(mistralLanguageModelChatOptions()));
//#endregion
//#region src/mistral-conversation-prepare-tools.ts
const mistralProviderToolNames = {
	"mistral.web_search": "web_search",
	"mistral.web_search_premium": "web_search_premium"
};
function prepareConversationTools({ tools, toolChoice }) {
	tools = tools?.length ? tools : void 0;
	const toolWarnings = [];
	if (tools == null) return {
		tools: void 0,
		toolChoice: void 0,
		toolWarnings
	};
	const mistralTools = [];
	for (const tool of tools) if (tool.type === "provider") {
		if (tool.id === "mistral.web_search" || tool.id === "mistral.web_search_premium") {
			mistralTools.push({ type: mistralProviderToolNames[tool.id] });
			continue;
		}
		toolWarnings.push({
			type: "unsupported",
			feature: `provider-defined tool ${tool.id}`
		});
	} else mistralTools.push({
		type: "function",
		function: {
			name: tool.name,
			description: tool.description,
			parameters: tool.inputSchema,
			...tool.strict != null ? { strict: tool.strict } : {}
		}
	});
	if (toolChoice == null) return {
		tools: mistralTools,
		toolChoice: void 0,
		toolWarnings
	};
	const type = toolChoice.type;
	switch (type) {
		case "auto":
		case "none": return {
			tools: mistralTools,
			toolChoice: type,
			toolWarnings
		};
		case "required": return {
			tools: mistralTools,
			toolChoice: "any",
			toolWarnings
		};
		case "tool": {
			const toolName = createToolNameMapping({
				tools,
				providerToolNames: mistralProviderToolNames
			}).toProviderToolName(toolChoice.toolName);
			return {
				tools: mistralTools.filter((tool) => tool.type === "function" ? tool.function.name === toolName : tool.type === toolName),
				toolChoice: "any",
				toolWarnings
			};
		}
		default: throw new UnsupportedFunctionalityError({ functionality: `tool choice type: ${type}` });
	}
}
//#endregion
//#region src/mistral-conversation-language-model.ts
var MistralConversationLanguageModel = class MistralConversationLanguageModel {
	static [WORKFLOW_SERIALIZE](model) {
		return serializeModelOptions({
			modelId: model.modelId,
			config: model.config
		});
	}
	static [WORKFLOW_DESERIALIZE](options) {
		return new MistralConversationLanguageModel(options.modelId, options.config);
	}
	constructor(modelId, config) {
		this.specificationVersion = "v4";
		this.supportedUrls = { "application/pdf": [/^https:\/\/.*$/] };
		this.modelId = modelId;
		this.config = config;
		this.generateId = config.generateId ?? generateId;
	}
	get provider() {
		return this.config.provider;
	}
	async getArgs({ prompt, maxOutputTokens, temperature, topP, topK, frequencyPenalty, presencePenalty, reasoning, stopSequences, responseFormat, seed, providerOptions, tools, toolChoice }) {
		const warnings = [];
		const options = await parseProviderOptions({
			provider: "mistral",
			providerOptions,
			schema: mistralLanguageModelConversationOptions
		}) ?? {};
		if (topK != null) warnings.push({
			type: "unsupported",
			feature: "topK"
		});
		const { reasoning: reasoningCapabilities } = getMistralLanguageModelEntry(this.modelId).capabilities.language.endpoints.conversation;
		let resolvedReasoningEffort;
		if (reasoningCapabilities.support) resolvedReasoningEffort = mapReasoningToProviderEffort({
			reasoning,
			providerOptionsEffort: options.reasoningEffort,
			effortMap: Object.fromEntries(reasoningCapabilities.efforts.map((effort) => [effort, effort])),
			warnings
		});
		else if (isCustomReasoning(reasoning)) warnings.push({
			type: "unsupported",
			feature: "reasoning",
			details: "This model does not support reasoning configuration."
		});
		const structuredOutputs = options.structuredOutputs ?? true;
		const strictJsonSchema = options.strictJsonSchema ?? false;
		if (responseFormat?.type === "json" && (!structuredOutputs || responseFormat.schema == null)) prompt = injectJsonInstructionIntoMessages({
			messages: prompt,
			schema: responseFormat.schema
		});
		const baseArgs = {
			max_tokens: maxOutputTokens,
			temperature,
			top_p: topP,
			...frequencyPenalty != null ? { frequency_penalty: frequencyPenalty } : {},
			...presencePenalty != null ? { presence_penalty: presencePenalty } : {},
			stop: stopSequences,
			random_seed: seed,
			reasoning_effort: resolvedReasoningEffort,
			response_format: 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" } : void 0
		};
		const { tools: mistralTools, toolChoice: mistralToolChoice, toolWarnings } = prepareConversationTools({
			tools,
			toolChoice
		});
		for (const [feature, value] of Object.entries({
			safePrompt: options.safePrompt,
			documentImageLimit: options.documentImageLimit,
			documentPageLimit: options.documentPageLimit,
			promptCacheKey: options.promptCacheKey,
			parallelToolCalls: options.parallelToolCalls
		})) if (value != null) warnings.push({
			type: "unsupported",
			feature,
			details: "Not supported by the Mistral Conversations API."
		});
		return {
			args: {
				model: this.modelId,
				store: false,
				...convertToMistralConversationInputs(prompt, createToolNameMapping({
					tools,
					providerToolNames: mistralProviderToolNames
				})),
				tools: mistralTools,
				completion_args: {
					...baseArgs,
					tool_choice: mistralToolChoice
				}
			},
			warnings: [...warnings, ...toolWarnings]
		};
	}
	async doGenerate(options) {
		const { args: body, warnings } = await this.getArgs(options);
		const { value: response, rawValue: rawResponse, responseHeaders } = await postJsonToApi({
			url: `${this.config.baseURL}/conversations`,
			headers: combineHeaders(await resolve(this.config.headers), options.headers),
			body,
			failedResponseHandler: mistralFailedResponseHandler,
			successfulResponseHandler: createJsonResponseHandler(mistralConversationResponseSchema),
			abortSignal: options.abortSignal,
			fetch: this.config.fetch
		});
		const converter = createContentConverter({
			tools: options.tools,
			generateId: this.generateId
		});
		const content = [];
		let hasFunctionCalls = false;
		let modelId;
		for (const output of response.outputs) switch (output.type) {
			case "tool.execution":
				content.push(...converter.convertTool(output));
				break;
			case "function.call":
				hasFunctionCalls = true;
				content.push({
					type: "tool-call",
					toolCallId: output.tool_call_id,
					toolName: output.name,
					input: typeof output.arguments === "string" ? output.arguments : JSON.stringify(output.arguments)
				});
				break;
			case "message.output":
				modelId = output.model ?? modelId;
				for (const chunk of typeof output.content === "string" ? [{
					type: "text",
					text: output.content
				}] : output.content) content.push(...converter.convertChunk(chunk));
		}
		return {
			content,
			finishReason: {
				unified: hasFunctionCalls ? "tool-calls" : "stop",
				raw: void 0
			},
			usage: convertMistralUsage(response.usage),
			request: { body },
			response: {
				id: response.conversation_id,
				modelId,
				headers: responseHeaders,
				body: rawResponse
			},
			warnings
		};
	}
	async doStream(options) {
		const { args, warnings } = await this.getArgs(options);
		const body = {
			...args,
			stream: true
		};
		const { value: response, responseHeaders } = await postJsonToApi({
			url: `${this.config.baseURL}/conversations`,
			headers: combineHeaders(await resolve(this.config.headers), options.headers),
			body,
			failedResponseHandler: mistralFailedResponseHandler,
			successfulResponseHandler: createEventSourceResponseHandler(mistralConversationChunkSchema),
			abortSignal: options.abortSignal,
			fetch: this.config.fetch
		});
		const converter = createContentConverter({
			tools: options.tools,
			generateId: this.generateId
		});
		const executions = /* @__PURE__ */ new Map();
		let toolCallTracker;
		let active;
		let usage;
		let hasFunctionCalls = false;
		let hasError = false;
		let isDone = false;
		let hasModelId = false;
		const closeContent = (controller) => {
			if (active != null) {
				controller.enqueue({
					type: active.type === "text" ? "text-end" : "reasoning-end",
					id: active.id
				});
				active = void 0;
			}
		};
		const generateId = this.generateId;
		return {
			stream: response.pipeThrough(new TransformStream({
				start(controller) {
					toolCallTracker = new StreamingToolCallTracker(controller, { generateId });
					controller.enqueue({
						type: "stream-start",
						warnings
					});
				},
				transform(chunk, controller) {
					if (options.includeRawChunks) controller.enqueue({
						type: "raw",
						rawValue: chunk.rawValue
					});
					if (!chunk.success) {
						hasError = true;
						controller.enqueue({
							type: "error",
							error: chunk.error
						});
						return;
					}
					const event = chunk.value;
					switch (event.type) {
						case "conversation.response.started":
							controller.enqueue({
								type: "response-metadata",
								id: event.conversation_id,
								...event.created_at != null ? { timestamp: new Date(event.created_at) } : {}
							});
							break;
						case "conversation.response.done":
							usage = event.usage ?? void 0;
							isDone = true;
							break;
						case "conversation.response.error":
							hasError = true;
							controller.enqueue({
								type: "error",
								error: event
							});
							break;
						case "message.output.delta":
							if (!hasModelId && event.model != null) {
								hasModelId = true;
								controller.enqueue({
									type: "response-metadata",
									modelId: event.model
								});
							}
							for (const part of converter.convertChunk(typeof event.content === "string" ? {
								type: "text",
								text: event.content
							} : event.content)) if (part.type === "text" || part.type === "reasoning") {
								const id = `${event.id}-${event.content_index ?? 0}`;
								if (active?.id !== id || active.type !== part.type) {
									closeContent(controller);
									active = {
										id,
										type: part.type
									};
									controller.enqueue({
										type: part.type === "text" ? "text-start" : "reasoning-start",
										id
									});
								}
								controller.enqueue({
									type: part.type === "text" ? "text-delta" : "reasoning-delta",
									id,
									delta: part.text
								});
							} else if (part.type === "source") controller.enqueue(part);
							break;
						case "function.call.delta":
							closeContent(controller);
							hasFunctionCalls = true;
							toolCallTracker.processDelta({
								id: event.tool_call_id,
								index: event.output_index,
								function: {
									name: event.name,
									arguments: event.arguments
								}
							});
							break;
						case "tool.execution.started":
						case "tool.execution.delta": {
							closeContent(controller);
							const execution = executions.get(event.id);
							if (execution == null) {
								executions.set(event.id, {
									name: event.name,
									arguments: event.arguments,
									function: event.function
								});
								controller.enqueue({
									type: "tool-input-start",
									id: event.id,
									toolName: converter.toolNameMapping.toCustomToolName(event.name),
									providerExecuted: true
								});
							} else execution.arguments += event.arguments;
							break;
						}
						case "tool.execution.done": {
							const execution = executions.get(event.id);
							if (execution == null) {
								hasError = true;
								controller.enqueue({
									type: "error",
									error: /* @__PURE__ */ new Error(`Missing tool execution start for ${event.id}`)
								});
								break;
							}
							controller.enqueue({
								type: "tool-input-delta",
								id: event.id,
								delta: JSON.stringify({ arguments: execution.arguments })
							});
							controller.enqueue({
								type: "tool-input-end",
								id: event.id
							});
							for (const part of converter.convertTool({
								type: "tool.execution",
								id: event.id,
								name: execution.name,
								arguments: execution.arguments,
								function: event.function ?? execution.function,
								info: event.info
							})) controller.enqueue(part);
							executions.delete(event.id);
							break;
						}
					}
				},
				flush(controller) {
					closeContent(controller);
					toolCallTracker.flush();
					controller.enqueue({
						type: "finish",
						finishReason: {
							unified: hasError || !isDone || executions.size > 0 ? "error" : hasFunctionCalls ? "tool-calls" : "stop",
							raw: void 0
						},
						usage: convertMistralUsage(usage)
					});
				}
			})),
			request: { body },
			response: { headers: responseHeaders }
		};
	}
};
function createContentConverter({ tools, generateId }) {
	const toolNameMapping = createToolNameMapping({
		tools,
		providerToolNames: mistralProviderToolNames
	});
	const sourceUrls = /* @__PURE__ */ new Set();
	return {
		toolNameMapping,
		convertChunk(chunk) {
			switch (chunk.type) {
				case "text": return chunk.text.length > 0 ? [{
					type: "text",
					text: chunk.text
				}] : [];
				case "thinking": {
					const text = chunk.thinking.map((part) => part.text).join("");
					return text.length > 0 ? [{
						type: "reasoning",
						text
					}] : [];
				}
				case "tool_reference":
					if (chunk.url == null || sourceUrls.has(chunk.url)) return [];
					const id = generateId();
					sourceUrls.add(chunk.url);
					return [{
						type: "source",
						sourceType: "url",
						id,
						url: chunk.url,
						title: chunk.title ?? chunk.url
					}];
			}
		},
		convertTool(output) {
			const toolName = toolNameMapping.toCustomToolName(output.name);
			return [{
				type: "tool-call",
				toolCallId: output.id,
				toolName,
				input: JSON.stringify({ arguments: output.arguments }),
				providerExecuted: true,
				providerMetadata: { mistral: {
					type: "tool.execution",
					name: output.name,
					...output.function != null ? { function: output.function } : {}
				} }
			}, {
				type: "tool-result",
				toolCallId: output.id,
				toolName,
				result: { ...output.info != null ? { info: output.info } : {} }
			}];
		}
	};
}
const mistralConversationContentSchema = () => z.discriminatedUnion("type", [
	z.object({
		type: z.literal("text"),
		text: z.string()
	}),
	z.object({
		type: z.literal("thinking"),
		thinking: z.array(z.object({
			type: z.literal("text"),
			text: z.string()
		}))
	}),
	z.object({
		type: z.literal("tool_reference"),
		tool: z.string().nullish(),
		title: z.string().nullish(),
		url: z.string().nullish()
	})
]);
const mistralConversationMessageContentSchema = () => z.union([z.string(), z.array(mistralConversationContentSchema())]);
const mistralConversationToolExecutionSchema = () => z.object({
	type: z.literal("tool.execution"),
	id: z.string(),
	name: z.string(),
	arguments: z.string(),
	function: z.string().nullish(),
	info: z.record(z.string(), z.json()).nullish()
});
const mistralConversationFunctionCallSchema = () => z.object({
	type: z.literal("function.call"),
	tool_call_id: z.string(),
	name: z.string(),
	arguments: z.union([z.string(), z.record(z.string(), z.json())])
});
const mistralConversationUsageSchema = () => mistralUsageSchema.extend({
	prompt_tokens: z.number().default(0),
	completion_tokens: z.number().default(0),
	total_tokens: z.number().default(0)
});
const mistralConversationResponseSchema = lazySchema(() => zodSchema(z.object({
	conversation_id: z.string(),
	outputs: z.array(z.discriminatedUnion("type", [
		mistralConversationToolExecutionSchema(),
		mistralConversationFunctionCallSchema(),
		z.object({
			type: z.literal("message.output"),
			content: mistralConversationMessageContentSchema(),
			model: z.string().nullish()
		})
	])),
	usage: mistralConversationUsageSchema().nullish()
})));
const mistralConversationChunkSchema = lazySchema(() => zodSchema(z.discriminatedUnion("type", [
	z.object({
		type: z.literal("conversation.response.started"),
		conversation_id: z.string(),
		created_at: z.string().nullish()
	}),
	z.object({
		type: z.literal("conversation.response.done"),
		usage: mistralConversationUsageSchema().nullish()
	}),
	z.object({
		type: z.literal("conversation.response.error"),
		message: z.string(),
		code: z.number()
	}),
	z.object({
		type: z.literal("message.output.delta"),
		id: z.string(),
		content_index: z.number().nullish(),
		content: z.union([z.string(), mistralConversationContentSchema()]),
		model: z.string().nullish()
	}),
	z.object({
		type: z.literal("function.call.delta"),
		tool_call_id: z.string(),
		name: z.string(),
		arguments: z.string(),
		output_index: z.number().nullish()
	}),
	z.object({
		type: z.enum(["tool.execution.started", "tool.execution.delta"]),
		id: z.string(),
		name: z.string(),
		arguments: z.string(),
		function: z.string().nullish()
	}),
	z.object({
		type: z.literal("tool.execution.done"),
		id: z.string(),
		name: z.string(),
		function: z.string().nullish(),
		info: z.record(z.string(), z.json()).nullish()
	})
])));
//#endregion
//#region src/mistral-embedding-model-options.ts
const mistralEmbeddingModelOptions = z.object({
	/**
	* Additional metadata to attach to the embedding request.
	*/
	metadata: z.record(z.string(), z.any()).optional(),
	/**
	* The dimension of the output embeddings when supported by the model.
	*/
	outputDimension: z.number().int().positive().optional(),
	/**
	* The data type of the output embeddings when supported by the model.
	*/
	outputDtype: z.enum([
		"float",
		"int8",
		"uint8",
		"binary",
		"ubinary"
	]).optional()
});
//#endregion
//#region src/mistral-embedding-model.ts
var MistralEmbeddingModel = class MistralEmbeddingModel {
	get provider() {
		return this.config.provider;
	}
	static [WORKFLOW_SERIALIZE](model) {
		return serializeModelOptions({
			modelId: model.modelId,
			config: model.config
		});
	}
	static [WORKFLOW_DESERIALIZE](options) {
		return new MistralEmbeddingModel(options.modelId, options.config);
	}
	constructor(modelId, config) {
		this.specificationVersion = "v4";
		this.maxEmbeddingsPerCall = 32;
		this.supportsParallelCalls = false;
		this.modelId = modelId;
		this.config = config;
	}
	async doEmbed({ values, dimensions, abortSignal, headers, providerOptions }) {
		if (values.length > this.maxEmbeddingsPerCall) throw new TooManyEmbeddingValuesForCallError({
			provider: this.provider,
			modelId: this.modelId,
			maxEmbeddingsPerCall: this.maxEmbeddingsPerCall,
			values
		});
		const mistralOptions = await parseProviderOptions({
			provider: "mistral",
			providerOptions,
			schema: mistralEmbeddingModelOptions
		}) ?? {};
		const { responseHeaders, value: response, rawValue } = await postJsonToApi({
			url: `${this.config.baseURL}/embeddings`,
			headers: combineHeaders(await resolve(this.config.headers), headers),
			body: {
				model: this.modelId,
				input: values,
				metadata: mistralOptions.metadata,
				output_dimension: mistralOptions.outputDimension ?? dimensions,
				output_dtype: mistralOptions.outputDtype,
				encoding_format: "float"
			},
			failedResponseHandler: mistralFailedResponseHandler,
			successfulResponseHandler: createJsonResponseHandler(MistralTextEmbeddingResponseSchema),
			abortSignal,
			fetch: this.config.fetch
		});
		return {
			warnings: [],
			embeddings: response.data.map((item) => item.embedding),
			usage: response.usage ? { tokens: response.usage.prompt_tokens } : void 0,
			response: {
				headers: responseHeaders,
				body: rawValue
			}
		};
	}
};
const MistralTextEmbeddingResponseSchema = lazySchema(() => zodSchema(z.object({
	data: z.array(z.object({ embedding: z.array(z.number()) })),
	usage: z.object({ prompt_tokens: z.number() }).nullish()
})));
//#endregion
//#region src/mistral-speech-model-options.ts
const mistralSpeechModelOptions = lazySchema(() => zodSchema(z.object({
	/**
	* Base64-encoded reference audio for one-off voice cloning.
	*
	* When provided, this takes precedence over the standard `voice` option.
	*/
	refAudio: z.string().min(1).optional(),
	/**
	* How expressive the speech is, from 1 to 5. Higher values trade voice
	* similarity and stability for stronger delivery. Supported by Voxtral 3.
	*/
	expressiveness: z.number().min(1).max(5).optional(),
	/**
	* Pronunciation hints mapping words to lists of IPA phonemes.
	* Supported by Voxtral 3.
	*/
	phonemeHints: z.record(z.string().min(1), z.array(z.string().min(1)).min(1)).optional()
})));
//#endregion
//#region src/mistral-speech-model.ts
var MistralSpeechModel = class MistralSpeechModel {
	static [WORKFLOW_SERIALIZE](model) {
		return serializeModelOptions({
			modelId: model.modelId,
			config: model.config
		});
	}
	static [WORKFLOW_DESERIALIZE](options) {
		return new MistralSpeechModel(options.modelId, options.config);
	}
	get provider() {
		return this.config.provider;
	}
	constructor(modelId, config) {
		this.modelId = modelId;
		this.config = config;
		this.specificationVersion = "v4";
	}
	async getArgs({ text, voice, outputFormat = "mp3", instructions, speed, language, providerOptions }) {
		const warnings = [];
		const mistralOptions = await parseProviderOptions({
			provider: "mistral",
			providerOptions,
			schema: mistralSpeechModelOptions
		});
		const { speech } = getMistralSpeechModelEntry(this.modelId).capabilities;
		let responseFormat = "mp3";
		if (speech.outputFormats.includes(outputFormat)) responseFormat = outputFormat;
		else warnings.push({
			type: "unsupported",
			feature: "outputFormat",
			details: `Unsupported output format: ${outputFormat}. Using mp3 instead.`
		});
		if (speech.instructions === false && instructions != null) warnings.push({
			type: "unsupported",
			feature: "instructions",
			details: "Mistral speech models do not support the `instructions` option. Use a reference audio clip to guide delivery."
		});
		if (speed != null) warnings.push({
			type: "unsupported",
			feature: "speed",
			details: "Mistral speech models do not support the `speed` option. It was ignored."
		});
		if (language != null) warnings.push({
			type: "unsupported",
			feature: "language",
			details: "Mistral speech models do not support the `language` option. Language is inferred from the input text and voice."
		});
		const refAudio = mistralOptions?.refAudio;
		const requestBody = {
			model: this.modelId,
			input: text,
			voice_id: refAudio == null ? voice : void 0,
			ref_audio: refAudio,
			expressiveness: mistralOptions?.expressiveness,
			phoneme_hints: mistralOptions?.phonemeHints,
			response_format: responseFormat,
			stream: false
		};
		return {
			requestBody,
			requestBodyValues: {
				...requestBody,
				ref_audio: refAudio == null ? void 0 : "[redacted]"
			},
			warnings
		};
	}
	async doGenerate(options) {
		const currentDate = this.config._internal?.currentDate?.() ?? /* @__PURE__ */ new Date();
		const { requestBody, requestBodyValues, warnings } = await this.getArgs(options);
		const { value: response, responseHeaders, rawValue: rawResponse } = await postToApi({
			url: `${this.config.baseURL}/audio/speech`,
			headers: combineHeaders({ "Content-Type": "application/json" }, await resolve(this.config.headers), options.headers),
			body: {
				content: JSON.stringify(requestBody),
				values: requestBodyValues
			},
			failedResponseHandler: mistralFailedResponseHandler,
			successfulResponseHandler: createJsonResponseHandler(mistralSpeechResponseSchema),
			abortSignal: options.abortSignal,
			fetch: this.config.fetch
		});
		return {
			audio: response.audio_data,
			warnings,
			request: { body: JSON.stringify(requestBodyValues) },
			response: {
				timestamp: currentDate,
				modelId: this.modelId,
				headers: responseHeaders,
				body: rawResponse
			}
		};
	}
};
const mistralSpeechResponseSchema = lazySchema(() => zodSchema(z.object({ audio_data: z.string() })));
//#endregion
//#region src/mistral-transcription-model-options.ts
const mistralTranscriptionModelOptions = lazySchema(() => zodSchema(z.object({
	/**
	* The language of the audio, e.g. "en". Providing the language can boost
	* accuracy.
	*/
	language: z.string().min(1).optional(),
	/**
	* Return the detected language. Cannot be combined with `language`.
	*/
	returnLanguage: z.boolean().optional(),
	/**
	* The sampling temperature.
	*/
	temperature: z.number().optional(),
	/**
	* The timestamp granularities to include in the transcription response.
	* Voxtral 3 supports segment timestamps only.
	*/
	timestampGranularities: z.array(z.enum(["segment", "word"])).min(1).optional(),
	/**
	* Whether to identify speakers in the transcription.
	* Offline Voxtral 3 requires segment timestamps when diarization is enabled.
	* Realtime diarization cannot be combined with turn detection.
	*/
	diarize: z.boolean().optional(),
	/**
	* Words or phrases to guide the model toward correct spellings of names,
	* technical terms, or domain-specific vocabulary.
	*
	* Voxtral 3 also accepts phrases and descriptions of the recording,
	* including spaces and punctuation. Entries share the context window
	* with the audio.
	*/
	contextBias: z.array(z.string().min(1)).optional(),
	/** Realtime only. Delay in milliseconds: 80–1200, or 2400. */
	targetStreamingDelayMs: z.union([z.number().int().min(80).max(1200), z.literal(2400)]).optional(),
	/**
	* Realtime only. Named base64-encoded audio clips for known speakers.
	* Requires diarize. Mistral accepts up to 8 clips of 3–15 seconds each.
	*/
	speakerReferences: z.record(z.string(), z.string().min(1)).optional(),
	/**
	* Realtime only. Enable turn detection with an empty object for defaults.
	* Turn events are available through includeRawChunks. Mistral validates
	* threshold ordering and compatibility with diarization.
	*/
	turnDetection: z.object({
		startThreshold: z.number().min(0).max(1).optional(),
		eagerEndThreshold: z.number().min(0).max(1).optional(),
		endThreshold: z.number().min(0).max(1).optional(),
		minSilenceMs: z.number().int().nonnegative().optional(),
		endTimeoutMs: z.number().int().nonnegative().optional()
	}).optional()
})));
//#endregion
//#region src/mistral-transcription-stream.ts
async function streamMistralTranscription({ modelId, baseURL, headers, webSocket, currentDate, ...options }) {
	const mistralOptions = await parseProviderOptions({
		provider: "mistral",
		providerOptions: options.providerOptions,
		schema: mistralTranscriptionModelOptions
	});
	const { type, rate = 16e3 } = options.inputAudioFormat;
	if (type !== "audio/pcm" || !Number.isInteger(rate) || rate <= 0) throw new InvalidArgumentError({
		argument: "inputAudioFormat",
		message: "Mistral realtime transcription requires audio/pcm (mono, signed 16-bit little-endian) with a positive integer sample rate."
	});
	const warnings = [];
	for (const option of [
		"returnLanguage",
		"temperature",
		"timestampGranularities"
	]) if (mistralOptions?.[option] != null) warnings.push({
		type: "unsupported",
		feature: `providerOptions.mistral.${option}`,
		details: "This option is not supported for realtime transcription."
	});
	const turnDetection = mistralOptions?.turnDetection;
	const session = {
		audio_format: {
			encoding: "pcm_s16le",
			sample_rate: rate
		},
		target_streaming_delay_ms: mistralOptions?.targetStreamingDelayMs,
		language: mistralOptions?.language,
		context_bias: mistralOptions?.contextBias,
		diarize: mistralOptions?.diarize,
		speaker_references: mistralOptions?.speakerReferences,
		turn_detection: turnDetection == null ? void 0 : {
			start_threshold: turnDetection.startThreshold,
			eager_end_threshold: turnDetection.eagerEndThreshold,
			end_threshold: turnDetection.endThreshold,
			min_silence_ms: turnDetection.minSilenceMs,
			end_timeout_ms: turnDetection.endTimeoutMs
		}
	};
	const url = toWebSocketUrl(`${baseURL}/audio/transcriptions/realtime`);
	url.searchParams.set("model", modelId);
	let finished = false;
	let cleanup = () => {};
	return {
		request: { body: url.toString() },
		response: {
			timestamp: currentDate,
			modelId
		},
		stream: new ReadableStream({
			start(controller) {
				let connection;
				let reader;
				let configured = false;
				let sending = false;
				const stop = new AbortController();
				cleanup = () => {
					stop.abort();
					(reader != null ? reader.cancel() : options.audio.cancel()).catch(() => {});
					connection?.close(1e3);
				};
				const fail = (error) => {
					if (finished) return;
					finished = true;
					cleanup();
					controller.error(error);
				};
				const sendAudio = async () => {
					const socket = connection.socket;
					reader = options.audio.getReader();
					try {
						while (true) {
							if (finished) break;
							const { done, value } = await reader.read();
							if (finished || done) break;
							const bytes = typeof value === "string" ? convertBase64ToUint8Array(value) : value;
							for (let offset = 0; offset < bytes.length; offset += 65536) {
								if (finished) break;
								socket.send(JSON.stringify({
									type: "input_audio.append",
									audio: convertUint8ArrayToBase64(bytes.subarray(offset, offset + 65536))
								}));
								await waitForWebSocketBufferDrain(socket, { abortSignal: stop.signal });
							}
						}
						if (!finished) socket.send(JSON.stringify({ type: "input_audio.end" }));
					} finally {
						reader.releaseLock();
						reader = void 0;
					}
				};
				controller.enqueue({
					type: "stream-start",
					warnings
				});
				connection = connectToWebSocket({
					url,
					headers,
					webSocket,
					abortSignal: options.abortSignal,
					onAbort: fail,
					onProcessingError: fail,
					onMessageText: async (text) => {
						if (finished) return;
						const parsed = await safeParseJSON({
							text,
							schema: eventEnvelopeSchema
						});
						if (finished) return;
						if (!parsed.success) throw parsed.error;
						const raw = parsed.value;
						if (options.includeRawChunks) controller.enqueue({
							type: "raw",
							rawValue: raw
						});
						if (!handledEvents.has(raw.type)) return;
						const validated = await safeValidateTypes({
							value: raw,
							schema: transcriptionEventSchema
						});
						if (finished) return;
						if (!validated.success) throw validated.error;
						const event = validated.value;
						switch (event.type) {
							case "session.created":
								if (configured) break;
								configured = true;
								connection.socket.send(JSON.stringify({
									type: "session.update",
									session
								}));
								break;
							case "session.updated":
								if (!configured || sending) break;
								sending = true;
								sendAudio().catch(fail);
								break;
							case "transcription.text.delta":
								controller.enqueue({
									type: "transcript-delta",
									delta: event.text
								});
								break;
							case "transcription.segment":
								controller.enqueue({
									type: "transcript-final",
									text: event.text,
									startSecond: event.start ?? void 0,
									endSecond: event.end ?? void 0,
									...event.speaker_id != null && { providerMetadata: { mistral: { speakerId: event.speaker_id } } }
								});
								break;
							case "transcription.done": {
								const segments = event.segments ?? [];
								controller.enqueue({
									type: "response-metadata",
									modelId: event.model ?? modelId,
									body: raw
								});
								controller.enqueue({
									type: "finish",
									text: event.text,
									segments: segments.flatMap((segment) => segment.start == null || segment.end == null ? [] : [{
										text: segment.text,
										startSecond: segment.start,
										endSecond: segment.end
									}]),
									language: event.language ?? void 0,
									durationInSeconds: typeof event.usage?.prompt_audio_seconds === "number" ? event.usage.prompt_audio_seconds : void 0,
									usage: event.usage ?? void 0,
									providerMetadata: { mistral: {
										...event.usage != null && { usage: event.usage },
										segments: segments.map((segment) => ({
											text: segment.text,
											...segment.start != null && { startSecond: segment.start },
											...segment.end != null && { endSecond: segment.end },
											...segment.speaker_id != null && { speakerId: segment.speaker_id }
										}))
									} }
								});
								finished = true;
								controller.close();
								cleanup();
								break;
							}
							case "error": fail(new Error(event.error.message));
						}
					},
					onSocketError: () => fail(/* @__PURE__ */ new Error("Mistral realtime transcription WebSocket error." + (webSocket == null ? " Pass a header-capable WebSocket implementation (e.g. ws) to createMistral({ webSocket }) to send the Authorization header." : ""))),
					onClose: ({ code, reason }) => fail(/* @__PURE__ */ new Error(`Mistral realtime transcription connection closed before transcription.done (code: ${code ?? "unknown"}${reason ? `, reason: ${reason}` : ""}).`))
				});
				if (finished) connection.close();
			},
			cancel() {
				if (finished) return;
				finished = true;
				cleanup();
			}
		})
	};
}
const handledEvents = /* @__PURE__ */ new Set([
	"session.created",
	"session.updated",
	"transcription.text.delta",
	"transcription.segment",
	"transcription.done",
	"error"
]);
const eventEnvelopeSchema = lazySchema(() => zodSchema(z.looseObject({ type: z.string() })));
const transcriptionEventSchema = lazySchema(() => {
	const segment = {
		text: z.string(),
		start: z.number().nullish(),
		end: z.number().nullish(),
		speaker_id: z.string().nullish()
	};
	return zodSchema(z.discriminatedUnion("type", [
		z.object({ type: z.literal("session.created") }),
		z.object({ type: z.literal("session.updated") }),
		z.object({
			type: z.literal("transcription.text.delta"),
			text: z.string()
		}),
		z.object({
			type: z.literal("transcription.segment"),
			...segment
		}),
		z.object({
			type: z.literal("transcription.done"),
			text: z.string(),
			model: z.string().nullish(),
			language: z.string().nullish(),
			segments: z.array(z.object(segment)).nullish(),
			usage: z.record(z.string(), z.json()).nullish()
		}),
		z.object({
			type: z.literal("error"),
			error: z.object({ message: z.string() })
		})
	]));
});
//#endregion
//#region src/mistral-transcription-model.ts
var MistralTranscriptionModel = class MistralTranscriptionModel {
	static [WORKFLOW_SERIALIZE](model) {
		return serializeModelOptions({
			modelId: model.modelId,
			config: model.config
		});
	}
	static [WORKFLOW_DESERIALIZE](options) {
		return new MistralTranscriptionModel(options.modelId, options.config);
	}
	get provider() {
		return this.config.provider;
	}
	constructor(modelId, config) {
		this.modelId = modelId;
		this.config = config;
		this.specificationVersion = "v4";
	}
	async getArgs({ audio, mediaType, providerOptions }) {
		const warnings = [];
		const mistralOptions = await parseProviderOptions({
			provider: "mistral",
			providerOptions,
			schema: mistralTranscriptionModelOptions
		});
		for (const option of [
			"targetStreamingDelayMs",
			"speakerReferences",
			"turnDetection"
		]) if (mistralOptions?.[option] != null) warnings.push({
			type: "unsupported",
			feature: `providerOptions.mistral.${option}`,
			details: "This option is only supported for realtime transcription."
		});
		if (!getMistralTranscriptionModelEntry(this.modelId).capabilities.transcription.languageWithTimestamps && mistralOptions?.language != null && mistralOptions.timestampGranularities != null) throw new InvalidArgumentError({
			argument: "providerOptions",
			message: "providerOptions.mistral.language cannot be combined with providerOptions.mistral.timestampGranularities"
		});
		if (mistralOptions?.language != null && mistralOptions.returnLanguage) throw new InvalidArgumentError({
			argument: "providerOptions",
			message: "providerOptions.mistral.language cannot be combined with providerOptions.mistral.returnLanguage"
		});
		const formData = new FormData();
		const blob = audio instanceof Uint8Array ? new Blob([audio]) : new Blob([convertBase64ToUint8Array(audio)]);
		formData.append("model", this.modelId);
		formData.append("file", new File([blob], "audio", { type: mediaType }), `audio.${mediaTypeToExtension(mediaType)}`);
		if (mistralOptions != null) {
			appendFormValue(formData, "language", mistralOptions.language);
			appendFormValue(formData, "return_language", mistralOptions.returnLanguage);
			appendFormValue(formData, "temperature", mistralOptions.temperature);
			appendFormValue(formData, "timestamp_granularities", mistralOptions.timestampGranularities);
			appendFormValue(formData, "diarize", mistralOptions.diarize);
			appendFormValue(formData, "context_bias", mistralOptions.contextBias);
		}
		return {
			formData,
			warnings
		};
	}
	async doStream(options) {
		return streamMistralTranscription({
			...options,
			modelId: this.modelId,
			baseURL: this.config.baseURL,
			headers: combineHeaders(await resolve(this.config.headers), options.headers),
			webSocket: this.config.webSocket,
			currentDate: this.config._internal?.currentDate?.() ?? /* @__PURE__ */ new Date()
		});
	}
	async doGenerate(options) {
		const currentDate = this.config._internal?.currentDate?.() ?? /* @__PURE__ */ new Date();
		const { formData, warnings } = await this.getArgs(options);
		const { value: response, responseHeaders, rawValue: rawResponse } = await postFormDataToApi({
			url: `${this.config.baseURL}/audio/transcriptions`,
			headers: combineHeaders(await resolve(this.config.headers), options.headers),
			formData,
			failedResponseHandler: mistralFailedResponseHandler,
			successfulResponseHandler: createJsonResponseHandler(mistralTranscriptionResponseSchema),
			abortSignal: options.abortSignal,
			fetch: this.config.fetch
		});
		const segments = response.segments?.map((segment) => ({
			text: segment.text,
			startSecond: segment.start,
			endSecond: segment.end
		})) ?? [];
		const mistralMetadata = {};
		if (response.usage != null) mistralMetadata.usage = {
			...response.usage.prompt_tokens != null && { promptTokens: response.usage.prompt_tokens },
			...response.usage.completion_tokens != null && { completionTokens: response.usage.completion_tokens },
			...response.usage.total_tokens != null && { totalTokens: response.usage.total_tokens },
			...response.usage.prompt_audio_seconds != null && { promptAudioSeconds: response.usage.prompt_audio_seconds },
			...response.usage.request_count != null && { requestCount: response.usage.request_count }
		};
		const providerSegments = response.segments?.filter((segment) => segment.type != null || segment.score != null || segment.speaker_id != null).map((segment) => ({
			text: segment.text,
			startSecond: segment.start,
			endSecond: segment.end,
			...segment.type != null && { type: segment.type },
			...segment.score != null && { score: segment.score },
			...segment.speaker_id != null && { speakerId: segment.speaker_id }
		}));
		if (providerSegments != null && providerSegments.length > 0) mistralMetadata.segments = providerSegments;
		return {
			text: response.text,
			segments,
			language: response.language ?? void 0,
			durationInSeconds: response.usage?.prompt_audio_seconds ?? segments.at(-1)?.endSecond ?? void 0,
			warnings,
			...response.usage != null && { usage: response.usage },
			response: {
				timestamp: currentDate,
				modelId: response.model,
				headers: responseHeaders,
				body: rawResponse
			},
			...Object.keys(mistralMetadata).length > 0 && { providerMetadata: { mistral: mistralMetadata } }
		};
	}
};
function appendFormValue(formData, key, value) {
	if (value == null) return;
	if (Array.isArray(value)) {
		for (const item of value) formData.append(key, item);
		return;
	}
	formData.append(key, String(value));
}
const mistralTranscriptionResponseSchema = lazySchema(() => zodSchema(z.object({
	model: z.string(),
	text: z.string(),
	language: z.string().nullish(),
	segments: z.array(z.object({
		type: z.literal("transcription_segment").nullish(),
		text: z.string(),
		start: z.number(),
		end: z.number(),
		score: z.number().nullish(),
		speaker_id: z.string().nullish()
	})).nullish(),
	usage: z.object({
		prompt_tokens: z.number().nullish(),
		completion_tokens: z.number().nullish(),
		total_tokens: z.number().nullish(),
		prompt_audio_seconds: z.number().nullish(),
		request_count: z.number().nullish()
	}).nullish()
})));
//#endregion
//#region src/version.ts
const VERSION = "4.0.87";
//#endregion
//#region src/tool/web-search.ts
const inputSchema = lazySchema(() => zodSchema(z.object({ arguments: z.string() })));
const outputSchema = lazySchema(() => zodSchema(z.object({ info: z.record(z.string(), z.json()).optional() })));
const webSearchFactory = createProviderExecutedToolFactory({
	id: "mistral.web_search",
	inputSchema,
	outputSchema
});
const webSearchPremiumFactory = createProviderExecutedToolFactory({
	id: "mistral.web_search_premium",
	inputSchema,
	outputSchema
});
/** Search the web using Mistral's Conversations API. */
const webSearch = (args = {}) => webSearchFactory(args);
/** Search the web and verified news using Mistral's Conversations API. */
const webSearchPremium = (args = {}) => webSearchPremiumFactory(args);
//#endregion
//#region src/tool/index.ts
const mistralTools = {
	webSearch,
	webSearchPremium
};
//#endregion
//#region src/realtime/mistral-realtime-model-options.ts
const mistralRealtimeModelOptions = lazySchema(() => zodSchema(z.strictObject({
	/** Speech recognition settings for the managed voice agent. */
	stt: z.strictObject({
		model: z.string().min(1).optional(),
		language: z.string().min(1).optional(),
		contextBias: z.array(z.string().min(1)).optional(),
		targetStreamingDelayMs: z.number().int().min(80).max(1200).optional(),
		turnDetection: z.strictObject({
			startThreshold: z.number().min(0).max(1).optional(),
			eagerEndThreshold: z.number().min(0).max(1).optional(),
			endThreshold: z.number().min(0).max(1).optional(),
			minSilenceMs: z.number().int().nonnegative().optional(),
			endTimeoutMs: z.number().int().nonnegative().optional()
		}).optional()
	}).optional(),
	/** Speech synthesis settings. `sessionConfig.voice` overrides voiceId. */
	tts: z.strictObject({
		model: z.string().min(1).optional(),
		voiceId: z.string().min(1).optional(),
		phonemeHints: z.record(z.string(), z.array(z.string().min(1)).min(1)).optional()
	}).optional(),
	/** Interruptions and reminders during periods of silence. */
	turn: z.strictObject({
		allowInterruptions: z.boolean().optional(),
		inactivity: z.strictObject({
			timeoutMs: z.number().int().nonnegative().optional(),
			maxReminders: z.number().int().nonnegative().optional(),
			messages: z.array(z.string()).optional()
		}).optional()
	}).optional(),
	/** Text spoken when the session connects. */
	welcomeMessage: z.string().optional(),
	/** Saved agent whose configuration is overridden for this session. */
	agentId: z.string().min(1).optional(),
	/** Version of the saved agent. Omit to use its latest version. */
	agentVersion: z.number().int().nonnegative().optional()
})));
/** Builds the REST configuration or the subset accepted by session.update. */
async function buildMistralRealtimeSessionConfig(config, { modelId, update = false } = {}) {
	const allowed = /* @__PURE__ */ new Set([
		"instructions",
		"tools",
		"providerOptions",
		...!update ? [
			"voice",
			"inputAudioTranscription",
			"outputAudioTranscription",
			"outputModalities"
		] : []
	]);
	for (const [key, value] of Object.entries(config)) if (value !== void 0 && !allowed.has(key)) unsupported(key, update);
	if (config.inputAudioTranscription?.prompt != null) unsupported("inputAudioTranscription.prompt", update);
	if (config.outputAudioTranscription != null && Object.values(config.outputAudioTranscription).some((value) => value != null)) unsupported("outputAudioTranscription settings", update);
	if (config.outputModalities != null && (!config.outputModalities.includes("audio") || config.outputModalities.some((value) => value !== "audio" && value !== "text"))) unsupported("outputModalities without audio", update);
	const options = await parseProviderOptions({
		provider: "mistral",
		providerOptions: config.providerOptions,
		schema: mistralRealtimeModelOptions
	});
	if (update && options != null) {
		for (const [key, value] of Object.entries(options)) if (value !== void 0 && key !== "turn") unsupported(`providerOptions.mistral.${key}`, true);
	}
	if (options?.agentVersion != null && options.agentId == null) throw new InvalidArgumentError({
		argument: "providerOptions.mistral.agentVersion",
		message: "Mistral agentVersion requires agentId."
	});
	const stt = options?.stt;
	const turnDetection = stt?.turnDetection;
	const tts = options?.tts;
	const turn = options?.turn;
	const inactivity = turn?.inactivity;
	return {
		...modelId != null && { llm: { model: modelId } },
		...config.instructions != null && { instructions: config.instructions },
		...config.tools != null && { tools: config.tools.map((tool) => ({
			type: "function",
			function: {
				name: tool.name,
				...tool.description != null && { description: tool.description },
				parameters: tool.parameters
			}
		})) },
		...(stt != null || config.inputAudioTranscription != null) && { stt: {
			model: config.inputAudioTranscription?.model ?? stt?.model,
			language: config.inputAudioTranscription?.language ?? stt?.language,
			context_bias: stt?.contextBias,
			target_streaming_delay_ms: stt?.targetStreamingDelayMs,
			...turnDetection != null && { turn_detection: {
				start_threshold: turnDetection.startThreshold,
				eager_end_threshold: turnDetection.eagerEndThreshold,
				end_threshold: turnDetection.endThreshold,
				min_silence_ms: turnDetection.minSilenceMs,
				end_timeout_ms: turnDetection.endTimeoutMs
			} }
		} },
		...(tts != null || config.voice != null) && { tts: {
			model: tts?.model,
			voice_id: config.voice ?? tts?.voiceId,
			phoneme_hints: tts?.phonemeHints
		} },
		...turn != null && { turn: {
			allow_interruptions: turn.allowInterruptions,
			...inactivity != null && { inactivity: {
				timeout_ms: inactivity.timeoutMs,
				max_reminders: inactivity.maxReminders,
				messages: inactivity.messages
			} }
		} },
		...options?.welcomeMessage != null && { welcome_message: options.welcomeMessage },
		...options?.agentId != null && { agent_id: options.agentId },
		...options?.agentVersion != null && { agent_version: options.agentVersion }
	};
}
function unsupported(setting, update) {
	throw new UnsupportedFunctionalityError({ functionality: `Mistral voice agent ${update ? "live update of" : "setting"} ${setting}` });
}
//#endregion
//#region src/realtime/mistral-realtime-transport.ts
const sessionSchema$1 = z.object({
	id: z.string().min(1),
	participantToken: z.string().min(1),
	serverUrl: z.string().min(1)
});
const transcriptSchema = z.object({
	type: z.literal("transcription.segment"),
	id: z.string(),
	role: z.enum(["user", "assistant"]),
	content: z.string(),
	final: z.boolean()
});
const errorSchema = z.object({
	type: z.literal("error"),
	message: z.string(),
	code: z.string(),
	fatal: z.boolean()
});
const functionCallSchema = z.object({
	name: z.string(),
	arguments: z.record(z.string(), z.unknown()).optional()
});
/** Voice transcripts contain replacement text, rather than append-only deltas. */
function parseMistralRealtimeEvent(raw) {
	const type = raw != null && typeof raw === "object" && "type" in raw ? raw.type : void 0;
	switch (type) {
		case "transcription.segment": {
			const segment = transcriptSchema.parse(raw);
			if (!segment.final) return [];
			return segment.role === "user" ? [{
				type: "input-transcription-completed",
				itemId: segment.id,
				transcript: segment.content,
				raw
			}] : [
				{
					type: "response-created",
					responseId: segment.id,
					raw
				},
				{
					type: "audio-transcript-delta",
					responseId: segment.id,
					itemId: segment.id,
					delta: segment.content,
					raw
				},
				{
					type: "audio-transcript-done",
					responseId: segment.id,
					itemId: segment.id,
					transcript: segment.content,
					raw
				},
				{
					type: "response-done",
					responseId: segment.id,
					status: "completed",
					raw
				}
			];
		}
		case "session.updated": return [{
			type: "session-updated",
			raw
		}];
		case "error": {
			const error = errorSchema.parse(raw);
			return [{
				type: "error",
				message: error.message,
				code: error.code,
				raw
			}];
		}
		default: return [{
			type: "custom",
			rawType: typeof type === "string" ? type : "unknown",
			raw
		}];
	}
}
function asError(error) {
	return error instanceof Error ? error : new Error(String(error));
}
async function loadLiveKit() {
	try {
		return await import("livekit-client");
	} catch (cause) {
		throw Object.assign(/* @__PURE__ */ new Error("Cannot load \"livekit-client\". Install it to use Mistral realtime voice connections."), { cause });
	}
}
/** LiveKit stays inside the Mistral provider and is loaded only on connection. */
var MistralRealtimeTransport = class {
	constructor(options) {
		this.options = options;
		this.started = false;
		this.closed = false;
		this.accepting = true;
		this.ready = false;
		this.failed = false;
		this.reconnecting = false;
		this.agentDisconnected = false;
		this.agentCheckQueued = false;
		this.abort = new AbortController();
		this.incoming = Promise.resolve();
		this.deliveries = Promise.resolve();
		this.pendingEvents = [];
		this.pendingCount = 0;
		this.pendingBytes = 0;
		this.finalizedSegments = /* @__PURE__ */ new Set();
		this.captureVersion = 0;
		this.captureOperations = Promise.resolve();
		this.ownedTracks = /* @__PURE__ */ new Set();
		this.playbackEnabled = true;
		this.agentSpeaking = false;
		this.remoteAudio = /* @__PURE__ */ new Map();
		this.pendingTools = /* @__PURE__ */ new Map();
	}
	async connect({ api, sessionConfig, stream, capture = true, abortSignal }) {
		if (this.started || this.closed) throw new Error("Create a new Mistral transport for each connection.");
		this.started = true;
		this.api = api;
		const onAbort = () => this.dispose();
		abortSignal.addEventListener("abort", onAbort, { once: true });
		this.removeAbortListener = () => abortSignal.removeEventListener("abort", onAbort);
		if (abortSignal.aborted) {
			this.dispose();
			throw new Error("Mistral voice connection cancelled.");
		}
		this.setup = this.open({
			sessionConfig,
			stream,
			capture
		});
		try {
			await this.setup;
		} catch (error) {
			await this.close().catch((cleanupError) => this.options.onError(asError(cleanupError)));
			throw error;
		}
	}
	async open({ sessionConfig, stream, capture }) {
		const livekit = await loadLiveKit();
		this.assertOpen();
		const timeout = new AbortController();
		const timer = setTimeout(() => timeout.abort(), 3e4);
		try {
			const response = await fetch(this.api, {
				method: "POST",
				headers: { "Content-Type": "application/json" },
				body: JSON.stringify({ sessionConfig }),
				signal: timeout.signal
			});
			if (!response.ok) throw new Error(`Failed to create Mistral voice session: ${response.status}`);
			const parsed = await safeParseJSON({
				text: await response.text(),
				schema: sessionSchema$1
			});
			if (!parsed.success) throw parsed.error;
			this.session = parsed.value;
		} finally {
			clearTimeout(timer);
		}
		this.assertOpen();
		const room = new livekit.Room();
		this.room = room;
		const agentReady = new Promise((resolve) => {
			this.resolveAgent = resolve;
		});
		const onParticipantConnected = (participant) => {
			if (participant.isAgent) {
				this.agentDisconnected = false;
				this.resolveAgent?.();
			}
		};
		const onParticipantDisconnected = (participant) => {
			if (participant.isAgent) {
				this.agentDisconnected = true;
				this.checkAgentDisconnect();
			}
		};
		const onReconnecting = () => {
			this.reconnecting = true;
		};
		const onReconnected = () => {
			this.reconnecting = false;
			this.checkAgentDisconnect();
		};
		const onDisconnected = () => {
			if (!this.closed) this.fail(/* @__PURE__ */ new Error("Mistral voice connection disconnected."));
		};
		const onTrackSubscribed = (track, _publication, participant) => {
			if (this.closed || !participant.isAgent || track.kind !== livekit.Track.Kind.Audio) return;
			const element = track.attach();
			this.remoteAudio.set(track, element);
			if (this.playbackEnabled) element.play().catch((error) => {
				if (!this.closed) this.options.onError(asError(error));
			});
			else element.pause();
		};
		const onTrackUnsubscribed = (track) => {
			this.removeRemoteTrack(track);
		};
		const onDataReceived = (payload, participant, _kind, topic) => {
			if (topic !== "voice_agent.events" || !participant?.isAgent) return;
			this.receive(payload);
		};
		room.on(livekit.RoomEvent.ParticipantConnected, onParticipantConnected);
		room.on(livekit.RoomEvent.ParticipantDisconnected, onParticipantDisconnected);
		room.on(livekit.RoomEvent.Disconnected, onDisconnected);
		room.on(livekit.RoomEvent.Reconnecting, onReconnecting);
		room.on(livekit.RoomEvent.Reconnected, onReconnected);
		room.on(livekit.RoomEvent.TrackSubscribed, onTrackSubscribed);
		room.on(livekit.RoomEvent.TrackUnsubscribed, onTrackUnsubscribed);
		room.on(livekit.RoomEvent.DataReceived, onDataReceived);
		this.removeRoomListeners = () => {
			room.off(livekit.RoomEvent.ParticipantConnected, onParticipantConnected);
			room.off(livekit.RoomEvent.ParticipantDisconnected, onParticipantDisconnected);
			room.off(livekit.RoomEvent.Disconnected, onDisconnected);
			room.off(livekit.RoomEvent.Reconnecting, onReconnecting);
			room.off(livekit.RoomEvent.Reconnected, onReconnected);
			room.off(livekit.RoomEvent.TrackSubscribed, onTrackSubscribed);
			room.off(livekit.RoomEvent.TrackUnsubscribed, onTrackUnsubscribed);
			room.off(livekit.RoomEvent.DataReceived, onDataReceived);
		};
		const connecting = room.connect(this.session.serverUrl, this.session.participantToken);
		connecting.then(() => {
			if (this.closed) room.disconnect(false).catch(() => {});
		}, () => {});
		await this.untilAborted(connecting);
		this.assertOpen();
		room.localParticipant.registerRpcMethod("mistral.function_tool", (data) => this.handleToolCall(data));
		if (this.findAgent() != null) this.resolveAgent?.();
		if (capture) await this.untilAborted(this.startCapture(stream));
		await this.untilAborted(agentReady);
		this.assertOpen();
		await this.options.onEvent({
			type: "session-created",
			sessionId: this.session.id,
			raw: {
				type: "session.created",
				id: this.session.id
			}
		});
		this.assertOpen();
		this.ready = true;
		const events = this.pendingEvents.splice(0);
		await Promise.all(events.map((event) => this.emit(event)));
	}
	sendEvent(event, shouldSend) {
		this.assertOpen();
		if (shouldSend?.() === false) return Promise.resolve();
		switch (event.type) {
			case "session-update": return this.updateSession(event.config, shouldSend);
			case "input-audio-mute": return this.stopCapture();
			case "input-audio-unmute": return this.startCapture();
			case "conversation-item-create":
				if (event.item.type === "function-call-output") {
					const pending = this.pendingTools.get(event.item.callId);
					if (pending == null) throw new Error("Mistral function call is no longer pending.");
					this.pendingTools.delete(event.item.callId);
					clearTimeout(pending.timer);
					pending.resolve(event.item.output);
					return Promise.resolve();
				}
				break;
			case "session-close": return this.close();
		}
		throw new UnsupportedFunctionalityError({ functionality: `${event.type} in Mistral voice sessions` });
	}
	async updateSession(config, shouldSend) {
		const payload = await buildMistralRealtimeSessionConfig(config, { update: true });
		this.assertOpen();
		if (shouldSend?.() === false) return;
		const agent = this.findAgent();
		if (agent == null) throw new Error("Mistral voice agent is not connected.");
		const response = await this.room.localParticipant.performRpc({
			destinationIdentity: agent.identity,
			method: "mistral.session_update",
			payload: JSON.stringify(payload),
			responseTimeout: 5e3
		});
		const parsed = await safeParseJSON({ text: response });
		if (!parsed.success) throw parsed.error;
	}
	async handleToolCall(data) {
		this.assertOpen();
		if (data.callerIdentity !== this.findAgent()?.identity) throw new Error("Only the Mistral voice agent may call tools.");
		const parsed = await safeParseJSON({
			text: data.payload,
			schema: functionCallSchema
		});
		if (!parsed.success) throw parsed.error;
		this.assertOpen();
		const call = parsed.value;
		if (this.pendingTools.has(data.requestId) || this.pendingTools.size >= 64) throw new Error("Mistral voice has too many pending function calls.");
		const result = new Promise((resolve, reject) => {
			const timer = setTimeout(() => {
				this.pendingTools.delete(data.requestId);
				reject(/* @__PURE__ */ new Error(`Mistral function ${call.name} timed out.`));
			}, data.responseTimeout);
			this.pendingTools.set(data.requestId, {
				resolve,
				reject,
				timer
			});
		});
		result.catch(() => {});
		await this.emit({
			type: "function-call-arguments-delta",
			responseId: data.requestId,
			itemId: data.requestId,
			callId: data.requestId,
			delta: "",
			raw: call
		});
		await this.emit({
			type: "function-call-arguments-done",
			responseId: data.requestId,
			itemId: data.requestId,
			callId: data.requestId,
			name: call.name,
			arguments: JSON.stringify(call.arguments ?? {}),
			raw: call
		});
		return result;
	}
	async startCapture(stream) {
		this.assertOpen();
		const version = ++this.captureVersion;
		this.sourceStream = stream ?? this.sourceStream;
		const source = this.sourceStream;
		let owned;
		if (source == null) {
			const { createLocalAudioTrack } = await loadLiveKit();
			if (this.closed || version !== this.captureVersion) return;
			owned = await createLocalAudioTrack({
				echoCancellation: true,
				noiseSuppression: true,
				autoGainControl: true
			});
			this.ownedTracks.add(owned);
		}
		const track = owned?.mediaStreamTrack ?? source?.getAudioTracks().find((track) => track.readyState === "live");
		if (this.closed || version !== this.captureVersion) {
			this.stopOwnedTrack(owned);
			return;
		}
		if (track == null) {
			this.stopOwnedTrack(owned);
			throw new Error("Mistral voice requires a live audio track.");
		}
		const room = this.room;
		if (room == null) {
			this.stopOwnedTrack(owned);
			throw new Error("Mistral voice is not connected.");
		}
		const operation = this.captureOperations.then(async () => {
			try {
				await this.releaseMicrophone();
				const { Track } = await loadLiveKit();
				if (this.closed || version !== this.captureVersion) {
					this.stopOwnedTrack(owned);
					return;
				}
				await room.localParticipant.publishTrack(track, { source: Track.Source.Microphone });
				if (this.closed || version !== this.captureVersion) {
					await room.localParticipant.unpublishTrack(track, false);
					this.stopOwnedTrack(owned);
					return;
				}
				const onEnded = () => {
					if (this.microphone?.track === track) this.options.onCapturing(false);
				};
				track.addEventListener("ended", onEnded);
				this.microphone = {
					track,
					owned,
					removeListener: () => track.removeEventListener("ended", onEnded)
				};
				this.options.onCapturing(track.enabled && !track.muted);
			} catch (error) {
				this.stopOwnedTrack(owned);
				throw error;
			}
		});
		this.captureOperations = operation.catch(() => {});
		return operation;
	}
	stopCapture() {
		++this.captureVersion;
		const operation = this.captureOperations.then(() => this.releaseMicrophone());
		this.captureOperations = operation.catch(() => {});
		return operation;
	}
	async releaseMicrophone() {
		const microphone = this.microphone;
		this.microphone = void 0;
		if (microphone != null) {
			microphone.removeListener();
			try {
				await this.room?.localParticipant.unpublishTrack(microphone.track, false);
			} finally {
				this.stopOwnedTrack(microphone.owned);
				this.options.onCapturing(false);
			}
		} else this.options.onCapturing(false);
	}
	stopOwnedTrack(track) {
		if (track != null && this.ownedTracks.delete(track)) track.stop();
	}
	stopPlayback() {
		this.playbackEnabled = false;
		for (const element of this.remoteAudio.values()) element.pause();
		this.options.onPlaying(false);
	}
	async resumePlayback() {
		this.assertOpen();
		this.playbackEnabled = true;
		await this.room?.startAudio();
		await Promise.all([...this.remoteAudio.values()].map((element) => element.play()));
		if (!this.closed) this.options.onPlaying(this.agentSpeaking);
	}
	receive(payload) {
		if (!this.accepting || this.closed) return;
		if (this.pendingCount >= 512 || this.pendingBytes + payload.byteLength > 8388608) {
			this.fail(/* @__PURE__ */ new Error("Mistral voice event queue exceeded its limit."));
			return;
		}
		++this.pendingCount;
		this.pendingBytes += payload.byteLength;
		this.incoming = this.incoming.then(async () => {
			if (this.closed) return;
			const parsed = await safeParseJSON({ text: new TextDecoder().decode(payload) });
			if (!parsed.success) throw parsed.error;
			const raw = parsed.value;
			const transcript = transcriptSchema.safeParse(raw);
			if (transcript.success && transcript.data.final) {
				if (this.finalizedSegments.has(transcript.data.id)) return;
				this.finalizedSegments.add(transcript.data.id);
				if (this.finalizedSegments.size > 500) this.finalizedSegments.delete(this.finalizedSegments.values().next().value);
			}
			const state = z.object({
				type: z.literal("agent.state.changed"),
				state: z.string()
			}).safeParse(raw);
			if (state.success) {
				this.agentSpeaking = state.data.state === "speaking";
				this.options.onPlaying(this.playbackEnabled && this.agentSpeaking);
			}
			for (const event of parseMistralRealtimeEvent(raw)) await this.emit(event);
			const error = errorSchema.safeParse(raw);
			if (error.success && error.data.fatal) this.fail(new Error(error.data.message));
		}).catch((error) => this.fail(asError(error))).finally(() => {
			--this.pendingCount;
			this.pendingBytes -= payload.byteLength;
		});
	}
	async emit(event) {
		if (this.closed) return;
		if (!this.ready) {
			if (this.pendingEvents.length >= 512) throw new Error("Mistral voice startup event queue is full.");
			this.pendingEvents.push(event);
			return;
		}
		const delivery = this.deliveries.then(async () => {
			if (this.closed) return;
			try {
				await this.options.onEvent(event);
			} catch (error) {
				this.options.onError(asError(error));
			}
		});
		this.deliveries = delivery.catch(() => {});
		return delivery;
	}
	findAgent() {
		return [...this.room?.remoteParticipants.values() ?? []].find((participant) => participant.isAgent);
	}
	checkAgentDisconnect() {
		if (!this.agentDisconnected || this.agentCheckQueued) return;
		this.agentCheckQueued = true;
		queueMicrotask(() => {
			this.agentCheckQueued = false;
			if (this.closed || this.reconnecting) return;
			if (this.findAgent() != null) this.agentDisconnected = false;
			else this.fail(/* @__PURE__ */ new Error("Mistral voice agent disconnected."));
		});
	}
	assertOpen() {
		if (this.closed || this.abort.signal.aborted) throw new Error("Mistral voice connection is closed.");
	}
	untilAborted(operation) {
		if (this.abort.signal.aborted) return Promise.reject(/* @__PURE__ */ new Error("Mistral voice connection cancelled."));
		return new Promise((resolve, reject) => {
			const onAbort = () => reject(/* @__PURE__ */ new Error("Mistral voice connection cancelled."));
			this.abort.signal.addEventListener("abort", onAbort, { once: true });
			operation.then(resolve, reject).finally(() => {
				this.abort.signal.removeEventListener("abort", onAbort);
			});
		});
	}
	fail(error) {
		if (this.closed || this.failed) return;
		this.failed = true;
		this.accepting = false;
		this.options.onFatalError(error);
		this.dispose();
	}
	async finish() {
		this.accepting = false;
		await this.incoming;
		await this.deliveries;
	}
	removeRemoteTrack(track) {
		const element = this.remoteAudio.get(track);
		if (element == null) return;
		this.remoteAudio.delete(track);
		element.pause();
		element.srcObject = null;
		track.detach(element);
		element.remove();
	}
	close() {
		if (this.cleanup != null) return this.cleanup;
		let disconnected;
		this.cleanup = Promise.resolve().then(async () => {
			try {
				await disconnected;
			} finally {
				await this.setup?.catch(() => {});
				if (this.session != null && this.api != null) {
					const separator = this.api.includes("?") ? "&" : "?";
					const response = await fetch(`${this.api}${separator}sessionId=${encodeURIComponent(this.session.id)}`, {
						method: "DELETE",
						keepalive: true
					});
					if (!response.ok) throw new Error(`Failed to close Mistral voice session: ${response.status}`);
				}
			}
		});
		this.closed = true;
		this.accepting = false;
		++this.captureVersion;
		this.abort.abort();
		this.removeAbortListener?.();
		this.removeRoomListeners?.();
		this.pendingEvents = [];
		for (const pending of this.pendingTools.values()) {
			clearTimeout(pending.timer);
			pending.reject(/* @__PURE__ */ new Error("Mistral voice session closed."));
		}
		this.pendingTools.clear();
		for (const track of this.remoteAudio.keys()) this.removeRemoteTrack(track);
		for (const track of this.ownedTracks) this.stopOwnedTrack(track);
		this.microphone?.removeListener();
		this.microphone = void 0;
		this.options.onCapturing(false);
		this.options.onPlaying(false);
		disconnected = this.room?.disconnect(false);
		return this.cleanup;
	}
	dispose() {
		this.close().catch((error) => this.options.onError(asError(error)));
	}
};
//#endregion
//#region src/realtime/mistral-realtime-model.ts
/** A managed Mistral voice agent with provider-owned LiveKit transport. */
var MistralRealtimeModel = class {
	constructor(modelId) {
		this.modelId = modelId;
		this.specificationVersion = "v4";
		this.provider = "mistral.realtime";
		this.capabilities = {
			conversation: "turn-based",
			transports: ["webrtc"],
			connections: ["provider"],
			startup: "session-update",
			finalization: "transport-close"
		};
	}
	createTransport(options) {
		return new MistralRealtimeTransport(options);
	}
	parseServerEvent(raw) {
		return parseMistralRealtimeEvent(raw);
	}
	serializeClientEvent(event) {
		throw new UnsupportedFunctionalityError({ functionality: `Mistral voice agent ${event.type} outside its provider transport` });
	}
	buildSessionConfig(config) {
		return buildMistralRealtimeSessionConfig(config, { modelId: this.modelId });
	}
};
//#endregion
//#region src/realtime/mistral-realtime-factory.ts
function createMistralRealtimeFactory(config) {
	return Object.assign((modelId) => new MistralRealtimeModel(modelId), {
		async createSession({ model, sessionConfig = {}, abortSignal }) {
			if (model.trim().length === 0) throw new InvalidArgumentError({
				argument: "model",
				message: "Mistral voice sessions require a model ID."
			});
			const body = await buildMistralRealtimeSessionConfig(sessionConfig, { modelId: model });
			const { value } = await postJsonToApi({
				url: `${config.baseURL}/audio/sessions`,
				headers: await resolve(config.headers),
				body,
				failedResponseHandler: mistralFailedResponseHandler,
				successfulResponseHandler: createJsonResponseHandler(sessionSchema),
				abortSignal,
				fetch: config.fetch
			});
			return {
				id: value.id,
				participantToken: value.participant_token,
				serverUrl: value.server_url
			};
		},
		async closeSession({ sessionId, abortSignal }) {
			if (sessionId.trim().length === 0 || sessionId === "." || sessionId === "..") throw new InvalidArgumentError({
				argument: "sessionId",
				message: "Mistral voice sessions require a valid session ID."
			});
			await deleteFromApi({
				url: `${config.baseURL}/audio/sessions/${encodeURIComponent(sessionId)}`,
				headers: await resolve(config.headers),
				failedResponseHandler: mistralFailedResponseHandler,
				successfulResponseHandler: async ({ response }) => {
					await response.body?.cancel();
					return { value: void 0 };
				},
				abortSignal,
				fetch: config.fetch
			});
		}
	});
}
const sessionSchema = lazySchema(() => zodSchema(z.object({
	id: z.string().min(1),
	participant_token: z.string().min(1),
	server_url: z.string().min(1)
})));
//#endregion
//#region src/mistral-provider.ts
/**
* Create a Mistral AI provider instance.
*/
function createMistral(options = {}) {
	const baseURL = withoutTrailingSlash(options.baseURL) ?? "https://api.mistral.ai/v1";
	const getHeaders = () => resolveWith(options.apiKey, (apiKey) => withUserAgentSuffix({
		Authorization: `Bearer ${loadApiKey({
			apiKey,
			environmentVariableName: "MISTRAL_API_KEY",
			description: "Mistral"
		})}`,
		...options.headers
	}, `ai-sdk-mistral/${VERSION}`));
	const createChatModel = (modelId) => new MistralChatLanguageModel(modelId, {
		provider: "mistral.chat",
		baseURL,
		headers: getHeaders,
		fetch: options.fetch,
		generateId: options.generateId
	});
	const createEmbeddingModel = (modelId) => new MistralEmbeddingModel(modelId, {
		provider: "mistral.embedding",
		baseURL,
		headers: getHeaders,
		fetch: options.fetch
	});
	const createConversationModel = (modelId) => new MistralConversationLanguageModel(modelId, {
		provider: "mistral.conversation",
		baseURL,
		headers: getHeaders,
		fetch: options.fetch,
		generateId: options.generateId
	});
	const createSpeechModel = (modelId) => new MistralSpeechModel(modelId, {
		provider: "mistral.speech",
		baseURL,
		headers: getHeaders,
		fetch: options.fetch
	});
	const createTranscriptionModel = (modelId) => new MistralTranscriptionModel(modelId, {
		provider: "mistral.transcription",
		baseURL,
		headers: getHeaders,
		fetch: options.fetch,
		webSocket: options.webSocket
	});
	const provider = function(modelId) {
		if (new.target) throw new Error("The Mistral model function cannot be called with the new keyword.");
		return createChatModel(modelId);
	};
	provider.specificationVersion = "v4";
	provider.languageModel = createChatModel;
	provider.chat = createChatModel;
	provider.conversation = createConversationModel;
	provider.tools = mistralTools;
	provider.experimental_realtime = createMistralRealtimeFactory({
		baseURL,
		headers: getHeaders,
		fetch: options.fetch
	});
	provider.embedding = createEmbeddingModel;
	provider.embeddingModel = createEmbeddingModel;
	provider.textEmbedding = createEmbeddingModel;
	provider.textEmbeddingModel = createEmbeddingModel;
	provider.speech = createSpeechModel;
	provider.speechModel = createSpeechModel;
	provider.transcription = createTranscriptionModel;
	provider.transcriptionModel = createTranscriptionModel;
	provider.imageModel = (modelId) => {
		throw new NoSuchModelError({
			modelId,
			modelType: "imageModel"
		});
	};
	return provider;
}
/**
* Default Mistral provider instance.
*/
const mistral = createMistral();
//#endregion
export { VERSION, createMistral, mistral };

//# sourceMappingURL=index.js.map