feat: Add equals, hashCode, deep copy, and tests to AnthropicChatOptions
This commit enhances `AnthropicChatOptions` by: - Adding `equals` and `hashCode` methods for proper object comparison. - Implementing a deep `copy()` method, creating new instances of mutable collections (List, Set, Map, Metadata) to prevent shared state. - Adding `AnthropicChatOptionsTests` to verify `copy()`, builders, setters, and default values. Signed-off-by: Alexandros Pappas <apappascs@gmail.com>
This commit is contained in:
committed by
Christian Tzolov
parent
53bb6a5b00
commit
092bbae5a1
@@ -22,6 +22,7 @@ import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
@@ -97,15 +98,17 @@ public class AnthropicChatOptions implements ToolCallingChatOptions {
|
||||
return builder().model(fromOptions.getModel())
|
||||
.maxTokens(fromOptions.getMaxTokens())
|
||||
.metadata(fromOptions.getMetadata())
|
||||
.stopSequences(fromOptions.getStopSequences())
|
||||
.stopSequences(
|
||||
fromOptions.getStopSequences() != null ? new ArrayList<>(fromOptions.getStopSequences()) : null)
|
||||
.temperature(fromOptions.getTemperature())
|
||||
.topP(fromOptions.getTopP())
|
||||
.topK(fromOptions.getTopK())
|
||||
.toolCallbacks(fromOptions.getToolCallbacks())
|
||||
.toolNames(fromOptions.getToolNames())
|
||||
.toolCallbacks(
|
||||
fromOptions.getToolCallbacks() != null ? new ArrayList<>(fromOptions.getToolCallbacks()) : null)
|
||||
.toolNames(fromOptions.getToolNames() != null ? new HashSet<>(fromOptions.getToolNames()) : null)
|
||||
.internalToolExecutionEnabled(fromOptions.isInternalToolExecutionEnabled())
|
||||
.toolContext(fromOptions.getToolContext())
|
||||
.httpHeaders(fromOptions.getHttpHeaders())
|
||||
.toolContext(fromOptions.getToolContext() != null ? new HashMap<>(fromOptions.getToolContext()) : null)
|
||||
.httpHeaders(fromOptions.getHttpHeaders() != null ? new HashMap<>(fromOptions.getHttpHeaders()) : null)
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -288,10 +291,36 @@ public class AnthropicChatOptions implements ToolCallingChatOptions {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public AnthropicChatOptions copy() {
|
||||
return fromOptions(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof AnthropicChatOptions that)) {
|
||||
return false;
|
||||
}
|
||||
return Objects.equals(this.model, that.model) && Objects.equals(this.maxTokens, that.maxTokens)
|
||||
&& Objects.equals(this.metadata, that.metadata)
|
||||
&& Objects.equals(this.stopSequences, that.stopSequences)
|
||||
&& Objects.equals(this.temperature, that.temperature) && Objects.equals(this.topP, that.topP)
|
||||
&& Objects.equals(this.topK, that.topK) && Objects.equals(this.toolCallbacks, that.toolCallbacks)
|
||||
&& Objects.equals(this.toolNames, that.toolNames)
|
||||
&& Objects.equals(this.internalToolExecutionEnabled, that.internalToolExecutionEnabled)
|
||||
&& Objects.equals(this.toolContext, that.toolContext)
|
||||
&& Objects.equals(this.httpHeaders, that.httpHeaders);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(model, maxTokens, metadata, stopSequences, temperature, topP, topK, toolCallbacks,
|
||||
toolNames, internalToolExecutionEnabled, toolContext, httpHeaders);
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
private final AnthropicChatOptions options = new AnthropicChatOptions();
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2025-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.ai.anthropic;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.ai.anthropic.api.AnthropicApi.ChatCompletionRequest.Metadata;
|
||||
|
||||
/**
|
||||
* Tests for {@link AnthropicChatOptions}.
|
||||
*
|
||||
* @author Alexandros Pappas
|
||||
*/
|
||||
class AnthropicChatOptionsTests {
|
||||
|
||||
@Test
|
||||
void testBuilderWithAllFields() {
|
||||
AnthropicChatOptions options = AnthropicChatOptions.builder()
|
||||
.model("test-model")
|
||||
.maxTokens(100)
|
||||
.stopSequences(List.of("stop1", "stop2"))
|
||||
.temperature(0.7)
|
||||
.topP(0.8)
|
||||
.topK(50)
|
||||
.metadata(new Metadata("userId_123"))
|
||||
.build();
|
||||
|
||||
assertThat(options).extracting("model", "maxTokens", "stopSequences", "temperature", "topP", "topK", "metadata")
|
||||
.containsExactly("test-model", 100, List.of("stop1", "stop2"), 0.7, 0.8, 50, new Metadata("userId_123"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCopy() {
|
||||
AnthropicChatOptions original = AnthropicChatOptions.builder()
|
||||
.model("test-model")
|
||||
.maxTokens(100)
|
||||
.stopSequences(List.of("stop1", "stop2"))
|
||||
.temperature(0.7)
|
||||
.topP(0.8)
|
||||
.topK(50)
|
||||
.metadata(new Metadata("userId_123"))
|
||||
.toolContext(Map.of("key1", "value1"))
|
||||
.build();
|
||||
|
||||
AnthropicChatOptions copied = original.copy();
|
||||
|
||||
assertThat(copied).isNotSameAs(original).isEqualTo(original);
|
||||
// Ensure deep copy
|
||||
assertThat(copied.getStopSequences()).isNotSameAs(original.getStopSequences());
|
||||
assertThat(copied.getToolContext()).isNotSameAs(original.getToolContext());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSetters() {
|
||||
AnthropicChatOptions options = new AnthropicChatOptions();
|
||||
options.setModel("test-model");
|
||||
options.setMaxTokens(100);
|
||||
options.setTemperature(0.7);
|
||||
options.setTopK(50);
|
||||
options.setTopP(0.8);
|
||||
options.setStopSequences(List.of("stop1", "stop2"));
|
||||
options.setMetadata(new Metadata("userId_123"));
|
||||
|
||||
assertThat(options.getModel()).isEqualTo("test-model");
|
||||
assertThat(options.getMaxTokens()).isEqualTo(100);
|
||||
assertThat(options.getTemperature()).isEqualTo(0.7);
|
||||
assertThat(options.getTopK()).isEqualTo(50);
|
||||
assertThat(options.getTopP()).isEqualTo(0.8);
|
||||
assertThat(options.getStopSequences()).isEqualTo(List.of("stop1", "stop2"));
|
||||
assertThat(options.getMetadata()).isEqualTo(new Metadata("userId_123"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDefaultValues() {
|
||||
AnthropicChatOptions options = new AnthropicChatOptions();
|
||||
assertThat(options.getModel()).isNull();
|
||||
assertThat(options.getMaxTokens()).isNull();
|
||||
assertThat(options.getTemperature()).isNull();
|
||||
assertThat(options.getTopK()).isNull();
|
||||
assertThat(options.getTopP()).isNull();
|
||||
assertThat(options.getStopSequences()).isNull();
|
||||
assertThat(options.getMetadata()).isNull();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user