1313
1414import java .io .IOException ;
1515import java .util .Map ;
16+ import java .util .concurrent .CompletableFuture ;
17+ import java .util .concurrent .atomic .AtomicReference ;
1618import java .util .function .Consumer ;
1719
1820import com .fasterxml .jackson .core .JsonProcessingException ;
1921import com .fasterxml .jackson .core .type .TypeReference ;
2022import io .a2a .client .sse .SSEEventListener ;
23+ import io .a2a .http .A2AHttpClient ;
24+ import io .a2a .http .A2AHttpResponse ;
25+ import io .a2a .http .JdkA2AHttpClient ;
2126import io .a2a .spec .A2A ;
2227import io .a2a .spec .A2AServerException ;
2328import io .a2a .spec .AgentCard ;
4045import io .a2a .spec .TaskIdParams ;
4146import io .a2a .spec .TaskPushNotificationConfig ;
4247import io .a2a .spec .TaskQueryParams ;
43- import okhttp3 .MediaType ;
44- import okhttp3 .OkHttpClient ;
45- import okhttp3 .Request ;
46- import okhttp3 .RequestBody ;
47- import okhttp3 .Response ;
48- import okhttp3 .sse .EventSources ;
4948
5049/**
5150 * An A2A client.
@@ -57,8 +56,7 @@ public class A2AClient {
5756 private static final TypeReference <CancelTaskResponse > CANCEL_TASK_RESPONSE_REFERENCE = new TypeReference <>() {};
5857 private static final TypeReference <GetTaskPushNotificationConfigResponse > GET_TASK_PUSH_NOTIFICATION_CONFIG_RESPONSE_REFERENCE = new TypeReference <>() {};
5958 private static final TypeReference <SetTaskPushNotificationConfigResponse > SET_TASK_PUSH_NOTIFICATION_CONFIG_RESPONSE_REFERENCE = new TypeReference <>() {};
60- private static final MediaType JSON_MEDIA_TYPE = MediaType .parse ("application/json; charset=utf-8" );
61- private final OkHttpClient httpClient ;
59+ private final A2AHttpClient httpClient ;
6260 private final String agentUrl ;
6361 private AgentCard agentCard ;
6462
@@ -72,7 +70,7 @@ public A2AClient(AgentCard agentCard) {
7270 checkNotNullParam ("agentCard" , agentCard );
7371 this .agentCard = agentCard ;
7472 this .agentUrl = agentCard .url ();
75- this .httpClient = new OkHttpClient ();
73+ this .httpClient = new JdkA2AHttpClient ();
7674 }
7775
7876 /**
@@ -83,7 +81,7 @@ public A2AClient(AgentCard agentCard) {
8381 public A2AClient (String agentUrl ) {
8482 checkNotNullParam ("agentUrl" , agentUrl );
8583 this .agentUrl = agentUrl ;
86- this .httpClient = new OkHttpClient ();
84+ this .httpClient = new JdkA2AHttpClient ();
8785 }
8886
8987 /**
@@ -349,20 +347,6 @@ public SetTaskPushNotificationConfigResponse setTaskPushNotificationConfig(Strin
349347 }
350348 }
351349
352- /**
353- * Send a streaming message to the remote agent.
354- *
355- * @param messageSendParams the parameters for the message to be sent
356- * @param eventHandler a consumer that will be invoked for each event received from the remote agent
357- * @param errorHandler a consumer that will be invoked if the remote agent returns an error
358- * @param failureHandler a consumer that will be invoked if a failure occurs when processing events
359- * @throws A2AServerException if sending the streaming message fails for any reason
360- */
361- public void sendStreamingMessage (MessageSendParams messageSendParams , Consumer <StreamingEventKind > eventHandler ,
362- Consumer <JSONRPCError > errorHandler , Runnable failureHandler ) throws A2AServerException {
363- sendStreamingMessage (null , messageSendParams , eventHandler , errorHandler , failureHandler );
364- }
365-
366350 /**
367351 * Send a streaming message to the remote agent.
368352 *
@@ -374,7 +358,7 @@ public void sendStreamingMessage(MessageSendParams messageSendParams, Consumer<S
374358 * @throws A2AServerException if sending the streaming message fails for any reason
375359 */
376360 public void sendStreamingMessage (String requestId , MessageSendParams messageSendParams , Consumer <StreamingEventKind > eventHandler ,
377- Consumer <JSONRPCError > errorHandler , Runnable failureHandler ) throws A2AServerException {
361+ Consumer <JSONRPCError > errorHandler , Runnable failureHandler ) throws A2AServerException {
378362 checkNotNullParam ("messageSendParams" , messageSendParams );
379363 checkNotNullParam ("eventHandler" , eventHandler );
380364 checkNotNullParam ("errorHandler" , errorHandler );
@@ -389,52 +373,41 @@ public void sendStreamingMessage(String requestId, MessageSendParams messageSend
389373 sendStreamingMessageRequestBuilder .id (requestId );
390374 }
391375
376+ AtomicReference <CompletableFuture <Void >> ref = new AtomicReference <>();
377+ SSEEventListener sseEventListener = new SSEEventListener (eventHandler , errorHandler , failureHandler );
392378 SendStreamingMessageRequest sendStreamingMessageRequest = sendStreamingMessageRequestBuilder .build ();
393- SSEEventListener sseEventListener = new SSEEventListener .Builder ()
394- .eventHandler (eventHandler )
395- .errorHandler (errorHandler )
396- .failureHandler (failureHandler )
397- .build ();
398379 try {
399- EventSources .createFactory (httpClient )
400- .newEventSource (createPostRequest (sendStreamingMessageRequest ,
401- true ), sseEventListener );
380+ A2AHttpClient .PostBuilder builder = createPostBuilder (sendStreamingMessageRequest );
381+ ref .set (builder .postAsyncSSE (
382+ msg -> sseEventListener .onMessage (msg , ref .get ()),
383+ throwable -> sseEventListener .onError (throwable , ref .get ()),
384+ () -> {
385+ // We don't need to do anything special on completion
386+ }));
387+
402388 } catch (IOException e ) {
403389 throw new A2AServerException ("Failed to send streaming message request: " + e );
390+ } catch (InterruptedException e ) {
391+ throw new A2AServerException ("Send streaming message request timed out: " + e );
404392 }
405393 }
406394
407- private String sendPostRequest (Object value ) throws IOException , InterruptedException {
408- return sendPostRequest (value , false );
409- }
410-
411-
412- private String sendPostRequest (Object value , boolean addEventStreamHeader ) throws IOException , InterruptedException {
413- Request okRequest = createPostRequest (value , addEventStreamHeader );
414- try (Response response = httpClient .newCall (okRequest ).execute ()) {
415- if (! response .isSuccessful ()) {
416- throw new IOException ("Request failed " + response .code ());
417- }
418- return response .body ().string ();
395+ private String sendPostRequest (Object value ) throws IOException , InterruptedException {
396+ A2AHttpClient .PostBuilder builder = createPostBuilder (value );
397+ A2AHttpResponse response = builder .post ();
398+ if (!response .success ()) {
399+ throw new IOException ("Request failed " + response .status ());
419400 }
420-
401+ return response . body ();
421402 }
422403
423- private Request createPostRequest (Object value ) throws IOException {
424- return createPostRequest (value , false );
425- }
426-
427- private Request createPostRequest (Object value , boolean addEventStreamHeader ) throws IOException {
428- Request .Builder builder = new Request .Builder ()
404+ private A2AHttpClient .PostBuilder createPostBuilder (Object value ) throws JsonProcessingException {
405+ return httpClient .createPost ()
429406 .url (agentUrl )
430407 .addHeader ("Content-Type" , "application/json" )
431- .post (RequestBody .create (OBJECT_MAPPER .writeValueAsString (value ), JSON_MEDIA_TYPE ));
432- if (addEventStreamHeader ) {
433- builder .addHeader ("Accept" , "text/event-stream" );
434- }
435- return builder .build ();
436- }
408+ .body (OBJECT_MAPPER .writeValueAsString (value ));
437409
410+ }
438411
439412 private <T extends JSONRPCResponse > T unmarshalResponse (String response , TypeReference <T > typeReference )
440413 throws A2AServerException , JsonProcessingException {
0 commit comments