use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum MemoryType {
Code,
Architecture,
BugFix,
Feature,
Documentation,
UserPreference,
Decision,
Learning,
Configuration,
Testing,
Performance,
Security,
Insight,
}
impl std::fmt::Display for MemoryType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
MemoryType::Code => write!(f, "code"),
MemoryType::Architecture => write!(f, "architecture"),
MemoryType::BugFix => write!(f, "bug_fix"),
MemoryType::Feature => write!(f, "feature"),
MemoryType::Documentation => write!(f, "documentation"),
MemoryType::UserPreference => write!(f, "user_preference"),
MemoryType::Decision => write!(f, "decision"),
MemoryType::Learning => write!(f, "learning"),
MemoryType::Configuration => write!(f, "configuration"),
MemoryType::Testing => write!(f, "testing"),
MemoryType::Performance => write!(f, "performance"),
MemoryType::Security => write!(f, "security"),
MemoryType::Insight => write!(f, "insight"),
}
}
}
impl From<String> for MemoryType {
fn from(s: String) -> Self {
match s.to_lowercase().as_str() {
"code" => MemoryType::Code,
"architecture" => MemoryType::Architecture,
"bug_fix" | "bugfix" | "bug" => MemoryType::BugFix,
"feature" => MemoryType::Feature,
"documentation" | "docs" | "doc" => MemoryType::Documentation,
"user_preference" | "preference" | "user" => MemoryType::UserPreference,
"decision" | "meeting" | "planning" => MemoryType::Decision,
"learning" | "tutorial" | "education" => MemoryType::Learning,
"configuration" | "config" | "setup" | "deployment" => MemoryType::Configuration,
"testing" | "test" | "qa" => MemoryType::Testing,
"performance" | "perf" | "optimization" => MemoryType::Performance,
"security" | "vulnerability" | "vuln" => MemoryType::Security,
_ => MemoryType::Insight, }
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MemoryMetadata {
pub git_commit: Option<String>,
pub related_files: Vec<String>,
pub tags: Vec<String>,
pub importance: f32,
pub confidence: f32,
pub created_by: Option<String>,
pub custom_fields: HashMap<String, String>,
}
impl Default for MemoryMetadata {
fn default() -> Self {
Self {
git_commit: None,
related_files: Vec::new(),
tags: Vec::new(),
importance: 0.5,
confidence: 1.0,
created_by: None,
custom_fields: HashMap::new(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Memory {
pub id: String,
pub memory_type: MemoryType,
pub title: String,
pub content: String,
pub metadata: MemoryMetadata,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
#[serde(skip_serializing_if = "Option::is_none")]
pub relevance_score: Option<f32>,
}
impl Memory {
pub fn new(
memory_type: MemoryType,
title: String,
content: String,
metadata: Option<MemoryMetadata>,
) -> Self {
let now = Utc::now();
Self {
id: uuid::Uuid::new_v4().to_string(),
memory_type,
title,
content,
metadata: metadata.unwrap_or_default(),
created_at: now,
updated_at: now,
relevance_score: None,
}
}
pub fn update(
&mut self,
title: Option<String>,
content: Option<String>,
metadata: Option<MemoryMetadata>,
) {
if let Some(title) = title {
self.title = title;
}
if let Some(content) = content {
self.content = content;
}
if let Some(metadata) = metadata {
self.metadata = metadata;
}
self.updated_at = Utc::now();
}
pub fn get_searchable_text(&self) -> String {
format!(
"{} {} {} {}",
self.title,
self.content,
self.metadata.tags.join(" "),
self.metadata.related_files.join(" ")
)
}
pub fn add_tag(&mut self, tag: String) {
if !self.metadata.tags.contains(&tag) {
self.metadata.tags.push(tag);
self.updated_at = Utc::now();
}
}
pub fn remove_tag(&mut self, tag: &str) {
if let Some(pos) = self.metadata.tags.iter().position(|t| t == tag) {
self.metadata.tags.remove(pos);
self.updated_at = Utc::now();
}
}
pub fn add_related_file(&mut self, file_path: String) {
if !self.metadata.related_files.contains(&file_path) {
self.metadata.related_files.push(file_path);
self.updated_at = Utc::now();
}
}
pub fn remove_related_file(&mut self, file_path: &str) {
if let Some(pos) = self
.metadata
.related_files
.iter()
.position(|f| f == file_path)
{
self.metadata.related_files.remove(pos);
self.updated_at = Utc::now();
}
}
}
#[derive(Debug, Clone, Default)]
pub struct MemoryQuery {
pub query_text: Option<String>,
pub memory_types: Option<Vec<MemoryType>>,
pub tags: Option<Vec<String>>,
pub related_files: Option<Vec<String>>,
pub git_commit: Option<String>,
pub min_importance: Option<f32>,
pub min_confidence: Option<f32>,
pub created_after: Option<DateTime<Utc>>,
pub created_before: Option<DateTime<Utc>>,
pub limit: Option<usize>,
pub min_relevance: Option<f32>,
pub sort_by: Option<MemorySortBy>,
pub sort_order: Option<SortOrder>,
}
#[derive(Debug, Clone)]
pub enum MemorySortBy {
CreatedAt,
UpdatedAt,
Importance,
Confidence,
Relevance,
}
#[derive(Debug, Clone)]
pub enum SortOrder {
Ascending,
Descending,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MemorySearchResult {
pub memory: Memory,
pub relevance_score: f32,
pub selection_reason: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MemoryRelationship {
pub id: String,
pub source_id: String,
pub target_id: String,
pub relationship_type: RelationshipType,
pub strength: f32,
pub description: String,
pub created_at: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum RelationshipType {
RelatedTo,
DependsOn,
Supersedes,
Similar,
Conflicts,
Implements,
Extends,
Custom(String),
}
impl std::fmt::Display for RelationshipType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
RelationshipType::RelatedTo => write!(f, "related_to"),
RelationshipType::DependsOn => write!(f, "depends_on"),
RelationshipType::Supersedes => write!(f, "supersedes"),
RelationshipType::Similar => write!(f, "similar"),
RelationshipType::Conflicts => write!(f, "conflicts"),
RelationshipType::Implements => write!(f, "implements"),
RelationshipType::Extends => write!(f, "extends"),
RelationshipType::Custom(s) => write!(f, "{}", s),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MemoryConfig {
pub max_memories: Option<usize>,
pub auto_cleanup_days: Option<u32>,
pub cleanup_min_importance: f32,
pub auto_relationships: bool,
pub relationship_threshold: f32,
pub max_search_results: usize,
pub default_importance: f32,
}
impl Default for MemoryConfig {
fn default() -> Self {
Self {
max_memories: Some(10000),
auto_cleanup_days: Some(365),
cleanup_min_importance: 0.1,
auto_relationships: true,
relationship_threshold: 0.7,
max_search_results: 50,
default_importance: 0.5,
}
}
}