From 6e7052136d12aeb443e7d2ae1867ebbcb354f70f Mon Sep 17 00:00:00 2001 From: Mahdi-Hasan <43575088+Mahdi-Hasan@users.noreply.github.com> Date: Mon, 2 Nov 2026 17:25:47 +0600 Subject: [PATCH 1/4] Python: Report the injected Mistral SDK client's endpoint in service_url Mistral chat and embedding clients kept MISTRAL_SERVER_URL (or an explicit server_url) in self.server_url when an SDK client was injected. Requests still went to the injected client's endpoint, so service_url() and the telemetry metadata reported the wrong server. An injected mistralai.client.Mistral now always defines server_url. Fixes #9965 Co-Authored-By: Claude Opus 5.5 --- .../agent_framework_mistral/_chat_client.py | 8 ++++---- .../_embedding_client.py | 8 ++++---- .../tests/mistral/test_mistral_chat_client.py | 17 +++++++++++++++++ .../mistral/test_mistral_embedding_client.py | 15 +++++++++++++++ 4 files changed, 40 insertions(+), 8 deletions(-) diff --git a/python/packages/mistral/agent_framework_mistral/_chat_client.py b/python/packages/mistral/agent_framework_mistral/_chat_client.py index 1cd384e34ab..42b01024220 100644 --- a/python/packages/mistral/agent_framework_mistral/_chat_client.py +++ b/python/packages/mistral/agent_framework_mistral/_chat_client.py @@ -361,7 +361,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 ``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. @@ -405,8 +405,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] else: client_kwargs: dict[str, Any] = {"timeout_ms": _DEFAULT_TIMEOUT_MS} if resolved_api_key := mistral_settings.get("api_key"): @@ -994,7 +994,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 ``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. diff --git a/python/packages/mistral/agent_framework_mistral/_embedding_client.py b/python/packages/mistral/agent_framework_mistral/_embedding_client.py index 29b0107c22e..6d9436b56ac 100644 --- a/python/packages/mistral/agent_framework_mistral/_embedding_client.py +++ b/python/packages/mistral/agent_framework_mistral/_embedding_client.py @@ -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 ``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 @@ -157,8 +157,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] else: client_kwargs: dict[str, Any] = {"timeout_ms": _DEFAULT_TIMEOUT_MS} if resolved_api_key := mistral_settings.get("api_key"): @@ -293,7 +293,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 ``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. diff --git a/python/packages/mistral/tests/mistral/test_mistral_chat_client.py b/python/packages/mistral/tests/mistral/test_mistral_chat_client.py index 9430f61bb01..80da9f619ce 100644 --- a/python/packages/mistral/tests/mistral/test_mistral_chat_client.py +++ b/python/packages/mistral/tests/mistral/test_mistral_chat_client.py @@ -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"]) diff --git a/python/packages/mistral/tests/mistral/test_mistral_embedding_client.py b/python/packages/mistral/tests/mistral/test_mistral_embedding_client.py index eb6851e803b..8471d10e39c 100644 --- a/python/packages/mistral/tests/mistral/test_mistral_embedding_client.py +++ b/python/packages/mistral/tests/mistral/test_mistral_embedding_client.py @@ -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 From 7c234d8030a03d55292fd2db2ab96c7bbdbcccbb Mon Sep 17 00:00:00 2001 From: Mahdi-Hasan <43575088+Mahdi-Hasan@users.noreply.github.com> Date: Tue, 3 Nov 2026 11:42:14 +0600 Subject: [PATCH 2/4] Clarify server_url docstring for injected Mistral SDK client server_url is only ignored when a Mistral SDK client is injected. The deprecated httpx.AsyncClient path via `client` still uses it. Co-Authored-By: Claude Opus 5.5 --- .../packages/mistral/agent_framework_mistral/_chat_client.py | 4 ++-- .../mistral/agent_framework_mistral/_embedding_client.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/python/packages/mistral/agent_framework_mistral/_chat_client.py b/python/packages/mistral/agent_framework_mistral/_chat_client.py index 42b01024220..10671e99608 100644 --- a/python/packages/mistral/agent_framework_mistral/_chat_client.py +++ b/python/packages/mistral/agent_framework_mistral/_chat_client.py @@ -361,7 +361,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. Ignored when ``client`` is provided. + 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. @@ -994,7 +994,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. Ignored when ``client`` is provided. + 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. diff --git a/python/packages/mistral/agent_framework_mistral/_embedding_client.py b/python/packages/mistral/agent_framework_mistral/_embedding_client.py index 6d9436b56ac..a67ca2c3ed4 100644 --- a/python/packages/mistral/agent_framework_mistral/_embedding_client.py +++ b/python/packages/mistral/agent_framework_mistral/_embedding_client.py @@ -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. Ignored when ``client`` is provided. + 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 @@ -293,7 +293,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. Ignored when ``client`` is provided. + 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. From 00d13ae750c57834f866e0f1c380d8a3ebcb2411 Mon Sep 17 00:00:00 2001 From: Mahdi-Hasan <43575088+Mahdi-Hasan@users.noreply.github.com> Date: Wed, 4 Nov 2026 15:28:47 +0600 Subject: [PATCH 3/4] Read only the model setting when a Mistral SDK client is injected An injected SDK client owns its credentials and endpoint, so the chat and embedding clients no longer resolve MISTRAL_API_KEY or MISTRAL_SERVER_URL for it. Co-Authored-By: Claude Sonnet 5.5 --- .../agent_framework_mistral/_chat_client.py | 40 ++++++++++++----- .../_embedding_client.py | 43 +++++++++++++------ .../tests/mistral/test_mistral_chat_client.py | 22 ++++++++++ .../mistral/test_mistral_embedding_client.py | 21 +++++++++ 4 files changed, 104 insertions(+), 22 deletions(-) diff --git a/python/packages/mistral/agent_framework_mistral/_chat_client.py b/python/packages/mistral/agent_framework_mistral/_chat_client.py index 10671e99608..dac194c52f0 100644 --- a/python/packages/mistral/agent_framework_mistral/_chat_client.py +++ b/python/packages/mistral/agent_framework_mistral/_chat_client.py @@ -165,6 +165,16 @@ class MistralSettings(TypedDict, total=False): server_url: str | None +class MistralChatModelSettings(TypedDict, total=False): + """Mistral AI chat model setting, read alone when a Mistral SDK client is injected. + + Fields: + chat_model: Chat model name. Resolved from ``MISTRAL_CHAT_MODEL``. + """ + + chat_model: str | None + + # endregion _MISTRAL_API_BASE_URL = "https://api.mistral.ai" @@ -387,16 +397,26 @@ def __init__( if client is not None and http_client is not None: raise ValueError("Provide either 'client' or 'http_client', not both.") - mistral_settings = load_settings( - MistralSettings, - env_prefix="MISTRAL_", - required_fields=[] if client is not None or http_client is not None else ["api_key"], - api_key=api_key, - chat_model=model, - server_url=server_url, - env_file_path=env_file_path, - env_file_encoding=env_file_encoding, - ) + if isinstance(client, Mistral): + # The injected SDK client owns its credentials and endpoint, so only the model is resolved. + mistral_settings: MistralSettings = load_settings( # type: ignore[assignment] + MistralChatModelSettings, + env_prefix="MISTRAL_", + chat_model=model, + env_file_path=env_file_path, + env_file_encoding=env_file_encoding, + ) + else: + mistral_settings = load_settings( + MistralSettings, + env_prefix="MISTRAL_", + required_fields=[] if http_client is not None else ["api_key"], + api_key=api_key, + chat_model=model, + server_url=server_url, + env_file_path=env_file_path, + env_file_encoding=env_file_encoding, + ) self.model = mistral_settings.get("chat_model") self.server_url = mistral_settings.get("server_url") diff --git a/python/packages/mistral/agent_framework_mistral/_embedding_client.py b/python/packages/mistral/agent_framework_mistral/_embedding_client.py index a67ca2c3ed4..0f65f5019c5 100644 --- a/python/packages/mistral/agent_framework_mistral/_embedding_client.py +++ b/python/packages/mistral/agent_framework_mistral/_embedding_client.py @@ -83,6 +83,16 @@ class MistralEmbeddingSettings(TypedDict, total=False): server_url: str | None +class MistralEmbeddingModelSettings(TypedDict, total=False): + """Mistral AI embedding model setting, read alone when a Mistral SDK client is injected. + + Fields: + embedding_model: Embedding model name. Resolved from ``MISTRAL_EMBEDDING_MODEL``. + """ + + embedding_model: str | None + + class RawMistralEmbeddingClient( BaseEmbeddingClient[str, list[float], MistralEmbeddingOptionsT], Generic[MistralEmbeddingOptionsT], @@ -138,18 +148,27 @@ def __init__( if client is not None and http_client is not None: raise ValueError("Provide either 'client' or 'http_client', not both.") - 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( - MistralEmbeddingSettings, - env_prefix="MISTRAL_", - required_fields=required_fields, - api_key=api_key, - embedding_model=model, - server_url=server_url, - env_file_path=env_file_path, - env_file_encoding=env_file_encoding, - ) + if isinstance(client, Mistral): + # The injected SDK client owns its credentials and endpoint, so only the model is resolved. + mistral_settings: MistralEmbeddingSettings = load_settings( # type: ignore[assignment] + MistralEmbeddingModelSettings, + env_prefix="MISTRAL_", + required_fields=["embedding_model"], + embedding_model=model, + env_file_path=env_file_path, + env_file_encoding=env_file_encoding, + ) + else: + mistral_settings = load_settings( + MistralEmbeddingSettings, + env_prefix="MISTRAL_", + required_fields=["embedding_model"] if http_client is not None else ["embedding_model", "api_key"], + api_key=api_key, + embedding_model=model, + server_url=server_url, + env_file_path=env_file_path, + env_file_encoding=env_file_encoding, + ) self.model: str = mistral_settings["embedding_model"] # type: ignore[assignment] self.server_url = mistral_settings.get("server_url") diff --git a/python/packages/mistral/tests/mistral/test_mistral_chat_client.py b/python/packages/mistral/tests/mistral/test_mistral_chat_client.py index 80da9f619ce..b60872b161e 100644 --- a/python/packages/mistral/tests/mistral/test_mistral_chat_client.py +++ b/python/packages/mistral/tests/mistral/test_mistral_chat_client.py @@ -1450,3 +1450,25 @@ def get_secret_word() -> str: assert "pineapple" in result.text.lower() finally: await client.close() + + +@pytest.mark.parametrize("client_type", [RawMistralChatClient, MistralChatClient]) +def test_injected_sdk_client_reads_only_the_model_setting( + client_type: type[RawMistralChatClient], + monkeypatch: pytest.MonkeyPatch, +) -> None: + """An injected SDK client owns its credentials and endpoint, so only the model is read from settings.""" + monkeypatch.setenv("MISTRAL_CHAT_MODEL", "mistral-env-model") + loaded: list[type] = [] + real_load_settings = chat_client_module.load_settings + + def spy(settings_type: type, **kwargs: Any) -> Any: + loaded.append(settings_type) + return real_load_settings(settings_type, **kwargs) + + monkeypatch.setattr(chat_client_module, "load_settings", spy) + + client = client_type(client=Mistral(api_key="test-key")) + + assert client.model == "mistral-env-model" + assert loaded == [chat_client_module.MistralChatModelSettings] diff --git a/python/packages/mistral/tests/mistral/test_mistral_embedding_client.py b/python/packages/mistral/tests/mistral/test_mistral_embedding_client.py index 8471d10e39c..e56ccdf2ec1 100644 --- a/python/packages/mistral/tests/mistral/test_mistral_embedding_client.py +++ b/python/packages/mistral/tests/mistral/test_mistral_embedding_client.py @@ -18,6 +18,7 @@ ) from mistralai.client import Mistral +import agent_framework_mistral._embedding_client as embedding_client_module from agent_framework_mistral import MistralEmbeddingClient, MistralEmbeddingOptions from agent_framework_mistral._http_client import ( # pyright: ignore[reportPrivateUsage] AsyncClientUsingConfiguredTimeout, @@ -432,3 +433,23 @@ async def test_mistral_embedding_integration() -> None: assert result.usage["input_token_count"] > 0 finally: await client.close() + + +def test_mistral_embedding_injected_sdk_client_reads_only_the_model_setting( + monkeypatch: pytest.MonkeyPatch, +) -> None: + """An injected SDK client owns its credentials and endpoint, so only the model is read from settings.""" + monkeypatch.setenv("MISTRAL_EMBEDDING_MODEL", "mistral-env-embed") + loaded: list[type] = [] + real_load_settings = embedding_client_module.load_settings + + def spy(settings_type: type, **kwargs: Any) -> Any: + loaded.append(settings_type) + return real_load_settings(settings_type, **kwargs) + + monkeypatch.setattr(embedding_client_module, "load_settings", spy) + + client = MistralEmbeddingClient(client=Mistral(api_key="test-key")) + + assert client.model == "mistral-env-embed" + assert loaded == [embedding_client_module.MistralEmbeddingModelSettings] From 2152a92a24e04259c7e5dd32726800551e8c374f Mon Sep 17 00:00:00 2001 From: Mahdi-Hasan <43575088+Mahdi-Hasan@users.noreply.github.com> Date: Thu, 5 Nov 2026 19:46:53 +0600 Subject: [PATCH 4/4] Use the regular Mistral settings types for an injected SDK client Drop MistralChatModelSettings and MistralEmbeddingModelSettings. The injected path loads MistralSettings / MistralEmbeddingSettings with relaxed required fields and ignores the api_key and server_url values, as requested in review. Co-Authored-By: Claude Opus 5.5 --- .../agent_framework_mistral/_chat_client.py | 42 +++++------------ .../_embedding_client.py | 45 ++++++------------- .../tests/mistral/test_mistral_chat_client.py | 22 --------- .../mistral/test_mistral_embedding_client.py | 21 --------- 4 files changed, 26 insertions(+), 104 deletions(-) diff --git a/python/packages/mistral/agent_framework_mistral/_chat_client.py b/python/packages/mistral/agent_framework_mistral/_chat_client.py index f51b1596079..d70b6a61f13 100644 --- a/python/packages/mistral/agent_framework_mistral/_chat_client.py +++ b/python/packages/mistral/agent_framework_mistral/_chat_client.py @@ -161,16 +161,6 @@ class MistralSettings(TypedDict, total=False): server_url: str | None -class MistralChatModelSettings(TypedDict, total=False): - """Mistral AI chat model setting, read alone when a Mistral SDK client is injected. - - Fields: - chat_model: Chat model name. Resolved from ``MISTRAL_CHAT_MODEL``. - """ - - chat_model: str | None - - # endregion _MISTRAL_API_BASE_URL = "https://api.mistral.ai" @@ -393,26 +383,18 @@ def __init__( if client is not None and http_client is not None: raise ValueError("Provide either 'client' or 'http_client', not both.") - if isinstance(client, Mistral): - # The injected SDK client owns its credentials and endpoint, so only the model is resolved. - mistral_settings: MistralSettings = load_settings( # type: ignore[assignment] - MistralChatModelSettings, - env_prefix="MISTRAL_", - chat_model=model, - env_file_path=env_file_path, - env_file_encoding=env_file_encoding, - ) - else: - mistral_settings = load_settings( - MistralSettings, - env_prefix="MISTRAL_", - required_fields=[] if http_client is not None else ["api_key"], - api_key=api_key, - chat_model=model, - server_url=server_url, - env_file_path=env_file_path, - env_file_encoding=env_file_encoding, - ) + # 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_", + required_fields=[] if client is not None or http_client is not None else ["api_key"], + api_key=api_key, + chat_model=model, + server_url=server_url, + env_file_path=env_file_path, + env_file_encoding=env_file_encoding, + ) self.model = mistral_settings.get("chat_model") self.server_url = mistral_settings.get("server_url") diff --git a/python/packages/mistral/agent_framework_mistral/_embedding_client.py b/python/packages/mistral/agent_framework_mistral/_embedding_client.py index 0f65f5019c5..a097bc3c58a 100644 --- a/python/packages/mistral/agent_framework_mistral/_embedding_client.py +++ b/python/packages/mistral/agent_framework_mistral/_embedding_client.py @@ -83,16 +83,6 @@ class MistralEmbeddingSettings(TypedDict, total=False): server_url: str | None -class MistralEmbeddingModelSettings(TypedDict, total=False): - """Mistral AI embedding model setting, read alone when a Mistral SDK client is injected. - - Fields: - embedding_model: Embedding model name. Resolved from ``MISTRAL_EMBEDDING_MODEL``. - """ - - embedding_model: str | None - - class RawMistralEmbeddingClient( BaseEmbeddingClient[str, list[float], MistralEmbeddingOptionsT], Generic[MistralEmbeddingOptionsT], @@ -148,27 +138,20 @@ def __init__( if client is not None and http_client is not None: raise ValueError("Provide either 'client' or 'http_client', not both.") - if isinstance(client, Mistral): - # The injected SDK client owns its credentials and endpoint, so only the model is resolved. - mistral_settings: MistralEmbeddingSettings = load_settings( # type: ignore[assignment] - MistralEmbeddingModelSettings, - env_prefix="MISTRAL_", - required_fields=["embedding_model"], - embedding_model=model, - env_file_path=env_file_path, - env_file_encoding=env_file_encoding, - ) - else: - mistral_settings = load_settings( - MistralEmbeddingSettings, - env_prefix="MISTRAL_", - required_fields=["embedding_model"] if http_client is not None else ["embedding_model", "api_key"], - api_key=api_key, - embedding_model=model, - server_url=server_url, - env_file_path=env_file_path, - env_file_encoding=env_file_encoding, - ) + # 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( + MistralEmbeddingSettings, + env_prefix="MISTRAL_", + required_fields=required_fields, + api_key=api_key, + embedding_model=model, + server_url=server_url, + env_file_path=env_file_path, + env_file_encoding=env_file_encoding, + ) self.model: str = mistral_settings["embedding_model"] # type: ignore[assignment] self.server_url = mistral_settings.get("server_url") diff --git a/python/packages/mistral/tests/mistral/test_mistral_chat_client.py b/python/packages/mistral/tests/mistral/test_mistral_chat_client.py index b60872b161e..80da9f619ce 100644 --- a/python/packages/mistral/tests/mistral/test_mistral_chat_client.py +++ b/python/packages/mistral/tests/mistral/test_mistral_chat_client.py @@ -1450,25 +1450,3 @@ def get_secret_word() -> str: assert "pineapple" in result.text.lower() finally: await client.close() - - -@pytest.mark.parametrize("client_type", [RawMistralChatClient, MistralChatClient]) -def test_injected_sdk_client_reads_only_the_model_setting( - client_type: type[RawMistralChatClient], - monkeypatch: pytest.MonkeyPatch, -) -> None: - """An injected SDK client owns its credentials and endpoint, so only the model is read from settings.""" - monkeypatch.setenv("MISTRAL_CHAT_MODEL", "mistral-env-model") - loaded: list[type] = [] - real_load_settings = chat_client_module.load_settings - - def spy(settings_type: type, **kwargs: Any) -> Any: - loaded.append(settings_type) - return real_load_settings(settings_type, **kwargs) - - monkeypatch.setattr(chat_client_module, "load_settings", spy) - - client = client_type(client=Mistral(api_key="test-key")) - - assert client.model == "mistral-env-model" - assert loaded == [chat_client_module.MistralChatModelSettings] diff --git a/python/packages/mistral/tests/mistral/test_mistral_embedding_client.py b/python/packages/mistral/tests/mistral/test_mistral_embedding_client.py index e56ccdf2ec1..8471d10e39c 100644 --- a/python/packages/mistral/tests/mistral/test_mistral_embedding_client.py +++ b/python/packages/mistral/tests/mistral/test_mistral_embedding_client.py @@ -18,7 +18,6 @@ ) from mistralai.client import Mistral -import agent_framework_mistral._embedding_client as embedding_client_module from agent_framework_mistral import MistralEmbeddingClient, MistralEmbeddingOptions from agent_framework_mistral._http_client import ( # pyright: ignore[reportPrivateUsage] AsyncClientUsingConfiguredTimeout, @@ -433,23 +432,3 @@ async def test_mistral_embedding_integration() -> None: assert result.usage["input_token_count"] > 0 finally: await client.close() - - -def test_mistral_embedding_injected_sdk_client_reads_only_the_model_setting( - monkeypatch: pytest.MonkeyPatch, -) -> None: - """An injected SDK client owns its credentials and endpoint, so only the model is read from settings.""" - monkeypatch.setenv("MISTRAL_EMBEDDING_MODEL", "mistral-env-embed") - loaded: list[type] = [] - real_load_settings = embedding_client_module.load_settings - - def spy(settings_type: type, **kwargs: Any) -> Any: - loaded.append(settings_type) - return real_load_settings(settings_type, **kwargs) - - monkeypatch.setattr(embedding_client_module, "load_settings", spy) - - client = MistralEmbeddingClient(client=Mistral(api_key="test-key")) - - assert client.model == "mistral-env-embed" - assert loaded == [embedding_client_module.MistralEmbeddingModelSettings]