Skip to content

Typed Choice answers, as the JS SDK's ChoiceResponse<T> #10

Description

@xbt-a4224j

Proposal to type Choice answers from systemOne calls. Feedback welcome.

Today response.choice("dept") returns a ChoiceAnswer whose choice() is a String and whose probabilities() is Map<String, Double> (ChoiceAnswer.java:15). A misspelled label compiles and is silently never true; a switch needs a default; the enum the caller already has is re-derived by hand.

The JS SDK types the labels at compile time: choice(instructions, {…}) captures them (questions.ts:55), ChoiceResponse<T> has choice: keyof T (types.ts:80), ResultFor<T> maps question to answer (types.ts:118).

Java version: the same type parameter on the question and its answer. Choice<E> from an enum's constants, ChoiceAnswer<E> read back from the question. Java can't type map keys off a literal, so the id is still a string at the read.

// today
Choice dept = Choice.of("Which team should handle this?", "BILLING", "SHIPPING", "SECURITY");
TypeSafeResponse response = client.systemOne(Map.of("email", email), Map.of("dept", dept));

ChoiceAnswer d = response.choice("dept");
d.choice();                           // "SECURITY"                                   String
d.probabilities();                    // {BILLING=0.48, SHIPPING=0.01, SECURITY=0.51} Map<String, Double>
d.choice().equals("BILLNG");          // false, compiles
d.probabilities().get("security");    // null
switch (d.choice()) {
    case "BILLING" -> ...; case "SHIPPING" -> ...; case "SECURITY" -> ...;
    default -> ...;                   // required
}
// with Choice<E>
enum Dept { BILLING, SHIPPING, SECURITY }

Choice<Dept> dept = Choice.of("Which team should handle this?", Dept.values());
TypeSafeResponse response = client.systemOne(Map.of("email", email), Map.of("dept", dept));

ChoiceAnswer<Dept> d = response.choice("dept", dept);
d.choice();                           // Dept.SECURITY                                Dept
d.probabilities();                    // {BILLING=0.48, SHIPPING=0.01, SECURITY=0.51} Map<Dept, Double>
d.choice() == Dept.BILLING;           // == on the enum; == "BILLNG" is a compile error
d.probabilities().get(Dept.SECURITY); // keyed by Dept
switch (d.choice()) {                 // exhaustive: a missing case is a compile error
    case BILLING -> ...; case SHIPPING -> ...; case SECURITY -> ...;
}
  • Additive on the way in: Choice.of(…, String...) and the builder still infer Choice<String>, and response.choice("dept") still returns the String form.
  • Breaking: ChoiceAnswer gains a type parameter; a raw ChoiceAnswer used as a String needs <String> or var, and code compiled against 0.3.0 needs a recompile.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions