Skip to content

Commit d79284a

Browse files
Fix #732 - Add static imports and consumer recipes for Agentic DSL (#785)
* Fix #732 - Add static imports and consumer recipes for Agentic DSL Signed-off-by: Ricardo Zanini <ricardozanini@gmail.com> * Adding agentic workflow patterns to the DSL Signed-off-by: Ricardo Zanini <ricardozanini@gmail.com> --------- Signed-off-by: Ricardo Zanini <ricardozanini@gmail.com>
1 parent fec6de9 commit d79284a

File tree

13 files changed

+478
-78
lines changed

13 files changed

+478
-78
lines changed

experimental/fluent/agentic/src/main/java/io/serverlessworkflow/fluent/agentic/AgentWorkflowBuilder.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515
*/
1616
package io.serverlessworkflow.fluent.agentic;
1717

18+
import dev.langchain4j.agentic.scope.AgenticScope;
1819
import io.serverlessworkflow.fluent.func.spi.FuncTransformations;
1920
import io.serverlessworkflow.fluent.spec.BaseWorkflowBuilder;
2021
import java.util.UUID;
22+
import java.util.function.Predicate;
2123

2224
public class AgentWorkflowBuilder
2325
extends BaseWorkflowBuilder<AgentWorkflowBuilder, AgentDoTaskBuilder, AgentTaskItemListBuilder>
@@ -40,6 +42,40 @@ public static AgentWorkflowBuilder workflow(String name, String ns) {
4042
return new AgentWorkflowBuilder(name, ns, DEFAULT_VERSION);
4143
}
4244

45+
public AgentWorkflowBuilder sequence(Object... agents) {
46+
return sequence(UUID.randomUUID().toString(), agents);
47+
}
48+
49+
public AgentWorkflowBuilder sequence(String name, Object... agents) {
50+
final AgentDoTaskBuilder doTaskBuilder = this.newDo();
51+
doTaskBuilder.sequence(name, agents);
52+
this.workflow.setDo(doTaskBuilder.build().getDo());
53+
return this;
54+
}
55+
56+
public AgentWorkflowBuilder parallel(Object... agents) {
57+
return this.parallel(UUID.randomUUID().toString(), agents);
58+
}
59+
60+
public AgentWorkflowBuilder parallel(String name, Object... agents) {
61+
final AgentDoTaskBuilder doTaskBuilder = this.newDo();
62+
doTaskBuilder.parallel(name, agents);
63+
this.workflow.setDo(doTaskBuilder.build().getDo());
64+
return this;
65+
}
66+
67+
public AgentWorkflowBuilder loop(Predicate<AgenticScope> exitCondition, Object... agents) {
68+
return this.loop(UUID.randomUUID().toString(), exitCondition, agents);
69+
}
70+
71+
public AgentWorkflowBuilder loop(
72+
String name, Predicate<AgenticScope> exitCondition, Object... agents) {
73+
final AgentDoTaskBuilder doTaskBuilder = this.newDo();
74+
doTaskBuilder.loop(name, loop -> loop.subAgents(agents).exitCondition(exitCondition));
75+
this.workflow.setDo(doTaskBuilder.build().getDo());
76+
return this;
77+
}
78+
4379
@Override
4480
protected AgentDoTaskBuilder newDo() {
4581
return new AgentDoTaskBuilder();
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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.configurer;
17+
18+
import io.serverlessworkflow.fluent.agentic.AgentDoTaskBuilder;
19+
import java.util.function.Consumer;
20+
21+
@FunctionalInterface
22+
public interface AgentTaskConfigurer extends Consumer<AgentDoTaskBuilder> {}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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.configurer;
17+
18+
import io.serverlessworkflow.fluent.func.FuncPredicateEventPropertiesBuilder;
19+
import java.util.function.Consumer;
20+
21+
@FunctionalInterface
22+
public interface FuncPredicateEventConfigurer
23+
extends Consumer<FuncPredicateEventPropertiesBuilder> {}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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.configurer;
17+
18+
import io.serverlessworkflow.fluent.agentic.AgentListenTaskBuilder;
19+
import java.util.function.Consumer;
20+
21+
@FunctionalInterface
22+
public interface ListenConfigurer extends Consumer<AgentListenTaskBuilder> {}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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.configurer;
17+
18+
import io.serverlessworkflow.fluent.func.FuncSwitchTaskBuilder;
19+
import java.util.function.Consumer;
20+
21+
@FunctionalInterface
22+
public interface SwitchCaseConfigurer
23+
extends Consumer<FuncSwitchTaskBuilder.SwitchCasePredicateBuilder> {}
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
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.dsl;
17+
18+
import dev.langchain4j.agentic.scope.AgenticScope;
19+
import io.cloudevents.CloudEventData;
20+
import io.serverlessworkflow.api.types.FlowDirectiveEnum;
21+
import io.serverlessworkflow.fluent.agentic.AgentDoTaskBuilder;
22+
import io.serverlessworkflow.fluent.agentic.configurer.AgentTaskConfigurer;
23+
import io.serverlessworkflow.fluent.agentic.configurer.FuncPredicateEventConfigurer;
24+
import io.serverlessworkflow.fluent.agentic.configurer.SwitchCaseConfigurer;
25+
import io.serverlessworkflow.fluent.func.FuncCallTaskBuilder;
26+
import io.serverlessworkflow.fluent.func.FuncEmitTaskBuilder;
27+
import io.serverlessworkflow.fluent.func.FuncSwitchTaskBuilder;
28+
import java.util.List;
29+
import java.util.Objects;
30+
import java.util.function.Consumer;
31+
import java.util.function.Function;
32+
import java.util.function.Predicate;
33+
34+
public final class AgenticDSL {
35+
36+
private AgenticDSL() {}
37+
38+
public static <T, V> Consumer<FuncCallTaskBuilder> fn(
39+
Function<T, V> function, Class<T> argClass) {
40+
return f -> f.function(function, argClass);
41+
}
42+
43+
public static <T, V> Consumer<FuncCallTaskBuilder> fn(Function<T, V> function) {
44+
return f -> f.function(function);
45+
}
46+
47+
public static Consumer<FuncSwitchTaskBuilder> cases(SwitchCaseConfigurer... cases) {
48+
return s -> {
49+
for (SwitchCaseConfigurer c : cases) {
50+
s.onPredicate(c);
51+
}
52+
};
53+
}
54+
55+
public static <T> SwitchCaseSpec<T> on(Predicate<T> when, Class<T> whenClass) {
56+
return new SwitchCaseSpec<T>().when(when, whenClass);
57+
}
58+
59+
public static <T> SwitchCaseSpec<T> on(Predicate<T> when) {
60+
return new SwitchCaseSpec<T>().when(when);
61+
}
62+
63+
public static SwitchCaseConfigurer onDefault(String task) {
64+
return s -> s.then(task);
65+
}
66+
67+
public static SwitchCaseConfigurer onDefault(FlowDirectiveEnum directive) {
68+
return s -> s.then(directive);
69+
}
70+
71+
public static ListenSpec to() {
72+
return new ListenSpec();
73+
}
74+
75+
public static ListenSpec toOne(String type) {
76+
return new ListenSpec().one(e -> e.type(type));
77+
}
78+
79+
public static ListenSpec toAll(String... types) {
80+
FuncPredicateEventConfigurer[] events = new FuncPredicateEventConfigurer[types.length];
81+
for (int i = 0; i < types.length; i++) {
82+
events[i] = event(types[i]);
83+
}
84+
return new ListenSpec().all(events);
85+
}
86+
87+
public static ListenSpec toAny(String... types) {
88+
FuncPredicateEventConfigurer[] events = new FuncPredicateEventConfigurer[types.length];
89+
for (int i = 0; i < types.length; i++) {
90+
events[i] = event(types[i]);
91+
}
92+
return new ListenSpec().any(events);
93+
}
94+
95+
public static FuncPredicateEventConfigurer event(String type) {
96+
return e -> e.type(type);
97+
}
98+
99+
// TODO: expand the `event` static ref with more attributes based on community feedback
100+
101+
public static <T> Consumer<FuncEmitTaskBuilder> event(
102+
String type, Function<T, CloudEventData> function) {
103+
return event -> event.event(e -> e.type(type).data(function));
104+
}
105+
106+
public static <T> Consumer<FuncEmitTaskBuilder> event(
107+
String type, Function<T, CloudEventData> function, Class<T> clazz) {
108+
return event -> event.event(e -> e.type(type).data(function, clazz));
109+
}
110+
111+
// -------- Agentic Workflow Patterns -------- //
112+
public static AgentTaskConfigurer sequence(Object... agents) {
113+
return list -> list.sequence(agents);
114+
}
115+
116+
public static AgentTaskConfigurer loop(Predicate<AgenticScope> exitCondition, Object... agents) {
117+
return list -> list.loop(l -> l.subAgents(agents).exitCondition(exitCondition));
118+
}
119+
120+
public static AgentTaskConfigurer parallel(Object... agents) {
121+
return list -> list.parallel(agents);
122+
}
123+
124+
// --------- Tasks ------ //
125+
public static Consumer<AgentDoTaskBuilder> doTasks(AgentTaskConfigurer... steps) {
126+
Objects.requireNonNull(steps, "Steps in a tasks are required");
127+
final List<AgentTaskConfigurer> snapshot = List.of(steps.clone());
128+
return list -> snapshot.forEach(s -> s.accept(list));
129+
}
130+
131+
public static <T, V> AgentTaskConfigurer function(Function<T, V> function, Class<T> argClass) {
132+
return list -> list.callFn(fn(function, argClass));
133+
}
134+
135+
public static <T, V> AgentTaskConfigurer function(Function<T, V> function) {
136+
return list -> list.callFn(fn(function));
137+
}
138+
139+
public static AgentTaskConfigurer agent(Object agent) {
140+
return list -> list.agent(agent);
141+
}
142+
143+
public static AgentTaskConfigurer emit(Consumer<FuncEmitTaskBuilder> event) {
144+
return list -> list.emit(event);
145+
}
146+
147+
public static AgentTaskConfigurer switchCase(Consumer<FuncSwitchTaskBuilder> switchCase) {
148+
return list -> list.switchCase(switchCase);
149+
}
150+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
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.dsl;
17+
18+
import io.serverlessworkflow.fluent.agentic.AgentListenTaskBuilder;
19+
import io.serverlessworkflow.fluent.agentic.configurer.FuncPredicateEventConfigurer;
20+
import io.serverlessworkflow.fluent.agentic.configurer.ListenConfigurer;
21+
import io.serverlessworkflow.fluent.func.FuncEventFilterBuilder;
22+
import io.serverlessworkflow.fluent.func.FuncListenToBuilder;
23+
import java.util.Objects;
24+
import java.util.function.Consumer;
25+
26+
public class ListenSpec implements ListenConfigurer {
27+
28+
private Consumer<FuncListenToBuilder> strategyStep;
29+
private Consumer<FuncListenToBuilder> untilStep;
30+
31+
@SuppressWarnings("unchecked")
32+
private static Consumer<FuncEventFilterBuilder>[] asFilters(
33+
FuncPredicateEventConfigurer[] events) {
34+
Consumer<FuncEventFilterBuilder>[] filters = new Consumer[events.length];
35+
for (int i = 0; i < events.length; i++) {
36+
FuncPredicateEventConfigurer ev = Objects.requireNonNull(events[i], "events[" + i + "]");
37+
filters[i] = f -> f.with(ev);
38+
}
39+
return filters;
40+
}
41+
42+
public final ListenSpec all(FuncPredicateEventConfigurer... events) {
43+
strategyStep = t -> t.all(asFilters(events));
44+
return this;
45+
}
46+
47+
public ListenSpec one(FuncPredicateEventConfigurer e) {
48+
strategyStep = t -> t.one(f -> f.with(e));
49+
return this;
50+
}
51+
52+
public final ListenSpec any(FuncPredicateEventConfigurer... events) {
53+
strategyStep = t -> t.any(asFilters(events));
54+
return this;
55+
}
56+
57+
public ListenSpec until(String expression) {
58+
untilStep = t -> t.until(expression);
59+
return this;
60+
}
61+
62+
@Override
63+
public void accept(AgentListenTaskBuilder agentListenTaskBuilder) {
64+
agentListenTaskBuilder.to(
65+
t -> {
66+
strategyStep.accept(t);
67+
if (untilStep != null) {
68+
untilStep.accept(t);
69+
}
70+
});
71+
}
72+
}

0 commit comments

Comments
 (0)