Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,7 @@ def initialize(self, session_id: str, **kwargs: Any) -> None: # type: ignore[ov
MemosBridgeClient(
runtime_home=home,
extra_env=env,
owner_id=f"provider-{id(self)}",
)
),
before_spawn=lambda home=runtime_home: _prepare_shared_bridge(home),
Expand All @@ -526,6 +527,7 @@ def initialize(self, session_id: str, **kwargs: Any) -> None: # type: ignore[ov
new_bridge = MemosBridgeClient(
runtime_home=str(runtime_home),
extra_env=runtime_env,
owner_id=f"provider-{id(self)}",
)
new_bridge.register_host_handler(
"host.llm.complete",
Expand Down Expand Up @@ -2195,6 +2197,7 @@ def _reconnect_bridge(self, session_id: str = "", *, timeout: float = 30.0) -> N
MemosBridgeClient(
runtime_home=home,
extra_env=env,
owner_id=f"provider-{id(self)}",
)
),
before_spawn=lambda home=runtime_home: _prepare_shared_bridge(home),
Expand Down Expand Up @@ -2261,6 +2264,7 @@ def _reconnect_bridge(self, session_id: str = "", *, timeout: float = 30.0) -> N
new_bridge = MemosBridgeClient(
runtime_home=str(runtime_home),
extra_env=runtime_env,
owner_id=f"provider-{id(self)}",
)
logger.info(
"MemOS: new bridge created (pid=%s)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
# This is the Python-side guard against issue #1910 (bridge process leak:
# every turn spawns new bridge.cjs). Defence in depth on the Node side
# lives in ``bridge.cts`` via ``bridge-stdio.pid``.
_ACTIVE_CLIENTS: dict[tuple[str, bool, str], MemosBridgeClient] = {}
_ACTIVE_CLIENTS: dict[tuple[str, bool, str, str], MemosBridgeClient] = {}
_ACTIVE_CLIENTS_LOCK = threading.Lock()


Expand Down Expand Up @@ -150,6 +150,7 @@ def __init__(
no_viewer: bool = True,
extra_env: dict[str, str] | None = None,
runtime_home: str | None = None,
owner_id: str | None = None,
) -> None:
self._lock = threading.Lock()
self._next_id = 1
Expand Down Expand Up @@ -265,6 +266,10 @@ def __init__(
self._singleton_agent = agent
self._singleton_no_viewer = bool(no_viewer)
self._singleton_runtime_home = str(resolved_runtime_home)
# owner-keying: widen the singleton tracker key to (agent, no_viewer, home,
# owner_id) so concurrent provider instances in ONE process (gateway
# email/cron/subagent sessions) do not reap each other's bridges.
self._singleton_owner = owner_id or f"anon-{id(self)}"
previous = self._register_active()
if previous is not None and previous is not self:
prev_pid = getattr(previous, "pid", "?")
Expand All @@ -282,6 +287,7 @@ def _register_active(self) -> MemosBridgeClient | None:
self._singleton_agent,
self._singleton_no_viewer,
self._singleton_runtime_home,
self._singleton_owner,
)
with _ACTIVE_CLIENTS_LOCK:
previous = _ACTIVE_CLIENTS.get(key)
Expand All @@ -294,6 +300,7 @@ def _unregister_active(self) -> None:
self._singleton_agent,
self._singleton_no_viewer,
self._singleton_runtime_home,
self._singleton_owner,
)
with _ACTIVE_CLIENTS_LOCK:
if _ACTIVE_CLIENTS.get(key) is self:
Expand Down
Loading