Refactor MoonshotChatOptions builder methods

- Refactor the builder methods to remove `with` as the prefix.
- Introduce new methods with updated naming conventions.
- Deprecate the existing `with*` methods to maintain backward compatibility.
- Update the `copy()` method to use the new builder methods.
- Update MoonshotChatOptions builder documentation
This commit is contained in:
Alexandros Pappas
2024-12-16 17:31:32 +01:00
committed by Ilayaperumal Gopinathan
parent 8edf1bea47
commit 8c51f7a84c
12 changed files with 214 additions and 82 deletions

View File

@@ -74,6 +74,7 @@ import org.springframework.util.CollectionUtils;
* MoonshotChatModel is a {@link ChatModel} implementation that uses the Moonshot
*
* @author Geng Rong
* @author Alexandros Pappas
*/
public class MoonshotChatModel extends AbstractToolCallSupport implements ChatModel, StreamingChatModel {
@@ -109,7 +110,7 @@ public class MoonshotChatModel extends AbstractToolCallSupport implements ChatMo
* Moonshot Chat API.
*/
public MoonshotChatModel(MoonshotApi moonshotApi) {
this(moonshotApi, MoonshotChatOptions.builder().withModel(MoonshotApi.DEFAULT_CHAT_MODEL).build());
this(moonshotApi, MoonshotChatOptions.builder().model(MoonshotApi.DEFAULT_CHAT_MODEL).build());
}
/**
@@ -411,7 +412,7 @@ public class MoonshotChatModel extends AbstractToolCallSupport implements ChatMo
if (!CollectionUtils.isEmpty(enabledToolsToUse)) {
request = ModelOptionsUtils.merge(
MoonshotChatOptions.builder().withTools(this.getFunctionTools(enabledToolsToUse)).build(), request,
MoonshotChatOptions.builder().tools(this.getFunctionTools(enabledToolsToUse)).build(), request,
ChatCompletionRequest.class);
}

View File

@@ -36,6 +36,7 @@ import org.springframework.util.Assert;
*
* @author Geng Rong
* @author Thomas Vitale
* @author Alexandros Pappas
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
public class MoonshotChatOptions implements FunctionCallingOptions {
@@ -281,21 +282,21 @@ public class MoonshotChatOptions implements FunctionCallingOptions {
@Override
public MoonshotChatOptions copy() {
return builder().withModel(this.model)
.withMaxTokens(this.maxTokens)
.withTemperature(this.temperature)
.withTopP(this.topP)
.withN(this.n)
.withPresencePenalty(this.presencePenalty)
.withFrequencyPenalty(this.frequencyPenalty)
.withStop(this.stop)
.withUser(this.user)
.withTools(this.tools)
.withToolChoice(this.toolChoice)
.withFunctionCallbacks(this.functionCallbacks)
.withFunctions(this.functions)
.withProxyToolCalls(this.proxyToolCalls)
.withToolContext(this.toolContext)
return builder().model(this.model)
.maxTokens(this.maxTokens)
.temperature(this.temperature)
.topP(this.topP)
.N(this.n)
.presencePenalty(this.presencePenalty)
.frequencyPenalty(this.frequencyPenalty)
.stop(this.stop)
.user(this.user)
.tools(this.tools)
.toolChoice(this.toolChoice)
.functionCallbacks(this.functionCallbacks)
.functions(this.functions)
.proxyToolCalls(this.proxyToolCalls)
.toolContext(this.toolContext)
.build();
}
@@ -416,94 +417,89 @@ public class MoonshotChatOptions implements FunctionCallingOptions {
public static class Builder {
protected MoonshotChatOptions options;
private final MoonshotChatOptions options = new MoonshotChatOptions();
public Builder() {
this.options = new MoonshotChatOptions();
}
public Builder(MoonshotChatOptions options) {
this.options = options;
}
public Builder withModel(String model) {
public Builder model(String model) {
this.options.model = model;
return this;
}
public Builder withMaxTokens(Integer maxTokens) {
public Builder maxTokens(Integer maxTokens) {
this.options.maxTokens = maxTokens;
return this;
}
public Builder withTemperature(Double temperature) {
public Builder temperature(Double temperature) {
this.options.temperature = temperature;
return this;
}
public Builder withTopP(Double topP) {
public Builder topP(Double topP) {
this.options.topP = topP;
return this;
}
public Builder withN(Integer n) {
public Builder N(Integer n) {
this.options.n = n;
return this;
}
public Builder withPresencePenalty(Double presencePenalty) {
public Builder presencePenalty(Double presencePenalty) {
this.options.presencePenalty = presencePenalty;
return this;
}
public Builder withFrequencyPenalty(Double frequencyPenalty) {
public Builder frequencyPenalty(Double frequencyPenalty) {
this.options.frequencyPenalty = frequencyPenalty;
return this;
}
public Builder withStop(List<String> stop) {
public Builder stop(List<String> stop) {
this.options.stop = stop;
return this;
}
public Builder withUser(String user) {
public Builder user(String user) {
this.options.user = user;
return this;
}
public Builder withTools(List<MoonshotApi.FunctionTool> tools) {
public Builder tools(List<MoonshotApi.FunctionTool> tools) {
this.options.tools = tools;
return this;
}
public Builder withToolChoice(String toolChoice) {
public Builder toolChoice(String toolChoice) {
this.options.toolChoice = toolChoice;
return this;
}
public Builder withFunctionCallbacks(List<FunctionCallback> functionCallbacks) {
public Builder functionCallbacks(List<FunctionCallback> functionCallbacks) {
this.options.functionCallbacks = functionCallbacks;
return this;
}
public Builder withFunctions(Set<String> functionNames) {
public Builder functions(Set<String> functionNames) {
Assert.notNull(functionNames, "Function names must not be null");
this.options.functions = functionNames;
return this;
}
public Builder withFunction(String functionName) {
public Builder function(String functionName) {
Assert.hasText(functionName, "Function name must not be empty");
if (this.options.functions == null) {
this.options.functions = new HashSet<>();
}
this.options.functions.add(functionName);
return this;
}
public Builder withProxyToolCalls(Boolean proxyToolCalls) {
public Builder proxyToolCalls(Boolean proxyToolCalls) {
this.options.proxyToolCalls = proxyToolCalls;
return this;
}
public Builder withToolContext(Map<String, Object> toolContext) {
public Builder toolContext(Map<String, Object> toolContext) {
if (this.options.toolContext == null) {
this.options.toolContext = toolContext;
}
@@ -513,6 +509,134 @@ public class MoonshotChatOptions implements FunctionCallingOptions {
return this;
}
/**
* @deprecated use {@link #functions(Set)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public Builder withFunctions(Set<String> functionNames) {
return functions(functionNames);
}
/**
* @deprecated use {@link #function(String)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public Builder withFunction(String functionName) {
return function(functionName);
}
/**
* @deprecated use {@link #model(String)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public Builder withModel(String model) {
return model(model);
}
/**
* @deprecated use {@link #maxTokens(Integer)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public Builder withMaxTokens(Integer maxTokens) {
return maxTokens(maxTokens);
}
/**
* @deprecated use {@link #temperature(Double)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public Builder withTemperature(Double temperature) {
return temperature(temperature);
}
/**
* @deprecated use {@link #topP(Double)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public Builder withTopP(Double topP) {
return topP(topP);
}
/**
* @deprecated use {@link #N(Integer)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public Builder withN(Integer n) {
return N(n);
}
/**
* @deprecated use {@link #presencePenalty(Double)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public Builder withPresencePenalty(Double presencePenalty) {
return presencePenalty(presencePenalty);
}
/**
* @deprecated use {@link #frequencyPenalty(Double)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public Builder withFrequencyPenalty(Double frequencyPenalty) {
return frequencyPenalty(frequencyPenalty);
}
/**
* @deprecated use {@link #stop(List)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public Builder withStop(List<String> stop) {
return stop(stop);
}
/**
* @deprecated use {@link #user(String)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public Builder withUser(String user) {
return user(user);
}
/**
* @deprecated use {@link #tools(List)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public Builder withTools(List<MoonshotApi.FunctionTool> tools) {
return tools(tools);
}
/**
* @deprecated use {@link #toolChoice(String)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public Builder withToolChoice(String toolChoice) {
return toolChoice(toolChoice);
}
/**
* @deprecated use {@link #functionCallbacks(List)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public Builder withFunctionCallbacks(List<FunctionCallback> functionCallbacks) {
return functionCallbacks(functionCallbacks);
}
/**
* @deprecated use {@link #proxyToolCalls(Boolean)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public Builder withProxyToolCalls(Boolean proxyToolCalls) {
return proxyToolCalls(proxyToolCalls);
}
/**
* @deprecated use {@link #toolContext(Map)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public Builder withToolContext(Map<String, Object> toolContext) {
return toolContext(toolContext);
}
public MoonshotChatOptions build() {
return this.options;
}

View File

@@ -27,6 +27,7 @@ import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Geng Rong
* @author Alexandros Pappas
*/
@SpringBootTest
@EnabledIfEnvironmentVariable(named = "MOONSHOT_API_KEY", matches = ".+")
@@ -47,7 +48,7 @@ public class MoonshotChatCompletionRequestTest {
@Test
void chatCompletionRequestWithOptionsTest() {
var options = MoonshotChatOptions.builder().withTemperature(0.5).withTopP(0.8).build();
var options = MoonshotChatOptions.builder().temperature(0.5).topP(0.8).build();
var request = this.chatModel.createRequest(new Prompt("test content", options), true);
assertThat(request.messages().size()).isEqualTo(1);

View File

@@ -49,6 +49,7 @@ import static org.mockito.BDDMockito.given;
/**
* @author Geng Rong
* @author Alexandros Pappas
*/
@SuppressWarnings("unchecked")
@ExtendWith(MockitoExtension.class)
@@ -68,9 +69,9 @@ public class MoonshotRetryTests {
this.chatModel = new MoonshotChatModel(this.moonshotApi,
MoonshotChatOptions.builder()
.withTemperature(0.7)
.withTopP(1.0)
.withModel(MoonshotApi.ChatModel.MOONSHOT_V1_32K.getValue())
.temperature(0.7)
.topP(1.0)
.model(MoonshotApi.ChatModel.MOONSHOT_V1_32K.getValue())
.build(),
null, retryTemplate);
}

View File

@@ -62,8 +62,8 @@ class MoonshotChatModelFunctionCallingIT {
List<Message> messages = new ArrayList<>(List.of(userMessage));
var promptOptions = MoonshotChatOptions.builder()
.withModel(MoonshotApi.ChatModel.MOONSHOT_V1_8K.getValue())
.withFunctionCallbacks(List.of(FunctionCallback.builder()
.model(MoonshotApi.ChatModel.MOONSHOT_V1_8K.getValue())
.functionCallbacks(List.of(FunctionCallback.builder()
.function("getCurrentWeather", new MockWeatherService())
.description("Get the weather in location")
.inputType(MockWeatherService.Request.class)
@@ -86,7 +86,7 @@ class MoonshotChatModelFunctionCallingIT {
List<Message> messages = new ArrayList<>(List.of(userMessage));
var promptOptions = MoonshotChatOptions.builder()
.withFunctionCallbacks(List.of(FunctionCallback.builder()
.functionCallbacks(List.of(FunctionCallback.builder()
.function("getCurrentWeather", new MockWeatherService())
.description("Get the weather in location")
.build()))

View File

@@ -50,6 +50,7 @@ import static org.springframework.ai.chat.observation.ChatModelObservationDocume
* Integration tests for observation instrumentation in {@link MoonshotChatModel}.
*
* @author Geng Rong
* @author Alexandros Pappas
*/
@SpringBootTest(classes = MoonshotChatModelObservationIT.Config.class)
@EnabledIfEnvironmentVariable(named = "MOONSHOT_API_KEY", matches = ".+")
@@ -70,13 +71,13 @@ public class MoonshotChatModelObservationIT {
void observationForChatOperation() {
var options = MoonshotChatOptions.builder()
.withModel(MoonshotApi.ChatModel.MOONSHOT_V1_8K.getValue())
.withFrequencyPenalty(0.0)
.withMaxTokens(2048)
.withPresencePenalty(0.0)
.withStop(List.of("this-is-the-end"))
.withTemperature(0.7)
.withTopP(1.0)
.model(MoonshotApi.ChatModel.MOONSHOT_V1_8K.getValue())
.frequencyPenalty(0.0)
.maxTokens(2048)
.presencePenalty(0.0)
.stop(List.of("this-is-the-end"))
.temperature(0.7)
.topP(1.0)
.build();
Prompt prompt = new Prompt("Why does a raven look like a desk?", options);
@@ -93,13 +94,13 @@ public class MoonshotChatModelObservationIT {
@Test
void observationForStreamingChatOperation() {
var options = MoonshotChatOptions.builder()
.withModel(MoonshotApi.ChatModel.MOONSHOT_V1_8K.getValue())
.withFrequencyPenalty(0.0)
.withMaxTokens(2048)
.withPresencePenalty(0.0)
.withStop(List.of("this-is-the-end"))
.withTemperature(0.7)
.withTopP(1.0)
.model(MoonshotApi.ChatModel.MOONSHOT_V1_8K.getValue())
.frequencyPenalty(0.0)
.maxTokens(2048)
.presencePenalty(0.0)
.stop(List.of("this-is-the-end"))
.temperature(0.7)
.topP(1.0)
.build();
Prompt prompt = new Prompt("Why does a raven look like a desk?", options);

View File

@@ -155,7 +155,7 @@ MoonshotChatModel chatModel = ...
UserMessage userMessage = new UserMessage("What's the weather like in San Francisco, Tokyo, and Paris?");
ChatResponse response = this.chatModel.call(new Prompt(List.of(this.userMessage),
MoonshotChatOptions.builder().withFunction("CurrentWeather").build())); // (1) Enable the function
MoonshotChatOptions.builder().function("CurrentWeather").build())); // (1) Enable the function
logger.info("Response: {}", response);
----
@@ -185,7 +185,7 @@ MoonshotChatModel chatModel = ...
UserMessage userMessage = new UserMessage("What's the weather like in San Francisco, Tokyo, and Paris?");
var promptOptions = MoonshotChatOptions.builder()
.withFunctionCallbacks(List.of(FunctionCallback.builder()
.functionCallbacks(List.of(FunctionCallback.builder()
.function("CurrentWeather", new MockWeatherService()) // (1) function name
.description("Get the weather in location") // (2) function description
.inputType(MockWeatherService.Request.class) // (3) function signature

View File

@@ -120,8 +120,8 @@ ChatResponse response = chatModel.call(
new Prompt(
"Generate the names of 5 famous pirates.",
MoonshotChatOptions.builder()
.withModel(MoonshotApi.ChatModel.MOONSHOT_V1_8K.getValue())
.withTemperature(0.5)
.model(MoonshotApi.ChatModel.MOONSHOT_V1_8K.getValue())
.temperature(0.5)
.build()
));
----
@@ -203,9 +203,9 @@ Next, create a `MoonshotChatModel` and use it for text generations:
var moonshotApi = new MoonshotApi(System.getenv("MOONSHOT_API_KEY"));
var chatModel = new MoonshotChatModel(this.moonshotApi, MoonshotChatOptions.builder()
.withModel(MoonshotApi.ChatModel.MOONSHOT_V1_8K.getValue())
.withTemperature(0.4)
.withMaxTokens(200)
.model(MoonshotApi.ChatModel.MOONSHOT_V1_8K.getValue())
.temperature(0.4)
.maxTokens(200)
.build());
ChatResponse response = this.chatModel.call(

View File

@@ -25,6 +25,7 @@ import org.springframework.boot.context.properties.NestedConfigurationProperty;
* Configuration properties for Moonshot chat client.
*
* @author Geng Rong
* @author Alexandros Pappas
*/
@ConfigurationProperties(MoonshotChatProperties.CONFIG_PREFIX)
public class MoonshotChatProperties extends MoonshotParentProperties {
@@ -42,8 +43,8 @@ public class MoonshotChatProperties extends MoonshotParentProperties {
@NestedConfigurationProperty
private MoonshotChatOptions options = MoonshotChatOptions.builder()
.withModel(DEFAULT_CHAT_MODEL)
.withTemperature(DEFAULT_TEMPERATURE)
.model(DEFAULT_CHAT_MODEL)
.temperature(DEFAULT_TEMPERATURE)
.build();
public MoonshotChatOptions getOptions() {

View File

@@ -43,6 +43,7 @@ import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Geng Rong
* @author Alexandros Pappas
*/
@EnabledIfEnvironmentVariable(named = "MOONSHOT_API_KEY", matches = ".*")
public class FunctionCallbackInPromptIT {
@@ -64,7 +65,7 @@ public class FunctionCallbackInPromptIT {
"What's the weather like in San Francisco, Tokyo, and Paris? Return the temperature in Celsius");
var promptOptions = MoonshotChatOptions.builder()
.withFunctionCallbacks(List.of(FunctionCallback.builder()
.functionCallbacks(List.of(FunctionCallback.builder()
.function("CurrentWeatherService", new MockWeatherService())
.description("Get the weather in location")
.inputType(MockWeatherService.Request.class)
@@ -90,7 +91,7 @@ public class FunctionCallbackInPromptIT {
"What's the weather like in San Francisco, Tokyo, and Paris? Return the temperature in Celsius");
var promptOptions = MoonshotChatOptions.builder()
.withFunctionCallbacks(List.of(FunctionCallback.builder()
.functionCallbacks(List.of(FunctionCallback.builder()
.function("CurrentWeatherService", new MockWeatherService())
.description("Get the weather in location")
.inputType(MockWeatherService.Request.class)

View File

@@ -47,6 +47,7 @@ import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Geng Rong
* @author Alexandros Pappas
*/
@EnabledIfEnvironmentVariable(named = "MOONSHOT_API_KEY", matches = ".*")
class FunctionCallbackWithPlainFunctionBeanIT {
@@ -70,7 +71,7 @@ class FunctionCallbackWithPlainFunctionBeanIT {
"What's the weather like in San Francisco, Tokyo, and Paris? Return the temperature in Celsius");
ChatResponse response = chatModel.call(new Prompt(List.of(userMessage),
MoonshotChatOptions.builder().withFunction("weatherFunction").build()));
MoonshotChatOptions.builder().function("weatherFunction").build()));
logger.info("Response: {}", response);
@@ -78,7 +79,7 @@ class FunctionCallbackWithPlainFunctionBeanIT {
// Test weatherFunctionTwo
response = chatModel.call(new Prompt(List.of(userMessage),
MoonshotChatOptions.builder().withFunction("weatherFunctionTwo").build()));
MoonshotChatOptions.builder().function("weatherFunctionTwo").build()));
logger.info("Response: {}", response);
@@ -118,7 +119,7 @@ class FunctionCallbackWithPlainFunctionBeanIT {
"What's the weather like in San Francisco, Tokyo, and Paris? Return the temperature in Celsius");
Flux<ChatResponse> response = chatModel.stream(new Prompt(List.of(userMessage),
MoonshotChatOptions.builder().withFunction("weatherFunction").build()));
MoonshotChatOptions.builder().function("weatherFunction").build()));
String content = response.collectList()
.block()
@@ -136,7 +137,7 @@ class FunctionCallbackWithPlainFunctionBeanIT {
// Test weatherFunctionTwo
response = chatModel.stream(new Prompt(List.of(userMessage),
MoonshotChatOptions.builder().withFunction("weatherFunctionTwo").build()));
MoonshotChatOptions.builder().function("weatherFunctionTwo").build()));
content = response.collectList()
.block()

View File

@@ -46,6 +46,7 @@ import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Geng Rong
* @author Alexandros Pappas
*/
@EnabledIfEnvironmentVariable(named = "MOONSHOT_API_KEY", matches = ".*")
public class MoonshotFunctionCallbackIT {
@@ -67,8 +68,8 @@ public class MoonshotFunctionCallbackIT {
UserMessage userMessage = new UserMessage(
"What's the weather like in San Francisco, Tokyo, and Paris? Return the temperature in Celsius");
ChatResponse response = chatModel.call(new Prompt(List.of(userMessage),
MoonshotChatOptions.builder().withFunction("WeatherInfo").build()));
ChatResponse response = chatModel
.call(new Prompt(List.of(userMessage), MoonshotChatOptions.builder().function("WeatherInfo").build()));
logger.info("Response: {}", response);
@@ -86,8 +87,8 @@ public class MoonshotFunctionCallbackIT {
UserMessage userMessage = new UserMessage(
"What's the weather like in San Francisco, Tokyo, and Paris? Return the temperature in Celsius");
Flux<ChatResponse> response = chatModel.stream(new Prompt(List.of(userMessage),
MoonshotChatOptions.builder().withFunction("WeatherInfo").build()));
Flux<ChatResponse> response = chatModel.stream(
new Prompt(List.of(userMessage), MoonshotChatOptions.builder().function("WeatherInfo").build()));
String content = response.collectList()
.block()