Skip to main content

jev-lite

OpenAI-style Python client for TypeSafe Jev (System One).

Jev does not generate text. Send state plus typed questions; get structured decisions with probabilities. jev-lite is the official TypeSafe HTTP client — sync and async, same shape as the OpenAI Python SDK. jev-lite@0.0.2 added Dialogflow-style system entities; jev-lite@0.0.3 adds a privacy filter and a reranker (all three are previews, below); jev-lite@0.0.4 adds images and Box answers for Jev 1.14.

pip install jev-lite
# or: uv add jev-lite

Python 3.11+. Set TYPESAFE_API_KEY. Docs: https://docs.typesafe.ai/

Usage

from jev_lite import Choice, Noul, Score, TypeSafe

client = TypeSafe()  # TYPESAFE_API_KEY

result = client.system_one.create(
    state="I was charged twice. Please fix this ASAP.",
    questions={
        "billing": Noul(instructions="Is this ticket about billing?"),
        "tone": Choice(
            instructions="What is the customer's tone?",
            criteria={"calm": None, "frustrated": None, "angry": None},
        ),
        "urgency": Score(
            instructions="How urgent is this ticket?",
            criteria=["can wait", "this week", "today"],
        ),
    },
)

print(result.nouls["billing"].noul)
print(result.choices["tone"].choice)
print(result.scores["urgency"].score)
print(result.elapsed_ms, result.request_id, result.usage)
print(client.models.list())  # GET /v1/models

Async is the same surface with await:

from jev_lite import AsyncTypeSafe, Noul

async with AsyncTypeSafe() as client:
    result = await client.system_one.create(
        state="I was charged twice. Please fix this ASAP.",
        questions={"billing": Noul(instructions="Is this ticket about billing?")},
    )
    models = await client.models.list()

Pin the model with TypeSafe(model="jev-1.13.0") (or TYPESAFE_DEFAULT_MODEL); jev-latest moves. Prefer one system_one.create with many questions over a loop of calls. jev-1.14.0 matches 1.13 on the modules below but scores lower on hard semantic decisions, so the modules stay on 1.13; TypeSafe will retire 1.13 with 60 days' notice, and the pins move then (1.14 vs 1.13).

Re-running unchanged questions can replay answers from disk (pip install "jev-lite[cache]"):

client = TypeSafe(cache="~/.cache/jev")  # or a configured diskcache.Cache

Only 200 responses are stored, keyed on the request body (which carries the model id). Leave the cache off when you measure repeat or order stability.

Images and Box (Jev 1.14, experimental)

Put an Image anywhere a value can go: in state, instructions or criteria. The client uploads it as an asset and adds the TypeSafe-Danger-Zone-Images header. A Box answer is where a target is, as edges in fractions of the image; it needs jev-1.14.0.

from pathlib import Path
from jev_lite import Box, Image, Noul, TypeSafe

with TypeSafe(model="jev-1.14.0") as client:
    result = client.system_one.create(
        state={"photo": Image(Path("kitchen.jpg"))},  # PNG/JPEG, sides 280-1568 px
        questions={
            "has_mug": Noul(instructions="Is there a coffee mug in `photo`?"),
            "mug": Box(instructions="the coffee mug in `photo`"),
        },
    )

mug = result.boxes["mug"]
print(mug.box.left, mug.box.top, mug.box.right, mug.box.bottom, mug.confidence)

A Box always returns a box, so gate it on the Noul. An image costs about 2·⌈w/28⌉·⌈h/28⌉ input tokens. Measured limits (targets under ~40 px, counting past five, text under 7 px) and usage rules: docs/system-one/use/images.md; the benchmark is image-questions@v0.0.1.

System entities (preview)

jev_lite.system_entities extracts the 59 Dialogflow ES system entities (@sys.date-time, @sys.unit-currency, @sys.geo-city, …) and fills typed slots, in ten languages (en and zh-Hant primary). Code proposes candidates, Jev jev-1.13.0 decides, code normalizes. Preview: the API may change within 0.0.x. Same install; no extra dependency.

from datetime import datetime
from zoneinfo import ZoneInfo

from jev_lite import TypeSafe
from jev_lite.system_entities import extract

now = datetime(2026, 10, 1, 16, 0, tzinfo=ZoneInfo("Asia/Taipei"))
with TypeSafe() as client:
    result = extract(client, "Book a table for 4 next Friday at 7pm", ["date-time", "number"], now=now)
for match in result.matches:
    print(match.entity, match.span.text, match.value)  # number 4 …; date-time … 2026-10-09 19:00

Slot filling, async and the value models: API. Read the known limitations first: extraction is not a security boundary. On the held-out set system-entities-cases@v0.0.1 (301 cases, ten languages) it is 99.3% exact on accepted values; a same-day rerun gave 98.9% on jev-1.13.0 and 99.3% on jev-1.14.0 (release gates).

Privacy filter and reranker (preview)

jev_lite.privacy_filter and jev_lite.reranker ship in jev-lite@0.0.3 as previews: the APIs may change within 0.0.x. Import them as modules (from jev_lite.privacy_filter import detect, from jev_lite.reranker import rerank). All numbers pin jev-1.13.0.

Privacy filter: private-span detection. Public multilingual gold (ai4privacy OpenPII, Gretel finance, NVIDIA Nemotron-PII), 300 test texts, exact-span precision / recall:

Setup P / R Over-redaction Speed
openai/privacy-filter, local GPU 63.4 / 62.9 5.2% ~20 ms per text
openai/privacy-filter proposes, Jev decides 75.4 / 60.1 2.5% p50 210 ms
Jev only, no GPU (broader proposals, per-label cuts) 68.6 / 60.5 2.4% p50 215 ms
Jev only, round-04 default 80.4 / 57.6 1.5% p50 210 ms
Jev only, before the person proposer 78.3 / 63.6 1.6% p50 209 ms
Jev only, default detect(client, text), no GPU 79.3 / 69.2 1.6% p50 ~0.7 s
Same default on jev-1.14.0 (same-day 1.13: 79.7 / 69.7, 1.6%) 82.4 / 68.2 1.3% call p50 0.19 s

The default uses per-label proposers and cuts fitted on dev, and finds people with system_entities person spans plus a person detect Noul (person recall 43.9 → 71.9), with an order-stable name boundary. On overlap it scores 88.9 / 77.6; exact address recall is 0 because the gold splits an address into components while the filter masks the whole address. It fails most written robustness bars, so it is a preview. Hosted Jev sees the raw text before masking. Details: docs/privacy-filter/.

Reranker: batched evidence Noul over a first-stage pool (balanced batches of at most 30, independent of the caller's order), nDCG@10:

Bank First stage Reranked Query p50 Same day, 1.13 → 1.14
SciFact (50 q) .556 .638 0.30 s .635 → .634
FiQA (50 q) .219 .346 0.26 s .346 → .348
zh, BM25 (50 q) .526 .587 0.30 s .603 → .618
zh, E5 (50 q) .551 .647 0.27 s .640 → .656
Mr. TyDi ko / ja / ar (30 q each) .415 / .605 / .529 .675 / .791 / .754 0.23–0.24 s .687 / .791 / .741 → .675 / .808 / .741

A batch score is relative to the other passages in its request, not a standalone probability. A passage that echoes the relevance criteria can be lifted into the top 10; rerank(..., check_echo=True) (off by default) re-checks the top-k and moves such passages down, at about +0.23 s. Details: docs/reranker/.

Tracing

Off by default. Opt in and pick the destination:

from jev_lite import instrument

instrument(endpoint="http://127.0.0.1:4318")  # local Grafana LGTM

Or set OTEL_EXPORTER_OTLP_ENDPOINT and call instrument(), or install your own TracerProvider first (Logfire, etc.). Spans record prompt, result, and latency.

Develop

uv sync --dev
uv run ruff check . && uv run pytest

The supported public API is the TypeSafe client. Optional local engines live under jev_lite.engine (pip install 'jev-lite[ml]'). See docs/.

Semantic decisions v0.0.2

Dataset semantic-decisions@v0.0.2, versioned separately from the package (versions).

252 frozen zh-Hant rows in 18 families (36 easy, 48 medium, 168 hard), gold derived from visible text. This natural zh-Hant v1 qualified freeze is v0.0.2, and it is the only semantic-decision eval in this repo. Every model answers the same 504 locked requests: each row in canonical and left-rotated option order. Charts are percent correct. The families were seen during development before the freeze, so this is not unseen confirmation.

All 504

Easy

Medium

Hard

Model Easy /72 Medium /96 Hard /336 All /504 Hard priority reversals /29
AutoTrust JEV-27B 72 96 318 486 28
AutoTrust JEV-27B-VL 72 96 318 486 28
Jev jev-1.13.0 72 96 313 481 28
AutoJev-27B 72 96 302 470 29
Rune v3 26B-A4B 72 95 301 468 24
Jev jev-1.14.0 72 96 293 461 24
decider-4b v2 72 95 269 436 14
NeoHorse-Jev-4B 72 92 264 428 5
Tev1-4B 72 96 257 425 15
AutoTrust JEV-9B 72 96 248 416 4
Clef 27B 72 94 238 404 4
Mica v0.1 4B 72 96 235 403 7
Kev 4B 72 95 233 400 9
Clef-Flash 9B 72 90 222 384 3
RSI-Jev v4.0-VL 2B 72 84 220 376 0
RSI-Jev v3.0 2B 72 77 216 365 2
Strands Decider 2B 72 73 207 352 1
Tev1-0.8B 72 86 176 334 0
SemIf, Qwen3.5-4B 72 82 178 332 2
JevEmbed Qwen3-Embedding-4B 60 82 188 330 1
Lev 4B 72 76 169 317 1
decider-0.8b 67 70 176 313 1
JevK5 4B v0.2 72 88 130 290 2
Plumb-4B 72 83 126 281 1
GLiNER2.5-Decide 24 39 194 257 0
Laya multilingual 38 37 165 240 0
jeff (GLiFormer large) 45 34 140 219 0

Easy and medium are regression and "insufficient information" controls. Hard carries the difference: a priority reversal counts only if both ends of a same-case pair are right in both orders. Always answering B already scores 194/336 on hard. All 13,608 first attempts (27 models × 504) are valid, with no errors. Adapters differ, so these are task-level scores, not weight comparisons. Jev jev-1.14.0 scores 20 fewer than jev-1.13.0, all on hard (293 vs 313; a repeat gave 462 in all), so keep jev-1.13.0 pinned for text decisions. Details and disclosures.

Earlier banks (semantic-decisions@v0.0.1, the controlled slices, r2) are retired. v0.0.1 survives only at package tag v0.0.1, and none of their scores is pooled with v0.0.2. No model redistribution is authorized.

License

Apache-2.0

Metadata

Release files for jev-lite 0.0.4

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

Source distribution (sdist)

Source distribution for jev-lite 0.0.4
File Size Uploaded
jev_lite-0.0.4.tar.gz 4.2 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for jev-lite 0.0.4
File Interpreter ABI Platform
jev_lite-0.0.4-py3-none-any.whl Python 3 none any Details

Total release size: 4.5 MB

Release files / jev_lite-0.0.4.tar.gz

Download URL jev_lite-0.0.4.tar.gz
Size 4.2 MB
Tags Source
SHA-256 checksum
How to use checksums
06dd02be24bbb4833e3c3362822bb91e6aa5044a5599dc2909249e9e2887669c
BLAKE2b-256 checksum
How to use checksums
a588eebb5972f218c19b2ed88a9cee2f561c5a12e8fca91e1d1232b6a9cd95ee
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.

Transparency log

Release files / jev_lite-0.0.4-py3-none-any.whl

Download URL jev_lite-0.0.4-py3-none-any.whl
Size 354.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
67e81f156b7c143ec3e8de0188c0e60a9bf1c872c80b2079dd3d3ce407104702
BLAKE2b-256 checksum
How to use checksums
c8b47d536c73e93c9b2028600921e839a1b85fd367404603743cc70127f9008c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.0.4 This release

2 release files

0.0.3

2 release files

0.0.2

2 release files

0.0.1

2 release files

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