kaxil opened a new pull request, #74686:
URL: https://github.com/apache/airflow/pull/74686

   Stacked on #74679.
   
   Today an `AgentOperator` task can pause for tool approval only once per Dag 
run; a second request fails the task with `ToolApprovalAlreadyRequestedError`. 
An agent decides its next call after it sees the last result, so a refund agent 
that approves order 1, reads the result and then asks to refund order 2 fails 
on the second ask.
   
   The limit came from core: on Airflow 3.3, a repeat approval request for the 
same task instance keeps the first request's subject and body, so the reviewer 
would approve a new call while reading the old one. #73235 (in 3.4) makes a 
repeat request replace those details and clear the earlier answer. On Airflow 
3.4 and later, this PR lets the run pause at every step that calls a marked 
tool. On 3.3 the rule stays, with an error message that names the upgrade.
   
   Run end to end on Airflow main with a scripted agent that refunds three 
orders, one per step: the task paused three times in one try, each Required 
Actions request showed only its own order, each refund ran once, and the task 
returned all three results.
   
   ## Design rationale
   
   **A stale answer can still reach a later request, so each request is 
numbered.** Core accepts an answer without knowing which request it was for. If 
one reviewer approves request 1 and the agent pauses for request 2, a second 
reviewer who still has request 1's form open could approve refund 2 while 
reading refund 1. Each request now carries its number in its subject and in a 
hidden `const` form field, which the review form sends back with the answer. An 
answer naming an earlier request is not applied: the task asks about the 
waiting calls again under a new number. A REST API answer without the field is 
applied to the waiting request, so existing integrations keep working. In the 
end-to-end run, a deliberately stale answer for request 1 while request 2 was 
waiting produced request 3 for the same order, and nothing ran twice. A core 
change that ties every answer to its request revision is the proper fix for all 
HITL operators; this guard can go once that ships.
   
   **Why gate on Airflow 3.4 rather than detect the core behaviour?** The 
behaviour is a property of the core version, `AIRFLOW_V_3_4_PLUS` is already in 
the `common.compat` floor, and #73235 was not backported to a 3.3 release.
   
   **Each resumed run gets its own `run_id`, `<ti id>-resumed-<n>`.** 
pydantic-ai refuses a `run_id` that already appears in the history, so a second 
resume with the old fixed `<ti id>-resumed` failed.
   
   ## Gotchas
   
   - A retry or a clear asks again for the calls the new attempt makes, 
including ones approved in an earlier attempt that then failed. The approved 
call has already run once, as before.
   - `usage_limits` counts across every pause, so a run with many gated steps 
can reach `request_limit` (50 by default) partway through.
   - The `run_id` XCom of a resumed run changes from `<ti id>-resumed` to `<ti 
id>-resumed-<n>`.
   
   Per-tool approval moves to the stable table in `stability.rst`, since the 
once-per-run limit was the reason #74679 keeps it experimental.
   


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

To unsubscribe, e-mail: [email protected]

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

Reply via email to