Memory and Recall
Choose what agents remember, how they recall it, and when it expires.
#Memory and Recall
A model on its own forgets everything once a conversation gets long enough. Memory is how mAIvn gives an agent a working recollection: it remembers what was said earlier, pulls back the parts that matter for the current question, and learns reusable lessons over time.
Concretely, memory keeps long-running conversations accurate by combining:
- summarization when thread context grows too large
- retrieval of relevant memory signals (vector, keyword, graph, skills, insights, resources)
- asynchronous post-finalize indexing and extraction
#How It Works
Each invocation can include three core stages:
- Summarize: compacts history before execution when needed.
- Retrieve: injects relevant memory context into the current turn.
- Index: persists new memory after the response is returned.
Indexing is asynchronous by design, so latency-sensitive responses are not blocked by persistence work.
#Thread Recall vs Scope-Shared Assets
Memory is intentionally split into two layers:
- Thread recall: summaries, vector hits, keyword hits, graph neighbors, and other transcript-like recall stay tied to the current
thread_id. - Scope-shared assets: skills, bound resources, and promoted insights are reusable across future threads within their sharing scope (
agent,swarm,project, ororg).
This means future threads already benefit from scoped skills and resources. AI-generated insights are narrower by default: auto extraction only supports agent or swarm, and broader reuse happens through portal promotion to project or org.
#Memory Levels
MemoryConfig.level controls recall context size. It does not by itself select retrieval-only or vector-only persistence:
Use persistence_mode="persist_none" for retrieval without new persistence, "vector_only" to exclude graph extraction, or "vector_plus_graph" to permit it. Configured SDK memory defaults to enabled, clarity, and vector_plus_graph when those fields are omitted. The runtime and tenant policy can further restrict behavior. Explicit bound-resource access for a schema-bearing request has separate handling; see Structured Output.
#Quick Start
Use a stable thread_id and set scope defaults:
from maivn import (
Agent,
MemoryConfig,
MemoryInsightExtractionConfig,
MemoryRetrievalConfig,
MemorySkillExtractionConfig,
)
from maivn.messages import HumanMessage
agent = Agent(
name="memory_demo",
system_prompt="Use prior context when relevant.",
api_key="your-api-key",
memory_config=MemoryConfig(
enabled=True,
level="clarity", # none | glimpse | focus | clarity
persistence_mode="vector_plus_graph",
retrieval=MemoryRetrievalConfig(
top_k=4,
skills_enabled=True,
insights_enabled=True,
resources_enabled=True,
),
skill_extraction=MemorySkillExtractionConfig(
enabled=True,
),
insight_extraction=MemoryInsightExtractionConfig(
enabled=True,
),
),
)
thread_id = "customer-success-q1"
agent.invoke(
messages=[HumanMessage(content="Store this rollout plan and owners.")],
thread_id=thread_id,
)
result = agent.invoke(
messages=[HumanMessage(content="Who owns the rollout milestones?")],
thread_id=thread_id,
)#Scope Memory Assets
Agent and Swarm can define memory assets directly:
skills: user-defined reusable skill payloadsresources: bound resource payloads (inline content, file, URL, or document reference)
Use add_skill to register and attach a skill, or attach_skill for an existing ID. Constructor skills declarations are only stored locally in this SDK. Constructor resources are uploaded before first invocation; set binding_type to bind them to the scope. These paths do not transmit MemoryAssetsConfig.
agent = Agent(
name="deploy_agent",
api_key="your-api-key",
memory_config=MemoryConfig(
level="clarity",
),
resources=[
{
"name": "deploy-runbook.txt",
"mime_type": "text/plain",
"text_content": "Rollback immediately if canary validation fails.",
"binding_type": "agent",
"sharing_scope": "agent",
"tags": ["deploy", "rollback"],
}
],
)
agent.add_skill(
name="deploy_with_health_checks",
description="Deploy, run health checks, then cut over traffic.",
steps=["Deploy the service.", "Check service health before switching traffic."],
)#Bound Resource Versioning
Scope resource declarations are uploaded once per scope instance. Content hashes support server-side deduplication, but the upload still sends the bytes. Changing a file after registration does not make that same scope upload again.
For an explicit replacement version, use client.resources.upload with ResourceUploadOptions(resource_id=existing_id). The constructor path does not forward resource_id as a replacement request. See SDK Resource Configuration.
#Message Attachments
HumanMessage and RedactedMessage support attachments. Attachment payloads are normalized and sent as document candidates for registration.
from maivn.messages import HumanMessage
message = HumanMessage(
content="Use the attached runbook for this request.",
attachments=[
{
"name": "runbook.txt",
"mime_type": "text/plain",
"text_content": "Escalate if error rate exceeds 2%.",
"sharing_scope": "project",
"tags": ["runbook", "ops"],
}
],
)Supported attachment inputs include content_base64, content_bytes, text_content, and file.
#Per-Invocation Overrides
Override scope defaults per call with memory_config:
from maivn import MemoryConfig, MemoryRetrievalConfig
result = agent.invoke(
messages=[HumanMessage(content="Use retrieval only for this turn.")],
thread_id=thread_id,
memory_config=MemoryConfig(
level="glimpse",
retrieval=MemoryRetrievalConfig(
skills_enabled=True,
insights_enabled=True,
resources_enabled=True,
skill_injection_max_count=3,
insight_injection_max_count=2,
resource_injection_max_count=2,
),
),
)#Observe Memory and Resource Events
Use event streaming to inspect enrichment phases:
events = []
def on_event(event: dict) -> None:
if event.get("event") != "enrichment":
return
payload = event.get("payload") or {}
phase = payload.get("phase")
if isinstance(phase, str) and (
phase.startswith("memory_") or phase.startswith("document_")
):
events.append(
{
"phase": phase,
"message": payload.get("message"),
"memory": payload.get("memory"),
}
)
agent.events(include="enrichment", on_event=on_event).invoke(
messages=[HumanMessage(content="Recall the project constraints.")],
thread_id=thread_id,
)Common memory phases:
memory_summarizingmemory_summarizedmemory_retrievingmemory_retrievedmemory_indexingmemory_graph_extractingmemory_indexedmemory_skill_extractingmemory_insight_extracting
Common resource phases:
resource_registeringresource_registeredresource_dedup_reusedresource_version_supersededresource_extractingresource_extracted
payload.memory can include hit counts, per-signal counts (skill_hits, insight_hits, resource_hits), latency, and effective memory level.
#Async Post-Finalize Behavior
Memory extraction can finish after the response stream closes. An extraction-start event or a non-zero retrieval count does not prove that the latest invocation's assets were saved.
Use client.memory.enrichments.list(session_id) or its async alist counterpart to read persisted outcomes. A receipt reports completed or failed and skill, insight, and graph-edge counts. Completed can legitimately mean zero assets. An empty receipt list does not imply completion; if polling, use a bounded retry policy and retain a pending state when no receipt arrives.
#Configuration Reference
Active SDK controls include enabled, level, persistence_mode, retrieval signal toggles and injection counts, and extraction enabled/max_count. Graph retrieval and extraction controls are also available.
The compatibility fields summarization_enabled, candidate_limit, insight_relevance_floor, extraction sharing_scope, confidence_threshold, and min_relevance_score are accepted but not forwarded. Do not rely on them to change behavior. Nested per-call configuration replaces the corresponding nested scope configuration rather than merging each nested field.
See Session Config Models for exact fields, validation, and request behavior. Invocation metadata is ignored; it is not an alternate configuration channel.