Skip to content

Jev Python SDK: Install, Examples and Error Handling

Last checked · Independent guide, not affiliated with TypeSafe AI

ANSWER

Install the official SDK with pip install typesafe-sdk (Python 3.10 or newer), set TYPESAFE_API_KEY, and call client.system_one(state=..., questions={...}) with Noul, Choice and Score objects. The SDK retries rate limits and server errors automatically and raises typed exceptions such as TypeSafeAuthenticationError.

The official Python client is typesafe-sdk (imported as typesafe_sdk). It talks to TypeSafe’s own API only; for OpenRouter or Vercel, use those platforms’ SDKs. Everything below was run with version 0.7.0 on Python 3.10 on September 19, 2026.

Terminal window
pip install typesafe-sdk # or: uv add typesafe-sdk

It requires Python 3.10 or newer.

Mirror gotcha. If pip says No matching distribution found for typesafe-sdk==0.7.0 and lists only older versions, your pip is probably using a package mirror that has not synced yet. That happened to us with a mirror that only had 0.6.0. Install from PyPI directly:

Terminal window
pip install -i https://pypi.org/simple typesafe-sdk

Version 0.7.0 switched the SDK’s serialization library to pydantic; if you pinned 0.6.x, read the changelog before upgrading.

The client reads TYPESAFE_API_KEY from the environment. You can also pass api_key= to the constructor. With no key at all, the SDK raises TypeSafeError: No API key was provided... before sending anything.

from typesafe_sdk import Choice, Noul, Score, TypeSafeClient
client = TypeSafeClient(model="jev-1.13.0")
message = "I was charged twice for my annual plan this morning. Please refund one of the charges today."
response = client.system_one(
state=message,
questions={
"wants_refund": Noul(instructions="Is the customer asking for money back?"),
"queue": Choice(
instructions="Which team should handle this message?",
criteria={
"billing": "Charges, invoices, refunds",
"technical": "Bugs, outages, integrations",
"sales": "New plans, upgrades, quotes",
},
),
"urgency": Score(
instructions="How urgent is this message?",
criteria=["Can wait a week", "Should be handled this week", "Needs a reply today"],
),
},
)
print(response.answers["wants_refund"].noul) # 0.99
print(response.answers["queue"].choice) # billing
print(response.answers["urgency"].score) # 2.0
print(response.usage) # input_tokens=418 output_tokens=72

The sync example took 557 ms end to end in our run. Besides response.answers[...], the response has typed shortcuts: response.nouls, response.choices and response.scores.

Since 0.7.0 you can pass a pydantic model to get attribute access and type checking:

from typesafe_sdk import ChoiceAnswer, Noul, Choice, NoulAnswer, SystemOneResponse, TypeSafeClient
class Triage(SystemOneResponse):
is_bug: NoulAnswer
queue: ChoiceAnswer
with TypeSafeClient(model="jev-1.13.0") as client:
r = client.system_one(
"My invoice lists two seats, but only one of us can sign in.",
{
"is_bug": Noul(instructions="Does the customer describe something not working?"),
"queue": Choice(instructions="Which team should handle this message?",
criteria={"billing": None, "technical": None, "other": None}),
},
response_model=Triage,
)
print(r.is_bug.noul, r.queue.choice, r.request_id)

Pass model= to the client; the default is jev-latest. Use the full versioned ID jev-1.13.0. The shortened jev-1.13, which appears in one example in TypeSafe’s docs, fails with TypeSafeBadRequestError: ... 400 Unknown model: jev-1.13. To see what your account can use:

print([m.name for m in client.models.list().models]) # ['jev-latest', 'jev-preview']
Exception When
TypeSafeError No API key configured (raised locally)
TypeSafeAuthenticationError 401: invalid key
TypeSafeBadRequestError 400: unknown model, unknown question type, max_tokens_exceeded
TypeSafeUnprocessableEntityError 422: missing required field
TypeSafeRateLimitError 429 after retries are exhausted
TypeSafeInternalServerError 5xx (including 529) after retries
TypeSafeAPITimeoutError, TypeSafeAPIConnectionError Network problems after retries

Messages include the method, URL, status and a request_id, for example POST https://api.typesafe.ai/v1/systemone: 401 Cannot authenticate with the server... (request_id=req_...).

By default the client retries 408, 429 and all 5xx responses, plus timeouts and connection errors, twice after the first attempt, with backoff starting at 0.5 seconds and capped at 5 seconds, and it honors Retry-After. To change this:

from typesafe_sdk import RetryPolicy, TypeSafeClient
client = TypeSafeClient(
model="jev-1.13.0",
retry=RetryPolicy(max_retries=4, backoff_max=10.0),
)
  • Create one client and reuse it; use it as a context manager (with / async with) or close it when done.
  • Put all the questions for one input into one system_one call. It costs about the same and takes the same time as a single question.
  • Keep question text and thresholds in one module so they are easy to review and re-test.

See also: Your first Jev call, Jev API reference and Jev API errors.

Sources

  1. TypeSafe Python SDK (TypeSafe docs)
  2. Python SDK usage (TypeSafe docs)
  3. Python SDK retries (TypeSafe docs)
  4. Python SDK changelog (TypeSafe docs)
  5. typesafe-sdk on PyPI
  6. typesafe-sdk-python on GitHub