Skip to content

Commit b0a16ee

Browse files
committed
fix: Require channel configuration for gRPC
1 parent f43e0d8 commit b0a16ee

File tree

5 files changed

+50
-17
lines changed

5 files changed

+50
-17
lines changed

client/transport/grpc/src/main/java/io/a2a/client/transport/grpc/GrpcTransportProvider.java

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77
import io.a2a.client.config.ClientTransportConfig;
88
import io.a2a.client.transport.spi.ClientTransport;
99
import io.a2a.client.transport.spi.ClientTransportProvider;
10+
import io.a2a.spec.A2AClientException;
1011
import io.a2a.spec.AgentCard;
1112
import io.a2a.spec.TransportProtocol;
1213
import io.grpc.Channel;
13-
import io.grpc.ManagedChannelBuilder;
1414

1515
/**
1616
* Provider for gRPC transport implementation.
@@ -19,21 +19,18 @@ public class GrpcTransportProvider implements ClientTransportProvider {
1919

2020
@Override
2121
public ClientTransport create(ClientConfig clientConfig, AgentCard agentCard,
22-
String agentUrl, List<ClientCallInterceptor> interceptors) {
22+
String agentUrl, List<ClientCallInterceptor> interceptors) throws A2AClientException {
2323
// not making use of the interceptors for gRPC for now
24-
Channel channel;
2524
List<ClientTransportConfig> clientTransportConfigs = clientConfig.getClientTransportConfigs();
2625
if (clientTransportConfigs != null) {
2726
for (ClientTransportConfig clientTransportConfig : clientTransportConfigs) {
2827
if (clientTransportConfig instanceof GrpcTransportConfig grpcTransportConfig) {
29-
channel = grpcTransportConfig.getChannelFactory().apply(agentUrl);
28+
Channel channel = grpcTransportConfig.getChannelFactory().apply(agentUrl);
3029
return new GrpcTransport(channel, agentCard);
3130
}
3231
}
3332
}
34-
// no channel factory configured
35-
channel = ManagedChannelBuilder.forTarget(agentUrl).build();
36-
return new GrpcTransport(channel, agentCard);
33+
throw new A2AClientException("Missing required GrpcTransportConfig");
3734
}
3835

3936
@Override

client/transport/jsonrpc/src/main/java/io/a2a/client/transport/jsonrpc/JSONRPCTransportProvider.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@
88
import io.a2a.client.http.A2AHttpClient;
99
import io.a2a.client.transport.spi.ClientTransport;
1010
import io.a2a.client.transport.spi.ClientTransportProvider;
11+
import io.a2a.spec.A2AClientException;
1112
import io.a2a.spec.AgentCard;
1213
import io.a2a.spec.TransportProtocol;
1314

1415
public class JSONRPCTransportProvider implements ClientTransportProvider {
1516

1617
@Override
1718
public ClientTransport create(ClientConfig clientConfig, AgentCard agentCard,
18-
String agentUrl, List<ClientCallInterceptor> interceptors) {
19+
String agentUrl, List<ClientCallInterceptor> interceptors) throws A2AClientException {
1920
A2AHttpClient httpClient = null;
2021
List<ClientTransportConfig> clientTransportConfigs = clientConfig.getClientTransportConfigs();
2122
if (clientTransportConfigs != null) {

client/transport/spi/src/main/java/io/a2a/client/transport/spi/ClientTransportProvider.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import io.a2a.client.config.ClientCallInterceptor;
66
import io.a2a.client.config.ClientConfig;
7+
import io.a2a.spec.A2AClientException;
78
import io.a2a.spec.AgentCard;
89

910
/**
@@ -19,9 +20,10 @@ public interface ClientTransportProvider {
1920
* @param agentUrl the remote agent's URL
2021
* @param interceptors the optional interceptors to use for a client call (may be {@code null})
2122
* @return the client transport
23+
* @throws io.a2a.spec.A2AClientException if an error occurs trying to create the client
2224
*/
2325
ClientTransport create(ClientConfig clientConfig, AgentCard agentCard,
24-
String agentUrl, List<ClientCallInterceptor> interceptors);
26+
String agentUrl, List<ClientCallInterceptor> interceptors) throws A2AClientException;
2527

2628
/**
2729
* Get the name of the client transport.

reference/grpc/src/test/java/io/a2a/server/grpc/quarkus/QuarkusA2AGrpcTest.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,24 @@
11
package io.a2a.server.grpc.quarkus;
22

3+
import java.util.ArrayList;
4+
import java.util.List;
5+
import java.util.concurrent.TimeUnit;
6+
7+
import io.a2a.client.config.ClientTransportConfig;
8+
import io.a2a.client.transport.grpc.GrpcTransportConfig;
39
import io.a2a.server.apps.common.AbstractA2AServerTest;
410
import io.a2a.spec.TransportProtocol;
11+
import io.grpc.ManagedChannel;
12+
import io.grpc.ManagedChannelBuilder;
513
import io.quarkus.test.junit.QuarkusTest;
614

15+
import org.junit.jupiter.api.AfterAll;
16+
717
@QuarkusTest
818
public class QuarkusA2AGrpcTest extends AbstractA2AServerTest {
919

20+
private static ManagedChannel channel;
21+
1022
public QuarkusA2AGrpcTest() {
1123
super(8081); // HTTP server port for utility endpoints
1224
}
@@ -20,4 +32,25 @@ protected String getTransportProtocol() {
2032
protected String getTransportUrl() {
2133
return "localhost:9001"; // gRPC server runs on port 9001
2234
}
35+
36+
@Override
37+
protected List<ClientTransportConfig> getClientTransportConfigs() {
38+
List<ClientTransportConfig> transportConfigs = new ArrayList<>();
39+
transportConfigs.add(new GrpcTransportConfig(
40+
target -> {
41+
channel = ManagedChannelBuilder.forTarget(target).usePlaintext().build();
42+
return channel;
43+
}));
44+
return transportConfigs;
45+
}
46+
47+
@AfterAll
48+
public static void closeChannel() {
49+
channel.shutdownNow();
50+
try {
51+
channel.awaitTermination(10, TimeUnit.SECONDS);
52+
} catch (InterruptedException e) {
53+
Thread.currentThread().interrupt();
54+
}
55+
}
2356
}

tests/server-common/src/test/java/io/a2a/server/apps/common/AbstractA2AServerTest.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,13 @@ protected AbstractA2AServerTest(int serverPort) {
134134
*/
135135
protected abstract String getTransportUrl();
136136

137+
/**
138+
* Get the transport configs to use for this test.
139+
*/
140+
protected List<ClientTransportConfig> getClientTransportConfigs() {
141+
return new ArrayList<>();
142+
}
143+
137144
@Test
138145
public void testTaskStoreMethodsSanityTest() throws Exception {
139146
Task task = new Task.Builder(MINIMAL_TASK).id("abcde").build();
@@ -1144,14 +1151,7 @@ private ClientConfig createClientConfig(boolean streaming) {
11441151
.setAcceptedOutputModes(List.of("text"));
11451152

11461153
// Set transport-specific configuration
1147-
List<ClientTransportConfig> transportConfigs = new ArrayList<>();
1148-
if (TransportProtocol.JSONRPC.asString().equals(getTransportProtocol())) {
1149-
transportConfigs.add(new JSONRPCTransportConfig(new JdkA2AHttpClient()));
1150-
} else if (TransportProtocol.GRPC.asString().equals(getTransportProtocol())) {
1151-
// For gRPC, use a function that creates a channel with plaintext communication
1152-
transportConfigs.add(new GrpcTransportConfig(
1153-
target -> ManagedChannelBuilder.forTarget(target).usePlaintext().build()));
1154-
}
1154+
List<ClientTransportConfig> transportConfigs = getClientTransportConfigs();
11551155

11561156
if (!transportConfigs.isEmpty()) {
11571157
builder.setClientTransportConfigs(transportConfigs);

0 commit comments

Comments
 (0)