Skip to content

MemoryMiddleware

MemoryMiddleware

Bases: AgentMiddleware

Middleware for loading agent memory from AGENTS.md files.

Loads memory content from configured sources and injects into the system prompt.

Supports multiple sources that are combined together.

PARAMETER DESCRIPTION
backend

Backend instance or factory function for file operations.

TYPE: BACKEND_TYPES

sources

List of MemorySource configurations specifying paths and names.

TYPE: list[str]

METHOD DESCRIPTION
__init__

Initialize the memory middleware.

before_agent

Load memory content before agent execution (synchronous).

abefore_agent

Load memory content before agent execution.

modify_request

Inject memory content into the system message.

wrap_model_call

Wrap model call to inject memory into system prompt.

awrap_model_call

Async wrap model call to inject memory into system prompt.

before_model

Logic to run before the model is called.

abefore_model

Async logic to run before the model is called.

after_model

Logic to run after the model is called.

aafter_model

Async logic to run after the model is called.

after_agent

Logic to run after the agent execution completes.

aafter_agent

Async logic to run after the agent execution completes.

wrap_tool_call

Intercept tool execution for retries, monitoring, or modification.

awrap_tool_call

Intercept and control async tool execution via handler callback.

state_schema class-attribute instance-attribute

state_schema = MemoryState

The schema for state passed to the middleware nodes.

tools instance-attribute

Additional tools registered by the middleware.

name property

name: str

The name of the middleware instance.

Defaults to the class name, but can be overridden for custom naming.

__init__

__init__(*, backend: BACKEND_TYPES, sources: list[str]) -> None

Initialize the memory middleware.

PARAMETER DESCRIPTION
backend

Backend instance or factory function that takes runtime and returns a backend. Use a factory for StateBackend.

TYPE: BACKEND_TYPES

sources

List of memory file paths to load (e.g., ["~/.deepagents/AGENTS.md", "./.deepagents/AGENTS.md"]).

 Display names are automatically derived from the paths.

 Sources are loaded in order.

TYPE: list[str]

before_agent

before_agent(
    state: MemoryState, runtime: Runtime, config: RunnableConfig
) -> MemoryStateUpdate | None

Load memory content before agent execution (synchronous).

Loads memory from all configured sources and stores in state. Only loads if not already present in state.

PARAMETER DESCRIPTION
state

Current agent state.

TYPE: MemoryState

runtime

Runtime context.

TYPE: Runtime

config

Runnable config.

TYPE: RunnableConfig

RETURNS DESCRIPTION
MemoryStateUpdate | None

State update with memory_contents populated.

abefore_agent async

abefore_agent(
    state: MemoryState, runtime: Runtime, config: RunnableConfig
) -> MemoryStateUpdate | None

Load memory content before agent execution.

Loads memory from all configured sources and stores in state. Only loads if not already present in state.

PARAMETER DESCRIPTION
state

Current agent state.

TYPE: MemoryState

runtime

Runtime context.

TYPE: Runtime

config

Runnable config.

TYPE: RunnableConfig

RETURNS DESCRIPTION
MemoryStateUpdate | None

State update with memory_contents populated.

modify_request

modify_request(request: ModelRequest) -> ModelRequest

Inject memory content into the system message.

PARAMETER DESCRIPTION
request

Model request to modify.

TYPE: ModelRequest

RETURNS DESCRIPTION
ModelRequest

Modified request with memory injected into system message.

wrap_model_call

wrap_model_call(
    request: ModelRequest, handler: Callable[[ModelRequest], ModelResponse]
) -> ModelResponse

Wrap model call to inject memory into system prompt.

PARAMETER DESCRIPTION
request

Model request being processed.

TYPE: ModelRequest

handler

Handler function to call with modified request.

TYPE: Callable[[ModelRequest], ModelResponse]

RETURNS DESCRIPTION
ModelResponse

Model response from handler.

awrap_model_call async

awrap_model_call(
    request: ModelRequest, handler: Callable[[ModelRequest], Awaitable[ModelResponse]]
) -> ModelResponse

Async wrap model call to inject memory into system prompt.

PARAMETER DESCRIPTION
request

Model request being processed.

TYPE: ModelRequest

handler

Async handler function to call with modified request.

TYPE: Callable[[ModelRequest], Awaitable[ModelResponse]]

RETURNS DESCRIPTION
ModelResponse

Model response from handler.

before_model

before_model(state: StateT, runtime: Runtime[ContextT]) -> dict[str, Any] | None

Logic to run before the model is called.

PARAMETER DESCRIPTION
state

The current agent state.

TYPE: StateT

runtime

The runtime context.

TYPE: Runtime[ContextT]

RETURNS DESCRIPTION
dict[str, Any] | None

Agent state updates to apply before model call.

abefore_model async

abefore_model(state: StateT, runtime: Runtime[ContextT]) -> dict[str, Any] | None

Async logic to run before the model is called.

PARAMETER DESCRIPTION
state

The agent state.

TYPE: StateT

runtime

The runtime context.

TYPE: Runtime[ContextT]

RETURNS DESCRIPTION
dict[str, Any] | None

Agent state updates to apply before model call.

after_model

after_model(state: StateT, runtime: Runtime[ContextT]) -> dict[str, Any] | None

Logic to run after the model is called.

PARAMETER DESCRIPTION
state

The current agent state.

TYPE: StateT

runtime

The runtime context.

TYPE: Runtime[ContextT]

RETURNS DESCRIPTION
dict[str, Any] | None

Agent state updates to apply after model call.

aafter_model async

aafter_model(state: StateT, runtime: Runtime[ContextT]) -> dict[str, Any] | None

Async logic to run after the model is called.

PARAMETER DESCRIPTION
state

The current agent state.

TYPE: StateT

runtime

The runtime context.

TYPE: Runtime[ContextT]

RETURNS DESCRIPTION
dict[str, Any] | None

Agent state updates to apply after model call.

after_agent

after_agent(state: StateT, runtime: Runtime[ContextT]) -> dict[str, Any] | None

Logic to run after the agent execution completes.

PARAMETER DESCRIPTION
state

The current agent state.

TYPE: StateT

runtime

The runtime context.

TYPE: Runtime[ContextT]

RETURNS DESCRIPTION
dict[str, Any] | None

Agent state updates to apply after agent execution.

aafter_agent async

aafter_agent(state: StateT, runtime: Runtime[ContextT]) -> dict[str, Any] | None

Async logic to run after the agent execution completes.

PARAMETER DESCRIPTION
state

The current agent state.

TYPE: StateT

runtime

The runtime context.

TYPE: Runtime[ContextT]

RETURNS DESCRIPTION
dict[str, Any] | None

Agent state updates to apply after agent execution.

wrap_tool_call

wrap_tool_call(
    request: ToolCallRequest,
    handler: Callable[[ToolCallRequest], ToolMessage | Command[Any]],
) -> ToolMessage | Command[Any]

Intercept tool execution for retries, monitoring, or modification.

Async version is awrap_tool_call

Multiple middleware compose automatically (first defined = outermost).

Exceptions propagate unless handle_tool_errors is configured on ToolNode.

PARAMETER DESCRIPTION
request

Tool call request with call dict, BaseTool, state, and runtime.

Access state via request.state and runtime via request.runtime.

TYPE: ToolCallRequest

handler

Callable to execute the tool (can be called multiple times).

TYPE: Callable[[ToolCallRequest], ToolMessage | Command[Any]]

RETURNS DESCRIPTION
ToolMessage | Command[Any]

ToolMessage or Command (the final result).

The handler Callable can be invoked multiple times for retry logic.

Each call to handler is independent and stateless.

Examples:

Modify request before execution

def wrap_tool_call(self, request, handler):
    modified_call = {
        **request.tool_call,
        "args": {
            **request.tool_call["args"],
            "value": request.tool_call["args"]["value"] * 2,
        },
    }
    request = request.override(tool_call=modified_call)
    return handler(request)

Retry on error (call handler multiple times)

def wrap_tool_call(self, request, handler):
    for attempt in range(3):
        try:
            result = handler(request)
            if is_valid(result):
                return result
        except Exception:
            if attempt == 2:
                raise
    return result

Conditional retry based on response

def wrap_tool_call(self, request, handler):
    for attempt in range(3):
        result = handler(request)
        if isinstance(result, ToolMessage) and result.status != "error":
            return result
        if attempt < 2:
            continue
        return result

awrap_tool_call async

awrap_tool_call(
    request: ToolCallRequest,
    handler: Callable[[ToolCallRequest], Awaitable[ToolMessage | Command[Any]]],
) -> ToolMessage | Command[Any]

Intercept and control async tool execution via handler callback.

The handler callback executes the tool call and returns a ToolMessage or Command. Middleware can call the handler multiple times for retry logic, skip calling it to short-circuit, or modify the request/response. Multiple middleware compose with first in list as outermost layer.

PARAMETER DESCRIPTION
request

Tool call request with call dict, BaseTool, state, and runtime.

Access state via request.state and runtime via request.runtime.

TYPE: ToolCallRequest

handler

Async callable to execute the tool and returns ToolMessage or Command.

Call this to execute the tool.

Can be called multiple times for retry logic.

Can skip calling it to short-circuit.

TYPE: Callable[[ToolCallRequest], Awaitable[ToolMessage | Command[Any]]]

RETURNS DESCRIPTION
ToolMessage | Command[Any]

ToolMessage or Command (the final result).

The handler Callable can be invoked multiple times for retry logic.

Each call to handler is independent and stateless.

Examples:

Async retry on error

async def awrap_tool_call(self, request, handler):
    for attempt in range(3):
        try:
            result = await handler(request)
            if is_valid(result):
                return result
        except Exception:
            if attempt == 2:
                raise
    return result
async def awrap_tool_call(self, request, handler):
    if cached := await get_cache_async(request):
        return ToolMessage(content=cached, tool_call_id=request.tool_call["id"])
    result = await handler(request)
    await save_cache_async(request, result)
    return result