Memory¶
Auto-generated from source docstrings (mkdocstrings). The complete public contract is agentmaker.__all__ plus each subpackage __all__.
agentmaker.memory
¶
agentmaker.memory: memory subsystem (built on top of the agentmaker.retrieval base).
Provided
- MemoryItem: the data type for a single memory (type is a free-form label).
- MemoryStore: the memory source-of-truth store (full memories persisted by id in SQLite).
- Memory: semantic memory combining the source-of-truth store with the retrieval base; add / search / update / delete + forget / stats / summary / consolidate (the source-to-derived-index sync seam IndexSync / SyncIndexSync is shared with RAG and lives in agentmaker.retrieval).
- SmartWriter: Mem0-style smart writing (extract facts -> ADD/UPDATE/DELETE/NOOP).
- MemoryTool: wraps memory as a tool so an agent can actively record / recall (agentic memory).
- KVStore / KVMemory: key-value memory, structured facts stored and read by exact key (complements semantic memory).
KVMemory
¶
Key-value memory facade: adds JSON encode/decode on top of KVStore, supporting str / number / list / dict values; carries a fixed scope.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
kv
|
KVStore
|
the underlying key-value store. |
required |
scope
|
Optional[Scope]
|
the ownership of this facade (e.g. a given user); defaults to Scope(base="kv"). |
None
|
KVStore
¶
Key-value store: (scope, key) is unique, set writes by overwrite, get reads exactly. Values are strings.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
db_path
|
str
|
SQLite file path; defaults to ":memory:" for self-tests only. |
':memory:'
|
lock
|
Optional[RLock]
|
a reentrant lock serializing the connection; pass the same one when sharing a connection with another store, otherwise a new one is created. |
None
|
set
¶
set(key: str, value: str, *, scope: Optional[Scope] = None, all_scopes: bool = False) -> None
Overwrite-write: update value if (scope, key) already exists, otherwise insert.
Rejects an empty scope (unless all_scopes=True is explicit): an empty scope would write into an "ownerless" row mixed in with all users, which is a slip.
get
¶
get(key: str, *, scope: Optional[Scope] = None, all_scopes: bool = False) -> Optional[str]
Read exactly by key; returns None if not found.
Rejects an empty scope (unless all_scopes=True is explicit): an empty scope adds no ownership filter and would read another user's value. When the scope spans multiple sub-ownerships (a coarse scope hits several rows for the same key), fail loud: KV semantics are "one value per key under a scope" and require a unique footprint.
delete
¶
delete(key: str, *, scope: Optional[Scope] = None, all_scopes: bool = False) -> None
Delete a key.
Rejects an empty scope (unless all_scopes=True is explicit): an empty scope would delete this key across all users, which is a dangerous operation.
all
¶
all(*, scope: Optional[Scope] = None, all_scopes: bool = False) -> dict
Return all key-values under this scope (as a dict).
Rejects an empty scope (unless all_scopes=True is explicit): an empty scope would read across users. When the
same key appears in multiple matched sub-ownerships (a coarse scope / all_scopes spanning users), fail loud: a
dict cannot represent duplicate keys, so ambiguity requires an exact scope or per-scope reads.
Memory
¶
Memory(retriever: HybridRetriever, store: MemoryStore, *, llm: Optional[LLMClient] = None, scope: Optional[Scope] = None, config: Optional[MemoryConfig] = None, index_sync: Optional[IndexSync] = None, tracer: Optional[Tracer] = None)
Memory manager: coordinates the source-of-truth store (MemoryStore) with the retrieval index (HybridRetriever).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
retriever
|
HybridRetriever
|
Retrieval backend handling the read path (vector + keyword + RRF + optional rerank). |
required |
store
|
MemoryStore
|
The memory source-of-truth store, holding complete MemoryItem records. |
required |
llm
|
Optional[LLMClient]
|
Optional; used by summary / consolidate. Calling those two without it raises. |
None
|
scope
|
Optional[Scope]
|
Default ownership label that isolates memories from rag documents and from different users / agents; defaults to Scope(base="memory"). |
None
|
config
|
Optional[MemoryConfig]
|
Optional memory knobs (scoring weights / halflife / search_top_k / summary_top_k / batch_size / default_importance / forget_threshold); defaults to MemoryConfig(). Per-call kwargs on each method override these (three-level resolution). |
None
|
index_sync
|
Optional[IndexSync]
|
Optional derived-index sync seam (IndexSync, see index_sync.py); write paths (add/update/delete/rebuild) propagate changes to the retrieval index and reconcile through it. Defaults to SyncIndexSync(retriever) (synchronous write-through + in-process tracking); for async / distributed delivery (outbox + worker), implement one and inject it, and the Memory write paths stay unchanged. |
None
|
tracer
|
Optional[Tracer]
|
Optional tracer (duck-typed emit, same shape as Harness); once attached, search emits memory_search events and the summary / consolidate LLM calls flow into trace and RunPolicy governance. Zero overhead when not attached. |
None
|
from_config
classmethod
¶
from_config(config: AgentmakerConfig, *, embedder: Optional[Embedder] = None, retriever: Optional[HybridRetriever] = None, store: Optional[MemoryStore] = None, llm: Optional[LLMClient] = None, db_path: str = ':memory:', reranker: Optional[Reranker] = None, scope: Optional[Scope] = None, retrieval: Optional[RetrievalConfig] = None, index_sync: Optional[IndexSync] = None, tracer: Optional[Tracer] = None) -> Memory
Assemble a Memory in one line from an AgentmakerConfig: defaults to the sqlite backend; pass retriever / store to inject a custom backend (without touching framework source).
Pluggable backends follow the "assembly root lives in the app" principle (the library does not hardwire the wiring, it only ships default batteries; wiring is the app's job): to swap in pgvector or similar, implement the retrieval VectorStore / KeywordIndex interfaces and pass the retriever (plus store if needed); otherwise build_sqlite_hybrid is used.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
AgentmakerConfig
|
AgentmakerConfig (reads config.memory; the default backend's retrieval knobs come from retrieval or config.retrieval). |
required |
embedder
|
Optional[Embedder]
|
Text-to-vector encoder; required when using the default sqlite backend, unneeded when a retriever is injected. |
None
|
retriever
|
Optional[HybridRetriever]
|
Inject a custom retrieval backend (HybridRetriever); defaults to building the sqlite backend. |
None
|
store
|
Optional[MemoryStore]
|
Inject a custom memory metadata store; defaults to MemoryStore(db_path). |
None
|
retrieval
|
Optional[RetrievalConfig]
|
Optional RetrievalConfig override (for the default backend): pass it when memory and rag should use different retrieval knobs. Note: Memory's return count / candidate pool is set by MemoryConfig.search_top_k plus an internal strategy (x4), which overrides the backend RetrievalConfig's top_k / candidate_pool; for memory the backend config mainly just supplies rrf_k (the fusion constant). |
None
|
Example
mem = Memory.from_config(AgentmakerConfig(memory=MemoryConfig(recency_halflife_hours=24)), embedder=emb, scope=ALICE)
add
¶
add(content: str, *, type: str = 'semantic', importance: Optional[float] = None, metadata: Optional[dict] = None, scope: Optional[Scope] = None) -> MemoryItem
Record a memory: build a MemoryItem, persist to the source-of-truth store (authoritative), sync into the retrieval index through the seam, and return the item.
An index write failure does not roll back the store; the entry is marked pending reindex (the store is authoritative and eventually consistent, see index_sync / pending_reindex). (This stores directly; for de-duplicating / updating "smart writes" of the same fact see SmartWriter.)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
content
|
str
|
The memory body text. |
required |
type
|
str
|
Memory type (free-form label, defaults to semantic). |
'semantic'
|
importance
|
Optional[float]
|
Importance 0..1; when None, uses self.cfg.default_importance (an explicit 0 is not swallowed). |
None
|
metadata
|
Optional[dict]
|
Attached information. |
None
|
scope
|
Optional[Scope]
|
Ownership label for this item; defaults to the Memory's default scope. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
MemoryItem |
MemoryItem
|
The newly created and persisted memory. |
update
¶
update(id: str, content: str, *, scope: Optional[Scope] = None) -> Optional[MemoryItem]
Update a memory's body text: the store deletes the old row and inserts the new one in a single transaction (authoritative, no lost rows), and the index converges via an upsert through the seam. Returns None if the item is not in this scope.
Scope defaults to this Memory's scope (by default it only touches its own, preventing cross-scope edits); it mirrors add's scope= to allow explicit targeting when multiple scopes share one Memory instance (e.g. a coarse-ownership instance editing a fine-ownership memory). Deleting the old and writing the new go through store.replace in one transaction, so a mid-way crash does not lose this memory. An index write failure does not roll back the store; the entry is marked pending reindex and converges via rebuild_index or read-time self-heal (store authoritative, eventually consistent).
invalidate
¶
invalidate(id: str, *, superseded_by: Optional[str] = None, scope: Optional[Scope] = None) -> Optional[MemoryItem]
Exclude a memory from retrieval while retaining its audit record.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
id
|
str
|
The memory id to invalidate. |
required |
superseded_by
|
Optional[str]
|
Optional id of the replacement memory. |
None
|
scope
|
Optional[Scope]
|
Ownership; defaults to this Memory's scope. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
MemoryItem |
Optional[MemoryItem]
|
The item marked invalid; None if not in this scope. |
delete
¶
delete(id: str, *, scope: Optional[Scope] = None) -> None
Delete a memory from the authoritative store and request index cleanup.
delete_many
¶
delete_many(ids: List[str], *, scope: Optional[Scope] = None) -> None
Delete memories from the authoritative store and request best-effort index cleanup.
rebuild_index
¶
rebuild_index(*, scope: Optional[Scope] = None, batch_size: Optional[int] = None) -> int
Rebuild the retrieval index from the store: iterate all memories in this scope and re-write them into the retrieval backend (re-embed + reindex).
The store is the authoritative record and the index is its disposable derivative; this method delivers on "the derivative can be rebuilt from the record." Typical uses: after swapping the retrieval backend (e.g. SQLite vector store -> pgvector), import the data into the new index; or reload the whole thing when the index is corrupt or inconsistent with the store.
Notes
- retriever.add is an upsert (same id overwrites): a fresh build for an empty index, an in-place refresh for an existing one.
- Bookkeeping-known index orphans are removed per exact ownership footprint. Physical entries absent from bookkeeping remain covered by read-time self-heal.
- Rebuilds by this Memory's (or the given) scope; with one Memory instance per user, call rebuild_index for each.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scope
|
Optional[Scope]
|
Which ownership range to rebuild; defaults to this Memory's scope. |
None
|
batch_size
|
Optional[int]
|
Rows written per batch; batching avoids embedding too much at once on large stores. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
int |
int
|
The number of memories reloaded. |
pending_reindex
¶
pending_reindex(*, scope: Optional[Scope] = None) -> set
Return the set of ids pending reindex (recent index writes that failed and have not yet been converged by rebuild_index / reconcile).
Store authoritative, index eventually consistent (see index_sync): an index write failure does not roll back the store, it only marks the entry pending. An app can use this to monitor drift and periodically trigger rebuild_index to converge. The default backend's (SyncIndexSync) pending set is in-process state (cleared on restart, rebuildable via rebuild).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scope
|
Optional[Scope]
|
Which ownership range to query; defaults to this Memory's scope. |
None
|
search
¶
search(query: str, *, top_k: Optional[int] = None, scope: Optional[Scope] = None, relevance_weight: Optional[float] = None, recency_weight: Optional[float] = None, importance_weight: Optional[float] = None, recency_halflife_hours: Optional[float] = None, filters: Optional[List[MetadataFilter]] = None) -> List[RetrievalResult]
Recall the most relevant memories for a query, ranked by a combined relevance x recency x importance score.
Inspired by Generative Agents: the final score = each component normalized to 0..1 then weighted and summed. With all three weights at 0 it degrades to pure relevance ranking (backward compatible). Recency decays via a halflife: more recent approaches 1, older approaches 0. The knobs below default to self.cfg (MemoryConfig) when None (an explicit 0 is not swallowed).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
query
|
str
|
The query text. |
required |
top_k
|
Optional[int]
|
Number of results to return (defaults to cfg.search_top_k). |
None
|
relevance_weight
|
Optional[float]
|
Relevance weight (defaults to cfg.relevance_weight). |
None
|
recency_weight
|
Optional[float]
|
Recency weight (defaults to cfg.recency_weight). |
None
|
importance_weight
|
Optional[float]
|
Importance weight (defaults to cfg.importance_weight). |
None
|
recency_halflife_hours
|
Optional[float]
|
The recency halflife in hours (defaults to cfg.recency_halflife_hours); smaller favors newer memories more strongly. |
None
|
filters
|
Optional[List[MetadataFilter]]
|
Optional metadata hard filter (list of MetadataFilter, see agentmaker.retrieval.types), passed through to the retrieval backend for pre-filtering; the backend must have declared the corresponding filterable columns. Complements the three-way scoring (soft ranking): filters are hard constraints. |
None
|
Returns:
| Type | Description |
|---|---|
List[RetrievalResult]
|
List[RetrievalResult]: Ordered by combined score, highest first; metadata carries the relevance / recency / importance / final component scores. |
aupdate
async
¶
aupdate(id: str, content: str, **kwargs) -> Optional[MemoryItem]
Async variant of update (to_thread).
ainvalidate
async
¶
ainvalidate(id: str, **kwargs) -> Optional[MemoryItem]
Async variant of invalidate (to_thread).
adelete_many
async
¶
Async variant of delete_many (to_thread).
asearch
async
¶
asearch(query: str, **kwargs) -> List[RetrievalResult]
Async variant of search (to_thread).
arebuild_index
async
¶
Async variant of rebuild_index (to_thread; full re-embedding is a long network operation, so never run it synchronously on the event loop).
forget
¶
forget(*, strategy: str = 'importance', threshold: Optional[float] = None, max_age_days: Optional[float] = None, capacity: Optional[int] = None, scope: Optional[Scope] = None) -> List[str]
Forget by strategy, returning the list of deleted ids.
Strategies
importance: delete items with importance < threshold (threshold defaults to self.cfg.forget_threshold); age: delete items older than max_age_days days (requires max_age_days); capacity: keep only the "most important + newest" capacity items, delete the rest (requires capacity).
stats
¶
stats(*, scope: Optional[Scope] = None) -> dict
Stats: {total, by_type} (total count + distribution by type). Pure data, no LLM call.
summary
async
¶
summary(query: Optional[str] = None, *, top_k: Optional[int] = None, scope: Optional[Scope] = None) -> str
Use the LLM to summarize the selected memories into one paragraph (async: the LLM call awaits chat; the synchronous DB fetch runs in a thread pool).
Requires an llm passed at construction. top_k defaults to self.cfg.summary_top_k when None. Sync callers go through agentmaker.core.aio.run_sync.
consolidate
async
¶
consolidate(*, scope: Optional[Scope] = None) -> dict
Consolidate (async): hand all memories to the LLM to de-duplicate / merge / keep-latest-on-conflict, then replace them in the store; returns {before, after}. Requires an llm.
The LLM call awaits chat; the synchronous fetch / persist DB operations run in a thread pool. Sync callers go through agentmaker.core.aio.run_sync.
MemoryTool
¶
MemoryTool(memory: Memory, writer: Optional[SmartWriter] = None, *, top_k: int = 5, confirm_writer_edits: bool = True, scope_policy: Union[str, Callable] = 'fixed', inherit_dimensions: tuple = ('user', 'agent', 'app'), prompts=None)
Bases: Tool
A tool letting an Agent manage long-term memory: remember / recall / forget / summary / stats / consolidate.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
memory
|
Memory
|
The memory manager (provides search / forget / summary / stats / consolidate / add). |
required |
writer
|
Optional[SmartWriter]
|
Optional smart writer; when provided, remember goes through SmartWriter (auto de-duplicate / rewrite), otherwise it calls add directly. |
None
|
top_k
|
int
|
Number of results recall returns. |
5
|
confirm_writer_edits
|
bool
|
When a writer is attached, whether remember also passes through the confirmation gate (default True). SmartWriter may decide, per the LLM, to UPDATE / DELETE existing memories (soft-invalidate, rewrite), which modifies existing data, so by default it goes through the confirmation gate like forget / consolidate (fail-safe). Pure add (no writer) never gates. Pass False to disable in low-friction scenarios. |
True
|
scope_policy
|
Union[str, Callable]
|
|
'fixed'
|
inherit_dimensions
|
tuple
|
Dimensions used by |
('user', 'agent', 'app')
|
get_parameters
¶
get_parameters() -> List[ToolParameter]
Declare parameters: one action + content / query depending on the operation.
needs_confirmation
¶
Data-deleting / data-modifying actions require human confirmation: forget / consolidate always do; remember also does when a writer is attached and confirm_writer_edits is set (SmartWriter may UPDATE / DELETE existing memories). recall / summary / stats and pure-add remember pass through.
is_external_content
¶
Guard only calls that return persisted memory content.
run
¶
run(parameters: dict) -> ToolResponse
Dispatch by action to the memory operations, returning a result for the LLM to read (errors as status="error").
arun
async
¶
arun(parameters: dict) -> ToolResponse
Native async variant of run: LLM-calling actions (remember/summary/consolidate) go async via await; non-LLM ones (recall/stats/forget) reuse the sync logic directly (no network wait, no need for async).
SmartWriter
¶
SmartWriter(memory: Memory, llm: LLMClient, *, similar_k: Optional[int] = None, fail_open: bool = True, extract_prompt: Optional[str] = None, reconcile_prompt: Optional[str] = None, prompts: Optional[PromptRegistry] = None, tracer: Optional[Tracer] = None)
Mem0-style smart writing: extract facts -> compare against existing memories -> decide ADD/UPDATE/DELETE/NOOP -> execute.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
memory
|
Memory
|
The memory manager (provides search / add / update / delete). |
required |
llm
|
LLMClient
|
LLM client, used for fact extraction and reconcile decisions (ideally a cheap model such as deepseek). |
required |
similar_k
|
Optional[int]
|
How many similar existing memories to fetch per fact for the comparison; defaults to the injected memory's cfg.similar_k when None. |
None
|
fail_open
|
bool
|
Strategy when extraction parsing fails. True (default) degrades to storing the whole original text as a single fact, losing no information; False drops the segment and does not store it. Set False for chit-chat / long text / sensitive content you don't want stored wholesale. |
True
|
extract_prompt
|
Optional[str]
|
System prompt for fact extraction; defaults to the framework default (registry memory.extract). Pass your own to change language or tune the extraction categories. |
None
|
reconcile_prompt
|
Optional[str]
|
System prompt for the reconcile decision (ADD/UPDATE/DELETE/NOOP); defaults to the framework default (registry memory.reconcile). |
None
|
prompts
|
Optional[PromptRegistry]
|
Optional prompt registry (PromptRegistry, see agentmaker.prompts); defaults to the framework default DEFAULT_PROMPTS. extract_prompt / reconcile_prompt are its nearby shortcut overrides (equivalent to overriding the memory.extract / memory.reconcile keys). |
None
|
tracer
|
Optional[Tracer]
|
Optional tracer; defaults to following the injected memory's tracer. The extraction / reconcile LLM calls flow through governance (into trace and RunPolicy limits, see governed_chat in runtime/execution/run_context.py). |
None
|
write
async
¶
write(text: str, *, scope: Optional[Scope] = None) -> List[dict]
Smartly write a piece of input into memory (async); returns a processing record per fact (with op, so you can see what was done).
Extraction / reconcile await chat; retrieval uses memory.asearch and CRUD runs in a thread pool. Sync callers go through agentmaker.core.aio.run_sync.
Writing / reconciling / edits+deletes all land within the injected memory's scope: in multi-user scenarios, give each user its own Memory(scope=...) instance each with its own SmartWriter and isolation is natural (consistent with the alice/bob pattern).
MemoryStore
¶
Memory source-of-truth store: full MemoryItems persisted by id in SQLite.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
db_path
|
str
|
SQLite file path; defaults to ":memory:" for self-tests only. For real use pass a file path to persist (pass the same file path as the vector store / keyword index when sharing a database). |
':memory:'
|
lock
|
Optional[RLock]
|
a reentrant lock serializing the connection; pass the same one when sharing a connection with another store, otherwise a new one is created. |
None
|
save
¶
save(item: MemoryItem, *, scope: Optional[Scope] = None) -> None
Store a memory (overwrites if the same id + same scope already exists; same id under different scopes stays independent). metadata is stored as JSON, times as isoformat.
replace
¶
replace(id: str, item: MemoryItem, *, scope: Optional[Scope] = None) -> None
Atomically replace within a single transaction: delete the old row matching (id, scope) first, then insert item.
When a range scope resolves to one finer ownership footprint, that exact footprint is retained. Multiple matches fail without modifying the store.
get
¶
get(id: str, *, scope: Optional[Scope] = None) -> Optional[MemoryItem]
Fetch the full memory by id (including soft-invalidated ones; whether to filter is up to the caller); returns None if not found.
With a scope, the fetch is limited to that ownership (B semantics: only filter on non-empty dimensions), to avoid reading someone else's memory across scopes. Without a scope (None / empty Scope), fetch by id across the whole database (raw low-level use; the higher-level Memory always passes a scope).
get_with_scope
¶
get_with_scope(id: str, *, scope: Optional[Scope] = None) -> Optional[tuple[MemoryItem, Scope]]
Fetch one memory together with its exact stored ownership footprint.
touch
¶
touch(ids: List[str], *, scope: Optional[Scope] = None) -> None
Batch-write last_accessed_at = now (a retrieval hit means "got used", Generative Agents semantics); one commit.
delete
¶
delete(id: str, *, scope: Optional[Scope] = None) -> None
Delete a memory (within the scope-limited range, to avoid cross-ownership deletion).
delete_many
¶
delete_many(ids: List[str], *, scope: Optional[Scope] = None) -> None
Batch-delete memories (within the scope-limited range); one commit.
scopes_for_ids
¶
Resolve ids to every exact stored footprint within a scope range.
all
¶
all(*, scope: Optional[Scope] = None, include_invalid: bool = False) -> List[MemoryItem]
List all valid memories within the scope-limited range (in reverse time order; B semantics: only filter on non-empty dimensions).
With include_invalid=True, soft-invalidated ones are returned too (for auditing / inspecting the fact evolution chain). By default only valid ones are returned: rebuild_index / forget / consolidate / summary all build on this, so invalidated memories won't be re-indexed or revived by cleanup.
all_with_scopes
¶
all_with_scopes(*, scope: Optional[Scope] = None, include_invalid: bool = False) -> List[tuple[MemoryItem, Scope]]
List memories together with their exact stored ownership footprints.
MemoryConfig
dataclass
¶
MemoryConfig(relevance_weight: float = 1.0, recency_weight: float = 1.0, importance_weight: float = 1.0, recency_halflife_hours: float = 72.0, recency_anchor: str = 'created_at', search_top_k: int = 5, summary_top_k: int = 20, rebuild_batch_size: int = 256, similar_k: int = 5, forget_threshold: float = 0.3, default_importance: float = 0.5)
All tunable knobs for the memory subsystem: combined scoring + summary + rebuild + write-time dedup + forget/write defaults. Fully frozen.
Attributes:
| Name | Type | Description |
|---|---|---|
relevance_weight |
/ recency_weight / importance_weight
|
the three scoring weights for search (all 0 degenerates to pure relevance). |
recency_halflife_hours |
float
|
recency half-life in hours; smaller values favor newer memories more strongly. |
recency_anchor |
str
|
the time anchor for the recency dimension. "created_at" (default; actually uses updated_at or created_at, so edited content decays by its edit time) or "last_accessed" (decays by the most recent retrieval-hit time, the original Generative Agents semantics). |
summary_top_k |
int
|
how many memories summary takes by default. |
rebuild_batch_size |
int
|
how many memories rebuild_index writes per batch. |
similar_k |
int
|
how many similar memories SmartWriter looks up before writing, for dedup. |
forget_threshold |
float
|
the importance threshold for Memory.forget. |
default_importance |
float
|
the default used by Memory.add when importance is not given. |
validate
¶
Range-check: weights non-negative, half-life > 0, count fields >= 1, threshold/importance in [0,1], anchor within the enum.
MemoryItem
dataclass
¶
MemoryItem(content: str, id: str = (lambda: hex)(), type: str = 'semantic', importance: float = 0.5, created_at: datetime = now_utc(), updated_at: Optional[datetime] = None, last_accessed_at: Optional[datetime] = None, invalid_at: Optional[datetime] = None, superseded_by: Optional[str] = None, metadata: Dict[str, Any] = dict())
A single memory.
Attributes:
| Name | Type | Description |
|---|---|---|
content |
str
|
the memory body. |
id |
str
|
unique identifier, auto-generated by default (uuid). |
type |
str
|
memory type (working / episodic / semantic / procedural); not enforced initially, used as a label for now. |
importance |
float
|
importance in 0~1, used by ranking and forgetting. |
created_at |
datetime
|
the time the memory was recorded, defaults to now. |
updated_at |
Optional[datetime]
|
the time of the most recent content update; None means never updated (falls back to created_at). Recency scoring uses this so edited memories decay from their edit time. |
last_accessed_at |
Optional[datetime]
|
the most recent retrieval-hit time; None means never hit. Used as the recency anchor when recency_anchor="last_accessed". |
invalid_at |
Optional[datetime]
|
soft-invalidation time; None means valid. An invalidated memory is excluded from retrieval while its source-of-truth record remains available for auditing. |
superseded_by |
Optional[str]
|
the id of the newer memory that supersedes this one (recorded on soft-invalidation, forming a fact evolution chain); None means none. |
metadata |
Dict[str, Any]
|
attached information, defaults to an empty dict. |