Middleware
Middleware
LM and tool middleware hooks, guardrail decisions, step hooks, and stop_when predicates for the agent runner loop.
Middleware and hooks let you intercept, rewrite, block, or pause agent behavior without changing core runner logic. Configure them on each Agent spec.
Agent spec fields
interface Agent {
lm_middleware?: LMMiddleware[];
tool_middleware?: ToolMiddleware[];
lm_guardrails?: LMGuardrail[];
tool_guardrails?: ToolGuardrail[];
step_hooks?: StepHook[];
prepare_step?: PrepareStep | null;
stop_when?: StopWhen | null;
}| Layer | When it runs |
|---|---|
| LM middleware | Before/after each Model.infer / stream call |
| Tool middleware | Before/after each tool handler |
| Guardrails | Input/output checks on LM requests and tool calls |
| Step hooks | Start/end of each runner iteration |
stop_when | Budget predicate checked after each step |
Evaluation order (tool path)
flowchart LR
MW1["tool_middleware.beforeInvoke"] --> GR1["tool_guardrails.checkCall"]
GR1 --> POL["policy.evaluate"]
POL --> INV["tool handler"]
INV --> GR2["tool_guardrails.checkResult"]
GR2 --> MW2["tool_middleware.afterInvoke"]Guardrail require_approval and policy requires_approval both route to the same HITL pause path.
Quick example
import {
runAgent,
BaseToolGuardrail,
block,
stepCountIs
} from "@maniac-ai/agents";
class BlockDestructive extends BaseToolGuardrail {
async checkCall(_ctx, call) {
if (call.tool === "delete_account") {
return block("destructive action blocked");
}
return { action: "allow" };
}
}
const result = await runAgent({
id: "support",
instructions: "Help users safely.",
model,
tool_guardrails: [new BlockDestructive()],
stop_when: stepCountIs(10)
}, "Reset my password");Topics
- Middleware & guardrails —
LMMiddleware,ToolMiddleware,allow/block/rewrite/requireApproval - Step hooks —
StepHooklifecycle,prepare_step, shippedstop_whenpredicates
API reference
Generated TypeDoc: middleware module.