Agent and MCP guides · 2026-09-17
What is Jev? TypeSafe's choice-based decision model for browser agents
TypeSafe's Jev model produces structured decisions such as choices, scores and truthfulness ratings instead of free text. Read how jev-ultrafast applies this to browser agents, the speed difference measured in its own docs, and where the architecture's limits are.
What are Jev and TypeSafe?
Jev is the flagship member of what TypeSafe calls its "System One" model family. Its job is not free text generation; it makes structured decisions: choosing from a list (Choice), scoring a state against a rubric (Score), or rating how true a statement is on a 0-to-1 scale (Noul). The company's own landing page sums this up as "Ask Jev, up to a million times."
The point of the design is parallelism: every question in one request is evaluated against the same state, independently and at once. According to TypeSafe's documentation, adding a question barely affects response time, because questions are processed in isolation and in parallel. The recommended design philosophy is to split a complex decision into small, well-scoped questions rather than one large one, and combine the results in code.
The usual slowness of browser agents
A common agent architecture takes a screenshot, sends it to a vision model, has the model answer in free text such as "click this coordinate," and has code parse and execute that text. Every step of that loop carries the cost of image processing, free-text generation and parsing; as step count grows, the number of low-level protocol calls made to the browser grows with it.
In jev-ultrafast's own measurement, this older approach needed a median of 1,092 browser protocol calls to complete the same task. The problem is not one slow step; it is the fixed cost each step carries, added up.
jev-ultrafast: separating the decision from the text
jev-ultrafast is an MIT-licensed open-source demo published jointly by Browser Use and TypeSafe. Every page observation produces an indexed table of visible controls (buttons, comboboxes, text fields). One Jev request asks which operation to perform (CLICK, TYPE_TEXT, SELECT, SCROLL_UP, SCROLL_DOWN, WAIT, DONE, BLOCKED) and, at the same time, a candidate target for every operation that is currently valid; the executor only consumes the target answer for the operation that was actually chosen.
So the operation and target decisions happen in one network round trip instead of two serial calls. An actual text-generating language model only gets involved when TYPE_TEXT is chosen, and only to produce the value for that one field; it never decides the operation or the target. The browser connection itself runs through a separate open-source component, Browser Harness.
The speed difference measured in the source project
The table below comes from jev-ultrafast's own measurement file; it has not been independently reproduced by LLMTR. The source itself states plainly that this is not a general reliability benchmark, but a few repeats of one task on one browser profile.
| Measurement | Value | Note |
|---|---|---|
| Zurich → London, Google Flights | 7.1 seconds (7,073 ms) | Starts after the first page observation; includes model calls, generated text and loading waits |
| Median task time, six alternating runs | 9.450 s → 7.092 s (25% reduction) | Same task, same browser profile, same models and settings |
| Median browser protocol calls | 1,092 → 101 | Same six runs; both versions passed 3/3 |
| Opening a Wikipedia article | 2.798 s | Separate, single-task measurement, same decision policy |
| Local hotel search/filter task | 1.896 s | Separate, single-task measurement, same decision policy |
Limits and the need for independent verification
A DONE choice is not proof that the task actually succeeded; even the source's own guidance recommends an independent verification step. Coverage is limited too: shadow DOM, iframes, canvas, file uploads, pop-ups and nested scrolling are explicitly left out of this first version.
Working on two example sites (Google Flights, Wikipedia) is not proof of general reliability, and the source says as much: the policy is generic, but two websites do not establish broad reliability. A valid operation choice can still be the wrong one.
Why this architecture is being talked about now
AI agents that can control a browser are spreading quickly across different providers and open-source projects, and they all share the same trade-off: how much image processing and free-text generation each step needs, and what that costs in latency and money. jev-ultrafast answers that trade-off concretely by reducing decision-making to a choice and compressing free-text generation into the one moment it is actually needed — the value written into a field.
That separation has a practical consequence too: the text-generation step becomes an ordinary OpenAI-compatible request, independent of the decision engine. That makes it portable to architectures where a different system makes the decisions.
Beyond browser agents: where this helps in your code
The job Jev does is not specific to browser agents. Every place in your code where you have thought "I would ask a language model this, but then I would have to parse the answer" fits the same shape: turn the decision into a typed question and keep the threshold in code.
The table below shows that shape across four different jobs. The common thread is the last column: the model does not make the decision, it supplies the input to the decision.
| Job | Questions | What the code does |
|---|---|---|
| Support ticket routing | department (Choice), urgent (Noul), frustration (Score) | Picks the queue; weights urgency and frustration into a priority |
| Moderation queue | One Noul per policy | A separate threshold per policy; publishes automatically when all are low, escalates when one is high |
| Relevance filter before RAG | chunk_relevant (Noul), for each candidate chunk | Drops anything below the threshold so fewer tokens reach the language model |
| Instead of fragile parsing | format (Choice) over the expected formats plus an 'other' option | Replaces a chain of regexes; a new format adds an option rather than a pattern |
One request, four questions, thresholds in code
The function below judges a support ticket with four questions in a single request. Three things in it are worth noticing.
First, the questions travel together. Questions in one request are evaluated in parallel and independently, so adding one does not noticeably lengthen the response; it adds that question's tokens. That is why the refund question is asked on every ticket: it only matters for billing tickets, and asking anyway is cheaper than a second round trip.
Second, the definition of high priority lives in the code. The model returns probabilities; you set the weights and the cut-off. When the team changes what counts as urgent, a coefficient changes and no prompt is rewritten.
Third, the decision goes to a person when the distribution is not peaked. That is what the confidence field is for: drawing the line between acting automatically and asking someone.
Support ticket triage in one request
import os, requests
QUESTIONS = {
"departman": {
"type": "choice",
"instructions": "Bu talebi hangi ekip karsilamali?",
"criteria": {
"faturalama": "Odeme, fatura, iade",
"teknik": "Hata, kesinti, entegrasyon",
"satis": "Fiyatlandirma, hesap acma",
"diger": None,
},
},
"acil": {
"type": "noul",
"instructions": "Mesaj zaman baskisi bildiriyor mu?",
},
"memnuniyetsizlik": {
"type": "score",
"instructions": "Musteri ne kadar rahatsiz gorunuyor?",
"criteria": ["Sakin", "Rahatsiz ama nazik", "Cok ofkeli"],
},
# Yalnizca faturalama kaydinda ise yarar; yine de ayni istekte sorulur.
"iade_talebi": {
"type": "noul",
"instructions": "Musteri para iadesi istiyor mu?",
},
}
def triage(ticket: str) -> dict:
res = requests.post(
f"{os.environ['LLMTR_BASE_URL']}/v1/systemone",
headers={"Authorization": f"Bearer {os.environ['LLMTR_API_KEY']}"},
json={"model": "typesafe/jev", "state": ticket, "questions": QUESTIONS},
)
res.raise_for_status()
a = res.json()["answers"]
# Esikler ve agirliklar TEK yerde. Model yalnizca olasilik dondurur;
# "yuksek oncelik" tanimi sizin kodunuzda yasar ve bir katsayi
# degistirilerek revize edilir.
oncelik = 2 * a["acil"]["noul"] + a["memnuniyetsizlik"]["score"] / 2
return {
"kuyruk": a["departman"]["choice"],
"oncelik": "yuksek" if oncelik > 1.5 else "normal",
# Dagilim tepe yapmadiysa karari insana birak.
"insana_devret": a["departman"]["confidence"] < 0.7,
"iade_akisi": a["iade_talebi"]["noul"] > 0.8,
}
When it is the wrong tool
If you need free text, this model does not do that job: producing a summary, a draft reply or an explanation needs a chat model. Combining both in one flow is normal, with the decision going to Jev and the wording to a chat model.
Do not compress a judgment that needs extended reasoning, or that weighs several independent factors, into one question; decompose it and combine the answers in code. Rather than scoring a startup pitch in a single question, ask about market size, technical feasibility and differentiation separately and weight them with your own formula. That is both more reliable and revisable afterwards.
It is also the wrong tool when you need the reasoning behind a decision as text: what comes back is a probability distribution, not an explanation. The distribution is often a more useful signal than a rationale, but it is not the same thing.
Where LLMTR fits in this architecture
LLMTR can serve both steps of this architecture. The small language model called on the TYPE_TEXT operation is a standard OpenAI-compatible chat completions request — exactly the endpoint shape LLMTR serves.
The decision step has an option too: Jev is in the LLMTR catalog as `typesafe/jev` and answers on the `/v1/systemone` endpoint. Same `state` and `questions` body, same response shape; the only change is where the request goes and which key it carries. The Structured Decisions documentation linked below covers every request and response field.
You can move the two steps independently: the text-generation step only, the decision step only, or both. The environment variable changes, the actual request shape, and what to watch for are covered step by step in this series' integration guide.
Frequently asked questions
What is Jev?
Jev is the flagship member of TypeSafe's "System One" model family. It produces structured decisions — choices, scores, and truthfulness ratings — instead of free text, evaluating every question in a request in parallel and in isolation.
Is jev-ultrafast an LLMTR product?
No. jev-ultrafast is an MIT-licensed open-source demo owned by Browser Use and TypeSafe. LLMTR does not own or operate this project; this article only examines its architecture and where it intersects with LLMTR.
Did LLMTR run the speed measurements in this article?
No. The figures come from jev-ultrafast's own measurement file, and the source itself states this is not a general reliability benchmark. LLMTR has not independently reproduced these measurements.
Can I call Jev's decision API through LLMTR?
Yes. Jev is in the LLMTR catalog as `typesafe/jev` and answers on the `/v1/systemone` endpoint, with the same request and response body TypeSafe uses. That was not the case when this article was first published; it was added afterwards. LLMTR also fits the architecture's text-generation step (TYPE_TEXT).
Do I need jev-ultrafast to use this architecture?
No. Splitting decisions into a structured choice API and text generation into a separate, narrow LLM call is not specific to jev-ultrafast; you can build the same separation into your own agent and point the text-generation step at LLMTR.
Related posts
- Running jev-ultrafast's text-generation step through LLMTR
- AI agent API architecture: tool calling, security, and LLM gateway
- What is MCP? Guide for LLM API and AI agent integration
- Leyla: the first Turkey-hosted System One decision model
- Choosing a text classification model: Leyla, Leyla English and Leyla Typed Decisions