This repository was archived by the owner on Jun 3, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 54
Expand file tree
/
Copy pathmemory_lifecycle.py
More file actions
63 lines (45 loc) · 1.86 KB
/
memory_lifecycle.py
File metadata and controls
63 lines (45 loc) · 1.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
"""Memory lifecycle metadata helpers.
These helpers keep duplicate detection, version lineage, and soft-forget
metadata consistent across vector-store implementations.
"""
from __future__ import annotations
import hashlib
import re
from datetime import datetime, timezone
from typing import Any, Dict, Optional
CONTENT_HASH_KEY = "content_hash"
PARENT_MEMORY_ID_KEY = "parent_memory_id"
VERSION_KEY = "version"
IS_CURRENT_KEY = "is_current"
FORGOTTEN_AT_KEY = "forgotten_at"
FORGET_REASON_KEY = "forget_reason"
def normalize_memory_content(content: str) -> str:
"""Normalize memory text before hashing to catch whitespace-only duplicates."""
return re.sub(r"\s+", " ", content.strip()).casefold()
def compute_memory_hash(content: str) -> str:
"""Return a stable SHA-256 digest for normalized memory content."""
normalized = normalize_memory_content(content)
return hashlib.sha256(normalized.encode("utf-8")).hexdigest()
def utc_now_iso() -> str:
return datetime.now(timezone.utc).isoformat()
def build_lifecycle_metadata(
content: str,
metadata: Optional[Dict[str, Any]] = None,
*,
parent_memory_id: Optional[str] = None,
version: int = 1,
is_current: bool = True,
) -> Dict[str, Any]:
"""Merge caller metadata with lifecycle fields without losing custom keys."""
merged = dict(metadata or {})
merged[CONTENT_HASH_KEY] = compute_memory_hash(content)
merged[PARENT_MEMORY_ID_KEY] = parent_memory_id
merged[VERSION_KEY] = version
merged[IS_CURRENT_KEY] = is_current
merged[FORGOTTEN_AT_KEY] = None
merged[FORGET_REASON_KEY] = None
return merged
def is_retrievable_memory(metadata: Optional[Dict[str, Any]]) -> bool:
"""Return False for superseded or soft-forgotten memory records."""
meta = metadata or {}
return meta.get(IS_CURRENT_KEY, True) is not False and not meta.get(FORGOTTEN_AT_KEY)