Skip to content

symfonic.memory.models

models

Pydantic data models for the graph memory system.

Re-exports all model classes for convenient importing.

AssembledContext

AssembledContext(**data: Any)

Bases: BaseModel

Fully assembled context ready for LLM consumption.

.. deprecated:: AssembledContext is deprecated. Hydration is handled by SymfonicAgent._hydrate() which returns HydratedMemory.

Source code in symfonic/memory/models/context.py
def __init__(self, **data: Any) -> None:
    warnings.warn(
        "AssembledContext is deprecated. Hydration is handled by "
        "SymfonicAgent._hydrate().",
        DeprecationWarning,
        stacklevel=2,
    )
    super().__init__(**data)

is_within_budget

is_within_budget(budget: ContextBudget) -> bool

Check whether this context respects all budget constraints.

Returns True if all component counts are within the budget limits. max_memory_entries was removed in v5.6.0 (v6.0 API freeze prep); memory-entry count is no longer budget-enforced -- the live SymfonicAgent._hydrate path uses max_tokens instead.

Source code in symfonic/memory/models/context.py
def is_within_budget(self, budget: ContextBudget) -> bool:
    """Check whether this context respects all budget constraints.

    Returns True if all component counts are within the budget limits.
    ``max_memory_entries`` was removed in v5.6.0 (v6.0 API freeze prep);
    memory-entry count is no longer budget-enforced -- the live
    ``SymfonicAgent._hydrate`` path uses ``max_tokens`` instead.
    """
    if len(self.selected_tools) > budget.max_tools:
        return False
    return not len(self.conversation_history) > budget.max_history_messages

CandidateNode

Bases: BaseModel

Intermediate model normalizing vector and graph results before scoring.

The RetrievalEngine converts all candidate results (whether from vector search or graph traversal) into CandidateNode instances. Hits without a graph node get a synthetic MemoryNode with access_count=0 and graph_proximity=0.0.

ContextBudget

ContextBudget(**data: Any)

Bases: BaseModel

Defines the limits for context assembly.

.. deprecated:: ContextBudget is deprecated. Budget constraints are now handled internally by SymfonicAgent._hydrate() via FrameworkConfig.

Source code in symfonic/memory/models/context.py
def __init__(self, **data: Any) -> None:
    warnings.warn(
        "ContextBudget is deprecated. Budget constraints are handled internally "
        "by SymfonicAgent._hydrate() via FrameworkConfig.",
        DeprecationWarning,
        stacklevel=2,
    )
    super().__init__(**data)

framework_default classmethod

framework_default() -> ContextBudget

The framework's own default, built without the adopter-facing warning.

OrchestratorConfig.context_budget needs an instance, and taking it from __init__ made the framework fire a deprecation about its own default on the first line of every platform program — pinned as EX-3 in the warning budget and recorded there as "not actionable by an adopter", because there was nothing for them to change.

A deprecation warns whoever chose the deprecated thing. Nobody chose this one, so nobody is warned for it. An adopter who constructs ContextBudget() is still warned, and a test pins both halves.

model_construct rather than a suppressed __init__: suppression needs warnings.catch_warnings, which mutates process-global filter state and would briefly swallow another thread's warnings. Validation loses nothing here — every field is a literal default this class declares, with no input to check.

Source code in symfonic/memory/models/context.py
@classmethod
def framework_default(cls) -> ContextBudget:
    """The framework's own default, built without the adopter-facing warning.

    ``OrchestratorConfig.context_budget`` needs an instance, and taking it
    from ``__init__`` made the framework fire a deprecation *about its own
    default* on the first line of every platform program — pinned as EX-3 in
    the warning budget and recorded there as "not actionable by an adopter",
    because there was nothing for them to change.

    A deprecation warns whoever chose the deprecated thing. Nobody chose
    this one, so nobody is warned for it. An adopter who constructs
    ``ContextBudget()`` **is** still warned, and a test pins both halves.

    ``model_construct`` rather than a suppressed ``__init__``: suppression
    needs ``warnings.catch_warnings``, which mutates process-global filter
    state and would briefly swallow another thread's warnings. Validation
    loses nothing here — every field is a literal default this class
    declares, with no input to check.
    """
    return cls.model_construct()

MemoryEdge

Bases: BaseModel

A directed edge in the tenant-scoped memory graph.

Edges represent typed relationships between MemoryNodes, such as 'KNOWS', 'USED_IN', 'TRIGGERED_BY', etc. Weight can be used to express relationship strength.

MemoryEntry

Bases: BaseModel

A memory entry returned from retrieval or submitted for writing.

Represents a single piece of information from any memory layer, optionally linked to a graph node and carrying a retrieval score.

MemoryNode

Bases: BaseModel

A node in the tenant-scoped memory graph.

Nodes represent facts, events, skills, triggers, or working context depending on their layer assignment. Each node carries an optional embedding vector for similarity search and tracks access frequency for retrieval scoring.

durability property

durability: Durability

Return the node's durability marker (v7.26.2 -- Shape C1).

Reads from properties['durability']. Pre-v7.26.2 nodes (and adopters who never set the key) get "durable" -- the safe default that preserves byte-identical promotion behaviour. An unknown persisted value falls back to "durable" so the consolidation gate never silently drops a row.

This is a computed property, NOT a model Field: it does not change the serialised shape (Contract A).

is_promotable

is_promotable() -> bool

Return True when the node is eligible for consolidation promotion.

Only "durable" nodes promote. "transient" and "expired" are gated out of Phases 10/11/12.

Source code in symfonic/memory/models/node.py
def is_promotable(self) -> bool:
    """Return True when the node is eligible for consolidation promotion.

    Only ``"durable"`` nodes promote.  ``"transient"`` and ``"expired"``
    are gated out of Phases 10/11/12.
    """
    return self.durability == "durable"

is_transient

is_transient() -> bool

Return True when the node is marked transient.

Source code in symfonic/memory/models/node.py
def is_transient(self) -> bool:
    """Return True when the node is marked transient."""
    return self.durability == "transient"

MemoryOperation

Bases: BaseModel

A pending memory mutation to be applied by the orchestrator.

Each operation targets a specific layer and action. The node and edge fields are populated depending on the action type.

WritePolicy

Bases: BaseModel

Controls which operations are applied and how many can be pending.

Operations with importance below min_importance_threshold are silently dropped during commit_pending.