quarkiverse / quarkus-langchain4j

Quarkus Langchain4j extension
https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html
Apache License 2.0
148 stars 89 forks source link

How to use async tools (Uni) #837

Open dastrobu opened 2 months ago

dastrobu commented 2 months ago

When declaring a tool with a Uni as return type,

@ApplicationScoped
public class MyTool {

    @RestClient
    @Inject
    MyClient client;

    @Tool(name = "schema.json", value = "get the schema.json schema.")
    Uni<String> get() {
        return myClient.get();
    }
}

the tool call fails with a very long exception.

com.fasterxml.jackson.databind.JsonMappingException: Document nesting depth (1001) exceeds the maximum allowed (1000, from `StreamWriteConstraints.getMaxNestingDepth()`) (through reference chain: io.smallrye.mutiny.operators.uni.UniOnFailureTransform["upstream"]->io.smallrye.mutiny.operators.uni.build...

Relevant code is: https://github.com/quarkiverse/quarkus-langchain4j/blob/5245831ea7e6817423352291c7433dda4c0558bb/core/runtime/src/main/java/io/quarkiverse/langchain4j/runtime/tool/QuarkusToolExecutor.java#L50 and https://github.com/quarkiverse/quarkus-langchain4j/blob/5245831ea7e6817423352291c7433dda4c0558bb/core/runtime/src/main/java/io/quarkiverse/langchain4j/runtime/tool/QuarkusToolExecutor.java#L66

where the uni result is passed into the JSON decoder.

Alternatives Considered

Awaiting the rest client call in the tool also does not seem to work.

@ApplicationScoped
public class MyTool {

    @RestClient
    @Inject
    MyClient client;

    @Tool(name = "schema.json", value = "get the schema.json schema.")
    String get() {
        String schema = unityClient.getSchema()
            .runSubscriptionOn(Infrastructure.getDefaultExecutor())
            .await().indefinitely();
        return schema;
    }
}

This results in "The current thread cannot be blocked: vert.x-eventloop-thread-4".

Adding @Blocking:

    @Tool(name = "schema.json", value = "get the schema.json schema.")
    @Blocking
    String get() {

results in

Wrong usage(s) of @Blocking found:
        - MyTool.get()()

Is there something I am missing?

geoand commented 2 months ago

Using async tools is currently not supported, but something we should consider in the future