The five backend values, in the order every port's error message lists them.
The five backend values, in the order every port's error message lists them.
§8B :backend — the backend table, AS DATA (change add-classifier-backends,
PD-2). Each row is a PRESET that sets base-url + model + api-key-env AS A UNIT
(D5 / ADR 0027), plus the wire it speaks, whether it sends the
TypeSafe-Danger-Zone-Images header, and :supports — (fn [model] {:images bool}), the image column. custom has no base-url and no
:supports: the caller must declare both.
The table is a fail-fast for WHAT THE TABLE SAYS, never a claim about the
vendor; :supports {:images true} on a classifier overrides it. Every default
here is a PROPOSED default, owner to confirm (design.md PD-1..PD-4).
§8B `:backend` — the backend table, AS DATA (change add-classifier-backends,
PD-2). Each row is a PRESET that sets base-url + model + api-key-env AS A UNIT
(D5 / ADR 0027), plus the wire it speaks, whether it sends the
`TypeSafe-Danger-Zone-Images` header, and `:supports` — `(fn [model]
{:images bool})`, the image column. `custom` has no base-url and no
`:supports`: the caller must declare both.
The table is a fail-fast for WHAT THE TABLE SAYS, never a claim about the
vendor; `:supports {:images true}` on a classifier overrides it. Every default
here is a PROPOSED default, owner to confirm (design.md PD-1..PD-4).(canonical-request model questions)The bytes the byte-identity claim covers: model + questions, keys sorted
recursively in ASCII (code-point) order, arrays NEVER reordered, compact
separators, and < > & ' " plus non-ASCII transmitted RAW.
koine.json/write-str already is that encoder — it owns key order, escaping
and number formatting precisely so the two hosts cannot drift — so there is no
second canonicaliser here to keep in agreement with it.
state is DELIBERATELY NOT HERE. It is transmitted verbatim as the host
supplied it and is outside the claim, because numbers do not canonicalise
across languages (-0.0 renders four ways across our own seven runtimes). Do
not re-widen this: a caller who needs their state pinned canonicalises it
themselves before handing it over.
The bytes the byte-identity claim covers: `model` + `questions`, keys sorted recursively in ASCII (code-point) order, arrays NEVER reordered, compact separators, and `< > & ' "` plus non-ASCII transmitted RAW. `koine.json/write-str` already is that encoder — it owns key order, escaping and number formatting precisely so the two hosts cannot drift — so there is no second canonicaliser here to keep in agreement with it. `state` is DELIBERATELY NOT HERE. It is transmitted verbatim as the host supplied it and is outside the claim, because numbers do not canonicalise across languages (`-0.0` renders four ways across our own seven runtimes). Do not re-widen this: a caller who needs their state pinned canonicalises it themselves before handing it over.
(choice decision key)The choice answer at key, or an error.
The choice answer at `key`, or an error.
(choice-over instructions items)A choice over any (name, description) pairs — a Tool, a skill, an agent, an
A2A card skill. The description must say what picking that option would MEAN;
see the encoding obligation on choice-question.
Keys may be strings, keywords or symbols; each reaches the wire as its plain
name, with no : sigil (§8B).
A `choice` over any (name, description) pairs — a Tool, a skill, an agent, an A2A card skill. The description must say what picking that option would MEAN; see the encoding obligation on `choice-question`. Keys may be strings, keywords or symbols; each reaches the wire as its plain name, with no `:` sigil (§8B).
(choice-question instructions criteria)One option from a named set, 1..255 options. criteria maps an option id to
WHAT PICKING IT WOULD MEAN.
THE ENCODING OBLIGATION IS THE CALLER'S (§8B, docs/adr/0021 D1). criteria[id]
is the ONLY thing that differentiates one option from another to the model:
the instructions describe the question and the state describes the situation,
and neither says what picking left rather than right would mean. Passing
the id itself, an empty string, or one value repeated is schema-valid, passes
validation, returns HTTP 200 and a well-formed distribution — and ranks at
chance (measured: 17 apples described by consequence, 0/1/0 described by id,
against a shuffle control's 1/0/1).
One option from a named set, 1..255 options. `criteria` maps an option id to WHAT PICKING IT WOULD MEAN. THE ENCODING OBLIGATION IS THE CALLER'S (§8B, docs/adr/0021 D1). `criteria[id]` is the ONLY thing that differentiates one option from another to the model: the instructions describe the question and the state describes the situation, and neither says what picking `left` rather than `right` would mean. Passing the id itself, an empty string, or one value repeated is schema-valid, passes validation, returns HTTP 200 and a well-formed distribution — and ranks at chance (measured: 17 apples described by consequence, 0/1/0 described by id, against a shuffle control's 1/0/1).
(chunk-questions questions size)Split a question map into consecutive chunks of size, keys in ASCII order.
A helper, NOT automatic: joint calibration across a split is unproven, so the
host decides to split and merges. size < 1 is an error.
Split a question map into consecutive chunks of `size`, keys in ASCII order. A helper, NOT automatic: joint calibration across a split is unproven, so the host decides to split and merges. `size < 1` is an error.
(classifier-unsupported backend model feature)The typed ClassifierUnsupported error (§8B, PD-5): an ex-info whose data
carries :toolnexus/error :classifier-unsupported plus :backend, :model
and :feature. Message, exact: classifier: <backend> (<model>) does not support <feature>.
The typed `ClassifierUnsupported` error (§8B, PD-5): an ex-info whose data carries `:toolnexus/error :classifier-unsupported` plus `:backend`, `:model` and `:feature`. Message, exact: `classifier: <backend> (<model>) does not support <feature>`.
(create-classifier opts)Build a classifier. Options mirror §8 create-client field-for-field
wherever a field makes sense, so a host that has configured one has configured
the other:
:style "systemone" | "llm" | "custom" | "static"
(default "systemone")
:base-url default "https://api.typesafe.ai/v1"
:model default "jev-latest"
:api-key-env the NAME of an env var, never a value — read at call time
and never logged. Default "TYPESAFE_API_KEY". §8's
:api-key takes a value; this option deliberately does not.
:headers extra request headers; values expand ${ENV_VAR} from the
environment AT CALL TIME and are NEVER logged, identically
to remote-MCP headers (§2)
:timeout-ms per REQUEST, not per run — default 10000
:http-client the §8 injectable transport, (fn [url headers body]);
scope is the classifier path only
:retry-base-ms base of the retry backoff in ms (default 500); the delay is
base * 2^attempt with no jitter, and a Retry-After
header still wins.
:retries transient-failure budget (default 2); retries on
408/429/500/502/503/504/529 + network. Widen
the status set with :retryable-statuses.
:retryable-statuses
extra HTTP statuses to treat as retryable, ADDED to the
default set (429/500/502/503/504/529, plus 408
here). It can only widen: a host cannot remove 429 and
lose Retry-After handling with it. This sets the DEFAULT
classification; :on-error still runs per attempt and has
the final say, so :on-error returning :fail overrides a
status listed here. Example: a Cloudflare-fronted origin
that answers 520–527.
:on-error the §8 ErrorInfo -> :retry | :fail classifier, REUSED
verbatim from toolnexus.client along with the Retry-After
delay-seconds rule. There is no second retry policy here and
no :suspend tier.
:request-params extra top-level body keys, shallow-merged AFTER the
classifier builds its own; a param WINS on collision
:body-transform runs LAST on the assembled body; its return value is sent
:on-metric the SAME §8 sink — "classifier.evaluate" events and the
degenerate-criteria "classifier.warning"
:client :style "llm" only — the §8 client to emulate over
:evaluate :style "custom" only — (fn [state questions] decision);
every wire option is ignored
:decisions :style "static" only — a vector of
{:state … :questions … :response <parsed body>}
:backend "typesafe" (default) | "openrouter" | "cloudflare" |
"vercel" | "custom" — a row of backends. An explicit
:base-url / :model / :api-key-env still wins.
${NAME} in the base URL expands AT CALL TIME; errors
name it unexpanded. custom requires :base-url and
:supports (systemone style).
:supports {:images bool} — overrides the backend row's image column
:cache opt-in {:get (fn [k]) -> string|nil, :set (fn [k v])};
systemone style only; see memory-cache. Absent = off.
:style "llm" is DEPRECATED (kept working, no runtime warning).
A style whose required option is missing, and an unknown style, are rejected HERE rather than at the first call.
Build a classifier. Options mirror §8 `create-client` field-for-field
wherever a field makes sense, so a host that has configured one has configured
the other:
:style "systemone" | "llm" | "custom" | "static"
(default "systemone")
:base-url default "https://api.typesafe.ai/v1"
:model default "jev-latest"
:api-key-env the NAME of an env var, never a value — read at call time
and never logged. Default "TYPESAFE_API_KEY". §8's
`:api-key` takes a value; this option deliberately does not.
:headers extra request headers; values expand ${ENV_VAR} from the
environment AT CALL TIME and are NEVER logged, identically
to remote-MCP headers (§2)
:timeout-ms per REQUEST, not per run — default 10000
:http-client the §8 injectable transport, `(fn [url headers body])`;
scope is the classifier path only
:retry-base-ms base of the retry backoff in ms (default 500); the delay is
`base * 2^attempt` with no jitter, and a `Retry-After`
header still wins.
:retries transient-failure budget (default 2); retries on
`408`/`429`/`500`/`502`/`503`/`504`/`529` + network. Widen
the status set with `:retryable-statuses`.
:retryable-statuses
extra HTTP statuses to treat as retryable, ADDED to the
default set (`429`/`500`/`502`/`503`/`504`/`529`, plus `408`
here). It can only widen: a host cannot remove `429` and
lose `Retry-After` handling with it. This sets the DEFAULT
classification; `:on-error` still runs per attempt and has
the final say, so `:on-error` returning `:fail` overrides a
status listed here. Example: a Cloudflare-fronted origin
that answers `520`–`527`.
:on-error the §8 `ErrorInfo -> :retry | :fail` classifier, REUSED
verbatim from `toolnexus.client` along with the Retry-After
delay-seconds rule. There is no second retry policy here and
no `:suspend` tier.
:request-params extra top-level body keys, shallow-merged AFTER the
classifier builds its own; a param WINS on collision
:body-transform runs LAST on the assembled body; its return value is sent
:on-metric the SAME §8 sink — `"classifier.evaluate"` events and the
degenerate-criteria `"classifier.warning"`
:client `:style "llm"` only — the §8 client to emulate over
:evaluate `:style "custom"` only — `(fn [state questions] decision)`;
every wire option is ignored
:decisions `:style "static"` only — a vector of
`{:state … :questions … :response <parsed body>}`
:backend "typesafe" (default) | "openrouter" | "cloudflare" |
"vercel" | "custom" — a row of `backends`. An explicit
`:base-url` / `:model` / `:api-key-env` still wins.
`${NAME}` in the base URL expands AT CALL TIME; errors
name it unexpanded. `custom` requires `:base-url` and
`:supports` (systemone style).
:supports `{:images bool}` — overrides the backend row's image column
:cache opt-in `{:get (fn [k]) -> string|nil, :set (fn [k v])}`;
systemone style only; see `memory-cache`. Absent = off.
`:style "llm"` is DEPRECATED (kept working, no runtime warning).
A style whose required option is missing, and an unknown style, are rejected
HERE rather than at the first call.(decision-cache-key endpoint served state assets questions)§8B decisionKey = sha256hex(canon({assets?, endpoint, kind:"decision",
model:<served>, questions, state})). endpoint is the configured base URL,
${ENV} unexpanded; state is the state AS SENT (after lifting); an empty or
nil assets omits the member.
§8B decisionKey = sha256hex(canon({assets?, endpoint, kind:"decision",
model:<served>, questions, state})). `endpoint` is the configured base URL,
`${ENV}` unexpanded; `state` is the state AS SENT (after lifting); an empty or
nil `assets` omits the member.The NAME of the environment variable holding the credential, never a value.
The NAME of the environment variable holding the credential, never a value.
The System One endpoint base. OpenRouter (https://openrouter.ai/api/v1) serves this wire today; self-hosted and open-weights implementations speak it too.
The System One endpoint base. OpenRouter (https://openrouter.ai/api/v1) serves this wire today; self-hosted and open-weights implementations speak it too.
At most this many evaluate calls in flight in one batch (§8B Batch).
At most this many `evaluate` calls in flight in one batch (§8B Batch).
The floating alias. PIN IT (e.g. "jev-1.13.0") once thresholds are tuned —
:model on the decision echoes what actually answered, which may be more
specific.
The floating alias. PIN IT (e.g. "jev-1.13.0") once thresholds are tuned — `:model` on the decision echoes what actually answered, which may be more specific.
jevx's INCLUSIVE cut-points (T1): 0.8 / 0.2 / 0.6. They sit ALONGSIDE the
judge layer's exclusive default-bands, which stay the default of ask /
gate.
jevx's INCLUSIVE cut-points (T1): 0.8 / 0.2 / 0.6. They sit ALONGSIDE the judge layer's exclusive `default-bands`, which stay the default of `ask` / `gate`.
Bounds ONE request. A classifier has no loop to bound.
Bounds ONE request. A classifier has no loop to bound.
(degenerate-criteria criteria)The §8B predicate. Returns a human reason string when a choice's criteria
are degenerate, nil otherwise. Degenerate <=> ANY of:
A single-option choice (n = 1) is NEVER reported — there is nothing to differentiate. Note the ordering: with n = 1 rules 1 and 2 can still hold and rule 3 is vacuous, so the n < 2 gate comes first for all three.
The §8B predicate. Returns a human reason string when a `choice`'s criteria are degenerate, nil otherwise. Degenerate <=> ANY of: 1. every value is empty (empty string or absent), or 2. every value equals its own key, or 3. every value is identical to every other value (n >= 2). A single-option choice (n = 1) is NEVER reported — there is nothing to differentiate. Note the ordering: with n = 1 rules 1 and 2 can still hold and rule 3 is vacuous, so the n < 2 gate comes first for all three.
(evaluate c state questions)A state plus typed questions in, a decision out.
state is a string, a map, or a vector — whatever the host already has.
questions maps CALLER-CHOSEN keys to question maps. The keys are ADDRESSING,
NOT CONTENT: they are never transmitted to the model, so a key MAY be a tool,
skill or agent name verbatim, and two evaluations differing only in their keys
send identical content.
Questions are INDEPENDENT — one answer is never context for another. A backend
that cannot guarantee that reports :calibrated false, which carries both
caveats.
On style systemone, content parts in the state are lifted into assets
(§8B images). A reply that fails validate-decision is still RETURNED here
(unchanged behaviour) but never cached; evaluate-state fails closed on it.
A decision served from :cache carries :cached true.
A state plus typed questions in, a decision out. `state` is a string, a map, or a vector — whatever the host already has. `questions` maps CALLER-CHOSEN keys to question maps. The keys are ADDRESSING, NOT CONTENT: they are never transmitted to the model, so a key MAY be a tool, skill or agent name verbatim, and two evaluations differing only in their keys send identical content. Questions are INDEPENDENT — one answer is never context for another. A backend that cannot guarantee that reports `:calibrated false`, which carries both caveats. On style systemone, content parts in the state are lifted into `assets` (§8B images). A reply that fails `validate-decision` is still RETURNED here (unchanged behaviour) but never cached; `evaluate-state` fails closed on it. A decision served from `:cache` carries `:cached true`.
(evaluate-batch c states questions)(evaluate-batch c states questions opts)§8B Batch — the SAME questions over many states. Each state goes through the
per-state evaluate (every style), at most :concurrency (default 16) in
flight, and the decisions come back IN STATE ORDER regardless of completion
order. FAIL CLOSED: if any state fails, this throws naming the first failing
state's index and returns no decisions. No states is an error and sends
nothing.
koine.process/run-async! + a promise, not future — the same reason as the
client's parallel tool calls: library code never holds its host's process
open.
§8B Batch — the SAME questions over many states. Each state goes through the per-state `evaluate` (every style), at most `:concurrency` (default 16) in flight, and the decisions come back IN STATE ORDER regardless of completion order. FAIL CLOSED: if any state fails, this throws naming the first failing state's index and returns no decisions. No states is an error and sends nothing. `koine.process/run-async!` + a promise, not `future` — the same reason as the client's parallel tool calls: library code never holds its host's process open.
(evaluate-state bound & qs)state(v).evaluate(questions…): one request with the NAMED questions qs,
and the reply validated FAIL-CLOSED (validate-decision) — an invalid reply
is an error, reported on the metric event.
`state(v).evaluate(questions…)`: one request with the NAMED questions `qs`, and the reply validated FAIL-CLOSED (`validate-decision`) — an invalid reply is an error, reported on the metric event.
(evaluate-states bound & qs)states(…).evaluate(questions…): evaluate-state per state, at most 16 in
flight, results IN STATE ORDER, one per state: {:decision d} or
{:error e}. One state's failure NEVER fails the batch. A question-set error
(duplicate name) throws once, before any request. No states => [].
evaluate-batch (fail-closed) is unchanged.
`states(…).evaluate(questions…)`: `evaluate-state` per state, at most 16 in
flight, results IN STATE ORDER, one per state: `{:decision d}` or
`{:error e}`. One state's failure NEVER fails the batch. A question-set error
(duplicate name) throws once, before any request. No states => `[]`.
`evaluate-batch` (fail-closed) is unchanged.Per image, DECODED bytes (16 MiB).
Per image, DECODED bytes (16 MiB).
(image-size format bs)[width height] read from a PNG IHDR or the first JPEG SOF marker of the
decoded bytes bs (a host byte array or a seq of byte values), or nil when
the bytes are not a readable header of format ("png" | "jpeg").
`[width height]` read from a PNG IHDR or the first JPEG SOF marker of the
decoded bytes `bs` (a host byte array or a seq of byte values), or nil when
the bytes are not a readable header of `format` ("png" | "jpeg").TypeSafe's opt-in for image ("danger zone") input. Sent as true only when
a request carries assets AND the backend row says so.
TypeSafe's opt-in for image ("danger zone") input. Sent as `true` only when
a request carries assets AND the backend row says so.(levels answer)A score answer's legend in LEVEL order, which the map itself loses. Sorted numerically-by-length-then-lexicographically, because "2" < "10" as levels and "10" < "2" as strings.
A score answer's legend in LEVEL order, which the map itself loses. Sorted numerically-by-length-then-lexicographically, because "2" < "10" as levels and "10" < "2" as strings.
The client-side cap on a choice's named options (§8B).
The client-side cap on a choice's named options (§8B).
(memory-cache)(memory-cache ttl-ms max)An in-process {:get :set} cache, safe for concurrent use. ttl-ms 0 => no
expiry; max 0 => unbounded; over max the OLDEST-INSERTED entries go first.
toolnexus persists nothing itself — a host persists by implementing
:get/:set.
An in-process `{:get :set}` cache, safe for concurrent use. `ttl-ms` 0 => no
expiry; `max` 0 => unbounded; over `max` the OLDEST-INSERTED entries go first.
toolnexus persists nothing itself — a host persists by implementing
`:get`/`:set`.The :event value of the per-evaluation metric. It goes into the SAME §8
:on-metric sink as the client's "llm" event and is NOT folded into any
registry, so rendered metrics text is unchanged by this file's existence.
The `:event` value of the per-evaluation metric. It goes into the SAME §8 `:on-metric` sink as the client's `"llm"` event and is NOT folded into any registry, so rendered metrics text is unchanged by this file's existence.
The :event value of the degenerate-criteria warning. Carries :question.
The `:event` value of the degenerate-criteria warning. Carries `:question`.
(model-cache-key endpoint model)§8B modelKey = sha256hex(canon({endpoint, kind:"model", model})). Its value is the model the endpoint SERVED for this requested model last time.
§8B modelKey = sha256hex(canon({endpoint, kind:"model", model})). Its
value is the model the endpoint SERVED for this requested model last time.The ABSOLUTE tolerance on max|p - 1/n|, compared INCLUSIVELY (§8B). Pinned
across every port; examples/judge/near-uniform.json pins both sides at
0.0499 / 0.0501, so no port needs an epsilon.
The ABSOLUTE tolerance on max|p - 1/n|, compared INCLUSIVELY (§8B). Pinned across every port; `examples/judge/near-uniform.json` pins both sides at 0.0499 / 0.0501, so no port needs an epsilon.
(near-uniform? probabilities)Whether a choice answer's probability map is indistinguishable from flat:
nearUniform <=> max over i of |p_i - 1/n| <= 0.05
n is the number of ENTRIES IN THE MAP and the values are taken AS RETURNED
— not renormalised, not sorted, not rounded; an offered option absent from the
map counts as 0 by not being an entry. The tolerance is ABSOLUTE (a relative
band collapses below the wire's two-decimal rounding on a 255-option roster)
and the comparison is INCLUSIVE. n = 1 is trivially uniform; an EMPTY map
has no distribution at all and is false.
DERIVED ON DECODE, never read from the wire: no wire change, no request change, no fixture change.
ADVISORY, NOT A CORRECTNESS SIGNAL. It detects an encoding that gave the model
nothing to rank on — the one encoding health check available with no ground
truth. It cannot tell a good encoding from a subtly wrong one, because a
wrong-but-answerable question still reads as answerable. :calibrated carries
the same caveat.
Whether a choice answer's probability map is indistinguishable from flat:
nearUniform <=> max over i of |p_i - 1/n| <= 0.05
`n` is the number of ENTRIES IN THE MAP and the values are taken AS RETURNED
— not renormalised, not sorted, not rounded; an offered option absent from the
map counts as 0 by not being an entry. The tolerance is ABSOLUTE (a relative
band collapses below the wire's two-decimal rounding on a 255-option roster)
and the comparison is INCLUSIVE. `n = 1` is trivially uniform; an EMPTY map
has no distribution at all and is false.
DERIVED ON DECODE, never read from the wire: no wire change, no request
change, no fixture change.
ADVISORY, NOT A CORRECTNESS SIGNAL. It detects an encoding that gave the model
nothing to rank on — the one encoding health check available with no ground
truth. It cannot tell a good encoding from a subtly wrong one, because a
wrong-but-answerable question still reads as answerable. `:calibrated` carries
the same caveat.(noul decision key)The noul answer at key, or an error.
The noul answer at `key`, or an error.
(noul-question instructions)(noul-question instructions criteria)The probability that a statement holds, one number in 0..1. It reports NO confidence: the number IS the answer.
criteria, when given, is {"true" <desc> "false" <desc>}. Omit the
arity rather than passing nil or {} — the three are different values and
the wire carries the difference.
The probability that a statement holds, one number in 0..1. It reports NO
confidence: the number IS the answer.
`criteria`, when given, is `{"true" <desc> "false" <desc>}`. Omit the
arity rather than passing `nil` or `{}` — the three are different values and
the wire carries the difference.(parse-decision body)A recorded or live response body (already parsed JSON with STRING keys) as a Decision:
{:model what actually answered
:answers {caller-key -> answer}
:usage {:input-tokens :output-tokens :cost}
:calibrated true|false}
calibrated ABSENT means true: the systemone wire reports calibration by
being itself, and a backend that is not calibrated says so explicitly. A
THRESHOLD TUNED AGAINST ONE BACKEND DOES NOT TRANSFER TO ANOTHER.
A recorded or live response body (already parsed JSON with STRING keys) as a
Decision:
{:model what actually answered
:answers {caller-key -> answer}
:usage {:input-tokens :output-tokens :cost}
:calibrated true|false}
`calibrated` ABSENT means true: the systemone wire reports calibration by
being itself, and a backend that is not calibrated says so explicitly. A
THRESHOLD TUNED AGAINST ONE BACKEND DOES NOT TRANSFER TO ANOTHER.(raw-answer decision key)The raw answer at key — an answer of a type the library does not model —
or an error when absent or when it IS a modelled type.
The raw answer at `key` — an answer of a type the library does not model — or an error when absent or when it IS a modelled type.
(raw-question type instructions)(raw-question type instructions criteria)The OPEN end of the question union (§8B, PD-14): a System One question type
the library does not model yet (e.g. Jev 1.14 box), sent AS WRITTEN —
{type, instructions, criteria?} — with no client-side limits, because the
library does not know the type. type must be non-empty. Its answer decodes
to a raw answer {:type t :value <the answer object>}.
The OPEN end of the question union (§8B, PD-14): a System One question type
the library does not model yet (e.g. Jev 1.14 `box`), sent AS WRITTEN —
`{type, instructions, criteria?}` — with no client-side limits, because the
library does not know the type. `type` must be non-empty. Its answer decodes
to a raw answer `{:type t :value <the answer object>}`.All images of one request, decoded bytes (32 MiB).
All images of one request, decoded bytes (32 MiB).
(score decision key)The score answer at key, or an error.
The score answer at `key`, or an error.
(score-question instructions criteria)A rating against an ORDERED rubric of 2..10 levels. criteria is a VECTOR
and its order IS the level numbering, so it is never sorted — a "sort
everything" canonicaliser silently renumbers the rubric.
A rating against an ORDERED rubric of 2..10 levels. `criteria` is a VECTOR and its order IS the level numbering, so it is never sorted — a "sort everything" canonicaliser silently renumbers the rubric.
(sha256-hex s)SHA-256 of the UTF-8 bytes of s, lower-case hex. Pure Clojure: correct on
both hosts, not fast — a cache key over megabytes of image data costs real
time, which is one more reason the cache is opt-in.
SHA-256 of the UTF-8 bytes of `s`, lower-case hex. Pure Clojure: correct on both hosts, not fast — a cache key over megabytes of image data costs real time, which is one more reason the cache is opt-in.
(state c v)Bind a state to a classifier. A VALUE, not a session: nothing is sent or
stored until evaluate-state.
Bind a state to a classifier. A VALUE, not a session: nothing is sent or stored until `evaluate-state`.
(states c vs)Bind a batch of states. See evaluate-states.
Bind a batch of states. See `evaluate-states`.
(static-classifier decisions)(static-classifier decisions opts)A static classifier from recorded decisions in ONE call — what a hermetic
test wants. Each entry is {:state … :questions … :response <parsed body>},
or {:state … :questions … :answers <wire answers>} as shorthand for a body
that is only its answers. opts merges into create-classifier (e.g.
:model).
A `static` classifier from recorded decisions in ONE call — what a hermetic
test wants. Each entry is `{:state … :questions … :response <parsed body>}`,
or `{:state … :questions … :answers <wire answers>}` as shorthand for a body
that is only its answers. `opts` merges into `create-classifier` (e.g.
`:model`).The four styles (§8B). "systemone" is the default; "static" is what
CI runs — no network, no credential.
"llm" is DEPRECATED (ADR 0038 D3, PD-15): System One is the single
product wire. It keeps working byte-identically, as an alias, for at least one
minor release, with no runtime warning. A string value carries no :deprecated
metadata, so this docstring is the marker.
The four styles (§8B). `"systemone"` is the default; `"static"` is what CI runs — no network, no credential. `"llm"` is DEPRECATED (ADR 0038 D3, PD-15): System One is the single product wire. It keeps working byte-identically, as an alias, for at least one minor release, with no runtime warning. A string value carries no `:deprecated` metadata, so this docstring is the marker.
(threshold-band answer)(threshold-band answer thresholds)"yes" | "no" | "uncertain" for one answer, INCLUSIVE: noul p >= yes
=> yes, else p <= no => no; choice/score confidence >= min-confidence =>
yes. No near-uniform demotion (that is the bands' rule). A raw answer is
uncertain. thresholds merges over default-thresholds.
"yes" | "no" | "uncertain" for one answer, INCLUSIVE: noul `p >= yes` => yes, else `p <= no` => no; choice/score `confidence >= min-confidence` => yes. No near-uniform demotion (that is the bands' rule). A raw answer is uncertain. `thresholds` merges over `default-thresholds`.
(unsupported? e)True when e is a ClassifierUnsupported error.
True when `e` is a `ClassifierUnsupported` error.
(validate-decision questions decision)nil when decision answers EXACTLY questions within their schema, else an
ex-info whose message starts classifier: invalid decision: and names the
key as "<key>". Checks, first failure wins: a missing answer (question
keys ASCII), an unexpected answer (ASCII), then per key the type, noul in
[0,1], choice offered / probability keys offered / each in [0,1] / a
non-empty map sums to 1 ± 0.02 / confidence in [0,1], score in
[0, levels-1] with the same probability rules over level indices. A raw
question only needs an answer of its own type.
nil when `decision` answers EXACTLY `questions` within their schema, else an ex-info whose message starts `classifier: invalid decision: ` and names the key as `"<key>"`. Checks, first failure wins: a missing answer (question keys ASCII), an unexpected answer (ASCII), then per key the type, noul in [0,1], choice offered / probability keys offered / each in [0,1] / a non-empty map sums to 1 ± 0.02 / confidence in [0,1], score in [0, levels-1] with the same probability rules over level indices. A raw question only needs an answer of its own type.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |