This is an automated email from the ASF dual-hosted git repository.

kaxil pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new dcd360f7454 Fix common ai Azure OpenAI docs (#73024)
dcd360f7454 is described below

commit dcd360f7454780ec4602c6cba3a8bff9d7b10d00
Author: Jeff(Wei-Hao) Lu <[email protected]>
AuthorDate: Wed Sep 16 05:24:39 2026 +0800

    Fix common ai Azure OpenAI docs (#73024)
---
 .../common/ai/docs/connections/pydantic_ai.rst     |  4 ++-
 .../ai/docs/connections/pydantic_ai_azure.rst      | 32 +++++++++++-------
 providers/common/ai/provider.yaml                  |  8 +++--
 .../providers/common/ai/get_provider_info.py       |  6 ++--
 .../providers/common/ai/hooks/pydantic_ai.py       | 12 ++++---
 .../tests/unit/common/ai/hooks/test_pydantic_ai.py | 38 +++++++++++++++++++++-
 6 files changed, 76 insertions(+), 24 deletions(-)

diff --git a/providers/common/ai/docs/connections/pydantic_ai.rst 
b/providers/common/ai/docs/connections/pydantic_ai.rst
index e71b703da48..19a48988da9 100644
--- a/providers/common/ai/docs/connections/pydantic_ai.rst
+++ b/providers/common/ai/docs/connections/pydantic_ai.rst
@@ -60,7 +60,9 @@ Host (optional)
 
     - Ollama: ``http://localhost:11434/v1``
     - vLLM: ``http://localhost:8000/v1``
-    - Azure OpenAI: 
``https://<resource>.openai.azure.com/openai/deployments/<deployment>``
+    - Azure OpenAI with an ``openai:`` model:
+      ``https://<resource>.openai.azure.com/openai/v1``. For an ``azure:`` 
model,
+      use the dedicated :doc:`pydantic_ai_azure` connection instead.
     - Any OpenAI-compatible API: the base URL of that service
 
 Extra (JSON, optional)
diff --git a/providers/common/ai/docs/connections/pydantic_ai_azure.rst 
b/providers/common/ai/docs/connections/pydantic_ai_azure.rst
index 4c8ee7daf65..8f7b9167060 100644
--- a/providers/common/ai/docs/connections/pydantic_ai_azure.rst
+++ b/providers/common/ai/docs/connections/pydantic_ai_azure.rst
@@ -23,9 +23,11 @@ Pydantic AI (Azure OpenAI) Connection
 The ``pydanticai_azure`` connection type configures access to
 `Azure OpenAI 
<https://azure.microsoft.com/en-us/products/ai-services/openai-service>`__
 via the pydantic-ai framework. It backs ``PydanticAIAzureHook``, the dedicated
-subclass of ``PydanticAIHook`` for Azure's non-standard auth (an endpoint URL
-plus an API version, rather than the plain ``api_key`` + optional ``base_url``
-that the generic :doc:`pydantic_ai` connection assumes).
+subclass of ``PydanticAIHook`` that maps Airflow connection fields to
+Azure-specific parameters: ``api_key``, ``azure_endpoint``, and, for endpoints
+that do not use the OpenAI-compatible v1 API, ``api_version``. The generic
+:doc:`pydantic_ai` connection instead supplies ``api_key`` and an optional
+``base_url``.
 
 .. note::
 
@@ -71,11 +73,14 @@ API Key (Password field)
 
 Azure Endpoint (Host field)
     The Azure OpenAI resource endpoint, e.g.
-    ``https://<resource>.openai.azure.com/openai/deployments/<deployment>``.
+    ``https://<resource>.openai.azure.com/openai/v1``.
 
 API Version (Extra field)
-    Azure OpenAI API version (e.g. ``2024-07-01-preview``). Falls back to the
-    ``OPENAI_API_VERSION`` environment variable when omitted.
+    Azure OpenAI API version (e.g. ``2024-07-01-preview``). Set it when the
+    endpoint path does not end in ``/v1`` and the host is not
+    ``*.models.ai.azure.com``. When required, it falls back to the
+    ``OPENAI_API_VERSION`` environment variable if omitted. Endpoints matching
+    either OpenAI-compatible v1 form reject this field.
 
 Examples
 --------
@@ -85,15 +90,18 @@ Examples
     {
         "conn_type": "pydanticai_azure",
         "password": "<azure-api-key>",
-        "host": "https://<resource>.openai.azure.com",
-        "extra": "{\"model\": \"azure:gpt-4o\", \"api_version\": 
\"2024-07-01-preview\"}"
+        "host": "https://<resource>.openai.azure.com/openai/v1",
+        "extra": "{\"model\": \"azure:gpt-4o\"}"
     }
 
 Relationship to the hook
 -------------------------
 
 ``PydanticAIAzureHook`` maps the connection's ``password`` to the provider's
-``api_key``, ``host`` to ``azure_endpoint``, and ``extra["api_version"]`` to
-``api_version``, then constructs pydantic-ai's Azure provider with those 
values.
-If none of them are set, the hook falls back to pydantic-ai's own 
environment-variable
-resolution (``AZURE_OPENAI_API_KEY``, ``AZURE_OPENAI_ENDPOINT``, 
``OPENAI_API_VERSION``).
+``api_key`` and ``host`` to ``azure_endpoint``, and maps
+``extra["api_version"]`` to ``api_version`` when provided. The API version is
+valid only when the endpoint path does not end in ``/v1`` and the host is not
+``*.models.ai.azure.com``. The hook then constructs pydantic-ai's Azure 
provider
+with those values. If none of them are set, it falls back to pydantic-ai's own
+environment-variable resolution (``AZURE_OPENAI_API_KEY``,
+``AZURE_OPENAI_ENDPOINT``, ``OPENAI_API_VERSION``).
diff --git a/providers/common/ai/provider.yaml 
b/providers/common/ai/provider.yaml
index bf4f9d0dbe2..c23468202df 100644
--- a/providers/common/ai/provider.yaml
+++ b/providers/common/ai/provider.yaml
@@ -194,8 +194,8 @@ connection-types:
         password: API Key
         host: Azure Endpoint
       placeholders:
-        host: "https://<resource>.openai.azure.com"
-        extra: '{"model": "azure:gpt-4o", "api_version": "2024-07-01-preview"}'
+        host: "https://<resource>.openai.azure.com/openai/v1"
+        extra: '{"model": "azure:gpt-4o"}'
     conn-fields:
       model:
         label: Model
@@ -206,7 +206,9 @@ connection-types:
             - 'null'
       api_version:
         label: API Version
-        description: "Azure OpenAI API version (e.g. 2024-07-01-preview). 
Falls back to OPENAI_API_VERSION."
+        description: >-
+          Azure OpenAI API version (e.g. 2024-07-01-preview). Set when the 
endpoint path does not end
+          in /v1 and the host is not *.models.ai.azure.com. Falls back to 
OPENAI_API_VERSION.
         schema:
           type:
             - string
diff --git 
a/providers/common/ai/src/airflow/providers/common/ai/get_provider_info.py 
b/providers/common/ai/src/airflow/providers/common/ai/get_provider_info.py
index 70fe47e607c..a964ee6e823 100644
--- a/providers/common/ai/src/airflow/providers/common/ai/get_provider_info.py
+++ b/providers/common/ai/src/airflow/providers/common/ai/get_provider_info.py
@@ -161,8 +161,8 @@ def get_provider_info():
                     "hidden-fields": ["schema", "port", "login"],
                     "relabeling": {"password": "API Key", "host": "Azure 
Endpoint"},
                     "placeholders": {
-                        "host": "https://<resource>.openai.azure.com",
-                        "extra": '{"model": "azure:gpt-4o", "api_version": 
"2024-07-01-preview"}',
+                        "host": 
"https://<resource>.openai.azure.com/openai/v1",
+                        "extra": '{"model": "azure:gpt-4o"}',
                     },
                 },
                 "conn-fields": {
@@ -173,7 +173,7 @@ def get_provider_info():
                     },
                     "api_version": {
                         "label": "API Version",
-                        "description": "Azure OpenAI API version (e.g. 
2024-07-01-preview). Falls back to OPENAI_API_VERSION.",
+                        "description": "Azure OpenAI API version (e.g. 
2024-07-01-preview). Set when the endpoint path does not end in /v1 and the 
host is not *.models.ai.azure.com. Falls back to OPENAI_API_VERSION.",
                         "schema": {"type": ["string", "null"]},
                     },
                 },
diff --git 
a/providers/common/ai/src/airflow/providers/common/ai/hooks/pydantic_ai.py 
b/providers/common/ai/src/airflow/providers/common/ai/hooks/pydantic_ai.py
index 3ffd5da1c9d..c24672cc913 100644
--- a/providers/common/ai/src/airflow/providers/common/ai/hooks/pydantic_ai.py
+++ b/providers/common/ai/src/airflow/providers/common/ai/hooks/pydantic_ai.py
@@ -308,10 +308,14 @@ class PydanticAIAzureHook(PydanticAIHook):
 
     Connection fields:
         - **password**: Azure API key
-        - **host**: Azure endpoint (e.g. 
``https://<resource>.openai.azure.com``)
+        - **host**: Azure endpoint (e.g. 
``https://<resource>.openai.azure.com/openai/v1``)
         - **extra** JSON::
 
-            {"model": "azure:gpt-4o", "api_version": "2024-07-01-preview"}
+            {"model": "azure:gpt-4o"}
+
+          ``api_version`` must be omitted when the endpoint path ends in 
``/v1``
+          or the host is ``*.models.ai.azure.com``. For other endpoints, set it
+          here or with ``OPENAI_API_VERSION``.
 
     :param llm_conn_id: Airflow connection ID.
     :param model_id: Model identifier, e.g. ``"azure:gpt-4o"``.
@@ -328,8 +332,8 @@ class PydanticAIAzureHook(PydanticAIHook):
             "hidden_fields": ["schema", "port", "login"],
             "relabeling": {"password": "API Key", "host": "Azure Endpoint"},
             "placeholders": {
-                "host": "https://<resource>.openai.azure.com",
-                "extra": '{"model": "azure:gpt-4o", "api_version": 
"2024-07-01-preview"}',
+                "host": "https://<resource>.openai.azure.com/openai/v1",
+                "extra": '{"model": "azure:gpt-4o"}',
             },
         }
 
diff --git a/providers/common/ai/tests/unit/common/ai/hooks/test_pydantic_ai.py 
b/providers/common/ai/tests/unit/common/ai/hooks/test_pydantic_ai.py
index 76cf0e0dd03..d4ef9a46de6 100644
--- a/providers/common/ai/tests/unit/common/ai/hooks/test_pydantic_ai.py
+++ b/providers/common/ai/tests/unit/common/ai/hooks/test_pydantic_ai.py
@@ -525,9 +525,29 @@ class TestPydanticAIAzureHook:
     def test_hook_name(self):
         assert "Azure" in PydanticAIAzureHook.hook_name
 
-    def test_ui_field_behaviour_relabels_host(self):
+    def test_ui_metadata(self):
+        expected_placeholders = {
+            "host": "https://<resource>.openai.azure.com/openai/v1",
+            "extra": '{"model": "azure:gpt-4o"}',
+        }
+        expected_api_version_description = (
+            "Azure OpenAI API version (e.g. 2024-07-01-preview). Set when the 
endpoint path does not "
+            "end in /v1 and the host is not *.models.ai.azure.com. Falls back 
to OPENAI_API_VERSION."
+        )
+
         behaviour = PydanticAIAzureHook.get_ui_field_behaviour()
         assert behaviour["relabeling"].get("host") == "Azure Endpoint"
+        assert behaviour["placeholders"] == expected_placeholders
+
+        connection_types = get_provider_info()["connection-types"]
+        azure_connection_type = next(
+            c for c in connection_types if c["connection-type"] == 
"pydanticai_azure"
+        )
+        assert azure_connection_type["ui-field-behaviour"]["placeholders"] == 
expected_placeholders
+        assert (
+            azure_connection_type["conn-fields"]["api_version"]["description"]
+            == expected_api_version_description
+        )
 
     def test_get_provider_kwargs_maps_azure_endpoint(self):
         hook = PydanticAIAzureHook.__new__(PydanticAIAzureHook)
@@ -597,6 +617,22 @@ class TestPydanticAIAzureHook:
             api_version="2024-07-01-preview",
         )
 
+    def test_get_conn_accepts_v1_endpoint_without_api_version(self):
+        conn = Connection(
+            conn_id="azure_test",
+            conn_type="pydanticai_azure",
+            password="azure-key",
+            host="https://myresource.openai.azure.com/openai/v1";,
+            extra=json.dumps({"model": "azure:gpt-4o"}),
+        )
+        hook = PydanticAIAzureHook(llm_conn_id="azure_test")
+
+        with patch.object(hook, "get_connection", return_value=conn):
+            model = hook.get_conn()
+
+        assert model.system == "azure"
+        assert model.base_url.rstrip("/") == 
"https://myresource.openai.azure.com/openai/v1";
+
     @patch("airflow.providers.common.ai.hooks.pydantic_ai.infer_model", 
autospec=True)
     def test_get_conn_falls_back_to_env_auth_when_no_kwargs(self, 
mock_infer_model):
         """No host + no password → env-var auth path (empty 
_get_provider_kwargs)."""

Reply via email to