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

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

commit 7fef4a28399936426760594167fc38bd538533fc
Author: Wei Lee <[email protected]>
AuthorDate: Fri Sep 12 03:10:52 2025 +0800

    fix(hitl): make the user model in HITLDetail consistent with airflow user 
model (#55463)
    
    (cherry picked from commit 30c193b103cf9f48038a5898e72d29b1ad8b3dcc)
---
 airflow-core/docs/img/airflow_erd.sha256           |   2 +-
 airflow-core/docs/img/airflow_erd.svg              | 120 ++++++++++-----------
 airflow-core/docs/tutorial/hitl.rst                |   3 +
 .../src/airflow/api_fastapi/common/parameters.py   |   9 +-
 .../api_fastapi/core_api/datamodels/hitl.py        |  15 ++-
 .../api_fastapi/core_api/openapi/_private_ui.yaml  |  36 ++++---
 .../core_api/openapi/v2-rest-api-generated.yaml    |  55 +++++-----
 .../api_fastapi/core_api/routes/public/hitl.py     |  16 +--
 .../api_fastapi/execution_api/datamodels/hitl.py   |  24 ++++-
 .../api_fastapi/execution_api/routes/hitl.py       |   5 +-
 .../0076_3_1_0_add_human_in_the_loop_response.py   |   5 +-
 airflow-core/src/airflow/models/hitl.py            | 101 ++++++++++++++++-
 .../src/airflow/ui/openapi-gen/queries/common.ts   |   8 +-
 .../ui/openapi-gen/queries/ensureQueryData.ts      |  12 +--
 .../src/airflow/ui/openapi-gen/queries/prefetch.ts |  12 +--
 .../src/airflow/ui/openapi-gen/queries/queries.ts  |  12 +--
 .../src/airflow/ui/openapi-gen/queries/suspense.ts |  12 +--
 .../airflow/ui/openapi-gen/requests/schemas.gen.ts |  65 +++++------
 .../ui/openapi-gen/requests/services.gen.ts        |   8 +-
 .../airflow/ui/openapi-gen/requests/types.gen.ts   |  20 ++--
 .../core_api/routes/public/test_hitl.py            |  30 +++---
 .../api_fastapi/core_api/routes/ui/test_dags.py    |   3 +-
 .../execution_api/versions/head/test_hitl.py       |  22 ++--
 .../src/airflowctl/api/datamodels/generated.py     |  27 +++--
 .../standard/example_dags/example_hitl_operator.py |   1 +
 .../airflow/providers/standard/operators/hitl.py   |   8 +-
 .../airflow/providers/standard/triggers/hitl.py    |  31 ++++--
 .../tests/unit/standard/operators/test_hitl.py     |  57 +++++++---
 .../tests/unit/standard/triggers/test_hitl.py      |  26 +++--
 task-sdk/src/airflow/sdk/api/client.py             |   5 +-
 .../src/airflow/sdk/api/datamodels/_generated.py   |  54 ++++++----
 task-sdk/src/airflow/sdk/execution_time/hitl.py    |  16 ++-
 .../src/airflow/sdk/execution_time/supervisor.py   |   2 +-
 task-sdk/tests/task_sdk/api/test_client.py         |  15 ++-
 .../tests/task_sdk/execution_time/test_hitl.py     |  19 ++--
 .../task_sdk/execution_time/test_supervisor.py     |   4 +-
 36 files changed, 529 insertions(+), 331 deletions(-)

diff --git a/airflow-core/docs/img/airflow_erd.sha256 
b/airflow-core/docs/img/airflow_erd.sha256
index ee840ec21f2..b6b5a4a9270 100644
--- a/airflow-core/docs/img/airflow_erd.sha256
+++ b/airflow-core/docs/img/airflow_erd.sha256
@@ -1 +1 @@
-c05cefbe080ed889ebe132a0285756db477ff28256bbc1e86da1e053873f6478
\ No newline at end of file
+e491b0c58188f06ab4696cc09c765413065069f90d78e27eb53fdac5e2e92c82
\ No newline at end of file
diff --git a/airflow-core/docs/img/airflow_erd.svg 
b/airflow-core/docs/img/airflow_erd.svg
index a129862ad11..f08f88ff3f6 100644
--- a/airflow-core/docs/img/airflow_erd.svg
+++ b/airflow-core/docs/img/airflow_erd.svg
@@ -1437,72 +1437,68 @@
 <!-- hitl_detail -->
 <g id="node43" class="node">
 <title>hitl_detail</title>
-<polygon fill="none" stroke="black" points="2170,-2328 2170,-2356 2463,-2356 
2463,-2328 2170,-2328"/>
-<text text-anchor="start" x="2272.5" y="-2339.2" 
font-family="Helvetica,sans-Serif" font-weight="bold" 
font-size="16.00">hitl_detail</text>
-<polygon fill="none" stroke="black" points="2170,-2303 2170,-2328 2463,-2328 
2463,-2303 2170,-2303"/>
-<text text-anchor="start" x="2175" y="-2312.8" 
font-family="Helvetica,sans-Serif" text-decoration="underline" 
font-size="14.00">ti_id</text>
-<text text-anchor="start" x="2204" y="-2312.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
-<text text-anchor="start" x="2209" y="-2312.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> [UUID]</text>
-<text text-anchor="start" x="2261" y="-2312.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> NOT NULL</text>
-<polygon fill="none" stroke="black" points="2170,-2278 2170,-2303 2463,-2303 
2463,-2278 2170,-2278"/>
-<text text-anchor="start" x="2175" y="-2287.8" 
font-family="Helvetica,sans-Serif" font-size="14.00">body</text>
-<text text-anchor="start" x="2210" y="-2287.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
-<text text-anchor="start" x="2215" y="-2287.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> [TEXT]</text>
-<polygon fill="none" stroke="black" points="2170,-2253 2170,-2278 2463,-2278 
2463,-2253 2170,-2253"/>
-<text text-anchor="start" x="2175" y="-2262.8" 
font-family="Helvetica,sans-Serif" font-size="14.00">chosen_options</text>
-<text text-anchor="start" x="2283" y="-2262.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
-<text text-anchor="start" x="2288" y="-2262.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> [JSON]</text>
-<polygon fill="none" stroke="black" points="2170,-2228 2170,-2253 2463,-2253 
2463,-2228 2170,-2228"/>
-<text text-anchor="start" x="2175" y="-2237.8" 
font-family="Helvetica,sans-Serif" font-size="14.00">defaults</text>
-<text text-anchor="start" x="2232" y="-2237.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
-<text text-anchor="start" x="2237" y="-2237.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> [JSON]</text>
-<polygon fill="none" stroke="black" points="2170,-2203 2170,-2228 2463,-2228 
2463,-2203 2170,-2203"/>
-<text text-anchor="start" x="2175" y="-2212.8" 
font-family="Helvetica,sans-Serif" font-size="14.00">multiple</text>
-<text text-anchor="start" x="2232" y="-2212.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
-<text text-anchor="start" x="2237" y="-2212.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> [BOOLEAN]</text>
-<polygon fill="none" stroke="black" points="2170,-2178 2170,-2203 2463,-2203 
2463,-2178 2170,-2178"/>
-<text text-anchor="start" x="2175" y="-2187.8" 
font-family="Helvetica,sans-Serif" font-size="14.00">options</text>
-<text text-anchor="start" x="2227" y="-2187.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
-<text text-anchor="start" x="2232" y="-2187.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> [JSON]</text>
-<text text-anchor="start" x="2283" y="-2187.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> NOT NULL</text>
-<polygon fill="none" stroke="black" points="2170,-2153 2170,-2178 2463,-2178 
2463,-2153 2170,-2153"/>
-<text text-anchor="start" x="2175" y="-2162.8" 
font-family="Helvetica,sans-Serif" font-size="14.00">params</text>
-<text text-anchor="start" x="2228" y="-2162.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
-<text text-anchor="start" x="2233" y="-2162.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> [JSON]</text>
-<text text-anchor="start" x="2284" y="-2162.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> NOT NULL</text>
-<polygon fill="none" stroke="black" points="2170,-2128 2170,-2153 2463,-2153 
2463,-2128 2170,-2128"/>
-<text text-anchor="start" x="2175" y="-2137.8" 
font-family="Helvetica,sans-Serif" font-size="14.00">params_input</text>
-<text text-anchor="start" x="2271" y="-2137.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
-<text text-anchor="start" x="2276" y="-2137.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> [JSON]</text>
-<text text-anchor="start" x="2327" y="-2137.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> NOT NULL</text>
-<polygon fill="none" stroke="black" points="2170,-2103 2170,-2128 2463,-2128 
2463,-2103 2170,-2103"/>
-<text text-anchor="start" x="2175" y="-2112.8" 
font-family="Helvetica,sans-Serif" font-size="14.00">responded_user_id</text>
-<text text-anchor="start" x="2306" y="-2112.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
-<text text-anchor="start" x="2311" y="-2112.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> [VARCHAR(128)]</text>
-<polygon fill="none" stroke="black" points="2170,-2078 2170,-2103 2463,-2103 
2463,-2078 2170,-2078"/>
-<text text-anchor="start" x="2175" y="-2087.8" 
font-family="Helvetica,sans-Serif" font-size="14.00">responded_user_name</text>
-<text text-anchor="start" x="2332" y="-2087.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
-<text text-anchor="start" x="2337" y="-2087.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> [VARCHAR(128)]</text>
-<polygon fill="none" stroke="black" points="2170,-2053 2170,-2078 2463,-2078 
2463,-2053 2170,-2053"/>
-<text text-anchor="start" x="2175" y="-2062.8" 
font-family="Helvetica,sans-Serif" font-size="14.00">respondents</text>
-<text text-anchor="start" x="2262" y="-2062.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
-<text text-anchor="start" x="2267" y="-2062.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> [JSON]</text>
-<polygon fill="none" stroke="black" points="2170,-2028 2170,-2053 2463,-2053 
2463,-2028 2170,-2028"/>
-<text text-anchor="start" x="2175" y="-2037.8" 
font-family="Helvetica,sans-Serif" font-size="14.00">response_at</text>
-<text text-anchor="start" x="2259" y="-2037.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
-<text text-anchor="start" x="2264" y="-2037.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> [TIMESTAMP]</text>
-<polygon fill="none" stroke="black" points="2170,-2003 2170,-2028 2463,-2028 
2463,-2003 2170,-2003"/>
-<text text-anchor="start" x="2175" y="-2012.8" 
font-family="Helvetica,sans-Serif" font-size="14.00">subject</text>
-<text text-anchor="start" x="2226" y="-2012.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
-<text text-anchor="start" x="2231" y="-2012.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> [TEXT]</text>
-<text text-anchor="start" x="2281" y="-2012.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> NOT NULL</text>
+<polygon fill="none" stroke="black" points="2197,-2304 2197,-2332 2435,-2332 
2435,-2304 2197,-2304"/>
+<text text-anchor="start" x="2272" y="-2315.2" 
font-family="Helvetica,sans-Serif" font-weight="bold" 
font-size="16.00">hitl_detail</text>
+<polygon fill="none" stroke="black" points="2197,-2279 2197,-2304 2435,-2304 
2435,-2279 2197,-2279"/>
+<text text-anchor="start" x="2202" y="-2288.8" 
font-family="Helvetica,sans-Serif" text-decoration="underline" 
font-size="14.00">ti_id</text>
+<text text-anchor="start" x="2231" y="-2288.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
+<text text-anchor="start" x="2236" y="-2288.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> [UUID]</text>
+<text text-anchor="start" x="2288" y="-2288.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> NOT NULL</text>
+<polygon fill="none" stroke="black" points="2197,-2254 2197,-2279 2435,-2279 
2435,-2254 2197,-2254"/>
+<text text-anchor="start" x="2202" y="-2263.8" 
font-family="Helvetica,sans-Serif" font-size="14.00">assignees</text>
+<text text-anchor="start" x="2272" y="-2263.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
+<text text-anchor="start" x="2277" y="-2263.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> [JSON]</text>
+<polygon fill="none" stroke="black" points="2197,-2229 2197,-2254 2435,-2254 
2435,-2229 2197,-2229"/>
+<text text-anchor="start" x="2202" y="-2238.8" 
font-family="Helvetica,sans-Serif" font-size="14.00">body</text>
+<text text-anchor="start" x="2237" y="-2238.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
+<text text-anchor="start" x="2242" y="-2238.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> [TEXT]</text>
+<polygon fill="none" stroke="black" points="2197,-2204 2197,-2229 2435,-2229 
2435,-2204 2197,-2204"/>
+<text text-anchor="start" x="2202" y="-2213.8" 
font-family="Helvetica,sans-Serif" font-size="14.00">chosen_options</text>
+<text text-anchor="start" x="2310" y="-2213.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
+<text text-anchor="start" x="2315" y="-2213.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> [JSON]</text>
+<polygon fill="none" stroke="black" points="2197,-2179 2197,-2204 2435,-2204 
2435,-2179 2197,-2179"/>
+<text text-anchor="start" x="2202" y="-2188.8" 
font-family="Helvetica,sans-Serif" font-size="14.00">defaults</text>
+<text text-anchor="start" x="2259" y="-2188.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
+<text text-anchor="start" x="2264" y="-2188.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> [JSON]</text>
+<polygon fill="none" stroke="black" points="2197,-2154 2197,-2179 2435,-2179 
2435,-2154 2197,-2154"/>
+<text text-anchor="start" x="2202" y="-2163.8" 
font-family="Helvetica,sans-Serif" font-size="14.00">multiple</text>
+<text text-anchor="start" x="2259" y="-2163.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
+<text text-anchor="start" x="2264" y="-2163.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> [BOOLEAN]</text>
+<polygon fill="none" stroke="black" points="2197,-2129 2197,-2154 2435,-2154 
2435,-2129 2197,-2129"/>
+<text text-anchor="start" x="2202" y="-2138.8" 
font-family="Helvetica,sans-Serif" font-size="14.00">options</text>
+<text text-anchor="start" x="2254" y="-2138.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
+<text text-anchor="start" x="2259" y="-2138.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> [JSON]</text>
+<text text-anchor="start" x="2310" y="-2138.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> NOT NULL</text>
+<polygon fill="none" stroke="black" points="2197,-2104 2197,-2129 2435,-2129 
2435,-2104 2197,-2104"/>
+<text text-anchor="start" x="2202" y="-2113.8" 
font-family="Helvetica,sans-Serif" font-size="14.00">params</text>
+<text text-anchor="start" x="2255" y="-2113.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
+<text text-anchor="start" x="2260" y="-2113.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> [JSON]</text>
+<text text-anchor="start" x="2311" y="-2113.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> NOT NULL</text>
+<polygon fill="none" stroke="black" points="2197,-2079 2197,-2104 2435,-2104 
2435,-2079 2197,-2079"/>
+<text text-anchor="start" x="2202" y="-2088.8" 
font-family="Helvetica,sans-Serif" font-size="14.00">params_input</text>
+<text text-anchor="start" x="2298" y="-2088.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
+<text text-anchor="start" x="2303" y="-2088.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> [JSON]</text>
+<text text-anchor="start" x="2354" y="-2088.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> NOT NULL</text>
+<polygon fill="none" stroke="black" points="2197,-2054 2197,-2079 2435,-2079 
2435,-2054 2197,-2054"/>
+<text text-anchor="start" x="2202" y="-2063.8" 
font-family="Helvetica,sans-Serif" font-size="14.00">responded_by</text>
+<text text-anchor="start" x="2300" y="-2063.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
+<text text-anchor="start" x="2305" y="-2063.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> [JSON]</text>
+<polygon fill="none" stroke="black" points="2197,-2029 2197,-2054 2435,-2054 
2435,-2029 2197,-2029"/>
+<text text-anchor="start" x="2202" y="-2038.8" 
font-family="Helvetica,sans-Serif" font-size="14.00">response_at</text>
+<text text-anchor="start" x="2286" y="-2038.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
+<text text-anchor="start" x="2291" y="-2038.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> [TIMESTAMP]</text>
+<polygon fill="none" stroke="black" points="2197,-2004 2197,-2029 2435,-2029 
2435,-2004 2197,-2004"/>
+<text text-anchor="start" x="2202" y="-2013.8" 
font-family="Helvetica,sans-Serif" font-size="14.00">subject</text>
+<text text-anchor="start" x="2253" y="-2013.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
+<text text-anchor="start" x="2258" y="-2013.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> [TEXT]</text>
+<text text-anchor="start" x="2308" y="-2013.8" 
font-family="Helvetica,sans-Serif" font-size="14.00"> NOT NULL</text>
 </g>
 <!-- task_instance&#45;&#45;hitl_detail -->
 <g id="edge48" class="edge">
 <title>task_instance&#45;&#45;hitl_detail</title>
-<path fill="none" stroke="#7f7f7f" stroke-dasharray="5,2" 
d="M2081.12,-1859.57C2103.71,-1904.92 2128.13,-1949.64 2154,-1991 
2156.4,-1994.84 2158.87,-1998.68 2161.41,-2002.51"/>
-<text text-anchor="start" x="2151.41" y="-1991.31" font-family="Times,serif" 
font-size="14.00">1</text>
-<text text-anchor="start" x="2081.12" y="-1848.37" font-family="Times,serif" 
font-size="14.00">1</text>
+<path fill="none" stroke="#7f7f7f" stroke-dasharray="5,2" 
d="M2081.05,-1862.88C2103.53,-1907.23 2127.94,-1950.81 2154,-1991 
2164.45,-2007.12 2176.38,-2023.19 2188.91,-2038.71"/>
+<text text-anchor="start" x="2178.91" y="-2027.51" font-family="Times,serif" 
font-size="14.00">1</text>
+<text text-anchor="start" x="2081.05" y="-1851.68" font-family="Times,serif" 
font-size="14.00">1</text>
 </g>
 <!-- task_map -->
 <g id="node44" class="node">
diff --git a/airflow-core/docs/tutorial/hitl.rst 
b/airflow-core/docs/tutorial/hitl.rst
index b104bc7d033..a84ef735598 100644
--- a/airflow-core/docs/tutorial/hitl.rst
+++ b/airflow-core/docs/tutorial/hitl.rst
@@ -95,6 +95,9 @@ Approval or Rejection
 ---------------------
 
 A specialized form of option selection, which has only 'Approval' and 
'Rejection' as options.
+You can also set the ``assigned_users`` to restrict the users allowed to 
respond for a HITL operator.
+It should be a list of user ids and user names (both needed) (e.g., ``[{"id": 
"1", "name": "user1"}, {"id": "2", "name": "user2"}]``.
+ONLY the users within this list will be allowed to respond.
 
 .. exampleinclude:: 
/../../providers/standard/src/airflow/providers/standard/example_dags/example_hitl_operator.py
    :language: python
diff --git a/airflow-core/src/airflow/api_fastapi/common/parameters.py 
b/airflow-core/src/airflow/api_fastapi/common/parameters.py
index 7a555454cd1..d2dce9743f7 100644
--- a/airflow-core/src/airflow/api_fastapi/common/parameters.py
+++ b/airflow-core/src/airflow/api_fastapi/common/parameters.py
@@ -1025,15 +1025,16 @@ QueryHITLDetailResponseReceivedFilter = Annotated[
         )
     ),
 ]
+
 QueryHITLDetailRespondedUserIdFilter = Annotated[
     FilterParam[list[str]],
     Depends(
         filter_param_factory(
-            HITLDetail.responded_user_id,
+            HITLDetail.responded_by_user_id,
             list[str],
             FilterOptionEnum.ANY_EQUAL,
             default_factory=list,
-            filter_name="responded_user_id",
+            filter_name="responded_by_user_id",
         )
     ),
 ]
@@ -1041,11 +1042,11 @@ QueryHITLDetailRespondedUserNameFilter = Annotated[
     FilterParam[list[str]],
     Depends(
         filter_param_factory(
-            HITLDetail.responded_user_name,
+            HITLDetail.responded_by_user_name,
             list[str],
             FilterOptionEnum.ANY_EQUAL,
             default_factory=list,
-            filter_name="responded_user_name",
+            filter_name="responded_by_user_name",
         )
     ),
 ]
diff --git a/airflow-core/src/airflow/api_fastapi/core_api/datamodels/hitl.py 
b/airflow-core/src/airflow/api_fastapi/core_api/datamodels/hitl.py
index ea0f045539e..24a18821f13 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/datamodels/hitl.py
+++ b/airflow-core/src/airflow/api_fastapi/core_api/datamodels/hitl.py
@@ -37,13 +37,19 @@ class UpdateHITLDetailPayload(BaseModel):
 class HITLDetailResponse(BaseModel):
     """Response of updating a Human-in-the-loop detail."""
 
-    responded_user_id: str
-    responded_user_name: str
+    responded_by: HITLUser
     response_at: datetime
     chosen_options: list[str] = Field(min_length=1)
     params_input: Mapping = Field(default_factory=dict)
 
 
+class HITLUser(BaseModel):
+    """Schema for a Human-in-the-loop users."""
+
+    id: str
+    name: str
+
+
 class HITLDetail(BaseModel):
     """Schema for Human-in-the-loop detail."""
 
@@ -56,11 +62,10 @@ class HITLDetail(BaseModel):
     defaults: list[str] | None = None
     multiple: bool = False
     params: dict[str, Any] = Field(default_factory=dict)
-    respondents: list[str] | None = None
+    assigned_users: list[HITLUser] = Field(default_factory=list)
 
     # Response Content Detail
-    responded_user_id: str | None = None
-    responded_user_name: str | None = None
+    responded_by_user: HITLUser | None = None
     response_at: datetime | None = None
     chosen_options: list[str] | None = None
     params_input: dict[str, Any] = Field(default_factory=dict)
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 a4d85b16dd3..383b9fca62f 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
@@ -1994,23 +1994,15 @@ components:
           additionalProperties: true
           type: object
           title: Params
-        respondents:
-          anyOf:
-          - items:
-              type: string
-            type: array
-          - type: 'null'
-          title: Respondents
-        responded_user_id:
-          anyOf:
-          - type: string
-          - type: 'null'
-          title: Responded User Id
-        responded_user_name:
+        assigned_users:
+          items:
+            $ref: '#/components/schemas/HITLUser'
+          type: array
+          title: Assigned Users
+        responded_by_user:
           anyOf:
-          - type: string
+          - $ref: '#/components/schemas/HITLUser'
           - type: 'null'
-          title: Responded User Name
         response_at:
           anyOf:
           - type: string
@@ -2039,6 +2031,20 @@ components:
       - subject
       title: HITLDetail
       description: Schema for Human-in-the-loop detail.
+    HITLUser:
+      properties:
+        id:
+          type: string
+          title: Id
+        name:
+          type: string
+          title: Name
+      type: object
+      required:
+      - id
+      - name
+      title: HITLUser
+      description: Schema for a Human-in-the-loop users.
     HTTPExceptionResponse:
       properties:
         detail:
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 f9057f2d5ca..9150f12c012 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
@@ -8200,22 +8200,22 @@ paths:
           - type: boolean
           - type: 'null'
           title: Response Received
-      - name: responded_user_id
+      - name: responded_by_user_id
         in: query
         required: false
         schema:
           type: array
           items:
             type: string
-          title: Responded User Id
-      - name: responded_user_name
+          title: Responded By User Id
+      - name: responded_by_user_name
         in: query
         required: false
         schema:
           type: array
           items:
             type: string
-          title: Responded User Name
+          title: Responded By User Name
       - name: subject_search
         in: query
         required: false
@@ -10856,23 +10856,15 @@ components:
           additionalProperties: true
           type: object
           title: Params
-        respondents:
-          anyOf:
-          - items:
-              type: string
-            type: array
-          - type: 'null'
-          title: Respondents
-        responded_user_id:
-          anyOf:
-          - type: string
-          - type: 'null'
-          title: Responded User Id
-        responded_user_name:
+        assigned_users:
+          items:
+            $ref: '#/components/schemas/HITLUser'
+          type: array
+          title: Assigned Users
+        responded_by_user:
           anyOf:
-          - type: string
+          - $ref: '#/components/schemas/HITLUser'
           - type: 'null'
-          title: Responded User Name
         response_at:
           anyOf:
           - type: string
@@ -10919,12 +10911,8 @@ components:
       description: Schema for a collection of Human-in-the-loop details.
     HITLDetailResponse:
       properties:
-        responded_user_id:
-          type: string
-          title: Responded User Id
-        responded_user_name:
-          type: string
-          title: Responded User Name
+        responded_by:
+          $ref: '#/components/schemas/HITLUser'
         response_at:
           type: string
           format: date-time
@@ -10941,12 +10929,25 @@ components:
           title: Params Input
       type: object
       required:
-      - responded_user_id
-      - responded_user_name
+      - responded_by
       - response_at
       - chosen_options
       title: HITLDetailResponse
       description: Response of updating a Human-in-the-loop detail.
+    HITLUser:
+      properties:
+        id:
+          type: string
+          title: Id
+        name:
+          type: string
+          title: Name
+      type: object
+      required:
+      - id
+      - name
+      title: HITLUser
+      description: Schema for a Human-in-the-loop users.
     HTTPExceptionResponse:
       properties:
         detail:
diff --git 
a/airflow-core/src/airflow/api_fastapi/core_api/routes/public/hitl.py 
b/airflow-core/src/airflow/api_fastapi/core_api/routes/public/hitl.py
index e04714e0a91..5f39e18dd13 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/routes/public/hitl.py
+++ b/airflow-core/src/airflow/api_fastapi/core_api/routes/public/hitl.py
@@ -53,7 +53,7 @@ from airflow.api_fastapi.core_api.openapi.exceptions import 
create_openapi_http_
 from airflow.api_fastapi.core_api.security import GetUserDep, 
ReadableTIFilterDep, requires_access_dag
 from airflow.api_fastapi.logging.decorators import action_logging
 from airflow.models.dagrun import DagRun
-from airflow.models.hitl import HITLDetail as HITLDetailModel
+from airflow.models.hitl import HITLDetail as HITLDetailModel, HITLUser
 from airflow.models.taskinstance import TaskInstance as TI
 
 hitl_router = AirflowRouter(tags=["HumanInTheLoop"], prefix="/hitlDetails")
@@ -144,19 +144,19 @@ def update_hitl_detail(
 
     user_id = user.get_id()
     user_name = user.get_name()
-    if hitl_detail_model.respondents:
-        if isinstance(user_id, int):
-            # FabAuthManager (ab_user) store user id as integer, but common 
interface is string type
-            user_id = str(user_id)
-        if user_id not in hitl_detail_model.respondents:
+    if isinstance(user_id, int):
+        # FabAuthManager (ab_user) store user id as integer, but common 
interface is string type
+        user_id = str(user_id)
+    hitl_user = HITLUser(id=user_id, name=user_name)
+    if hitl_detail_model.assigned_users:
+        if hitl_user not in hitl_detail_model.assigned_users:
             log.error("User=%s (id=%s) is not a respondent for the task", 
user_name, user_id)
             raise HTTPException(
                 status.HTTP_403_FORBIDDEN,
                 f"User={user_name} (id={user_id}) is not a respondent for the 
task.",
             )
 
-    hitl_detail_model.responded_user_id = user_id
-    hitl_detail_model.responded_user_name = user_name
+    hitl_detail_model.responded_by = hitl_user
     hitl_detail_model.response_at = timezone.utcnow()
     hitl_detail_model.chosen_options = 
update_hitl_detail_payload.chosen_options
     hitl_detail_model.params_input = update_hitl_detail_payload.params_input
diff --git 
a/airflow-core/src/airflow/api_fastapi/execution_api/datamodels/hitl.py 
b/airflow-core/src/airflow/api_fastapi/execution_api/datamodels/hitl.py
index 4162d2cf771..a5f16eb8818 100644
--- a/airflow-core/src/airflow/api_fastapi/execution_api/datamodels/hitl.py
+++ b/airflow-core/src/airflow/api_fastapi/execution_api/datamodels/hitl.py
@@ -26,6 +26,13 @@ from airflow.api_fastapi.core_api.base import BaseModel
 from airflow.models.hitl import HITLDetail
 
 
+class HITLUser(BaseModel):
+    """Schema for a Human-in-the-loop users."""
+
+    id: str
+    name: str
+
+
 class HITLDetailRequest(BaseModel):
     """Schema for the request part of a Human-in-the-loop detail for a 
specific task instance."""
 
@@ -36,7 +43,7 @@ class HITLDetailRequest(BaseModel):
     defaults: list[str] | None = None
     multiple: bool = False
     params: dict[str, Any] = Field(default_factory=dict)
-    respondents: list[str] | None = None
+    assigned_users: list[HITLUser] = Field(default_factory=list)
 
 
 class UpdateHITLDetailPayload(BaseModel):
@@ -51,8 +58,7 @@ class HITLDetailResponse(BaseModel):
     """Schema for the response part of a Human-in-the-loop detail for a 
specific task instance."""
 
     response_received: bool
-    responded_user_name: str | None
-    responded_user_id: str | None
+    responded_by_user: HITLUser | None = None
     response_at: datetime | None
     # It's empty if the user has not yet responded.
     chosen_options: list[str] | None
@@ -60,11 +66,19 @@ class HITLDetailResponse(BaseModel):
 
     @classmethod
     def from_hitl_detail_orm(cls, hitl_detail: HITLDetail) -> 
HITLDetailResponse:
+        hitl_user = (
+            HITLUser(
+                id=hitl_detail.responded_by_user_id,
+                name=hitl_detail.responded_by_user_name,
+            )
+            if hitl_detail.responded_by_user
+            else None
+        )
+
         return HITLDetailResponse(
             response_received=hitl_detail.response_received,
             response_at=hitl_detail.response_at,
-            responded_user_id=hitl_detail.responded_user_id,
-            responded_user_name=hitl_detail.responded_user_name,
+            responded_by_user=hitl_user,
             chosen_options=hitl_detail.chosen_options,
             params_input=hitl_detail.params_input or {},
         )
diff --git a/airflow-core/src/airflow/api_fastapi/execution_api/routes/hitl.py 
b/airflow-core/src/airflow/api_fastapi/execution_api/routes/hitl.py
index c9efbda78f0..8a6606bd280 100644
--- a/airflow-core/src/airflow/api_fastapi/execution_api/routes/hitl.py
+++ b/airflow-core/src/airflow/api_fastapi/execution_api/routes/hitl.py
@@ -71,7 +71,7 @@ def upsert_hitl_detail(
             defaults=payload.defaults,
             multiple=payload.multiple,
             params=payload.params,
-            respondents=payload.respondents,
+            assignees=[user.model_dump() for user in payload.assigned_users],
         )
         session.add(hitl_detail_model)
     elif hitl_detail_model.response_received:
@@ -116,8 +116,7 @@ def update_hitl_detail(
             f"Human-in-the-loop detail for Task Instance with id {ti_id_str} 
already exists.",
         )
 
-    hitl_detail_model.responded_user_id = HITLDetail.DEFAULT_USER_NAME
-    hitl_detail_model.responded_user_name = HITLDetail.DEFAULT_USER_NAME
+    hitl_detail_model.responded_by = HITLDetail.DEFAULT_USER
     hitl_detail_model.response_at = datetime.now(timezone.utc)
     hitl_detail_model.chosen_options = payload.chosen_options
     hitl_detail_model.params_input = payload.params_input
diff --git 
a/airflow-core/src/airflow/migrations/versions/0076_3_1_0_add_human_in_the_loop_response.py
 
b/airflow-core/src/airflow/migrations/versions/0076_3_1_0_add_human_in_the_loop_response.py
index 3e0ede0183e..60f870ff44c 100644
--- 
a/airflow-core/src/airflow/migrations/versions/0076_3_1_0_add_human_in_the_loop_response.py
+++ 
b/airflow-core/src/airflow/migrations/versions/0076_3_1_0_add_human_in_the_loop_response.py
@@ -59,10 +59,9 @@ def upgrade():
         Column("defaults", sqlalchemy_jsonfield.JSONField(json=json), 
nullable=True),
         Column("multiple", Boolean, unique=False, default=False),
         Column("params", sqlalchemy_jsonfield.JSONField(json=json), 
nullable=False, default={}),
-        Column("respondents", sqlalchemy_jsonfield.JSONField(json=json), 
nullable=True),
+        Column("assignees", sqlalchemy_jsonfield.JSONField(json=json), 
nullable=True),
         Column("response_at", UtcDateTime, nullable=True),
-        Column("responded_user_id", String(128), nullable=True),
-        Column("responded_user_name", String(128), nullable=True),
+        Column("responded_by", sqlalchemy_jsonfield.JSONField(json=json), 
nullable=True),
         Column("chosen_options", sqlalchemy_jsonfield.JSONField(json=json), 
nullable=True),
         Column("params_input", sqlalchemy_jsonfield.JSONField(json=json), 
nullable=False, default={}),
         ForeignKeyConstraint(
diff --git a/airflow-core/src/airflow/models/hitl.py 
b/airflow-core/src/airflow/models/hitl.py
index 448939e2c6f..e2055344bc3 100644
--- a/airflow-core/src/airflow/models/hitl.py
+++ b/airflow-core/src/airflow/models/hitl.py
@@ -16,16 +16,68 @@
 # under the License.
 from __future__ import annotations
 
+from typing import TYPE_CHECKING, Any, TypedDict
+
 import sqlalchemy_jsonfield
-from sqlalchemy import Boolean, Column, ForeignKeyConstraint, String, Text
+from sqlalchemy import Boolean, Column, ForeignKeyConstraint, String, Text, 
func, literal
 from sqlalchemy.dialects import postgresql
+from sqlalchemy.ext.compiler import compiles
 from sqlalchemy.ext.hybrid import hybrid_property
 from sqlalchemy.orm import relationship
+from sqlalchemy.sql.functions import FunctionElement
 
 from airflow.models.base import Base
 from airflow.settings import json
 from airflow.utils.sqlalchemy import UtcDateTime
 
+if TYPE_CHECKING:
+    from sqlalchemy.sql import ColumnElement
+    from sqlalchemy.sql.compiler import SQLCompiler
+
+
+class JSONExtract(FunctionElement):
+    """
+    Cross-dialect JSON key extractor.
+
+    :meta: private
+    """
+
+    type = String()
+    inherit_cache = True
+
+    def __init__(self, column: ColumnElement[Any], key: str, **kwargs: 
dict[str, Any]) -> None:
+        super().__init__(column, literal(key), **kwargs)
+
+
+@compiles(JSONExtract, "postgresql")
+def compile_postgres(element: JSONExtract, compiler: SQLCompiler, **kwargs: 
dict[str, Any]) -> str:
+    """
+    Compile JSONExtract for PostgreSQL.
+
+    :meta: private
+    """
+    column, key = element.clauses
+    return compiler.process(func.json_extract_path_text(column, key), **kwargs)
+
+
+@compiles(JSONExtract, "sqlite")
+@compiles(JSONExtract, "mysql")
+def compile_sqlite_mysql(element: JSONExtract, compiler: SQLCompiler, 
**kwargs: dict[str, Any]) -> str:
+    """
+    Compile JSONExtract for SQLite/MySQL.
+
+    :meta: private
+    """
+    column, key = element.clauses
+    return compiler.process(func.json_extract(column, f"$.{key.value}"), 
**kwargs)
+
+
+class HITLUser(TypedDict):
+    """Typed dict for saving a Human-in-the-loop user information."""
+
+    id: str
+    name: str
+
 
 class HITLDetail(Base):
     """Human-in-the-loop request and corresponding response."""
@@ -44,12 +96,11 @@ class HITLDetail(Base):
     defaults = Column(sqlalchemy_jsonfield.JSONField(json=json), nullable=True)
     multiple = Column(Boolean, unique=False, default=False)
     params = Column(sqlalchemy_jsonfield.JSONField(json=json), nullable=False, 
default={})
-    respondents = Column(sqlalchemy_jsonfield.JSONField(json=json), 
nullable=True)
+    assignees = Column(sqlalchemy_jsonfield.JSONField(json=json), 
nullable=True)
 
     # Response Content Detail
     response_at = Column(UtcDateTime, nullable=True)
-    responded_user_id = Column(String(128), nullable=True)
-    responded_user_name = Column(String(128), nullable=True)
+    responded_by = Column(sqlalchemy_jsonfield.JSONField(json=json), 
nullable=True)
     chosen_options = Column(
         sqlalchemy_jsonfield.JSONField(json=json),
         nullable=True,
@@ -80,4 +131,44 @@ class HITLDetail(Base):
     def response_received(cls):
         return cls.response_at.is_not(None)
 
-    DEFAULT_USER_NAME = "Fallback to defaults"
+    @hybrid_property
+    def responded_by_user_id(self) -> str | None:
+        return self.responded_by["id"] if self.responded_by else None
+
+    @responded_by_user_id.expression  # type: ignore[no-redef]
+    def responded_by_user_id(cls):
+        return JSONExtract(cls.responded_by, "id")
+
+    @hybrid_property
+    def responded_by_user_name(self) -> str | None:
+        return self.responded_by["name"] if self.responded_by else None
+
+    @responded_by_user_name.expression  # type: ignore[no-redef]
+    def responded_by_user_name(cls):
+        return JSONExtract(cls.responded_by, "name")
+
+    @hybrid_property
+    def assigned_users(self) -> list[HITLUser]:
+        if not self.assignees:
+            return []
+        return [
+            HITLUser(
+                id=assignee["id"],
+                name=assignee["name"],
+            )
+            for assignee in self.assignees
+        ]
+
+    @hybrid_property
+    def responded_by_user(self) -> HITLUser | None:
+        if self.responded_by is None:
+            return None
+        return HITLUser(
+            id=self.responded_by["id"],
+            name=self.responded_by["name"],
+        )
+
+    DEFAULT_USER = HITLUser(
+        id="Fallback to defaults",
+        name="Fallback to defaults",
+    )
diff --git a/airflow-core/src/airflow/ui/openapi-gen/queries/common.ts 
b/airflow-core/src/airflow/ui/openapi-gen/queries/common.ts
index 457aac893ee..d4ffa8098f9 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/queries/common.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/queries/common.ts
@@ -717,7 +717,7 @@ export const UseHumanInTheLoopServiceGetHitlDetailKeyFn = 
({ dagId, dagRunId, ma
 export type HumanInTheLoopServiceGetHitlDetailsDefaultResponse = 
Awaited<ReturnType<typeof HumanInTheLoopService.getHitlDetails>>;
 export type HumanInTheLoopServiceGetHitlDetailsQueryResult<TData = 
HumanInTheLoopServiceGetHitlDetailsDefaultResponse, TError = unknown> = 
UseQueryResult<TData, TError>;
 export const useHumanInTheLoopServiceGetHitlDetailsKey = 
"HumanInTheLoopServiceGetHitlDetails";
-export const UseHumanInTheLoopServiceGetHitlDetailsKeyFn = ({ bodySearch, 
dagId, dagIdPattern, dagRunId, limit, offset, orderBy, respondedUserId, 
respondedUserName, responseReceived, state, subjectSearch, taskId, 
taskIdPattern }: {
+export const UseHumanInTheLoopServiceGetHitlDetailsKeyFn = ({ bodySearch, 
dagId, dagIdPattern, dagRunId, limit, offset, orderBy, respondedByUserId, 
respondedByUserName, responseReceived, state, subjectSearch, taskId, 
taskIdPattern }: {
   bodySearch?: string;
   dagId?: string;
   dagIdPattern?: string;
@@ -725,14 +725,14 @@ export const UseHumanInTheLoopServiceGetHitlDetailsKeyFn 
= ({ bodySearch, dagId,
   limit?: number;
   offset?: number;
   orderBy?: string[];
-  respondedUserId?: string[];
-  respondedUserName?: string[];
+  respondedByUserId?: string[];
+  respondedByUserName?: string[];
   responseReceived?: boolean;
   state?: string[];
   subjectSearch?: string;
   taskId?: string;
   taskIdPattern?: string;
-} = {}, queryKey?: Array<unknown>) => 
[useHumanInTheLoopServiceGetHitlDetailsKey, ...(queryKey ?? [{ bodySearch, 
dagId, dagIdPattern, dagRunId, limit, offset, orderBy, respondedUserId, 
respondedUserName, responseReceived, state, subjectSearch, taskId, 
taskIdPattern }])];
+} = {}, queryKey?: Array<unknown>) => 
[useHumanInTheLoopServiceGetHitlDetailsKey, ...(queryKey ?? [{ bodySearch, 
dagId, dagIdPattern, dagRunId, limit, offset, orderBy, respondedByUserId, 
respondedByUserName, responseReceived, state, subjectSearch, taskId, 
taskIdPattern }])];
 export type MonitorServiceGetHealthDefaultResponse = Awaited<ReturnType<typeof 
MonitorService.getHealth>>;
 export type MonitorServiceGetHealthQueryResult<TData = 
MonitorServiceGetHealthDefaultResponse, TError = unknown> = 
UseQueryResult<TData, TError>;
 export const useMonitorServiceGetHealthKey = "MonitorServiceGetHealth";
diff --git a/airflow-core/src/airflow/ui/openapi-gen/queries/ensureQueryData.ts 
b/airflow-core/src/airflow/ui/openapi-gen/queries/ensureQueryData.ts
index fac229938af..da76a35a8ce 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/queries/ensureQueryData.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/queries/ensureQueryData.ts
@@ -1371,14 +1371,14 @@ export const 
ensureUseHumanInTheLoopServiceGetHitlDetailData = (queryClient: Que
 * @param data.taskIdPattern SQL LIKE expression — use `%` / `_` wildcards 
(e.g. `%customer_%`). Regular expressions are **not** supported.
 * @param data.state
 * @param data.responseReceived
-* @param data.respondedUserId
-* @param data.respondedUserName
+* @param data.respondedByUserId
+* @param data.respondedByUserName
 * @param data.subjectSearch SQL LIKE expression — use `%` / `_` wildcards 
(e.g. `%customer_%`). Regular expressions are **not** supported.
 * @param data.bodySearch SQL LIKE expression — use `%` / `_` wildcards (e.g. 
`%customer_%`). Regular expressions are **not** supported.
 * @returns HITLDetailCollection Successful Response
 * @throws ApiError
 */
-export const ensureUseHumanInTheLoopServiceGetHitlDetailsData = (queryClient: 
QueryClient, { bodySearch, dagId, dagIdPattern, dagRunId, limit, offset, 
orderBy, respondedUserId, respondedUserName, responseReceived, state, 
subjectSearch, taskId, taskIdPattern }: {
+export const ensureUseHumanInTheLoopServiceGetHitlDetailsData = (queryClient: 
QueryClient, { bodySearch, dagId, dagIdPattern, dagRunId, limit, offset, 
orderBy, respondedByUserId, respondedByUserName, responseReceived, state, 
subjectSearch, taskId, taskIdPattern }: {
   bodySearch?: string;
   dagId?: string;
   dagIdPattern?: string;
@@ -1386,14 +1386,14 @@ export const 
ensureUseHumanInTheLoopServiceGetHitlDetailsData = (queryClient: Qu
   limit?: number;
   offset?: number;
   orderBy?: string[];
-  respondedUserId?: string[];
-  respondedUserName?: string[];
+  respondedByUserId?: string[];
+  respondedByUserName?: string[];
   responseReceived?: boolean;
   state?: string[];
   subjectSearch?: string;
   taskId?: string;
   taskIdPattern?: string;
-} = {}) => queryClient.ensureQueryData({ queryKey: 
Common.UseHumanInTheLoopServiceGetHitlDetailsKeyFn({ bodySearch, dagId, 
dagIdPattern, dagRunId, limit, offset, orderBy, respondedUserId, 
respondedUserName, responseReceived, state, subjectSearch, taskId, 
taskIdPattern }), queryFn: () => HumanInTheLoopService.getHitlDetails({ 
bodySearch, dagId, dagIdPattern, dagRunId, limit, offset, orderBy, 
respondedUserId, respondedUserName, responseReceived, state, subjectSearch, 
taskId, taskIdPattern }) });
+} = {}) => queryClient.ensureQueryData({ queryKey: 
Common.UseHumanInTheLoopServiceGetHitlDetailsKeyFn({ bodySearch, dagId, 
dagIdPattern, dagRunId, limit, offset, orderBy, respondedByUserId, 
respondedByUserName, responseReceived, state, subjectSearch, taskId, 
taskIdPattern }), queryFn: () => HumanInTheLoopService.getHitlDetails({ 
bodySearch, dagId, dagIdPattern, dagRunId, limit, offset, orderBy, 
respondedByUserId, respondedByUserName, responseReceived, state, subjectSearch, 
taskId, taskId [...]
 /**
 * Get Health
 * @returns HealthInfoResponse Successful Response
diff --git a/airflow-core/src/airflow/ui/openapi-gen/queries/prefetch.ts 
b/airflow-core/src/airflow/ui/openapi-gen/queries/prefetch.ts
index 1870bb85c32..af773c94bdd 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/queries/prefetch.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/queries/prefetch.ts
@@ -1371,14 +1371,14 @@ export const 
prefetchUseHumanInTheLoopServiceGetHitlDetail = (queryClient: Query
 * @param data.taskIdPattern SQL LIKE expression — use `%` / `_` wildcards 
(e.g. `%customer_%`). Regular expressions are **not** supported.
 * @param data.state
 * @param data.responseReceived
-* @param data.respondedUserId
-* @param data.respondedUserName
+* @param data.respondedByUserId
+* @param data.respondedByUserName
 * @param data.subjectSearch SQL LIKE expression — use `%` / `_` wildcards 
(e.g. `%customer_%`). Regular expressions are **not** supported.
 * @param data.bodySearch SQL LIKE expression — use `%` / `_` wildcards (e.g. 
`%customer_%`). Regular expressions are **not** supported.
 * @returns HITLDetailCollection Successful Response
 * @throws ApiError
 */
-export const prefetchUseHumanInTheLoopServiceGetHitlDetails = (queryClient: 
QueryClient, { bodySearch, dagId, dagIdPattern, dagRunId, limit, offset, 
orderBy, respondedUserId, respondedUserName, responseReceived, state, 
subjectSearch, taskId, taskIdPattern }: {
+export const prefetchUseHumanInTheLoopServiceGetHitlDetails = (queryClient: 
QueryClient, { bodySearch, dagId, dagIdPattern, dagRunId, limit, offset, 
orderBy, respondedByUserId, respondedByUserName, responseReceived, state, 
subjectSearch, taskId, taskIdPattern }: {
   bodySearch?: string;
   dagId?: string;
   dagIdPattern?: string;
@@ -1386,14 +1386,14 @@ export const 
prefetchUseHumanInTheLoopServiceGetHitlDetails = (queryClient: Quer
   limit?: number;
   offset?: number;
   orderBy?: string[];
-  respondedUserId?: string[];
-  respondedUserName?: string[];
+  respondedByUserId?: string[];
+  respondedByUserName?: string[];
   responseReceived?: boolean;
   state?: string[];
   subjectSearch?: string;
   taskId?: string;
   taskIdPattern?: string;
-} = {}) => queryClient.prefetchQuery({ queryKey: 
Common.UseHumanInTheLoopServiceGetHitlDetailsKeyFn({ bodySearch, dagId, 
dagIdPattern, dagRunId, limit, offset, orderBy, respondedUserId, 
respondedUserName, responseReceived, state, subjectSearch, taskId, 
taskIdPattern }), queryFn: () => HumanInTheLoopService.getHitlDetails({ 
bodySearch, dagId, dagIdPattern, dagRunId, limit, offset, orderBy, 
respondedUserId, respondedUserName, responseReceived, state, subjectSearch, 
taskId, taskIdPattern }) });
+} = {}) => queryClient.prefetchQuery({ queryKey: 
Common.UseHumanInTheLoopServiceGetHitlDetailsKeyFn({ bodySearch, dagId, 
dagIdPattern, dagRunId, limit, offset, orderBy, respondedByUserId, 
respondedByUserName, responseReceived, state, subjectSearch, taskId, 
taskIdPattern }), queryFn: () => HumanInTheLoopService.getHitlDetails({ 
bodySearch, dagId, dagIdPattern, dagRunId, limit, offset, orderBy, 
respondedByUserId, respondedByUserName, responseReceived, state, subjectSearch, 
taskId, taskIdPa [...]
 /**
 * Get Health
 * @returns HealthInfoResponse Successful Response
diff --git a/airflow-core/src/airflow/ui/openapi-gen/queries/queries.ts 
b/airflow-core/src/airflow/ui/openapi-gen/queries/queries.ts
index e48235d6184..6c70c69ac5c 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/queries/queries.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/queries/queries.ts
@@ -1371,14 +1371,14 @@ export const useHumanInTheLoopServiceGetHitlDetail = 
<TData = Common.HumanInTheL
 * @param data.taskIdPattern SQL LIKE expression — use `%` / `_` wildcards 
(e.g. `%customer_%`). Regular expressions are **not** supported.
 * @param data.state
 * @param data.responseReceived
-* @param data.respondedUserId
-* @param data.respondedUserName
+* @param data.respondedByUserId
+* @param data.respondedByUserName
 * @param data.subjectSearch SQL LIKE expression — use `%` / `_` wildcards 
(e.g. `%customer_%`). Regular expressions are **not** supported.
 * @param data.bodySearch SQL LIKE expression — use `%` / `_` wildcards (e.g. 
`%customer_%`). Regular expressions are **not** supported.
 * @returns HITLDetailCollection Successful Response
 * @throws ApiError
 */
-export const useHumanInTheLoopServiceGetHitlDetails = <TData = 
Common.HumanInTheLoopServiceGetHitlDetailsDefaultResponse, TError = unknown, 
TQueryKey extends Array<unknown> = unknown[]>({ bodySearch, dagId, 
dagIdPattern, dagRunId, limit, offset, orderBy, respondedUserId, 
respondedUserName, responseReceived, state, subjectSearch, taskId, 
taskIdPattern }: {
+export const useHumanInTheLoopServiceGetHitlDetails = <TData = 
Common.HumanInTheLoopServiceGetHitlDetailsDefaultResponse, TError = unknown, 
TQueryKey extends Array<unknown> = unknown[]>({ bodySearch, dagId, 
dagIdPattern, dagRunId, limit, offset, orderBy, respondedByUserId, 
respondedByUserName, responseReceived, state, subjectSearch, taskId, 
taskIdPattern }: {
   bodySearch?: string;
   dagId?: string;
   dagIdPattern?: string;
@@ -1386,14 +1386,14 @@ export const useHumanInTheLoopServiceGetHitlDetails = 
<TData = Common.HumanInThe
   limit?: number;
   offset?: number;
   orderBy?: string[];
-  respondedUserId?: string[];
-  respondedUserName?: string[];
+  respondedByUserId?: string[];
+  respondedByUserName?: string[];
   responseReceived?: boolean;
   state?: string[];
   subjectSearch?: string;
   taskId?: string;
   taskIdPattern?: string;
-} = {}, queryKey?: TQueryKey, options?: Omit<UseQueryOptions<TData, TError>, 
"queryKey" | "queryFn">) => useQuery<TData, TError>({ queryKey: 
Common.UseHumanInTheLoopServiceGetHitlDetailsKeyFn({ bodySearch, dagId, 
dagIdPattern, dagRunId, limit, offset, orderBy, respondedUserId, 
respondedUserName, responseReceived, state, subjectSearch, taskId, 
taskIdPattern }, queryKey), queryFn: () => 
HumanInTheLoopService.getHitlDetails({ bodySearch, dagId, dagIdPattern, 
dagRunId, limit, offset, orderBy [...]
+} = {}, queryKey?: TQueryKey, options?: Omit<UseQueryOptions<TData, TError>, 
"queryKey" | "queryFn">) => useQuery<TData, TError>({ queryKey: 
Common.UseHumanInTheLoopServiceGetHitlDetailsKeyFn({ bodySearch, dagId, 
dagIdPattern, dagRunId, limit, offset, orderBy, respondedByUserId, 
respondedByUserName, responseReceived, state, subjectSearch, taskId, 
taskIdPattern }, queryKey), queryFn: () => 
HumanInTheLoopService.getHitlDetails({ bodySearch, dagId, dagIdPattern, 
dagRunId, limit, offset, ord [...]
 /**
 * Get Health
 * @returns HealthInfoResponse Successful Response
diff --git a/airflow-core/src/airflow/ui/openapi-gen/queries/suspense.ts 
b/airflow-core/src/airflow/ui/openapi-gen/queries/suspense.ts
index a8578766cd5..79a5f974e07 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/queries/suspense.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/queries/suspense.ts
@@ -1371,14 +1371,14 @@ export const 
useHumanInTheLoopServiceGetHitlDetailSuspense = <TData = Common.Hum
 * @param data.taskIdPattern SQL LIKE expression — use `%` / `_` wildcards 
(e.g. `%customer_%`). Regular expressions are **not** supported.
 * @param data.state
 * @param data.responseReceived
-* @param data.respondedUserId
-* @param data.respondedUserName
+* @param data.respondedByUserId
+* @param data.respondedByUserName
 * @param data.subjectSearch SQL LIKE expression — use `%` / `_` wildcards 
(e.g. `%customer_%`). Regular expressions are **not** supported.
 * @param data.bodySearch SQL LIKE expression — use `%` / `_` wildcards (e.g. 
`%customer_%`). Regular expressions are **not** supported.
 * @returns HITLDetailCollection Successful Response
 * @throws ApiError
 */
-export const useHumanInTheLoopServiceGetHitlDetailsSuspense = <TData = 
Common.HumanInTheLoopServiceGetHitlDetailsDefaultResponse, TError = unknown, 
TQueryKey extends Array<unknown> = unknown[]>({ bodySearch, dagId, 
dagIdPattern, dagRunId, limit, offset, orderBy, respondedUserId, 
respondedUserName, responseReceived, state, subjectSearch, taskId, 
taskIdPattern }: {
+export const useHumanInTheLoopServiceGetHitlDetailsSuspense = <TData = 
Common.HumanInTheLoopServiceGetHitlDetailsDefaultResponse, TError = unknown, 
TQueryKey extends Array<unknown> = unknown[]>({ bodySearch, dagId, 
dagIdPattern, dagRunId, limit, offset, orderBy, respondedByUserId, 
respondedByUserName, responseReceived, state, subjectSearch, taskId, 
taskIdPattern }: {
   bodySearch?: string;
   dagId?: string;
   dagIdPattern?: string;
@@ -1386,14 +1386,14 @@ export const 
useHumanInTheLoopServiceGetHitlDetailsSuspense = <TData = Common.Hu
   limit?: number;
   offset?: number;
   orderBy?: string[];
-  respondedUserId?: string[];
-  respondedUserName?: string[];
+  respondedByUserId?: string[];
+  respondedByUserName?: string[];
   responseReceived?: boolean;
   state?: string[];
   subjectSearch?: string;
   taskId?: string;
   taskIdPattern?: string;
-} = {}, queryKey?: TQueryKey, options?: Omit<UseQueryOptions<TData, TError>, 
"queryKey" | "queryFn">) => useSuspenseQuery<TData, TError>({ queryKey: 
Common.UseHumanInTheLoopServiceGetHitlDetailsKeyFn({ bodySearch, dagId, 
dagIdPattern, dagRunId, limit, offset, orderBy, respondedUserId, 
respondedUserName, responseReceived, state, subjectSearch, taskId, 
taskIdPattern }, queryKey), queryFn: () => 
HumanInTheLoopService.getHitlDetails({ bodySearch, dagId, dagIdPattern, 
dagRunId, limit, offset, [...]
+} = {}, queryKey?: TQueryKey, options?: Omit<UseQueryOptions<TData, TError>, 
"queryKey" | "queryFn">) => useSuspenseQuery<TData, TError>({ queryKey: 
Common.UseHumanInTheLoopServiceGetHitlDetailsKeyFn({ bodySearch, dagId, 
dagIdPattern, dagRunId, limit, offset, orderBy, respondedByUserId, 
respondedByUserName, responseReceived, state, subjectSearch, taskId, 
taskIdPattern }, queryKey), queryFn: () => 
HumanInTheLoopService.getHitlDetails({ bodySearch, dagId, dagIdPattern, 
dagRunId, limit, off [...]
 /**
 * Get Health
 * @returns HealthInfoResponse Successful Response
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 72795ca4551..332d112cb7c 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
@@ -3571,41 +3571,22 @@ export const $HITLDetail = {
             type: 'object',
             title: 'Params'
         },
-        respondents: {
-            anyOf: [
-                {
-                    items: {
-                        type: 'string'
-                    },
-                    type: 'array'
-                },
-                {
-                    type: 'null'
-                }
-            ],
-            title: 'Respondents'
-        },
-        responded_user_id: {
-            anyOf: [
-                {
-                    type: 'string'
-                },
-                {
-                    type: 'null'
-                }
-            ],
-            title: 'Responded User Id'
+        assigned_users: {
+            items: {
+                '$ref': '#/components/schemas/HITLUser'
+            },
+            type: 'array',
+            title: 'Assigned Users'
         },
-        responded_user_name: {
+        responded_by_user: {
             anyOf: [
                 {
-                    type: 'string'
+                    '$ref': '#/components/schemas/HITLUser'
                 },
                 {
                     type: 'null'
                 }
-            ],
-            title: 'Responded User Name'
+            ]
         },
         response_at: {
             anyOf: [
@@ -3672,13 +3653,8 @@ export const $HITLDetailCollection = {
 
 export const $HITLDetailResponse = {
     properties: {
-        responded_user_id: {
-            type: 'string',
-            title: 'Responded User Id'
-        },
-        responded_user_name: {
-            type: 'string',
-            title: 'Responded User Name'
+        responded_by: {
+            '$ref': '#/components/schemas/HITLUser'
         },
         response_at: {
             type: 'string',
@@ -3700,11 +3676,28 @@ export const $HITLDetailResponse = {
         }
     },
     type: 'object',
-    required: ['responded_user_id', 'responded_user_name', 'response_at', 
'chosen_options'],
+    required: ['responded_by', 'response_at', 'chosen_options'],
     title: 'HITLDetailResponse',
     description: 'Response of updating a Human-in-the-loop detail.'
 } as const;
 
+export const $HITLUser = {
+    properties: {
+        id: {
+            type: 'string',
+            title: 'Id'
+        },
+        name: {
+            type: 'string',
+            title: 'Name'
+        }
+    },
+    type: 'object',
+    required: ['id', 'name'],
+    title: 'HITLUser',
+    description: 'Schema for a Human-in-the-loop users.'
+} as const;
+
 export const $HTTPExceptionResponse = {
     properties: {
         detail: {
diff --git a/airflow-core/src/airflow/ui/openapi-gen/requests/services.gen.ts 
b/airflow-core/src/airflow/ui/openapi-gen/requests/services.gen.ts
index 5c944d4bc6a..ed570c2fc9d 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/requests/services.gen.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/requests/services.gen.ts
@@ -3623,8 +3623,8 @@ export class HumanInTheLoopService {
      * @param data.taskIdPattern SQL LIKE expression — use `%` / `_` wildcards 
(e.g. `%customer_%`). Regular expressions are **not** supported.
      * @param data.state
      * @param data.responseReceived
-     * @param data.respondedUserId
-     * @param data.respondedUserName
+     * @param data.respondedByUserId
+     * @param data.respondedByUserName
      * @param data.subjectSearch SQL LIKE expression — use `%` / `_` wildcards 
(e.g. `%customer_%`). Regular expressions are **not** supported.
      * @param data.bodySearch SQL LIKE expression — use `%` / `_` wildcards 
(e.g. `%customer_%`). Regular expressions are **not** supported.
      * @returns HITLDetailCollection Successful Response
@@ -3645,8 +3645,8 @@ export class HumanInTheLoopService {
                 task_id_pattern: data.taskIdPattern,
                 state: data.state,
                 response_received: data.responseReceived,
-                responded_user_id: data.respondedUserId,
-                responded_user_name: data.respondedUserName,
+                responded_by_user_id: data.respondedByUserId,
+                responded_by_user_name: data.respondedByUserName,
                 subject_search: data.subjectSearch,
                 body_search: data.bodySearch
             },
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 c1320c1c635..e88e743d5b5 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
@@ -940,9 +940,8 @@ export type HITLDetail = {
     params?: {
         [key: string]: unknown;
     };
-    respondents?: Array<(string)> | null;
-    responded_user_id?: string | null;
-    responded_user_name?: string | null;
+    assigned_users?: Array<HITLUser>;
+    responded_by_user?: HITLUser | null;
     response_at?: string | null;
     chosen_options?: Array<(string)> | null;
     params_input?: {
@@ -963,8 +962,7 @@ export type HITLDetailCollection = {
  * Response of updating a Human-in-the-loop detail.
  */
 export type HITLDetailResponse = {
-    responded_user_id: string;
-    responded_user_name: string;
+    responded_by: HITLUser;
     response_at: string;
     chosen_options: Array<(string)>;
     params_input?: {
@@ -972,6 +970,14 @@ export type HITLDetailResponse = {
     };
 };
 
+/**
+ * Schema for a Human-in-the-loop users.
+ */
+export type HITLUser = {
+    id: string;
+    name: string;
+};
+
 /**
  * HTTPException Model used for error response.
  */
@@ -3100,8 +3106,8 @@ export type GetHitlDetailsData = {
     limit?: number;
     offset?: number;
     orderBy?: Array<(string)>;
-    respondedUserId?: Array<(string)>;
-    respondedUserName?: Array<(string)>;
+    respondedByUserId?: Array<(string)>;
+    respondedByUserName?: Array<(string)>;
     responseReceived?: boolean | null;
     state?: Array<(string)>;
     /**
diff --git 
a/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_hitl.py 
b/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_hitl.py
index 9dfd3559920..e20f9fabba4 100644
--- a/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_hitl.py
+++ b/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_hitl.py
@@ -31,6 +31,7 @@ from sqlalchemy.orm import Session
 from airflow._shared.timezones.timezone import utcnow
 from airflow.models.hitl import HITLDetail
 from airflow.models.log import Log
+from airflow.sdk.execution_time.hitl import HITLUser
 from airflow.utils.state import TaskInstanceState
 
 if TYPE_CHECKING:
@@ -77,7 +78,7 @@ def sample_hitl_detail(sample_ti: TaskInstance, session: 
Session) -> HITLDetail:
         defaults=["Approve"],
         multiple=False,
         params={"input_1": 1},
-        respondents=None,
+        assignees=None,
     )
     session.add(hitl_detail_model)
     session.commit()
@@ -95,7 +96,7 @@ def sample_hitl_detail_non_respondent(sample_ti: 
TaskInstance, session: Session)
         defaults=["Approve"],
         multiple=False,
         params={"input_1": 1},
-        respondents=["non_test"],
+        assignees=[HITLUser(id="non_test", name="non_test")],
     )
     session.add(hitl_detail_model)
     session.commit()
@@ -113,7 +114,7 @@ def sample_hitl_detail_respondent(sample_ti: TaskInstance, 
session: Session) ->
         defaults=["Approve"],
         multiple=False,
         params={"input_1": 1},
-        respondents=["test"],
+        assignees=[HITLUser(id="test", name="test")],
     )
     session.add(hitl_detail_model)
     session.commit()
@@ -173,8 +174,7 @@ def sample_hitl_details(sample_tis: list[TaskInstance], 
session: Session) -> lis
                 response_at=utcnow(),
                 chosen_options=[str(i)],
                 params_input={"input": i},
-                responded_user_id="test",
-                responded_user_name="test",
+                responded_by={"id": "test", "name": "test"},
             )
             for i, ti in enumerate(sample_tis[5:])
         ]
@@ -208,14 +208,13 @@ def expected_sample_hitl_detail_dict(sample_ti: 
TaskInstance) -> dict[str, Any]:
         "multiple": False,
         "options": ["Approve", "Reject"],
         "params": {"input_1": 1},
-        "respondents": None,
+        "assigned_users": [],
         "params_input": {},
         "response_at": None,
         "chosen_options": None,
         "response_received": False,
         "subject": "This is subject",
-        "responded_user_id": None,
-        "responded_user_name": None,
+        "responded_by_user": None,
         "task_instance": {
             "dag_display_name": DAG_ID,
             "dag_id": DAG_ID,
@@ -321,8 +320,7 @@ class TestUpdateHITLDetailEndpoint:
         assert response.json() == {
             "params_input": {"input_1": 2},
             "chosen_options": ["Approve"],
-            "responded_user_id": "test",
-            "responded_user_name": "test",
+            "responded_by": {"id": "test", "name": "test"},
             "response_at": "2025-07-03T00:00:00Z",
         }
 
@@ -332,7 +330,7 @@ class TestUpdateHITLDetailEndpoint:
     @time_machine.travel(datetime(2025, 7, 3, 0, 0, 0), tick=False)
     @pytest.mark.usefixtures("sample_hitl_detail_respondent")
     @pytest.mark.parametrize("map_index", [None, -1])
-    def test_should_respond_200_to_respondent_user(
+    def test_should_respond_200_to_assigned_users(
         self,
         test_client: TestClient,
         sample_ti_url_identifier: str,
@@ -351,8 +349,7 @@ class TestUpdateHITLDetailEndpoint:
         assert response.json() == {
             "params_input": {"input_1": 2},
             "chosen_options": ["Approve"],
-            "responded_user_id": "test",
-            "responded_user_name": "test",
+            "responded_by": {"id": "test", "name": "test"},
             "response_at": "2025-07-03T00:00:00Z",
         }
 
@@ -453,8 +450,7 @@ class TestUpdateHITLDetailEndpoint:
         expected_response = {
             "params_input": {"input_1": 2},
             "chosen_options": ["Approve"],
-            "responded_user_id": "test",
-            "responded_user_name": "test",
+            "responded_by": {"id": "test", "name": "test"},
             "response_at": "2025-07-03T00:00:00Z",
         }
         assert response.status_code == 200
@@ -579,8 +575,8 @@ class TestGetHITLDetailsEndpoint:
             ({"body_search": "this is"}, 8),
             ({"response_received": False}, 5),
             ({"response_received": True}, 3),
-            ({"responded_user_id": ["test"]}, 3),
-            ({"responded_user_name": ["test"]}, 3),
+            ({"responded_by_user_id": ["test"]}, 3),
+            ({"responded_by_user_name": ["test"]}, 3),
         ],
         ids=[
             "dag_id_pattern_hitl_dag",
diff --git 
a/airflow-core/tests/unit/api_fastapi/core_api/routes/ui/test_dags.py 
b/airflow-core/tests/unit/api_fastapi/core_api/routes/ui/test_dags.py
index ea1f6293151..0272b584ab6 100644
--- a/airflow-core/tests/unit/api_fastapi/core_api/routes/ui/test_dags.py
+++ b/airflow-core/tests/unit/api_fastapi/core_api/routes/ui/test_dags.py
@@ -161,7 +161,7 @@ class TestGetDagRuns(TestPublicDagEndpoint):
                 defaults=["Approve"],
                 response_at=utcnow(),
                 chosen_options=["Approve"],
-                responded_user_id="test",
+                responded_by={"id": "test", "name": "test"},
             )
             for i in range(3, 5)
         ]
@@ -187,6 +187,7 @@ class TestGetDagRuns(TestPublicDagEndpoint):
                         "params": {},
                         "params_input": {},
                         "response_received": False,
+                        "assigned_users": [],
                     }
                     for i in range(3)
                 ],
diff --git 
a/airflow-core/tests/unit/api_fastapi/execution_api/versions/head/test_hitl.py 
b/airflow-core/tests/unit/api_fastapi/execution_api/versions/head/test_hitl.py
index 085fc7ae6a8..764d5a48ccd 100644
--- 
a/airflow-core/tests/unit/api_fastapi/execution_api/versions/head/test_hitl.py
+++ 
b/airflow-core/tests/unit/api_fastapi/execution_api/versions/head/test_hitl.py
@@ -45,13 +45,12 @@ default_hitl_detail_request_kwargs: dict[str, Any] = {
     "defaults": ["Approve"],
     "multiple": False,
     "params": {"input_1": 1},
-    "respondents": None,
+    "assignees": None,
 }
 expected_empty_hitl_detail_response_part: dict[str, Any] = {
     "response_at": None,
     "chosen_options": None,
-    "responded_user_id": None,
-    "responded_user_name": None,
+    "responded_by_user": None,
     "params_input": {},
     "response_received": False,
 }
@@ -94,8 +93,7 @@ def expected_sample_hitl_detail_dict(sample_ti: TaskInstance) 
-> dict[str, Any]:
                 "params_input": {"input_1": 2},
                 "response_at": convert_to_utc(datetime(2025, 7, 3, 0, 0, 0)),
                 "chosen_options": ["Reject"],
-                "responded_user_id": "Fallback to defaults",
-                "responded_user_name": "Fallback to defaults",
+                "responded_by": {"id": "Fallback to defaults", "name": 
"Fallback to defaults"},
             },
         },
     ],
@@ -125,11 +123,15 @@ def test_upsert_hitl_detail(
             **default_hitl_detail_request_kwargs,
         },
     )
-    assert response.status_code == 201
-    assert response.json() == {
+
+    expected_json = {
         "ti_id": ti.id,
         **default_hitl_detail_request_kwargs,
     }
+    expected_json["assigned_users"] = expected_json.pop("assignees") or []
+
+    assert response.status_code == 201
+    assert response.json() == expected_json
 
 
 def test_upsert_hitl_detail_with_empty_option(
@@ -172,8 +174,10 @@ def test_update_hitl_detail(client: Client, sample_ti: 
TaskInstance) -> None:
         "response_at": "2025-07-03T00:00:00Z",
         "chosen_options": ["Reject"],
         "response_received": True,
-        "responded_user_id": "Fallback to defaults",
-        "responded_user_name": "Fallback to defaults",
+        "responded_by_user": {
+            "id": "Fallback to defaults",
+            "name": "Fallback to defaults",
+        },
     }
 
 
diff --git a/airflow-ctl/src/airflowctl/api/datamodels/generated.py 
b/airflow-ctl/src/airflowctl/api/datamodels/generated.py
index 37ecd597a5c..ccad0f23ed8 100644
--- a/airflow-ctl/src/airflowctl/api/datamodels/generated.py
+++ b/airflow-ctl/src/airflowctl/api/datamodels/generated.py
@@ -525,16 +525,13 @@ class FastAPIRootMiddlewareResponse(BaseModel):
     name: Annotated[str, Field(title="Name")]
 
 
-class HITLDetailResponse(BaseModel):
+class HITLUser(BaseModel):
     """
-    Response of updating a Human-in-the-loop detail.
+    Schema for a Human-in-the-loop users.
     """
 
-    responded_user_id: Annotated[str, Field(title="Responded User Id")]
-    responded_user_name: Annotated[str, Field(title="Responded User Name")]
-    response_at: Annotated[datetime, Field(title="Response At")]
-    chosen_options: Annotated[list[str], Field(min_length=1, title="Chosen 
Options")]
-    params_input: Annotated[dict[str, Any] | None, Field(title="Params 
Input")] = None
+    id: Annotated[str, Field(title="Id")]
+    name: Annotated[str, Field(title="Name")]
 
 
 class HTTPExceptionResponse(BaseModel):
@@ -1434,6 +1431,17 @@ class EventLogCollectionResponse(BaseModel):
     total_entries: Annotated[int, Field(title="Total Entries")]
 
 
+class HITLDetailResponse(BaseModel):
+    """
+    Response of updating a Human-in-the-loop detail.
+    """
+
+    responded_by: HITLUser
+    response_at: Annotated[datetime, Field(title="Response At")]
+    chosen_options: Annotated[list[str], Field(min_length=1, title="Chosen 
Options")]
+    params_input: Annotated[dict[str, Any] | None, Field(title="Params 
Input")] = None
+
+
 class HTTPValidationError(BaseModel):
     detail: Annotated[list[ValidationError] | None, Field(title="Detail")] = 
None
 
@@ -1828,9 +1836,8 @@ class HITLDetail(BaseModel):
     defaults: Annotated[list[str] | None, Field(title="Defaults")] = None
     multiple: Annotated[bool | None, Field(title="Multiple")] = False
     params: Annotated[dict[str, Any] | None, Field(title="Params")] = None
-    respondents: Annotated[list[str] | None, Field(title="Respondents")] = None
-    responded_user_id: Annotated[str | None, Field(title="Responded User Id")] 
= None
-    responded_user_name: Annotated[str | None, Field(title="Responded User 
Name")] = None
+    assigned_users: Annotated[list[HITLUser] | None, Field(title="Assigned 
Users")] = None
+    responded_by_user: HITLUser | None = None
     response_at: Annotated[datetime | None, Field(title="Response At")] = None
     chosen_options: Annotated[list[str] | None, Field(title="Chosen Options")] 
= None
     params_input: Annotated[dict[str, Any] | None, Field(title="Params 
Input")] = None
diff --git 
a/providers/standard/src/airflow/providers/standard/example_dags/example_hitl_operator.py
 
b/providers/standard/src/airflow/providers/standard/example_dags/example_hitl_operator.py
index dd7b4dc277f..44d77ba4959 100644
--- 
a/providers/standard/src/airflow/providers/standard/example_dags/example_hitl_operator.py
+++ 
b/providers/standard/src/airflow/providers/standard/example_dags/example_hitl_operator.py
@@ -140,6 +140,7 @@ with DAG(
         notifiers=[hitl_request_callback],
         on_success_callback=hitl_success_callback,
         on_failure_callback=hitl_failure_callback,
+        assigned_users=[{"id": "admin", "name": "admin"}],
     )
     # [END howto_hitl_approval_operator]
 
diff --git 
a/providers/standard/src/airflow/providers/standard/operators/hitl.py 
b/providers/standard/src/airflow/providers/standard/operators/hitl.py
index 440abf9a516..f8e1c631ea6 100644
--- a/providers/standard/src/airflow/providers/standard/operators/hitl.py
+++ b/providers/standard/src/airflow/providers/standard/operators/hitl.py
@@ -41,6 +41,7 @@ from airflow.sdk.timezone import utcnow
 
 if TYPE_CHECKING:
     from airflow.sdk.definitions.context import Context
+    from airflow.sdk.execution_time.hitl import HITLUser
     from airflow.sdk.types import RuntimeTaskInstanceProtocol
 
 
@@ -70,7 +71,7 @@ class HITLOperator(BaseOperator):
         multiple: bool = False,
         params: ParamsDict | dict[str, Any] | None = None,
         notifiers: Sequence[BaseNotifier] | BaseNotifier | None = None,
-        respondents: str | list[str] | None = None,
+        assigned_users: HITLUser | list[HITLUser] | None = None,
         **kwargs,
     ) -> None:
         super().__init__(**kwargs)
@@ -86,7 +87,7 @@ class HITLOperator(BaseOperator):
         self.notifiers: Sequence[BaseNotifier] = (
             [notifiers] if isinstance(notifiers, BaseNotifier) else notifiers 
or []
         )
-        self.respondents = [respondents] if isinstance(respondents, str) else 
respondents
+        self.assigned_users = [assigned_users] if isinstance(assigned_users, 
dict) else assigned_users
 
         self.validate_options()
         self.validate_params()
@@ -138,7 +139,7 @@ class HITLOperator(BaseOperator):
             defaults=self.defaults,
             multiple=self.multiple,
             params=self.serialized_params,
-            respondents=self.respondents,
+            assigned_users=self.assigned_users,
         )
 
         if self.execution_timeout:
@@ -178,6 +179,7 @@ class HITLOperator(BaseOperator):
         return HITLTriggerEventSuccessPayload(
             chosen_options=chosen_options,
             params_input=params_input,
+            responded_by_user=event["responded_by_user"],
         )
 
     def process_trigger_event_error(self, event: dict[str, Any]) -> None:
diff --git a/providers/standard/src/airflow/providers/standard/triggers/hitl.py 
b/providers/standard/src/airflow/providers/standard/triggers/hitl.py
index c5f32800058..a9299ae2407 100644
--- a/providers/standard/src/airflow/providers/standard/triggers/hitl.py
+++ b/providers/standard/src/airflow/providers/standard/triggers/hitl.py
@@ -25,12 +25,13 @@ if not AIRFLOW_V_3_1_PLUS:
 import asyncio
 from collections.abc import AsyncIterator
 from datetime import datetime
-from typing import Any, Literal, TypedDict
+from typing import TYPE_CHECKING, Any, Literal, TypedDict
 from uuid import UUID
 
 from asgiref.sync import sync_to_async
 
 from airflow.sdk.execution_time.hitl import (
+    HITLUser,
     get_hitl_detail_content_detail,
     update_hitl_detail_response,
 )
@@ -43,6 +44,7 @@ class HITLTriggerEventSuccessPayload(TypedDict, total=False):
 
     chosen_options: list[str]
     params_input: dict[str, Any]
+    responded_by_user: HITLUser
     timedout: bool
 
 
@@ -100,12 +102,15 @@ class HITLTrigger(BaseTrigger):
             if self.timeout_datetime and self.timeout_datetime < utcnow():
                 # Fetch latest HITL detail before fallback
                 resp = await 
sync_to_async(get_hitl_detail_content_detail)(ti_id=self.ti_id)
+                # Response already received, yield success and exit
                 if resp.response_received and resp.chosen_options:
-                    # Response already received, yield success and exit
+                    if TYPE_CHECKING:
+                        assert resp.responded_by_user is not None
+
                     self.log.info(
                         "[HITL] responded_by=%s (id=%s) options=%s at %s 
(timeout fallback skipped)",
-                        resp.responded_user_name,
-                        resp.responded_user_id,
+                        resp.responded_by_user.name,
+                        resp.responded_by_user.id,
                         resp.chosen_options,
                         resp.response_at,
                     )
@@ -113,6 +118,10 @@ class HITLTrigger(BaseTrigger):
                         HITLTriggerEventSuccessPayload(
                             chosen_options=resp.chosen_options,
                             params_input=resp.params_input or {},
+                            responded_by_user=HITLUser(
+                                id=resp.responded_by_user.id,
+                                name=resp.responded_by_user.name,
+                            ),
                             timedout=False,
                         )
                     )
@@ -139,6 +148,10 @@ class HITLTrigger(BaseTrigger):
                     HITLTriggerEventSuccessPayload(
                         chosen_options=self.defaults,
                         params_input=self.params,
+                        responded_by_user=HITLUser(
+                            id="Fallback to defaults",
+                            name="Fallback to defaults",
+                        ),
                         timedout=True,
                     )
                 )
@@ -146,10 +159,12 @@ class HITLTrigger(BaseTrigger):
 
             resp = await 
sync_to_async(get_hitl_detail_content_detail)(ti_id=self.ti_id)
             if resp.response_received and resp.chosen_options:
+                if TYPE_CHECKING:
+                    assert resp.responded_by_user is not None
                 self.log.info(
                     "[HITL] responded_by=%s (id=%s) options=%s at %s",
-                    resp.responded_user_name,
-                    resp.responded_user_id,
+                    resp.responded_by_user.name,
+                    resp.responded_by_user.id,
                     resp.chosen_options,
                     resp.response_at,
                 )
@@ -157,6 +172,10 @@ class HITLTrigger(BaseTrigger):
                     HITLTriggerEventSuccessPayload(
                         chosen_options=resp.chosen_options,
                         params_input=resp.params_input or {},
+                        responded_by_user=HITLUser(
+                            id=resp.responded_by_user.id,
+                            name=resp.responded_by_user.name,
+                        ),
                         timedout=False,
                     )
                 )
diff --git a/providers/standard/tests/unit/standard/operators/test_hitl.py 
b/providers/standard/tests/unit/standard/operators/test_hitl.py
index 18646ab118d..98d0bf66864 100644
--- a/providers/standard/tests/unit/standard/operators/test_hitl.py
+++ b/providers/standard/tests/unit/standard/operators/test_hitl.py
@@ -43,6 +43,7 @@ from airflow.providers.standard.operators.hitl import (
 )
 from airflow.sdk import Param, timezone
 from airflow.sdk.definitions.param import ParamsDict
+from airflow.sdk.execution_time.hitl import HITLUser
 
 from tests_common.test_utils.config import conf_vars
 
@@ -66,7 +67,7 @@ def hitl_task_and_ti_for_generating_link(dag_maker: DagMaker) 
-> tuple[HITLOpera
             options=["1", "2", "3", "4", "5"],
             body="This is body",
             defaults=["1"],
-            respondents="test",
+            assigned_users=HITLUser(id="test", name="test"),
             multiple=True,
             params=ParamsDict({"input_1": 1, "input_2": 2, "input_3": 3}),
         )
@@ -165,7 +166,7 @@ class TestHITLOperator:
                 options=["1", "2", "3", "4", "5"],
                 body="This is body",
                 defaults=["1"],
-                respondents="test",
+                assigned_users=HITLUser(id="test", name="test"),
                 multiple=False,
                 params=ParamsDict({"input_1": 1}),
                 notifiers=[notifier],
@@ -181,10 +182,9 @@ class TestHITLOperator:
         assert hitl_detail_model.defaults == ["1"]
         assert hitl_detail_model.multiple is False
         assert hitl_detail_model.params == {"input_1": 1}
-        assert hitl_detail_model.respondents == ["test"]
+        assert hitl_detail_model.assignees == [{"id": "test", "name": "test"}]
         assert hitl_detail_model.response_at is None
-        assert hitl_detail_model.responded_user_id is None
-        assert hitl_detail_model.responded_user_name is None
+        assert hitl_detail_model.responded_by is None
         assert hitl_detail_model.chosen_options is None
         assert hitl_detail_model.params_input == {}
 
@@ -232,7 +232,11 @@ class TestHITLOperator:
 
         ret = hitl_op.execute_complete(
             context={},
-            event={"chosen_options": ["1"], "params_input": {"input": 2}},
+            event={
+                "chosen_options": ["1"],
+                "params_input": {"input": 2},
+                "responded_by_user": {"id": "test", "name": "test"},
+            },
         )
 
         assert ret["chosen_options"] == ["1"]
@@ -253,6 +257,7 @@ class TestHITLOperator:
                 event={
                     "chosen_options": ["not exists"],
                     "params_input": {"input": 2},
+                    "responded_by_user": {"id": "test", "name": "test"},
                 },
             )
 
@@ -271,6 +276,7 @@ class TestHITLOperator:
                 event={
                     "chosen_options": ["1"],
                     "params_input": {"no such key": 2, "input": 333},
+                    "responded_by_user": {"id": "test", "name": "test"},
                 },
             )
 
@@ -397,12 +403,17 @@ class TestApprovalOperator:
 
         ret = hitl_op.execute_complete(
             context={},
-            event={"chosen_options": ["Approve"], "params_input": {}},
+            event={
+                "chosen_options": ["Approve"],
+                "params_input": {},
+                "responded_by_user": {"id": "test", "name": "test"},
+            },
         )
 
         assert ret == {
             "chosen_options": ["Approve"],
             "params_input": {},
+            "responded_by_user": {"id": "test", "name": "test"},
         }
 
     def test_execute_complete_with_downstream_tasks(self, dag_maker) -> None:
@@ -419,7 +430,11 @@ class TestApprovalOperator:
         with pytest.raises(DownstreamTasksSkipped) as exc_info:
             hitl_op.execute_complete(
                 context={"ti": ti, "task": ti.task},
-                event={"chosen_options": ["Reject"], "params_input": {}},
+                event={
+                    "chosen_options": ["Reject"],
+                    "params_input": {},
+                    "responded_by_user": {"id": "test", "name": "test"},
+                },
             )
         assert set(exc_info.value.tasks) == {"op1"}
 
@@ -480,6 +495,7 @@ class TestHITLBranchOperator:
                 event={
                     "chosen_options": ["branch_1"],
                     "params_input": {},
+                    "responded_by_user": {"id": "test", "name": "test"},
                 },
             )
         assert set(exc_info.value.tasks) == set((f"branch_{i}", -1) for i in 
range(2, 6))
@@ -503,6 +519,7 @@ class TestHITLBranchOperator:
                 event={
                     "chosen_options": [f"branch_{i}" for i in range(1, 4)],
                     "params_input": {},
+                    "responded_by_user": {"id": "test", "name": "test"},
                 },
             )
         assert set(exc_info.value.tasks) == set((f"branch_{i}", -1) for i in 
range(4, 6))
@@ -524,7 +541,11 @@ class TestHITLBranchOperator:
         with pytest.raises(DownstreamTasksSkipped) as exc:
             op.execute_complete(
                 context={"ti": ti, "task": ti.task},
-                event={"chosen_options": ["Approve"], "params_input": {}},
+                event={
+                    "chosen_options": ["Approve"],
+                    "params_input": {},
+                    "responded_by_user": {"id": "test", "name": "test"},
+                },
             )
         # checks to see that the "archive" task was skipped
         assert set(exc.value.tasks) == {("archive", -1)}
@@ -551,7 +572,11 @@ class TestHITLBranchOperator:
         with pytest.raises(DownstreamTasksSkipped) as exc:
             op.execute_complete(
                 context={"ti": ti, "task": ti.task},
-                event={"chosen_options": ["Approve", "KeepAsIs"], 
"params_input": {}},
+                event={
+                    "chosen_options": ["Approve", "KeepAsIs"],
+                    "params_input": {},
+                    "responded_by_user": {"id": "test", "name": "test"},
+                },
             )
         # publish + keep chosen → only "other" skipped
         assert set(exc.value.tasks) == {("other", -1)}
@@ -572,7 +597,11 @@ class TestHITLBranchOperator:
         with pytest.raises(DownstreamTasksSkipped) as exc:
             op.execute_complete(
                 context={"ti": ti, "task": ti.task},
-                event={"chosen_options": ["branch_2"], "params_input": {}},
+                event={
+                    "chosen_options": ["branch_2"],
+                    "params_input": {},
+                    "responded_by_user": {"id": "test", "name": "test"},
+                },
             )
         assert set(exc.value.tasks) == {("branch_1", -1)}
 
@@ -593,7 +622,11 @@ class TestHITLBranchOperator:
         with pytest.raises(AirflowException, match="downstream|not found"):
             op.execute_complete(
                 context={"ti": ti, "task": ti.task},
-                event={"chosen_options": ["Approve"], "params_input": {}},
+                event={
+                    "chosen_options": ["Approve"],
+                    "params_input": {},
+                    "responded_by_user": {"id": "test", "name": "test"},
+                },
             )
 
     @pytest.mark.parametrize("bad", [123, ["publish"], {"x": "y"}, b"publish"])
diff --git a/providers/standard/tests/unit/standard/triggers/test_hitl.py 
b/providers/standard/tests/unit/standard/triggers/test_hitl.py
index 7b33715e68d..ef82f9e09d9 100644
--- a/providers/standard/tests/unit/standard/triggers/test_hitl.py
+++ b/providers/standard/tests/unit/standard/triggers/test_hitl.py
@@ -31,7 +31,7 @@ from unittest import mock
 from uuid6 import uuid7
 
 from airflow._shared.timezones.timezone import utc, utcnow
-from airflow.api_fastapi.execution_api.datamodels.hitl import 
HITLDetailResponse
+from airflow.api_fastapi.execution_api.datamodels.hitl import 
HITLDetailResponse, HITLUser
 from airflow.providers.standard.triggers.hitl import (
     HITLTrigger,
     HITLTriggerEventFailurePayload,
@@ -110,8 +110,7 @@ class TestHITLTrigger:
         )
         mock_supervisor_comms.send.return_value = HITLDetailResponse(
             response_received=False,
-            responded_user_id=None,
-            responded_user_name=None,
+            responded_by_user=None,
             response_at=None,
             chosen_options=None,
             params_input={},
@@ -123,7 +122,12 @@ class TestHITLTrigger:
         event = await trigger_task
 
         assert event == TriggerEvent(
-            HITLTriggerEventSuccessPayload(chosen_options=["1"], 
params_input={"input": 1}, timedout=True)
+            HITLTriggerEventSuccessPayload(
+                chosen_options=["1"],
+                params_input={"input": 1},
+                responded_by_user={"id": "Fallback to defaults", "name": 
"Fallback to defaults"},
+                timedout=True,
+            )
         )
 
         assert mock_log.info.call_args == mock.call(
@@ -149,8 +153,7 @@ class TestHITLTrigger:
         )
         mock_supervisor_comms.send.return_value = HITLDetailResponse(
             response_received=True,
-            responded_user_id="1",
-            responded_user_name="test",
+            responded_by_user=HITLUser(id="1", name="test"),
             response_at=action_datetime,
             chosen_options=["2"],
             params_input={},
@@ -162,7 +165,12 @@ class TestHITLTrigger:
         event = await trigger_task
 
         assert event == TriggerEvent(
-            HITLTriggerEventSuccessPayload(chosen_options=["2"], 
params_input={}, timedout=False)
+            HITLTriggerEventSuccessPayload(
+                chosen_options=["2"],
+                params_input={},
+                responded_by_user={"id": "1", "name": "test"},
+                timedout=False,
+            )
         )
 
         assert mock_log.info.call_args == mock.call(
@@ -188,8 +196,7 @@ class TestHITLTrigger:
         )
         mock_supervisor_comms.send.return_value = HITLDetailResponse(
             response_received=True,
-            responded_user_id="test",
-            responded_user_name="test",
+            responded_by_user=HITLUser(id="test", name="test"),
             response_at=utcnow(),
             chosen_options=["3"],
             params_input={"input": 50},
@@ -203,6 +210,7 @@ class TestHITLTrigger:
             HITLTriggerEventSuccessPayload(
                 chosen_options=["3"],
                 params_input={"input": 50},
+                responded_by_user={"id": "test", "name": "test"},
                 timedout=False,
             )
         )
diff --git a/task-sdk/src/airflow/sdk/api/client.py 
b/task-sdk/src/airflow/sdk/api/client.py
index 04575fa770d..0a353271c10 100644
--- a/task-sdk/src/airflow/sdk/api/client.py
+++ b/task-sdk/src/airflow/sdk/api/client.py
@@ -44,6 +44,7 @@ from airflow.sdk.api.datamodels._generated import (
     DagRunStateResponse,
     DagRunType,
     HITLDetailResponse,
+    HITLUser,
     InactiveAssetsResponse,
     PrevSuccessfulDagRunResponse,
     TaskInstanceState,
@@ -723,7 +724,7 @@ class HITLOperations:
         defaults: list[str] | None = None,
         multiple: bool = False,
         params: dict[str, Any] | None = None,
-        respondents: list[str] | None = None,
+        assigned_users: list[HITLUser] | None = None,
     ) -> HITLDetailRequestResult:
         """Add a Human-in-the-loop response that waits for human response for 
a specific Task Instance."""
         payload = CreateHITLDetailPayload(
@@ -734,7 +735,7 @@ class HITLOperations:
             defaults=defaults,
             multiple=multiple,
             params=params,
-            respondents=respondents,
+            assigned_users=assigned_users,
         )
         resp = self.client.post(
             f"/hitlDetails/{ti_id}",
diff --git a/task-sdk/src/airflow/sdk/api/datamodels/_generated.py 
b/task-sdk/src/airflow/sdk/api/datamodels/_generated.py
index cd861bf07d1..d2151d59d02 100644
--- a/task-sdk/src/airflow/sdk/api/datamodels/_generated.py
+++ b/task-sdk/src/airflow/sdk/api/datamodels/_generated.py
@@ -154,32 +154,13 @@ class DagRunType(str, Enum):
     ASSET_TRIGGERED = "asset_triggered"
 
 
-class HITLDetailRequest(BaseModel):
+class HITLUser(BaseModel):
     """
-    Schema for the request part of a Human-in-the-loop detail for a specific 
task instance.
+    Schema for a Human-in-the-loop users.
     """
 
-    ti_id: Annotated[UUID, Field(title="Ti Id")]
-    options: Annotated[list[str], Field(min_length=1, title="Options")]
-    subject: Annotated[str, Field(title="Subject")]
-    body: Annotated[str | None, Field(title="Body")] = None
-    defaults: Annotated[list[str] | None, Field(title="Defaults")] = None
-    multiple: Annotated[bool | None, Field(title="Multiple")] = False
-    params: Annotated[dict[str, Any] | None, Field(title="Params")] = None
-    respondents: Annotated[list[str] | None, Field(title="Respondents")] = None
-
-
-class HITLDetailResponse(BaseModel):
-    """
-    Schema for the response part of a Human-in-the-loop detail for a specific 
task instance.
-    """
-
-    response_received: Annotated[bool, Field(title="Response Received")]
-    responded_user_name: Annotated[str | None, Field(title="Responded User 
Name")] = None
-    responded_user_id: Annotated[str | None, Field(title="Responded User Id")] 
= None
-    response_at: Annotated[AwareDatetime | None, Field(title="Response At")] = 
None
-    chosen_options: Annotated[list[str] | None, Field(title="Chosen Options")] 
= None
-    params_input: Annotated[dict[str, Any] | None, Field(title="Params 
Input")] = None
+    id: Annotated[str, Field(title="Id")]
+    name: Annotated[str, Field(title="Name")]
 
 
 class InactiveAssetsResponse(BaseModel):
@@ -561,6 +542,33 @@ class DagRun(BaseModel):
     consumed_asset_events: Annotated[list[AssetEventDagRunReference], 
Field(title="Consumed Asset Events")]
 
 
+class HITLDetailRequest(BaseModel):
+    """
+    Schema for the request part of a Human-in-the-loop detail for a specific 
task instance.
+    """
+
+    ti_id: Annotated[UUID, Field(title="Ti Id")]
+    options: Annotated[list[str], Field(min_length=1, title="Options")]
+    subject: Annotated[str, Field(title="Subject")]
+    body: Annotated[str | None, Field(title="Body")] = None
+    defaults: Annotated[list[str] | None, Field(title="Defaults")] = None
+    multiple: Annotated[bool | None, Field(title="Multiple")] = False
+    params: Annotated[dict[str, Any] | None, Field(title="Params")] = None
+    assigned_users: Annotated[list[HITLUser] | None, Field(title="Assigned 
Users")] = None
+
+
+class HITLDetailResponse(BaseModel):
+    """
+    Schema for the response part of a Human-in-the-loop detail for a specific 
task instance.
+    """
+
+    response_received: Annotated[bool, Field(title="Response Received")]
+    responded_by_user: HITLUser | None = None
+    response_at: Annotated[AwareDatetime | None, Field(title="Response At")] = 
None
+    chosen_options: Annotated[list[str] | None, Field(title="Chosen Options")] 
= None
+    params_input: Annotated[dict[str, Any] | None, Field(title="Params 
Input")] = None
+
+
 class HTTPValidationError(BaseModel):
     detail: Annotated[list[ValidationError] | None, Field(title="Detail")] = 
None
 
diff --git a/task-sdk/src/airflow/sdk/execution_time/hitl.py 
b/task-sdk/src/airflow/sdk/execution_time/hitl.py
index 500be78ab4e..07f94e63c05 100644
--- a/task-sdk/src/airflow/sdk/execution_time/hitl.py
+++ b/task-sdk/src/airflow/sdk/execution_time/hitl.py
@@ -17,9 +17,10 @@
 
 from __future__ import annotations
 
-from typing import TYPE_CHECKING, Any
+from typing import TYPE_CHECKING, Any, TypedDict
 from uuid import UUID
 
+from airflow.sdk.api.datamodels._generated import HITLUser as APIHITLUser
 from airflow.sdk.execution_time.comms import (
     CreateHITLDetailPayload,
     GetHITLDetailResponse,
@@ -30,6 +31,11 @@ if TYPE_CHECKING:
     from airflow.sdk.api.datamodels._generated import HITLDetailResponse
 
 
+class HITLUser(TypedDict):
+    id: str
+    name: str
+
+
 def upsert_hitl_detail(
     ti_id: UUID,
     options: list[str],
@@ -38,7 +44,7 @@ def upsert_hitl_detail(
     defaults: list[str] | None = None,
     multiple: bool = False,
     params: dict[str, Any] | None = None,
-    respondents: list[str] | None = None,
+    assigned_users: list[HITLUser] | None = None,
 ) -> None:
     from airflow.sdk.execution_time.task_runner import SUPERVISOR_COMMS
 
@@ -51,7 +57,11 @@ def upsert_hitl_detail(
             defaults=defaults,
             params=params,
             multiple=multiple,
-            respondents=respondents,
+            assigned_users=(
+                [APIHITLUser(id=user["id"], name=user["name"]) for user in 
assigned_users]
+                if assigned_users
+                else []
+            ),
         )
     )
 
diff --git a/task-sdk/src/airflow/sdk/execution_time/supervisor.py 
b/task-sdk/src/airflow/sdk/execution_time/supervisor.py
index 76a52acd98f..4969ed8a1d4 100644
--- a/task-sdk/src/airflow/sdk/execution_time/supervisor.py
+++ b/task-sdk/src/airflow/sdk/execution_time/supervisor.py
@@ -1344,7 +1344,7 @@ class ActivitySubprocess(WatchedSubprocess):
                 defaults=msg.defaults,
                 params=msg.params,
                 multiple=msg.multiple,
-                respondents=msg.respondents,
+                assigned_users=msg.assigned_users,
             )
             self.send_msg(resp, request_id=req_id, error=None, **dump_opts)
         elif isinstance(msg, MaskSecret):
diff --git a/task-sdk/tests/task_sdk/api/test_client.py 
b/task-sdk/tests/task_sdk/api/test_client.py
index 986ab5fe5e8..9464296934d 100644
--- a/task-sdk/tests/task_sdk/api/test_client.py
+++ b/task-sdk/tests/task_sdk/api/test_client.py
@@ -38,6 +38,7 @@ from airflow.sdk.api.datamodels._generated import (
     DagRunState,
     DagRunStateResponse,
     HITLDetailResponse,
+    HITLUser,
     VariableResponse,
     XComResponse,
 )
@@ -1289,7 +1290,7 @@ class TestHITLOperations:
         assert result.defaults == ["Approval"]
         assert result.params is None
         assert result.multiple is False
-        assert result.respondents is None
+        assert result.assigned_users is None
 
     def test_update_response(self, time_machine: TimeMachineFixture) -> None:
         time_machine.move_to(datetime(2025, 7, 3, 0, 0, 0))
@@ -1302,8 +1303,7 @@ class TestHITLOperations:
                     json={
                         "chosen_options": ["Approval"],
                         "params_input": {},
-                        "responded_user_id": "admin",
-                        "responded_user_name": "admin",
+                        "responded_by_user": {"id": "admin", "name": "admin"},
                         "response_received": True,
                         "response_at": "2025-07-03T00:00:00Z",
                     },
@@ -1320,8 +1320,7 @@ class TestHITLOperations:
         assert result.response_received is True
         assert result.chosen_options == ["Approval"]
         assert result.params_input == {}
-        assert result.responded_user_id == "admin"
-        assert result.responded_user_name == "admin"
+        assert result.responded_by_user == HITLUser(id="admin", name="admin")
         assert result.response_at == timezone.datetime(2025, 7, 3, 0, 0, 0)
 
     def test_get_detail_response(self, time_machine: TimeMachineFixture) -> 
None:
@@ -1335,8 +1334,7 @@ class TestHITLOperations:
                     json={
                         "chosen_options": ["Approval"],
                         "params_input": {},
-                        "responded_user_id": "admin",
-                        "responded_user_name": "admin",
+                        "responded_by_user": {"id": "admin", "name": "admin"},
                         "response_received": True,
                         "response_at": "2025-07-03T00:00:00Z",
                     },
@@ -1349,6 +1347,5 @@ class TestHITLOperations:
         assert result.response_received is True
         assert result.chosen_options == ["Approval"]
         assert result.params_input == {}
-        assert result.responded_user_id == "admin"
-        assert result.responded_user_name == "admin"
+        assert result.responded_by_user == HITLUser(id="admin", name="admin")
         assert result.response_at == timezone.datetime(2025, 7, 3, 0, 0, 0)
diff --git a/task-sdk/tests/task_sdk/execution_time/test_hitl.py 
b/task-sdk/tests/task_sdk/execution_time/test_hitl.py
index a5ed016f44d..ad74ade5cd2 100644
--- a/task-sdk/tests/task_sdk/execution_time/test_hitl.py
+++ b/task-sdk/tests/task_sdk/execution_time/test_hitl.py
@@ -20,9 +20,10 @@ from __future__ import annotations
 from uuid6 import uuid7
 
 from airflow.sdk import timezone
-from airflow.sdk.api.datamodels._generated import HITLDetailResponse
+from airflow.sdk.api.datamodels._generated import HITLDetailResponse, HITLUser 
as APIHITLUser
 from airflow.sdk.execution_time.comms import CreateHITLDetailPayload
 from airflow.sdk.execution_time.hitl import (
+    HITLUser,
     get_hitl_detail_content_detail,
     update_hitl_detail_response,
     upsert_hitl_detail,
@@ -39,7 +40,7 @@ def test_upsert_hitl_detail(mock_supervisor_comms) -> None:
         body="Optional body",
         defaults=["Approve", "Reject"],
         params={"input_1": 1},
-        respondents=["test"],
+        assigned_users=[HITLUser(id="test", name="test")],
         multiple=False,
     )
     mock_supervisor_comms.send.assert_called_with(
@@ -50,7 +51,7 @@ def test_upsert_hitl_detail(mock_supervisor_comms) -> None:
             body="Optional body",
             defaults=["Approve", "Reject"],
             params={"input_1": 1},
-            respondents=["test"],
+            assigned_users=[APIHITLUser(id="test", name="test")],
             multiple=False,
         )
     )
@@ -62,8 +63,7 @@ def test_update_hitl_detail_response(mock_supervisor_comms) 
-> None:
         response_received=True,
         chosen_options=["Approve"],
         response_at=timestamp,
-        responded_user_id="admin",
-        responded_user_name="admin",
+        responded_by_user=APIHITLUser(id="admin", name="admin"),
         params_input={"input_1": 1},
     )
     resp = update_hitl_detail_response(
@@ -75,8 +75,7 @@ def test_update_hitl_detail_response(mock_supervisor_comms) 
-> None:
         response_received=True,
         chosen_options=["Approve"],
         response_at=timestamp,
-        responded_user_id="admin",
-        responded_user_name="admin",
+        responded_by_user=APIHITLUser(id="admin", name="admin"),
         params_input={"input_1": 1},
     )
 
@@ -86,8 +85,7 @@ def 
test_get_hitl_detail_content_detail(mock_supervisor_comms) -> None:
         response_received=False,
         chosen_options=None,
         response_at=None,
-        responded_user_id=None,
-        responded_user_name=None,
+        responded_by_user=None,
         params_input={},
     )
     resp = get_hitl_detail_content_detail(TI_ID)
@@ -95,7 +93,6 @@ def 
test_get_hitl_detail_content_detail(mock_supervisor_comms) -> None:
         response_received=False,
         chosen_options=None,
         response_at=None,
-        responded_user_id=None,
-        responded_user_name=None,
+        responded_by_user=None,
         params_input={},
     )
diff --git a/task-sdk/tests/task_sdk/execution_time/test_supervisor.py 
b/task-sdk/tests/task_sdk/execution_time/test_supervisor.py
index ce60753bf6a..ae39595197a 100644
--- a/task-sdk/tests/task_sdk/execution_time/test_supervisor.py
+++ b/task-sdk/tests/task_sdk/execution_time/test_supervisor.py
@@ -2008,7 +2008,7 @@ REQUEST_TEST_CASES = [
             "defaults": ["Approve"],
             "multiple": False,
             "params": {},
-            "respondents": None,
+            "assigned_users": None,
             "type": "HITLDetailRequestResult",
         },
         client_mock=ClientMock(
@@ -2019,7 +2019,7 @@ REQUEST_TEST_CASES = [
                 "multiple": False,
                 "options": ["Approve", "Reject"],
                 "params": {},
-                "respondents": None,
+                "assigned_users": None,
                 "subject": "This is subject",
                 "ti_id": TI_ID,
             },

Reply via email to