Skip to content

Commit b11505b

Browse files
Introduce Fluent Agent DSL (depends on LangChain4j SNAPSHOT) (#677)
Signed-off-by: Ricardo Zanini <[email protected]>
1 parent 410b167 commit b11505b

File tree

14 files changed

+889
-2
lines changed

14 files changed

+889
-2
lines changed

.github/workflows/maven-verify.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ on:
1010
pull_request:
1111
branches:
1212
- main
13+
1314
jobs:
1415
build:
1516
runs-on: ubuntu-latest
@@ -25,8 +26,10 @@ jobs:
2526

2627
- name: Verify with Maven
2728
run: |
28-
mvn -B -f pom.xml clean install verify
29+
mvn -B -f pom.xml clean install verify \
30+
-pl ",!fluent/agentic" \
31+
-am
2932
3033
- name: Verify Examples with Maven
3134
run: |
32-
mvn -B -f examples/pom.xml clean install verify
35+
mvn -B -f examples/pom.xml clean install verify

fluent/agentic/pom.xml

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
<parent>
7+
<groupId>io.serverlessworkflow</groupId>
8+
<artifactId>serverlessworkflow-fluent</artifactId>
9+
<version>8.0.0-SNAPSHOT</version>
10+
</parent>
11+
12+
<name>Serverless Workflow :: Fluent :: Agentic</name>
13+
<artifactId>serverlessworkflow-fluent-agentic</artifactId>
14+
15+
<properties>
16+
<maven.compiler.source>17</maven.compiler.source>
17+
<maven.compiler.target>17</maven.compiler.target>
18+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
19+
20+
<version.dev.langchain4j>1.2.0-beta8-SNAPSHOT</version.dev.langchain4j>
21+
</properties>
22+
23+
<dependencies>
24+
<dependency>
25+
<groupId>io.serverlessworkflow</groupId>
26+
<artifactId>serverlessworkflow-experimental-types</artifactId>
27+
</dependency>
28+
<dependency>
29+
<groupId>io.serverlessworkflow</groupId>
30+
<artifactId>serverlessworkflow-fluent-func</artifactId>
31+
</dependency>
32+
<dependency>
33+
<groupId>dev.langchain4j</groupId>
34+
<artifactId>langchain4j-agentic</artifactId>
35+
<version>${version.dev.langchain4j}</version>
36+
</dependency>
37+
<dependency>
38+
<groupId>org.slf4j</groupId>
39+
<artifactId>slf4j-simple</artifactId>
40+
<scope>test</scope>
41+
</dependency>
42+
43+
<dependency>
44+
<groupId>org.junit.jupiter</groupId>
45+
<artifactId>junit-jupiter-api</artifactId>
46+
<scope>test</scope>
47+
</dependency>
48+
<dependency>
49+
<groupId>org.mockito</groupId>
50+
<artifactId>mockito-core</artifactId>
51+
<scope>test</scope>
52+
</dependency>
53+
<dependency>
54+
<groupId>org.assertj</groupId>
55+
<artifactId>assertj-core</artifactId>
56+
</dependency>
57+
<dependency>
58+
<groupId>dev.langchain4j</groupId>
59+
<artifactId>langchain4j-ollama</artifactId>
60+
<scope>test</scope>
61+
<version>1.2.0-SNAPSHOT</version>
62+
</dependency>
63+
</dependencies>
64+
65+
</project>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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;
17+
18+
import static dev.langchain4j.agentic.internal.AgentExecutor.agentsToExecutors;
19+
20+
import dev.langchain4j.agentic.Cognisphere;
21+
import dev.langchain4j.agentic.internal.AgentExecutor;
22+
import dev.langchain4j.agentic.internal.AgentInstance;
23+
import io.serverlessworkflow.impl.expressions.LoopPredicateIndex;
24+
import java.util.List;
25+
import java.util.function.Function;
26+
import java.util.function.Predicate;
27+
import java.util.stream.Stream;
28+
29+
public final class AgentAdapters {
30+
private AgentAdapters() {}
31+
32+
public static List<AgentExecutor> toExecutors(Object... agents) {
33+
return agentsToExecutors(Stream.of(agents).map(AgentInstance.class::cast).toList());
34+
}
35+
36+
public static Function<Cognisphere, Object> toFunction(AgentExecutor exec) {
37+
return exec::invoke;
38+
}
39+
40+
public static LoopPredicateIndex<Object, Object> toWhile(Predicate<Cognisphere> exit) {
41+
return (model, item, idx) -> !exit.test((Cognisphere) model);
42+
}
43+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
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;
17+
18+
import io.serverlessworkflow.fluent.agentic.spi.AgentDoFluent;
19+
import io.serverlessworkflow.fluent.func.FuncCallTaskBuilder;
20+
import io.serverlessworkflow.fluent.func.FuncEmitTaskBuilder;
21+
import io.serverlessworkflow.fluent.func.FuncForTaskBuilder;
22+
import io.serverlessworkflow.fluent.func.FuncForkTaskBuilder;
23+
import io.serverlessworkflow.fluent.func.FuncSetTaskBuilder;
24+
import io.serverlessworkflow.fluent.func.FuncSwitchTaskBuilder;
25+
import io.serverlessworkflow.fluent.func.spi.ConditionalTaskBuilder;
26+
import io.serverlessworkflow.fluent.spec.BaseDoTaskBuilder;
27+
import java.util.function.Consumer;
28+
29+
public class AgentDoTaskBuilder
30+
extends BaseDoTaskBuilder<AgentDoTaskBuilder, AgentTaskItemListBuilder>
31+
implements ConditionalTaskBuilder<AgentDoTaskBuilder>, AgentDoFluent<AgentDoTaskBuilder> {
32+
33+
public AgentDoTaskBuilder() {
34+
super(new AgentTaskItemListBuilder());
35+
}
36+
37+
@Override
38+
protected AgentDoTaskBuilder self() {
39+
return this;
40+
}
41+
42+
@Override
43+
public AgentDoTaskBuilder agent(String name, Object agent) {
44+
this.listBuilder().agent(name, agent);
45+
return self();
46+
}
47+
48+
@Override
49+
public AgentDoTaskBuilder sequence(String name, Object... agents) {
50+
this.listBuilder().sequence(name, agents);
51+
return self();
52+
}
53+
54+
@Override
55+
public AgentDoTaskBuilder loop(String name, Consumer<LoopAgentsBuilder> builder) {
56+
this.listBuilder().loop(name, builder);
57+
return self();
58+
}
59+
60+
@Override
61+
public AgentDoTaskBuilder parallel(String name, Object... agents) {
62+
this.listBuilder().parallel(name, agents);
63+
return self();
64+
}
65+
66+
@Override
67+
public AgentDoTaskBuilder callFn(String name, Consumer<FuncCallTaskBuilder> cfg) {
68+
this.listBuilder().callFn(name, cfg);
69+
return self();
70+
}
71+
72+
@Override
73+
public AgentDoTaskBuilder emit(String name, Consumer<FuncEmitTaskBuilder> itemsConfigurer) {
74+
this.listBuilder().emit(name, itemsConfigurer);
75+
return self();
76+
}
77+
78+
@Override
79+
public AgentDoTaskBuilder forEach(String name, Consumer<FuncForTaskBuilder> itemsConfigurer) {
80+
this.listBuilder().forEach(name, itemsConfigurer);
81+
return self();
82+
}
83+
84+
@Override
85+
public AgentDoTaskBuilder fork(String name, Consumer<FuncForkTaskBuilder> itemsConfigurer) {
86+
this.listBuilder().fork(name, itemsConfigurer);
87+
return self();
88+
}
89+
90+
@Override
91+
public AgentDoTaskBuilder set(String name, Consumer<FuncSetTaskBuilder> itemsConfigurer) {
92+
this.listBuilder().set(name, itemsConfigurer);
93+
return self();
94+
}
95+
96+
@Override
97+
public AgentDoTaskBuilder set(String name, String expr) {
98+
this.listBuilder().set(name, expr);
99+
return self();
100+
}
101+
102+
@Override
103+
public AgentDoTaskBuilder switchCase(
104+
String name, Consumer<FuncSwitchTaskBuilder> itemsConfigurer) {
105+
this.listBuilder().switchCase(name, itemsConfigurer);
106+
return self();
107+
}
108+
}
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
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;
17+
18+
import dev.langchain4j.agentic.internal.AgentExecutor;
19+
import io.serverlessworkflow.api.types.Task;
20+
import io.serverlessworkflow.api.types.TaskItem;
21+
import io.serverlessworkflow.fluent.agentic.spi.AgentDoFluent;
22+
import io.serverlessworkflow.fluent.func.FuncCallTaskBuilder;
23+
import io.serverlessworkflow.fluent.func.FuncEmitTaskBuilder;
24+
import io.serverlessworkflow.fluent.func.FuncForTaskBuilder;
25+
import io.serverlessworkflow.fluent.func.FuncForkTaskBuilder;
26+
import io.serverlessworkflow.fluent.func.FuncSetTaskBuilder;
27+
import io.serverlessworkflow.fluent.func.FuncSwitchTaskBuilder;
28+
import io.serverlessworkflow.fluent.func.FuncTaskItemListBuilder;
29+
import io.serverlessworkflow.fluent.spec.BaseTaskItemListBuilder;
30+
import java.util.List;
31+
import java.util.function.Consumer;
32+
33+
public class AgentTaskItemListBuilder extends BaseTaskItemListBuilder<AgentTaskItemListBuilder>
34+
implements AgentDoFluent<AgentTaskItemListBuilder> {
35+
36+
private final FuncTaskItemListBuilder delegate;
37+
38+
public AgentTaskItemListBuilder() {
39+
super();
40+
this.delegate = new FuncTaskItemListBuilder(super.mutableList());
41+
}
42+
43+
@Override
44+
protected AgentTaskItemListBuilder self() {
45+
return this;
46+
}
47+
48+
@Override
49+
protected AgentTaskItemListBuilder newItemListBuilder() {
50+
return new AgentTaskItemListBuilder();
51+
}
52+
53+
@Override
54+
public AgentTaskItemListBuilder agent(String name, Object agent) {
55+
AgentAdapters.toExecutors(agent)
56+
.forEach(
57+
exec -> this.delegate.callFn(name, fn -> fn.function(AgentAdapters.toFunction(exec))));
58+
return self();
59+
}
60+
61+
@Override
62+
public AgentTaskItemListBuilder sequence(String name, Object... agents) {
63+
for (int i = 0; i < agents.length; i++) {
64+
agent(name + "-" + i, agents[i]);
65+
}
66+
return self();
67+
}
68+
69+
@Override
70+
public AgentTaskItemListBuilder loop(String name, Consumer<LoopAgentsBuilder> consumer) {
71+
final LoopAgentsBuilder builder = new LoopAgentsBuilder();
72+
consumer.accept(builder);
73+
this.addTaskItem(new TaskItem(name, new Task().withForTask(builder.build())));
74+
return self();
75+
}
76+
77+
@Override
78+
public AgentTaskItemListBuilder parallel(String name, Object... agents) {
79+
this.delegate.fork(
80+
name,
81+
fork -> {
82+
List<AgentExecutor> execs = AgentAdapters.toExecutors(agents);
83+
for (int i = 0; i < execs.size(); i++) {
84+
AgentExecutor ex = execs.get(i);
85+
fork.branch("branch-" + i + "-" + name, AgentAdapters.toFunction(ex));
86+
}
87+
});
88+
return self();
89+
}
90+
91+
@Override
92+
public AgentTaskItemListBuilder callFn(String name, Consumer<FuncCallTaskBuilder> cfg) {
93+
this.delegate.callFn(name, cfg);
94+
return self();
95+
}
96+
97+
@Override
98+
public AgentTaskItemListBuilder emit(String name, Consumer<FuncEmitTaskBuilder> itemsConfigurer) {
99+
this.delegate.emit(name, itemsConfigurer);
100+
return self();
101+
}
102+
103+
@Override
104+
public AgentTaskItemListBuilder forEach(
105+
String name, Consumer<FuncForTaskBuilder> itemsConfigurer) {
106+
this.delegate.forEach(name, itemsConfigurer);
107+
return self();
108+
}
109+
110+
@Override
111+
public AgentTaskItemListBuilder fork(String name, Consumer<FuncForkTaskBuilder> itemsConfigurer) {
112+
this.delegate.fork(name, itemsConfigurer);
113+
return self();
114+
}
115+
116+
@Override
117+
public AgentTaskItemListBuilder set(String name, Consumer<FuncSetTaskBuilder> itemsConfigurer) {
118+
this.delegate.set(name, itemsConfigurer);
119+
return self();
120+
}
121+
122+
@Override
123+
public AgentTaskItemListBuilder set(String name, String expr) {
124+
this.delegate.set(name, expr);
125+
return self();
126+
}
127+
128+
@Override
129+
public AgentTaskItemListBuilder switchCase(
130+
String name, Consumer<FuncSwitchTaskBuilder> itemsConfigurer) {
131+
this.delegate.switchCase(name, itemsConfigurer);
132+
return self();
133+
}
134+
}

0 commit comments

Comments
 (0)