diff --git a/backend/packages/harness/deerflow/runtime/events/store/db.py b/backend/packages/harness/deerflow/runtime/events/store/db.py index 6d55f2b84d..cc46014160 100644 --- a/backend/packages/harness/deerflow/runtime/events/store/db.py +++ b/backend/packages/harness/deerflow/runtime/events/store/db.py @@ -424,7 +424,7 @@ class DbRunEventStore(RunEventStore): stmt = select(RunEventRow).where(RunEventRow.thread_id == thread_id, RunEventRow.run_id == run_id) if resolved_user_id is not None: stmt = stmt.where(RunEventRow.user_id == resolved_user_id) - if event_types: + if event_types is not None: stmt = stmt.where(RunEventRow.event_type.in_(event_types)) if task_id is not None: # Filter on metadata["task_id"] in SQL (before LIMIT) so cursor diff --git a/backend/tests/test_db_run_event_empty_filter.py b/backend/tests/test_db_run_event_empty_filter.py new file mode 100644 index 0000000000..ece87ee68c --- /dev/null +++ b/backend/tests/test_db_run_event_empty_filter.py @@ -0,0 +1,49 @@ +"""Regression tests for explicit empty event-type filters across backends.""" + +import pytest + +from deerflow.persistence.engine import close_engine, get_session_factory, init_engine +from deerflow.runtime.events.store.db import DbRunEventStore +from deerflow.runtime.events.store.jsonl import JsonlRunEventStore +from deerflow.runtime.events.store.memory import MemoryRunEventStore + + +@pytest.mark.anyio +@pytest.mark.parametrize("backend", ["memory", "jsonl", "db"]) +async def test_empty_event_types_is_an_empty_filter_across_backends(tmp_path, backend): + if backend == "db": + await init_engine( + "sqlite", + url=f"sqlite+aiosqlite:///{tmp_path / 'run-events.db'}", + sqlite_dir=str(tmp_path), + ) + event_store = DbRunEventStore(get_session_factory()) + elif backend == "jsonl": + event_store = JsonlRunEventStore(base_dir=tmp_path / "jsonl") + else: + event_store = MemoryRunEventStore() + + try: + await event_store.put( + thread_id="t1", + run_id="r1", + event_type="llm_end", + category="trace", + ) + await event_store.put( + thread_id="t1", + run_id="r1", + event_type="tool_start", + category="trace", + ) + + unfiltered = await event_store.list_events("t1", "r1", event_types=None) + assert [event["event_type"] for event in unfiltered] == ["llm_end", "tool_start"] + + filtered = await event_store.list_events("t1", "r1", event_types=["llm_end"]) + assert [event["event_type"] for event in filtered] == ["llm_end"] + + assert await event_store.list_events("t1", "r1", event_types=[]) == [] + finally: + if backend == "db": + await close_engine()