Airflow Summit 2026 is coming August 31 - September 2 in Austin, TX. Register now to secure your spot!

Source code for tests.system.microsoft.azure.example_azure_ai_agents

#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
"""
System test for Azure AI Foundry Hosted agent operators.

Requires a real Azure AI Foundry project and a Hosted agent container image pushed to
Azure Container Registry:

* ``AIRFLOW_CONN_AZURE_AI_AGENTS_DEFAULT``: Azure AI Agents connection URI.
* ``AZURE_AI_AGENTS_ENDPOINT``: Azure AI Foundry project endpoint.
* ``AZURE_AI_AGENTS_CONTAINER_IMAGE``: Hosted agent container image URI.
* ``AZURE_AI_AGENTS_MODEL_DEPLOYMENT_NAME``: Model deployment available in the project.
* ``AZURE_AI_AGENTS_RUN_PROTOCOL``: Optional runtime protocol to invoke (``responses`` or ``invocations``).
* ``AZURE_AI_AGENTS_USE_MODEL``: Optional, defaults to ``false`` for a deterministic smoke test.
* ``AZURE_AI_AGENTS_USE_MOCKS``: Optional, defaults to ``true`` so the sample agent does not need
  external service credentials.
"""

from __future__ import annotations

import atexit
import json
import os
import tempfile
from datetime import datetime
from typing import Any

from airflow.providers.microsoft.azure.operators.ai_agents import (
    CreateAzureAIAgentOperator,
    DeleteAzureAIAgentOperator,
    RunAzureAIAgentOperator,
    UpdateAzureAIAgentOperator,
)

from tests_common.test_utils.version_compat import AIRFLOW_V_3_0_PLUS

if AIRFLOW_V_3_0_PLUS:
    from airflow.sdk import DAG, chain
else:
    from airflow.models.baseoperator import chain  # type: ignore[attr-defined,no-redef]
    from airflow.models.dag import DAG  # type: ignore[attr-defined,no-redef,assignment]

try:
    from airflow.sdk import TriggerRule
except ImportError:
    from airflow.utils.trigger_rule import TriggerRule  # type: ignore[no-redef,attr-defined]

[docs] DAG_ID = "example_azure_ai_agents"
[docs] ENV_ID = os.environ.get("SYSTEM_TESTS_ENV_ID") or "default"
def _get_env(name: str, default: str = "") -> str: return os.environ.get(name) or os.environ.get(f"AIRFLOW_VAR_{name}", default)
[docs] AZURE_AI_AGENTS_CONN_ID = _get_env("AZURE_AI_AGENTS_CONN_ID", "azure_ai_agents_default")
[docs] AZURE_AI_AGENTS_CONN_URI = _get_env("AIRFLOW_CONN_AZURE_AI_AGENTS_DEFAULT")
[docs] ENDPOINT = _get_env("AZURE_AI_AGENTS_ENDPOINT")
[docs] MODEL_DEPLOYMENT_NAME = _get_env("AZURE_AI_AGENTS_MODEL_DEPLOYMENT_NAME", "gpt-4o")
[docs] CONTAINER_IMAGE = _get_env( "AZURE_AI_AGENTS_CONTAINER_IMAGE", "myregistry.azurecr.io/airflow-hosted-agent:latest" )
[docs] AGENT_NAME = _get_env("AZURE_AI_AGENT_NAME", f"airflow-ai-agent-{ENV_ID}")
[docs] RUN_AGENT_PROTOCOL = _get_env("AZURE_AI_AGENTS_RUN_PROTOCOL").lower()
if RUN_AGENT_PROTOCOL not in {"", "responses", "invocations"}: raise RuntimeError("AZURE_AI_AGENTS_RUN_PROTOCOL must be either 'responses' or 'invocations'.")
[docs] HOSTED_AGENT_PROTOCOL = RUN_AGENT_PROTOCOL or "responses"
[docs] run_agent: RunAzureAIAgentOperator | None
[docs] HOSTED_AGENT_DEFINITION: dict[str, Any] = { "kind": "hosted", "container_configuration": { "image": CONTAINER_IMAGE, }, "cpu": "1", "memory": "2Gi", "protocol_versions": [ {"protocol": HOSTED_AGENT_PROTOCOL, "version": "1.0.0"}, ], "environment_variables": { "AZURE_AI_MODEL_DEPLOYMENT_NAME": MODEL_DEPLOYMENT_NAME, "AIRFLOW_AGENT_FOUNDRY_PROJECT_ENDPOINT": ENDPOINT, "AIRFLOW_AGENT_USE_MODEL": _get_env("AZURE_AI_AGENTS_USE_MODEL", "false"), "AIRFLOW_AGENT_USE_MOCKS": _get_env("AZURE_AI_AGENTS_USE_MOCKS", "true"), }, }
[docs] UPDATED_AGENT_DEFINITION: dict[str, Any] = { **HOSTED_AGENT_DEFINITION, "environment_variables": { **HOSTED_AGENT_DEFINITION["environment_variables"], "AIRFLOW_AGENT_BEHAVIOR": "troubleshoot-airflow-task-failures", }, }
[docs] SMOKE_FAILURE_CONTEXT = json.dumps( { "dag_id": "azure_ai_agents_demo_failing_etl", "run_id": "manual__azure_ai_agents_smoke", "dag_file": "azure_ai_agents/demo_failing_etl.py", "failed_task": { "task_id": "transform", "state": "failed", "try_number": 1, }, "log_excerpt": "KeyError: 'rowz'", } )
[docs] RUN_AGENT_PROMPT = ( "Analyze this Airflow failure context and return JSON with summary, " "root_cause, and suggested_fix. Do not claim PR or Slack actions unless " "the hosted agent tools actually performed them.\n\n" f"{SMOKE_FAILURE_CONTEXT}" )
[docs] RUN_AGENT_INPUT = {"input" if RUN_AGENT_PROTOCOL == "responses" else "message": RUN_AGENT_PROMPT}
[docs] def create_connection_file(conn_id_name: str, conn_uri: str) -> str | None: if not conn_uri: return None with tempfile.NamedTemporaryFile("w", suffix=".env", delete=False) as conn_file: conn_file.write(f"{conn_id_name}={conn_uri}\n") atexit.register(os.unlink, conn_file.name) return conn_file.name
[docs] CONN_FILE_PATH = create_connection_file(AZURE_AI_AGENTS_CONN_ID, AZURE_AI_AGENTS_CONN_URI)
with DAG( dag_id=DAG_ID, schedule="@once", start_date=datetime(2021, 1, 1), catchup=False, ) as dag: # [START howto_operator_azure_ai_agent_create]
[docs] create_agent = CreateAzureAIAgentOperator( task_id="create_agent", agent_name=AGENT_NAME, definition=HOSTED_AGENT_DEFINITION, poll_interval=10, timeout=900, deferrable=False, azure_ai_agents_conn_id=AZURE_AI_AGENTS_CONN_ID, endpoint=ENDPOINT, )
# [END howto_operator_azure_ai_agent_create] # [START howto_operator_azure_ai_agent_update] update_agent = UpdateAzureAIAgentOperator( task_id="update_agent", agent_name=AGENT_NAME, definition=UPDATED_AGENT_DEFINITION, poll_interval=10, timeout=900, deferrable=False, azure_ai_agents_conn_id=AZURE_AI_AGENTS_CONN_ID, endpoint=ENDPOINT, ) # [END howto_operator_azure_ai_agent_update] # [START howto_operator_azure_ai_agent_update_deferrable] update_agent_deferrable = UpdateAzureAIAgentOperator( task_id="update_agent_deferrable", agent_name=AGENT_NAME, definition=UPDATED_AGENT_DEFINITION, poll_interval=10, timeout=900, deferrable=True, azure_ai_agents_conn_id=AZURE_AI_AGENTS_CONN_ID, endpoint=ENDPOINT, ) # [END howto_operator_azure_ai_agent_update_deferrable] if RUN_AGENT_PROTOCOL: # [START howto_operator_azure_ai_agent_run] run_agent = RunAzureAIAgentOperator( task_id="run_agent", agent_name=AGENT_NAME, protocol=RUN_AGENT_PROTOCOL, input_data=RUN_AGENT_INPUT, azure_ai_agents_conn_id=AZURE_AI_AGENTS_CONN_ID, endpoint=ENDPOINT, ) # [END howto_operator_azure_ai_agent_run] else: run_agent = None # [START howto_operator_azure_ai_agent_delete] delete_agent = DeleteAzureAIAgentOperator( task_id="delete_agent", agent_name=AGENT_NAME, force=True, poll_interval=10, timeout=900, trigger_rule=TriggerRule.ALL_DONE, azure_ai_agents_conn_id=AZURE_AI_AGENTS_CONN_ID, endpoint=ENDPOINT, ) # [END howto_operator_azure_ai_agent_delete] if run_agent is None: chain(create_agent, update_agent, update_agent_deferrable, delete_agent) else: chain(create_agent, update_agent, update_agent_deferrable, run_agent, delete_agent) from tests_common.test_utils.watcher import watcher list(dag.tasks) >> watcher() from tests_common.test_utils.system_tests import get_test_run # noqa: E402
[docs] test_run = get_test_run(dag, conn_file_path=CONN_FILE_PATH)

Was this entry helpful?