Skip to content
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

Javet: Integrate as code execution engine #43

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
109 changes: 109 additions & 0 deletions code-execution-engines/langchain4j-code-execution-engine-javet/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<?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>dev.langchain4j</groupId>
<artifactId>langchain4j-community</artifactId>
<version>1.0.0-alpha2-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

<artifactId>langchain4j-community-code-execution-engine-javet</artifactId>
<packaging>jar</packaging>

<name>LangChain4j :: Community :: Integration :: Javet</name>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<javet.engine.version>4.0.0</javet.engine.version>
</properties>

<dependencies>

<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-core</artifactId>
<version>${project.version}</version>
</dependency>

<!-- Linux and Windows (x86_64) -->
<dependency>
<groupId>com.caoccao.javet</groupId>
<artifactId>javet</artifactId>
<version>${javet.engine.version}</version>
</dependency>

<!-- Linux (arm64) -->
<dependency>
<groupId>com.caoccao.javet</groupId>
<artifactId>javet-linux-arm64</artifactId>
<version>${javet.engine.version}</version>
</dependency>

<!-- Mac OS (x86_64 and arm64) -->
<dependency>
<groupId>com.caoccao.javet</groupId>
<artifactId>javet-macos</artifactId>
<version>${javet.engine.version}</version>
</dependency>

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<artifactId>junit-jupiter-engine</artifactId>
<artifactId>junit-jupiter-api</artifactId>

<scope>test</scope>
</dependency>

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Looks like this dependency is not necessary

<scope>test</scope>
</dependency>

<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Looks like this dependency is not necessary

<scope>test</scope>
</dependency>

<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Looks like this dependency is not necessary

<scope>test</scope>
</dependency>

<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Looks like this dependency is not necessary

<version>${project.version}</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-code-execution-engine-graalvm-polyglot</artifactId>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Looks like this dependency is not necessary

<version>${project.version}</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.tinylog</groupId>
<artifactId>tinylog-impl</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.tinylog</groupId>
<artifactId>slf4j-tinylog</artifactId>
<scope>test</scope>
</dependency>

</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package dev.langchain4j.community.agent;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please move it to dev.langchain4j.community.code.javet package?


import com.caoccao.javet.exceptions.JavetException;
import com.caoccao.javet.interop.V8Runtime;
import com.caoccao.javet.interop.engine.IJavetEnginePool;
import com.caoccao.javet.interop.engine.JavetEngineConfig;
import com.caoccao.javet.interop.engine.JavetEnginePool;
import com.caoccao.javet.values.V8Value;
import dev.langchain4j.code.CodeExecutionEngine;

public class V8JavaScriptExecutionEngine implements CodeExecutionEngine {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public class V8JavaScriptExecutionEngine implements CodeExecutionEngine {
public class JavetJavaScriptExecutionEngine implements CodeExecutionEngine {

WDYT?


private final IJavetEnginePool<V8Runtime> javetEnginePool;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this pool does not close properly.


public V8JavaScriptExecutionEngine() {
this(createDefaultConfig());
}

public V8JavaScriptExecutionEngine(JavetEngineConfig config) {
javetEnginePool = new JavetEnginePool<>(config);
}

@Override
public String execute(final String code) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public String execute(final String code) {
public String execute(String code) {

try (V8Value v8Value =
javetEnginePool.getEngine().getV8Runtime().getExecutor(code).execute()) {
return v8Value.asString();
} catch (JavetException e) {
throw new RuntimeException("Execution failed", e);
}
}

private static JavetEngineConfig createDefaultConfig() {
JavetEngineConfig config = new JavetEngineConfig();
config.setPoolMaxSize(20);
config.setPoolMinSize(10);
return config;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package dev.langchain4j.community.agent;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please move it to dev.langchain4j.community.agent.tool.javet package?


import dev.langchain4j.agent.tool.P;
import dev.langchain4j.agent.tool.Tool;
import dev.langchain4j.code.CodeExecutionEngine;

public class V8JavaScriptExecutionTool {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public class V8JavaScriptExecutionTool {
public class JavetJavaScriptExecutionTool {


private final CodeExecutionEngine engine;

public V8JavaScriptExecutionTool() {
this(new V8JavaScriptExecutionEngine());
}

public V8JavaScriptExecutionTool(CodeExecutionEngine engine) {
this.engine = engine;
}

@Tool("MUST be used for accurate calculations: math, sorting, filtering, aggregating, string processing, etc")
public String executeJavaScriptCode(
@P("JavaScript code to execute, result MUST be returned by the code") String code) {
return engine.execute(code);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package dev.langchain4j.community.agent;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Please always use the same assert framework (Prefer AssertJ).


import dev.langchain4j.code.CodeExecutionEngine;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import org.junit.jupiter.api.Test;

class V8JavaScriptExecutionEngineTest {

CodeExecutionEngine engine = new V8JavaScriptExecutionEngine();

@Test
void should_execute_code() {

String code =
"""
function fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}

fibonacci(10)
""";

String result = engine.execute(code);

assertThat(result).isEqualTo("55");
}

@Test
void testV8RuntimeThreadSafety() throws InterruptedException, ExecutionException {

V8JavaScriptExecutionEngine engine = new V8JavaScriptExecutionEngine();

String code = "'Hello from thread ' + this.threadId";

int threadCount = 10;
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(threadCount);

List<Callable<String>> tasks = new ArrayList<>();
for (int i = 0; i < threadCount; i++) {
final int threadId = i;
tasks.add(() -> {
try {
// Each thread executes the JavaScript code
return engine.execute(code.replace("this.threadId", Integer.toString(threadId)));
} catch (RuntimeException e) {
return "Execution failed for thread " + threadId + ": " + e.getMessage();
}
});
}

List<Future<String>> results = executor.invokeAll(tasks);
executor.shutdown();
executor.awaitTermination(1, TimeUnit.MINUTES);

for (int i = 0; i < threadCount; i++) {
String result = results.get(i).get();
assertEquals("Hello from thread " + i, result, "Unexpected result in thread " + i);
}
}
}
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@

<!-- Integration of web search engine -->
<module>web-search-engines/langchain4j-community-web-search-engine-searxng</module>
<module>code-execution-engines/langchain4j-code-execution-engine-javet</module>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like the directory name is not correctly. (Missing community)


<!-- Spring Boot Starters -->
<module>spring-boot-starters</module>
Expand Down