bsorrentino / langgraph4j

🚀 LangGraph for Java. A library for building stateful, multi-actor applications with LLMs, built for work jointly with langchain4j
https://bsorrentino.github.io/langgraph4j/
MIT License
138 stars 23 forks source link

FEAT: Support for Tools specified dynamically to be added. #44

Closed TiruvedulaMithun closed 2 weeks ago

TiruvedulaMithun commented 2 weeks ago

Curently in org.bsc.langgraph4j.langchain4j.tool.ToolNode.of(Collection objectsWithTools)

When we pass tool specifications specified dynamically or programatically as per Langchain4j documentation here like example:

    Map<ToolSpecification, ToolExecutor> toolSpecificationMap = new HashMap<>();
    ToolSpecification toolSpecification = ToolSpecification.builder()
      .name("getPCName")
      .description("Returns a String - PC name the AI is currently running in. Returns null if station is not running")
      .build();

    ToolExecutor toolExecutor = (toolExecutionRequest, memoryId) -> {
      return getStationName();
    };
    toolSpecificationMap.put(toolSpecification, toolExecutor);

    toolSpecification = ToolSpecification.builder()
      .name("specialKTwoNumbers")
      .addParameter("operand1", JsonSchemaProperty.type("float"), description("Operand 1 for specialK operation"))
      .addParameter("operand2", JsonSchemaProperty.type("float"), description("Operand 2 for specialK operation"))
      .description("Returns a Float - Performs a specialK operation on 2 nubmers and returns the result")
      .build();

    toolExecutor = (toolExecutionRequest, memoryId) -> {
      LinkedTreeMap<String, Object> arguments = null;
      Object arguments1 = fromJson(toolExecutionRequest.arguments(), Map.class);
      if (arguments1 instanceof LinkedTreeMap)
      {
        @SuppressWarnings("unchecked")
        LinkedTreeMap<String, Object> arguments2 = (LinkedTreeMap<String, Object>)arguments1;
        arguments = arguments2;
      }
      float operand1 = Float.parseFloat(arguments.get("operand1").toString());
      float operand2 = Float.parseFloat(arguments.get("operand2").toString());
      float ans = specialKTwoNumbers(operand1, operand2);
      return String.valueOf(ans);
    };
    toolSpecificationMap.put(toolSpecification, toolExecutor);

Where getStationName() and float specialKTwoNumbers(float, float) are two local functions.

We get the following error:

Exception in thread "main" java.lang.IllegalArgumentException: entries cannot be empty!
    at org.bsc.langgraph4j.langchain4j.tool.ToolNode.<init>(ToolNode.java:61)
    at org.bsc.langgraph4j.langchain4j.tool.ToolNode.of(ToolNode.java:49)
    at org.bsc.langgraph4j.agentexecutor.AgentExecutor$GraphBuilder.build(AgentExecutor.java:68)
    at org.bsc.langgraph4j.agentexecutor.Main.main(Main.java:46)

It is because in the ToolNode.of function, we only consider a function a tool if tool annotation is present

 if (method.isAnnotationPresent(Tool.class)) {
     toolSpecifications.add(new Specification(objectWithTool, method));
  }

Can you please add support for tool specifications specified dynamically or programatically?

Thank you!!

bsorrentino commented 2 weeks ago

HI @TiruvedulaMithun, I'll work on as soon as possible

bsorrentino commented 2 weeks ago

Hi @TiruvedulaMithun I've added the requested feature, it is available in the last 1.0-SNAPSHOT

Sample code is here. Please take the opportunity to try it and let me know.

TiruvedulaMithun commented 2 weeks ago

@bsorrentino Wow that was hella fast!! Thank you!

Dumb question, how do I go about adding the 1.0-SNAPSHOT version to my dependency? When I add the maven string org.bsc.langgraph4j:langgraph4j-core-jdk8:1.0-SNAPSHOT to my project i get and the same jar as before: image

bsorrentino commented 2 weeks ago

@bsorrentino Wow that was hella fast! Thank you!

Dumb question, I can't seem to find the 1.0-SNAPSHOT version on maven central. How would I go about finding it?

The feature is interesting and implementation was pretty simple. To use snapshot in maven you have configure the repository

                <repository>
                    <id>sonatype-server</id>
                    <name>sonatype snapshots</name>
                    <url>https://oss.sonatype.org/content/repositories/snapshots</url>
                    <snapshots>
                        <enabled>true</enabled>
                    </snapshots>
                    <releases>
                        <enabled>false</enabled>
                    </releases>
                </repository>
TiruvedulaMithun commented 2 weeks ago

Unfortunately I keep getting the error: Could not transfer artifact org.bsc.langgraph4j:langgraph4j-core-jdk8:pom:1.0-SNAPSHOT from/to sonatype-server (https://oss.sonatype.org/content/repositories/snapshots): PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

When replace https with http i get: Could not transfer artifact org.bsc.langgraph4j:langgraph4j-core-jdk8:pom:1.0-SNAPSHOT from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [sonatype-server (http://oss.sonatype.org/content/repositories/snapshots, default, snapshots)]

Any help? Thank you!

bsorrentino commented 2 weeks ago

Unfortunately I keep getting the error: Could not transfer artifact org.bsc.langgraph4j:langgraph4j-core-jdk8:pom:1.0-SNAPSHOT from/to sonatype-server (https://oss.sonatype.org/content/repositories/snapshots): PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

When replace https with http i get: Could not transfer artifact org.bsc.langgraph4j:langgraph4j-core-jdk8:pom:1.0-SNAPSHOT from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [sonatype-server (http://oss.sonatype.org/content/repositories/snapshots, default, snapshots)]

Any help? Thank you!

I've deployed an intermediate version 1.0-20241111

TiruvedulaMithun commented 2 weeks ago

Yup, works. Tested. Thank you! 🙌