symfonic.capabilities.knowledge.documents¶
documents ¶
The document bridge: a document store, adapted into one context declaration.
The guard that matters here is small and easy to lose in a rewrite: a document
id is a key, and AS-ING-2 says untrusted input must not select a filesystem
path. A store keyed by open(f"docs/{document_id}") and an id of
../../etc/passwd is the whole vulnerability, so the id is validated against
a charset before the store sees it. This package performs no filesystem
access itself; the check exists to protect stores that do.
Titles get the same treatment as citation sources: they arrive with the content, they are interpolated into a rendered delimiter, so they are reduced to labels rather than trusted.
.. note::
:class:DocumentPolicy's ceilings bound what this bridge emits; the
prompt compiler applies its own, much smaller, learned-content cap
(RenderPolicy.max_learned_chars, 500 by default) and drops any block
above it rather than truncating. The two are deliberately independent — the
bridge does not import the prompting capability — which means a composition
root wiring this contribution must raise max_learned_chars to at least
the ceiling it sets here. Leave it at its default and a real document
compiles to nothing but a diagnostic. See tests/capabilities/knowledge/
test_prompting_seam.py::TestRenderPolicyAlignment.
DocumentPolicy
dataclass
¶
The ceilings applied to a rendered document block.
DocumentSource
dataclass
¶
DocumentSource(store: DocumentStore, document_ids: Sequence[str], policy: DocumentPolicy = DocumentPolicy(), scope_aware: bool = False, offline_safe: bool = False)
A :class:~.contracts.ContextSource backed by a document store.
select ¶
Read the documents, and say why each omitted one was omitted.
Four different things make a declared document not appear — the store
has no such id, the document is blank, it is over the per-document
ceiling, or it would cross the aggregate one — and the rendered text
looks identical in all four. The reason channel is what lets a
composition root tell an operator which happened, the way the knowledge
bridge's :class:~.retrieval.FragmentSelection already does.
Source code in src/symfonic/capabilities/knowledge/documents.py
DocumentStore ¶
Bases: Protocol
The port a document store adapter satisfies.
None means "not here", not "empty". A store that answered with an empty
document for a missing id would make a deleted document indistinguishable
from a blank one, and the bridge would render a heading over nothing.
StoredDocument
dataclass
¶
StoredDocument(document_id: str, title: str, text: str, revision: str = '', media_type: str = 'text/plain')
One document as a store returns it.
document_contribution ¶
document_contribution(contribution_id: str, source: DocumentSource, *, order: int = 0, scope: str | None = None) -> ContextContribution
Declare a document set as standing (L1), session-tier context.
L1 rather than L2: the documents attached to a conversation are
stable for its life, and putting them on the volatile layer would push the
per-turn boundary above them and forfeit the cached prefix for content that
never changes.
Source code in src/symfonic/capabilities/knowledge/documents.py
validate_document_id ¶
Refuse any id that could be read as a path or a delimiter.