# LangChain Middleware

Ref: https://docs.langchain.com/oss/python/langchain/middleware/overview

Middleware allows you to control and customize agent execution at every step.


## Setup

Configure `.env` before running. See `.env.sample`.



```python
import rich
from dotenv import load_dotenv

load_dotenv()
```




    True



## Custom Middleware: Logging All Hooks

Create a middleware that logs every hook to understand the execution flow.



```python
from collections.abc import Callable
from datetime import datetime
from typing import Any

from langchain.agents import create_agent
from langchain.agents.middleware.types import (
    AgentMiddleware,
    AgentState,
    ToolCallRequest,
)
from langchain_anthropic import ChatAnthropic
from langchain_core.messages import ToolMessage
from langchain_core.tools import tool
from langgraph.graph.state import CompiledStateGraph
from langgraph.runtime import Runtime
from langgraph.types import Command


class LoggingMiddleware(AgentMiddleware[AgentState[Any], None]):
    """Middleware that logs all hooks."""

    def before_agent(self, state: AgentState[Any], runtime: Runtime[None]) -> dict[str, Any] | None:
        rich.print("[bold blue]>>> before_agent[/bold blue]")
        rich.print("state =", state)
        rich.print("runtime =", runtime)
        return None

    def before_model(self, state: AgentState[Any], runtime: Runtime[None]) -> dict[str, Any] | None:
        rich.print("[bold green]>>> before_model[/bold green]")
        rich.print("state =", state)
        rich.print("runtime =", runtime)
        return None

    def after_model(self, state: AgentState[Any], runtime: Runtime[None]) -> dict[str, Any] | None:
        rich.print("[bold green]<<< after_model[/bold green]")
        rich.print("state =", state)
        rich.print("runtime =", runtime)
        return None

    def wrap_tool_call(
        self,
        request: ToolCallRequest,
        handler: Callable[[ToolCallRequest], ToolMessage | Command[Any]],
    ) -> ToolMessage | Command[Any]:
        rich.print("[bold yellow]>>> wrap_tool_call (before)[/bold yellow]")
        rich.print("request =", request)
        result = handler(request)
        rich.print("[bold yellow]<<< wrap_tool_call (after)[/bold yellow]")
        rich.print("result =", result)
        return result

    def after_agent(self, state: AgentState[Any], runtime: Runtime[None]) -> dict[str, Any] | None:
        rich.print("[bold blue]<<< after_agent[/bold blue]")
        rich.print("state =", state)
        rich.print("runtime =", runtime)
        return None


@tool
def get_current_time() -> str:
    """Get the current time."""
    return datetime.now().isoformat()


model = ChatAnthropic(model="claude-sonnet-4-5-20250929")
agent: CompiledStateGraph[Any] = create_agent(
    model=model,
    tools=[get_current_time],
    system_prompt="You are a helpful assistant.",
    middleware=[LoggingMiddleware()],
)
```


```python
response = agent.invoke({"messages": [{"role": "user", "content": "What time is it?"}]})
rich.print("response =", response)
```


    >>> before_agent




    state =
    {
        'messages': [
            HumanMessage(
                content='What time is it?',
                additional_kwargs={},
                response_metadata={},
                id='da5820f3-014b-4f6b-8520-55f1a14cd89d'
            )
        ]
    }




    runtime =
    Runtime(
        context=None,
        store=None,
        stream_writer=<function Pregel.stream.<locals>.stream_writer at 0x10f8405e0>,
        previous=None
    )




    >>> before_model




    state =
    {
        'messages': [
            HumanMessage(
                content='What time is it?',
                additional_kwargs={},
                response_metadata={},
                id='da5820f3-014b-4f6b-8520-55f1a14cd89d'
            )
        ]
    }




    runtime =
    Runtime(
        context=None,
        store=None,
        stream_writer=<function Pregel.stream.<locals>.stream_writer at 0x10f8405e0>,
        previous=None
    )




    <<< after_model




    state =
    {
        'messages': [
            HumanMessage(
                content='What time is it?',
                additional_kwargs={},
                response_metadata={},
                id='da5820f3-014b-4f6b-8520-55f1a14cd89d'
            ),
            AIMessage(
                content=[
                    {
                        'id': 'toolu_01PbcfXo9S1qwA7o7eNs2ZDB',
                        'input': {},
                        'name': 'get_current_time',
                        'type': 'tool_use'
                    }
                ],
                additional_kwargs={},
                response_metadata={
                    'id': 'msg_012HPcqE4tyUxDUMbJGtxe11',
                    'model': 'claude-sonnet-4-5-20250929',
                    'stop_reason': 'tool_use',
                    'stop_sequence': None,
                    'usage': {
                        'cache_creation': {'ephemeral_1h_input_tokens': 0, 'ephemeral_5m_input_tokens': 0},
                        'cache_creation_input_tokens': 0,
                        'cache_read_input_tokens': 0,
                        'input_tokens': 555,
                        'output_tokens': 38,
                        'server_tool_use': None,
                        'service_tier': 'standard'
                    },
                    'model_name': 'claude-sonnet-4-5-20250929',
                    'model_provider': 'anthropic'
                },
                id='lc_run--cce12dd8-c135-44a7-ae76-d35cd89217d8-0',
                tool_calls=[
                    {
                        'name': 'get_current_time',
                        'args': {},
                        'id': 'toolu_01PbcfXo9S1qwA7o7eNs2ZDB',
                        'type': 'tool_call'
                    }
                ],
                usage_metadata={
                    'input_tokens': 555,
                    'output_tokens': 38,
                    'total_tokens': 593,
                    'input_token_details': {
                        'cache_read': 0,
                        'cache_creation': 0,
                        'ephemeral_5m_input_tokens': 0,
                        'ephemeral_1h_input_tokens': 0
                    }
                }
            )
        ]
    }




    runtime =
    Runtime(
        context=None,
        store=None,
        stream_writer=<function Pregel.stream.<locals>.stream_writer at 0x10f8405e0>,
        previous=None
    )




    >>> wrap_tool_call (before)




    request =
    ToolCallRequest(
        tool_call={
            'name': 'get_current_time',
            'args': {},
            'id': 'toolu_01PbcfXo9S1qwA7o7eNs2ZDB',
            'type': 'tool_call'
        },
        tool=StructuredTool(
            name='get_current_time',
            description='Get the current time.',
            args_schema=<class 'langchain_core.utils.pydantic.get_current_time'>,
            func=<function get_current_time at 0x10ef9ca40>
        ),
        state={
            'messages': [
                HumanMessage(
                    content='What time is it?',
                    additional_kwargs={},
                    response_metadata={},
                    id='da5820f3-014b-4f6b-8520-55f1a14cd89d'
                ),
                AIMessage(
                    content=[
                        {
                            'id': 'toolu_01PbcfXo9S1qwA7o7eNs2ZDB',
                            'input': {},
                            'name': 'get_current_time',
                            'type': 'tool_use'
                        }
                    ],
                    additional_kwargs={},
                    response_metadata={
                        'id': 'msg_012HPcqE4tyUxDUMbJGtxe11',
                        'model': 'claude-sonnet-4-5-20250929',
                        'stop_reason': 'tool_use',
                        'stop_sequence': None,
                        'usage': {
                            'cache_creation': {'ephemeral_1h_input_tokens': 0, 'ephemeral_5m_input_tokens': 0},
                            'cache_creation_input_tokens': 0,
                            'cache_read_input_tokens': 0,
                            'input_tokens': 555,
                            'output_tokens': 38,
                            'server_tool_use': None,
                            'service_tier': 'standard'
                        },
                        'model_name': 'claude-sonnet-4-5-20250929',
                        'model_provider': 'anthropic'
                    },
                    id='lc_run--cce12dd8-c135-44a7-ae76-d35cd89217d8-0',
                    tool_calls=[
                        {
                            'name': 'get_current_time',
                            'args': {},
                            'id': 'toolu_01PbcfXo9S1qwA7o7eNs2ZDB',
                            'type': 'tool_call'
                        }
                    ],
                    usage_metadata={
                        'input_tokens': 555,
                        'output_tokens': 38,
                        'total_tokens': 593,
                        'input_token_details': {
                            'cache_read': 0,
                            'cache_creation': 0,
                            'ephemeral_5m_input_tokens': 0,
                            'ephemeral_1h_input_tokens': 0
                        }
                    }
                )
            ]
        },
        runtime=ToolRuntime(
            state={
                'messages': [
                    HumanMessage(
                        content='What time is it?',
                        additional_kwargs={},
                        response_metadata={},
                        id='da5820f3-014b-4f6b-8520-55f1a14cd89d'
                    ),
                    AIMessage(
                        content=[
                            {
                                'id': 'toolu_01PbcfXo9S1qwA7o7eNs2ZDB',
                                'input': {},
                                'name': 'get_current_time',
                                'type': 'tool_use'
                            }
                        ],
                        additional_kwargs={},
                        response_metadata={
                            'id': 'msg_012HPcqE4tyUxDUMbJGtxe11',
                            'model': 'claude-sonnet-4-5-20250929',
                            'stop_reason': 'tool_use',
                            'stop_sequence': None,
                            'usage': {
                                'cache_creation': {'ephemeral_1h_input_tokens': 0, 'ephemeral_5m_input_tokens': 0},
                                'cache_creation_input_tokens': 0,
                                'cache_read_input_tokens': 0,
                                'input_tokens': 555,
                                'output_tokens': 38,
                                'server_tool_use': None,
                                'service_tier': 'standard'
                            },
                            'model_name': 'claude-sonnet-4-5-20250929',
                            'model_provider': 'anthropic'
                        },
                        id='lc_run--cce12dd8-c135-44a7-ae76-d35cd89217d8-0',
                        tool_calls=[
                            {
                                'name': 'get_current_time',
                                'args': {},
                                'id': 'toolu_01PbcfXo9S1qwA7o7eNs2ZDB',
                                'type': 'tool_call'
                            }
                        ],
                        usage_metadata={
                            'input_tokens': 555,
                            'output_tokens': 38,
                            'total_tokens': 593,
                            'input_token_details': {
                                'cache_read': 0,
                                'cache_creation': 0,
                                'ephemeral_5m_input_tokens': 0,
                                'ephemeral_1h_input_tokens': 0
                            }
                        }
                    )
                ]
            },
            context=None,
            config={
                'tags': [],
                'metadata': {
                    'langgraph_step': 5,
                    'langgraph_node': 'tools',
                    'langgraph_triggers': ('__pregel_push',),
                    'langgraph_path': ('__pregel_push', 0, False),
                    'langgraph_checkpoint_ns': 'tools:17128c41-bf4e-d372-dfcf-fbd1f8b001ef',
                    'checkpoint_ns': 'tools:17128c41-bf4e-d372-dfcf-fbd1f8b001ef'
                },
                'callbacks': <langchain_core.callbacks.manager.CallbackManager object at 0x10fc545d0>,
                'recursion_limit': 10000,
                'configurable': {
                    '__pregel_runtime': Runtime(
                        context=None,
                        store=None,
                        stream_writer=<function Pregel.stream.<locals>.stream_writer at 0x10f8405e0>,
                        previous=None
                    ),
                    '__pregel_task_id': '17128c41-bf4e-d372-dfcf-fbd1f8b001ef',
                    '__pregel_send': <built-in method extend of collections.deque object at 0x108a405e0>,
                    '__pregel_read': functools.partial(<function local_read at 0x10ee52660>, PregelScratchpad(step=5, 
    stop=10000, call_counter=<langgraph.pregel._algo.LazyAtomicCounter object at 0x10f7fcfd0>, 
    interrupt_counter=<langgraph.pregel._algo.LazyAtomicCounter object at 0x10f7fcf40>, get_null_resume=<function 
    _scratchpad.<locals>.get_null_resume at 0x10f840860>, resume=[], 
    subgraph_counter=<langgraph.pregel._algo.LazyAtomicCounter object at 0x10f7fccd0>), {'messages': 
    <langgraph.channels.binop.BinaryOperatorAggregate object at 0x108a06580>, 'jump_to': 
    <langgraph.channels.ephemeral_value.EphemeralValue object at 0x1088c3a00>, 'structured_response': 
    <langgraph.channels.last_value.LastValue object at 0x1088c23c0>, '__start__': 
    <langgraph.channels.ephemeral_value.EphemeralValue object at 0x10841b500>, '__pregel_tasks': 
    <langgraph.channels.topic.Topic object at 0x10efc8080>, 'branch:to:model': 
    <langgraph.channels.ephemeral_value.EphemeralValue object at 0x108a0af80>, 'branch:to:tools': 
    <langgraph.channels.ephemeral_value.EphemeralValue object at 0x108a09580>, 
    'branch:to:LoggingMiddleware.before_agent': <langgraph.channels.ephemeral_value.EphemeralValue object at 
    0x108a08c40>, 'branch:to:LoggingMiddleware.before_model': <langgraph.channels.ephemeral_value.EphemeralValue object
    at 0x108a0b180>, 'branch:to:LoggingMiddleware.after_model': <langgraph.channels.ephemeral_value.EphemeralValue 
    object at 0x108a0b040>, 'branch:to:LoggingMiddleware.after_agent': 
    <langgraph.channels.ephemeral_value.EphemeralValue object at 0x108a0ae80>}, {}, 
    PregelTaskWrites(path=('__pregel_push', 0, False), name='tools', writes=deque([]), triggers=('__pregel_push',))),
                    '__pregel_checkpointer': None,
                    'checkpoint_map': {'': '1f0d1627-1925-665c-8004-27f8133a0a14'},
                    'checkpoint_id': None,
                    'checkpoint_ns': 'tools:17128c41-bf4e-d372-dfcf-fbd1f8b001ef',
                    '__pregel_scratchpad': PregelScratchpad(
                        step=5,
                        stop=10000,
                        call_counter=<langgraph.pregel._algo.LazyAtomicCounter object at 0x10f7fcfd0>,
                        interrupt_counter=<langgraph.pregel._algo.LazyAtomicCounter object at 0x10f7fcf40>,
                        get_null_resume=<function _scratchpad.<locals>.get_null_resume at 0x10f840860>,
                        resume=[],
                        subgraph_counter=<langgraph.pregel._algo.LazyAtomicCounter object at 0x10f7fccd0>
                    ),
                    '__pregel_call': functools.partial(<function _call at 0x10ee84fe0>, <weakref at 0x10f83a0c0; to 
    'langgraph.types.PregelExecutableTask' at 0x10f806e70>, retry_policy=None, futures=<weakref at 0x10fc52570; to 
    'langgraph.pregel._runner.FuturesDict' at 0x10f83a120>, schedule_task=<bound method SyncPregelLoop.accept_push of 
    <langgraph.pregel._loop.SyncPregelLoop object at 0x10f789fd0>>, submit=<weakref at 0x10f850e50; to 
    'langgraph.pregel._executor.BackgroundExecutor' at 0x10f78a120>)
                }
            },
            stream_writer=<function Pregel.stream.<locals>.stream_writer at 0x10f8405e0>,
            tool_call_id='toolu_01PbcfXo9S1qwA7o7eNs2ZDB',
            store=None
        )
    )




    <<< wrap_tool_call (after)




    result =
    ToolMessage(
        content='2025-12-05T07:41:59.107322',
        name='get_current_time',
        tool_call_id='toolu_01PbcfXo9S1qwA7o7eNs2ZDB'
    )




    >>> before_model




    state =
    {
        'messages': [
            HumanMessage(
                content='What time is it?',
                additional_kwargs={},
                response_metadata={},
                id='da5820f3-014b-4f6b-8520-55f1a14cd89d'
            ),
            AIMessage(
                content=[
                    {
                        'id': 'toolu_01PbcfXo9S1qwA7o7eNs2ZDB',
                        'input': {},
                        'name': 'get_current_time',
                        'type': 'tool_use'
                    }
                ],
                additional_kwargs={},
                response_metadata={
                    'id': 'msg_012HPcqE4tyUxDUMbJGtxe11',
                    'model': 'claude-sonnet-4-5-20250929',
                    'stop_reason': 'tool_use',
                    'stop_sequence': None,
                    'usage': {
                        'cache_creation': {'ephemeral_1h_input_tokens': 0, 'ephemeral_5m_input_tokens': 0},
                        'cache_creation_input_tokens': 0,
                        'cache_read_input_tokens': 0,
                        'input_tokens': 555,
                        'output_tokens': 38,
                        'server_tool_use': None,
                        'service_tier': 'standard'
                    },
                    'model_name': 'claude-sonnet-4-5-20250929',
                    'model_provider': 'anthropic'
                },
                id='lc_run--cce12dd8-c135-44a7-ae76-d35cd89217d8-0',
                tool_calls=[
                    {
                        'name': 'get_current_time',
                        'args': {},
                        'id': 'toolu_01PbcfXo9S1qwA7o7eNs2ZDB',
                        'type': 'tool_call'
                    }
                ],
                usage_metadata={
                    'input_tokens': 555,
                    'output_tokens': 38,
                    'total_tokens': 593,
                    'input_token_details': {
                        'cache_read': 0,
                        'cache_creation': 0,
                        'ephemeral_5m_input_tokens': 0,
                        'ephemeral_1h_input_tokens': 0
                    }
                }
            ),
            ToolMessage(
                content='2025-12-05T07:41:59.107322',
                name='get_current_time',
                id='bd77b651-d924-4dbc-a05e-7eb906b3f82b',
                tool_call_id='toolu_01PbcfXo9S1qwA7o7eNs2ZDB'
            )
        ]
    }




    runtime =
    Runtime(
        context=None,
        store=None,
        stream_writer=<function Pregel.stream.<locals>.stream_writer at 0x10f8405e0>,
        previous=None
    )




    <<< after_model




    state =
    {
        'messages': [
            HumanMessage(
                content='What time is it?',
                additional_kwargs={},
                response_metadata={},
                id='da5820f3-014b-4f6b-8520-55f1a14cd89d'
            ),
            AIMessage(
                content=[
                    {
                        'id': 'toolu_01PbcfXo9S1qwA7o7eNs2ZDB',
                        'input': {},
                        'name': 'get_current_time',
                        'type': 'tool_use'
                    }
                ],
                additional_kwargs={},
                response_metadata={
                    'id': 'msg_012HPcqE4tyUxDUMbJGtxe11',
                    'model': 'claude-sonnet-4-5-20250929',
                    'stop_reason': 'tool_use',
                    'stop_sequence': None,
                    'usage': {
                        'cache_creation': {'ephemeral_1h_input_tokens': 0, 'ephemeral_5m_input_tokens': 0},
                        'cache_creation_input_tokens': 0,
                        'cache_read_input_tokens': 0,
                        'input_tokens': 555,
                        'output_tokens': 38,
                        'server_tool_use': None,
                        'service_tier': 'standard'
                    },
                    'model_name': 'claude-sonnet-4-5-20250929',
                    'model_provider': 'anthropic'
                },
                id='lc_run--cce12dd8-c135-44a7-ae76-d35cd89217d8-0',
                tool_calls=[
                    {
                        'name': 'get_current_time',
                        'args': {},
                        'id': 'toolu_01PbcfXo9S1qwA7o7eNs2ZDB',
                        'type': 'tool_call'
                    }
                ],
                usage_metadata={
                    'input_tokens': 555,
                    'output_tokens': 38,
                    'total_tokens': 593,
                    'input_token_details': {
                        'cache_read': 0,
                        'cache_creation': 0,
                        'ephemeral_5m_input_tokens': 0,
                        'ephemeral_1h_input_tokens': 0
                    }
                }
            ),
            ToolMessage(
                content='2025-12-05T07:41:59.107322',
                name='get_current_time',
                id='bd77b651-d924-4dbc-a05e-7eb906b3f82b',
                tool_call_id='toolu_01PbcfXo9S1qwA7o7eNs2ZDB'
            ),
            AIMessage(
                content='The current time is **7:41:59 AM** on December 5th, 2025.',
                additional_kwargs={},
                response_metadata={
                    'id': 'msg_01DCMHBDuKjqHkb6d2Gg8Uw3',
                    'model': 'claude-sonnet-4-5-20250929',
                    'stop_reason': 'end_turn',
                    'stop_sequence': None,
                    'usage': {
                        'cache_creation': {'ephemeral_1h_input_tokens': 0, 'ephemeral_5m_input_tokens': 0},
                        'cache_creation_input_tokens': 0,
                        'cache_read_input_tokens': 0,
                        'input_tokens': 621,
                        'output_tokens': 26,
                        'server_tool_use': None,
                        'service_tier': 'standard'
                    },
                    'model_name': 'claude-sonnet-4-5-20250929',
                    'model_provider': 'anthropic'
                },
                id='lc_run--8728465d-2f06-4497-9e69-2aea62f2ab37-0',
                usage_metadata={
                    'input_tokens': 621,
                    'output_tokens': 26,
                    'total_tokens': 647,
                    'input_token_details': {
                        'cache_read': 0,
                        'cache_creation': 0,
                        'ephemeral_5m_input_tokens': 0,
                        'ephemeral_1h_input_tokens': 0
                    }
                }
            )
        ]
    }




    runtime =
    Runtime(
        context=None,
        store=None,
        stream_writer=<function Pregel.stream.<locals>.stream_writer at 0x10f8405e0>,
        previous=None
    )




    <<< after_agent




    state =
    {
        'messages': [
            HumanMessage(
                content='What time is it?',
                additional_kwargs={},
                response_metadata={},
                id='da5820f3-014b-4f6b-8520-55f1a14cd89d'
            ),
            AIMessage(
                content=[
                    {
                        'id': 'toolu_01PbcfXo9S1qwA7o7eNs2ZDB',
                        'input': {},
                        'name': 'get_current_time',
                        'type': 'tool_use'
                    }
                ],
                additional_kwargs={},
                response_metadata={
                    'id': 'msg_012HPcqE4tyUxDUMbJGtxe11',
                    'model': 'claude-sonnet-4-5-20250929',
                    'stop_reason': 'tool_use',
                    'stop_sequence': None,
                    'usage': {
                        'cache_creation': {'ephemeral_1h_input_tokens': 0, 'ephemeral_5m_input_tokens': 0},
                        'cache_creation_input_tokens': 0,
                        'cache_read_input_tokens': 0,
                        'input_tokens': 555,
                        'output_tokens': 38,
                        'server_tool_use': None,
                        'service_tier': 'standard'
                    },
                    'model_name': 'claude-sonnet-4-5-20250929',
                    'model_provider': 'anthropic'
                },
                id='lc_run--cce12dd8-c135-44a7-ae76-d35cd89217d8-0',
                tool_calls=[
                    {
                        'name': 'get_current_time',
                        'args': {},
                        'id': 'toolu_01PbcfXo9S1qwA7o7eNs2ZDB',
                        'type': 'tool_call'
                    }
                ],
                usage_metadata={
                    'input_tokens': 555,
                    'output_tokens': 38,
                    'total_tokens': 593,
                    'input_token_details': {
                        'cache_read': 0,
                        'cache_creation': 0,
                        'ephemeral_5m_input_tokens': 0,
                        'ephemeral_1h_input_tokens': 0
                    }
                }
            ),
            ToolMessage(
                content='2025-12-05T07:41:59.107322',
                name='get_current_time',
                id='bd77b651-d924-4dbc-a05e-7eb906b3f82b',
                tool_call_id='toolu_01PbcfXo9S1qwA7o7eNs2ZDB'
            ),
            AIMessage(
                content='The current time is **7:41:59 AM** on December 5th, 2025.',
                additional_kwargs={},
                response_metadata={
                    'id': 'msg_01DCMHBDuKjqHkb6d2Gg8Uw3',
                    'model': 'claude-sonnet-4-5-20250929',
                    'stop_reason': 'end_turn',
                    'stop_sequence': None,
                    'usage': {
                        'cache_creation': {'ephemeral_1h_input_tokens': 0, 'ephemeral_5m_input_tokens': 0},
                        'cache_creation_input_tokens': 0,
                        'cache_read_input_tokens': 0,
                        'input_tokens': 621,
                        'output_tokens': 26,
                        'server_tool_use': None,
                        'service_tier': 'standard'
                    },
                    'model_name': 'claude-sonnet-4-5-20250929',
                    'model_provider': 'anthropic'
                },
                id='lc_run--8728465d-2f06-4497-9e69-2aea62f2ab37-0',
                usage_metadata={
                    'input_tokens': 621,
                    'output_tokens': 26,
                    'total_tokens': 647,
                    'input_token_details': {
                        'cache_read': 0,
                        'cache_creation': 0,
                        'ephemeral_5m_input_tokens': 0,
                        'ephemeral_1h_input_tokens': 0
                    }
                }
            )
        ]
    }




    runtime =
    Runtime(
        context=None,
        store=None,
        stream_writer=<function Pregel.stream.<locals>.stream_writer at 0x10f8405e0>,
        previous=None
    )




    response =
    {
        'messages': [
            HumanMessage(
                content='What time is it?',
                additional_kwargs={},
                response_metadata={},
                id='da5820f3-014b-4f6b-8520-55f1a14cd89d'
            ),
            AIMessage(
                content=[
                    {
                        'id': 'toolu_01PbcfXo9S1qwA7o7eNs2ZDB',
                        'input': {},
                        'name': 'get_current_time',
                        'type': 'tool_use'
                    }
                ],
                additional_kwargs={},
                response_metadata={
                    'id': 'msg_012HPcqE4tyUxDUMbJGtxe11',
                    'model': 'claude-sonnet-4-5-20250929',
                    'stop_reason': 'tool_use',
                    'stop_sequence': None,
                    'usage': {
                        'cache_creation': {'ephemeral_1h_input_tokens': 0, 'ephemeral_5m_input_tokens': 0},
                        'cache_creation_input_tokens': 0,
                        'cache_read_input_tokens': 0,
                        'input_tokens': 555,
                        'output_tokens': 38,
                        'server_tool_use': None,
                        'service_tier': 'standard'
                    },
                    'model_name': 'claude-sonnet-4-5-20250929',
                    'model_provider': 'anthropic'
                },
                id='lc_run--cce12dd8-c135-44a7-ae76-d35cd89217d8-0',
                tool_calls=[
                    {
                        'name': 'get_current_time',
                        'args': {},
                        'id': 'toolu_01PbcfXo9S1qwA7o7eNs2ZDB',
                        'type': 'tool_call'
                    }
                ],
                usage_metadata={
                    'input_tokens': 555,
                    'output_tokens': 38,
                    'total_tokens': 593,
                    'input_token_details': {
                        'cache_read': 0,
                        'cache_creation': 0,
                        'ephemeral_5m_input_tokens': 0,
                        'ephemeral_1h_input_tokens': 0
                    }
                }
            ),
            ToolMessage(
                content='2025-12-05T07:41:59.107322',
                name='get_current_time',
                id='bd77b651-d924-4dbc-a05e-7eb906b3f82b',
                tool_call_id='toolu_01PbcfXo9S1qwA7o7eNs2ZDB'
            ),
            AIMessage(
                content='The current time is **7:41:59 AM** on December 5th, 2025.',
                additional_kwargs={},
                response_metadata={
                    'id': 'msg_01DCMHBDuKjqHkb6d2Gg8Uw3',
                    'model': 'claude-sonnet-4-5-20250929',
                    'stop_reason': 'end_turn',
                    'stop_sequence': None,
                    'usage': {
                        'cache_creation': {'ephemeral_1h_input_tokens': 0, 'ephemeral_5m_input_tokens': 0},
                        'cache_creation_input_tokens': 0,
                        'cache_read_input_tokens': 0,
                        'input_tokens': 621,
                        'output_tokens': 26,
                        'server_tool_use': None,
                        'service_tier': 'standard'
                    },
                    'model_name': 'claude-sonnet-4-5-20250929',
                    'model_provider': 'anthropic'
                },
                id='lc_run--8728465d-2f06-4497-9e69-2aea62f2ab37-0',
                usage_metadata={
                    'input_tokens': 621,
                    'output_tokens': 26,
                    'total_tokens': 647,
                    'input_token_details': {
                        'cache_read': 0,
                        'cache_creation': 0,
                        'ephemeral_5m_input_tokens': 0,
                        'ephemeral_1h_input_tokens': 0
                    }
                }
            )
        ]
    }


