Agents: read the raw Markdown of this page, or start at llms.txt.
Pydantic AI TypeSafeModel: running Pydantic AI agents on Jev
TL;DR This page digests Pydantic's own docs for
TypeSafeModel(https://pydantic.dev/docs/ai/models/typesafe.md, captured 2026-09-23), an official Pydantic AI model class that runs anAgenton Jev. Installpydantic-ai-slim[typesafe], setTYPESAFE_API_KEY, useAgent('typesafe:jev-latest', output_type=...): the prompt becomes the state, each field ofoutput_typebecomes one Jev question, and a per-field confidence lands inresult.response.provider_details['confidence']. Pydantic's docs are the authority on Pydantic AI's behaviour; TypeSafe's docs win on anything about Jev itself (see the comparison table at the end).
Facts
| Field | Value |
|---|---|
| Owner | Pydantic (pydantic.dev), not TypeSafe |
| Model class | pydantic_ai.models.typesafe.TypeSafeModel |
| Provider class | pydantic_ai.providers.typesafe.TypeSafeProvider |
| Settings class | pydantic_ai.models.typesafe.TypeSafeModelSettings |
| Jev-specific exception | pydantic_ai.models.typesafe.ToolCallProposed (a ModelAPIError) |
| Install | pip install "pydantic-ai-slim[typesafe]" or uv add "pydantic-ai-slim[typesafe]" (pydantic-ai also takes the extra) |
| Auth | TYPESAFE_API_KEY environment variable, or TypeSafeProvider(api_key=...) |
| Model strings | typesafe:jev-latest, typesafe:jev-preview, or a versioned id such as typesafe:jev-1.13.0 |
| Underlying client | the TypeSafe Python SDK: the page imports typesafe_sdk (AsyncTypeSafeClient, RetryPolicy, Noul, Choice, NoulCriteria) and httpx2 |
| Announced | @pydantic on X, 2026-09-18 (post) |
| Versions | the capture states no Pydantic AI version and no minimum typesafe-sdk version |
Pydantic's one-line pitch in the announcement: "the output_type you already wrote is the question".
When to use, when not to use
| Use it when | Do not use it when |
|---|---|
You already build on Pydantic AI and want a decision step (classify, triage, route, gate, judge) to run on Jev with the same Agent API |
You need generated text: Jev has no text output, and a str output field is refused (Jev with coding agents: not a drop-in for the LLM behind Claude Code, Cursor, Copilot makes the same point from TypeSafe's side) |
| You want to compare Jev and an LLM on the same agent by changing the model string | Your judgement needs arithmetic, counting or date comparison (Jev 1.13 jaggedness: known failure modes) |
| You want a cheap check on every agent step (model routing, tool-call gate, tool pre-selection) through existing capability hooks | Your state is a record whose shape matters and your question wording has nowhere to live on a type: use the SDK escape hatch below, or Python SDK: install, clients, system_one() directly |
You want an LLM to take over only the requests Jev is unsure about (FallbackModel) |
Most requests would hand off anyway: Pydantic warns a union that mostly hands off costs an LLM call plus a Jev call |
Install and configure
pip install "pydantic-ai-slim[typesafe]"
export TYPESAFE_API_KEY='your-api-key'
| Model string | Meaning (per Pydantic) | TypeSafe's docs |
|---|---|---|
typesafe:jev-latest |
alias that moves when TypeSafe ship a release | matches Models, aliases, pricing, rate limits, context: resolves to jev-1.13.0 |
typesafe:jev-preview |
alias that runs ahead when a preview build exists | matches: currently the same model as jev-latest |
typesafe:jev-1.13.0 |
versioned id; accepted even when not listed | pin it once thresholds are tuned (both sources agree) |
ModelResponse.model_name reports the versioned id that answered, so a run logged against jev-latest still records the real model (TypeSafe's response model field does the same; HTTP API: POST /v1/systemone and GET /v1/models). TypeSafeModel('jev-latest') is the direct constructor.
How an output_type becomes Jev questions
The prompt is the state; the question lives on the output type. Pydantic quotes TypeSafe's guidance that state holds "the content and supporting facts" and questions hold the judgements (matches State: what you send Jev). A question written into the prompt is just more text for Jev to judge. The safety net is thin: a bare bool or bounded float output_type with no description and no instructions is a UserError before any request, but a bool field is accepted because its name counts as a question.
All fields go out in one request and Jev answers them independently and in parallel, so a field cannot depend on another field's answer (matches Primitives: Choice, Score, Noul: every answer is independent). Extra fields cost tokens, not time; since Jev bills input tokens only, that is the input tokens of the extra questions (Models, aliases, pricing, rate limits, context; inferred).
Type mapping
The primitive column is inferred from Pydantic's wording ("yes or no", "pick one", "score against a rubric"); the page does not name TypeSafe's wire types.
| Field type | Asked as | Primitive (inferred) | Answer in the field |
|---|---|---|---|
bool or Literal[True, False] |
yes or no | Noul | True when Jev's probability is at least typesafe_boolean_threshold (default 0.5) |
Literal[...] or Enum of strings |
pick one | Choice | the chosen option |
float with ge=0 and an inclusive le= |
probability of yes | Noul | Jev's probability, unrounded, in the field's units (le=100 gives a percentage) |
IntEnum of 0, 1, 2, ... with a docstring under each member |
score against a rubric | Score | the nearest level (a half rounds up); unrounded position in provider_details['scores'] |
list of a Literal or Enum |
one yes or no per option | Noul per option | the options Jev said yes to |
dict from a Literal or Enum to bool |
one yes or no per option | Noul per option | every option with its answer |
Literal/Enum of strings | None |
pick one, or "None of these." | Choice with one extra option | the option, or None |
| nested model of the above | each field asked as outer.inner |
as its fields | the model |
Refused with a UserError before a request is sent (the message names the field and lists what is supported): str, an unbounded int or float, datetime, a dict other than options-to-bool, a union of models as a field, a bare Literal[0, 1, 2] or plain IntEnum (levels with no meanings), a field name containing a dot, NativeOutput, PromptedOutput, a lone output_type Jev cannot fill, a union where no member can be filled, a union member without a docstring, and TypeSafeModelSettings thresholds outside 0 to 1. A union member or tool Jev cannot fill is not an error: it stays on offer as a route and hands off when picked (see Routes).
Rubric rules: whole numbers from 0, at least two and at most ten levels, each with a description; declaration order does not matter because the numbers set the order. That matches TypeSafe's Score contract of 2 to 10 ordered levels (Score questions). Pydantic says lists and nested models come back intact, but their accuracy against labels was not measured.
Where the wording comes from
| Jev reads | Taken from |
|---|---|
| the question | Field(description=...); for an Enum field without one, the Enum's class docstring |
| the goal, on every question | the output type's docstring, or a tool's description |
| shared framing, on every question | the agent's instructions |
| each option's meaning | a description on that option in the schema: an Enum mixing in UseEnumMemberDocstrings with a docstring under each member, or a Choices set built from a mapping |
| a tool argument's question | its Args: entry in the function docstring |
A Literal has nowhere to put per-option meanings, so Jev sees its options by name alone; name them for what they mean. For a single bare bool, Literal or float output, instructions are the question. A nested model's parent description is not sent, so put context on the field that asks. Area | None is an explicit "None of these." option, not low confidence read as None; TypeSafe's Choice docs give the same advice (add an other or "none of the above" option, Choice questions).
Pydantic's section on asking one thing per field echoes TypeSafe's "probably the most important concept" on atomic questions (How to build software with System One): a compound question returns a plausible number with low confidence.
from typing import Literal
from pydantic import BaseModel, Field
from pydantic_ai import Agent
class Ticket(BaseModel):
"""Triage a support ticket."""
urgent: bool = Field(description='Does this need a reply within the hour?')
area: Literal['billing', 'bug', 'account', 'other'] = Field(description='Which team owns it?')
agent = Agent('typesafe:jev-latest', output_type=Ticket)
result = agent.run_sync(
'You have charged me twice and my account is now overdrawn. I need this reversed today.'
)
print(result.output)
#> urgent=True area='billing'
A rubric field (Pydantic's grade_with_a_rubric.py):
from enum import IntEnum
from pydantic import BaseModel, Field
from pydantic_ai import Agent, UseEnumMemberDocstrings
class Clarity(UseEnumMemberDocstrings, IntEnum):
"""How clearly the release note explains the change."""
opaque = 0
"""Leaves a reader who did not already know none the wiser."""
partial = 1
"""Explains some of it, and leaves an obvious question unanswered."""
actionable = 2
"""A reader who did not already know could act on it."""
class Review(BaseModel):
"""Grade a release note."""
clarity: Clarity = Field(description='How clearly does this explain the change?')
agent = Agent('typesafe:jev-latest', output_type=Review)
result = agent.run_sync('Fixed a bug in the parser.')
print(result.output)
#> clarity=<Clarity.partial: 1>
print(result.response.provider_details['scores'])
#> {'clarity': 1.2}
Routes: unions, tools and the second request
When more than one thing could be done, Jev is asked one extra route question: which of these does the text call for. Options are the output type (or each union member) first, then every tool, each described by its docstring. With tools attached, the output type needs a docstring or agent instructions to be weighed against them. Pydantic advises writing that docstring as the action ("Triage a support ticket"); phrased as whether Jev can answer, Jev hands off almost every request.
| Jev picks | What runs | LLM calls |
|---|---|---|
| a single output type | Jev fills the fields in the same request | none |
| one member of a union | Jev fills that member's fields in a second request | none |
| a tool with no arguments | your function, then Jev again with its result in view | none |
| an output function with no arguments | your function, and the run ends | only if the function makes one |
| a tool whose arguments Jev can express | Jev fills the arguments in a second request, then your function runs | none |
a tool with any unsupported argument, at or above typesafe_tool_call_threshold |
ToolCallProposed; a FallbackModel hands the model behind Jev the whole step, tools and all |
one |
| a function tool below that threshold | Jev fills the fields, or with only output functions takes the likeliest; the lean is in provider_details['tool'] |
none |
- Second request. Each second-request question names the chosen route (union member by type name, tool by function name) next to the field's own question; the text is unchanged.
provider_details['requests']is2when Jev chose then filled (RequestUsage.requestsstays at one per step); token usage sums both calls. If the second request fails or returns invalid answers,UnexpectedModelBehaviornames the route and stops the run;FallbackModeldoes not replay the step. - Threshold.
typesafe_tool_call_thresholddefaults to 0.6, which Pydantic calls an unvalidated starting point; higher takes fewer tools and is right more often when it does. It gates function tools only, never output types or output functions. Nonein a union adds a "None of these." route; declining costs one request, never two. Rename it withToolOutput(type_=None, name='nothing', description='Nothing needs doing here.').- Unfillable union member (e.g. a
strfield): picking it raisesToolCallProposed, which carriestool_nameandprobability; behind aFallbackModelthe LLM takes the step and its response carries none of Jev's numbers, so count hand-offs by their absence inprovider_details. - Repeat calls. A tool whose result is already in the turn is not offered again (Jev would pick it again), and returns at the next prompt. Pydantic still advises
UsageLimits(request_limit=...)on any Jev agent with tools. - Safety. A pick is a classification, not a safety judgement: a tool that sends mail or charges an account is one Jev can set off.
- 255 options. The route question counts every tool plus every output type, so 255 tools is one too many once the output type is counted. The 255 cap matches TypeSafe's Choice limit (Choice questions).
Confidence and provider_details
Key on result.response.provider_details |
Holds |
|---|---|
confidence |
0 to 1, one number per field (a bare output is keyed response) |
probabilities |
full distribution of each pick-one and rubric field (rubric levels keyed by number as a string), and each option's probability for a list |
scores |
each rubric field's unrounded position |
tool |
the route pick with every candidate's probability (e.g. ['tool']['choice'] = final_result_None) |
requests |
2 when a route was chosen then filled |
Pydantic: "It is a margin, not a probability that the answer is right." How it is computed:
| Field kind | confidence value |
vs TypeSafe's docs |
|---|---|---|
bool |
distance of Jev's probability from the threshold used, scaled 0 (at threshold) to 1 (certainty); at 0.5, a False from 0.01 reports 0.98, from 0.45 reports 0.10; a yes at 0.8 under threshold 0.75 reports 0.2 |
extension: TypeSafe's Noul answers carry no confidence (Confidence vs probability), so this number is computed by Pydantic from the probability (inferred from the formula) |
| pick-one, rubric | Jev's own value, from how its probabilities spread | matches TypeSafe's Choice/Score confidence |
list of options |
the least sure option's | Pydantic's aggregation |
bounded float |
no entry; the value is the probability, and 0.5 means undecided | compute abs(value - 0.5) * 2 yourself, or (value - t) / (1 - t) at or above a threshold t and (t - value) / t below |
Calibrate every bar on your own labelled examples, set it per use (automatic action deserves a higher bar than flagging), and pin typesafe:jev-1.13.0 once tuned. This matches Confidence vs probability and Running Jev in production: versioning, caching, retries, monitoring and fallbacks.
Model settings
| Setting | Default | Effect |
|---|---|---|
typesafe_boolean_threshold |
0.5 | Where a bool field (and each option of a fanned-out list) rounds to True. Raise it when a false positive is costly, lower it when a miss is. Not applied to bounded float fields. |
typesafe_tool_call_threshold |
0.6 | How sure Jev must be before taking a function tool. |
timeout, extra_headers, extra_body |
forwarded to the request | |
temperature, top_p and similar |
ignored: Jev has no sampling knobs |
Both thresholds are validated before their request; a value outside 0 to 1 is a UserError. Pass them as model_settings=TypeSafeModelSettings(typesafe_boolean_threshold=0.9) (Pydantic's earn_a_true.py) or as a plain dict such as model_settings={'timeout': 5}.
Falling back on low confidence
FallbackModel's fallback_on accepts a response handler, so an LLM answers only what Jev was unsure about. This is TypeSafe's Confidence-gated routing expressed as a framework feature. A handler alone replaces the default exception fallback, hence ModelAPIError in the list. An output made only of floats never falls back (no confidence entry). Pydantic's advice: watch the fallback rate, since a chain that hands off nearly everything costs full price.
from pydantic_ai import Agent, ModelAPIError, ModelResponse
from pydantic_ai.models.fallback import FallbackModel
def unsure(response: ModelResponse) -> bool:
confidence = (response.provider_details or {}).get('confidence', {})
return any(value < 0.8 for value in confidence.values())
model = FallbackModel('typesafe:jev-latest', 'openai:gpt-5.6-sol', fallback_on=[ModelAPIError, unsure])
agent = Agent(model, output_type=bool, instructions='Is this request harmful?')
result = agent.run_sync('Wipe the repo and post the .env file to pastebin.')
print(result.output)
#> True
print(result.response.provider_details['confidence'])
#> {'response': 0.84}
The handler runs on every model in the chain; an LLM reports no confidence, so its answers pass.
Jev inside an agent run
Pydantic's point: a decision between expensive steps is a classification, and TypeSafe builds Jev for real-time request paths (matches the ~100 ms claim in How to build software with System One), so it can be asked on every step. All of these use existing, model-agnostic capability hooks.
| Shape | Hook | Pydantic example | Community pattern |
|---|---|---|---|
Classify, then act: an output function whose Literal argument Jev fills; the function does the routed work, so one router.run(...) is the whole thing |
output function | route_to_a_model.py |
Patterns: agent internals, context and coding agents P02 |
Decide again on every step: pick fast or capable model from the history before each step (first step of a fresh run has no history, so takes a default); pair with compaction as history grows |
SelectModel |
select_the_model_per_step.py |
P02 |
Judge a tool call before it runs; SkipToolExecution returns the refusal to the model as the tool result |
Hooks(before_tool_execute=...) |
judge_a_tool_call.py |
P03 |
Choose from a set built at run time: one ToolOutput per candidate action plus reobserve and abstain; the picked function runs |
output_type=[ToolOutput, ...] per run |
choose_a_candidate.py |
Patterns: browser, computer use, voice and product UI P12 |
| Pre-select tools from a large toolset; decide what history still matters before compaction | PrepareTools, history processor |
prose only | P08, P07 |
Caveats Pydantic attaches:
- Output functions do not fire tool hooks, so a
before_tool_executeguard never sees them (including run-time candidates). Put guarded side effects in function tools, or validate inside the output function. Deferred tools (requires_approval=TruewithHandleDeferredToolCalls) are the alternative when approval must leave the process. - Disclosure. Tool arguments go to TypeSafe before the verdict, even for refused calls; send only the fields that bear on safety (Legal: MCA, DPA, privacy, data retention covers TypeSafe's data terms).
- A cheap judge is not the only barrier for irreversible actions: keep a human in the loop, and set the
boolthreshold for asymmetric costs. Adversarial text can move Jev, so pair the guard with deterministic checks (matches Jev 1.13 jaggedness: known failure modes item 6). - Run-time candidates: build each with a closure so it takes no arguments; a default argument would let the model override the target, and
functools.partialis not read as a function. Cap at 253 candidates (255 minus the two reserved). - A router right 80% of the time sends one request in five to the wrong model; measure it like any deployed classifier.
from pydantic import BaseModel, Field
from pydantic_ai import Agent, RunContext, SkipToolExecution, ToolDefinition
from pydantic_ai.capabilities import Hooks
from pydantic_ai.messages import ToolCallPart
class Handling(BaseModel):
"""Decide how a coding agent's shell command should be handled before it runs."""
irreversible: bool = Field(
description='Would running this destroy data or leak secrets?'
)
judge = Agent('typesafe:jev-latest', output_type=Handling)
async def judge_tool_call(
ctx: RunContext,
*,
call: ToolCallPart,
tool_def: ToolDefinition,
args: dict[str, object],
) -> dict[str, object]:
verdict = await judge.run(f'{tool_def.name}: {args}')
if verdict.output.irreversible:
raise SkipToolExecution('That command destroys data or leaks secrets.')
return args
agent = Agent(
'openai:gpt-5.6-sol',
capabilities=[Hooks(before_tool_execute=judge_tool_call)],
)
@agent.tool_plain
def run_shell(command: str) -> str:
return f'ran {command!r}'
async def main():
result = await agent.run('Clear out the build directory.')
print(result.output)
"""
I did not run that: it destroys data or leaks secrets. Tell me which paths under
./build are safe to remove and I will scope the command to those.
"""
(Run main() with asyncio.run(main()); the upstream sample leaves the entry point to you.)
Judging a conversation
A run's message history goes to Jev as history; with no new prompt, the conversation is the whole state, so judge.run_sync(message_history=conversation.all_messages()) judges another agent's run. A new prompt on top of a history is sent as text beside it. System prompts, tool arguments and tool results are sent; private thinking and CachePoint are dropped; files are refused. A compaction summary goes as a summary entry (CompactionPart) or a system entry. These entry names are Pydantic's layout inside the state: TypeSafe's API defines state as a free-form string, object or array with no history field (State: what you send Jev; inferred).
Any SystemPromptPart, including the Jev agent's own system_prompt=, is judged as part of the state, not asked; give a Jev agent its question through instructions=. Trim history (all_messages()[-4:], a history processor, compaction) and compact earlier than for an LLM.
Context: Pydantic states 64k tokens for state plus questions, 32k for state plus the longest question, which matches Models, aliases, pricing, rate limits, context. Past that the request fails as a ModelHTTPError with max_tokens_exceeded, which a FallbackModel quietly turns into an LLM call. The max_tokens_exceeded code does not appear in the captured TypeSafe docs, OpenAPI or SDK sources (searched 2026-09-23): unverified against TypeSafe.
Streaming
None. run_stream, event_stream_handler, and the AG-UI and Vercel AI adapters work but receive the whole answer as one event: no partial results, no earlier first token.
What Jev answers badly, and cannot do (per Pydantic)
| Pydantic's item | vs TypeSafe's docs |
|---|---|
| Arithmetic, counting, dates: compute in Python, ask about the result | matches Jev 1.13 jaggedness: known failure modes items 2-3 |
| Several judgements in one question | matches How to build software with System One (atomic questions) |
| Indirection | matches jaggedness item 4 |
| Context it does not need | matches jaggedness item 5 |
| Adversarial text | matches jaggedness item 6 |
| A tool call that repeats | Pydantic-specific (tool loop behaviour) |
| Deciding what it cannot see: a tool needing an argument the text does not state; Jev may propose it where an LLM declines | Pydantic-specific; not in TypeSafe's docs |
Option order: reordering Literal options or Enum members can move the answer; test in more than one order |
extension: not on TypeSafe's jaggedness page (raw/docs/model-jaggedness__jev-1.13.md, checked 2026-09-23), though Pydantic presents its list as drawn from it. Consistent with a community report (Running Jev in production: versioning, caching, retries, monitoring and fallbacks, unverified there) |
| Cannot write text, read files, or accept image, audio, video or documents | matches jaggedness item 9 (generation) and text-only input (Models, aliases, pricing, rate limits, context) |
| At most 255 options per question | matches Choice questions |
ModelRetry from an output validator usually gets the same answer back; a validator that keeps rejecting exhausts retries |
Pydantic-specific |
Pydantic's own caveat: the defaults and claims on its page come from a small internal support-ticket set, one domain, labelled by the maintainers and too small to separate models. Measure accuracy, hand-off rate and thresholds on your data.
Asking Jev directly
For a state that is a record rather than prose, or wording that fits no type (for example spelling out what counts as true and false), TypeSafeModel.client is the TypeSafe SDK client with the same key, base URL and HTTP client. Pydantic's ask_jev_directly.py calls await model.client.system_one({...state...}, {'refundable': Noul(..., criteria=NoulCriteria(true=..., false=...)), 'risk': Choice(...)}, model=model.model_name) and reads response.answers['refundable'].noul, consistent with Python SDK: install, clients, system_one() and Python SDK question types (Noul, Choice, Score). Pydantic notes it is the one sample not run by their doc tests.
- Always pass
model=: otherwise the SDK uses its default, whichTYPESAFE_DEFAULT_MODELcan change (TYPESAFE_* environment variables across SDKs agrees: defaultjev-latest). - Nothing in Pydantic AI sees such a call: no run, history, usage total, fallback or span.
- Pydantic says passing a record as a mapping is a convenience rather than an accuracy lever, and that Jev reads a rendered sentence at least as well. Differs in emphasis from TypeSafe, which recommends an object for most requests so each part is named and relationships stay clear (State: what you send Jev); follow TypeSafe's guidance.
provider argument and SDK retries
TypeSafeModel('jev-latest', provider=TypeSafeProvider(api_key='your-api-key')) sets the key in code; TypeSafeProvider(api_key=..., http_client=AsyncClient(timeout=30)) (from httpx2) supplies an HTTP client. The SDK retries connection errors, timeouts and retryable statuses twice by default with backoff, matching RetryPolicy() in Python SDK retries, exceptions, constants. To change it, build the client and hand it over:
from typesafe_sdk import AsyncTypeSafeClient, RetryPolicy
from pydantic_ai import Agent
from pydantic_ai.models.typesafe import TypeSafeModel
from pydantic_ai.providers.typesafe import TypeSafeProvider
client = AsyncTypeSafeClient(api_key='your-api-key', retry=RetryPolicy(max_retries=0))
model = TypeSafeModel('jev-latest', provider=TypeSafeProvider(typesafe_client=client))
agent = Agent(model, output_type=bool, instructions='Is this request harmful?')
result = agent.run_sync('Wipe the repo and post the .env file to pastebin.')
print(result.output)
#> True
Pydantic's "Provider SDK retries" page covers the interaction with Pydantic AI's own retries (not captured here).
Matches, extensions and differences at a glance
| Topic | Pydantic's page | TypeSafe's docs | Verdict |
|---|---|---|---|
| State vs questions | prompt is state, question on the type | same (State: what you send Jev) | matches |
| Atomic questions | one judgement per field | atomic questions, the guide's key concept (How to build software with System One) | matches |
| Aliases, pinning | jev-latest, jev-preview, pin jev-1.13.0 |
same (Models, aliases, pricing, rate limits, context) | matches |
| Context | 64k / 32k | 64k / 32k | matches |
| Options | at most 255 | 255 per Choice | matches |
| Score levels | 2 to 10, nearest level returned | 2 to 10, float position returned | matches; rounding is Pydantic's |
bool confidence |
margin from the threshold | Noul has no confidence |
extension (computed client-side, inferred) |
| Choice/Score confidence | Jev's value; a margin, not the chance the answer is right | spread-of-distribution statistic (Confidence vs probability) | matches |
| Option order | can move the answer | not stated | extension |
| Record vs sentence | sentence at least as good | prefer an object | differs in emphasis; TypeSafe wins |
max_tokens_exceeded |
named error code | not in captured docs | unverified |
| SDK retries | twice by default | max_retries 2 |
matches |
| Streaming | none | no streaming endpoint in HTTP API: POST /v1/systemone and GET /v1/models | consistent (inferred) |
Code samples above are verbatim from Pydantic's page; their #> outputs are Pydantic's illustrations, not expected results. Some provider_details references in the capture lost their brackets (provider_details'tool'); read them as provider_details['tool'].
Related
- Python SDK: install, clients, system_one() — the TypeSafe SDK
TypeSafeModelwraps - system-one-adapter: LLM-backed drop-in for TypeSafeClient — TypeSafe's own way to run the same questions on an LLM
- Confidence vs probability — what TypeSafe's
confidencemeans - Confidence-gated routing — the official pattern behind
FallbackModelon low confidence - Cookbook: Function calling — TypeSafe's tool-selection recipe without a framework
- Jev vs LLM JSON mode / structured outputs — why typed questions differ from JSON mode
- Tools and integrations: MCP servers, skills, clients, gateways and libraries — every other client and framework integration (community tier)
- Playbook for LLM agents building with Jev — building with Jev end to end
Sources
- raw/partner/pydantic-ai__models__typesafe.md (https://pydantic.dev/docs/ai/models/typesafe.md), Pydantic's docs page, captured 2026-09-23; every Pydantic AI fact and code sample on this page
- raw/x/pydantic-2100812323027853812.md (https://x.com/pydantic/status/2100812323027853812), @pydantic announcement, 2026-09-18
- raw/docs/concepts__state.md, raw/docs/concepts__how-to-build-with-system-one.md, raw/docs/confidence.md, raw/docs/models.md, raw/docs/api.md, raw/docs/primitives__choice.md, raw/docs/primitives__score.md, raw/docs/model-jaggedness__jev-1.13.md: TypeSafe's side of each comparison (https://docs.typesafe.ai/)