Skip to content

Commit e40c7a5

Browse files
committed
Introduce WorkflowInvocationHandler
Signed-off-by: Ricardo Zanini <ricardozanini@gmail.com>
1 parent 53e698b commit e40c7a5

File tree

11 files changed

+142
-29
lines changed

11 files changed

+142
-29
lines changed

fluent/agentic-langchain4j/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
<dependencies>
1717
<dependency>
1818
<groupId>io.serverlessworkflow</groupId>
19-
<artifactId>serverlessworkflow-experimental-types</artifactId>
19+
<artifactId>serverlessworkflow-experimental-agentic</artifactId>
2020
</dependency>
2121
<dependency>
2222
<groupId>io.serverlessworkflow</groupId>

fluent/agentic-langchain4j/src/main/java/io/serverlessworkflow/fluent/agentic/langchain4j/AbstractAgentService.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,12 @@
1616
package io.serverlessworkflow.fluent.agentic.langchain4j;
1717

1818
import dev.langchain4j.agentic.cognisphere.Cognisphere;
19+
import dev.langchain4j.agentic.internal.AgentInstance;
20+
import dev.langchain4j.agentic.internal.CognisphereOwner;
1921
import io.serverlessworkflow.api.types.Workflow;
2022
import io.serverlessworkflow.fluent.agentic.AgentWorkflowBuilder;
23+
import io.serverlessworkflow.impl.WorkflowApplication;
24+
import java.lang.reflect.Proxy;
2125
import java.util.function.Consumer;
2226
import java.util.function.Function;
2327

@@ -26,8 +30,9 @@ public abstract class AbstractAgentService<T, S> implements WorkflowDefinitionBu
2630
// Workflow OutputAs
2731
private static final Function<Cognisphere, Object> DEFAULT_OUTPUT_FUNCTION = cognisphere -> null;
2832
// Workflow InputFrom
29-
private static final Consumer<Cognisphere> DEFAULT_INIT_FUNCTION = cognisphere -> {};
33+
private static final Consumer<Cognisphere> DEFAULT_INPUT_FUNCTION = cognisphere -> {};
3034

35+
protected final WorkflowApplication.Builder workflowExecBuilder;
3136
protected final AgentWorkflowBuilder workflowBuilder;
3237
protected final Class<T> agentServiceClass;
3338

@@ -39,8 +44,18 @@ protected AbstractAgentService(String name, Class<T> agentServiceClass) {
3944
this.workflowBuilder =
4045
AgentWorkflowBuilder.workflow(name)
4146
.outputAs(DEFAULT_OUTPUT_FUNCTION)
42-
.input(i -> i.from(DEFAULT_INIT_FUNCTION));
47+
.input(i -> i.from(DEFAULT_INPUT_FUNCTION));
4348
this.agentServiceClass = agentServiceClass;
49+
this.workflowExecBuilder = WorkflowApplication.builder();
50+
}
51+
52+
@SuppressWarnings("unchecked")
53+
public T build() {
54+
return (T)
55+
Proxy.newProxyInstance(
56+
this.agentServiceClass.getClassLoader(),
57+
new Class<?>[] {agentServiceClass, AgentInstance.class, CognisphereOwner.class},
58+
new WorkflowInvocationHandler(this.workflowBuilder.build(), this.workflowExecBuilder));
4459
}
4560

4661
@SuppressWarnings("unchecked")
@@ -56,6 +71,8 @@ public S beforeCall(Consumer<Cognisphere> beforeCall) {
5671
public S outputName(String outputName) {
5772
Function<Cognisphere, Object> outputFunction = cog -> cog.readState(outputName);
5873
this.workflowBuilder.outputAs(outputFunction);
74+
this.workflowBuilder.document(
75+
d -> d.metadata(m -> m.metadata(META_KEY_OUTPUTNAME, outputName)));
5976
return (S) this;
6077
}
6178

fluent/agentic-langchain4j/src/main/java/io/serverlessworkflow/fluent/agentic/langchain4j/ConditionalAgentServiceImpl.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,6 @@ public static <T> ConditionalAgentService<T> builder(Class<T> agentServiceClass)
3434
return new ConditionalAgentServiceImpl<>(agentServiceClass);
3535
}
3636

37-
@Override
38-
public T build() {
39-
return null;
40-
}
41-
4237
@Override
4338
public ConditionalAgentService<T> subAgents(Object... agents) {
4439
this.workflowBuilder.tasks(t -> t.sequence(agents));

fluent/agentic-langchain4j/src/main/java/io/serverlessworkflow/fluent/agentic/langchain4j/LoopAgentServiceImpl.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,6 @@ public LoopAgentService<T> exitCondition(Predicate<Cognisphere> exitCondition) {
4747
return this;
4848
}
4949

50-
@Override
51-
public T build() {
52-
return null;
53-
}
54-
5550
@Override
5651
public LoopAgentService<T> subAgents(Object... agents) {
5752
this.loopAgentsBuilder.subAgents(agents);

fluent/agentic-langchain4j/src/main/java/io/serverlessworkflow/fluent/agentic/langchain4j/ParallelAgentServiceImpl.java

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@
2323
public class ParallelAgentServiceImpl<T> extends AbstractAgentService<T, ParallelAgentService<T>>
2424
implements ParallelAgentService<T> {
2525

26-
private ExecutorService executor;
27-
2826
private ParallelAgentServiceImpl(Class<T> agentServiceClass) {
2927
super(agentServiceClass);
3028
}
@@ -35,15 +33,10 @@ public static <T> ParallelAgentService<T> builder(Class<T> agentServiceClass) {
3533

3634
@Override
3735
public ParallelAgentService<T> executorService(ExecutorService executorService) {
38-
this.executor = executorService;
36+
this.workflowExecBuilder.withExecutorFactory(() -> executorService);
3937
return this;
4038
}
4139

42-
@Override
43-
public T build() {
44-
return null;
45-
}
46-
4740
@Override
4841
public ParallelAgentService<T> subAgents(Object... agents) {
4942
this.workflowBuilder.tasks(t -> t.parallel(agents));

fluent/agentic-langchain4j/src/main/java/io/serverlessworkflow/fluent/agentic/langchain4j/SequentialAgentServiceImpl.java

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,6 @@ public static <T> SequentialAgentServiceImpl<T> builder(Class<T> agentServiceCla
3131
return new SequentialAgentServiceImpl<>(agentServiceClass);
3232
}
3333

34-
@Override
35-
public T build() {
36-
// TODO: create a proxy of an InvocationHandler wrapping our WorkflowApplication, calling `run`
37-
// on `invoke`.
38-
// TODO: we pass what we built here to the runner
39-
return null;
40-
}
41-
4234
@Override
4335
public SequentialAgentService<T> subAgents(Object... agents) {
4436
this.workflowBuilder.tasks(t -> t.sequence(agents));

fluent/agentic-langchain4j/src/main/java/io/serverlessworkflow/fluent/agentic/langchain4j/WorkflowDefinitionBuilder.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,7 @@
1919

2020
public interface WorkflowDefinitionBuilder {
2121

22+
String META_KEY_OUTPUTNAME = "outputName";
23+
2224
Workflow getDefinition();
2325
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
* Copyright 2020-Present The Serverless Workflow Specification Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.serverlessworkflow.fluent.agentic.langchain4j;
17+
18+
public class WorkflowExecutor {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
* Copyright 2020-Present The Serverless Workflow Specification Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.serverlessworkflow.fluent.agentic.langchain4j;
17+
18+
import dev.langchain4j.agentic.cognisphere.Cognisphere;
19+
import dev.langchain4j.agentic.cognisphere.CognisphereAccess;
20+
import dev.langchain4j.agentic.cognisphere.CognisphereKey;
21+
import dev.langchain4j.agentic.cognisphere.CognisphereRegistry;
22+
import dev.langchain4j.agentic.internal.AgentInstance;
23+
import dev.langchain4j.agentic.internal.CognisphereOwner;
24+
import io.serverlessworkflow.api.types.Workflow;
25+
import io.serverlessworkflow.impl.WorkflowApplication;
26+
import java.lang.reflect.Method;
27+
28+
public class WorkflowInvocationHandler implements CognisphereOwner {
29+
30+
private final Workflow workflow;
31+
private final WorkflowApplication.Builder workflowApplicationBuilder;
32+
private Cognisphere cognisphere;
33+
34+
WorkflowInvocationHandler(
35+
Workflow workflow, WorkflowApplication.Builder workflowApplicationBuilder) {
36+
this.workflow = workflow;
37+
this.workflowApplicationBuilder = workflowApplicationBuilder;
38+
}
39+
40+
@Override
41+
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
42+
// outputName
43+
if (method.getDeclaringClass() == AgentInstance.class) {
44+
return switch (method.getName()) {
45+
case "outputName" ->
46+
this.workflow
47+
.getDocument()
48+
.getMetadata()
49+
.getAdditionalProperties()
50+
.get(WorkflowDefinitionBuilder.META_KEY_OUTPUTNAME);
51+
default ->
52+
throw new UnsupportedOperationException(
53+
"Unknown method on AgentInstance class : " + method.getName());
54+
};
55+
}
56+
// withCognisphere
57+
if (method.getDeclaringClass() == CognisphereOwner.class) {
58+
// Ingest the workflow input as a Cognisphere object
59+
// Later, retrieve it and start the workflow with it as input.
60+
return switch (method.getName()) {
61+
case "withCognisphere" -> this.withCognisphere((Cognisphere) args[0]);
62+
default ->
63+
throw new UnsupportedOperationException(
64+
"Unknown method on CognisphereOwner class : " + method.getName());
65+
};
66+
}
67+
// getCognisphere
68+
// evictCognisphere
69+
if (method.getDeclaringClass() == CognisphereAccess.class) {
70+
return switch (method.getName()) {
71+
case "getCognisphere" ->
72+
CognisphereRegistry.get(
73+
new CognisphereKey(this.workflow.getDocument().getName(), args[0]));
74+
case "evictCognisphere" ->
75+
CognisphereRegistry.evict(
76+
new CognisphereKey(this.workflow.getDocument().getName(), args[0]));
77+
default ->
78+
throw new UnsupportedOperationException(
79+
"Unknown method on CognisphereAccess class : " + method.getName());
80+
};
81+
}
82+
83+
// invoke
84+
return null;
85+
}
86+
87+
@Override
88+
public CognisphereOwner withCognisphere(Cognisphere cognisphere) {
89+
this.cognisphere = cognisphere;
90+
return this;
91+
}
92+
}

fluent/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@
5454
<artifactId>serverlessworkflow-fluent-agentic-langchain4j</artifactId>
5555
<version>${project.version}</version>
5656
</dependency>
57+
<dependency>
58+
<groupId>io.serverlessworkflow</groupId>
59+
<artifactId>serverlessworkflow-experimental-agentic</artifactId>
60+
<version>${project.version}</version>
61+
</dependency>
5762
<dependency>
5863
<groupId>io.serverlessworkflow</groupId>
5964
<artifactId>serverlessworkflow-fluent-agentic</artifactId>

0 commit comments

Comments
 (0)