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]
