symfonic.capabilities.memory.sources¶
sources ¶
What a store contributes to a retrieval, and the in-process store that does.
The split this module draws is the one that lets the coordinator be the same component behind a vector database, a graph, and a dict: a store says what it found and what it observed about each hit; it does not say what any of that is worth, how many survive, or in what order they render. Those are deployment decisions, and a backend that made them would give every backend a vote on the prompt — with two of them disagreeing.
So :class:CandidateSource answers with a record plus
:class:~.relevance.RelevanceSignals, and stops. It is deliberately not the
:class:~.ports.MemoryRetrievalPort: the port is what the bridge holds and
returns a finished, ranked, capped result. The coordinator is the thing in
between, and it is the component that implements the port over this seam.
:class:LexicalCandidateSource is the in-process reference (CON-S-4, same
reasoning as :class:~.in_memory.InMemoryHms): the framework must retrieve with
no database and no embedding model installed, so the default source scores cue
overlap with arithmetic. It is not a test double — a single-process deployment
selects it on purpose — but a deployment that outgrows lexical matching swaps it
without the coordinator noticing.
Candidate
dataclass
¶
Candidate(record: MemoryRecord, signals: RelevanceSignals = RelevanceSignals(), pre_ranked: bool = False)
One memory a store found, with whatever it observed about it.
The signals are the store's honest report, including its silences: a layer
with no embedding leaves cue at None, and the coordinator treats that
as "cannot answer" rather than "answered zero".
CandidateSource ¶
Bases: Protocol
A store, as the retrieval coordinator needs it.
search
async
¶
Return what this store can find for query within layers.
layers is the effective set — the deployment's enabled layers
narrowed by the query's — passed so a store can skip work rather than
return rows the coordinator will drop. The coordinator re-checks what
comes back regardless: a source that answers outside the set is a bug
this seam should surface, not one it should hide.
Ranking, limits, and ceilings are not this method's business. Return everything plausible; the coordinator decides what reaches a prompt.
Raises :class:~.errors.MemoryUnavailable when the store is unreachable.
Returning an empty sequence instead would be indistinguishable from a
scope that genuinely remembers nothing.
Source code in src/symfonic/capabilities/memory/sources.py
LexicalCandidateSource
dataclass
¶
A complete candidate source over records held in this process.
Scores cue overlap with token arithmetic rather than an embedding, because this is the zero-dependency default: a source that needed a model would make "retrieval works out of the box" false. Salience is left to the coordinator, which reads it off the record — a source should not restate what the record already carries.