Follow-up from #7515 (raised by Evan Mattson (@moonbox3) in review: #7515 (comment)).
_auto_invoke_function converts every function-middleware exception into a tool error and keeps looping (_tools.py), so the only loud escape from the loop today is MiddlewareTermination. Middleware that needs fail-closed semantics (enforcement layers, guardrails) must mutate shared state, raise the loop's one loud exception, and re-raise the real failure two hops away at the run boundary.
Proposal (either shape):
- a
fatal flag on MiddlewareTermination that the loop re-raises instead of absorbing, or
- a dedicated
MiddlewareFailure exception the loop propagates.
Either would give every function-middleware author fail-closed semantics without the state-mutation dance, and would let the agent-hooks feature (#7515) delete its halted-state back-channel and the approval-request special case.
Deliberately not included in #7515 since it widens the _tools loop contract.
Follow-up from #7515 (raised by Evan Mattson (@moonbox3) in review: #7515 (comment)).
_auto_invoke_functionconverts every function-middleware exception into a tool error and keeps looping (_tools.py), so the only loud escape from the loop today isMiddlewareTermination. Middleware that needs fail-closed semantics (enforcement layers, guardrails) must mutate shared state, raise the loop's one loud exception, and re-raise the real failure two hops away at the run boundary.Proposal (either shape):
fatalflag onMiddlewareTerminationthat the loop re-raises instead of absorbing, orMiddlewareFailureexception the loop propagates.Either would give every function-middleware author fail-closed semantics without the state-mutation dance, and would let the agent-hooks feature (#7515) delete its
halted-state back-channel and the approval-request special case.Deliberately not included in #7515 since it widens the
_toolsloop contract.