From c3a19a1920fda937647d84099377f6b4c0f97196 Mon Sep 17 00:00:00 2001 From: Thanaphoom Babparn Date: Mon, 8 Jun 2026 15:34:36 +0700 Subject: [PATCH] Make modelName optional if providing ChatModel or StreamingChatModel --- .../adk/models/langchain4j/LangChain4j.java | 29 ++++++++++- .../models/langchain4j/LangChain4jTest.java | 48 +++++++++++++++++++ 2 files changed, 76 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 b35c68f89..f2ce914e1 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 @@ -76,6 +76,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; import org.slf4j.Logger; @@ -100,6 +101,7 @@ public abstract class LangChain4j extends BaseLlm { public abstract ObjectMapper objectMapper(); + @Nullable public abstract String modelName(); @Nullable @@ -126,7 +128,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 affacd7c3..60e3e59b8 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; @@ -1145,4 +1146,51 @@ void testGenerateContentWithMalformedCharsetFallback() { assertThat(textContent.text()).isEqualTo(textPayload); } + + @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"); + } }