Assembling one scope's hydrator from the parts a deployment supplied.
Split from :mod:symfonic.capabilities.memory.factory at the 300-line budget,
and the two halves are two questions: the factory decides what a memory
capability is, and this decides how the recall half of it is put together.
The factory supplies the conversation window and optional activation here.
The cutover bundle independently supplies its window but no activation.
Keeping the assembly in one named place is what makes a third such seam
visible when it is added rather than quietly skipped.
hydrator_for
hydrator_for(store: Any, *, conversation: Any | None = None, recent_turns: int = 0, activation: Any | None = None, retrieval_policy: RetrievalPolicy | None = None, retrieval: RetrievalCoordinator | None = None, exclude_speakers: frozenset[str] = frozenset()) -> HydrationCoordinator
The recall half of a memory capability, with what was supplied wired in.
A window with no source stays closed rather than being invented: the
conversation belongs to the deployment, and a factory that synthesised one
would be deciding what the model is told was said.
Zero explicitly disables the working window, retaining ranked recall.
A positive count still requires a conversation source.
Raises:
Source code in src/symfonic/capabilities/memory/hydrator_assembly.py
| def hydrator_for(
store: Any,
*,
conversation: Any | None = None,
recent_turns: int = 0,
activation: Any | None = None,
retrieval_policy: RetrievalPolicy | None = None,
retrieval: RetrievalCoordinator | None = None,
exclude_speakers: frozenset[str] = frozenset(),
) -> HydrationCoordinator:
"""The recall half of a memory capability, with what was supplied wired in.
A window with no source stays closed rather than being invented: the
conversation belongs to the deployment, and a factory that synthesised one
would be deciding what the model is told was said.
Zero explicitly disables the working window, retaining ranked recall.
A positive count still requires a conversation source.
Raises:
MemoryContractError: if a positive count has no conversation source.
"""
if recent_turns < 0 or (conversation is None and recent_turns > 0):
raise MemoryContractError(
"the conversation window needs a source for positive "
f"recent_turns and rejects negative counts; got conversation="
f"{'a source' if conversation is not None else 'None'} and "
f"recent_turns={recent_turns}. Zero disables the window."
)
if retrieval is not None and (retrieval_policy is not None or activation is not None):
raise MemoryContractError(
"a supplied retrieval coordinator already owns its policy and activation; "
"do not also pass retrieval_policy or activation"
)
if retrieval_policy is not None and not isinstance(retrieval_policy, RetrievalPolicy):
raise MemoryContractError("retrieval_policy must be a RetrievalPolicy")
if retrieval is not None and not isinstance(retrieval, RetrievalCoordinator):
raise MemoryContractError("retrieval must be a RetrievalCoordinator")
return HydrationCoordinator(
retrieval=(retrieval or RetrievalCoordinator(
source=PortCandidateSource(store), policy=retrieval_policy, activation=activation
)).excluding_speakers(exclude_speakers),
working=(
None
if conversation is None
else WorkingWindow(
source=conversation,
recent_turns=recent_turns,
exclude_speakers=exclude_speakers,
)
),
)
|