Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,24 @@ public S output(Function<AgenticScope, Object> output) {

@SuppressWarnings("unchecked")
public S errorHandler(Function<ErrorContext, ErrorRecoveryResult> errorHandler) {
// TODO: implement
return (S) this;
}

@Override
public Workflow getDefinition() {
return this.workflowBuilder.build();
}

@SuppressWarnings("unchecked")
public S name(String name) {
this.workflowBuilder.document(d -> d.name(name));
return (S) this;
}

@SuppressWarnings("unchecked")
public S description(String description) {
this.workflowBuilder.document(d -> d.summary(description));
return (S) this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import dev.langchain4j.agentic.workflow.ParallelAgentService;
import io.serverlessworkflow.impl.ExecutorServiceHolder;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;

public class ParallelAgentServiceImpl<T> extends AbstractAgentService<T, ParallelAgentService<T>>
Expand All @@ -32,12 +33,6 @@ public static <T> ParallelAgentService<T> builder(Class<T> agentServiceClass) {
return new ParallelAgentServiceImpl<>(agentServiceClass);
}

@Override
public ParallelAgentService<T> executorService(ExecutorService executorService) {
this.workflowExecBuilder.withExecutorFactory(new ExecutorServiceHolder(executorService));
return this;
}

@Override
public ParallelAgentService<T> subAgents(Object... agents) {
this.workflowBuilder.tasks(t -> t.parallel(agents));
Expand All @@ -48,4 +43,16 @@ public ParallelAgentService<T> subAgents(Object... agents) {
public ParallelAgentService<T> subAgents(List<AgentExecutor> agentExecutors) {
return this.subAgents(agentExecutors.toArray());
}

@Override
public ParallelAgentService<T> executor(Executor executor) {
if (!(executor instanceof ExecutorService)) {
throw new IllegalArgumentException(
"ExecutorService is required for the ParallelAgentService");
}
// TODO: create an adapter or change or internal holder to accept a plain `Executor`.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fjtirado do you think this is reasonable? Or do we must use an ExecutorService?

this.workflowExecBuilder.withExecutorFactory(
new ExecutorServiceHolder((ExecutorService) executor));
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,15 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
// outputName
if (method.getDeclaringClass() == AgentSpecification.class) {
return switch (method.getName()) {
case "name" -> this.workflow.getDocument().getName();
case "description" -> this.workflow.getDocument().getSummary();
case "outputName" -> outputName();
default ->
throw new UnsupportedOperationException(
"Unknown method on AgentInstance class : " + method.getName());
};
}
// withCognisphere
// withAgenticScope
if (method.getDeclaringClass() == AgenticScopeOwner.class) {
// Ingest the workflow input as a AgenticScope object
// Later, retrieve it and start the workflow with it as input.
Expand All @@ -99,11 +101,11 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
case "registry" -> registry;
default ->
throw new UnsupportedOperationException(
"Unknown method on CognisphereOwner class : " + method.getName());
"Unknown method on AgenticScopeOwner class : " + method.getName());
};
}
// getAgenticScope
// evictCognisphere
// evictAgenticScope
if (method.getDeclaringClass() == AgenticScopeAccess.class) {
return switch (method.getName()) {
case "getAgenticScope" -> registry().get(args[0]);
Expand Down Expand Up @@ -132,7 +134,7 @@ private Object executeWorkflow(AgenticScope agenticScope, Method method, Object[
.orElseThrow(
() ->
new IllegalArgumentException(
"Workflow hasn't returned a Cognisphere object."));
"Workflow hasn't returned a AgenticScope object."));
Object result = output.readState(outputName());

return method.getReturnType().equals(ResultWithAgenticScope.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public void testAgent() throws ExecutionException, InterruptedException {

when(storySeedAgent.invoke(eq("A Great Story"))).thenReturn("storySeedAgent");
when(storySeedAgent.outputName()).thenReturn("premise");
when(storySeedAgent.name()).thenReturn("storySeedAgent");

Workflow workflow =
AgentWorkflowBuilder.workflow("storyFlow")
Expand Down Expand Up @@ -72,12 +73,15 @@ public void testAgents() throws ExecutionException, InterruptedException {

when(storySeedAgent.invoke(eq("A Great Story"))).thenReturn("storySeedAgent");
when(storySeedAgent.outputName()).thenReturn("premise");
when(storySeedAgent.name()).thenReturn("storySeedAgent");

when(plotAgent.invoke(eq("storySeedAgent"))).thenReturn("plotAgent");
when(plotAgent.outputName()).thenReturn("plot");
when(plotAgent.name()).thenReturn("plotAgent");

when(sceneAgent.invoke(eq("plotAgent"))).thenReturn("sceneAgent");
when(sceneAgent.outputName()).thenReturn("story");
when(sceneAgent.name()).thenReturn("sceneAgent");

Workflow workflow =
AgentWorkflowBuilder.workflow("storyFlow")
Expand Down Expand Up @@ -112,12 +116,15 @@ public void testSequence() throws ExecutionException, InterruptedException {

when(storySeedAgent.invoke(eq("A Great Story"))).thenReturn("storySeedAgent");
when(storySeedAgent.outputName()).thenReturn("premise");
when(storySeedAgent.name()).thenReturn("storySeedAgent");

when(plotAgent.invoke(eq("storySeedAgent"))).thenReturn("plotAgent");
when(plotAgent.outputName()).thenReturn("plot");
when(plotAgent.name()).thenReturn("plotAgent");

when(sceneAgent.invoke(eq("plotAgent"))).thenReturn("sceneAgent");
when(sceneAgent.outputName()).thenReturn("story");
when(sceneAgent.name()).thenReturn("sceneAgent");

Workflow workflow =
AgentWorkflowBuilder.workflow("storyFlow")
Expand Down Expand Up @@ -149,12 +156,15 @@ public void testParallel() throws ExecutionException, InterruptedException {

when(setting.invoke(eq("sci-fi"))).thenReturn("Fake conflict response");
when(setting.outputName()).thenReturn("setting");
when(setting.name()).thenReturn("setting");

when(hero.invoke(eq("sci-fi"))).thenReturn("Fake hero response");
when(hero.outputName()).thenReturn("hero");
when(hero.name()).thenReturn("hero");

when(conflict.invoke(eq("sci-fi"))).thenReturn("Fake setting response");
when(conflict.outputName()).thenReturn("conflict");
when(conflict.name()).thenReturn("conflict");

Workflow workflow =
AgentWorkflowBuilder.workflow("parallelFlow")
Expand Down Expand Up @@ -193,12 +203,15 @@ public void testSeqAndThenParallel() throws ExecutionException, InterruptedExcep

when(factAgent.invoke(eq("alien"))).thenReturn("Some Fact about aliens");
when(factAgent.outputName()).thenReturn("fact");
when(factAgent.name()).thenReturn("fact");

when(cultureAgent.invoke(eq("Some Fact about aliens"))).thenReturn(cultureTraits);
when(cultureAgent.outputName()).thenReturn("culture");
when(cultureAgent.name()).thenReturn("culture");

when(technologyAgent.invoke(eq("Some Fact about aliens"))).thenReturn(technologyTraits);
when(technologyAgent.outputName()).thenReturn("technology");
when(technologyAgent.name()).thenReturn("technology");
Workflow workflow =
AgentWorkflowBuilder.workflow("alienCultureFlow")
.tasks(
Expand Down Expand Up @@ -237,11 +250,13 @@ public void humanInTheLoop() throws ExecutionException, InterruptedException {
eq("Discuss project updates")))
.thenReturn("Drafted meeting invitation for John Doe");
when(meetingInvitationDraft.outputName()).thenReturn("draft");
when(meetingInvitationDraft.name()).thenReturn("draft");

final MeetingInvitationStyle meetingInvitationStyle = mock(MeetingInvitationStyle.class);
when(meetingInvitationStyle.invoke(eq("Drafted meeting invitation for John Doe"), eq("formal")))
.thenReturn("Styled meeting invitation for John Doe");
when(meetingInvitationStyle.outputName()).thenReturn("styled");
when(meetingInvitationStyle.name()).thenReturn("styled");

AtomicReference<String> request = new AtomicReference<>();

Expand Down
7 changes: 4 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@

<!-- Dependencies versions, please keep in alphabetical order -->
<version.ch.qos.logback>1.5.18</version.ch.qos.logback>
<version.com.fasterxml.jackson>2.19.2</version.com.fasterxml.jackson>
<version.com.fasterxml.jackson>2.20.0</version.com.fasterxml.jackson>
<version.com.fasterxml.jackson.annotations>2.20</version.com.fasterxml.jackson.annotations>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a bug on their side, they released without the patch version number..

<version.com.networknt>1.5.8</version.com.networknt>
<version.com.squareup.okhttp3.mockwebserver>5.1.0</version.com.squareup.okhttp3.mockwebserver>
<version.io.cloudevents>4.0.1</version.io.cloudevents>
Expand All @@ -90,7 +91,7 @@
<version.org.hibernate.validator>9.0.1.Final</version.org.hibernate.validator>
<version.org.glassfish.expressly>6.0.0</version.org.glassfish.expressly>
<!-- Experimental modules from langchain4j -->
<version.dev.langchain4j.beta>1.3.0-beta9</version.dev.langchain4j.beta>
<version.dev.langchain4j.beta>1.4.0-beta10</version.dev.langchain4j.beta>
<!-- Base langchain4j version -->
<version.dev.langchain4j>1.4.0</version.dev.langchain4j>

Expand Down Expand Up @@ -136,7 +137,7 @@
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${version.com.fasterxml.jackson}</version>
<version>${version.com.fasterxml.jackson.annotations}</version>
</dependency>
<dependency>
<groupId>io.cloudevents</groupId>
Expand Down