Skip to content

Commit 381d0e9

Browse files
committed
Added AgenticServices helper
Signed-off-by: Dmitrii Tikhomirov <[email protected]>
1 parent 286cdb9 commit 381d0e9

File tree

4 files changed

+152
-160
lines changed

4 files changed

+152
-160
lines changed

experimental/fluent/agentic-langchain4j/src/test/java/io/serverlessworkflow/fluent/agentic/langchain4j/AgenticServicesHelperTest.java

Lines changed: 0 additions & 155 deletions
This file was deleted.

experimental/fluent/agentic-langchain4j/src/test/java/io/serverlessworkflow/fluent/agentic/langchain4j/Agents.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,4 +248,10 @@ public interface EveningPlannerAgent {
248248
@Agent
249249
List<EveningPlan> plan(@V("mood") String mood);
250250
}
251+
252+
public interface HoroscopeAgent {
253+
254+
@Agent
255+
String invoke(@V("name") String name);
256+
}
251257
}

experimental/fluent/agentic-langchain4j/src/test/java/io/serverlessworkflow/fluent/agentic/langchain4j/WorkflowAgentsIT.java

Lines changed: 144 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,40 @@
1515
*/
1616
package io.serverlessworkflow.fluent.agentic.langchain4j;
1717

18+
import static io.serverlessworkflow.fluent.agentic.AgentWorkflowBuilder.workflow;
19+
import static io.serverlessworkflow.fluent.agentic.AgentsUtils.newAstrologyAgent;
20+
import static io.serverlessworkflow.fluent.agentic.AgentsUtils.newAudienceEditor;
21+
import static io.serverlessworkflow.fluent.agentic.AgentsUtils.newCreativeWriter;
22+
import static io.serverlessworkflow.fluent.agentic.AgentsUtils.newFoodExpert;
23+
import static io.serverlessworkflow.fluent.agentic.AgentsUtils.newMovieExpert;
24+
import static io.serverlessworkflow.fluent.agentic.AgentsUtils.newStyleEditor;
25+
import static io.serverlessworkflow.fluent.agentic.AgentsUtils.newStyleScorer;
26+
import static io.serverlessworkflow.fluent.agentic.AgentsUtils.newSummaryStory;
27+
import static io.serverlessworkflow.fluent.agentic.dsl.AgenticDSL.fn;
28+
import static io.serverlessworkflow.fluent.agentic.langchain4j.Agents.*;
1829
import static io.serverlessworkflow.fluent.agentic.langchain4j.Agents.AudienceEditor;
1930
import static io.serverlessworkflow.fluent.agentic.langchain4j.Agents.CreativeWriter;
2031
import static io.serverlessworkflow.fluent.agentic.langchain4j.Agents.StyleEditor;
2132
import static io.serverlessworkflow.fluent.agentic.langchain4j.Models.BASE_MODEL;
33+
import static org.junit.jupiter.api.Assertions.assertEquals;
34+
import static org.junit.jupiter.api.Assertions.assertNotNull;
35+
import static org.junit.jupiter.api.Assertions.assertTrue;
2236
import static org.mockito.ArgumentMatchers.any;
2337
import static org.mockito.ArgumentMatchers.eq;
2438
import static org.mockito.Mockito.spy;
2539
import static org.mockito.Mockito.verify;
2640

27-
import dev.langchain4j.agentic.AgenticServices;
2841
import dev.langchain4j.agentic.UntypedAgent;
42+
import dev.langchain4j.agentic.scope.AgenticScope;
2943
import dev.langchain4j.agentic.workflow.WorkflowAgentsBuilder;
44+
import io.serverlessworkflow.fluent.agentic.AgenticServices;
45+
import io.serverlessworkflow.fluent.agentic.AgentsUtils;
46+
import java.util.List;
3047
import java.util.Map;
48+
import java.util.function.Function;
49+
import java.util.function.Predicate;
50+
import java.util.stream.IntStream;
51+
3152
import org.junit.jupiter.api.Test;
3253

3354
public class WorkflowAgentsIT {
@@ -38,21 +59,21 @@ void sequential_agents_tests() {
3859

3960
CreativeWriter creativeWriter =
4061
spy(
41-
AgenticServices.agentBuilder(CreativeWriter.class)
62+
dev.langchain4j.agentic.AgenticServices.agentBuilder(CreativeWriter.class)
4263
.chatModel(BASE_MODEL)
4364
.outputName("story")
4465
.build());
4566

4667
AudienceEditor audienceEditor =
4768
spy(
48-
AgenticServices.agentBuilder(AudienceEditor.class)
69+
dev.langchain4j.agentic.AgenticServices.agentBuilder(AudienceEditor.class)
4970
.chatModel(BASE_MODEL)
5071
.outputName("story")
5172
.build());
5273

5374
StyleEditor styleEditor =
5475
spy(
55-
AgenticServices.agentBuilder(StyleEditor.class)
76+
dev.langchain4j.agentic.AgenticServices.agentBuilder(StyleEditor.class)
5677
.chatModel(BASE_MODEL)
5778
.outputName("story")
5879
.build());
@@ -77,4 +98,123 @@ void sequential_agents_tests() {
7798
verify(audienceEditor).editStory(any(), eq("young adults"));
7899
verify(styleEditor).editStory(any(), eq("fantasy"));
79100
}
101+
102+
@Test
103+
public void sequenceHelperTest() {
104+
var creativeWriter = newCreativeWriter();
105+
var audienceEditor = newAudienceEditor();
106+
var styleEditor = newStyleEditor();
107+
108+
AgentsUtils.NovelCreator novelCreator =
109+
io.serverlessworkflow.fluent.agentic.AgenticServices.of(AgentsUtils.NovelCreator.class)
110+
.flow(workflow("seqFlow").sequence(creativeWriter, audienceEditor, styleEditor))
111+
.build();
112+
113+
String story = novelCreator.createNovel("dragons and wizards", "young adults", "fantasy");
114+
assertNotNull(story);
115+
}
116+
117+
@Test
118+
public void agentAndSequenceHelperTest() {
119+
var creativeWriter = newCreativeWriter();
120+
var audienceEditor = newAudienceEditor();
121+
var styleEditor = newStyleEditor();
122+
123+
AgentsUtils.NovelCreator novelCreator =
124+
io.serverlessworkflow.fluent.agentic.AgenticServices.of(AgentsUtils.NovelCreator.class)
125+
.flow(workflow("seqFlow").agent(creativeWriter).sequence(audienceEditor, styleEditor))
126+
.build();
127+
128+
String story = novelCreator.createNovel("dragons and wizards", "young adults", "fantasy");
129+
assertNotNull(story);
130+
}
131+
132+
@Test
133+
public void agentAndSequenceAndAgentHelperTest() {
134+
var creativeWriter = newCreativeWriter();
135+
var audienceEditor = newAudienceEditor();
136+
var styleEditor = newStyleEditor();
137+
var summaryStory = newSummaryStory();
138+
139+
AgentsUtils.NovelCreator novelCreator =
140+
io.serverlessworkflow.fluent.agentic.AgenticServices.of(AgentsUtils.NovelCreator.class)
141+
.flow(
142+
workflow("seqFlow")
143+
.agent(creativeWriter)
144+
.sequence(audienceEditor, styleEditor)
145+
.agent(summaryStory))
146+
.build();
147+
148+
String story = novelCreator.createNovel("dragons and wizards", "young adults", "fantasy");
149+
assertNotNull(story);
150+
}
151+
152+
@Test
153+
public void parallelWorkflow() {
154+
var foodExpert = newFoodExpert();
155+
var movieExpert = newMovieExpert();
156+
157+
Function<Map<String, List<String>>, List<EveningPlan>> planEvening =
158+
input -> {
159+
List<String> movies = input.get("findMovie");
160+
List<String> meals = input.get("findMeal");
161+
162+
int max = Math.min(movies.size(), meals.size());
163+
return IntStream.range(0, max)
164+
.mapToObj(i -> new EveningPlan(movies.get(i), meals.get(i)))
165+
.toList();
166+
};
167+
168+
EveningPlannerAgent eveningPlannerAgent =
169+
AgenticServices.of(EveningPlannerAgent.class)
170+
.flow(workflow("parallelFlow").parallel(foodExpert, movieExpert).outputAs(planEvening))
171+
.build();
172+
List<EveningPlan> result = eveningPlannerAgent.plan("romantic");
173+
assertEquals(3, result.size());
174+
}
175+
176+
@Test
177+
public void loopTest() {
178+
var creativeWriter = newCreativeWriter();
179+
var scorer = newStyleScorer();
180+
var editor = newStyleEditor();
181+
182+
Predicate<AgenticScope> until = s -> s.readState("score", 0.0) >= 0.8;
183+
184+
StyledWriter styledWriter =
185+
AgenticServices.of(StyledWriter.class)
186+
.flow(workflow("loopFlow").agent(creativeWriter).loop(until, scorer, editor))
187+
.build();
188+
189+
String story = styledWriter.writeStoryWithStyle("dragons and wizards", "fantasy");
190+
assertNotNull(story);
191+
}
192+
193+
@Test
194+
public void humanInTheLoop() {
195+
var astrologyAgent = newAstrologyAgent();
196+
197+
var askSign =
198+
new Function<Map<String, Object>, Map<String, Object>>() {
199+
@Override
200+
public Map<String, Object> apply(Map<String, Object> holder) {
201+
System.out.println("What's your star sign?");
202+
// var sign = System.console().readLine();
203+
holder.put("sign", "piscis");
204+
return holder;
205+
}
206+
};
207+
208+
String result =
209+
AgenticServices.of(Agents.HoroscopeAgent.class)
210+
.flow(
211+
workflow("humanInTheLoop")
212+
.inputFrom(askSign)
213+
// .tasks(tasks -> tasks.callFn(fn(askSign))) // TODO should work too
214+
.agent(astrologyAgent))
215+
.build()
216+
.invoke("My name is Mario. What is my horoscope?");
217+
218+
assertNotNull(result);
219+
}
80220
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,13 @@ public void sequentialWorkflow() {
7777
@Test
7878
@DisplayName("Looping agents via DSL.loop(...)")
7979
public void loopWorkflow() {
80-
80+
var creativeWriter = AgentsUtils.newCreativeWriter();
8181
var scorer = AgentsUtils.newStyleScorer();
8282
var editor = AgentsUtils.newStyleEditor();
8383

8484
Workflow wf =
8585
AgentWorkflowBuilder.workflow("retryFlow")
86+
.agent(creativeWriter)
8687
.loop("reviewLoop", c -> c.readState("score", 0).doubleValue() >= 0.8, scorer, editor)
8788
.build();
8889

0 commit comments

Comments
 (0)