symfonic.capabilities.memory.contribution¶
contribution ¶
What memory is allowed to declare to the prompt compiler.
A deliberate narrowing of T3.2.1's prompt contribution contract, not a copy. The prompting capability accepts contributions at any tier because some of them are the operator's own instructions; a recall is content the system inferred from what a user said, so three declarations the general contract permits are refused here — the authored tiers, the L0 cached prefix, and pinning — and the refusal is a constructor check rather than a review note.
The two contracts are kept aligned by vocabulary, not by an import. A
capability may import the kernel's contracts and its own package; two
capabilities that import each other are one capability wearing two names. This
is the same seam T3.2.3's knowledge bridge uses, for the same reason, and
tests/capabilities/memory/test_prompting_seam.py holds both halves at once
so a vocabulary drift is a red test rather than a runtime ValueError in an
adopter's deployment.
The source here is pre-hydrated: retrieval already happened, asynchronously, in
the bridge's prompt/input stage, and :meth:HydratedMemorySource.read only
projects the materialised result. That is what lets an async memory system feed a
synchronous compiler without either one learning about the other — and why this
source can honestly declare itself offline-safe.
ContributionLayer ¶
Bases: StrEnum
The stratigraphic layer a recall renders on.
ContributionScope ¶
Bases: StrEnum
How widely one contribution's content is shared.
ContributionTier ¶
Bases: StrEnum
Authority tiers, mirroring the prompt contract's vocabulary.
HydratedMemorySource
dataclass
¶
HydratedMemorySource(result: RetrievalResult, scope_path: str, scope_aware: bool = True, offline_safe: bool = True)
A source over an already-hydrated retrieval, bound to the scope it used.
The binding is the security property. A compiled prompt is built from whatever contributions the caller passed; without the check below, a hydration performed for one tenant would render into another tenant's compile if a composition root reused the object — which is exactly the kind of reuse an object pool or a cached request makes easy.
MemoryContextSource ¶
Bases: Protocol
Reads the recall block for one contribution and scope.
The two flags are read-only properties, not settable attributes, and the
distinction is not a typing nicety. As bare annotations they described a
shape the snapshot refuses at runtime: a non-frozen dataclass satisfying
this protocol exactly as written is rejected by canonical_payload with
"carries a mutable dataclass". The protocol was inviting an adopter to write
a source that type-checks and then dies on its first turn.
Settable flags are also wrong on their own terms here.
MemoryContribution.validate() gates on scope_aware, and an input to
a gate that can change after validation — on an object that then lives in a
shared snapshot — is not an input, it is a suggestion.
@property + @abstractmethod rather than annotations, matching
BlockSource in core/prompt/blocks/protocol.py, whose own docstring
explains why: a bare annotation leaves the nominal inheritance path
unenforced, so a subclass that forgets one still answers isinstance
truthfully and raises AttributeError on access.
MemoryContribution
dataclass
¶
MemoryContribution(contribution_id: str, source: MemoryContextSource, capability: str = 'memory', layer: ContributionLayer = ContributionLayer.L2, tier: ContributionTier = ContributionTier.SESSION, scope: ContributionScope = ContributionScope.DEPLOYMENT, order: int = 0, inherit: bool = True, pinned: bool = False, requires_hydration: bool = True)
The bridge's declaration of the recall block it contributes.
validate ¶
Refuse every declaration this capability is not allowed to make.
Source code in src/symfonic/capabilities/memory/contribution.py
MemoryRead
dataclass
¶
What a memory source answered.
untrusted defaults to True — the inverse of the general prompt
contract's default, and the whole point of a separate value type. A recall
is aggregated from what a user said; a source here would have to remember to
declare it trusted, which nothing in this capability ever does.
MemoryRequest
dataclass
¶
What a source is asked for: one contribution, one scope, one turn.
contribution_spec ¶
Project a validated declaration into compiler-ready keyword values.
A mapping rather than a compiler object: the composition root — which is
allowed to see both capabilities — turns this into a PromptContribution,
so neither capability can quietly start depending on the other's internals.
Enum members are emitted as their string values; the prompt contract's
layers, tiers, and scopes are StrEnums over the same strings, so the
root's conversion is total by construction.
Source code in src/symfonic/capabilities/memory/contribution.py
resolve_contribution_scope ¶
Turn a caller's scope string into a member, or refuse it in-hierarchy.