This is an automated email from the ASF dual-hosted git repository.
ashb pushed a change to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
from 051d5d85d2f TS SDK: Add human-in-the-loop tasks to native Dags (#74484)
new 0c3853692bc Add user-facing docs for the new Task Loops feature.
(#74274)
new 78572f6efc7 Introduce the (internal/db level) concept of "dynamic
regions" for TIs (#74275)
new 2f7d9662623 Resolve live producers by region and read their XCom by
attempt (#74344)
new 9bc8cad3f84 Pin loop definitions and carry region coordinates through
task execution (#74345)
new 93f857f40da Give every mapped expansion a region and store its index
as region_index (#74346)
new 6b20a69691e Attribute log, asset-event and asset-state writes to the
task attempt (#74347)
new 551d54bdaee Run loop gates and advance iterations atomically (#74348)
new ea4519b9f56 Clear selected loop work and regenerate only what was
replaced (#74349)
new 0226554076f Read current task executions by exact region and try
(#74350)
new feafb6c5ee1 Let the HITL review plugin address one loop pass or mapped
slot (#74351)
new d0f83bb4a3a Show current task executions in the UI (#74352)
new fe589528ee4 Show loop iterations and outcomes throughout the UI
(#74354)
The 12 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.../dag-serialization.rst | 2 +-
.../task-and-asset-state-store.rst | 4 +-
.../docs/authoring-and-scheduling/deferring.rst | 2 +-
.../dynamic-task-mapping.rst | 18 +-
.../docs/authoring-and-scheduling/index.rst | 2 +
.../loops-and-mapped-tasks.rst | 61 +
.../docs/authoring-and-scheduling/loops.rst | 392 +++++
.../core-concepts/task-and-asset-state-store.rst | 2 +-
.../docs/core-concepts/task-state-store.rst | 4 +-
airflow-core/docs/core-concepts/tasks.rst | 2 +-
airflow-core/docs/migrations-ref.rst | 11 +-
airflow-core/newsfragments/task-loops.feature.rst | 1 +
.../airflow/api_fastapi/common/parameters/misc.py | 3 +-
.../airflow/api_fastapi/common/parameters/sort.py | 6 +-
.../api_fastapi/common/parameters/task_instance.py | 7 +-
.../src/airflow/api_fastapi/common/region.py | 54 +
.../core_api/datamodels/asset_state_store.py | 8 +-
.../api_fastapi/core_api/datamodels/assets.py | 2 +
.../api_fastapi/core_api/datamodels/event_logs.py | 2 +
.../core_api/datamodels/task_instance_history.py | 10 +-
.../core_api/datamodels/task_instances.py | 42 +-
.../api_fastapi/core_api/datamodels/ui/common.py | 4 +
.../datamodels/ui/{gantt.py => execution.py} | 44 +-
.../api_fastapi/core_api/datamodels/ui/gantt.py | 10 +-
.../api_fastapi/core_api/datamodels/ui/grid.py | 58 +
.../core_api/datamodels/ui/structure.py | 4 +
.../api_fastapi/core_api/datamodels/xcom.py | 10 +-
.../api_fastapi/core_api/openapi/_private_ui.yaml | 653 +++++++++
.../core_api/openapi/v2-rest-api-generated.yaml | 1150 ++++++++++++++-
.../core_api/routes/public/asset_state_store.py | 16 +
.../api_fastapi/core_api/routes/public/assets.py | 6 +
.../api_fastapi/core_api/routes/public/dag_run.py | 7 +-
.../core_api/routes/public/event_logs.py | 33 +-
.../core_api/routes/public/extra_links.py | 39 +-
.../api_fastapi/core_api/routes/public/hitl.py | 98 +-
.../api_fastapi/core_api/routes/public/log.py | 27 +-
.../core_api/routes/public/task_instances.py | 537 +++++--
.../core_api/routes/public/task_state_store.py | 105 +-
.../api_fastapi/core_api/routes/public/xcom.py | 119 +-
.../api_fastapi/core_api/routes/ui/__init__.py | 2 +
.../airflow/api_fastapi/core_api/routes/ui/dags.py | 12 +-
.../api_fastapi/core_api/routes/ui/execution.py | 112 ++
.../api_fastapi/core_api/routes/ui/gantt.py | 28 +-
.../airflow/api_fastapi/core_api/routes/ui/grid.py | 123 +-
.../core_api/services/public/dag_run.py | 119 +-
.../core_api/services/public/event_logs.py | 10 +-
.../core_api/services/public/task_coordinates.py | 249 ++++
.../core_api/services/public/task_instances.py | 398 ++++-
.../api_fastapi/core_api/services/ui/execution.py | 74 +
.../api_fastapi/core_api/services/ui/grid.py | 278 +++-
.../api_fastapi/core_api/services/ui/task_group.py | 15 +
.../src/airflow/api_fastapi/execution_api/app.py | 12 +-
.../execution_api/datamodels/taskinstance.py | 39 +-
.../execution_api/routes/asset_state_store.py | 40 +-
.../execution_api/routes/task_instances.py | 496 +++++--
.../execution_api/routes/task_state_store.py | 8 +-
.../api_fastapi/execution_api/routes/xcoms.py | 359 ++++-
.../api_fastapi/execution_api/versions/__init__.py | 8 +
.../execution_api/versions/v2026_10_30.py | 25 +
.../versions/v2026_10_30_xcom_params.py} | 32 +-
.../src/airflow/api_fastapi/logging/decorators.py | 39 +
airflow-core/src/airflow/assets/manager.py | 7 +-
.../src/airflow/cli/commands/dag_command.py | 9 +-
.../airflow/cli/commands/state_store_command.py | 6 +-
.../src/airflow/cli/commands/task_command.py | 103 +-
.../src/airflow/example_dags/example_task_loops.py | 114 ++
.../src/airflow/executors/base_executor.py | 5 +-
.../src/airflow/executors/workloads/task.py | 23 +-
.../src/airflow/jobs/scheduler_job_runner.py | 205 ++-
.../src/airflow/jobs/triggerer_job_runner.py | 37 +-
airflow-core/src/airflow/migrations/utils.py | 72 +
.../0142_3_4_0_unify_task_attempt_ownership.py | 26 +-
.../0143_3_4_0_add_dynamic_region_storage.py | 211 +++
.../versions/0144_3_4_0_rename_stored_map_index.py | 76 +
.../0145_3_4_0_add_task_identity_to_events.py | 49 +
.../0146_3_4_0_add_asset_state_writer_identity.py | 55 +
airflow-core/src/airflow/models/__init__.py | 1 +
airflow-core/src/airflow/models/asset.py | 11 +-
.../src/airflow/models/asset_state_store.py | 9 +-
airflow-core/src/airflow/models/dagrun.py | 627 ++++++--
airflow-core/src/airflow/models/dynamic_region.py | 885 +++++++++++
airflow-core/src/airflow/models/expandinput.py | 31 +-
airflow-core/src/airflow/models/log.py | 71 +-
.../src/airflow/models/renderedtifields.py | 2 +-
airflow-core/src/airflow/models/serialized_dag.py | 4 +-
.../src/airflow/models/task_coordinates.py | 838 +++++++++++
.../src/airflow/models/task_state_store.py | 20 +-
airflow-core/src/airflow/models/taskinstance.py | 773 +++++++++-
airflow-core/src/airflow/models/trigger.py | 17 +-
airflow-core/src/airflow/models/xcom.py | 71 +-
.../src/airflow/serialization/dag_version_diff.py | 2 +
.../serialization/definitions/baseoperator.py | 6 +-
.../src/airflow/serialization/definitions/dag.py | 154 +-
.../serialization/definitions/mappedoperator.py | 55 +-
.../serialization/definitions/operatorlink.py | 8 +-
.../airflow/serialization/definitions/taskgroup.py | 10 +
.../airflow/serialization/definitions/xcom_arg.py | 111 +-
airflow-core/src/airflow/serialization/schema.json | 12 +
.../airflow/serialization/serialized_objects.py | 22 +-
airflow-core/src/airflow/state/metastore.py | 94 +-
airflow-core/src/airflow/ti_deps/dep_context.py | 71 +-
.../airflow/ti_deps/deps/mapped_task_expanded.py | 2 +-
.../ti_deps/deps/mapped_task_upstream_dep.py | 37 +-
.../ti_deps/deps/not_previously_skipped_dep.py | 8 +-
.../airflow/ti_deps/deps/ready_to_reschedule.py | 9 +-
.../src/airflow/ti_deps/deps/trigger_rule_dep.py | 98 +-
.../src/airflow/ui/openapi-gen/queries/common.ts | 170 ++-
.../ui/openapi-gen/queries/ensureQueryData.ts | 257 +++-
.../src/airflow/ui/openapi-gen/queries/prefetch.ts | 257 +++-
.../src/airflow/ui/openapi-gen/queries/queries.ts | 363 ++++-
.../src/airflow/ui/openapi-gen/queries/suspense.ts | 257 +++-
.../airflow/ui/openapi-gen/requests/schemas.gen.ts | 1205 +++++++++++++--
.../ui/openapi-gen/requests/services.gen.ts | 366 ++++-
.../airflow/ui/openapi-gen/requests/types.gen.ts | 526 ++++++-
.../airflow/ui/public/i18n/locales/en/common.json | 2 +
.../src/airflow/ui/public/i18n/locales/en/dag.json | 47 +
.../airflow/ui/public/i18n/locales/en/dags.json | 4 +-
.../components/ActionAccordion/ActionAccordion.tsx | 6 +-
.../ui/src/components/ActionAccordion/columns.tsx | 16 +-
.../TaskInstance/ClearGroupTaskInstanceDialog.tsx | 1 -
.../ClearTaskInstanceConfirmationDialog.tsx | 33 +-
.../TaskInstance/ClearTaskInstanceDialog.test.tsx | 357 ++++-
.../Clear/TaskInstance/ClearTaskInstanceDialog.tsx | 383 +++--
.../ui/src/components/DurationChart.test.tsx | 36 +-
.../airflow/ui/src/components/DurationChart.tsx | 10 +-
.../ui/src/components/Graph/TaskLink.test.tsx | 6 +-
.../airflow/ui/src/components/Graph/TaskLink.tsx | 11 +-
.../airflow/ui/src/components/Graph/TaskNode.tsx | 4 +
.../ui/src/components/Graph/elkGraphUtils.ts | 6 +
.../ui/src/components/Graph/reactflowUtils.ts | 2 +
.../TaskInstance/MarkTaskInstanceAsDialog.test.tsx | 61 +-
.../TaskInstance/MarkTaskInstanceAsDialog.tsx | 14 +-
.../ui/src/components/TaskInstanceTooltip.test.tsx | 1 +
.../ui/src/components/TaskInstanceTooltip.tsx | 31 +-
.../src/airflow/ui/src/components/TaskName.tsx | 17 +-
.../ui/src/components/TaskTrySelect.test.tsx | 18 +-
.../airflow/ui/src/components/TaskTrySelect.tsx | 31 +-
.../src/airflow/ui/src/constants/searchParams.ts | 5 +
.../ui/src/hooks/useHITLReviewTabs.test.tsx | 58 +
.../src/airflow/ui/src/hooks/useHITLReviewTabs.ts | 26 +-
.../src/airflow/ui/src/hooks/useLoopRuleStats.tsx | 61 +
.../ui/src/hooks/usePluginAppliesToContext.test.ts | 36 +-
.../ui/src/hooks/usePluginAppliesToContext.ts | 4 +-
.../airflow/ui/src/hooks/useRequiredActionTabs.ts | 55 +-
.../ui/src/hooks/useSelectedVersion.test.tsx | 73 +
.../src/airflow/ui/src/hooks/useSelectedVersion.ts | 3 +
.../useTaskInstanceCoordinates.ts} | 13 +-
.../ui/src/hooks/useTaskInstanceView.test.ts | 97 ++
.../airflow/ui/src/hooks/useTaskInstanceView.ts | 68 +
.../ui/src/layouts/Details/DagBreadcrumb.test.tsx | 20 +-
.../ui/src/layouts/Details/DagBreadcrumb.tsx | 6 +-
.../airflow/ui/src/layouts/Details/Gantt/Gantt.tsx | 1 -
.../layouts/Details/Gantt/GanttTimeline.test.tsx | 120 +-
.../ui/src/layouts/Details/Gantt/GanttTimeline.tsx | 20 +-
.../ui/src/layouts/Details/Gantt/utils.test.ts | 122 +-
.../airflow/ui/src/layouts/Details/Gantt/utils.ts | 50 +-
.../airflow/ui/src/layouts/Details/Grid/Bar.tsx | 3 +-
.../ui/src/layouts/Details/Grid/GridButton.tsx | 4 +-
.../ui/src/layouts/Details/Grid/GridTI.test.tsx | 13 +
.../airflow/ui/src/layouts/Details/Grid/GridTI.tsx | 10 +-
.../layouts/Details/Grid/TaskInstancesColumn.tsx | 1 +
.../ui/src/layouts/Details/Grid/TaskNames.tsx | 5 +-
.../Asset/AssetStateStore/AssetStateStore.test.tsx | 123 ++
.../Asset/AssetStateStore/AssetStateStore.tsx | 14 +-
.../airflow/ui/src/pages/Events/Events.test.tsx | 61 +
.../src/airflow/ui/src/pages/Events/Events.tsx | 8 +-
.../pages/GroupTaskInstance/GroupTaskInstance.tsx | 1 +
.../GroupTaskInstance/GroupTaskInstances.test.tsx | 93 ++
.../pages/GroupTaskInstance/GroupTaskInstances.tsx | 47 +
.../ui/src/pages/GroupTaskInstance/Header.tsx | 19 +
.../LoopIterations/IterationSelect.test.tsx | 107 ++
.../LoopIterations/IterationSelect.tsx | 155 ++
.../{ => LoopIterations}/index.ts | 3 +-
.../LoopIterations/loopUtils.test.ts | 110 ++
.../GroupTaskInstance/LoopIterations/loopUtils.ts | 58 +
.../ui/src/pages/GroupTaskInstance/index.ts | 2 +-
.../GroupTaskInstance/useLoopOutcomeStats.tsx | 74 +
.../pages/HITLTaskInstances/HITLResponseForm.tsx | 2 +
.../src/airflow/ui/src/pages/ReactPlugin.test.tsx | 28 +-
.../src/airflow/ui/src/pages/ReactPlugin.tsx | 4 +
.../airflow/ui/src/pages/Run/Execution.test.tsx | 512 +++++++
.../src/airflow/ui/src/pages/Run/Execution.tsx | 325 ++++
airflow-core/src/airflow/ui/src/pages/Run/Run.tsx | 1 +
.../airflow/ui/src/pages/Task/GroupTaskHeader.tsx | 7 +-
.../pages/Task/Overview/LoopHistoryChart.test.tsx | 129 ++
.../src/pages/Task/Overview/LoopHistoryChart.tsx | 137 ++
.../ui/src/pages/Task/Overview/Overview.test.tsx | 43 +-
.../ui/src/pages/Task/Overview/Overview.tsx | 9 +-
.../ui/src/pages/TaskInstance/AssetEvents.test.tsx | 61 +
.../ui/src/pages/TaskInstance/AssetEvents.tsx | 8 +-
.../ui/src/pages/TaskInstance/BlockingDeps.tsx | 2 +
.../ui/src/pages/TaskInstance/Details.test.tsx | 19 +-
.../airflow/ui/src/pages/TaskInstance/Details.tsx | 64 +-
.../ui/src/pages/TaskInstance/ExtraLinks.test.tsx | 20 +-
.../ui/src/pages/TaskInstance/ExtraLinks.tsx | 3 +
.../ui/src/pages/TaskInstance/HITLResponse.tsx | 4 +
.../ui/src/pages/TaskInstance/Header.test.tsx | 32 +-
.../airflow/ui/src/pages/TaskInstance/Header.tsx | 24 +-
.../pages/TaskInstance/Logs/ExternalLogLink.tsx | 6 +-
.../ui/src/pages/TaskInstance/Logs/Logs.tsx | 28 +-
.../pages/TaskInstance/Logs/LogsTryNumber.test.tsx | 25 +
.../src/pages/TaskInstance/Logs/TaskLogHeader.tsx | 6 +-
.../src/pages/TaskInstance/RenderedTemplates.tsx | 3 +
.../src/pages/TaskInstance/TaskInstance.test.tsx | 253 +++-
.../ui/src/pages/TaskInstance/TaskInstance.tsx | 116 +-
.../TaskInstances/BulkClearTaskInstancesButton.tsx | 126 +-
.../BulkDeleteTaskInstancesButton.tsx | 3 +
.../BulkMarkTaskInstancesAsButton.tsx | 13 +-
.../DeleteTaskInstanceButton.test.tsx | 58 +
.../TaskInstances/DeleteTaskInstanceButton.tsx | 3 +
.../src/pages/TaskInstances/TaskInstances.test.tsx | 88 +-
.../ui/src/pages/TaskInstances/TaskInstances.tsx | 50 +-
.../ClearAllTaskStateStoreButton.tsx | 4 +-
.../TaskStateStore/DeleteTaskStateStoreButton.tsx | 4 +-
.../pages/TaskStateStore/TaskStateStore.test.tsx | 114 ++
.../ui/src/pages/TaskStateStore/TaskStateStore.tsx | 4 +
.../TaskStateStore/TaskStateStoreModal.test.tsx | 81 +
.../pages/TaskStateStore/TaskStateStoreModal.tsx | 5 +-
.../airflow/ui/src/pages/XCom/AddXComButton.tsx | 4 +
.../airflow/ui/src/pages/XCom/DeleteXComButton.tsx | 2 +
.../airflow/ui/src/pages/XCom/EditXComButton.tsx | 2 +
.../src/airflow/ui/src/pages/XCom/XCom.tsx | 24 +-
.../airflow/ui/src/pages/XCom/XComEntry.test.tsx | 46 +-
.../src/airflow/ui/src/pages/XCom/XComEntry.tsx | 15 +-
.../airflow/ui/src/pages/XCom/XComModal.test.tsx | 82 ++
.../src/airflow/ui/src/pages/XCom/XComModal.tsx | 21 +-
.../airflow/ui/src/queries/gridViewQueryKeys.ts | 4 +
.../airflow/ui/src/queries/useBulkClearDryRun.ts | 114 --
.../ui/src/queries/useBulkClearTaskInstances.ts | 133 --
.../ui/src/queries/useBulkMarkAsDryRun.test.tsx | 76 +
.../airflow/ui/src/queries/useBulkMarkAsDryRun.ts | 4 +-
.../ui/src/queries/useClearTaskInstances.test.tsx | 82 ++
.../ui/src/queries/useClearTaskInstances.ts | 38 +-
.../queries/useClearTaskInstancesDryRun.test.tsx | 88 ++
.../ui/src/queries/useClearTaskInstancesDryRun.ts | 57 +-
.../index.ts => queries/useIsLoopGroup.ts} | 14 +-
.../src/airflow/ui/src/queries/useLogs.test.ts | 44 +-
.../src/airflow/ui/src/queries/useLogs.tsx | 22 +-
.../index.ts => queries/useLoopHistory.ts} | 7 +-
.../airflow/ui/src/queries/useLoopSummary.test.tsx | 93 ++
.../src/airflow/ui/src/queries/useLoopSummary.ts | 77 +
.../ui/src/queries/usePatchTaskInstance.test.tsx | 60 +
.../airflow/ui/src/queries/usePatchTaskInstance.ts | 6 +-
.../ui/src/queries/usePatchTaskInstanceDryRun.ts | 2 +
.../ui/src/queries/useTaskInstanceNote.test.tsx | 54 +
.../airflow/ui/src/queries/useTaskInstanceNote.ts | 2 +-
.../airflow/ui/src/queries/useUpdateHITLDetail.ts | 6 +
airflow-core/src/airflow/ui/src/router.tsx | 6 +-
.../index.ts => utils/executionParams.test.ts} | 16 +-
.../index.ts => utils/executionParams.ts} | 20 +-
.../src/airflow/ui/src/utils/links.test.ts | 15 +
airflow-core/src/airflow/ui/src/utils/links.ts | 18 +-
.../index.ts => utils/loopTaskInstance.ts} | 4 +-
airflow-core/src/airflow/utils/db.py | 5 +-
airflow-core/src/airflow/utils/db_cleanup.py | 8 +-
.../src/airflow/utils/log/file_task_handler.py | 42 +-
.../src/airflow/utils/log/task_log_address.py | 268 ++++
airflow-core/src/airflow/utils/sqlalchemy.py | 57 +-
.../unit/api_fastapi/common/test_parameters.py | 12 +
.../routes/public/test_asset_state_store.py | 55 +
.../core_api/routes/public/test_assets.py | 61 +
.../core_api/routes/public/test_dag_run.py | 212 ++-
.../core_api/routes/public/test_event_logs.py | 205 ++-
.../core_api/routes/public/test_execution.py | 177 +++
.../core_api/routes/public/test_extra_links.py | 111 +-
.../core_api/routes/public/test_hitl.py | 140 ++
.../api_fastapi/core_api/routes/public/test_log.py | 129 +-
.../core_api/routes/public/test_task_instances.py | 1546 +++++++++++++++++++-
.../routes/public/test_task_state_store.py | 143 +-
.../core_api/routes/public/test_xcom.py | 164 ++-
.../api_fastapi/core_api/routes/test_routes.py | 22 +
.../core_api/routes/ui/test_execution.py | 82 ++
.../api_fastapi/core_api/routes/ui/test_gantt.py | 47 +
.../api_fastapi/core_api/routes/ui/test_grid.py | 435 +++++-
.../core_api/routes/ui/test_structure.py | 28 +
.../core_api/services/ui/test_execution.py | 72 +
.../unit/api_fastapi/execution_api/test_app.py | 2 +-
.../versions/head/test_asset_state_store.py | 52 +
.../versions/head/test_task_instances.py | 1441 +++++++++++++++++-
.../versions/head/test_task_state_store.py | 27 +-
.../execution_api/versions/head/test_xcoms.py | 682 ++++++++-
.../versions/v2026_10_30/test_task_instances.py | 16 +
.../unit/api_fastapi/logging/test_decorators.py | 67 +
airflow-core/tests/unit/assets/test_manager.py | 6 +-
.../tests/unit/callbacks/test_callback_requests.py | 13 +-
.../tests/unit/cli/commands/test_dag_command.py | 40 +-
.../unit/cli/commands/test_partition_command.py | 53 +-
.../unit/cli/commands/test_state_store_command.py | 10 +-
.../tests/unit/cli/commands/test_task_command.py | 283 +++-
.../tests/unit/executors/test_base_executor.py | 11 +
.../tests/unit/executors/test_workloads.py | 159 +-
airflow-core/tests/unit/jobs/test_scheduler_job.py | 477 +++++-
airflow-core/tests/unit/jobs/test_triggerer_job.py | 44 +-
.../test_0143_add_dynamic_region_storage.py | 231 +++
.../test_0144_rename_stored_map_index.py | 324 ++++
airflow-core/tests/unit/models/conftest.py | 113 ++
airflow-core/tests/unit/models/test_asset.py | 87 +-
airflow-core/tests/unit/models/test_cleartasks.py | 868 ++++++++++-
airflow-core/tests/unit/models/test_dag.py | 63 +-
airflow-core/tests/unit/models/test_dagrun.py | 904 +++++++++++-
.../tests/unit/models/test_dynamic_region.py | 885 +++++++++++
airflow-core/tests/unit/models/test_log.py | 92 +-
.../tests/unit/models/test_mappedoperator.py | 414 +++++-
.../tests/unit/models/test_task_coordinates.py | 635 ++++++++
airflow-core/tests/unit/models/test_task_data.py | 22 +-
.../tests/unit/models/test_task_state_store.py | 18 +-
.../tests/unit/models/test_taskinstance.py | 402 ++++-
airflow-core/tests/unit/models/test_xcom_arg.py | 242 +++
.../unit/serialization/test_dag_serialization.py | 104 +-
.../unit/serialization/test_dag_version_diff.py | 31 +
airflow-core/tests/unit/state/test_metastore.py | 136 ++
.../ti_deps/deps/test_mapped_task_upstream_dep.py | 33 +-
.../ti_deps/deps/test_ready_to_reschedule_dep.py | 28 +
.../unit/ti_deps/deps/test_trigger_rule_dep.py | 295 +++-
.../tests/unit/utils/log/test_task_log_address.py | 362 +++++
airflow-core/tests/unit/utils/test_db.py | 20 +
airflow-core/tests/unit/utils/test_db_cleanup.py | 49 +-
airflow-core/tests/unit/utils/test_log_handlers.py | 1 +
airflow-core/tests/unit/utils/test_sqlalchemy.py | 62 +-
.../src/airflowctl/api/datamodels/generated.py | 74 +
airflow-ctl/src/airflowctl/ctl/cli_config.py | 30 +-
.../tests/airflow_ctl/api/test_operations.py | 2 +
.../airflow_ctl/ctl/commands/test_task_command.py | 3 +
.../tests/airflow_ctl/ctl/test_cli_config.py | 60 +-
.../src/tests_common/test_utils/asserts.py | 20 +
.../tests_common/test_utils/attempt_ownership.py | 10 +-
.../src/tests_common/test_utils/taskinstance.py | 8 +-
go-sdk/internal/genspec/authoring.go | 2 +
go-sdk/pkg/execution/genmodels/models.gen.go | 75 +-
go-sdk/schema/dag-schema.json | 12 +
go-sdk/schema/supervisor-schema.json | 101 ++
java-sdk/sdk/build.gradle.kts | 1 +
java-sdk/sdk/schema/dag-schema.json | 12 +
.../aws/executors/batch/test_batch_executor.py | 31 +-
.../amazon/aws/executors/ecs/test_ecs_executor.py | 31 +-
providers/common/ai/.pre-commit-config.yaml | 2 +-
providers/common/ai/docs/hitl_review.rst | 5 +
.../providers/common/ai/plugins/hitl_review.py | 125 +-
.../providers/common/ai/plugins/www/package.json | 1 +
.../providers/common/ai/plugins/www/src/api.ts | 13 +-
.../ai/plugins/www/src/components/ChatPage.tsx | 9 +-
.../common/ai/plugins/www/src/hooks/useSession.ts | 5 +-
.../providers/common/ai/plugins/www/src/main.tsx | 46 +-
.../common/ai/plugins/www/tests/api.test.ts | 63 +
.../common/ai/plugins/www/tests/main.test.mjs | 43 +
.../unit/common/ai/plugins/test_hitl_review.py | 469 +++++-
providers/common/io/docs/state_store_backend.rst | 4 +-
providers/common/io/provider.yaml | 4 +-
.../providers/common/io/get_provider_info.py | 2 +-
.../providers/common/io/state_store/backend.py | 32 +-
.../airflow/providers/common/io/version_compat.py | 1 +
.../unit/common/io/state_store/test_backend.py | 49 +-
.../src/airflow/providers/edge3/cli/api_client.py | 19 +-
.../src/airflow/providers/edge3/cli/worker.py | 3 +
.../providers/edge3/worker_api/datamodels.py | 7 +
.../providers/edge3/worker_api/routes/logs.py | 31 +-
.../edge3/worker_api/v2-edge-generated.yaml | 28 +
.../edge3/tests/unit/edge3/cli/test_api_client.py | 52 +
.../edge3/tests/unit/edge3/cli/test_worker.py | 31 +-
.../unit/edge3/worker_api/routes/test_logs.py | 139 ++
.../providers/elasticsearch/log/es_task_handler.py | 3 +-
.../unit/elasticsearch/log/test_es_task_handler.py | 6 +
.../providers/openlineage/plugins/facets.py | 7 +-
.../providers/openlineage/plugins/listener.py | 37 +-
.../providers/openlineage/plugins/macros.py | 6 +-
.../airflow/providers/openlineage/utils/utils.py | 163 ++-
.../providers/openlineage/version_compat.py | 3 +-
.../unit/openlineage/plugins/test_listener.py | 71 +
.../tests/unit/openlineage/plugins/test_macros.py | 40 +-
.../tests/unit/openlineage/utils/test_utils.py | 252 +++-
.../providers/opensearch/log/os_task_handler.py | 3 +-
.../unit/opensearch/log/test_os_task_handler.py | 6 +
.../check_template_context_variable_in_sync.py | 2 +
scripts/ci/prek/ts_compile_lint_common_ai.py | 1 +
shared/state/src/airflow_shared/state/__init__.py | 48 +-
shared/state/tests/state/test_state.py | 28 +
task-sdk/docs/concepts.rst | 2 +-
task-sdk/docs/deferred-vs-async-operators.rst | 12 +-
task-sdk/docs/dynamic-task-mapping.rst | 8 +-
task-sdk/docs/examples.rst | 4 +-
task-sdk/src/airflow/sdk/api/client.py | 50 +-
.../src/airflow/sdk/api/datamodels/_generated.py | 17 +
task-sdk/src/airflow/sdk/bases/decorator.py | 27 +-
task-sdk/src/airflow/sdk/bases/operator.py | 1 +
task-sdk/src/airflow/sdk/bases/xcom.py | 2 +
.../src/airflow/sdk/definitions/_internal/loop.py | 218 +++
.../src/airflow/sdk/definitions/_internal/node.py | 15 +-
task-sdk/src/airflow/sdk/definitions/context.py | 4 +-
task-sdk/src/airflow/sdk/definitions/dag.py | 17 +-
.../sdk/definitions/decorators/task_group.py | 39 +-
.../src/airflow/sdk/definitions/mappedoperator.py | 1 -
task-sdk/src/airflow/sdk/definitions/xcom_arg.py | 3 +-
task-sdk/src/airflow/sdk/execution_time/comms.py | 4 +
.../airflow/sdk/execution_time/lazy_sequence.py | 4 +
task-sdk/src/airflow/sdk/execution_time/loop.py | 104 ++
.../airflow/sdk/execution_time/request_handlers.py | 34 +-
.../airflow/sdk/execution_time/schema/schema.json | 101 ++
.../sdk/execution_time/schema/versions/__init__.py | 4 +
.../execution_time/schema/versions/v2026_10_30.py | 35 +-
.../src/airflow/sdk/execution_time/supervisor.py | 6 +-
.../src/airflow/sdk/execution_time/task_runner.py | 58 +-
task-sdk/src/airflow/sdk/types.py | 9 +-
.../task_sdk/definitions/_internal/test_loop.py | 431 ++++++
.../task_sdk/definitions/decorators/test_result.py | 39 +-
.../definitions/decorators/test_task_group.py | 120 +-
task-sdk/tests/task_sdk/definitions/test_dag.py | 106 ++
.../tests/task_sdk/definitions/test_xcom_arg.py | 51 +-
.../execution_time/schema/test_migrator.py | 81 +-
.../tests/task_sdk/execution_time/test_comms.py | 16 +-
.../tests/task_sdk/execution_time/test_loop.py | 245 ++++
.../execution_time/test_request_handlers.py | 51 +
.../task_sdk/execution_time/test_supervisor.py | 42 +-
.../task_sdk/execution_time/test_task_runner.py | 111 +-
ts-sdk/schema/dag-schema.json | 12 +
ts-sdk/schema/supervisor-schema.json | 101 ++
ts-sdk/scripts/generate-dag-schema.mjs | 2 +
ts-sdk/src/generated/supervisor.ts | 35 +
417 files changed, 36519 insertions(+), 2878 deletions(-)
create mode 100644
airflow-core/docs/authoring-and-scheduling/loops-and-mapped-tasks.rst
create mode 100644 airflow-core/docs/authoring-and-scheduling/loops.rst
create mode 100644 airflow-core/newsfragments/task-loops.feature.rst
create mode 100644 airflow-core/src/airflow/api_fastapi/common/region.py
copy airflow-core/src/airflow/api_fastapi/core_api/datamodels/ui/{gantt.py =>
execution.py} (52%)
create mode 100644
airflow-core/src/airflow/api_fastapi/core_api/routes/ui/execution.py
create mode 100644
airflow-core/src/airflow/api_fastapi/core_api/services/public/task_coordinates.py
create mode 100644
airflow-core/src/airflow/api_fastapi/core_api/services/ui/execution.py
copy airflow-core/src/airflow/api_fastapi/{core_api/datamodels/ui/grid.py =>
execution_api/versions/v2026_10_30_xcom_params.py} (52%)
create mode 100644 airflow-core/src/airflow/example_dags/example_task_loops.py
create mode 100644
airflow-core/src/airflow/migrations/versions/0143_3_4_0_add_dynamic_region_storage.py
create mode 100644
airflow-core/src/airflow/migrations/versions/0144_3_4_0_rename_stored_map_index.py
create mode 100644
airflow-core/src/airflow/migrations/versions/0145_3_4_0_add_task_identity_to_events.py
create mode 100644
airflow-core/src/airflow/migrations/versions/0146_3_4_0_add_asset_state_writer_identity.py
create mode 100644 airflow-core/src/airflow/models/dynamic_region.py
create mode 100644 airflow-core/src/airflow/models/task_coordinates.py
create mode 100644
airflow-core/src/airflow/ui/src/hooks/useHITLReviewTabs.test.tsx
create mode 100644 airflow-core/src/airflow/ui/src/hooks/useLoopRuleStats.tsx
create mode 100644
airflow-core/src/airflow/ui/src/hooks/useSelectedVersion.test.tsx
copy airflow-core/src/airflow/ui/src/{pages/GroupTaskInstance/index.ts =>
hooks/useTaskInstanceCoordinates.ts} (64%)
create mode 100644
airflow-core/src/airflow/ui/src/hooks/useTaskInstanceView.test.ts
create mode 100644 airflow-core/src/airflow/ui/src/hooks/useTaskInstanceView.ts
create mode 100644
airflow-core/src/airflow/ui/src/pages/Asset/AssetStateStore/AssetStateStore.test.tsx
create mode 100644 airflow-core/src/airflow/ui/src/pages/Events/Events.test.tsx
create mode 100644
airflow-core/src/airflow/ui/src/pages/GroupTaskInstance/GroupTaskInstances.test.tsx
create mode 100644
airflow-core/src/airflow/ui/src/pages/GroupTaskInstance/GroupTaskInstances.tsx
create mode 100644
airflow-core/src/airflow/ui/src/pages/GroupTaskInstance/LoopIterations/IterationSelect.test.tsx
create mode 100644
airflow-core/src/airflow/ui/src/pages/GroupTaskInstance/LoopIterations/IterationSelect.tsx
copy airflow-core/src/airflow/ui/src/pages/GroupTaskInstance/{ =>
LoopIterations}/index.ts (93%)
create mode 100644
airflow-core/src/airflow/ui/src/pages/GroupTaskInstance/LoopIterations/loopUtils.test.ts
create mode 100644
airflow-core/src/airflow/ui/src/pages/GroupTaskInstance/LoopIterations/loopUtils.ts
create mode 100644
airflow-core/src/airflow/ui/src/pages/GroupTaskInstance/useLoopOutcomeStats.tsx
create mode 100644 airflow-core/src/airflow/ui/src/pages/Run/Execution.test.tsx
create mode 100644 airflow-core/src/airflow/ui/src/pages/Run/Execution.tsx
create mode 100644
airflow-core/src/airflow/ui/src/pages/Task/Overview/LoopHistoryChart.test.tsx
create mode 100644
airflow-core/src/airflow/ui/src/pages/Task/Overview/LoopHistoryChart.tsx
create mode 100644
airflow-core/src/airflow/ui/src/pages/TaskInstance/AssetEvents.test.tsx
create mode 100644
airflow-core/src/airflow/ui/src/pages/TaskInstances/DeleteTaskInstanceButton.test.tsx
create mode 100644
airflow-core/src/airflow/ui/src/pages/TaskStateStore/TaskStateStore.test.tsx
create mode 100644
airflow-core/src/airflow/ui/src/pages/TaskStateStore/TaskStateStoreModal.test.tsx
create mode 100644
airflow-core/src/airflow/ui/src/pages/XCom/XComModal.test.tsx
delete mode 100644
airflow-core/src/airflow/ui/src/queries/useBulkClearDryRun.ts
delete mode 100644
airflow-core/src/airflow/ui/src/queries/useBulkClearTaskInstances.ts
create mode 100644
airflow-core/src/airflow/ui/src/queries/useBulkMarkAsDryRun.test.tsx
create mode 100644
airflow-core/src/airflow/ui/src/queries/useClearTaskInstances.test.tsx
create mode 100644
airflow-core/src/airflow/ui/src/queries/useClearTaskInstancesDryRun.test.tsx
copy airflow-core/src/airflow/ui/src/{pages/GroupTaskInstance/index.ts =>
queries/useIsLoopGroup.ts} (54%)
copy airflow-core/src/airflow/ui/src/{pages/GroupTaskInstance/index.ts =>
queries/useLoopHistory.ts} (70%)
create mode 100644
airflow-core/src/airflow/ui/src/queries/useLoopSummary.test.tsx
create mode 100644 airflow-core/src/airflow/ui/src/queries/useLoopSummary.ts
create mode 100644
airflow-core/src/airflow/ui/src/queries/usePatchTaskInstance.test.tsx
create mode 100644
airflow-core/src/airflow/ui/src/queries/useTaskInstanceNote.test.tsx
copy airflow-core/src/airflow/ui/src/{pages/GroupTaskInstance/index.ts =>
utils/executionParams.test.ts} (58%)
copy airflow-core/src/airflow/ui/src/{pages/GroupTaskInstance/index.ts =>
utils/executionParams.ts} (57%)
copy airflow-core/src/airflow/ui/src/{pages/GroupTaskInstance/index.ts =>
utils/loopTaskInstance.ts} (74%)
create mode 100644 airflow-core/src/airflow/utils/log/task_log_address.py
create mode 100644
airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_execution.py
create mode 100644
airflow-core/tests/unit/api_fastapi/core_api/routes/ui/test_execution.py
create mode 100644
airflow-core/tests/unit/api_fastapi/core_api/services/ui/test_execution.py
create mode 100644
airflow-core/tests/unit/migrations/test_0143_add_dynamic_region_storage.py
create mode 100644
airflow-core/tests/unit/migrations/test_0144_rename_stored_map_index.py
create mode 100644 airflow-core/tests/unit/models/conftest.py
create mode 100644 airflow-core/tests/unit/models/test_dynamic_region.py
create mode 100644 airflow-core/tests/unit/models/test_task_coordinates.py
create mode 100644 airflow-core/tests/unit/utils/log/test_task_log_address.py
create mode 100644
providers/common/ai/src/airflow/providers/common/ai/plugins/www/tests/api.test.ts
create mode 100644
providers/common/ai/src/airflow/providers/common/ai/plugins/www/tests/main.test.mjs
create mode 100644 task-sdk/src/airflow/sdk/definitions/_internal/loop.py
create mode 100644 task-sdk/src/airflow/sdk/execution_time/loop.py
create mode 100644 task-sdk/tests/task_sdk/definitions/_internal/test_loop.py
create mode 100644 task-sdk/tests/task_sdk/execution_time/test_loop.py