domain

package
v1.1.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 31, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Index

Constants

View Source
const (
	DefaultChunkSize    = 512
	DefaultChunkOverlap = 76
)

Default chunking parameters: ~512 tokens, ~15% overlap. For the fixed strategy a "token" is a whitespace word; the structure-aware strategies measure real tokens via an injected counter.

View Source
const FixedChunkerVersion = 1

FixedChunkerVersion is the algorithm version of the fixed (word-window) strategy, recorded in a Collection's ChunkerSpec. Bump it if the fixed chunker's output could change for the same input.

View Source
const MetaKeyModTime = "mtime"

MetaKeyModTime is the reserved metadata key under which ingestion records a source file's filesystem modification time (RFC3339). It is a recency signal (see HitTime), distinct from author-supplied front-matter dates.

View Source
const RRFDefaultK = 60

RRFDefaultK is the conventional Reciprocal Rank Fusion constant. It dampens the weight of low ranks so a chunk near the top of several lists outranks one at the top of a single list without any one list dominating.

View Source
const SheetHeadingPrefix = "# Sheet: "

SheetHeadingPrefix introduces a sheet boundary in extracted tabular text. An extractor that can name its tables (the xlsx extractor, from the workbook's tab names) emits one such line before each table's rows; SheetChunker splits on it and repeats it on every chunk. It lives in domain rather than beside the extractor because it is the contract between them, and both sides must agree on it — the tabular analogue of markdown's "#".

View Source
const StructureChunkerVersion = 2

StructureChunkerVersion is the algorithm version of the structure-aware strategy (markdown sections + token sizing, plus the plain-text and tabular strategies that share its sizing), recorded in a ChunkerSpec. Bump it when any structure chunker's output could change for the same input.

v2 added SheetChunker: tabular formats gained sheet names and repeated header rows, so their chunk text changed. The spec is collection-wide, so this invalidates collections that hold no spreadsheets either — they stay queryable, but refuse further ingest until rebuilt.

Variables

View Source
var (
	// ErrInvalidArgument marks construction/validation failures of domain values.
	ErrInvalidArgument = errors.New("invalid argument")

	// ErrSpaceMismatch marks a space-coherence violation:
	// an attempt to mix vectors from a different EmbeddingSpace into a Collection.
	ErrSpaceMismatch = errors.New("embedding space mismatch")

	// ErrChunkerMismatch marks an attempt to (re-)ingest into a Collection with a
	// chunker different from the one it was pinned to (or any chunker, for a
	// collection that predates pinning). Like a space mismatch it is an invariant
	// violation; the CLI maps it to exit 4.
	ErrChunkerMismatch = errors.New("chunker mismatch")
)

Sentinel errors for domain invariant violations. Infrastructure-level errors (ErrNotFound etc.) live in internal/app, next to the ports.

Functions

func AllSupported added in v1.0.0

func AllSupported(claims []Claim) bool

AllSupported reports whether every claim is supported — the condition for a faithfulness gate to pass.

func HitRate added in v1.0.0

func HitRate(retrieved []string, relevant map[string]bool, k int) float64

HitRate is 1 if any of the top k is relevant, else 0.

func HitTime added in v1.0.0

func HitTime(h ChunkHit) (time.Time, bool)

HitTime infers the most meaningful timestamp for ranking a hit by recency, trying signals strongest-to-weakest and reporting whether one was found:

  1. an explicit "last modified" front-matter date (updated/modified/lastmod/…),
  2. the source file's recorded filesystem mtime (MetaKeyModTime),
  3. a date embedded in the source filename/path (2026-06-09, 2026-W20, …),
  4. a "created"/"date" front-matter date,
  5. the document's ingest time.

It assumes no single format: front-matter keys match case-insensitively, dates parse in several layouts (see parseDate), and filename dates cover ISO calendar dates and ISO weeks. A hit with none of these is unknown (ok=false) and keeps full weight in DecayByRecency rather than being treated as ancient.

func MRR added in v1.0.0

func MRR(retrieved []string, relevant map[string]bool) float64

MRR is the reciprocal rank of the first relevant identifier (1-based), or 0 if none is relevant.

func NDCGAtK added in v1.0.0

func NDCGAtK(retrieved []string, relevant map[string]bool, k int) float64

NDCGAtK is the normalized discounted cumulative gain at k with binary relevance: DCG over the top k divided by the ideal DCG (all relevant ranked first). 0 when there is nothing relevant.

func PrecisionAtK added in v1.0.0

func PrecisionAtK(retrieved []string, relevant map[string]bool, k int) float64

PrecisionAtK is the fraction of the top k that is relevant. 0 when nothing was retrieved.

func RecallAtK added in v1.0.0

func RecallAtK(retrieved []string, relevant map[string]bool, k int) float64

RecallAtK is the fraction of the relevant set found in the top k. 0 when there is nothing relevant (recall is undefined; callers exclude such cases).

func SameSpace

func SameSpace(colls []*Collection) error

SameSpace enforces space coherence across a set of collections: their vectors are directly comparable only if every collection shares one EmbeddingSpace. It is the precondition for any cross-collection retrieval — feeding one collection's vectors into another (query --from-collection) or merging hits from several (multi-collection ask/query) — and returns ErrSpaceMismatch naming the first offending collection (and both spaces) on a divergence. Zero or one collection trivially shares a space.

func SupportRate added in v1.0.0

func SupportRate(claims []Claim) float64

SupportRate is the fraction of claims that are supported (0..1). No claims is vacuously faithful (1.0); unsupported and uncited claims both lower it.

func ValidateCollectionName

func ValidateCollectionName(name string) error

ValidateCollectionName reports whether name is non-empty, filesystem- and shell-safe, and at most 64 chars. It is the shared rule behind NewCollection and the import path, which reconstructs a (possibly renamed) collection from an artifact and must validate the target name without building a full collection.

Types

type Attachment

type Attachment struct {
	MediaType string // e.g. "image/png", "application/pdf"
	Name      string // original filename, for display/citation; optional
	Data      []byte
}

Attachment is raw content handed to a Generator alongside retrieved chunks — an image or document the model reads directly. Unlike ingested content it is ephemeral: never chunked, embedded, or stored. How it is encoded for a provider, and whether the provider accepts it, are the Generator adapter's concern.

func NewAttachment

func NewAttachment(mediaType, name string, data []byte) (Attachment, error)

NewAttachment validates and constructs an Attachment. Name may be empty.

type Chunk

type Chunk struct {
	ID         ChunkID
	DocumentID DocumentID
	Seq        int
	Text       string
	// HeadingPath is the document section a chunk came from, joined with " > "
	// (e.g. "Auth > Keys > Rotation"). Set by structure-aware chunkers; empty for
	// formats or strategies without headings. It is provenance for display and
	// inspection, not part of the chunk's identity.
	HeadingPath string
}

Chunk is the unit of retrieval. It belongs to exactly one Document (deleting the Document deletes its Chunks).

func NewChunk

func NewChunk(docID DocumentID, seq int, text string) (Chunk, error)

NewChunk constructs a Chunk with its deterministic ID.

type ChunkHit

type ChunkHit struct {
	Chunk  Chunk
	Score  float64
	Source string // source URI of the chunk's document
	// Collection names the collection the chunk came from. It is empty for
	// single-collection retrieval (where it is implied by the request) and set
	// only for cross-collection results (multi-collection query/ask), so the
	// merged hits stay attributable to their origin.
	Collection  string
	RerankScore *float64
	// Metadata is the chunk's document-level attributes, attached at hydration for
	// display (--json, human output). Empty unless the document carried metadata.
	Metadata Metadata
	// IngestedAt is when the chunk's document was ingested, attached at hydration.
	// It is the recency fallback (see HitTime) when the document carries no date
	// metadata; the zero value means unknown.
	IngestedAt time.Time
}

ChunkHit is a hydrated retrieval result: the chunk itself, its similarity score, and the URI of the source document it came from (provenance for display and citation). RerankScore is set only after a cross-encoder rerank — nil means the hit was never reranked, so it serializes additively (rerank_score omitted) and the original Score is always preserved alongside it.

func CapPerSource added in v1.0.0

func CapPerSource(hits []ChunkHit, max int) []ChunkHit

CapPerSource caps the number of hits kept per source document to max, preserving the input order (assumed already ranked). A document that dominates the ranking cannot then sweep the result set. max <= 0 is a no-op.

func DecayByRecency added in v1.0.0

func DecayByRecency(hits []ChunkHit, halfLife time.Duration, now time.Time, k int) []ChunkHit

DecayByRecency reorders hits by relevance blended with an exponential time decay, then returns the top k (all of them when k <= 0). Each hit's cosine Score is multiplied by 2^(-age/halfLife), where age is now minus the hit's timestamp (HitTime); the hits are stable-sorted by this adjusted score. A hit with no known timestamp, or one dated in the future, keeps its full score (decay 1.0) — only known-older hits are demoted, so retrieval never buries an undated chunk on a guess. The cosine Score is preserved for display; only the order changes (mirroring rerank/MMR). halfLife <= 0 is a no-op reorder.

func SelectMMR added in v1.0.0

func SelectMMR(candidates []MMRCandidate, lambda float64, k int) []ChunkHit

SelectMMR reorders candidates by Maximal Marginal Relevance, greedily picking the candidate that maximizes lambda*relevance - (1-lambda)*maxSimilarityToSelected, where relevance is the hit's (cosine) Score and similarity is cosine between candidate vectors. lambda in [0,1] trades relevance (1.0) against diversity (0.0); ~0.5 is a balanced default. It returns up to k selected hits in selection order; k <= 0 selects all. Ties break by ChunkID for determinism.

Relevance (Score) and the similarity penalty are both cosine-scaled, so they combine meaningfully; under --rerank the rerank score is a different scale and is deliberately not used here (cosine relevance keeps MMR's two terms comparable).

type ChunkID

type ChunkID string

ChunkID is deterministic, derived from (DocumentID, Seq), so re-chunking an unchanged document yields identical identities, keeping ingestion idempotent.

func DeriveChunkID

func DeriveChunkID(docID DocumentID, seq int) ChunkID

DeriveChunkID computes the deterministic identity of a chunk.

func (ChunkID) Valid

func (id ChunkID) Valid() bool

Valid reports whether id has the canonical shape produced by DeriveChunkID: a 64-character lowercase-hex document hash, a colon, and a non-negative sequence number (e.g. "3f2a…9c:5"). It is a format check, not an existence check.

type ChunkResult

type ChunkResult struct {
	Text string
	// EmbedText is the text to embed when it should differ from the stored Text —
	// e.g. a heading-path context prefix prepended so the embedding captures the
	// chunk's place in the document. Empty means embed Text as-is; either way the
	// stored Text (what citations and inspection show) is the original, never the
	// prefixed form.
	EmbedText string
	// HeadingPath is the document section the chunk came from (e.g.
	// "Auth > Keys > Rotation"), set by structure-aware chunkers; empty otherwise.
	HeadingPath string
}

ChunkResult is one chunk a Chunker produced: the text to store and cite, plus any section metadata. Identity (ChunkID, Seq) is assigned by the ingestor, not the chunker, since only the ingestor knows the owning Document.

func (ChunkResult) TextToEmbed

func (r ChunkResult) TextToEmbed() string

TextToEmbed returns the text that should be embedded for this chunk: the EmbedText override when set, otherwise the stored Text.

type Chunker

type Chunker interface {
	Chunk(doc ParsedDoc) ([]ChunkResult, error)
}

Chunker splits a parsed document into ordered chunks. Implementations are deterministic and pure: same input → identical output, no I/O, no map-iteration-order dependence. A token-aware strategy receives a token-count func at construction rather than importing a tokenizer, so stdlib-only domain stays clean.

type ChunkerSpec

type ChunkerSpec struct {
	Strategy      string // "structure" | "fixed"
	Version       int    // strategy algorithm version; bump when output could change for the same input
	Size          int    // target chunk size (tokens for structure, words for fixed)
	Overlap       int    // overlap between adjacent chunks, same unit as Size
	Tokenizer     string // sizing tokenizer identity, e.g. "o200k_base" (structure) or "words" (fixed)
	ContextPrefix bool   // whether a heading-path context line is prepended to the embedded text
}

ChunkerSpec identifies the chunking configuration a Collection is pinned to: the strategy, its algorithm version, the size/overlap parameters, the tokenizer used for sizing, and whether a heading-path context prefix is embedded. Any of these changing alters chunk output (boundaries, count, or embedded text) for the same input, so a Collection records its spec at creation and refuses re-ingestion under a different one — the chunker analogue of space coherence. It is comparable with ==.

func NewChunkerSpec

func NewChunkerSpec(strategy string, version, size, overlap int, tokenizer string, contextPrefix bool) (ChunkerSpec, error)

NewChunkerSpec validates and constructs a ChunkerSpec.

func (ChunkerSpec) IsZero

func (s ChunkerSpec) IsZero() bool

IsZero reports whether the spec is uninitialized — the state of a Collection created before chunker pinning existed.

func (ChunkerSpec) String

func (s ChunkerSpec) String() string

String renders the spec for human and error output, e.g. "structure/v1 size=512 overlap=64 tok=o200k_base prefix=on".

func (ChunkerSpec) Validate

func (s ChunkerSpec) Validate() error

Validate reports whether the spec is well-formed.

type Citation

type Citation struct {
	ChunkID ChunkID
	Source  string // source URI of the chunk's document
	Seq     int    // the chunk's position within that document
	// Collection names the chunk's collection, set only for cross-collection
	// answers (multi-collection ask) so a citation stays attributable to its
	// origin; empty for single-collection answers.
	Collection string
}

Citation references a chunk an answer was grounded in, carrying the provenance needed to display it: the source document's URI and the chunk's position within it.

type Claim added in v1.0.0

type Claim struct {
	Text        string
	CitedChunks []ChunkID
	Verdict     ClaimVerdict
	Rationale   string
}

Claim is one sentence of an answer with the chunks it cites and its verdict. A cited claim starts with an empty Verdict (the Verifier fills it); an uncited claim is VerdictUncited from segmentation.

func SegmentClaims added in v1.0.0

func SegmentClaims(answer string, citations []Citation) []Claim

SegmentClaims splits an answer into claims (sentences), extracts the chunk IDs each cites (keeping only those present in citations — hallucinated IDs are dropped), and strips the citation markers from the claim text. A sentence with no letters is list structure or a stray number ("1." enumerators split as "1"), not a claim, and is dropped. A sentence with no marker of its own inherits the citations of its block — generators cite once at the end of a multi-sentence point, and the point's earlier sentences are grounded in the same chunks. Only a sentence whose whole block cites nothing is marked VerdictUncited; every other claim is left unjudged for the Verifier. Empty/whitespace-only answers yield no claims.

type ClaimVerdict added in v1.0.0

type ClaimVerdict string

ClaimVerdict is the faithfulness verdict for one claim (sentence) of an answer.

const (
	// VerdictSupported: the claim is entailed by the chunk(s) it cites.
	VerdictSupported ClaimVerdict = "supported"
	// VerdictUnsupported: the claim cites chunks but is not entailed by them.
	VerdictUnsupported ClaimVerdict = "unsupported"
	// VerdictUncited: the claim cites no chunk in the grounding set, so it cannot
	// be verified — flagged rather than trusted.
	VerdictUncited ClaimVerdict = "uncited"
)

type Collection

type Collection struct {
	Name      string
	Space     EmbeddingSpace
	Chunker   ChunkerSpec
	CreatedAt time.Time
	// Sources are the paths ingested into this collection, recorded by add and
	// sync so `lore sync` can replay them without a path argument.
	Sources []string
}

Collection is the aggregate root: a named corpus bound to exactly one EmbeddingSpace, and pinned to exactly one ChunkerSpec, for its entire lifetime.

func NewCollection

func NewCollection(name string, space EmbeddingSpace, chunker ChunkerSpec, now time.Time) (*Collection, error)

NewCollection validates identity, space, and chunker spec, and constructs a Collection. The clock is injected so the domain stays deterministic and testable. A new collection must be pinned to a valid ChunkerSpec; collections loaded from storage that predate chunker pinning carry a zero spec (built as a literal by the repository, not through this constructor).

func (*Collection) AcceptsChunker

func (c *Collection) AcceptsChunker(spec ChunkerSpec) error

AcceptsChunker enforces chunker coherence: a collection may be (re-)ingested only by the chunker it was pinned to. Mixing chunker configurations within a collection would silently leave it holding chunks of two incompatible layouts (unchanged documents fast-skip re-chunking), so a mismatch is refused — the collection must be rebuilt under the new chunker. A collection that predates chunker pinning (zero spec) is read-only: queryable, but not re-ingestable.

func (*Collection) AcceptsSpace

func (c *Collection) AcceptsSpace(s EmbeddingSpace) error

AcceptsSpace enforces space coherence: vectors may enter the collection only if they were produced in the collection's own space.

type Condition added in v1.0.0

type Condition struct {
	Key   string
	Op    Operator
	Value string
}

Condition is one metadata comparison: <key> <op> <value>.

type ContentHash

type ContentHash string

ContentHash is the SHA-256 of document content, hex-encoded. Hash equality is what makes ingestion idempotent.

func HashContent

func HashContent(content []byte) ContentHash

HashContent computes the ContentHash of raw content.

type CorpusSnapshot added in v1.0.0

type CorpusSnapshot struct {
	// Digest is the hex sha256 over the corpus's (SourceURI, Hash) pairs.
	Digest ContentHash
	// LastIngest is the maximum Document.IngestedAt, or the zero time when the
	// corpus is empty.
	LastIngest time.Time
}

CorpusSnapshot is a content-derived identity for a collection's document set. Its Digest changes if and only if the set of (source, content-hash) pairs changes — any addition, removal, or edit — and is therefore the field a provenance trail should stamp, unlike Collection.CreatedAt, which is a birth/ rebuild marker that a sync leaves untouched. LastIngest names when the most recently (re)ingested document entered the corpus.

The snapshot is space- and chunker-independent by design: it identifies what was ingested, not how it was embedded, mirroring CollectionDiff.

func SnapshotOf added in v1.0.0

func SnapshotOf(docs []*Document) CorpusSnapshot

SnapshotOf computes the CorpusSnapshot of docs. The Digest is order- independent (the pairs are hashed in SourceURI order) and unambiguous: each field is NUL-terminated, so neither a URI nor a hash can straddle a boundary — the same framing guarantee DeriveDocumentID relies on.

type Document

type Document struct {
	ID         DocumentID
	Collection string
	SourceURI  string
	Hash       ContentHash
	IngestedAt time.Time
	// Fingerprint is a cheap source-side signature (e.g. size + sampled-content
	// hash) used to skip re-reading unchanged files before extraction. Unlike
	// Hash it is a heuristic, not an identity; empty means "unknown".
	Fingerprint string
	// Metadata holds the document's structured attributes (user-supplied --meta
	// pairs, extracted front-matter, path/mtime-derived fields). It is provenance
	// for display and the substrate for --where filtering; it is not part of the
	// document's identity (Hash) and may change without re-chunking.
	Metadata Metadata
}

Document is source content with identity. Whether its content *changed* is decided by Hash (hash equality => ingestion is a no-op).

func NewDocument

func NewDocument(collection, sourceURI string, hash ContentHash, now time.Time) (*Document, error)

NewDocument constructs a Document with its deterministic ID.

func (*Document) Unchanged

func (d *Document) Unchanged(hash ContentHash) bool

Unchanged reports whether content with the given hash would be a no-op re-ingestion of this document.

type DocumentID

type DocumentID string

DocumentID is deterministic, derived from (collection, source URI): re-ingesting the same source addresses the same identity, which is what makes `lore add` an upsert rather than an append.

func DeriveDocumentID

func DeriveDocumentID(collection, sourceURI string) DocumentID

DeriveDocumentID computes the deterministic identity of a source within a collection. The NUL separator prevents ambiguity between (a,bc) and (ab,c).

type EmbeddingSpace

type EmbeddingSpace struct {
	Model      string
	Dimensions int
}

EmbeddingSpace identifies the vector space a Collection is bound to: the embedding model plus its output dimensionality. Two vectors are comparable only if they come from the same space.

func NewEmbeddingSpace

func NewEmbeddingSpace(model string, dimensions int) (EmbeddingSpace, error)

NewEmbeddingSpace validates and constructs an EmbeddingSpace.

func (EmbeddingSpace) Equal

func (s EmbeddingSpace) Equal(other EmbeddingSpace) bool

Equal reports whether two spaces are the same (and therefore whether their vectors are comparable).

func (EmbeddingSpace) IsZero

func (s EmbeddingSpace) IsZero() bool

IsZero reports whether the space is uninitialized.

func (EmbeddingSpace) String

func (s EmbeddingSpace) String() string

type FixedChunker

type FixedChunker struct {
	// contains filtered or unexported fields
}

FixedChunker emits fixed-size, overlapping windows measured in whitespace words — the legacy chunking behavior, preserved verbatim as the `fixed` strategy and the default fallback. Word sizing is dependency-free and deterministic; the structure-aware strategies use real token counts instead. Chunk text is whitespace-normalized as a side effect.

Construct with NewFixedChunker; the zero value is not usable.

func NewFixedChunker

func NewFixedChunker(size, overlap int) (FixedChunker, error)

NewFixedChunker returns a FixedChunker that emits chunks of at most size words, with consecutive chunks sharing overlap words. It requires size > 0 and 0 <= overlap < size, so every window advances.

func (FixedChunker) Chunk

func (c FixedChunker) Chunk(doc ParsedDoc) ([]ChunkResult, error)

Chunk implements Chunker by windowing the document text. ContentType is ignored — fixed sizing is format-agnostic.

func (FixedChunker) Split

func (c FixedChunker) Split(text string) []string

Split divides text into chunks in document order. Consecutive chunks share up to overlap words. Empty or whitespace-only input yields no chunks, and no chunk is ever empty.

type MMRCandidate added in v1.0.0

type MMRCandidate struct {
	Hit    ChunkHit
	Vector []float32
}

MMRCandidate is a hit paired with its embedding vector, the input to Maximal Marginal Relevance selection. The hit's Score is used as its relevance to the query; the vector is used for the redundancy penalty against already-selected hits.

type MarkdownChunker

type MarkdownChunker struct {
	// contains filtered or unexported fields
}

MarkdownChunker splits markdown into token-sized chunks that respect the document's heading hierarchy: each chunk is a section (the content under a heading), carrying the full heading path as metadata. It never breaks inside a fenced code block; oversized sections split at paragraph (then sentence, then word) boundaries, and undersized adjacent sections merge up to the target size. Deterministic and pure.

Construct with NewMarkdownChunker; the zero value is not usable.

func NewMarkdownChunker

func NewMarkdownChunker(size, overlap int, contextPrefix bool, countTokens func(string) int) (MarkdownChunker, error)

NewMarkdownChunker returns a MarkdownChunker targeting size tokens per chunk with overlap tokens shared between size-driven sub-splits. When contextPrefix is true, each chunk's embedded text is prefixed with its heading path so the embedding captures the chunk's place in the document (the stored text is unchanged). It requires size > 0, 0 <= overlap < size, and a non-nil counter.

func (MarkdownChunker) Chunk

func (c MarkdownChunker) Chunk(doc ParsedDoc) ([]ChunkResult, error)

Chunk splits the document into heading-aware, token-sized chunks.

type Metadata added in v1.0.0

type Metadata map[string]string

Metadata is a small, flat set of structured attributes attached to a Document and carried on its chunks' index entries for retrieval filtering. Values are stored canonically as strings; the typed comparison semantics (numeric, date, glob, tag membership) live in Predicate, not in the storage. Keys are caller-defined: user-supplied --meta pairs, extracted front-matter, or path/mtime-derived fields.

func ParseFrontMatter added in v1.0.0

func ParseFrontMatter(text string) (Metadata, string)

ParseFrontMatter extracts a leading YAML-style front-matter block — a `---` fence, `key: value` lines, then a closing `---` fence — into Metadata, and returns the document body with that block removed. It is a deliberately small parser, not full YAML: each line is a single `key: value` scalar; a value wrapped in matching quotes is unquoted, and a `[a, b, c]` bracket list is flattened to a comma-joined string (so tag membership via the ~ operator works). Blank lines, `#` comments, and lines without a colon are ignored.

If text does not begin with a `---` fence, or the block is never closed, the text is returned unchanged with nil metadata — front matter is opt-in, never guessed. An empty block strips cleanly and yields nil metadata.

func (Metadata) Clone added in v1.0.0

func (m Metadata) Clone() Metadata

Clone returns an independent copy so callers may retain or mutate it without aliasing stored state (adapters return copies, like vectors). Nil clones to nil.

type Operator added in v1.0.0

type Operator string

Operator is the comparison in a --where Condition.

const (
	OpEqual        Operator = "="
	OpNotEqual     Operator = "!="
	OpLess         Operator = "<"
	OpLessEqual    Operator = "<="
	OpGreater      Operator = ">"
	OpGreaterEqual Operator = ">="
	OpMatch        Operator = "~"
)

The supported operators. Ordered/equality comparisons coerce both sides (numeric, then date, then string); ~ is a case-insensitive glob with tag-list membership. The grammar is deliberately small — a filter, not a query language.

type ParsedDoc

type ParsedDoc struct {
	Text        string
	ContentType string
	SourceURI   string
}

ParsedDoc is the input to a Chunker: the extracted text of one document plus the context a strategy may need. ContentType lets the Registry dispatch to a per-format strategy; SourceURI is carried for diagnostics.

type Predicate added in v1.0.0

type Predicate struct {
	Conditions []Condition
}

Predicate is a conjunction (AND) of metadata Conditions — the parsed form of the repeatable --where flag. The zero Predicate has no conditions and matches every document, so an absent --where filters nothing.

func ParseWhere added in v1.0.0

func ParseWhere(clauses []string) (Predicate, error)

ParseWhere parses repeatable --where clauses into a conjunctive Predicate. Each clause is one `key op value` (whitespace around each part is trimmed); the operators are =, !=, <, <=, >, >=, and ~. No clauses yields the zero predicate. A clause with no operator, an empty key, or an empty value is ErrInvalidArgument.

func (Predicate) IsZero added in v1.0.0

func (p Predicate) IsZero() bool

IsZero reports whether the predicate has no conditions, i.e. matches every document. Adapters use it to skip filtering entirely.

func (Predicate) Match added in v1.0.0

func (p Predicate) Match(md Metadata) bool

Match reports whether md satisfies every condition. The zero predicate matches any metadata, including nil.

type RankedID added in v1.0.0

type RankedID struct {
	ID    ChunkID
	Score float64
}

RankedID is a chunk identity with its fusion score, best (highest) first.

func FuseRRF added in v1.0.0

func FuseRRF(k int, lists ...[]ChunkID) []RankedID

FuseRRF combines several ranked lists of chunk IDs by Reciprocal Rank Fusion: each list contributes 1/(k + rank) to an ID's score (rank is 1-based, best first), summed across the lists it appears in; the result is sorted by score descending, ties broken by ID for determinism. A duplicate ID within a single list counts only at its best (first) rank. Rank-based fusion needs no score normalization, which is why it is the default merge of the (cosine) vector and (BM25) lexical result lists — their score scales are not comparable, but their ranks are.

type Registry

type Registry struct {
	// contains filtered or unexported fields
}

Registry selects a Chunker by content type, falling back to a default. It is how per-format strategies (markdown, plain text, ...) plug in without the ingestor knowing which is which; a future code-aware strategy is just another registered entry (though a tree-sitter strategy could not be pure-domain). It also carries the ChunkerSpec the active configuration corresponds to, so the use cases can pin it on new collections and refuse re-ingest under a different one. Construct with NewRegistry; the zero value is not usable.

func NewRegistry

func NewRegistry(spec ChunkerSpec, def Chunker, byType map[string]Chunker) (Registry, error)

NewRegistry builds a Registry routing each content type in byType to its Chunker and everything else to def, identified by spec. It requires a valid spec and a non-nil default, and rejects nil entries; content-type keys are normalized so dispatch is case- and parameter-insensitive.

func (Registry) Chunk

func (r Registry) Chunk(doc ParsedDoc) ([]ChunkResult, error)

Chunk dispatches to the chunker registered for the document's content type, or the default if none matches.

func (Registry) Spec

func (r Registry) Spec() ChunkerSpec

Spec returns the ChunkerSpec the registry's active configuration corresponds to — what new collections are pinned to and re-ingest is checked against.

type SheetChunker added in v1.1.0

type SheetChunker struct {
	// contains filtered or unexported fields
}

SheetChunker splits tabular text — one record per line — into token-sized chunks that stay readable on their own. A table's header row is the only thing naming its columns, and a sheet's tab name the only thing naming the table, so both are repeated at the top of every chunk cut from that table. Without this a chunk from the middle of a workbook retrieves as bare cells whose columns the reader (and the model) cannot recover.

Unlike MarkdownChunker's context prefix, the repetition goes into the stored Text, not just EmbedText: the header is genuinely absent from the interior of a table, so a reader of the cited chunk needs it as much as the embedding does.

Rows are never split across chunks and never duplicated between them; the header is the shared context instead of an overlap window. The first line of each table is taken to be its header, which is wrong for a workbook with banner rows above the real header — a limitation, not a heuristic to grow.

Deterministic and pure. Construct with NewSheetChunker; the zero value is not usable.

func NewSheetChunker added in v1.1.0

func NewSheetChunker(size, overlap int, countTokens func(string) int) (SheetChunker, error)

NewSheetChunker returns a SheetChunker targeting size tokens per chunk. The overlap applies only when a single row is itself too large to fit and has to be hard-split. It requires size > 0, 0 <= overlap < size, and a non-nil counter.

func (SheetChunker) Chunk added in v1.1.0

func (c SheetChunker) Chunk(doc ParsedDoc) ([]ChunkResult, error)

Chunk splits the document into per-table, header-carrying chunks.

type TextChunker

type TextChunker struct {
	// contains filtered or unexported fields
}

TextChunker splits plain text into token-sized chunks at paragraph (then sentence, then word) boundaries, never mid-sentence where avoidable. It has no heading awareness: it is the structure strategy's chunker for plain text and the default fallback for formats without their own structure-aware chunker (docx paragraphs; best-effort pdf/xlsx text). Deterministic and pure.

Construct with NewTextChunker; the zero value is not usable.

func NewTextChunker

func NewTextChunker(size, overlap int, countTokens func(string) int) (TextChunker, error)

NewTextChunker returns a TextChunker targeting size tokens per chunk with overlap tokens shared between size-driven splits. It requires size > 0, 0 <= overlap < size, and a non-nil token counter.

func (TextChunker) Chunk

func (c TextChunker) Chunk(doc ParsedDoc) ([]ChunkResult, error)

Chunk packs the document text into token-sized chunks. There is no heading path; ContentType is ignored.

type VectorMatch

type VectorMatch struct {
	ChunkID ChunkID
	Score   float64
}

VectorMatch is what a VectorIndex returns: an identity and a similarity score (higher is more similar), not yet hydrated with chunk content.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL