TypeSafe maintains Python and JavaScript/TypeScript clients. Every other language depends on a community port, and that label covers a wide range: a careful reimplementation of the official retry and error behavior, a thin value-object wrapper, a generated Swift package, or a separate Go server with a compatibility endpoint. The question is how much of the official contract the port preserves, and what happens when it drifts.
.NET: two different bets
TypeSafeSharp is the parity bet. It is an unofficial .NET client that ports the official JS and Python behavior (retries, errors, key handling) to netstandard2.0 and net10.0, with typed Choice and Noul answers, dependency injection, and OpenTelemetry tracing. netstandard2.0 covers .NET Framework 4.7.2+ and .NET 8/9; the API is callable from C# 7.3, without records or init setters. net10.0 is trimming- and NativeAOT-clean.
EvaluateManyAsync runs batches with bounded concurrency (default 4) and yields results as they finish, with an index back to the input; one item's failure comes back as that item, while a rejected key or wrong model ends the loop. AddTypeSafe wires DI over IHttpClientFactory, and a missing key stops the app at startup. BaseUrl and DefaultModel point the client at another /v1/systemone gateway.
The caveats matter. It is unofficial and can lag a TypeSafe release; the stated mitigations are a nightly OpenAPI diff and a weekly live-test job. And retried timeouts can bill twice because the API has no idempotency key. That is true of every client here, but TypeSafeSharp says it out loud.
decisionkit-dotnet makes a different bet: keep the domain independent of the vendor. Four packages with a one-way dependency; DecisionKit.Core has no Jev, HTTP, or JSON knowledge, and only the Jev, Extensions, and Testing packages point at it. A question fixes the type of its answer at compile time, unknown response shapes are preserved as raw data, and failures are distinguishable as validation, auth, transport, timeout, cancellation, rate limiting, or serialization.
Retries are off by default because Jev has no idempotency mechanism: a repeated call is a second evaluation, billed again, and may answer differently. The testing package replaces the provider with fakes, injected failures, and a TimeProvider, so tests run with no HTTP. It is pre-release, the API is unstable until 1.0.0, and it targets net8.0/net10.0. Use TypeSafeSharp for parity; use DecisionKit if the abstraction is the point and you can pin a pre-release.
Java: the SDK and the CLI
TypeSafe AI Java SDK is a Java 21 client with sync and async HTTP clients, typed Noul, Choice, and Score questions, JSON models, error mapping, and retries. A second Maven module auto-configures Jev as a Spring AI Model. It is MIT-licensed but not on Maven Central; install ai.typesafe 0.1.0-SNAPSHOT locally. Snapshot status is the adoption cost.
typesafe-java is a different community client, published on Maven Central as io.github.dfa1.typesafe-java with core, mapping, and CLI modules. It reads the token from ~/.typesafe.apikey or an environment variable, maps a Java record annotated with @Noul directly to a typed result, and ships a self-contained CLI uber-jar whose --min thresholds make it exit 1 on failure: a pass/fail gate for a shell script or CI job.
It also runs local Clef and Laya models through ONNX Runtime behind the same client, with no API key. The README compares each local model against jev-1.13.0 on 104 cached requests; it lists Laya fp32 at 85% and 64% agreement on two measures. Those are the author's measurements, and the excerpt truncated the full table.
| Java option | Strength | Cost |
|---|---|---|
| TypeSafe AI Java SDK | Official-behavior parity, Spring AI starter | Snapshot, local Maven install |
| typesafe-java | Maven Central, typed records, CLI gate, local models | Community; agreement numbers are author's |
Rust: the closest port
typesafe-rust-sdk is the Rust sibling of the official clients. The async client is default and needs a tokio runtime with the time driver; a blocking client must not be called inside an async runtime. Question types cover Noul, Choice, Score, and BoxQuestion for image localization. Features select rustls or native-tls and gzip or zstd compression.
Its behavior follows the official Python SDK: the same environment variables and defaults, the same retry policy, and the same error kinds. Every call returns a typed Error with kind, status, message, and request id. Retries are up to 2 on 408, 429, 5xx, timeouts, and connection failures, with 500 ms backoff doubling to 5 s and a 30 s budget per call.
All models take 64k tokens per request and 32k per question; CallOptions::long_context raises both to 262k at the same price, slower and less accurate. Box questions need jev-1.14.0 or jev-preview; jev-latest still pointed at jev-1.13.0 on 16 October 2026. Images are PNG or JPEG, 280 to 1568 pixels per side, 16 MiB per file and 32 MiB per request. The README calls the client unofficial and notes that images and Box are experimental.
Go and PHP: a server and two wrappers
laya-go is not a TypeSafe SDK. It is a Go server, agent CLI, and MCP for Laya, an open System 1 model that scores structured features and returns ranked pattern probabilities. laya-deploy listens on 0.0.0.0:7710; agents call decide over MCP, HTTP, or CLI and take top.id as the action. MCP exposes laya_health, laya_models, and laya_decide, and jev_compat: true restores legacy JEV semantics on decision calls. The README positions it as replacing legacy JEV and includes a migration guide, but the catalog carries no benchmark or accuracy numbers, and the microsecond-to-millisecond latency is the project's own framing.
PHP has two wrappers with different scopes. jev-php is a small PHP 8.1 library extracted from LLPhant: typed NoulAnswer, ChoiceAnswer, and ScoreAnswer, a JEV_API_KEY default, optional LayaConfig, and LGPL-2.1. It documents no retry, batching, or streaming behavior, so production hardening is yours. TypeSafe PHP & Laravel SDK is broader: PHP 8.2+, PSR-18/PSR-17, Laravel 11/12 auto-discovery, a TypeSafe facade, and retry defaults of 2 attempts, 500–5000 ms backoff, jitter 0.25, and 408/429/500–599. Its core deliberately never reads the environment; only the Laravel bridge does, so outside Laravel you pass the key, base URL, and timeout explicitly. Answers are immutable, missing keys throw on get(), and the key is redacted from var_dump() and json_encode().
Swift: a generated provider
SwiftAITypeSafeAI is a Swift-native port of @ai-sdk/typesafe-ai, distributed as a generated SwiftPM package at version 1.0.0. TypeSafeAIProvider accepts an API key plus custom base URL, headers, environment override, and an injected AITransport; the model conforms to the common SwiftAIProvider protocols used across the SwiftAISDK ports. It is a client provider, not an inference engine: there is no bundled decision model.
The distribution detail matters. The package is generated, and source, issues, and contributions belong in the canonical SwiftAISDK repository. Patching the generated repository is the wrong fix; upstream it or pin a version that contains the change.
How to choose
The official SDKs are the baseline. A port is worth adopting when it preserves the contract you depend on: retry policy, error taxonomy, answer types, and model pinning. Ask for the version it tracks, the test story, and the license. Then run the same small labeled set through the port and the official client and compare answers. A client SDK is not a drop-in model swap unless the behavior survives.
A wire-compatible endpoint only proves that the JSON parses. The open reimplementations vary in question support and calibration, and Serving System One Locally covers the local-server path. If the port points at a different host, keep the base URL and the model id in the same configuration so you can see the whole route.
Pin the port and the model, and write down which official version it claims to follow. The language is the easy part; the contract is the work.