Decision Logic & Memory Pruning
How Sieve evaluates candidate agent memories, scores importance and actionability, supersedes outdated facts, and curates compact, high-signal active prompt context in sub-millisecond local sweeps.
Overview #
Vector databases retrieve memories based strictly on lexical or semantic embedding similarity. However, semantic similarity cannot determine temporal order, factual contradiction, or actionability.
When an agent records "User is in Tokyo for the week" on Monday, and then "User relocated to Berlin permanently" on Thursday, vector search retrieves both memories simultaneously. This causes conflicting context, ballooning token usage, and inevitable model hallucinations.
Sieve acts as the deterministic garbage collection layer between your agent storage and your model prompts. It continuously identifies superseding facts, marks superseded items as archived with direct pointer attribution, and produces clean prompt context without requiring recurring per-turn LLM evaluator calls.
The Memory Decision Lifecycle #
Every memory ingested into Sieve passes through a disciplined four-stage pipeline: Ingestion, Calibration, Pairing, and Policy Execution.
Quickstart in 5 Minutes #
Integrate Sieve with any Python agent in three lines of code. The SieveMemory class manages local database storage, automatic scoring, and prompt context rendering.
from sieve import SieveMemory # 1. Initialize local persistent engine (SQLite WAL mode) memory = SieveMemory(db_path="agent_memory.db") # 2. Ingest observations across turns memory.remember("Target database is PostgreSQL 15 on port 5432", namespace="tenant_1") memory.remember("Actually, database was migrated to PostgreSQL 16 on port 5433", namespace="tenant_1") # 3. Execute automatic garbage collection sweep results = memory.sweep(namespace="tenant_1") print(f"Archived superseded facts: {results['items_archived']}") # 4. Inject clean, deduplicated context into your agent prompt prompt_context = memory.get_context(namespace="tenant_1") print(prompt_context)
Installation Options #
Sieve is designed to have zero mandatory heavy external dependencies for its core engine. Install via pip, uv, or clone from source:
# Install core memory engine and CLI pip install sieve-memory # Optional: Install with full server and API dashboard support pip install "sieve-memory[serve]" # Optional: Install with real Laya neural calibration backend pip install "sieve-memory[laya]"
Memory Scoring Engine #
Every memory item is scored across two continuous axes and one discrete category classifier:
| Metric | Type | Range | Description |
|---|---|---|---|
| importance | float | 0.0 – 1.0 | Significance of the memory to user profile, permanent business rules, or core identity. High importance memories survive decay longer. |
| actionable | float | 0.0 – 1.0 | Operational readiness. High actionable scores indicate pending tasks, explicit commands, architectural constraints, or current objectives. |
| category | string | enum | Classification tag: decision (conclusions/commitments), reference (facts/specs), task (open action items), smalltalk (transient conversation). |
Scoring Backends: Mock vs Real Laya
Sieve provides two pluggable scorer implementations:
- MockScorer (Default): Ultra-fast, deterministic rule-based heuristic scoring (0.01ms). Requires no GPU, neural dependencies, or API keys. Ideal for local unit tests, CI pipelines, and high-throughput microservices.
- LayaScorer: Neural calibrated cross-encoder backend trained on contradiction resolution and memory salience datasets. Enabled via
SIEVE_SCORER=layaorSieveMemory(use_real_laya=True).
Staleness & Superseding Logic #
The core decision rule for resolving factual contradiction is Pairwise Staleness Resolution.
When a sweep is triggered, Sieve runs BM25 candidate generation across memory pairs in the target namespace. If candidate pair (A, B) satisfies:
B.created_at > A.created_at(B was recorded after A)lexical_overlap(A, B) >= staleness_threshold(subject topic matches)A.pinned == 0(A is not an immutable system directive)
Memory A is automatically updated: status = 'archived' and superseded_by = B.id. It is evicted from active prompt context, but remains queryable for audit trails or historical replay.
# Memory A (Turn 1) id_a = memory.remember("Primary cluster is us-east-1", namespace="infra") # Memory B (Turn 12) id_b = memory.remember("Cluster failed over to us-west-2 permanently", namespace="infra") # Execute staleness pruning sweep report = memory.sweep(namespace="infra") # Inspect archived item archived_item = memory.store.get(id_a) assert archived_item.status == "archived" assert archived_item.superseded_by == id_b
Pinned Invariants #
Certain agent guidelines must never be pruned regardless of time or superficial topic overlap. Examples include:
- System constraints: "Never disclose internal customer IDs in output".
- User accessibility settings: "Always respond in concise markdown".
- Compliance policies: "HIPAA data redaction rule 4.2 active".
Marking a memory as pinned ensures it is permanently immune to staleness eviction, redundancy sweeps, or retention expiration, while remaining included at the highest priority in all prompt context generation.
# Save and immediately pin critical guideline item_id = memory.remember( "Never delete production tables without explicit multi-sig approval", namespace="security_policy" ) memory.pin(item_id) # Verify pinned item persists through aggressive sweeps memory.sweep(namespace="security_policy") assert memory.store.get(item_id).pinned == 1
LangChain Memory History #
Drop Sieve directly into your existing LangChain agent or runnable chain using SieveChatMessageHistory:
from sieve.integrations.langchain import SieveChatMessageHistory # Wrap Sieve as a native LangChain chat message history history = SieveChatMessageHistory( session_id="session_user_42", db_path="sieve.db", auto_sweep_interval=4 # Automatically run curation sweep every 4 turns ) # Append user and AI messages history.add_user_message("My shipping address is 100 Main St") history.add_ai_message("Noted shipping address.") history.add_user_message("Change shipping address to 450 Broadway St") # Returns only valid, active messages (the old address is pruned!) messages = history.messages
ChromaDB Vector Store Sync #
If your agent already stores dense embeddings in ChromaDB, use sync_from_chroma to synchronize memories, score them, prune stale contradictions, and purge archived vectors:
import chromadb from sieve import SieveMemory from sieve.integrations.chroma import sync_from_chroma client = chromadb.Client() collection = client.create_collection("agent_knowledge") memory = SieveMemory(db_path="sieve.db") # Synchronize, score, run staleness sweeps, and delete pruned vectors from Chroma summary = sync_from_chroma( collection=collection, memory=memory, namespace="rag_knowledge", prune_vectors=True ) print(f"Synced: {summary['synced']}, Archived: {summary['archived']}")
REST API Endpoints #
Sieve includes a high-performance REST API built on FastAPI. Start the server using the CLI: sieve serve --port 8000 (or sieve ui).
| Method | Endpoint | Description |
|---|---|---|
| POST | /items |
Ingest and immediately score a new memory item. Accepts text, namespace, metadata. |
| POST | /items/batch |
Batch ingest multiple memories in a single atomic transaction. |
| GET | /active |
Retrieve all active and pinned memories for an agent namespace. Supports pagination. |
| GET | /context |
Generate formatted plain-text or JSON context ready for direct LLM system prompt injection. |
| POST | /sweep/staleness |
Execute pairwise staleness sweep. Flags and archives superseded facts. |
| POST | /sweep/redundancy |
Execute redundancy sweep. Detects identical or highly repetitive memories. |
| PATCH | /item/{id}/status |
Update item status: active, archived, or pinned. |
| GET | /stats |
Retrieve memory counts (active, pinned, archived) and sweep telemetry metrics. |
💡 Note on Interactive Dashboard (/ui): The web dashboard is served dynamically by the FastAPI server when running locally (sieve serve or sieve ui) or deployed as an API backend container. On static hosting providers (such as static Vercel deployments), the documentation and landing pages are served statically, while the interactive /ui dashboard requires the running FastAPI backend server.
# Ingest memory via HTTP curl -X POST http://localhost:8000/items \ -H "Content-Type: application/json" \ -H "X-API-Key: YOUR_SECRET_KEY" \ -d '{"text": "User preferred language is Python 3.12", "namespace": "user_42"}' # Trigger staleness sweep curl -X POST "http://localhost:8000/sweep/staleness?namespace=user_42" \ -H "X-API-Key: YOUR_SECRET_KEY" # Fetch compact prompt context curl "http://localhost:8000/context?namespace=user_42&format=text"
Python SDK Interface #
The Sieve Python library provides complete object models and lifecycle wrappers. Primary classes include:
SieveMemory(db_path, use_real_laya=False, policy_config=None): High-level developer wrapper with turnkey methods.Store(db_path): Thread-safe, WAL-enabled SQLite persistence layer with BM25 FTS5 indexing.PolicyEngine(store, config): Core rule evaluation engine containing staleness and redundancy algorithms.SievePipeline(store, scorer, policy): Fully orchestrated end-to-end pipeline.
PolicyEngine Configuration #
Fine-tune pruning aggression, similarity thresholds, and memory limits via PolicyConfig:
| Attribute | Type | Default | Description |
|---|---|---|---|
| staleness_threshold | float | 0.70 | Minimum lexical overlap required to flag older memory as superseded by newer assertion. |
| redundancy_threshold | float | 0.75 | Token similarity threshold for detecting duplicate or repeated memories. |
| min_importance_to_keep | float | 0.20 | Memories below this threshold are prioritized for auto-archiving during memory pressure. |
| retention_days | int | 30 | Age threshold after which unpinned memories are considered for archival. |
| max_active_items | int | 100 | Hard upper limit of active context items in prompt rendering. |
Authentication & Security #
Secure your Sieve HTTP service by configuring the SIEVE_API_KEY environment variable:
# Export secret key before launching API export SIEVE_API_KEY="sv_prod_89f3a920c812d" sieve serve --port 8000 # Requests must pass Authorization: Beareror X-API-Key:
When SIEVE_API_KEY is active, the interactive Dashboard (/ui) prompts for your key and caches it in this browser's localStorage to authenticate all background polling calls.
SQLite WAL Mode & Concurrency #
Sieve initializes SQLite with Write-Ahead Logging (WAL) mode and a 30-second busy timeout. This architecture guarantees:
- Concurrent Readers & Writers: Readers never block writers, and writers never block readers. Multiple parallel agent threads can fetch context while worker processes ingest new turns.
- Thread-Safe Store: Each API request is scoped with its own isolated SQLite connection and automatic lifecycle cleanup.
Zero-Downtime Backups & Migrations #
Never risk database corruption with raw file copies. Sieve utilizes the SQLite Online Backup API for hot, atomic live snapshots:
from sieve import Store store = Store("production.db") # Execute online backup without locking concurrent writers store.backup("/backups/sieve_backup_2026_10_11.db") print("Atomic snapshot completed successfully.")
Background Daemon Worker #
Run Sieve's autonomous background worker in Python to score pending memories and run curation sweeps continuously across agent namespaces:
from sieve import SieveMemory memory = SieveMemory("production.db") # Start autonomous background worker checking and sweeping every 60 seconds memory.start_daemon(interval_seconds=60.0, namespaces=["user_prod", "agent_session"]) # Stop worker when shutting down # memory.stop_daemon()
CLI Command Reference #
| Command | Arguments | Description |
|---|---|---|
sieve serve / sieve ui |
--host, --port, --db, --api-key |
Launch FastAPI REST API server and interactive UI dashboard. |
sieve remember |
"<text>", --namespace, --db |
Ingest and score a single text memory from the shell. |
sieve context |
--namespace, --max-items, --db |
Print active memories formatted for LLM system prompt injection. |
sieve sweep |
--namespace, --db |
Trigger immediate staleness and redundancy sweeps. |
sieve pin / sieve unpin |
<item_id>, --db |
Protect critical guidelines from pruning or remove pinned status. |
sieve stats |
--namespace, --db |
Display summary counts of active, pinned, and archived memories. |
sieve backup |
<destination>, --db |
Create an atomic online backup of SQLite database in WAL mode. |