Guide
How to use Jev to triage your support inbox
Build a TypeScript triage worker with AI SDK and TypeSafe’s Jev model: classify tickets, flag production blockers, and route uncertain cases for review.

“Can you resend our invoice?” “Our production API is returning 401.” “Does this plan include SSO?” All three arrive in the same support inbox. Before anyone can help, someone has to decide who should handle each message and which one needs attention first.
Jev, TypeSafe’s new decision model, gives you a way to make those judgments in code. Supply the ticket and a few specific questions. Use the returned classifications and probabilities to propose a queue, flag a reported production block, or send an uncertain case for review.
We’ll build a small TypeScript worker with Vercel’s AI SDK. It reads one ticket, asks Jev three questions through AI Gateway, and prints a routing proposal. Then we’ll show where to connect it to your support inbox and how to pass a technical ticket into investigation.
What Jev does in this workflow
TypeSafe introduced Jev in September 2026 as its first public System One model. Jev produces typed decisions from the state you supply. It does not write the customer reply or retrieve your account records. Your application provides the context and applies the result.
| Decision | AI SDK question type | How we use the answer |
|---|---|---|
| What is the support need? | Choice | Select billing, access, technical, product, or review. |
| How much work is affected? | Score | Rate the reported impact against three defined levels. |
| Is production currently blocked? | Boolean | Use the probability of that statement to raise a review flag. |
These are separate decisions. A customer can ask calmly about a production outage or write angrily about a routine invoice. Their wording should not be the only thing that determines who gets helped first.
This example produces proposals only. It does not send replies, close tickets, change account access, or connect directly to a help desk. The inbox connection is an adapter you add after evaluating the policy.
1. Start with a ticket you can recognize
Keep the input close to what a teammate would need to triage the case: subject, customer message, and relevant recent context. For a follow-up such as “it still fails,” include the earlier description of what failed. Keep customer text separate from trusted account facts and routing instructions.
{
"id": "demo-401",
"subject": "Production requests failing",
"message": "Every production API request has returned 401 since 09:10 UTC. Rotating the key did not help. We cannot process new orders. An example request is req_demo_42."
}This message gives the worker enough information to recognize a reported production block. It does not establish why the requests fail. An expired credential, the wrong environment, and a change in the authentication path would require different evidence to distinguish.
SLA deadlines, current assignment, and a human-set priority belong in your application’s rules. Read those fields from the help desk rather than asking Jev to infer them from the customer’s tone.
2. Ask three focused questions in one request
AI SDK’s experimental_evaluate function accepts shared state and named questions. Use choice for the support category, score for the impact rubric, and boolean for the production-block question. AI SDK calls the last type Boolean; TypeSafe’s native API calls it Noul.
import {
experimental_evaluate as evaluate,
type Experimental_EvaluationQuestion as EvaluationQuestion,
} from "ai";
const questions = {
topic: {
type: "choice",
instructions: "What is the main support need in `ticket`?",
criteria: {
billing: "Invoices, charges, subscription payments, or refunds.",
access: "A person's sign-in, invitation, or workspace membership.",
technical: "API errors (including API authentication), integrations, or broken product behavior.",
product: "How to use a working feature or a request for a new one.",
review: "Several unrelated needs, unclear intent, or none of these categories.",
},
},
impact: {
type: "score",
instructions: "What workflow impact does the customer report in `ticket`?",
criteria: [
"The customer asks a question without reporting impaired work.",
"Work is impaired, but the customer describes a usable workaround.",
"The customer reports blocked work without a working alternative.",
],
},
productionBlocked: {
type: "boolean",
instructions: "Does `ticket` report a production workflow that is currently unusable?",
},
} as const satisfies Record<string, EvaluationQuestion>;Pass the ticket and questions to evaluate. The model ID typesafe-ai/jev uses AI Gateway, which reads AI_GATEWAY_API_KEY from your server environment. The call below allows one retry and sets a 20-second deadline. Section 4 has the complete download and setup commands.
const result = await evaluate({
model: "typesafe-ai/jev",
state: { ticket },
questions,
maxRetries: 1,
abortSignal: AbortSignal.timeout(20_000),
});The category descriptions matter. In this policy, API authentication failures belong to technical investigation; a person’s workspace invitation belongs to account support. The review option catches requests that do not fit cleanly. Use names and boundaries your own team can apply consistently.
The impact rubric runs from 0 to 2 because it has three levels. A fractional result is a weighted position on that scale. It is not the percentage of customers affected or a probability that the product has a bug.
3. Keep the routing policy in code
The first rule in this example checks the reported production block. A strong signal goes to urgent review even if the topic classification is uncertain. An ambiguous production signal also stays with a person. Only after those checks can a sufficiently clear category and impact assessment produce a specialist-queue proposal.
export function route(result: Result) {
// Example thresholds only; evaluate them against your own labeled tickets.
try {
const { topic, impact, productionBlocked } = result.answers;
const blocked = number(productionBlocked.probability);
if (blocked >= 0.8) {
return plan("urgent-review", "high", "reported_production_block");
}
if (blocked >= 0.2) {
return plan("triage-review", "unassessed", "uncertain_production_impact");
}
const queue = QUEUES[topic.choice];
const topicConfidence = confidenceFor(result, "topic");
const impactConfidence = confidenceFor(result, "impact");
const score = number(impact.score, 2);
if (!queue) throw new Error("Unknown topic");
if (queue === "triage-review" || topicConfidence < 0.8 || impactConfidence < 0.7) {
return plan("triage-review", "unassessed", "classification_needs_review");
}
return plan(queue, score >= 1.5 ? "high" : "standard", "classified");
} catch {
return plan("triage-review", "unassessed", "invalid_model_response");
}
}The thresholds here are illustrative policy settings, not measured operating points. Test them against labeled tickets from your inbox. Confidence summarizes the answer distribution; a value of 0.8 does not mean your routing system is 80% accurate. The Boolean answer exposes the probability of the statement being true through productionBlocked.probability.
In AI SDK, Choice and Score confidence is available at result.providerMetadata.typesafe.confidence, keyed by question name. It is separate from answers.topic.probabilities. The download’s confidenceFor helper validates that metadata; missing confidence holds an otherwise routine case for review. A strong production-block signal takes precedence over confidence checks.
The reason field comes from a rule in our code. It tells a reviewer which branch selected the proposal. It is not a generated explanation from Jev. Keep the original message and returned answers available when reviewing a decision.
4. Run the TypeScript example
Use Node.js 22 or later. Create a project, install the versions below, and save the download as jev-support-inbox-triage.ts in that directory. AI SDK’s evaluation API is experimental, so keep the version and lockfile pinned and rerun your checks before upgrading.
mkdir jev-triage
cd jev-triage
npm init -y
npm pkg set type=module
npm install --save-exact ai@7.0.114
npm install --save-dev --save-exact tsx@4.23.15- Download the complete TypeScript example — Includes AI SDK evaluation, typed questions, routing rules, and an offline demo.
npx tsx jev-support-inbox-triage.tsThe default run makes no model call. It prints mode: synthetic_demo and an urgent-review proposal with high priority. The supplied answers are fabricated to exercise the production-block rule; they are not a recorded Jev evaluation.
For a live evaluation, create an AI Gateway API key and set AI_GATEWAY_API_KEY in your local environment. Then run either command below. Live calls use your Gateway account. The optional JSON file must contain nonempty subject and message fields; an id is also accepted.
# Set AI_GATEWAY_API_KEY in your shell before running.
npx tsx jev-support-inbox-triage.ts --live
npx tsx jev-support-inbox-triage.ts --live --ticket ticket.jsonThe worker prints the model ID, typed answers, provider metadata, and proposal. AI SDK validates the answers before our routing function runs. An API failure or invalid answer returns an unassessed review proposal with a nonzero exit code. Missing or invalid confidence metadata also leads to review unless a production-block signal has already selected a review queue.
5. Connect the proposal to your support inbox
Put the worker behind the new-ticket and customer-reply events from your help desk. Your adapter retrieves the ticket context, calls the worker, and maps its fixed queue names to actual team IDs. Jev does not choose an arbitrary destination or make the help-desk API call.
- Start in shadow mode. Save the proposed queue and priority beside the human decision without changing ownership.
- Keep current context. Before applying a result, check that the ticket version has not changed and a teammate has not already taken ownership.
- Apply the existing service policy. Preserve higher priorities and SLA escalation rules; an unassessed result must not downgrade a ticket.
- Make retries safe. Deduplicate each ticket event or revision, and use bounded backoff for transient API failures. Keep the ticket visible for review when evaluation is unavailable.
- Enable one reversible action first. Add a triage label or suggest an assignee before allowing automatic reassignment.
An inbox adapter should retain the event ID, ticket revision, model ID, question version, raw decisions, applied rule, and reviewer correction. That lets you explain a routing change and replay the same inputs when the questions or model change.
6. Check the cases that change the decision
Use a held-out set of resolved tickets with labels agreed by your team. Include ordinary questions, production failures, mixed requests, and short replies that only make sense in context. The cases below describe intended policy behavior to test, not observed Jev results.
| Ticket or condition | What to check |
|---|---|
| “Please resend the invoice.” | A clear routine case can propose billing. |
| “Every production request fails; we cannot process orders.” | A strong production-block signal gets urgent review even with uncertain ownership. |
| “It still fails” without earlier messages | The workflow gathers context or holds for review instead of guessing. |
| A confident low-impact answer | The policy can propose standard handling; low impact and low confidence are different. |
| Timeout, incomplete response, or duplicate webhook | The ticket remains visible and the workflow avoids duplicate changes. |
Measure incorrect queue assignments, missed urgent reports, review volume, and time to a useful first action. A classifier that sends every ticket to review may avoid routing errors while saving no work. Adjust the questions and thresholds against both kinds of cost.
We checked this example against the pinned AI SDK package and tested its routing, response validation, and failure paths with synthetic fixtures. We have not benchmarked Jev on a production support inbox. Run live evaluations on representative tickets before enabling automatic routing.
After triage, investigate the customer’s problem
For the 401 ticket, triage establishes a useful starting point: a reported production block that needs attention. The next step is to follow req_demo_42 through the relevant logs, inspect how the deployed code authenticates the request, and check the customer’s configuration.
Decimal helps customer teams investigate that technical context through connected help desks, code, logs, and customer data. Keep the original conversation and operation identifiers with the ticket so the investigation starts with the evidence already collected.
This is a custom triage workflow you can build with Jev; it does not assume a native Jev integration in Decimal. Connect routing through your help desk’s supported API or workflow, then use your existing investigation process for the cases that need it.
A useful first rollout is one queue, one proposed assignment, and a record of every correction. Expand when the team can see that tickets are reaching the right owner sooner—and that the owner has enough context to move the customer’s problem forward.
Frequently asked questions
Is Jev an inbox or a support agent?
Jev is a decision model from TypeSafe. Your application supplies ticket context and typed questions, then uses the answers to decide what happens in the help desk.
What do I need to run the AI SDK example?
Node.js 22 or later, the pinned AI SDK and tsx packages, and an AI Gateway API key for live calls. The offline demo uses synthetic answers and needs no API key.
Does the example reply to customers or reassign tickets?
No. It prints a routing proposal. You connect that proposal to a help-desk API or workflow after testing the policy. A human or a separate response workflow handles the customer reply.
Does a high confidence value guarantee correct routing?
No. Confidence describes the model’s answer distribution. Evaluate routing accuracy and missed urgent cases on your own tickets, and retain a review path.
What happens if Jev is unavailable?
The example prints an unassessed review proposal and exits with an error status. Your inbox adapter should preserve visibility and existing priority, with bounded retries for transient failures.