Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
00d236d
Update 2 files
Sep 23, 2025
53d7049
Merge branch 'RobJenks:master' into master-copy
RobJenks Sep 24, 2025
595c01f
Merge branch 'RobJenks:master' into master-copy
RobJenks Sep 24, 2025
27978da
Merge branch 'RobJenks:master' into master-copy
RobJenks Sep 24, 2025
8d2f364
Merge branch 'RobJenks:master' into master-copy
RobJenks Sep 24, 2025
de33e0a
Add BPMN global variable library, extra customisation steps, and high…
Oct 5, 2025
7ea1854
Merge branch 'RobJenks:master' into master-copy
RobJenks Oct 5, 2025
e2c6ecc
Added list of inputs to HL model schema
Oct 9, 2025
e2792a8
Merge branch 'RobJenks:master' into master-copy
RobJenks Oct 28, 2025
aa1719b
Enhanced BPMN component library and enabled detail level generation
Nov 11, 2025
1de9c78
Handle missing input properties; avoid serializing empty inputs and o…
Nov 14, 2025
1ad7c0d
Merge branch 'master' into master-copy
RobJenks Nov 26, 2025
5d3289a
Merge branch 'RobJenks:master' into master-copy
RobJenks Nov 26, 2025
37a0651
Merge branch 'RobJenks:master' into master-copy
RobJenks Nov 26, 2025
2525a32
Merge master
Jan 6, 2026
f6ed3c8
Latest BPMN generation and intermediate model changes
Feb 26, 2026
7411c5b
Extended BPMN validation and generation capabilities
Mar 11, 2026
75c1f6d
Merge latest version into master
Mar 12, 2026
f48a02f
Default inputs and IR model assets
Mar 16, 2026
ad22ad4
Merge branch 'RobJenks:master' into master-copy
RobJenks Mar 19, 2026
ac7e398
Merge branch 'RobJenks:master' into master-copy
RobJenks Mar 20, 2026
7515286
Merge branch 'RobJenks:master' into master-copy
RobJenks Mar 20, 2026
277a471
Merge branch 'RobJenks:master' into master-copy
RobJenks Mar 20, 2026
1e56d0b
Merge upstream
RobJenks Mar 23, 2026
63fbf64
Merge branch 'RobJenks:master' into master-copy
RobJenks Mar 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
include:
- project: 'fp/open-source/os-ci'
file:
- '.gitlab-ci.yml'
1 change: 1 addition & 0 deletions .gs-project.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
productGuid: "product::823826"
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.apache.commons.lang3.StringUtils;
import org.rj.modelgen.bpmn.component.common.BpmnComponentVariableType;
import org.rj.modelgen.bpmn.component.common.BpmnComponentInputSourceType;
import org.rj.modelgen.llm.component.Component;
import org.rj.modelgen.llm.component.ComponentInputResolutionStrategy;

import java.util.List;
import java.util.ArrayList;
Expand Down Expand Up @@ -69,18 +72,17 @@ public String generateSerializedPromptData(BpmnComponentLibrarySerializationOpti
.collect(Collectors.partitioningBy(i -> (i.isMandatory() || i.isKeyValue())));
final var mandatory = inputs.get(Boolean.TRUE);
final var optional = inputs.get(Boolean.FALSE);
boolean shouldIncludeConstants = options.shouldIncludeConstantInputs();

if (!mandatory.isEmpty()) {
result.append("Mandatory inputs: \n").append(mandatory.stream()
.map(InputVariable::getVariableSummary)
.collect(Collectors.joining(",\n")))
result.append("Mandatory inputs: \n")
.append(serializeInputs(mandatory, 0, shouldIncludeConstants))
.append('\n');
}

if (!options.isMandatoryInputsOnly() && !optional.isEmpty()) {
result.append("Optional inputs: \n").append(optional.stream()
.map(InputVariable::getVariableSummary)
.collect(Collectors.joining(",\n ")))
result.append("Optional inputs: \n")
.append(serializeInputs(optional, 0, shouldIncludeConstants))
.append('\n');
}
}
Expand All @@ -97,16 +99,100 @@ public String generateSerializedPromptData(BpmnComponentLibrarySerializationOpti
return result.toString().trim();
}

private String serializeInputs(List<InputVariable> inputs, int level, boolean shouldIncludeConstants) {
if (inputs == null || inputs.isEmpty()) {
return "";
}

final StringBuilder sb = new StringBuilder();
for (InputVariable input : inputs) {
if (input == null) continue;

var sourceTypes = input.getAllowedInputSourceTypes();
if (!shouldIncludeConstants && sourceTypes != null && sourceTypes.size() == 1 && sourceTypes.get(0).equals(BpmnComponentInputSourceType.CONSTANT)) {
continue;
}

final String indent = " ".repeat(level * 4);
final String bullet = (level == 0) ? "- " : "* ";
String singleInput = indent + bullet + input.getName() + " (" + buildInlineInputDetails(input) + ")";
sb.append(singleInput);

final List<InputVariable> props = input.getProperties();
if (props != null && !props.isEmpty()) {
sb.append(" Object properties:\n")
.append(serializeInputs(props, level + 1, shouldIncludeConstants));
}
sb.append('\n');
}

// trim last newline
while (!sb.isEmpty() && sb.charAt(sb.length() - 1) == '\n') {
sb.setLength(sb.length() - 1);
}
return sb.toString();
}

private String buildInlineInputDetails(InputVariable input) {
final List<String> components = new ArrayList<>();

components.add(input.isMandatory() || input.isKeyValue() ? "Mandatory" : "Optional");

if (input.getType() != null) {
components.add("Type: " + input.getType().name());
}
if (StringUtils.isNotBlank(input.getDescription())) {
components.add(input.getDescription().trim());
}
if (input.getAllowedValues() != null && !input.getAllowedValues().isEmpty()) {
components.add("Allowed values: " + String.join(", ", input.getAllowedValues()));
}
if (input.getAllowedInputSourceTypes() != null && !input.getAllowedInputSourceTypes().isEmpty()) {
components.add("Allowed input source types: " + input.getAllowedInputSourceTypes().stream()
.map(BpmnComponentInputSourceType::toString)
.collect(Collectors.joining(", ")));
}

return String.join("; ", components);
}

@Override
public String defaultSerialize() {
return generateSerializedPromptData(BpmnComponentLibrarySerializationOptions.defaultOptions());
}

@JsonIgnore
public Optional<InputVariable> getInputVariable(String inputVarName) {
if (StringUtils.isBlank(inputVarName)) {
return Optional.empty();
}
return findInputVariable(requiredInputs, inputVarName);
}

private Optional<InputVariable> findInputVariable(List<InputVariable> inputs, String inputVarName) {
if (inputs == null || inputs.isEmpty()) {
return Optional.empty();
}

for (InputVariable input : inputs) {
if (input == null) continue;
if (inputVarName.equals(input.getName())) {
return Optional.of(input);
}
var nestedInput = findInputVariable(input.getProperties(), inputVarName);
if (nestedInput.isPresent()) {
return nestedInput;
}
}
return Optional.empty();
}

public static class Variable {
private String name;
private String description;
private BpmnComponentVariableType type;
private boolean keyValue;
private String resolveValue;

public Variable() {
this(null, null);
Expand Down Expand Up @@ -155,6 +241,14 @@ public void setKeyValue(boolean keyValue) {
this.keyValue = keyValue;
}

public String getResolveValue() {
return resolveValue;
}

public void setResolveValue(String resolveValue) {
this.resolveValue = resolveValue;
}

protected List<String> buildSummaryComponents() {
final List<String> components = new ArrayList<>();
if (type != null && type != BpmnComponentVariableType.String) {
Expand All @@ -178,20 +272,32 @@ public String getVariableSummary() {

public static class InputVariable extends Variable {
private boolean mandatory;
private String defaultValue;
private String alias;
private List<InputVariable> properties;
private List<String> allowedValues;
private List<BpmnComponentInputSourceType> allowedInputSourceTypes;
private ComponentInputResolutionStrategy resolutionStrategy;

public InputVariable() {
this(null, null);
}

public InputVariable(String name, String description) {
this(name, description, BpmnComponentVariableType.String, false, List.of());
this(name, description, BpmnComponentVariableType.String, false, null, null, List.of(), List.of(), List.of(), null);
}

public InputVariable(String name, String description, BpmnComponentVariableType type, boolean mandatory, List<String> allowedValues) {
public InputVariable(String name, String description, BpmnComponentVariableType type, boolean mandatory, String defaultValue, String alias,
List<InputVariable> properties, List<String> allowedValues, List<BpmnComponentInputSourceType> allowedInputSourceTypes,
ComponentInputResolutionStrategy resolutionStrategy) {
super(name, description, type);
this.mandatory = mandatory;
this.defaultValue = defaultValue;
this.alias = alias;
this.properties = properties;
this.allowedValues = allowedValues;
this.allowedInputSourceTypes = allowedInputSourceTypes;
this.resolutionStrategy = resolutionStrategy;
}

public boolean isMandatory() {
Expand All @@ -202,6 +308,30 @@ public void setMandatory(boolean mandatory) {
this.mandatory = mandatory;
}

public String getDefaultValue() {
return defaultValue;
}

public void setDefaultValue(String defaultValue) {
this.defaultValue = defaultValue;
}

public String getAlias() {
return alias;
}

public void setAlias(String alias) {
this.alias = alias;
}

public List<InputVariable> getProperties() {
return properties;
}

public void setProperties(List<InputVariable> properties) {
this.properties = properties;
}

public List<String> getAllowedValues() {
return allowedValues;
}
Expand All @@ -210,18 +340,28 @@ public void setAllowedValues(List<String> allowedValues) {
this.allowedValues = allowedValues;
}

@Override
protected List<String> buildSummaryComponents() {
final List<String> components = super.buildSummaryComponents();
if (allowedValues != null && !allowedValues.isEmpty()) {
components.add("Allowed values: " + String.join(", ", allowedValues));
public List<BpmnComponentInputSourceType> getAllowedInputSourceTypes() {
return allowedInputSourceTypes;
}

public void setAllowedInputSourceTypes(List<BpmnComponentInputSourceType> allowedInputType) {
this.allowedInputSourceTypes = allowedInputType;
}

public Boolean isAllowedInputSourceType(String type) {
if (allowedInputSourceTypes == null || allowedInputSourceTypes.isEmpty()) {
return true;
}
return components;
return allowedInputSourceTypes.stream()
.anyMatch(t -> t.name().equalsIgnoreCase(type));
}

@JsonIgnore
public String getVariableSummary() {
return super.getVariableSummary();
public ComponentInputResolutionStrategy getResolutionStrategy() {
return resolutionStrategy;
}

public void setResolutionStrategy(ComponentInputResolutionStrategy resolutionStrategy) {
this.resolutionStrategy = resolutionStrategy;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@
import org.rj.modelgen.llm.component.ComponentLibrary;
import org.rj.modelgen.llm.util.Util;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.*;
import java.util.stream.Collectors;

public class BpmnComponentLibrary extends ComponentLibrary<BpmnComponent> {
Expand Down Expand Up @@ -71,6 +69,33 @@ public String defaultSerialize() {
return generateSerializedPromptData(BpmnComponentLibrarySerializationOptions.defaultOptions());
}

@JsonIgnore
public BpmnComponentLibrary merge(BpmnComponentLibrary other) {
if (other == null || other.components == null) {
return new BpmnComponentLibrary(new ArrayList<>(this.components));
}

Set<String> duplicatedComponentNames = this.components.stream()
.map(BpmnComponent::getName)
.collect(Collectors.toSet());

List<BpmnComponent> mergedComponents = new ArrayList<>(this.components);
other.components.stream()
.filter(component -> !duplicatedComponentNames.contains(component.getName()))
.forEach(mergedComponents::add);

return new BpmnComponentLibrary(mergedComponents);
}

@JsonIgnore
public Map<String, Collection<BpmnComponent.Variable>> getAutoGeneratedOutputs() {
Map<String, Collection<BpmnComponent.Variable>> autoGeneratedOutputs = new HashMap<>();
for (BpmnComponent component : components) {
autoGeneratedOutputs.put(component.getName(), component.getGeneratedOutputs());
}
return autoGeneratedOutputs;
}

public static BpmnComponentLibrary defaultLibrary() {
return fromResource("content/components/bpmn-component-library.json");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ public class BpmnComponentLibraryHighLevelSerializer implements ComponentLibrary
private final BpmnComponentLibrarySerializationOptions options = BpmnComponentLibrarySerializationOptions.defaultOptions()
.withIncludeInputs(true)
.withIncludeOutputs(true)
.withMandatoryInputsOnly(false);
.withMandatoryInputsOnly(false)
.withIncludeConstantInputs(false);

@Override
public String serialize(BpmnComponentLibrary library) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ public class BpmnComponentLibrarySerializationOptions {
private boolean mandatoryInputsOnly = false;
private boolean includeInputs = true;
private boolean includeOutputs = true;
private boolean includeConstantInputs = true;

public BpmnComponentLibrarySerializationOptions() { }

Expand Down Expand Up @@ -50,4 +51,17 @@ public BpmnComponentLibrarySerializationOptions withIncludeOutputs(boolean inclu
setIncludeOutputs(includeOutputs);
return this;
}

public boolean shouldIncludeConstantInputs() {
return includeConstantInputs;
}

public void setIncludeConstantInputs(boolean includeConstantInputs) {
this.includeConstantInputs = includeConstantInputs;
}

public BpmnComponentLibrarySerializationOptions withIncludeConstantInputs(boolean includeConstantInputs) {
setIncludeConstantInputs(includeConstantInputs);
return this;
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package org.rj.modelgen.bpmn.generation;
package org.rj.modelgen.bpmn.component.common;

public enum BpmnModelComponentNodeInputType {
public enum BpmnComponentInputSourceType {
CONSTANT,
SCRIPT,
EXPRESSION,
NODE,
GLOBAL;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ public enum BpmnComponentVariableType {
String,
Integer,
Float,
Boolean;
Boolean,
Array,
Object;

public static Optional<BpmnComponentVariableType> parse(String name) {
return Arrays.stream(values())
Expand Down
Loading