diff --git a/src/main/java/com/google/genai/ApiClient.java b/src/main/java/com/google/genai/ApiClient.java index 0a88ed467c9..3a2e3dc8437 100644 --- a/src/main/java/com/google/genai/ApiClient.java +++ b/src/main/java/com/google/genai/ApiClient.java @@ -223,6 +223,7 @@ private OkHttpClient createHttpClient( builder.connectTimeout(Duration.ofMillis(0)); builder.readTimeout(Duration.ofMillis(0)); builder.writeTimeout(Duration.ofMillis(0)); + builder.callTimeout(Duration.ofMillis(0)); timeout.ifPresent(connectTimeout -> builder.connectTimeout(Duration.ofMillis(connectTimeout))); @@ -232,6 +233,11 @@ private OkHttpClient createHttpClient( options.maxConnections().ifPresent(dispatcher::setMaxRequests); options.maxConnectionsPerHost().ifPresent(dispatcher::setMaxRequestsPerHost); builder.dispatcher(dispatcher); + + // Apply timeout configurations from ClientOptions + options.readTimeout().ifPresent(rt -> builder.readTimeout(Duration.ofMillis(rt))); + options.writeTimeout().ifPresent(wt -> builder.writeTimeout(Duration.ofMillis(wt))); + options.callTimeout().ifPresent(ct -> builder.callTimeout(Duration.ofMillis(ct))); }); return builder.build(); diff --git a/src/main/java/com/google/genai/types/ClientOptions.java b/src/main/java/com/google/genai/types/ClientOptions.java index 245d93d9d1a..27843f0f106 100644 --- a/src/main/java/com/google/genai/types/ClientOptions.java +++ b/src/main/java/com/google/genai/types/ClientOptions.java @@ -37,6 +37,18 @@ public abstract class ClientOptions extends JsonSerializable { @JsonProperty("maxConnectionsPerHost") public abstract Optional maxConnectionsPerHost(); + /** Read timeout in milliseconds. */ + @JsonProperty("readTimeout") + public abstract Optional readTimeout(); + + /** Write timeout in milliseconds. */ + @JsonProperty("writeTimeout") + public abstract Optional writeTimeout(); + + /** Call timeout in milliseconds. */ + @JsonProperty("callTimeout") + public abstract Optional callTimeout(); + /** Instantiates a builder for ClientOptions. */ @ExcludeFromGeneratedCoverageReport public static Builder builder() { @@ -71,6 +83,30 @@ private static Builder create() { @JsonProperty("maxConnectionsPerHost") public abstract Builder maxConnectionsPerHost(Integer maxConnectionsPerHost); + /** + * Setter for readTimeout. + * + *

readTimeout: Read timeout in milliseconds. + */ + @JsonProperty("readTimeout") + public abstract Builder readTimeout(Integer readTimeout); + + /** + * Setter for writeTimeout. + * + *

writeTimeout: Write timeout in milliseconds. + */ + @JsonProperty("writeTimeout") + public abstract Builder writeTimeout(Integer writeTimeout); + + /** + * Setter for callTimeout. + * + *

callTimeout: Call timeout in milliseconds. + */ + @JsonProperty("callTimeout") + public abstract Builder callTimeout(Integer callTimeout); + 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 bbbd91a50a4..809bde344f9 100644 --- a/src/test/java/com/google/genai/HttpApiClientTest.java +++ b/src/test/java/com/google/genai/HttpApiClientTest.java @@ -1013,6 +1013,99 @@ public void testHttpClientMldevDefaultClientOptions() throws Exception { assertFalse(client.vertexAI()); } + @Test + public void testHttpClientMldevWithTimeoutSettings() throws Exception { + ClientOptions clientOptions = + ClientOptions.builder() + .readTimeout(5000) + .writeTimeout(10000) + .callTimeout(15000) + .build(); + HttpApiClient client = + new HttpApiClient(Optional.of(API_KEY), Optional.empty(), Optional.of(clientOptions)); + + OkHttpClient httpClient = client.httpClient(); + + assertEquals(API_KEY, client.apiKey()); + assertFalse(client.vertexAI()); + assertEquals(5000, httpClient.readTimeoutMillis()); + assertEquals(10000, httpClient.writeTimeoutMillis()); + assertEquals(15000, httpClient.callTimeoutMillis()); + } + + @Test + public void testHttpClientVertexWithTimeoutSettings() throws Exception { + ClientOptions clientOptions = + ClientOptions.builder() + .readTimeout(3000) + .writeTimeout(6000) + .callTimeout(9000) + .build(); + HttpApiClient client = + new HttpApiClient( + Optional.empty(), + Optional.of(PROJECT), + Optional.of(LOCATION), + Optional.of(CREDENTIALS), + Optional.empty(), + Optional.of(clientOptions)); + + OkHttpClient httpClient = client.httpClient(); + + assertEquals(PROJECT, client.project()); + assertEquals(LOCATION, client.location()); + assertTrue(client.vertexAI()); + assertEquals(3000, httpClient.readTimeoutMillis()); + assertEquals(6000, httpClient.writeTimeoutMillis()); + assertEquals(9000, httpClient.callTimeoutMillis()); + } + + @Test + public void testHttpClientWithPartialTimeoutSettings() throws Exception { + ClientOptions clientOptions = + ClientOptions.builder() + .readTimeout(5000) + .build(); + HttpApiClient client = + new HttpApiClient(Optional.of(API_KEY), Optional.empty(), Optional.of(clientOptions)); + + OkHttpClient httpClient = client.httpClient(); + + assertEquals(API_KEY, client.apiKey()); + assertFalse(client.vertexAI()); + assertEquals(5000, httpClient.readTimeoutMillis()); + // When not set, timeouts should remain at default 0 (no timeout) + assertEquals(0, httpClient.writeTimeoutMillis()); + assertEquals(0, httpClient.callTimeoutMillis()); + } + + @Test + public void testHttpClientWithAllClientOptionsIncludingTimeouts() throws Exception { + ClientOptions clientOptions = + ClientOptions.builder() + .maxConnections(32) + .maxConnectionsPerHost(8) + .readTimeout(2000) + .writeTimeout(4000) + .callTimeout(8000) + .build(); + HttpApiClient client = + new HttpApiClient(Optional.of(API_KEY), Optional.empty(), Optional.of(clientOptions)); + + OkHttpClient httpClient = client.httpClient(); + Dispatcher dispatcher = httpClient.dispatcher(); + + assertEquals(API_KEY, client.apiKey()); + assertFalse(client.vertexAI()); + // Test dispatcher settings + assertEquals(32, dispatcher.getMaxRequests()); + assertEquals(8, dispatcher.getMaxRequestsPerHost()); + // Test timeout settings + assertEquals(2000, httpClient.readTimeoutMillis()); + assertEquals(4000, httpClient.writeTimeoutMillis()); + assertEquals(8000, httpClient.callTimeoutMillis()); + } + @Test public void testHttpClientWithCustomCredentials() throws Exception { HttpApiClient client =