From 4b4195e8da69000006ca25acbd7d89d92dfc8ae0 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 5 Aug 2026 11:08:32 +0000 Subject: [PATCH] fix: make Azure Responses OpenAICompletion mock reliable under xdist Patch AzureCompletion._openai_completion_class instead of the dynamic import target so Responses delegate tests do not intermittently use the real OpenAICompletion and fail under pytest-xdist. Co-authored-by: Rip&Tear --- .../src/crewai/llms/providers/azure/completion.py | 15 +++++++++++++-- .../tests/llms/azure/test_azure_responses.py | 14 +++++++++----- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/lib/crewai/src/crewai/llms/providers/azure/completion.py b/lib/crewai/src/crewai/llms/providers/azure/completion.py index 4597fd623..f6fd6e27d 100644 --- a/lib/crewai/src/crewai/llms/providers/azure/completion.py +++ b/lib/crewai/src/crewai/llms/providers/azure/completion.py @@ -183,13 +183,24 @@ class AzureCompletion(BaseLLM): pass return self + @staticmethod + def _openai_completion_class() -> Any: + """Return the OpenAICompletion class used for Responses API delegation. + + Isolated so tests can patch this lookup reliably under pytest-xdist + instead of racing the dynamic import inside ``_init_responses_delegate``. + """ + from crewai.llms.providers.openai.completion import OpenAICompletion + + return OpenAICompletion + def _init_responses_delegate(self) -> None: """Create an OpenAICompletion delegate for the Azure OpenAI Responses API. The Azure OpenAI Responses API uses the standard OpenAI Python SDK with a base_url pointing to the Azure resource's /openai/v1/ endpoint. """ - from crewai.llms.providers.openai.completion import OpenAICompletion + openai_completion_cls = self._openai_completion_class() base_url = self._get_responses_base_url() @@ -239,7 +250,7 @@ class AzureCompletion(BaseLLM): if self.additional_params: delegate_kwargs["additional_params"] = self.additional_params - self._responses_delegate = OpenAICompletion(**delegate_kwargs) + self._responses_delegate = openai_completion_cls(**delegate_kwargs) def _get_responses_base_url(self) -> str: """Construct the base URL for the Azure OpenAI Responses API. diff --git a/lib/crewai/tests/llms/azure/test_azure_responses.py b/lib/crewai/tests/llms/azure/test_azure_responses.py index 6949058f6..41bada66c 100644 --- a/lib/crewai/tests/llms/azure/test_azure_responses.py +++ b/lib/crewai/tests/llms/azure/test_azure_responses.py @@ -29,9 +29,12 @@ def azure_env(): def mock_openai_completion(): """Mock OpenAICompletion to avoid real client creation. - Patches at the source module so that the dynamic import inside - _init_responses_delegate picks up the mock. + Patches ``AzureCompletion._openai_completion_class`` so the Responses + delegate lookup is deterministic under pytest-xdist (patching the + dynamic import target alone can miss under parallel workers). """ + from crewai.llms.providers.azure.completion import AzureCompletion + instance = MagicMock() instance.call = MagicMock(return_value="responses-result") instance.acall = AsyncMock(return_value="async-responses-result") @@ -41,9 +44,10 @@ def mock_openai_completion(): instance.reset_reasoning_chain = MagicMock() mock_cls = MagicMock(return_value=instance) - with patch( - "crewai.llms.providers.openai.completion.OpenAICompletion", - mock_cls, + with patch.object( + AzureCompletion, + "_openai_completion_class", + return_value=mock_cls, ): yield mock_cls, instance