[build-system]
requires = ["setuptools>=68"]
build-backend = "setuptools.build_meta"

[project]
name = "arborist"
version = "0.0.1"
description = "An arborist for trees and forests of cross-linked information"
readme = "README.md"
license = { text = "AGPL-3.0-only" }
requires-python = ">=3.10"
authors = [
  { name = "Russell Ballestrini", email = "russell@unturf.com" },
  { name = "foxhop" },
  { name = "TimeHexOn" },
]
dependencies = [
  "httpx>=0.27",
  "zstandard>=0.22",
  "cryptography>=42",
]

[project.optional-dependencies]
html = [
  "selectolax>=0.3",
]
wikitext = [
  "mwparserfromhell>=0.6",
]
mesh = [
  # httpx is already in core deps; mesh wire only depends on stdlib +
  # cryptography (also core). This extras block exists as the documented
  # opt-in surface even though no extra packages are required today.
]
math = [
  # Symbolic algebra/calculus π* substrate (ticket #000030). SymPy is
  # ~30 MB installed; pulling it into core deps would inflate every
  # fresh checkout. Tests skip via pytest.importorskip when absent.
  "sympy>=1.13",
]
hessian = [
  # Phi_alignment_probe (ticket #000034 Phase 1a). Lanczos top-k +
  # bottom-k eigendecomposition for measuring whether v7's frozen
  # linear projection W aligns with the loss Hessian's low-eigenvalue
  # subspace. Numpy + scipy together ~80 MB; gated separately from
  # core to keep the default install lightweight. Tests skip via
  # pytest.importorskip when absent. Install with:
  #     pip install 'arborist[hessian]'
  "numpy>=1.26",
  "scipy>=1.11",
]
crawler = [
  # Verbatim lift from agents.ai.unturf.com/core. Off by default — the
  # default test suite never imports the crawler. Install with:
  #     pip install 'arborist[crawler]'
  # then run `make test-crawler`.
  "aiohttp>=3.8",
  "beautifulsoup4>=4.11",
  "lxml>=4.9",
  "html5lib>=1.1",
  "html2text>=2024.2.26",
  "miniuri>=1.1",
  "feedparser>=6.0",
  "Pillow>=10.0",
  "cairosvg>=2.7",
  "pypdf>=4.0",
]
vec = [
  # Optional sqlite-vec semantic retrieval backend (ticket #000039).
  # sqlite-vec ships only the loadable SQLite extension (~1 MB);
  # fastembed pulls onnxruntime + tokenizers + huggingface-hub
  # (~150 MB) and downloads the bge-small-en-v1.5 ONNX model
  # (~130 MB) on first use. Gated separately so a fresh checkout
  # stays python3.12 + venv + sqlite3. CLI surfaces `arborist embed`
  # / `--backend vec` only when `sqlite_vec` imports. Install with:
  #     pip install 'arborist[vec]'
  # (sentence-transformers is the heavier "official" embedder path
  #  the ticket §5 names; fastembed is the lightweight ONNX one.)
  "sqlite-vec>=0.1.9",
  "fastembed>=0.4",
]
nli = [
  # Sentence-pair NLI for the #000049 Phase-2 *shadow* path
  # (arborist/qa/nli/) — measures whether a clause-level contradiction
  # veto would demote a weakly-grounded answer; never touches
  # audit_mode. transformers + a CPU torch is ~600 MB installed, so it
  # is gated hard out of core / dev — a fresh checkout stays
  # python3.12 + venv + sqlite3, and the default test suite skips the
  # NLI tests via pytest.importorskip when this extra is absent.
  # Install with:
  #     pip install 'arborist[nli]'
  # `optimum[onnxruntime]` gives the ONNX-export + int8-quantize path
  # (`bench/scripts/export_nli_onnx.py`, `make export-nli-onnx`):
  # `onnxruntime` on a quantized cross-encoder is ~2-4x faster on CPU
  # than the torch forward path; `ShadowNLI._ensure_loaded` auto-prefers
  # an export if it finds one. torch is still here because `optimum`'s
  # exporter uses it, and it's the fallback when no export exists; a
  # Phase-3 runtime could ship an `[nli-onnx]`-only extra (onnxruntime,
  # no torch) once the export is committed/distributed (cf. [vec]).
  "transformers>=4.40",
  "torch>=2.2",
  "sentencepiece>=0.2",
  "protobuf>=4.0",
  "optimum[onnxruntime]>=1.20",
]
mt = [
  # Local machine-translation engine for the #000056 "Operation
  # Sandwich" cross-language grounding edges (arborist/qa/mt/):
  # translate the query es->en (retrieval-side) and render the
  # *verified English* answer en->es for display only. Helsinki-NLP
  # opus-mt (MarianMT) is Apache-2.0, hash-pinnable by HF revision
  # (reproducible — provenance-critical for a Merkle-replay system),
  # and es<->en is its best-resourced pair. Hard out of core/dev like
  # [nli]: a fresh checkout stays python3.12 + venv + sqlite3, and the
  # default suite drives the sandwich via a deterministic
  # StubTranslator so it never needs these weights. Install with:
  #     pip install 'arborist[mt]'
  # Weights are NOT in the repo; they cache under
  # ~/.arborist/models/mt/. Never Hermes-3-8B (8B unfit for
  # human-language translation); never an external API (zero egress /
  # Operation Voyeur; opaque API "versions" are provenance-hostile).
  "transformers>=4.40",
  "torch>=2.2",
  "sentencepiece>=0.2",
  "protobuf>=4.0",
  "sacremoses>=0.1",
]
dev = [
  "pytest>=8",
  "pytest-asyncio>=0.23",
  "pytest-xdist>=3.5",
  "arborist[html]",
  "arborist[wikitext]",
  "arborist[mesh]",
  "arborist[crawler]",
  "arborist[math]",
  "arborist[hessian]",
  "arborist[vec]",
]

[project.scripts]
arborist = "arborist.cli:main"

[tool.setuptools.packages.find]
where = ["."]
include = ["arborist*"]
