mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-04-30 23:02:50 +00:00
fix: recompute is_azure_openai_endpoint after lazy endpoint resolve
`_prepare_completion_params` uses `is_azure_openai_endpoint` to decide whether to include the `model` parameter in requests — Azure OpenAI endpoints embed the deployment name in the URL and reject a `model` field. When the endpoint was resolved lazily from env vars, the flag stayed at its pre-resolve `False` value, causing every lazily-inited Azure OpenAI request to include `model` and fail. Factor the classification into `_is_azure_openai_endpoint` and call it from both `_normalize_azure_fields` and `_make_client_kwargs`. Extend the lazy-build regression test to assert the flag flips to `True` once the endpoint is resolved.
This commit is contained in:
@@ -123,18 +123,23 @@ class AzureCompletion(BaseLLM):
|
||||
data["endpoint"] = AzureCompletion._validate_and_fix_endpoint(
|
||||
data["endpoint"], model
|
||||
)
|
||||
parsed = urlparse(data["endpoint"])
|
||||
hostname = parsed.hostname or ""
|
||||
data["is_azure_openai_endpoint"] = (
|
||||
hostname == "openai.azure.com" or hostname.endswith(".openai.azure.com")
|
||||
) and "/openai/deployments/" in data["endpoint"]
|
||||
else:
|
||||
data["is_azure_openai_endpoint"] = False
|
||||
data["is_azure_openai_endpoint"] = AzureCompletion._is_azure_openai_endpoint(
|
||||
data["endpoint"]
|
||||
)
|
||||
data["is_openai_model"] = any(
|
||||
prefix in model.lower() for prefix in ["gpt-", "o1-", "text-"]
|
||||
)
|
||||
return data
|
||||
|
||||
@staticmethod
|
||||
def _is_azure_openai_endpoint(endpoint: str | None) -> bool:
|
||||
if not endpoint:
|
||||
return False
|
||||
hostname = urlparse(endpoint).hostname or ""
|
||||
return (
|
||||
hostname == "openai.azure.com" or hostname.endswith(".openai.azure.com")
|
||||
) and "/openai/deployments/" in endpoint
|
||||
|
||||
@model_validator(mode="after")
|
||||
def _init_clients(self) -> AzureCompletion:
|
||||
"""Eagerly build clients when credentials are available, otherwise
|
||||
@@ -170,6 +175,13 @@ class AzureCompletion(BaseLLM):
|
||||
self.endpoint = AzureCompletion._validate_and_fix_endpoint(
|
||||
endpoint, self.model
|
||||
)
|
||||
# Recompute the routing flag now that the endpoint is known —
|
||||
# _prepare_completion_params uses it to decide whether to
|
||||
# include `model` in the request body (Azure OpenAI endpoints
|
||||
# embed the deployment name in the URL and reject it).
|
||||
self.is_azure_openai_endpoint = (
|
||||
AzureCompletion._is_azure_openai_endpoint(self.endpoint)
|
||||
)
|
||||
|
||||
if not self.api_key:
|
||||
raise ValueError(
|
||||
|
||||
@@ -419,13 +419,16 @@ async def test_azure_aclose_is_noop_when_uninitialized():
|
||||
def test_azure_lazy_build_reads_env_vars_set_after_construction():
|
||||
"""When `LLM(model="azure/...")` is constructed before env vars are set,
|
||||
the lazy client builder must re-read `AZURE_API_KEY` / `AZURE_ENDPOINT`
|
||||
so the LLM actually works once credentials become available."""
|
||||
so the LLM actually works once credentials become available, and the
|
||||
`is_azure_openai_endpoint` routing flag must be recomputed off the
|
||||
newly-resolved endpoint."""
|
||||
from crewai.llms.providers.azure.completion import AzureCompletion
|
||||
|
||||
with patch.dict(os.environ, {}, clear=True):
|
||||
llm = AzureCompletion(model="gpt-4")
|
||||
assert llm.api_key is None
|
||||
assert llm.endpoint is None
|
||||
assert llm.is_azure_openai_endpoint is False
|
||||
|
||||
with patch.dict(
|
||||
os.environ,
|
||||
@@ -440,6 +443,7 @@ def test_azure_lazy_build_reads_env_vars_set_after_construction():
|
||||
assert llm.api_key == "late-key"
|
||||
assert llm.endpoint is not None
|
||||
assert "test.openai.azure.com" in llm.endpoint
|
||||
assert llm.is_azure_openai_endpoint is True
|
||||
|
||||
|
||||
def test_azure_endpoint_configuration():
|
||||
|
||||
Reference in New Issue
Block a user