Jev Case Study: Support Ticket Triage (Full Code)

Updated Applies to Jev 1.13 Example fixture

TL;DR: This Jev case study shows a two-call ticket triage pipeline on Jev 1.13: a choice question assigns each ticket to billing, technical-support, or sales, and a judgment question decides whether to escalate. Full request bodies, an example-fixture response, and a runnable Python script are below.

Scenario

Our team runs support for a B2B SaaS product with roughly 40,000 tickets per month. Triage used to be the first agent’s job: read the ticket, pick a queue, decide whether it is urgent. It was slow, inconsistent across shift handovers, and it burned senior agents’ time on work a rules engine could not handle — tickets rarely say “billing” outright; they say “I think you charged me twice and I need this fixed today,” and the tone ranges from polite to furious.

We replaced that first pass with two Jev calls per ticket:

  1. A choice question — assign the ticket to exactly one queue: billing, technical-support, or sales.
  2. A judgment question — should this ticket be escalated? Answer yes, no, or unclear.

Jev is a System One judgment model from TypeSafe AI, released in September 2026, built for exactly this kind of work — judgment, choice, and scoring questions — rather than open-ended chat. It returns typed JSON with a confidence value, which is what a triage gate actually needs: route on high-confidence answers, send everything else to a human.

The example ticket below is deliberately typical: a duplicate charge, a same-day deadline, and a bank-dispute threat. It should land in the billing queue and get escalated.

Request

Call 1 — queue assignment (choice question):

{
  "model": "typesafe/jev-1.13",
  "messages": [
    {
      "role": "system",
      "content": "Choice question. Assign the ticket to exactly one queue: billing, technical-support, or sales. Reply with JSON only: {\"answer\": <queue>, \"confidence\": <0-1>, \"rationale\": <one sentence>}"
    },
    {
      "role": "user",
      "content": "Subject: Card charged twice for the September invoice\n\nBody: Hi, I see two charges of $49 on my card from your billing page this morning. Please refund the duplicate charge today, otherwise I will ask my bank to reverse the payment."
    }
  ]
}

Call 2 — escalation check (judgment question):

{
  "model": "typesafe/jev-1.13",
  "messages": [
    {
      "role": "system",
      "content": "Judgment question. Answer yes, no, or unclear. Reply with JSON only: {\"answer\": <yes|no|unclear>, \"confidence\": <0-1>, \"rationale\": <one sentence>}"
    },
    {
      "role": "user",
      "content": "Ticket: Card charged twice for the September invoice. The customer reports a duplicate $49 charge, asks for a same-day refund, and says they will contact their bank otherwise. Should this ticket be escalated?"
    }
  ]
}

Response

Both responses below are example fixtures — illustrative output, not a live capture.

Call 1:

{
  "answer": "billing",
  "confidence": 0.94,
  "rationale": "The customer reports a duplicate charge on an invoice, which is a billing dispute rather than a product defect or a purchase request."
}

Call 2:

{
  "answer": "yes",
  "confidence": 0.97,
  "rationale": "The customer names a same-day deadline and a bank-dispute escalation path, which matches the urgent-financial-impact escalation rule."
}

Reproduce

Save as triage.py, set OPENROUTER_API_KEY, and run python3 triage.py:

import json, os, urllib.request

URL = "https://openrouter.ai/api/v1/chat/completions"
MODEL = "typesafe/jev-1.13"  # confirm exact slug on the OpenRouter model page

def ask(system, user):
    body = {"model": MODEL, "messages": [
        {"role": "system", "content": system},
        {"role": "user", "content": user}]}
    req = urllib.request.Request(URL, data=json.dumps(body).encode(),
        headers={"Authorization": "Bearer " + os.environ["OPENROUTER_API_KEY"],
                 "Content-Type": "application/json"})
    with urllib.request.urlopen(req) as res:
        payload = json.load(res)
    return json.loads(payload["choices"][0]["message"]["content"])

CHOICE = ('Choice question. Assign the ticket to exactly one queue: '
          'billing, technical-support, or sales. Reply with JSON only: '
          '{"answer": <queue>, "confidence": <0-1>, "rationale": <one sentence>}')

JUDGE = ('Judgment question. Answer yes, no, or unclear. Reply with JSON only: '
         '{"answer": <yes|no|unclear>, "confidence": <0-1>, "rationale": <one sentence>}')

ticket = """Subject: Card charged twice for the September invoice

Body: Hi, I see two charges of $49 on my card from your billing page this
morning. Please refund the duplicate charge today, otherwise I will ask my
bank to reverse the payment."""

queue = ask(CHOICE, ticket)
escalate = ask(JUDGE, "Ticket:\n" + ticket + "\n\nShould this ticket be escalated?")
print(queue)
print(escalate)

Key parameters

FieldValueWhy it matters
modeltypesafe/jev-1.13Pin the version so a newer release cannot silently change your triage behavior. Confirm the exact slug on the OpenRouter model page.
messages[0] (system)Question type + option list + JSON shapeJev answers judgment, choice, and scoring questions. Naming the type and the exact options keeps the typed output stable.
messages[1] (user)The ticket textOne ticket per call keeps confidence values comparable across calls.
answer (response)billing / yesThe decision itself — map it straight to a queue name or an escalation flag.
confidence (response)0.94 / 0.97 (example fixture)Gate your fallback on it: below your threshold, hand the ticket to a human instead of routing it.
rationale (response)One sentenceEnough signal for audit logs without a second model call.
Price$0.0462 per 1M input tokensAt thousands of triage calls per day, cost per call matters. Verify current pricing on OpenRouter before budgeting.

Notes

Keep reading