From 9426c9dfd5484482a6e0a25a4c2a4f0b9b8c47f3 Mon Sep 17 00:00:00 2001 From: Mark Daoust Date: Fri, 27 Mar 2026 09:26:42 -0700 Subject: [PATCH] feat: make stream_handler_executor publicly settable. PiperOrigin-RevId: 890494216 --- src/main/java/com/google/genai/ApiClient.java | 16 ++++----- .../com/google/genai/types/ClientOptions.java | 25 +++++++++++++ .../com/google/genai/HttpApiClientTest.java | 36 ++++++++++++++++++- 3 files changed, 67 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/google/genai/ApiClient.java b/src/main/java/com/google/genai/ApiClient.java index a59c505c677..8658122c39d 100644 --- a/src/main/java/com/google/genai/ApiClient.java +++ b/src/main/java/com/google/genai/ApiClient.java @@ -404,15 +404,13 @@ private com.google.genai.interactions.core.ClientOptions createInteractionsClien .baseUrl(httpOptions.baseUrl()) .apiKey(apiKey); - // BEGIN_SDK_PRIVATE_ONLY - // clientOptions - // .flatMap(ClientOptions::streamHandlerExecutor) - // .ifPresent( - // streamHandlerExecutor -> { - // com.google.genai.interactions.core.ClientOptions.Builder unused = - // builder.streamHandlerExecutor(streamHandlerExecutor); - // }); - // END_SDK_PRIVATE_ONLY + clientOptions + .flatMap(ClientOptions::streamHandlerExecutor) + .ifPresent( + streamHandlerExecutor -> { + com.google.genai.interactions.core.ClientOptions.Builder unused = + builder.streamHandlerExecutor(streamHandlerExecutor); + }); httpOptions .apiVersion() diff --git a/src/main/java/com/google/genai/types/ClientOptions.java b/src/main/java/com/google/genai/types/ClientOptions.java index f6827d7a83b..f64ec728a0a 100644 --- a/src/main/java/com/google/genai/types/ClientOptions.java +++ b/src/main/java/com/google/genai/types/ClientOptions.java @@ -19,12 +19,14 @@ package com.google.genai.types; import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.google.auto.value.AutoValue; import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.genai.JsonSerializable; import java.util.Optional; +import java.util.concurrent.Executor; /** Client options to be used in the client instantiation. */ @AutoValue @@ -42,6 +44,10 @@ public abstract class ClientOptions extends JsonSerializable { @JsonProperty("proxyOptions") public abstract Optional proxyOptions(); + /** EXPERIMENTAL the executor to use for running async stream handler callbacks. */ + @JsonIgnore + public abstract Optional streamHandlerExecutor(); + /** Instantiates a builder for ClientOptions. */ @ExcludeFromGeneratedCoverageReport public static Builder builder() { @@ -124,6 +130,25 @@ public Builder clearProxyOptions() { return proxyOptions(Optional.empty()); } + /** + * Setter for streamHandlerExecutor. + * + *

streamHandlerExecutor: EXPERIMENTAL the executor to use for running async stream handler + * callbacks. + */ + @JsonIgnore + public abstract Builder streamHandlerExecutor(Executor streamHandlerExecutor); + + @ExcludeFromGeneratedCoverageReport + abstract Builder streamHandlerExecutor(Optional streamHandlerExecutor); + + /** Clears the value of streamHandlerExecutor field. */ + @ExcludeFromGeneratedCoverageReport + @CanIgnoreReturnValue + public Builder clearStreamHandlerExecutor() { + return streamHandlerExecutor(Optional.empty()); + } + public abstract ClientOptions build(); } diff --git a/src/test/java/com/google/genai/HttpApiClientTest.java b/src/test/java/com/google/genai/HttpApiClientTest.java index 1b801fd0b73..ac55c01e3b4 100644 --- a/src/test/java/com/google/genai/HttpApiClientTest.java +++ b/src/test/java/com/google/genai/HttpApiClientTest.java @@ -1714,7 +1714,41 @@ public void testCloseClient() { assertTrue(client.httpClient().dispatcher().executorService().isShutdown()); assertEquals(0, client.httpClient().connectionPool().connectionCount()); if (client.interactionsClientOptions.streamHandlerExecutor() instanceof ExecutorService) { - assertTrue(((ExecutorService) client.interactionsClientOptions.streamHandlerExecutor()).isShutdown()); + assertTrue( + ((ExecutorService) client.interactionsClientOptions.streamHandlerExecutor()) + .isShutdown()); } } + + @Test + public void testCloseClient_withExecutorService() { + ExecutorService customExecutor = java.util.concurrent.Executors.newSingleThreadExecutor(); + HttpApiClient client = + new HttpApiClient( + Optional.empty(), + Optional.of(PROJECT), + Optional.of(LOCATION), + Optional.of(CREDENTIALS), + Optional.empty(), + Optional.of(ClientOptions.builder().streamHandlerExecutor(customExecutor).build())); + + client.close(); + + assertTrue(customExecutor.isShutdown()); + } + + @Test + public void testStreamHandlerExecutorPassthrough() { + java.util.concurrent.Executor customExecutor = Runnable::run; + HttpApiClient client = + new HttpApiClient( + Optional.empty(), + Optional.of(PROJECT), + Optional.of(LOCATION), + Optional.of(CREDENTIALS), + Optional.empty(), + Optional.of(ClientOptions.builder().streamHandlerExecutor(customExecutor).build())); + + assertEquals(customExecutor, client.interactionsClientOptions.streamHandlerExecutor()); + } }