1515 */
1616package 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 .*;
1829import static io .serverlessworkflow .fluent .agentic .langchain4j .Agents .AudienceEditor ;
1930import static io .serverlessworkflow .fluent .agentic .langchain4j .Agents .CreativeWriter ;
2031import static io .serverlessworkflow .fluent .agentic .langchain4j .Agents .StyleEditor ;
2132import 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 ;
2236import static org .mockito .ArgumentMatchers .any ;
2337import static org .mockito .ArgumentMatchers .eq ;
2438import static org .mockito .Mockito .spy ;
2539import static org .mockito .Mockito .verify ;
2640
27- import dev .langchain4j .agentic .AgenticServices ;
2841import dev .langchain4j .agentic .UntypedAgent ;
42+ import dev .langchain4j .agentic .scope .AgenticScope ;
2943import dev .langchain4j .agentic .workflow .WorkflowAgentsBuilder ;
44+ import io .serverlessworkflow .fluent .agentic .AgenticServices ;
45+ import io .serverlessworkflow .fluent .agentic .AgentsUtils ;
46+ import java .util .List ;
3047import java .util .Map ;
48+ import java .util .function .Function ;
49+ import java .util .function .Predicate ;
50+ import java .util .stream .IntStream ;
51+
3152import org .junit .jupiter .api .Test ;
3253
3354public 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}
0 commit comments