kedi-typesafe
Framework-native integrations for using TypeSafe AI's Jev models with Kedi's supported agent
frameworks. Core Jev schema translation and the Pydantic AI and LangChain integrations ship as
one kedi-typesafe package.
Pydantic AI
Install the package and provide TYPESAFE_API_KEY in your environment:
pip install kedi-typesafe
export TYPESAFE_API_KEY="your-key"
from typing import Literal
from pydantic import BaseModel, Field
from pydantic_ai import Agent
from kedi_typesafe.integrations.pydantic import TypeSafeModel
class Triage(BaseModel):
urgent: bool = Field(description="The request needs action today")
route: Literal["billing", "support", "other"] = Field(
description="Which team should handle the request?"
)
model = TypeSafeModel("jev-latest")
agent = Agent(model, output_type=Triage)
result = agent.run_sync("I was charged twice. Please fix this today.")
print(result.output)
The initial surface supports booleans, finite string Literal/Enum values, constrained text
extraction, and flat Pydantic models composed of those fields. Pydantic's native EmailStr and
pydantic-extra-types PhoneNumber schemas are recognized automatically. A JSON Schema pattern
is treated as a regex candidate extractor; other string fields can provide an explicit field
extractor:
Install kedi-typesafe[email], kedi-typesafe[phone], or kedi-typesafe[all] when those optional
Pydantic field types are used.
from kedi_typesafe import RegexExtractor
from kedi_typesafe.integrations.pydantic import TypeSafeModel
model = TypeSafeModel(
text_extractors={"ticket_id": RegexExtractor(pattern=r"CASE-\d+")},
)
Candidate extraction is deterministic and Jev only selects among values found in state, following TypeSafe's pre-parsed extraction pattern. Jev is not a free-form text-generation model, so unconstrained strings, tool calling, streaming, arbitrary numbers, nested models, and optional fields are rejected before a provider request is made.
Boolean answers use Jev's Noul probability and a configurable threshold. The default decision is
strictly probability > 0.5; the full probability remains available in model response metadata.
LangChain
Install kedi-typesafe[langchain] and use the native structured-output surface:
from typing import Literal
from langchain.agents import create_agent
from pydantic import BaseModel, Field
from kedi_typesafe.integrations.langchain import TypeSafeChatModel
class Triage(BaseModel):
urgent: bool = Field(description="The request needs action today")
route: Literal["billing", "support", "other"] = Field(
description="Which team should handle the request?"
)
agent = create_agent(TypeSafeChatModel("jev-latest"), response_format=Triage)
result = agent.invoke(
{"messages": [{"role": "user", "content": "I was charged twice. Fix this today."}]}
)
print(result["structured_response"])
TypeSafeChatModel.with_structured_output(...) is also supported for direct LangChain model use.
The same Jev schema restrictions described above apply. Free-form invocation, function tools,
media/tool history, stop sequences, and arbitrary model settings fail before a provider request.
Email and Phone Extraction
Install the field validators:
pip install 'kedi-typesafe[email,phone]'
from pydantic import BaseModel, EmailStr, Field
from pydantic_ai import Agent
from pydantic_extra_types.phone_numbers import PhoneNumber
from kedi_typesafe.integrations.pydantic import TypeSafeModel
class Contact(BaseModel):
email: EmailStr = Field(description="The current support email, not the archived address")
phone: PhoneNumber = Field(description="The current support phone number")
agent = Agent(TypeSafeModel(), output_type=Contact)
result = agent.run_sync(
"Archived contact: old@example.com. Current support: help@example.com, +1 202-555-0100."
)
print(result.output)
Email and phone candidates are extracted from the supplied text automatically. Jev selects the
candidate matching the field description; Pydantic then validates the result. Phone numbers use
Pydantic's normalized format, for example tel:+1-202-555-0100. Provide international numbers
with a country code. Missing candidates or a no-match answer raise an extraction error rather
than inventing a value. All fields in this initial integration must be required.
For LangChain, use the same Contact schema with
create_agent(TypeSafeChatModel(), response_format=Contact) and install
kedi-typesafe[langchain,email,phone].
Runnable Examples
After cloning this repository, run uv sync --all-extras and set TYPESAFE_API_KEY.
| Example | Command |
|---|---|
| Pydantic classification | uv run examples/pydantic_agent.py |
| LangChain classification | uv run examples/langchain_agent.py |
| Pydantic email and phone | uv run examples/pydantic_contacts.py |
| LangChain email and phone | uv run examples/langchain_contacts.py |
These examples call the real TypeSafe API. An async context manager closes owned connections after use; it is optional for constructing the model. Reusing a model within the same event loop allows its HTTP connection to be reused.
Development
uv sync --all-extras --group dev
make prod
Normal tests use deterministic typed fakes and never call TypeSafe. Live API validation is kept separate so CI and local quality gates do not consume credentials or incur cost.
Release files for kedi-typesafe 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| kedi_typesafe-0.1.0.tar.gz | 155.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| kedi_typesafe-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 173.4 kB
Release files / kedi_typesafe-0.1.0.tar.gz
| Download URL | kedi_typesafe-0.1.0.tar.gz |
|---|---|
| Size | 155.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2772e1645ab779649cba11bbaef500b85119d15142046d4520fc3f785bc114b4
|
|
BLAKE2b-256 checksum How to use checksums |
ed6a6331133c90f8ff4dadd365161301d94d796471e9f26d58659e8b8f1cf054
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","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 / kedi_typesafe-0.1.0-py3-none-any.whl
| Download URL | kedi_typesafe-0.1.0-py3-none-any.whl |
|---|---|
| Size | 17.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
dd4a06f296e2944f1d91d583e7e544537b7c117139ae900d4d7a9cce7b85623c
|
|
BLAKE2b-256 checksum How to use checksums |
07870f6fd37ff62711a82e48d1a98136de529f65fc60a12f5fec48b760448514
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","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}
|