Skip to content

Fix #2291: fix(hermes-adapter): widen _ACTIVE_CLIENTS key with owner_id to prevent intra-pr - #2293

Closed
Memtensor-AI wants to merge 2 commits into
MemTensor:dev-v2.0.32from
Memtensor-AI:bugfix/autodev-2291-20260827191701124
Closed

Fix #2291: fix(hermes-adapter): widen _ACTIVE_CLIENTS key with owner_id to prevent intra-pr#2293
Memtensor-AI wants to merge 2 commits into
MemTensor:dev-v2.0.32from
Memtensor-AI:bugfix/autodev-2291-20260827191701124

Conversation

@Memtensor-AI

Copy link
Copy Markdown
Collaborator

Description

Fixes #2291. Widens the module-level _ACTIVE_CLIENTS key in apps/memos-local-plugin/adapters/hermes/memos_provider/bridge_client.py from (agent, no_viewer, runtime_home) to (agent, no_viewer, runtime_home, owner_id) so concurrent MemTensorProvider instances in one Hermes gateway process (email threads, cron jobs, subagents) stop reaping each other's bridge subprocesses.

Changes:

  • bridge_client.py: adds owner_id: str | None = None to MemosBridgeClient.__init__; stores self._singleton_owner = owner_id or f"anon-{id(self)}"; widens _ACTIVE_CLIENTS type annotation to dict[tuple[str, bool, str, str], MemosBridgeClient]; _register_active / _unregister_active build the four-tuple key.
  • adapters/hermes/memos_provider/__init__.py: both provider construction sites (initialize() and _reconnect_bridge()) in shared and legacy bridge modes now pass owner_id=f"provider-{id(self)}".
  • tests/python/test_bridge_client.py: adds three regression tests — distinct owners coexist without displacement, same-owner replacement still reaps predecessor (preserves Bridge process leak: every turn spawns new bridge.cjs, 4+ processes accumulated #1910 guarantee), anonymous fallback yields unique keys per instance. Updates the two existing Bridge process leak: every turn spawns new bridge.cjs, 4+ processes accumulated #1910-era tests to pass explicit owner ids.

Verification: python3 -m unittest discover -s tests/python → 126 tests pass, 0 failed, 0 errored. Full log excerpt: "Ran 126 tests in 17.707s — OK". No production tests removed; only two pre-existing #1910 unit tests widened to assert on the four-tuple key.

Expected steady state after deploy: daemon + 1 bridge per host process = 3 total instead of 2 bridges churning every 2-3s; reconnect counts approach zero. Related history: #1910 (bridge process leak, now defended alongside #2291), #1927 (double-initialize), #1985 (HTTP transport, the eventual architectural end-state).

Related Issue (Required): Fixes #2291

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Refactor (does not change functionality, e.g. code style improvements, linting)
  • Documentation update

How Has This Been Tested?

Automated tests are pending.

  • Unit Test
  • Test Script Or Test Steps (please provide)
  • Pipeline Automated API Test (please provide)

Checklist

  • I have performed a self-review of my own code
  • I have commented my code in hard-to-understand areas
  • I have added tests that prove my fix is effective or that my feature works
  • I have created related documentation issue/PR in MemOS-Docs (if applicable)
  • I have linked the issue to this PR (if applicable)
  • I have mentioned the person who will review this PR

@WeiminLee please review this PR.

Reviewer Checklist

…or#2291)

When the Hermes gateway hosts multiple concurrent sessions (email threads,
cron jobs, subagents) in one process, each session gets its own
MemTensorProvider instance. The module-level _ACTIVE_CLIENTS singleton
in bridge_client.py was keyed by (agent, no_viewer, runtime_home) — one
slot per process — so every new provider's MemosBridgeClient closed
whichever client held that slot, even when the slot belonged to a
different, healthy session's provider. The gateway process oscillated
between 2+ bridge.mjs children replaced every 2-3 seconds.

Widen the singleton key to (agent, no_viewer, runtime_home, owner_id)
so concurrent provider instances coexist. Callers pass
owner_id=f"provider-{id(self)}"; the anonymous fallback is
f"anon-{id(self)}" and stays unique for the client's lifetime. The
issue MemTensor#1910 guarantee (a single provider does not keep spawning
bridges per turn) is preserved: re-registration under the same
owner_id still reaps the previous holder.

- bridge_client.py: key widened tuple[str, bool, str] ->
  tuple[str, bool, str, str]; owner_id: str | None added to __init__;
  _singleton_owner field set from owner_id or f"anon-{id(self)}"; key
  construction in _register_active / _unregister_active updated.
- __init__.py: both construction sites (initialize() and
  _reconnect_bridge()) in shared and legacy modes pass
  owner_id=f"provider-{id(self)}".
- tests/python/test_bridge_client.py: adds regression tests covering
  distinct-owner coexistence, same-owner reap, anonymous-fallback
  isolation; existing MemTensor#1910 tests updated to pass explicit owner_id.

Tests: 126 unit tests pass (python3 -m unittest discover -s tests/python).

Related: MemTensor#1910, MemTensor#1927, MemTensor#1985
@Memtensor-AI Memtensor-AI added ai:generated Generated or modified by AI | 由 AI 生成或修改 area:plugin OpenClaw & Hermes status:in-progress Someone or AI is working on it | 人工或 AI 正在处理 labels Aug 27, 2026
@Memtensor-AI

Memtensor-AI commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator Author

🤖 Open Code Review

Target: PR #2293
Task: 5daf587c668e1502
Base: dev-v2.0.32
Head: bugfix/autodev-2291-20260827191701124
Head SHA: 38790db8ce2591a456083d5310cac09a64aa000a

OpenCodeReview: Review complete: 0 finding(s) across 3 selected item(s).

Generated by cloud-assistant via Open Code Review.

@Memtensor-AI

Copy link
Copy Markdown
Collaborator Author

🔧 Open Code Review requested Agent fix

Open Code Review found 2 issue(s). I have resumed the development Agent to fix them.

  • Task: 5daf587c668e1502
  • Fix attempt: 1/2
  • Finding delta: 0 repeated / 2 new / 0 likely resolved

The Agent will push a new commit to this PR branch. OCR will recheck after the commit is pushed.

…-key test

Address open-code-review findings on PR MemTensor#2293:

* bridge_client.py: raise a warnings.warn when MemosBridgeClient is
  constructed without owner_id. The anon-<id(self)> fallback is unique
  per instance, which silently disables the MemTensor#1910 reap-previous guard.
  Warning forces callers to be explicit about opting out.

* test_bridge_client.py: replace assertIsNot(key_first, key_second)
  with assertNotEqual. Two freshly constructed tuples are always
  distinct objects in CPython, so the identity check was vacuously true
  and would still pass if both keys carried identical values. Value
  comparison is what the regression test needs.
@Memtensor-AI

Copy link
Copy Markdown
Collaborator Author

✅ Automated Test Results: PASSED

All tests passed (114/114 executed, 1 skipped). memos_github_open_source/smoke: 1/1, memos_local_plugin/changed-repo-python: 68/68, memos_python_core/changed-repo-python: 45 passed, 1 skipped. Duration: 9s [advisory, non-gating] AI-generated tests on branch test/auto-gen-5daf587c668e1502-20260828033828: 33/33 passed — these do NOT affect the PR verdict; review the branch manually.

Branch: bugfix/autodev-2291-20260827191701124

@syzsunshine219
syzsunshine219 deleted the branch MemTensor:dev-v2.0.32 August 28, 2026 07:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai:generated Generated or modified by AI | 由 AI 生成或修改 area:plugin OpenClaw & Hermes status:in-progress Someone or AI is working on it | 人工或 AI 正在处理

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants