Skip to content

Commit e0b20c6

Browse files
authored
fix(bundles): tombstone the broken legacy ZepChatMemory build method (#13580)
build_message_history targeted the zep-python v1 SDK (ZepClient + zep_python.langchain.ZepChatMessageHistory); both were removed in zep-python 2.x and the zep extra pins 2.0.2, so the method has been unable to run for as long as the pin has existed -- its ImportError guard misleadingly told users to 'pip install zep-python' (already installed). The component is legacy=True with helpers.Memory as its designated replacement, so rather than hand-write a new integration against the 2.x SDK, the method now raises a clear RuntimeError pointing at the Message History component. Flow identity is preserved: class/component name, display_name, description, inputs and the memory output are byte-identical, so saved flows keep loading, i18n locale keys are unchanged, and migration_table.json needs no edits. New bundle tests pin the stub contract (identity, actionable error, no zep_python import).
1 parent fc35f85 commit e0b20c6

2 files changed

Lines changed: 105 additions & 16 deletions

File tree

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,37 @@
1+
"""Non-functional compatibility stub for the legacy Zep Chat Memory component.
2+
3+
The original implementation targeted the zep-python v1 SDK (``ZepClient`` plus
4+
``zep_python.langchain.ZepChatMessageHistory``). zep-python 2.x removed both
5+
symbols, and the bundle's ``zep`` extra pins ``zep-python==2.0.2``, so
6+
``build_message_history`` could never succeed on a supported install -- it
7+
always hit its ImportError guard, which misleadingly told users to
8+
``pip install zep-python`` (already installed, just incompatible).
9+
10+
The component is deprecated (``legacy=True``, replaced by the Message History
11+
component, ``helpers.Memory``). Rather than delete it outright -- which would
12+
break saved flows that still reference it -- it is kept as a stub: existing
13+
flows continue to load, and building the node now raises a clear error
14+
pointing at the replacement instead of the misleading install hint.
15+
"""
16+
117
from lfx.base.memory.model import LCChatMemoryComponent
218
from lfx.field_typing.constants import Memory
319
from lfx.inputs.inputs import DropdownInput, MessageTextInput, SecretStrInput
420

21+
DISABLED_MESSAGE = (
22+
"The legacy 'Zep Chat Memory' component no longer functions: it was built on the "
23+
"zep-python v1 API, which no longer exists in the zep-python 2.x release that "
24+
"Langflow installs. Replace this node with the 'Message History' component (its "
25+
"designated replacement) or another memory integration."
26+
)
27+
528

629
class ZepChatMemory(LCChatMemoryComponent):
730
display_name = "Zep Chat Memory"
31+
# NOTE: display_name/description/input strings are intentionally kept identical to the
32+
# pre-stub component so flow identity and the i18n locale keys (locales/*.json) do not
33+
# change. The deprecation is signalled via legacy=True, the replacement below, and the
34+
# runtime error raised by build_message_history.
835
description = "Retrieves and store chat messages from Zep."
936
name = "ZepChatMemory"
1037
icon = "ZepMemory"
@@ -27,19 +54,5 @@ class ZepChatMemory(LCChatMemoryComponent):
2754
]
2855

2956
def build_message_history(self) -> Memory:
30-
try:
31-
# Monkeypatch API_BASE_PATH to
32-
# avoid 404
33-
# This is a workaround for the local Zep instance
34-
# cloud Zep works with v2
35-
import zep_python.zep_client
36-
from zep_python import ZepClient
37-
from zep_python.langchain import ZepChatMessageHistory
38-
39-
zep_python.zep_client.API_BASE_PATH = self.api_base_path
40-
except ImportError as e:
41-
msg = "Could not import zep-python package. Please install it with `pip install zep-python`."
42-
raise ImportError(msg) from e
43-
44-
zep_client = ZepClient(api_url=self.url, api_key=self.api_key)
45-
return ZepChatMessageHistory(session_id=self.session_id, zep_client=zep_client)
57+
"""Always raise: the zep-python v1 API this component was built on is gone."""
58+
raise RuntimeError(DISABLED_MESSAGE)
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
"""Unit tests for the tombstoned Zep Chat Memory component (``lfx-bundles``).
2+
3+
``ZepChatMemory`` is legacy (replaced by the Message History component) and its
4+
implementation targeted the zep-python v1 SDK; the pinned ``zep-python==2.0.2``
5+
removed that API, so ``build_message_history`` could never succeed. The
6+
component is now a non-functional stub. These tests pin the stub contract:
7+
8+
* flow identity (component name, display_name, inputs, output wiring) is
9+
unchanged, so saved flows keep loading and i18n locale keys are unaffected;
10+
* ``build_message_history`` fails with a clear, actionable error -- not the old
11+
misleading ``pip install zep-python`` ImportError hint;
12+
* the stub never imports ``zep_python``, so the failure mode does not depend on
13+
which zep-python version happens to be installed.
14+
"""
15+
16+
import ast
17+
import inspect
18+
19+
import pytest
20+
from lfx_bundles.zep import ZepChatMemory
21+
from lfx_bundles.zep import zep as zep_module
22+
23+
24+
@pytest.fixture
25+
def component():
26+
return ZepChatMemory(
27+
url="http://localhost:8000",
28+
api_key="test-api-key", # pragma: allowlist secret
29+
api_base_path="api/v1",
30+
session_id="test-session",
31+
_session_id="test-run-session",
32+
)
33+
34+
35+
def test_flow_identity_is_preserved(component):
36+
# The component name is a flow-identity contract: saved flows reference it and
37+
# migration_table.json maps it. The deprecation metadata must survive the stub.
38+
assert ZepChatMemory.name == "ZepChatMemory"
39+
assert ZepChatMemory.legacy is True
40+
assert ZepChatMemory.replacement == ["helpers.Memory"]
41+
assert ZepChatMemory.display_name == "Zep Chat Memory"
42+
43+
frontend_node = component.to_frontend_node()
44+
template = frontend_node["data"]["node"]["template"]
45+
for field in ("url", "api_key", "api_base_path", "session_id"):
46+
assert field in template
47+
assert template["url"]["value"] == "http://localhost:8000"
48+
49+
# Same single Memory output, wired to the same method name.
50+
assert [(output.name, output.method) for output in component.outputs] == [
51+
("memory", "build_message_history"),
52+
]
53+
54+
55+
def test_build_raises_actionable_error_not_install_hint(component):
56+
with pytest.raises(RuntimeError, match="no longer functions") as exc_info:
57+
component.build_message_history()
58+
59+
error_text = str(exc_info.value)
60+
# Points at the designated replacement...
61+
assert "Message History" in error_text
62+
# ...and is not the old misleading missing-dependency path.
63+
assert not isinstance(exc_info.value, ImportError)
64+
assert "pip install" not in error_text
65+
66+
67+
def test_stub_does_not_import_zep_python():
68+
tree = ast.parse(inspect.getsource(zep_module))
69+
imported = set()
70+
for node in ast.walk(tree):
71+
if isinstance(node, ast.Import):
72+
imported.update(alias.name for alias in node.names)
73+
elif isinstance(node, ast.ImportFrom) and node.module:
74+
imported.add(node.module)
75+
zep_imports = {name for name in imported if name == "zep_python" or name.startswith("zep_python.")}
76+
assert not zep_imports

0 commit comments

Comments
 (0)