Skip to content

Commit 950e310

Browse files
committed
Rest WIP
Signed-off-by: Emmanuel Hugonnet <[email protected]>
1 parent 7d3df0b commit 950e310

File tree

18 files changed

+1599
-964
lines changed

18 files changed

+1599
-964
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,3 @@ nb-configuration.xml
4444
# TLS Certificates
4545
.certs/
4646
nbproject/
47-

client/base/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@
6363
<groupId>io.grpc</groupId>
6464
<artifactId>grpc-api</artifactId>
6565
</dependency>
66+
<dependency>
67+
<groupId>com.google.protobuf</groupId>
68+
<artifactId>protobuf-java-util</artifactId>
69+
<type>jar</type>
70+
</dependency>
6671
</dependencies>
6772

6873
</project>

client/src/main/java/io/a2a/client/A2AClient.java

Lines changed: 0 additions & 716 deletions
This file was deleted.
Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
/*
2+
* Copyright The WildFly Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
package io.a2a.client.transport;
6+
7+
import static io.a2a.util.Assert.checkNotNullParam;
8+
9+
import com.fasterxml.jackson.core.JsonProcessingException;
10+
import com.google.protobuf.InvalidProtocolBufferException;
11+
import com.google.protobuf.MessageOrBuilder;
12+
import com.google.protobuf.util.JsonFormat;
13+
import io.a2a.client.ClientCallContext;
14+
import io.a2a.client.ClientCallInterceptor;
15+
import io.a2a.client.PayloadAndHeaders;
16+
import io.a2a.grpc.CancelTaskRequest;
17+
import io.a2a.grpc.GetTaskRequest;
18+
import io.a2a.grpc.SendMessageRequest;
19+
import io.a2a.grpc.utils.ProtoUtils;
20+
import io.a2a.http.A2AHttpClient;
21+
import io.a2a.http.A2AHttpResponse;
22+
import io.a2a.http.JdkA2AHttpClient;
23+
import io.a2a.spec.A2AClientException;
24+
import io.a2a.spec.AgentCard;
25+
import io.a2a.spec.DeleteTaskPushNotificationConfigParams;
26+
import io.a2a.spec.EventKind;
27+
import io.a2a.spec.GetTaskPushNotificationConfigParams;
28+
import io.a2a.spec.ListTaskPushNotificationConfigParams;
29+
import io.a2a.spec.MessageSendParams;
30+
import io.a2a.spec.StreamingEventKind;
31+
import io.a2a.spec.Task;
32+
import io.a2a.spec.TaskIdParams;
33+
import io.a2a.spec.TaskPushNotificationConfig;
34+
import io.a2a.spec.TaskQueryParams;
35+
import java.io.IOException;
36+
import java.util.List;
37+
import java.util.Map;
38+
import java.util.function.Consumer;
39+
40+
public class JSONRestTransport extends ClientTransport {
41+
42+
private final A2AHttpClient httpClient;
43+
private final String agentUrl;
44+
private final List<ClientCallInterceptor> interceptors;
45+
private AgentCard agentCard;
46+
47+
public JSONRestTransport(String agentUrl) {
48+
this(null, null, agentUrl, null);
49+
}
50+
51+
public JSONRestTransport(AgentCard agentCard) {
52+
this(null, agentCard, agentCard.url(), null);
53+
}
54+
55+
public JSONRestTransport(A2AHttpClient httpClient, AgentCard agentCard,
56+
String agentUrl, List<ClientCallInterceptor> interceptors) {
57+
this.httpClient = httpClient == null ? new JdkA2AHttpClient() : httpClient;
58+
this.agentCard = agentCard;
59+
this.agentUrl = agentUrl.endsWith("/") ? agentUrl.substring(0, agentUrl.length() - 1) : agentUrl;
60+
this.interceptors = interceptors;
61+
}
62+
63+
@Override
64+
public EventKind sendMessage(MessageSendParams messageSendParams, ClientCallContext context) throws A2AClientException {
65+
checkNotNullParam("messageSendParams", messageSendParams);
66+
SendMessageRequest.Builder builder = SendMessageRequest.newBuilder();
67+
builder.setRequest(ProtoUtils.ToProto.message(messageSendParams.message()));
68+
if (messageSendParams.configuration() != null) {
69+
builder.setConfiguration(ProtoUtils.ToProto.messageSendConfiguration(messageSendParams.configuration()));
70+
}
71+
if (messageSendParams.metadata() != null) {
72+
builder.setMetadata(ProtoUtils.ToProto.struct(messageSendParams.metadata()));
73+
}
74+
PayloadAndHeaders payloadAndHeaders = applyInterceptors(io.a2a.spec.SendMessageRequest.METHOD, builder.getRequestOrBuilder(),
75+
agentCard, context);
76+
try {
77+
String httpResponseBody = sendPostRequest(agentUrl + "/v1/message:send", payloadAndHeaders);
78+
System.out.println("Response " + httpResponseBody);
79+
io.a2a.grpc.SendMessageResponse.Builder responseBuilder = io.a2a.grpc.SendMessageResponse.newBuilder();
80+
JsonFormat.parser().merge(httpResponseBody, responseBuilder);
81+
if (responseBuilder.hasMsg()) {
82+
return ProtoUtils.FromProto.message(responseBuilder.getMsg());
83+
}
84+
return ProtoUtils.FromProto.task(responseBuilder.getTask());
85+
} catch (A2AClientException e) {
86+
throw e;
87+
} catch (IOException | InterruptedException e) {
88+
throw new A2AClientException("Failed to send message: " + e, e);
89+
}
90+
}
91+
92+
@Override
93+
public void sendMessageStreaming(MessageSendParams request, Consumer<StreamingEventKind> eventConsumer, Consumer<Throwable> errorConsumer, ClientCallContext context) throws A2AClientException {
94+
throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody
95+
}
96+
97+
@Override
98+
public Task getTask(TaskQueryParams taskQueryParams, ClientCallContext context) throws A2AClientException {
99+
checkNotNullParam("taskQueryParams", taskQueryParams);
100+
GetTaskRequest.Builder builder = GetTaskRequest.newBuilder();
101+
builder.setName("tasks/" + taskQueryParams.id());
102+
PayloadAndHeaders payloadAndHeaders = applyInterceptors(io.a2a.spec.SendMessageRequest.METHOD, builder,
103+
agentCard, context);
104+
try {
105+
String url;
106+
if(taskQueryParams.historyLength() != null) {
107+
url = agentUrl + String.format("/v1/tasks/%1s?historyLength=%2d", taskQueryParams.id(), taskQueryParams.historyLength());
108+
} else {
109+
url = agentUrl + String.format("/v1/tasks/%1s", taskQueryParams.id());
110+
}
111+
System.out.println("Getting URL: " + url);
112+
A2AHttpClient.GetBuilder getBuilder = httpClient.createGet().url(url);
113+
if (payloadAndHeaders.getHttpHeaders() != null) {
114+
for (Map.Entry<String, String> entry : payloadAndHeaders.getHttpHeaders().entrySet()) {
115+
getBuilder.addHeader(entry.getKey(), entry.getValue());
116+
}
117+
}
118+
A2AHttpResponse response = getBuilder.get();
119+
if (!response.success()) {
120+
IOException e = new IOException("Request failed " + response.status());
121+
throw new A2AClientException("Failed to send message: " + e, e);
122+
}
123+
String httpResponseBody = response.body();
124+
System.out.println("Response " + httpResponseBody);
125+
io.a2a.grpc.Task.Builder responseBuilder = io.a2a.grpc.Task.newBuilder();
126+
JsonFormat.parser().merge(httpResponseBody, responseBuilder);
127+
return ProtoUtils.FromProto.task(responseBuilder);
128+
} catch (A2AClientException e) {
129+
throw e;
130+
} catch (IOException | InterruptedException e) {
131+
throw new A2AClientException("Failed to send message: " + e, e);
132+
}
133+
}
134+
135+
@Override
136+
public Task cancelTask(TaskIdParams taskIdParams, ClientCallContext context) throws A2AClientException {
137+
checkNotNullParam("taskIdParams", taskIdParams);
138+
CancelTaskRequest.Builder builder = CancelTaskRequest.newBuilder();
139+
builder.setName("tasks/" + taskIdParams.id());
140+
PayloadAndHeaders payloadAndHeaders = applyInterceptors(io.a2a.spec.SendMessageRequest.METHOD, builder,
141+
agentCard, context);
142+
try {
143+
String httpResponseBody = sendPostRequest(agentUrl + String.format("/v1/tasks/%1s:cancel", taskIdParams.id()), payloadAndHeaders);
144+
System.out.println("Response " + httpResponseBody);
145+
io.a2a.grpc.Task.Builder responseBuilder = io.a2a.grpc.Task.newBuilder();
146+
JsonFormat.parser().merge(httpResponseBody, responseBuilder);
147+
return ProtoUtils.FromProto.task(responseBuilder);
148+
} catch (A2AClientException e) {
149+
throw e;
150+
} catch (IOException | InterruptedException e) {
151+
throw new A2AClientException("Failed to send message: " + e, e);
152+
}
153+
}
154+
155+
@Override
156+
public TaskPushNotificationConfig setTaskPushNotificationConfiguration(TaskPushNotificationConfig request, ClientCallContext context) throws A2AClientException {
157+
throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody
158+
}
159+
160+
@Override
161+
public TaskPushNotificationConfig getTaskPushNotificationConfiguration(GetTaskPushNotificationConfigParams request, ClientCallContext context) throws A2AClientException {
162+
throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody
163+
}
164+
165+
@Override
166+
public List<TaskPushNotificationConfig> listTaskPushNotificationConfigurations(ListTaskPushNotificationConfigParams request, ClientCallContext context) throws A2AClientException {
167+
throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody
168+
}
169+
170+
@Override
171+
public void deleteTaskPushNotificationConfigurations(DeleteTaskPushNotificationConfigParams request, ClientCallContext context) throws A2AClientException {
172+
throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody
173+
}
174+
175+
@Override
176+
public void resubscribe(TaskIdParams request, Consumer<StreamingEventKind> eventConsumer,
177+
Consumer<Throwable> errorConsumer, ClientCallContext context) throws A2AClientException {
178+
throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody
179+
}
180+
181+
@Override
182+
public AgentCard getAgentCard(ClientCallContext context) throws A2AClientException {
183+
throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody
184+
}
185+
186+
@Override
187+
public void close() {
188+
throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody
189+
}
190+
191+
private PayloadAndHeaders applyInterceptors(String methodName, MessageOrBuilder payload,
192+
AgentCard agentCard, ClientCallContext clientCallContext) {
193+
PayloadAndHeaders payloadAndHeaders = new PayloadAndHeaders(payload, getHttpHeaders(clientCallContext));
194+
if (interceptors != null && !interceptors.isEmpty()) {
195+
for (ClientCallInterceptor interceptor : interceptors) {
196+
payloadAndHeaders = interceptor.intercept(methodName, payloadAndHeaders.getPayload(),
197+
payloadAndHeaders.getHttpHeaders(), agentCard, clientCallContext);
198+
}
199+
}
200+
return payloadAndHeaders;
201+
}
202+
203+
private String sendPostRequest(String url, PayloadAndHeaders payloadAndHeaders) throws IOException, InterruptedException {
204+
A2AHttpClient.PostBuilder builder = createPostBuilder(url, payloadAndHeaders);
205+
A2AHttpResponse response = builder.post();
206+
if (!response.success()) {
207+
throw new IOException("Request failed " + response.status());
208+
}
209+
return response.body();
210+
}
211+
212+
private A2AHttpClient.PostBuilder createPostBuilder(String url, PayloadAndHeaders payloadAndHeaders) throws JsonProcessingException, InvalidProtocolBufferException {
213+
System.out.println("**************************************************************************");
214+
System.out.println(JsonFormat.printer().print((MessageOrBuilder) payloadAndHeaders.getPayload()));
215+
System.out.println("**************************************************************************");
216+
A2AHttpClient.PostBuilder postBuilder = httpClient.createPost()
217+
.url(url)
218+
.addHeader("Content-Type", "application/json")
219+
.body(JsonFormat.printer().print((MessageOrBuilder) payloadAndHeaders.getPayload()));
220+
221+
if (payloadAndHeaders.getHttpHeaders() != null) {
222+
for (Map.Entry<String, String> entry : payloadAndHeaders.getHttpHeaders().entrySet()) {
223+
postBuilder.addHeader(entry.getKey(), entry.getValue());
224+
}
225+
}
226+
227+
return postBuilder;
228+
}
229+
230+
private Map<String, String> getHttpHeaders(ClientCallContext context) {
231+
return context != null ? context.getHttpHeaders() : null;
232+
}
233+
}

0 commit comments

Comments
 (0)