Skip to content
Closed
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 @@ -23,6 +23,11 @@
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.content.Media;

/**
* @author Mark Pollack
* @author Soby Chacko
* @author Sun Yuhan
*/
public class DeepSeekAssistantMessage extends AssistantMessage {

private Boolean prefix;
Expand Down Expand Up @@ -57,6 +62,13 @@ public DeepSeekAssistantMessage(String content, String reasoningContent, Map<Str
this.reasoningContent = reasoningContent;
}

public DeepSeekAssistantMessage(String content, String reasoningContent, Boolean prefix,
Map<String, Object> properties, List<ToolCall> toolCalls, List<Media> media) {
super(content, properties, toolCalls, media);
this.reasoningContent = reasoningContent;
this.prefix = prefix;
}

public static DeepSeekAssistantMessage prefixAssistantMessage(String context) {
return prefixAssistantMessage(context, null);
}
Expand Down Expand Up @@ -102,9 +114,60 @@ public int hashCode() {

@Override
public String toString() {
return "AssistantMessage [messageType=" + this.messageType + ", toolCalls=" + super.getToolCalls()
return "DeepSeekAssistantMessage [messageType=" + this.messageType + ", toolCalls=" + super.getToolCalls()
+ ", textContent=" + this.textContent + ", reasoningContent=" + this.reasoningContent + ", prefix="
+ this.prefix + ", metadata=" + this.metadata + "]";
}

public static final class Builder {

private String content;

private Map<String, Object> properties = Map.of();

private List<ToolCall> toolCalls = List.of();

private List<Media> media = List.of();

private Boolean prefix;

private String reasoningContent;

public Builder content(String content) {
this.content = content;
return this;
}

public Builder properties(Map<String, Object> properties) {
this.properties = properties;
return this;
}

public Builder toolCalls(List<ToolCall> toolCalls) {
this.toolCalls = toolCalls;
return this;
}

public Builder media(List<Media> media) {
this.media = media;
return this;
}

public Builder prefix(Boolean prefix) {
this.prefix = prefix;
return this;
}

public Builder reasoningContent(String reasoningContent) {
this.reasoningContent = reasoningContent;
return this;
}

public DeepSeekAssistantMessage build() {
return new DeepSeekAssistantMessage(this.content, this.reasoningContent, this.prefix, this.properties,
this.toolCalls, this.media);
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -340,8 +340,13 @@ private Generation buildGeneration(Choice choice, Map<String, Object> metadata)
String textContent = choice.message().content();
String reasoningContent = choice.message().reasoningContent();

DeepSeekAssistantMessage assistantMessage = new DeepSeekAssistantMessage(textContent, reasoningContent,
metadata, toolCalls);
DeepSeekAssistantMessage.Builder builder = new DeepSeekAssistantMessage.Builder();
DeepSeekAssistantMessage assistantMessage = builder.content(textContent)
.reasoningContent(reasoningContent)
.properties(metadata)
.toolCalls(toolCalls)
.build();

return new Generation(assistantMessage, generationMetadataBuilder.build());
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
/*
* 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.deepseek;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.junit.jupiter.api.Test;

import org.springframework.ai.chat.messages.AssistantMessage.ToolCall;
import org.springframework.ai.content.Media;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatNoException;

/**
* Unit tests for {@link DeepSeekAssistantMessage}.
*
* @author Sun Yuhan
*/
class DeepSeekAssistantMessageTests {

@Test
public void testConstructorWithContentOnly() {
String content = "Hello, world!";
DeepSeekAssistantMessage message = new DeepSeekAssistantMessage(content);

assertThat(message.getText()).isEqualTo(content);
assertThat(message.getReasoningContent()).isNull();
assertThat(message.getPrefix()).isNull();
}

@Test
public void testConstructorWithContentAndReasoningContent() {
String content = "Hello, world!";
String reasoningContent = "This is my reasoning";
DeepSeekAssistantMessage message = new DeepSeekAssistantMessage(content, reasoningContent);

assertThat(message.getText()).isEqualTo(content);
assertThat(message.getReasoningContent()).isEqualTo(reasoningContent);
assertThat(message.getPrefix()).isNull();
}

@Test
public void testConstructorWithContentAndProperties() {
String content = "Hello, world!";
Map<String, Object> properties = new HashMap<>();
properties.put("key1", "value1");
properties.put("key2", 123);

DeepSeekAssistantMessage message = new DeepSeekAssistantMessage(content, properties);

assertThat(message.getText()).isEqualTo(content);
assertThat(message.getMetadata()).containsAllEntriesOf(properties);
assertThat(message.getReasoningContent()).isNull();
assertThat(message.getPrefix()).isNull();
}

@Test
public void testConstructorWithContentPropertiesAndToolCalls() {
String content = "Hello, world!";
Map<String, Object> properties = new HashMap<>();
properties.put("key1", "value1");

List<ToolCall> toolCalls = List.of(new ToolCall("1", "function", "myFunction", "{}"));

DeepSeekAssistantMessage message = new DeepSeekAssistantMessage(content, properties, toolCalls);

assertThat(message.getText()).isEqualTo(content);
assertThat(message.getMetadata()).containsAllEntriesOf(properties);
assertThat(message.getToolCalls()).isEqualTo(toolCalls);
assertThat(message.getReasoningContent()).isNull();
assertThat(message.getPrefix()).isNull();
}

@Test
public void testConstructorWithAllParameters() {
String content = "Hello, world!";
String reasoningContent = "This is my reasoning";
Boolean prefix = true;
Map<String, Object> properties = new HashMap<>();
properties.put("key1", "value1");
List<ToolCall> toolCalls = List.of(new ToolCall("1", "function", "myFunction", "{}"));

DeepSeekAssistantMessage message = new DeepSeekAssistantMessage(content, reasoningContent, prefix, properties,
toolCalls, List.of());

assertThat(message.getText()).isEqualTo(content);
assertThat(message.getReasoningContent()).isEqualTo(reasoningContent);
assertThat(message.getPrefix()).isEqualTo(prefix);
assertThat(message.getMetadata()).containsAllEntriesOf(properties);
assertThat(message.getToolCalls()).isEqualTo(toolCalls);
}

@Test
public void testPrefixAssistantMessageFactoryMethod() {
String content = "Hello, world!";
DeepSeekAssistantMessage message = DeepSeekAssistantMessage.prefixAssistantMessage(content);

assertThat(message.getText()).isEqualTo(content);
assertThat(message.getReasoningContent()).isNull();
}

@Test
public void testPrefixAssistantMessageFactoryMethodWithReasoning() {
String content = "Hello, world!";
String reasoningContent = "This is my reasoning";
DeepSeekAssistantMessage message = DeepSeekAssistantMessage.prefixAssistantMessage(content, reasoningContent);

assertThat(message.getText()).isEqualTo(content);
assertThat(message.getReasoningContent()).isEqualTo(reasoningContent);
}

@Test
public void testSettersAndGetters() {
DeepSeekAssistantMessage message = new DeepSeekAssistantMessage("test");

String reasoningContent = "New reasoning content";
Boolean prefix = false;

message.setReasoningContent(reasoningContent);
message.setPrefix(prefix);

assertThat(message.getReasoningContent()).isEqualTo(reasoningContent);
assertThat(message.getPrefix()).isEqualTo(prefix);
}

@Test
public void testEqualsAndHashCode() {
DeepSeekAssistantMessage message1 = new DeepSeekAssistantMessage("content", "reasoning", true, Map.of(),
List.of(), List.of());
DeepSeekAssistantMessage message2 = new DeepSeekAssistantMessage("content", "reasoning", true, Map.of(),
List.of(), List.of());

assertThat(message1).isEqualTo(message2);
assertThat(message1.hashCode()).isEqualTo(message2.hashCode());

DeepSeekAssistantMessage message3 = new DeepSeekAssistantMessage("content", "different reasoning", true,
Map.of(), List.of(), List.of());
assertThat(message1).isNotEqualTo(message3);
}

@Test
public void testToString() {
DeepSeekAssistantMessage message = new DeepSeekAssistantMessage("content", "reasoning");
message.setPrefix(true);

assertThatNoException().isThrownBy(message::toString);
assertThat(message.toString()).contains("content", "reasoning", "true");
}

@Test
public void testBuilderComplete() {
Map<String, Object> properties = Map.of("key", "value");
List<ToolCall> toolCalls = List.of(new ToolCall("1", "function", "testFunction", "{}"));
List<Media> media = List.of();

DeepSeekAssistantMessage.Builder builder = new DeepSeekAssistantMessage.Builder();
DeepSeekAssistantMessage message = builder.content("content")
.reasoningContent("reasoning")
.prefix(true)
.properties(properties)
.toolCalls(toolCalls)
.media(media)
.build();

assertThat(message.getText()).isEqualTo("content");
assertThat(message.getReasoningContent()).isEqualTo("reasoning");
assertThat(message.getPrefix()).isEqualTo(true);
assertThat(message.getMetadata()).containsAllEntriesOf(properties);
assertThat(message.getToolCalls()).isEqualTo(toolCalls);
assertThat(message.getMedia()).isEqualTo(media);
}

}