refactor(backend): alihkan Memory ke zesdex-cms MarkdownMemoryRepository

Ganti semua pemanggilan Memory::read/write/remove/list di zesdex-backend
dengan MarkdownMemoryRepository dari zesdex-cms. Hapus re-export
model::memory yang sudah tidak dipakai.

Method mapping: read -> load, write -> save, remove -> delete, list -> list.
Import trait MemoryRepository untuk method resolution.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
asepharyana
2026-07-17 09:08:41 +07:00
co-authored by Claude Sonnet 5
parent dc9fd4dbd1
commit 0ad3b0e539
8 changed files with 37 additions and 28 deletions
@@ -1,4 +1,5 @@
use crate::app::state::rest::AppStateRest; use crate::app::state::rest::AppStateRest;
use zesdex_cms::domain::repository::MemoryRepository;
/// A unified representation of a lesson item for the interactive TUI overlay. /// A unified representation of a lesson item for the interactive TUI overlay.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -53,9 +54,9 @@ pub fn get_learning_items(state: &AppStateRest) -> Vec<LearningItem> {
} }
// 2. Load stored memory lessons from long-term memory directory // 2. Load stored memory lessons from long-term memory directory
let names = crate::model::memory::Memory::list(&state.memory_dir); let names = zesdex_cms::infrastructure::persistence::memory_repo::MarkdownMemoryRepository::new().list(&state.memory_dir).unwrap_or_default();
for name in names { for name in names {
if let Ok(mem) = crate::model::memory::Memory::read(&state.memory_dir, &name) { if let Ok(mem) = zesdex_cms::infrastructure::persistence::memory_repo::MarkdownMemoryRepository::new().load(&state.memory_dir, &name) {
if mem.kind == "lesson" { if mem.kind == "lesson" {
items.push(LearningItem::Stored { items.push(LearningItem::Stored {
name: mem.name, name: mem.name,
+13 -7
View File
@@ -9,6 +9,9 @@ use crate::app::subagent::context::build_subagent_context;
use crate::app::subagent::engine::run_subagent; use crate::app::subagent::engine::run_subagent;
use crate::app::subagent::spawn::AgentDefinition; use crate::app::subagent::spawn::AgentDefinition;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use zesdex_cms::domain::memory::Memory;
use zesdex_cms::domain::repository::MemoryRepository;
use zesdex_cms::infrastructure::persistence::memory_repo::MarkdownMemoryRepository;
/// How much trust a lesson's origin/verification warrants. /// How much trust a lesson's origin/verification warrants.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
@@ -484,14 +487,15 @@ const STALE_AFTER_DAYS: i64 = 60;
/// `mem.write`. /// `mem.write`.
pub fn run_staleness_sweep(memory_dir: &std::path::Path) -> std::io::Result<Vec<String>> { pub fn run_staleness_sweep(memory_dir: &std::path::Path) -> std::io::Result<Vec<String>> {
let mut flagged = Vec::new(); let mut flagged = Vec::new();
let names = crate::model::memory::Memory::list(memory_dir); let names = MarkdownMemoryRepository::new().list(memory_dir).unwrap_or_default();
let now = chrono::Utc::now().timestamp_millis(); let now = chrono::Utc::now().timestamp_millis();
let cutoff = now - STALE_AFTER_DAYS * 24 * 3600 * 1000; let cutoff = now - STALE_AFTER_DAYS * 24 * 3600 * 1000;
for name in names { for name in names {
if let Ok(mut mem) = crate::model::memory::Memory::read(memory_dir, &name) { if let Ok(mut mem) = MarkdownMemoryRepository::new().load(memory_dir, &name) {
if mem.updated_at < cutoff && mem.lifecycle != "stale" { if mem.updated_at < cutoff && mem.lifecycle != "stale" {
mem.lifecycle = "stale".to_string(); mem.lifecycle = "stale".to_string();
mem.write(memory_dir)?; MarkdownMemoryRepository::new().save(memory_dir, &mem)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
flagged.push(name); flagged.push(name);
} }
} }
@@ -581,7 +585,7 @@ pub fn process_pending_lessons(session_dir: &std::path::Path, memory_dir: &std::
} }
} }
for lesson in &to_keep { for lesson in &to_keep {
let mem = crate::model::memory::Memory { let mem = Memory {
name: lesson.name.clone(), name: lesson.name.clone(),
description: lesson.content.chars().take(80).collect(), description: lesson.content.chars().take(80).collect(),
content: lesson.content.clone(), content: lesson.content.clone(),
@@ -595,7 +599,8 @@ pub fn process_pending_lessons(session_dir: &std::path::Path, memory_dir: &std::
after_snippet: None, after_snippet: None,
provenances: vec![], provenances: vec![],
}; };
mem.write(memory_dir)?; MarkdownMemoryRepository::new().save(memory_dir, &mem)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
} }
save_pending_lessons(session_dir, &remaining)?; save_pending_lessons(session_dir, &remaining)?;
@@ -625,7 +630,7 @@ pub fn resolve_pending_lesson(
for p in pending { for p in pending {
if p.lesson.name == lesson_name { if p.lesson.name == lesson_name {
if keep { if keep {
let mem = crate::model::memory::Memory { let mem = Memory {
name: p.lesson.name.clone(), name: p.lesson.name.clone(),
description: p.lesson.content.chars().take(80).collect(), description: p.lesson.content.chars().take(80).collect(),
content: p.lesson.content.clone(), content: p.lesson.content.clone(),
@@ -639,7 +644,8 @@ pub fn resolve_pending_lesson(
after_snippet: None, after_snippet: None,
provenances: vec![], provenances: vec![],
}; };
mem.write(memory_dir)?; MarkdownMemoryRepository::new().save(memory_dir, &mem)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
} }
} else { } else {
remaining.push(p); remaining.push(p);
@@ -29,6 +29,8 @@ use crate::app::state::rest::{AppStateRest, ChatMessageDisplay};
use crate::app::state::runtime::TurnEvent; use crate::app::state::runtime::TurnEvent;
use crate::app::state::types::{Origin, Overlay, Toast, ToastKind}; use crate::app::state::types::{Origin, Overlay, Toast, ToastKind};
use crate::dto::chat::message::{ChatMessage, Role}; use crate::dto::chat::message::{ChatMessage, Role};
use zesdex_cms::domain::repository::MemoryRepository;
use zesdex_cms::infrastructure::persistence::memory_repo::MarkdownMemoryRepository;
/// A single, well-typed event in the app — produced by key input, the /// A single, well-typed event in the app — produced by key input, the
/// streaming pipeline, or subagent threads — that mutates `AppStateRest` /// streaming pipeline, or subagent threads — that mutates `AppStateRest`
@@ -589,7 +591,7 @@ pub fn apply_action(state: &mut AppStateRest, action: Action) {
state.dirty = true; state.dirty = true;
} }
Action::LessonDelete { name } => { Action::LessonDelete { name } => {
let _ = crate::model::memory::Memory::remove(&state.memory_dir, &name); let _ = MarkdownMemoryRepository::new().delete(&state.memory_dir, &name);
if let Some(ref mut rt) = state.session_runtime { if let Some(ref mut rt) = state.session_runtime {
refresh_lesson_counters(&state.memory_dir, rt); refresh_lesson_counters(&state.memory_dir, rt);
} }
@@ -795,7 +797,7 @@ fn generate_workspace_tree(roots: &[std::path::PathBuf]) -> String {
/// ///
/// Return: a formatted string (may be empty if no memory entries exist). /// Return: a formatted string (may be empty if no memory entries exist).
fn build_memory_section(memory_dir: &std::path::Path) -> String { fn build_memory_section(memory_dir: &std::path::Path) -> String {
let names = crate::model::memory::Memory::list(memory_dir); let names = MarkdownMemoryRepository::new().list(memory_dir).unwrap_or_default();
if names.is_empty() { if names.is_empty() {
return String::new(); return String::new();
} }
@@ -808,7 +810,7 @@ fn build_memory_section(memory_dir: &std::path::Path) -> String {
section.push_str("... (more entries omitted, use recall() to see all)\n"); section.push_str("... (more entries omitted, use recall() to see all)\n");
break; break;
} }
if let Ok(mem) = crate::model::memory::Memory::read(memory_dir, name) { if let Ok(mem) = MarkdownMemoryRepository::new().load(memory_dir, name) {
if mem.lifecycle == "stale" { if mem.lifecycle == "stale" {
continue; continue;
} }
@@ -831,7 +833,7 @@ fn build_memory_section(memory_dir: &std::path::Path) -> String {
/// breakdown counters. This runs on every user submit so the dashboard /// breakdown counters. This runs on every user submit so the dashboard
/// reflects actual memory state. /// reflects actual memory state.
fn refresh_lesson_counters(memory_dir: &std::path::Path, rt: &mut crate::app::state::runtime::SessionRuntime) { fn refresh_lesson_counters(memory_dir: &std::path::Path, rt: &mut crate::app::state::runtime::SessionRuntime) {
let names = crate::model::memory::Memory::list(memory_dir); let names = MarkdownMemoryRepository::new().list(memory_dir).unwrap_or_default();
rt.lesson_count = 0; rt.lesson_count = 0;
rt.lessons_user = 0; rt.lessons_user = 0;
rt.lessons_feedback = 0; rt.lessons_feedback = 0;
@@ -841,7 +843,7 @@ fn refresh_lesson_counters(memory_dir: &std::path::Path, rt: &mut crate::app::st
rt.lessons_stale = 0; rt.lessons_stale = 0;
rt.lessons_contradicted = 0; rt.lessons_contradicted = 0;
for name in &names { for name in &names {
if let Ok(mem) = crate::model::memory::Memory::read(memory_dir, name) { if let Ok(mem) = MarkdownMemoryRepository::new().load(memory_dir, name) {
rt.lesson_count += 1; rt.lesson_count += 1;
match mem.kind.as_str() { match mem.kind.as_str() {
"user" => rt.lessons_user += 1, "user" => rt.lessons_user += 1,
@@ -7,7 +7,7 @@
//! Core Intelligence can omit or reshape — and always runs after any //! Core Intelligence can omit or reshape — and always runs after any
//! hive-mind convergence completes. //! hive-mind convergence completes.
use crate::app::workflow::hive_mind::NodeReport; use crate::app::workflow::hive_mind::NodeReport;
use crate::model::memory::Memory; use zesdex_cms::domain::memory::Memory;
use std::fmt::Write as _; use std::fmt::Write as _;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
-3
View File
@@ -8,9 +8,6 @@ pub mod store {
pub mod editlog { pub mod editlog {
pub use zesdex_entities::seaorm::common::edit_log::*; pub use zesdex_entities::seaorm::common::edit_log::*;
} }
pub mod memory {
pub use zesdex_entities::seaorm::common::memory::*;
}
/// Local modules not extracted to workspace crates /// Local modules not extracted to workspace crates
pub mod msglog; pub mod msglog;
pub mod agent_def; pub mod agent_def;
@@ -1,7 +1,8 @@
//! Tool for deleting a persisted memory entry by name. //! Tool for deleting a persisted memory entry by name.
use super::super::Tool; use super::super::Tool;
use super::super::ToolCtx; use super::super::ToolCtx;
use crate::model::memory::Memory; use zesdex_cms::domain::repository::MemoryRepository;
use zesdex_cms::infrastructure::persistence::memory_repo::MarkdownMemoryRepository;
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use serde_json::{json, Value}; use serde_json::{json, Value};
@@ -42,7 +43,7 @@ impl Tool for Forget {
.and_then(|v| v.as_str()) .and_then(|v| v.as_str())
.ok_or_else(|| anyhow!("missing required argument: name"))?; .ok_or_else(|| anyhow!("missing required argument: name"))?;
Memory::remove(&ctx.memory_dir, name) MarkdownMemoryRepository::new().delete(&ctx.memory_dir, name)
.map_err(|e| anyhow!("failed to remove memory '{name}': {e}"))?; .map_err(|e| anyhow!("failed to remove memory '{name}': {e}"))?;
Ok(format!("removed memory '{name}'")) Ok(format!("removed memory '{name}'"))
@@ -1,7 +1,8 @@
//! Tool for reading a single memory entry or listing the whole memory index. //! Tool for reading a single memory entry or listing the whole memory index.
use super::super::Tool; use super::super::Tool;
use super::super::ToolCtx; use super::super::ToolCtx;
use crate::model::memory::Memory; use zesdex_cms::domain::repository::MemoryRepository;
use zesdex_cms::infrastructure::persistence::memory_repo::MarkdownMemoryRepository;
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use serde_json::{json, Value}; use serde_json::{json, Value};
use std::fmt::Write; use std::fmt::Write;
@@ -41,7 +42,7 @@ impl Tool for Recall {
if name.is_empty() { if name.is_empty() {
return Ok(list_all(ctx)); return Ok(list_all(ctx));
} }
let memory = Memory::read(&ctx.memory_dir, name) let memory = MarkdownMemoryRepository::new().load(&ctx.memory_dir, name)
.map_err(|e| anyhow!("memory '{name}' not found: {e}"))?; .map_err(|e| anyhow!("memory '{name}' not found: {e}"))?;
Ok(format!( Ok(format!(
"---\nname: {}\ndescription: {}\nkind: {}\nlifecycle: {}\n---\n\n{}", "---\nname: {}\ndescription: {}\nkind: {}\nlifecycle: {}\n---\n\n{}",
@@ -60,13 +61,13 @@ impl Tool for Recall {
/// ///
/// Return: `Ok` with the formatted index (never fails; missing dir yields "(no memory entries)"). /// Return: `Ok` with the formatted index (never fails; missing dir yields "(no memory entries)").
fn list_all(ctx: &ToolCtx) -> String { fn list_all(ctx: &ToolCtx) -> String {
let names = Memory::list(&ctx.memory_dir); let names = MarkdownMemoryRepository::new().list(&ctx.memory_dir).unwrap_or_default();
if names.is_empty() { if names.is_empty() {
return "(no memory entries)".to_string(); return "(no memory entries)".to_string();
} }
let mut lines = String::new(); let mut lines = String::new();
for name in &names { for name in &names {
if let Ok(mem) = Memory::read(&ctx.memory_dir, name) { if let Ok(mem) = MarkdownMemoryRepository::new().load(&ctx.memory_dir, name) {
let _ = writeln!(lines, "- {} [{}]: {}", name, mem.kind, mem.description); let _ = writeln!(lines, "- {} [{}]: {}", name, mem.kind, mem.description);
} else { } else {
let _ = writeln!(lines, "- {name}"); let _ = writeln!(lines, "- {name}");
@@ -1,7 +1,9 @@
//! Tool for saving a new memory entry to persistent project memory. //! Tool for saving a new memory entry to persistent project memory.
use super::super::Tool; use super::super::Tool;
use super::super::ToolCtx; use super::super::ToolCtx;
use crate::model::memory::Memory; use zesdex_cms::domain::memory::Memory;
use zesdex_cms::domain::repository::MemoryRepository;
use zesdex_cms::infrastructure::persistence::memory_repo::MarkdownMemoryRepository;
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use serde_json::{json, Value}; use serde_json::{json, Value};
@@ -91,9 +93,8 @@ impl Tool for Remember {
provenances: vec![], provenances: vec![],
}; };
memory MarkdownMemoryRepository::new().save(&ctx.memory_dir, &memory)
.write(&ctx.memory_dir) .map_err(|e| anyhow!("failed to save memory '{name}': {e}"))?;
.map_err(|e| anyhow!("failed to write memory '{name}': {e}"))?;
Ok(format!("saved memory '{name}' ({kind})")) Ok(format!("saved memory '{name}' ({kind})"))
} }