LangChain/Memory & Middleware
Advanced12 min

Custom Middleware

Build custom middleware with node-style hooks (before/after) for state updates and wrap-style hooks (wrap_model_call, wrap_tool_call) for retry, caching, and request mutation. Use request.override() to change the model or tools per call.

Quick Reference

  • @before_model(can_jump_to=['end']) — early exit hook with jump support
  • return {'jump_to': 'end'} — exit the agent loop from any hook
  • request.override(model=model, tools=tools) — mutate model call in wrap_model_call
  • ExtendedModelResponse(response, Command(update={...})) — write state from wrap_model_call
  • abefore_model / aafter_model — async versions of all node hooks

Two Hook Styles

Middleware has two fundamentally different hook styles. Node-style hooks run at discrete points (before/after) and return state diffs. Wrap-style hooks surround the actual call and give you control over whether and how many times the underlying operation runs.

HookStyleWhen it runs
@before_agentnodeOnce before the agent loop starts
@before_modelnodeBefore each model call
@after_modelnodeAfter each model response
@after_agentnodeOnce after the agent loop ends
@wrap_model_callwrapAround each model call — you call handler()
@wrap_tool_callwrapAround each tool call — you call handler()
Node-style vs wrap-style side by side