Jev PlaygroundAPI guide

FROM STATE TO SOFTWARE DECISIONS

Jev API

Call TypeSafe Jev through Vercel AI Gateway with typesafe-ai/jev. Send state and typed questions; receive answers and probabilities your application can use.

Try Jev in Playground

The example runs on your server. Set your Gateway key first.
Setup instructions ↓

Verified with AI SDK 7.0.105
Last checked

refund.tsTypeScript
import { createGateway, experimental_evaluate as evaluate } from 'ai';

const gateway = createGateway({
  apiKey: process.env.AI_GATEWAY_API_KEY,
});

const result = await evaluate({
  model: gateway.evaluationModel('typesafe-ai/jev'),
  state: 'The support agent issued a full refund.',
  questions: {
    refunded: {
      type: 'boolean',
      instructions: 'Was a refund issued?',
    },
  },
  maxRetries: 0,
  abortSignal: AbortSignal.timeout(30_000),
  providerOptions: { gateway: { zeroDataRetention: true } },
});

console.log(result.answers.refunded.probability);

Start with a Boolean. Try this in Jev Playground using Refund Verification.

01 / GET CONNECTED

Install once. Keep the key on your server.

Use AI SDK 7 or later. These examples are checked against ai@7.0.105; pin your version because the evaluation API is experimental and can change in patch releases.

Install the validated versionShell
npm install ai@7.0.105
# Or with pnpm:
pnpm add ai@7.0.105

Create a key in your Vercel dashboard under AI Gateway → API Keys. Add your own Gateway API key to the server environment. In a Next.js app, use an ignored .env.local file; never prefix the key with NEXT_PUBLIC_.

.env.localEnvironment
AI_GATEWAY_API_KEY=

The TypeScript examples belong in a server module or script with that environment loaded—not in a browser component. A Node.js 24 script saved as refund.mts can run with node --env-file=.env.local refund.mts. A Next.js server loads .env.local itself.

We use createGateway and gateway.evaluationModel(...), matching this site’s working integration. A model ID string is also supported when the default provider is Gateway. Do not call generateText or a chat-completions endpoint for this evaluation interface.

Official sources and setup references ↓

02 / ONE SHARED CONTEXT

The request has four parts

Model
typesafe-ai/jev selects Jev through Gateway. The direct TypeSafe API has its own identifiers and contract.
State
The context to inspect: a string, JSON object, or array. An array is one shared state, not a batch of unrelated requests.
Questions
A named map of decisions. A question named refunded is returned at result.answers.refunded.
Answer types
Boolean for a proposition; Choice for named alternatives; Score for ordered levels. Instructions explain what to judge; criteria define the answer space.

New to the model? Read what Jev is and where it fits.

03 / BOOLEAN

A probability of true, not a true/false field

The refund example above asks whether the supplied state records a refund. Its answer contains type and probability. Our real Refund Verification production call returned this answer:

Observed Boolean answerJSON · answer excerpt
{
  "type": "boolean",
  "probability": 0.99
}

0.99 means P(true) = 99%. Display P(false) as 1 - probability, or 1% here. The API does not add a native true verdict; the application sets any threshold. A low P(true) means a likely false proposition, not necessarily uncertainty.

The observed preset used the longer state confirming a full refund and a five-business-day arrival. The shorter copyable example preserves the task, but its result is not guaranteed to match.

These are Gateway field names. TypeSafe’s direct API uses Noul and a noul field; do not substitute that field for probability in these SDK examples.

Try Boolean in Playground Select the “Refund Verification” preset.

04 / CHOICE

Route a request to one team

Use a criteria map: keys are the allowed answer labels, values explain them. This version of Support Routing uses lowercase keys for application code.

routing.tsTypeScript
import { createGateway, experimental_evaluate as evaluate } from 'ai';

const gateway = createGateway({
  apiKey: process.env.AI_GATEWAY_API_KEY,
});

const result = await evaluate({
  model: gateway.evaluationModel('typesafe-ai/jev'),
  state: 'I was charged twice. Please refund the extra charge.',
  questions: {
    team: {
      type: 'choice',
      instructions: 'Which team should handle this customer request?',
      criteria: {
        billing: 'Charges, payments, and refunds',
        technical: 'Bugs and technical problems',
        sales: 'Questions before purchasing',
        other: 'Requests outside the categories above',
      },
    },
  },
  maxRetries: 0,
  abortSignal: AbortSignal.timeout(30_000),
  providerOptions: { gateway: { zeroDataRetention: true } },
});

const answer = result.answers.team;
console.log(answer.choice);
console.log(answer.probabilities?.[answer.choice]);

choice tells you which label won. probabilities, when present, tells you how decisive that selection was. A close race deserves different handling from a clear lead.

Keep label casing exact.

Our production Playground preset uses Billing, Technical, Sales, and Other. It actually returned the uppercase-key answer below. In the copyable example, the permitted answer is billing. That example is an adaptation, not a transcript of the earlier call.

Observed Support Routing answerJSON · answer excerpt
{
  "type": "choice",
  "choice": "Billing",
  "probabilities": {
    "Billing": 1,
    "Technical": 0,
    "Sales": 0,
    "Other": 0
  }
}
Try Choice in Playground Select the “Support Routing” preset.

05 / SCORE

Place an incident on an ordered rubric

Criteria are an array ordered from low to high. The five labels below define 0 — No urgency, 1 — Low, 2 — Moderate, 3 — High, and 4 — Critical.

urgency.tsTypeScript
import { createGateway, experimental_evaluate as evaluate } from 'ai';

const gateway = createGateway({
  apiKey: process.env.AI_GATEWAY_API_KEY,
});

const result = await evaluate({
  model: gateway.evaluationModel('typesafe-ai/jev'),
  state: 'Production is completely unavailable to all customers.',
  questions: {
    urgency: {
      type: 'score',
      instructions: 'How urgent is this incident?',
      criteria: ['No urgency', 'Low', 'Moderate', 'High', 'Critical'],
    },
  },
  maxRetries: 0,
  abortSignal: AbortSignal.timeout(30_000),
  providerOptions: { gateway: { zeroDataRetention: true } },
});

console.log(result.answers.urgency.score);
console.log(result.answers.urgency.probabilities);

Our real Incident Urgency preset described a complete production outage affecting all customers. This was its answer:

Observed Incident Urgency answerJSON · answer excerpt
{
  "type": "score",
  "score": 4,
  "probabilities": {
    "0": 0,
    "1": 0,
    "2": 0,
    "3": 0,
    "4": 1
  }
}

The "4" distribution key refers to the fifth level, Critical. The UI displays 4 / 4 by combining the score with its rubric. There is no separate SDK label field. A Score can be fractional within the rubric; it is not an arbitrary open-ended number. Preserve that value rather than silently rounding it to an integer.

Try Score in Playground Select the “Incident Urgency” preset.

06 / MULTIPLE QUESTIONS

One state, three different decisions

A locked account and a duplicate charge can raise several questions at once. Declare them together to receive a Choice, Score, and Boolean under their own answer keys.

triage.tsTypeScript
import { createGateway, experimental_evaluate as evaluate } from 'ai';

const gateway = createGateway({
  apiKey: process.env.AI_GATEWAY_API_KEY,
});

const result = await evaluate({
  model: gateway.evaluationModel('typesafe-ai/jev'),
  state: {
    message: 'I was charged twice and cannot access my account.',
    accountStatus: 'locked',
  },
  questions: {
    team: {
      type: 'choice',
      instructions: 'Which team should handle this first?',
      criteria: {
        billing: 'Payment or refund problems',
        technical: 'Account access or product problems',
      },
    },
    urgency: {
      type: 'score',
      instructions: 'How urgently does this need attention?',
      criteria: ['Routine', 'Time-sensitive', 'Blocked'],
    },
    refundReview: {
      type: 'boolean',
      instructions: 'Does the customer request require refund review?',
    },
  },
  maxRetries: 0,
  abortSignal: AbortSignal.timeout(30_000),
  providerOptions: { gateway: { zeroDataRetention: true } },
});

console.log(result.answers.team.choice);
console.log(result.answers.urgency.score);
console.log(result.answers.refundReview.probability);

All questions see the same state. They do not consume each other’s answers: if a later decision depends on an earlier result, orchestrate separate calls in code. This is one evaluation request, not a promise of a particular speedup. A successful SDK result includes all declared answers; a failed call is not partial success.

This multi-question example is type-checked, not presented as a recorded model run. The current Playground evaluates one question per run; test each question there separately.

Try Jev in Playground

07 / THE RETURN CONTRACT

What Jev actually returns

The JSON above shows individual SDK answer objects, not the entire HTTP response from this website. The Playground wraps results for its UI; your own integration reads result.answers directly.

Useful application fields

Boolean
type: 'boolean' and required probability in [0, 1].
Choice
type: 'choice', choice, and optional probabilities keyed by your exact criteria labels.
Score
type: 'score', numeric score, and optional probabilities keyed by zero-based level indices as strings.

Our three production calls returned distributions for Choice and Score. The SDK contract still marks them optional. Check for absence; do not turn an unavailable distribution into zero probabilities.

Usage and diagnostic fields

usage
inputTokens, outputTokens, totalTokens. Counts may be undefined; total is known only when both component counts are known. Reported output usage does not itself imply an output charge.
rounding
Optional probabilityDecimals and scoreDecimals. Our calls reported two-decimal probability rounding. Rounded values can sum near, rather than exactly to, 1.
warnings
Provider warnings for diagnostics. Do not serialize raw diagnostics blindly into a public response.

Evidence: three real calls on September 18, 2026 through typesafe-ai/jev. These demonstrate the interface, not model accuracy or calibration. A rounded 100% is not a correctness guarantee. Read the test context.

08 / APPLICATION POLICY

Do more than take the winning label

Read the selected label and its probability before permitting an action. The conceptual guide explains clear leads and close calls; this example implements a simple review policy.

Example policy after routing.tsTypeScript
// Example policy for the Choice result above.
const decision = result.answers.team;
const p = decision.probabilities?.[decision.choice];
const action =
  p == null ? 'human-review' :
  p >= 0.90 ? 'automate' :
  p >= 0.60 ? 'verify' :
  'human-review';

// Your application decides which action is permitted.
console.log(action);

These 0.90 and 0.60 thresholds are an example policy, not TypeSafe recommendations. Choose them using representative labeled data and the consequences of errors. A missing distribution uses the review path here. Also consider the margin between alternatives.

For Boolean, apply thresholds to the proposition you actually care about. For Score, inspect rubric levels and their probabilities; a score such as 3.7 is not a 93% confidence value. Keep eligibility checks and consequential actions in application code.

09 / PRODUCTION BEHAVIOR

Make failure an explicit outcome

The call can fail before or after reaching a provider. Validate state size and question criteria before sending, set a deadline, and return a safe fallback to your UI.

Server-side error boundaryTypeScript
// In a server-side module that imports evaluate and configures gateway.
async function verifyRefund(state: string) {
  if (!state.trim()) return { ok: false, error: 'Enter the state.' };
  const timeout = AbortSignal.timeout(30_000);
  try {
    const result = await evaluate({
      model: gateway.evaluationModel('typesafe-ai/jev'),
      state,
      questions: {
        refunded: { type: 'boolean', instructions: 'Was a refund issued?' },
      },
      maxRetries: 0,
      abortSignal: timeout,
      providerOptions: { gateway: { zeroDataRetention: true } },
    });
    return { ok: true, answer: result.answers.refunded };
  } catch {
    return {
      ok: false,
      error: timeout.aborted
        ? 'Evaluation timed out.'
        : 'Evaluation unavailable. Please try later.',
    };
  }
}

This small boundary deliberately returns a safe message instead of raw provider errors. In a real endpoint, also enforce input limits and your own request limits. The SDK normally allows two retries; this example uses maxRetries: 0 for a predictable single attempt.

Invalid request / answer
Validate empty state, criteria and allowed sizes. The SDK rejects malformed answers too; fix the request or handle the provider failure instead of inventing a result.
Provider 429
Back off before retrying and honor retry guidance where available. Distinguish upstream throttling from your own application’s rate limit.
Timeout
Use abortSignal; show a retry path. Do not leave the interface waiting indefinitely.
Quota / budget
A Gateway 402 or usage-limit error requires checking credits or budget. Repeated immediate retries do not replenish either.
Provider unavailable
Preserve the user’s input and offer later retry or human review. Do not silently treat a failed call as a negative Boolean answer.

10 / PRIVACY

Request a ZDR-compatible route

All complete request examples above include this option, matching this site’s server implementation. Vercel currently documents ZDR routing for Pro and Enterprise accounts; verify your account’s eligibility.

ZDR optionTypeScript · evaluate option
providerOptions: {
  gateway: { zeroDataRetention: true },
}

Per-request ZDR has no additional charge in the current documentation; the separate team-wide feature can have account-level charges. Vercel documents ZDR as a routing requirement: Gateway selects providers compatible with zero data retention. If none is available, the request fails. Our production Jev validation successfully used this setting, and Gateway logs showed ZDR enabled.

This setting does not govern your own application logs, analytics, browser storage, or every provider policy. Send only needed context, avoid logging raw state, and review the applicable terms. It is not a blanket claim that no metadata exists anywhere.

ZDR provider documentation is listed in Sources ↓

11 / COST

Estimate your API workload

The currently published model rate is $0.042 per million input tokens, with $0.00 output-token charges. This is provider pricing, separate from this free Playground.

Pricing last verified: . Prices and account terms can change.

Jev pricing calculator and rate sources — use actual input usage, compare workloads, and see costs beyond the model.

12 / SOURCES

Verified against the working integration

This independent guide uses the same Gateway factory, model ID, answer types and ZDR option as Jev Playground. Examples were checked against installed AI SDK 7.0.105 and the repository’s validated production responses on September 18, 2026.

API details can change. Keep the package version and your integration tests together. Need the model explanation first?