Memory¶
Persistent agent memory: protocol, retrieval pipeline, shared org memory, consolidation, and archival.
Protocol¶
protocol
¶
MemoryBackend protocol -- lifecycle + memory operations.
Application code depends on this protocol for agent memory storage and retrieval. Concrete backends implement this protocol to provide connection management, health monitoring, and memory CRUD operations.
MemoryBackend
¶
Bases: Protocol
Structural interface for agent memory storage backends.
Concrete backends implement this protocol to provide per-agent memory storage, retrieval, and lifecycle management.
All CRUD operations (store, retrieve, get, delete,
count) require a connected backend and raise
MemoryConnectionError if called before connect().
Attributes:
| Name | Type | Description |
|---|---|---|
is_connected |
bool
|
Whether the backend has an active connection. |
backend_name |
NotBlankStr
|
Human-readable backend identifier. |
connect
async
¶
Establish connection to the memory backend.
Raises:
| Type | Description |
|---|---|
MemoryConnectionError
|
If the connection cannot be established. |
disconnect
async
¶
health_check
async
¶
Check whether the backend is healthy and responsive.
Returns:
| Type | Description |
|---|---|
bool
|
|
bool
|
|
Note
Implementations should catch connection-level errors,
log them at WARNING level with full exception context,
and return False. The caught exception must never be
silently discarded. Only raise for programming errors
(e.g. backend not initialized).
Source code in src/synthorg/memory/protocol.py
store
async
¶
Store a memory entry for an agent.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
agent_id
|
NotBlankStr
|
Owning agent identifier. |
required |
request
|
MemoryStoreRequest
|
Memory content and metadata. |
required |
Returns:
| Type | Description |
|---|---|
NotBlankStr
|
The backend-assigned memory ID. |
Raises:
| Type | Description |
|---|---|
MemoryConnectionError
|
If the backend is not connected. |
MemoryStoreError
|
If the store operation fails. |
Source code in src/synthorg/memory/protocol.py
retrieve
async
¶
Retrieve memories for an agent, ordered by relevance.
When query.text is None, performs metadata-only
filtering (no semantic search).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
agent_id
|
NotBlankStr
|
Owning agent identifier. |
required |
query
|
MemoryQuery
|
Retrieval parameters. |
required |
Returns:
| Type | Description |
|---|---|
tuple[MemoryEntry, ...]
|
Matching memory entries ordered by relevance. |
Raises:
| Type | Description |
|---|---|
MemoryConnectionError
|
If the backend is not connected. |
MemoryRetrievalError
|
If the retrieval fails. |
Source code in src/synthorg/memory/protocol.py
get
async
¶
Get a specific memory entry by ID.
Returns None when the entry does not exist;
MemoryNotFoundError is never raised by this method.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
agent_id
|
NotBlankStr
|
Owning agent identifier. |
required |
memory_id
|
NotBlankStr
|
Memory identifier. |
required |
Returns:
| Type | Description |
|---|---|
MemoryEntry | None
|
The memory entry, or |
Raises:
| Type | Description |
|---|---|
MemoryConnectionError
|
If the backend is not connected. |
MemoryRetrievalError
|
If the backend query fails. |
Source code in src/synthorg/memory/protocol.py
delete
async
¶
Delete a specific memory entry.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
agent_id
|
NotBlankStr
|
Owning agent identifier. |
required |
memory_id
|
NotBlankStr
|
Memory identifier. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
|
Raises:
| Type | Description |
|---|---|
MemoryConnectionError
|
If the backend is not connected. |
MemoryStoreError
|
If the delete operation fails. |
Source code in src/synthorg/memory/protocol.py
count
async
¶
Count memory entries for an agent.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
agent_id
|
NotBlankStr
|
Owning agent identifier. |
required |
category
|
MemoryCategory | None
|
Optional category filter. |
None
|
Returns:
| Type | Description |
|---|---|
int
|
Number of matching entries. |
Raises:
| Type | Description |
|---|---|
MemoryConnectionError
|
If the backend is not connected. |
MemoryRetrievalError
|
If the count query fails. |
Source code in src/synthorg/memory/protocol.py
Config¶
config
¶
Memory configuration models.
Frozen Pydantic models for company-wide memory backend selection and backend-specific settings.
MemoryStorageConfig
pydantic-model
¶
Bases: BaseModel
Storage-specific memory configuration.
Attributes:
| Name | Type | Description |
|---|---|---|
data_dir |
NotBlankStr
|
Directory path for memory data persistence. |
vector_store |
NotBlankStr
|
Vector store backend name. |
history_store |
NotBlankStr
|
History store backend name. |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
Validators:
-
_validate_store_names -
_reject_traversal
data_dir
pydantic-field
¶
Directory path for memory data persistence. Default targets a Docker volume mount -- override for local development.
MemoryOptionsConfig
pydantic-model
¶
Bases: BaseModel
Memory behaviour options.
Attributes:
| Name | Type | Description |
|---|---|---|
retention_days |
int | None
|
Days to retain memories ( |
max_memories_per_agent |
int
|
Maximum memories per agent. |
consolidation_interval |
ConsolidationInterval
|
How often to consolidate memories. |
shared_knowledge_base |
bool
|
Whether shared knowledge is enabled. |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
retention_days(int | None) -
max_memories_per_agent(int) -
consolidation_interval(ConsolidationInterval) -
shared_knowledge_base(bool)
EmbedderOverrideConfig
pydantic-model
¶
Bases: BaseModel
User-facing embedder override configuration.
Allows users to override the auto-selected embedding model via
company YAML config, runtime settings, or template config. All
fields are optional -- None means "use auto-selection".
Attributes:
| Name | Type | Description |
|---|---|---|
provider |
NotBlankStr | None
|
Embedding provider name override. |
model |
NotBlankStr | None
|
Embedding model identifier override. |
dims |
int | None
|
Embedding vector dimensions (required when |
Config:
frozen:Trueextra:forbidallow_inf_nan:False
Fields:
-
provider(NotBlankStr | None) -
model(NotBlankStr | None) -
dims(int | None)
Validators:
-
_model_requires_dims
CompanyMemoryConfig
pydantic-model
¶
Bases: BaseModel
Top-level company-wide memory configuration.
Attributes:
| Name | Type | Description |
|---|---|---|
backend |
NotBlankStr
|
Memory backend name (validated against |
level |
MemoryLevel
|
Default memory persistence level. |
storage |
MemoryStorageConfig
|
Storage-specific settings. |
options |
MemoryOptionsConfig
|
Memory behaviour options. |
retrieval |
MemoryRetrievalConfig
|
Memory retrieval pipeline settings. |
consolidation |
ConsolidationConfig
|
Memory consolidation settings. |
embedder |
EmbedderOverrideConfig | None
|
Optional embedder override ( |
procedural |
ProceduralMemoryConfig
|
Procedural memory auto-generation settings. |
composite |
CompositeBackendConfig | None
|
Composite backend routing config (required when
backend is |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
backend(NotBlankStr) -
level(MemoryLevel) -
storage(MemoryStorageConfig) -
options(MemoryOptionsConfig) -
retrieval(MemoryRetrievalConfig) -
consolidation(ConsolidationConfig) -
embedder(EmbedderOverrideConfig | None) -
procedural(ProceduralMemoryConfig) -
composite(CompositeBackendConfig | None)
Validators:
-
_apply_mirrors -
_validate_backend_name -
_validate_composite_config
embedder
pydantic-field
¶
Optional embedder override. When set, overrides auto-selection for provider, model, and/or dims.
procedural
pydantic-field
¶
Procedural memory auto-generation settings. Controls whether failure-driven skill proposals are generated, which model to use, and quality thresholds.
composite
pydantic-field
¶
Composite backend routing configuration. Required when backend is 'composite'.
Models¶
models
¶
Memory domain models.
Frozen Pydantic models for memory storage requests, entries, and
queries. MemoryStoreRequest is what callers pass to store();
MemoryEntry is what comes back from retrieve().
MemoryMetadata
pydantic-model
¶
Bases: BaseModel
Metadata associated with a memory entry.
Attributes:
| Name | Type | Description |
|---|---|---|
source |
NotBlankStr | None
|
Origin of the memory (task ID, conversation, etc.). |
confidence |
float
|
Confidence score for the memory (0.0 to 1.0). |
tags |
tuple[NotBlankStr, ...]
|
Categorization tags for filtering. |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
source(NotBlankStr | None) -
confidence(float) -
tags(tuple[NotBlankStr, ...])
Validators:
-
_deduplicate_tags→tags
MemoryStoreRequest
pydantic-model
¶
Bases: BaseModel
Input to MemoryBackend.store().
The backend assigns id and created_at; callers should not
fabricate them.
Attributes:
| Name | Type | Description |
|---|---|---|
category |
MemoryCategory
|
Memory type category. |
namespace |
NotBlankStr
|
Storage namespace for routing (e.g. |
content |
NotBlankStr
|
Memory content text. |
metadata |
MemoryMetadata
|
Associated metadata. |
expires_at |
AwareDatetime | None
|
Optional expiration timestamp. |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
category(MemoryCategory) -
namespace(NotBlankStr) -
content(NotBlankStr) -
metadata(MemoryMetadata) -
expires_at(AwareDatetime | None)
MemoryEntry
pydantic-model
¶
Bases: BaseModel
A memory entry returned from the backend.
Attributes:
| Name | Type | Description |
|---|---|---|
id |
NotBlankStr
|
Unique memory identifier (assigned by backend). |
agent_id |
NotBlankStr
|
Owning agent identifier. |
namespace |
NotBlankStr
|
Storage namespace (routing key for composite backend). |
category |
MemoryCategory
|
Memory type category. |
content |
NotBlankStr
|
Memory content text. |
metadata |
MemoryMetadata
|
Associated metadata. |
created_at |
AwareDatetime
|
Creation timestamp. |
updated_at |
AwareDatetime | None
|
Last update timestamp. |
expires_at |
AwareDatetime | None
|
Optional expiration timestamp. |
relevance_score |
float | None
|
Relevance score set by backend on retrieval. |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
id(NotBlankStr) -
agent_id(NotBlankStr) -
namespace(NotBlankStr) -
category(MemoryCategory) -
content(NotBlankStr) -
metadata(MemoryMetadata) -
created_at(AwareDatetime) -
updated_at(AwareDatetime | None) -
expires_at(AwareDatetime | None) -
relevance_score(float | None)
Validators:
-
_validate_timestamps
MemoryQuery
pydantic-model
¶
Bases: BaseModel
Query parameters for MemoryBackend.retrieve().
When text is None, the backend performs metadata-only
filtering (no semantic search).
Attributes:
| Name | Type | Description |
|---|---|---|
text |
NotBlankStr | None
|
Semantic search text ( |
namespaces |
frozenset[NotBlankStr] | None
|
Filter by storage namespaces. |
categories |
frozenset[MemoryCategory] | None
|
Filter by memory categories. |
tags |
tuple[NotBlankStr, ...]
|
Filter by tags (AND semantics). |
min_relevance |
float
|
Minimum relevance score threshold. |
limit |
int
|
Maximum number of results. |
since |
AwareDatetime | None
|
Only memories created at or after this timestamp. |
until |
AwareDatetime | None
|
Only memories created before this timestamp. |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
text(NotBlankStr | None) -
namespaces(frozenset[NotBlankStr] | None) -
categories(frozenset[MemoryCategory] | None) -
tags(tuple[NotBlankStr, ...]) -
min_relevance(float) -
limit(int) -
since(AwareDatetime | None) -
until(AwareDatetime | None)
Validators:
-
_deduplicate_tags→tags -
_validate_time_range
Capabilities¶
capabilities
¶
MemoryCapabilities protocol -- capability discovery.
Backends that implement MemoryCapabilities expose what features
they support, enabling runtime capability checks.
MemoryCapabilities
¶
Bases: Protocol
Capability discovery for memory backends.
Attributes:
| Name | Type | Description |
|---|---|---|
supported_categories |
frozenset[MemoryCategory]
|
Memory categories this backend supports. |
supports_graph |
bool
|
Whether graph-based memory is available. |
supports_temporal |
bool
|
Whether temporal tracking is available. |
supports_vector_search |
bool
|
Whether vector/semantic search is available. |
supports_shared_access |
bool
|
Whether cross-agent shared memory is available. |
max_memories_per_agent |
int | None
|
Maximum memories per agent, or |
Errors¶
errors
¶
Memory error hierarchy.
All memory-related errors inherit from MemoryError so callers can
catch the entire family with a single except clause.
Note: this shadows the built-in MemoryError (which signals
out-of-memory conditions in CPython). Within the synthorg
namespace the domain-specific meaning is unambiguous; callers outside
the package should import explicitly.
MemoryError
¶
Bases: DomainError
Base exception for all memory operations.
Inherits :class:DomainError so the prefix-vs-category validator
runs on every subclass.
Subclasses keep the inherited ErrorCode.INTERNAL_ERROR default
(8000, INTERNAL category) -- callers that need a more specific
code per memory failure mode should override the ClassVars on the
subclass.
Source code in src/synthorg/core/domain_errors.py
MemoryConnectionError
¶
Bases: MemoryError
Raised when a backend connection cannot be established or is lost.
Source code in src/synthorg/core/domain_errors.py
MemoryStoreError
¶
Bases: MemoryError
Raised when a store operation fails.
Source code in src/synthorg/core/domain_errors.py
MemoryRetrievalError
¶
Bases: MemoryError
Raised when a retrieve or search operation fails.
Source code in src/synthorg/core/domain_errors.py
MemoryNotFoundError
¶
Bases: MemoryError
Raised when a specific memory ID is not found.
Note: The MemoryBackend.get() protocol method returns None
for missing entries rather than raising this error. This exception
is available for concrete backend implementations that need to
signal "not found" in non-protocol internal methods or batch
operations.
Source code in src/synthorg/core/domain_errors.py
MemoryConfigError
¶
Bases: MemoryError
Raised when memory configuration is invalid.
Source code in src/synthorg/core/domain_errors.py
MemoryCapabilityError
¶
Bases: MemoryError
Raised when an unsupported operation is attempted for a backend.
Source code in src/synthorg/core/domain_errors.py
FineTuneDependencyError
¶
Bases: MemoryError
Raised when fine-tuning ML dependencies are not installed.
In the default Docker-orchestrated deployment torch and
sentence-transformers ship inside the
synthorg-fine-tune-gpu / synthorg-fine-tune-cpu container
that the backend spawns on demand; this error indicates the
feature is turned off for the current install (synthorg config
set fine_tuning true enables it). The optional
synthorg[fine-tune-gpu] / synthorg[fine-tune-cpu] extras
only apply when running fine-tuning in-process (dev / testing).
Source code in src/synthorg/core/domain_errors.py
FineTuneCancelledError
¶
Bases: MemoryError
Raised when a fine-tuning pipeline run is cancelled.
Source code in src/synthorg/core/domain_errors.py
Factory¶
factory
¶
Factory for creating memory backends from configuration.
Each company gets its own MemoryBackend instance. The factory
dispatches to concrete backend implementations based on
config.backend via :class:MemoryBackendRegistry.
default_registry
¶
create_memory_backend
¶
Create a memory backend from configuration.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
CompanyMemoryConfig
|
Memory configuration (includes backend selection and backend-specific settings). |
required |
embedder
|
Mem0EmbedderConfig | None
|
Backend-specific embedder configuration. Required
for the |
None
|
Returns:
| Type | Description |
|---|---|
MemoryBackend
|
A new, disconnected backend instance. The caller must call |
MemoryBackend
|
|
Raises:
| Type | Description |
|---|---|
MemoryConfigError
|
If the backend is not recognized or required configuration is missing. |
Source code in src/synthorg/memory/factory.py
Retriever¶
retriever
¶
Context injection strategy -- pre-retrieves and injects memories.
Orchestrates the full retrieval pipeline: backend query → ranking →
budget-fit → format. Implements MemoryInjectionStrategy protocol.
ContextInjectionStrategy
¶
ContextInjectionStrategy(
*,
backend,
config,
shared_store=None,
token_estimator=None,
memory_filter=None,
hierarchical_retriever=None,
reranker=None,
)
Context injection strategy -- pre-retrieves and injects memories.
Implements MemoryInjectionStrategy protocol. Orchestrates
the full pipeline: retrieve → rank → budget-fit → format.
Initialise the context injection strategy.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
backend
|
MemoryBackend
|
Memory backend for personal memories. |
required |
config
|
MemoryRetrievalConfig
|
Retrieval pipeline configuration. |
required |
shared_store
|
SharedKnowledgeStore | None
|
Optional shared knowledge store. |
None
|
token_estimator
|
TokenEstimator | None
|
Optional custom token estimator. |
None
|
memory_filter
|
MemoryFilterStrategy | None
|
Optional filter applied after ranking,
before formatting. When |
None
|
hierarchical_retriever
|
HierarchicalRetriever | None
|
Optional hierarchical retriever
(used when |
None
|
reranker
|
QuerySpecificReranker | None
|
Optional query-specific re-ranker (used when
|
None
|
Source code in src/synthorg/memory/retriever.py
strategy_name
property
¶
Human-readable strategy identifier.
Returns:
| Type | Description |
|---|---|
str
|
|
prepare_messages
async
¶
Full pipeline: retrieve → rank → budget-fit → format.
Returns empty tuple on any failure (graceful degradation).
Never raises domain memory errors to the caller.
Re-raises builtins.MemoryError and RecursionError.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
agent_id
|
NotBlankStr
|
The agent requesting memories. |
required |
query_text
|
NotBlankStr
|
Text for semantic retrieval. |
required |
token_budget
|
int
|
Maximum tokens for memory content. |
required |
categories
|
frozenset[MemoryCategory] | None
|
Optional category filter. |
None
|
Returns:
| Type | Description |
|---|---|
tuple[ChatMessage, ...]
|
Tuple of |
Source code in src/synthorg/memory/retriever.py
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 | |
get_tool_definitions
¶
Context injection provides no tools.
Returns:
| Type | Description |
|---|---|
tuple[ToolDefinition, ...]
|
Empty tuple. |
Retrieval Config¶
retrieval_config
¶
Memory retrieval pipeline configuration.
Frozen Pydantic config for the retrieval pipeline -- weights, thresholds, strategy selection, hierarchical retriever, and query-specific re-ranking.
MemoryRetrievalConfig
pydantic-model
¶
Bases: BaseModel
Configuration for the memory retrieval and ranking pipeline.
Attributes:
| Name | Type | Description |
|---|---|---|
strategy |
InjectionStrategy
|
Which injection strategy to use. |
relevance_weight |
float
|
Weight for backend relevance score (0.0-1.0). |
recency_weight |
float
|
Weight for recency decay score (0.0-1.0). |
recency_decay_rate |
float
|
Exponential decay rate per hour. |
personal_boost |
float
|
Boost applied to personal over shared (0.0-1.0). |
min_relevance |
float
|
Minimum combined (relevance + recency) score to include. |
max_memories |
int
|
Maximum candidates to retrieve (1-100). |
include_shared |
bool
|
Whether to query SharedKnowledgeStore. |
default_relevance |
float
|
Score for entries missing relevance_score. |
injection_point |
InjectionPoint
|
Message role for context injection. |
non_inferable_only |
bool
|
When True, auto-creates a |
fusion_strategy |
FusionStrategy
|
Ranking fusion strategy -- LINEAR for single-source relevance+recency, RRF for multi-source ranked list merging. |
rrf_k |
int
|
RRF smoothing constant (1-1000, only used with RRF strategy). |
diversity_penalty_enabled |
bool
|
When True, apply MMR-style diversity
penalty to re-rank retrieval results, reducing redundancy.
Only consumed by |
diversity_lambda |
float
|
MMR trade-off parameter (0.0-1.0). |
query_reformulation_enabled |
bool
|
When True, enables the
Search-and-Ask iterative query-reformulation loop in the
TOOL_BASED strategy. Requires |
max_reformulation_rounds |
int
|
Maximum rounds of query reformulation in the Search-and-Ask loop (1-5). Defaults to 2. |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
strategy(InjectionStrategy) -
relevance_weight(float) -
recency_weight(float) -
recency_decay_rate(float) -
personal_boost(float) -
min_relevance(float) -
max_memories(int) -
include_shared(bool) -
default_relevance(float) -
injection_point(InjectionPoint) -
non_inferable_only(bool) -
fusion_strategy(FusionStrategy) -
rrf_k(int) -
diversity_penalty_enabled(bool) -
diversity_lambda(float) -
candidate_pool_multiplier(int) -
query_reformulation_enabled(bool) -
max_reformulation_rounds(int) -
retriever(Literal['flat', 'hierarchical']) -
max_workers_per_query(int) -
reflective_retry_enabled(bool) -
max_retry_count(int) -
query_specific_rerank_enabled(bool) -
rerank_cache_ttl_seconds(int)
Validators:
-
_validate_weight_sum -
_validate_rrf_k_strategy_consistency -
_validate_diversity_lambda_consistency -
_validate_diversity_strategy_consistency -
_validate_reformulation_requires_tool_based -
_validate_personal_boost_rrf_consistency -
_validate_pool_multiplier_consistency -
_validate_supported_strategy -
_validate_hierarchical_requires_context -
_validate_hierarchical_field_consistency -
_validate_rerank_cache_ttl_consistency
min_relevance
pydantic-field
¶
Minimum combined (relevance + recency) score to include
default_relevance
pydantic-field
¶
Score for entries missing relevance_score
non_inferable_only
pydantic-field
¶
When True, only inject memories tagged as non-inferable
fusion_strategy
pydantic-field
¶
Ranking fusion strategy: linear for single-source relevance+recency, rrf for multi-source ranked list merging
rrf_k
pydantic-field
¶
RRF smoothing constant k (only used with RRF strategy)
diversity_penalty_enabled
pydantic-field
¶
When True, apply MMR-style diversity penalty to re-rank retrieval results, reducing redundancy
diversity_lambda
pydantic-field
¶
MMR trade-off parameter: 1.0 = pure relevance (no diversity), 0.0 = maximum diversity
candidate_pool_multiplier
pydantic-field
¶
Over-fetch multiplier for the candidate pool when diversity_penalty_enabled is True. The backend query fetches max_memories * candidate_pool_multiplier entries so MMR can promote diverse candidates that would otherwise fall below the top-K cutoff. Ignored when diversity_penalty_enabled is False.
query_reformulation_enabled
pydantic-field
¶
Enables iterative query reformulation in the TOOL_BASED strategy. When True, ToolBasedInjectionStrategy runs a Search-and-Ask loop (retrieve -> check sufficiency -> reformulate -> re-retrieve) up to max_reformulation_rounds rounds. Requires both reformulator AND sufficiency_checker to be passed to the strategy constructor -- the constructor raises ValueError when the flag is set but either collaborator is missing (fail-fast at wiring time rather than silent no-op at retrieval time). A config-level validator also rejects this flag with strategies other than TOOL_BASED.
max_reformulation_rounds
pydantic-field
¶
Maximum rounds of query reformulation in the Search-and-Ask loop when query_reformulation_enabled is True (1-5).
retriever
pydantic-field
¶
Retriever topology: flat uses the existing single-pass pipeline, hierarchical uses supervisor-worker routing with semantic, episodic, and procedural workers.
max_workers_per_query
pydantic-field
¶
Maximum workers the supervisor may invoke per query (only used when retriever is hierarchical).
reflective_retry_enabled
pydantic-field
¶
When True, the hierarchical supervisor evaluates result quality and retries with corrected queries on poor results.
max_retry_count
pydantic-field
¶
Maximum reflective retry attempts (only used when retriever is hierarchical and reflective_retry_enabled is True).
query_specific_rerank_enabled
pydantic-field
¶
When True, apply query-specific LLM-based re-ranking after RRF/linear fusion. Works with both flat and hierarchical retrievers. Adds an LLM call per retrieve.
rerank_cache_ttl_seconds
pydantic-field
¶
TTL in seconds for the re-ranker cache (only used when query_specific_rerank_enabled is True).
Ranking¶
ranking
¶
Memory ranking -- scoring and sorting functions.
All functions are functionally pure (deterministic given the same inputs). Logging calls are the only side effect.
rank_memories scores entries via linear combination of relevance
and recency (single-source). fuse_ranked_lists merges multiple
pre-ranked lists via Reciprocal Rank Fusion (multi-source).
apply_diversity_penalty re-ranks using MMR to reduce redundancy.
FusionStrategy
¶
Bases: StrEnum
Ranking fusion strategy selection.
Attributes:
| Name | Type | Description |
|---|---|---|
LINEAR |
Weighted linear combination of relevance and recency (default, for single-source scoring). |
|
RRF |
Reciprocal Rank Fusion for merging multiple ranked lists (for multi-source hybrid search). |
ScoredMemory
pydantic-model
¶
Bases: BaseModel
Memory entry with computed ranking scores.
Produced by either rank_memories (LINEAR fusion) or
fuse_ranked_lists (RRF fusion). Field semantics depend on
which producer created the instance:
- LINEAR:
relevance_scoreis raw backend relevance pluspersonal_boost(for personal entries),recency_scoreis the exponential decay based on age, andcombined_scoreis the weighted linear combination of the two. - RRF:
relevance_scorepreserves the raw backend relevance (or0.0if absent),recency_scoreis always0.0(RRF is rank-based, not time-based), andcombined_scoreis the min-max-normalized fusion score.
Attributes:
| Name | Type | Description |
|---|---|---|
entry |
MemoryEntry
|
The original memory entry. |
relevance_score |
float
|
For LINEAR, post-boost relevance; for RRF, raw backend relevance (0.0-1.0). |
recency_score |
float
|
Exponential decay based on age (LINEAR) or always 0.0 (RRF). |
combined_score |
float
|
Final ranking signal (0.0-1.0). LINEAR weighted combination or RRF normalized fusion score. |
is_shared |
bool
|
Whether this came from SharedKnowledgeStore. |
scoring_strategy |
FusionStrategy | None
|
Which fusion strategy produced this instance, or None when unset (backward compatibility). |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
entry(MemoryEntry) -
relevance_score(float) -
recency_score(float) -
combined_score(float) -
is_shared(bool) -
scoring_strategy(FusionStrategy | None)
compute_recency_score
¶
Compute exponential recency decay score.
exp(-decay_rate * age_hours). Returns 1.0 for zero age,
decays toward 0.0 over time. Future timestamps are clamped to
1.0.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
created_at
|
datetime
|
When the memory was created. |
required |
now
|
datetime
|
Current timestamp for age calculation. |
required |
decay_rate
|
float
|
Exponential decay rate per hour. |
required |
Returns:
| Type | Description |
|---|---|
float
|
Recency score between 0.0 and 1.0. |
Source code in src/synthorg/memory/ranking.py
compute_combined_score
¶
Weighted linear combination of relevance and recency.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
relevance
|
float
|
Relevance score (0.0-1.0). |
required |
recency
|
float
|
Recency score (0.0-1.0). |
required |
relevance_weight
|
float
|
Weight for relevance. |
required |
recency_weight
|
float
|
Weight for recency. |
required |
Returns:
| Type | Description |
|---|---|
float
|
Combined score clamped to [0.0, 1.0]. When |
float
|
|
float
|
in [0.0, 1.0], the result is naturally bounded; the clamp |
float
|
guards against floating-point tolerance in the weight sum. |
Source code in src/synthorg/memory/ranking.py
rank_memories
¶
Score, merge, sort, filter, and truncate memory entries.
- Score personal entries (with
personal_boost). - Score shared entries (no boost).
- Merge both sets.
- Filter by
min_relevancethreshold oncombined_score. - Sort descending by
combined_score. - Truncate to
max_memories.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
entries
|
tuple[MemoryEntry, ...]
|
Personal memory entries. |
required |
config
|
MemoryRetrievalConfig
|
Retrieval pipeline configuration. |
required |
now
|
datetime
|
Current timestamp for recency calculations. |
required |
shared_entries
|
tuple[MemoryEntry, ...]
|
Shared memory entries (no personal boost). |
()
|
Returns:
| Type | Description |
|---|---|
tuple[ScoredMemory, ...]
|
Sorted and filtered tuple of |
Source code in src/synthorg/memory/ranking.py
fuse_ranked_lists
¶
Merge multiple pre-ranked lists via Reciprocal Rank Fusion.
RRF_score(doc) = sum(1 / (k + rank_i)) across all lists
containing the document. Scores are min-max normalized to
[0.0, 1.0].
For RRF output, only combined_score is the meaningful
ranking signal. relevance_score preserves the entry's raw
backend relevance (or 0.0 if absent); recency_score is 0.0.
When the same entry ID appears in multiple lists, the first
MemoryEntry object encountered is retained.
Unlike rank_memories, this function does not apply a
min_relevance threshold -- callers are responsible for
post-filtering if needed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ranked_lists
|
tuple[tuple[MemoryEntry, ...], ...]
|
Each inner tuple is a pre-sorted ranked list of memory entries (best first). |
required |
k
|
int
|
RRF smoothing constant (default 60, must be >= 1). Smaller values amplify rank differences. |
_DEFAULT_K
|
max_results
|
int
|
Maximum entries to return (must be >= 1). |
_DEFAULT_MAX_RESULTS
|
Returns:
| Type | Description |
|---|---|
tuple[ScoredMemory, ...]
|
Sorted tuple of |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/synthorg/memory/ranking.py
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 | |
bigram_jaccard
¶
Word-bigram Jaccard similarity between two texts.
Returns 0.0 when either text has fewer than 2 words (no bigrams possible).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text_a
|
str
|
First text. |
required |
text_b
|
str
|
Second text. |
required |
Returns:
| Type | Description |
|---|---|
float
|
Similarity score between 0.0 and 1.0. |
Source code in src/synthorg/memory/ranking.py
apply_diversity_penalty
¶
apply_diversity_penalty(
scored, *, diversity_lambda=_DEFAULT_DIVERSITY_LAMBDA, similarity_fn=None
)
Re-rank scored memories using Maximal Marginal Relevance.
Iteratively selects entries that balance relevance (via
combined_score) with diversity (via pairwise dissimilarity
to already-selected entries).
MMR score: lambda * combined_score - (1 - lambda) * max_sim
When similarity_fn is None (the default), the implementation
pre-computes each entry's word bigrams once and computes Jaccard
from the cached sets, avoiding O(n**2 * k) re-tokenization of
already-selected content on each iteration.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scored
|
tuple[ScoredMemory, ...]
|
Pre-ranked scored memories. |
required |
diversity_lambda
|
float
|
Trade-off between relevance (1.0) and diversity (0.0). Must be in [0.0, 1.0]. |
_DEFAULT_DIVERSITY_LAMBDA
|
similarity_fn
|
Callable[[str, str], float] | None
|
Optional pairwise text similarity function.
Defaults to bigram Jaccard (with precomputed bigram cache)
when |
None
|
Returns:
| Type | Description |
|---|---|
tuple[ScoredMemory, ...]
|
Re-ordered tuple of the same length as |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/synthorg/memory/ranking.py
Filter¶
filter
¶
Memory filter strategies for non-inferable principle enforcement.
Filters scored memories before injection into agent prompts. The
TagBasedMemoryFilter (initial D23 implementation) retains only
memories tagged with "non-inferable"; the PassthroughMemoryFilter
is a no-op for backward compatibility and testing.
Both satisfy the MemoryFilterStrategy runtime-checkable protocol.
MemoryFilterStrategy
¶
Bases: Protocol
Protocol for filtering scored memories before prompt injection.
filter_for_injection
¶
Filter memories suitable for injection.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
memories
|
tuple[ScoredMemory, ...]
|
Ranked scored memories from the retrieval pipeline. |
required |
Returns:
| Type | Description |
|---|---|
tuple[ScoredMemory, ...]
|
Subset of memories that pass the filter. |
Source code in src/synthorg/memory/filter.py
TagBasedMemoryFilter
¶
Filter that retains only memories with a required tag.
The default required tag is "non-inferable" per D23. Memories
whose entry.metadata.tags do not contain the required tag are
excluded from prompt injection.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
required_tag
|
str
|
Tag that must be present for a memory to pass. |
NON_INFERABLE_TAG
|
Source code in src/synthorg/memory/filter.py
strategy_name
property
¶
Human-readable name of the filter strategy.
Returns:
| Type | Description |
|---|---|
str
|
|
filter_for_injection
¶
Return only memories containing the required tag.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
memories
|
tuple[ScoredMemory, ...]
|
Ranked scored memories. |
required |
Returns:
| Type | Description |
|---|---|
tuple[ScoredMemory, ...]
|
Filtered tuple with only tagged memories. |
Source code in src/synthorg/memory/filter.py
PassthroughMemoryFilter
¶
No-op filter that returns all memories unchanged.
Useful for backward compatibility and testing -- all memories pass through without filtering.
strategy_name
property
¶
Human-readable name of the filter strategy.
Returns:
| Type | Description |
|---|---|
str
|
|
filter_for_injection
¶
Return all memories unchanged.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
memories
|
tuple[ScoredMemory, ...]
|
Ranked scored memories. |
required |
Returns:
| Type | Description |
|---|---|
tuple[ScoredMemory, ...]
|
The input tuple unchanged. |
Source code in src/synthorg/memory/filter.py
Formatter¶
formatter
¶
Memory context formatter: converts ranked memories to ChatMessages.
Handles token budget enforcement via greedy packing: iterates by rank, skips entries that exceed the remaining budget, and continues with smaller entries to maximise context within the token limit.
Each memory entry is wrapped under TAG_MEMORY_ENTRY via
:func:wrap_untrusted so an attacker who plants a stored memory cannot
break out of the fence and inject system-prompt-level instructions.
Consumers that splice the formatted messages into an LLM call must
append :func:untrusted_content_directive for TAG_MEMORY_ENTRY to
their system prompt: :func:format_memory_context_with_directive is
the canonical helper that bundles both steps.
format_memory_context_with_directive
¶
format_memory_context_with_directive(
memories, *, estimator, token_budget, injection_point=SYSTEM
)
Format memories with the untrusted-content directive prepended.
Calls the private :func:_format_memory_context and prepends a
SYSTEM-role :class:ChatMessage carrying the untrusted-content
directive for TAG_MEMORY_ENTRY. Returns an empty tuple when
no memories fit.
This is the only public memory-formatter entry point: the directive is the contract that tells the model the memory blocks are data, not instructions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
memories
|
tuple[ScoredMemory, ...]
|
Pre-ranked memories (highest score first). |
required |
estimator
|
TokenEstimator
|
Token estimation implementation. |
required |
token_budget
|
int
|
Maximum tokens for the memory block. |
required |
injection_point
|
InjectionPoint
|
Role for the memory message. |
SYSTEM
|
Returns:
| Type | Description |
|---|---|
ChatMessage
|
|
...
|
tuple when no memories fit (so the directive does not appear |
tuple[ChatMessage, ...]
|
on its own). |
Source code in src/synthorg/memory/formatter.py
Injection¶
injection
¶
Memory injection strategy protocol and supporting types.
Defines the pluggable MemoryInjectionStrategy protocol that
controls how memories reach agents during execution. Three
strategies are planned (context injection, tool-based, self-editing);
this module provides the protocol and enums for all.
ContextInjectionStrategy (in synthorg.memory.retriever) and
ToolBasedInjectionStrategy (in synthorg.memory.tool_retriever)
are implemented.
TokenEstimator is a local structural protocol that avoids a
memory -> engine import cycle (PromptTokenEstimator lives in
engine/prompt.py). Any object with estimate_tokens(str) -> int
satisfies it automatically.
InjectionStrategy
¶
Bases: StrEnum
Which injection strategy to use for surfacing memories.
Attributes:
| Name | Type | Description |
|---|---|---|
CONTEXT |
Pre-execution context injection (implemented). |
|
TOOL_BASED |
On-demand via agent tools (implemented). |
|
SELF_EDITING |
Structured read/write memory blocks (implemented). |
InjectionPoint
¶
Bases: StrEnum
Role of the injected memory message.
Attributes:
| Name | Type | Description |
|---|---|---|
SYSTEM |
Memory injected as a SYSTEM message (default). |
|
USER |
Memory injected as a USER message. |
TokenEstimator
¶
Bases: Protocol
Token estimation protocol (avoids memory → engine dependency).
Any object with estimate_tokens(str) -> int satisfies this
protocol structurally.
estimate_tokens
¶
Estimate the number of tokens in text.
Implementations must return non-negative values.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The text to estimate tokens for. |
required |
Returns:
| Type | Description |
|---|---|
int
|
Estimated token count (non-negative). |
Source code in src/synthorg/memory/injection.py
DefaultTokenEstimator
¶
Heuristic token estimator: len(text) // 4.
Suitable for rough budget enforcement when a model-specific tokenizer is unavailable.
estimate_tokens
¶
Estimate tokens as max(1, len(text) // 4) for non-empty text.
Returns 0 for empty text, at least 1 for any non-empty text.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The text to estimate tokens for. |
required |
Returns:
| Type | Description |
|---|---|
int
|
Estimated token count (non-negative). |
Source code in src/synthorg/memory/injection.py
MemoryInjectionStrategy
¶
Bases: Protocol
Pluggable strategy for making memories available to agents.
Implementations determine how memories reach the agent:
- Context injection: pre-execution message injection.
- Tool-based: on-demand retrieval via agent tools.
- Self-editing: structured read/write memory blocks.
strategy_name
property
¶
Human-readable strategy identifier.
Returns:
| Type | Description |
|---|---|
str
|
Strategy name string. |
prepare_messages
async
¶
Return memory messages to inject into agent context.
Context injection returns ranked, formatted memories. Tool-based may return empty (tools handle retrieval). Self-editing returns the core memory block.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
agent_id
|
NotBlankStr
|
The agent requesting memories. |
required |
query_text
|
NotBlankStr
|
Text to use for semantic retrieval. |
required |
token_budget
|
int
|
Maximum tokens for memory content. |
required |
Returns:
| Type | Description |
|---|---|
tuple[ChatMessage, ...]
|
Tuple of |
Source code in src/synthorg/memory/injection.py
get_tool_definitions
¶
Return tool definitions this strategy provides.
Context injection returns (). Tool-based returns
recall/search tools. Self-editing returns read/write tools.
Returns:
| Type | Description |
|---|---|
tuple[ToolDefinition, ...]
|
Tuple of |
Source code in src/synthorg/memory/injection.py
Org Memory¶
protocol
¶
OrgMemoryBackend protocol -- lifecycle + org memory operations.
Application code depends on this protocol for shared organizational memory storage and retrieval. Concrete backends implement this protocol to provide company-wide knowledge management.
OrgMemoryBackend
¶
Bases: Protocol
Structural interface for organizational memory backends.
Provides company-wide knowledge storage, retrieval, and lifecycle management. All operations require a connected backend.
Attributes:
| Name | Type | Description |
|---|---|---|
is_connected |
bool
|
Whether the backend has an active connection. |
backend_name |
NotBlankStr
|
Human-readable backend identifier. |
connect
async
¶
Establish connection to the org memory backend.
Raises:
| Type | Description |
|---|---|
OrgMemoryConnectionError
|
If the connection fails. |
disconnect
async
¶
health_check
async
¶
Check whether the backend is healthy and responsive.
Returns:
| Type | Description |
|---|---|
bool
|
|
query
async
¶
Query organizational facts.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
query
|
OrgMemoryQuery
|
Query parameters. |
required |
Returns:
| Type | Description |
|---|---|
tuple[OrgFact, ...]
|
Matching facts ordered by relevance. |
Raises:
| Type | Description |
|---|---|
OrgMemoryConnectionError
|
If not connected. |
OrgMemoryQueryError
|
If the query fails. |
Source code in src/synthorg/memory/org/protocol.py
write
async
¶
Write a new organizational fact.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
request
|
OrgFactWriteRequest
|
Fact content and category. |
required |
author
|
OrgFactAuthor
|
The author of the fact. |
required |
Returns:
| Type | Description |
|---|---|
NotBlankStr
|
The assigned fact ID. |
Raises:
| Type | Description |
|---|---|
OrgMemoryConnectionError
|
If not connected. |
OrgMemoryAccessDeniedError
|
If write access is denied. |
OrgMemoryWriteError
|
If the write operation fails. |
Source code in src/synthorg/memory/org/protocol.py
list_policies
async
¶
List core policy facts, optionally paginated.
limit=None (the default) preserves the historical
"return everything" contract for callers that pre-date
pagination. When limit is set, the implementation MUST
honour offset and slice the policy snapshot consistently
with its intrinsic ordering (static config first, then
dynamically written facts, in the reference impl).
Returns:
| Type | Description |
|---|---|
tuple[OrgFact, ...]
|
Tuple of core policy facts (full or sliced view). |
Raises:
| Type | Description |
|---|---|
OrgMemoryConnectionError
|
If not connected. |
Source code in src/synthorg/memory/org/protocol.py
count_policies
async
¶
Return the unfiltered count of core policy facts.
Companion to :meth:list_policies for paginated controllers
that need a total alongside the page.
config
¶
Org memory configuration models.
Frozen Pydantic models for organizational memory behaviour settings.
ExtendedStoreConfig
pydantic-model
¶
Bases: BaseModel
Configuration for the extended org facts store.
Attributes:
| Name | Type | Description |
|---|---|---|
max_retrieved_per_query |
int
|
Maximum facts to retrieve per query. |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
max_retrieved_per_query(int)
max_retrieved_per_query
pydantic-field
¶
Maximum facts to retrieve per query
OrgMemoryConfig
pydantic-model
¶
Bases: BaseModel
Top-level organizational memory configuration.
Attributes:
| Name | Type | Description |
|---|---|---|
core_policies |
tuple[NotBlankStr, ...]
|
Core policy texts injected into system prompts. |
extended_store |
ExtendedStoreConfig
|
Extended facts store configuration. |
write_access |
WriteAccessConfig
|
Write access control configuration. |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
core_policies(tuple[NotBlankStr, ...]) -
extended_store(ExtendedStoreConfig) -
write_access(WriteAccessConfig)
models
¶
Org memory domain models.
Frozen Pydantic models for organizational facts -- shared company-wide knowledge such as policies, ADRs, procedures, and conventions.
Includes MVCC models for the append-only operation log and the materialized snapshot.
OrgFactAuthor
pydantic-model
¶
Bases: BaseModel
Author of an organizational fact.
If is_human is True, agent_id must be None.
If is_human is False, agent_id and seniority
are required; autonomy_level is optional (captures the
instance-specific value at write time).
Attributes:
| Name | Type | Description |
|---|---|---|
agent_id |
NotBlankStr | None
|
Agent identifier ( |
seniority |
SeniorityLevel | None
|
Agent seniority level ( |
is_human |
bool
|
Whether the author is a human operator. |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
agent_id(NotBlankStr | None) -
seniority(SeniorityLevel | None) -
autonomy_level(AutonomyLevel | None) -
is_human(bool)
Validators:
-
_validate_author_consistency
autonomy_level
pydantic-field
¶
Agent autonomy level at write time (None for human authors)
OrgFact
pydantic-model
¶
Bases: BaseModel
An organizational fact -- a piece of shared company-wide knowledge.
Attributes:
| Name | Type | Description |
|---|---|---|
id |
NotBlankStr
|
Unique identifier for this fact. |
content |
NotBlankStr
|
The fact content text. |
category |
OrgFactCategory
|
Category classification. |
tags |
tuple[NotBlankStr, ...]
|
Metadata tags for cross-cutting concerns. |
author |
OrgFactAuthor
|
Who created this fact. |
created_at |
AwareDatetime
|
Creation timestamp. |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
id(NotBlankStr) -
content(NotBlankStr) -
category(OrgFactCategory) -
tags(tuple[NotBlankStr, ...]) -
author(OrgFactAuthor) -
created_at(AwareDatetime)
OrgFactWriteRequest
pydantic-model
¶
Bases: BaseModel
Request to write a new organizational fact.
Attributes:
| Name | Type | Description |
|---|---|---|
content |
NotBlankStr
|
The fact content text. |
category |
OrgFactCategory
|
Category classification. |
tags |
tuple[NotBlankStr, ...]
|
Metadata tags for cross-cutting concerns. |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
content(NotBlankStr) -
category(OrgFactCategory) -
tags(tuple[NotBlankStr, ...])
OrgMemoryQuery
pydantic-model
¶
Bases: BaseModel
Query parameters for org memory retrieval.
Attributes:
| Name | Type | Description |
|---|---|---|
context |
NotBlankStr | None
|
Text search context ( |
categories |
frozenset[OrgFactCategory] | None
|
Filter by fact categories. |
limit |
int
|
Maximum number of results. |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
context(NotBlankStr | None) -
categories(frozenset[OrgFactCategory] | None) -
limit(int)
OperationLogEntry
pydantic-model
¶
Bases: BaseModel
Single row in the append-only operation log.
Every publish or retract is recorded as an immutable log entry.
The version counter is monotonically increasing per fact_id.
Attributes:
| Name | Type | Description |
|---|---|---|
operation_id |
NotBlankStr
|
Globally unique operation identifier. |
fact_id |
NotBlankStr
|
Logical fact identifier. |
operation_type |
Literal['PUBLISH', 'RETRACT']
|
|
content |
NotBlankStr | None
|
Fact body ( |
category |
OrgFactCategory | None
|
Fact category at time of operation. |
tags |
tuple[NotBlankStr, ...]
|
Metadata tags at time of operation. |
author_agent_id |
NotBlankStr | None
|
Agent that performed the operation
( |
author_seniority |
SeniorityLevel | None
|
Agent seniority level at write time. |
author_is_human |
bool
|
Whether the author is a human operator. |
author_autonomy_level |
AutonomyLevel | None
|
Agent autonomy level at write time. |
timestamp |
AwareDatetime
|
UTC timestamp of the operation. |
version |
int
|
Per-fact version counter (starts at 1). |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
operation_id(NotBlankStr) -
fact_id(NotBlankStr) -
operation_type(Literal['PUBLISH', 'RETRACT']) -
content(NotBlankStr | None) -
category(OrgFactCategory | None) -
tags(tuple[NotBlankStr, ...]) -
author_agent_id(NotBlankStr | None) -
author_seniority(SeniorityLevel | None) -
author_is_human(bool) -
author_autonomy_level(AutonomyLevel | None) -
timestamp(AwareDatetime) -
version(int)
Validators:
-
_validate_content_alignment
author_autonomy_level
pydantic-field
¶
Agent autonomy level at write time
OperationLogSnapshot
pydantic-model
¶
Bases: BaseModel
Materialized snapshot row for current committed state.
Represents the state of a single fact at a point in time.
Active facts have retracted_at=None.
Attributes:
| Name | Type | Description |
|---|---|---|
fact_id |
NotBlankStr
|
Logical fact identifier (primary key). |
content |
NotBlankStr
|
Current fact body. |
category |
OrgFactCategory
|
Fact category. |
tags |
tuple[NotBlankStr, ...]
|
Current metadata tags. |
created_at |
AwareDatetime
|
Timestamp of first PUBLISH. |
retracted_at |
AwareDatetime | None
|
Timestamp of retraction ( |
version |
int
|
Version matching most recent operation log entry. |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
fact_id(NotBlankStr) -
content(NotBlankStr) -
category(OrgFactCategory) -
tags(tuple[NotBlankStr, ...]) -
created_at(AwareDatetime) -
retracted_at(AwareDatetime | None) -
version(int)
Validators:
-
_validate_created_before_retracted
access_control
¶
Write access control for organizational memory.
Provides seniority-based and human-based write restriction models, configuration, and enforcement functions.
CategoryWriteRule
pydantic-model
¶
Bases: BaseModel
Write permission rule for a single fact category.
Attributes:
| Name | Type | Description |
|---|---|---|
allowed_seniority |
SeniorityLevel | None
|
Minimum seniority level for agent writes
( |
human_allowed |
bool
|
Whether human operators can write. |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
allowed_seniority(SeniorityLevel | None) -
human_allowed(bool)
WriteAccessConfig
pydantic-model
¶
Bases: BaseModel
Write access configuration for all fact categories.
The runtime type of rules is :class:types.MappingProxyType,
expressed in the annotation as :class:collections.abc.Mapping so
callers see an immutable interface at the type boundary instead of
a freely mutable dict.
Attributes:
| Name | Type | Description |
|---|---|---|
rules |
Mapping[OrgFactCategory, CategoryWriteRule]
|
Per-category write rules (read-only mapping). |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
rules(Mapping[OrgFactCategory, CategoryWriteRule])
Validators:
-
_wrap_rules_readonly
check_write_access
¶
Check whether the given author may write to the given category.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
WriteAccessConfig
|
Write access configuration. |
required |
category
|
OrgFactCategory
|
Target fact category. |
required |
author
|
OrgFactAuthor
|
The author attempting the write. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
|
Source code in src/synthorg/memory/org/access_control.py
require_write_access
¶
Check write access and raise if denied.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
WriteAccessConfig
|
Write access configuration. |
required |
category
|
OrgFactCategory
|
Target fact category. |
required |
author
|
OrgFactAuthor
|
The author attempting the write. |
required |
Raises:
| Type | Description |
|---|---|
OrgMemoryAccessDeniedError
|
If write is not permitted. |
Source code in src/synthorg/memory/org/access_control.py
Consolidation¶
config
¶
Memory consolidation configuration models.
Frozen Pydantic models for consolidation interval, retention, archival, LLM consolidation strategy, experience compressor, and wiki export settings.
ConsolidationStrategyType
¶
Bases: StrEnum
Discriminator selecting the consolidation composite to build.
Each value maps (in
:mod:synthorg.memory.consolidation.factory) to a
Composite(HighestRelevanceSelector, <op>):
SIMPLE->ConcatenationOp(truncated-bullet summary).DUAL_MODE->DensityRoutingOp(density-routed extractive / abstractive).LLM->LLMSynthesisOp(LLM synthesis, parallel groups).
RetentionConfig
pydantic-model
¶
Bases: BaseModel
Per-category retention configuration (company-level defaults).
These rules apply as the baseline for all agents. Individual agents
can override specific categories via
:attr:~synthorg.core.agent.MemoryConfig.retention_overrides.
Resolution order per category (highest priority first):
- Agent per-category override
- Company per-category rule (this config)
- Agent global default (
MemoryConfig.retention_days) - Company global default (
default_retention_days) - Keep forever (no expiry)
Attributes:
| Name | Type | Description |
|---|---|---|
rules |
tuple[RetentionRule, ...]
|
Per-category retention rules (unique categories). |
default_retention_days |
int | None
|
Default retention in days
( |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
rules(tuple[RetentionRule, ...]) -
default_retention_days(int | None)
Validators:
-
_validate_unique_categories
DualModeConfig
pydantic-model
¶
Bases: BaseModel
Configuration for dual-mode archival.
Controls density-aware archival: LLM abstractive summaries for sparse/conversational content vs extractive preservation (verbatim key facts + start/mid/end anchors) for dense/factual content.
Attributes:
| Name | Type | Description |
|---|---|---|
enabled |
bool
|
Whether dual-mode density classification is active.
When |
dense_threshold |
float
|
Density score threshold for DENSE classification (0.0 = classify everything as dense, 1.0 = everything sparse). |
summarization_model |
NotBlankStr | None
|
Model ID for abstractive summarization. |
max_summary_tokens |
int
|
Maximum tokens for LLM summary responses. |
max_facts |
int
|
Maximum number of extracted key facts for extractive mode. |
anchor_length |
int
|
Character length for each extractive anchor snippet (start/mid/end). |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
enabled(bool) -
dense_threshold(float) -
summarization_model(NotBlankStr | None) -
max_summary_tokens(int) -
max_facts(int) -
anchor_length(int)
Validators:
-
_validate_model_when_enabled
ArchivalConfig
pydantic-model
¶
Bases: BaseModel
Archival configuration.
Attributes:
| Name | Type | Description |
|---|---|---|
enabled |
bool
|
Whether archival is enabled. |
age_threshold_days |
int
|
Minimum age in days before archival. |
dual_mode |
DualModeConfig
|
Dual-mode archival configuration. |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
enabled(bool) -
age_threshold_days(int) -
dual_mode(DualModeConfig)
ExperienceCompressorConfig
pydantic-model
¶
Bases: BaseModel
Configuration for the GEMS two-tier experience compressor.
Controls whether raw execution traces (DetailedExperience) are
compressed into strategic learnings (CompressedExperience).
Attributes:
| Name | Type | Description |
|---|---|---|
enabled |
bool
|
Whether two-tier compression is active. |
model |
NotBlankStr | None
|
Model identifier for the compressor LLM call
( |
temperature |
float
|
Sampling temperature for compression. |
max_tokens |
int
|
Token budget for the compressor response. |
min_compression_ratio |
float
|
Discard compressions with a ratio below this threshold (0.0 = keep all, closer to 1.0 = stricter). |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
enabled(bool) -
model(NotBlankStr | None) -
temperature(float) -
max_tokens(int) -
min_compression_ratio(float)
WikiExportConfig
pydantic-model
¶
Bases: BaseModel
Configuration for post-consolidation wiki filesystem export.
Three-view export: raw/ (Tier 1 raw artifacts), wiki/
(Tier 2 compressed experiences), and index.md (navigation).
Attributes:
| Name | Type | Description |
|---|---|---|
enabled |
bool
|
Whether wiki export is enabled. |
export_root |
NotBlankStr
|
Root directory for the wiki filesystem export. |
trigger |
Literal['on_consolidation', 'manual']
|
When to trigger export ( |
include_raw_tier |
bool
|
Export Tier 1 (DetailedExperience) to
|
include_compressed_tier |
bool
|
Export Tier 2 (CompressedExperience)
to |
max_entries_per_view |
int | None
|
Maximum entries per view ( |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
enabled(bool) -
export_root(NotBlankStr) -
trigger(Literal['on_consolidation', 'manual']) -
include_raw_tier(bool) -
include_compressed_tier(bool) -
max_entries_per_view(int | None)
Validators:
-
_reject_traversal
export_root
pydantic-field
¶
Root directory for the wiki filesystem export
include_compressed_tier
pydantic-field
¶
Export Tier 2 compressed experiences to wiki/ view
max_entries_per_view
pydantic-field
¶
Maximum entries per view. None means 'use the backend's maximum page size' (MemoryQuery.limit is capped at 1000 by schema). Multi-page exports for collections larger than 1000 are not yet supported.
ConsolidationConfig
pydantic-model
¶
Bases: BaseModel
Top-level memory consolidation configuration.
Attributes:
| Name | Type | Description |
|---|---|---|
enabled |
bool
|
Master kill switch for memory consolidation. When
|
interval |
ConsolidationInterval
|
How often to run consolidation. |
max_memories_per_agent |
int
|
Upper bound on memories per agent. |
retention |
RetentionConfig
|
Per-category retention settings. |
archival |
ArchivalConfig
|
Archival settings. |
experience_compressor |
ExperienceCompressorConfig
|
GEMS two-tier compressor settings. |
wiki_export |
WikiExportConfig
|
Wiki filesystem export settings. |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
enabled(bool) -
interval(ConsolidationInterval) -
max_memories_per_agent(int) -
retention(RetentionConfig) -
archival(ArchivalConfig) -
experience_compressor(ExperienceCompressorConfig) -
wiki_export(WikiExportConfig)
Validators:
-
_apply_mirrors
LLMConsolidationConfig
pydantic-model
¶
Bases: BaseModel
Configuration for the LLM-based consolidation strategy.
Encapsulates all tuning knobs previously passed as loose kwargs to
LLMConsolidationStrategy.__init__ and module-level constants.
Aligns with the frozen Pydantic config convention used by sibling
strategies (DualModeConfig, RetentionConfig).
Attributes:
| Name | Type | Description |
|---|---|---|
group_threshold |
int
|
Minimum category group size for consolidation.
At threshold 3, |
temperature |
float
|
Sampling temperature for the synthesis LLM call. |
max_summary_tokens |
int
|
Maximum tokens for the synthesis response. |
include_distillation_context |
bool
|
When True, fetches recent distillation entries as trajectory context for the synthesis prompt. |
max_trajectory_context_entries |
int
|
Maximum distillation entries to include as trajectory context. |
max_trajectory_chars_per_entry |
int
|
Character limit per trajectory snippet in the synthesis prompt. |
max_entry_input_chars |
int
|
Per-entry content character limit before being sent to the LLM. |
max_total_user_content_chars |
int
|
Total character cap for the concatenated user prompt sent to the LLM. |
fallback_truncate_length |
int
|
Per-entry truncation limit in concatenation-fallback summaries. |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
group_threshold(int) -
temperature(float) -
max_summary_tokens(int) -
include_distillation_context(bool) -
max_trajectory_context_entries(int) -
max_trajectory_chars_per_entry(int) -
max_entry_input_chars(int) -
max_total_user_content_chars(int) -
fallback_truncate_length(int)
Validators:
-
_validate_entry_vs_total_chars
group_threshold
pydantic-field
¶
Minimum category group size for consolidation (must be >= 3)
max_summary_tokens
pydantic-field
¶
Maximum tokens for the synthesis response
include_distillation_context
pydantic-field
¶
When True, fetch recent distillation entries as trajectory context for the synthesis prompt
max_trajectory_context_entries
pydantic-field
¶
Maximum distillation entries to include as trajectory context
max_trajectory_chars_per_entry
pydantic-field
¶
Character limit per trajectory snippet in the synthesis prompt
max_entry_input_chars
pydantic-field
¶
Per-entry content character limit before being sent to the LLM
max_total_user_content_chars
pydantic-field
¶
Total character cap for the concatenated user prompt sent to the LLM
fallback_truncate_length
pydantic-field
¶
Per-entry truncation limit in concatenation-fallback summaries
models
¶
Memory consolidation domain models.
Frozen Pydantic models for consolidation results, archival entries, retention rules, dual-mode archival types, and GEMS two-tier compressed/detailed experience models.
ArchivalMode
¶
Bases: StrEnum
How a memory entry was archived during consolidation.
Determines the preservation strategy applied before archival.
ArchivalModeAssignment
pydantic-model
¶
Bases: BaseModel
Maps a removed memory entry to the archival mode applied.
Attributes:
| Name | Type | Description |
|---|---|---|
original_id |
NotBlankStr
|
ID of the removed memory entry. |
mode |
ArchivalMode
|
Archival mode applied to this entry. |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
ArchivalIndexEntry
pydantic-model
¶
Bases: BaseModel
Maps a removed memory entry to its archival store ID.
Enables deterministic index-based restore: agents can look up their own archived entries by original ID without semantic search.
Attributes:
| Name | Type | Description |
|---|---|---|
original_id |
NotBlankStr
|
ID of the original memory entry. |
archival_id |
NotBlankStr
|
ID assigned by the archival store. |
mode |
ArchivalMode
|
Archival mode used for this entry. |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
ConsolidationResult
pydantic-model
¶
Bases: BaseModel
Result of a memory consolidation run.
Attributes:
| Name | Type | Description |
|---|---|---|
removed_ids |
tuple[NotBlankStr, ...]
|
IDs of removed memory entries. |
summary_ids |
tuple[NotBlankStr, ...]
|
IDs of summary entries created during the run.
Strategies that produce a single summary populate a
one-element tuple; strategies that produce per-group
summaries (e.g. |
summary_id |
NotBlankStr | None
|
Derived from |
archived_count |
int
|
Number of entries archived. |
consolidated_count |
int
|
Derived from |
mode_assignments |
tuple[ArchivalModeAssignment, ...]
|
Per-entry archival mode assignments (set by strategy, empty for strategies that don't classify density). |
archival_index |
tuple[ArchivalIndexEntry, ...]
|
Maps original memory IDs to archival store IDs (built by service after archival completes). |
Config:
frozen:Trueallow_inf_nan:False
Fields:
-
removed_ids(tuple[NotBlankStr, ...]) -
summary_ids(tuple[NotBlankStr, ...]) -
archived_count(int) -
mode_assignments(tuple[ArchivalModeAssignment, ...]) -
archival_index(tuple[ArchivalIndexEntry, ...])
Validators:
-
_validate_archival_consistency
consolidated_count
property
¶
Number of memories consolidated (derived from removed_ids).
summary_id
property
¶
Representative summary id (last one produced, or None).
Derived from summary_ids. Callers that need every summary
(e.g. multi-category LLMConsolidationStrategy runs) should
read summary_ids directly.
Exposed as a plain @property (not @computed_field) so
it is NOT emitted by model_dump(). Otherwise the serialized
payload would include summary_id and a round-trip through
model_validate(result.model_dump()) would fail against the
extra='forbid' guard -- a nasty surprise for any
persistence or copy-through-JSON path.
ArchivalEntry
pydantic-model
¶
Bases: BaseModel
An archived memory entry.
Attributes:
| Name | Type | Description |
|---|---|---|
original_id |
NotBlankStr
|
ID from the hot store. |
agent_id |
NotBlankStr
|
Owning agent identifier. |
content |
NotBlankStr
|
Memory content text. |
category |
MemoryCategory
|
Memory type category. |
metadata |
MemoryMetadata
|
Associated metadata. |
created_at |
AwareDatetime
|
Original creation timestamp. |
archived_at |
AwareDatetime
|
When this entry was archived. |
archival_mode |
ArchivalMode
|
How this entry was archived. |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
original_id(NotBlankStr) -
agent_id(NotBlankStr) -
content(NotBlankStr) -
category(MemoryCategory) -
metadata(MemoryMetadata) -
created_at(AwareDatetime) -
archived_at(AwareDatetime) -
archival_mode(ArchivalMode)
Validators:
-
_validate_temporal_order
RetentionRule
pydantic-model
¶
Bases: BaseModel
Per-category retention rule.
Attributes:
| Name | Type | Description |
|---|---|---|
category |
MemoryCategory
|
Memory category this rule applies to. |
retention_days |
int
|
Number of days to retain memories. |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
category(MemoryCategory) -
retention_days(int)
ContentDensity
¶
Bases: StrEnum
Content density classification for archival mode selection.
Attributes:
| Name | Type | Description |
|---|---|---|
SPARSE |
Conversational, narrative, low information density. |
|
DENSE |
Code, structured data, identifiers, high density. |
DetailedExperience
pydantic-model
¶
Bases: BaseModel
Tier 1 raw artifact -- append-only execution trace.
Stores the complete raw execution context for a single turn or
task. Retrieved by entry.id only (audit/debug), NOT used
for context injection.
Attributes:
| Name | Type | Description |
|---|---|---|
id |
NotBlankStr
|
Unique identifier. |
agent_id |
NotBlankStr
|
Owning agent identifier. |
prompt |
NotBlankStr
|
Raw prompt sent to the agent. |
output |
NotBlankStr
|
Raw output produced by the agent. |
verification_feedback |
NotBlankStr | None
|
Verification result text ( |
reasoning_trace |
tuple[NotBlankStr, ...]
|
Step-by-step reasoning trace entries. |
metadata |
MemoryMetadata
|
Associated metadata (tags include
|
created_at |
AwareDatetime
|
When the experience was captured. |
source_task_id |
NotBlankStr | None
|
Optional originating task identifier. |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
id(NotBlankStr) -
agent_id(NotBlankStr) -
prompt(NotBlankStr) -
output(NotBlankStr) -
verification_feedback(NotBlankStr | None) -
reasoning_trace(tuple[NotBlankStr, ...]) -
metadata(MemoryMetadata) -
created_at(AwareDatetime) -
source_task_id(NotBlankStr | None)
Validators:
-
_validate_tier_tag
CompressedExperience
pydantic-model
¶
Bases: BaseModel
Tier 2 compressed learning -- retrieval-primary.
Distilled from one or more DetailedExperience entries by the
ExperienceCompressor. These are the entries agents see during
context injection -- raw traces are NOT injected.
GEMS ablation shows compressed experiences outperform raw reasoning traces by 2.5x (GEMS section 4.3).
Attributes:
| Name | Type | Description |
|---|---|---|
id |
NotBlankStr
|
Unique identifier. |
agent_id |
NotBlankStr
|
Owning agent identifier. |
strategic_decisions |
tuple[NotBlankStr, ...]
|
Distilled "what worked, what didn't" learnings. |
applicable_contexts |
tuple[NotBlankStr, ...]
|
When and where this experience applies. |
source_artifact_ids |
tuple[NotBlankStr, ...]
|
Links back to |
compression_ratio |
float
|
|
compressor_version |
NotBlankStr
|
Version stamp for the compressor that produced this entry. |
metadata |
MemoryMetadata
|
Associated metadata (tags include
|
created_at |
AwareDatetime
|
When the compression was performed. |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
id(NotBlankStr) -
agent_id(NotBlankStr) -
strategic_decisions(tuple[NotBlankStr, ...]) -
applicable_contexts(tuple[NotBlankStr, ...]) -
source_artifact_ids(tuple[NotBlankStr, ...]) -
compression_ratio(float) -
compressor_version(NotBlankStr) -
metadata(MemoryMetadata) -
created_at(AwareDatetime)
Validators:
-
_validate_non_empty
strategy
¶
Consolidation strategy protocol.
Defines the interface for memory consolidation algorithms that compress and summarize older memories.
ConsolidationStrategy
¶
Bases: Protocol
Protocol for memory consolidation strategies.
Implementations receive a batch of memory entries and produce
a ConsolidationResult indicating which entries were merged,
removed, or summarized.
consolidate
async
¶
Consolidate a batch of memory entries.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
entries
|
tuple[MemoryEntry, ...]
|
Memory entries to consolidate. |
required |
agent_id
|
NotBlankStr
|
Owning agent identifier. |
required |
Returns:
| Type | Description |
|---|---|
ConsolidationResult
|
Result describing what was consolidated. |
Source code in src/synthorg/memory/consolidation/strategy.py
service
¶
Memory consolidation service.
Orchestrates retention cleanup, consolidation, archival, and max-memories enforcement into a single maintenance entry point.
MemoryConsolidationService
¶
MemoryConsolidationService(
*,
backend,
config,
strategy=None,
archival_store=None,
max_enforce_batch=_MAX_ENFORCE_BATCH,
config_resolver=None,
)
Orchestrates memory consolidation, retention, and archival.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
backend
|
MemoryBackend
|
Memory backend for CRUD operations. |
required |
config
|
ConsolidationConfig
|
Consolidation configuration. |
required |
strategy
|
ConsolidationStrategy | None
|
Optional consolidation strategy (skips consolidation
step if |
None
|
archival_store
|
ArchivalStore | None
|
Optional archival store (skips archival if
|
None
|
max_enforce_batch
|
int
|
Maximum memories to enforce retention on per
invocation. Must match the bounds of the
|
_MAX_ENFORCE_BATCH
|
Source code in src/synthorg/memory/consolidation/service.py
run_consolidation
async
¶
Run memory consolidation for an agent.
Retrieves up to 1000 entries per invocation and applies the consolidation strategy, then archives removed entries if archival is configured and enabled. Per-entry archival failures are logged and skipped -- they do not abort the entire batch.
Gated by the memory.consolidation_enabled kill-switch:
when False the call short-circuits immediately without
touching the backend or strategy, so operators can pause
consolidation mid-flight without tearing down scheduling.
The flag is resolved per call when a ConfigResolver is
wired (runtime-controllable); without a resolver we fall back
to the YAML-baked config.enabled field.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
agent_id
|
NotBlankStr
|
Agent whose memories to consolidate. |
required |
Returns:
| Type | Description |
|---|---|
ConsolidationResult
|
Consolidation result (including archival count). |
Source code in src/synthorg/memory/consolidation/service.py
enforce_max_memories
async
¶
Enforce the maximum memories limit for an agent.
Retrieves excess entries in batches (up to 1000 per query,
the MemoryQuery.limit cap) and deletes them. The entries
selected for deletion depend on the backend's default query
ordering -- typically oldest-first, but consult the concrete
backend for specifics.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
agent_id
|
NotBlankStr
|
Agent to check. |
required |
Returns:
| Type | Description |
|---|---|
int
|
Number of entries deleted. |
Source code in src/synthorg/memory/consolidation/service.py
cleanup_retention
async
¶
Run retention cleanup for an agent.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
agent_id
|
NotBlankStr
|
Agent whose expired memories to clean up. |
required |
agent_category_overrides
|
Mapping[MemoryCategory, int] | None
|
Per-category retention overrides for this agent. |
None
|
agent_default_retention_days
|
int | None
|
Agent-level default retention in days. |
None
|
Returns:
| Type | Description |
|---|---|
int
|
Number of expired memories deleted. |
Source code in src/synthorg/memory/consolidation/service.py
run_maintenance
async
¶
Run full maintenance cycle for an agent.
Orchestrates: retention cleanup -> consolidation -> max enforcement.
Gated by the memory.consolidation_enabled kill-switch: when
False the whole cycle short-circuits (retention, consolidation,
and max-memory enforcement all pause together so the scheduler can
be resumed without partial state).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
agent_id
|
NotBlankStr
|
Agent to maintain. |
required |
agent_category_overrides
|
Mapping[MemoryCategory, int] | None
|
Per-category retention overrides for this agent. |
None
|
agent_default_retention_days
|
int | None
|
Agent-level default retention in days. |
None
|
Returns:
| Type | Description |
|---|---|
ConsolidationResult
|
Consolidation result from the consolidation step. |
Source code in src/synthorg/memory/consolidation/service.py
retention
¶
Retention enforcer for memory lifecycle management.
Deletes memories that have exceeded their per-category retention period. Supports per-agent overrides that take priority over company-level defaults.
RetentionEnforcer
¶
Enforces per-category memory retention policies.
Queries for memories older than the configured retention period and deletes them from the backend.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
RetentionConfig
|
Retention configuration with per-category rules. |
required |
backend
|
MemoryBackend
|
Memory backend for querying and deleting. |
required |
Source code in src/synthorg/memory/consolidation/retention.py
cleanup_expired
async
¶
cleanup_expired(
agent_id,
now=None,
*,
agent_category_overrides=None,
agent_default_retention_days=None,
)
Delete memories that have exceeded their retention period.
Processes each category independently so that a failure in one category does not prevent cleanup of the remaining categories.
Processes up to 1000 expired entries per category per invocation. Multiple calls may be needed for categories with a large backlog.
When agent_category_overrides or agent_default_retention_days
is provided, per-agent retention rules are merged with company
defaults using the internal resolution chain
(_resolve_categories).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
agent_id
|
NotBlankStr
|
Agent whose memories to clean up. |
required |
now
|
datetime | None
|
Current time (defaults to UTC now). |
None
|
agent_category_overrides
|
Mapping[MemoryCategory, int] | None
|
Per-category retention overrides for this agent (mapping of category to days). |
None
|
agent_default_retention_days
|
int | None
|
Agent-level default retention in days. |
None
|
Returns:
| Type | Description |
|---|---|
int
|
Number of expired memories deleted. |
Source code in src/synthorg/memory/consolidation/retention.py
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 | |
archival
¶
Archival store protocol for long-term memory storage.
Defines the protocol for moving memories from the hot store into cold (archival) storage, with search and restore capabilities.
ArchivalStore
¶
Bases: Protocol
Protocol for long-term memory archival storage.
Concrete implementations handle moving memories from the hot (active) store into cold storage for long-term preservation.
archive
async
¶
Archive a memory entry.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
entry
|
ArchivalEntry
|
The archival entry to store. |
required |
Returns:
| Type | Description |
|---|---|
NotBlankStr
|
The assigned archive entry ID. |
search
async
¶
Search archived entries for a specific agent.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
agent_id
|
NotBlankStr
|
Agent whose archived entries to search. |
required |
query
|
MemoryQuery
|
Search parameters. |
required |
Returns:
| Type | Description |
|---|---|
tuple[ArchivalEntry, ...]
|
Matching archived entries owned by the agent. |
Source code in src/synthorg/memory/consolidation/archival.py
restore
async
¶
Restore a specific archived entry for a specific agent.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
agent_id
|
NotBlankStr
|
Agent who owns the archived entry. |
required |
entry_id
|
NotBlankStr
|
The archive entry ID. |
required |
Returns:
| Type | Description |
|---|---|
ArchivalEntry | None
|
The archived entry, or |
ArchivalEntry | None
|
owned by the agent. |
Source code in src/synthorg/memory/consolidation/archival.py
count
async
¶
Count archived entries for an agent.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
agent_id
|
NotBlankStr
|
Agent identifier. |
required |
Returns:
| Type | Description |
|---|---|
int
|
Number of archived entries. |
density
¶
Content density classification for dual-mode archival.
Heuristic-based classifier that determines whether memory content is sparse (conversational, narrative) or dense (code, structured data, identifiers). Classification is deterministic -- no LLM calls.
ContentDensity
¶
Bases: StrEnum
Classification of memory content density.
Determines the archival mode: sparse content receives abstractive LLM summarization, dense content receives extractive preservation.
DensityClassifier
¶
Heuristic content density classifier.
Classifies text as SPARSE or DENSE based on structural signals: code patterns, structured data markers, identifier density, numeric density, and line structure.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dense_threshold
|
float
|
Score threshold for DENSE classification (0.0-1.0). Lower values classify more content as dense. |
_DEFAULT_DENSE_THRESHOLD
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/synthorg/memory/consolidation/density.py
classify
¶
Classify content density.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
content
|
str
|
Text to classify. |
required |
Returns:
| Type | Description |
|---|---|
ContentDensity
|
DENSE if score >= threshold, SPARSE otherwise. |
Source code in src/synthorg/memory/consolidation/density.py
classify_batch
¶
Classify density for a batch of memory entries.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
entries
|
tuple[MemoryEntry, ...]
|
Memory entries to classify. |
required |
Returns:
| Type | Description |
|---|---|
tuple[tuple[MemoryEntry, ContentDensity], ...]
|
Tuple of (entry, density) pairs in input order. |
Source code in src/synthorg/memory/consolidation/density.py
extractive
¶
Extractive preservation for dense memory content.
For dense content (code, structured data, identifiers), summarization is catastrophically lossy. Instead, this module extracts verbatim key facts and structural anchors (start/mid/end) to preserve the most important information.
ExtractivePreserver
¶
Extracts key facts and structural anchors from dense content.
For dense content (code, structured data, IDs), summarization is catastrophically lossy. Instead, this preserver extracts verbatim key facts (identifiers, URLs, version numbers, key-value pairs) and structural anchors (start/mid/end snippets of the original).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
max_facts
|
int
|
Maximum number of key facts to extract. |
_DEFAULT_MAX_FACTS
|
anchor_length
|
int
|
Character length of each anchor snippet. |
_DEFAULT_ANCHOR_LENGTH
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/synthorg/memory/consolidation/extractive.py
extract
¶
Extract key facts and anchors from dense content.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
content
|
str
|
The dense text to extract from. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Structured text block with extracted facts and anchors. |
Source code in src/synthorg/memory/consolidation/extractive.py
abstractive
¶
Abstractive summarizer for sparse memory content.
Uses an LLM (via CompletionProvider) to generate concise summaries
of conversational/narrative memory content. Falls back to truncation
if the LLM call fails.
AbstractiveSummarizer
¶
AbstractiveSummarizer(
*,
provider,
model,
max_summary_tokens=_DEFAULT_MAX_SUMMARY_TOKENS,
temperature=_DEFAULT_TEMPERATURE,
cost_tracker=None,
)
LLM-based abstractive summarizer for sparse content.
Uses a CompletionProvider to generate concise summaries of
conversational/narrative memory content. Falls back to truncation
if the LLM call fails with a retryable error.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
provider
|
CompletionProvider
|
Completion provider for LLM calls. |
required |
model
|
NotBlankStr
|
Model identifier to use for summarization. |
required |
max_summary_tokens
|
int
|
Maximum tokens for the summary response. |
_DEFAULT_MAX_SUMMARY_TOKENS
|
temperature
|
float
|
Sampling temperature for summarization. |
_DEFAULT_TEMPERATURE
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/synthorg/memory/consolidation/abstractive.py
summarize
async
¶
Generate an abstractive summary of the given content.
Falls back to truncation if the LLM call fails with a retryable error or returns empty content. Non-retryable provider errors (authentication, invalid model) propagate.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
content
|
str
|
The sparse/conversational text to summarize. |
required |
agent_id
|
NotBlankStr | None
|
Owning agent for cost attribution. When
|
None
|
Returns:
| Type | Description |
|---|---|
str
|
Summary text. |
Source code in src/synthorg/memory/consolidation/abstractive.py
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | |
summarize_batch
async
¶
Summarize multiple entries concurrently.
Each entry is summarized independently via asyncio.TaskGroup.
Failures for individual entries fall back to truncation without
aborting the batch.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
entries
|
tuple[MemoryEntry, ...]
|
Memory entries to summarize. |
required |
Returns:
| Type | Description |
|---|---|
tuple[tuple[NotBlankStr, str], ...]
|
Tuple of |