A cross-cutting concern - approval, guardrails, logging, retry, rate limits - around an agent run, its model calls and its tool calls. Every hook passes through by default; override only those the concern needs.
Middleware run as a MiddlewareStack, ordered by registration and by runsBefore and runsAfter: the first in stack order is the outermost wrapper and runs beforeAgent first; unwinding, and afterAgent, run in reverse. A hook that throws fails the run with GraphError.MiddlewareFailed; a thrown cancellation cancels it.
wrapToolCall runs concurrently for the calls of one batch (up to RunBudgets.maxConcurrency), on task threads, so a middleware's own state must be thread-safe.
A wrapper should pass ToolOutcome.Fatal(CancelledError) through and not retry it: the call was cancelled, and a retry gets the same outcome without running the tool again.
Wraps one model call. A wrapper may rewrite the request (inject a note, filter tools), call next more than once (retry, fallback), transform its result, or return Left, which fails the run. A model wrapper cannot suspend.
Wraps one model call. A wrapper may rewrite the request (inject a note, filter tools), call next more than once (retry, fallback), transform its result, or return Left, which fails the run. A model wrapper cannot suspend.
Filtering ModelRequest.tools shapes what the model is offered and is not a permission control: a tool the model calls anyway still runs through wrapToolCall, where denial belongs.
Wraps one tool call, after its arguments were validated. A wrapper denies with ToolOutcome.Error("Denied: ..."), asks for approval with NeedsApproval(reason) (unless context.approved), fails the run with Fatal, and short-circuits by not calling next. It may call next more than once (retry) and transform the outcome next returns.
Wraps one tool call, after its arguments were validated. A wrapper denies with ToolOutcome.Error("Denied: ..."), asks for approval with NeedsApproval(reason) (unless context.approved), fails the run with Fatal, and short-circuits by not calling next. It may call next more than once (retry) and transform the outcome next returns.