Memory & State
Manage persistent memory and conversational state across agent sessions.
Overview
The isA Agent SDK provides multiple layers of memory to give agents context awareness:
- Session memory — conversational context within a single session
- Checkpointing — durable state that survives restarts
- Working memory — short-lived context for active tasks
- Long-term memory — factual, episodic, semantic, and procedural memory stored via MCP
Session Memory
Within a session, agents automatically maintain conversational context using the ISAAgentClient:
from isa_agent_sdk import ISAAgentClient
async with ISAAgentClient() as client:
await client.query("My name is Alice")
async for msg in client.receive():
print(msg.content)
# Agent remembers the context
await client.query("What's my name?")
async for msg in client.receive():
print(msg.content) # "Your name is Alice"Session memory persists for the lifetime of the client connection. For multi-turn conversations, use ISAAgentClient instead of the stateless query() function.
Checkpointing (Durable State)
For long-running tasks, checkpointing saves execution state so agents can resume after interruptions:
from isa_agent_sdk import query, ISAAgentOptions, ExecutionMode
options = ISAAgentOptions(
execution_mode=ExecutionMode.COLLABORATIVE,
session_id="data-processing-001"
)
async for msg in query("Process all CSV files in /data", options=options):
if msg.is_checkpoint:
# Agent paused — respond to continue
await msg.respond({"continue": True})
elif msg.is_text:
print(msg.content, end="")Resume later from the saved checkpoint:
from isa_agent_sdk import resume
async for msg in resume("data-processing-001"):
print(msg.content)The checkpointer backend is configurable:
| Backend | Config | Description |
|---|---|---|
| Redis | CHECKPOINTER_BACKEND=redis | Recommended for production |
| Filesystem | CHECKPOINTER_BACKEND=filesystem | Local development fallback |
Working Memory
Working memory stores short-lived context for the current task. It is automatically managed by the agent during execution and cleared when the task completes.
# Working memory is used internally by the agent
# Access it programmatically via MCP tools:
from isa_agent_sdk import execute_tool
# Store context for current task
await execute_tool("store_working_memory", {
"key": "current_analysis",
"content": "User wants a performance report for Q1",
"ttl_minutes": 60
})
# Retrieve active working memories
memories = await execute_tool("get_active_working_memories", {})Long-Term Memory (MCP)
For persistent knowledge that spans sessions, the SDK integrates with the isA MCP memory service:
MemoryStack Helpers
Recent SDK builds expose MemoryStack helpers for listing stored memories and retrieving aggregate health/statistics data:
from isa_agent_sdk.stack.memory_stack import MemoryStack
memory = MemoryStack()
await memory.start()
items = await memory.list_memories(user_id="user_123", limit=20)
stats = await memory.get_stats(user_id="user_123")
await memory.stop()Use list_memories for inspection and debugging. Use get_stats when dashboards or health checks need summarized memory counts, backend state, or capacity signals.
Factual Memory
Store facts about users, projects, or domains:
await execute_tool("store_factual_memory", {
"subject": "user-123",
"predicate": "prefers",
"object": "dark mode",
"confidence": 0.95
})
# Search by subject
facts = await execute_tool("search_facts_by_subject", {
"subject": "user-123"
})Episodic Memory
Record events and interactions:
await execute_tool("store_episodic_memory", {
"event_type": "code_review",
"description": "Reviewed auth module - found 3 security issues",
"metadata": {"module": "auth", "issues_found": 3}
})Semantic Memory
Store conceptual knowledge:
await execute_tool("store_semantic_memory", {
"concept": "rate_limiting",
"category": "security_patterns",
"description": "Token bucket algorithm with Redis backend",
"related_concepts": ["throttling", "api_gateway"]
})Procedural Memory
Store how-to knowledge:
await execute_tool("store_procedural_memory", {
"task": "deploy_to_kubernetes",
"steps": [
"Build Docker image",
"Push to registry",
"Apply K8s manifests",
"Run health checks"
],
"preconditions": ["Docker installed", "kubectl configured"]
})Searching Memories
# General search across all memory types
results = await execute_tool("search_memories", {
"query": "user preferences for UI",
"memory_types": ["factual", "episodic"],
"limit": 10
})
# Get memory statistics
stats = await execute_tool("get_memory_statistics", {})Memory in Steward Mode
When using the agent as a Steward, memory is used automatically to:
- Remember user preferences and habits
- Track task history and completion patterns
- Store calendar context for scheduling
- Maintain trigger conditions and alert history
Tiered Memory Architecture
Sprint 3 (PR #528) replaced the flat summary string with a three-tier in-process memory model. The tiers mirror how humans consolidate experience: active context, recent episodes, and compressed long-term knowledge.
┌─────────────────────────────────────────────────────┐
│ Agent State (LangGraph) │
│ │
│ ┌─────────────────┐ │
│ │ Working Memory │ ← current task context │
│ │ (messages[]) │ cleared when task ends │
│ └────────┬────────┘ │
│ │ summarize on overflow │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Episodic Memory │ ← summary_chain[] │
│ │ (recent sessions│ one entry per episode │
│ │ as summaries) │ rolling, incremental │
│ └────────┬────────┘ │
│ │ meta-compaction when threshold reached │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Semantic Memory │ ← compressed knowledge │
│ │ (long-term, │ persists across sessions │
│ │ compressed) │ stored via MCP │
│ └─────────────────┘ │
└─────────────────────────────────────────────────────┘Memory Tiers
| Tier | Scope | Backing Field | Lifecycle |
|---|---|---|---|
| Working | Current task | messages[] | Cleared on task completion |
| Episodic | Recent session history | summary_chain[] | Rolling summaries, pruned by threshold |
| Semantic | Long-term compressed knowledge | MCP memory service | Persists across sessions |
New State Fields
Three new fields were added to the agent state schema:
| Field | Type | Description |
|---|---|---|
summary_chain | list[str] | Ordered list of episode summaries. Each entry is a compressed narrative of one past episode. |
last_summary_index | int | Pointer into the message log marking where the last incremental summary was taken. Used by rolling summarization to avoid re-summarizing already-processed messages. |
meta_compaction_threshold | int | Number of entries in summary_chain that triggers meta-compaction. When the chain exceeds this value, all episodes are compressed into a single semantic memory entry and the chain is reset. Default: 10. |
Rolling Summarization
Previous versions performed batch summarization — the full message history was compressed in one pass whenever context grew too large. Sprint 3 (PR #522) replaced this with progressive rolling summarization:
- After each exchange, new messages since
last_summary_indexare summarized into a new episode entry. - The summary is appended to
summary_chain. last_summary_indexadvances to the current end of the message log.- Only the delta is processed, keeping summarization fast and predictable.
Meta-Compaction
When summary_chain exceeds meta_compaction_threshold, meta-compaction fires:
- All entries in
summary_chainare compressed into a single semantic memory artifact. - The artifact is written to the MCP semantic memory store (see Long-Term Memory).
summary_chainis reset to an empty list.last_summary_indexis set to the current end of the message log.
This prevents summary_chain from growing indefinitely while preserving durable knowledge in semantic memory.
Configuration Example
from isa_agent_sdk import ISAAgentOptions
options = ISAAgentOptions(
session_id="research-session-001",
# How many episode summaries to accumulate before compacting
# into semantic memory. Lower values reduce memory footprint;
# higher values preserve more short-term episodic detail.
meta_compaction_threshold=10,
)To inspect the current state of the memory tiers during a session:
from isa_agent_sdk import get_session_state
state = await get_session_state("research-session-001")
# Episodic tier
print(f"Episodes in chain: {len(state['summary_chain'])}")
print(f"Last summary index: {state['last_summary_index']}")
print(f"Compaction threshold: {state['meta_compaction_threshold']}")
# Print each episode summary
for i, episode in enumerate(state["summary_chain"]):
print(f"\n--- Episode {i + 1} ---")
print(episode)Best Practices
- Use session memory for conversational context — it’s automatic with
ISAAgentClient - Use checkpointing for tasks that may take a long time or need to survive restarts
- Use long-term memory for knowledge that should persist across sessions
- Set TTLs on working memory to avoid stale context accumulating
- Use factual memory for structured facts (user preferences, project metadata)
- Use episodic memory for event logs (reviews, deployments, decisions)
- Tune
meta_compaction_thresholdbased on session length — increase for long research sessions, decrease for short interactive tasks to keep memory lean