Skip to content

Introduce LangChain4j Agentic Workflow Implementation #681

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
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 @@ -16,20 +16,15 @@
package io.serverlessworkflow.impl.expressions.agentic;

import dev.langchain4j.agentic.cognisphere.Cognisphere;
import dev.langchain4j.agentic.cognisphere.ResultWithCognisphere;
import io.serverlessworkflow.impl.WorkflowModel;
import io.serverlessworkflow.impl.expressions.func.JavaModel;
import java.util.Collection;
import java.util.Collections;
import java.util.Optional;

class AgenticModel extends JavaModel {

private final Cognisphere cognisphere;

AgenticModel(Object object, Cognisphere cognisphere) {
super(object);
this.cognisphere = cognisphere;
AgenticModel(Cognisphere cognisphere) {
super(cognisphere);
}

@Override
Expand All @@ -39,17 +34,13 @@ public void setObject(Object obj) {

@Override
public Collection<WorkflowModel> asCollection() {
return object instanceof Collection value
? new AgenticModelCollection(value, cognisphere)
: Collections.emptyList();
throw new UnsupportedOperationException("Not supported yet.");
}

@Override
public <T> Optional<T> as(Class<T> clazz) {
if (Cognisphere.class.isAssignableFrom(clazz)) {
return Optional.of(clazz.cast(cognisphere));
} else if (ResultWithCognisphere.class.isAssignableFrom(clazz)) {
return Optional.of(clazz.cast(new ResultWithCognisphere<>(cognisphere, object)));
return Optional.of(clazz.cast(object));
} else {
return super.as(clazz);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class AgenticModelCollection extends JavaModelCollection {

@Override
protected WorkflowModel nextItem(Object obj) {
return new AgenticModel(obj, cognisphere);
return new AgenticModel((Cognisphere) obj);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,17 @@
package io.serverlessworkflow.impl.expressions.agentic;

import dev.langchain4j.agentic.cognisphere.Cognisphere;
import dev.langchain4j.agentic.cognisphere.CognisphereRegistry;
import io.cloudevents.CloudEvent;
import io.cloudevents.CloudEventData;
import io.serverlessworkflow.impl.WorkflowModel;
import io.serverlessworkflow.impl.WorkflowModelCollection;
import io.serverlessworkflow.impl.WorkflowModelFactory;
import io.serverlessworkflow.impl.expressions.func.JavaModel;
import java.time.OffsetDateTime;
import java.util.Map;

class AgenticModelFactory implements WorkflowModelFactory {

private Cognisphere cognisphere = CognisphereRegistry.createEphemeralCognisphere();

private final AgenticModel TrueModel = new AgenticModel(Boolean.TRUE, cognisphere);
private final AgenticModel FalseModel = new AgenticModel(Boolean.FALSE, cognisphere);
private final AgenticModel NullModel = new AgenticModel(null, cognisphere);

public void setCognishere(Cognisphere cognisphere) {
this.cognisphere = cognisphere;
}

@Override
public WorkflowModel fromAny(WorkflowModel prev, Object obj) {
((AgenticModel) prev).setObject(obj);
Expand All @@ -45,57 +35,59 @@ public WorkflowModel fromAny(WorkflowModel prev, Object obj) {

@Override
public WorkflowModel combine(Map<String, WorkflowModel> workflowVariables) {
return new AgenticModel(workflowVariables, cognisphere);
throw new UnsupportedOperationException();
}

@Override
public WorkflowModelCollection createCollection() {
return new AgenticModelCollection(cognisphere);
throw new UnsupportedOperationException();
}

@Override
public WorkflowModel from(boolean value) {
return value ? TrueModel : FalseModel;
return new JavaModel(value);
}

@Override
public WorkflowModel from(Number value) {
return new AgenticModel(value, cognisphere);
return new JavaModel(value);
}

@Override
public WorkflowModel from(String value) {
return new AgenticModel(value, cognisphere);
return new JavaModel(value);
}

@Override
public WorkflowModel from(CloudEvent ce) {
return new AgenticModel(ce, cognisphere);
return new JavaModel(ce);
}

@Override
public WorkflowModel from(CloudEventData ce) {
return new AgenticModel(ce, cognisphere);
return new JavaModel(ce);
}

@Override
public WorkflowModel from(OffsetDateTime value) {
return new AgenticModel(value, cognisphere);
return new JavaModel(value);
}

@Override
public WorkflowModel from(Map<String, Object> map) {
cognisphere.writeStates(map);
return new AgenticModel(map, cognisphere);
return new JavaModel(map);
}

@Override
public WorkflowModel fromNull() {
return NullModel;
return new JavaModel(null);
}

@Override
public WorkflowModel fromOther(Object value) {
return new AgenticModel(value, cognisphere);
if (value instanceof Cognisphere) {
return new AgenticModel((Cognisphere) value);
}
return new JavaModel(value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public class JavaModel implements WorkflowModel {

protected Object object;

protected JavaModel(Object object) {
public JavaModel(Object object) {
this.object = asJavaObject(object);
}

Expand Down
68 changes: 68 additions & 0 deletions fluent/agentic-langchain4j/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.serverlessworkflow</groupId>
<artifactId>serverlessworkflow-fluent</artifactId>
<version>8.0.0-SNAPSHOT</version>
</parent>

<artifactId>serverlessworkflow-fluent-agentic-langchain4j</artifactId>
<name>Serverless Workflow :: Fluent :: Agentic LangChain4j</name>
<description>Agentic Workflow DSL Implementation for langchain4j-agentic</description>

<dependencies>
<dependency>
<groupId>io.serverlessworkflow</groupId>
<artifactId>serverlessworkflow-experimental-agentic</artifactId>
</dependency>
<dependency>
<groupId>io.serverlessworkflow</groupId>
<artifactId>serverlessworkflow-fluent-agentic</artifactId>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-agentic</artifactId>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-ollama</artifactId>
<scope>test</scope>
<version>${version.dev.langchain4j}</version>
</dependency>
<dependency>
<groupId>io.serverlessworkflow</groupId>
<artifactId>serverlessworkflow-fluent-agentic</artifactId>
<type>test-jar</type>
<scope>test</scope>
</dependency>
</dependencies>





</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright 2020-Present The Serverless Workflow Specification Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.serverlessworkflow.fluent.agentic.langchain4j;

import dev.langchain4j.agentic.cognisphere.Cognisphere;
import dev.langchain4j.agentic.internal.AgentSpecification;
import dev.langchain4j.agentic.internal.CognisphereOwner;
import io.serverlessworkflow.api.types.Workflow;
import io.serverlessworkflow.fluent.agentic.AgentWorkflowBuilder;
import io.serverlessworkflow.impl.WorkflowApplication;
import java.lang.reflect.Proxy;
import java.util.function.Consumer;
import java.util.function.Function;

public abstract class AbstractAgentService<T, S> implements WorkflowDefinitionBuilder {

// Workflow OutputAs
private static final Function<Cognisphere, Object> DEFAULT_OUTPUT_FUNCTION = cognisphere -> null;
// Workflow InputFrom
private static final Consumer<Cognisphere> DEFAULT_INPUT_FUNCTION = cognisphere -> {};

protected final WorkflowApplication.Builder workflowExecBuilder;
protected final AgentWorkflowBuilder workflowBuilder;
protected final Class<T> agentServiceClass;

protected AbstractAgentService(Class<T> agentServiceClass) {
this.workflowBuilder =
AgentWorkflowBuilder.workflow()
.outputAs(DEFAULT_OUTPUT_FUNCTION)
.input(i -> i.from(DEFAULT_INPUT_FUNCTION));
this.agentServiceClass = agentServiceClass;
this.workflowExecBuilder = WorkflowApplication.builder();
}

@SuppressWarnings("unchecked")
public T build() {
return (T)
Proxy.newProxyInstance(
this.agentServiceClass.getClassLoader(),
new Class<?>[] {agentServiceClass, AgentSpecification.class, CognisphereOwner.class},
new WorkflowInvocationHandler(this.workflowBuilder.build(), this.workflowExecBuilder, this.agentServiceClass));
}

@SuppressWarnings("unchecked")
public S beforeCall(Consumer<Cognisphere> beforeCall) {
this.workflowBuilder.inputFrom(
cog -> {
beforeCall.accept(cog);
return cog;
},
Cognisphere.class);
return (S) this;
}

@SuppressWarnings("unchecked")
public S outputName(String outputName) {
Function<Cognisphere, Object> outputFunction = cog -> cog.readState(outputName);
this.workflowBuilder.outputAs(outputFunction, Cognisphere.class);
this.workflowBuilder.document(
d -> d.metadata(m -> m.metadata(META_KEY_OUTPUTNAME, outputName)));
return (S) this;
}

@SuppressWarnings("unchecked")
public S output(Function<Cognisphere, Object> output) {
this.workflowBuilder.outputAs(output, Cognisphere.class);
return (S) this;
}

@Override
public Workflow getDefinition() {
return this.workflowBuilder.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright 2020-Present The Serverless Workflow Specification Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.serverlessworkflow.fluent.agentic.langchain4j;

import dev.langchain4j.agentic.cognisphere.Cognisphere;
import dev.langchain4j.agentic.internal.AgentExecutor;
import dev.langchain4j.agentic.workflow.ConditionalAgentService;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

public class ConditionalAgentServiceImpl<T>
extends AbstractAgentService<T, ConditionalAgentService<T>>
implements ConditionalAgentService<T> {

private ConditionalAgentServiceImpl(Class<T> agentServiceClass) {
super(agentServiceClass);
}

public static <T> ConditionalAgentService<T> builder(Class<T> agentServiceClass) {
return new ConditionalAgentServiceImpl<>(agentServiceClass);
}

@Override
public ConditionalAgentService<T> subAgents(Object... agents) {
this.workflowBuilder.tasks(t -> t.sequence(agents));
return this;
}

@Override
public ConditionalAgentService<T> subAgents(List<AgentExecutor> agentExecutors) {
return this.subAgents(agentExecutors.toArray());
}

@Override
public ConditionalAgentService<T> subAgents(Predicate<Cognisphere> condition, Object... agents) {
this.workflowBuilder.tasks(
t -> Arrays.stream(agents).forEach(agent -> t.when(condition).agent(agent)));
return this;
}

@Override
public ConditionalAgentService<T> subAgents(
Predicate<Cognisphere> condition, List<AgentExecutor> agentExecutors) {
return this.subAgents(condition, agentExecutors.toArray());
}

@Override
public ConditionalAgentService<T> subAgent(
Predicate<Cognisphere> condition, AgentExecutor agentExecutor) {
this.workflowBuilder.tasks(t -> t.when(condition).agent(agentExecutor));
return this;
}
}
Loading
Loading