fix(memory): address Codex PR#33 P1 — cross-user identity + prefetch scoping - #36
fix(memory): address Codex PR#33 P1 — cross-user identity + prefetch scoping#36dizhaky wants to merge 17 commits into
Conversation
sync_turn accepted user_id but _write_filters() always read self._user_id set at provider initialize() time. In shared gateway sessions, User B's turn was synced under User A's Mem0 namespace.
queue_prefetch scoped the gateway request per-user but stored the result in a single _prefetch_result. In shared-thread sessions, User B could consume User A's prefetch context. Now track _prefetch_result_user and discard on mismatch.
Thread user_id from queue_prefetch_all (which already scoped requests) through to prefetch() so providers can validate result ownership.
…R#33 P1 Thread the per-turn user identity to prefetch_all so providers can validate which user's prefetch result to return.
…#33 P1 _init_cached_agent_for_turn only reset timing/API counters. In shared-thread sessions (thread_sessions_per_user=False), a reused AIAgent kept its prior _user_id/_user_name/_chat_id — so User B's turn synced memory under User A's identity. Refresh all caller-identity fields from source after init.
🔎 Lint report:
|
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Prefetch user_id breaks providers
- Added signature inspection in prefetch_all so user_id is only forwarded to providers whose prefetch method accepts it, restoring prefetch for mem0, honcho, and other legacy providers.
Or push these changes by commenting:
@cursor push 9177ca9475
Preview (9177ca9475)
diff --git a/agent/memory_manager.py b/agent/memory_manager.py
--- a/agent/memory_manager.py
+++ b/agent/memory_manager.py
@@ -336,6 +336,18 @@
# -- Prefetch / recall ---------------------------------------------------
+ @staticmethod
+ def _prefetch_accepts_user_id(provider: MemoryProvider) -> bool:
+ """Return True if provider.prefetch accepts a user_id keyword."""
+ try:
+ signature = inspect.signature(provider.prefetch)
+ except (TypeError, ValueError):
+ return False
+ params = signature.parameters
+ if any(p.kind == inspect.Parameter.VAR_KEYWORD for p in params.values()):
+ return True
+ return "user_id" in params
+
def prefetch_all(self, query: str, *, session_id: str = "", user_id: str = "") -> str:
"""Collect prefetch context from all providers.
@@ -345,7 +357,10 @@
parts = []
for provider in self._providers:
try:
- result = provider.prefetch(query, session_id=session_id, user_id=user_id)
+ prefetch_kwargs = {"session_id": session_id}
+ if self._prefetch_accepts_user_id(provider):
+ prefetch_kwargs["user_id"] = user_id
+ result = provider.prefetch(query, **prefetch_kwargs)
if result and result.strip():
parts.append(result)
except Exception as e:You can send follow-ups to the cloud agent here.
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 792dc62. Configure here.
Codex Review Follow-up AnalysisReviewing the active bot findings on this PR: 🔴 cursor[bot] bug (High) + Codex P2 re-raised:
|
Fix applied:
|
ty fix: add
|
Claude triage — cursor[bot] concern + Codex P1 statusPR #36 is open and addressing 3 P1 Codex findings from PR #33 (cross-user memory scoping in shared gateway sessions). cursor[bot] flag: Assessment: This is real. The P2 compatibility comment from Codex on PR #33 (preserve external provider interface) aligns with this. Options:
Remaining P1 items from Codex PR #33 not yet verified as fixed in this PR:
Recommend resolving the cursor[bot] TypeError before merging. Generated by Claude Code |
Codex P2 status update (automated triage — 2026-06-28)All 15 Codex P2 findings from PR #37 ( PR #38 (fix(email): add <hr> to HTML body detection) covers the last outstanding item. Summary of what was in each finding and its resolution
Codex usage limits
Generated by Claude Code |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Pull request was closed


Summary
Follow-up to Codex PR #33 review — implements 3 P1 findings that were left unresolved when PR #33 was merged.
Previous attempt: Claude Code posted patches in a PR #33 comment on 2026-06-27 but couldn't push due to egress policy. This PR applies those patches.
P1 — Cached agent identity not refreshed on gateway reuse (
gateway/run.py)_init_cached_agent_for_turnonly reset_last_activity_tsand_api_call_count. In shared-thread sessions wherethread_sessions_per_user=False, a reusedAIAgentretained its prior_user_id,_user_name,_chat_id, etc. User B's turn was therefore synced to memory under User A's identity.Fix: After
_init_cached_agent_for_turn, overwrite all caller-identity fields from the currentsourceobject.P1 — Prefetch result not scoped by user (
plugins/memory/memgw/__init__.py+agent/memory_manager.py+agent/conversation_loop.py)queue_prefetchcorrectly scoped the gateway request per-user via_user_scope(user_id), but stored the result in a single_prefetch_resultwith no ownership tracking.prefetch()returned that result to whoever called next — potentially a different user in shared-thread sessions.Fix:
_prefetch_result_userfield to track ownership alongside_prefetch_resultprefetch()acceptsuser_id=''and discards stale results when user mismatchesmemory_manager.prefetch_all()accepts and threadsuser_idto providersconversation_loop.pypassesagent._user_idtoprefetch_all()P1 — Mem0 sync_turn ignores per-turn
user_id(plugins/memory/mem0/__init__.py)sync_turnaccepteduser_idas a keyword argument but the inner_sync()closure calledclient.add(messages, **self._write_filters())which always readsself._user_idset atinitialize()time. In shared gateway sessions, every turn was written to the first user's Mem0 namespace.Fix: Capture
effective_user_id = user_id or self._user_idin the outer scope and pass it directly toclient.add().Files changed
gateway/run.py_init_cached_agent_for_turnplugins/memory/memgw/__init__.py_prefetch_result_user; scopeprefetch()by user; store user in_run()plugins/memory/mem0/__init__.pyeffective_user_id = user_id or self._user_idinsync_turnagent/memory_manager.pyuser_idtoprefetch_all()signatureagent/conversation_loop.pyagent._user_idtoprefetch_all()Test plan
pytest tests/ -k memory -v🤖 Generated with Claude Code
Generated by Claude Code
Note
Medium Risk
Touches gateway session identity and memory read/write paths where wrong user scoping could leak or corrupt stored context; changes are narrow and defensive.
Overview
Fixes cross-user memory identity leaks when the gateway reuses a cached
AIAgentin shared-thread sessions (thread_sessions_per_user=False).On cache hit,
gateway/run.pynow overwrites caller identity on the agent (_user_id,_user_name, chat/thread fields) from the currentsourceafter_init_cached_agent_for_turn, so a later user’s turn is not attributed to the first user.Memory prefetch is threaded with
user_id:memory_manager.prefetch_all()forwards it to providers;conversation_loop.pypassesagent._user_id. The memgw provider tracks_prefetch_result_userwith the cached prefetch blob and discards the result whenprefetch()is called for a different user; ownership is cleared on session switch.Mem0
sync_turnnow useseffective_user_id = user_id or self._user_idand passes it toclient.add()instead of relying only on init-timeself._user_idvia_write_filters().Reviewed by Cursor Bugbot for commit 792dc62. Configure here.