mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-04-11 21:42:36 +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.
|
||||
|
||||
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"):
|
||||
await self._get_async_client().close()
|
||||
if self._async_client is not None and hasattr(self._async_client, "close"):
|
||||
await self._async_client.close()
|
||||
|
||||
async def __aenter__(self) -> Self:
|
||||
"""Async context manager entry."""
|
||||
|
||||
@@ -401,6 +401,21 @@ def test_azure_raises_error_when_api_key_missing():
|
||||
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():
|
||||
"""
|
||||
Test that Azure endpoint configuration works with multiple environment variable names
|
||||
|
||||
Reference in New Issue
Block a user