Skip to content

Commit bd2a14a

Browse files
Bump dev.langchain4j:langchain4j from 0.36.2 to 1.0.0 (#13146)
* Bump dev.langchain4j:langchain4j from 0.36.2 to 1.0.0 Bumps [dev.langchain4j:langchain4j](https://github.com/langchain4j/langchain4j) from 0.36.2 to 1.0.0. - [Release notes](https://github.com/langchain4j/langchain4j/releases) - [Commits](langchain4j/langchain4j@0.36.2...1.0.0) --- updated-dependencies: - dependency-name: dev.langchain4j:langchain4j dependency-version: 1.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <[email protected]> * use bom for langhchain * use bom * migrate * checkstyle --------- Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Christoph <[email protected]>
1 parent 3c97e33 commit bd2a14a

15 files changed

+90
-85
lines changed

jabgui/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ dependencies {
8080

8181
implementation("com.google.guava:guava:33.4.8-jre")
8282

83-
implementation("dev.langchain4j:langchain4j:0.36.2")
83+
implementation("dev.langchain4j:langchain4j:1.0.0")
8484

8585
implementation("io.github.java-diff-utils:java-diff-utils:4.15")
8686

jablib/build.gradle.kts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1+
12
import com.vanniktech.maven.publish.JavaLibrary
23
import com.vanniktech.maven.publish.JavadocJar
34
import com.vanniktech.maven.publish.SonatypeHost
45
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
5-
import java.util.Calendar;
6+
import java.util.*
67

78
plugins {
89
id("buildlogic.java-common-conventions")
@@ -148,23 +149,23 @@ dependencies {
148149
implementation("org.glassfish.jaxb:jaxb-runtime:4.0.5")
149150

150151
// region AI
151-
implementation("dev.langchain4j:langchain4j:0.36.2")
152+
implementation("dev.langchain4j:langchain4j:1.0.0")
152153
// Even though we use jvm-openai for LLM connection, we still need this package for tokenization.
153-
implementation("dev.langchain4j:langchain4j-open-ai:0.36.2") {
154+
implementation("dev.langchain4j:langchain4j-open-ai:1.0.0") {
154155
exclude(group = "com.squareup.okhttp3")
155156
exclude(group = "com.squareup.retrofit2", module = "retrofit")
156157
exclude(group = "org.jetbrains.kotlin")
157158
}
158-
implementation("dev.langchain4j:langchain4j-mistral-ai:0.36.2") {
159+
implementation("dev.langchain4j:langchain4j-mistral-ai:1.0.0-beta5") {
159160
exclude(group = "com.squareup.okhttp3")
160161
exclude(group = "com.squareup.retrofit2", module = "retrofit")
161162
exclude(group = "org.jetbrains.kotlin")
162163
}
163-
implementation("dev.langchain4j:langchain4j-google-ai-gemini:0.36.2") {
164+
implementation("dev.langchain4j:langchain4j-google-ai-gemini:1.0.0-beta5") {
164165
exclude(group = "com.squareup.okhttp3")
165166
exclude(group = "com.squareup.retrofit2", module = "retrofit")
166167
}
167-
implementation("dev.langchain4j:langchain4j-hugging-face:0.36.2") {
168+
implementation("dev.langchain4j:langchain4j-hugging-face:1.0.0-beta5") {
168169
exclude(group = "com.squareup.okhttp3")
169170
exclude(group = "com.squareup.retrofit2", module = "retrofit")
170171
exclude(group = "org.jetbrains.kotlin")

jablib/src/main/java/org/jabref/logic/ai/chatting/AiChatLogic.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@
2525
import dev.langchain4j.data.segment.TextSegment;
2626
import dev.langchain4j.memory.ChatMemory;
2727
import dev.langchain4j.memory.chat.TokenWindowChatMemory;
28-
import dev.langchain4j.model.chat.ChatLanguageModel;
28+
import dev.langchain4j.model.chat.ChatModel;
2929
import dev.langchain4j.model.embedding.EmbeddingModel;
3030
import dev.langchain4j.model.openai.OpenAiChatModelName;
31-
import dev.langchain4j.model.openai.OpenAiTokenizer;
31+
import dev.langchain4j.model.openai.OpenAiTokenCountEstimator;
3232
import dev.langchain4j.store.embedding.EmbeddingMatch;
3333
import dev.langchain4j.store.embedding.EmbeddingSearchRequest;
3434
import dev.langchain4j.store.embedding.EmbeddingSearchResult;
@@ -42,7 +42,7 @@ public class AiChatLogic {
4242
private static final Logger LOGGER = LoggerFactory.getLogger(AiChatLogic.class);
4343

4444
private final AiPreferences aiPreferences;
45-
private final ChatLanguageModel chatLanguageModel;
45+
private final ChatModel chatLanguageModel;
4646
private final EmbeddingModel embeddingModel;
4747
private final EmbeddingStore<TextSegment> embeddingStore;
4848
private final TemplatesService templatesService;
@@ -57,7 +57,7 @@ public class AiChatLogic {
5757
private Optional<Filter> filter = Optional.empty();
5858

5959
public AiChatLogic(AiPreferences aiPreferences,
60-
ChatLanguageModel chatLanguageModel,
60+
ChatModel chatLanguageModel,
6161
EmbeddingModel embeddingModel,
6262
EmbeddingStore<TextSegment> embeddingStore,
6363
TemplatesService templatesService,
@@ -108,7 +108,7 @@ private void rebuildChatMemory(List<ChatMessage> chatMessages) {
108108
// This is another dark workaround of AI integration. But it works "good-enough" for now.
109109
this.chatMemory = TokenWindowChatMemory
110110
.builder()
111-
.maxTokens(aiPreferences.getContextWindowSize(), new OpenAiTokenizer(OpenAiChatModelName.GPT_4_O_MINI))
111+
.maxTokens(aiPreferences.getContextWindowSize(), new OpenAiTokenCountEstimator(OpenAiChatModelName.GPT_4_O_MINI))
112112
.build();
113113

114114
chatMessages.stream().filter(chatMessage -> !(chatMessage instanceof ErrorMessage)).forEach(chatMemory::add);
@@ -176,15 +176,15 @@ public AiMessage execute(UserMessage message) {
176176
// This is crazy, but langchain4j {@link ChatMemory} does not allow to remove single messages.
177177
ChatMemory tempChatMemory = TokenWindowChatMemory
178178
.builder()
179-
.maxTokens(aiPreferences.getContextWindowSize(), new OpenAiTokenizer())
179+
.maxTokens(aiPreferences.getContextWindowSize(), new OpenAiTokenCountEstimator(OpenAiChatModelName.GPT_4_O_MINI))
180180
.build();
181181

182182
chatMemory.messages().forEach(tempChatMemory::add);
183183

184184
tempChatMemory.add(new UserMessage(templatesService.makeChattingUserMessage(entries, message.singleText(), excerpts)));
185185
chatMemory.add(message);
186186

187-
AiMessage aiMessage = chatLanguageModel.generate(tempChatMemory.messages()).content();
187+
AiMessage aiMessage = chatLanguageModel.chat(tempChatMemory.messages()).aiMessage();
188188

189189
chatMemory.add(aiMessage);
190190
chatHistory.add(aiMessage);

jablib/src/main/java/org/jabref/logic/ai/chatting/AiChatService.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,19 @@
1010

1111
import dev.langchain4j.data.message.ChatMessage;
1212
import dev.langchain4j.data.segment.TextSegment;
13-
import dev.langchain4j.model.chat.ChatLanguageModel;
13+
import dev.langchain4j.model.chat.ChatModel;
1414
import dev.langchain4j.model.embedding.EmbeddingModel;
1515
import dev.langchain4j.store.embedding.EmbeddingStore;
1616

1717
public class AiChatService {
1818
private final AiPreferences aiPreferences;
19-
private final ChatLanguageModel chatLanguageModel;
19+
private final ChatModel chatLanguageModel;
2020
private final EmbeddingModel embeddingModel;
2121
private final EmbeddingStore<TextSegment> embeddingStore;
2222
private final TemplatesService templatesService;
2323

2424
public AiChatService(AiPreferences aiPreferences,
25-
ChatLanguageModel chatLanguageModel,
25+
ChatModel chatLanguageModel,
2626
EmbeddingModel embeddingModel,
2727
EmbeddingStore<TextSegment> embeddingStore,
2828
TemplatesService templatesService

jablib/src/main/java/org/jabref/logic/ai/chatting/JabRefContentInjector.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import org.jabref.model.database.BibDatabaseContext;
1010
import org.jabref.model.entry.BibEntry;
1111

12+
import dev.langchain4j.data.message.ChatMessage;
1213
import dev.langchain4j.data.message.UserMessage;
1314
import dev.langchain4j.model.input.PromptTemplate;
1415
import dev.langchain4j.rag.content.Content;
@@ -26,11 +27,14 @@ public JabRefContentInjector(BibDatabaseContext bibDatabaseContext) {
2627
}
2728

2829
@Override
29-
public UserMessage inject(List<Content> list, UserMessage userMessage) {
30-
String contentText = list.stream().map(this::contentToString).collect(Collectors.joining("\n\n"));
30+
public UserMessage inject(List<Content> contents, ChatMessage chatMessage) {
31+
String contentText = contents.stream().map(this::contentToString).collect(Collectors.joining("\n\n"));
3132

32-
String res = applyPrompt(userMessage.singleText(), contentText);
33-
return new UserMessage(res);
33+
if (chatMessage instanceof UserMessage userMessage) {
34+
String res = applyPrompt(userMessage.singleText(), contentText);
35+
return new UserMessage(res);
36+
}
37+
return new UserMessage("INVALID");
3438
}
3539

3640
private String contentToString(Content content) {

jablib/src/main/java/org/jabref/logic/ai/chatting/model/Gpt4AllModel.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@
1616
import dev.langchain4j.data.message.SystemMessage;
1717
import dev.langchain4j.data.message.ToolExecutionResultMessage;
1818
import dev.langchain4j.data.message.UserMessage;
19-
import dev.langchain4j.model.chat.ChatLanguageModel;
19+
import dev.langchain4j.model.chat.ChatModel;
20+
import dev.langchain4j.model.chat.response.ChatResponse;
2021
import dev.langchain4j.model.output.FinishReason;
21-
import dev.langchain4j.model.output.Response;
2222
import dev.langchain4j.model.output.TokenUsage;
2323
import org.slf4j.Logger;
2424
import org.slf4j.LoggerFactory;
2525

26-
public class Gpt4AllModel implements ChatLanguageModel {
26+
public class Gpt4AllModel implements ChatModel {
2727

2828
private static final Logger LOGGER = LoggerFactory.getLogger(Gpt4AllModel.class);
2929

@@ -37,7 +37,7 @@ public Gpt4AllModel(AiPreferences aiPreferences, HttpClient httpClient) {
3737
}
3838

3939
@Override
40-
public Response<AiMessage> generate(List<ChatMessage> list) {
40+
public ChatResponse chat(List<ChatMessage> list) {
4141
LOGGER.debug("Generating response from Gpt4All model with {} messages: {}", list.size(), list);
4242

4343
List<Message> messages = list.stream()
@@ -84,7 +84,10 @@ public Response<AiMessage> generate(List<ChatMessage> list) {
8484
// Note: We do not check the token usage and finish reason here.
8585
// This class is not a complete implementation of langchain4j's ChatLanguageModel.
8686
// We only implemented the functionality we specifically need.
87-
return new Response<>(new AiMessage(generatedText), new TokenUsage(0, 0), FinishReason.OTHER);
87+
return new ChatResponse.Builder().aiMessage(new AiMessage(generatedText))
88+
.tokenUsage(new TokenUsage(0, 0))
89+
.finishReason(FinishReason.OTHER)
90+
.build();
8891
} catch (Exception e) {
8992
LOGGER.error("Error generating message from Gpt4All", e);
9093
throw new RuntimeException("Failed to generate AI message", e);

jablib/src/main/java/org/jabref/logic/ai/chatting/model/JabRefChatLanguageModel.java

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,21 @@
1313
import org.jabref.model.ai.AiProvider;
1414

1515
import com.google.common.util.concurrent.ThreadFactoryBuilder;
16-
import dev.langchain4j.data.message.AiMessage;
1716
import dev.langchain4j.data.message.ChatMessage;
1817
import dev.langchain4j.memory.ChatMemory;
19-
import dev.langchain4j.model.chat.ChatLanguageModel;
18+
import dev.langchain4j.model.chat.ChatModel;
19+
import dev.langchain4j.model.chat.response.ChatResponse;
2020
import dev.langchain4j.model.googleai.GoogleAiGeminiChatModel;
2121
import dev.langchain4j.model.huggingface.HuggingFaceChatModel;
2222
import dev.langchain4j.model.mistralai.MistralAiChatModel;
23-
import dev.langchain4j.model.output.Response;
2423

2524
/**
2625
* Wrapper around langchain4j chat language model.
2726
* <p>
2827
* Notice, that the real chat model is created lazily, when it's needed. This is done, so API key is fetched only,
2928
* when user wants to chat with AI.
3029
*/
31-
public class JabRefChatLanguageModel implements ChatLanguageModel, AutoCloseable {
30+
public class JabRefChatLanguageModel implements ChatModel, AutoCloseable {
3231
private static final Duration CONNECTION_TIMEOUT = Duration.ofSeconds(5);
3332

3433
private final AiPreferences aiPreferences;
@@ -38,7 +37,7 @@ public class JabRefChatLanguageModel implements ChatLanguageModel, AutoCloseable
3837
new ThreadFactoryBuilder().setNameFormat("ai-api-connection-pool-%d").build()
3938
);
4039

41-
private Optional<ChatLanguageModel> langchainChatModel = Optional.empty();
40+
private Optional<ChatModel> langchainChatModel = Optional.empty();
4241

4342
public JabRefChatLanguageModel(AiPreferences aiPreferences) {
4443
this.aiPreferences = aiPreferences;
@@ -48,7 +47,7 @@ public JabRefChatLanguageModel(AiPreferences aiPreferences) {
4847
}
4948

5049
/**
51-
* Update the underlying {@link dev.langchain4j.model.chat.ChatLanguageModel} by current {@link AiPreferences} parameters.
50+
* Update the underlying {@link dev.langchain4j.model.chat.ChatModel} by current {@link AiPreferences} parameters.
5251
* When the model is updated, the chat messages are not lost.
5352
* See {@link AiChatLogic}, where messages are stored in {@link ChatMemory},
5453
* and see {@link org.jabref.logic.ai.chatting.chathistory.ChatHistoryStorage}.
@@ -101,18 +100,18 @@ private void rebuild() {
101100
private void setupListeningToPreferencesChanges() {
102101
// Setting "langchainChatModel" to "Optional.empty()" will trigger a rebuild on the next usage
103102

104-
aiPreferences.enableAiProperty().addListener(obs -> langchainChatModel = Optional.empty());
105-
aiPreferences.aiProviderProperty().addListener(obs -> langchainChatModel = Optional.empty());
106-
aiPreferences.customizeExpertSettingsProperty().addListener(obs -> langchainChatModel = Optional.empty());
107-
aiPreferences.temperatureProperty().addListener(obs -> langchainChatModel = Optional.empty());
103+
aiPreferences.enableAiProperty().addListener(_ -> langchainChatModel = Optional.empty());
104+
aiPreferences.aiProviderProperty().addListener(_ -> langchainChatModel = Optional.empty());
105+
aiPreferences.customizeExpertSettingsProperty().addListener(_ -> langchainChatModel = Optional.empty());
106+
aiPreferences.temperatureProperty().addListener(_ -> langchainChatModel = Optional.empty());
108107

109108
aiPreferences.addListenerToChatModels(() -> langchainChatModel = Optional.empty());
110109
aiPreferences.addListenerToApiBaseUrls(() -> langchainChatModel = Optional.empty());
111110
aiPreferences.setApiKeyChangeListener(() -> langchainChatModel = Optional.empty());
112111
}
113112

114113
@Override
115-
public Response<AiMessage> generate(List<ChatMessage> list) {
114+
public ChatResponse chat(List<ChatMessage> list) {
116115
// The rationale for RuntimeExceptions in this method:
117116
// 1. langchain4j error handling is a mess, and it uses RuntimeExceptions
118117
// everywhere. Because this method implements a langchain4j interface,
@@ -134,7 +133,7 @@ public Response<AiMessage> generate(List<ChatMessage> list) {
134133
}
135134
}
136135

137-
return langchainChatModel.get().generate(list);
136+
return langchainChatModel.get().chat(list);
138137
}
139138

140139
@Override

jablib/src/main/java/org/jabref/logic/ai/chatting/model/JvmOpenAiChatLanguageModel.java

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010
import dev.langchain4j.data.message.SystemMessage;
1111
import dev.langchain4j.data.message.ToolExecutionResultMessage;
1212
import dev.langchain4j.data.message.UserMessage;
13-
import dev.langchain4j.model.chat.ChatLanguageModel;
13+
import dev.langchain4j.model.chat.ChatModel;
14+
import dev.langchain4j.model.chat.response.ChatResponse;
1415
import dev.langchain4j.model.output.FinishReason;
15-
import dev.langchain4j.model.output.Response;
1616
import dev.langchain4j.model.output.TokenUsage;
1717
import io.github.stefanbratanov.jvm.openai.ChatClient;
1818
import io.github.stefanbratanov.jvm.openai.ChatCompletion;
@@ -22,7 +22,7 @@
2222
import org.slf4j.Logger;
2323
import org.slf4j.LoggerFactory;
2424

25-
public class JvmOpenAiChatLanguageModel implements ChatLanguageModel {
25+
public class JvmOpenAiChatLanguageModel implements ChatModel {
2626
private static final Logger LOGGER = LoggerFactory.getLogger(JvmOpenAiChatLanguageModel.class);
2727

2828
private final AiPreferences aiPreferences;
@@ -42,16 +42,21 @@ public JvmOpenAiChatLanguageModel(AiPreferences aiPreferences, HttpClient httpCl
4242
}
4343

4444
@Override
45-
public Response<AiMessage> generate(List<ChatMessage> list) {
45+
public ChatResponse chat(List<ChatMessage> list) {
4646
LOGGER.debug("Generating response from jvm-openai chat model with {} messages: {}", list.size(), list);
4747

4848
List<io.github.stefanbratanov.jvm.openai.ChatMessage> messages =
4949
list.stream().map(chatMessage -> (io.github.stefanbratanov.jvm.openai.ChatMessage) switch (chatMessage) {
50-
case AiMessage aiMessage -> io.github.stefanbratanov.jvm.openai.ChatMessage.assistantMessage(aiMessage.text());
51-
case SystemMessage systemMessage -> io.github.stefanbratanov.jvm.openai.ChatMessage.systemMessage(systemMessage.text());
52-
case ToolExecutionResultMessage toolExecutionResultMessage -> io.github.stefanbratanov.jvm.openai.ChatMessage.toolMessage(toolExecutionResultMessage.text(), toolExecutionResultMessage.id());
53-
case UserMessage userMessage -> io.github.stefanbratanov.jvm.openai.ChatMessage.userMessage(userMessage.singleText());
54-
default -> throw new IllegalStateException("unknown conversion of chat message from langchain4j to jvm-openai");
50+
case AiMessage aiMessage ->
51+
io.github.stefanbratanov.jvm.openai.ChatMessage.assistantMessage(aiMessage.text());
52+
case SystemMessage systemMessage ->
53+
io.github.stefanbratanov.jvm.openai.ChatMessage.systemMessage(systemMessage.text());
54+
case ToolExecutionResultMessage toolExecutionResultMessage ->
55+
io.github.stefanbratanov.jvm.openai.ChatMessage.toolMessage(toolExecutionResultMessage.text(), toolExecutionResultMessage.id());
56+
case UserMessage userMessage ->
57+
io.github.stefanbratanov.jvm.openai.ChatMessage.userMessage(userMessage.singleText());
58+
default ->
59+
throw new IllegalStateException("unknown conversion of chat message from langchain4j to jvm-openai");
5560
}).toList();
5661

5762
CreateChatCompletionRequest request = CreateChatCompletionRequest
@@ -79,6 +84,8 @@ public Response<AiMessage> generate(List<ChatMessage> list) {
7984

8085
ChatCompletion.Choice choice = choices.getFirst();
8186

82-
return new Response<>(new AiMessage(choice.message().content()), new TokenUsage(usage.promptTokens(), usage.completionTokens()), FinishReason.OTHER);
87+
return new ChatResponse.Builder().aiMessage(new AiMessage(choice.message().content()))
88+
.tokenUsage(new TokenUsage(usage.promptTokens(), usage.completionTokens()))
89+
.finishReason(FinishReason.OTHER).build();
8390
}
8491
}

jablib/src/main/java/org/jabref/logic/ai/ingestion/FileToDocument.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import org.jabref.logic.util.io.FileUtil;
1111
import org.jabref.logic.xmp.XmpUtilReader;
1212

13+
import dev.langchain4j.data.document.DefaultDocument;
1314
import dev.langchain4j.data.document.Document;
1415
import org.apache.pdfbox.pdmodel.PDDocument;
1516
import org.slf4j.Logger;
@@ -57,6 +58,6 @@ private Optional<Document> fromPdfFile(Path path) {
5758
}
5859

5960
public Optional<Document> fromString(String content) {
60-
return Optional.of(new Document(content));
61+
return Optional.of(new DefaultDocument(content));
6162
}
6263
}

jablib/src/main/java/org/jabref/logic/ai/ingestion/LowLevelIngestor.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import org.jabref.logic.ai.AiPreferences;
99

10+
import dev.langchain4j.data.document.DefaultDocument;
1011
import dev.langchain4j.data.document.Document;
1112
import dev.langchain4j.data.document.DocumentSplitter;
1213
import dev.langchain4j.data.document.splitter.DocumentSplitters;
@@ -48,7 +49,7 @@ private void rebuild() {
4849
}
4950

5051
private void setupListeningToPreferencesChanges() {
51-
aiPreferences.customizeExpertSettingsProperty().addListener(obs -> rebuild());
52+
aiPreferences.customizeExpertSettingsProperty().addListener(_ -> rebuild());
5253
aiPreferences.addListenerToEmbeddingsParametersChange(this::rebuild);
5354
}
5455

@@ -68,7 +69,7 @@ public void ingestDocument(Document document, ReadOnlyBooleanProperty stopProper
6869
throw new InterruptedException();
6970
}
7071

71-
ingestor.ingest(new Document(documentPart.text(), document.metadata()));
72+
ingestor.ingest(new DefaultDocument(documentPart.text(), document.metadata()));
7273

7374
workDone.set(workDone.get() + 1);
7475
}

0 commit comments

Comments
 (0)