Skip to content

Commit 71c56ea

Browse files
authored
feat: Add message creation methods with contextId and taskId support (#322)
## PR Description - Added new message creation methods to A2A.java (createUserMessage, createAgentMessage, createMessage) - Implemented support for configuring contextId, taskId, parts, metadata, and referenceTaskIds - Added comprehensive test cases in A2ATest.java to verify functionality - Methods follow similar pattern to the Python implementation for consistency across SDKs - [x] Follow the [`CONTRIBUTING` Guide](../CONTRIBUTING.md). - [x] Ensure the tests pass Fixes #302 🦕
1 parent d6fef7e commit 71c56ea

File tree

2 files changed

+207
-1
lines changed

2 files changed

+207
-1
lines changed

client/base/src/main/java/io/a2a/A2A.java

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package io.a2a;
22

33
import java.util.Collections;
4+
import java.util.List;
45
import java.util.Map;
6+
import java.util.UUID;
57

68
import io.a2a.client.http.A2ACardResolver;
79
import io.a2a.client.http.A2AHttpClient;
@@ -10,6 +12,7 @@
1012
import io.a2a.spec.A2AClientJSONError;
1113
import io.a2a.spec.AgentCard;
1214
import io.a2a.spec.Message;
15+
import io.a2a.spec.Part;
1316
import io.a2a.spec.TextPart;
1417

1518

@@ -60,11 +63,67 @@ public static Message toAgentMessage(String text, String messageId) {
6063
return toMessage(text, Message.Role.AGENT, messageId);
6164
}
6265

66+
/**
67+
* Create a user message with text content and optional context and task IDs.
68+
*
69+
* @param text the message text (required)
70+
* @param contextId the context ID to use (optional)
71+
* @param taskId the task ID to use (optional)
72+
* @return the user message
73+
*/
74+
public static Message createUserTextMessage(String text, String contextId, String taskId) {
75+
return toMessage(text, Message.Role.USER, null, contextId, taskId);
76+
}
77+
78+
/**
79+
* Create an agent message with text content and optional context and task IDs.
80+
*
81+
* @param text the message text (required)
82+
* @param contextId the context ID to use (optional)
83+
* @param taskId the task ID to use (optional)
84+
* @return the agent message
85+
*/
86+
public static Message createAgentTextMessage(String text, String contextId, String taskId) {
87+
return toMessage(text, Message.Role.AGENT, null, contextId, taskId);
88+
}
89+
90+
/**
91+
* Create an agent message with custom parts and optional context and task IDs.
92+
*
93+
* @param parts the message parts (required)
94+
* @param contextId the context ID to use (optional)
95+
* @param taskId the task ID to use (optional)
96+
* @return the agent message
97+
*/
98+
public static Message createAgentPartsMessage(List<Part<?>> parts, String contextId, String taskId) {
99+
if (parts == null || parts.isEmpty()) {
100+
throw new IllegalArgumentException("Parts cannot be null or empty");
101+
}
102+
return toMessage(parts, Message.Role.AGENT, null, contextId, taskId);
103+
}
63104

64105
private static Message toMessage(String text, Message.Role role, String messageId) {
106+
return toMessage(text, role, messageId, null, null);
107+
}
108+
109+
private static Message toMessage(String text, Message.Role role, String messageId, String contextId, String taskId) {
110+
Message.Builder messageBuilder = new Message.Builder()
111+
.role(role)
112+
.parts(Collections.singletonList(new TextPart(text)))
113+
.contextId(contextId)
114+
.taskId(taskId);
115+
if (messageId != null) {
116+
messageBuilder.messageId(messageId);
117+
}
118+
return messageBuilder.build();
119+
}
120+
121+
private static Message toMessage(List<Part<?>> parts, Message.Role role, String messageId, String contextId, String taskId) {
65122
Message.Builder messageBuilder = new Message.Builder()
66123
.role(role)
67-
.parts(Collections.singletonList(new TextPart(text)));
124+
.parts(parts)
125+
.contextId(contextId)
126+
.taskId(taskId);
68127
if (messageId != null) {
69128
messageBuilder.messageId(messageId);
70129
}
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
package io.a2a;
2+
3+
import io.a2a.spec.Message;
4+
import io.a2a.spec.Part;
5+
import io.a2a.spec.TextPart;
6+
import org.junit.jupiter.api.Test;
7+
8+
import java.util.Arrays;
9+
import java.util.Collections;
10+
import java.util.List;
11+
12+
import static org.junit.jupiter.api.Assertions.assertEquals;
13+
import static org.junit.jupiter.api.Assertions.assertNotNull;
14+
import static org.junit.jupiter.api.Assertions.assertNull;
15+
16+
public class A2ATest {
17+
18+
@Test
19+
public void testToUserMessage() {
20+
String text = "Hello, world!";
21+
Message message = A2A.toUserMessage(text);
22+
23+
assertEquals(Message.Role.USER, message.getRole());
24+
assertEquals(1, message.getParts().size());
25+
assertEquals(text, ((TextPart) message.getParts().get(0)).getText());
26+
assertNotNull(message.getMessageId());
27+
assertNull(message.getContextId());
28+
assertNull(message.getTaskId());
29+
}
30+
31+
@Test
32+
public void testToUserMessageWithId() {
33+
String text = "Hello, world!";
34+
String messageId = "test-message-id";
35+
Message message = A2A.toUserMessage(text, messageId);
36+
37+
assertEquals(Message.Role.USER, message.getRole());
38+
assertEquals(messageId, message.getMessageId());
39+
}
40+
41+
@Test
42+
public void testToAgentMessage() {
43+
String text = "Hello, I'm an agent!";
44+
Message message = A2A.toAgentMessage(text);
45+
46+
assertEquals(Message.Role.AGENT, message.getRole());
47+
assertEquals(1, message.getParts().size());
48+
assertEquals(text, ((TextPart) message.getParts().get(0)).getText());
49+
assertNotNull(message.getMessageId());
50+
}
51+
52+
@Test
53+
public void testToAgentMessageWithId() {
54+
String text = "Hello, I'm an agent!";
55+
String messageId = "agent-message-id";
56+
Message message = A2A.toAgentMessage(text, messageId);
57+
58+
assertEquals(Message.Role.AGENT, message.getRole());
59+
assertEquals(messageId, message.getMessageId());
60+
}
61+
62+
@Test
63+
public void testCreateUserTextMessage() {
64+
String text = "User message with context";
65+
String contextId = "context-123";
66+
String taskId = "task-456";
67+
68+
Message message = A2A.createUserTextMessage(text, contextId, taskId);
69+
70+
assertEquals(Message.Role.USER, message.getRole());
71+
assertEquals(contextId, message.getContextId());
72+
assertEquals(taskId, message.getTaskId());
73+
assertEquals(1, message.getParts().size());
74+
assertEquals(text, ((TextPart) message.getParts().get(0)).getText());
75+
assertNotNull(message.getMessageId());
76+
assertNull(message.getMetadata());
77+
assertNull(message.getReferenceTaskIds());
78+
}
79+
80+
@Test
81+
public void testCreateUserTextMessageWithNullParams() {
82+
String text = "Simple user message";
83+
84+
Message message = A2A.createUserTextMessage(text, null, null);
85+
86+
assertEquals(Message.Role.USER, message.getRole());
87+
assertNull(message.getContextId());
88+
assertNull(message.getTaskId());
89+
assertEquals(1, message.getParts().size());
90+
assertEquals(text, ((TextPart) message.getParts().get(0)).getText());
91+
}
92+
93+
@Test
94+
public void testCreateAgentTextMessage() {
95+
String text = "Agent message with context";
96+
String contextId = "context-789";
97+
String taskId = "task-012";
98+
99+
Message message = A2A.createAgentTextMessage(text, contextId, taskId);
100+
101+
assertEquals(Message.Role.AGENT, message.getRole());
102+
assertEquals(contextId, message.getContextId());
103+
assertEquals(taskId, message.getTaskId());
104+
assertEquals(1, message.getParts().size());
105+
assertEquals(text, ((TextPart) message.getParts().get(0)).getText());
106+
assertNotNull(message.getMessageId());
107+
}
108+
109+
@Test
110+
public void testCreateAgentPartsMessage() {
111+
List<Part<?>> parts = Arrays.asList(
112+
new TextPart("Part 1"),
113+
new TextPart("Part 2")
114+
);
115+
String contextId = "context-parts";
116+
String taskId = "task-parts";
117+
118+
Message message = A2A.createAgentPartsMessage(parts, contextId, taskId);
119+
120+
assertEquals(Message.Role.AGENT, message.getRole());
121+
assertEquals(contextId, message.getContextId());
122+
assertEquals(taskId, message.getTaskId());
123+
assertEquals(2, message.getParts().size());
124+
assertEquals("Part 1", ((TextPart) message.getParts().get(0)).getText());
125+
assertEquals("Part 2", ((TextPart) message.getParts().get(1)).getText());
126+
}
127+
128+
@Test
129+
public void testCreateAgentPartsMessageWithNullParts() {
130+
try {
131+
A2A.createAgentPartsMessage(null, "context", "task");
132+
org.junit.jupiter.api.Assertions.fail("Expected IllegalArgumentException");
133+
} catch (IllegalArgumentException e) {
134+
assertEquals("Parts cannot be null or empty", e.getMessage());
135+
}
136+
}
137+
138+
@Test
139+
public void testCreateAgentPartsMessageWithEmptyParts() {
140+
try {
141+
A2A.createAgentPartsMessage(Collections.emptyList(), "context", "task");
142+
org.junit.jupiter.api.Assertions.fail("Expected IllegalArgumentException");
143+
} catch (IllegalArgumentException e) {
144+
assertEquals("Parts cannot be null or empty", e.getMessage());
145+
}
146+
}
147+
}

0 commit comments

Comments
 (0)