Lee-W commented on code in PR #71051:
URL: https://github.com/apache/airflow/pull/71051#discussion_r3757025366


##########
providers/common/ai/src/airflow/providers/common/ai/operators/llm_schema_compare.py:
##########
@@ -313,8 +324,32 @@ def execute(self, context: Context) -> dict[str, Any]:
         self.log.info("Running LLM schema comparison...")
         result = agent.run_sync(self.prompt, usage_limits=self.usage_limits)
         log_run_summary(self.log, result)
+        output = result.output
 
-        output_result = result.output.model_dump()
+        output_result = output.model_dump()
         self.log.info("Schema comparison result: \n %s", 
json.dumps(output_result, indent=2))
 
+        if self.require_approval:
+            severity_counts = Counter(mismatch.severity for mismatch in 
output.mismatches)
+            summary = ", ".join(
+                f"{severity_counts[severity]} {severity}"
+                for severity in ("critical", "warning", "info")
+                if severity_counts[severity]
+            )
+            body = (
+                f"Compatible: {output.compatible}"
+                + (f" (mismatches: {summary})" if summary else "")
+                + f"\n\n```\nPrompt: 
{self.prompt}\n\n{output.model_dump_json(indent=2)}\n```"

Review Comment:
   ```suggestion
                   + (
                       "\n\n```\n"
                       f"Prompt: {self.prompt}\n\n"
                       f"{output.model_dump_json(indent=2)}\n'
                       "```"   
                   )
   ```
   
   easier to understand what this if



##########
providers/common/ai/tests/unit/common/ai/operators/test_llm_schema_compare.py:
##########
@@ -16,20 +16,36 @@
 # under the License.
 from __future__ import annotations
 
+import json
 from unittest import mock
 from unittest.mock import MagicMock
+from uuid import uuid4
 
 import pytest
 
 from airflow.providers.common.ai.operators.llm_schema_compare import (
     LLMSchemaCompareOperator,
     SchemaCompareResult,
+    SchemaMismatch,
 )
-from airflow.providers.common.compat.sdk import 
AirflowOptionalProviderFeatureException
+from airflow.providers.common.compat.sdk import 
AirflowOptionalProviderFeatureException, TaskDeferred
 from airflow.providers.common.sql.config import DataSourceConfig
 from airflow.providers.common.sql.datafusion.engine import DataFusionEngine
 from airflow.providers.common.sql.hooks.sql import DbApiHook
 
+from tests_common.test_utils.version_compat import AIRFLOW_V_3_1_PLUS, 
AIRFLOW_V_3_3_PLUS
+
+if AIRFLOW_V_3_3_PLUS:
+    from airflow.sdk.exceptions import TaskAwaitingInput as ApprovalPauseSignal

Review Comment:
   Why do we need alias here



##########
providers/common/ai/src/airflow/providers/common/ai/example_dags/example_llm_schema_compare.py:
##########
@@ -105,6 +105,27 @@ def check_migration_readiness(ds=None):
 example_llm_schema_compare_decorator()
 
 
+# [START howto_operator_llm_schema_compare_approval]
+@dag(tags=["example"])
+def example_llm_schema_compare_approval():
+    from datetime import timedelta

Review Comment:
   I think we can move it to the top



##########
providers/common/ai/src/airflow/providers/common/ai/operators/llm_schema_compare.py:
##########
@@ -313,8 +324,32 @@ def execute(self, context: Context) -> dict[str, Any]:
         self.log.info("Running LLM schema comparison...")
         result = agent.run_sync(self.prompt, usage_limits=self.usage_limits)
         log_run_summary(self.log, result)
+        output = result.output
 
-        output_result = result.output.model_dump()
+        output_result = output.model_dump()
         self.log.info("Schema comparison result: \n %s", 
json.dumps(output_result, indent=2))
 
+        if self.require_approval:
+            severity_counts = Counter(mismatch.severity for mismatch in 
output.mismatches)
+            summary = ", ".join(
+                f"{severity_counts[severity]} {severity}"
+                for severity in ("critical", "warning", "info")
+                if severity_counts[severity]
+            )
+            body = (
+                f"Compatible: {output.compatible}"
+                + (f" (mismatches: {summary})" if summary else "")
+                + f"\n\n```\nPrompt: 
{self.prompt}\n\n{output.model_dump_json(indent=2)}\n```"
+            )
+            self.defer_for_approval(context, output, body=body)  # type: 
ignore[misc]
+
         return output_result
+
+    def execute_complete(self, context: Context, generated_output: str, event: 
dict[str, Any]) -> Any:
+        output = super().execute_complete(context, generated_output, event)
+        if not isinstance(output, dict):

Review Comment:
   we only check ths type here. how do we know whether it's a valid 
SchemaCompareResult JSON or not? 



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to