Class ClientBuilder
Client to communicate with A2A agents.
ClientBuilder provides a fluent API for configuring and creating client instances that communicate with A2A agents. It handles transport negotiation, event consumer registration, and client configuration in a type-safe manner.
Key responsibilities:
- Transport selection and negotiation between client and server capabilities
- Event consumer registration for processing agent responses
- Error handler configuration for streaming scenarios
- Client behavior configuration (streaming, polling, preferences)
Transport Selection: The builder automatically negotiates the best transport protocol
based on the agent's AgentCard and the client's configured transports. By default,
the server's preferred transport (first in AgentCard.supportedInterfaces()) is used.
This can be changed by setting ClientConfig.isUseClientPreference() to true.
Typical usage pattern:
// 1. Get the agent card
AgentCard card = A2A.getAgentCard("http://localhost:9999");
// 2. Build client with transport and event consumer
Client client = Client.builder(card)
.withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder())
.addConsumer((event, agentCard) -> {
if (event instanceof MessageEvent me) {
System.out.println("Received: " + me.getMessage().parts());
} else if (event instanceof TaskUpdateEvent tue) {
System.out.println("Task status: " + tue.getTask().status().state());
}
})
.build();
// 3. Send messages
client.sendMessage(A2A.toUserMessage("Hello agent!"));
Multiple transports: You can configure multiple transports for fallback:
Client client = Client.builder(card)
.withTransport(GrpcTransport.class, new GrpcTransportConfigBuilder()
.channelFactory(ManagedChannelBuilder::forAddress))
.withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder())
.clientConfig(new ClientConfig.Builder()
.setUseClientPreference(true) // Try client's preferred order
.build())
.build();
Error handling: For streaming scenarios, configure an error handler to process exceptions:
Client client = Client.builder(card)
.withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder())
.streamingErrorHandler(throwable -> {
System.err.println("Stream error: " + throwable.getMessage());
})
.build();
Thread safety: ClientBuilder is not thread-safe and should only be used from a single
thread during client construction. The resulting Client instance is thread-safe.
- See Also:
-
Method Summary
Modifier and TypeMethodDescriptionaddConsumer(BiConsumer<ClientEvent, AgentCard> consumer) Add a single event consumer to process events from the agent.addConsumers(List<BiConsumer<ClientEvent, AgentCard>> consumers) Add multiple event consumers to process events from the agent.build()Build the configuredClientinstance.clientConfig(@NonNull ClientConfig clientConfig) Configure client behavior such as streaming mode, polling, and transport preference.streamingErrorHandler(Consumer<Throwable> streamErrorHandler) Configure an error handler for streaming scenarios.<T extends ClientTransport>
ClientBuilderwithTransport(Class<T> clazz, ClientTransportConfig<T> config) Configure a transport protocol with a pre-built configuration.<T extends ClientTransport>
ClientBuilderwithTransport(Class<T> clazz, ClientTransportConfigBuilder<? extends ClientTransportConfig<T>, ?> configBuilder) Configure a transport protocol using a builder for type-safe configuration.
-
Method Details
-
withTransport
public <T extends ClientTransport> ClientBuilder withTransport(Class<T> clazz, ClientTransportConfigBuilder<? extends ClientTransportConfig<T>, ?> configBuilder) Configure a transport protocol using a builder for type-safe configuration.Multiple transports can be configured to support fallback scenarios. The actual transport used is negotiated based on the agent's capabilities and the
ClientConfig.Example:
builder.withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder() .httpClient(customHttpClient) .addInterceptor(loggingInterceptor));- Type Parameters:
T- the transport type- Parameters:
clazz- the transport class to configureconfigBuilder- the transport configuration builder- Returns:
- this builder for method chaining
-
withTransport
public <T extends ClientTransport> ClientBuilder withTransport(Class<T> clazz, ClientTransportConfig<T> config) Configure a transport protocol with a pre-built configuration.Multiple transports can be configured to support fallback scenarios. The actual transport used is negotiated based on the agent's capabilities and the
ClientConfig.Example:
JSONRPCTransportConfig config = new JSONRPCTransportConfig(myHttpClient); builder.withTransport(JSONRPCTransport.class, config);- Type Parameters:
T- the transport type- Parameters:
clazz- the transport class to configureconfig- the transport configuration- Returns:
- this builder for method chaining
-
addConsumer
Add a single event consumer to process events from the agent.Consumers receive
ClientEventinstances (MessageEvent, TaskEvent, TaskUpdateEvent) along with the agent'sAgentCard. Multiple consumers can be registered and will be invoked in registration order.Example:
builder.addConsumer((event, card) -> { if (event instanceof MessageEvent me) { String text = me.getMessage().parts().stream() .filter(p -> p instanceof TextPart) .map(p -> ((TextPart) p).text()) .collect(Collectors.joining()); System.out.println("Agent: " + text); } });- Parameters:
consumer- the event consumer to add- Returns:
- this builder for method chaining
- See Also:
-
addConsumers
Add multiple event consumers to process events from the agent.Consumers receive
ClientEventinstances and are invoked in the order they appear in the list.- Parameters:
consumers- the list of event consumers to add- Returns:
- this builder for method chaining
- See Also:
-
streamingErrorHandler
Configure an error handler for streaming scenarios.This handler is invoked when errors occur during streaming event consumption. It's only applicable when the client and agent both support streaming. For non-streaming scenarios, errors are thrown directly as
A2AClientException.Example:
builder.streamingErrorHandler(throwable -> { if (throwable instanceof A2AClientException e) { log.error("A2A error: " + e.getMessage(), e); } else { log.error("Unexpected error: " + throwable.getMessage(), throwable); } });- Parameters:
streamErrorHandler- the error handler for streaming errors- Returns:
- this builder for method chaining
-
clientConfig
Configure client behavior such as streaming mode, polling, and transport preference.The configuration controls how the client communicates with the agent:
- Streaming vs blocking mode
- Polling for updates vs receiving events
- Client vs server transport preference
- Output modes, history length, and metadata
Example:
ClientConfig config = new ClientConfig.Builder() .setStreaming(true) // Enable streaming if server supports it .setUseClientPreference(true) // Use client's transport order .setHistoryLength(10) // Request last 10 messages of context .build(); builder.clientConfig(config);- Parameters:
clientConfig- the client configuration- Returns:
- this builder for method chaining
- See Also:
-
build
Build the configuredClientinstance.This method performs transport negotiation between the client's configured transports and the agent's
AgentCard.supportedInterfaces(). The selection algorithm:- If
ClientConfig.isUseClientPreference()istrue, iterate through client transports in registration order and select the first one the server supports - Otherwise, iterate through server interfaces in preference order (first entry
in
AgentCard.supportedInterfaces()) and select the first one the client supports
Important: At least one transport must be configured via
withTransport(java.lang.Class<T>, org.a2aproject.sdk.client.transport.spi.ClientTransportConfigBuilder<? extends org.a2aproject.sdk.client.transport.spi.ClientTransportConfig<T>, ?>), otherwise this method throwsA2AClientException.- Returns:
- the configured client instance
- Throws:
A2AClientException- if no compatible transport is found or if transport configuration is missing
- If
-