@@ -211,8 +211,14 @@ public class WeatherAgentExecutorProducer {
211211
212212## A2A Client
213213
214- The A2A Java SDK provides a Java client implementation of the [ Agent2Agent (A2A) Protocol] ( https://google-a2a.github.io/A2A ) , allowing communication with A2A servers.
215- To make use of the Java ` A2AClient ` , simply add the following dependency:
214+ The A2A Java SDK provides a Java client implementation of the [ Agent2Agent (A2A) Protocol] ( https://google-a2a.github.io/A2A ) , allowing communication with A2A servers. The Java client implementation currently supports two transport protocols: JSON-RPC 2.0 and gRPC.
215+
216+ To make use of the Java ` Client ` :
217+
218+ ### 1. Add the A2A Java SDK Client dependency to your project
219+
220+ Adding a dependency on ` a2a-java-sdk-client ` will provide access to a ` ClientFactory `
221+ that you can use to create your A2A ` Client ` .
216222
217223----
218224> * ⚠️ The ` io.github.a2asdk ` ` groupId ` below is temporary and will likely change for future releases.*
@@ -227,67 +233,222 @@ To make use of the Java `A2AClient`, simply add the following dependency:
227233</dependency >
228234```
229235
236+ ### 2. Add dependencies on the A2A Java SDK Client Transport(s) you'd like to use
237+
238+ You need to add a dependency on at least one of the following client transport modules:
239+
240+ ----
241+ > * ⚠️ The ` io.github.a2asdk ` ` groupId ` below is temporary and will likely change for future releases.*
242+ ----
243+
244+ ``` xml
245+ <dependency >
246+ <groupId >io.github.a2asdk</groupId >
247+ <artifactId >a2a-java-sdk-client-transport-jsonrpc</artifactId >
248+ <!-- Use a released version from https://github.com/a2aproject/a2a-java/releases -->
249+ <version >${io.a2a.sdk.version}</version >
250+ </dependency >
251+ ```
252+
253+ ``` xml
254+ <dependency >
255+ <groupId >io.github.a2asdk</groupId >
256+ <artifactId >a2a-java-sdk-client-transport-grpc</artifactId >
257+ <!-- Use a released version from https://github.com/a2aproject/a2a-java/releases -->
258+ <version >${io.a2a.sdk.version}</version >
259+ </dependency >
260+ ```
261+
262+ Support for the HTTP+JSON/REST transport will be coming soon.
263+
230264### Sample Usage
231265
232- #### Create an A2A client
266+ #### Create a Client using the ClientFactory
267+
268+ ``` java
269+ // First, get the agent card for the A2A server agent you want to connect to
270+ AgentCard agentCard = new A2ACardResolver (" http://localhost:1234" ). getAgentCard();
271+
272+ // Specify configuration for the ClientFactory
273+ ClientConfig clientConfig = new ClientConfig .Builder ()
274+ .setAcceptedOutputModes(List . of(" text" ))
275+ .build();
276+
277+ // Create event consumers to handle responses that will be received from the A2A server
278+ // (these consumers will be used for both streaming and non-streaming responses)
279+ List<BiConsumer<ClientEvent , AgentCard > > consumers = List . of(
280+ (event, card) - > {
281+ if (event instanceof MessageEvent messageEvent) {
282+ // handle the messageEvent.getMessage()
283+ ...
284+ } else if (event instanceof TaskEvent taskEvent) {
285+ // handle the taskEvent.getTask()
286+ ...
287+ } else if (event instanceof TaskUpdateEvent updateEvent) {
288+ // handle the updateEvent.getTask()
289+ ...
290+ }
291+ }
292+ );
293+
294+ // Create a handler that will be used for any errors that occur during streaming
295+ Consumer<Throwable > errorHandler = error - > {
296+ // handle the error.getMessage()
297+ ...
298+ };
299+
300+ // Create the client using ClientFactory
301+ ClientFactory clientFactory = new ClientFactory (clientConfig);
302+ Client client = clientFactory. create(agentCard, consumers, errorHandler);
303+ ```
304+
305+ #### Configuring Transport-Specific Settings
306+
307+ Different transport protocols can be configured with specific settings using ` ClientTransportConfig ` implementations. The A2A Java SDK provides ` JSONRPCTransportConfig ` for the JSON-RPC transport and ` GrpcTransportConfig ` for the gRPC transport.
308+
309+ ##### JSON-RPC Transport Configuration
310+
311+ For the JSON-RPC transport, if you'd like to use the default ` JdkA2AHttpClient ` , no additional
312+ configuration is needed. To use a custom HTTP client instead, simply create a ` JSONRPCTransportConfig `
313+ as follows:
314+
315+ ``` java
316+ // Create a custom HTTP client
317+ A2AHttpClient customHttpClient = ...
318+
319+ // Create JSON-RPC transport configuration
320+ JSONRPCTransportConfig jsonrpcConfig = new JSONRPCTransportConfig (customHttpClient);
321+
322+ // Configure the client with transport-specific settings
323+ ClientConfig clientConfig = new ClientConfig .Builder ()
324+ .setAcceptedOutputModes(List . of(" text" ))
325+ .setClientTransportConfigs(List . of(jsonrpcConfig))
326+ .build();
327+ ```
328+
329+ ##### gRPC Transport Configuration
330+
331+ For the gRPC transport, you must configure a channel factory:
233332
234333``` java
235- // Create an A2AClient (the URL specified is the server agent's URL, be sure to replace it with the actual URL of the A2A server you want to connect to)
236- A2AClient client = new A2AClient (" http://localhost:1234" );
334+ // Create a channel factory function that takes the agent URL and returns a Channel
335+ Function<String , Channel > channelFactory = agentUrl - > {
336+ return ManagedChannelBuilder . forTarget(agentUrl)
337+ ...
338+ .build();
339+ };
340+
341+ // Create gRPC transport configuration
342+ GrpcTransportConfig grpcConfig = new GrpcTransportConfig (channelFactory);
343+
344+ // Configure the client with transport-specific settings
345+ ClientConfig clientConfig = new ClientConfig .Builder ()
346+ .setAcceptedOutputModes(List . of(" text" ))
347+ .setClientTransportConfigs(List . of(grpcConfig))
348+ .build();
349+ ```
350+
351+ ##### Multiple Transport Configurations
352+
353+ You can specify configuration for multiple transports, the appropriate configuration
354+ will be used based on the selected transport:
355+
356+ ``` java
357+ // Configure both JSON-RPC and gRPC transports
358+ List<ClientTransportConfig > transportConfigs = List . of(
359+ new JSONRPCTransportConfig (... ),
360+ new GrpcTransportConfig (... )
361+ );
362+
363+ ClientConfig clientConfig = new ClientConfig .Builder ()
364+ .setAcceptedOutputModes(List . of(" text" ))
365+ .setClientTransportConfigs(transportConfigs)
366+ .build();
237367```
238368
239369#### Send a message to the A2A server agent
240370
241371``` java
242372// Send a text message to the A2A server agent
243- Message message = A2A . toUserMessage(" tell me a joke" ); // the message ID will be automatically generated for you
244- MessageSendParams params = new MessageSendParams .Builder ()
245- .message(message)
246- .build();
247- SendMessageResponse response = client. sendMessage(params);
373+ Message message = A2A . toUserMessage(" tell me a joke" );
374+
375+ // Send the message (uses configured consumers to handle responses)
376+ // Streaming will automatically be used if supported by both client and server,
377+ // otherwise the non-streaming send message method will be used automatically
378+ client. sendMessage(message);
379+
380+ // You can also optionally specify a ClientCallContext with call-specific config to use
381+ client. sendMessage(message, clientCallContext);
248382```
249383
250- Note that ` A2A#toUserMessage ` will automatically generate a message ID for you when creating the ` Message `
251- if you don't specify it. You can also explicitly specify a message ID like this:
384+ #### Send a message with custom event handling
252385
253386``` java
254- Message message = A2A . toUserMessage(" tell me a joke" , " message-1234" ); // messageId is message-1234
387+ // Create custom consumers for this specific message
388+ List<BiConsumer<ClientEvent , AgentCard > > customConsumers = List . of(
389+ (event, card) - > {
390+ // handle this specific message's responses
391+ ...
392+ }
393+ );
394+
395+ // Create custom error handler
396+ Consumer<Throwable > customErrorHandler = error - > {
397+ // handle the error
398+ ...
399+ };
400+
401+ Message message = A2A . toUserMessage(" tell me a joke" );
402+ client. sendMessage(message, customConsumers, customErrorHandler);
255403```
256404
257405#### Get the current state of a task
258406
259407``` java
260408// Retrieve the task with id "task-1234"
261- GetTaskResponse response = client. getTask(" task-1234" );
409+ Task task = client. getTask(new TaskQueryParams ( " task-1234" ) );
262410
263411// You can also specify the maximum number of items of history for the task
264- // to include in the response
265- GetTaskResponse response = client. getTask(new TaskQueryParams (" task-1234" , 10 ));
412+ // to include in the response and
413+ Task task = client. getTask(new TaskQueryParams (" task-1234" , 10 ));
414+
415+ // You can also optionally specify a ClientCallContext with call-specific config to use
416+ Task task = client. getTask(new TaskQueryParams (" task-1234" ), clientCallContext);
266417```
267418
268419#### Cancel an ongoing task
269420
270421``` java
271422// Cancel the task we previously submitted with id "task-1234"
272- CancelTaskResponse response = client. cancelTask(" task-1234" );
423+ Task cancelledTask = client. cancelTask(new TaskIdParams ( " task-1234" ) );
273424
274425// You can also specify additional properties using a map
275- Map<String , Object > metadata = ...
276- CancelTaskResponse response = client. cancelTask(new TaskIdParams (" task-1234" , metadata));
426+ Map<String , Object > metadata = Map . of(" reason" , " user_requested" );
427+ Task cancelledTask = client. cancelTask(new TaskIdParams (" task-1234" , metadata));
428+
429+ // You can also optionally specify a ClientCallContext with call-specific config to use
430+ Task cancelledTask = client. cancelTask(new TaskIdParams (" task-1234" ), clientCallContext);
277431```
278432
279433#### Get a push notification configuration for a task
280434
281435``` java
282436// Get task push notification configuration
283- GetTaskPushNotificationConfigResponse response = client. getTaskPushNotificationConfig(" task-1234" );
437+ TaskPushNotificationConfig config = client. getTaskPushNotificationConfiguration(
438+ new GetTaskPushNotificationConfigParams (" task-1234" ));
284439
285440// The push notification configuration ID can also be optionally specified
286- GetTaskPushNotificationConfigResponse response = client. getTaskPushNotificationConfig(" task-1234" , " config-4567" );
441+ TaskPushNotificationConfig config = client. getTaskPushNotificationConfiguration(
442+ new GetTaskPushNotificationConfigParams (" task-1234" , " config-4567" ));
287443
288444// Additional properties can be specified using a map
289- Map<String , Object > metadata = ...
290- GetTaskPushNotificationConfigResponse response = client. getTaskPushNotificationConfig(new GetTaskPushNotificationConfigParams (" task-1234" , " config-1234" , metadata));
445+ Map<String , Object > metadata = Map . of(" source" , " client" );
446+ TaskPushNotificationConfig config = client. getTaskPushNotificationConfiguration(
447+ new GetTaskPushNotificationConfigParams (" task-1234" , " config-1234" , metadata));
448+
449+ // You can also optionally specify a ClientCallContext with call-specific config to use
450+ TaskPushNotificationConfig config = client. getTaskPushNotificationConfiguration(
451+ new GetTaskPushNotificationConfigParams (" task-1234" ), clientCallContext);
291452```
292453
293454#### Set a push notification configuration for a task
@@ -298,79 +459,75 @@ PushNotificationConfig pushNotificationConfig = new PushNotificationConfig.Build
298459 .url(" https://example.com/callback" )
299460 .authenticationInfo(new AuthenticationInfo (Collections . singletonList(" jwt" ), null ))
300461 .build();
301- SetTaskPushNotificationResponse response = client. setTaskPushNotificationConfig(" task-1234" , pushNotificationConfig);
302- ```
303462
304- #### List the push notification configurations for a task
463+ TaskPushNotificationConfig taskConfig = new TaskPushNotificationConfig .Builder ()
464+ .taskId(" task-1234" )
465+ .pushNotificationConfig(pushNotificationConfig)
466+ .build();
305467
306- ``` java
307- ListTaskPushNotificationConfigResponse response = client. listTaskPushNotificationConfig(" task-1234" );
468+ TaskPushNotificationConfig result = client. setTaskPushNotificationConfiguration(taskConfig);
308469
309- // Additional properties can be specified using a map
310- Map<String , Object > metadata = ...
311- ListTaskPushNotificationConfigResponse response = client. listTaskPushNotificationConfig(new ListTaskPushNotificationConfigParams (" task-123" , metadata));
470+ // You can also optionally specify a ClientCallContext with call-specific config to use
471+ TaskPushNotificationConfig result = client. setTaskPushNotificationConfiguration(taskConfig, clientCallContext);
312472```
313473
314- #### Delete a push notification configuration for a task
474+ #### List the push notification configurations for a task
315475
316476``` java
317- DeleteTaskPushNotificationConfigResponse response = client. deleteTaskPushNotificationConfig(" task-1234" , " config-4567" );
477+ List<TaskPushNotificationConfig > configs = client. listTaskPushNotificationConfigurations(
478+ new ListTaskPushNotificationConfigParams (" task-1234" ));
318479
319480// Additional properties can be specified using a map
320- Map<String , Object > metadata = ...
321- DeleteTaskPushNotificationConfigResponse response = client. deleteTaskPushNotificationConfig(new DeleteTaskPushNotificationConfigParams (" task-1234" , " config-4567" , metadata));
481+ Map<String , Object > metadata = Map . of(" filter" , " active" );
482+ List<TaskPushNotificationConfig > configs = client. listTaskPushNotificationConfigurations(
483+ new ListTaskPushNotificationConfigParams (" task-1234" , metadata));
484+
485+ // You can also optionally specify a ClientCallContext with call-specific config to use
486+ List<TaskPushNotificationConfig > configs = client. listTaskPushNotificationConfigurations(
487+ new ListTaskPushNotificationConfigParams (" task-1234" ), clientCallContext);
322488```
323489
324- #### Send a streaming message
490+ #### Delete a push notification configuration for a task
325491
326492``` java
327- // Send a text message to the remote agent
328- Message message = A2A . toUserMessage(" tell me some jokes" ); // the message ID will be automatically generated for you
329- MessageSendParams params = new MessageSendParams .Builder ()
330- .message(message)
331- .build();
332-
333- // Create a handler that will be invoked for Task, Message, TaskStatusUpdateEvent, and TaskArtifactUpdateEvent
334- Consumer<StreamingEventKind > eventHandler = event - > {... };
493+ client. deleteTaskPushNotificationConfigurations(
494+ new DeleteTaskPushNotificationConfigParams (" task-1234" , " config-4567" ));
335495
336- // Create a handler that will be invoked if an error is received
337- Consumer<JSONRPCError > errorHandler = error - > {... };
338-
339- // Create a handler that will be invoked in the event of a failure
340- Runnable failureHandler = () - > {... };
496+ // Additional properties can be specified using a map
497+ Map<String , Object > metadata = Map . of(" reason" , " cleanup" );
498+ client. deleteTaskPushNotificationConfigurations(
499+ new DeleteTaskPushNotificationConfigParams (" task-1234" , " config-4567" , metadata));
341500
342- // Send the streaming message to the remote agent
343- client. sendStreamingMessage(params, eventHandler, errorHandler, failureHandler);
501+ // You can also optionally specify a ClientCallContext with call-specific config to use
502+ client. deleteTaskPushNotificationConfigurations(
503+ new DeleteTaskPushNotificationConfigParams (" task-1234" , " config-4567" , clientCallContext);
344504```
345505
346506#### Resubscribe to a task
347507
348508```java
349- // Create a handler that will be invoked for Task, Message, TaskStatusUpdateEvent, and TaskArtifactUpdateEvent
350- Consumer<StreamingEventKind > eventHandler = event - > {... };
509+ // Resubscribe to an ongoing task with id "task-1234" using configured consumers
510+ TaskIdParams taskIdParams = new TaskIdParams (" task-1234" );
511+ client. resubscribe(taskIdParams);
351512
352- // Create a handler that will be invoked if an error is received
353- Consumer<JSONRPCError > errorHandler = error - > {... };
513+ // Or resubscribe with custom consumers and error handler
514+ List<BiConsumer<ClientEvent , AgentCard > > customConsumers = List . of(
515+ (event, card) - > System . out. println(" Resubscribe event: " + event)
516+ );
517+ Consumer<Throwable > customErrorHandler = error - >
518+ System . err. println(" Resubscribe error: " + error. getMessage());
354519
355- // Create a handler that will be invoked in the event of a failure
356- Runnable failureHandler = () - > {... };
520+ client. resubscribe(taskIdParams, customConsumers, customErrorHandler);
357521
358- // Resubscribe to an ongoing task with id "task-1234"
359- TaskIdParams taskIdParams = new TaskIdParams (" task-1234" );
360- client. resubscribeToTask(" request-1234" , taskIdParams, eventHandler, errorHandler, failureHandler);
522+ // You can also optionally specify a ClientCallContext with call-specific config to use
523+ client. resubscribe(taskIdParams, clientCallContext);
361524```
362525
363526#### Retrieve details about the server agent that this client agent is communicating with
364527```java
365528AgentCard serverAgentCard = client. getAgentCard();
366529```
367530
368- An agent card can also be retrieved using the ` A2A#getAgentCard ` method:
369- ``` java
370- // http://localhost:1234 is the base URL for the agent whose card we want to retrieve
371- AgentCard agentCard = A2A . getAgentCard(" http://localhost:1234" );
372- ```
373-
374531## Additional Examples
375532
376533### Hello World Client Example
0 commit comments