Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions datamind/capabilities/memory/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,20 @@ async def recall(
session_id: str | None = None,
top_k: int = 8,
kinds: Sequence[str] | None = None,
scope_filter: Sequence[str] | None = None,
include_archived: bool = False,
) -> list[dict[str, Any]]:
effective_profile = profile or self._default_profile
effective_session = session_id
if scope_filter:
if 'profile' not in scope_filter:
effective_profile = None
if 'session' not in scope_filter:
effective_session = None
hits = await self.long_term.recall(
query,
profile=profile or self._default_profile,
session_id=session_id,
profile=effective_profile,
session_id=effective_session,
top_k=top_k,
kinds=kinds,
include_archived=include_archived,
Expand Down
1 change: 1 addition & 0 deletions datamind/capabilities/memory/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ async def _recall(
session_id=eff_session,
top_k=top_k,
kinds=kinds,
scope_filter=scope_filter,
)
return {"query": query, "count": len(hits), "results": hits}

Expand Down
30 changes: 30 additions & 0 deletions datamind/tests/test_memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from datamind.capabilities.memory import (
MemoryService,
ShortTermMemory,
build_memory_tools,
)
from datamind.capabilities.memory.providers.sqlite_store import SQLiteMemoryStore
from datamind.core.protocols import MemoryStore
Expand Down Expand Up @@ -276,6 +277,35 @@ async def test_service_combines_short_and_long(tmp_path):
assert await svc.forget(rid)


@pytest.mark.asyncio
async def test_memory_recall_scope_filter_excludes_unselected_scopes(tmp_path):
'''A global-only recall must not reintroduce the default profile.'''
lt = SQLiteMemoryStore(db_path=str(tmp_path / 'm.db'), embedding=_FakeEmbed())
svc = MemoryService(
short_term=ShortTermMemory(max_turns=5),
long_term=lt,
default_profile='acme',
)
tools = {tool.name: tool.handler for tool in build_memory_tools(svc)}

await tools['memory_save']('global fact', scope='global')
await tools['memory_save']('profile fact', scope='profile', profile='acme')
await tools['memory_save'](
'session fact', scope='session', session_id='chat-1'
)

result = await tools['memory_recall'](
'fact',
profile='acme',
session_id='chat-1',
scope_filter=['global'],
)

assert result['count'] == 1
assert result['results'][0]['scope'] == 'global'
assert result['results'][0]['content'] == 'global fact'


@pytest.mark.asyncio
async def test_service_default_profile_used_when_omitted(tmp_path):
"""save without explicit profile should land under default_profile."""
Expand Down