Skip to content

Latest commit

 

History

28 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Jev Java SDK

Idiomatic Java 17+ client library for TypeSafe AI's Jev System One decision engine.

Installation

Maven

<dependency>
    <groupId>io.github.olti1947</groupId>
    <artifactId>jev-java</artifactId>
    <version>2.0.0</version>
</dependency>

Gradle

implementation 'io.github.olti1947:jev-java:2.0.0'

Quick Start

JevClient jev = JevClient.create(System.getenv("TYPESAFE_API_KEY"));

JevResponse response = jev.evaluate(
    "Cancel my subscription immediately!",
    List.of(
        new Choice("intent", "Select classification", List.of("billing", "support", "cancel")),
        new Noul("is_angry", "Is the customer expressing anger?")
    )
);

response.choice("intent").choice();        // "cancel"
response.choice("intent").probabilities(); // {billing=0.01, support=0.0, cancel=0.99}
response.noul("is_angry").noul();          // 0.79
response.noul("is_angry").isTrue(0.7);     // true

Structured instructions and criteria

Everywhere a primitive takes a string, it also accepts a structured value. Plain strings keep working exactly as before; use structured values when you need to give Jev richer context. See the advanced primitives docs.

// Structured instructions: any map (question, focus, inspect, field, ...)
Noul invoiceCheck = Noul.builder("invoice_number_is_correct")
    .instructions(Map.of(
        "field", Map.of("name", "invoice_number", "type", "string"),
        "extracted_value", "4471",
        "question", "Does `extracted_value` match the `field` as it appears in `source_text`?"))
    .build();

// Choice options with what / not_for / examples boundaries
Choice department = Choice.builder("department")
    .instructions(Map.of("question", "Which team should handle this message?"))
    .candidate("billing", Rubric.of("Charges, invoices, refunds", "I was charged twice")
        .notFor("Order tracking or account access"))
    .candidate("orders", "Order status, delivery, or returns")   // strings still work
    .candidate("other")                                          // no description
    .build();

// Score levels with a summary and signals (levels run low -> high)
Score prScope = Score.builder("pr_scope")
    .instructions("How focused is this pull request on a single change?")
    .addCriteriaLevel(ScoreLevel.of("One change, clearly stated", "A single fix or feature"))
    .addCriteriaLevel(ScoreLevel.of("Several changes bundled together", "Two or more unrelated fixes"))
    .build();

// Noul true / false boundaries
Noul credentials = Noul.builder("requests_credentials")
    .instructions("Does the message ask for a sensitive credential?")
    .criteria(
        Rubric.of("Asks the recipient to send a password or one-time code", "Send us the 6-digit code"),
        Rubric.of("No sensitive credential is requested", "Reset your password from settings"))
    .build();

Rubric and ScoreLevel are typed helpers, but any Map/List works too, so nested category maps and custom keys are supported. Constructors taking plain strings (new Noul(name, "question"), new Score(name, "q", "low", "high")) are unchanged.

Building a reusable request

evaluate(state, primitives) is convenient for a one-off call, but sometimes you want to assemble a request in one place (e.g. adding primitives conditionally) and execute it in another, or reuse the same request. Build a JevRequest and hand it to the client:

JevRequest request = JevRequest.builder()
    .state(sourceStatePayload)
    .addPrimitive(invoiceCheck)
    .addPrimitive(departmentChoice)
    .build();

JevResponse response = jev.evaluate(request);
CompletableFuture<JevResponse> future = jev.evaluateAsync(request);

builder() defaults model to jev-latest (override with .model(...)) and build() throws JevValidationException if no primitives were added or if two primitives share a name.

Vercel AI Gateway

Jev is also available through the Vercel AI Gateway, which is handy while direct TypeSafe API access is waitlisted. Use an AI Gateway API key (vck_...) and enable gateway mode on the builder — the rest of the API is unchanged:

JevClient jev = JevClient.builder()
    .apiKey(System.getenv("AI_GATEWAY_API_KEY"))
    .vercelGateway()
    .build();

Notes:

  • The gateway model id defaults to typesafe-ai/jev and can be overridden with .gatewayModel(...).
  • In gateway mode the model is always the client's .gatewayModel(...), sent as a header; a JevRequest built with .model(...) is only respected outside gateway mode.

Maven Central License: MIT Build Status

About

Idiomatic Java SDK for TypeSafe AI Jev System One decision engine

Resources

Contributing

Stars

6 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages