fathomdb-embedder 0.8.21

FathomDB embedder runtime — built-in embedder implementations for the fathomdb-embedder-api trait.
Documentation
[package]
name = "fathomdb-embedder"
description = "FathomDB embedder runtime — built-in embedder implementations for the fathomdb-embedder-api trait."
# 0.8.20 Slice 39 (R-20-DOC) — see the fathomdb facade manifest for the rationale
# behind `readme` being explicit and `categories` being absent (HITL seq-198).
readme = "README.md"
keywords = ["embeddings", "embedder", "candle", "onnx", "reranker"]
version.workspace = true
edition.workspace = true
license.workspace = true
# 0.8.20 Slice 39 (R-20-DOC): ships the repo-root MIT LICENSE inside this
# crate's `.crate` tarball. Path is resolved relative to the workspace root.
license-file.workspace = true
repository.workspace = true
rust-version.workspace = true

[dependencies]
fathomdb-embedder-api.workspace = true

# Default-embedder loader deps. Gated behind the `default-embedder` feature
# per dev/plans/prompts/0.7.1-EMBEDDER-UNDEFER-HANDOFF.md §EU-3 so callers
# who never opt in pay zero dependency cost.
ureq = { version = "2", optional = true, default-features = false, features = ["tls"] }
sha2 = { version = "0.11", optional = true }
dirs = { version = "5", optional = true }
fs2 = { version = "0.4", optional = true }
serde_json = { version = "1", optional = true }
thiserror = { version = "1", optional = true }

# Candle stack + tokenizer for the default `CandleBgeEmbedder` (EU-4).
# FathomDB-maintained Candle 0.10.2 CPU packages retain Candle's Rust crate
# names while treating CPU F16 matmul as unsupported only on Linux AArch64,
# where Gemm's F16 backend requires unavailable instructions. Gated under
# `default-embedder` so the no-feature build closure remains thin
# (EMB-3 wheel-size gate). `safetensors` is reached transitively via
# candle-core's re-export per ADR-0.6.0-default-embedder consequences;
# no direct dep here.
candle-core         = { package = "candle-core-fathomdb", version = "=0.10.2", optional = true }
candle-nn           = { package = "candle-nn-fathomdb", version = "=0.10.2", optional = true }
candle-transformers = { package = "candle-transformers-fathomdb", version = "=0.10.2", optional = true, default-features = false }
tokenizers          = { version = "0.20", optional = true, default-features = false, features = ["onig"] }

# 0.8.16 Slice 10 (ADR-0.8.16-onnx-embedder-backend §2) — cross-vendor ONNX
# Runtime backend for `OrtBgeEmbedder` (mod ort_bge), a caller-supplied
# `impl Embedder` injected via `EmbedderChoice::Caller` with ZERO engine
# change. Optional + feature-gated behind `onnx-embedder` so the thin
# `default = []` build stays ML-free and gains ZERO new deps (EMB-3
# wheel-size gate / footprint invariant). Pinned to `=2.0.0-rc.10`: the
# `ort` 2.0 line is the maintained series (1.x is EOL) but is published
# only as release candidates; rc.10 is the latest rc that builds cleanly
# in the offline envelope (rc.12 has an ort/ort-sys VitisAI EP mismatch).
# RC PIN ACCEPTED BY HITL 2026-07-08 (this is a non-default, opt-in
# eval-only feature); the eventual 2.0-STABLE bump is tracked as TC-9.
# `load-dynamic`
# dlopens the ONNX Runtime native lib at RUNTIME (via ORT_DYLIB_PATH), so
# `cargo build`/`cargo check` never download or link a native binary at
# build time (no `download-binaries`); the runtime lib is an offline
# build/eval concern, not a compile dep.
ort = { version = "=2.0.0-rc.10", optional = true, default-features = false, features = ["load-dynamic"] }

[features]
default = []
default-embedder = [
    "dep:ureq",
    "dep:sha2",
    "dep:dirs",
    "dep:fs2",
    "dep:serde_json",
    "dep:thiserror",
    "dep:candle-core",
    "dep:candle-nn",
    "dep:candle-transformers",
    "dep:tokenizers",
]
# 0.8.2 Slice E1 — the default CPU cross-encoder reranker (TinyBERT-L-2). Pulls
# the SAME Candle + tokenizers + loader stack as `default-embedder` (CPU only),
# but is a distinct opt-in so the engine can enable reranking without forcing the
# default embedder on, and the feature-off build stays ML-free + no-network.
default-reranker = [
    "dep:ureq",
    "dep:sha2",
    "dep:dirs",
    "dep:fs2",
    "dep:serde_json",
    "dep:thiserror",
    "dep:candle-core",
    "dep:candle-nn",
    "dep:candle-transformers",
    "dep:tokenizers",
]
# GPU acceleration (opt-in; default build stays CPU so tests + byte-stability are
# unaffected). Activate the device at runtime with FATHOMDB_EMBED_DEVICE=cuda|metal.
# Cross-vendor (AMD ROCm / Intel) is NOT a candle backend — that path is a separate
# `impl Embedder` (ONNX-Runtime) via EmbedderChoice::Caller; see
# dev/design/0.8.1-embedder-gpu-and-portability.md.
embed-cuda = ["default-embedder", "candle-core/cuda", "candle-nn/cuda", "candle-transformers/cuda"]
embed-metal = ["default-embedder", "candle-core/metal", "candle-nn/metal", "candle-transformers/metal"]
# 0.8.12 — GPU acceleration for the CE reranker (opt-in; default build stays CPU
# so Decision 2 / byte-stability are unaffected). Mirrors `embed-cuda` exactly
# but pulls in `default-reranker` (not `default-embedder`) and is activated at
# runtime via the SEPARATE knob FATHOMDB_RERANK_DEVICE=cuda|cuda:N|metal. The CE
# stack is the same Candle bert path, so enabling the cuda backend on the shared
# candle crates is the only build-side change. Cross-vendor (AMD/Intel) is not a
# candle backend — out of scope, same as the embedder.
rerank-cuda = ["default-reranker", "candle-core/cuda", "candle-nn/cuda", "candle-transformers/cuda"]
rerank-metal = ["default-reranker", "candle-core/metal", "candle-nn/metal", "candle-transformers/metal"]
# 0.8.16 Slice 10 — cross-vendor ONNX embedder (`OrtBgeEmbedder`). Pulls the
# `ort` ONNX-Runtime binding + the shared `tokenizers` stack (for BGE-small
# tokenization parity with the candle reference). NON-default: the thin
# `default = []` build gains ZERO new deps (footprint invariant / EMB-3).
# The cross-vendor execution providers (ROCm / DirectML / OpenVINO / CUDA)
# that candle cannot reach are selected at RUNTIME from `FATHOMDB_EMBED_DEVICE`
# (R-ONNX-2); the ONNX Runtime native lib is dlopen'd at runtime (load-dynamic).
# `sha2` derives the self-describing identity revision from a content digest of
# the ACTUALLY-loaded model + tokenizer assets (codex §9 fix-5): two different
# assets → two different identities, so the engine rejects cross-asset vector
# mixing; the same asset → a stable identity. `sha2` is ALREADY in the tree
# (default-embedder / default-reranker / dev-deps + Cargo.lock) so this reuses
# an existing dependency and adds ZERO new crates; it stays OPTIONAL + gated so
# the thin `default = []` build is unchanged (no `sha2` in the default tree).
onnx-embedder = [
    "dep:ort",
    "dep:tokenizers",
    "dep:sha2",
]
# Exposes `LoaderConfig` constructors/setters and `load_with_config` so
# integration tests (or downstream test harnesses) can substitute base URLs,
# cache roots, and pinned shas. Production callers MUST NOT enable this
# feature — `load_pinned_default_embedder()` is the only production-blessed
# entry point per ADR-0.7.1 scope-guardrail #1.
loader-test-hooks = ["default-embedder"]

[dev-dependencies]
httpmock = "0.7"
tempfile = "3"
sha2 = "0.11"

# 0.8.7 Slice 10 — GPU vs CPU embed speedup measurement. Needs a constructible
# embedder, so it only builds when `default-embedder` (CPU) or `embed-cuda` is
# active; without this guard `cargo build --examples` on the thin no-feature
# build would fail to compile (R-GPU-2: default build unperturbed).
[[example]]
name = "gpu_speedup"
required-features = ["default-embedder"]