Home / File/ test_fetch_last_ai_and_tool_messages.py — langchain Source File

test_fetch_last_ai_and_tool_messages.py — langchain Source File

Architecture documentation for test_fetch_last_ai_and_tool_messages.py, a python file in the langchain codebase. 2 imports, 0 dependents.

File python LangChainCore Runnables 2 imports 6 functions

Entity Profile

Dependency Diagram

graph LR
  377b132d_d3e1_0d37_8fdd_618ce0d34bb1["test_fetch_last_ai_and_tool_messages.py"]
  9444498b_8066_55c7_b3a2_1d90c4162a32["langchain_core.messages"]
  377b132d_d3e1_0d37_8fdd_618ce0d34bb1 --> 9444498b_8066_55c7_b3a2_1d90c4162a32
  998e41c8_6a3e_eb9b_699f_db967a1242f7["langchain.agents.factory"]
  377b132d_d3e1_0d37_8fdd_618ce0d34bb1 --> 998e41c8_6a3e_eb9b_699f_db967a1242f7
  style 377b132d_d3e1_0d37_8fdd_618ce0d34bb1 fill:#6366f1,stroke:#818cf8,color:#fff

Relationship Graph

Source Code

"""Unit tests for _fetch_last_ai_and_tool_messages helper function.

These tests verify that the helper function correctly handles edge cases,
including the scenario where no AIMessage exists in the message list
(fixes issue #34792).
"""

from langchain_core.messages import AIMessage, HumanMessage, SystemMessage, ToolMessage

from langchain.agents.factory import _fetch_last_ai_and_tool_messages


def test_fetch_last_ai_and_tool_messages_normal() -> None:
    """Test normal case with AIMessage and subsequent ToolMessages."""
    messages = [
        HumanMessage(content="Hello"),
        AIMessage(content="Hi there!", tool_calls=[{"name": "test", "id": "1", "args": {}}]),
        ToolMessage(content="Tool result", tool_call_id="1"),
    ]

    ai_msg, tool_msgs = _fetch_last_ai_and_tool_messages(messages)

    assert ai_msg is not None
    assert isinstance(ai_msg, AIMessage)
    assert ai_msg.content == "Hi there!"
    assert len(tool_msgs) == 1
    assert tool_msgs[0].content == "Tool result"


def test_fetch_last_ai_and_tool_messages_multiple_ai() -> None:
    """Test that the last AIMessage is returned when multiple exist."""
    messages = [
        HumanMessage(content="First question"),
        AIMessage(content="First answer", id="ai1"),
        HumanMessage(content="Second question"),
        AIMessage(content="Second answer", id="ai2"),
    ]

    ai_msg, tool_msgs = _fetch_last_ai_and_tool_messages(messages)

    assert ai_msg is not None
    assert isinstance(ai_msg, AIMessage)
    assert ai_msg.content == "Second answer"
    assert ai_msg.id == "ai2"
    assert len(tool_msgs) == 0


def test_fetch_last_ai_and_tool_messages_no_ai_message() -> None:
    """Test handling when no AIMessage exists in messages.

    This is the edge case that caused issue #34792 - UnboundLocalError
    when using RemoveMessage(id=REMOVE_ALL_MESSAGES) to clear thread messages.
    The function now returns None for the AIMessage, allowing callers to
    handle this edge case explicitly.
    """
    messages = [
        HumanMessage(content="Hello"),
        SystemMessage(content="You are a helpful assistant"),
    ]

    ai_msg, tool_msgs = _fetch_last_ai_and_tool_messages(messages)

    # Should return None when no AIMessage is found
    assert ai_msg is None
    assert len(tool_msgs) == 0


def test_fetch_last_ai_and_tool_messages_empty_list() -> None:
    """Test handling of empty messages list.

    This can occur after RemoveMessage(id=REMOVE_ALL_MESSAGES) clears all messages.
    """
    messages: list = []

    ai_msg, tool_msgs = _fetch_last_ai_and_tool_messages(messages)

    # Should return None when no AIMessage is found
    assert ai_msg is None
    assert len(tool_msgs) == 0


def test_fetch_last_ai_and_tool_messages_only_human_messages() -> None:
    """Test handling when only HumanMessages exist."""
    messages = [
        HumanMessage(content="Hello"),
        HumanMessage(content="Are you there?"),
    ]

    ai_msg, tool_msgs = _fetch_last_ai_and_tool_messages(messages)

    assert ai_msg is None
    assert len(tool_msgs) == 0


def test_fetch_last_ai_and_tool_messages_ai_without_tool_calls() -> None:
    """Test AIMessage without tool_calls returns empty tool messages list."""
    messages = [
        HumanMessage(content="Hello"),
        AIMessage(content="Hi! How can I help you today?"),
    ]

    ai_msg, tool_msgs = _fetch_last_ai_and_tool_messages(messages)

    assert ai_msg is not None
    assert isinstance(ai_msg, AIMessage)
    assert ai_msg.content == "Hi! How can I help you today?"
    assert len(tool_msgs) == 0

Domain

Subdomains

Dependencies

  • langchain.agents.factory
  • langchain_core.messages

Frequently Asked Questions

What does test_fetch_last_ai_and_tool_messages.py do?
test_fetch_last_ai_and_tool_messages.py is a source file in the langchain codebase, written in python. It belongs to the LangChainCore domain, Runnables subdomain.
What functions are defined in test_fetch_last_ai_and_tool_messages.py?
test_fetch_last_ai_and_tool_messages.py defines 6 function(s): test_fetch_last_ai_and_tool_messages_ai_without_tool_calls, test_fetch_last_ai_and_tool_messages_empty_list, test_fetch_last_ai_and_tool_messages_multiple_ai, test_fetch_last_ai_and_tool_messages_no_ai_message, test_fetch_last_ai_and_tool_messages_normal, test_fetch_last_ai_and_tool_messages_only_human_messages.
What does test_fetch_last_ai_and_tool_messages.py depend on?
test_fetch_last_ai_and_tool_messages.py imports 2 module(s): langchain.agents.factory, langchain_core.messages.
Where is test_fetch_last_ai_and_tool_messages.py in the architecture?
test_fetch_last_ai_and_tool_messages.py is located at libs/langchain_v1/tests/unit_tests/agents/test_fetch_last_ai_and_tool_messages.py (domain: LangChainCore, subdomain: Runnables, directory: libs/langchain_v1/tests/unit_tests/agents).

Analyze Your Own Codebase

Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.

Try Supermodel Free