Skip to content

feat(memory): add lifecycle inspector and archive preview - #1858

Merged
zerob13 merged 4 commits into
devfrom
feat/agent-memory-lifecycle-view
Jul 1, 2026
Merged

feat(memory): add lifecycle inspector and archive preview#1858
zerob13 merged 4 commits into
devfrom
feat/agent-memory-lifecycle-view

Conversation

@yyhhyyyyyy

@yyhhyyyyyy yyhhyyyyyy commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator
  • Add per-memory lifecycle inspection showing recall diagnostics, decay state, materialized decay comparison, and archive eligibility.
  • Add memory.getLifecycle(agentId, memoryId) as a single-memory lifecycle route with memoryId required.
  • Add bounded archive candidate preview via memory.getArchiveCandidateLifecyclePreview.
  • Limit archive preview work to scanLimit=200 scanned rows and previewLimit=25 rendered lifecycles.
  • Use narrow lifecycle projection queries instead of full-row/content reads.
  • Lazy-load lifecycle details only when a memory row is expanded.
  • Lazy-load archive preview only when the Health tab is opened.
  • Split preview limit messaging between scan cap and display cap.
  • Add localized lifecycle/health strings across all locales.

Summary by CodeRabbit

  • New Features
    • Added memory lifecycle inspection for individual memories, including recall, forgetting, and archive eligibility details.
    • Added an archive-candidate preview view to help predict which memories are nearing archiving.
    • Expanded the memory health UI with a new archive prediction card and detailed lifecycle diagnostics, including tiered styling.
  • Bug Fixes
    • Improved handling for non-manageable or non-supported agents by returning empty lifecycle/preview data.
    • Added stronger lifecycle/preview loading, retry, and refresh behavior to keep UI state consistent and prevent stale updates.

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ca25ab9b-5ba5-4cd9-8700-d0c57959fd29

📥 Commits

Reviewing files that changed from the base of the PR and between 6ccd4a3 and 1e47565.

📒 Files selected for processing (12)
  • src/main/presenter/memoryPresenter/index.ts
  • src/main/presenter/memoryPresenter/lifecycle.ts
  • src/renderer/settings/components/MemoryHealthSection.vue
  • src/shared/contracts/routes/memory.routes.ts
  • test/main/presenter/agentMemoryTable.test.ts
  • test/main/presenter/memoryLifecycle.test.ts
  • test/main/routes/dispatcher.test.ts
  • test/main/routes/memoryDto.test.ts
  • test/renderer/api/clients.test.ts
  • test/renderer/components/MemoryHealthSection.test.ts
  • test/renderer/components/MemoryLifecyclePanel.test.ts
  • test/renderer/components/MemoryManagerDialog.test.ts
🚧 Files skipped from review as they are similar to previous changes (12)
  • test/main/routes/dispatcher.test.ts
  • src/renderer/settings/components/MemoryHealthSection.vue
  • test/main/presenter/agentMemoryTable.test.ts
  • test/main/routes/memoryDto.test.ts
  • test/renderer/api/clients.test.ts
  • src/shared/contracts/routes/memory.routes.ts
  • test/renderer/components/MemoryLifecyclePanel.test.ts
  • test/renderer/components/MemoryHealthSection.test.ts
  • test/main/presenter/memoryLifecycle.test.ts
  • src/main/presenter/memoryPresenter/lifecycle.ts
  • test/renderer/components/MemoryManagerDialog.test.ts
  • src/main/presenter/memoryPresenter/index.ts

📝 Walkthrough

Walkthrough

Adds lifecycle derivation for memory rows, archive-candidate preview APIs, renderer UI for lifecycle inspection, locale strings, and tests covering the new data flow.

Changes

Memory Lifecycle Feature

Layer / File(s) Summary
Lifecycle contracts and storage
src/main/presenter/memoryPresenter/lifecycleConstants.ts, src/shared/contracts/routes/memory.routes.ts, src/main/presenter/memoryPresenter/types.ts, src/main/presenter/sqlitePresenter/tables/agentMemory.ts, src/main/presenter/memoryPresenter/scoring.ts
Adds lifecycle constants, repository and row types, lifecycle schemas, preview limits, and the archive-candidate SQL query; clamp01 is exported.
Presenter, routes, and client wiring
src/main/presenter/memoryPresenter/index.ts, src/shared/contracts/routes.ts, src/main/routes/index.ts, src/renderer/api/MemoryClient.ts
Adds lifecycle derivation methods, registers the new IPC routes, and exposes matching renderer client calls.
Renderer lifecycle UI
src/renderer/settings/components/MemoryLifecyclePanel.vue, src/renderer/settings/components/MemoryHealthSection.vue, src/renderer/settings/components/MemoryManagerPanel.vue
Adds lifecycle inspection panels, archive-prediction rendering, and per-memory lifecycle state management in the renderer.
Locale strings
src/renderer/src/i18n/*/settings.json
Adds archivePrediction and lifecycle translation keys across supported locales.
Backend tests
test/main/presenter/fakes/memoryFakes.ts, test/main/presenter/agentMemoryTable.test.ts, test/main/presenter/memoryLifecycle.test.ts, test/main/routes/dispatcher.test.ts, test/main/routes/memoryDto.test.ts
Adds backend coverage for repository filtering, lifecycle derivation, presenter behavior, route dispatch, and DTO contract validation.
Renderer tests
test/renderer/api/clients.test.ts, test/renderer/components/MemoryHealthSection.test.ts, test/renderer/components/MemoryLifecyclePanel.test.ts, test/renderer/components/MemoryManagerDialog.test.ts
Adds renderer coverage for the memory client, health section, lifecycle panel, and manager dialog interactions.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

Suggested reviewers: zerob13

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main feature additions: lifecycle inspection and archive preview for memory.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/agent-memory-lifecycle-view

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (2)
src/shared/contracts/routes/memory.routes.ts (2)

316-320: 🗄️ Data Integrity & Integration | 🔵 Trivial | 🏗️ Heavy lift

Use a singular payload for the single-memory route.

memoryId identifies one row, but this contract exposes lifecycles: MemoryLifecycle[]. That weakens the new API boundary by allowing accidental duplicates to validate and forces callers to treat a single-resource lookup as a collection. A { lifecycle: MemoryLifecycleSchema.nullable() } shape would better match the route semantics before this API hardens across layers.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/shared/contracts/routes/memory.routes.ts` around lines 316 - 320, The
memory.getLifecycle contract currently returns a collection-shaped payload even
though it targets a single memoryId. Update memoryGetLifecycleRoute in the route
contract to expose a singular lifecycle field, ideally nullable, instead of
lifecycles: MemoryLifecycle[], and make sure any schema consumers or validators
referenced by memoryGetLifecycleRoute are aligned with that single-resource
shape.

208-227: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Enforce the “archive candidate” invariant in the preview schema.

MemoryArchiveCandidateLifecyclePreviewSchema currently accepts any MemoryLifecycle, including rows where archiveEligibility.eligible is false. src/main/presenter/memoryPresenter/index.ts:2345-2347 already filters these out, so that guarantee belongs in the shared contract too. Tightening the element schema here will catch regressions at the IPC boundary instead of letting non-candidates leak to the renderer.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/shared/contracts/routes/memory.routes.ts` around lines 208 - 227,
`MemoryArchiveCandidateLifecyclePreviewSchema` is too permissive because its
`lifecycles` array still allows any `MemoryLifecycle`, including non-candidates.
Tighten the shared contract by refining the element schema inside
`MemoryArchiveCandidateLifecyclePreviewSchema` so each item requires
`archiveEligibility.eligible` to be true, matching the filtering already done in
`memoryPresenter` and preventing invalid rows from crossing the IPC boundary.
Keep the existing preview and scan checks intact while updating the schema
definition to enforce this invariant at validation time.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/presenter/memoryPresenter/lifecycle.ts`:
- Around line 48-52: The lifecycle eligibility checks in the memory presenter
use strict comparisons, so rows exactly on the archive-age or decay threshold
are still marked ineligible even though deriveArchiveGaps() shows zero
remaining. Update the eligibility logic in lifecycle.ts to use inclusive
boundary checks for oldEnough and decayedEnough, and make sure deriveDecayTier()
uses the same threshold semantics so the UI and eligibility state stay
consistent. Apply the same fix at the other call sites referenced by the review
so all archive/decay decisions use the same boundary behavior.

In `@src/renderer/settings/components/MemoryHealthSection.vue`:
- Around line 321-334: The archive candidate preview logic in
archiveCandidatePreviewLimitMessage is inferring truncation from
lifecycles.length reaching previewLimit, which can show a “limited” message even
when nothing was actually dropped. Update the shared preview DTO returned to
MemoryHealthSection.vue to expose an explicit previewTruncated (or equivalent
eligible-count) flag from the route, and use that flag in this computed branch
instead of comparing lifecycles.length to previewLimit. Keep scanTruncated
handling unchanged and only show the preview-limited message when the new
explicit signal says the eligible list overflowed the display cap.

In `@src/renderer/settings/components/MemoryManagerPanel.vue`:
- Around line 313-320: The lifecycle toggle/panel in MemoryManagerPanel’s row
rendering is shown for every memory, even when
runtime.memoryPresenter.getLifecycle() returns an empty result for working
memories. Update the logic around the Button and the expanded lifecycle panel to
only render for supported kinds, or show a dedicated unsupported-state message
instead; use the existing memory.kind and isLifecycleExpanded/toggleLifecycle
paths to locate the affected UI.

In `@test/main/presenter/agentMemoryTable.test.ts`:
- Around line 714-736: The archive-candidate lifecycle test is relying on
AgentMemoryTable.insert()’s default Date.now() timestamps, so
listArchiveCandidateLifecycleRows('a', 5000, 10) filters everything out. Update
this test to seed deterministic createdAt values on the inserted rows
(especially the ones meant to qualify before the cutoff) so the call to
listArchiveCandidateLifecycleRows exercises the intended projection and
filtering logic. Use the insert() calls and listArchiveCandidateLifecycleRows()
as the main anchors when adjusting the fixture data.

In `@test/renderer/components/MemoryLifecyclePanel.test.ts`:
- Around line 71-77: The locale coverage in the MemoryLifecyclePanel test is too
narrow because getLifecycleMessages only inspects memoryManager.lifecycle, so it
misses new copy like health.archivePrediction and related strings. Update the
test assertions around getLifecycleMessages and the locale regex checks to
include the additional strings/scripts added here, and broaden the Chinese
matching so zh-HK/zh-TW variants such as 複習, 晉級, 回顧, and 倒數 are validated
instead of passing silently.

---

Nitpick comments:
In `@src/shared/contracts/routes/memory.routes.ts`:
- Around line 316-320: The memory.getLifecycle contract currently returns a
collection-shaped payload even though it targets a single memoryId. Update
memoryGetLifecycleRoute in the route contract to expose a singular lifecycle
field, ideally nullable, instead of lifecycles: MemoryLifecycle[], and make sure
any schema consumers or validators referenced by memoryGetLifecycleRoute are
aligned with that single-resource shape.
- Around line 208-227: `MemoryArchiveCandidateLifecyclePreviewSchema` is too
permissive because its `lifecycles` array still allows any `MemoryLifecycle`,
including non-candidates. Tighten the shared contract by refining the element
schema inside `MemoryArchiveCandidateLifecyclePreviewSchema` so each item
requires `archiveEligibility.eligible` to be true, matching the filtering
already done in `memoryPresenter` and preventing invalid rows from crossing the
IPC boundary. Keep the existing preview and scan checks intact while updating
the schema definition to enforce this invariant at validation time.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2ce04072-a662-4503-81e4-3837a944dd5b

📥 Commits

Reviewing files that changed from the base of the PR and between 657c5e7 and 6ccd4a3.

📒 Files selected for processing (42)
  • src/main/presenter/memoryPresenter/index.ts
  • src/main/presenter/memoryPresenter/lifecycle.ts
  • src/main/presenter/memoryPresenter/lifecycleConstants.ts
  • src/main/presenter/memoryPresenter/scoring.ts
  • src/main/presenter/memoryPresenter/types.ts
  • src/main/presenter/sqlitePresenter/tables/agentMemory.ts
  • src/main/routes/index.ts
  • src/renderer/api/MemoryClient.ts
  • src/renderer/settings/components/MemoryHealthSection.vue
  • src/renderer/settings/components/MemoryLifecyclePanel.vue
  • src/renderer/settings/components/MemoryManagerPanel.vue
  • src/renderer/src/i18n/da-DK/settings.json
  • src/renderer/src/i18n/de-DE/settings.json
  • src/renderer/src/i18n/en-US/settings.json
  • src/renderer/src/i18n/es-ES/settings.json
  • src/renderer/src/i18n/fa-IR/settings.json
  • src/renderer/src/i18n/fr-FR/settings.json
  • src/renderer/src/i18n/he-IL/settings.json
  • src/renderer/src/i18n/id-ID/settings.json
  • src/renderer/src/i18n/it-IT/settings.json
  • src/renderer/src/i18n/ja-JP/settings.json
  • src/renderer/src/i18n/ko-KR/settings.json
  • src/renderer/src/i18n/ms-MY/settings.json
  • src/renderer/src/i18n/pl-PL/settings.json
  • src/renderer/src/i18n/pt-BR/settings.json
  • src/renderer/src/i18n/ru-RU/settings.json
  • src/renderer/src/i18n/tr-TR/settings.json
  • src/renderer/src/i18n/vi-VN/settings.json
  • src/renderer/src/i18n/zh-CN/settings.json
  • src/renderer/src/i18n/zh-HK/settings.json
  • src/renderer/src/i18n/zh-TW/settings.json
  • src/shared/contracts/routes.ts
  • src/shared/contracts/routes/memory.routes.ts
  • test/main/presenter/agentMemoryTable.test.ts
  • test/main/presenter/fakes/memoryFakes.ts
  • test/main/presenter/memoryLifecycle.test.ts
  • test/main/routes/dispatcher.test.ts
  • test/main/routes/memoryDto.test.ts
  • test/renderer/api/clients.test.ts
  • test/renderer/components/MemoryHealthSection.test.ts
  • test/renderer/components/MemoryLifecyclePanel.test.ts
  • test/renderer/components/MemoryManagerDialog.test.ts

Comment thread src/main/presenter/memoryPresenter/lifecycle.ts Outdated
Comment thread src/renderer/settings/components/MemoryHealthSection.vue
Comment thread src/renderer/settings/components/MemoryManagerPanel.vue
Comment thread test/main/presenter/agentMemoryTable.test.ts Outdated
Comment thread test/renderer/components/MemoryLifecyclePanel.test.ts Outdated
@zerob13
zerob13 merged commit 645998a into dev Jul 1, 2026
3 checks passed
@zhangmo8
zhangmo8 deleted the feat/agent-memory-lifecycle-view branch July 1, 2026 05:50
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