Skip to content

mistral_common.protocol.instruct.request

ChatCompletionRequest(**data)

Bases: BaseCompletionRequest, Generic[ChatMessageType]

Request for a chat completion.

Main entry point for creating instruct model requests. Contains all configuration for a single chat completion including messages, tools, and model settings.

Attributes:

Name Type Description
model str | None

Name of the model to use. Required in serving mode; optional in other modes. If None, the default model will be used.

messages list[ChatMessageType]

List of chat messages (user, assistant, system, tool). Must not be empty.

response_format ResponseFormat

Format of the response (text or JSON). Defaults to text.

tools list[Tool] | None

List of available tools for the model to use. If None, no tools are available.

tool_choice ToolChoice

Strategy for tool selection. Options: auto (model decides), none (no tools), any/required (deprecated, use required). Default: auto.

truncate_for_context_length bool

If True, automatically truncate messages to fit within the model's context length. Default: False.

reasoning_effort ReasoningEffort | None

Controls reasoning effort (none or high). Requires tokenizer

= v15. If None, uses model default.

Examples:

>>> from mistral_common.protocol.instruct.messages import UserMessage, AssistantMessage
>>> from mistral_common.protocol.instruct.tool_calls import ToolTypes, Function
>>> request = ChatCompletionRequest(
...     messages=[
...         UserMessage(content="Hello!"),
...         AssistantMessage(content="Hi! How can I help you?"),
...     ],
...     response_format=ResponseFormat(type=ResponseFormats.text),
...     tools=[Tool(type=ToolTypes.function, function=Function(name="get_weather", parameters={}))],
...     tool_choice=ToolChoiceEnum.auto,
...     truncate_for_context_length=True,
... )
Source code in pydantic/main.py
def __init__(self, /, **data: Any) -> None:
    """Create a new model by parsing and validating input data from keyword arguments.

    Raises [`ValidationError`][pydantic_core.ValidationError] if the input data cannot be
    validated to form a valid model.

    `self` is explicitly positional-only to allow `self` as a field name.
    """
    # `__tracebackhide__` tells pytest and some other tools to omit this function from tracebacks
    __tracebackhide__ = True
    validated_self = self.__pydantic_validator__.validate_python(data, self_instance=self)
    if self is not validated_self:
        warnings.warn(
            'A custom validator is returning a value other than `self`.\n'
            "Returning anything other than `self` from a top level model validator isn't supported when validating via `__init__`.\n"
            'See the `model_validator` docs (https://docs.pydantic.dev/latest/concepts/validators/#model-validators) for more details.',
            stacklevel=2,
        )

from_openai(messages, tools=None, continue_final_message=False, **kwargs) classmethod

Create a ChatCompletionRequest from OpenAI ChatCompletion request format.

Parameters:

Name Type Description Default
messages list[dict[str, str | list[dict[str, str | dict[str, Any]]]]]

List of message dicts in OpenAI format. Each dict must have a "role" key and optionally "content" or other role-specific fields.

required
tools list[dict[str, Any]] | None

List of tool dicts in OpenAI format, or None. Each tool dict must have "type" and "function" keys for function tools.

None
continue_final_message bool

If True and the last message is an assistant, sets AssistantMessage.prefix=True on it.

False
**kwargs Any

Additional request parameters. Supports both OpenAI names (e.g., "seed") and mistral-common names (e.g., random_seed). Cannot specify both "seed" and random_seed.

{}

Returns:

Type Description
ChatCompletionRequest

A ChatCompletionRequest instance with messages and tools converted

ChatCompletionRequest

from OpenAI format.

Raises:

Type Description
ValueError

If both "seed" and random_seed are specified in kwargs.

Source code in src/mistral_common/protocol/instruct/request.py
@classmethod
def from_openai(
    cls,
    messages: list[dict[str, str | list[dict[str, str | dict[str, Any]]]]],
    tools: list[dict[str, Any]] | None = None,
    continue_final_message: bool = False,
    **kwargs: Any,
) -> "ChatCompletionRequest":
    r"""Create a ChatCompletionRequest from OpenAI ChatCompletion request format.

    Args:
        messages: List of message dicts in OpenAI format. Each dict must have
            a "role" key and optionally "content" or other role-specific fields.
        tools: List of tool dicts in OpenAI format, or `None`. Each tool dict must
            have "type" and "function" keys for function tools.
        continue_final_message: If `True` and the last message is an assistant,
            sets `AssistantMessage.prefix=True` on it.
        **kwargs: Additional request parameters. Supports both OpenAI names
            (e.g., "seed") and mistral-common names (e.g., `random_seed`).
            Cannot specify both "seed" and `random_seed`.

    Returns:
        A ChatCompletionRequest instance with messages and tools converted
        from OpenAI format.

    Raises:
        ValueError: If both "seed" and `random_seed` are specified in kwargs.
    """
    if "seed" in kwargs and "random_seed" in kwargs:
        raise ValueError("Cannot specify both `seed` and `random_seed`.")

    random_seed = kwargs.pop("seed", None)
    if random_seed is None:
        random_seed = kwargs.pop("random_seed", None)

    filtered_kwargs = cls._filter_cls_fields(kwargs)

    converted_messages: list[ChatMessage] = convert_openai_messages(messages)
    converted_messages = _map_continue_final_message(
        messages=converted_messages,
        continue_final_message=TypeAdapter(bool).validate_python(continue_final_message),
    )

    converted_tools = convert_openai_tools(tools) if tools is not None else None

    return cls(
        # Pydantic cannot express the runtime-selected request class's message generic here.
        messages=converted_messages,  # type: ignore[arg-type]
        tools=converted_tools,
        random_seed=random_seed,
        **filtered_kwargs,
    )

to_openai(reasoning_field_format=None, **kwargs)

Convert this request to OpenAI ChatCompletion API format.

Parameters:

Name Type Description Default
reasoning_field_format ReasoningFieldFormat | None

Format for converting thinking/thinking chunks in assistant messages to OpenAI's reasoning field. If None, uses default. See AssistantMessage.to_openai for available formats.

None
**kwargs Any

Additional OpenAI-specific parameters to include in the output (e.g., stream, temperature, top_p). Must not conflict with existing fields.

{}

Returns:

Type Description
dict[str, Any]

Dictionary matching the OpenAI ChatCompletion request schema.

Raises:

Type Description
ValueError

If kwargs contains duplicate or conflicting keys.

NotImplementedError

If truncate_for_context_length is True (not implemented).

Examples:

>>> from mistral_common.protocol.instruct.messages import UserMessage
>>> from mistral_common.protocol.instruct.tool_calls import Tool, Function
>>> request = ChatCompletionRequest(messages=[UserMessage(content="Hello, how are you?")], temperature=0.15)
>>> request.to_openai(stream=True)
{'temperature': 0.15, 'top_p': 1.0, 'response_format': {'type': 'text'}, 'continue_final_message': False, 'messages': [{'role': 'user', 'content': 'Hello, how are you?'}], 'tool_choice': 'auto', 'stream': True}
>>> request = ChatCompletionRequest(messages=[UserMessage(content="Hello, how are you?")], tools=[
...     Tool(function=Function(
...         name="get_current_weather",
...         description="Get the current weather in a given location",
...         parameters={
...             "type": "object",
...             "properties": {
...                 "location": {
...                     "type": "string",
...                     "description": "The city and state, e.g. San Francisco, CA",
...                 },
...                 "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
...             },
...             "required": ["location"],
...         },
...     ),
... )])
>>> request.to_openai()
{'temperature': 0.7, 'top_p': 1.0, 'response_format': {'type': 'text'}, 'continue_final_message': False, 'messages': [{'role': 'user', 'content': 'Hello, how are you?'}], 'tools': [{'type': 'function', 'function': {'name': 'get_current_weather', 'description': 'Get the current weather in a given location', 'parameters': {'type': 'object', 'properties': {'location': {'type': 'string', 'description': 'The city and state, e.g. San Francisco, CA'}, 'unit': {'type': 'string', 'enum': ['celsius', 'fahrenheit']}}, 'required': ['location']}, 'strict': False}}], 'tool_choice': 'auto'}
Source code in src/mistral_common/protocol/instruct/request.py
def to_openai(
    self,
    reasoning_field_format: ReasoningFieldFormat | None = None,
    **kwargs: Any,
) -> dict[str, Any]:
    r"""Convert this request to OpenAI ChatCompletion API format.

    Args:
        reasoning_field_format: Format for converting thinking/thinking chunks in
            assistant messages to OpenAI's reasoning field. If `None`, uses default.
            See `AssistantMessage.to_openai` for available formats.
        **kwargs: Additional OpenAI-specific parameters to include in the output
            (e.g., stream, temperature, `top_p`). Must not conflict with existing fields.

    Returns:
        Dictionary matching the OpenAI ChatCompletion request schema.

    Raises:
        ValueError: If kwargs contains duplicate or conflicting keys.
        NotImplementedError: If `truncate_for_context_length` is `True` (not implemented).

    Examples:
        >>> from mistral_common.protocol.instruct.messages import UserMessage
        >>> from mistral_common.protocol.instruct.tool_calls import Tool, Function
        >>> request = ChatCompletionRequest(messages=[UserMessage(content="Hello, how are you?")], temperature=0.15)
        >>> request.to_openai(stream=True)
        {'temperature': 0.15, 'top_p': 1.0, 'response_format': {'type': 'text'}, 'continue_final_message': False, 'messages': [{'role': 'user', 'content': 'Hello, how are you?'}], 'tool_choice': 'auto', 'stream': True}
        >>> request = ChatCompletionRequest(messages=[UserMessage(content="Hello, how are you?")], tools=[
        ...     Tool(function=Function(
        ...         name="get_current_weather",
        ...         description="Get the current weather in a given location",
        ...         parameters={
        ...             "type": "object",
        ...             "properties": {
        ...                 "location": {
        ...                     "type": "string",
        ...                     "description": "The city and state, e.g. San Francisco, CA",
        ...                 },
        ...                 "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
        ...             },
        ...             "required": ["location"],
        ...         },
        ...     ),
        ... )])
        >>> request.to_openai()
        {'temperature': 0.7, 'top_p': 1.0, 'response_format': {'type': 'text'}, 'continue_final_message': False, 'messages': [{'role': 'user', 'content': 'Hello, how are you?'}], 'tools': [{'type': 'function', 'function': {'name': 'get_current_weather', 'description': 'Get the current weather in a given location', 'parameters': {'type': 'object', 'properties': {'location': {'type': 'string', 'description': 'The city and state, e.g. San Francisco, CA'}, 'unit': {'type': 'string', 'enum': ['celsius', 'fahrenheit']}}, 'required': ['location']}, 'strict': False}}], 'tool_choice': 'auto'}
    """  # noqa: E501

    # Handle messages and tools separately.
    openai_request: dict[str, Any] = self.model_dump(
        exclude={"messages", "tools", "truncate_for_context_length", "tool_choice"}, exclude_none=True
    )

    # Rename random_seed to seed.
    seed = openai_request.pop("random_seed", None)
    if seed is not None:
        openai_request["seed"] = seed

    reasoning_effort = openai_request.pop("reasoning_effort", None)
    openai_request["continue_final_message"] = bool(
        self.messages and isinstance(self.messages[-1], AssistantMessage) and self.messages[-1].prefix
    )
    if reasoning_effort is not None:
        openai_request["reasoning_effort"] = reasoning_effort

    if self.truncate_for_context_length:
        raise NotImplementedError("Truncating for context length is not implemented for OpenAI requests.")

    for kwarg in kwargs:
        if kwarg in openai_request:
            raise ValueError(f"Duplicate keyword argument: {kwarg}")
        elif kwarg in ChatCompletionRequest.model_fields:
            raise ValueError(f"Keyword argument {kwarg} is already set in the request.")

    openai_messages = []
    for message in self.messages:
        if isinstance(message, AssistantMessage):
            openai_messages.append(message.to_openai(reasoning_field_format=reasoning_field_format))
        else:
            openai_messages.append(message.to_openai())

    openai_request["messages"] = openai_messages
    if self.tools is not None:
        openai_request["tools"] = [tool.to_openai() for tool in self.tools]

    openai_tool_choice: str | dict[str, Any]
    match self.tool_choice:
        case ToolChoiceEnum.auto | ToolChoiceEnum.none:
            openai_tool_choice = self.tool_choice
        case ToolChoiceEnum.required | ToolChoiceEnum.any:
            openai_tool_choice = ToolChoiceEnum.required.value
        case _:
            openai_tool_choice = self.tool_choice.model_dump()

    openai_request["tool_choice"] = openai_tool_choice

    openai_request.update(kwargs)

    return openai_request

InstructRequest(**data)

Bases: MistralBase, Generic[ChatMessageType, ToolType]

Internal representation of a validated instruct request ready for tokenization.

This class represents the fully normalized and validated request that will be passed to the tokenizer. It separates system prompts from regular messages and handles tool configuration.

Note

This class is intended for internal use only. External users should use ChatCompletionRequest to build requests and convert to/from OpenAI format.

Attributes:

Name Type Description
messages list[ChatMessageType]

List of chat messages (user and assistant only; system is separate).

system_prompt str | None

System prompt string, or None if no system prompt.

available_tools list[ToolType] | None

List of tools available to the assistant. If None, no tools are available. Tools are separate from messages here.

truncate_at_max_tokens int | None

Maximum token count for truncation. If None, no truncation is performed. If set, messages will be truncated from the beginning to fit within this limit.

settings ModelSettings

Model configuration settings. Defaults to all None values.

Examples:

>>> from mistral_common.protocol.instruct.messages import UserMessage, SystemMessage
>>> request = InstructRequest(
...     messages=[UserMessage(content="Hello, how are you?")],
...     system_prompt="You are a helpful assistant."
... )
Source code in pydantic/main.py
def __init__(self, /, **data: Any) -> None:
    """Create a new model by parsing and validating input data from keyword arguments.

    Raises [`ValidationError`][pydantic_core.ValidationError] if the input data cannot be
    validated to form a valid model.

    `self` is explicitly positional-only to allow `self` as a field name.
    """
    # `__tracebackhide__` tells pytest and some other tools to omit this function from tracebacks
    __tracebackhide__ = True
    validated_self = self.__pydantic_validator__.validate_python(data, self_instance=self)
    if self is not validated_self:
        warnings.warn(
            'A custom validator is returning a value other than `self`.\n'
            "Returning anything other than `self` from a top level model validator isn't supported when validating via `__init__`.\n"
            'See the `model_validator` docs (https://docs.pydantic.dev/latest/concepts/validators/#model-validators) for more details.',
            stacklevel=2,
        )

ModelSettings(**data)

Bases: MistralBase

Model configuration settings for instruct requests.

Encapsulates model-specific settings that influence inference behavior. Currently supports reasoning effort configuration.

Attributes:

Name Type Description
reasoning_effort ReasoningEffort | None

Controls reasoning effort. If None (default), the model uses its default reasoning behavior. Requires tokenizer >= v15.

Source code in pydantic/main.py
def __init__(self, /, **data: Any) -> None:
    """Create a new model by parsing and validating input data from keyword arguments.

    Raises [`ValidationError`][pydantic_core.ValidationError] if the input data cannot be
    validated to form a valid model.

    `self` is explicitly positional-only to allow `self` as a field name.
    """
    # `__tracebackhide__` tells pytest and some other tools to omit this function from tracebacks
    __tracebackhide__ = True
    validated_self = self.__pydantic_validator__.validate_python(data, self_instance=self)
    if self is not validated_self:
        warnings.warn(
            'A custom validator is returning a value other than `self`.\n'
            "Returning anything other than `self` from a top level model validator isn't supported when validating via `__init__`.\n"
            'See the `model_validator` docs (https://docs.pydantic.dev/latest/concepts/validators/#model-validators) for more details.',
            stacklevel=2,
        )

none() staticmethod

Create a ModelSettings instance with all fields set to None.

Returns:

Type Description
ModelSettings

ModelSettings with reasoning_effort=None.

Source code in src/mistral_common/protocol/instruct/request.py
@staticmethod
def none() -> "ModelSettings":
    r"""Create a ModelSettings instance with all fields set to `None`.

    Returns:
        ModelSettings with `reasoning_effort=None`.
    """
    return ModelSettings()

ReasoningEffort

Bases: str, Enum

Controls the amount of reasoning effort the model applies during generation.

Attributes:

Name Type Description
none

No reasoning effort; model generates responses directly.

high

High reasoning effort for complex tasks; model spends more compute on reasoning before generating the final response.

Note

Supported for tokenizer >= v15 only. Earlier versions will raise an error.

ResponseFormat(**data)

Bases: MistralBase

Configuration for the response format.

Attributes:

Name Type Description
type ResponseFormats

The response format type. Use ResponseFormats.text for plain text or ResponseFormats.json for JSON output.

Examples:

>>> response_format = ResponseFormat(type=ResponseFormats.text)
Source code in pydantic/main.py
def __init__(self, /, **data: Any) -> None:
    """Create a new model by parsing and validating input data from keyword arguments.

    Raises [`ValidationError`][pydantic_core.ValidationError] if the input data cannot be
    validated to form a valid model.

    `self` is explicitly positional-only to allow `self` as a field name.
    """
    # `__tracebackhide__` tells pytest and some other tools to omit this function from tracebacks
    __tracebackhide__ = True
    validated_self = self.__pydantic_validator__.validate_python(data, self_instance=self)
    if self is not validated_self:
        warnings.warn(
            'A custom validator is returning a value other than `self`.\n'
            "Returning anything other than `self` from a top level model validator isn't supported when validating via `__init__`.\n"
            'See the `model_validator` docs (https://docs.pydantic.dev/latest/concepts/validators/#model-validators) for more details.',
            stacklevel=2,
        )

ResponseFormats

Bases: str, Enum

Enum of the different formats for an instruct response.

Attributes:

Name Type Description
text

Response will be plain text.

json

Response will be a valid JSON object.

Examples:

>>> response_format = ResponseFormats.text