Java 21 client for the TypeSafe API. Send a state (any JSON value)
plus a set of Noul/Choice/Score questions, get back typed answers.
Save a token to ~/.typesafe.apikey first — either way below picks it up automatically.
ApiKey token = ApiKey.fromDefaultFile(); // reads ~/.typesafe.apikey
// or: ApiKey.fromEnv(); // reads the TYPESAFE_API_KEY environment variable
TypeSafeClient client = DefaultTypeSafeClient.builder().apiKey(token).build();
EvaluateRequest request = EvaluateRequest.of(
Content.text("Help! My payouts have been failing for 3 days."),
Map.of("is_urgent", Question.noul("Does this convey urgency?")));
Answer.Noul answer = client.evaluate(request).nouls().get("is_urgent");
answer.noul(); // e.g. 0.92Or skip the Map/cast with a typed record (typesafe-java-client-mapping):
record UrgencyCheck(@Noul("Does this convey urgency?") double isUrgent) {
}
MappingTypeSafeClient client = DefaultTypeSafeClient.builder().apiKey(token).build(MappingTypeSafeClient::decorate);
UrgencyCheck result = client.evaluateTyped(
Content.text("Help! My payouts have been failing for 3 days."), UrgencyCheck.class);
result.isUrgent(); // e.g. 0.92See Install below to add it as a dependency, or the tutorial for the full walkthrough — including every way to provide the token, in how-to.md.
No Java coding required — the cli module builds a self-contained uber-jar, handy for wiring a
check into a Jenkins job, a shell script, or any other CI pipeline without writing a line of
Java. Download it from
Maven Central
(under the all classifier — the plain artifact is just this module's own classes, not
runnable on its own; the latest release
notes link straight to the jar), or build it from source:
./mvnw -pl cli -am package -DskipTestsEither way, run it the same way:
java -jar typesafe-java-cli-*-all.jar \
--state "My card was charged twice." \
--noul "urgent=Is this urgent?" \
--min "urgent=0.5" || echo "not urgent enough"Exits 1 if --min's threshold isn't met, so it doubles as a pass/fail gate — stdout stays
silent by default; add --print urgent for the value or --verbose for the full response as
JSON. See how-to.md for the
full flag reference (--choice/--score, --print, --verbose, ...).
Every model we tested behind the same TypeSafeClient, measured on an Apple M5 (32 GB). "Agrees with Jev"
compares answers with the real jev-1.13.0 on 104 cached requests (yes/no on the same side of 0.5 · same choice).
| Model | Runs on | Download | Memory | Seconds per request (1–3 questions) | Agrees with Jev |
|---|---|---|---|---|---|
TypeSafe API (jev-1.13.0) |
api.typesafe.ai |
— | — | ≈ 0.35 (network included) | — |
| Laya fp32 | client-local, CPU |
1.7 GB | not measured | 0.055–0.165 | 85% · 64% |
| Laya fp16 | client-local, CPU |
0.85 GB | not measured | 0.11–0.5 (2–3× fp32, same answers) | as fp32 |
| Qwen2.5-1.5B, 4-bit | client-local, CPU |
1.8 GB | not measured | 0.8–2.1 | 80% · 68% |
| Clef-flash (9B), bf16 as published | client-local, CPU |
19 GB | 20 GB peak | ≈ 60 | not measured |
| Clef-flash, 4-bit | client-local, CPU |
19 GB + 4.4 GB | 7.7 GB | 7–13 | not measured |
| Clef-flash, 4-bit | client-local, Apple GPU (loadOnGpu) |
19 GB + 4.4 GB | 7.7 GB | 2–4 | not measured |
| Clef-flash, MLX 4-bit | local MLX server, regular client | 6.2 GB | ≈ 7 GB | ≈ 0.55 | 95% · 88% |
Laya is the fastest; Clef-flash is the closest to Jev, at the cost of size. The 4-bit ONNX graph keeps Clef-flash's embeddings and output layer in Cloudflare's original bf16 files, so those 19 GB stay on disk next to it (hard-linked, not copied); the MLX port doesn't need them. Setup for each: run without the API and Clef-flash on a Mac with MLX.
Maven, via the BOM (see the Maven Central badge above for the latest version):
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.github.dfa1.typesafe-java</groupId>
<artifactId>typesafe-java-bom</artifactId>
<version>0.7.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.github.dfa1.typesafe-java</groupId>
<artifactId>typesafe-java-client-http-jdk</artifactId>
</dependency>
<dependency>
<groupId>io.github.dfa1.typesafe-java</groupId>
<artifactId>typesafe-java-codec-jackson3</artifactId>
</dependency>
</dependencies>On Android, or anywhere else java.net.http isn't available, swap typesafe-java-client-http-jdk
for typesafe-java-client-http-okhttp.
| Module | Contains |
|---|---|
core |
the model (EvaluateRequest, EvaluateResponse, Question, Answer, ...), as plain records; no dependencies |
codec |
the Codec SPI: serialization to and from bytes; no dependencies |
client |
the TypeSafeClient interface, TypeSafeException, and the decorators that wrap any client (retries, deadline, token counting) |
codec-jackson2 / codec-jackson3 |
Codec backed by Jackson 2.x / 3.x |
client-http |
DefaultTypeSafeClient, the TypeSafeClient that calls the API, and the HttpTransport SPI |
client-http-jdk |
HttpTransport backed by java.net.http |
client-http-okhttp |
HttpTransport backed by OkHttp — an alternative for environments java.net.http doesn't cover, e.g. Android |
client-local |
LocalLayaTypeSafeClient, LocalQwenTypeSafeClient, LocalClefTypeSafeClient — evaluate in-process on ONNX Runtime instead of calling the API (Laya, Qwen2.5 or Clef-flash, from a local model directory); API parity, not model parity with Jev. See how-to; on a Mac, Clef-flash via MLX is closer to Jev (how-to) |
client-mapping |
MappingTypeSafeClient — maps a @Noul/@Choice/@Score-annotated record to/from EvaluateRequest/EvaluateResponse |
client-testkit |
RecordingTypeSafeClient/FailingTypeSafeClient, TypeSafeClient test doubles for unit tests |
bom |
dependency management for the modules above |
cli |
ad hoc checks from a terminal; runnable uber-jar under the all classifier, java -jar |
acceptance |
live-API tests only — not published |
Each module's directory, artifact (typesafe-java-<module>) and package
(io.github.dfa1.typesafe.<module>, dashes as dots) share one name. See
ADR 0003 for why it's split this way.
Structured by Diataxis:
- Tutorial — your first evaluation, end to end
- How-to — task-oriented recipes: codecs, transports, testing, the CLI, ...
- Reference — full API surface
- Explanation — design rationale
./mvnw clean verify # build + unit tests, all modules
./mvnw test -pl acceptance -am -DexcludedGroups= # + live-API acceptance tests, needs ~/.typesafe.apikeyMIT — see LICENSE.