From bde33890f1716a9fc6de3f5f5a9208e1252466fc Mon Sep 17 00:00:00 2001 From: Thanaphoom Babparn Date: Thu, 9 Apr 2026 07:51:54 +0700 Subject: [PATCH] Make modelName optional if providing ChatModel or StreamingChatModel --- .../adk/models/langchain4j/LangChain4j.java | 29 ++++++++++- .../models/langchain4j/LangChain4jTest.java | 49 +++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/contrib/langchain4j/src/main/java/com/google/adk/models/langchain4j/LangChain4j.java b/contrib/langchain4j/src/main/java/com/google/adk/models/langchain4j/LangChain4j.java index 97331e7b4..aa239eda5 100644 --- a/contrib/langchain4j/src/main/java/com/google/adk/models/langchain4j/LangChain4j.java +++ b/contrib/langchain4j/src/main/java/com/google/adk/models/langchain4j/LangChain4j.java @@ -75,6 +75,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.UUID; import org.jspecify.annotations.Nullable; @@ -96,6 +97,7 @@ public abstract class LangChain4j extends BaseLlm { public abstract ObjectMapper objectMapper(); + @Nullable public abstract String modelName(); @Nullable @@ -122,7 +124,32 @@ public abstract static class Builder { public abstract Builder modelName(String modelName); - public abstract LangChain4j build(); + abstract @Nullable ChatModel chatModel(); + + abstract @Nullable StreamingChatModel streamingChatModel(); + + abstract @Nullable String modelName(); + + abstract LangChain4j autoBuild(); + + public LangChain4j build() { + if (Objects.isNull(modelName())) { + // Try to extract modelName from chatModel or streamingChatModel + if (!Objects.isNull(chatModel()) + && !Objects.isNull(chatModel().defaultRequestParameters())) { + modelName(chatModel().defaultRequestParameters().modelName()); + } else if (!Objects.isNull(streamingChatModel()) + && !Objects.isNull(streamingChatModel().defaultRequestParameters())) { + modelName(streamingChatModel().defaultRequestParameters().modelName()); + } + } + // Up to this step, if modelName still null - Fail fast + if (modelName() == null) { + throw new IllegalStateException( + "modelName is required. Either set it explicitly via modelName() or provide a ChatModel/StreamingChatModel"); + } + return autoBuild(); + } } public LangChain4j(ChatModel chatModel) { diff --git a/contrib/langchain4j/src/test/java/com/google/adk/models/langchain4j/LangChain4jTest.java b/contrib/langchain4j/src/test/java/com/google/adk/models/langchain4j/LangChain4jTest.java index a1ec7a3c2..02e5cf3d2 100644 --- a/contrib/langchain4j/src/test/java/com/google/adk/models/langchain4j/LangChain4jTest.java +++ b/contrib/langchain4j/src/test/java/com/google/adk/models/langchain4j/LangChain4jTest.java @@ -31,6 +31,7 @@ import dev.langchain4j.model.chat.ChatModel; import dev.langchain4j.model.chat.StreamingChatModel; import dev.langchain4j.model.chat.request.ChatRequest; +import dev.langchain4j.model.chat.request.ChatRequestParameters; import dev.langchain4j.model.chat.request.json.JsonObjectSchema; import dev.langchain4j.model.chat.request.json.JsonStringSchema; import dev.langchain4j.model.chat.response.ChatResponse; @@ -993,4 +994,52 @@ void testGenerateContentWithNullAiMessageText() { assertThat(response.content()).isPresent(); assertThat(response.content().get().parts().orElse(List.of())).isEmpty(); } + + @Test + @DisplayName("Should auto-detect model name from ChatModel when not explicitly set") + void testBuilderAutoDetectsModelNameFromChatModel() { + // Given + final ChatRequestParameters params = mock(ChatRequestParameters.class); + when(params.modelName()).thenReturn("auto-detected-model"); + when(chatModel.defaultRequestParameters()).thenReturn(params); + + // When + final LangChain4j lc4j = LangChain4j.builder().chatModel(chatModel).build(); + + // Then + assertThat(lc4j.modelName()).isEqualTo("auto-detected-model"); + assertThat(lc4j.model()).isEqualTo("auto-detected-model"); + } + + @Test + @DisplayName("Should auto-detect model name from StreamingChatModel when not explicitly set") + void testBuilderAutoDetectsModelNameFromStreamingChatModel() { + // Given + final ChatRequestParameters params = mock(ChatRequestParameters.class); + when(params.modelName()).thenReturn("auto-detected-streaming-model"); + when(streamingChatModel.defaultRequestParameters()).thenReturn(params); + + // When + final LangChain4j lc4j = LangChain4j.builder().streamingChatModel(streamingChatModel).build(); + + // Then + assertThat(lc4j.modelName()).isEqualTo("auto-detected-streaming-model"); + assertThat(lc4j.model()).isEqualTo("auto-detected-streaming-model"); + } + + @Test + @DisplayName("Should prefer explicit model name over auto-detected one") + void testBuilderPrefersExplicitModelName() { + // Given + final ChatRequestParameters params = mock(ChatRequestParameters.class); + when(params.modelName()).thenReturn("auto-detected-model"); + when(chatModel.defaultRequestParameters()).thenReturn(params); + + // When + final LangChain4j lc4j = + LangChain4j.builder().chatModel(chatModel).modelName("explicit-model").build(); + + // Then + assertThat(lc4j.modelName()).isEqualTo("explicit-model"); + } }