diff --git a/langchain4j/pom.xml b/langchain4j/pom.xml index 80ffdef49c7..fd3b56fe95b 100644 --- a/langchain4j/pom.xml +++ b/langchain4j/pom.xml @@ -13,7 +13,9 @@ langchain4j LangChain4j - Java implementation of LangChain: Integrate your Java application with countless AI tools and services smoothly + Java implementation of LangChain: Integrate your Java application with countless AI + tools and services smoothly + @@ -28,12 +30,6 @@ opennlp-tools - - org.projectlombok - lombok - provided - - org.slf4j slf4j-api diff --git a/langchain4j/src/main/java/dev/langchain4j/chain/ConversationalChain.java b/langchain4j/src/main/java/dev/langchain4j/chain/ConversationalChain.java index 7c35faa3965..99f11bd0ef9 100644 --- a/langchain4j/src/main/java/dev/langchain4j/chain/ConversationalChain.java +++ b/langchain4j/src/main/java/dev/langchain4j/chain/ConversationalChain.java @@ -5,7 +5,6 @@ import dev.langchain4j.memory.chat.MessageWindowChatMemory; import dev.langchain4j.model.chat.ChatLanguageModel; import dev.langchain4j.service.AiServices; -import lombok.Builder; import static dev.langchain4j.data.message.UserMessage.userMessage; import static dev.langchain4j.internal.ValidationUtils.ensureNotBlank; @@ -22,12 +21,15 @@ public class ConversationalChain implements Chain { private final ChatLanguageModel chatLanguageModel; private final ChatMemory chatMemory; - @Builder private ConversationalChain(ChatLanguageModel chatLanguageModel, ChatMemory chatMemory) { this.chatLanguageModel = ensureNotNull(chatLanguageModel, "chatLanguageModel"); this.chatMemory = chatMemory == null ? MessageWindowChatMemory.withMaxMessages(10) : chatMemory; } + public static ConversationalChainBuilder builder() { + return new ConversationalChainBuilder(); + } + @Override public String execute(String userMessage) { @@ -39,4 +41,30 @@ public String execute(String userMessage) { return aiMessage.text(); } + + public static class ConversationalChainBuilder { + private ChatLanguageModel chatLanguageModel; + private ChatMemory chatMemory; + + ConversationalChainBuilder() { + } + + public ConversationalChainBuilder chatLanguageModel(ChatLanguageModel chatLanguageModel) { + this.chatLanguageModel = chatLanguageModel; + return this; + } + + public ConversationalChainBuilder chatMemory(ChatMemory chatMemory) { + this.chatMemory = chatMemory; + return this; + } + + public ConversationalChain build() { + return new ConversationalChain(this.chatLanguageModel, this.chatMemory); + } + + public String toString() { + return "ConversationalChain.ConversationalChainBuilder(chatLanguageModel=" + this.chatLanguageModel + ", chatMemory=" + this.chatMemory + ")"; + } + } } diff --git a/langchain4j/src/main/java/dev/langchain4j/data/document/loader/FileSystemDocumentLoader.java b/langchain4j/src/main/java/dev/langchain4j/data/document/loader/FileSystemDocumentLoader.java index 12eec27cbf9..6982e522858 100644 --- a/langchain4j/src/main/java/dev/langchain4j/data/document/loader/FileSystemDocumentLoader.java +++ b/langchain4j/src/main/java/dev/langchain4j/data/document/loader/FileSystemDocumentLoader.java @@ -1,7 +1,7 @@ package dev.langchain4j.data.document.loader; -import dev.langchain4j.data.document.Document; import dev.langchain4j.data.document.BlankDocumentException; +import dev.langchain4j.data.document.Document; import dev.langchain4j.data.document.DocumentLoader; import dev.langchain4j.data.document.DocumentParser; import dev.langchain4j.data.document.parser.TextDocumentParser; diff --git a/langchain4j/src/main/java/dev/langchain4j/data/document/parser/TextDocumentParser.java b/langchain4j/src/main/java/dev/langchain4j/data/document/parser/TextDocumentParser.java index 8184596c0c5..d4444ecfe39 100644 --- a/langchain4j/src/main/java/dev/langchain4j/data/document/parser/TextDocumentParser.java +++ b/langchain4j/src/main/java/dev/langchain4j/data/document/parser/TextDocumentParser.java @@ -1,14 +1,12 @@ package dev.langchain4j.data.document.parser; -import dev.langchain4j.data.document.Document; import dev.langchain4j.data.document.BlankDocumentException; +import dev.langchain4j.data.document.Document; import dev.langchain4j.data.document.DocumentParser; -import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.nio.charset.Charset; -import static dev.langchain4j.internal.Utils.isNullOrBlank; import static dev.langchain4j.internal.ValidationUtils.ensureNotNull; import static java.nio.charset.StandardCharsets.UTF_8; diff --git a/langchain4j/src/main/java/dev/langchain4j/data/document/splitter/HierarchicalDocumentSplitter.java b/langchain4j/src/main/java/dev/langchain4j/data/document/splitter/HierarchicalDocumentSplitter.java index faadf60f126..1f70fa8ef85 100644 --- a/langchain4j/src/main/java/dev/langchain4j/data/document/splitter/HierarchicalDocumentSplitter.java +++ b/langchain4j/src/main/java/dev/langchain4j/data/document/splitter/HierarchicalDocumentSplitter.java @@ -5,7 +5,6 @@ import dev.langchain4j.data.document.Metadata; import dev.langchain4j.data.segment.TextSegment; import dev.langchain4j.model.Tokenizer; -import lombok.Getter; import java.util.ArrayList; import java.util.Arrays; @@ -14,7 +13,9 @@ import java.util.concurrent.atomic.AtomicInteger; import static dev.langchain4j.internal.Utils.firstChars; -import static dev.langchain4j.internal.ValidationUtils.*; +import static dev.langchain4j.internal.ValidationUtils.ensureBetween; +import static dev.langchain4j.internal.ValidationUtils.ensureGreaterThanZero; +import static dev.langchain4j.internal.ValidationUtils.ensureNotNull; /** * Base class for hierarchical document splitters. @@ -23,9 +24,14 @@ * when a single segment is too long. */ public abstract class HierarchicalDocumentSplitter implements DocumentSplitter { - @Getter(lazy = true) - private final HierarchicalDocumentSplitter overlapSentenceSplitter = - new DocumentBySentenceSplitter(1, 0, null, null); + private HierarchicalDocumentSplitter overlapSentenceSplitter; + + private HierarchicalDocumentSplitter getOverlapSentenceSplitter() { + if (overlapSentenceSplitter == null) { + overlapSentenceSplitter = new DocumentBySentenceSplitter(1, 0, null, null); + } + return overlapSentenceSplitter; + } private static final String INDEX = "index"; diff --git a/langchain4j/src/main/java/dev/langchain4j/service/Result.java b/langchain4j/src/main/java/dev/langchain4j/service/Result.java index f1721263412..a0efd53dd0f 100644 --- a/langchain4j/src/main/java/dev/langchain4j/service/Result.java +++ b/langchain4j/src/main/java/dev/langchain4j/service/Result.java @@ -1,10 +1,9 @@ package dev.langchain4j.service; -import dev.langchain4j.service.tool.ToolExecution; import dev.langchain4j.model.output.FinishReason; import dev.langchain4j.model.output.TokenUsage; import dev.langchain4j.rag.content.Content; -import lombok.Builder; +import dev.langchain4j.service.tool.ToolExecution; import java.util.List; @@ -17,7 +16,7 @@ * such as {@link TokenUsage} and sources ({@link Content}s retrieved during RAG). * * @param The type of the content. Can be of any return type supported by AI Services, - * such as String, Enum, MyCustomPojo, etc. + * such as String, Enum, MyCustomPojo, etc. */ public class Result { @@ -27,7 +26,6 @@ public class Result { private final FinishReason finishReason; private final List toolExecutions; - @Builder public Result(T content, TokenUsage tokenUsage, List sources, FinishReason finishReason, List toolExecutions) { this.content = ensureNotNull(content, "content"); this.tokenUsage = tokenUsage; @@ -36,6 +34,10 @@ public Result(T content, TokenUsage tokenUsage, List sources, FinishRea this.toolExecutions = copyIfNotNull(toolExecutions); } + public static ResultBuilder builder() { + return new ResultBuilder(); + } + public T content() { return content; } @@ -55,4 +57,48 @@ public FinishReason finishReason() { public List toolExecutions() { return toolExecutions; } + + public static class ResultBuilder { + private T content; + private TokenUsage tokenUsage; + private List sources; + private FinishReason finishReason; + private List toolExecutions; + + ResultBuilder() { + } + + public ResultBuilder content(T content) { + this.content = content; + return this; + } + + public ResultBuilder tokenUsage(TokenUsage tokenUsage) { + this.tokenUsage = tokenUsage; + return this; + } + + public ResultBuilder sources(List sources) { + this.sources = sources; + return this; + } + + public ResultBuilder finishReason(FinishReason finishReason) { + this.finishReason = finishReason; + return this; + } + + public ResultBuilder toolExecutions(List toolExecutions) { + this.toolExecutions = toolExecutions; + return this; + } + + public Result build() { + return new Result(this.content, this.tokenUsage, this.sources, this.finishReason, this.toolExecutions); + } + + public String toString() { + return "Result.ResultBuilder(content=" + this.content + ", tokenUsage=" + this.tokenUsage + ", sources=" + this.sources + ", finishReason=" + this.finishReason + ", toolExecutions=" + this.toolExecutions + ")"; + } + } } diff --git a/langchain4j/src/main/java/dev/langchain4j/service/output/DefaultOutputParserFactory.java b/langchain4j/src/main/java/dev/langchain4j/service/output/DefaultOutputParserFactory.java index dce02bfd622..6081582349e 100644 --- a/langchain4j/src/main/java/dev/langchain4j/service/output/DefaultOutputParserFactory.java +++ b/langchain4j/src/main/java/dev/langchain4j/service/output/DefaultOutputParserFactory.java @@ -5,7 +5,12 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; -import java.util.*; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; class DefaultOutputParserFactory implements OutputParserFactory { diff --git a/langchain4j/src/main/java/dev/langchain4j/store/embedding/inmemory/InMemoryEmbeddingStore.java b/langchain4j/src/main/java/dev/langchain4j/store/embedding/inmemory/InMemoryEmbeddingStore.java index f8973c54247..79f024da20b 100644 --- a/langchain4j/src/main/java/dev/langchain4j/store/embedding/inmemory/InMemoryEmbeddingStore.java +++ b/langchain4j/src/main/java/dev/langchain4j/store/embedding/inmemory/InMemoryEmbeddingStore.java @@ -4,19 +4,32 @@ import dev.langchain4j.data.embedding.Embedding; import dev.langchain4j.data.segment.TextSegment; import dev.langchain4j.spi.store.embedding.inmemory.InMemoryEmbeddingStoreJsonCodecFactory; -import dev.langchain4j.store.embedding.*; +import dev.langchain4j.store.embedding.CosineSimilarity; +import dev.langchain4j.store.embedding.EmbeddingMatch; +import dev.langchain4j.store.embedding.EmbeddingSearchRequest; +import dev.langchain4j.store.embedding.EmbeddingSearchResult; +import dev.langchain4j.store.embedding.EmbeddingStore; +import dev.langchain4j.store.embedding.RelevanceScore; import dev.langchain4j.store.embedding.filter.Filter; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Objects; +import java.util.PriorityQueue; import java.util.concurrent.CopyOnWriteArrayList; import java.util.stream.IntStream; import static dev.langchain4j.internal.Utils.randomUUID; -import static dev.langchain4j.internal.ValidationUtils.*; +import static dev.langchain4j.internal.ValidationUtils.ensureNotBlank; +import static dev.langchain4j.internal.ValidationUtils.ensureNotEmpty; +import static dev.langchain4j.internal.ValidationUtils.ensureNotNull; import static dev.langchain4j.spi.ServiceHelper.loadFactories; import static java.nio.file.StandardOpenOption.CREATE; import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING; diff --git a/langchain4j/src/test/java/dev/langchain4j/data/document/splitter/SegmentBuilderTest.java b/langchain4j/src/test/java/dev/langchain4j/data/document/splitter/SegmentBuilderTest.java index 1b8e88f00b6..89772531d63 100644 --- a/langchain4j/src/test/java/dev/langchain4j/data/document/splitter/SegmentBuilderTest.java +++ b/langchain4j/src/test/java/dev/langchain4j/data/document/splitter/SegmentBuilderTest.java @@ -51,7 +51,7 @@ public void test_reset() { builder.reset(); assertThat(builder.isNotEmpty()).isFalse(); - assertThat(builder.getSize()).isEqualTo(0); + assertThat(builder.getSize()).isZero(); assertThat(builder.toString()).isEqualTo(""); } @@ -70,4 +70,4 @@ public void test_append_prepend() { assertThat(builder.toString()).isEqualTo("Hello world"); } } -} \ No newline at end of file +} diff --git a/langchain4j/src/test/java/dev/langchain4j/rag/query/router/LanguageModelQueryRouterIT.java b/langchain4j/src/test/java/dev/langchain4j/rag/query/router/LanguageModelQueryRouterIT.java index db1de838118..22eeec2ea44 100644 --- a/langchain4j/src/test/java/dev/langchain4j/rag/query/router/LanguageModelQueryRouterIT.java +++ b/langchain4j/src/test/java/dev/langchain4j/rag/query/router/LanguageModelQueryRouterIT.java @@ -4,6 +4,7 @@ import dev.langchain4j.model.openai.OpenAiChatModel; import dev.langchain4j.rag.content.retriever.ContentRetriever; import dev.langchain4j.rag.query.Query; +import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; @@ -19,6 +20,7 @@ import static org.assertj.core.api.Assertions.assertThat; @ExtendWith(MockitoExtension.class) +@EnabledIfEnvironmentVariable(named = "OPENAI_API_KEY", matches = ".+") class LanguageModelQueryRouterIT { @Mock diff --git a/langchain4j/src/test/java/dev/langchain4j/rag/query/transformer/CompressingQueryTransformerIT.java b/langchain4j/src/test/java/dev/langchain4j/rag/query/transformer/CompressingQueryTransformerIT.java index 235a5a82bee..9780493486e 100644 --- a/langchain4j/src/test/java/dev/langchain4j/rag/query/transformer/CompressingQueryTransformerIT.java +++ b/langchain4j/src/test/java/dev/langchain4j/rag/query/transformer/CompressingQueryTransformerIT.java @@ -7,6 +7,7 @@ import dev.langchain4j.model.openai.OpenAiChatModel; import dev.langchain4j.rag.query.Metadata; import dev.langchain4j.rag.query.Query; +import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -18,6 +19,7 @@ import static java.util.Arrays.asList; import static org.assertj.core.api.Assertions.assertThat; +@EnabledIfEnvironmentVariable(named = "OPENAI_API_KEY", matches = ".+") class CompressingQueryTransformerIT { @ParameterizedTest diff --git a/langchain4j/src/test/java/dev/langchain4j/rag/query/transformer/ExpandingQueryTransformerIT.java b/langchain4j/src/test/java/dev/langchain4j/rag/query/transformer/ExpandingQueryTransformerIT.java index e419c6001b5..74b9bd7f941 100644 --- a/langchain4j/src/test/java/dev/langchain4j/rag/query/transformer/ExpandingQueryTransformerIT.java +++ b/langchain4j/src/test/java/dev/langchain4j/rag/query/transformer/ExpandingQueryTransformerIT.java @@ -3,6 +3,7 @@ import dev.langchain4j.model.chat.ChatLanguageModel; import dev.langchain4j.model.openai.OpenAiChatModel; import dev.langchain4j.rag.query.Query; +import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -12,6 +13,7 @@ import static org.assertj.core.api.Assertions.assertThat; +@EnabledIfEnvironmentVariable(named = "OPENAI_API_KEY", matches = ".+") class ExpandingQueryTransformerIT { @ParameterizedTest @@ -49,4 +51,4 @@ static Stream should_expand_query() { // TODO add more models ); } -} \ No newline at end of file +} diff --git a/langchain4j/src/test/java/dev/langchain4j/service/AiServicesIT.java b/langchain4j/src/test/java/dev/langchain4j/service/AiServicesIT.java index 2b4a5845fd1..3a5e8dfa7a2 100644 --- a/langchain4j/src/test/java/dev/langchain4j/service/AiServicesIT.java +++ b/langchain4j/src/test/java/dev/langchain4j/service/AiServicesIT.java @@ -10,10 +10,9 @@ import dev.langchain4j.model.openai.OpenAiModerationModel; import dev.langchain4j.model.output.TokenUsage; import dev.langchain4j.model.output.structured.Description; -import lombok.Builder; -import lombok.ToString; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; @@ -47,7 +46,8 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; @ExtendWith(MockitoExtension.class) -public class AiServicesIT { +@EnabledIfEnvironmentVariable(named = "OPENAI_API_KEY", matches = ".+") +class AiServicesIT { @Spy ChatLanguageModel chatLanguageModel = OpenAiChatModel.builder() @@ -358,19 +358,18 @@ void should_extract_map() { verify(chatLanguageModel).supportedCapabilities(); } - @ToString - static class Address { - private Integer streetNumber; - private String street; - private String city; + record Address( + Integer streetNumber, + String street, + String city + ) { } - @ToString - static class Person { - private String firstName; - private String lastName; - private LocalDate birthDate; - private Address address; + static record Person( + String firstName, + String lastName, + LocalDate birthDate, + Address address) { } interface PersonExtractor { @@ -463,14 +462,13 @@ void should_extract_custom_POJO_with_explicit_json_response_format() { } - @ToString - static class Recipe { + static record Recipe( - private String title; - private String description; - @Description("each step should be described in 4 words, steps should rhyme") - private String[] steps; - private Integer preparationTimeMinutes; + String title, + String description, + @Description("each step should be described in 4 words, steps should rhyme") + String[] steps, + Integer preparationTimeMinutes) { } interface Chef { @@ -628,12 +626,10 @@ void should_fail_when_user_message_resource_is_blank() { .hasMessage("@UserMessage's template cannot be empty"); } - @Builder @StructuredPrompt("Create a recipe of a {{dish}} that can be prepared using only {{ingredients}}") - static class CreateRecipePrompt { - - private String dish; - private List ingredients; + record CreateRecipePrompt( + String dish, + List ingredients) { } @Test @@ -641,10 +637,10 @@ void test_create_recipe_using_structured_prompt() { Chef chef = AiServices.create(Chef.class, chatLanguageModel); - CreateRecipePrompt prompt = CreateRecipePrompt.builder() - .dish("salad") - .ingredients(asList("cucumber", "tomato", "feta", "onion", "olives")) - .build(); + CreateRecipePrompt prompt = new CreateRecipePrompt( + "salad", + List.of("cucumber", "tomato", "feta", "onion", "olives") + ); Recipe recipe = chef.createRecipeFrom(prompt); @@ -669,11 +665,9 @@ void test_create_recipe_using_structured_prompt_and_system_message() { Chef chef = AiServices.create(Chef.class, chatLanguageModel); - CreateRecipePrompt prompt = CreateRecipePrompt - .builder() - .dish("salad") - .ingredients(asList("cucumber", "tomato", "feta", "onion", "olives")) - .build(); + CreateRecipePrompt prompt = new CreateRecipePrompt( + "salad", + List.of("cucumber", "tomato", "feta", "onion", "olives")); Recipe recipe = chef.createRecipeFrom(prompt, "funny"); @@ -700,11 +694,9 @@ void test_create_recipe_using_structured_prompt_and_system_message_from_resource Chef chef = AiServices.create(Chef.class, chatLanguageModel); - CreateRecipePrompt prompt = CreateRecipePrompt - .builder() - .dish("salad") - .ingredients(asList("cucumber", "tomato", "feta", "onion", "olives")) - .build(); + CreateRecipePrompt prompt = new CreateRecipePrompt( + "salad", + List.of("cucumber", "tomato", "feta", "onion", "olives")); Recipe recipe = chef.createRecipeFromUsingResource(prompt, "funny"); diff --git a/langchain4j/src/test/java/dev/langchain4j/service/AiServicesWithChatMemoryIT.java b/langchain4j/src/test/java/dev/langchain4j/service/AiServicesWithChatMemoryIT.java index c03f4321825..f50c4d0bc36 100644 --- a/langchain4j/src/test/java/dev/langchain4j/service/AiServicesWithChatMemoryIT.java +++ b/langchain4j/src/test/java/dev/langchain4j/service/AiServicesWithChatMemoryIT.java @@ -9,6 +9,7 @@ import dev.langchain4j.store.memory.chat.ChatMemoryStore; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; @@ -28,9 +29,12 @@ import static java.util.Arrays.asList; import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; @ExtendWith(MockitoExtension.class) +@EnabledIfEnvironmentVariable(named = "OPENAI_API_KEY", matches = ".+") class AiServicesWithChatMemoryIT { @Spy diff --git a/langchain4j/src/test/java/dev/langchain4j/service/AiServicesWithJsonSchemaWithDescriptionsIT.java b/langchain4j/src/test/java/dev/langchain4j/service/AiServicesWithJsonSchemaWithDescriptionsIT.java index 53d0e870fa4..4f541bb8c5c 100644 --- a/langchain4j/src/test/java/dev/langchain4j/service/AiServicesWithJsonSchemaWithDescriptionsIT.java +++ b/langchain4j/src/test/java/dev/langchain4j/service/AiServicesWithJsonSchemaWithDescriptionsIT.java @@ -16,6 +16,7 @@ import dev.langchain4j.model.output.structured.Description; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; @@ -38,7 +39,8 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; @ExtendWith(MockitoExtension.class) -public class AiServicesWithJsonSchemaWithDescriptionsIT { +@EnabledIfEnvironmentVariable(named = "OPENAI_API_KEY", matches = ".+") +class AiServicesWithJsonSchemaWithDescriptionsIT { @Spy ChatLanguageModel model = OpenAiChatModel.builder() diff --git a/langchain4j/src/test/java/dev/langchain4j/service/AiServicesWithNewToolsIT.java b/langchain4j/src/test/java/dev/langchain4j/service/AiServicesWithNewToolsIT.java index 87cca4380bd..d738b7acf3c 100644 --- a/langchain4j/src/test/java/dev/langchain4j/service/AiServicesWithNewToolsIT.java +++ b/langchain4j/src/test/java/dev/langchain4j/service/AiServicesWithNewToolsIT.java @@ -13,9 +13,6 @@ import dev.langchain4j.model.chat.request.json.JsonSchemaElement; import dev.langchain4j.model.chat.request.json.JsonStringSchema; import dev.langchain4j.model.output.Response; -import lombok.AllArgsConstructor; -import lombok.EqualsAndHashCode; -import lombok.ToString; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledIf; import org.junit.jupiter.api.extension.ExtendWith; @@ -81,22 +78,22 @@ int add(int a, int b) { @Test protected void should_execute_tool_with_primitive_parameters() { - for (ChatLanguageModel model : models()) { + for (var model : models()) { // given model = spy(model); - ToolWithPrimitiveParameters tool = spy(new ToolWithPrimitiveParameters()); + var tool = spy(new ToolWithPrimitiveParameters()); - Assistant assistant = AiServices.builder(Assistant.class) + var assistant = AiServices.builder(Assistant.class) .chatLanguageModel(model) .tools(tool) .build(); - String text = "How much is 37 plus 87?"; + var text = "How much is 37 plus 87?"; // when - Response response = assistant.chat(text); + var response = assistant.chat(text); // then assertThat(response.content().text()).contains("124"); @@ -109,9 +106,9 @@ protected void should_execute_tool_with_primitive_parameters() { verify(model, times(2)).generate(anyList(), toolSpecificationCaptor.capture()); verifyNoMoreInteractions(model); - List toolSpecifications = toolSpecificationCaptor.getValue(); + var toolSpecifications = toolSpecificationCaptor.getValue(); assertThat(toolSpecifications).hasSize(1); - ToolSpecification toolSpecification = toolSpecifications.get(0); + var toolSpecification = toolSpecifications.get(0); assertThat(toolSpecification.name()).isEqualTo("add"); assertThat(toolSpecification.description()).isNull(); assertThat(toolSpecification.parameters()).isEqualTo(ToolWithPrimitiveParameters.EXPECTED_SCHEMA); @@ -121,15 +118,12 @@ protected void should_execute_tool_with_primitive_parameters() { static class ToolWithPojoParameter { - @ToString - @AllArgsConstructor - @EqualsAndHashCode - static class Person { + record Person( - String name; - int age; - Double height; - boolean married; + String name, + int age, + Double height, + boolean married) { } @Tool @@ -150,20 +144,19 @@ void process(Person person) { @Test protected void should_execute_tool_with_pojo_with_primitives() { - - for (ChatLanguageModel model : models()) { + for (var model : models()) { // given model = spy(model); - ToolWithPojoParameter tool = spy(new ToolWithPojoParameter()); + var tool = spy(new ToolWithPojoParameter()); - Assistant assistant = AiServices.builder(Assistant.class) + var assistant = AiServices.builder(Assistant.class) .chatLanguageModel(model) .tools(tool) .build(); - String text = "Use 'process' tool to process the following: Klaus is 37 years old, 1.78m height and single"; + var text = "Use 'process' tool to process the following: Klaus is 37 years old, 1.78m height and single"; // when assistant.chat(text); @@ -177,9 +170,9 @@ protected void should_execute_tool_with_pojo_with_primitives() { verify(model, times(2)).generate(anyList(), toolSpecificationCaptor.capture()); verifyNoMoreInteractions(model); - List toolSpecifications = toolSpecificationCaptor.getValue(); + var toolSpecifications = toolSpecificationCaptor.getValue(); assertThat(toolSpecifications).hasSize(1); - ToolSpecification toolSpecification = toolSpecifications.get(0); + var toolSpecification = toolSpecifications.get(0); assertThat(toolSpecification.name()).isEqualTo("process"); assertThat(toolSpecification.description()).isNull(); assertThat(toolSpecification.parameters()).isEqualTo(ToolWithPojoParameter.EXPECTED_SCHEMA); @@ -189,21 +182,13 @@ protected void should_execute_tool_with_pojo_with_primitives() { static class ToolWithNestedPojoParameter { - @ToString - @AllArgsConstructor - @EqualsAndHashCode - static class Person { - - String name; - Address address; + record Person( + String name, + Address address + ) { } - @ToString - @AllArgsConstructor - @EqualsAndHashCode - static class Address { - - String city; + record Address(String city) { } @Tool @@ -226,19 +211,19 @@ void process(Person person) { @Test protected void should_execute_tool_with_pojo_with_nested_pojo() { - for (ChatLanguageModel model : models()) { + for (var model : models()) { // given model = spy(model); - ToolWithNestedPojoParameter tool = spy(new ToolWithNestedPojoParameter()); + var tool = spy(new ToolWithNestedPojoParameter()); - Assistant assistant = AiServices.builder(Assistant.class) + var assistant = AiServices.builder(Assistant.class) .chatLanguageModel(model) .tools(tool) .build(); - String text = "Use 'process' tool to process the following: Klaus lives in Langley Falls"; + var text = "Use 'process' tool to process the following: Klaus lives in Langley Falls"; // when assistant.chat(text); @@ -252,9 +237,9 @@ protected void should_execute_tool_with_pojo_with_nested_pojo() { verify(model, times(2)).generate(anyList(), toolSpecificationCaptor.capture()); verifyNoMoreInteractions(model); - List toolSpecifications = toolSpecificationCaptor.getValue(); + var toolSpecifications = toolSpecificationCaptor.getValue(); assertThat(toolSpecifications).hasSize(1); - ToolSpecification toolSpecification = toolSpecifications.get(0); + var toolSpecification = toolSpecifications.get(0); assertThat(toolSpecification.name()).isEqualTo("process"); assertThat(toolSpecification.description()).isNull(); assertThat(toolSpecification.parameters()).isEqualTo(ToolWithNestedPojoParameter.EXPECTED_SCHEMA); @@ -264,13 +249,10 @@ protected void should_execute_tool_with_pojo_with_nested_pojo() { static class ToolWithRecursion { - @ToString - @AllArgsConstructor - @EqualsAndHashCode - static class Person { - - String name; - List children; + record Person( + String name, + List children + ) { } @Tool @@ -280,7 +262,7 @@ void process(Person person) { static final String REFERENCE = generateUUIDFrom(ToolWithRecursion.Person.class.getName()); static final JsonObjectSchema PERSON_SCHEMA = JsonObjectSchema.builder() - .properties(new LinkedHashMap() {{ + .properties(new LinkedHashMap<>() {{ put("name", new JsonStringSchema()); put("children", JsonArraySchema.builder() .items(JsonReferenceSchema.builder() @@ -302,19 +284,19 @@ void process(Person person) { @EnabledIf("supportsRecursion") protected void should_execute_tool_with_pojo_with_recursion() { - for (ChatLanguageModel model : models()) { + for (var model : models()) { // given model = spy(model); - ToolWithRecursion tool = spy(new ToolWithRecursion()); + var tool = spy(new ToolWithRecursion()); - Assistant assistant = AiServices.builder(Assistant.class) + var assistant = AiServices.builder(Assistant.class) .chatLanguageModel(model) .tools(tool) .build(); - String text = "Use 'process' tool to process the following: Francine has 2 children: Steve and Hayley"; + var text = "Use 'process' tool to process the following: Francine has 2 children: Steve and Hayley"; // when assistant.chat(text); @@ -336,9 +318,9 @@ protected void should_execute_tool_with_pojo_with_recursion() { verify(model, times(2)).generate(anyList(), toolSpecificationCaptor.capture()); verifyNoMoreInteractions(model); - List toolSpecifications = toolSpecificationCaptor.getValue(); + var toolSpecifications = toolSpecificationCaptor.getValue(); assertThat(toolSpecifications).hasSize(1); - ToolSpecification toolSpecification = toolSpecifications.get(0); + var toolSpecification = toolSpecifications.get(0); assertThat(toolSpecification.name()).isEqualTo("process"); assertThat(toolSpecification.description()).isNull(); assertThat(toolSpecification.parameters()).isEqualTo(ToolWithRecursion.EXPECTED_SCHEMA); @@ -361,22 +343,22 @@ LocalTime currentTime() { // TODO support LocalTime @Test protected void should_execute_tool_without_parameters() { - for (ChatLanguageModel model : models()) { + for (var model : models()) { // given model = spy(model); - ToolWithoutParameters tools = spy(new ToolWithoutParameters()); + var tools = spy(new ToolWithoutParameters()); - Assistant assistant = AiServices.builder(Assistant.class) + var assistant = AiServices.builder(Assistant.class) .chatLanguageModel(model) .tools(tools) .build(); - String text = "What is the time now? Respond in HH:MM:SS format."; + var text = "What is the time now? Respond in HH:MM:SS format."; // when - Response response = assistant.chat(text); + var response = assistant.chat(text); // then assertThat(response.content().text()).contains("17:11:45"); @@ -389,9 +371,9 @@ protected void should_execute_tool_without_parameters() { verify(model, times(2)).generate(anyList(), toolSpecificationCaptor.capture()); verifyNoMoreInteractions(model); - List toolSpecifications = toolSpecificationCaptor.getValue(); + var toolSpecifications = toolSpecificationCaptor.getValue(); assertThat(toolSpecifications).hasSize(1); - ToolSpecification toolSpecification = toolSpecifications.get(0); + var toolSpecification = toolSpecifications.get(0); assertThat(toolSpecification.name()).isEqualTo("currentTime"); assertThat(toolSpecification.description()).isNull(); assertThat(toolSpecification.parameters()).isNull(); @@ -426,22 +408,22 @@ int currentTemperature(String city, TemperatureUnit unit) { @Test protected void should_execute_tool_with_enum_parameter() { - for (ChatLanguageModel model : models()) { + for (var model : models()) { // given model = spy(model); - ToolWithEnumParameter tool = spy(new ToolWithEnumParameter()); + var tool = spy(new ToolWithEnumParameter()); - Assistant assistant = AiServices.builder(Assistant.class) + var assistant = AiServices.builder(Assistant.class) .chatLanguageModel(model) .tools(tool) .build(); - String text = "What is the weather in Munich in celsius?"; + var text = "What is the weather in Munich in celsius?"; // when - Response response = assistant.chat(text); + var response = assistant.chat(text); // then assertThat(response.content().text()).contains("19"); @@ -454,7 +436,7 @@ protected void should_execute_tool_with_enum_parameter() { verify(model, times(2)).generate(anyList(), toolSpecificationCaptor.capture()); verifyNoMoreInteractions(model); - List toolSpecifications = toolSpecificationCaptor.getValue(); + var toolSpecifications = toolSpecificationCaptor.getValue(); assertThat(toolSpecifications).hasSize(1); assertThat(toolSpecifications.get(0)).isEqualTo(ToolWithEnumParameter.EXPECTED_SPECIFICATION); } @@ -482,19 +464,19 @@ void process(@P("map from name to age") Map ages) { @EnabledIf("supportsMapParameters") protected void should_execute_tool_with_map_parameter() { - for (ChatLanguageModel model : modelsSupportingMapParametersInTools()) { + for (var model : modelsSupportingMapParametersInTools()) { // given model = spy(model); - ToolWithMapParameter tool = spy(new ToolWithMapParameter()); + var tool = spy(new ToolWithMapParameter()); - Assistant assistant = AiServices.builder(Assistant.class) + var assistant = AiServices.builder(Assistant.class) .chatLanguageModel(model) .tools(tool) .build(); - String text = "Process the following: Klaus is 42 years old and Francine is 47 years old"; + var text = "Process the following: Klaus is 42 years old and Francine is 47 years old"; // when assistant.chat(text); @@ -511,7 +493,7 @@ protected void should_execute_tool_with_map_parameter() { verify(model, times(2)).generate(anyList(), toolSpecificationCaptor.capture()); verifyNoMoreInteractions(model); - List toolSpecifications = toolSpecificationCaptor.getValue(); + var toolSpecifications = toolSpecificationCaptor.getValue(); assertThat(toolSpecifications).hasSize(1); assertThat(toolSpecifications.get(0)).isEqualTo(ToolWithMapParameter.EXPECTED_SPECIFICATION); } @@ -542,19 +524,19 @@ void processNames(List names) { @Test protected void should_execute_tool_with_list_of_strings_parameter() { - for (ChatLanguageModel model : models()) { + for (var model : models()) { // given model = spy(model); - ToolWithListOfStringsParameter tool = spy(new ToolWithListOfStringsParameter()); + var tool = spy(new ToolWithListOfStringsParameter()); - Assistant assistant = AiServices.builder(Assistant.class) + var assistant = AiServices.builder(Assistant.class) .chatLanguageModel(model) .tools(tool) .build(); - String text = "Process the following names: Klaus and Franny"; + var text = "Process the following names: Klaus and Franny"; // when assistant.chat(text); @@ -568,7 +550,7 @@ protected void should_execute_tool_with_list_of_strings_parameter() { verify(model, times(2)).generate(anyList(), toolSpecificationCaptor.capture()); verifyNoMoreInteractions(model); - List toolSpecifications = toolSpecificationCaptor.getValue(); + var toolSpecifications = toolSpecificationCaptor.getValue(); assertThat(toolSpecifications).hasSize(1); assertThat(toolSpecifications.get(0)).isEqualTo(ToolWithListOfStringsParameter.EXPECTED_SPECIFICATION); } @@ -602,19 +584,19 @@ void process(Set colors) { @Test protected void should_execute_tool_with_set_of_enums_parameter() { - for (ChatLanguageModel model : models()) { + for (var model : models()) { // given model = spy(model); - ToolWithSetOfEnumsParameter tool = spy(new ToolWithSetOfEnumsParameter()); + var tool = spy(new ToolWithSetOfEnumsParameter()); - Assistant assistant = AiServices.builder(Assistant.class) + var assistant = AiServices.builder(Assistant.class) .chatLanguageModel(model) .tools(tool) .build(); - String text = "Process the following colors: RED and GREEN"; + var text = "Process the following colors: RED and GREEN"; // when assistant.chat(text); @@ -628,7 +610,7 @@ protected void should_execute_tool_with_set_of_enums_parameter() { verify(model, times(2)).generate(anyList(), toolSpecificationCaptor.capture()); verifyNoMoreInteractions(model); - List toolSpecifications = toolSpecificationCaptor.getValue(); + var toolSpecifications = toolSpecificationCaptor.getValue(); assertThat(toolSpecifications).hasSize(1); assertThat(toolSpecifications.get(0)).isEqualTo(ToolWithSetOfEnumsParameter.EXPECTED_SPECIFICATION); } @@ -655,19 +637,19 @@ void processNumbers(Collection names) { @Test protected void should_execute_tool_with_collection_of_integers_parameter() { - for (ChatLanguageModel model : models()) { + for (var model : models()) { // given model = spy(model); - ToolWithCollectionOfIntegersParameter tool = spy(new ToolWithCollectionOfIntegersParameter()); + var tool = spy(new ToolWithCollectionOfIntegersParameter()); - Assistant assistant = AiServices.builder(Assistant.class) + var assistant = AiServices.builder(Assistant.class) .chatLanguageModel(model) .tools(tool) .build(); - String text = "Process the following integers: 37, 73"; + var text = "Process the following integers: 37, 73"; // when assistant.chat(text); @@ -681,7 +663,7 @@ protected void should_execute_tool_with_collection_of_integers_parameter() { verify(model, times(2)).generate(anyList(), toolSpecificationCaptor.capture()); verifyNoMoreInteractions(model); - List toolSpecifications = toolSpecificationCaptor.getValue(); + var toolSpecifications = toolSpecificationCaptor.getValue(); assertThat(toolSpecifications).hasSize(1); assertThat(toolSpecifications.get(0)).isEqualTo(ToolWithCollectionOfIntegersParameter.EXPECTED_SPECIFICATION); } @@ -690,12 +672,7 @@ protected void should_execute_tool_with_collection_of_integers_parameter() { static class ToolWithListOfPojoParameter { - @ToString - @AllArgsConstructor - @EqualsAndHashCode - static class Person { - - String name; + record Person(String name) { } @Tool @@ -720,19 +697,19 @@ void process(List people) { @Test protected void should_execute_tool_with_list_of_POJOs_parameter() { - for (ChatLanguageModel model : models()) { + for (var model : models()) { // given model = spy(model); - ToolWithListOfPojoParameter tool = spy(new ToolWithListOfPojoParameter()); + var tool = spy(new ToolWithListOfPojoParameter()); - Assistant assistant = AiServices.builder(Assistant.class) + var assistant = AiServices.builder(Assistant.class) .chatLanguageModel(model) .tools(tool) .build(); - String text = "Process the following people: Klaus and Franny"; + var text = "Process the following people: Klaus and Franny"; // when assistant.chat(text); @@ -754,7 +731,7 @@ protected void should_execute_tool_with_list_of_POJOs_parameter() { verify(model, times(2)).generate(anyList(), toolSpecificationCaptor.capture()); verifyNoMoreInteractions(model); - List toolSpecifications = toolSpecificationCaptor.getValue(); + var toolSpecifications = toolSpecificationCaptor.getValue(); assertThat(toolSpecifications).hasSize(1); assertThat(toolSpecifications.get(0)).isEqualTo(ToolWithListOfPojoParameter.EXPECTED_SPECIFICATION); } diff --git a/langchain4j/src/test/java/dev/langchain4j/service/AiServicesWithNewToolsWithDescriptionIT.java b/langchain4j/src/test/java/dev/langchain4j/service/AiServicesWithNewToolsWithDescriptionIT.java index e50f2236425..c3a93d319ba 100644 --- a/langchain4j/src/test/java/dev/langchain4j/service/AiServicesWithNewToolsWithDescriptionIT.java +++ b/langchain4j/src/test/java/dev/langchain4j/service/AiServicesWithNewToolsWithDescriptionIT.java @@ -14,9 +14,7 @@ import dev.langchain4j.model.openai.OpenAiChatModel; import dev.langchain4j.model.output.Response; import dev.langchain4j.model.output.structured.Description; -import lombok.AllArgsConstructor; -import lombok.EqualsAndHashCode; -import lombok.ToString; +import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -45,6 +43,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; @ExtendWith(MockitoExtension.class) +@EnabledIfEnvironmentVariable(named = "OPENAI_API_KEY", matches = ".+") class AiServicesWithNewToolsWithDescriptionIT { @Captor @@ -123,27 +122,26 @@ void should_execute_tool_with_primitive_parameters(ChatLanguageModel model) { static class ToolWithPojoParameter { - @ToString - @AllArgsConstructor - @EqualsAndHashCode @Description("a person") - static class Person { + record Person( - @Description("a name") - String name; + @Description("a name") + String name, - @Description("an age") - int age; + @Description("an age") + int age, - @Description("a height") - Double height; + @Description("a height") + Double height, - @Description("is married") - boolean married; + @Description("is married") + boolean married + ) { } @Tool("processes a person") void process(@P("a person 2") Person person) { + // this method is empty } static JsonSchemaElement EXPECTED_SCHEMA = JsonObjectSchema.builder() @@ -197,27 +195,20 @@ void should_execute_tool_with_pojo_with_primitives(ChatLanguageModel model) { static class ToolWithNestedPojoParameter { - @ToString - @AllArgsConstructor - @EqualsAndHashCode @Description("a person") - static class Person { + record Person( - @Description("a name") - String name; + @Description("a name") + String name, - @Description("an address 2") - Address address; + @Description("an address 2") + Address address) { } - @ToString - @AllArgsConstructor - @EqualsAndHashCode @Description("an address") - static class Address { - - @Description("a city") - String city; + record Address( + @Description("a city") + String city) { } @Tool("processes a person") @@ -276,21 +267,19 @@ void should_execute_tool_with_pojo_with_nested_pojo(ChatLanguageModel model) { static class ToolWithRecursion { - @ToString - @AllArgsConstructor - @EqualsAndHashCode @Description("a person") - static class Person { - - @Description("a name") - String name; + record Person( + @Description("a name") + String name, - @Description("a list of person") - List children; + @Description("a list of person") + List children + ) { } @Tool("processes a person") void process(@P("a person 2") Person person) { + // this method is empty } static final String REFERENCE = generateUUIDFrom(Person.class.getName()); @@ -422,6 +411,7 @@ static class ToolWithMapParameter { @Tool("processes ages") void process(@P("map from name to age") Map ages) { + // this method is empty } static ToolSpecification EXPECTED_SPECIFICATION = ToolSpecification.builder() @@ -456,7 +446,7 @@ void should_execute_tool_with_map_parameter(ChatLanguageModel model) { assistant.chat(text); // then - verify(tool).process(new HashMap() {{ + verify(tool).process(new HashMap<>() {{ put("Klaus", 42); put("Francine", 47); }}); diff --git a/langchain4j/src/test/java/dev/langchain4j/service/AiServicesWithRagIT.java b/langchain4j/src/test/java/dev/langchain4j/service/AiServicesWithRagIT.java index 2777fb3c019..addf55c63a7 100644 --- a/langchain4j/src/test/java/dev/langchain4j/service/AiServicesWithRagIT.java +++ b/langchain4j/src/test/java/dev/langchain4j/service/AiServicesWithRagIT.java @@ -9,8 +9,8 @@ import dev.langchain4j.data.segment.TextSegment; import dev.langchain4j.memory.chat.MessageWindowChatMemory; import dev.langchain4j.model.chat.ChatLanguageModel; -import dev.langchain4j.model.embedding.onnx.allminilml6v2q.AllMiniLmL6V2QuantizedEmbeddingModel; import dev.langchain4j.model.embedding.EmbeddingModel; +import dev.langchain4j.model.embedding.onnx.allminilml6v2q.AllMiniLmL6V2QuantizedEmbeddingModel; import dev.langchain4j.model.openai.OpenAiChatModel; import dev.langchain4j.model.openai.OpenAiTokenizer; import dev.langchain4j.model.output.Response; @@ -37,6 +37,7 @@ import dev.langchain4j.store.embedding.filter.builder.sql.TableDefinition; import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -59,8 +60,15 @@ import static java.util.Collections.emptyList; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.Mockito.*; - +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +@EnabledIfEnvironmentVariable(named = "OPENAI_API_KEY", matches = ".+") class AiServicesWithRagIT { private static final String ALLOWED_CANCELLATION_PERIOD_DAYS = "61"; diff --git a/langchain4j/src/test/java/dev/langchain4j/service/AiServicesWithToolsIT.java b/langchain4j/src/test/java/dev/langchain4j/service/AiServicesWithToolsIT.java index a231c862212..15c6084e4e3 100644 --- a/langchain4j/src/test/java/dev/langchain4j/service/AiServicesWithToolsIT.java +++ b/langchain4j/src/test/java/dev/langchain4j/service/AiServicesWithToolsIT.java @@ -29,9 +29,8 @@ import dev.langchain4j.service.tool.ToolProvider; import dev.langchain4j.service.tool.ToolProviderRequest; import dev.langchain4j.service.tool.ToolProviderResult; -import lombok.AllArgsConstructor; -import lombok.Data; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -65,6 +64,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; @ExtendWith(MockitoExtension.class) +@EnabledIfEnvironmentVariable(named = "OPENAI_API_KEY", matches = ".+") class AiServicesWithToolsIT { static Stream models() { @@ -626,35 +626,32 @@ String executeQuery(@P("query to execute") Query query) { } } - @Data - static class Query { + static record Query( @Description("List of fields to fetch records") - List select; + List select, @Description("List of conditions to filter on. Pass null if no condition") - List where; + List where, @Description("limit on number of records") - Integer limit; + Integer limit, @Description("offset for fetching records") - Integer offset; - } + Integer offset) + {} - @Data - @AllArgsConstructor - static class Condition { + static record Condition( @Description("Field to filter on") - String field; + String field, @Description("Operator to apply") - Operator operator; + Operator operator, @Description("Value to compare with") - String value; - } + String value) + {} enum Operator { @@ -941,7 +938,8 @@ public void should_execute_a_tool_and_context_included_in_result(ChatLanguageMod @ParameterizedTest @MethodSource("models") - public void should_execute_multi_tool_in_parallel_and_context_included_in_result(ChatLanguageModel chatLanguageModel) { + @EnabledIfEnvironmentVariable(named = "OPENAI_API_KEY", matches = ".+") + void should_execute_multi_tool_in_parallel_and_context_included_in_result(ChatLanguageModel chatLanguageModel) { // given TransactionService transactionService = spy(new TransactionService()); diff --git a/langchain4j/src/test/java/dev/langchain4j/service/AiServicesWithToolsWithoutMemoryIT.java b/langchain4j/src/test/java/dev/langchain4j/service/AiServicesWithToolsWithoutMemoryIT.java index ee651995ef5..7d5cd84636f 100644 --- a/langchain4j/src/test/java/dev/langchain4j/service/AiServicesWithToolsWithoutMemoryIT.java +++ b/langchain4j/src/test/java/dev/langchain4j/service/AiServicesWithToolsWithoutMemoryIT.java @@ -8,6 +8,7 @@ import dev.langchain4j.model.output.Response; import dev.langchain4j.model.output.TokenUsage; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; @@ -16,9 +17,12 @@ import static dev.langchain4j.model.output.FinishReason.STOP; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.data.Percentage.withPercentage; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; @ExtendWith(MockitoExtension.class) +@EnabledIfEnvironmentVariable(named = "OPENAI_API_KEY", matches = ".+") class AiServicesWithToolsWithoutMemoryIT { @Spy diff --git a/langchain4j/src/test/java/dev/langchain4j/service/OpenAiAiServiceWithToolsIT.java b/langchain4j/src/test/java/dev/langchain4j/service/OpenAiAiServiceWithToolsIT.java index 1ae84d4d747..5afd1a8c672 100644 --- a/langchain4j/src/test/java/dev/langchain4j/service/OpenAiAiServiceWithToolsIT.java +++ b/langchain4j/src/test/java/dev/langchain4j/service/OpenAiAiServiceWithToolsIT.java @@ -2,6 +2,7 @@ import dev.langchain4j.model.chat.ChatLanguageModel; import dev.langchain4j.model.openai.OpenAiChatModel; +import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import java.util.List; @@ -10,6 +11,7 @@ import static java.util.Collections.singletonList; // TODO move to langchain4j-open-ai module once cyclic dependency is resolved +@EnabledIfEnvironmentVariable(named = "OPENAI_API_KEY", matches = ".+") class OpenAiAiServiceWithToolsIT extends AiServicesWithNewToolsIT { @Override diff --git a/langchain4j/src/test/java/dev/langchain4j/service/OpenAiAiServicesWithJsonSchemaIT.java b/langchain4j/src/test/java/dev/langchain4j/service/OpenAiAiServicesWithJsonSchemaIT.java index 78bcdd0f3b4..52c9b656c02 100644 --- a/langchain4j/src/test/java/dev/langchain4j/service/OpenAiAiServicesWithJsonSchemaIT.java +++ b/langchain4j/src/test/java/dev/langchain4j/service/OpenAiAiServicesWithJsonSchemaIT.java @@ -2,6 +2,7 @@ import dev.langchain4j.model.chat.ChatLanguageModel; import dev.langchain4j.model.openai.OpenAiChatModel; +import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import java.util.List; @@ -9,6 +10,7 @@ import static java.util.Arrays.asList; // TODO move to langchain4j-open-ai module once dependency cycle is resolved +@EnabledIfEnvironmentVariable(named = "OPENAI_API_KEY", matches = ".+") class OpenAiAiServicesWithJsonSchemaIT extends AiServicesWithJsonSchemaIT { @Override diff --git a/langchain4j/src/test/java/dev/langchain4j/service/StreamingAiServicesIT.java b/langchain4j/src/test/java/dev/langchain4j/service/StreamingAiServicesIT.java index ecf27503ce1..933d370e75d 100644 --- a/langchain4j/src/test/java/dev/langchain4j/service/StreamingAiServicesIT.java +++ b/langchain4j/src/test/java/dev/langchain4j/service/StreamingAiServicesIT.java @@ -17,6 +17,7 @@ import dev.langchain4j.rag.RetrievalAugmentor; import dev.langchain4j.rag.content.Content; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -36,7 +37,8 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; -public class StreamingAiServicesIT { +@EnabledIfEnvironmentVariable(named = "OPENAI_API_KEY", matches = ".+") +class StreamingAiServicesIT { static Stream models() { return Stream.of( diff --git a/langchain4j/src/test/java/dev/langchain4j/service/StreamingAiServicesWithToolsIT.java b/langchain4j/src/test/java/dev/langchain4j/service/StreamingAiServicesWithToolsIT.java index 1d6274f2c63..f150d5a5361 100644 --- a/langchain4j/src/test/java/dev/langchain4j/service/StreamingAiServicesWithToolsIT.java +++ b/langchain4j/src/test/java/dev/langchain4j/service/StreamingAiServicesWithToolsIT.java @@ -20,6 +20,7 @@ import dev.langchain4j.service.tool.ToolProvider; import dev.langchain4j.service.tool.ToolProviderResult; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -43,6 +44,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; +@EnabledIfEnvironmentVariable(named = "OPENAI_API_KEY", matches = ".+") class StreamingAiServicesWithToolsIT { static Stream models() { diff --git a/langchain4j/src/test/java/dev/langchain4j/service/StreamingAiServicesWithToolsWithoutMemoryIT.java b/langchain4j/src/test/java/dev/langchain4j/service/StreamingAiServicesWithToolsWithoutMemoryIT.java index 0b3573bb31d..3434c85235a 100644 --- a/langchain4j/src/test/java/dev/langchain4j/service/StreamingAiServicesWithToolsWithoutMemoryIT.java +++ b/langchain4j/src/test/java/dev/langchain4j/service/StreamingAiServicesWithToolsWithoutMemoryIT.java @@ -11,6 +11,7 @@ import dev.langchain4j.model.output.Response; import dev.langchain4j.model.output.TokenUsage; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.Spy; @@ -23,9 +24,15 @@ import static dev.langchain4j.model.openai.OpenAiChatModelName.GPT_4_O_MINI; import static dev.langchain4j.model.output.FinishReason.STOP; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyList; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; @ExtendWith(MockitoExtension.class) +@EnabledIfEnvironmentVariable(named = "OPENAI_API_KEY", matches = ".+") class StreamingAiServicesWithToolsWithoutMemoryIT { @Spy diff --git a/langchain4j/src/test/java/dev/langchain4j/service/tool/DefaultToolExecutorTest.java b/langchain4j/src/test/java/dev/langchain4j/service/tool/DefaultToolExecutorTest.java index f61851995f4..7c22fb71e5e 100644 --- a/langchain4j/src/test/java/dev/langchain4j/service/tool/DefaultToolExecutorTest.java +++ b/langchain4j/src/test/java/dev/langchain4j/service/tool/DefaultToolExecutorTest.java @@ -4,8 +4,6 @@ import dev.langchain4j.agent.tool.Tool; import dev.langchain4j.agent.tool.ToolExecutionRequest; import dev.langchain4j.agent.tool.ToolMemoryId; -import lombok.AllArgsConstructor; -import lombok.EqualsAndHashCode; import org.assertj.core.api.WithAssertions; import org.junit.jupiter.api.Test; @@ -149,12 +147,10 @@ public void test_prepareArguments() throws Exception { } } - @AllArgsConstructor - @EqualsAndHashCode - static class Person { + record Person( - String name; - int age; + String name, + int age) { } @Test @@ -481,4 +477,4 @@ public void should_execute_tools_with_collection() { " }\n" + "]"); } -} \ No newline at end of file +}