Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

Jevantic

Jevantic gives Python programs typed, probabilistic decisions from Jev. Define a question, evaluate application state, and receive an answer whose type matches the question: a probability, a typed label, an original local object, or a scored rubric.

Jevantic is an experimental alpha. Its public API may change as complete workflows reveal better interfaces. It is standalone, with optional Pydantic AI capabilities in its pydantic-ai extra.

Install

The first alpha is being prepared for PyPI. Once it is available, add the core package or the optional Pydantic AI capability extra:

uv add jevantic
uv add 'jevantic[pydantic-ai]'

Start with one decision

The examples below assume evaluator is already open. In application code, async with Jevaluator() as evaluator: creates a TypeSafe SDK client from its normal environment configuration, or pass api_key= explicitly.

from jevantic import Jevaluator, Question

question = Question.noul(
    'Could this command disclose credentials outside the workspace?',
    true='The command could disclose sensitive data.',
    false='The command stays within its intended workspace.',
)

assessment = await evaluator.evaluate({'command': 'printenv'}, question)
risk = assessment.value.probability
# 0.82  # illustrative provider result; float

Question.noul() produces a NoulAnswer with the probability of its yes outcome. Probabilities in this README are illustrative values, not measured model output or policy thresholds.

Keep the answer type you chose

Use Question.choice() when the answer is one of typed string labels. Annotating the labels retains a Literal or StrEnum type after evaluation.

from typing import Literal

from jevantic import JsonContent, Question

Route = Literal['send', 'review']
routes: dict[Route, JsonContent | None] = {
    'send': 'The message is ready for its intended audience.',
    'review': 'A person should review the message before it is sent.',
}

route = (await evaluator.evaluate('Draft: deploy production now', Question.choice(routes))).value
route.selected
# 'review'  # illustrative provider result; Route
route.distribution[0].value
# 'send'  # Route

Use Question.select() when a label represents an object your program already owns. Jev receives each key and description; the selected answer returns the original object.

from dataclasses import dataclass

from jevantic import Option, Question


@dataclass(frozen=True)
class Candidate:
    identifier: str
    summary: str


alba = Candidate('alba', 'Built the search service')
bryn = Candidate('bryn', 'Led support engineering')

question = Question.select(
    [
        Option(alba.identifier, alba, alba.summary),
        Option(bryn.identifier, bryn, bryn.summary),
    ],
    instructions='Select the candidate whose experience best fits the role.',
)
candidate = (await evaluator.evaluate('Role: lead search engineering', question)).value.selected
assert candidate is alba  # Candidate; illustrative selected identity

Object identity matters when the selected value carries application-only fields, connections, or relationships that must never be reconstructed from a model label.

Score against a rubric

Question.score() preserves a fractional ScoreAnswer, its probability distribution, rubric legend, and provider confidence.

from jevantic import Question

quality = await evaluator.evaluate(
    'Draft: Jevantic asks structured decision questions.',
    Question.score(['Does not explain the library', 'Explains part of the library', 'Clear explanation']),
)
quality.value.score
# 1.6  # illustrative provider result; float on the 0–2 rubric
quality.value.probabilities
# {0: 0.1, 1: 0.2, 2: 0.7}  # illustrative provider result; Mapping[int, float]

Evaluate several questions over shared state

A Batch evaluates independent questions against one state in one provider request. batch.add() returns a typed Handle, so a mixed batch keeps every answer's precise type.

from jevantic import Question

batch = evaluator.batch('Draft: deploy production now')
risk = batch.add('risk', Question.noul('Could the draft cause operational harm?'))
route = batch.add('route', Question.choice(routes))
quality = batch.add('quality', Question.score(['unclear', 'adequate', 'clear']))

result = await batch.run()
result.answer(risk).probability
# 0.31  # illustrative provider result; float
result.answer(route).selected
# 'review'  # illustrative provider result; Route
result.answer(quality).score
# 1.8  # illustrative provider result; float

Questions are ordinary Python values, so functions can build reusable questions from application inputs:

from jevantic import NoulAnswer, Question


def relevance_question(query: str) -> Question[NoulAnswer]:
    return Question.noul(f'Does this document answer {query!r}?')


evaluation = await evaluator.evaluate('Document: …', relevance_question('How do I install Jevantic?'))

Evaluate one question over independent inputs

Use evaluate_many() when every input needs a separate evaluation. Set concurrency explicitly for your traffic and provider limits; results retain the input order.

from jevantic import Question

documents = ['First document', 'Second document', 'Third document']
evaluations = await evaluator.evaluate_many(
    documents,
    Question.noul('Does this document answer the user question?'),
    concurrency=4,
)
[evaluation.value.probability for evaluation in evaluations]
# [0.91, 0.12, 0.73]  # illustrative provider results; list[float], input order

For a complete ranking function that keeps the original document objects and preserves tied order, see the document-ranking example. For a complete assessment function with two Score questions, see the assessment example.

Guard an agent's input

InputGuardrail evaluates an original plain-text prompt with a Noul question before the first model request. Its accept policy receives the complete typed evaluation; returning False prevents the primary model from running.

from pydantic_ai import Agent

from jevantic import Jevaluator, Question
from jevantic.pydantic_ai import InputGuardrail

question = Question.noul('Does this prompt request disclosure of private data?')

async with Jevaluator() as evaluator:
    agent = Agent(
        existing_model,
        capabilities=[
            InputGuardrail(
                evaluator,
                question,
                accept=lambda _ctx, evaluation: evaluation.value.probability < 0.1,
            )
        ],
    )
    result = await agent.run('Summarize this meeting agenda.')

The guardrail borrows evaluator, so the application closes it. See the complete input-guardrail example for an agent builder and an explicit policy function.

Guard an agent's output

OutputGuardrail evaluates complete plain-text output before Agent.run() returns. Its accept policy receives the same typed evaluation shape as InputGuardrail.

from pydantic_ai import Agent

from jevantic import Jevaluator, Question
from jevantic.pydantic_ai import OutputGuardrail

question = Question.noul('Could this response disclose private data?')

async with Jevaluator() as evaluator:
    agent = Agent(
        existing_model,
        capabilities=[
            OutputGuardrail(
                evaluator,
                question,
                accept=lambda _ctx, evaluation: evaluation.value.probability < 0.1,
            )
        ],
    )
    result = await agent.run('Summarize this meeting agenda.')
    # result.output: str  # available only when the output is accepted

Streaming can expose partial and final text before rejection; output functions can already have side effects. The check runs after ordinary result transformations. Place the guardrail before other outermost capabilities that change results. See the complete example and streaming contract.

Reference and further reading

The API reference covers input snapshots, response validation, errors, client ownership, request metadata, and fan-out failure behavior.

Develop

Use Python 3.13 locally. Install the optional integration before running the complete test suite:

uv sync --extra pydantic-ai
uv run pytest tests -q
uv run pyright src tests examples checks
uv run python checks/typecheck_negative.py
uv run ruff check src tests examples checks typecheck
uv run ruff format --check src tests examples checks typecheck
uv build

The verification evidence records environments, results, and limits for checked revisions.

Metadata

Release files for jevantic 0.1.0a0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for jevantic 0.1.0a0
File Size Uploaded Provenance
jevantic-0.1.0a0.tar.gz 763.1 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for jevantic 0.1.0a0
File Interpreter ABI Platform
jevantic-0.1.0a0-py3-none-any.whl Python 3 none any Details

Total release size: 779.3 kB

Release files / jevantic-0.1.0a0.tar.gz

Download URL jevantic-0.1.0a0.tar.gz
Size 763.1 kB
Tags Source
SHA-256 checksum
How to use checksums
a23ab94d8cdf48f8bb8b518e33f6e676d0f30a04bbd94fed6751327e88d24440
BLAKE2b-256 checksum
How to use checksums
82f5416df123b94fd87fe8e7a34dd083acb35c3dd8ab2c5ad40bd414f8e619be
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / jevantic-0.1.0a0-py3-none-any.whl

Download URL jevantic-0.1.0a0-py3-none-any.whl
Size 16.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
35cb6e63da7a4918875faa552e07ca89d2733a6d64293dd9a4040444be54be06
BLAKE2b-256 checksum
How to use checksums
58c280e6f4c46480387a04e26ea73b0f8183ac6295c0a919684e93eefd7e1534
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for jevantic 0.1.0a0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page