> For the complete documentation index, see [llms.txt](https://ai.ortusbooks.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ai.ortusbooks.com/main-components/agents/middleware.md).

# Middleware

Attaching middleware to an agent and the agent-specific lifecycle it participates in — full hook/result/built-in reference lives on the main Middleware page.

{% hint style="info" %}
**Since BoxLang AI v3.0+**. This page covers attaching middleware to an **agent** specifically. For the full hook list, the complete `AiMiddlewareResult` vocabulary, and one page per middleware class, see [Middleware Overview](/main-components/middleware.md).
{% endhint %}

## Adding Middleware to an Agent

Pass an array of middleware instances (or struct-based inline middleware) to `aiAgent()`:

```javascript
agent = aiAgent(
    name      : "SafeAgent",
    middleware: [
        new LoggingMiddleware(),
        new RetryMiddleware( maxRetries: 3 ),
        new GuardrailMiddleware( blockedTools: [ "deleteRecord" ] )
    ]
)
```

Or attach after construction with the fluent API:

```javascript
agent = aiAgent( name: "Assistant" )
    .withMiddleware( new LoggingMiddleware() )
    .withMiddleware( new RetryMiddleware() )
```

Middleware fires **in order** on inbound hooks (`beforeAgentRun`, `beforeLLMCall`, `beforeToolCall`) and in **reverse order** on outbound hooks (`afterToolCall`, `afterLLMCall`, `afterAgentRun`) — a stack, not a flat list. Fetch an attached instance back by name:

```javascript
recorder = agent.getMiddlewareByName( "Flight Recorder Middleware" )
```

## Agent-Scoped Hooks

Two hooks only make sense at the agent level — they bracket the entire `run()` call, not an individual LLM or tool call:

| Hook             | Fires When              | Context                                           |
| ---------------- | ----------------------- | ------------------------------------------------- |
| `beforeAgentRun` | Agent `run()` begins    | `agent`, `input`, `messages`, `params`, `options` |
| `afterAgentRun`  | Agent `run()` completes | + `response`                                      |

```javascript
class UsageTrackerMiddleware extends="bxModules.bxai.models.middleware.BaseAiMiddleware" {

    property name="name" default="UsageTracker";

    AiMiddlewareResult function beforeAgentRun( required struct context ) {
        variables.startedAt = getTickCount()
        return AiMiddlewareResult.continue()
    }

    AiMiddlewareResult function afterAgentRun( required struct context ) {
        recordDuration( context.agent.getName(), getTickCount() - variables.startedAt )
        return AiMiddlewareResult.continue()
    }
}
```

Every other hook (`beforeLLMCall`/`afterLLMCall`, `beforeToolCall`/`afterToolCall`, `afterToolBatch`, the wrap-style hooks, `onError`) behaves identically whether attached to an agent or a bare model — see [Middleware Overview](/main-components/middleware.md#hook-reference) for all of them.

## Suspending an Agent for Human Approval

`HumanInTheLoopMiddleware` is the middleware you'll attach to agents most often — it suspends `agent.run()` mid-turn until a human approves, rejects, or edits a pending tool call, and resumes via `agent.resume()`/`resumeStream()`.

```javascript
import bxModules.bxai.models.middleware.core.HumanInTheLoopMiddleware;

agent = aiAgent(
    tools       : [ deployTool ],
    checkpointer: aiMemory( "cache" ),
    middleware  : [ new HumanInTheLoopMiddleware(
        mode                  : "web",
        toolsRequiringApproval: [ "deploy" ]
    ) ]
)

threadId = "deploy-42"
result   = agent.run( "Deploy the new version to production", {}, { threadId: threadId } )

if ( result.isSuspended() ) {
    pending = result.getData().pendingActions
    // ... notify a human, persist threadId ...
    finalResponse = agent.resume( "approve", threadId )
}
```

This is a thin slice of a larger topic — approval policies, durable `approve_always`/`approve_session` grants, batched approvals, and presenting through a gateway all live on their own pages:

* [Human-in-the-Loop](/main-components/human-in-the-loop.md) — the full picture
* [Agent Memory Management](/main-components/agents/memory.md) — the `checkpointer` and suspend/resume mechanics
* [Gateways](/main-components/gateways.md) — presenting approvals over CLI, HTTP, or a platform module

## Related Pages

* [Middleware Overview](/main-components/middleware.md) — full hook reference and middleware index
* [HumanInTheLoopMiddleware](/main-components/middleware/human-in-the-loop.md) — dedicated middleware reference
* [RetryMiddleware](/main-components/middleware/retry.md) — retry/backoff configuration
* [GuardrailMiddleware](/main-components/middleware/guardrail.md) — tool-level blocking and argument patterns
* [OutputGuardMiddleware](/main-components/middleware/output-guard.md) — output redaction and exfiltration stripping
* [Human-in-the-Loop](/main-components/human-in-the-loop.md) — approval policies, durable grants, batching
* [Memory Management](/main-components/agents/memory.md) — checkpointers and suspend/resume
* [Advanced Patterns](/main-components/agents/advanced.md) — event interception alternatives


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://ai.ortusbooks.com/main-components/agents/middleware.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
