Skip to content

Jev Choice

Rasmus Wulff Jensen edited this page Sep 22, 2026 · 3 revisions

Jev Choice

Use Choice when the answer must be one member of a fixed set: a ticket category, the team that should handle it, or a document type. For a graded scale, use Score; for a yes/no proposition, use Noul.

In JevDotNet, a Choice has two parts: an enum defining the allowed options and [JevChoiceQuestion<TEnum>] on a property of your return object. The API chooses one option and also returns probabilities and confidence. You decide whether to keep just the enum value or all the detail.

Define the options

using System.ComponentModel;
using JevDotNet.Models;

public enum SupportTeam
{
    [Description("Returns, exchanges, and damaged items")]
    Returns,

    [Description("Delivery status, delays, and lost packages")]
    Shipping,

    [Description("Charges, invoices, and payment problems")]
    Billing,

    [Description("Requests that fit none of the other teams")]
    Other
}

The enum member names (Returns, Shipping, etc.) are the option IDs. [Description] supplies the explanation sent with each option; if omitted, JevDotNet uses the member name as its description. The enum's underlying numeric values are not the option IDs sent to Jev. Make descriptions distinct, and include an Other option if real input may fall outside the named categories.

The TypeSafe API accepts up to 255 Choice options; JevDotNet does not enforce that limit before sending the request. This library currently uses strings for criteria, even though the underlying API also supports structured criteria.

Add a Choice property

public sealed class TicketRouting
{
    [JevChoiceQuestion<SupportTeam>("Which team should handle this ticket?")]
    public SupportTeam? Team { get; set; }
}

SupportTeam in the attribute defines the options. Team is the question ID in the request and the answer ID in the response. The question text becomes the API's instructions. The property must be public and writable, and the question text must not be blank.

Choose a property shape:

Property type What you get
SupportTeam or SupportTeam? Only the selected enum member.
JevChoice<SupportTeam> or JevChoice<SupportTeam>? The selected member, confidence, and probabilities for the options.

The enum inside JevChoice<T> must be exactly the same enum used by the attribute. A string, int, or unrelated enum is not a supported Choice property type. A nullable property is convenient before evaluation; a successful answer still supplies a value.

Read the selected option

This complete example needs the NuGet package and a TypeSafe AI key in JEV_API_KEY:

using System;
using System.ComponentModel;
using JevDotNet;
using JevDotNet.Models;

string apiKey = Environment.GetEnvironmentVariable("JEV_API_KEY")
    ?? throw new InvalidOperationException("Set JEV_API_KEY first.");

JevClient client = new(apiKey);
JevResponse<TicketRouting> response = await client.EvaluateAsync<TicketRouting>(
    "My running shoes arrived in the wrong size. Can I exchange them?");

SupportTeam? team = response.Result.Team;
Console.WriteLine($"Team: {team}");

public sealed class TicketRouting
{
    [JevChoiceQuestion<SupportTeam>("Which team should handle this ticket?")]
    public SupportTeam? Team { get; set; }
}

public enum SupportTeam
{
    [Description("Returns, exchanges, and damaged items")]
    Returns,
    [Description("Delivery status, delays, and lost packages")]
    Shipping,
    [Description("Charges, invoices, and payment problems")]
    Billing,
    [Description("Requests that fit none of the other teams")]
    Other
}

The result class needs a public parameterless constructor; declaring no constructor provides one here. JevDotNet creates a new result object, matches the Team answer, and sets the property.

Keep confidence and probabilities

Change the property to JevChoice<SupportTeam>? when routing logic needs more than the winner:

public sealed class DetailedTicketRouting
{
    [JevChoiceQuestion<SupportTeam>("Which team should handle this ticket?")]
    public JevChoice<SupportTeam>? Team { get; set; }
}

Then evaluate it and read the detailed answer:

JevResponse<DetailedTicketRouting> detailedResponse =
    await client.EvaluateAsync<DetailedTicketRouting>(
        "My running shoes arrived in the wrong size. Can I exchange them?");

JevChoice<SupportTeam> answer = detailedResponse.Result.Team
    ?? throw new InvalidOperationException("Team answer was missing.");

SupportTeam selected = answer.Choice;
double confidence = answer.Confidence;
double returnsProbability = answer.Probabilities[SupportTeam.Returns];

if (confidence < 0.5)
{
    Console.WriteLine("Review this ticket before routing it.");
}

In this follow-on snippet, client and SupportTeam are defined as in the preceding example. Choice is the selected enum member. Probabilities is an IReadOnlyDictionary<SupportTeam, double>; each value is the model's probability for that option. Confidence is a separate 0–1 summary of how concentrated the distribution is, not the selected option's probability. A spread across options produces lower confidence. These values describe the model's answer, not a guarantee that the classification is correct.

If your code needs only Team, use the simple enum property. The API may still return probability data, but JevDotNet does not retain it in that property.

What JevDotNet sends and reads

The Team property above produces a Choice question shaped like this (the surrounding request also contains model and state):

{
  "questions": {
    "Team": {
      "type": "choice",
      "instructions": "Which team should handle this ticket?",
      "criteria": {
        "Returns": "Returns, exchanges, and damaged items",
        "Shipping": "Delivery status, delays, and lost packages",
        "Billing": "Charges, invoices, and payment problems",
        "Other": "Requests that fit none of the other teams"
      }
    }
  }
}

An illustrative response entry for that question is:

{
  "Team": {
    "type": "choice",
    "choice": "Returns",
    "confidence": 0.82,
    "probabilities": {
      "Returns": 0.91,
      "Shipping": 0.04,
      "Billing": 0.01,
      "Other": 0.04
    }
  }
}

JevDotNet expects a choice answer under Team. It reads the selected name, checks that it is a declared enum member (case-insensitively), and maps it to SupportTeam. For a detailed property it also maps the returned confidence and probability entries. Unknown choice names or unknown probability-option names cause a JsonException; JevDotNet does not turn them into unnamed enum numbers.

Common mistakes

  • Wrong property type: [JevChoiceQuestion<SupportTeam>] cannot map to string or JevChoice<AnotherEnum>.
  • Vague or overlapping options: distinguish each enum member with a useful [Description] and try representative inputs.
  • Using Choice for severity: if answers have a meaningful low-to-high order, Score preserves a position between levels.
  • Treating confidence as probability: use answer.Probabilities[option] for one option's probability; use answer.Confidence for the overall concentration measure.

Build the full return object · Evaluate text and use results · TypeSafe Choice reference

Clone this wiki locally