Skip to content

Typed Decisions (Jev) ​

Several places in the agent need a decision, not a paragraph: which tool categories a message needs, whether a knowledge lookup is worth running, which branch a workflow should take, which element on a page to click next. Uranus answers those with a typed decision model that returns probabilities instead of text. Since 2026-10-02 the default is Cloudflare's own Clef (@cf/cloudflare/clef, with @cf/cloudflare/clef-flash as the fast fallback) — first-party Workers AI, Jev-API compatible, so it is available on every conversation without the partner-AI consent step. TypeSafe's Jev (typesafe/jev) remains supported: pin it through the model-policy decision role (settings.llm.roles.decision or a tenant policy) and the partner data-flow policy applies again. Call sites and table names still say "Jev" for the pattern.

Jev does not generate text. It takes a piece of state plus typed questions and returns typed answers with calibrated probabilities:

Question typeReturns
noula probability that the statement is true (yes/no)
choiceone option from a criteria set, with a probability per option
scorea score against a list of criteria

jevRun(ai, state, questions, { gatewayId, timeoutMs }) in src/agent/jev.ts is the single entry point. State is capped at 48 000 characters (Cloudflare's route caps the request at 32K tokens), the default timeout is 4 s (10 s inside workflows), and every call goes through the authenticated AI Gateway, which partner models bill through.

Every Jev-backed decision has a non-Jev fallback. A timeout, an error, or the data-flow policy withholding the model never leaves a conversation without tools, a workflow without a branch, or a memory unwritten.

Claim check ​

After the model's final reply in a turn where tools were available but no write-style tool succeeded, one question — does this reply claim an action was performed? — decides whether the reply goes out, is pushed back with a correction, or (on a repeat) is replaced with an honest one. When writes did happen, a second question compares the reply with the list of tools that succeeded (over-claim). Logged as kind claim_check with the probability. A regex covers agents whose policy withholds the decision model.

Where it is used ​

Tool-category routing ​

jev-tools.ts replaces the regex trigger table in selectToolsForContext with one call per message: for every enabled category Jev answers "does this message need these tools?" against a sharp description of what the category does (CATEGORY_ROUTING_HINTS), and the categories at or above the threshold (default 0.6) are loaded. The state sent is the latest message (≤ 4 000 chars), the last three turns, and the recently used tool names, so a confirmation reply like "yes, tomorrow at noon" keeps its category.

Agents with a connected MCP server always get the custom category regardless of routing.

Controls live in Prompt Studio → Tool Categories → Tool routing: an on/off switch (settings.toolRouting.jev, default on; off = regex triggers only) and the load threshold (settings.toolRouting.threshold).

Knowledge-lookup gate ​

When auto-RAG is on, shouldTriggerRAGJev asks one yes/no question — does this message need the agent's documents? — and runs the fused knowledge search only when the probability is ≥ 0.5. The regex gate is the fallback. See Data Sources.

Task auto-close ​

After each turn, Jev judges every open task in the conversation: completed? and abandoned? A probability ≥ 0.75 closes the task as done or cancelled.

Memory verifier ​

Before a new memory is stored, Jev compares it with up to three similar existing memories (replaces? / contradicts?) and marks replaced ones superseded. See Agent Memory.

browser_task ​

jev-browser.ts drives a browser step by step from the accessibility snapshot: Jev picks the next operation and target ref, the browser performs it, and the loop repeats until the goal is met or a stop condition is hit. One browser_task(goal, url?, inputs?, sessionId?, maxSteps?, confirm?) call replaces a chain of browser_action calls. The result status is one of:

StatusMeaning
donegoal reached; the final page text is returned
needs_inputa value is missing — call again with it in inputs
needs_confirmationstopped before a consequential step (order, payment, message, deletion, personal data); pendingAction describes it. Call again with confirm=true after the user approves — one approval allows exactly one such step
blocked, uncertain, stuck, max_stepscontinue manually with browser_action on the returned sessionId
driver_unavailableno browser driver; fall back to browser_action

Details that matter in practice: pages with more than 200 refs are handled by describing elements first and letting Jev pick a region; a failed step is shown to Jev as "choose again from the current page" rather than the raw error; press_enter clicks the last typed field first; and inputs whose key looks like a credential (password, secret, token, otp, pin, cvv, apikey, passcode, or any key prefixed secret_) are shown to the model as [secret] while the value is typed locally.

Workflow decision node ​

The Decision logic node in the workflow builder asks Jev to pick one of the node's outputs. resolveDecision() (shared by the interpreter and the generated Worker code) accepts the top option only when its probability reaches the threshold (default 0.6) and beats the runner-up by the margin (default 0.15); otherwise the node takes its default output.

Decision log ​

Every call is written to jev_decisions (migration 073): kind (routing, rag_gate, browser_task, decision, task_close), outcome, headline confidence, input_tokens, calls, duration_ms and a payload with the per-option probabilities. Input tokens are also charged to the agent's token usage under the decision model that answered (@cf/cloudflare/clef by default). Newer kinds: claim_check, model_switch, skill_match, skill_learned.

  • Dashboard: Diagnostics → Decision log, filterable by kind.
  • API: GET /api/agents/{id}/jev-decisions?kind=&limit= (limit 1–200, default 50).

Use it to tune thresholds: a routing decision that loaded nothing at 0.58 is one threshold change away.

Data-flow policy ​

Jev is a partner model, so what reaches it is governed by manage/docs/DATA_FLOW_POLICY.md (decided 2026-09-22). In short:

  1. Owner and internal use — dashboard chats, scheduled runs, internal agents — is allowed by default; the per-agent switch settings.toolRouting.jev turns it off.
  2. Customer-facing conversations (any gateway conversation) on an agent that belongs to a product tenant are off by default. The tenant must accept the sub-processor term, which stamps tenants.partner_ai_consent_at through the platform API. Until then every Jev-backed decision in that conversation uses its non-partner fallback.
  3. Secrets never leave — see the browser_task masking above.
  4. The Cloudflare Agent Memory provider follows the same rule.

DashboardAgent.partnerAiAllowed(ctx) is the single check; every Jev call site and the memory-provider choice go through it. The answer is cached for five minutes per isolate.