symfonic.capabilities.memory.hydration¶
hydration ¶
Turning a ranked recall into one block of text and one declaration.
Hydration is the last thing memory does before the prompt compiler runs, and the
only thing it hands over: a block, a revision, and a
:class:~.contribution.MemoryContribution declaring where that block belongs.
Everything upstream — layers, scoring, gates, activation — has already happened;
this module composes and bounds the result.
Order is a decision, not a formatting detail. The conversation window leads, then the ranked recall. The window is what the user just said; a recall that displaced it would answer a question about the conversation with a fact about the user.
Lines drop whole, from the tail. The ceiling cuts the weakest recall rather
than half of one. A memory truncated mid-sentence still reads as a complete
statement, and the statement it reads as is not the one the store held — the
same rule :func:~.queries.select applies per memory, applied again to the
assembled block.
JIT hydrates nothing. In :attr:HydrationMode.JIT the block is empty, no
contribution is declared, and the store is never called: the model asks for a
recall through a tool once it decides it needs one, which is
:meth:HydrationCoordinator.hydrate_on_demand. That is a real difference in
what happens, not a rendering mode — the round trip a JIT deployment is paying
to avoid is the one this skips.
Compression arrives bound. A deterministic text compressor lives in the framework's utilities, outside this layer, so the policy takes a callable rather than importing one. A capability that reached across for it would be two layers wearing one name, and a capability that reimplemented its abbreviation table would drift from it silently.
CoordinatedHydration
dataclass
¶
CoordinatedHydration(query: MemoryQuery, retrieval: CoordinatedRetrieval, working: WorkingContext = WorkingContext(), block: str = '', revision: str = '', contribution: MemoryContribution | None = None, request: MemoryRequest = (lambda: MemoryRequest(contribution_id=''))(), dropped: tuple[tuple[str, str], ...] = ())
HydrationCoordinator ¶
HydrationCoordinator(*, retrieval: RetrievalCoordinator, working: WorkingWindow | None = None, policy: HydrationPolicy | None = None, contribution_id: str = 'memory.recall', order: int = 0)
Composes the recall block and declares it to the prompt compiler.
Source code in src/symfonic/capabilities/memory/hydration.py
hydrate
async
¶
The prompt/input pass. Retrieves nothing in JIT mode.
Source code in src/symfonic/capabilities/memory/hydration.py
hydrate_on_demand
async
¶
The tool-facing pass: retrieve now, declare nothing.
The compiler has already run by the time a model calls a tool, so a contribution here would be a declaration nobody reads. The block is the tool's return value.
Source code in src/symfonic/capabilities/memory/hydration.py
HydrationMode ¶
HydrationPolicy
dataclass
¶
HydrationPolicy(mode: HydrationMode = HydrationMode.EAGER, max_block_chars: int = DEFAULT_BLOCK_CHARS, compressor: Callable[[str], str] | None = None)
How the block is assembled and bounded.