Skip to content

OxyJen v0.5.1: Deterministic DAG Runtime for AI Workflows in Java

Latest

Choose a tag to compare

@11divyansh 11divyansh released this 08 Jun 09:40

v0.5.1

Note: v0.5.0 had a JitPack caching/build issue and should be considered deprecated. Please use v0.5.1 instead.

OxyJen v0.5.1 is a major architectural shift. The project moves from a sequential chain model to a DAG-based
execution runtime, so AI workflows are no longer hidden inside a linear pipeline. They are explicit, typed, and
deterministic.

This release centers on the graph module, which is now the core of OxyJen.

Graph Module

The graph module lets you build workflows out of nodes and edges instead of one long chain. That gives you:

  • BranchNode for one-of-many routing
  • RouterNode for multi-path fan-out
  • MergeNode for fan-in and result aggregation
  • ParallelNode for pure Java concurrent tasks
  • MapNode for batch processing over collections
  • GatherNode for collecting and reshaping outputs
  • DirectEdge, ConditionalEdge, FailureEdge, CyclicEdge, and RouteEdge for explicit graph behavior
  • GraphBuilder for fluent graph construction
  • Explicit failure handling with FailureEdge and connectAnyFailureTo(...), so errors can be routed, collected,
    and handled as part of the graph instead of breaking the workflow blindly.

Small example:

  Graph graph = GraphBuilder.named("doc-flow")                                                                    
      .addNode("classify", classifyNode)                                                                          
      .addNode("branch", BranchNode.<DocType>builder()                                                            
          .when("invoice", d -> "invoice".equals(d.type())).then("invoiceExtract")                                
          .when("contract", d -> "contract".equals(d.type())).then("contractExtract")                             
          .orElse("genericExtract")                                                                               
          .build("branch"))                                                                                       
      .addNode("invoiceExtract", invoiceNode)                                                                     
      .addNode("contractExtract", contractNode)                                                                   
      .addNode("genericExtract", genericNode)                                                                     
      .addNode("router", RouterNode.<Document>builder()                                                           
          .route("summary", d -> true, "summaryNode")                                                             
          .route("risk", d -> true, "riskNode")                                                                   
          .build("router"))                                                                                       
      .addNode("merge", mergeNode)                                                                                
      .connect("classify", "branch")                                                                              
      .connect("branch", "invoiceExtract")                                                                        
      .connect("branch", "contractExtract")                                                                       
      .connect("branch", "genericExtract")                                                                        
      .connect("invoiceExtract", "router")                                                                        
      .connect("contractExtract", "router")                                                                       
      .connect("genericExtract", "router")                                                                        
      .connect("router", "summaryNode")                                                                           
      .connect("router", "riskNode")                                                                              
      .connect("summaryNode", "merge")                                                                            
      .connect("riskNode", "merge")  

What’s new

  • DAG graph execution with explicit topology
  • Typed node-based workflows instead of sequential-only chains
  • Structured extraction with SchemaNode
  • Validation-aware SchemaResult and FieldError
  • Retry/fallback/timeout control with LLMChain
  • Gemini support through LLM.gemini(...) and Gemini transport classes
  • Failure routing with connectOnFailure(...) and connectAnyFailureTo(...)
  • Runnable examples for document extraction and batch extraction

Why this matters

v0.5.1 is the point where OxyJen becomes a deterministic AI execution runtime, not just a sequence of model
calls.

That means:

  • branching is explicit,
  • parallelism is controlled,
  • failures are visible,
  • schema outputs are typed,
  • and workflows are easier to test and reason about.

Who this is for

This release is for Java developers building:

  • document extraction systems
  • support triage pipelines
  • batch enrichment workflows
  • compliance and review flows
  • deterministic AI systems with real execution control

Summary

The biggest change in v0.5.1 is the shift from sequential chains to DAG execution. That is the foundation for
the next phase of OxyJen, including observability, persistence, checkpointing, and metrics.