solvi.core¶
The low level: the catalog and its value classes (parts, questions, answers, quotes, decisions). Each area has its own
module under solvi.core (solvi.core.types, solvi.core.runtime, ...); in 0.9 solvi.core was the catalog module
and its public names are still exported here. It also exports the extension points — protocols, base classes and
the concrete System, Response, Dispatcher — explained in Building blocks.
solvi.core — the low level: the primitives and base classes the ready-made solutions are built from.
from solvi.core import Catalog, Question, Answer, Quote, Decision # the catalog and its value classes
from solvi.core import SlowPath, TraceStorage, Strategist, Head # the extension points (docs: Building blocks)
from solvi.core.types import Maybe, Span # one area: solvi.core.<area>
The extension points — what you implement to rebuild one part, and what you then get for free — are exported here:
protocols (Scorer, Decider, Adapter, Head, Extractor, Strategist, Monitor, Proposer, Space, Environment; an object with
their methods is one, isinstance checks it), base classes with abstract methods (TraceStorage, SlowPath with AskPath,
RefinePath, SearchPath), the records and classes they meet (Thought, Outcome, DefaultStrategist, Fail) and the concrete
System, Response and Dispatcher. They load on first use (solvi.core.SlowPath imports solvi.core.dispatch then), so
importing solvi.core or one area does not import the others. solvi.testing.conformance checks your implementation.
The areas (solvi.core.), bottom to top: the kernel — catalog (parts, questions, answers, quotes), types (typed
answers), runtime (flows, traces, replay), provenance (fingerprints, grounding), schema (export), textin (reading a
text), environment, primitives, sets, calibration and calibfile, costs, sources, chain; deciders (models as catalog
parts: the decider, LLMs, System One, cascades and votes, learned heads, rule lists), extract (long texts), plan
(strategists); guarantees (calibrated promises, drift, open-set, monitors); store (the decision store, audit, diff,
reports, signatures) and response; system (System); slow (generation, agreement, refine, search) and dispatch (the fast
and the slow path); knowledge (the knowledge store, write gates, action model, risk policies, agenda, failure memory,
world map, episodes, memory of corrections). A module imports only its own area's tier or the ones
below it. In 0.9 solvi.core was the catalog module; its public names are still here.
Answer ¶
maybe
staticmethod
¶
The same answer type, with "not stated" (solvi.Unknown) as a valid answer — distinct from "no" and from an
abstention. Maybe[T] in a type hint does the same.
span
staticmethod
¶
An exact substring of a given text fact (source), with its offsets: always grounded (the text must be literally
at the offsets), then coerced to type with pydantic (e.g. float: "12.50" → 12.5; a failure is "type rejected").
The answer is the value; result.span is the Quote (text, start, end, source). Span[float] in a type hint.
rank
staticmethod
¶
An ordering of the options, best first: the top k (all by default) as a tuple, with a score per option
(result.scores). A rule returns {option: score} (e.g. from a key function) or an ordered list; a model its
probabilities (Plackett–Luce). Rank[Literal[...], k] in a type hint.
estimate
staticmethod
¶
estimate(bins=None, *, lo=None, hi=None, step=None, coverage=0.8, unit=None, integer=None) -> AnswerType
A number with its uncertainty: a distribution over bins cut at the edges bins (ascending; or lo, hi, step) —
len(bins) + 1 bins, the first and last open: (−∞, e0), [e0, e1), …, [e_last, ∞) — whose labels are the options
("less than 0", "0–6", "7–13", "14 or more" for integer edges; integer= overrides). The value is the middle of the
median bin (an open bin: its edge), result.interval the bins holding the central coverage of the probability
((1 − c)/2 to (1 + c)/2 of the cumulative; None for an open end), and the confidence their probability mass. A rule
returns a plain number (interval [x, x], confidence 1) or a distribution ({bin label or index: p}, or a list of p per
bin); a model its probabilities over the bins as ordered options. Without bins the estimate is a plain number (rules
only). Estimate[0, 7, 14] in a type hint.
choice
staticmethod
¶
One of the options. options is a list, or a dict {option: description}.
ordinal
staticmethod
¶
One of ordered levels, lowest first (e.g. ["low", "medium", "high"]). A learned head answers with the median of its distribution instead of the most likely level, so it never jumps over the middle.
multi
staticmethod
¶
Any subset of the options (possibly empty), returned as a tuple in option order. A rule may return a list or set.
from_type
staticmethod
¶
From a Python type: bool → yes_no; Literal[...] / an Enum → choice (ordinal=True: ordinal, in declaration
order); list[Literal[...]] (or set, tuple, of an Enum) → multi. X | None is X (None = abstain).
AnswerType
dataclass
¶
Catalog ¶
Everything the system can do; the strategist decides which parts each question needs.
quotes: how quotes and evidence are matched against their source text — "normalized" (default since 1.0: a quote that differs from its text only in Unicode form, no-break spaces or hyphens, dashes, "…", whitespace runs or curly quotes is found, and the source's own substring is kept, see solvi.core.locate) or "literal" (0.9: the text as written, up to whitespace runs). It applies to the parts registered after it is set.
extract ¶
extract(f=None, *, provides=None, cost=None, validate=None, min_confidence=None, model=None, provenance=None, exact=None, source=None, timeout=None, blocking=None)
Extract a value from text (returns a Quote). With provides="fact" the function is one of several alternative
producers of that fact: its output is used only if it passes validate / min_confidence, otherwise the next
alternative runs. cost (ms) is a prior for scheduling until run times are measured.
model: the model behind it (recorded in the trace with its fingerprint); a model's Quote must be literally the text
at its offsets or it is rejected (exact=False turns that off, exact=True turns it on for hand-written code).
source: the given fact (text) its quotes point into. By default: "doc" if the function reads doc, else its only
argument, else its only str-typed argument; if that is ambiguous, registration raises and asks for source=. A
returned Quote that names another source (Quote(..., source="notes")) keeps it.
The function may be async def (awaited by System.aask). timeout (seconds) and blocking (a sync function that
waits on I/O or a model: aask runs it in a worker thread) apply under aask; see System.aask.
fn ¶
fn(f=None, *, provides=None, cost=None, validate=None, model=None, provenance=None, options=None, min_confidence=None, timeout=None, blocking=None)
A computation. provides, validate, cost, timeout, blocking: as for extract. A model-backed fn (model=)
with options is a model decision: it returns a Decision (or a plain value) that must be one of the options, else
it is rejected.
check ¶
check(f=None, *, hard=False, then=None, cost=None, model=None, provenance=None, timeout=None, blocking=None)
A check: a function of facts that answers True or False (or solvi.core.slow.refine.Fail("why") for False with its
reasons). hard=True: when it is False it decides the questions it governs — the model cannot override it.
then: {question: answer} — the answer a question gets when this hard check is False (a question listed here is
governed by it; without then the check governs every question whose flow runs it, and they abstain). The check
is put into the flow of every question its then names (since 1.0; no requires= needed). An answer may be a
function of facts instead of a constant — then={"step": free_side} with def free_side(position, walls) ->
str — whose argument names are the facts it reads (typed like any part's); it runs only when the check is
False, its value must be one of the question's answers (else the question abstains), and it is recorded in the
trace (record kind "then") and re-checked by replay.
features ¶
Cheap features of the input for choosing among a fact's alternative producers (the learned producer policy):
@cat.features("total") def total_features(doc): return {"length": len(doc), "has_total": "TOTAL" in doc}.
Arguments must be among the producers' inputs; values are numbers, booleans or short strings.
rule ¶
The answer rule of a question. With model= the rule is a model's decision: it may return a Decision with
probabilities; an answer outside the question's options abstains, as for any rule. timeout, blocking: as for
extract.
replace_rule ¶
Install a ready rule Part (System.learn_rule: a learned rule list) as its question's rule, in place of the one registered before; what the catalog recorded about the replaced rule's typed arguments is dropped with it.
constraint ¶
A rule between answers: argument names are question names, it returns True when the answers fit together
(e.g. def unsafe_if_harm(verdict, harm): return harm == "none" or verdict == "unsafe"). When learned answers break it,
solvi picks the most probable combination that satisfies every constraint; answers from rules and hard checks stay.
unreadable_validates ¶
Producers whose validate requires an argument no producer of their fact takes as an input → [(fact, producer,
[names])]. Such a validate cannot run, so every output of that producer would be rejected. (A part that is not
an alternative producer is checked when it is declared; a fact's producers only once all of them are.)
Claim
dataclass
¶
Claim(value: Any, evidence: list = list(), confidence: float = 1.0, source: str | None = None, extra: dict = dict())
A value with the quotes that support it — what a plain rule (or any part) returns to attach evidence and / or a
confidence to its answer: return Claim("billing", evidence=["charged twice"]). Evidence items are Quotes (their
offsets are checked: the text must be literally there) or strings (located in source: by default the part's only text
input, or "doc" — as whole words and numbers: "3" is not evidence when the text says "30"); an item not in its text
rejects the output (safeguard "grounding rejected"). The provenance stays the part's own (a hand-written rule:
computed). extra: details recorded in the trace with the fact (record.extra) — a check's reasons
(solvi.core.slow.refine.Fail), a generator's request (solvi.core.slow.generate.Generated).
Decision
dataclass
¶
Decision(value: Any, probs: dict = dict(), confidence: float | None = None, escalate: str | None = None, extra: dict = dict(), evidence: list = list())
A model's choice among declared options, with probabilities. Return it from a model-backed part (or rule): the value is
accepted only if it is one of the part's options (or of the probability keys), and downstream parts receive the plain
value.
ExperimentalWarning ¶
Bases: UserWarning
A feature whose API and behaviour may still change (solvi.experimental.learning, solvi.experimental.lora).
NotStated ¶
The type of solvi.Unknown: the answer "the text does not state it". It is a real answer — the evidence says the
input does not state the value, with a confidence — unlike an abstention (None: solvi refuses to answer). Declare it
with Maybe[T] (or T | NotStated); constraints see it as solvi.Unknown (falsy; x is Unknown).
Part
dataclass
¶
Part(kind: str, name: str, inputs: list, func: Callable | None, doc: str = '', hard: bool = False, then: dict = dict(), question: str | None = None, cost: float | None = None, provides: str | None = None, validate: Callable | None = None, min_confidence: float | None = None, alternatives: list | None = None, features: Callable | None = None, model: Any = None, provenance: str | None = None, options: list | None = None, exact: bool | None = None, source: str | None = None, types: dict | None = None, returns: Any = None, timeout: float | None = None, blocking: bool = False, quotes: str = 'normalized', then_parts: dict | None = None, tin: dict | None = None, tout: Any = None)
strict ¶
Must a Quote from this part be literally at its offsets? Yes for model-backed parts (unless exact=False).
Question
dataclass
¶
Question(name: str, text: str, answer: AnswerType | None = None, requires: list = list(), uses: list | None = None, min_confidence: float | None = None, require_evidence: bool = False)
Bases: Serial
A question the System answers: its name, text and answer type (None: from its rule's return type), the parts
that must run in its flow (requires; checkpoints= in 0.7, removed in 0.9), the facts that matter for a question without a rule (uses), and the
abstentions it asks for (min_confidence, require_evidence).
Quote
dataclass
¶
A value extracted from text, with its location (doc[start:end] is the supporting quote). As evidence (Claim, Decision, Result.evidence) the value is the quoted text itself.
Serial ¶
pydantic-backed export of solvi's data classes (see solvi.core.schema; pydantic is imported on first use):
x.model_dump(mode="python"|"json"), x.to_json(), Cls.model_validate(d), Cls.from_json(s), Cls.model_json_schema().
Traces and responses take catalog= on load to restore typed values (dates, enums, models) from the facts' types.
accept ¶
Does an alternative producer's output pass its checks? → (ok, reason, plain value — coerced to its return type). None
means "not found"; otherwise the output must be grounded (see ground: a quote in the text — literally, for a model — a
decision among the options, min_confidence), pass its return type (typed parts) and validate, which gets the plain value
plus any of the producer's inputs it names.
bin_labels ¶
Bin edges e0 < … < e_last → the labels of their len(edges) + 1 bins (−∞, e0), [e0, e1), …, [e_last, ∞) — exactly the
labels of the answer-primitives decider (its training code's bin_labels): "less than e0", then "a" (a one-wide integer
bin), "a–(b−1)" (integers) or "a to b", then "e_last or more"; the unit after a space.
check_evidence ¶
Every evidence Quote must lie in its (given) source text and be literally the text at its offsets → None or the rejection reason (a grounding reason: "quote outside the text" / "not grounded").
cuts_number ¶
Does t[i:j] begin or end inside a longer number written in t? A quote [26:27] of "30" is the "3" of "30", one of "3.5" or "1,300" is part of that number. (Words are not held to this: a quote with offsets may end inside a word.)
evidence_rows ¶
Located evidence → [[start, end, source, text]] (what the trace records in extra["evidence"]).
find_quote ¶
Where a quote is in one or several labelled texts → Quote(the source's own substring, start, end, label) or None. sources: a text (labelled "doc") or {label: text}, searched in order ("notes", "dialogues", "map", ...); the first text that holds the quote wins. A literal occurrence is preferred in every text before the normalized view is tried (quotes="normalized", the default: Unicode NFKC, no-break spaces and hyphens, dash variants, "…" for "...", whitespace runs, curly quotes — see solvi.core.provenance.norm_view); quotes="literal" finds the text as written only. whole: as whole words and numbers ("3" is not found in "30").
find_whole ¶
Where text is written in t as whole words and numbers → the start of its first such occurrence, or -1.
An occurrence that begins or ends inside a longer word or number is not one: "3" is not found in "30", in "3.5" or
in "1,300", "cat" not in "category" — but "30" is found in "30." and "30%", "charged twice" in "was charged twice,".
(Only the ends are held to this: what the evidence itself contains is compared literally.)
ground ¶
Is a part's output grounded? → None, or the reason it is rejected. A Quote must lie inside its source text and, for a
strict (model-backed) part, its value must be literally the text at its offsets (strings up to whitespace, numbers as
written); a Decision (or any value of a part with options) must be among the options; min_confidence is enforced.
locate ¶
A Claim's / Decision's evidence with every item as a Quote: a string is located in the output's source text —
Claim.source, else the part's source, else "doc" if the part reads it, else its only given text input, else "doc";
then the part's other text inputs (several labelled sources: "notes", "dialogues", "map" — the Quote records which
one) — at its first occurrence as whole words and numbers (find_whole: "3" does not quote "30"); a string that is
not there becomes Quote(text, -1, -1, source), which ground rejects. An item given as a Quote keeps its own offsets.
Quote matching (the part's quotes, Catalog(quotes=...)): "normalized" (default) — a quote that is not literally in
its text is looked for, and compared at its offsets, in the normalized view (solvi.core.provenance.norm_view: NFKC,
no-break spaces and hyphens, dashes, "…", whitespace runs, curly quotes); the Quote kept is then the source's own
substring at offsets into the original text, and the output carries extra["quote_match"] = {"form", "written"} —
what the part wrote — so the record says so and a replay re-checks it. A literal match never needs the view and
leaves the output as it was. "literal": as 0.9 (the text as written, up to whitespace runs at given offsets).
Outputs without evidence or quotes are returned as they are (no work).
plain_json ¶
Is v JSON data as it is — str / int / bool / None, finite floats, lists and tuples, dicts with str keys — so that solvi.core.schema.jsonable would give it back unchanged (up to tuples as lists)?
question_data ¶
A question as plain data (its serialized form, solvi.core.schema) — without importing pydantic.
unwrap ¶
A part's output → (plain value, quote (start, end, source) or None, confidence, probs or None).
validated ¶
Run a part's validate(value, [its inputs by name]) → None or the rejection reason.