AgentMiddleware

org.llm4s.agent.graph.middleware.AgentMiddleware

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.

Attributes

Graph
Supertypes
class Object
trait Matchable
class Any
Known subtypes

Members list

Value members

Abstract methods

This middleware's identifier, unique in its stack; must match [a-zA-Z0-9_-]{1,64}.

This middleware's identifier, unique in its stack; must match [a-zA-Z0-9_-]{1,64}.

Attributes

Concrete methods

def afterAgent(answer: String, context: RunContext): Result[String]

Sees the run's final answer: returns it, possibly changed, or Left to fail the run.

Sees the run's final answer: returns it, possibly changed, or Left to fail the run.

Attributes

def beforeAgent(input: String, context: RunContext): Result[String]

Sees the run's input before anything else runs: returns it, possibly changed, or Left to fail the run.

Sees the run's input before anything else runs: returns it, possibly changed, or Left to fail the run.

Attributes

Middleware this one must run inside of (be wrapped by); each must be registered in the same stack.

Middleware this one must run inside of (be wrapped by); each must be registered in the same stack.

Attributes

Middleware this one must run outside of (wrap); each must be registered in the same stack.

Middleware this one must run outside of (wrap); each must be registered in the same stack.

Attributes

def tools: Vector[AgentTool[_]]

Tools this middleware contributes; they join the loop's tool set and are validated like any other.

Tools this middleware contributes; they join the loop's tool set and are validated like any other.

Attributes

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.

Attributes

def wrapToolCall(request: ToolCallRequest, context: ToolContext)(next: () => ToolOutcome): ToolOutcome

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.

Attributes

def writes: Set[StateKey[_, _]]

The state keys this middleware's wrapToolCall may add to a Success update.

The state keys this middleware's wrapToolCall may add to a Success update.

Attributes