Skip to content

Commit 9a4858a

Browse files
committed
Wrap up langchain4j integration work; add CI to run integration tests
Signed-off-by: Ricardo Zanini <[email protected]>
1 parent eeee93d commit 9a4858a

File tree

19 files changed

+235
-163
lines changed

19 files changed

+235
-163
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: sdk-java Integration Tests
2+
on:
3+
issue_comment:
4+
types: [ created ]
5+
6+
jobs:
7+
run-integration-tests:
8+
# 2) Only run if the comment is exactly "/run integration-tests"
9+
# and it’s on a pull request (not on an issue)
10+
if: >
11+
github.event.comment.body == '/run integration-tests' &&
12+
github.event.issue.pull_request != null
13+
runs-on: ubuntu-latest
14+
15+
permissions:
16+
contents: read
17+
pull-requests: write
18+
checks: write
19+
id-token: write
20+
21+
steps:
22+
# 3) Checkout the **PR’s** code
23+
- name: Checkout PR code
24+
uses: actions/checkout@v4
25+
with:
26+
repository: ${{ github.event.issue.pull_request.head.repo.full_name }}
27+
ref: ${{ github.event.issue.pull_request.head.ref }}
28+
token: ${{ secrets.GITHUB_TOKEN }}
29+
30+
# 4) Set up Java/Maven (cache enabled)
31+
- name: Set up JDK 17
32+
uses: actions/setup-java@v4
33+
with:
34+
distribution: temurin
35+
java-version: 17
36+
cache: maven
37+
38+
# 5) Run only the IT suite
39+
- name: Run integration-tests profile
40+
run: mvn -B -f pom.xml clean verify -Pintegration-tests

.github/workflows/maven-verify.yml

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,35 +17,20 @@ jobs:
1717
- name: Checkout sdk-java
1818
uses: actions/checkout@v4
1919

20-
# 2. (Temporary) Checkout the langchain4j repo at agentic-module
21-
- name: Checkout langchain4j (agentic-module)
22-
uses: actions/checkout@v4
23-
with:
24-
repository: mariofusco/langchain4j
25-
ref: agentic-module
26-
path: langchain4j
27-
28-
# 3. Set up JDK 17 for both builds
20+
# 2. Set up JDK 17 for both builds
2921
- name: Set up JDK 17
3022
uses: actions/setup-java@v4
3123
with:
3224
distribution: temurin
3325
java-version: 17
3426
cache: 'maven'
3527

36-
# 4. Build the external agentic module
37-
- name: Build langchain4j-agentic
38-
run: |
39-
mvn -B -U -T12C -f langchain4j/pom.xml clean package -DskipTests
40-
mvn -B -f langchain4j/langchain4j-agentic/pom.xml clean install -DskipTests
41-
42-
# 5. Verify the main sdk-java project, excluding the two agentic modules
28+
# 3. Verify the main sdk-java project, excluding the two agentic modules
4329
- name: Verify with Maven
4430
run: |
45-
mvn -B -f pom.xml clean install verify \
46-
-am
31+
mvn -B -f pom.xml clean install verify -am
4732
48-
# 6. Verify examples
33+
# 4. Verify examples
4934
- name: Verify Examples with Maven
5035
run: |
5136
mvn -B -f examples/pom.xml clean install verify

experimental/agentic/src/main/java/io/serverlessworkflow/impl/expressions/agentic/AgenticModel.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,17 @@
1515
*/
1616
package io.serverlessworkflow.impl.expressions.agentic;
1717

18-
import dev.langchain4j.agentic.cognisphere.Cognisphere;
18+
import dev.langchain4j.agentic.scope.AgenticScope;
1919
import io.serverlessworkflow.impl.WorkflowModel;
2020
import io.serverlessworkflow.impl.expressions.func.JavaModel;
2121
import java.util.Collection;
22+
import java.util.Map;
2223
import java.util.Optional;
2324

2425
class AgenticModel extends JavaModel {
2526

26-
AgenticModel(Cognisphere cognisphere) {
27-
super(cognisphere);
27+
AgenticModel(AgenticScope agenticScope) {
28+
super(agenticScope);
2829
}
2930

3031
@Override
@@ -39,8 +40,10 @@ public Collection<WorkflowModel> asCollection() {
3940

4041
@Override
4142
public <T> Optional<T> as(Class<T> clazz) {
42-
if (Cognisphere.class.isAssignableFrom(clazz)) {
43+
if (AgenticScope.class.isAssignableFrom(clazz)) {
4344
return Optional.of(clazz.cast(object));
45+
} else if (Map.class.isAssignableFrom(clazz)) {
46+
return Optional.of(clazz.cast(((AgenticScope) object).state()));
4447
} else {
4548
return super.as(clazz);
4649
}

experimental/agentic/src/main/java/io/serverlessworkflow/impl/expressions/agentic/AgenticModelCollection.java

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,37 +15,37 @@
1515
*/
1616
package io.serverlessworkflow.impl.expressions.agentic;
1717

18-
import dev.langchain4j.agentic.cognisphere.Cognisphere;
19-
import dev.langchain4j.agentic.cognisphere.ResultWithCognisphere;
18+
import dev.langchain4j.agentic.scope.AgenticScope;
19+
import dev.langchain4j.agentic.scope.ResultWithAgenticScope;
2020
import io.serverlessworkflow.impl.WorkflowModel;
2121
import io.serverlessworkflow.impl.expressions.func.JavaModelCollection;
2222
import java.util.Collection;
2323
import java.util.Optional;
2424

2525
class AgenticModelCollection extends JavaModelCollection {
2626

27-
private final Cognisphere cognisphere;
27+
private final AgenticScope agenticScope;
2828

29-
AgenticModelCollection(Collection<?> object, Cognisphere cognisphere) {
29+
AgenticModelCollection(Collection<?> object, AgenticScope agenticScope) {
3030
super(object);
31-
this.cognisphere = cognisphere;
31+
this.agenticScope = agenticScope;
3232
}
3333

34-
AgenticModelCollection(Cognisphere cognisphere) {
35-
this.cognisphere = cognisphere;
34+
AgenticModelCollection(AgenticScope agenticScope) {
35+
this.agenticScope = agenticScope;
3636
}
3737

3838
@Override
3939
protected WorkflowModel nextItem(Object obj) {
40-
return new AgenticModel((Cognisphere) obj);
40+
return new AgenticModel((AgenticScope) obj);
4141
}
4242

4343
@Override
4444
public <T> Optional<T> as(Class<T> clazz) {
45-
if (Cognisphere.class.isAssignableFrom(clazz)) {
46-
return Optional.of(clazz.cast(cognisphere));
47-
} else if (ResultWithCognisphere.class.isAssignableFrom(clazz)) {
48-
return Optional.of(clazz.cast(new ResultWithCognisphere<>(cognisphere, object)));
45+
if (AgenticScope.class.isAssignableFrom(clazz)) {
46+
return Optional.of(clazz.cast(agenticScope));
47+
} else if (ResultWithAgenticScope.class.isAssignableFrom(clazz)) {
48+
return Optional.of(clazz.cast(new ResultWithAgenticScope<>(agenticScope, object)));
4949
} else {
5050
return super.as(clazz);
5151
}

experimental/agentic/src/main/java/io/serverlessworkflow/impl/expressions/agentic/AgenticModelFactory.java

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,39 +15,38 @@
1515
*/
1616
package io.serverlessworkflow.impl.expressions.agentic;
1717

18-
import dev.langchain4j.agentic.cognisphere.Cognisphere;
18+
import dev.langchain4j.agentic.scope.AgenticScope;
1919
import io.cloudevents.CloudEvent;
2020
import io.cloudevents.CloudEventData;
2121
import io.serverlessworkflow.impl.WorkflowModel;
2222
import io.serverlessworkflow.impl.WorkflowModelCollection;
2323
import io.serverlessworkflow.impl.WorkflowModelFactory;
24-
import io.serverlessworkflow.impl.expressions.agentic.langchain4j.CognisphereRegistryAssessor;
24+
import io.serverlessworkflow.impl.expressions.agentic.langchain4j.AgenticScopeRegistryAssessor;
2525
import io.serverlessworkflow.impl.expressions.func.JavaModel;
2626
import java.time.OffsetDateTime;
2727
import java.util.Map;
2828

2929
class AgenticModelFactory implements WorkflowModelFactory {
3030

3131
/**
32-
* Applies any change to the model after running as task. We will always set it to
33-
* a @DefaultCognisphere object since @AgentExecutor is always adding the output to the
34-
* cognisphere. We just have to make sure that cognisphere is always passed to the next input
35-
* task.
32+
* Applies any change to the model after running as task. We will always set it to a @AgenticScope
33+
* object since @AgentExecutor is always adding the output to the agenticScope. We just have to
34+
* make sure that agenticScope is always passed to the next input task.
3635
*
37-
* @param prev the global Cognisphere object getting updated by the workflow context
38-
* @param obj the same Cognisphere object updated by the AgentExecutor
39-
* @return the workflow context model holding the cognisphere object.
36+
* @param prev the global AgenticScope object getting updated by the workflow context
37+
* @param obj the same AgenticScope object updated by the AgentExecutor
38+
* @return the workflow context model holding the agenticScope object.
4039
*/
4140
@Override
4241
public WorkflowModel fromAny(WorkflowModel prev, Object obj) {
43-
// We ignore `obj` since it's already included in `prev` within the Cognisphere instance
42+
// We ignore `obj` since it's already included in `prev` within the agenticScope instance
4443
return prev;
4544
}
4645

4746
@Override
4847
public WorkflowModel combine(Map<String, WorkflowModel> workflowVariables) {
49-
// TODO: create a new cognisphere object in the CognisphereRegistryAssessor per branch
50-
// TODO: Since we share the same cognisphere object, both branches are updating the same
48+
// TODO: create a new agenticScope object in the AgenticScopeRegistryAssessor per branch
49+
// TODO: Since we share the same agenticScope object, both branches are updating the same
5150
// instance, so for now we return the first key.
5251
return workflowVariables.values().iterator().next();
5352
}
@@ -57,7 +56,7 @@ public WorkflowModelCollection createCollection() {
5756
throw new UnsupportedOperationException();
5857
}
5958

60-
// TODO: all these methods can use Cognisphere as long as we have access to the `outputName`
59+
// TODO: all these methods can use agenticScope as long as we have access to the `outputName`
6160

6261
@Override
6362
public WorkflowModel from(boolean value) {
@@ -91,9 +90,9 @@ public WorkflowModel from(OffsetDateTime value) {
9190

9291
@Override
9392
public WorkflowModel from(Map<String, Object> map) {
94-
final Cognisphere cognisphere = new CognisphereRegistryAssessor().getCognisphere();
95-
cognisphere.writeStates(map);
96-
return new AgenticModel(cognisphere);
93+
final AgenticScope agenticScope = new AgenticScopeRegistryAssessor().getAgenticScope();
94+
agenticScope.writeStates(map);
95+
return new AgenticModel(agenticScope);
9796
}
9897

9998
@Override
@@ -103,8 +102,8 @@ public WorkflowModel fromNull() {
103102

104103
@Override
105104
public WorkflowModel fromOther(Object value) {
106-
if (value instanceof Cognisphere) {
107-
return new AgenticModel((Cognisphere) value);
105+
if (value instanceof AgenticScope) {
106+
return new AgenticModel((AgenticScope) value);
108107
}
109108
return new JavaModel(value);
110109
}
Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,56 +15,57 @@
1515
*/
1616
package io.serverlessworkflow.impl.expressions.agentic.langchain4j;
1717

18-
import dev.langchain4j.agentic.cognisphere.CognisphereRegistry;
19-
import dev.langchain4j.agentic.cognisphere.DefaultCognisphere;
20-
import dev.langchain4j.agentic.internal.CognisphereOwner;
18+
import dev.langchain4j.agentic.internal.AgenticScopeOwner;
19+
import dev.langchain4j.agentic.scope.AgenticScopeRegistry;
20+
import dev.langchain4j.agentic.scope.DefaultAgenticScope;
2121
import java.util.Objects;
2222
import java.util.UUID;
2323
import java.util.concurrent.atomic.AtomicReference;
2424

25-
public class CognisphereRegistryAssessor implements CognisphereOwner {
25+
public class AgenticScopeRegistryAssessor implements AgenticScopeOwner {
2626

27-
private final AtomicReference<CognisphereRegistry> cognisphereRegistry = new AtomicReference<>();
27+
private final AtomicReference<AgenticScopeRegistry> agenticScopeRegistry =
28+
new AtomicReference<>();
2829
private final String agentId;
29-
private DefaultCognisphere cognisphere;
30+
private DefaultAgenticScope agenticScope;
3031
private Object memoryId;
3132

32-
public CognisphereRegistryAssessor(String agentId) {
33+
public AgenticScopeRegistryAssessor(String agentId) {
3334
Objects.requireNonNull(agentId, "Agent id cannot be null");
3435
this.agentId = agentId;
3536
}
3637

3738
// TODO: have access to the workflow definition and assign its name instead
38-
public CognisphereRegistryAssessor() {
39+
public AgenticScopeRegistryAssessor() {
3940
this.agentId = UUID.randomUUID().toString();
4041
}
4142

4243
public void setMemoryId(Object memoryId) {
4344
this.memoryId = memoryId;
4445
}
4546

46-
public DefaultCognisphere getCognisphere() {
47-
if (cognisphere != null) {
48-
return cognisphere;
47+
public DefaultAgenticScope getAgenticScope() {
48+
if (agenticScope != null) {
49+
return agenticScope;
4950
}
5051

5152
if (memoryId != null) {
52-
this.cognisphere = registry().getOrCreate(memoryId);
53+
this.agenticScope = registry().getOrCreate(memoryId);
5354
} else {
54-
this.cognisphere = registry().createEphemeralCognisphere();
55+
this.agenticScope = registry().createEphemeralAgenticScope();
5556
}
56-
return this.cognisphere;
57+
return this.agenticScope;
5758
}
5859

5960
@Override
60-
public CognisphereOwner withCognisphere(DefaultCognisphere cognisphere) {
61-
this.cognisphere = cognisphere;
61+
public AgenticScopeOwner withAgenticScope(DefaultAgenticScope agenticScope) {
62+
this.agenticScope = agenticScope;
6263
return this;
6364
}
6465

6566
@Override
66-
public CognisphereRegistry registry() {
67-
cognisphereRegistry.compareAndSet(null, new CognisphereRegistry(agentId));
68-
return cognisphereRegistry.get();
67+
public AgenticScopeRegistry registry() {
68+
agenticScopeRegistry.compareAndSet(null, new AgenticScopeRegistry(agentId));
69+
return agenticScopeRegistry.get();
6970
}
7071
}

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

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

18-
import dev.langchain4j.agentic.cognisphere.Cognisphere;
19-
import dev.langchain4j.agentic.cognisphere.DefaultCognisphere;
18+
import dev.langchain4j.agentic.agent.ErrorContext;
19+
import dev.langchain4j.agentic.agent.ErrorRecoveryResult;
2020
import dev.langchain4j.agentic.internal.AgentSpecification;
21-
import dev.langchain4j.agentic.internal.CognisphereOwner;
21+
import dev.langchain4j.agentic.internal.AgenticScopeOwner;
22+
import dev.langchain4j.agentic.scope.AgenticScope;
23+
import dev.langchain4j.agentic.scope.DefaultAgenticScope;
2224
import io.serverlessworkflow.api.types.Workflow;
2325
import io.serverlessworkflow.fluent.agentic.AgentWorkflowBuilder;
2426
import io.serverlessworkflow.impl.WorkflowApplication;
@@ -29,7 +31,8 @@
2931
public abstract class AbstractAgentService<T, S> implements WorkflowDefinitionBuilder {
3032

3133
// Workflow OutputAs
32-
private static final Function<Cognisphere, Object> DEFAULT_OUTPUT_FUNCTION = cognisphere -> null;
34+
private static final Function<AgenticScope, Object> DEFAULT_OUTPUT_FUNCTION =
35+
agenticScope -> null;
3336

3437
protected final WorkflowApplication.Builder workflowExecBuilder;
3538
protected final AgentWorkflowBuilder workflowBuilder;
@@ -46,34 +49,39 @@ public T build() {
4649
return (T)
4750
Proxy.newProxyInstance(
4851
this.agentServiceClass.getClassLoader(),
49-
new Class<?>[] {agentServiceClass, AgentSpecification.class, CognisphereOwner.class},
52+
new Class<?>[] {agentServiceClass, AgentSpecification.class, AgenticScopeOwner.class},
5053
new WorkflowInvocationHandler(
5154
this.workflowBuilder.build(), this.workflowExecBuilder, this.agentServiceClass));
5255
}
5356

5457
@SuppressWarnings("unchecked")
55-
public S beforeCall(Consumer<Cognisphere> beforeCall) {
58+
public S beforeCall(Consumer<AgenticScope> beforeCall) {
5659
this.workflowBuilder.inputFrom(
5760
cog -> {
5861
beforeCall.accept(cog);
5962
return cog;
6063
},
61-
Cognisphere.class);
64+
AgenticScope.class);
6265
return (S) this;
6366
}
6467

6568
@SuppressWarnings("unchecked")
6669
public S outputName(String outputName) {
67-
Function<DefaultCognisphere, Object> outputFunction = cog -> cog.readState(outputName);
68-
this.workflowBuilder.outputAs(outputFunction, DefaultCognisphere.class);
70+
Function<DefaultAgenticScope, Object> outputFunction = cog -> cog.readState(outputName);
71+
this.workflowBuilder.outputAs(outputFunction, DefaultAgenticScope.class);
6972
this.workflowBuilder.document(
7073
d -> d.metadata(m -> m.metadata(META_KEY_OUTPUTNAME, outputName)));
7174
return (S) this;
7275
}
7376

7477
@SuppressWarnings("unchecked")
75-
public S output(Function<Cognisphere, Object> output) {
76-
this.workflowBuilder.outputAs(output, Cognisphere.class);
78+
public S output(Function<AgenticScope, Object> output) {
79+
this.workflowBuilder.outputAs(output, AgenticScope.class);
80+
return (S) this;
81+
}
82+
83+
@SuppressWarnings("unchecked")
84+
public S errorHandler(Function<ErrorContext, ErrorRecoveryResult> errorHandler) {
7785
return (S) this;
7886
}
7987

0 commit comments

Comments
 (0)