rig-typesafeai
Experimental TypeSafe Jev judgments for Rig. Enable the root rig feature
typesafeai to use rig::typesafeai, or depend on this crate and pair it with a
Rig HTTP transport explicitly. It uses Rig's Operation, Wire, Model, and
shared driver.
There are no Jev derive macros or schema-generation traits.
One structure for questions and answers
Implement Query on a generic named struct. Its associated Output replaces
question fields with their answer types while preserving their names and layout:
use ProviderError;
use ;
use ;
// The fields are declared once, for both questions and answers.
let query = Assessment ;
# Ok::
With a Jev model (Jev::from_env()?.evaluation()), evaluate it directly:
let answers: =
jev.evaluate.await?.answers;
The query is reusable by reference. .await? handles construction-independent
transport and response errors once; the result contains ordinary typed fields.
Serde field names and rename attributes supply question IDs. The request is
serialized directly, and Serde reconstructs the matching response struct before
decode validates each answer against its question. No manual map construction
or lookup is needed. Use #[serde(flatten)] to compose named groups.
See triage for a complete example
using Choice, Score, and Noul in the same generic struct. Its query and answer
forms are concrete instantiations of one type, with no type erasure.
Question builders
Choice::new(instructions, [(variant, description), ...])returnsChoiceAnswer<T>on evaluation. Values implementSerialize,DeserializeOwned, andOrd; their Serde representation must be a string.Score::new(instructions, [(level, description), ...])returnsScoreAnswer<L>with enum-keyed probabilities. Array order determines numeric positions, independently of enum discriminants andOrd. Evaluation requiresL: Ord + Cloneand the WASM-compatible transport bounds.DynamicScore::new(instructions, descriptions)returnsDynamicScoreAnswerwith numeric indices and a legend when rubric identities are runtime-defined.Noul::new(instructions)returnsNoulAnswer, the probability of yes..criteria(yes, no)?accepts structured descriptions for both outcomes.
Fixed arrays check choice counts (2–255) and score counts (2–10) at compile time.
try_from_iter constructors check runtime collections and reject duplicate
labels or levels. Builders accept serializable descriptions, including structs,
JSON objects, arrays, strings, and null. State accepts strings, objects, or arrays.
For runtime IDs, maps of questions implement Query, and .named("ready")?
gives a standalone question an ID. .join(other) flattens two query objects;
.map(...) projects validated answers. Empty or duplicate IDs and missing or
unexpected response IDs are rejected at the evaluation boundary.
For a fully runtime-defined question set, use DynamicQuery::new(definitions)?.
Its output is explicitly BTreeMap<String, types::Answer>; construction validates
the definitions and evaluation validates the provider's answers.
Jev::from_env() reads JEV_TOKEN without loading a secrets file. Its default
model is jev-latest; JevConfig::model(...) selects another provider model
identifier. Configure timeouts and retry middleware on the Rig transport and
pass it with JevConfig::connect.
Questions share state but cannot consume each other's answers in one request. Confidence measures concentration, not correctness. Keep distributions and put threshold policy in application code. Validation preserves the provider's values, including bounded hundredth-rounding error; it does not silently renormalize them.
Examples and verification
Run the interactive console from the repository root with JEV_TOKEN already
exported:
Add -- --agent for gpt-5.6-sol replies using OPENAI_API_KEY. The default
mode uses Jev alone and displays decisions plus deterministic next actions.
Both modes support /reset, /quit, and conversational history.
- Interactive chat: named generic query structs and batched judgments over conversation state.
- Mixed triage: all three primitives in one call.
Run cargo test -p rig-typesafeai to replay the synthetic, live-recorded
plain, structured, and
rounded matrix fixtures
offline, check local validation invariants, and run compile-fail doctests.
The fixtures contain no authentication headers. They were recorded against
jev-1.13.0; replay checks request JSON and decoded answers, not future model
accuracy or calibration. Mutation tests exercise invalid responses separately.