From 427d2d6397c7263a9ed5e40c610f468f6c563f1a Mon Sep 17 00:00:00 2001 From: Gurram Siddarth Reddy <73605274+siddarthreddygsr@users.noreply.github.com> Date: Sat, 19 Jul 2025 01:24:28 +0530 Subject: [PATCH 1/2] fix(core): implement sleep delay in FakeMessagesListChatModel `_generate` (#32014) implement sleep delay in FakeMessagesListChatModel._generate so the sleep parameter is respected, matching the documented behavior. This adds artificial latency between responses for testing purposes. Issue: closes [#31974](https://github.com/langchain-ai/langchain/issues/31974) following [docs](https://python.langchain.com/api_reference/core/language_models/langchain_core.language_models.fake_chat_models.FakeMessagesListChatModel.html#langchain_core.language_models.fake_chat_models.FakeMessagesListChatModel.sleep) Dependencies: none Twitter handle: [@siddarthreddyg2](https://x.com/siddarthreddyg2) --------- Signed-off-by: Siddarthreddygsr --- .../language_models/fake_chat_models.py | 2 ++ .../unit_tests/fake/test_fake_chat_model.py | 19 ++++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/libs/core/langchain_core/language_models/fake_chat_models.py b/libs/core/langchain_core/language_models/fake_chat_models.py index a1cdd49a7b3..b8dd7325242 100644 --- a/libs/core/langchain_core/language_models/fake_chat_models.py +++ b/libs/core/langchain_core/language_models/fake_chat_models.py @@ -36,6 +36,8 @@ class FakeMessagesListChatModel(BaseChatModel): run_manager: Optional[CallbackManagerForLLMRun] = None, **kwargs: Any, ) -> ChatResult: + if self.sleep is not None: + time.sleep(self.sleep) response = self.responses[self.i] if self.i < len(self.responses) - 1: self.i += 1 diff --git a/libs/core/tests/unit_tests/fake/test_fake_chat_model.py b/libs/core/tests/unit_tests/fake/test_fake_chat_model.py index 7500e1640ac..ce262797535 100644 --- a/libs/core/tests/unit_tests/fake/test_fake_chat_model.py +++ b/libs/core/tests/unit_tests/fake/test_fake_chat_model.py @@ -1,5 +1,6 @@ """Tests for verifying that testing utility code works as expected.""" +import time from itertools import cycle from typing import Any, Optional, Union from uuid import UUID @@ -9,10 +10,11 @@ from typing_extensions import override from langchain_core.callbacks.base import AsyncCallbackHandler from langchain_core.language_models import ( FakeListChatModel, + FakeMessagesListChatModel, GenericFakeChatModel, ParrotFakeChatModel, ) -from langchain_core.messages import AIMessage, AIMessageChunk, BaseMessage +from langchain_core.messages import AIMessage, AIMessageChunk, BaseMessage, HumanMessage from langchain_core.outputs import ChatGenerationChunk, GenerationChunk from tests.unit_tests.stubs import ( _any_id_ai_message, @@ -230,3 +232,18 @@ def test_fake_list_chat_model_batch() -> None: fake = FakeListChatModel(responses=["a", "b", "c"]) resp = fake.batch(["1", "2", "3"]) assert resp == expected + + +def test_fake_messages_list_chat_model_sleep_delay() -> None: + sleep_time = 0.1 + model = FakeMessagesListChatModel( + responses=[AIMessage(content="A"), AIMessage(content="B")], + sleep=sleep_time, + ) + messages = [HumanMessage(content="C")] + + start = time.time() + model.invoke(messages) + elapsed = time.time() - start + + assert elapsed >= sleep_time From 98bfd57a76233efddec46394015d2791e2f4dbed Mon Sep 17 00:00:00 2001 From: Isaac Francisco <78627776+isahers1@users.noreply.github.com> Date: Fri, 18 Jul 2025 14:00:02 -0700 Subject: [PATCH 2/2] fix(core): better error message for empty var names (#32073) Previously, we hit an index out of range error with empty variable names (accessing tag[0]), now we through a slightly nicer error --------- Co-authored-by: Mason Daugherty --- libs/core/langchain_core/utils/mustache.py | 5 +++++ libs/core/tests/unit_tests/prompts/test_structured.py | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/libs/core/langchain_core/utils/mustache.py b/libs/core/langchain_core/utils/mustache.py index be0739568c2..12cab8da0a3 100644 --- a/libs/core/langchain_core/utils/mustache.py +++ b/libs/core/langchain_core/utils/mustache.py @@ -150,6 +150,11 @@ def parse_tag(template: str, l_del: str, r_del: str) -> tuple[tuple[str, str], s msg = f"unclosed tag at line {_CURRENT_LINE}" raise ChevronError(msg) from e + # Check for empty tags + if not tag.strip(): + msg = f"empty tag at line {_CURRENT_LINE}" + raise ChevronError(msg) + # Find the type meaning of the first character tag_type = tag_types.get(tag[0], "variable") diff --git a/libs/core/tests/unit_tests/prompts/test_structured.py b/libs/core/tests/unit_tests/prompts/test_structured.py index 0b74b37cc6f..fda2d00b367 100644 --- a/libs/core/tests/unit_tests/prompts/test_structured.py +++ b/libs/core/tests/unit_tests/prompts/test_structured.py @@ -2,6 +2,7 @@ from functools import partial from inspect import isclass from typing import Any, Union, cast +import pytest from pydantic import BaseModel from langchain_core.language_models import FakeListChatModel @@ -10,6 +11,7 @@ from langchain_core.load.load import loads from langchain_core.messages import HumanMessage from langchain_core.prompts.structured import StructuredPrompt from langchain_core.runnables.base import Runnable, RunnableLambda +from langchain_core.utils.mustache import ChevronError from langchain_core.utils.pydantic import is_basemodel_subclass @@ -128,3 +130,8 @@ def test_structured_prompt_template_format() -> None: assert prompt.invoke({"person": {"name": "foo"}}).to_messages() == [ HumanMessage("hi foo") ] + + +def test_structured_prompt_template_empty_vars() -> None: + with pytest.raises(ChevronError, match="empty tag"): + StructuredPrompt([("human", "hi {{}}")], schema={}, template_format="mustache")