Skip to content

fix(session): avoid O(n²) semantic re-processing on memory commit#809

Open
sliverp wants to merge 1 commit intovolcengine:mainfrom
sliverp:fix/incremental-memory-semantic-processing
Open

fix(session): avoid O(n²) semantic re-processing on memory commit#809
sliverp wants to merge 1 commit intovolcengine:mainfrom
sliverp:fix/incremental-memory-semantic-processing

Conversation

@sliverp
Copy link

@sliverp sliverp commented Mar 20, 2026

Problem

When a new memory is extracted via session.commit(), the session unconditionally enqueues a SemanticMsg without any changes information (line 315 of session.py). This causes _process_memory_directory() to re-summarise and re-vectorise every file in the memory directory, regardless of whether it changed.

The cumulative cost grows as O(n²) with memory count:

  • Store 1st memory → process 1 file
  • Store 100th memory → process 100 files
  • Store 500th memory → process 500 files
  • Total = 1 + 2 + ... + n = O(n²)

Real-world impact: ~500 memories consumed hundreds of thousands of embedding tokens per day on Volcengine, with 2000+ rate-limit (429) retries.

Root Cause

Two interacting issues:

  1. session.py:315commit_async() always enqueues a full-directory SemanticMsg even when SessionCompressor._flush_semantic_operations() has already enqueued incremental messages with per-file change sets.

  2. semantic_processor.py:369_process_memory_directory() only attempts to reuse existing summaries from .overview.md when msg.changes is not None. When the fallback path sends a message without changes, every file gets re-summarised.

Fix

  1. session.py: Only enqueue the fallback SemanticMsg when the compressor is absent or extracted 0 memories. When the compressor runs successfully, it already handles incremental semantic processing.

  2. semantic_processor.py: Always try to load existing summaries from .overview.md, regardless of whether msg.changes is set. This ensures even the fallback/redo path can skip unchanged files.

Tests

Added 4 unit tests in tests/unit/session/test_incremental_semantic.py:

  • test_commit_skips_fallback_semantic_when_compressor_flushed — verifies no duplicate SemanticMsg
  • test_commit_enqueues_fallback_semantic_when_no_compressor — verifies fallback still works
  • test_commit_enqueues_fallback_when_compressor_extracts_zero — edge case
  • test_semantic_msg_changes_none_by_default — documents the default

Impact

For a workspace with N memories, this reduces per-commit semantic processing from O(N) file summaries down to O(changed_files), and eliminates the O(N²) cumulative cost growth.

Closes #505
Ref #744

When SessionCompressor successfully extracts memories it already
enqueues incremental SemanticMsg(s) with per-file change sets via
_flush_semantic_operations().  The session.commit_async() fallback was
unconditionally enqueueing a *second* SemanticMsg without any change
info, causing the semantic processor to re-summarise and re-vectorise
every file in the memory directory on every commit.

Cost impact: cumulative token usage grew as O(n²) with memory count —
500 memories produced ~250K embedding tokens/day with 2000+ rate-limit
retries.

Changes:
1. session.py: Only enqueue fallback SemanticMsg when compressor is
   absent or extracted 0 memories.
2. semantic_processor.py: Always try to load existing overview.md
   summaries regardless of whether msg.changes is set, so even
   the fallback path can skip unchanged files.
3. Add 4 unit tests covering both paths.

Closes volcengine#505
Ref volcengine#744
@CLAassistant
Copy link

CLAassistant commented Mar 20, 2026

CLA assistant check
All committers have signed the CLA.

@qin-ctx qin-ctx requested a review from myysy March 20, 2026 06:20
@myysy
Copy link
Collaborator

myysy commented Mar 20, 2026

Thanks for the PR. The final semantic step in commit_async targets the session path, which is different from the memory path flushed by the compressor, so it can’t be removed or skipped. We’ll revisit and adjust the session-path semantic logic later.

@qin-ctx qin-ctx closed this Mar 21, 2026
@github-project-automation github-project-automation bot moved this from Backlog to Done in OpenViking project Mar 21, 2026
@qin-ctx qin-ctx reopened this Mar 21, 2026
@github-actions
Copy link

Failed to generate code suggestions for PR

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

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Memory extraction triggers O(n²) semantic reprocessing — token cost grows quadratically with memory count

4 participants