Documentation
¶
Overview ¶
Package onnx implements agentic.RepresentationEncoder in this process, through ONNX Runtime, with no server and no network. This directory is a separate Go module and deliberately not part of github.com/regularkevvv/agentic, because it requires CGO, a native ONNX Runtime shared library, and a statically linked tokenizer — none of which can be a condition of using the library. That is why `go get github.com/regularkevvv/agentic` never pulls this package, and why a directory under provider/ is absent from the root module's build. Working on it means `cd provider/local/onnx`, with the setup in README.md done first.
What it produces ¶
Learned sparse vectors, and nothing else. Dense and multi-vector requests return agentic.UnsupportedRepresentationError rather than an answer derived from the wrong reduction. The target is the SPLADE family — a masked-language -model head pooled into vocabulary weights — which is what makes a document about an "automobile" carry weight on "car", a word it never contained.
Nothing is downloaded ¶
New takes filesystem paths and reads them. There is no model cache, no registry lookup, and no HTTP client in this package; a model you have not already exported is an error rather than a fetch. Producing the graph is a documented one-time step — see provider/local/onnx/export_onnx.py — and keeping it a step is the point: a 117 MiB artifact that appears by surprise during a test run is not a dependency anyone agreed to.
Batch width, not batch size, is the cost ¶
Every row in one forward pass is padded to the widest row in it, and padding buys compute nobody asked for. Measured on 2026-08-01, three short inputs padded to a common width of 18 took 20 ms as one call against 13 ms as three. The encoder therefore orders inputs by token length and groups neighbors, so a long document never drags short ones up to its width and no row is ever padded past twice its own length. The rule, and the bound it buys, are in batch.go.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Encoder ¶
type Encoder struct {
// contains filtered or unexported fields
}
Encoder runs an exported masked-language-model graph and pools its logits into a learned sparse vector.
It owns memory outside Go's heap and must be closed; see Encoder.Close.
func New ¶
func New(modelPath, tokenizerPath string, space agentic.VectorSpace, opts ...Option) (encoder *Encoder, err error)
New loads an exported SPLADE-family graph and its tokenizer and encodes with them in this process.
modelPath is an ONNX file whose graph takes int64 input_ids and attention_mask and returns float32 logits of shape [batch, sequence, vocabulary], with the batch and sequence axes dynamic. provider/local/onnx/export_onnx.py produces exactly that. Pooling is deliberately outside the graph, so what the model contributes and what this package contributes stay separable.
tokenizerPath is a Hugging Face tokenizer.json — the portable fast-tokenizer format, not a directory and not a sentencepiece model.
space is the identity that will be persisted beside every vector. Provider defaults to "onnx", Kind must be sparse, Metric defaults to dot product because a learned sparse weight is part of the score rather than a direction, Dimensions is filled from the graph's own output width when left zero, and ID is derived from the rest when left empty. Model is required: a file name is not an identity, since two exports of different weights can share one.
Nothing is downloaded, then or later. Both paths are read from the local filesystem and this package contains no HTTP client at all.
The graph is loaded twice here — once to read the vocabulary from its output shape, once for the session that will run it — which is what makes the vocabulary observed rather than assumed. Measured on darwin/arm64 against the 117 MiB Granite export, that costs 0.12 s of a 0.30 s construction. An encoder is meant to outlive the request that needed it.
func (*Encoder) Capabilities ¶
func (e *Encoder) Capabilities() agentic.RepresentationCapabilities
Capabilities implements agentic.RepresentationEncoder.
Truncation is not advertised. The exported graph accepts sequences up to the model's positional limit and nothing beyond it, and an over-long input is rejected with its token count rather than clipped — silently dropping the end of a document produces a vector for text the caller never asked about.
MaximumBatchSize is zero because this encoder splits a request into forward passes itself; the caller's batch is a request shape, not a hardware one.
An empty sparse vector is not allowed. A SPLADE head that predicts no vocabulary entry at all for a non-empty input is a broken graph rather than a short document, and storing the empty vector would put an unmatchable row in an index instead of failing.
func (*Encoder) Close ¶
Close releases the session and the tokenizer, and is safe to call twice.
Both hold memory outside Go's heap that no garbage collector reclaims, so an encoder that is never closed leaks a loaded model for the life of the process. Encode after Close returns an error rather than entering a destroyed session, which would be a crash.
The process-global ONNX Runtime environment is deliberately left up: another encoder may still be using it. A program that wants it down calls onnxruntime_go.DestroyEnvironment after closing every encoder.
func (*Encoder) Encode ¶
func (e *Encoder) Encode(ctx context.Context, req *agentic.RepresentationRequest) (*agentic.RepresentationResponse, error)
Encode implements agentic.RepresentationEncoder.
Cancellation is observed between forward passes rather than inside one. ONNX Runtime's Run has no cancellation, so a pass that has already started runs to completion; ctx bounds how many more begin.
func (*Encoder) Name ¶
Name implements agentic.RepresentationEncoder. It reports the model identifier from the vector space, which is the only model name this package has: an ONNX file declares no identity of its own.
type Option ¶
type Option func(*config)
Option configures an Encoder.
func WithLibraryPath ¶
WithLibraryPath points ONNX Runtime at its shared library — libonnxruntime.dylib, libonnxruntime.so, or onnxruntime.dll.
Without it the AGENTIC_ONNX_LIBRARY environment variable is used, and without that the binding falls back to the platform's default name, which resolves only if the library is already on the loader's search path.
The runtime environment is global to the process: whichever encoder is constructed first settles the path, and a later different one is ignored.
func WithLimits ¶
func WithLimits(limits agentic.RepresentationLimits) Option
WithLimits replaces the request-size ceilings, which default to agentic.DefaultRepresentationLimits.
The response-side ceilings still apply. MaxSparseNonZero is the one that matters here: a SPLADE head is sparse by training rather than by construction, so a long document can carry thousands of nonzero coordinates and nothing in the graph bounds that.
func WithMaxBatchBytes ¶
WithMaxBatchBytes caps the logits tensor a single forward pass allocates, defaulting to 256 MiB.
See [defaultBatchBytes] for what that buys. Lower it on a memory-constrained machine; raising it does not make encoding faster, because the encoder groups by token length and a group is closed by padding waste before it is closed by this ceiling for any realistic mix of inputs.
func WithMaxTokens ¶
WithMaxTokens sets the longest tokenized input the encoder will accept, defaulting to 512.
Inputs above it are rejected with their token count rather than truncated. Raise it only for a model whose positional embeddings actually extend that far; the limit exists because exceeding it is a runtime fault inside the graph rather than a degraded result.
func WithPadTokenID ¶
WithPadTokenID sets the id written into padded positions, defaulting to 0.
The value does not affect the result: padded positions are masked out of attention and out of pooling, which the live tests assert by encoding one padded row under two padding ids and comparing every coordinate. It still has to be a token the model has, since it indexes the embedding table, and zero is the only id every vocabulary contains. Set the model's real padding id if you would rather the tensors read the way its own tooling writes them.