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

shahar1 pushed a commit to branch airflow-ctl/v0-1-test
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/airflow-ctl/v0-1-test by this 
push:
     new 5617f7fadbb Accept the awaiting_input task instance state from Airflow 
3.3+ servers (#76118)
5617f7fadbb is described below

commit 5617f7fadbba0455e21ecfe76146e0ae253f4113
Author: Shahar Epstein <[email protected]>
AuthorDate: Sat Oct 31 09:28:31 2026 +0200

    Accept the awaiting_input task instance state from Airflow 3.3+ servers 
(#76118)
    
    Airflow 3.3.0+ servers emit the task-instance state awaiting_input for 
Human-in-the-loop tasks (upstream #68028, b64a0e636d9). airflowctl's 
TaskInstanceState lacked the value, so taskinstances list, tasks 
states-for-dag-run and the tasks clear preview crashed with a pydantic 
ValidationError whenever such a task instance existed on a 3.3.x or 3.4.0rc1 
server. 3.2.x servers never emit the value, so the client is a strict superset 
there.
    
    Only the enum value and what the branch's generators derive from it are 
backported, following 290f0226179: core utils/state.py (IntermediateTIState and 
TaskInstanceState, needed so the generate-openapi-spec output and the 
test_state union invariant stay consistent), both OpenAPI yamls, the UI 
openapi-gen ts files and the task-sdk datamodels. Left out on purpose because 
airflow-core, task-sdk and the UI are not released from this branch: the 
State.AWAITING_INPUT alias, the state_color  [...]
    
    Widening IntermediateTIState also widens the execution API's 
TITargetStatePayload.state and the task-sdk model without a Cadwyn version 
bump, as upstream did; this has no runtime effect on this branch.
---
 .../airflow/api_fastapi/core_api/openapi/_private_ui.yaml    |  1 +
 .../api_fastapi/core_api/openapi/v2-rest-api-generated.yaml  |  1 +
 .../src/airflow/ui/openapi-gen/requests/schemas.gen.ts       |  2 +-
 .../src/airflow/ui/openapi-gen/requests/types.gen.ts         |  2 +-
 airflow-core/src/airflow/utils/state.py                      |  2 ++
 airflow-ctl/src/airflowctl/api/datamodels/generated.py       |  1 +
 airflow-ctl/tests/airflow_ctl/api/test_operations.py         | 12 ++++++++++++
 task-sdk/src/airflow/sdk/api/datamodels/_generated.py        |  2 ++
 8 files changed, 21 insertions(+), 2 deletions(-)

diff --git 
a/airflow-core/src/airflow/api_fastapi/core_api/openapi/_private_ui.yaml 
b/airflow-core/src/airflow/api_fastapi/core_api/openapi/_private_ui.yaml
index 598b5e94ffb..8d3bba67267 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/openapi/_private_ui.yaml
+++ b/airflow-core/src/airflow/api_fastapi/core_api/openapi/_private_ui.yaml
@@ -3183,6 +3183,7 @@ components:
       - upstream_failed
       - skipped
       - deferred
+      - awaiting_input
       title: TaskInstanceState
       description: 'All possible states that a Task Instance can be in.
 
diff --git 
a/airflow-core/src/airflow/api_fastapi/core_api/openapi/v2-rest-api-generated.yaml
 
b/airflow-core/src/airflow/api_fastapi/core_api/openapi/v2-rest-api-generated.yaml
index f0875f305bb..c4cd87f3a08 100644
--- 
a/airflow-core/src/airflow/api_fastapi/core_api/openapi/v2-rest-api-generated.yaml
+++ 
b/airflow-core/src/airflow/api_fastapi/core_api/openapi/v2-rest-api-generated.yaml
@@ -12918,6 +12918,7 @@ components:
       - upstream_failed
       - skipped
       - deferred
+      - awaiting_input
       title: TaskInstanceState
       description: 'All possible states that a Task Instance can be in.
 
diff --git a/airflow-core/src/airflow/ui/openapi-gen/requests/schemas.gen.ts 
b/airflow-core/src/airflow/ui/openapi-gen/requests/schemas.gen.ts
index 0c7ee2e5f1d..87243cf7363 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/requests/schemas.gen.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/requests/schemas.gen.ts
@@ -5845,7 +5845,7 @@ export const $TaskInstanceResponse = {
 
 export const $TaskInstanceState = {
     type: 'string',
-    enum: ['removed', 'scheduled', 'queued', 'running', 'success', 
'restarting', 'failed', 'up_for_retry', 'up_for_reschedule', 'upstream_failed', 
'skipped', 'deferred'],
+    enum: ['removed', 'scheduled', 'queued', 'running', 'success', 
'restarting', 'failed', 'up_for_retry', 'up_for_reschedule', 'upstream_failed', 
'skipped', 'deferred', 'awaiting_input'],
     title: 'TaskInstanceState',
     description: `All possible states that a Task Instance can be in.
 
diff --git a/airflow-core/src/airflow/ui/openapi-gen/requests/types.gen.ts 
b/airflow-core/src/airflow/ui/openapi-gen/requests/types.gen.ts
index 2feb9ab4566..53cb0e415f8 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/requests/types.gen.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/requests/types.gen.ts
@@ -1468,7 +1468,7 @@ export type TaskInstanceResponse = {
  *
  * Note that None is also allowed, so always use this in a type hint with 
Optional.
  */
-export type TaskInstanceState = 'removed' | 'scheduled' | 'queued' | 'running' 
| 'success' | 'restarting' | 'failed' | 'up_for_retry' | 'up_for_reschedule' | 
'upstream_failed' | 'skipped' | 'deferred';
+export type TaskInstanceState = 'removed' | 'scheduled' | 'queued' | 'running' 
| 'success' | 'restarting' | 'failed' | 'up_for_retry' | 'up_for_reschedule' | 
'upstream_failed' | 'skipped' | 'deferred' | 'awaiting_input';
 
 /**
  * Task Instance body for get batch.
diff --git a/airflow-core/src/airflow/utils/state.py 
b/airflow-core/src/airflow/utils/state.py
index 332efb10553..ace056c333f 100644
--- a/airflow-core/src/airflow/utils/state.py
+++ b/airflow-core/src/airflow/utils/state.py
@@ -56,6 +56,7 @@ class IntermediateTIState(str, Enum):
     UP_FOR_RETRY = "up_for_retry"
     UP_FOR_RESCHEDULE = "up_for_reschedule"
     DEFERRED = "deferred"
+    AWAITING_INPUT = "awaiting_input"
 
     def __str__(self) -> str:
         return self.value
@@ -87,6 +88,7 @@ class TaskInstanceState(str, Enum):
     UPSTREAM_FAILED = TerminalTIState.UPSTREAM_FAILED  # One or more upstream 
deps failed
     SKIPPED = TerminalTIState.SKIPPED  # Skipped by branching or some other 
mechanism
     DEFERRED = IntermediateTIState.DEFERRED  # Deferrable operator waiting on 
a trigger
+    AWAITING_INPUT = IntermediateTIState.AWAITING_INPUT  # Parked waiting for 
human input (HITL)
 
     def __str__(self) -> str:
         return self.value
diff --git a/airflow-ctl/src/airflowctl/api/datamodels/generated.py 
b/airflow-ctl/src/airflowctl/api/datamodels/generated.py
index b8f1e473dad..e0ed5f45c03 100644
--- a/airflow-ctl/src/airflowctl/api/datamodels/generated.py
+++ b/airflow-ctl/src/airflowctl/api/datamodels/generated.py
@@ -809,6 +809,7 @@ class TaskInstanceState(str, Enum):
     UPSTREAM_FAILED = "upstream_failed"
     SKIPPED = "skipped"
     DEFERRED = "deferred"
+    AWAITING_INPUT = "awaiting_input"
 
 
 class TaskInstancesBatchBody(BaseModel):
diff --git a/airflow-ctl/tests/airflow_ctl/api/test_operations.py 
b/airflow-ctl/tests/airflow_ctl/api/test_operations.py
index 9e510c55f63..ad701bec997 100644
--- a/airflow-ctl/tests/airflow_ctl/api/test_operations.py
+++ b/airflow-ctl/tests/airflow_ctl/api/test_operations.py
@@ -1809,6 +1809,18 @@ class TestTaskInstancesOperations:
         response = client.task_instances.list(dag_id="dag_id", 
dag_run_id="dag_run_id")
         assert response == self.task_instance_collection_response
 
+    def test_list_accepts_awaiting_input_state(self):
+        """Servers on Airflow 3.3+ report Human-in-the-loop task instances as 
``awaiting_input``."""
+        payload = 
json.loads(self.task_instance_collection_response.model_dump_json())
+        payload["task_instances"][0]["state"] = "awaiting_input"
+
+        def handle_request(request: httpx.Request) -> httpx.Response:
+            return httpx.Response(200, json=payload)
+
+        client = make_api_client(transport=httpx.MockTransport(handle_request))
+        response = client.task_instances.list(dag_id="dag_id", 
dag_run_id="dag_run_id")
+        assert response.task_instances[0].state == 
TaskInstanceState.AWAITING_INPUT
+
 
 class TestTasksOperations:
     dag_id = "dag_id"
diff --git a/task-sdk/src/airflow/sdk/api/datamodels/_generated.py 
b/task-sdk/src/airflow/sdk/api/datamodels/_generated.py
index f0df33dda86..8573336e862 100644
--- a/task-sdk/src/airflow/sdk/api/datamodels/_generated.py
+++ b/task-sdk/src/airflow/sdk/api/datamodels/_generated.py
@@ -176,6 +176,7 @@ class IntermediateTIState(str, Enum):
     UP_FOR_RETRY = "up_for_retry"
     UP_FOR_RESCHEDULE = "up_for_reschedule"
     DEFERRED = "deferred"
+    AWAITING_INPUT = "awaiting_input"
 
 
 class PrevSuccessfulDagRunResponse(BaseModel):
@@ -341,6 +342,7 @@ class TaskInstanceState(str, Enum):
     UPSTREAM_FAILED = "upstream_failed"
     SKIPPED = "skipped"
     DEFERRED = "deferred"
+    AWAITING_INPUT = "awaiting_input"
 
 
 class TaskStatesResponse(BaseModel):

Reply via email to