Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions docs/docs/providers/inference/remote_mistral.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
description: "Mistral AI inference provider for accessing Mistral models via the Mistral API."
sidebar_label: Remote - Mistral
title: remote::mistral
---

# remote::mistral

## Description

Mistral AI inference provider for accessing Mistral models via the Mistral API.

## Configuration

| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `allowed_models` | `list[str] \| None` | No | | List of models that should be registered with the model registry. If None, all models are allowed. |
| `refresh_models` | `bool` | No | False | Whether to refresh models periodically from the provider |
| `api_key` | `SecretStr \| None` | No | | Authentication credential for the provider |
| `network` | `NetworkConfig \| None` | No | | Network configuration including TLS, proxy, and timeout settings. |
| `network.tls` | `TLSConfig \| None` | No | | TLS/SSL configuration for secure connections. |
| `network.tls.verify` | `bool \| Path` | No | True | Whether to verify TLS certificates. Can be a boolean or a path to a CA certificate file. |
| `network.tls.min_version` | `Literal[TLSv1.2, TLSv1.3] \| None` | No | | Minimum TLS version to use. Defaults to system default if not specified. |
| `network.tls.ciphers` | `list[str] \| None` | No | | List of allowed cipher suites (e.g., ['ECDHE+AESGCM', 'DHE+AESGCM']). |
| `network.tls.client_cert` | `Path \| None` | No | | Path to client certificate file for mTLS authentication. |
| `network.tls.client_key` | `Path \| None` | No | | Path to client private key file for mTLS authentication. |
| `network.proxy` | `ProxyConfig \| None` | No | | Proxy configuration for HTTP connections. |
| `network.proxy.url` | `HttpUrl \| None` | No | | Single proxy URL for all connections (e.g., 'http://proxy.example.com:8080'). |
| `network.proxy.http` | `HttpUrl \| None` | No | | Proxy URL for HTTP connections. |
| `network.proxy.https` | `HttpUrl \| None` | No | | Proxy URL for HTTPS connections. |
| `network.proxy.cacert` | `Path \| None` | No | | Path to CA certificate file for verifying the proxy's certificate. Required for proxies in interception mode. |
| `network.proxy.no_proxy` | `list[str] \| None` | No | | List of hosts that should bypass the proxy (e.g., ['localhost', '127.0.0.1', '.internal.corp']). |
| `network.timeout` | `float \| TimeoutConfig \| None` | No | | Timeout configuration. Can be a float (for both connect and read) or a TimeoutConfig object with separate connect and read timeouts. |
| `network.timeout.connect` | `float \| None` | No | | Connection timeout in seconds. |
| `network.timeout.read` | `float \| None` | No | | Read timeout in seconds. |
| `network.headers` | `dict[str, str] \| None` | No | | Additional HTTP headers to include in all requests. |
| `base_url` | `HttpUrl \| None` | No | https://api.mistral.ai/v1 | Base URL for the Mistral API |

## Sample Configuration

```yaml
base_url: https://api.mistral.ai/v1
api_key: ${env.MISTRAL_API_KEY:=}
```
10 changes: 10 additions & 0 deletions src/ogx/providers/registry/inference.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,16 @@ def available_providers() -> list[ProviderSpec]:
provider_data_validator="ogx.providers.remote.inference.cerebras.config.CerebrasProviderDataValidator",
description="Cerebras inference provider for running models on Cerebras Cloud platform.",
),
RemoteProviderSpec(
api=Api.inference,
adapter_type="mistral",
provider_type="remote::mistral",
pip_packages=[],
module="ogx.providers.remote.inference.mistral",
config_class="ogx.providers.remote.inference.mistral.MistralImplConfig",
provider_data_validator="ogx.providers.remote.inference.mistral.config.MistralProviderDataValidator",
description="Mistral AI inference provider for accessing Mistral models via the Mistral API.",
),
RemoteProviderSpec(
api=Api.inference,
adapter_type="ollama",
Expand Down
19 changes: 19 additions & 0 deletions src/ogx/providers/remote/inference/mistral/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright (c) The OGX Contributors.
# All rights reserved.
#
# This source code is licensed under the terms described in the LICENSE file in
# the root directory of this source tree.

from .config import MistralImplConfig


async def get_adapter_impl(config: MistralImplConfig, _deps):
from .mistral import MistralInferenceAdapter

assert isinstance(config, MistralImplConfig), f"Unexpected config type: {type(config)}"

impl = MistralInferenceAdapter(config=config)

await impl.initialize()

return impl
41 changes: 41 additions & 0 deletions src/ogx/providers/remote/inference/mistral/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Copyright (c) The OGX Contributors.
# All rights reserved.
#
# This source code is licensed under the terms described in the LICENSE file in
# the root directory of this source tree.

import os
from typing import Any

from pydantic import BaseModel, Field, HttpUrl, SecretStr

from ogx.providers.utils.inference.model_registry import RemoteInferenceProviderConfig
from ogx_api import json_schema_type

DEFAULT_BASE_URL = "https://api.mistral.ai/v1"


class MistralProviderDataValidator(BaseModel):
"""Validates provider-specific request data for Mistral inference."""

mistral_api_key: SecretStr | None = Field(
default=None,
description="API key for Mistral models",
)


@json_schema_type
class MistralImplConfig(RemoteInferenceProviderConfig):
"""Configuration for the Mistral inference provider."""

base_url: HttpUrl | None = Field(
default=HttpUrl(os.environ.get("MISTRAL_BASE_URL", DEFAULT_BASE_URL)),
description="Base URL for the Mistral API",
)

@classmethod
def sample_run_config(cls, api_key: str = "${env.MISTRAL_API_KEY:=}", **kwargs) -> dict[str, Any]:
return {
"base_url": DEFAULT_BASE_URL,
"api_key": api_key,
}
29 changes: 29 additions & 0 deletions src/ogx/providers/remote/inference/mistral/mistral.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Copyright (c) The OGX Contributors.
# All rights reserved.
#
# This source code is licensed under the terms described in the LICENSE file in
# the root directory of this source tree.

from ogx.providers.utils.inference.openai_mixin import OpenAIMixin

from .config import MistralImplConfig


class MistralInferenceAdapter(OpenAIMixin):
"""Inference adapter for the Mistral AI platform.

Mistral exposes an OpenAI-compatible API (chat completions and embeddings),
so the shared `OpenAIMixin` handles requests once pointed at Mistral's base
URL. See https://docs.mistral.ai/api/.
"""

config: MistralImplConfig

provider_data_api_key_field: str = "mistral_api_key"

embedding_model_metadata: dict[str, dict[str, int]] = {
"mistral-embed": {"embedding_dimension": 1024, "context_length": 8192},
}

def get_base_url(self) -> str:
return str(self.config.base_url)
50 changes: 50 additions & 0 deletions tests/unit/providers/inference/test_mistral_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Copyright (c) The OGX Contributors.
# All rights reserved.
#
# This source code is licensed under the terms described in the LICENSE file in
# the root directory of this source tree.

import os
from unittest.mock import patch

from ogx.core.stack import replace_env_vars
from ogx.providers.remote.inference.mistral.config import MistralImplConfig
from ogx.providers.remote.inference.mistral.mistral import MistralInferenceAdapter


class TestMistralConfig:
"""Tests for the Mistral inference provider config and adapter wiring."""

def test_default_base_url(self):
config = MistralImplConfig(api_key="test-key")
adapter = MistralInferenceAdapter(config=config)
adapter.provider_data_api_key_field = None

assert adapter.get_base_url() == "https://api.mistral.ai/v1"

def test_custom_base_url_from_config(self):
custom_url = "https://custom.mistral.ai/v1"
config = MistralImplConfig(api_key="test-key", base_url=custom_url)
adapter = MistralInferenceAdapter(config=config)
adapter.provider_data_api_key_field = None

assert adapter.get_base_url() == custom_url

@patch.dict(os.environ, {"MISTRAL_BASE_URL": "https://env.mistral.ai/v1"})
def test_base_url_from_environment_variable(self):
config_data = MistralImplConfig.sample_run_config(api_key="test-key")
processed_config = replace_env_vars(config_data)
config = MistralImplConfig.model_validate(processed_config)

assert str(config.base_url) == "https://api.mistral.ai/v1"

def test_sample_run_config_uses_env_placeholder(self):
cfg = MistralImplConfig.sample_run_config()
assert cfg["base_url"] == "https://api.mistral.ai/v1"
assert cfg["api_key"] == "${env.MISTRAL_API_KEY:=}"

def test_provider_data_api_key_field(self):
config = MistralImplConfig(api_key="test-key")
adapter = MistralInferenceAdapter(config=config)
assert adapter.provider_data_api_key_field == "mistral_api_key"
assert "mistral-embed" in adapter.embedding_model_metadata