Java
The Java client generated from a pack manifest: its classes, methods and records. Clients are generated per pack; the one documented here is generated from the built-in example pack's manifest (data protection, compliance.regulatory_pii_guard.v1), so its class names and state fields come from that pack. Read the status note first. The client compiles against a runtime artifact that has not shipped.
Status in 0.2.1
The generated Java sources are not yet distributed. Their pom.xml depends on ai.helixor:helixor-runtime:1.0.0, which provides ai.helixor.runtime.HelixorNativeRuntime. That artifact is Planned and is not published, so the client does not build today.
To call the runtime from Java now, run the decision service (helixor-pack serve, or start_server from Python) and call the HTTP API with java.net.http.HttpClient. See Services.
Coordinates#
groupId ai.helixor artifactId regulatorypiiguard-decision-sdk version 1.0.0 Java 17 depends on ai.helixor:helixor-runtime:1.0.0 (Planned)
Packages#
| Package | Contents |
|---|---|
ai.helixor.runtime.regulatorypiiguard.client | RegulatoryPiiGuardClient |
ai.helixor.runtime.regulatorypiiguard.model | Records: RegulatoryPiiGuardState, DecisionResult, NecessaryCause, Counterfactual, TrueUpReport |
ai.helixor.runtime.regulatorypiiguard.playbook | RegulatoryPiiGuardPlaybook, the rules compiled to Java |
RegulatoryPiiGuardClient#
Implements AutoCloseable. It decides on a RegulatoryPiiGuardState of six booleans that you have already extracted; it does not scan text.
RegulatoryPiiGuardClient(Path bundlePath) throws IOException
Creates its own runtime. If bundlePath is not null, the bundle is loaded from it. The pack ID is fixed to compliance.regulatory_pii_guard.v1.
No builder
The client has no builder() and no nativeLibPath option. Use one of the two constructors above.
DecisionResult decide(RegulatoryPiiGuardState state) DecisionResult decide(RegulatoryPiiGuardState state, String action)
Evaluates one state and measures latency with System.nanoTime(). The one-argument form uses "permit_clean_payload" as the action. executionMode is "graalvm_panama_native" or "embedded_bytecode".
TrueUpReport getAuditReport()
Returns the runtime's usage report. If the runtime returns none, you get an empty report with tier launch_trial.
void close()
Does nothing; the runtime manages its own lifecycle.
Records#
public record RegulatoryPiiGuardState(
boolean hasSsn, boolean hasCreditCard, boolean hasHealthRecord,
boolean hasEmail, boolean hasPhone, boolean hasIp) {
public static Builder builder(); // setters named after each field, then build()
public String toJson(); // {"has_ssn":true,...}
}
public record DecisionResult(
String packId, String action, String verdict, double confidence,
String proofSha256, double latencyUs, String executionMode,
List<NecessaryCause> necessaryCauses, Counterfactual counterfactual) {
public boolean isApproved(); // "approve".equalsIgnoreCase(verdict)
}
public record NecessaryCause(String factor, Object observedValue,
Double threshold, String direction, Double distanceToBoundary) {}
public record Counterfactual(String remedy, String targetFactor,
Object requiredValue, Double delta, double feasibility) {}
public record TrueUpReport(long totalDecisions, long peakHourlyVelocity,
String merkleRoot, double estimatedTrueUpUsd, String activeEnclaveUuid, String tier) {}
The state record has a builder; the client does not.
Example#
This is how the client is meant to be used once the runtime artifact ships.
import ai.helixor.runtime.regulatorypiiguard.client.RegulatoryPiiGuardClient;
import ai.helixor.runtime.regulatorypiiguard.model.RegulatoryPiiGuardState;
import ai.helixor.runtime.regulatorypiiguard.model.DecisionResult;
// bundlePath: the bundle location defined by the runtime artifact (Planned)
try (var client = new RegulatoryPiiGuardClient(bundlePath)) {
var state = RegulatoryPiiGuardState.builder()
.hasSsn(true).hasCreditCard(false).hasHealthRecord(false)
.hasEmail(true).hasPhone(false).hasIp(false)
.build();
DecisionResult result = client.decide(state);
boolean mustBlock = "refuse".equalsIgnoreCase(result.verdict());
}
Known issues in 0.2.1
The generated sources have these defects:
isApproved()is false for clean payloads. The generatedRegulatoryPiiGuardPlaybookreturns verdict"compliant"when nothing fires, soisApproved()(which checks for"approve") returnsfalse. Test for"refuse"instead, as in the example.- Any failure reports as an SSN block. The playbook returns action
block_glba_ssn_leakagefor every failure, whichever rule fired. (It now checks all six fields, includinghasPhoneandhasIp, and throwsIllegalArgumentExceptionwhen a field is missing or not a boolean.) - The action argument is ignored.
decide(state, action)does not passactionto the runtime. - Counterfactuals are mostly empty. Only
remedyis filled in.targetFactoris""and the numeric fields arenull. - The playbook's
merkleRoot()is a placeholder value, not a digest of the pack.
Fixed in the SDK generator, not yet in the published sources. The generator on main emits a client where decide(state) takes no action argument and the first hard rule that fires sets the action; verdict is approve or refuse and isApproved() agrees with it; every firing rule is a NecessaryCause that names its rule; counterfactual.changes() has one change per cause; the proof is a SHA-256 per decision over the pack ID, action, verdict and state; and getAuditReport() throws AuditReportUnavailableException when no native library is loaded. It also refuses to generate from a manifest without a well-formed merkle_root. The sources in sdks/java have not been regenerated with it, and the runtime artifact is still not published, so the status note at the top of this page still applies. This describes the generated source; it cannot be compiled until that artifact is available.
Calling the HTTP API from Java today#
import java.net.URI;
import java.net.http.*;
var http = HttpClient.newHttpClient();
var body = "{\"text\": \"Employee note: SSN is 123-45-6789.\"}";
var req = HttpRequest.newBuilder(URI.create("http://127.0.0.1:18734/v1/evaluate"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
var res = http.send(req, HttpResponse.BodyHandlers.ofString());
// res.body() is the DecisionResult JSON; read "action" and "remedy.clean_text"