Skip to main content
Skip to Content
DocsCross-Runtime SDKs

A flow you design in Heliox doesn’t have to stay in Heliox. Export it once, and the same DAG runs on any of three independent SDK runtimes — TypeScript, Java, or Python — with the execution semantics that matter (ordering, output, tool calls, loops) proven identical across all three.

The shape of the workflow

  1. Design a flow on the canvas or with Text-to-Flow (see Flow Design).
  2. Export it to a portable HelioxFlowExport — a .flow.json file. See API Reference for the exact schema.
  3. Hand that file to whichever runtime fits your deployment: keep it in the desktop app and serve it (see Serve & Deploy), or load it directly from a Java or Python service you already run.

The export format is intentionally vendor-neutral: step ids, the dependency graph, prompts, flattened system prompts, tool names, contracts, and model overrides all round-trip exactly. It’s the interchange layer that lets one design surface (the canvas) feed three execution runtimes without re-authoring the flow per target language.

Running a flow per runtime

TypeScript

The TypeScript runtime is the one built into Heliox itself. The straightforward path is heliox serve (see Serve & Deploy), which loads a .flow.json, validates its DAG, and executes it on request. Programmatically, the same execution core is importFlow (deserialize the export) followed by the flow executor that walks the DAG.

Java

The Java runtime (sdk/java in the heliox-ide repository, Maven coordinates io.heliox:heliox-sdk-java, Java 21) centers on two classes:

  • HelioxRuntime — the entry point and dependency root. Configure it with a builder: an LLM provider, any @HelioxTool-annotated tool objects, optional registered flows, then call .flow(name) to begin an execution.
  • FlowExecutor — orchestrates a FlowDefinition as a DAG. Dependency-free steps start immediately; a dependent step’s future is composed as allOf(parents).thenCompose(...), so independent branches genuinely run concurrently while shared step outputs stay race-free in a concurrent map. execute() returns a single typed sink; executeMultiSink() supports multiple typed outputs; executeAllText() is the canonical path for schema-less flows (raw text per step, no JSON-schema extraction).
HelioxRuntime runtime = HelioxRuntime.builder() .llmProvider(new OpenAiProvider(apiKey)) // or MimoProvider / a custom OpenAiCompatibleProvider subclass .registerTool(new MyTools()) // @HelioxTool-annotated methods .build(); var result = runtime.flow("my-flow") .withContext("input", "some value") .executeAsync();

Build it locally with mvn install -f sdk/java/pom.xml to place heliox-sdk-java in your local Maven repository, then depend on that coordinate from your own project.

Python

The Python runtime (sdk/python in the heliox-ide repository, package name heliox-sdk, requires Python 3.10+, zero runtime dependencies) exposes FlowExecutor with the same shape as its Java counterpart:

from heliox_sdk import FlowExecutor, FlowImport, StepExecutor flow = FlowImport.from_canonical_file("my-flow.flow.json") executor = FlowExecutor(StepExecutor(provider=my_provider)) trace = executor.execute_all_text_trace(flow)

execute_all_text / execute_all_text_trace mirror the Java runtime’s executeAllText — schema-less, raw per-step text output, in DAG order. Install it locally with pip install ./sdk/python (or pip install -e sdk/python for development).

The conformance story

Three independently-implemented runtimes are only as trustworthy as their agreement with each other. Heliox’s SDKs are conformance-verified across TypeScript, Java, and Python for DAG order, text output, typed-output rule, tool-calling, and contract/model round-trip; loop parity proven in TS + Java.

That guarantee is backed by a shared set of golden fixtures (canonical .flow.json files, scripted LLM responses, and expected traces) that all three runtimes’ test suites execute against:

GuaranteeWhat’s actually checked
DAG orderAll three runtimes reproduce the same deterministic topological order (Kahn’s algorithm, ties broken by step id ascending) over a shared canonical flow.
Text outputByte-identical per-step text output for schema-less flows — proven against a shared golden trace, not just eyeballed.
Typed-output ruleBoth runtimes propagate raw provider text by default; JSON-schema typed extraction is an explicit opt-in, never a silent default divergence between runtimes.
Tool-callingA real tool is actually invoked in each runtime (not bypassed by a scripted shortcut) — same arguments in, same result threaded back, same post-tool output.
Contract/model round-tripA step’s contract and per-step model override are carried opaquely through export/import and survive byte-for-byte, even though this format layer never interprets them.
Loop parity (TS + Java)The bounded loop-back expansion algorithm produces the same per-iteration execution trace in both runtimes.

Each runtime’s proof lives alongside its code: the TypeScript suite in src/main/flow-export/*.test.ts, the Java suite in CrossRuntimeConformanceTest, and the Python suite in sdk/python/tests/test_cross_runtime_conformance.py. All three must stay green before any change to the shared fixtures merges.

Versioning

The export format itself is versioned (HelioxFlowExport.version, currently "1") independently of each SDK’s own package version — a flow exported today stays loadable by future runtime releases that support format version 1. Bounded loops in the wire format require heliox-sdk0.2.0 on the consuming side.

Last updated on