kaxil opened a new pull request, #76785:
URL: https://github.com/apache/airflow/pull/76785
A function tool with `needs_approval` makes `Runner.run` return normally,
with `final_output` set to `None` and the pending call in
`result.interruptions`. In a `@task` that returns `run_durably_sync(agent,
prompt).final_output`, the task succeeded, pushed `None` to XCom, and the
durable journal was deleted as if the run had finished. Nothing in the task
answers the approval; the first sign of trouble was whatever read that XCom.
`run_durably` now raises `UnsupportedToolDeferralError` when the run comes
back with interruptions. The message names each tool and the agent that asked
for it (`lookup (specialist)`), so an approval raised inside an agent used
through `as_tool` doesn't look like it came from the starting agent. Outside a
task, `run_durably` is still `Runner.run` and returns the interruptions as
before.
## Design rationale
**It fails without retrying.** A retry replays the recorded model answer and
stops at the same call, so retries would only burn attempts.
`UnsupportedToolDeferralError` is the `AirflowFailException` that
`AgentOperator` already raises when it can't resolve an approval, including
under `durable=True`; reusing it keeps one exception for one condition across
the two durable paths and adds no public class. Its docstring now mentions
`run_durably`.
**The journal is kept, and the failure counts against the model's last
answer.** When the interrupted call belongs to an agent used through `as_tool`,
the outer tool call returns the inner run's `final_output` (`None`), which is
recorded as a completed tool step. Replaying it on a later attempt would hand
the model `None` as the agent tool's answer and let the run succeed.
`DurableRun.fail(error, model_at_fault=True)` makes a later attempt ask the
model again from its last answer, so nothing recorded after that answer
replays, while earlier turns still do. Deleting the whole run instead would
make a clear, after the user removes the approval requirement, pay for every
earlier model call and repeat every earlier tool call, and it would depend on a
best-effort delete.
**Behaviour change for code that handled approvals after `run_durably`.**
`run_durably` shipped in 1.0.0 returning interrupted runs. Code that called
`run_durably_sync`, then `result.to_state()` / `state.approve()` and resumed,
now gets the error instead. The message points at the way to keep doing that
(call `Runner.run` and handle `result.interruptions`). The next PR in this
stack connects `needs_approval` to Required Actions, so `run_durably` pauses
the task instead of failing it where Airflow 3.4 makes that possible.
## Evidence
- New tests fail on the base with `DID NOT RAISE
UnsupportedToolDeferralError` and pass with the change, on `openai-agents`
0.24.0 with `openai` 3.x and on 0.20.0 with `openai` 2.x.
- The clear test also fails when `model_at_fault=True` is dropped, and when
the run is deleted on interruption instead (earlier turns no longer replay).
- `airflow dags test` of a `@task` that runs a support agent whose
`issue_refund` tool has `needs_approval=True`, against a real model
(`gpt-5.4-mini` through an OpenAI-compatible gateway), `openai-agents` 0.20.0.
`issue_refund` did not run in either:
Before:
```
Done. Returned value was: None
Task instance in success state
```
After:
```
airflow.providers.common.ai.exceptions.UnsupportedToolDeferralError: The
agent stopped to ask for approval to call issue_refund (support), and
run_durably() cannot resume a run that waits for approval. Remove the approval
requirement (needs_approval, or require_approval on an MCP server), or call
Runner.run and handle result.interruptions yourself.
Task instance in failure state
```
## Known issues
- Strands' `invoke_durably` returns a run that stopped for an interrupt the
same way and deletes its saved state; that needs its own change.
--
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]