Skip to content

Commit c92ef52

Browse files
committed
Add name property support to AssistantMessage for multi-agent systems\n\n- Add name field to AssistantMessage for multi-agent system support\n- Add new constructors with name parameter for backward compatibility\n- Update equals, hashCode, and toString methods to include name\n- Add comprehensive test coverage for name property functionality\n- Update all AI provider implementations to pass name to API calls:\n * OpenAI ChatModel\n * DeepSeek ChatModel \n * MiniMax ChatModel\n * Mistral AI ChatModel\n * ZhiPu AI ChatModel\n * Azure OpenAI ChatModel (with reflection-based dynamic support)\n- Update Prompt class to properly copy name property\n- Update memory repository implementations (Neo4j, Cassandra)\n- Update DeepSeekAssistantMessage constructors to support name parameter\n- Apply Spring Java format to all modified files\n\nThis enhancement enables building multi-agent systems by allowing\nassistants to be distinguished by name, making it easier to share\nglobal context across different AI assistants.
Signed-off-by: huidong.yin <[email protected]>
1 parent eaca392 commit c92ef52

File tree

12 files changed

+197
-13
lines changed

12 files changed

+197
-13
lines changed

memory/repository/spring-ai-model-chat-memory-repository-cassandra/src/main/java/org/springframework/ai/chat/memory/repository/cassandra/CassandraChatMemoryRepository.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ private Message getMessage(UdtValue udt) {
209209
Map<String, Object> props = Map.of(CONVERSATION_TS, udt.getInstant(this.conf.messageUdtTimestampColumn));
210210
switch (MessageType.valueOf(udt.getString(this.conf.messageUdtTypeColumn))) {
211211
case ASSISTANT:
212-
return new AssistantMessage(content, props);
212+
return new AssistantMessage(content, props, List.of(), List.of(), null);
213213
case USER:
214214
return UserMessage.builder().text(content).metadata(props).build();
215215
case SYSTEM:

memory/repository/spring-ai-model-chat-memory-repository-neo4j/src/main/java/org/springframework/ai/chat/memory/repository/neo4j/Neo4jChatMemoryRepository.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ private Message buildAssistantMessage(org.neo4j.driver.Record record, Map<String
190190
return new AssistantMessage.ToolCall((String) toolCallMap.get("id"),
191191
(String) toolCallMap.get("type"), (String) toolCallMap.get("name"),
192192
(String) toolCallMap.get("arguments"));
193-
}), mediaList);
193+
}), mediaList, (String) messageMap.get("name"));
194194
return message;
195195
}
196196

models/spring-ai-azure-openai/src/main/java/org/springframework/ai/azure/openai/AzureOpenAiChatModel.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package org.springframework.ai.azure.openai;
1818

19+
import java.lang.reflect.InvocationTargetException;
20+
import java.lang.reflect.Method;
1921
import java.util.ArrayList;
2022
import java.util.Base64;
2123
import java.util.Collections;
@@ -596,6 +598,16 @@ private List<ChatRequestMessage> fromSpringAiMessage(Message message) {
596598
}
597599
var azureAssistantMessage = new ChatRequestAssistantMessage(message.getText());
598600
azureAssistantMessage.setToolCalls(toolCalls);
601+
// Try to set name field if supported by Azure OpenAI SDK
602+
try {
603+
// Use reflection to check if setName method exists and call it
604+
Method setNameMethod = azureAssistantMessage.getClass().getMethod("setName", String.class);
605+
setNameMethod.invoke(azureAssistantMessage, assistantMessage.getName());
606+
}
607+
catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
608+
// Name field not supported in current Azure OpenAI SDK version
609+
// This is expected behavior for some SDK versions
610+
}
599611
return List.of(azureAssistantMessage);
600612
case TOOL:
601613
ToolResponseMessage toolMessage = (ToolResponseMessage) message;

models/spring-ai-deepseek/src/main/java/org/springframework/ai/deepseek/DeepSeekAssistantMessage.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,28 @@ public DeepSeekAssistantMessage(String content, String reasoningContent, Map<Str
5757
this.reasoningContent = reasoningContent;
5858
}
5959

60+
// Constructors with name parameter
61+
public DeepSeekAssistantMessage(String content, Map<String, Object> properties, String name) {
62+
super(content, properties, name);
63+
}
64+
65+
public DeepSeekAssistantMessage(String content, Map<String, Object> properties, List<ToolCall> toolCalls,
66+
String name) {
67+
super(content, properties, toolCalls, name);
68+
}
69+
70+
public DeepSeekAssistantMessage(String content, String reasoningContent, Map<String, Object> properties,
71+
List<ToolCall> toolCalls, String name) {
72+
super(content, properties, toolCalls, name);
73+
this.reasoningContent = reasoningContent;
74+
}
75+
76+
public DeepSeekAssistantMessage(String content, String reasoningContent, Map<String, Object> properties,
77+
List<ToolCall> toolCalls, List<Media> media, String name) {
78+
super(content, properties, toolCalls, media, name);
79+
this.reasoningContent = reasoningContent;
80+
}
81+
6082
public static DeepSeekAssistantMessage prefixAssistantMessage(String context) {
6183
return prefixAssistantMessage(context, null);
6284
}

models/spring-ai-deepseek/src/main/java/org/springframework/ai/deepseek/DeepSeekChatModel.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -446,8 +446,9 @@ else if (message.getMessageType() == MessageType.ASSISTANT) {
446446
&& Boolean.TRUE.equals(((DeepSeekAssistantMessage) message).getPrefix())) {
447447
isPrefixAssistantMessage = true;
448448
}
449-
return List.of(new ChatCompletionMessage(assistantMessage.getText(),
450-
ChatCompletionMessage.Role.ASSISTANT, null, null, toolCalls, isPrefixAssistantMessage, null));
449+
return List
450+
.of(new ChatCompletionMessage(assistantMessage.getText(), ChatCompletionMessage.Role.ASSISTANT,
451+
assistantMessage.getName(), null, toolCalls, isPrefixAssistantMessage, null));
451452
}
452453
else if (message.getMessageType() == MessageType.TOOL) {
453454
ToolResponseMessage toolMessage = (ToolResponseMessage) message;

models/spring-ai-minimax/src/main/java/org/springframework/ai/minimax/MiniMaxChatModel.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -519,7 +519,7 @@ else if (message.getMessageType() == MessageType.ASSISTANT) {
519519
}).toList();
520520
}
521521
return List.of(new ChatCompletionMessage(assistantMessage.getText(),
522-
ChatCompletionMessage.Role.ASSISTANT, null, null, toolCalls));
522+
ChatCompletionMessage.Role.ASSISTANT, assistantMessage.getName(), null, toolCalls));
523523
}
524524
else if (message.getMessageType() == MessageType.TOOL) {
525525
ToolResponseMessage toolMessage = (ToolResponseMessage) message;

models/spring-ai-mistral-ai/src/main/java/org/springframework/ai/mistralai/MistralAiChatModel.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,8 @@ else if (message instanceof AssistantMessage assistantMessage) {
454454
}
455455

456456
return List.of(new MistralAiApi.ChatCompletionMessage(assistantMessage.getText(),
457-
MistralAiApi.ChatCompletionMessage.Role.ASSISTANT, null, toolCalls, null));
457+
MistralAiApi.ChatCompletionMessage.Role.ASSISTANT, assistantMessage.getName(), toolCalls,
458+
null));
458459
}
459460
else if (message instanceof ToolResponseMessage toolResponseMessage) {
460461
toolResponseMessage.getResponses()

models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiChatModel.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -591,8 +591,9 @@ else if (message.getMessageType() == MessageType.ASSISTANT) {
591591
audioOutput = new AudioOutput(assistantMessage.getMedia().get(0).getId(), null, null, null);
592592

593593
}
594-
return List.of(new ChatCompletionMessage(assistantMessage.getText(),
595-
ChatCompletionMessage.Role.ASSISTANT, null, null, toolCalls, null, audioOutput, null));
594+
return List
595+
.of(new ChatCompletionMessage(assistantMessage.getText(), ChatCompletionMessage.Role.ASSISTANT,
596+
assistantMessage.getName(), null, toolCalls, null, audioOutput, null));
596597
}
597598
else if (message.getMessageType() == MessageType.TOOL) {
598599
ToolResponseMessage toolMessage = (ToolResponseMessage) message;

models/spring-ai-zhipuai/src/main/java/org/springframework/ai/zhipuai/ZhiPuAiChatModel.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,7 @@ else if (message.getMessageType() == MessageType.ASSISTANT) {
510510
}).toList();
511511
}
512512
return List.of(new ChatCompletionMessage(assistantMessage.getText(),
513-
ChatCompletionMessage.Role.ASSISTANT, null, null, toolCalls));
513+
ChatCompletionMessage.Role.ASSISTANT, assistantMessage.getName(), null, toolCalls));
514514
}
515515
else if (message.getMessageType() == MessageType.TOOL) {
516516
ToolResponseMessage toolMessage = (ToolResponseMessage) message;

spring-ai-model/src/main/java/org/springframework/ai/chat/messages/AssistantMessage.java

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ public class AssistantMessage extends AbstractMessage implements MediaContent {
4141

4242
protected final List<Media> media;
4343

44+
private final String name;
45+
4446
public AssistantMessage(String content) {
4547
this(content, Map.of());
4648
}
@@ -55,11 +57,29 @@ public AssistantMessage(String content, Map<String, Object> properties, List<Too
5557

5658
public AssistantMessage(String content, Map<String, Object> properties, List<ToolCall> toolCalls,
5759
List<Media> media) {
60+
this(content, properties, toolCalls, media, null);
61+
}
62+
63+
public AssistantMessage(String content, String name) {
64+
this(content, Map.of(), name);
65+
}
66+
67+
public AssistantMessage(String content, Map<String, Object> properties, String name) {
68+
this(content, properties, List.of(), name);
69+
}
70+
71+
public AssistantMessage(String content, Map<String, Object> properties, List<ToolCall> toolCalls, String name) {
72+
this(content, properties, toolCalls, List.of(), name);
73+
}
74+
75+
public AssistantMessage(String content, Map<String, Object> properties, List<ToolCall> toolCalls, List<Media> media,
76+
String name) {
5877
super(MessageType.ASSISTANT, content, properties);
5978
Assert.notNull(toolCalls, "Tool calls must not be null");
6079
Assert.notNull(media, "Media must not be null");
6180
this.toolCalls = toolCalls;
6281
this.media = media;
82+
this.name = name;
6383
}
6484

6585
public List<ToolCall> getToolCalls() {
@@ -75,6 +95,16 @@ public List<Media> getMedia() {
7595
return this.media;
7696
}
7797

98+
/**
99+
* Get the name of the assistant. This field allows the model to distinguish the name
100+
* of the assistant, making it easier for building multi-agent systems to share global
101+
* context.
102+
* @return the assistant name, or null if not set
103+
*/
104+
public String getName() {
105+
return this.name;
106+
}
107+
78108
@Override
79109
public boolean equals(Object o) {
80110
if (this == o) {
@@ -86,18 +116,19 @@ public boolean equals(Object o) {
86116
if (!super.equals(o)) {
87117
return false;
88118
}
89-
return Objects.equals(this.toolCalls, that.toolCalls) && Objects.equals(this.media, that.media);
119+
return Objects.equals(this.toolCalls, that.toolCalls) && Objects.equals(this.media, that.media)
120+
&& Objects.equals(this.name, that.name);
90121
}
91122

92123
@Override
93124
public int hashCode() {
94-
return Objects.hash(super.hashCode(), this.toolCalls, this.media);
125+
return Objects.hash(super.hashCode(), this.toolCalls, this.media, this.name);
95126
}
96127

97128
@Override
98129
public String toString() {
99130
return "AssistantMessage [messageType=" + this.messageType + ", toolCalls=" + this.toolCalls + ", textContent="
100-
+ this.textContent + ", metadata=" + this.metadata + "]";
131+
+ this.textContent + ", name=" + this.name + ", metadata=" + this.metadata + "]";
101132
}
102133

103134
public record ToolCall(String id, String type, String name, String arguments) {

0 commit comments

Comments
 (0)