Maniac Docs
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;
}
LayerWhen it runs
LM middlewareBefore/after each Model.infer / stream call
Tool middlewareBefore/after each tool handler
GuardrailsInput/output checks on LM requests and tool calls
Step hooksStart/end of each runner iteration
stop_whenBudget 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 & guardrailsLMMiddleware, ToolMiddleware, allow / block / rewrite / requireApproval
  • Step hooksStepHook lifecycle, prepare_step, shipped stop_when predicates

API reference

Generated TypeDoc: middleware module.

On this page