Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ def __init__(
Can also be set via environment variable ``MISTRAL_CHAT_MODEL``.
api_key: Mistral API key. Defaults to ``MISTRAL_API_KEY`` environment variable.
server_url: Optional server URL override. Defaults to ``MISTRAL_SERVER_URL``
environment variable, or the Mistral default.
environment variable, or the Mistral default. Ignored when a Mistral SDK ``client`` is provided.
client: Optional pre-configured ``mistralai.client.Mistral``.
http_client: Optional pre-configured ``httpx.AsyncClient``. When provided, api_key
is not required and the client is expected to carry its own auth headers.
Expand All @@ -383,6 +383,8 @@ def __init__(
if client is not None and http_client is not None:
raise ValueError("Provide either 'client' or 'http_client', not both.")

# An injected SDK client owns its credentials and endpoint, so api_key and server_url are not required
# and their loaded values are ignored below.
mistral_settings = load_settings(
MistralSettings,
env_prefix="MISTRAL_",
Expand All @@ -401,8 +403,8 @@ def __init__(

if isinstance(client, Mistral):
self.client = client
if self.server_url is None:
self.server_url = client.sdk_configuration.get_server_details()[0]
# The injected SDK client sends the requests, so its endpoint wins over configured settings.
self.server_url = client.sdk_configuration.get_server_details()[0]
Comment thread
Mahdi-Hasan marked this conversation as resolved.
Resolved
else:
client_kwargs: dict[str, Any] = {"timeout_ms": _DEFAULT_TIMEOUT_MS}
if resolved_api_key := mistral_settings.get("api_key"):
Expand Down Expand Up @@ -990,7 +992,7 @@ def __init__(
Can also be set via environment variable ``MISTRAL_CHAT_MODEL``.
api_key: Mistral API key. Defaults to ``MISTRAL_API_KEY`` environment variable.
server_url: Optional server URL override. Defaults to ``MISTRAL_SERVER_URL``
environment variable, or the Mistral default.
environment variable, or the Mistral default. Ignored when a Mistral SDK ``client`` is provided.
client: Optional pre-configured ``mistralai.client.Mistral``.
http_client: Optional pre-configured ``httpx.AsyncClient``. When provided, api_key
is not required and the client is expected to carry its own auth headers.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ class RawMistralEmbeddingClient(
Can also be set via environment variable ``MISTRAL_EMBEDDING_MODEL``.
api_key: Mistral API key. Defaults to ``MISTRAL_API_KEY`` environment variable.
server_url: Optional server URL override. Defaults to ``MISTRAL_SERVER_URL``
environment variable, or the Mistral default.
environment variable, or the Mistral default. Ignored when a Mistral SDK ``client`` is provided.
http_client: Optional pre-configured ``httpx.AsyncClient``. When provided, api_key is
not required and the client is expected to carry its own auth headers and base URL.
client: Optional pre-configured ``mistralai.client.Mistral``. Passing an HTTP client via
Expand Down Expand Up @@ -138,6 +138,8 @@ def __init__(
if client is not None and http_client is not None:
raise ValueError("Provide either 'client' or 'http_client', not both.")

# An injected SDK client owns its credentials and endpoint, so api_key and server_url are not required
# and their loaded values are ignored below.
injected = client is not None or http_client is not None
required_fields = ["embedding_model"] if injected else ["embedding_model", "api_key"]
mistral_settings = load_settings(
Expand All @@ -157,8 +159,8 @@ def __init__(

if isinstance(client, Mistral):
self.client = client
if self.server_url is None:
self.server_url = client.sdk_configuration.get_server_details()[0]
# The injected SDK client sends the requests, so its endpoint wins over configured settings.
self.server_url = client.sdk_configuration.get_server_details()[0]
Comment thread
Copilot marked this conversation as resolved.
Resolved
else:
client_kwargs: dict[str, Any] = {"timeout_ms": _DEFAULT_TIMEOUT_MS}
if resolved_api_key := mistral_settings.get("api_key"):
Expand Down Expand Up @@ -293,7 +295,7 @@ class MistralEmbeddingClient(
Can also be set via environment variable ``MISTRAL_EMBEDDING_MODEL``.
api_key: Mistral API key. Defaults to ``MISTRAL_API_KEY`` environment variable.
server_url: Optional server URL override. Defaults to ``MISTRAL_SERVER_URL``
environment variable, or the Mistral default.
environment variable, or the Mistral default. Ignored when a Mistral SDK ``client`` is provided.
http_client: Optional pre-configured ``httpx.AsyncClient``.
client: Optional pre-configured ``mistralai.client.Mistral``. Passing an HTTP client via
this parameter remains supported but is deprecated; use ``http_client`` instead.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,23 @@ async def test_get_response_rejects_transport_arguments_split_across_options_and
await client.close()


@pytest.mark.parametrize("client_type", [RawMistralChatClient, MistralChatClient])
@pytest.mark.parametrize("server_url", [None, "https://explicit.example"], ids=["env", "explicit"])
def test_injected_sdk_client_endpoint_wins_over_configured_server_url(
client_type: type[RawMistralChatClient],
server_url: str | None,
monkeypatch: pytest.MonkeyPatch,
) -> None:
"""An injected SDK client defines the endpoint, so MISTRAL_SERVER_URL or server_url should not change it."""
monkeypatch.setenv("MISTRAL_SERVER_URL", "https://env.example")
sdk_client = Mistral(api_key="test-key", server_url="https://client.example")

client = client_type(model="mistral-small-latest", client=sdk_client, server_url=server_url)

assert client.service_url() == "https://client.example"
assert client.client is sdk_client


@pytest.mark.parametrize("client_type", [RawMistralChatClient, MistralChatClient])
@pytest.mark.parametrize("stream", [False, True])
@pytest.mark.parametrize("configuration", ["server_url", "http_client", "sdk"])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,21 @@ def test_mistral_embedding_service_url_custom() -> None:
assert client.service_url() == "https://custom.mistral.ai"


@pytest.mark.parametrize("server_url", [None, "https://explicit.example"], ids=["env", "explicit"])
def test_mistral_embedding_injected_sdk_client_endpoint_wins_over_configured_server_url(
server_url: str | None,
monkeypatch: pytest.MonkeyPatch,
) -> None:
"""An injected SDK client defines the endpoint, so MISTRAL_SERVER_URL or server_url should not change it."""
monkeypatch.setenv("MISTRAL_SERVER_URL", "https://env.example")
sdk_client = Mistral(api_key="test-key", server_url="https://client.example")

client = MistralEmbeddingClient(model="mistral-embed", client=sdk_client, server_url=server_url)

assert client.service_url() == "https://client.example"
assert client.client is sdk_client


async def test_mistral_embedding_close_only_closes_owned_client() -> None:
owned = MistralEmbeddingClient(model="mistral-embed", api_key="test-key")
owned_http_client = owned.client.sdk_configuration.async_client
Expand Down
Loading