Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,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.ToolChoice;
import dev.langchain4j.model.chat.request.json.JsonArraySchema;
import dev.langchain4j.model.chat.request.json.JsonBooleanSchema;
Expand Down Expand Up @@ -100,6 +101,7 @@ public abstract class LangChain4j extends BaseLlm {

public abstract ObjectMapper objectMapper();

@Nullable
public abstract String modelName();

@Nullable
Expand All @@ -126,7 +128,33 @@ 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 (modelName() == null) {
String name = chatModel() == null ? null : nameOf(chatModel().defaultRequestParameters());
if (name == null && streamingChatModel() != null) {
name = nameOf(streamingChatModel().defaultRequestParameters());
}
if (name == null) {
throw new IllegalStateException(
"Set modelName(), or use a ChatModel or StreamingChatModel whose"
+ " defaultRequestParameters() declare a model name");
}
modelName(name);
}
return autoBuild();
}

private static @Nullable String nameOf(@Nullable ChatRequestParameters parameters) {
return parameters == null ? null : parameters.modelName();
}
}

public LangChain4j(ChatModel chatModel) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package com.google.adk.models.langchain4j;

import static org.assertj.core.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;

Expand All @@ -31,6 +32,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;
Expand Down Expand Up @@ -1145,4 +1147,89 @@ void testGenerateContentWithMalformedCharsetFallback() {

assertThat(textContent.text()).isEqualTo(textPayload);
}

@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");
}

@Test
@DisplayName("Should fall back to StreamingChatModel name when ChatModel has none")
void testBuilderFallsBackToStreamingModelNameWhenChatModelHasNone() {
// Given
final ChatRequestParameters emptyParams = mock(ChatRequestParameters.class);
when(chatModel.defaultRequestParameters()).thenReturn(emptyParams);
final ChatRequestParameters streamingParams = mock(ChatRequestParameters.class);
when(streamingParams.modelName()).thenReturn("streaming-model");
when(streamingChatModel.defaultRequestParameters()).thenReturn(streamingParams);

// When
final LangChain4j lc4j =
LangChain4j.builder().chatModel(chatModel).streamingChatModel(streamingChatModel).build();

// Then
assertThat(lc4j.modelName()).isEqualTo("streaming-model");
}

@Test
@DisplayName("Should fail when no source declares a model name")
void testBuilderFailsWhenNoModelNameAvailable() {
// Given
final ChatRequestParameters emptyParams = mock(ChatRequestParameters.class);
when(chatModel.defaultRequestParameters()).thenReturn(emptyParams);
when(streamingChatModel.defaultRequestParameters()).thenReturn(emptyParams);

// When / Then
assertThrows(
IllegalStateException.class,
() ->
LangChain4j.builder()
.chatModel(chatModel)
.streamingChatModel(streamingChatModel)
.build());
assertThrows(IllegalStateException.class, () -> LangChain4j.builder().build());
}
}
Loading