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

gopidesupavan 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 6d4808b4e80 Add require_approval preflight check to 
@task.llm_schema_compare (#71688)
6d4808b4e80 is described below

commit 6d4808b4e802aacf6cf3a08dbb2272fadbb45951
Author: Jyun-An Chen <[email protected]>
AuthorDate: Sat Sep 5 07:41:54 2026 +0800

    Add require_approval preflight check to @task.llm_schema_compare (#71688)
    
    @task.llm, @task.llm_branch, and @task.llm_sql all reject a non-string
    Sequence[UserContent] prompt combined with require_approval=True before
    the LLM runs, with an error naming the decorator the caller actually used.
    @task.llm_schema_compare was missing this decorator-level check, so the
    same misuse instead fell through to the underlying operator's own guard --
    which names the internal _LLMSchemaCompareDecoratedOperator class rather
    than the decorator, confusing anyone who only ever wrote
    @task.llm_schema_compare.
---
 .../common/ai/decorators/llm_schema_compare.py      | 11 ++++++++++-
 .../common/ai/decorators/test_llm_schema_compare.py | 21 +++++++++++++++++++++
 2 files changed, 31 insertions(+), 1 deletion(-)

diff --git 
a/providers/common/ai/src/airflow/providers/common/ai/decorators/llm_schema_compare.py
 
b/providers/common/ai/src/airflow/providers/common/ai/decorators/llm_schema_compare.py
index 2e3a0e48ac9..d159da63ca9 100644
--- 
a/providers/common/ai/src/airflow/providers/common/ai/decorators/llm_schema_compare.py
+++ 
b/providers/common/ai/src/airflow/providers/common/ai/decorators/llm_schema_compare.py
@@ -28,7 +28,10 @@ from collections.abc import Callable, Collection, Mapping, 
Sequence
 from typing import TYPE_CHECKING, Any, ClassVar
 
 from airflow.providers.common.ai.operators.llm_schema_compare import 
LLMSchemaCompareOperator
-from airflow.providers.common.ai.utils.validation import validate_prompt
+from airflow.providers.common.ai.utils.validation import (
+    reject_sequence_with_unsupported_feature,
+    validate_prompt,
+)
 from airflow.providers.common.compat.sdk import (
     DecoratedOperator,
     TaskDecorator,
@@ -89,6 +92,12 @@ class _LLMSchemaCompareDecoratedOperator(DecoratedOperator, 
LLMSchemaCompareOper
         self.prompt = self.python_callable(*self.op_args, **kwargs)
 
         validate_prompt(self.prompt, decorator_name="@task.llm_schema_compare")
+        reject_sequence_with_unsupported_feature(
+            self.prompt,
+            decorator_name="@task.llm_schema_compare",
+            feature_name="require_approval",
+            feature_enabled=self.require_approval,
+        )
 
         self.render_template_fields(context)
         return LLMSchemaCompareOperator.execute(self, context)
diff --git 
a/providers/common/ai/tests/unit/common/ai/decorators/test_llm_schema_compare.py
 
b/providers/common/ai/tests/unit/common/ai/decorators/test_llm_schema_compare.py
index 0664b6c52b1..7074eb6ffdc 100644
--- 
a/providers/common/ai/tests/unit/common/ai/decorators/test_llm_schema_compare.py
+++ 
b/providers/common/ai/tests/unit/common/ai/decorators/test_llm_schema_compare.py
@@ -122,6 +122,27 @@ class TestLLMSchemaCompareDecoratedOperator:
         forwarded_prompt = mock_agent.run_sync.call_args[0][0]
         assert forwarded_prompt == prompt
 
+    @patch("airflow.providers.common.ai.operators.llm.PydanticAIHook", 
autospec=True)
+    @patch.object(LLMSchemaCompareOperator, "_build_schema_context", 
return_value="mocked schema")
+    def test_sequence_prompt_with_require_approval_raises_before_run_sync(
+        self, mock_build_ctx, mock_hook_cls
+    ):
+        mock_agent = _make_mock_agent(_make_compare_result())
+        mock_hook_cls.get_hook.return_value.create_agent.return_value = 
mock_agent
+
+        op = _LLMSchemaCompareDecoratedOperator(
+            task_id="test",
+            python_callable=lambda: ["Compare these schemas:", 
ImageUrl(url="https://example.com/x.png";)],
+            llm_conn_id="llm_conn",
+            db_conn_ids=["postgres_default", "snowflake_default"],
+            table_names=["test_table"],
+            require_approval=True,
+        )
+        with pytest.raises(TypeError, match=r"^@task\.llm_schema_compare: 
Sequence\[UserContent\]"):
+            op.execute(context={})
+
+        mock_agent.run_sync.assert_not_called()
+
     @patch("airflow.providers.common.ai.operators.llm.PydanticAIHook", 
autospec=True)
     @patch.object(LLMSchemaCompareOperator, "_build_schema_context", 
return_value="mocked schema")
     def test_execute_merges_op_kwargs_into_callable(self, mock_build_ctx, 
mock_hook_cls):

Reply via email to