IMiddleware and register it with decorator.middleware().
Defining middleware
The only required member isgetName; every hook is optional. Implement just the hooks you need:
IMiddleware<TContext> types the runtime context read via ctx.context.
Add it to an agent’s getMiddlewares, or pass it per request:
Lifecycle hooks
Hooks fire across the run’s lifecycle. All are optional.
The three terminal hooks (
onFinish, onAbort, onError) are mutually exclusive: exactly one fires per run.
Composition
Middleware composes in the order it appears in the array: the agent’s own middleware first, then any passed per request. How the hooks combine depends on their role. The piped hooks (onConfig, onStructuredOutputConfig, onChunk) each receive the previous middleware’s output, so transformations chain. onBeforeToolCall is first-win, stopping at the first middleware that returns a decision. Everything else runs sequentially, one after another.
Transforming the request
Config hooks return a partial config that is shallow-merged into the run. UseonConfig to adjust the whole run, or reach for onBeforeModel when you need a per-iteration tweak like raising the temperature on a retry:
void (or nothing) to pass the config through unchanged.
Filtering chunks
onChunk sees every streamed chunk and decides its fate. Return a chunk to replace it, an array to expand it, null to drop it, or void to pass it through:
Use
ctx.defer(promise) inside a hook to run side effects (logging, audit writes) without blocking the run — they are awaited as part of the run’s completion.