removed bricks part

This commit is contained in:
Lucio Lelii 2026-02-20 17:08:13 +01:00
parent cbc9ad987d
commit 4e500bbeee
35 changed files with 162 additions and 607 deletions

View File

@ -6,7 +6,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.4</version>
<version>3.5.11</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>it.cnr.isti</groupId>
@ -144,13 +144,11 @@
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>ollama</artifactId>
<version>1.21.3</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>workflow-manager</finalName>
<finalName>humainFlow</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@ -176,6 +174,7 @@
</excludes>
</configuration>
</plugin>
</plugins>
</build>

View File

@ -9,8 +9,6 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import it.cnr.isti.workflow.manager.blocks.configurations.BlockConfiguration;
import it.cnr.isti.workflow.manager.blocks.types.BlockType;
import it.cnr.isti.workflow.manager.blocks.types.BlockTypes;
import it.cnr.isti.workflow.manager.bricks.Brick;
import it.cnr.isti.workflow.manager.executions.executors.BlockExecutor;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
@ -51,7 +49,7 @@ public class Block<T extends BlockType> {
@Builder
public Block(@NonNull BlockConfiguration<T> specificConfiguration, @Singular List<String> inputs,
@Singular List<String> outputs, @Singular List<Brick> bricks, @NonNull T type) {
@Singular List<String> outputs, @NonNull T type) {
this.specificConfiguration = specificConfiguration;
this.name = specificConfiguration.getName();
this.inputs = inputs;

View File

@ -1,11 +1,7 @@
package it.cnr.isti.workflow.manager.blocks.configurations;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonTypeName;
import it.cnr.isti.workflow.manager.blocks.types.HumanInteractionBlockType;
import it.cnr.isti.workflow.manager.bricks.LLMBrick;
import it.cnr.isti.workflow.manager.llms.LLMDescriptor;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Builder;
@ -23,7 +19,7 @@ public class HumanInteractiveBlockConfiguration extends BlockConfiguration<Human
private String actionDescription;
@NotNull
private LLMBrick llmSimulatorBrick;
private LLMDescriptor llmDescriptor;
@Override
public Class<HumanInteractionBlockType> getBlockType() {
@ -32,10 +28,10 @@ public class HumanInteractiveBlockConfiguration extends BlockConfiguration<Human
@Builder
public HumanInteractiveBlockConfiguration(@NonNull String name, @NonNull String actionDescription,
@NonNull LLMBrick llmSimulatorBrick) {
@NonNull LLMDescriptor llmDescriptor) {
super(name);
this.actionDescription = actionDescription;
this.llmSimulatorBrick = llmSimulatorBrick;
this.llmDescriptor = llmDescriptor;
}
}

View File

@ -1,9 +1,7 @@
package it.cnr.isti.workflow.manager.blocks.configurations;
import com.fasterxml.jackson.annotation.JsonTypeName;
import it.cnr.isti.workflow.manager.blocks.types.LLMBlockType;
import it.cnr.isti.workflow.manager.bricks.LLMBrick;
import it.cnr.isti.workflow.manager.llms.LLMDescriptor;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Builder;
@ -22,13 +20,13 @@ public class LLMBlockConfiguration extends BlockConfiguration<LLMBlockType> {
String prompt;
@NotNull
LLMBrick brick;
LLMDescriptor llmDescriptor;
@Builder
public LLMBlockConfiguration(@NonNull String name, @NonNull String prompt, @NonNull LLMBrick brick) {
public LLMBlockConfiguration(@NonNull String name, @NonNull String prompt, @NonNull LLMDescriptor llmDescriptor) {
super(name);
this.prompt = prompt;
this.brick = brick;
this.llmDescriptor = llmDescriptor;
}
@Override

View File

@ -1,27 +0,0 @@
package it.cnr.isti.workflow.manager.bricks;
import java.util.Map;
import lombok.Getter;
import lombok.NoArgsConstructor;
@NoArgsConstructor(access = lombok.AccessLevel.PROTECTED)
@Getter
public abstract class Brick {
private String id;
private String brickManager;
public Brick(String id, String brickManager) {
this.brickManager = brickManager;
this.id = this.brickManager + ":" + id;
}
public String getBrickManager() {
return brickManager;
}
public Map<String, Object> getExecutionTimeConfiguration() {
return Map.of();
}
}

View File

@ -1,13 +0,0 @@
package it.cnr.isti.workflow.manager.bricks;
import java.util.List;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor(access = lombok.AccessLevel.PROTECTED)
public abstract class BrickManager<T extends Brick> {
public abstract List<T> getBricks();
}

View File

@ -1,37 +0,0 @@
package it.cnr.isti.workflow.manager.bricks;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonIgnore;
import it.cnr.isti.workflow.manager.llms.providers.LLMProvider;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class LLMBrick extends Brick {
@JsonIgnore
private LLMProvider provider;
private String model;
public String generate(String prompt, Map<String, Object> executionParameters) {
return provider.generate(model, prompt);
}
public LLMBrick(LLMProvider provider, String model, String brickManager) {
super(provider.getName() + "_" + model, brickManager);
this.provider = provider;
this.model = model;
}
public String getProvider() {
return provider.getName();
}
public String getModel() {
return model;
}
}

View File

@ -1,29 +0,0 @@
package it.cnr.isti.workflow.manager.bricks;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import it.cnr.isti.workflow.manager.bricks.annotations.BrickProvider;
import it.cnr.isti.workflow.manager.llms.providers.LLMProvider;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
@BrickProvider("llmBrickProvider")
public class LLMBrickManager extends BrickManager<LLMBrick> {
@Autowired
List<LLMProvider> llmProviders;
public List<LLMBrick> getBricks() {
List<LLMBrick> bricks = new ArrayList<>();
llmProviders.forEach(p -> p.getRegisteredModels().stream()
.map(model -> new LLMBrick(p, model, "llmBrickProvider"))
.forEach(brick -> bricks.add(brick)));
return bricks;
}
}

View File

@ -1,21 +0,0 @@
package it.cnr.isti.workflow.manager.bricks.annotations;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Component;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface BrickProvider {
@AliasFor(
annotation = Component.class
)
String value() default "";
}

View File

@ -1,8 +0,0 @@
package it.cnr.isti.workflow.manager.bricks.extensions;
import java.util.Map;
public interface ExecutionBrick<OUTPUT> {
OUTPUT execute(Map<String, Object> parameters, Map<String, Object> configParameters);
}

View File

@ -6,15 +6,12 @@ import it.cnr.isti.workflow.manager.blocks.Block;
import it.cnr.isti.workflow.manager.blocks.configurations.BlockConfiguration;
import it.cnr.isti.workflow.manager.blocks.factories.BlockFactory;
import it.cnr.isti.workflow.manager.blocks.types.BlockType;
import it.cnr.isti.workflow.manager.schema.JsonSchemaProducer;
import jakarta.validation.Valid;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@ -28,14 +25,18 @@ public class BlocksController {
@Autowired
List<BlockFactory<?, ?>> blockFactories;
/*
@Autowired
JsonSchemaProducer schemaProducer;
*/
@GetMapping("types")
public List<BlockType> getTypes() {
return new ArrayList<>(blockTypes.values());
}
/*
@GetMapping("/types/configurations/schemas")
public List<String> getSchemaConfigurations() {
return blockTypes.values().stream()
@ -48,6 +49,7 @@ public class BlocksController {
return schemaProducer.generateSchema(
blockTypes.get(type).getBlockConfigurationClass());
}
*/
@SuppressWarnings("unchecked")
@PostMapping

View File

@ -1,39 +0,0 @@
package it.cnr.isti.workflow.manager.controllers;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import it.cnr.isti.workflow.manager.bricks.Brick;
import it.cnr.isti.workflow.manager.bricks.BrickManager;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@RestController
@RequestMapping("/bricks")
public class BricksController {
@Autowired
private Map<String, BrickManager<?>> brickManagers;
@GetMapping("/providers")
public List<String> getProviders() {
return brickManagers.keySet().stream()
.sorted()
.toList();
}
@GetMapping("/providers/{provider}")
public List<? extends Brick> getBricksByProvider(@PathVariable String provider) {
BrickManager<?> manager = brickManagers.get(provider);
if (manager == null)
throw new IllegalArgumentException("Provider not found: " + provider);
return manager.getBricks();
}
}

View File

@ -1,17 +1,9 @@
package it.cnr.isti.workflow.manager.executions;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.springframework.stereotype.Service;
import it.cnr.isti.workflow.manager.executions.steps.Input;
import it.cnr.isti.workflow.manager.executions.steps.Output;
import it.cnr.isti.workflow.manager.executions.steps.Step;
import it.cnr.isti.workflow.manager.executions.steps.StepStatus;
import it.cnr.isti.workflow.manager.flows.model.Connection;
import it.cnr.isti.workflow.manager.flows.model.Flow;
@Service

View File

@ -4,24 +4,30 @@ import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import it.cnr.isti.workflow.manager.blocks.Block;
import it.cnr.isti.workflow.manager.blocks.configurations.HumanInteractiveBlockConfiguration;
import it.cnr.isti.workflow.manager.blocks.types.HumanInteractionBlockType;
import it.cnr.isti.workflow.manager.bricks.LLMBrick;
import it.cnr.isti.workflow.manager.executions.steps.Input;
import it.cnr.isti.workflow.manager.llms.LLMDescriptor;
import it.cnr.isti.workflow.manager.llms.providers.LLMProvider;
@Component
public class HumanInteractionExecutor implements BlockExecutor<HumanInteractionBlockType> {
@Autowired
private Map<String, LLMProvider> llmProviders;
@Override
public Map<String, Object> execute(Block<HumanInteractionBlockType> block, List<Input> inputs) {
HumanInteractiveBlockConfiguration config = (HumanInteractiveBlockConfiguration) block.getSpecificConfiguration();
String context= inputs.stream().map(input -> input.getName() + "= " + input.getValue()).collect(Collectors.joining(", "));
String prompt = String.format("giving the following context as input { %s } perform the Task : '%s'", context, config.getActionDescription());
LLMBrick llmBrick = config.getLlmSimulatorBrick();
return Map.of("output", llmBrick.generate(prompt, Map.of()));
LLMDescriptor llmDescriptor = config.getLlmDescriptor();
LLMProvider llmProvider = llmProviders.get(llmDescriptor.provider());
return Map.of("output", llmProvider.generate(llmDescriptor.model(), prompt));
}
@Override

View File

@ -3,18 +3,23 @@ package it.cnr.isti.workflow.manager.executions.executors;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import it.cnr.isti.workflow.manager.blocks.Block;
import it.cnr.isti.workflow.manager.blocks.configurations.LLMBlockConfiguration;
import it.cnr.isti.workflow.manager.blocks.factories.LLMBlockFactory;
import it.cnr.isti.workflow.manager.blocks.types.LLMBlockType;
import it.cnr.isti.workflow.manager.bricks.LLMBrick;
import it.cnr.isti.workflow.manager.executions.steps.Input;
import it.cnr.isti.workflow.manager.llms.LLMDescriptor;
import it.cnr.isti.workflow.manager.llms.providers.LLMProvider;
@Component
public class LLMExecutor implements BlockExecutor<LLMBlockType> {
@Autowired
private Map<String, LLMProvider> llmProviders;
@Override
public Map<String, Object> execute(Block<LLMBlockType> block, List<Input> inputs) {
System.out.println("Executing LLM Block: " + block.getName());
@ -25,8 +30,9 @@ public class LLMExecutor implements BlockExecutor<LLMBlockType> {
prompt = prompt.replaceAll("\\$\\{\\{" + input.getName() + "\\}\\}", input.getValue().toString());
}
LLMBrick llmBrick = config.getBrick();
String response = llmBrick.generate(prompt, Map.of());
LLMDescriptor llmDescriptor = config.getLlmDescriptor();
LLMProvider llmProvider = llmProviders.get(llmDescriptor.provider());
String response = llmProvider.generate(llmDescriptor.model(), prompt);
return Map.of(LLMBlockFactory.OUTPUT_NAME, response);
}

View File

@ -0,0 +1,6 @@
package it.cnr.isti.workflow.manager.llms;
import lombok.Builder;
@Builder
public record LLMDescriptor(String provider, String model){}

View File

@ -1,22 +0,0 @@
package it.cnr.isti.workflow.manager.schema;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
@Documented
@Constraint(validatedBy = MultiValuesValidator.class)
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DynamicMultiValues {
String message() default "value not valid";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String[] acceptedValues();
}

View File

@ -1,60 +0,0 @@
package it.cnr.isti.workflow.manager.schema;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.kjetland.jackson.jsonSchema.JsonSchemaConfig;
import com.kjetland.jackson.jsonSchema.JsonSchemaGenerator;
import it.cnr.isti.workflow.manager.bricks.BrickManager;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class DynamicSchemaGenerator {
private final ObjectMapper objectMapper;
private final JsonSchemaGenerator baseGenerator;
public DynamicSchemaGenerator(@Autowired ObjectMapper objectMapper) {
JsonSchemaConfig config = JsonSchemaConfig.vanillaJsonSchemaDraft4()
.withFailOnUnknownProperties(false);
this.baseGenerator = new JsonSchemaGenerator(objectMapper, config); // bean validation = true
this.objectMapper = objectMapper;
}
public JsonNode generateJsonSchema(Class<?> clazz) {
JsonNode schema = baseGenerator.generateJsonSchema(clazz);
// Trova i campi annotati con @DynamicMultiValues
for (Field field : clazz.getDeclaredFields()) {
DynamicMultiValues annotation = field.getAnnotation(DynamicMultiValues.class);
if (annotation != null) {
String[] acceptedValues = annotation.acceptedValues();
if (acceptedValues != null) {
// Naviga nello schema e inietta "enum"
JsonNode properties = schema.get("properties");
if (properties != null && properties.has(field.getName())) {
ArrayNode enumArray = objectMapper.createArrayNode();
for (String value : acceptedValues) {
enumArray.add(value);
}
((com.fasterxml.jackson.databind.node.ObjectNode) properties.get(field.getName()))
.set("enum", enumArray);
}
}
}
}
return schema;
}
}

View File

@ -1,27 +0,0 @@
package it.cnr.isti.workflow.manager.schema;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
@Service
public class JsonSchemaProducer {
@Autowired
private DynamicSchemaGenerator schemaGen;
@Autowired
private ObjectMapper mapper;
public String generateSchema(Class<?> clazz) {
JsonNode schema = schemaGen.generateJsonSchema(clazz);
try {
return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(schema);
} catch (JsonProcessingException e) {
throw new RuntimeException("Error generating JSON schema for class: " + clazz.getName(), e);
}
}
}

View File

@ -1,34 +0,0 @@
package it.cnr.isti.workflow.manager.schema;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import it.cnr.isti.workflow.manager.bricks.BrickManager;
import java.util.List;
import java.util.Map;
@Component
public class MultiValuesValidator implements ConstraintValidator<DynamicMultiValues, String> {
private String[] acceptedValues;
private Map<String, BrickManager<?>> brickManagers;
public MultiValuesValidator(@Autowired Map<String, BrickManager<?>> brickManagers) {
this.brickManagers = brickManagers;
}
@Override
public void initialize(DynamicMultiValues annotation) {
this.acceptedValues = annotation.acceptedValues();
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
return value == null || List.of(acceptedValues).contains(value);
}
}

View File

@ -1,8 +0,0 @@
package it.cnr.isti.workflow.manager.schema;
import java.util.List;
@FunctionalInterface
public interface ValuesRetriever {
List<String> getValues(String sourceKey);
}

View File

@ -4,32 +4,23 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.TestPropertySource;
import it.cnr.isti.workflow.manager.blocks.configurations.LLMBlockConfiguration;
import it.cnr.isti.workflow.manager.blocks.factories.BlockFactory;
import it.cnr.isti.workflow.manager.blocks.factories.LLMBlockFactory;
import it.cnr.isti.workflow.manager.blocks.types.LLMBlockType;
import it.cnr.isti.workflow.manager.bricks.BrickManager;
import it.cnr.isti.workflow.manager.bricks.LLMBrick;
import it.cnr.isti.workflow.manager.configuration.MyTestConfiguration;
import it.cnr.isti.workflow.manager.llms.LLMDescriptor;
@SpringBootTest
@Import(MyTestConfiguration.class)
@TestPropertySource(locations = "classpath:test.properties")
public class BlockTest {
@Autowired
LLMBlockFactory llmBlockFactory;
@Qualifier("llmBrickTestManager")
@Autowired
BrickManager<LLMBrick> llmBrickManager;
@Autowired
LLMBlockType llmBlockType;
@ -37,14 +28,19 @@ public class BlockTest {
@Test
void createLLMBlock() {
BlockFactory<LLMBlockType, LLMBlockConfiguration> factory = llmBlockFactory;
LLMBrick brick = (LLMBrick) llmBrickManager.getBricks().getFirst();
LLMDescriptor llmDescriptor = LLMDescriptor.builder()
.provider("testProvider")
.model("testModel")
.build();
assertNotNull(factory);
assertNotNull(brick);
assertNotNull(llmDescriptor);
// Assuming LLMBlockConfiguration is a valid configuration class for
// LLMBlockType
LLMBlockConfiguration config = LLMBlockConfiguration.builder()
.prompt("Hello, {{name}}!")
.brick(brick)
.llmDescriptor(llmDescriptor)
.name("master")
.build();
Block<LLMBlockType> block = factory.create(config);

View File

@ -1,21 +0,0 @@
package it.cnr.isti.workflow.manager.bricks.configurations;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
import it.cnr.isti.workflow.manager.schema.JsonSchemaProducer;
@SpringBootTest
@TestPropertySource(locations="classpath:test.properties")
public class TestConfig {
@Autowired
JsonSchemaProducer schemaProducer;
@Test
public void generateJSONSchema() throws Exception {
}
}

View File

@ -1,10 +1,11 @@
package it.cnr.isti.workflow.manager.configuration;
import org.testcontainers.DockerClientFactory;
public class ConditionChecks {
public static boolean isDockerAvailable() {
try {
Process process = new ProcessBuilder("docker", "ps").start();
return process.waitFor() == 0;
return DockerClientFactory.instance().isDockerAvailable();
} catch (Exception e) {
return false;
}

View File

@ -1,106 +0,0 @@
package it.cnr.isti.workflow.manager.configuration;
import java.util.List;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import it.cnr.isti.workflow.manager.bricks.Brick;
import it.cnr.isti.workflow.manager.bricks.BrickManager;
import it.cnr.isti.workflow.manager.bricks.LLMBrick;
import it.cnr.isti.workflow.manager.llms.providers.LLMProvider;
@TestConfiguration
public class MyTestConfiguration {
@Bean(name = "testProvider")
BrickManager<Brick> brickManager() {
return new BrickManager<Brick>() {
@Override
public List<Brick> getBricks() {
Brick b = new Brick("id", "testProvider") {
};
return List.of(b);
}
};
}
@Bean(name = "llmBrickTest")
LLMBrick llmBrickProvider() {
LLMProvider provider = new LLMProvider() {
@Override
public String getName() {
return "llmTestProvider";
}
@Override
public List<String> getRegisteredModels() {
return List.of("testModel");
}
@Override
public String generate(String model, String prompt) {
return "Generated response on " + model + " for prompt: " + prompt;
}
};
return new LLMBrick(provider, "testModel", "testBrick");
}
@Bean(name = "humanInteractionSimulationBrickTest")
LLMBrick humanInteractionSimulationBrickProvider() {
LLMProvider provider = new LLMProvider() {
@Override
public String getName() {
return "humanInteractionTestProvider";
}
@Override
public List<String> getRegisteredModels() {
return List.of("testModel");
}
@Override
public String generate(String model, String prompt) {
return "he is fine";
}
};
return new LLMBrick(provider, "testModel", "testBrick");
}
@Bean(name = "llmBrickTestManager")
BrickManager<LLMBrick> llmBrickManagerProvider() {
return new BrickManager<LLMBrick>() {
@Override
public List<LLMBrick> getBricks() {
LLMProvider provider = new LLMProvider() {
@Override
public String getName() {
return "llmTestProvider";
}
@Override
public List<String> getRegisteredModels() {
return List.of("testModel");
}
@Override
public String generate(String model, String prompt) {
return "Generated response on " + model + " for prompt: " + prompt;
}
};
LLMBrick b = new LLMBrick(provider, "testModel", "testBrickManager");
return List.of(b);
}
};
}
}

View File

@ -7,7 +7,6 @@ import org.springframework.context.annotation.Bean;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.utility.DockerImageName;
import it.cnr.isti.workflow.manager.bricks.LLMBrick;
import it.cnr.isti.workflow.manager.llms.providers.LLMProvider;
import it.cnr.isti.workflow.manager.ollama.OllamaClient;
import it.cnr.isti.workflow.manager.ollama.OllamaService;
@ -36,8 +35,8 @@ public class TestContainersConfiguration {
}
@Bean(name = "ollamaContainerBrickTest")
LLMBrick ollamaContainerBrickProvider(OllamaService ollamaService) {
@Bean(name = "ollamaTestProvider")
LLMProvider ollamaContainerBrickProvider(OllamaService ollamaService) {
LLMProvider provider = new LLMProvider() {
@Override
public String getName() {
@ -60,6 +59,6 @@ public class TestContainersConfiguration {
}
};
return new LLMBrick(provider, "sam860/gemma3:270m", "testBrick");
return provider;
}
}

View File

@ -8,29 +8,20 @@ import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.TestPropertySource;
import it.cnr.isti.workflow.manager.blocks.Block;
import it.cnr.isti.workflow.manager.blocks.configurations.LLMBlockConfiguration;
import it.cnr.isti.workflow.manager.blocks.types.BlockType;
import it.cnr.isti.workflow.manager.blocks.types.LLMBlockType;
import it.cnr.isti.workflow.manager.bricks.BrickManager;
import it.cnr.isti.workflow.manager.bricks.LLMBrick;
import it.cnr.isti.workflow.manager.configuration.MyTestConfiguration;
import it.cnr.isti.workflow.manager.llms.LLMDescriptor;
@SpringBootTest
@Import(MyTestConfiguration.class)
@TestPropertySource(locations = "classpath:test.properties")
public class BlocksControllerTest {
@Qualifier("llmBrickTestManager")
@Autowired
BrickManager<LLMBrick> llmBrickManager;
@Autowired
private BlocksController blocksController;
@ -49,8 +40,11 @@ public class BlocksControllerTest {
LLMBlockConfiguration config = LLMBlockConfiguration.builder()
.prompt("Hello, ${{name}}!")
.name("master")
.brick(llmBrickManager.getBricks().get(0))
.build();
.llmDescriptor(LLMDescriptor.builder()
.provider("testProvider")
.model("testModel")
.build())
.build();
Block<LLMBlockType> block = blocksController.create(config);
assertNotNull(block);
assertTrue(block.getInputs().size() == 1);

View File

@ -1,38 +0,0 @@
package it.cnr.isti.workflow.manager.controllers;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.TestPropertySource;
import it.cnr.isti.workflow.manager.bricks.Brick;
import it.cnr.isti.workflow.manager.configuration.MyTestConfiguration;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.List;
@SpringBootTest()
@Import(MyTestConfiguration.class)
@TestPropertySource(locations = "classpath:test.properties")
public class BricksControllerTest {
@Autowired
private BricksController bricksController;
@Test
public void testGetBricks() throws Exception {
String provider = bricksController.getProviders().stream().filter(p -> p.equals("testProvider")).findFirst().orElse(null);
assertNotNull(provider);
assertEquals("testProvider", provider);
List<? extends Brick> bricks = bricksController.getBricksByProvider(provider);
assertTrue(!bricks.isEmpty());
assertEquals(1, bricks.size());
Brick brick = bricks.get(0);
assertNotNull(brick);
assertEquals("testProvider:id", brick.getId());
}
}

View File

@ -4,38 +4,66 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.test.context.TestPropertySource;
import org.springframework.util.ResourceUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import it.cnr.isti.workflow.manager.app.ObjectMapperHolder;
import it.cnr.isti.workflow.manager.bricks.LLMBrick;
import it.cnr.isti.workflow.manager.configuration.MyTestConfiguration;
import it.cnr.isti.workflow.manager.executions.steps.Step;
import it.cnr.isti.workflow.manager.executions.steps.StepStatus;
import it.cnr.isti.workflow.manager.flows.FlowTestCreator;
import it.cnr.isti.workflow.manager.flows.model.Flow;
import it.cnr.isti.workflow.manager.llms.LLMDescriptor;
import it.cnr.isti.workflow.manager.llms.providers.LLMProvider;
@SpringBootTest
@Import(MyTestConfiguration.class)
@TestPropertySource(locations = "classpath:test.properties")
public class ExecutionTest {
@TestConfiguration
static class TestConfig {
@Bean
public LLMProvider testProvider() {
return new LLMProvider() {
@Override
public String getName() {
return "testProvider";
}
@Override
public List<String> getRegisteredModels() {
return List.of("testModel");
}
@Override
public String generate(String prompt, String model) {
return "Hello, " + prompt.replace("Hello, ", "").replace("!", "") + "!";
}
};
}
}
@Autowired
ExecutionsService executionsService;
@Autowired
FlowTestCreator flowTestCreator;
@Qualifier("llmBrickTest")
@Autowired
LLMBrick llmBrick;
LLMDescriptor llmBrick = LLMDescriptor.builder()
.provider("testProvider")
.model("testModel")
.build();
@Test
public void createExecution() {

View File

@ -4,25 +4,25 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledIf;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.TestPropertySource;
import org.testcontainers.containers.GenericContainer;
import it.cnr.isti.workflow.manager.bricks.LLMBrick;
import it.cnr.isti.workflow.manager.configuration.MyTestConfiguration;
import it.cnr.isti.workflow.manager.configuration.TestContainersConfiguration;
import it.cnr.isti.workflow.manager.executions.steps.Step;
import it.cnr.isti.workflow.manager.flows.FlowTestCreator;
import it.cnr.isti.workflow.manager.flows.model.Flow;
import it.cnr.isti.workflow.manager.llms.LLMDescriptor;
@SpringBootTest
@Import({ MyTestConfiguration.class, TestContainersConfiguration.class })
@Import({ TestContainersConfiguration.class })
@TestPropertySource(locations = "classpath:test.properties")
@EnabledIf("it.cnr.isti.workflow.manager.configuration.ConditionChecks#isDockerAvailable")
public class ExecutionWithContainer {
@Autowired
@ -31,9 +31,21 @@ public class ExecutionWithContainer {
@Autowired
FlowTestCreator flowTestCreator;
@Qualifier("ollamaContainerBrickTest")
@Autowired
LLMBrick llmBrick;
@Qualifier("ollamaContainer")
GenericContainer<?> ollama;
LLMDescriptor llmBrick = LLMDescriptor.builder()
.provider("ollamaTestProvider")
.model("sam860/gemma3:270m")
.build();
@BeforeAll
static void checkDocker() {
Assumptions.assumeTrue(
org.testcontainers.DockerClientFactory.instance().isDockerAvailable(),
"Docker not available, skipping tests");
}
@Test
public void getFlowAndExecute() {
@ -61,7 +73,6 @@ public class ExecutionWithContainer {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@ -69,7 +80,6 @@ public class ExecutionWithContainer {
execObject.getContext().getResult().forEach((k, v) -> System.out.println("Result: " + k + " -> " + v));
}
@Test
public void getInteractiveFlowAndExecute() {
Flow flow = flowTestCreator.createFlowWithInteraction(llmBrick);
@ -83,8 +93,9 @@ public class ExecutionWithContainer {
}
}
execObject.getContext().getSteps().values().stream().filter(s -> s.getBlock().getType().isUserInteractive()).forEach(s -> s.setSimulated(true));
execObject.getContext().getSteps().values().stream().filter(s -> s.getBlock().getType().isUserInteractive())
.forEach(s -> s.setSimulated(true));
assertEquals(ExecutionStatus.READY, execObject.getContext().getStatus());
execObject = executionsService.startExecution(execObject.getId());
assertEquals(ExecutionStatus.RUNNING, execObject.getContext().getStatus());
@ -93,13 +104,11 @@ public class ExecutionWithContainer {
Thread.sleep(100);
System.out.println("Execution status: " + execObject.getContext().getStatus());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
assertTrue(execObject.getContext().getStatus().isFinalState());
execObject.getContext().getResult().forEach((k, v) -> System.out.println("Result: " + k + " -> " + v));
}
}

View File

@ -8,12 +8,10 @@ import org.springframework.context.annotation.Import;
import org.springframework.test.context.TestPropertySource;
import com.fasterxml.jackson.databind.ObjectMapper;
import it.cnr.isti.workflow.manager.bricks.LLMBrick;
import it.cnr.isti.workflow.manager.configuration.MyTestConfiguration;
import it.cnr.isti.workflow.manager.flows.model.Flow;
import it.cnr.isti.workflow.manager.llms.LLMDescriptor;
@SpringBootTest
@Import(MyTestConfiguration.class)
@TestPropertySource(locations = "classpath:test.properties")
public class FlowTest {
@ -23,9 +21,10 @@ public class FlowTest {
@Autowired
FlowTestCreator flowTestCreator;
@Qualifier("llmBrickTest")
@Autowired
LLMBrick llmBrick;
LLMDescriptor llmBrick = LLMDescriptor.builder()
.provider("testProvider")
.model("testModel")
.build();
@Test
public void createEmptyFlow() {

View File

@ -12,39 +12,33 @@ import it.cnr.isti.workflow.manager.blocks.factories.HumanInteractiveBlockFactor
import it.cnr.isti.workflow.manager.blocks.factories.LLMBlockFactory;
import it.cnr.isti.workflow.manager.blocks.types.HumanInteractionBlockType;
import it.cnr.isti.workflow.manager.blocks.types.LLMBlockType;
import it.cnr.isti.workflow.manager.bricks.LLMBrick;
import it.cnr.isti.workflow.manager.configuration.MyTestConfiguration;
import it.cnr.isti.workflow.manager.flows.model.Connection;
import it.cnr.isti.workflow.manager.flows.model.Flow;
import it.cnr.isti.workflow.manager.llms.LLMDescriptor;
@Service
@Import(MyTestConfiguration.class)
public class FlowTestCreator {
@Qualifier("humanInteractionSimulationBrickTest")
@Autowired
LLMBrick humanInteractiveSimulationBrick;
@Autowired
LLMBlockFactory llmBlockFactory;
@Autowired
HumanInteractiveBlockFactory humanInteractiveBlockFactory;
public Flow createFlowWithConnection(LLMBrick llmBrick) {
public Flow createFlowWithConnection(LLMDescriptor llmBrick) {
Block<LLMBlockType> block1 = llmBlockFactory.create(LLMBlockConfiguration.builder()
.prompt("When ${{name}} died ? give me only the year as number")
.name("first")
.brick(llmBrick)
.llmDescriptor(llmBrick)
.build());
Block<LLMBlockType> block2 = llmBlockFactory.create(LLMBlockConfiguration.builder()
.prompt("what was the most important event in year ${{year}}?")
.name("second")
.brick(llmBrick)
.llmDescriptor(llmBrick)
.build());
block2.asSink();
@ -60,18 +54,18 @@ public class FlowTestCreator {
}
public Flow createFlowWithInteraction(LLMBrick llmBrick) {
public Flow createFlowWithInteraction(LLMDescriptor llmBrick) {
Block<LLMBlockType> block1 = llmBlockFactory.create(LLMBlockConfiguration.builder()
.prompt("Make a question about ${{name}}")
.name("first")
.brick(llmBrick)
.llmDescriptor(llmBrick)
.build());
Block<HumanInteractionBlockType> block2 = humanInteractiveBlockFactory.create(HumanInteractiveBlockConfiguration.builder()
.actionDescription("Answer the question in input")
.name("interactive")
.llmSimulatorBrick(llmBrick)
.llmDescriptor(llmBrick)
.build());
block2.asSink();

View File

@ -7,7 +7,11 @@ public class OllamaClient {
private final String baseUrl;
public OllamaClient(GenericContainer<?> container) {
this.baseUrl = "http://" + container.getHost() + ":" + container.getMappedPort(11434);
if (container.isRunning()) {
this.baseUrl = "http://" + container.getHost() + ":" + container.getMappedPort(11434);
} else {
this.baseUrl = "http://localhost:11434";
}
}
public String getBaseUrl() {

View File

@ -1,7 +1,10 @@
package it.cnr.isti.workflow.manager.ollama;
import static org.junit.Assert.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@ -25,19 +28,22 @@ class OllamaIntegrationTest {
@Autowired
OllamaService ollamaService;
@BeforeAll
static void checkDocker() {
Assumptions.assumeTrue(
org.testcontainers.DockerClientFactory.instance().isDockerAvailable(),
"Docker not available, skipping tests");
}
@Test
void testOllamaIsRunning() throws Exception {
String baseUrl = "http://" + ollama.getHost() + ":" + ollama.getMappedPort(11434);
assert ollama.isRunning();
void testOllamaIsRunning() {
assertTrue(ollama.isRunning(), "Container Ollama not running");
}
@Test
void generate() throws Exception {
String response = ollamaService.generate("llama3:8b", "how is the weather today in Pisa?");
String response = ollamaService.generate("sam860/gemma3:270m", "how is the weather today in Pisa?");
assertNotNull(response);
System.out.println("Response: " + response);
}
}

View File

@ -0,0 +1,12 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="org.testcontainers" level="DEBUG"/>
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
</configuration>