From 32decaedf9e5b77dee17dca0e77744f3e2e00b69 Mon Sep 17 00:00:00 2001 From: Anas Khan <83116240+anxkhn@users.noreply.github.com> Date: Sun, 5 Jul 2026 17:46:10 +0530 Subject: [PATCH 1/2] fix(crewai): align memory storage save with LongTermMemory contract CrewAI's LongTermMemory.save() calls its storage as save(task_description=..., score=..., metadata=..., datetime=...), passing the timestamp as the keyword argument 'datetime' (matching the reference LTMSQLiteStorage.save signature). KagentMemoryStorage named that parameter 'timestamp', so every long-term-memory write on a memory-enabled crew raised TypeError: got an unexpected keyword argument 'datetime'. Rename the parameter to 'datetime' so the signature matches the storage contract, and add a regression test that drives a save through crewai's LongTermMemory with the HTTP client mocked. Signed-off-by: Anas Khan <83116240+anxkhn@users.noreply.github.com> --- .../src/kagent/crewai/_memory.py | 4 +- .../packages/kagent-crewai/tests/conftest.py | 8 +++ .../kagent-crewai/tests/test_memory.py | 54 +++++++++++++++++++ 3 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 python/packages/kagent-crewai/tests/conftest.py create mode 100644 python/packages/kagent-crewai/tests/test_memory.py diff --git a/python/packages/kagent-crewai/src/kagent/crewai/_memory.py b/python/packages/kagent-crewai/src/kagent/crewai/_memory.py index aef7d1628..0b0ce614d 100644 --- a/python/packages/kagent-crewai/src/kagent/crewai/_memory.py +++ b/python/packages/kagent-crewai/src/kagent/crewai/_memory.py @@ -26,7 +26,7 @@ def __init__(self, thread_id: str, user_id: str, base_url: str): self.user_id = user_id self.base_url = base_url - def save(self, task_description: str, metadata: dict, timestamp: str, score: float) -> None: + def save(self, task_description: str, metadata: dict, datetime: str, score: float) -> None: """ Saves a memory item to the Kagent backend. The agent_id is expected to be in the metadata. @@ -39,7 +39,7 @@ def save(self, task_description: str, metadata: dict, timestamp: str, score: flo "task_description": task_description, "score": score, "metadata": metadata, - "datetime": timestamp, + "datetime": datetime, }, ) diff --git a/python/packages/kagent-crewai/tests/conftest.py b/python/packages/kagent-crewai/tests/conftest.py new file mode 100644 index 000000000..f64b22b8d --- /dev/null +++ b/python/packages/kagent-crewai/tests/conftest.py @@ -0,0 +1,8 @@ +import os + +# The kagent.crewai package imports KAgentApp at module load, which constructs a +# KAgentConfig and requires these environment variables to be present. Set safe +# defaults so the package can be imported in unit tests without a running backend. +os.environ.setdefault("KAGENT_URL", "http://localhost:8080") +os.environ.setdefault("KAGENT_NAME", "test-agent") +os.environ.setdefault("KAGENT_NAMESPACE", "default") diff --git a/python/packages/kagent-crewai/tests/test_memory.py b/python/packages/kagent-crewai/tests/test_memory.py new file mode 100644 index 000000000..57db578aa --- /dev/null +++ b/python/packages/kagent-crewai/tests/test_memory.py @@ -0,0 +1,54 @@ +import inspect +from unittest.mock import MagicMock, patch + +from crewai.memory.long_term.long_term_memory import LongTermMemory +from crewai.memory.long_term.long_term_memory_item import LongTermMemoryItem +from crewai.memory.storage.ltm_sqlite_storage import LTMSQLiteStorage + +from kagent.crewai._memory import KagentMemoryStorage + + +def test_save_signature_matches_crewai_storage_contract(): + """KagentMemoryStorage.save must accept the same keyword arguments CrewAI's + LongTermMemory passes to its storage. CrewAI calls storage.save() with + datetime= as a keyword (see LongTermMemory.save), and the reference + LTMSQLiteStorage.save names that parameter 'datetime'.""" + reference_params = list(inspect.signature(LTMSQLiteStorage.save).parameters) + kagent_params = list(inspect.signature(KagentMemoryStorage.save).parameters) + assert kagent_params == reference_params + + +def test_long_term_memory_save_posts_datetime(): + """A memory-enabled CrewAI crew wires KagentMemoryStorage as its + LongTermMemory backend. Saving must not raise and must forward the item's + datetime to the Kagent backend.""" + storage = KagentMemoryStorage( + thread_id="thread-1", + user_id="user-1", + base_url="http://kagent.test", + ) + long_term_memory = LongTermMemory(storage) + item = LongTermMemoryItem( + agent="researcher", + task="summarize the report", + expected_output="a summary", + datetime="2020-01-01T00:00:00", + quality=0.9, + metadata={"quality": 0.9}, + ) + + with patch("kagent.crewai._memory.httpx.Client") as mock_client_cls: + mock_client = MagicMock() + mock_client_cls.return_value.__enter__.return_value = mock_client + mock_response = MagicMock() + mock_response.raise_for_status.return_value = None + mock_client.post.return_value = mock_response + + long_term_memory.save(item) + + mock_client.post.assert_called_once() + _, kwargs = mock_client.post.call_args + memory_data = kwargs["json"]["memory_data"] + assert memory_data["datetime"] == "2020-01-01T00:00:00" + assert memory_data["task_description"] == "summarize the report" + assert memory_data["score"] == 0.9 From e8e674427682b48cb3de12491a8aa7cfb03090bb Mon Sep 17 00:00:00 2001 From: Eitan Yarmush Date: Tue, 14 Jul 2026 08:48:27 -0400 Subject: [PATCH 2/2] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Signed-off-by: Eitan Yarmush --- .../packages/kagent-crewai/tests/conftest.py | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/python/packages/kagent-crewai/tests/conftest.py b/python/packages/kagent-crewai/tests/conftest.py index f64b22b8d..1459449f3 100644 --- a/python/packages/kagent-crewai/tests/conftest.py +++ b/python/packages/kagent-crewai/tests/conftest.py @@ -1,8 +1,30 @@ import os -# The kagent.crewai package imports KAgentApp at module load, which constructs a -# KAgentConfig and requires these environment variables to be present. Set safe -# defaults so the package can be imported in unit tests without a running backend. -os.environ.setdefault("KAGENT_URL", "http://localhost:8080") -os.environ.setdefault("KAGENT_NAME", "test-agent") -os.environ.setdefault("KAGENT_NAMESPACE", "default") +_DEFAULTS = { + "KAGENT_URL": "http://localhost:8080", + "KAGENT_NAME": "test-agent", + "KAGENT_NAMESPACE": "default", +} + +_ORIGINAL_ENV: dict[str, str | None] = {} + + +def pytest_configure(config): + # The kagent.crewai package imports KAgentApp at module load, which constructs a + # KAgentConfig and requires these environment variables to be present. Set safe + # defaults so the package can be imported in unit tests without a running backend. + for key, value in _DEFAULTS.items(): + if key in os.environ: + _ORIGINAL_ENV[key] = os.environ[key] + else: + _ORIGINAL_ENV[key] = None + os.environ[key] = value + + +def pytest_unconfigure(config): + # Restore environment so these defaults don't leak into other test suites. + for key, original in _ORIGINAL_ENV.items(): + if original is None: + os.environ.pop(key, None) + else: + os.environ[key] = original