Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
22f4692
Add payload codec system to plug into storage wrappers
edwinyyyu Apr 22, 2026
a7fa468
Define APIs and models for new episodic memory
edwinyyyu Mar 6, 2026
53a75ff
Add recursive text chunking
edwinyyyu Mar 9, 2026
1a301a2
Add derivative consolidation
edwinyyyu Mar 9, 2026
50a481e
Rename some occurrences of session to partition to reflect semantics
edwinyyyu Mar 10, 2026
a549726
Simplify Episode and Segment models
edwinyyyu Mar 10, 2026
e4a35cc
Update SegmentLinker API
edwinyyyu Mar 10, 2026
c782007
Add background purge
edwinyyyu Mar 11, 2026
766db37
Redesign multimodal
edwinyyyu Mar 12, 2026
60fbc21
Support updated VectorStore API
edwinyyyu Mar 13, 2026
618f9ae
Use handles for partitions
edwinyyyu Mar 14, 2026
fb4870c
Fix vector query result type
edwinyyyu Mar 14, 2026
96d3f7e
Fix segment context zipping
edwinyyyu Mar 14, 2026
002dcef
Preserve order with no reranker
edwinyyyu Mar 16, 2026
26d2d06
Memory no longer knows about partition keys
edwinyyyu Mar 17, 2026
41f1667
Specify return types
edwinyyyu Mar 18, 2026
98f79ac
Fix purge logic
edwinyyyu Mar 19, 2026
4366236
Simplify SegmentLinkerPartition lifecycle
edwinyyyu Mar 19, 2026
b2c134d
Increase default purge limits
edwinyyyu Mar 20, 2026
77d9178
Add back startup/shutdown for partition
edwinyyyu Mar 20, 2026
9fd3031
Fix comment
edwinyyyu Mar 23, 2026
11167dd
Simplify APIs and use exact deduplication
edwinyyyu Mar 25, 2026
ebd5ac3
Make deduplication default False to support native vector DB filtering
edwinyyyu Mar 27, 2026
a7cf328
Simplify and rename
edwinyyyu Mar 30, 2026
8d29947
Update filtering
edwinyyyu Apr 2, 2026
f229f08
Remove unused utilities
edwinyyyu Apr 3, 2026
d950df8
Rename memory
edwinyyyu Apr 3, 2026
152ac73
Update partition lifecycle
edwinyyyu Apr 3, 2026
f71044c
Add options for timezone formatting
edwinyyyu Apr 3, 2026
7068d59
Add serialization and deserialization to data models
edwinyyyu Apr 6, 2026
9cc6d17
Renamed vector store Collection
edwinyyyu Apr 6, 2026
81e40b7
Prepare for wiring
edwinyyyu Apr 7, 2026
a451b1b
Add missing stuff
edwinyyyu Apr 7, 2026
6bc2d8d
Add naming rules for partitions
edwinyyyu Apr 7, 2026
81ef9a7
Add memory unit tests
edwinyyyu Apr 8, 2026
abb678f
Add derivative eviction logic
edwinyyyu Apr 9, 2026
b307f8e
Review and fix eviction logic
edwinyyyu Apr 9, 2026
57c2f00
Allow external system-defined fields and specify Context field types
edwinyyyu Apr 14, 2026
bd18b73
Improve timestamp formatting, logging
edwinyyyu Apr 14, 2026
12a3098
Decouple date and time formats
edwinyyyu Apr 14, 2026
20d5d4a
Add more methods for formatting context
edwinyyyu Apr 17, 2026
41f2fc1
Context fields may expose sensitive information if used in filtering
edwinyyyu Apr 22, 2026
0789622
Add NullContext
edwinyyyu Apr 22, 2026
a2e278e
Support encryption infrastructure
edwinyyyu Apr 23, 2026
36a14d8
Remove eviction system for simpler PR
edwinyyyu Apr 27, 2026
3abd691
Reduce default max text chunk length for easier context tuning
edwinyyyu Apr 27, 2026
e35d4d6
Remove encryption from test
edwinyyyu Apr 28, 2026
42589a5
Don't ensure ASCII in LLM-visible JSON strings
edwinyyyu Apr 28, 2026
7aa97c6
Remove unimplemented Block and Body types
edwinyyyu Apr 28, 2026
031c488
Fix rebase
edwinyyyu Apr 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add background purge
Signed-off-by: Edwin Yu <[email protected]>
  • Loading branch information
edwinyyyu committed May 4, 2026
commit c782007aa4865d15e418ee9bcccf1de66fa96181
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ class ExtraMemoryParams(BaseModel):
Max code-point length for text chunking in segment creation (default: 2000).
derivative_consolidation_threshold (float):
Threshold for consolidating derivatives (default: 0.0, range: 0.0 to 1.0).
purge_interval (float | None):
Seconds between purge cycles. None disables periodic purging (default: None).
"""

partition_key: str = Field(
Expand Down Expand Up @@ -99,6 +101,10 @@ class ExtraMemoryParams(BaseModel):
None,
description="Threshold for consolidating derivatives",
)
purge_interval: float | None = Field(
None,
description="Seconds between purge cycles. None disables periodic purging.",
)


class ExtraMemory:
Expand All @@ -125,6 +131,10 @@ def __init__(self, params: ExtraMemoryParams) -> None:
params.derivative_consolidation_threshold
)

self._purge_interval = params.purge_interval
self._purge_task: asyncio.Task[None] | None = None
self._shutdown_event = asyncio.Event()

self._text_splitter = RecursiveCharacterTextSplitter(
chunk_size=params.max_text_chunk_length,
chunk_overlap=0,
Expand Down Expand Up @@ -163,6 +173,57 @@ def __init__(self, params: ExtraMemoryParams) -> None:
keep_separator="end",
)

async def startup(self) -> None:
"""Start the periodic purge loop if purge_interval is configured."""
if self._purge_interval is not None:
self._shutdown_event.clear()
self._purge_task = asyncio.create_task(self._purge_loop())

async def shutdown(self) -> None:
"""Stop the periodic purge loop."""
if self._purge_task is not None:
self._shutdown_event.set()
await self._purge_task
self._purge_task = None

async def _purge_loop(self) -> None:
"""Periodically purge orphaned derivatives."""
assert self._purge_interval is not None
while True:
try:
await asyncio.wait_for(
self._shutdown_event.wait(), timeout=self._purge_interval
)
except TimeoutError:
pass
else:
# Shutdown event was set, so exit the loop.
return

try:
await self._purge_orphaned_derivatives()
except Exception:
logger.exception("Error during derivative purge cycle")

async def _purge_orphaned_derivatives(self) -> None:
"""Run a single purge cycle: identify, mark, delete from collection, then remove."""
orphan_uuids = list(
await self._segment_linker.get_orphaned_derivatives(self._partition_key)
)
if not orphan_uuids:
return

marked_uuids = list(
await self._segment_linker.mark_orphaned_derivatives_for_purging(
self._partition_key, orphan_uuids
)
)
if not marked_uuids:
return

await self._collection.delete(record_uuids=marked_uuids)
await self._segment_linker.purge_derivatives(self._partition_key, marked_uuids)

async def encode_episodes(
self,
episodes: Iterable[Episode],
Expand Down Expand Up @@ -726,14 +787,12 @@ async def forget_episodes(self, episode_uuids: Iterable[UUID]) -> None:
partition_key=self._partition_key,
episode_uuids=episode_uuids,
)
# TODO: Add background job to delete records from collection based on reference counting. May belong to class instead of instance.

async def forget_all_episodes(self) -> None:
"""Forget all episodes in this partition."""
await self._segment_linker.delete_all_segments(
partition_key=self._partition_key,
)
# TODO: Add background job to delete records from collection based on reference counting. May belong to class instead of instance.

@staticmethod
def _unify_anchored_segment_contexts(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,11 +176,15 @@ async def delete_all_segments(
raise NotImplementedError

@abstractmethod
async def get_orphaned_derivatives(self, limit: int = 1000) -> Iterable[UUID]:
async def get_orphaned_derivatives(
self, partition_key: str, limit: int = 1000
) -> Iterable[UUID]:
"""
Identify derivatives that are orphaned.

Args:
partition_key (str):
The key of the partition to which the derivatives belong.
limit (int):
The maximum number of orphaned derivatives to return (default: 1000).

Expand All @@ -193,12 +197,14 @@ async def get_orphaned_derivatives(self, limit: int = 1000) -> Iterable[UUID]:

@abstractmethod
async def mark_orphaned_derivatives_for_purging(
self, potential_orphan_uuids: Iterable[UUID]
self, partition_key: str, potential_orphan_uuids: Iterable[UUID]
) -> Iterable[UUID]:
"""
Transition derivatives from 'active' to 'purging' state if they are orphaned.

Args:
partition_key (str):
The key of the partition to which the derivatives belong.
potential_orphan_uuids (Iterable[UUID]):
The UUIDs of potentially orphaned derivatives.

Expand All @@ -210,13 +216,17 @@ async def mark_orphaned_derivatives_for_purging(
raise NotImplementedError

@abstractmethod
async def purge_derivatives(self, derivative_uuids: Iterable[UUID]) -> None:
async def purge_derivatives(
self, partition_key: str, derivative_uuids: Iterable[UUID]
) -> None:
"""
Physically remove derivatives from the segment linker.

Should be called after the derivatives have been deleted from external systems.

Args:
partition_key (str):
The key of the partition to which the derivatives belong.
derivative_uuids (Iterable[UUID]):
The UUIDs of the derivatives to purge.

Expand Down