DS DevShelfHub Projects · AI tools
Tutorials / LangChain / Reference / Decorators / @wrap_tool_call
Decorator langchain.agents

@wrap_tool_call: Reference Guide

By DevShelfHub

Middleware wrapping tool calls before execution.

What is @wrap_tool_call?

@wrap_tool_call is a LangChain agent middleware decorator that intercepts tool call objects before the corresponding @tool-decorated function is executed. It is the security and governance layer for tool use: you can inspect the tool name, validate its arguments, enforce access control rules, log every call for auditing, apply rate limits per tool, or outright block calls to forbidden tools by raising an exception.

The decorated function receives a tool call object with at minimum a .name attribute (the tool's registered name) and an .args attribute (the dict of arguments the model supplied). It must return the call object to allow execution to proceed, or raise an exception to abort the tool call. Modifying .args before returning allows you to sanitize or constrain the arguments — for example, capping a limit parameter the model set too high, or escaping SQL injection attempts in a query string argument.

The hook fires for every tool call in a multi-call turn. If the model decides to call three tools simultaneously (as happens with parallel tool calling on OpenAI models), @wrap_tool_call fires three times — once per call object — before any of them executes. This gives you a consistent enforcement point regardless of whether the model batches tool calls. For read-only tools (search, lookup), a logging-only hook is sufficient; for write tools (file operations, database writes, API mutations), validate and block in the hook before execution, since rolling back a completed write is far harder than preventing it.

Use Cases

  • Validate calls
  • Rate limit
  • Audit logs
  • Security checks
  • Log usage
  • Route calls

Key Features

  • Intercept calls
  • Parameter inspection
  • Error handling
  • Logging
  • Conditional execution
  • Validation

When NOT to Use

For tool definitions—use @tool.

Notes

Must return the call object — returning None causes the tool to receive no arguments

The middleware contract requires returning the call object. A hook that returns None passes None to the tool dispatcher, which then fails with a TypeError. Side-effect-only hooks (logging, incrementing counters) must still end with return call.

Fires once per tool call — parallel tool calls trigger it N times

When a model makes parallel tool calls (e.g., OpenAI's parallel_tool_calls feature), @wrap_tool_call fires once per call, not once per turn. If three tools are called simultaneously, the hook runs three times concurrently in different threads. Make sure any shared state accessed in the hook is thread-safe (use threading.Lock() for counters).

Modify call.args to sanitize model-supplied arguments before execution

call.args is a dict you can mutate before returning. Use this to cap numeric arguments the model set too aggressively (e.g., limit=10000 → limit=100), escape user-supplied strings in SQL query tools, or add required fields the model omitted. Sanitizing before execution is safer than catching errors after.

Raising an exception returns a ToolMessage with the error to the model

If you raise inside @wrap_tool_call, the agent's ToolNode (if configured with handle_tool_errors=True) catches it and adds a ToolMessage with the error text back to the conversation, allowing the model to respond to the error. Without handle_tool_errors=True, the exception propagates and crashes the agent turn.

Import

python
from langchain.agents import wrap_tool_call

How to Apply

python
@wrap_tool_call
def validate(call):
    if call.name == 'delete':
        if not is_safe(call.args):
            raise ValueError('Unsafe')
    return call

What It Enables

  • Call validation
  • Monitoring
  • Rate limiting
  • Security

Code Examples

Log every tool call

python
from langchain.agents import wrap_tool_call
@wrap_tool_call
def validate(call):
    print(f'Tool call: {call.name}({call.args})')
    return call

Block forbidden tools by name

python
from langchain.agents import wrap_tool_call
FORBIDDEN_TOOLS = {"delete_file", "drop_table"}
@wrap_tool_call
def security_guard(call):
    if call.name in FORBIDDEN_TOOLS:
        raise PermissionError(f"Tool {call.name!r} is not allowed")
    return call

Per-tool rate limiting

python
from langchain.agents import wrap_tool_call
import time
_rate = {}
@wrap_tool_call
def rate_limit_tools(call):
    now = time.time()
    last = _rate.get(call.name, 0)
    if now - last < 1.0:  # 1 call per second per tool
        raise RuntimeError(f"{call.name} called too frequently")
    _rate[call.name] = now
    return call

Integration Patterns

agent = create_agent(model, middleware=[wrapper])
Intercepts all calls

Common Mistakes

❌ @wrap_tool_call def h(call): # Forgot return

✅ @wrap_tool_call def h(call): return call

Browse the full LangChain API reference index to explore more classes, methods, and decorators, or start with the LangChain introduction tutorial for end-to-end context on building with @wrap_tool_call and the wider framework.

@wrap_tool_call FAQ

What does @wrap_tool_call do in LangChain?

Middleware wrapping tool calls before execution. @wrap_tool_call is a LangChain agent middleware decorator that intercepts tool call objects before the corresponding @tool-decorated function is executed. It is the security and governance layer for tool use: you can inspect the tool name, validate its arguments, enforce access control rules, log every call for auditing, apply rate limits per tool, or outright block calls to forbidden tools by raising an exception. The decorated function receives a tool call object with at m…

Which package provides @wrap_tool_call?

DevShelfHub documents @wrap_tool_call from the langchain.agents package. Pin your installed LangChain version and match imports to the snippet on this page.

When should I use @wrap_tool_call?

Use @wrap_tool_call when your LangChain agents, workflows, or pipelines need the behavior described in this guide.

When should I avoid using @wrap_tool_call?

For tool definitions—use @tool.

How do I apply @wrap_tool_call in Python?

Apply @wrap_tool_call as a decorator above your function definition. Import it from from langchain.agents import wrap_tool_call and annotate the function you want to wrap. See the code examples on this page for a complete working snippet.

Where can I explore more LangChain API reference pages?

Open the LangChain API reference index on DevShelfHub to browse classes, methods, and decorators, each with runnable examples, parameters, common mistakes, and cross-links.