new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

LangChain · Agents · all subjects

agents/middleware

224 notes in this subject, read out of this brain and free to use. This is page 3 of 4.

Dynamic model selection middleware capability

Middleware can dynamically select which model to use at runtime using wrap_model_call. Middleware can inspect state and runtime to determine which model should be used, then call handler with request.override(model=selected_model). This allows different models for different requests or conditions without recreating the agent.

Tool selection middleware for dynamic tool filtering

Middleware can select relevant tools at runtime using wrap_model_call. All available tools must be registered upfront with the agent. Middleware filters the tools by calling handler(request.override(tools=relevant_tools)). Benefits include shorter prompts (reduce complexity by exposing only relevant tools), better accuracy (models choose correctly from fewer options), and permission control (dynamically filter tools based on user access).

Tool call monitoring middleware capability

Middleware can monitor tool calls using wrap_tool_call hook. This allows tracking which tools are called, when they are called, their inputs and outputs, and success/failure status. Tool call monitoring middleware can be implemented as decorator-based or class-based middleware.

Anthropic prompt caching with middleware

When working with Anthropic models, use structured content blocks with cache control directives in middleware. Always work with content_blocks from system_message. Append new blocks with 'type': 'text' and 'cache_control': {'type': 'ephemeral'} to mark content for caching. Create new SystemMessage with modified content and pass to handler via request.override(system_message=new_system_message).

Middleware best practices

Best practices for middleware: Keep middleware focused - each should do one thing well. Handle errors gracefully - don't let middleware errors crash the agent. Use appropriate hook types - node-style for sequential logic (logging, validation), wrap-style for control flow (retry, fallback, caching). Clearly document any custom state properties. Unit test middleware independently before integrating. Consider execution order - place critical middleware first in the list. Use built-in middleware when possible.

Retry middleware example in Python

Example shows wrap_model_call decorator that retries model calls up to 3 times on exception. Pattern is: loop for attempt in range(max_retries), try handler(request), on exception check if last attempt (raise), otherwise print retry message and continue. This demonstrates control flow use case for wrap-style hooks.

Message limit middleware with jump_to example in Python

Example shows before_model decorator with can_jump_to=['end'] that checks if messages length >= max_messages and returns {'messages': [AIMessage(...)], 'jump_to': 'end'} to exit agent early. Also shows after_model decorator that logs the model response. Demonstrates node-style hooks and state checking.

JavaScript SystemMessage.concat method

In JavaScript, use SystemMessage.concat() method to modify system messages while preserving cache control metadata or structured content blocks created by other middleware. This is important when chaining multiple middleware that each modify the system message.

Core agent loop structure

The core agent loop involves calling a model, letting it choose tools to execute, and then finishing when it calls no more tools. Middleware exposes hooks before and after each of those steps.

Middleware in LangGraph workflow

Middleware is not a separate runtime; hooks run inside the compiled LangGraph that create_agent returns. The whole agent (middleware and all) can be dropped into a larger StateGraph as a node or subgraph, and every middleware hook continues to run. This pattern is useful when the surrounding topology is more than a standard loop until done: classifying input before routing to one of several agents, fanning out work in parallel, or stitching agent calls together with deterministic steps.

Middleware purpose and use cases

Middleware provides a way to tightly control what happens inside the agent. Middleware is useful for: tracking agent behavior with logging, analytics, and debugging; transforming prompts, tool selection, and output formatting; adding retries, fallbacks, and early termination logic; applying rate limits, guardrails, and PII detection.

HumanInTheLoopMiddleware interrupt_on parameter

HumanInTheLoopMiddleware matches against each tool's .name property. In Python, @tool-decorated functions take their name from the function name. The interrupt_on parameter is a dictionary mapping tool names to boolean values indicating whether to interrupt before executing that tool. Example: HumanInTheLoopMiddleware(interrupt_on={"send_email": True}). In TypeScript, the key matches the name you pass to tool({...}, { name }), and the parameter is humanInTheLoopMiddleware({ interruptOn: { send_email: true } }).

Middleware persistence in LangGraph subgraphs

The HITL interrupt, summarization, PII redaction, retries, and any custom hooks all travel with the agent node when used as a subgraph. Subgraph checkpointer scoping patterns support both per-invocation and per-thread scopes.

Add middleware to agent using create_agent

Middleware is added by passing a list to the middleware parameter of create_agent. In Python: from langchain.agents import create_agent; agent = create_agent(model="gpt-5.5", tools=[...], middleware=[SummarizationMiddleware(...), HumanInTheLoopMiddleware(...)]). In TypeScript: const agent = createAgent({model: "gpt-5.5", tools: [...], middleware: [summarizationMiddleware, humanInTheLoopMiddleware]}).

Tool call limit middleware configuration

ToolCallLimitMiddleware parameters: tool_name (optional string, if not provided limits apply to all tools globally), thread_limit (maximum tool calls across all runs in a thread, persists across invocations with same thread ID, requires checkpointer, None means no limit), run_limit (maximum tool calls per single invocation, resets each user message, None means no limit; at least one of thread_limit or run_limit must be specified), exit_behavior (default 'continue': 'continue' blocks exceeded calls with error messages allowing model to continue, 'error' raises ToolCallLimitExceededError stopping immediately, 'end' stops with ToolMessage+AIMessage for single-tool scenarios only). Can specify multiple ToolCallLimitMiddleware instances for global and tool-specific limits.

Model fallback middleware configuration

ModelFallbackMiddleware accepts variable number of fallback model arguments: first_model (required, string or BaseChatModel), additional optional models to try in order if previous models fail. Can be model identifier strings (e.g., 'openai:gpt-5.4-mini') or BaseChatModel instances. Automatically fallbacks to alternative models when primary model fails, enabling resilience against outages, cost optimization, and provider redundancy.

PII detection middleware configuration

PIIMiddleware parameters: pii_type (required, built-in types include email, credit_card, ip, mac_address, url or custom type name), strategy (default 'redact': 'block' raises exception, 'redact' replaces with [REDACTED_{TYPE}], 'mask' partially masks (e.g., ****-****-****-1234), 'hash' replaces with deterministic hash), detector (optional function or regex for custom detection), apply_to_input (default True, check user messages before model call), apply_to_output (default False, check AI messages after model call; langchain>=1.3.2 also redacts streamed wire output via stream transformer), apply_to_tool_results (default False, check tool result messages).

PII detection custom detectors

Three ways to create custom PII detectors: (1) Regex pattern string for simple pattern matching; (2) Compiled regex pattern for more control over flags; (3) Custom function accepting string content and returning list of dicts with 'text', 'start', and 'end' keys. Custom function signature: def detector(content: str) -> list[dict[str, str | int]]. Regex strings and patterns work for simple detection; custom functions enable complex validation logic.

To-do list middleware configuration

TodoListMiddleware automatically provides agents with a write_todos tool and system prompts to guide task planning. Parameters: system_prompt (optional custom prompt, uses built-in if not specified), tool_description (optional custom description for write_todos tool, uses built-in if not specified). Equips agents with task planning and tracking for complex multi-step tasks and long-running operations.

LLM tool selector middleware configuration

LLMToolSelectorMiddleware uses structured output to intelligently select relevant tools before calling main model. Parameters: model (optional string or BaseChatModel, defaults to agent's main model), system_prompt (optional custom instructions, uses built-in if not specified), max_tools (optional maximum number of tools to select; only first max_tools used if model selects more), always_include (optional list of tool names to always include regardless of selection, do not count against max_tools limit). Useful for agents with many tools (10+) where most aren't relevant, reduces token usage by filtering irrelevant tools.

Tool error middleware configuration

ToolErrorMiddleware (requires langchain>=1.3.14) catches tool execution exceptions and converts them to error ToolMessages. Parameters: on_error (Callable taking Exception and ToolCallRequest, returns str/list[ContentBlock]/None; return content to convert exception to ToolMessage(status='error'), return None to propagate exception), aon_error (optional async handler, falls back to on_error if not provided), tools (optional list of tool names or BaseTool instances to apply error handling to; None applies to all tools). Prevents exceptions from crashing agent; compose with Tool retry middleware (inner) to enable retries before error handling.

Tool retry middleware configuration

ToolRetryMiddleware parameters: max_retries (default 2, total 3 attempts including initial), tools (optional list of tool names or BaseTool instances; None applies to all), retry_on (default (Exception,), tuple of exception types or callable taking exception returning bool), on_failure (default 'continue': 'continue' returns ToolMessage with error, 'error' re-raises, callable returns custom error message), backoff_factor (default 2.0, multiplier for exponential backoff, 0.0 for constant), initial_delay (default 1.0 seconds), max_delay (default 60.0 seconds, caps exponential growth), jitter (default True, ±25% random variation to avoid thundering herd). Delay formula: initial_delay * (backoff_factor ** retry_number).

Summarization example with single condition

Example of SummarizationMiddleware triggering on single token threshold: from langchain.agents import create_agent from langchain.agents.middleware import SummarizationMiddleware agent = create_agent( model="gpt-5.5", tools=[your_weather_tool, your_calculator_tool], middleware=[ SummarizationMiddleware( model="gpt-5.4-mini", trigger=("tokens", 4000), keep=("messages", 20), ), ], )

Summarization example with OR logic

Example of SummarizationMiddleware with multiple trigger conditions (OR logic): from langchain.agents import create_agent from langchain.agents.middleware import SummarizationMiddleware agent = create_agent( model="gpt-5.5", tools=[your_weather_tool, your_calculator_tool], middleware=[ SummarizationMiddleware( model="gpt-5.4-mini", trigger=[ ("tokens", 3000), ("messages", 6), ], keep=("messages", 20), ), ], )

Summarization example with combined AND/OR logic

Example of SummarizationMiddleware combining AND and OR logic: from langchain.agents import create_agent from langchain.agents.middleware import SummarizationMiddleware agent = create_agent( model="gpt-5.5", tools=[your_weather_tool, your_calculator_tool], middleware=[ SummarizationMiddleware( model="gpt-5.4-mini", trigger=[ {"tokens": 5000, "messages": 3}, {"tokens": 3000, "messages": 6}, ], keep=("messages", 20), ), ], )

Summarization example with fractional limits

Example of SummarizationMiddleware using fractional model context limits: from langchain.agents import create_agent from langchain.agents.middleware import SummarizationMiddleware agent = create_agent( model="gpt-5.5", tools=[your_weather_tool, your_calculator_tool], middleware=[ SummarizationMiddleware( model="gpt-5.4-mini", trigger=("fraction", 0.8), keep=("fraction", 0.3), ), ], )

Human-in-the-loop middleware example

Example of HumanInTheLoopMiddleware with selective interruption: from langchain.agents import create_agent from langchain.agents.middleware import HumanInTheLoopMiddleware from langgraph.checkpoint.memory import InMemorySaver def your_read_email_tool(email_id: str) -> str: return f"Email content for ID: {email_id}" def your_send_email_tool(recipient: str, subject: str, body: str) -> str: return f"Email sent to {recipient} with subject '{subject}'" agent = create_agent( model="gpt-5.5", tools=[your_read_email_tool, your_send_email_tool], checkpointer=InMemorySaver(), middleware=[ HumanInTheLoopMiddleware( interrupt_on={ "your_send_email_tool": { "allowed_decisions": ["approve", "edit", "reject"], }, "your_read_email_tool": False, } ), ], )

Tool call limit middleware example with multiple limits

Example of ToolCallLimitMiddleware with global and tool-specific limits: from langchain.agents import create_agent from langchain.agents.middleware import ToolCallLimitMiddleware global_limiter = ToolCallLimitMiddleware(thread_limit=20, run_limit=10) search_limiter = ToolCallLimitMiddleware(tool_name="search", thread_limit=5, run_limit=3) database_limiter = ToolCallLimitMiddleware(tool_name="query_database", thread_limit=10) strict_limiter = ToolCallLimitMiddleware(tool_name="scrape_webpage", run_limit=2, exit_behavior="error") agent = create_agent( model="gpt-5.5", tools=[search_tool, database_tool, scraper_tool], middleware=[global_limiter, search_limiter, database_limiter, strict_limiter], )

Model fallback middleware example

Example of ModelFallbackMiddleware with multiple fallback models: from langchain.agents import create_agent from langchain.agents.middleware import ModelFallbackMiddleware agent = create_agent( model="gpt-5.5", tools=[], middleware=[ ModelFallbackMiddleware( "gpt-5.4-mini", "claude-3-5-sonnet-20241022", ), ], )

PII detection middleware example

Example of PIIMiddleware detecting email and credit card information: from langchain.agents import create_agent from langchain.agents.middleware import PIIMiddleware agent = create_agent( model="gpt-5.5", tools=[], middleware=[ PIIMiddleware("email", strategy="redact", apply_to_input=True), PIIMiddleware("credit_card", strategy="mask", apply_to_input=True), ], )

PII detection custom detector regex string example

Example of PIIMiddleware with custom regex detector for API keys: from langchain.agents import create_agent from langchain.agents.middleware import PIIMiddleware agent = create_agent( model="gpt-5.5", tools=[], middleware=[ PIIMiddleware( "api_key", detector=r"sk-[a-zA-Z0-9]{32}", strategy="block", ), ], )

PII detection custom detector regex compiled example

Example of PIIMiddleware with compiled regex for phone number detection: from langchain.agents import create_agent from langchain.agents.middleware import PIIMiddleware import re agent = create_agent( model="gpt-5.5", tools=[], middleware=[ PIIMiddleware( "phone_number", detector=re.compile(r"\+?\d{1,3}[\s.-]?\d{3,4}[\s.-]?\d{4}"), strategy="mask", ), ], )

PII detection custom detector function example

Example of PIIMiddleware with custom detector function for SSN validation: from langchain.agents import create_agent from langchain.agents.middleware import PIIMiddleware import re def detect_ssn(content: str) -> list[dict[str, str | int]]: """Detect SSN with validation. Returns a list of dictionaries with 'text', 'start', and 'end' keys. """ matches = [] pattern = r"\d{3}-\d{2}-\d{4}" for match in re.finditer(pattern, content): ssn = match.group(0) first_three = int(ssn[:3]) if first_three not in [0, 666] and not (900 <= first_three <= 999): matches.append({ "text": ssn, "start": match.start(), "end": match.end(), }) return matches agent = create_agent( model="gpt-5.5", tools=[], middleware=[ PIIMiddleware( "ssn", detector=detect_ssn, strategy="hash", ), ], )

To-do list middleware example

Example of TodoListMiddleware: from langchain.agents import create_agent from langchain.agents.middleware import TodoListMiddleware agent = create_agent( model="gpt-5.5", tools=[read_file, write_file, run_tests], middleware=[TodoListMiddleware()], )

LLM tool selector middleware example

Example of LLMToolSelectorMiddleware: from langchain.agents import create_agent from langchain.agents.middleware import LLMToolSelectorMiddleware agent = create_agent( model="gpt-5.5", tools=[tool1, tool2, tool3, tool4, tool5], middleware=[ LLMToolSelectorMiddleware( model="gpt-5.4-mini", max_tools=3, always_include=["search"], ), ], )

Tool error middleware example

Example of ToolErrorMiddleware with error handler: from langchain.agents import create_agent from langchain.agents.middleware import ToolErrorMiddleware def on_error(exc: Exception, request: ToolCallRequest) -> str | None: if isinstance(exc, ValueError): return f"`{request.tool_call['name']}` failed with {type(exc).__name__}." return None agent = create_agent( model="gpt-5.5", tools=[your_tools], middleware=[ToolErrorMiddleware(on_error)], )

Tool error middleware with retry example

Example of ToolErrorMiddleware composed with ToolRetryMiddleware: from langchain.agents import create_agent from langchain.agents.middleware import ToolErrorMiddleware, ToolRetryMiddleware def on_error(exc: Exception, request: ToolCallRequest) -> str | None: if isinstance(exc, ValueError): return f"`{request.tool_call['name']}` failed: {type(exc).__name__}. Fix the input and retry." return None async def aon_error(exc: Exception, request: ToolCallRequest) -> str | None: if isinstance(exc, ConnectionError): return f"Tool `{request.tool_call['name']}` encountered a connection error." return None agent = create_agent( model="gpt-5.5", tools=[search_tool, database_tool], middleware=[ ToolRetryMiddleware(max_retries=3, on_failure="error"), ToolErrorMiddleware(on_error=on_error, tools=["search_tool"]), ], ) async_agent = create_agent( model="gpt-5.5", tools=[api_tool], middleware=[ToolErrorMiddleware(aon_error=aon_error)], )

Tool retry middleware example

Example of ToolRetryMiddleware with exponential backoff: from langchain.agents import create_agent from langchain.agents.middleware import ToolRetryMiddleware agent = create_agent( model="gpt-5.5", tools=[search_tool, database_tool], middleware=[ ToolRetryMiddleware( max_retries=3, backoff_factor=2.0, initial_delay=1.0, ), ], )

Tool retry middleware full example

Example of ToolRetryMiddleware with selective retry and custom error handling: from langchain.agents import create_agent from langchain.agents.middleware import ToolRetryMiddleware agent = create_agent( model="gpt-5.5", tools=[search_tool, database_tool, api_tool], middleware=[ ToolRetryMiddleware( max_retries=3, backoff_factor=2.0, initial_delay=1.0, max_delay=60.0, jitter=True, tools=["api_tool"], retry_on=(ConnectionError, TimeoutError), on_failure="continue", ), ], )

Model retry middleware example

Example of ModelRetryMiddleware: from langchain.agents import create_agent from langchain.agents.middleware import ModelRetryMiddleware agent = create_agent( model="gpt-5.5", tools=[search_tool, database_tool], middleware=[ ModelRetryMiddleware( max_retries=3, backoff_factor=2.0, initial_delay=1.0, ), ], )

Deprecated SummarizationMiddleware parameters

Deprecated parameters in SummarizationMiddleware: summary_prefix (string, deprecated - use summary_prompt to provide full prompt instead), max_tokens_before_summary (number, deprecated - use trigger: ('tokens', value) instead), messages_to_keep (number, deprecated - use keep: ('messages', value) instead).

Model profiles for fraction-based conditions

Fraction conditions (fraction parameter in trigger and keep) for SummarizationMiddleware rely on chat model profile data if using langchain>=1.1. If profile data not available, use another condition type or specify model profile manually using init_chat_model with custom_profile dict containing max_input_tokens and other config.

LLMToolEmulator middleware purpose

LLMToolEmulator emulates tool execution using an LLM for testing purposes, replacing actual tool calls with AI-generated responses. It is useful for testing agent behavior without executing real tools, developing agents when external tools are unavailable or expensive, and prototyping agent workflows before implementing actual tools.

LLMToolEmulator configuration parameters

LLMToolEmulator accepts: tools parameter (list[str | BaseTool]) specifying which tools to emulate by name or instance. If None (default), all tools are emulated. If empty list [], no tools are emulated. If array with tool names/instances, only those tools are emulated. model parameter (string | BaseChatModel) specifies the model for generating emulated responses, can be model identifier string or BaseChatModel instance, defaults to agent's model if not specified.

LLMToolEmulator example - emulate all tools

from langchain.agents import create_agent from langchain.agents.middleware import LLMToolEmulator agent = create_agent( model="gpt-5.5", tools=[get_weather, send_email], middleware=[LLMToolEmulator()], ) This shows default behavior where all tools are emulated.

LLMToolEmulator example - selective emulation

from langchain.agents import create_agent from langchain.agents.middleware import LLMToolEmulator agent2 = create_agent( model="gpt-5.5", tools=[get_weather, send_email], middleware=[LLMToolEmulator(tools=["get_weather"])], ) agent4 = create_agent( model="gpt-5.5", tools=[get_weather, send_email], middleware=[LLMToolEmulator(model="claude-sonnet-4-6")], ) First example emulates only get_weather tool. Second example uses custom model for emulation.

ProviderToolSearchMiddleware purpose

ProviderToolSearchMiddleware defers selected tools behind model providers' server-side tool search, allowing the model to discover tools on demand instead of receiving every tool schema up front. This reduces context bloat when using many tools and improves tool selection accuracy by surfacing only relevant tools. Requires a model with server-side tool search support: Anthropic (Claude Sonnet 4+/Opus 4+/Haiku 4.5+) or OpenAI (gpt-5.5+).

ProviderToolSearchMiddleware configuration

ProviderToolSearchMiddleware accepts searchable_tools parameter (list[str | BaseTool]) specifying tools to defer behind provider's tool search, given by name or instance. Deferred tools are withheld from the model until its search surfaces them. Tools constructed with extras={"defer_loading": True} are deferred regardless of this option; if searchable_tools is omitted, only those pre-marked tools are deferred.

ProviderToolSearchMiddleware example - defer_loading at tool construction

from langchain.agents import create_agent from langchain.agents.middleware import ProviderToolSearchMiddleware from langchain.tools import tool @tool(extras={"defer_loading": True}) def send_email(to: str) -> str: """Send an email.""" return "sent" agent = create_agent( model="anthropic:claude-opus-4-8", tools=[send_email], middleware=[ProviderToolSearchMiddleware()], ) Marking defer_loading at construction defers the tool automatically without listing in searchable_tools.

FilesystemFileSearchMiddleware purpose

FilesystemFileSearchMiddleware provides Glob and Grep search tools over a filesystem. It is useful for code exploration and analysis, finding files by name patterns, searching code content with regex, and large codebases where file discovery is needed.

FilesystemFileSearchMiddleware configuration parameters

FilesystemFileSearchMiddleware accepts: root_path (str, required) root directory to search with all file operations relative to this path; use_ripgrep (bool, default True) whether to use ripgrep for search, falls back to Python regex if unavailable; max_file_size_mb (int, default 10) maximum file size to search in MB, files larger than this are skipped.

FilesystemFileSearchMiddleware tools - glob and grep

FilesystemFileSearchMiddleware adds two search tools to agents: Glob tool for fast file pattern matching supporting patterns like **/*.py and src/**/*.ts, returning matching file paths sorted by modification time. Grep tool for content search with regex supporting full regex syntax, filtering by file patterns with include parameter, and three output modes: files_with_matches, content, count.

FilesystemFileSearchMiddleware example

from langchain.agents import create_agent from langchain.agents.middleware import FilesystemFileSearchMiddleware from langchain.messages import HumanMessage agent = create_agent( model="gpt-5.5", tools=[], middleware=[ FilesystemFileSearchMiddleware( root_path="/workspace", use_ripgrep=True, max_file_size_mb=10, ), ], ) result = agent.invoke({ "messages": [HumanMessage("Find all Python files containing 'async def'")] }) Agent can use glob_search and grep_search tools to find Python files and search for async functions.

RubricMiddleware purpose

RubricMiddleware lets you declare what done looks like as a rubric and have the agent self-evaluate and iterate until the rubric is satisfied or a maximum iteration cap is hit. It is useful for tasks with a clear definition of done that an agent cannot reliably hit on the first try. Requires deepagents>=0.6.5 and is in beta; the API may change in the future.

Model call limit middleware example

Example of ModelCallLimitMiddleware with thread and run limits: from langchain.agents import create_agent from langchain.agents.middleware import ModelCallLimitMiddleware from langgraph.checkpoint.memory import InMemorySaver agent = create_agent( model="gpt-5.5", checkpointer=InMemorySaver(), tools=[], middleware=[ ModelCallLimitMiddleware( thread_limit=10, run_limit=5, exit_behavior="end", ), ], )

Prebuilt middleware overview

LangChain and Deep Agents provide prebuilt middleware for common agent use cases. Provider-agnostic middleware includes: Summarization, Human-in-the-loop, Model call limit, Tool call limit, Model fallback, PII detection, To-do list, LLM tool selector, Tool error, Tool retry, Model retry, LLM tool emulator, Context editing, Provider tool search, Shell tool, File search, Filesystem, Subagent, and Rubric grading (Beta).

Summarization middleware configuration

SummarizationMiddleware parameters: model (required, string or BaseChatModel), trigger (ContextSize tuple, TriggerClause dict, or list of these; supports fraction, tokens, messages thresholds with AND/OR logic), keep (ContextSize tuple with exactly one of fraction/tokens/messages, default ('messages', 20)), token_counter (custom function), summary_prompt (custom template with {messages} placeholder), trim_tokens_to_summarize (default 4000). Summarization compresses older context while preserving recent messages and their multimodal content; older multimodal messages are represented only as text summaries.

Summarization trigger and keep logic

Trigger conditions in SummarizationMiddleware: A single ContextSize tuple triggers when that threshold is met; a TriggerClause dict with multiple thresholds triggers when ALL thresholds are met (AND logic); a list of conditions triggers when ANY item is met (OR logic). Each threshold can use fraction (0-1 of model context), tokens (absolute count), or messages (message count). Keep condition specifies exactly one threshold type to control how much context to preserve after summarization.

Human-in-the-loop middleware configuration

HumanInTheLoopMiddleware pauses agent execution for human approval, editing, or rejection of tool calls before they execute. Requires a checkpointer to maintain state across interruptions. Configuration uses interrupt_on dict mapping tool names to decision settings. Each tool can have allowed_decisions list (e.g., ['approve', 'edit', 'reject']) or be set to False to skip interruption. Useful for high-stakes operations, compliance workflows, and long-running conversations.

Model call limit middleware configuration

ModelCallLimitMiddleware parameters: thread_limit (maximum model calls across all runs in a thread, defaults to no limit), run_limit (maximum model calls per single invocation, defaults to no limit), exit_behavior (default 'end': 'end' for graceful termination or 'error' to raise exception). Requires checkpointer for thread_limit. Prevents runaway agents, enforces cost controls, and enables testing within call budgets.

Give your agent this brain