Skip to content

Commit b7ad49d

Browse files
committed
post review
Signed-off-by: Dmitrii Tikhomirov <chani.liet@gmail.com>
1 parent c61d496 commit b7ad49d

File tree

2 files changed

+391
-75
lines changed

2 files changed

+391
-75
lines changed

experimental/fluent/agentic/src/test/java/io/serverlessworkflow/fluent/agentic/LC4JEquivalenceIT.java

Lines changed: 62 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,28 @@
1818
import static io.serverlessworkflow.fluent.agentic.AgentWorkflowBuilder.workflow;
1919
import static io.serverlessworkflow.fluent.agentic.dsl.AgenticDSL.conditional;
2020
import static io.serverlessworkflow.fluent.agentic.dsl.AgenticDSL.doTasks;
21+
import static io.serverlessworkflow.fluent.agentic.dsl.AgenticDSL.loop;
2122
import static io.serverlessworkflow.fluent.spec.dsl.DSL.tasks;
2223
import static org.assertj.core.api.Assertions.assertThat;
2324
import static org.junit.jupiter.api.Assertions.assertEquals;
2425

2526
import dev.langchain4j.agentic.AgenticServices;
27+
import dev.langchain4j.agentic.scope.AgenticScope;
2628
import dev.langchain4j.agentic.workflow.HumanInTheLoop;
2729
import io.serverlessworkflow.api.types.FlowDirectiveEnum;
2830
import io.serverlessworkflow.api.types.TaskItem;
2931
import io.serverlessworkflow.api.types.Workflow;
3032
import io.serverlessworkflow.api.types.func.CallTaskJava;
3133
import io.serverlessworkflow.api.types.func.ForTaskFunction;
34+
import io.serverlessworkflow.fluent.agentic.dsl.AgenticDSL;
35+
import io.serverlessworkflow.fluent.spec.dsl.DSL;
3236
import io.serverlessworkflow.impl.WorkflowApplication;
37+
3338
import java.util.List;
3439
import java.util.Map;
3540
import java.util.concurrent.atomic.AtomicReference;
41+
import java.util.function.Predicate;
42+
3643
import org.junit.jupiter.api.DisplayName;
3744
import org.junit.jupiter.api.Test;
3845

@@ -41,11 +48,11 @@ public class LC4JEquivalenceIT {
4148
@Test
4249
@DisplayName("Sequential agents via DSL.sequence(...)")
4350
public void sequentialWorkflow() {
44-
var a1 = AgentsUtils.newCreativeWriter();
45-
var a2 = AgentsUtils.newAudienceEditor();
46-
var a3 = AgentsUtils.newStyleEditor();
51+
var creativeWriter = AgentsUtils.newCreativeWriter();
52+
var audienceEditor = AgentsUtils.newAudienceEditor();
53+
var styleEditor = AgentsUtils.newStyleEditor();
4754

48-
Workflow wf = workflow("seqFlow").tasks(tasks -> tasks.sequence("process", a1, a2, a3)).build();
55+
Workflow wf = workflow("seqFlow").tasks(tasks -> tasks.sequence("process", creativeWriter, audienceEditor, styleEditor)).build();
4956

5057
List<TaskItem> items = wf.getDo();
5158
assertThat(items).hasSize(3);
@@ -56,10 +63,10 @@ public void sequentialWorkflow() {
5663
items.forEach(it -> assertThat(it.getTask().getCallTask()).isInstanceOf(CallTaskJava.class));
5764

5865
Map<String, Object> input =
59-
Map.of(
60-
"topic", "dragons and wizards",
61-
"style", "fantasy",
62-
"audience", "young adults");
66+
Map.of(
67+
"topic", "dragons and wizards",
68+
"style", "fantasy",
69+
"audience", "young adults");
6370

6471
Map<String, Object> result;
6572
try (WorkflowApplication app = WorkflowApplication.builder().build()) {
@@ -79,9 +86,9 @@ public void loopWorkflow() {
7986
var editor = AgentsUtils.newStyleEditor();
8087

8188
Workflow wf =
82-
AgentWorkflowBuilder.workflow("retryFlow")
83-
.loop("reviewLoop", c -> c.readState("score", 0).doubleValue() >= 0.8, scorer, editor)
84-
.build();
89+
AgentWorkflowBuilder.workflow("retryFlow")
90+
.loop("reviewLoop", c -> c.readState("score", 0).doubleValue() >= 0.8, scorer, editor)
91+
.build();
8592

8693
List<TaskItem> items = wf.getDo();
8794
assertThat(items).hasSize(1);
@@ -90,12 +97,12 @@ public void loopWorkflow() {
9097
assertThat(fn.getDo()).isNotNull();
9198
assertThat(fn.getDo()).hasSize(2);
9299
fn.getDo()
93-
.forEach(si -> assertThat(si.getTask().getCallTask()).isInstanceOf(CallTaskJava.class));
100+
.forEach(si -> assertThat(si.getTask().getCallTask()).isInstanceOf(CallTaskJava.class));
94101

95102
Map<String, Object> input =
96-
Map.of(
97-
"story", "dragons and wizards",
98-
"style", "comedy");
103+
Map.of(
104+
"story", "dragons and wizards",
105+
"style", "comedy");
99106

100107
Map<String, Object> result;
101108
try (WorkflowApplication app = WorkflowApplication.builder().build()) {
@@ -113,17 +120,13 @@ public void loopWorkflowWithMaxIterations() {
113120
var scorer = AgentsUtils.newStyleScorer();
114121
var editor = AgentsUtils.newStyleEditor();
115122

123+
124+
Predicate<AgenticScope> until = s -> s.readState("score", 0).doubleValue() >= 0.8;
125+
116126
Workflow wf =
117-
AgentWorkflowBuilder.workflow("maxFlow")
118-
.tasks(
119-
d ->
120-
d.loop(
121-
"limit",
122-
l ->
123-
l.maxIterations(5)
124-
.exitCondition(c -> c.readState("score", 0).doubleValue() >= 0.8)
125-
.subAgents("sub", scorer, editor)))
126-
.build();
127+
AgentWorkflowBuilder.workflow("retryFlow")
128+
.tasks(loop(until, scorer, 5, editor))
129+
.build();
127130

128131
List<TaskItem> items = wf.getDo();
129132
assertThat(items).hasSize(1);
@@ -132,12 +135,12 @@ public void loopWorkflowWithMaxIterations() {
132135
assertThat(fn.getDo()).isNotNull();
133136
assertThat(fn.getDo()).hasSize(2);
134137
fn.getDo()
135-
.forEach(si -> assertThat(si.getTask().getCallTask()).isInstanceOf(CallTaskJava.class));
138+
.forEach(si -> assertThat(si.getTask().getCallTask()).isInstanceOf(CallTaskJava.class));
136139

137140
Map<String, Object> input =
138-
Map.of(
139-
"story", "dragons and wizards",
140-
"style", "comedy");
141+
Map.of(
142+
"story", "dragons and wizards",
143+
"style", "comedy");
141144

142145
Map<String, Object> result;
143146
try (WorkflowApplication app = WorkflowApplication.builder().build()) {
@@ -152,10 +155,10 @@ public void loopWorkflowWithMaxIterations() {
152155
@Test
153156
@DisplayName("Parallel agents via DSL.parallel(...)")
154157
public void parallelWorkflow() {
155-
var a1 = AgentsUtils.newFoodExpert();
156-
var a2 = AgentsUtils.newMovieExpert();
158+
var foodExpert = AgentsUtils.newFoodExpert();
159+
var movieExpert = AgentsUtils.newMovieExpert();
157160

158-
Workflow wf = workflow("forkFlow").parallel("fanout", a1, a2).build();
161+
Workflow wf = workflow("forkFlow").parallel("fanout", foodExpert, movieExpert).build();
159162

160163
List<TaskItem> items = wf.getDo();
161164
assertThat(items).hasSize(1);
@@ -183,11 +186,11 @@ public void parallelWorkflow() {
183186
@Test
184187
@DisplayName("Error handling with agents")
185188
public void errorHandling() {
186-
var a1 = AgentsUtils.newCreativeWriter();
187-
var a2 = AgentsUtils.newAudienceEditor();
188-
var a3 = AgentsUtils.newStyleEditor();
189+
var creativeWriter = AgentsUtils.newCreativeWriter();
190+
var audienceEditor = AgentsUtils.newAudienceEditor();
191+
var styleEditor = AgentsUtils.newStyleEditor();
189192

190-
Workflow wf = workflow("seqFlow").tasks(tasks -> tasks.sequence("process", a1, a2, a3)).build();
193+
Workflow wf = workflow("seqFlow").tasks(tasks -> tasks.sequence("process", creativeWriter, audienceEditor, styleEditor)).build();
191194

192195
List<TaskItem> items = wf.getDo();
193196
assertThat(items).hasSize(3);
@@ -198,9 +201,9 @@ public void errorHandling() {
198201
items.forEach(it -> assertThat(it.getTask().getCallTask()).isInstanceOf(CallTaskJava.class));
199202

200203
Map<String, Object> input =
201-
Map.of(
202-
"style", "fantasy",
203-
"audience", "young adults");
204+
Map.of(
205+
"style", "fantasy",
206+
"audience", "young adults");
204207

205208
Map<String, Object> result;
206209
try (WorkflowApplication app = WorkflowApplication.builder().build()) {
@@ -218,27 +221,19 @@ public void errorHandling() {
218221
public void conditionalWorkflow() {
219222

220223
var category = AgentsUtils.newCategoryRouter();
221-
var a1 = AgentsUtils.newMedicalExpert();
222-
var a2 = AgentsUtils.newTechnicalExpert();
223-
var a3 = AgentsUtils.newLegalExpert();
224+
var medicalExpert = AgentsUtils.newMedicalExpert();
225+
var technicalExpert = AgentsUtils.newTechnicalExpert();
226+
var legalExpert = AgentsUtils.newLegalExpert();
224227

225228
Workflow wf =
226-
workflow("conditional")
227-
.sequence("process", category)
228-
.tasks(
229-
t ->
230-
t.switchCase(
231-
p ->
232-
p.onPredicate(
233-
item ->
234-
item.when(Agents.RequestCategory.UNKNOWN::equals)
235-
.then(FlowDirectiveEnum.END))))
236-
.tasks(
237-
doTasks(
238-
conditional(Agents.RequestCategory.MEDICAL::equals, a1),
239-
conditional(Agents.RequestCategory.TECHNICAL::equals, a2),
240-
conditional(Agents.RequestCategory.LEGAL::equals, a3)))
241-
.build();
229+
workflow("conditional")
230+
.sequence("process", category)
231+
.tasks(
232+
doTasks(
233+
conditional(Agents.RequestCategory.MEDICAL::equals, medicalExpert),
234+
conditional(Agents.RequestCategory.TECHNICAL::equals, technicalExpert),
235+
conditional(Agents.RequestCategory.LEGAL::equals, legalExpert)))
236+
.build();
242237

243238
Map<String, Object> input = Map.of("question", "What is the best treatment for a common cold?");
244239

@@ -259,17 +254,17 @@ public void humanInTheLoop() {
259254
AtomicReference<String> request = new AtomicReference<>();
260255

261256
HumanInTheLoop humanInTheLoop =
262-
AgenticServices.humanInTheLoopBuilder()
263-
.description("Please provide the horoscope request")
264-
.inputName("request")
265-
.outputName("sign")
266-
.requestWriter(q -> request.set("My name is Mario. What is my horoscope?"))
267-
.responseReader(() -> "piscis")
268-
.build();
257+
AgenticServices.humanInTheLoopBuilder()
258+
.description("Please provide the horoscope request")
259+
.inputName("request")
260+
.outputName("sign")
261+
.requestWriter(q -> request.set("My name is Mario. What is my horoscope?"))
262+
.responseReader(() -> "piscis")
263+
.build();
269264

270-
var a1 = AgentsUtils.newAstrologyAgent();
265+
var astrologyAgent = AgentsUtils.newAstrologyAgent();
271266

272-
Workflow wf = workflow("seqFlow").sequence("process", a1, humanInTheLoop).build();
267+
Workflow wf = workflow("seqFlow").sequence("process", astrologyAgent, humanInTheLoop).build();
273268

274269
assertThat(wf.getDo()).hasSize(2);
275270

0 commit comments

Comments
 (0)