mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-05-01 07:13:00 +00:00
fix: keep Azure aclose a no-op when the async client was never built
The lazy-init refactor rewrote `aclose` to access the async client via `_get_async_client()`, which forces lazy construction. When an `AzureCompletion` is instantiated without credentials (the whole point of deferred init), that call raises `ValueError: "Azure API key is required"` during cleanup — including via `async with` / `__aexit__`. Access the cached `_async_client` attribute directly so cleanup on an uninitialized LLM is a harmless no-op. Add a regression test that enters and exits an `async with` block against a credentials-less `AzureCompletion`.
This commit is contained in:
@@ -1132,10 +1132,13 @@ class AzureCompletion(BaseLLM):
|
|||||||
"""Close the async client and clean up resources.
|
"""Close the async client and clean up resources.
|
||||||
|
|
||||||
This ensures proper cleanup of the underlying aiohttp session
|
This ensures proper cleanup of the underlying aiohttp session
|
||||||
to avoid unclosed connector warnings.
|
to avoid unclosed connector warnings. Accesses the cached client
|
||||||
|
directly rather than going through `_get_async_client` so a
|
||||||
|
cleanup on an uninitialized LLM is a harmless no-op rather than
|
||||||
|
a credential-required error.
|
||||||
"""
|
"""
|
||||||
if hasattr(self._get_async_client(), "close"):
|
if self._async_client is not None and hasattr(self._async_client, "close"):
|
||||||
await self._get_async_client().close()
|
await self._async_client.close()
|
||||||
|
|
||||||
async def __aenter__(self) -> Self:
|
async def __aenter__(self) -> Self:
|
||||||
"""Async context manager entry."""
|
"""Async context manager entry."""
|
||||||
|
|||||||
@@ -401,6 +401,21 @@ def test_azure_raises_error_when_api_key_missing():
|
|||||||
llm._get_sync_client()
|
llm._get_sync_client()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_azure_aclose_is_noop_when_uninitialized():
|
||||||
|
"""`aclose` (and `async with`) on an uninstantiated-client LLM must be
|
||||||
|
a harmless no-op, not force lazy construction that then raises for
|
||||||
|
missing credentials."""
|
||||||
|
from crewai.llms.providers.azure.completion import AzureCompletion
|
||||||
|
|
||||||
|
with patch.dict(os.environ, {}, clear=True):
|
||||||
|
llm = AzureCompletion(model="gpt-4")
|
||||||
|
assert llm._async_client is None
|
||||||
|
await llm.aclose()
|
||||||
|
async with llm:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def test_azure_endpoint_configuration():
|
def test_azure_endpoint_configuration():
|
||||||
"""
|
"""
|
||||||
Test that Azure endpoint configuration works with multiple environment variable names
|
Test that Azure endpoint configuration works with multiple environment variable names
|
||||||
|
|||||||
Reference in New Issue
Block a user