Observed since 20 Oct, 22:40 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
Memory Fast and Slow for AI Agents
Memory Fast and Slow for AI Agents
A dual-store memory system inspired by Kahneman's "Thinking, Fast and Slow" — giving AI agents persistent, intelligent memory that survives context window limits.
AI agents lose context. When conversations get long, older messages get compacted or dropped. Critical information vanishes:
User: "Let's continue the project"
Agent: "I apologize, but I don't have context about what project..."
memfas fixes this with persistent memory that lives outside the context window.
[v0.1] Core Memory
[v0.2] Pluggable Backends
memfas reindex — migrate between backends[v0.3] Dynamic Context Curation
[v0.3.1] Curation Levels
auto level ready for smart selection[v0.4] Context Management
pip install agent-memfas # Core (FTS5, zero deps)
pip install agent-memfas[embeddings] # + semantic search
pip install agent-memfas[v3] # + dynamic curation
pip install agent-memfas[context] # + context management (v0.4)
pip install agent-memfas[all] # Everything
# Initialize
cd ~/my-agent && memfas init
# Add keyword triggers (Type 1)
memfas remember alice --hint "Project manager, prefers async communication"
memfas remember acme --hint "Client project, due Q2, React frontend"
# Index your memory files (Type 2)
memfas index ./MEMORY.md ./memory/
# Recall context
memfas recall "What did Alice say about the deadline?"
# → Returns triggered + searched memories
from agent_memfas import Memory
# Initialize
mem = Memory("./memfas.yaml")
# Type 1: Instant triggers
mem.add_trigger("alice", "Project manager, prefers async")
# Type 2: Index and search
mem.index_file("./MEMORY.md")
results = mem.search("preference learning", limit=5)
# Combined recall
context = mem.recall("What did Alice say about the deadline?")
print(context) # Ready to inject into LLM prompt
from agent_memfas import Memory
from agent_memfas.embedders.fastembed import FastEmbedEmbedder
# Local embeddings (~130MB model, runs on CPU)
mem = Memory(
"./memfas.yaml",
search_backend="embedding",
embedder=FastEmbedEmbedder()
)
# Now finds conceptually related content
results = mem.search("machine learning concepts")
from agent_memfas.v3 import ContextCurator
curator = ContextCurator("./memfas.yaml")
# Get curated context within token budget
result = curator.get_context(
query="what's the project status?",
session_id="main",
baseline_tokens=50000 # Your context limit
)
print(f"Curated: {result.curated_tokens} tokens")
print(f"Saved: {result.tokens_saved} ({result.compression_ratio:.0%})")
print(result.context) # Inject this into your prompt
from agent_memfas.context import ContextManager
# Initialize with callbacks for your agent's context
ctx = ContextManager(
config_path="./memfas.yaml",
memfas_memory_path="./memfas.yaml", # enables embedding-based scoring
get_context=lambda: current_messages,
set_context=lambda msgs: replace_messages(msgs),
get_token_count=lambda: count_tokens(current_messages),
get_messages=lambda n: current_messages[-n:],
)
# In your agent loop:
# 1. New message arrived
ctx.on_message(user_message, current_messages)
ctx.set_current_prompt(user_message)
# 2. Before generating response — checks health, auto-compacts if needed
status = ctx.before_response(max_tokens=100000)
print(f"Context: {status.pct_used:.0%} used, compaction: {status.needs_compaction}")
# 3. After response
ctx.after_response()
# 4. Session ending — archives to cold storage
ctx.session_end()
# 5. Need something back from cold storage?
recovered = ctx.recover("what was the database migration plan")
┌─────────────────────────────────────────────────────────────┐
│ agent-memfas │
├─────────────────────────────────────────────────────────────┤
│ v0.4: Context Management │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Context │ │Relevance │ │ Cold │ │Summarizer│ │
│ │ Manager │→ │ Scorer │→ │ Storage │→ │ (MiniMax)│ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ ↓ │
│ KEEP / SUMMARIZE / DROP → Recoverable for 30 days │
├─────────────────────────────────────────────────────────────┤
│ v0.3: Context Curation │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Topic │ │Relevance │ │ Token │ │ Session │ │
│ │ Detector │→ │ Scorer │→ │ Budget │→ │ State │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
├─────────────────────────────────────────────────────────────┤
│ v0.2: Search Backends │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ FTS5Backend │ │EmbeddingBackend │ │
│ │ (zero deps) │ │ (sqlite-vec) │ │
│ └─────────────────┘ └─────────────────┘ │
│ ↑ ↑ │
│ └──────┬───────────────┘ │
│ │ │
│ ┌───────────────┐ │
│ │ SearchBackend │ ← Pluggable interface │
│ │ ABC │ │
│ └───────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ v0.1: Core Memory │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Type 1: Fast │ │ Type 2: Slow │ │
│ │ Triggers │ │ Search │ │
│ │ O(1) │ │ O(log n) │ │
│ └─────────────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Create memfas.yaml:
db_path: ./memfas.db
sources:
- path: ./MEMORY.md
type: markdown
- path: ./memory/*.md
type: markdown
triggers:
- keyword: alice
hint: "Project manager, prefers async"
- keyword: work
hint: "Current projects"
search:
max_results: 5
recency_weight: 0.3 # Favor recent memories
min_score: 0.1
| Command | Description |
|---|---|
memfas init | Initialize in current directory |
memfas recall <context> | Recall memories (Type 1 + Type 2) |
memfas search <query> | Search only (Type 2) |
memfas remember <kw> --hint <h> | Add trigger |
memfas forget <keyword> | Remove trigger |
memfas triggers | List all triggers |
memfas index <paths...> | Index files/directories |
memfas suggest | Auto-suggest triggers from content |
memfas stats | Show statistics |
memfas clear | Clear indexed memories |
memfas curate <query> | Get curated context (v0.3) |
memfas telemetry summary | View performance stats (v0.3) |
Context Management (v0.4) — Python API only for now:
from agent_memfas.context import ContextManager, ContextConfig
# Status check
ctx.status() # Returns ContextStatus with tokens, chunks, pct_used
# Manual compaction
result = ctx.compact() # Returns CompactionResult
# Cold storage recovery
chunks = ctx.recover("database migration")
# Health metrics
ctx.health_check() # Dict with tokens, cold storage count, config
| Embedder | Install | Model | Notes |
|---|---|---|---|
| FastEmbed | pip install fastembed | bge-small-en | Recommended, ~130MB |
| Ollama | ollama pull nomic-embed-text | nomic-embed | Good if using Ollama |
Input: "What's the status on the acme project?"
↓
Trigger table scan: "alice" → match!
↓
Return hint + linked memories instantly
FTS5 (default):
Input: "preference learning papers"
↓
BM25 ranking + recency decay
↓
Top results by relevance
Embeddings:
Input: "machine learning concepts"
↓
Generate query embedding
↓
KNN search (cosine similarity)
↓
Semantically related results
Context: "Let's continue the project discussion"
↓
┌─────────────────────────────────────┐
│ 1. Detect topic: "project" │
│ 2. Score all memories: │
│ - Semantic relevance: 0.85 │
│ - Recency: 0.92 │
│ - Topic continuity: 0.78 │
│ - Access pattern: 0.65 │
│ 3. Fill 8000 token budget │
│ 4. Return curated context │
└─────────────────────────────────────┘
↓
Result: 84% token reduction, focused context
Context window at 50% capacity
↓
┌─────────────────────────────────────┐
│ 1. Score each chunk: │
│ score = (embedding_sim × 0.6) │
│ + (recency_decay × 0.2) │
│ + (importance × 0.1) │
│ │
│ 2. Classify: │
│ ≥ 0.7 → KEEP │
│ 0.3-0.7 → SUMMARIZE (MiniMax) │
│ ≤ 0.3 → DROP to cold storage │
│ │
│ 3. Enforce min_chunks_to_keep │
│ 4. Log all drops for debugging │
└─────────────────────────────────────┘
↓
Result: Pre-emptive compaction, recoverable drops
Recency decay: Exponential with ~4h half-life. A chunk added 6h ago retains 37% of recency bonus.
Cold storage recovery: Jaccard-ranked search with stopword filtering. Chunks recoverable for 30 days.
| Metric | v0.1 | v0.2 | v0.3 | v0.4 |
|---|---|---|---|---|
| Trigger lookup | O(1) | O(1) | O(1) | O(1) |
| FTS5 search | O(log n) | O(log n) | O(log n) | O(log n) |
| Embedding search | - | O(n) | O(n) cached | O(n) cached |
| Token reduction | - | - | 84% | dynamic |
| Warm query latency | - | - | 8ms | <10ms |
| Cold storage recovery | - | - | - | Jaccard O(n) |
| Summarization | - | - | - | MiniMax API |
## Memory (in AGENTS.md)
Before answering about prior work:
1. Run `memfas recall "<context>"`
2. Include returned context in reasoning
After compaction:
1. Run `memfas recall "current project"`
2. Check `memfas triggers`
# In your agent loop — with v0.3 Curation
from agent_memfas.v3 import ContextCurator
curator = ContextCurator("./memfas.yaml")
def get_response(user_message):
# Get curated memory context
mem_result = curator.get_context(
query=user_message,
session_id="main",
baseline_tokens=100000
)
# Inject into prompt
prompt = f"""
{mem_result.context}
User: {user_message}
"""
return llm.complete(prompt)
from agent_memfas.context import ContextManager
class Agent:
def __init__(self):
self.messages = []
self.ctx = ContextManager(
config_path="./memfas.yaml",
memfas_memory_path="./memfas.yaml",
get_context=lambda: self.messages,
set_context=lambda m: setattr(self, 'messages', m),
get_token_count=lambda: sum(len(m['content'])//4 for m in self.messages),
get_messages=lambda n: self.messages[-n:],
)
def handle_message(self, user_input: str) -> str:
self.messages.append({"role": "user", "content": user_input})
# Pre-response: check health, auto-compact if needed
self.ctx.set_current_prompt(user_input)
status = self.ctx.before_response(max_tokens=100000)
# Generate response (your LLM call here)
response = self.generate(self.messages)
self.messages.append({"role": "assistant", "content": response})
self.ctx.after_response()
return response
def end_session(self):
self.ctx.session_end() # Archives to cold storage
Add to your memfas.yaml:
context:
compaction_trigger_pct: 0.50 # Trigger early at 50%
relevance_cutoff: 0.3 # DROP below this score
relevance_keep_threshold: 0.7 # KEEP above this score
min_chunks_to_keep: 5 # Safety floor
# Scoring weights
memfas_weight: 0.6 # Embedding similarity weight
recency_bonus: 0.2 # Max recency boost (decays over ~4h)
importance_bonus: 0.1 # Flat boost for important chunks
# Cold storage
cold_storage_enabled: true
cold_storage_path: "./cold-storage/"
recoverable_days: 30
# Summarization (optional)
summarize_medium_chunks: true
summary_model: "minimax/MiniMax-M2.1" # Set MINIMAX_API_KEY env var
# Logging
log_path: "./logs/context/"
log_compaction: true
log_drops: true
/docs for architecture decisionsMIT
Built for AI agents that need to remember. Inspired by losing context while building a memory system.
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.4.0 | 4 Feb 2026 | 7 |
This describes our collected data; it is not a security assessment.
Observed since 20 Oct, 22:40 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:7f5bc4b092db10d779402eb5f48c54f4ccf5784193667a51e474c0412cd4b140