diff --git a/aleatoricism-chain/src/main/java/io/github/scitia/aleatoricism/chain/MarkdownInstructionProvider.java b/aleatoricism-chain/src/main/java/io/github/scitia/aleatoricism/chain/MarkdownInstructionProvider.java index 16ae099..8949f72 100644 --- a/aleatoricism-chain/src/main/java/io/github/scitia/aleatoricism/chain/MarkdownInstructionProvider.java +++ b/aleatoricism-chain/src/main/java/io/github/scitia/aleatoricism/chain/MarkdownInstructionProvider.java @@ -47,21 +47,21 @@ public String getInstructions() { private String getDefaultInstructions() { return """ # Aleatoric HTTP Router Instructions - - This is the default instruction set. - To customize, create 'aleatoric-instructions.md' in your project's resources folder. - + \s + This is the default instruction set.\s + To customize, create 'aleatoricism.md' in your project's resources folder. + \s ## HTTP Method Handling - + \s The router will automatically handle: - GET: Retrieve resources - POST: Create resources - PUT: Replace resources - PATCH: Update resources - DELETE: Remove resources - + \s Each request will be processed by the AI model which will decide the appropriate business operation. - """; + \s"""; } } diff --git a/aleatoricism-flows/src/main/java/io/github/scitia/aleatoricism/flows/api/Waypoint.java b/aleatoricism-flows/src/main/java/io/github/scitia/aleatoricism/flows/api/Waypoint.java index 6657661..9fc9722 100644 --- a/aleatoricism-flows/src/main/java/io/github/scitia/aleatoricism/flows/api/Waypoint.java +++ b/aleatoricism-flows/src/main/java/io/github/scitia/aleatoricism/flows/api/Waypoint.java @@ -2,6 +2,7 @@ import io.github.scitia.aleatoricism.flows.execution.ExecutionContext; import io.github.scitia.aleatoricism.flows.execution.FlowExecutionException; +import jakarta.validation.Valid; /** * Smallest executable unit in a business graph. @@ -9,9 +10,9 @@ @FunctionalInterface public interface Waypoint { - O handle(I input, ExecutionContext context) throws Exception; + O handle(@Valid I input, ExecutionContext context) throws Exception; - default O execute(I input, ExecutionContext context) { + default O execute(@Valid I input, ExecutionContext context) { try { return handle(input, context); } catch (FlowExecutionException exception) { diff --git a/aleatoricism-spring-boot-sample-app/README.md b/aleatoricism-spring-boot-sample-app/README.md index 5c36b19..b42dd5a 100644 --- a/aleatoricism-spring-boot-sample-app/README.md +++ b/aleatoricism-spring-boot-sample-app/README.md @@ -10,11 +10,17 @@ This sample app includes domain flows for quotes and agile scrum workflows. The ```json { - "name": "Sprint 12", - "goal": "Ship planning improvements", - "startDate": "2026-06-01", - "endDate": "2026-06-14", - "capacity": 30, - "team": "alpha" + "name": "Name", + "goal": "Goal", + "issues": [ + { + "name": "Issue 1", + "description": "Description 1", + "reporter": "Reporter 1", + "estimation": 5, + "acceptanceCriteria": ["Criterion 1"] + } + ] } +``` diff --git a/aleatoricism-spring-boot-sample-app/docker-compose.yml b/aleatoricism-spring-boot-sample-app/docker-compose.yml deleted file mode 100644 index 29c7c93..0000000 --- a/aleatoricism-spring-boot-sample-app/docker-compose.yml +++ /dev/null @@ -1,9 +0,0 @@ -services: - database: - image: 'postgres:15.2' - ports: - - '5432:5432' - environment: - - 'POSTGRES_USER=appuser' - - 'POSTGRES_DB=aleatoricismdb' - - 'POSTGRES_PASSWORD=topsecret' \ No newline at end of file diff --git a/aleatoricism-spring-boot-sample-app/pom.xml b/aleatoricism-spring-boot-sample-app/pom.xml index f1a142c..6f25bc8 100644 --- a/aleatoricism-spring-boot-sample-app/pom.xml +++ b/aleatoricism-spring-boot-sample-app/pom.xml @@ -16,6 +16,9 @@ 2.2.224 3.10.0.2594 0.2.2-java.1 + 1.18.46 + 1.6.3 + 3.13.0 @@ -44,24 +47,23 @@ org.projectlombok lombok - 1.18.46 - - - org.springframework.boot - spring-boot-docker-compose - true - runtime + ${lombok.version} com.h2database h2 - 2.2.224 + ${h2.version} test org.mapstruct mapstruct - 1.6.3 + ${mapstruct.version} + + + org.postgresql + postgresql + runtime @@ -79,18 +81,18 @@ org.apache.maven.plugins maven-compiler-plugin - 3.13.0 + ${maven.compiler.plugin.version} org.mapstruct mapstruct-processor - 1.6.3 + ${mapstruct.version} org.projectlombok lombok - 1.18.46 + ${lombok.version} diff --git a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/api/IssueDto.java b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/api/IssueDto.java deleted file mode 100644 index 3c5fab6..0000000 --- a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/api/IssueDto.java +++ /dev/null @@ -1,12 +0,0 @@ -package io.github.scitia.app.sprint.api; - -import java.util.List; - -public record IssueDto( - String name, - String description, - String reporter, - Integer estimation, - List acceptanceCriteria -) { -} diff --git a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/api/SprintPlanningRequest.java b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/api/SprintPlanningRequest.java deleted file mode 100644 index 23eec31..0000000 --- a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/api/SprintPlanningRequest.java +++ /dev/null @@ -1,7 +0,0 @@ -package io.github.scitia.app.sprint.api; - -import java.util.List; - -public record SprintPlanningRequest(String name, String goal, List issues) { -} - diff --git a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/domain/Issue.java b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/domain/issue/Issue.java similarity index 87% rename from aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/domain/Issue.java rename to aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/domain/issue/Issue.java index a4e36c3..0320f6b 100644 --- a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/domain/Issue.java +++ b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/domain/issue/Issue.java @@ -1,5 +1,6 @@ -package io.github.scitia.app.sprint.domain; +package io.github.scitia.app.sprint.domain.issue; +import io.github.scitia.app.sprint.domain.sprint.Sprint; import jakarta.persistence.ElementCollection; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; diff --git a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/domain/issue/IssueDto.java b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/domain/issue/IssueDto.java new file mode 100644 index 0000000..61b636a --- /dev/null +++ b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/domain/issue/IssueDto.java @@ -0,0 +1,17 @@ +package io.github.scitia.app.sprint.domain.issue; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; + +import java.util.List; + +public record IssueDto( + @NotNull @NotBlank String name, + @NotNull @NotBlank String description, + @NotNull @NotBlank String reporter, + @Positive Integer estimation, + @NotEmpty List acceptanceCriteria +) { +} diff --git a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/mapper/IssueMapper.java b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/domain/issue/IssueMapper.java similarity index 72% rename from aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/mapper/IssueMapper.java rename to aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/domain/issue/IssueMapper.java index 7ee3286..fa2976c 100644 --- a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/mapper/IssueMapper.java +++ b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/domain/issue/IssueMapper.java @@ -1,7 +1,5 @@ -package io.github.scitia.app.sprint.mapper; +package io.github.scitia.app.sprint.domain.issue; -import io.github.scitia.app.sprint.api.IssueDto; -import io.github.scitia.app.sprint.domain.Issue; import org.springframework.stereotype.Component; @Component diff --git a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/domain/issue/IssueRepository.java b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/domain/issue/IssueRepository.java new file mode 100644 index 0000000..321db98 --- /dev/null +++ b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/domain/issue/IssueRepository.java @@ -0,0 +1,6 @@ +package io.github.scitia.app.sprint.domain.issue; + +import org.springframework.data.jpa.repository.JpaRepository; + +public interface IssueRepository extends JpaRepository { +} diff --git a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/domain/Sprint.java b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/domain/sprint/Sprint.java similarity index 88% rename from aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/domain/Sprint.java rename to aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/domain/sprint/Sprint.java index 058d2b8..e1846fe 100644 --- a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/domain/Sprint.java +++ b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/domain/sprint/Sprint.java @@ -1,5 +1,6 @@ -package io.github.scitia.app.sprint.domain; +package io.github.scitia.app.sprint.domain.sprint; +import io.github.scitia.app.sprint.domain.issue.Issue; import jakarta.persistence.CascadeType; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; diff --git a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/api/SprintDto.java b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/domain/sprint/SprintDto.java similarity index 50% rename from aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/api/SprintDto.java rename to aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/domain/sprint/SprintDto.java index bf15437..c84c667 100644 --- a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/api/SprintDto.java +++ b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/domain/sprint/SprintDto.java @@ -1,4 +1,6 @@ -package io.github.scitia.app.sprint.api; +package io.github.scitia.app.sprint.domain.sprint; + +import io.github.scitia.app.sprint.domain.issue.IssueDto; import java.util.List; diff --git a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/mapper/SprintMapper.java b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/domain/sprint/SprintMapper.java similarity index 72% rename from aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/mapper/SprintMapper.java rename to aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/domain/sprint/SprintMapper.java index b7e9aaf..da4914c 100644 --- a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/mapper/SprintMapper.java +++ b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/domain/sprint/SprintMapper.java @@ -1,8 +1,7 @@ -package io.github.scitia.app.sprint.mapper; +package io.github.scitia.app.sprint.domain.sprint; -import io.github.scitia.app.sprint.api.IssueDto; -import io.github.scitia.app.sprint.api.SprintDto; -import io.github.scitia.app.sprint.domain.Sprint; +import io.github.scitia.app.sprint.domain.issue.IssueDto; +import io.github.scitia.app.sprint.domain.issue.IssueMapper; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; diff --git a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/infrastructure/SprintRepository.java b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/domain/sprint/SprintRepository.java similarity index 57% rename from aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/infrastructure/SprintRepository.java rename to aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/domain/sprint/SprintRepository.java index 8ad2f76..eee4723 100644 --- a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/infrastructure/SprintRepository.java +++ b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/domain/sprint/SprintRepository.java @@ -1,6 +1,5 @@ -package io.github.scitia.app.sprint.infrastructure; +package io.github.scitia.app.sprint.domain.sprint; -import io.github.scitia.app.sprint.domain.Sprint; import org.springframework.data.jpa.repository.JpaRepository; public interface SprintRepository extends JpaRepository { diff --git a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/flow/SprintFlows.java b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/flow/SprintFlows.java index 911806b..12c4c1c 100644 --- a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/flow/SprintFlows.java +++ b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/flow/SprintFlows.java @@ -1,16 +1,16 @@ package io.github.scitia.app.sprint.flow; +import io.github.scitia.aleatoricism.flows.annotation.BusinessFlow; import io.github.scitia.aleatoricism.flows.engine.BusinessFlowBuilder; import io.github.scitia.aleatoricism.flows.engine.Flow; -import io.github.scitia.app.sprint.api.SprintPlanningRequest; -import io.github.scitia.app.sprint.domain.Sprint; -import io.github.scitia.app.sprint.flow.plan.AddIssuesToSprintWaypoint; -import io.github.scitia.app.sprint.flow.plan.CreateSprintEntityWaypoint; -import io.github.scitia.app.sprint.flow.plan.PersistSprintWaypoint; -import io.github.scitia.app.sprint.flow.plan.ValidateSprintPlanningRequestWaypoint; -import lombok.Getter; +import io.github.scitia.app.sprint.flow.api.SprintPlanningRequest; +import io.github.scitia.app.sprint.domain.sprint.Sprint; +import io.github.scitia.app.sprint.flow.plan.waypoint.AddIssuesToSprintWaypoint; +import io.github.scitia.app.sprint.flow.plan.waypoint.CreateSprintEntityWaypoint; +import io.github.scitia.app.sprint.flow.plan.waypoint.PersistSprintWaypoint; +import io.github.scitia.app.sprint.flow.plan.waypoint.ValidateSprintPlanningRequestWaypoint; +import io.github.scitia.app.sprint.flow.plan.store.SprintPlanningStore; import lombok.RequiredArgsConstructor; -import lombok.Setter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -19,17 +19,19 @@ public class SprintFlows { private final PersistSprintWaypoint persistSprintWaypoint; - - @Setter - @Getter - public static class ExampleStore { - private SprintPlanningRequest sprintPlanningRequest; - } + private final ValidateSprintPlanningRequestWaypoint validationWaypoint; @Bean(name = "sprint-planning-flow") - public Flow sprintPlanningFlow() { + @BusinessFlow( + name = "sprint-planning-flow", + description = """ + Flow to plan a new sprint, including validation, + creation, and persistence of the sprint and its associated issues. + """ + ) + public Flow sprintPlanningFlow() { return BusinessFlowBuilder.define() - .start(new ValidateSprintPlanningRequestWaypoint(), ExampleStore::new) + .start(validationWaypoint, SprintPlanningStore::new) .then(new CreateSprintEntityWaypoint()) .then(new AddIssuesToSprintWaypoint()) .then(persistSprintWaypoint) diff --git a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/flow/api/SprintPlanningRequest.java b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/flow/api/SprintPlanningRequest.java new file mode 100644 index 0000000..8515648 --- /dev/null +++ b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/flow/api/SprintPlanningRequest.java @@ -0,0 +1,16 @@ +package io.github.scitia.app.sprint.flow.api; + +import io.github.scitia.app.sprint.domain.issue.IssueDto; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; + +import java.util.List; + +public record SprintPlanningRequest( + @NotNull @NotBlank String name, + @NotNull @NotBlank String goal, + @NotEmpty List issues +) { +} + diff --git a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/flow/plan/ValidateSprintPlanningRequestWaypoint.java b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/flow/plan/ValidateSprintPlanningRequestWaypoint.java deleted file mode 100644 index 588820b..0000000 --- a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/flow/plan/ValidateSprintPlanningRequestWaypoint.java +++ /dev/null @@ -1,57 +0,0 @@ -package io.github.scitia.app.sprint.flow.plan; - -import io.github.scitia.aleatoricism.flows.api.Waypoint; -import io.github.scitia.aleatoricism.flows.execution.ExecutionContext; -import io.github.scitia.app.sprint.api.IssueDto; -import io.github.scitia.app.sprint.api.SprintPlanningRequest; -import io.github.scitia.app.sprint.flow.SprintFlows; -import org.springframework.util.CollectionUtils; -import org.springframework.util.StringUtils; - -public class ValidateSprintPlanningRequestWaypoint implements Waypoint { - - @Override - public SprintPlanningRequest handle(SprintPlanningRequest input, ExecutionContext context) throws Exception { - if (input == null) { - throw new IllegalArgumentException("Sprint planning request cannot be null."); - } - if (!StringUtils.hasText(input.name())) { - throw new IllegalArgumentException("Sprint name cannot be empty."); - } - if (!StringUtils.hasText(input.goal())) { - throw new IllegalArgumentException("Sprint goal cannot be empty."); - } - if (CollectionUtils.isEmpty(input.issues())) { - throw new IllegalArgumentException("Sprint must have at least one issue."); - } - for (IssueDto issue : input.issues()) { - validateIssue(issue); - } - - context.getStore().setSprintPlanningRequest(input); - - return input; - } - - private void validateIssue(IssueDto issue) { - if (issue == null) { - throw new IllegalArgumentException("Issue cannot be null."); - } - if (!StringUtils.hasText(issue.name())) { - throw new IllegalArgumentException("Issue name cannot be empty."); - } - if (!StringUtils.hasText(issue.description())) { - throw new IllegalArgumentException("Issue description cannot be empty."); - } - if (!StringUtils.hasText(issue.reporter())) { - throw new IllegalArgumentException("Issue reporter cannot be empty."); - } - if (issue.estimation() == null || issue.estimation() <= 0) { - throw new IllegalArgumentException("Issue estimation must be a positive number."); - } - if (CollectionUtils.isEmpty(issue.acceptanceCriteria())) { - throw new IllegalArgumentException("Issue must have at least one acceptance criterion."); - } - } -} - diff --git a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/flow/plan/store/SprintPlanningStore.java b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/flow/plan/store/SprintPlanningStore.java new file mode 100644 index 0000000..94ca33d --- /dev/null +++ b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/flow/plan/store/SprintPlanningStore.java @@ -0,0 +1,13 @@ +package io.github.scitia.app.sprint.flow.plan.store; + +import io.github.scitia.app.sprint.flow.api.SprintPlanningRequest; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +public class SprintPlanningStore { + private SprintPlanningRequest sprintPlanningRequest; +} diff --git a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/flow/plan/AddIssuesToSprintWaypoint.java b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/flow/plan/waypoint/AddIssuesToSprintWaypoint.java similarity index 65% rename from aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/flow/plan/AddIssuesToSprintWaypoint.java rename to aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/flow/plan/waypoint/AddIssuesToSprintWaypoint.java index 315a48f..8f7bf52 100644 --- a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/flow/plan/AddIssuesToSprintWaypoint.java +++ b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/flow/plan/waypoint/AddIssuesToSprintWaypoint.java @@ -1,15 +1,15 @@ -package io.github.scitia.app.sprint.flow.plan; +package io.github.scitia.app.sprint.flow.plan.waypoint; import io.github.scitia.aleatoricism.flows.api.Waypoint; import io.github.scitia.aleatoricism.flows.execution.ExecutionContext; -import io.github.scitia.app.sprint.domain.Issue; -import io.github.scitia.app.sprint.domain.Sprint; -import io.github.scitia.app.sprint.flow.SprintFlows; +import io.github.scitia.app.sprint.domain.issue.Issue; +import io.github.scitia.app.sprint.domain.sprint.Sprint; +import io.github.scitia.app.sprint.flow.plan.store.SprintPlanningStore; -public class AddIssuesToSprintWaypoint implements Waypoint { +public class AddIssuesToSprintWaypoint implements Waypoint { @Override - public Sprint handle(Sprint sprint, ExecutionContext context) { + public Sprint handle(Sprint sprint, ExecutionContext context) { context.getStore().getSprintPlanningRequest().issues().forEach(issueDto -> { Issue issue = new Issue(); issue.setName(issueDto.name()); diff --git a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/flow/plan/CreateSprintEntityWaypoint.java b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/flow/plan/waypoint/CreateSprintEntityWaypoint.java similarity index 55% rename from aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/flow/plan/CreateSprintEntityWaypoint.java rename to aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/flow/plan/waypoint/CreateSprintEntityWaypoint.java index 55aa2e9..24dc672 100644 --- a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/flow/plan/CreateSprintEntityWaypoint.java +++ b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/flow/plan/waypoint/CreateSprintEntityWaypoint.java @@ -1,16 +1,15 @@ -package io.github.scitia.app.sprint.flow.plan; +package io.github.scitia.app.sprint.flow.plan.waypoint; import io.github.scitia.aleatoricism.flows.api.Waypoint; import io.github.scitia.aleatoricism.flows.execution.ExecutionContext; -import io.github.scitia.app.sprint.api.SprintPlanningRequest; -import io.github.scitia.app.sprint.domain.Sprint; -import io.github.scitia.app.sprint.flow.SprintFlows; +import io.github.scitia.app.sprint.flow.api.SprintPlanningRequest; +import io.github.scitia.app.sprint.domain.sprint.Sprint; +import io.github.scitia.app.sprint.flow.plan.store.SprintPlanningStore; -public class CreateSprintEntityWaypoint implements Waypoint { +public class CreateSprintEntityWaypoint implements Waypoint { @Override - public Sprint handle(SprintPlanningRequest input, ExecutionContext context) throws Exception { - + public Sprint handle(SprintPlanningRequest input, ExecutionContext context) { Sprint sprint = new Sprint(); sprint.setName(input.name()); sprint.setGoal(input.goal()); diff --git a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/flow/plan/PersistSprintWaypoint.java b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/flow/plan/waypoint/PersistSprintWaypoint.java similarity index 54% rename from aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/flow/plan/PersistSprintWaypoint.java rename to aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/flow/plan/waypoint/PersistSprintWaypoint.java index ecc6260..f57abf4 100644 --- a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/flow/plan/PersistSprintWaypoint.java +++ b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/flow/plan/waypoint/PersistSprintWaypoint.java @@ -1,21 +1,21 @@ -package io.github.scitia.app.sprint.flow.plan; +package io.github.scitia.app.sprint.flow.plan.waypoint; import io.github.scitia.aleatoricism.flows.api.Waypoint; import io.github.scitia.aleatoricism.flows.execution.ExecutionContext; -import io.github.scitia.app.sprint.domain.Sprint; -import io.github.scitia.app.sprint.flow.SprintFlows; -import io.github.scitia.app.sprint.infrastructure.SprintRepository; +import io.github.scitia.app.sprint.domain.sprint.Sprint; +import io.github.scitia.app.sprint.flow.plan.store.SprintPlanningStore; +import io.github.scitia.app.sprint.domain.sprint.SprintRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; @Component @RequiredArgsConstructor -public class PersistSprintWaypoint implements Waypoint { +public class PersistSprintWaypoint implements Waypoint { private final SprintRepository sprintRepository; @Override - public Sprint handle(Sprint sprint, ExecutionContext context) { + public Sprint handle(Sprint sprint, ExecutionContext context) { return sprintRepository.save(sprint); } } diff --git a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/flow/plan/waypoint/ValidateSprintPlanningRequestWaypoint.java b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/flow/plan/waypoint/ValidateSprintPlanningRequestWaypoint.java new file mode 100644 index 0000000..2ef1f1a --- /dev/null +++ b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/app/sprint/flow/plan/waypoint/ValidateSprintPlanningRequestWaypoint.java @@ -0,0 +1,20 @@ +package io.github.scitia.app.sprint.flow.plan.waypoint; + +import io.github.scitia.aleatoricism.flows.api.Waypoint; +import io.github.scitia.aleatoricism.flows.execution.ExecutionContext; +import io.github.scitia.app.sprint.flow.api.SprintPlanningRequest; +import io.github.scitia.app.sprint.flow.plan.store.SprintPlanningStore; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +@Service +@Validated +public class ValidateSprintPlanningRequestWaypoint implements Waypoint { + + @Override + public SprintPlanningRequest handle(SprintPlanningRequest input, ExecutionContext context) { + context.getStore().setSprintPlanningRequest(input); + return input; + } +} + diff --git a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/config/aleatoricism/controller/AleatoricismChainController.java b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/config/aleatoricism/controller/AleatoricismChainController.java index 0c95251..a01d873 100644 --- a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/config/aleatoricism/controller/AleatoricismChainController.java +++ b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/config/aleatoricism/controller/AleatoricismChainController.java @@ -17,7 +17,7 @@ import java.util.Map; @RestController -@RequestMapping(path = "/api/aleachain", produces = MediaType.APPLICATION_JSON_VALUE) +@RequestMapping(path = "/api/chain", produces = MediaType.APPLICATION_JSON_VALUE) public class AleatoricismChainController { private final AleatoricCopilotGateway gateway; diff --git a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/config/aleatoricism/core/AleatoricCopilotGateway.java b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/config/aleatoricism/core/AleatoricCopilotGateway.java index 4de5488..dc03308 100644 --- a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/config/aleatoricism/core/AleatoricCopilotGateway.java +++ b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/config/aleatoricism/core/AleatoricCopilotGateway.java @@ -79,8 +79,7 @@ public AleatoricCommandResponse execute(@Valid AleatoricCommandRequest request) var done = new CompletableFuture(); session.on(SessionIdleEvent.class, _ -> done.complete(null)); - - session.send(new MessageOptions().setPrompt(buildAgentPrompt(request))).get(); + session.sendAndWait(new MessageOptions().setPrompt(buildAgentPrompt(request))).get(); done.get(); } catch (InterruptedException exception) { Thread.currentThread().interrupt(); @@ -123,6 +122,7 @@ private String buildAgentPrompt(AleatoricCommandRequest request) { metadataJson = String.valueOf(request.metadata()); } + return """ You are an execution planner for business tools. Choose tool(s) from the catalog and invoke them with proper JSON arguments. diff --git a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/config/aleatoricism/tools/app/agile/AgileSprintPlanningToolHandler.java b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/config/aleatoricism/tools/app/agile/AgileSprintPlanningToolHandler.java index f29d560..d423229 100644 --- a/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/config/aleatoricism/tools/app/agile/AgileSprintPlanningToolHandler.java +++ b/aleatoricism-spring-boot-sample-app/src/main/java/io/github/scitia/config/aleatoricism/tools/app/agile/AgileSprintPlanningToolHandler.java @@ -4,15 +4,14 @@ import com.github.copilot.sdk.json.ToolHandler; import com.github.copilot.sdk.json.ToolInvocation; import io.github.scitia.aleatoricism.flows.engine.FlowEngine; -import io.github.scitia.app.sprint.api.SprintPlanningRequest; -import io.github.scitia.app.sprint.domain.Sprint; +import io.github.scitia.app.sprint.domain.sprint.Sprint; +import io.github.scitia.app.sprint.domain.sprint.SprintMapper; import io.github.scitia.app.sprint.flow.SprintFlows; -import io.github.scitia.app.sprint.mapper.SprintMapper; +import io.github.scitia.app.sprint.flow.api.SprintPlanningRequest; import io.github.scitia.config.aleatoricism.tools.AgenticBusinessTool; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; -import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; @@ -55,8 +54,7 @@ public Map inputSchema() { ) ) - ), - "required", List.of("name", "goal") + ) ) ); } diff --git a/aleatoricism-spring-boot-sample-app/src/main/resources/aleatoricism.md b/aleatoricism-spring-boot-sample-app/src/main/resources/aleatoricism.md index 828d522..139597f 100644 --- a/aleatoricism-spring-boot-sample-app/src/main/resources/aleatoricism.md +++ b/aleatoricism-spring-boot-sample-app/src/main/resources/aleatoricism.md @@ -1,68 +1,2 @@ -# Scrum Processes - Aleatoricism Flow Router -## Overview - -This application implements three core Scrum processes as agentic workflows. The HTTP router will analyze requests -and route them to the appropriate Scrum process based on the intent and path. - -## Scrum Processes and Endpoints - -### 1. Sprint Planning -- **Path**: `/scrum/planning` or `/scrum/sprint/{sprintId}/planning` -- **Method**: POST -- **Purpose**: Plan a sprint by selecting backlog items, estimating workload, and validating against team capacity -- **Tool**: `scrum_sprint_planning` -- **Practical aspects**: - - Validates story points against team capacity - - Detects capacity overflow situations - - Commits specific backlog items to sprint - - Ensures realistic sprint goals - - Emits audit trail for commitment tracking - -## Request Format - -All Scrum process requests should: -- Use **POST** method -- Include a **JSON body** with process-specific parameters -- Follow the input schema defined by each tool handler - -### Example Request Paths: -``` -POST /scrum/planning -POST /scrum/sprint/550e8400-e29b-41d4-a716-446655440000/planning -``` - -## Response Format - -All endpoints return a JSON response with: -- ID of the created/processed entity -- Status of the operation -- Relevant metadata for the Scrum process -- Audit trail information - -## Tool Availability - -Available Scrum tools: -- `scrum_sprint_planning` - Plan sprint backlog and validate capacity - -## Error Handling - -If the AI model cannot safely execute a request: -- Return a clear error message describing the issue -- Do not attempt to execute if the intent is unclear -- Always validate that required parameters are present -- Provide helpful feedback on missing or invalid data - -## Workflow Stages - -Each Scrum process follows this pattern: -1. **Normalize** - Sanitize input, apply defaults, handle missing values -2. **Build** - Create domain object with calculated values -3. **Audit** - Emit event for process tracking and monitoring - ---- - -**Note**: Modify this file to customize Scrum process handling. Restart the application for changes to take effect. - -For benchmarking and performance testing, all three processes are instrumented with audit trails. diff --git a/aleatoricism-spring-boot-sample-app/src/main/resources/application.yaml b/aleatoricism-spring-boot-sample-app/src/main/resources/application.yaml index 9b779d5..76f8d04 100644 --- a/aleatoricism-spring-boot-sample-app/src/main/resources/application.yaml +++ b/aleatoricism-spring-boot-sample-app/src/main/resources/application.yaml @@ -6,6 +6,16 @@ server: spring: application: name: aleatoricism-app + datasource: + url: jdbc:postgresql://localhost:5432/aleatoricismdb + username: appuser + password: topsecret + jpa: + hibernate: + ddl-auto: update + show-sql: true + open-in-view: false + generate-ddl: true aleatoricism: auto-router: diff --git a/aleatoricism-spring-boot-sample-app/src/test/java/io/github/scitia/aleachain/tools/AgileSprintPlanningToolHandlerTest.java b/aleatoricism-spring-boot-sample-app/src/test/java/io/github/scitia/aleachain/tools/AgileSprintPlanningToolHandlerTest.java index 6764dad..7bc08ea 100644 --- a/aleatoricism-spring-boot-sample-app/src/test/java/io/github/scitia/aleachain/tools/AgileSprintPlanningToolHandlerTest.java +++ b/aleatoricism-spring-boot-sample-app/src/test/java/io/github/scitia/aleachain/tools/AgileSprintPlanningToolHandlerTest.java @@ -2,7 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.github.copilot.sdk.json.ToolInvocation; -import io.github.scitia.app.sprint.api.SprintDto; +import io.github.scitia.app.sprint.domain.sprint.SprintDto; import io.github.scitia.config.aleatoricism.tools.app.agile.AgileSprintPlanningToolHandler; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired;