Skip to content

fix(reorganizer): optimize all graph tenants, run scheduled jobs, and survive non-JSON LLM output - #2481

Open
akushonkamen wants to merge 1 commit into
MemTensor:mainfrom
akushonkamen:fix/2480-reorganizer-multitenant
Open

akushonkamen wants to merge 1 commit into
MemTensor:mainfrom
akushonkamen:fix/2480-reorganizer-multitenant

Conversation

@akushonkamen

Copy link
Copy Markdown

Description

GraphStructureReorganizer had three defects on main @ a7367d0:

  1. Single-tenant blind spot — both the _reorganize_needed trigger and the scheduled jobs call optimize_structure(scope=...) without user_name, and the graph backends fall back to self.config.user_name, so only the default tenant (memosdefault) is ever optimized. Tenants written per-request via the REST API never receive PARENT/INFERS/FOLLOWS structure edges.
  2. Dead schedule — the schedule.every(100).seconds jobs are registered, but the loop never calls schedule.run_pending(), so periodic reorganization is dead code.
  3. Crash / silent corruption on non-JSON LLM output — extract_first_to_last_brace returns None for text without braces and _parse_json_result only catches JSONDecodeError (returning {} on that path), so None/non-dict values flow into response_json.get(...): an AttributeError kills the whole optimization round, and the {} path silently creates empty parent nodes via embed("").

Fix:

  • New get_all_user_names() — implemented on Neo4jGraphDB, with a fallback default on BaseGraphDB; postgres/polardb behavior is unchanged.
  • New _optimize_all_users(scope) enumerates the tenants actually present in the graph and runs the optimizer per tenant with per-tenant failure isolation; both the trigger and the scheduled jobs are routed through it. Backends without the new capability keep today's single-tenant behavior.
  • The loop now calls schedule.run_pending() so the registered jobs actually run.
  • _parse_json_result returns None for anything that is not a valid JSON object; _summarize_cluster / _local_subcluster short-circuit on None, so a malformed LLM reply skips one cluster instead of crashing the round or writing empty parents.

Related Issue (Required): Fixes #2480

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)

How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration

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

New tests: tests/memories/test_reorganizer.py (trigger routing, schedule execution, _parse_json_result behavior) and tests/graph_dbs/test_get_all_user_names.py (Neo4j implementation + BaseGraphDB fallback). Local venv, Python 3.12, repo @ 47a6f23.

  • Red (before fix, new tests included): pytest tests/memories/test_reorganizer.py tests/graph_dbs/test_get_all_user_names.py -q → 17 failed, 6 passed — every defect case red.
  • Green (after fix): same command → 25 passed.
  • Regression: timeout 120 python -m pytest tests/graph_dbs -q → 35 passed, 3 skipped (baseline 31 passed + 3 skipped + 4 new).
  • Regression: timeout 300 python -m pytest tests/memories -q --ignore=tests/memories/activation/test_kv.py → 87 passed, 3 failed. The 3 failures are all in tests/memories/activation/test_item.py::TestKVCacheItem and reproduce identically with the fix stashed (baseline re-run: same 3 failed / 3 passed) — pre-existing and unrelated to this change. test_kv.py requires torch and fails collection on the baseline as well (pre-existing environment gap), hence the --ignore.
  • Static: grep -c run_pending src/memos/memories/textual/tree_text_memory/organize/reorganizer.py → 0 before, 1 after.
  • ruff check / ruff format: both test files fully pass; on src/ the fix adds 2 new BLE001 findings (blind except Exception), consistent with the pre-existing style in the same file; the pre-existing pagination block that ruff --fix would rewrite was left untouched.

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) | 我已在 MemOS-Docs 中创建了相关的文档 issue/PR(如果适用)
  • I have linked the issue to this PR (if applicable) | 我已将 issue 链接到此 PR(如果适用)
  • I have mentioned the person who will review this PR | 我已提及将审查此 PR 的人

Reviewer Checklist

Transparency note: this fix and its tests were prepared with AI coding assistance (also disclosed in the issue claim comment).

… survive non-JSON LLM output

- enumerate tenants via new get_all_user_names() (Neo4jGraphDB impl +
  BaseGraphDB fallback) and route both the _reorganize_needed trigger and
  the schedule jobs through _optimize_all_users(scope), isolating
  per-tenant failures; backends without the capability keep the previous
  single-tenant behavior
- call schedule.run_pending() in the structure optimizer loop so the
  registered 100s jobs actually run instead of being dead code
- make _parse_json_result return None for anything that is not a valid
  JSON object and short-circuit _summarize_cluster/_local_subcluster, so
  a malformed LLM reply skips the cluster instead of crashing the whole
  optimization round or silently writing empty parent nodes

Fixes MemTensor#2480
@Memtensor-AI Memtensor-AI added area:database graph_db + vector_db | 图数据库与向量数据库 area:memory 记忆存储、检索、更新、召回逻辑 status:in-progress Someone or AI is working on it | 人工或 AI 正在处理 labels Oct 11, 2026
@Memtensor-AI

Copy link
Copy Markdown
Collaborator

🤖 Open Code Review

Target: PR #2481
Task: 591c0052b6b55317
Base: main
Head: fix/2480-reorganizer-multitenant

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

Generated by cloud-assistant via Open Code Review.

@Memtensor-AI

Copy link
Copy Markdown
Collaborator

⚠️ Automated Test Results: ENV ISSUE

The test environment encountered an issue that requires manual attention.

Details: Both failures are ModuleNotFoundError for the third-party 'schedule' package, raised when the new tests trigger the reorganizer's background loop. The production code under test already imports 'schedule', so the dependency is simply not installed in the test environment.
Branch: fix/2480-reorganizer-multitenant

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:database graph_db + vector_db | 图数据库与向量数据库 area:memory 记忆存储、检索、更新、召回逻辑 status:in-progress Someone or AI is working on it | 人工或 AI 正在处理

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: GraphStructureReorganizer only optimizes the default cube tenant; periodic schedule never runs; cluster summary crashes on non-JSON LLM output

3 participants