TypeScript
There is no embedded TypeScript or Node SDK in 0.2.1. Run the decision service next to your application and call its HTTP API. This page shows the types and calls to use.
Status#
An embedded TypeScript SDK generated from the pack manifest is Planned. Until it ships, TypeScript and Node callers use the local service:
- Start the service
Run
helixor-pack servefor a compiled pack (see CLI), orstart_serverfrom Python for the built-in example pack. It binds loopback by default. If callers on other hosts need it, give it a bearer token (HELIXOR_SERVICE_TOKEN) and sendAuthorization: Bearerfrom your client. - Call it with
fetchNode 18 and later include
fetch, so you need no dependencies.
Types#
These interfaces mirror the JSON the service returns. See the Python reference for what each field means.
export interface RegulatoryTrigger {
rule_id: string;
law: string;
severity: "FATAL" | "WARNING";
matched_items: string[]; // raw sensitive values: never log
}
export interface CounterfactualRemedy {
clean_text: string;
redactions_count: number;
redacted_categories: string[];
}
export interface DecisionResult {
pack_id: string;
action: string;
invariants_passed: boolean;
reason: string;
triggers: RegulatoryTrigger[];
remedy: CounterfactualRemedy;
latency_us: number;
tokens_spent: number;
egress_bytes: number;
receipt_hash: string;
license_status: string | null;
active_key_id: string | null;
active_epoch: number | null;
edition: string;
upgrade_notice: string | null;
}
export interface StreamChunkResult {
chunk_index: number;
text: string;
is_final: boolean;
redacted: boolean;
blocked: boolean;
action: string;
reason: string | null;
triggers: RegulatoryTrigger[];
}
Evaluate a payload#
import type { DecisionResult } from "./helixor-types";
const BASE_URL = process.env.HELIXOR_SERVICE_URL ?? "http://127.0.0.1:18734";
export async function evaluate(text: string): Promise<DecisionResult> {
const res = await fetch(`${BASE_URL}/v1/evaluate`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ text }),
});
if (!res.ok) {
throw new Error(`evaluate failed: HTTP ${res.status} ${await res.text()}`);
}
return (await res.json()) as DecisionResult;
}
const result = await evaluate("Customer card 4111-1111-1111-1111, contact jane@example.com");
const mustBlock = result.triggers.some((t) => t.severity === "FATAL");
if (mustBlock) {
console.log("blocked", result.action, result.receipt_hash);
} else {
console.log("forward", result.remedy.clean_text);
}
HELIXOR_SERVICE_URL is a name used by this example, not a variable the runtime reads. Fail closed: if the service is unreachable or returns an error, do not forward the payload.
Read an SSE stream#
POST /v1/evaluate/stream takes the whole text and splits it on the server, so it suits testing more than live model output. For live tokens, keep the /v1/ws/decision WebSocket open and send stream_chunk messages. Both are described in the HTTP API reference.
import type { StreamChunkResult } from "./helixor-types";
const res = await fetch(`${BASE_URL}/v1/evaluate/stream`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ text: "Call (415) 555-0100 today.", chunk_size: 8 }),
});
const reader = res.body!.pipeThrough(new TextDecoderStream()).getReader();
let buffer = "";
for (;;) {
const { value, done } = await reader.read();
if (done) break;
buffer += value;
let sep;
while ((sep = buffer.indexOf("\n\n")) >= 0) {
const line = buffer.slice(0, sep).trim();
buffer = buffer.slice(sep + 2);
if (!line.startsWith("data: ")) continue;
const chunk = JSON.parse(line.slice(6)) as StreamChunkResult;
if (chunk.blocked) throw new Error(`stream blocked: ${chunk.action}`);
process.stdout.write(chunk.text);
}
}