Skip to content

fix(memos-local-plugin): prevent orphan episode scan from closing active sessions; add episode delete API#1546

Open
Starfie1d1272 wants to merge 6 commits intoMemTensor:mainfrom
Starfie1d1272:main
Open

fix(memos-local-plugin): prevent orphan episode scan from closing active sessions; add episode delete API#1546
Starfie1d1272 wants to merge 6 commits intoMemTensor:mainfrom
Starfie1d1272:main

Conversation

@Starfie1d1272
Copy link
Copy Markdown

Description

This PR introduces two related fixes and feature enhancements for the memos-local-plugin (Hermes adapter) to improve session stability and data management.

1. Orphan Episode Protection (Reliability Fix)

Problem: Previously, the bridge init() process treated all status='open' episodes as orphans upon startup, auto-closing them with the reason "插件上次未正常退出". This caused episodes from active sessions to be prematurely abandoned during bridge restarts, gateway loops, or session switches.

Fix:

  • Updated init() logic to check session.meta.closedAt before closing open episodes.
  • Episodes belonging to sessions that haven't been explicitly closed are now preserved, allowing them to reconnect.
  • Updated closeSession() in the session manager to stamp closedAt via touchLastSeen(), enabling the system to distinguish between a "properly closed session" and a "bridge crash/reconnect" scenario.

2. WebUI Tasks Page Deletion Fix & Bulk Delete

Problem: The "Delete selected" button on the Tasks page was calling closeEpisode(), which is a no-op for already-closed episodes. This resulted in a successful UI confirmation while the data remained in the database.

Fix:

  • Repository Level: Added deleteById() to the episodes SQLite repo (supports cascading trace deletion via Foreign Keys).
  • Core Level: Added deleteEpisode and deleteEpisodes methods to the MemoryCore interface and implementation.
  • API Level: - Changed DELETE /api/v1/episodes route to use deleteEpisode instead of closeEpisode.
    • Added POST /api/v1/episodes/delete for bulk deletion operations.

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)

Files Changed

  • apps/memos-local-plugin/agent-contract/memory-core.ts: Added interface methods.
  • apps/memos-local-plugin/core/pipeline/memory-core.ts: Improved orphan filter & implemented delete logic.
  • apps/memos-local-plugin/core/session/manager.ts: Added closedAt timestamping.
  • apps/memos-local-plugin/core/storage/repos/episodes.ts: Implemented deleteById.
  • apps/memos-local-plugin/server/routes/session.ts: Fixed delete route and added bulk endpoint.

How Has This Been Tested?

Tested on Hermes agent with a live bridge:

  1. Orphan Fix: Created episodes in an active session -> killed bridge -> restarted. Verified all 20+ open episodes survived the init() scan and remained open in SQLite.
  2. Delete Fix: Executed deletion on closed episodes. Verified rows were physically removed from the SQLite database (previously they were ignored).

Checklist

  • I have performed a self-review of my own code.
  • I have commented my code, particularly in complex logic areas (e.g., orphan filtering).
  • I have added tests that prove my fix is effective.
  • I have created related documentation in MemOS-Docs.

…ive sessions; add episode delete API

Two related fixes:

1. Orphan episode protection (2 files):
   - core/pipeline/memory-core.ts: init() now checks session.meta.closedAt
     before treating open episodes as orphans. Episodes from sessions
     that haven't been explicitly closed are no longer abandoned on
     bridge restart.
   - core/session/manager.ts: closeSession() now stamps session.meta.closedAt
     so future init() calls can distinguish 'explicitly closed' from
     'crashed and might reconnect'.

2. WebUI Tasks page bulk delete (3 files):
   - core/storage/repos/episodes.ts: added deleteById() method
   - core/pipeline/memory-core.ts: added deleteEpisode() / deleteEpisodes()
   - agent-contract/memory-core.ts: added interface signatures
   - server/routes/session.ts: DELETE /api/v1/episodes now calls
     deleteEpisode (actually removes the row + cascading traces)
     instead of closeEpisode (no-op on already-closed episodes).
     Added POST /api/v1/episodes/delete for bulk operations.
…rmes session restart

Three fixes for the Hermes bridge adapter:

1. Use tsx runtime instead of node --experimental-strip-types
2. PID file to prevent duplicate bridge processes
3. Bridge lifetime tracking via register_bridge()
…d of hardcoding

Previously the bridge reported '2.0.0-alpha.1' regardless of the
actual package version. Now it reads from package.json at startup.
Copilot AI review requested due to automatic review settings April 27, 2026 05:50
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Improves Hermes memos-local-plugin session stability by refining startup orphan-episode handling, and adds hard-delete support for episodes (including a bulk-delete HTTP endpoint) to fix Tasks page deletions.

Changes:

  • Refine init() orphan-episode scan to only close open episodes when the owning session is explicitly closed (or missing).
  • Add episode hard-delete capabilities end-to-end (repo → core → HTTP routes), including a bulk delete route.
  • Stamp session.meta.closedAt on session close so restarts can distinguish “explicitly closed” vs “may reconnect”.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
apps/memos-local-plugin/server/routes/session.ts Switch single-episode delete to hard-delete and add bulk delete endpoint.
apps/memos-local-plugin/core/storage/repos/episodes.ts Add deleteById() to physically remove episodes (FK cascade expected).
apps/memos-local-plugin/core/session/manager.ts Stamp meta.closedAt on closeSession() to support orphan detection.
apps/memos-local-plugin/core/pipeline/memory-core.ts Update orphan filtering on init; implement deleteEpisode(s) in the core.
apps/memos-local-plugin/bridge.cts Update bridge version sourcing and daemon/stdin lifetime handling.
apps/memos-local-plugin/agent-contract/memory-core.ts Extend MemoryCore contract with deleteEpisode / deleteEpisodes.
apps/memos-local-plugin/adapters/hermes/memos_provider/daemon_manager.py Add PID-file-based singleton bridge management helpers.
apps/memos-local-plugin/adapters/hermes/memos_provider/bridge_client.py Use PID-file singleton management when spawning/closing the bridge.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +335 to +339
const openEpisodes = handle.repos.episodes.list({ status: "open", limit: 500 });
// Only treat an open episode as an orphan if its session has been
// explicitly closed (meta.closedAt is set) or no longer exists.
// Otherwise the session might reconnect — leave it alone.
const orphans = openEpisodes.filter((ep) => {
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new orphan-episode filter changes boot-time behavior in a subtle but reliability-critical way (preserving open episodes when the owning session wasn’t explicitly closed). There are existing MemoryCore tests (e.g. tests/unit/pipeline/memory-core.test.ts); please add coverage for this init-path so regressions don’t reintroduce accidental orphan-closing on restart.

Copilot uses AI. Check for mistakes.
Comment on lines +645 to +648
async function deleteEpisode(episodeId: EpisodeId): Promise<{ deleted: boolean }> {
ensureLive();
return { deleted: handle.repos.episodes.deleteById(episodeId) };
}
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New delete APIs/endpoints (deleteEpisode + bulk delete) are user-facing data-management operations; adding at least a small unit test around the delete behavior (and cascade expectations) would align with the existing MemoryCore test coverage and guard against regressions like the earlier no-op deletion bug.

Copilot uses AI. Check for mistakes.
Comment thread apps/memos-local-plugin/agent-contract/memory-core.ts Outdated
Comment thread apps/memos-local-plugin/core/session/manager.ts Outdated
Comment thread apps/memos-local-plugin/core/pipeline/memory-core.ts
Starfie1d1272 and others added 3 commits April 27, 2026 14:19
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Prevent deleting episodes that are currently open/in-flight,
which could cause FK violations and corrupt in-memory pipeline state.

Co-Authored-By: Copilot <copilot-pull-request-reviewer[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants