getVersion()` reads
-- [ ] Add a `breaksApplied(...)` step to any hand-built `SpeakV2SpeechMetadataControlsApplied` — pass `0`, since inline pause controls are not applied at launch (read paths need no change)
+- [ ] Add a `breaksApplied(...)` step to any hand-built `SpeakV2SpeechMetadataControlsApplied` — use `0` when reproducing the v0.8 launch payload shape (read paths need no change)
- [ ] Rebuild your project and fix any remaining references to the changed signatures
- [ ] (Optional) Adopt Speak V2 interrupt/configure, Listen V2 `redact`, client retry tuning, and the new Flux voices
-```
\ No newline at end of file
+```
diff --git a/examples/speak/FluxTtsControls.java b/examples/speak/FluxTtsControls.java
new file mode 100644
index 00000000..333c9805
--- /dev/null
+++ b/examples/speak/FluxTtsControls.java
@@ -0,0 +1,59 @@
+import com.deepgram.DeepgramClient;
+import com.deepgram.resources.speak.v2.audio.requests.SpeakV2Request;
+import com.deepgram.resources.speak.v2.audio.types.AudioGenerateRequestEncoding;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+
+/**
+ * Generates Flux TTS batch audio with pause and pronunciation controls.
+ *
+ * Usage: {@code java FluxTtsControls [output-directory]}
+ *
+ *
Pause and pronunciation controls cannot be combined in the same Flux TTS request. This example sends them
+ * separately.
+ */
+public class FluxTtsControls {
+ private static final String MODEL = "flux-alexis-en";
+
+ public static void main(String[] args) {
+ String apiKey = System.getenv("DEEPGRAM_API_KEY");
+ if (apiKey == null || apiKey.isEmpty()) {
+ System.err.println("DEEPGRAM_API_KEY environment variable is required");
+ System.exit(1);
+ }
+
+ Path outputDirectory = args.length == 1 ? Path.of(args[0]) : Path.of(".");
+
+ try (DeepgramClient client = DeepgramClient.builder().apiKey(apiKey).build()) {
+ Files.createDirectories(outputDirectory);
+
+ generate(
+ client,
+ "Your confirmation number is four seven two. \\{pause:500ms\\} Is there anything else I can help with?",
+ outputDirectory.resolve("flux-pause.mp3"));
+ generate(
+ client,
+ "Take \\{\"word\": \"dupilumab\", \"pronounce\": \"duːˈpɪljuːmæb\"\\} twice daily.",
+ outputDirectory.resolve("flux-pronunciation.mp3"));
+ } catch (Exception e) {
+ System.err.println("Error generating Flux TTS Controls audio: " + e.getMessage());
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+
+ private static void generate(DeepgramClient client, String text, Path outputPath) throws Exception {
+ SpeakV2Request request = SpeakV2Request.builder()
+ .model(MODEL)
+ .text(text)
+ .encoding(AudioGenerateRequestEncoding.MP3)
+ .build();
+
+ try (InputStream audio = client.speak().v2().audio().generate(request)) {
+ long bytes = Files.copy(audio, outputPath, StandardCopyOption.REPLACE_EXISTING);
+ System.out.printf("Audio saved to %s (%d bytes)%n", outputPath, bytes);
+ }
+ }
+}
diff --git a/src/main/java/com/deepgram/AsyncDeepgramApiClient.java b/src/main/java/com/deepgram/AsyncDeepgramApiClient.java
index c2aa87ee..0ae6c114 100644
--- a/src/main/java/com/deepgram/AsyncDeepgramApiClient.java
+++ b/src/main/java/com/deepgram/AsyncDeepgramApiClient.java
@@ -79,8 +79,9 @@ public AsyncVoiceAgentClient voiceAgent() {
}
/**
- * Releases resources owned by this client. See {@code ClientOptions.close()} for what is
- * and is not released.
+ * Releases resources owned by this client: any WebSocket clients still connected through
+ * it are disconnected first, then the SDK-owned HTTP client is shut down. See
+ * {@code ClientOptions.close()} for what is and is not released.
*/
@Override
public void close() {
diff --git a/src/main/java/com/deepgram/DeepgramApiClient.java b/src/main/java/com/deepgram/DeepgramApiClient.java
index ccb0d4a7..a67528ff 100644
--- a/src/main/java/com/deepgram/DeepgramApiClient.java
+++ b/src/main/java/com/deepgram/DeepgramApiClient.java
@@ -79,8 +79,9 @@ public VoiceAgentClient voiceAgent() {
}
/**
- * Releases resources owned by this client. See {@code ClientOptions.close()} for what is
- * and is not released.
+ * Releases resources owned by this client: any WebSocket clients still connected through
+ * it are disconnected first, then the SDK-owned HTTP client is shut down. See
+ * {@code ClientOptions.close()} for what is and is not released.
*/
@Override
public void close() {
diff --git a/src/main/java/com/deepgram/core/ClientOptions.java b/src/main/java/com/deepgram/core/ClientOptions.java
index 5329810c..828cc2b5 100644
--- a/src/main/java/com/deepgram/core/ClientOptions.java
+++ b/src/main/java/com/deepgram/core/ClientOptions.java
@@ -3,10 +3,14 @@
*/
package com.deepgram.core;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
import okhttp3.OkHttpClient;
@@ -21,6 +25,10 @@ public final class ClientOptions {
private final boolean ownsHttpClient;
+ private final AtomicBoolean closed;
+
+ private final Set openWebSockets;
+
private final int timeout;
private final int maxRetries;
@@ -41,6 +49,8 @@ private ClientOptions(
Map> headerSuppliers,
OkHttpClient httpClient,
boolean ownsHttpClient,
+ AtomicBoolean closed,
+ Set openWebSockets,
int timeout,
int maxRetries,
Optional initialRetryDelayMillis,
@@ -62,6 +72,8 @@ private ClientOptions(
this.headerSuppliers = headerSuppliers;
this.httpClient = httpClient;
this.ownsHttpClient = ownsHttpClient;
+ this.closed = closed;
+ this.openWebSockets = openWebSockets;
this.timeout = timeout;
this.maxRetries = maxRetries;
this.initialRetryDelayMillis = initialRetryDelayMillis;
@@ -132,12 +144,29 @@ public Optional retryJitterFactor() {
* OkHttpClient itself; an OkHttpClient supplied via httpClient is left running, since the
* caller owns its lifecycle.
*
- * In-flight calls are not cancelled or awaited. Later asynchronous requests fail when the
- * dispatcher rejects work, while synchronous requests may still run. Options derived from this
- * one via {@code Builder.from(...)} share the same dispatcher and connection pool, so closing
- * either releases them for both. Calling this method more than once has no further effect.
+ * In-flight calls are not cancelled or awaited. When this client owns its OkHttpClient, later
+ * asynchronous HTTP requests can fail when the dispatcher rejects work, while synchronous
+ * requests may still run. An OkHttpClient supplied through {@code httpClient(...)} remains
+ * caller-owned and running. Options derived via {@code Builder.from(...)} share lifecycle
+ * state; calling this method more than once has no further effect.
+ *
+ * WebSocket clients created from this client that are still connected are disconnected
+ * first (whether or not the OkHttpClient is owned), so they stop reconnecting before the
+ * dispatcher goes away. Any WebSocket connect or reconnect attempted afterwards fails with
+ * an {@code IllegalStateException} explaining that the client has been closed.
*/
public void close() {
+ if (!this.closed.compareAndSet(false, true)) {
+ return;
+ }
+ for (AutoCloseable webSocket : new ArrayList<>(this.openWebSockets)) {
+ try {
+ webSocket.close();
+ } catch (Exception e) {
+ // best effort; keep closing the remaining sockets and the HTTP client
+ }
+ }
+ this.openWebSockets.clear();
if (!this.ownsHttpClient) {
return;
}
@@ -145,6 +174,33 @@ public void close() {
this.httpClient.connectionPool().evictAll();
}
+ /**
+ * Returns whether {@link #close()} has been called on this client.
+ */
+ public boolean isClosed() {
+ return this.closed.get();
+ }
+
+ /**
+ * Tracks a connected WebSocket client so that {@link #close()} disconnects it.
+ *
+ * @throws IllegalStateException if this client has already been closed
+ */
+ public void registerWebSocket(AutoCloseable webSocket) {
+ this.openWebSockets.add(webSocket);
+ if (this.closed.get()) {
+ this.openWebSockets.remove(webSocket);
+ throw new IllegalStateException("root client has been closed");
+ }
+ }
+
+ /**
+ * Stops tracking a WebSocket client that has been disconnected.
+ */
+ public void unregisterWebSocket(AutoCloseable webSocket) {
+ this.openWebSockets.remove(webSocket);
+ }
+
public Optional webSocketFactory() {
return this.webSocketFactory;
}
@@ -178,6 +234,10 @@ public static class Builder {
private boolean ownsHttpClient = true;
+ private AtomicBoolean closed;
+
+ private Set openWebSockets;
+
private Optional logging = Optional.empty();
private Optional webSocketFactory = Optional.empty();
@@ -303,12 +363,18 @@ public ClientOptions build() {
this.httpClient = httpClientBuilder.build();
this.timeout = Optional.of(httpClient.callTimeoutMillis() / 1000);
+ AtomicBoolean closedToUse = this.closed != null ? this.closed : new AtomicBoolean(false);
+ Set openWebSocketsToUse =
+ this.openWebSockets != null ? this.openWebSockets : ConcurrentHashMap.newKeySet();
+
return new ClientOptions(
environment,
headers,
headerSuppliers,
httpClient,
this.ownsHttpClient,
+ closedToUse,
+ openWebSocketsToUse,
this.timeout.get(),
this.maxRetries,
this.initialRetryDelayMillis,
@@ -327,6 +393,8 @@ public static Builder from(ClientOptions clientOptions) {
builder.timeout = Optional.of(clientOptions.timeout(null));
builder.httpClient = clientOptions.httpClient();
builder.ownsHttpClient = clientOptions.ownsHttpClient;
+ builder.closed = clientOptions.closed;
+ builder.openWebSockets = clientOptions.openWebSockets;
builder.headers.putAll(clientOptions.headers);
builder.headerSuppliers.putAll(clientOptions.headerSuppliers);
builder.maxRetries = clientOptions.maxRetries();
diff --git a/src/main/java/com/deepgram/core/OkHttpWebSocketFactory.java b/src/main/java/com/deepgram/core/OkHttpWebSocketFactory.java
index 70e6c868..30653bcf 100644
--- a/src/main/java/com/deepgram/core/OkHttpWebSocketFactory.java
+++ b/src/main/java/com/deepgram/core/OkHttpWebSocketFactory.java
@@ -3,6 +3,7 @@
*/
package com.deepgram.core;
+import java.util.function.BooleanSupplier;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.WebSocket;
@@ -15,17 +16,38 @@
public final class OkHttpWebSocketFactory implements WebSocketFactory {
private final OkHttpClient okHttpClient;
+ private final BooleanSupplier closedCheck;
+
/**
* Creates a new OkHttpWebSocketFactory with the specified OkHttpClient.
*
* @param okHttpClient The OkHttpClient instance to use for creating WebSockets
*/
public OkHttpWebSocketFactory(OkHttpClient okHttpClient) {
+ this(okHttpClient, () -> false);
+ }
+
+ /**
+ * Creates a new OkHttpWebSocketFactory that refuses to open WebSockets once the owning
+ * client has been closed.
+ *
+ * @param okHttpClient The OkHttpClient instance to use for creating WebSockets
+ * @param closedCheck Returns true once the owning client has been closed (e.g.
+ * {@code clientOptions::isClosed})
+ */
+ public OkHttpWebSocketFactory(OkHttpClient okHttpClient, BooleanSupplier closedCheck) {
this.okHttpClient = okHttpClient;
+ this.closedCheck = closedCheck;
}
+ /**
+ * @throws IllegalStateException if the owning client has been closed
+ */
@Override
public WebSocket create(Request request, WebSocketListener listener) {
+ if (closedCheck.getAsBoolean()) {
+ throw new IllegalStateException("root client has been closed");
+ }
return okHttpClient.newWebSocket(request, listener);
}
}
diff --git a/src/main/java/com/deepgram/core/ReconnectingWebSocketListener.java b/src/main/java/com/deepgram/core/ReconnectingWebSocketListener.java
index 7f6d9df6..294316bb 100644
--- a/src/main/java/com/deepgram/core/ReconnectingWebSocketListener.java
+++ b/src/main/java/com/deepgram/core/ReconnectingWebSocketListener.java
@@ -14,6 +14,7 @@
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import java.util.function.Supplier;
import okhttp3.Response;
@@ -49,6 +50,8 @@ public abstract class ReconnectingWebSocketListener extends WebSocketListener {
private final Supplier extends WebSocket> connectionSupplier;
+ private final BooleanSupplier closedCheck;
+
/**
* Creates a new reconnecting WebSocket listener.
*
@@ -57,9 +60,26 @@ public abstract class ReconnectingWebSocketListener extends WebSocketListener {
*/
public ReconnectingWebSocketListener(
ReconnectingWebSocketListener.ReconnectOptions options, Supplier extends WebSocket> connectionSupplier) {
+ this(options, connectionSupplier, () -> false);
+ }
+
+ /**
+ * Creates a new reconnecting WebSocket listener.
+ *
+ * @param options Reconnection configuration options
+ * @param connectionSupplier Supplier that creates new WebSocket connections
+ * @param closedCheck Returns true once the owning client has been closed; connect and
+ * reconnect attempts made after that point fail with an {@link IllegalStateException}
+ * instead of being retried
+ */
+ public ReconnectingWebSocketListener(
+ ReconnectingWebSocketListener.ReconnectOptions options,
+ Supplier extends WebSocket> connectionSupplier,
+ BooleanSupplier closedCheck) {
this.activeOptions = options;
this.maxEnqueuedMessages = options.maxEnqueuedMessages;
this.connectionSupplier = connectionSupplier;
+ this.closedCheck = closedCheck;
}
/**
@@ -85,11 +105,18 @@ public void applyOptionsOverride(ReconnectOptions options) {
* - TimeoutException: Includes retry attempt context
* - InterruptedException: Preserves thread interruption status
* - ExecutionException: Extracts actual cause and adds context
+ * - Owning client closed: reports an IllegalStateException once and stops reconnecting
*/
public void connect() {
if (!connectLock.compareAndSet(false, true)) {
return;
}
+ if (closedCheck.getAsBoolean()) {
+ shouldReconnect.set(false);
+ connectLock.set(false);
+ onWebSocketFailure(null, new IllegalStateException("root client has been closed"), null);
+ return;
+ }
ReconnectOptions options = this.activeOptions;
if (retryCount.get() > options.maxRetries) {
connectLock.set(false);
@@ -391,10 +418,10 @@ protected boolean shouldReconnectAfterClose(WebSocket webSocket, int code, Strin
* - 2+ = exponential backoff up to maxReconnectionDelayMs
*/
private long getNextDelay() {
- ReconnectOptions options = this.activeOptions;
if (retryCount.get() == 1) {
- return options.minReconnectionDelayMs;
+ return activeOptions.minReconnectionDelayMs;
}
+ ReconnectOptions options = this.activeOptions;
long delay = (long)
(options.minReconnectionDelayMs * Math.pow(options.reconnectionDelayGrowFactor, retryCount.get() - 1));
return Math.min(delay, options.maxReconnectionDelayMs);
@@ -403,8 +430,13 @@ private long getNextDelay() {
/**
* Schedules a reconnection attempt with appropriate delay.
* Increments retry count and uses exponential backoff.
+ * Does nothing once the owning client has been closed.
*/
private void scheduleReconnect() {
+ if (closedCheck.getAsBoolean()) {
+ shouldReconnect.set(false);
+ return;
+ }
retryCount.incrementAndGet();
long delay = getNextDelay();
reconnectExecutor.schedule(this::connect, delay, MILLISECONDS);
diff --git a/src/main/java/com/deepgram/core/RetryInterceptor.java b/src/main/java/com/deepgram/core/RetryInterceptor.java
index a0959bbc..aad032cd 100644
--- a/src/main/java/com/deepgram/core/RetryInterceptor.java
+++ b/src/main/java/com/deepgram/core/RetryInterceptor.java
@@ -10,9 +10,13 @@
import java.time.format.DateTimeParseException;
import java.util.Optional;
import java.util.Random;
+import okhttp3.Call;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
+import okhttp3.ResponseBody;
+import okio.AsyncTimeout;
+import okio.Timeout;
public class RetryInterceptor implements Interceptor {
@@ -78,13 +82,28 @@ private Response retryChain(Response response, Chain chain, int maxRetries) thro
ExponentialBackoff backoff = new ExponentialBackoff(maxRetries);
Optional nextBackoff = backoff.nextBackoff(response);
while (nextBackoff.isPresent()) {
+ response = bufferResponse(response);
+ Optional callTimeout = suspendCallTimeout(chain);
try {
Thread.sleep(nextBackoff.get().toMillis());
} catch (InterruptedException e) {
+ response.close();
throw new IOException("Interrupted while trying request", e);
+ } finally {
+ callTimeout.ifPresent(AsyncTimeout::enter);
+ }
+ Response nextResponse;
+ try {
+ nextResponse = chain.proceed(chain.request());
+ } catch (IOException e) {
+ // A retry attempt failed with a transport error (connection reset, unreachable host, ...). The
+ // error is intentionally dropped: the response already received from the API is more actionable.
+ // Note that a call-timeout expiry or an explicit cancel() also ends up here, but OkHttp then
+ // discards whatever the interceptor chain returns and reports the cancellation itself.
+ return response;
}
response.close();
- response = chain.proceed(chain.request());
+ response = nextResponse;
if (shouldRetry(response.code())) {
nextBackoff = backoff.nextBackoff(response);
} else {
@@ -95,6 +114,51 @@ private Response retryChain(Response response, Chain chain, int maxRetries) thro
return response;
}
+ /**
+ * Pauses the OkHttp call timeout so that it applies to each attempt individually rather than to the whole
+ * retry loop: the backoff wait (e.g. a {@code Retry-After} the size of the call timeout) does not consume the
+ * budget of the next attempt, and each attempt starts with a fresh budget once {@link AsyncTimeout#enter()}
+ * is called again.
+ *
+ * {@link AsyncTimeout#exit()} and {@link AsyncTimeout#enter()} must stay strictly paired: {@code exit()} on
+ * a timeout that is not armed is a no-op, but {@code enter()} on one that is already armed throws
+ * {@code IllegalStateException}. Every caller must re-enter the returned timeout exactly once, on all paths.
+ */
+ private static Optional suspendCallTimeout(Chain chain) {
+ Call call = chain.call();
+ if (call == null) {
+ return Optional.empty();
+ }
+ Timeout timeout = call.timeout();
+ if (!(timeout instanceof AsyncTimeout)) {
+ return Optional.empty();
+ }
+ AsyncTimeout callTimeout = (AsyncTimeout) timeout;
+ callTimeout.exit();
+ return Optional.of(callTimeout);
+ }
+
+ /**
+ * Reads the body into memory so the response stays usable after the underlying connection
+ * is released or cancelled by a later attempt.
+ */
+ private static Response bufferResponse(Response response) {
+ ResponseBody body = response.body();
+ if (body == null) {
+ return response;
+ }
+ try {
+ byte[] bytes = body.bytes();
+ Response buffered = response.newBuilder()
+ .body(ResponseBody.create(bytes, body.contentType()))
+ .build();
+ response.close();
+ return buffered;
+ } catch (IOException e) {
+ return response;
+ }
+ }
+
/**
* Calculates the retry delay from response headers, with fallback to exponential backoff.
* Priority: Retry-After > X-RateLimit-Reset > Exponential Backoff
diff --git a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1AgentAudioDone.java b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1AgentAudioDone.java
index b6ee9000..5962f4bf 100644
--- a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1AgentAudioDone.java
+++ b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1AgentAudioDone.java
@@ -3,8 +3,6 @@
*/
package com.deepgram.resources.agent.v1.types;
-// Manual patch - see .fernignore.
-
import com.deepgram.core.ObjectMappers;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
diff --git a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ForceEndTurn.java b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ForceEndTurn.java
index 11d0d8d0..9bd5f769 100644
--- a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ForceEndTurn.java
+++ b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ForceEndTurn.java
@@ -3,8 +3,6 @@
*/
package com.deepgram.resources.agent.v1.types;
-// Manual patch - see .fernignore.
-
import com.deepgram.core.ObjectMappers;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
diff --git a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1KeepAlive.java b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1KeepAlive.java
index 588aad18..f82f59ee 100644
--- a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1KeepAlive.java
+++ b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1KeepAlive.java
@@ -3,8 +3,6 @@
*/
package com.deepgram.resources.agent.v1.types;
-// Manual patch - see .fernignore.
-
import com.deepgram.core.ObjectMappers;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
diff --git a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ListenUpdated.java b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ListenUpdated.java
index 3de75ec5..43b8628b 100644
--- a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ListenUpdated.java
+++ b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ListenUpdated.java
@@ -3,8 +3,6 @@
*/
package com.deepgram.resources.agent.v1.types;
-// Manual patch - see .fernignore.
-
import com.deepgram.core.ObjectMappers;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
diff --git a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1PromptUpdated.java b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1PromptUpdated.java
index 2b2f7946..e6efced0 100644
--- a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1PromptUpdated.java
+++ b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1PromptUpdated.java
@@ -3,8 +3,6 @@
*/
package com.deepgram.resources.agent.v1.types;
-// Manual patch - see .fernignore.
-
import com.deepgram.core.ObjectMappers;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
diff --git a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SettingsAgentContextListenProvider.java b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SettingsAgentContextListenProvider.java
index 1c21ce70..393f1f91 100644
--- a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SettingsAgentContextListenProvider.java
+++ b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SettingsAgentContextListenProvider.java
@@ -3,8 +3,6 @@
*/
package com.deepgram.resources.agent.v1.types;
-// Manual patch - see .fernignore.
-
import com.deepgram.types.DeepgramListenProviderV1;
import com.deepgram.types.DeepgramListenProviderV2;
import com.fasterxml.jackson.annotation.JsonCreator;
diff --git a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SettingsAgentListenProvider.java b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SettingsAgentListenProvider.java
index 06e47e60..345ba2f3 100644
--- a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SettingsAgentListenProvider.java
+++ b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SettingsAgentListenProvider.java
@@ -3,8 +3,6 @@
*/
package com.deepgram.resources.agent.v1.types;
-// Manual patch - see .fernignore.
-
import com.deepgram.types.DeepgramListenProviderV1;
import com.deepgram.types.DeepgramListenProviderV2;
import com.fasterxml.jackson.annotation.JsonCreator;
diff --git a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SettingsApplied.java b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SettingsApplied.java
index 443c2148..ad1fdb2f 100644
--- a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SettingsApplied.java
+++ b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SettingsApplied.java
@@ -3,8 +3,6 @@
*/
package com.deepgram.resources.agent.v1.types;
-// Manual patch - see .fernignore.
-
import com.deepgram.core.ObjectMappers;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
diff --git a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SpeakUpdated.java b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SpeakUpdated.java
index 87c8d7d1..8b134b54 100644
--- a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SpeakUpdated.java
+++ b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SpeakUpdated.java
@@ -3,8 +3,6 @@
*/
package com.deepgram.resources.agent.v1.types;
-// Manual patch - see .fernignore.
-
import com.deepgram.core.ObjectMappers;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
diff --git a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ThinkUpdated.java b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ThinkUpdated.java
index 4b6f6230..2d67cad1 100644
--- a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ThinkUpdated.java
+++ b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ThinkUpdated.java
@@ -3,8 +3,6 @@
*/
package com.deepgram.resources.agent.v1.types;
-// Manual patch - see .fernignore.
-
import com.deepgram.core.ObjectMappers;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
diff --git a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1UpdateListenListenProvider.java b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1UpdateListenListenProvider.java
index d0390e2d..e739aec6 100644
--- a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1UpdateListenListenProvider.java
+++ b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1UpdateListenListenProvider.java
@@ -3,8 +3,6 @@
*/
package com.deepgram.resources.agent.v1.types;
-// Manual patch - see .fernignore.
-
import com.deepgram.types.DeepgramListenProviderV1;
import com.deepgram.types.DeepgramListenProviderV2;
import com.fasterxml.jackson.annotation.JsonCreator;
diff --git a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1UserStartedSpeaking.java b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1UserStartedSpeaking.java
index 36e8a9d7..3556d319 100644
--- a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1UserStartedSpeaking.java
+++ b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1UserStartedSpeaking.java
@@ -3,8 +3,6 @@
*/
package com.deepgram.resources.agent.v1.types;
-// Manual patch - see .fernignore.
-
import com.deepgram.core.ObjectMappers;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
diff --git a/src/main/java/com/deepgram/resources/agent/v1/websocket/V1WebSocketClient.java b/src/main/java/com/deepgram/resources/agent/v1/websocket/V1WebSocketClient.java
index d8305b17..5bf4d734 100644
--- a/src/main/java/com/deepgram/resources/agent/v1/websocket/V1WebSocketClient.java
+++ b/src/main/java/com/deepgram/resources/agent/v1/websocket/V1WebSocketClient.java
@@ -3,8 +3,6 @@
*/
package com.deepgram.resources.agent.v1.websocket;
-// Manual patch - see .fernignore.
-
import com.deepgram.core.ClientOptions;
import com.deepgram.core.DisconnectReason;
import com.deepgram.core.ObjectMappers;
@@ -162,13 +160,22 @@ public CompletableFuture connect() {
? this.reconnectOptions
: ReconnectingWebSocketListener.ReconnectOptions.builder().build();
this.reconnectingListener =
- new ReconnectingWebSocketListener(reconnectOpts, () -> {
- if (clientOptions.webSocketFactory().isPresent()) {
- return clientOptions.webSocketFactory().get().create(request, this.reconnectingListener);
- } else {
- return okHttpClient.newWebSocket(request, this.reconnectingListener);
- }
- }) {
+ new ReconnectingWebSocketListener(
+ reconnectOpts,
+ () -> {
+ if (clientOptions.isClosed()) {
+ throw new IllegalStateException("root client has been closed");
+ }
+ if (clientOptions.webSocketFactory().isPresent()) {
+ return clientOptions
+ .webSocketFactory()
+ .get()
+ .create(request, this.reconnectingListener);
+ } else {
+ return okHttpClient.newWebSocket(request, this.reconnectingListener);
+ }
+ },
+ clientOptions::isClosed) {
@Override
protected void onWebSocketOpen(WebSocket webSocket, Response response) {
readyState = WebSocketReadyState.OPEN;
@@ -207,6 +214,7 @@ protected void onWebSocketClosed(WebSocket webSocket, int code, String reason) {
}
}
};
+ clientOptions.registerWebSocket(this);
reconnectingListener.connect();
return connectionFuture;
}
@@ -215,6 +223,7 @@ protected void onWebSocketClosed(WebSocket webSocket, int code, String reason) {
* Disconnects the WebSocket connection and releases resources.
*/
public void disconnect() {
+ clientOptions.unregisterWebSocket(this);
if (reconnectingListener != null) {
reconnectingListener.disconnect();
}
diff --git a/src/main/java/com/deepgram/resources/listen/v1/websocket/V1WebSocketClient.java b/src/main/java/com/deepgram/resources/listen/v1/websocket/V1WebSocketClient.java
index ffaa903e..278a2c9b 100644
--- a/src/main/java/com/deepgram/resources/listen/v1/websocket/V1WebSocketClient.java
+++ b/src/main/java/com/deepgram/resources/listen/v1/websocket/V1WebSocketClient.java
@@ -3,8 +3,6 @@
*/
package com.deepgram.resources.listen.v1.websocket;
-// Manual patch - see .fernignore.
-
import com.deepgram.core.ClientOptions;
import com.deepgram.core.DisconnectReason;
import com.deepgram.core.ObjectMappers;
@@ -229,13 +227,22 @@ public CompletableFuture connect(V1ConnectOptions options) {
? this.reconnectOptions
: ReconnectingWebSocketListener.ReconnectOptions.builder().build();
this.reconnectingListener =
- new ReconnectingWebSocketListener(reconnectOpts, () -> {
- if (clientOptions.webSocketFactory().isPresent()) {
- return clientOptions.webSocketFactory().get().create(request, this.reconnectingListener);
- } else {
- return okHttpClient.newWebSocket(request, this.reconnectingListener);
- }
- }) {
+ new ReconnectingWebSocketListener(
+ reconnectOpts,
+ () -> {
+ if (clientOptions.isClosed()) {
+ throw new IllegalStateException("root client has been closed");
+ }
+ if (clientOptions.webSocketFactory().isPresent()) {
+ return clientOptions
+ .webSocketFactory()
+ .get()
+ .create(request, this.reconnectingListener);
+ } else {
+ return okHttpClient.newWebSocket(request, this.reconnectingListener);
+ }
+ },
+ clientOptions::isClosed) {
@Override
protected void onWebSocketOpen(WebSocket webSocket, Response response) {
readyState = WebSocketReadyState.OPEN;
@@ -270,6 +277,7 @@ protected void onWebSocketClosed(WebSocket webSocket, int code, String reason) {
}
}
};
+ clientOptions.registerWebSocket(this);
reconnectingListener.connect();
return connectionFuture;
}
@@ -278,6 +286,7 @@ protected void onWebSocketClosed(WebSocket webSocket, int code, String reason) {
* Disconnects the WebSocket connection and releases resources.
*/
public void disconnect() {
+ clientOptions.unregisterWebSocket(this);
if (reconnectingListener != null) {
reconnectingListener.disconnect();
}
diff --git a/src/main/java/com/deepgram/resources/listen/v2/types/ListenV2CloseStream.java b/src/main/java/com/deepgram/resources/listen/v2/types/ListenV2CloseStream.java
index 8f7496d5..c9f2f357 100644
--- a/src/main/java/com/deepgram/resources/listen/v2/types/ListenV2CloseStream.java
+++ b/src/main/java/com/deepgram/resources/listen/v2/types/ListenV2CloseStream.java
@@ -3,8 +3,6 @@
*/
package com.deepgram.resources.listen.v2.types;
-// Manual patch - see .fernignore.
-
import com.deepgram.core.ObjectMappers;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
diff --git a/src/main/java/com/deepgram/resources/listen/v2/types/ListenV2ConfigureFailure.java b/src/main/java/com/deepgram/resources/listen/v2/types/ListenV2ConfigureFailure.java
index 478307b8..a48faaca 100644
--- a/src/main/java/com/deepgram/resources/listen/v2/types/ListenV2ConfigureFailure.java
+++ b/src/main/java/com/deepgram/resources/listen/v2/types/ListenV2ConfigureFailure.java
@@ -10,10 +10,12 @@
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSetter;
+import com.fasterxml.jackson.annotation.Nulls;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
+import java.util.Optional;
import org.jetbrains.annotations.NotNull;
@JsonInclude(JsonInclude.Include.NON_ABSENT)
@@ -23,11 +25,22 @@ public final class ListenV2ConfigureFailure {
private final int sequenceId;
+ private final Optional code;
+
+ private final Optional description;
+
private final Map additionalProperties;
- private ListenV2ConfigureFailure(String requestId, int sequenceId, Map additionalProperties) {
+ private ListenV2ConfigureFailure(
+ String requestId,
+ int sequenceId,
+ Optional code,
+ Optional description,
+ Map additionalProperties) {
this.requestId = requestId;
this.sequenceId = sequenceId;
+ this.code = code;
+ this.description = description;
this.additionalProperties = additionalProperties;
}
@@ -57,6 +70,22 @@ public int getSequenceId() {
return sequenceId;
}
+ /**
+ * @return Failure code identifying the rejected configuration
+ */
+ @JsonProperty("code")
+ public Optional getCode() {
+ return code;
+ }
+
+ /**
+ * @return A human-readable description of the configuration failure
+ */
+ @JsonProperty("description")
+ public Optional getDescription() {
+ return description;
+ }
+
@java.lang.Override
public boolean equals(Object other) {
if (this == other) return true;
@@ -69,12 +98,15 @@ public Map getAdditionalProperties() {
}
private boolean equalTo(ListenV2ConfigureFailure other) {
- return requestId.equals(other.requestId) && sequenceId == other.sequenceId;
+ return requestId.equals(other.requestId)
+ && sequenceId == other.sequenceId
+ && code.equals(other.code)
+ && description.equals(other.description);
}
@java.lang.Override
public int hashCode() {
- return Objects.hash(this.requestId, this.sequenceId);
+ return Objects.hash(this.requestId, this.sequenceId, this.code, this.description);
}
@java.lang.Override
@@ -110,6 +142,20 @@ public interface _FinalStage {
_FinalStage additionalProperty(String key, Object value);
_FinalStage additionalProperties(Map additionalProperties);
+
+ /**
+ * Failure code identifying the rejected configuration
+ */
+ _FinalStage code(Optional code);
+
+ _FinalStage code(String code);
+
+ /**
+ * A human-readable description of the configuration failure
+ */
+ _FinalStage description(Optional description);
+
+ _FinalStage description(String description);
}
@JsonIgnoreProperties(ignoreUnknown = true)
@@ -118,6 +164,10 @@ public static final class Builder implements RequestIdStage, SequenceIdStage, _F
private int sequenceId;
+ private Optional description = Optional.empty();
+
+ private Optional code = Optional.empty();
+
@JsonAnySetter
private Map additionalProperties = new HashMap<>();
@@ -127,6 +177,8 @@ private Builder() {}
public Builder from(ListenV2ConfigureFailure other) {
requestId(other.getRequestId());
sequenceId(other.getSequenceId());
+ code(other.getCode());
+ description(other.getDescription());
return this;
}
@@ -154,9 +206,49 @@ public _FinalStage sequenceId(int sequenceId) {
return this;
}
+ /**
+ * A human-readable description of the configuration failure
+ * @return Reference to {@code this} so that method calls can be chained together.
+ */
+ @java.lang.Override
+ public _FinalStage description(String description) {
+ this.description = Optional.ofNullable(description);
+ return this;
+ }
+
+ /**
+ * A human-readable description of the configuration failure
+ */
+ @java.lang.Override
+ @JsonSetter(value = "description", nulls = Nulls.SKIP)
+ public _FinalStage description(Optional description) {
+ this.description = description;
+ return this;
+ }
+
+ /**
+ * Failure code identifying the rejected configuration
+ * @return Reference to {@code this} so that method calls can be chained together.
+ */
+ @java.lang.Override
+ public _FinalStage code(String code) {
+ this.code = Optional.ofNullable(code);
+ return this;
+ }
+
+ /**
+ * Failure code identifying the rejected configuration
+ */
+ @java.lang.Override
+ @JsonSetter(value = "code", nulls = Nulls.SKIP)
+ public _FinalStage code(Optional code) {
+ this.code = code;
+ return this;
+ }
+
@java.lang.Override
public ListenV2ConfigureFailure build() {
- return new ListenV2ConfigureFailure(requestId, sequenceId, additionalProperties);
+ return new ListenV2ConfigureFailure(requestId, sequenceId, code, description, additionalProperties);
}
@java.lang.Override
diff --git a/src/main/java/com/deepgram/resources/listen/v2/types/ListenV2ConfigureSuccess.java b/src/main/java/com/deepgram/resources/listen/v2/types/ListenV2ConfigureSuccess.java
index ca93f2b2..a714b954 100644
--- a/src/main/java/com/deepgram/resources/listen/v2/types/ListenV2ConfigureSuccess.java
+++ b/src/main/java/com/deepgram/resources/listen/v2/types/ListenV2ConfigureSuccess.java
@@ -31,6 +31,8 @@ public final class ListenV2ConfigureSuccess {
private final Optional> languageHints;
+ private final Optional numerals;
+
private final int sequenceId;
private final Map additionalProperties;
@@ -40,12 +42,14 @@ private ListenV2ConfigureSuccess(
ListenV2ConfigureSuccessThresholds thresholds,
ListenV2Keyterm keyterms,
Optional> languageHints,
+ Optional numerals,
int sequenceId,
Map additionalProperties) {
this.requestId = requestId;
this.thresholds = thresholds;
this.keyterms = keyterms;
this.languageHints = languageHints;
+ this.numerals = numerals;
this.sequenceId = sequenceId;
this.additionalProperties = additionalProperties;
}
@@ -88,6 +92,14 @@ public Optional> getLanguageHints() {
return languageHints;
}
+ /**
+ * @return Whether numeral formatting is enabled for transcripts Flux STT sends after it processes the update.
+ */
+ @JsonProperty("numerals")
+ public Optional getNumerals() {
+ return numerals;
+ }
+
/**
* @return Starts at 0 and increments for each message the server sends
* to the client. This includes messages of other types, like
@@ -114,12 +126,14 @@ private boolean equalTo(ListenV2ConfigureSuccess other) {
&& thresholds.equals(other.thresholds)
&& keyterms.equals(other.keyterms)
&& languageHints.equals(other.languageHints)
+ && numerals.equals(other.numerals)
&& sequenceId == other.sequenceId;
}
@java.lang.Override
public int hashCode() {
- return Objects.hash(this.requestId, this.thresholds, this.keyterms, this.languageHints, this.sequenceId);
+ return Objects.hash(
+ this.requestId, this.thresholds, this.keyterms, this.languageHints, this.numerals, this.sequenceId);
}
@java.lang.Override
@@ -174,6 +188,13 @@ public interface _FinalStage {
_FinalStage languageHints(Optional> languageHints);
_FinalStage languageHints(List languageHints);
+
+ /**
+ * Whether numeral formatting is enabled for transcripts Flux STT sends after it processes the update.
+ */
+ _FinalStage numerals(Optional numerals);
+
+ _FinalStage numerals(Boolean numerals);
}
@JsonIgnoreProperties(ignoreUnknown = true)
@@ -187,6 +208,8 @@ public static final class Builder
private int sequenceId;
+ private Optional numerals = Optional.empty();
+
private Optional> languageHints = Optional.empty();
@JsonAnySetter
@@ -200,6 +223,7 @@ public Builder from(ListenV2ConfigureSuccess other) {
thresholds(other.getThresholds());
keyterms(other.getKeyterms());
languageHints(other.getLanguageHints());
+ numerals(other.getNumerals());
sequenceId(other.getSequenceId());
return this;
}
@@ -247,6 +271,26 @@ public _FinalStage sequenceId(int sequenceId) {
return this;
}
+ /**
+ * Whether numeral formatting is enabled for transcripts Flux STT sends after it processes the update.
+ * @return Reference to {@code this} so that method calls can be chained together.
+ */
+ @java.lang.Override
+ public _FinalStage numerals(Boolean numerals) {
+ this.numerals = Optional.ofNullable(numerals);
+ return this;
+ }
+
+ /**
+ * Whether numeral formatting is enabled for transcripts Flux STT sends after it processes the update.
+ */
+ @java.lang.Override
+ @JsonSetter(value = "numerals", nulls = Nulls.SKIP)
+ public _FinalStage numerals(Optional numerals) {
+ this.numerals = numerals;
+ return this;
+ }
+
/**
* The currently active language hints. Only applicable to the flux-general-multi model.
* @return Reference to {@code this} so that method calls can be chained together.
@@ -270,7 +314,7 @@ public _FinalStage languageHints(Optional> languageHints) {
@java.lang.Override
public ListenV2ConfigureSuccess build() {
return new ListenV2ConfigureSuccess(
- requestId, thresholds, keyterms, languageHints, sequenceId, additionalProperties);
+ requestId, thresholds, keyterms, languageHints, numerals, sequenceId, additionalProperties);
}
@java.lang.Override
diff --git a/src/main/java/com/deepgram/resources/listen/v2/types/ListenV2ForceEndTurn.java b/src/main/java/com/deepgram/resources/listen/v2/types/ListenV2ForceEndTurn.java
index 99471a55..894bd3c8 100644
--- a/src/main/java/com/deepgram/resources/listen/v2/types/ListenV2ForceEndTurn.java
+++ b/src/main/java/com/deepgram/resources/listen/v2/types/ListenV2ForceEndTurn.java
@@ -3,8 +3,6 @@
*/
package com.deepgram.resources.listen.v2.types;
-// Manual patch - see .fernignore.
-
import com.deepgram.core.ObjectMappers;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
diff --git a/src/main/java/com/deepgram/resources/listen/v2/types/ListenV2Warning.java b/src/main/java/com/deepgram/resources/listen/v2/types/ListenV2Warning.java
new file mode 100644
index 00000000..4eed2fb7
--- /dev/null
+++ b/src/main/java/com/deepgram/resources/listen/v2/types/ListenV2Warning.java
@@ -0,0 +1,247 @@
+/**
+ * This file was auto-generated by Fern from our API Definition.
+ */
+package com.deepgram.resources.listen.v2.types;
+
+import com.deepgram.core.ObjectMappers;
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonAnySetter;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonSetter;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import org.jetbrains.annotations.NotNull;
+
+@JsonInclude(JsonInclude.Include.NON_ABSENT)
+@JsonDeserialize(builder = ListenV2Warning.Builder.class)
+public final class ListenV2Warning {
+ private final String requestId;
+
+ private final int sequenceId;
+
+ private final String code;
+
+ private final String description;
+
+ private final Map additionalProperties;
+
+ private ListenV2Warning(
+ String requestId,
+ int sequenceId,
+ String code,
+ String description,
+ Map additionalProperties) {
+ this.requestId = requestId;
+ this.sequenceId = sequenceId;
+ this.code = code;
+ this.description = description;
+ this.additionalProperties = additionalProperties;
+ }
+
+ /**
+ * @return Message type identifier
+ */
+ @JsonProperty("type")
+ public String getType() {
+ return "Warning";
+ }
+
+ /**
+ * @return The unique identifier of the request
+ */
+ @JsonProperty("request_id")
+ public String getRequestId() {
+ return requestId;
+ }
+
+ /**
+ * @return Starts at 0 and increments for each message the server sends
+ * to the client. This includes messages of other types, like
+ * TurnInfo messages.
+ */
+ @JsonProperty("sequence_id")
+ public int getSequenceId() {
+ return sequenceId;
+ }
+
+ /**
+ * @return Warning code identifying the condition, in SCREAMING_SNAKE_CASE
+ */
+ @JsonProperty("code")
+ public String getCode() {
+ return code;
+ }
+
+ /**
+ * @return A human-readable description of the warning
+ */
+ @JsonProperty("description")
+ public String getDescription() {
+ return description;
+ }
+
+ @java.lang.Override
+ public boolean equals(Object other) {
+ if (this == other) return true;
+ return other instanceof ListenV2Warning && equalTo((ListenV2Warning) other);
+ }
+
+ @JsonAnyGetter
+ public Map getAdditionalProperties() {
+ return this.additionalProperties;
+ }
+
+ private boolean equalTo(ListenV2Warning other) {
+ return requestId.equals(other.requestId)
+ && sequenceId == other.sequenceId
+ && code.equals(other.code)
+ && description.equals(other.description);
+ }
+
+ @java.lang.Override
+ public int hashCode() {
+ return Objects.hash(this.requestId, this.sequenceId, this.code, this.description);
+ }
+
+ @java.lang.Override
+ public String toString() {
+ return ObjectMappers.stringify(this);
+ }
+
+ public static RequestIdStage builder() {
+ return new Builder();
+ }
+
+ public interface RequestIdStage {
+ /**
+ * The unique identifier of the request
+ */
+ SequenceIdStage requestId(@NotNull String requestId);
+
+ Builder from(ListenV2Warning other);
+ }
+
+ public interface SequenceIdStage {
+ /**
+ * Starts at 0 and increments for each message the server sends
+ * to the client. This includes messages of other types, like
+ * TurnInfo messages.
+ */
+ CodeStage sequenceId(int sequenceId);
+ }
+
+ public interface CodeStage {
+ /**
+ * Warning code identifying the condition, in SCREAMING_SNAKE_CASE
+ */
+ DescriptionStage code(@NotNull String code);
+ }
+
+ public interface DescriptionStage {
+ /**
+ * A human-readable description of the warning
+ */
+ _FinalStage description(@NotNull String description);
+ }
+
+ public interface _FinalStage {
+ ListenV2Warning build();
+
+ _FinalStage additionalProperty(String key, Object value);
+
+ _FinalStage additionalProperties(Map additionalProperties);
+ }
+
+ @JsonIgnoreProperties(ignoreUnknown = true)
+ public static final class Builder
+ implements RequestIdStage, SequenceIdStage, CodeStage, DescriptionStage, _FinalStage {
+ private String requestId;
+
+ private int sequenceId;
+
+ private String code;
+
+ private String description;
+
+ @JsonAnySetter
+ private Map additionalProperties = new HashMap<>();
+
+ private Builder() {}
+
+ @java.lang.Override
+ public Builder from(ListenV2Warning other) {
+ requestId(other.getRequestId());
+ sequenceId(other.getSequenceId());
+ code(other.getCode());
+ description(other.getDescription());
+ return this;
+ }
+
+ /**
+ * The unique identifier of the request
+ * @return Reference to {@code this} so that method calls can be chained together.
+ */
+ @java.lang.Override
+ @JsonSetter("request_id")
+ public SequenceIdStage requestId(@NotNull String requestId) {
+ this.requestId = Objects.requireNonNull(requestId, "requestId must not be null");
+ return this;
+ }
+
+ /**
+ * Starts at 0 and increments for each message the server sends
+ * to the client. This includes messages of other types, like
+ * TurnInfo messages.
+ * @return Reference to {@code this} so that method calls can be chained together.
+ */
+ @java.lang.Override
+ @JsonSetter("sequence_id")
+ public CodeStage sequenceId(int sequenceId) {
+ this.sequenceId = sequenceId;
+ return this;
+ }
+
+ /**
+ * Warning code identifying the condition, in SCREAMING_SNAKE_CASE
+ * @return Reference to {@code this} so that method calls can be chained together.
+ */
+ @java.lang.Override
+ @JsonSetter("code")
+ public DescriptionStage code(@NotNull String code) {
+ this.code = Objects.requireNonNull(code, "code must not be null");
+ return this;
+ }
+
+ /**
+ * A human-readable description of the warning
+ * @return Reference to {@code this} so that method calls can be chained together.
+ */
+ @java.lang.Override
+ @JsonSetter("description")
+ public _FinalStage description(@NotNull String description) {
+ this.description = Objects.requireNonNull(description, "description must not be null");
+ return this;
+ }
+
+ @java.lang.Override
+ public ListenV2Warning build() {
+ return new ListenV2Warning(requestId, sequenceId, code, description, additionalProperties);
+ }
+
+ @java.lang.Override
+ public Builder additionalProperty(String key, Object value) {
+ this.additionalProperties.put(key, value);
+ return this;
+ }
+
+ @java.lang.Override
+ public Builder additionalProperties(Map additionalProperties) {
+ this.additionalProperties.putAll(additionalProperties);
+ return this;
+ }
+ }
+}
diff --git a/src/main/java/com/deepgram/resources/listen/v2/websocket/V2WebSocketClient.java b/src/main/java/com/deepgram/resources/listen/v2/websocket/V2WebSocketClient.java
index b2dee9b4..5f55fea3 100644
--- a/src/main/java/com/deepgram/resources/listen/v2/websocket/V2WebSocketClient.java
+++ b/src/main/java/com/deepgram/resources/listen/v2/websocket/V2WebSocketClient.java
@@ -3,8 +3,6 @@
*/
package com.deepgram.resources.listen.v2.websocket;
-// Manual patch - see .fernignore.
-
import com.deepgram.core.ClientOptions;
import com.deepgram.core.DisconnectReason;
import com.deepgram.core.ObjectMappers;
@@ -20,6 +18,7 @@
import com.deepgram.resources.listen.v2.types.ListenV2FatalError;
import com.deepgram.resources.listen.v2.types.ListenV2ForceEndTurn;
import com.deepgram.resources.listen.v2.types.ListenV2TurnInfo;
+import com.deepgram.resources.listen.v2.types.ListenV2Warning;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.concurrent.CompletableFuture;
@@ -72,6 +71,8 @@ public class V2WebSocketClient implements AutoCloseable {
private volatile Consumer configureFailureHandler;
+ private volatile Consumer warningHandler;
+
private volatile Consumer errorHandler;
/**
@@ -175,13 +176,22 @@ public CompletableFuture connect(V2ConnectOptions options) {
? this.reconnectOptions
: ReconnectingWebSocketListener.ReconnectOptions.builder().build();
this.reconnectingListener =
- new ReconnectingWebSocketListener(reconnectOpts, () -> {
- if (clientOptions.webSocketFactory().isPresent()) {
- return clientOptions.webSocketFactory().get().create(request, this.reconnectingListener);
- } else {
- return okHttpClient.newWebSocket(request, this.reconnectingListener);
- }
- }) {
+ new ReconnectingWebSocketListener(
+ reconnectOpts,
+ () -> {
+ if (clientOptions.isClosed()) {
+ throw new IllegalStateException("root client has been closed");
+ }
+ if (clientOptions.webSocketFactory().isPresent()) {
+ return clientOptions
+ .webSocketFactory()
+ .get()
+ .create(request, this.reconnectingListener);
+ } else {
+ return okHttpClient.newWebSocket(request, this.reconnectingListener);
+ }
+ },
+ clientOptions::isClosed) {
@Override
protected void onWebSocketOpen(WebSocket webSocket, Response response) {
closeStreamSocket.set(null);
@@ -223,6 +233,7 @@ protected boolean shouldReconnectAfterClose(WebSocket webSocket, int code, Strin
&& (code != 1005 || closeStreamSocket.get() != webSocket);
}
};
+ clientOptions.registerWebSocket(this);
reconnectingListener.connect();
return connectionFuture;
}
@@ -231,6 +242,7 @@ protected boolean shouldReconnectAfterClose(WebSocket webSocket, int code, Strin
* Disconnects the WebSocket connection and releases resources.
*/
public void disconnect() {
+ clientOptions.unregisterWebSocket(this);
if (reconnectingListener != null) {
reconnectingListener.disconnect();
}
@@ -281,11 +293,6 @@ public CompletableFuture sendCloseStream(ListenV2CloseStream message) {
/**
* Sends a ListenV2ForceEndTurn message to the server asynchronously.
- *
- * Sending this with no turn in progress is not an error. The server answers with a
- * {@code Warning} frame carrying code {@code FORCE_END_TURN_NO_ACTIVE_TURN} and ignores the
- * request. Listen V2 has no typed warning event yet, so that frame is delivered as raw JSON
- * to {@link #onMessage(java.util.function.Consumer)}.
* @param message the message to send
* @return a CompletableFuture that completes when the message is sent
*/
@@ -334,6 +341,14 @@ public void onConfigureFailure(Consumer handler) {
this.configureFailureHandler = handler;
}
+ /**
+ * Registers a handler for ListenV2Warning messages from the server.
+ * @param handler the handler to invoke when a message is received
+ */
+ public void onWarning(Consumer handler) {
+ this.warningHandler = handler;
+ }
+
/**
* Registers a handler for ListenV2FatalError messages from the server.
* @param handler the handler to invoke when a message is received
@@ -351,8 +366,7 @@ public void onConnected(Runnable handler) {
}
/**
- * Registers a handler called when the connection is closed. An empty peer close frame is
- * reported with code 1005, even though the SDK acknowledges it with code 1000.
+ * Registers a handler called when the connection is closed.
* @param handler the handler to invoke when disconnected
*/
public void onDisconnected(Consumer handler) {
@@ -475,6 +489,23 @@ private void handleIncomingMessage(String json) {
return;
}
}
+ if (node.has("request_id")
+ && node.has("sequence_id")
+ && node.has("code")
+ && node.has("description")
+ && "Warning".equals(node.path("type").asText())) {
+ ListenV2Warning warningHandlerEvent = null;
+ try {
+ warningHandlerEvent = objectMapper.treeToValue(node, ListenV2Warning.class);
+ } catch (Exception e) {
+ }
+ if (warningHandlerEvent != null) {
+ if (warningHandler != null) {
+ warningHandler.accept(warningHandlerEvent);
+ }
+ return;
+ }
+ }
if (node.has("sequence_id")
&& node.has("code")
&& node.has("description")
diff --git a/src/main/java/com/deepgram/resources/speak/v1/websocket/V1WebSocketClient.java b/src/main/java/com/deepgram/resources/speak/v1/websocket/V1WebSocketClient.java
index ae271f2a..e6824a38 100644
--- a/src/main/java/com/deepgram/resources/speak/v1/websocket/V1WebSocketClient.java
+++ b/src/main/java/com/deepgram/resources/speak/v1/websocket/V1WebSocketClient.java
@@ -3,8 +3,6 @@
*/
package com.deepgram.resources.speak.v1.websocket;
-// Manual patch - see .fernignore.
-
import com.deepgram.core.ClientOptions;
import com.deepgram.core.DisconnectReason;
import com.deepgram.core.ObjectMappers;
@@ -140,13 +138,22 @@ public CompletableFuture connect(V1ConnectOptions options) {
? this.reconnectOptions
: ReconnectingWebSocketListener.ReconnectOptions.builder().build();
this.reconnectingListener =
- new ReconnectingWebSocketListener(reconnectOpts, () -> {
- if (clientOptions.webSocketFactory().isPresent()) {
- return clientOptions.webSocketFactory().get().create(request, this.reconnectingListener);
- } else {
- return okHttpClient.newWebSocket(request, this.reconnectingListener);
- }
- }) {
+ new ReconnectingWebSocketListener(
+ reconnectOpts,
+ () -> {
+ if (clientOptions.isClosed()) {
+ throw new IllegalStateException("root client has been closed");
+ }
+ if (clientOptions.webSocketFactory().isPresent()) {
+ return clientOptions
+ .webSocketFactory()
+ .get()
+ .create(request, this.reconnectingListener);
+ } else {
+ return okHttpClient.newWebSocket(request, this.reconnectingListener);
+ }
+ },
+ clientOptions::isClosed) {
@Override
protected void onWebSocketOpen(WebSocket webSocket, Response response) {
readyState = WebSocketReadyState.OPEN;
@@ -185,6 +192,7 @@ protected void onWebSocketClosed(WebSocket webSocket, int code, String reason) {
}
}
};
+ clientOptions.registerWebSocket(this);
reconnectingListener.connect();
return connectionFuture;
}
@@ -201,6 +209,7 @@ public CompletableFuture connect() {
* Disconnects the WebSocket connection and releases resources.
*/
public void disconnect() {
+ clientOptions.unregisterWebSocket(this);
if (reconnectingListener != null) {
reconnectingListener.disconnect();
}
diff --git a/src/main/java/com/deepgram/resources/speak/v2/audio/requests/SpeakV2Request.java b/src/main/java/com/deepgram/resources/speak/v2/audio/requests/SpeakV2Request.java
index bc3fb63e..d1a3d823 100644
--- a/src/main/java/com/deepgram/resources/speak/v2/audio/requests/SpeakV2Request.java
+++ b/src/main/java/com/deepgram/resources/speak/v2/audio/requests/SpeakV2Request.java
@@ -167,7 +167,7 @@ public Optional getSampleRate() {
}
/**
- * @return Speaking rate multiplier that adjusts the pace of generated speech while preserving natural prosody and voice quality. Accepted values run 0.5 to 1.5 in 0.05 increments. Not yet supported in all languages.
+ * @return Speaking rate multiplier that adjusts the pace of generated speech while preserving natural prosody and voice quality. Accepted values run 0.5 to 1.5 in 0.05 increments. Not yet supported in all languages. When the text contains an inline pause marker, speed is capped at 1.15 (PAUSE_SPEED_CAP_EXCEEDED above that). A value other than 1.0 cannot be combined with inline pronunciation controls (CONTROL_COMBINATION_INVALID).
*/
@JsonIgnore
public Optional getSpeed() {
@@ -183,7 +183,7 @@ public Optional getPriority() {
}
/**
- * @return The text content to be converted to speech. The server normalizes and preprocesses the text before synthesis. Inline pause and pronunciation controls are not yet applied; they are stripped from the text before synthesis.
+ * @return The text content to be converted to speech. The server normalizes and preprocesses the text before synthesis. May contain inline pause controls (\{pause:500ms\}, 500-3000 ms in 100 ms steps, at most 8 per request) and inline pronunciation controls (\{"word": "...", "pronounce": "<IPA>"\}, Early Access). Pronunciation cannot be combined with pause or with a speed other than 1.0, and speed is capped at 1.15 when a pause is present. See Speed, Pause, Pronunciation.
*/
@JsonProperty("text")
public String getText() {
@@ -255,7 +255,7 @@ public interface ModelStage {
public interface TextStage {
/**
- * The text content to be converted to speech. The server normalizes and preprocesses the text before synthesis. Inline pause and pronunciation controls are not yet applied; they are stripped from the text before synthesis.
+ * The text content to be converted to speech. The server normalizes and preprocesses the text before synthesis. May contain inline pause controls (\{pause:500ms\}, 500-3000 ms in 100 ms steps, at most 8 per request) and inline pronunciation controls (\{"word": "...", "pronounce": "<IPA>"\}, Early Access). Pronunciation cannot be combined with pause or with a speed other than 1.0, and speed is capped at 1.15 when a pause is present. See Speed, Pause, Pronunciation.
*/
_FinalStage text(@NotNull String text);
}
@@ -333,7 +333,7 @@ public interface _FinalStage {
_FinalStage sampleRate(Integer sampleRate);
/**
- * Speaking rate multiplier that adjusts the pace of generated speech while preserving natural prosody and voice quality. Accepted values run 0.5 to 1.5 in 0.05 increments. Not yet supported in all languages.
+ * Speaking rate multiplier that adjusts the pace of generated speech while preserving natural prosody and voice quality. Accepted values run 0.5 to 1.5 in 0.05 increments. Not yet supported in all languages. When the text contains an inline pause marker, speed is capped at 1.15 (PAUSE_SPEED_CAP_EXCEEDED above that). A value other than 1.0 cannot be combined with inline pronunciation controls (CONTROL_COMBINATION_INVALID).
*/
_FinalStage speed(Optional speed);
@@ -410,7 +410,7 @@ public TextStage model(@NotNull String model) {
}
/**
- * The text content to be converted to speech. The server normalizes and preprocesses the text before synthesis. Inline pause and pronunciation controls are not yet applied; they are stripped from the text before synthesis.
+ * The text content to be converted to speech. The server normalizes and preprocesses the text before synthesis. May contain inline pause controls (\{pause:500ms\}, 500-3000 ms in 100 ms steps, at most 8 per request) and inline pronunciation controls (\{"word": "...", "pronounce": "<IPA>"\}, Early Access). Pronunciation cannot be combined with pause or with a speed other than 1.0, and speed is capped at 1.15 when a pause is present. See Speed, Pause, Pronunciation.
* @return Reference to {@code this} so that method calls can be chained together.
*/
@java.lang.Override
@@ -441,7 +441,7 @@ public _FinalStage priority(Optional priority) {
}
/**
- * Speaking rate multiplier that adjusts the pace of generated speech while preserving natural prosody and voice quality. Accepted values run 0.5 to 1.5 in 0.05 increments. Not yet supported in all languages.
+ * Speaking rate multiplier that adjusts the pace of generated speech while preserving natural prosody and voice quality. Accepted values run 0.5 to 1.5 in 0.05 increments. Not yet supported in all languages. When the text contains an inline pause marker, speed is capped at 1.15 (PAUSE_SPEED_CAP_EXCEEDED above that). A value other than 1.0 cannot be combined with inline pronunciation controls (CONTROL_COMBINATION_INVALID).
* @return Reference to {@code this} so that method calls can be chained together.
*/
@java.lang.Override
@@ -451,7 +451,7 @@ public _FinalStage speed(Double speed) {
}
/**
- * Speaking rate multiplier that adjusts the pace of generated speech while preserving natural prosody and voice quality. Accepted values run 0.5 to 1.5 in 0.05 increments. Not yet supported in all languages.
+ * Speaking rate multiplier that adjusts the pace of generated speech while preserving natural prosody and voice quality. Accepted values run 0.5 to 1.5 in 0.05 increments. Not yet supported in all languages. When the text contains an inline pause marker, speed is capped at 1.15 (PAUSE_SPEED_CAP_EXCEEDED above that). A value other than 1.0 cannot be combined with inline pronunciation controls (CONTROL_COMBINATION_INVALID).
*/
@java.lang.Override
@JsonSetter(value = "speed", nulls = Nulls.SKIP)
diff --git a/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Close.java b/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Close.java
index 0479ff66..7fecd79f 100644
--- a/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Close.java
+++ b/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Close.java
@@ -3,8 +3,6 @@
*/
package com.deepgram.resources.speak.v2.types;
-// Manual patch - see .fernignore.
-
import com.deepgram.core.ObjectMappers;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
diff --git a/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2ConfigureFailure.java b/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2ConfigureFailure.java
index e43c252f..79702327 100644
--- a/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2ConfigureFailure.java
+++ b/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2ConfigureFailure.java
@@ -53,7 +53,7 @@ public String getType() {
}
/**
- * @return Failure code, in SCREAMING_SNAKE_CASE. SPEED_OUT_OF_RANGE: outside the range the model publishes. SPEED_INCREMENT_INVALID: inside the published range but off the 0.05 increment. SPEED_NOT_SUPPORTED: this model or language has no runtime speed control at all. INTERNAL_ERROR: the configuration was acceptable but the server could not apply it — unlike the others, a server-side failure rather than a statement about the request.
+ * @return Failure code, in SCREAMING_SNAKE_CASE. SPEED_OUT_OF_RANGE: outside the range the model publishes. SPEED_INCREMENT_INVALID: inside the published range but off the 0.05 increment. SPEED_NOT_SUPPORTED: this model or language has no runtime speed control at all. CONTROL_COMBINATION_INVALID: speed was set while a turn buffered behind the active one still carries a pronunciation control; pronunciation and speed cannot be combined, so flush that turn before setting speed (pronunciations in the active turn do not block the change). INTERNAL_ERROR: the configuration was acceptable but the server could not apply it — unlike the others, a server-side failure rather than a statement about the request.
*/
@JsonProperty("code")
public SpeakV2ConfigureFailureCode getCode() {
@@ -118,7 +118,7 @@ public static CodeStage builder() {
public interface CodeStage {
/**
- * Failure code, in SCREAMING_SNAKE_CASE. SPEED_OUT_OF_RANGE: outside the range the model publishes. SPEED_INCREMENT_INVALID: inside the published range but off the 0.05 increment. SPEED_NOT_SUPPORTED: this model or language has no runtime speed control at all. INTERNAL_ERROR: the configuration was acceptable but the server could not apply it — unlike the others, a server-side failure rather than a statement about the request.
+ * Failure code, in SCREAMING_SNAKE_CASE. SPEED_OUT_OF_RANGE: outside the range the model publishes. SPEED_INCREMENT_INVALID: inside the published range but off the 0.05 increment. SPEED_NOT_SUPPORTED: this model or language has no runtime speed control at all. CONTROL_COMBINATION_INVALID: speed was set while a turn buffered behind the active one still carries a pronunciation control; pronunciation and speed cannot be combined, so flush that turn before setting speed (pronunciations in the active turn do not block the change). INTERNAL_ERROR: the configuration was acceptable but the server could not apply it — unlike the others, a server-side failure rather than a statement about the request.
*/
DescriptionStage code(@NotNull SpeakV2ConfigureFailureCode code);
@@ -179,7 +179,7 @@ public Builder from(SpeakV2ConfigureFailure other) {
}
/**
- * Failure code, in SCREAMING_SNAKE_CASE. SPEED_OUT_OF_RANGE: outside the range the model publishes. SPEED_INCREMENT_INVALID: inside the published range but off the 0.05 increment. SPEED_NOT_SUPPORTED: this model or language has no runtime speed control at all. INTERNAL_ERROR: the configuration was acceptable but the server could not apply it — unlike the others, a server-side failure rather than a statement about the request.
+ * Failure code, in SCREAMING_SNAKE_CASE. SPEED_OUT_OF_RANGE: outside the range the model publishes. SPEED_INCREMENT_INVALID: inside the published range but off the 0.05 increment. SPEED_NOT_SUPPORTED: this model or language has no runtime speed control at all. CONTROL_COMBINATION_INVALID: speed was set while a turn buffered behind the active one still carries a pronunciation control; pronunciation and speed cannot be combined, so flush that turn before setting speed (pronunciations in the active turn do not block the change). INTERNAL_ERROR: the configuration was acceptable but the server could not apply it — unlike the others, a server-side failure rather than a statement about the request.
* @return Reference to {@code this} so that method calls can be chained together.
*/
@java.lang.Override
diff --git a/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2ConfigureFailureCode.java b/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2ConfigureFailureCode.java
index 7d02bce7..63ec45a7 100644
--- a/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2ConfigureFailureCode.java
+++ b/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2ConfigureFailureCode.java
@@ -7,6 +7,9 @@
import com.fasterxml.jackson.annotation.JsonValue;
public final class SpeakV2ConfigureFailureCode {
+ public static final SpeakV2ConfigureFailureCode CONTROL_COMBINATION_INVALID =
+ new SpeakV2ConfigureFailureCode(Value.CONTROL_COMBINATION_INVALID, "CONTROL_COMBINATION_INVALID");
+
public static final SpeakV2ConfigureFailureCode SPEED_OUT_OF_RANGE =
new SpeakV2ConfigureFailureCode(Value.SPEED_OUT_OF_RANGE, "SPEED_OUT_OF_RANGE");
@@ -52,6 +55,8 @@ public int hashCode() {
public T visit(Visitor visitor) {
switch (value) {
+ case CONTROL_COMBINATION_INVALID:
+ return visitor.visitControlCombinationInvalid();
case SPEED_OUT_OF_RANGE:
return visitor.visitSpeedOutOfRange();
case SPEED_INCREMENT_INVALID:
@@ -69,6 +74,8 @@ public T visit(Visitor visitor) {
@JsonCreator(mode = JsonCreator.Mode.DELEGATING)
public static SpeakV2ConfigureFailureCode valueOf(String value) {
switch (value) {
+ case "CONTROL_COMBINATION_INVALID":
+ return CONTROL_COMBINATION_INVALID;
case "SPEED_OUT_OF_RANGE":
return SPEED_OUT_OF_RANGE;
case "SPEED_INCREMENT_INVALID":
@@ -89,6 +96,8 @@ public enum Value {
SPEED_NOT_SUPPORTED,
+ CONTROL_COMBINATION_INVALID,
+
INTERNAL_ERROR,
UNKNOWN
@@ -101,6 +110,8 @@ public interface Visitor {
T visitSpeedNotSupported();
+ T visitControlCombinationInvalid();
+
T visitInternalError();
T visitUnknown(String unknownType);
diff --git a/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Error.java b/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Error.java
index 343cfa72..0a828475 100644
--- a/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Error.java
+++ b/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Error.java
@@ -40,7 +40,7 @@ public String getType() {
}
/**
- * @return A code identifying the error, e.g. MESSAGE-0000 or NET-0000.
+ * @return A code identifying the error, e.g. MESSAGE-0000 or NET-0000. DATA-0002 covers invalid inline controls and speed, including an inline pause marker (pause is batch-only) and a pronunciation control combined with a speed other than 1.0; description names the specific rule.
*/
@JsonProperty("code")
public SpeakV2ErrorCode getCode() {
@@ -86,7 +86,7 @@ public static CodeStage builder() {
public interface CodeStage {
/**
- * A code identifying the error, e.g. MESSAGE-0000 or NET-0000.
+ * A code identifying the error, e.g. MESSAGE-0000 or NET-0000. DATA-0002 covers invalid inline controls and speed, including an inline pause marker (pause is batch-only) and a pronunciation control combined with a speed other than 1.0; description names the specific rule.
*/
DescriptionStage code(@NotNull SpeakV2ErrorCode code);
@@ -127,7 +127,7 @@ public Builder from(SpeakV2Error other) {
}
/**
- * A code identifying the error, e.g. MESSAGE-0000 or NET-0000.
+ * A code identifying the error, e.g. MESSAGE-0000 or NET-0000. DATA-0002 covers invalid inline controls and speed, including an inline pause marker (pause is batch-only) and a pronunciation control combined with a speed other than 1.0; description names the specific rule.
* @return Reference to {@code this} so that method calls can be chained together.
*/
@java.lang.Override
diff --git a/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Flush.java b/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Flush.java
index db0b1ec5..130da0d9 100644
--- a/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Flush.java
+++ b/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Flush.java
@@ -3,8 +3,6 @@
*/
package com.deepgram.resources.speak.v2.types;
-// Manual patch - see .fernignore.
-
import com.deepgram.core.ObjectMappers;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
diff --git a/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Speak.java b/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Speak.java
index 16150bfa..8c8e5638 100644
--- a/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Speak.java
+++ b/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Speak.java
@@ -37,7 +37,7 @@ public String getType() {
}
/**
- * @return The input text to synthesize. Inline pause and pronunciation controls are not yet applied; they are stripped from the text before synthesis.
+ * @return The input text to synthesize. May contain inline pronunciation controls (\{"word": "...", "pronounce": "<IPA>"\}), which are in Early Access. Inline pause controls are supported on the batch (REST) transport only; a pause marker sent over the WebSocket fails the connection with DATA-0002. Pronunciation cannot be combined with a speed other than 1.0: text carrying a pronunciation control on a session opened with speed, or after a Configure that set it, also fails the connection with DATA-0002. See Speed, Pause, Pronunciation.
*/
@JsonProperty("text")
public String getText() {
@@ -75,7 +75,7 @@ public static TextStage builder() {
public interface TextStage {
/**
- * The input text to synthesize. Inline pause and pronunciation controls are not yet applied; they are stripped from the text before synthesis.
+ * The input text to synthesize. May contain inline pronunciation controls (\{"word": "...", "pronounce": "<IPA>"\}), which are in Early Access. Inline pause controls are supported on the batch (REST) transport only; a pause marker sent over the WebSocket fails the connection with DATA-0002. Pronunciation cannot be combined with a speed other than 1.0: text carrying a pronunciation control on a session opened with speed, or after a Configure that set it, also fails the connection with DATA-0002. See Speed, Pause, Pronunciation.
*/
_FinalStage text(@NotNull String text);
@@ -106,7 +106,7 @@ public Builder from(SpeakV2Speak other) {
}
/**
- * The input text to synthesize. Inline pause and pronunciation controls are not yet applied; they are stripped from the text before synthesis.
+ * The input text to synthesize. May contain inline pronunciation controls (\{"word": "...", "pronounce": "<IPA>"\}), which are in Early Access. Inline pause controls are supported on the batch (REST) transport only; a pause marker sent over the WebSocket fails the connection with DATA-0002. Pronunciation cannot be combined with a speed other than 1.0: text carrying a pronunciation control on a session opened with speed, or after a Configure that set it, also fails the connection with DATA-0002. See Speed, Pause, Pronunciation.
* @return Reference to {@code this} so that method calls can be chained together.
*/
@java.lang.Override
diff --git a/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2SpeechInterruptedMetadata.java b/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2SpeechInterruptedMetadata.java
index da249957..586f3c2e 100644
--- a/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2SpeechInterruptedMetadata.java
+++ b/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2SpeechInterruptedMetadata.java
@@ -79,7 +79,7 @@ public int getBillableCharacterCount() {
}
/**
- * @return Counts of the inline controls the server acted on during the turn. Inline pause and pronunciation controls are not applied at launch — support is coming soon — so every count is currently 0.
+ * @return Counts of the inline controls the server acted on during the turn. A pronunciation override that triggers an IPA warning is still applied best-effort and counted in pronunciations_applied; the warning is reported separately through a Warning and pronunciation_warnings.
*/
@JsonProperty("controls_applied")
public SpeakV2SpeechInterruptedMetadataControlsApplied getControlsApplied() {
@@ -156,7 +156,7 @@ public interface BillableCharacterCountStage {
public interface ControlsAppliedStage {
/**
- * Counts of the inline controls the server acted on during the turn. Inline pause and pronunciation controls are not applied at launch — support is coming soon — so every count is currently 0.
+ * Counts of the inline controls the server acted on during the turn. A pronunciation override that triggers an IPA warning is still applied best-effort and counted in pronunciations_applied; the warning is reported separately through a Warning and pronunciation_warnings.
*/
_FinalStage controlsApplied(@NotNull SpeakV2SpeechInterruptedMetadataControlsApplied controlsApplied);
}
@@ -247,7 +247,7 @@ public ControlsAppliedStage billableCharacterCount(int billableCharacterCount) {
}
/**
- * Counts of the inline controls the server acted on during the turn. Inline pause and pronunciation controls are not applied at launch — support is coming soon — so every count is currently 0.
+ * Counts of the inline controls the server acted on during the turn. A pronunciation override that triggers an IPA warning is still applied best-effort and counted in pronunciations_applied; the warning is reported separately through a Warning and pronunciation_warnings.
* @return Reference to {@code this} so that method calls can be chained together.
*/
@java.lang.Override
diff --git a/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2SpeechInterruptedMetadataControlsApplied.java b/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2SpeechInterruptedMetadataControlsApplied.java
index 85000d9a..0d0e0dce 100644
--- a/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2SpeechInterruptedMetadataControlsApplied.java
+++ b/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2SpeechInterruptedMetadataControlsApplied.java
@@ -38,7 +38,7 @@ private SpeakV2SpeechInterruptedMetadataControlsApplied(
}
/**
- * @return Pronunciation overrides successfully applied. Mirrors the Aura-2 dg-pronunciations-applied REST header. Currently always 0.
+ * @return Pronunciation overrides successfully applied. Mirrors the Aura-2 dg-pronunciations-applied REST header.
*/
@JsonProperty("pronunciations_applied")
public int getPronunciationsApplied() {
@@ -46,7 +46,7 @@ public int getPronunciationsApplied() {
}
/**
- * @return Pause (break) controls successfully applied. Mirrors the Aura-2 dg-breaks-applied REST header. Currently always 0.
+ * @return Pause (break) controls successfully applied. Mirrors the Aura-2 dg-breaks-applied REST header. Always 0 on the WebSocket, where inline pause controls are not supported.
*/
@JsonProperty("breaks_applied")
public int getBreaksApplied() {
@@ -54,7 +54,7 @@ public int getBreaksApplied() {
}
/**
- * @return Pronunciation entries that triggered a warning (invalid IPA, word too long). Mirrors the Aura-2 dg-pronunciation-warnings REST header. Currently always 0.
+ * @return Pronunciation entries that triggered a warning (invalid IPA, word too long). On batch requests the corresponding PRON-NNN codes are returned in the dg-warnings response header.
*/
@JsonProperty("pronunciation_warnings")
public int getPronunciationWarnings() {
@@ -95,7 +95,7 @@ public static PronunciationsAppliedStage builder() {
public interface PronunciationsAppliedStage {
/**
- * Pronunciation overrides successfully applied. Mirrors the Aura-2 dg-pronunciations-applied REST header. Currently always 0.
+ * Pronunciation overrides successfully applied. Mirrors the Aura-2 dg-pronunciations-applied REST header.
*/
BreaksAppliedStage pronunciationsApplied(int pronunciationsApplied);
@@ -104,14 +104,14 @@ public interface PronunciationsAppliedStage {
public interface BreaksAppliedStage {
/**
- * Pause (break) controls successfully applied. Mirrors the Aura-2 dg-breaks-applied REST header. Currently always 0.
+ * Pause (break) controls successfully applied. Mirrors the Aura-2 dg-breaks-applied REST header. Always 0 on the WebSocket, where inline pause controls are not supported.
*/
PronunciationWarningsStage breaksApplied(int breaksApplied);
}
public interface PronunciationWarningsStage {
/**
- * Pronunciation entries that triggered a warning (invalid IPA, word too long). Mirrors the Aura-2 dg-pronunciation-warnings REST header. Currently always 0.
+ * Pronunciation entries that triggered a warning (invalid IPA, word too long). On batch requests the corresponding PRON-NNN codes are returned in the dg-warnings response header.
*/
_FinalStage pronunciationWarnings(int pronunciationWarnings);
}
@@ -147,7 +147,7 @@ public Builder from(SpeakV2SpeechInterruptedMetadataControlsApplied other) {
}
/**
- * Pronunciation overrides successfully applied. Mirrors the Aura-2 dg-pronunciations-applied REST header. Currently always 0.
+ * Pronunciation overrides successfully applied. Mirrors the Aura-2 dg-pronunciations-applied REST header.
* @return Reference to {@code this} so that method calls can be chained together.
*/
@java.lang.Override
@@ -158,7 +158,7 @@ public BreaksAppliedStage pronunciationsApplied(int pronunciationsApplied) {
}
/**
- * Pause (break) controls successfully applied. Mirrors the Aura-2 dg-breaks-applied REST header. Currently always 0.
+ * Pause (break) controls successfully applied. Mirrors the Aura-2 dg-breaks-applied REST header. Always 0 on the WebSocket, where inline pause controls are not supported.
* @return Reference to {@code this} so that method calls can be chained together.
*/
@java.lang.Override
@@ -169,7 +169,7 @@ public PronunciationWarningsStage breaksApplied(int breaksApplied) {
}
/**
- * Pronunciation entries that triggered a warning (invalid IPA, word too long). Mirrors the Aura-2 dg-pronunciation-warnings REST header. Currently always 0.
+ * Pronunciation entries that triggered a warning (invalid IPA, word too long). On batch requests the corresponding PRON-NNN codes are returned in the dg-warnings response header.
* @return Reference to {@code this} so that method calls can be chained together.
*/
@java.lang.Override
diff --git a/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2SpeechMetadata.java b/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2SpeechMetadata.java
index d982b95e..be1ab9f4 100644
--- a/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2SpeechMetadata.java
+++ b/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2SpeechMetadata.java
@@ -87,7 +87,7 @@ public int getBillableCharacterCount() {
}
/**
- * @return Counts of the inline controls the server acted on during the turn. Inline pause and pronunciation controls are not applied at launch — support is coming soon — so every count is currently 0.
+ * @return Counts of the inline controls the server acted on during the turn. A pronunciation override that triggers an IPA warning is still applied best-effort and counted in pronunciations_applied; the warning is reported separately through a Warning and pronunciation_warnings.
*/
@JsonProperty("controls_applied")
public SpeakV2SpeechMetadataControlsApplied getControlsApplied() {
@@ -164,7 +164,7 @@ public interface BillableCharacterCountStage {
public interface ControlsAppliedStage {
/**
- * Counts of the inline controls the server acted on during the turn. Inline pause and pronunciation controls are not applied at launch — support is coming soon — so every count is currently 0.
+ * Counts of the inline controls the server acted on during the turn. A pronunciation override that triggers an IPA warning is still applied best-effort and counted in pronunciations_applied; the warning is reported separately through a Warning and pronunciation_warnings.
*/
_FinalStage controlsApplied(@NotNull SpeakV2SpeechMetadataControlsApplied controlsApplied);
}
@@ -255,7 +255,7 @@ public ControlsAppliedStage billableCharacterCount(int billableCharacterCount) {
}
/**
- * Counts of the inline controls the server acted on during the turn. Inline pause and pronunciation controls are not applied at launch — support is coming soon — so every count is currently 0.
+ * Counts of the inline controls the server acted on during the turn. A pronunciation override that triggers an IPA warning is still applied best-effort and counted in pronunciations_applied; the warning is reported separately through a Warning and pronunciation_warnings.
* @return Reference to {@code this} so that method calls can be chained together.
*/
@java.lang.Override
diff --git a/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2SpeechMetadataControlsApplied.java b/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2SpeechMetadataControlsApplied.java
index b258f91e..ddf185a7 100644
--- a/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2SpeechMetadataControlsApplied.java
+++ b/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2SpeechMetadataControlsApplied.java
@@ -38,7 +38,7 @@ private SpeakV2SpeechMetadataControlsApplied(
}
/**
- * @return Pronunciation overrides successfully applied. Mirrors the Aura-2 dg-pronunciations-applied REST header. Currently always 0.
+ * @return Pronunciation overrides successfully applied. Mirrors the Aura-2 dg-pronunciations-applied REST header.
*/
@JsonProperty("pronunciations_applied")
public int getPronunciationsApplied() {
@@ -46,7 +46,7 @@ public int getPronunciationsApplied() {
}
/**
- * @return Pause (break) controls successfully applied. Mirrors the Aura-2 dg-breaks-applied REST header. Currently always 0.
+ * @return Pause (break) controls successfully applied. Mirrors the Aura-2 dg-breaks-applied REST header. Always 0 on the WebSocket, where inline pause controls are not supported.
*/
@JsonProperty("breaks_applied")
public int getBreaksApplied() {
@@ -54,7 +54,7 @@ public int getBreaksApplied() {
}
/**
- * @return Pronunciation entries that triggered a warning (invalid IPA, word too long). Mirrors the Aura-2 dg-pronunciation-warnings REST header. Currently always 0.
+ * @return Pronunciation entries that triggered a warning (invalid IPA, word too long). On batch requests the corresponding PRON-NNN codes are returned in the dg-warnings response header.
*/
@JsonProperty("pronunciation_warnings")
public int getPronunciationWarnings() {
@@ -95,7 +95,7 @@ public static PronunciationsAppliedStage builder() {
public interface PronunciationsAppliedStage {
/**
- * Pronunciation overrides successfully applied. Mirrors the Aura-2 dg-pronunciations-applied REST header. Currently always 0.
+ * Pronunciation overrides successfully applied. Mirrors the Aura-2 dg-pronunciations-applied REST header.
*/
BreaksAppliedStage pronunciationsApplied(int pronunciationsApplied);
@@ -104,14 +104,14 @@ public interface PronunciationsAppliedStage {
public interface BreaksAppliedStage {
/**
- * Pause (break) controls successfully applied. Mirrors the Aura-2 dg-breaks-applied REST header. Currently always 0.
+ * Pause (break) controls successfully applied. Mirrors the Aura-2 dg-breaks-applied REST header. Always 0 on the WebSocket, where inline pause controls are not supported.
*/
PronunciationWarningsStage breaksApplied(int breaksApplied);
}
public interface PronunciationWarningsStage {
/**
- * Pronunciation entries that triggered a warning (invalid IPA, word too long). Mirrors the Aura-2 dg-pronunciation-warnings REST header. Currently always 0.
+ * Pronunciation entries that triggered a warning (invalid IPA, word too long). On batch requests the corresponding PRON-NNN codes are returned in the dg-warnings response header.
*/
_FinalStage pronunciationWarnings(int pronunciationWarnings);
}
@@ -147,7 +147,7 @@ public Builder from(SpeakV2SpeechMetadataControlsApplied other) {
}
/**
- * Pronunciation overrides successfully applied. Mirrors the Aura-2 dg-pronunciations-applied REST header. Currently always 0.
+ * Pronunciation overrides successfully applied. Mirrors the Aura-2 dg-pronunciations-applied REST header.
* @return Reference to {@code this} so that method calls can be chained together.
*/
@java.lang.Override
@@ -158,7 +158,7 @@ public BreaksAppliedStage pronunciationsApplied(int pronunciationsApplied) {
}
/**
- * Pause (break) controls successfully applied. Mirrors the Aura-2 dg-breaks-applied REST header. Currently always 0.
+ * Pause (break) controls successfully applied. Mirrors the Aura-2 dg-breaks-applied REST header. Always 0 on the WebSocket, where inline pause controls are not supported.
* @return Reference to {@code this} so that method calls can be chained together.
*/
@java.lang.Override
@@ -169,7 +169,7 @@ public PronunciationWarningsStage breaksApplied(int breaksApplied) {
}
/**
- * Pronunciation entries that triggered a warning (invalid IPA, word too long). Mirrors the Aura-2 dg-pronunciation-warnings REST header. Currently always 0.
+ * Pronunciation entries that triggered a warning (invalid IPA, word too long). On batch requests the corresponding PRON-NNN codes are returned in the dg-warnings response header.
* @return Reference to {@code this} so that method calls can be chained together.
*/
@java.lang.Override
diff --git a/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Warning.java b/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Warning.java
index 0eb0b3c8..84332f94 100644
--- a/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Warning.java
+++ b/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Warning.java
@@ -42,7 +42,8 @@ public String getType() {
/**
* @return Warning code identifying the condition, in SCREAMING_SNAKE_CASE.
* Turn-scoped codes: NO_ACTIVE_SPEECH (a speech-scoped message arrived with no active turn), NO_SYNTHESIZABLE_TEXT (the turn's text was entirely whitespace or punctuation, so it produced no audio and is completed with a zero-duration SpeechMetadata), and SYNTHESIS_RETRYING (a synthesis request failed and is being retried).
- * Inline-control codes are reserved and not currently emitted, because inline pause and pronunciation controls are not yet applied: BREAKS_LIMIT_EXCEEDED (too many pause controls, or two pauses with no intervening text), BREAK_TOKENS_OUT_OF_RANGE (pause durations outside the range the model supports), BREAK_TOKENS_WITH_INVALID_INCREMENTS (pause durations off the model's supported increment), PRONUNCIATION_WARNINGS (a pronunciation override contained invalid IPA), PRONUNCIATION_TOO_LONG (an IPA string exceeded the length limit), PRONUNCIATIONS_LIMIT_EXCEEDED (too many pronunciation controls in one turn).
+ * Pronunciation codes: PRONUNCIATION_WARNINGS (a pronunciation override contained invalid IPA; it is still applied best-effort and counted in pronunciations_applied), PRONUNCIATION_TOO_LONG (an IPA string exceeded the length limit), PRONUNCIATIONS_LIMIT_EXCEEDED (too many pronunciation controls in one turn).
+ * Pause codes (BREAKS_LIMIT_EXCEEDED, BREAK_TOKENS_OUT_OF_RANGE, BREAK_TOKENS_WITH_INVALID_INCREMENTS) are reserved and not emitted: inline pause controls are batch-only, and a pause marker on the WebSocket fails the connection instead.
* Interrupt-scoped codes, each meaning the Interrupt was ignored: NO_AUDIO_GENERATED (the session has produced no audio yet, so there is nothing to interrupt), INTERRUPT_IN_PROGRESS (an earlier Interrupt is still being processed — at most one is handled at a time), INVALID_INTERRUPT_OFFSET (the playback_offset did not advance past the position a prior interrupt established).
*/
@JsonProperty("code")
@@ -91,7 +92,8 @@ public interface CodeStage {
/**
* Warning code identifying the condition, in SCREAMING_SNAKE_CASE.
* Turn-scoped codes: NO_ACTIVE_SPEECH (a speech-scoped message arrived with no active turn), NO_SYNTHESIZABLE_TEXT (the turn's text was entirely whitespace or punctuation, so it produced no audio and is completed with a zero-duration SpeechMetadata), and SYNTHESIS_RETRYING (a synthesis request failed and is being retried).
- * Inline-control codes are reserved and not currently emitted, because inline pause and pronunciation controls are not yet applied: BREAKS_LIMIT_EXCEEDED (too many pause controls, or two pauses with no intervening text), BREAK_TOKENS_OUT_OF_RANGE (pause durations outside the range the model supports), BREAK_TOKENS_WITH_INVALID_INCREMENTS (pause durations off the model's supported increment), PRONUNCIATION_WARNINGS (a pronunciation override contained invalid IPA), PRONUNCIATION_TOO_LONG (an IPA string exceeded the length limit), PRONUNCIATIONS_LIMIT_EXCEEDED (too many pronunciation controls in one turn).
+ * Pronunciation codes: PRONUNCIATION_WARNINGS (a pronunciation override contained invalid IPA; it is still applied best-effort and counted in pronunciations_applied), PRONUNCIATION_TOO_LONG (an IPA string exceeded the length limit), PRONUNCIATIONS_LIMIT_EXCEEDED (too many pronunciation controls in one turn).
+ * Pause codes (BREAKS_LIMIT_EXCEEDED, BREAK_TOKENS_OUT_OF_RANGE, BREAK_TOKENS_WITH_INVALID_INCREMENTS) are reserved and not emitted: inline pause controls are batch-only, and a pause marker on the WebSocket fails the connection instead.
* Interrupt-scoped codes, each meaning the Interrupt was ignored: NO_AUDIO_GENERATED (the session has produced no audio yet, so there is nothing to interrupt), INTERRUPT_IN_PROGRESS (an earlier Interrupt is still being processed — at most one is handled at a time), INVALID_INTERRUPT_OFFSET (the playback_offset did not advance past the position a prior interrupt established).
*/
DescriptionStage code(@NotNull String code);
@@ -135,7 +137,8 @@ public Builder from(SpeakV2Warning other) {
/**
* Warning code identifying the condition, in SCREAMING_SNAKE_CASE.
* Turn-scoped codes: NO_ACTIVE_SPEECH (a speech-scoped message arrived with no active turn), NO_SYNTHESIZABLE_TEXT (the turn's text was entirely whitespace or punctuation, so it produced no audio and is completed with a zero-duration SpeechMetadata), and SYNTHESIS_RETRYING (a synthesis request failed and is being retried).
- * Inline-control codes are reserved and not currently emitted, because inline pause and pronunciation controls are not yet applied: BREAKS_LIMIT_EXCEEDED (too many pause controls, or two pauses with no intervening text), BREAK_TOKENS_OUT_OF_RANGE (pause durations outside the range the model supports), BREAK_TOKENS_WITH_INVALID_INCREMENTS (pause durations off the model's supported increment), PRONUNCIATION_WARNINGS (a pronunciation override contained invalid IPA), PRONUNCIATION_TOO_LONG (an IPA string exceeded the length limit), PRONUNCIATIONS_LIMIT_EXCEEDED (too many pronunciation controls in one turn).
+ * Pronunciation codes: PRONUNCIATION_WARNINGS (a pronunciation override contained invalid IPA; it is still applied best-effort and counted in pronunciations_applied), PRONUNCIATION_TOO_LONG (an IPA string exceeded the length limit), PRONUNCIATIONS_LIMIT_EXCEEDED (too many pronunciation controls in one turn).
+ * Pause codes (BREAKS_LIMIT_EXCEEDED, BREAK_TOKENS_OUT_OF_RANGE, BREAK_TOKENS_WITH_INVALID_INCREMENTS) are reserved and not emitted: inline pause controls are batch-only, and a pause marker on the WebSocket fails the connection instead.
* Interrupt-scoped codes, each meaning the Interrupt was ignored: NO_AUDIO_GENERATED (the session has produced no audio yet, so there is nothing to interrupt), INTERRUPT_IN_PROGRESS (an earlier Interrupt is still being processed — at most one is handled at a time), INVALID_INTERRUPT_OFFSET (the playback_offset did not advance past the position a prior interrupt established).
* @return Reference to {@code this} so that method calls can be chained together.
*/
diff --git a/src/main/java/com/deepgram/resources/speak/v2/websocket/V2WebSocketClient.java b/src/main/java/com/deepgram/resources/speak/v2/websocket/V2WebSocketClient.java
index a94145db..b4e01f7a 100644
--- a/src/main/java/com/deepgram/resources/speak/v2/websocket/V2WebSocketClient.java
+++ b/src/main/java/com/deepgram/resources/speak/v2/websocket/V2WebSocketClient.java
@@ -3,8 +3,6 @@
*/
package com.deepgram.resources.speak.v2.websocket;
-// Manual patch - see .fernignore.
-
import com.deepgram.core.ClientOptions;
import com.deepgram.core.DisconnectReason;
import com.deepgram.core.ObjectMappers;
@@ -163,13 +161,22 @@ public CompletableFuture connect(V2ConnectOptions options) {
? this.reconnectOptions
: ReconnectingWebSocketListener.ReconnectOptions.builder().build();
this.reconnectingListener =
- new ReconnectingWebSocketListener(reconnectOpts, () -> {
- if (clientOptions.webSocketFactory().isPresent()) {
- return clientOptions.webSocketFactory().get().create(request, this.reconnectingListener);
- } else {
- return okHttpClient.newWebSocket(request, this.reconnectingListener);
- }
- }) {
+ new ReconnectingWebSocketListener(
+ reconnectOpts,
+ () -> {
+ if (clientOptions.isClosed()) {
+ throw new IllegalStateException("root client has been closed");
+ }
+ if (clientOptions.webSocketFactory().isPresent()) {
+ return clientOptions
+ .webSocketFactory()
+ .get()
+ .create(request, this.reconnectingListener);
+ } else {
+ return okHttpClient.newWebSocket(request, this.reconnectingListener);
+ }
+ },
+ clientOptions::isClosed) {
@Override
protected void onWebSocketOpen(WebSocket webSocket, Response response) {
readyState = WebSocketReadyState.OPEN;
@@ -208,6 +215,7 @@ protected void onWebSocketClosed(WebSocket webSocket, int code, String reason) {
}
}
};
+ clientOptions.registerWebSocket(this);
reconnectingListener.connect();
return connectionFuture;
}
@@ -216,6 +224,7 @@ protected void onWebSocketClosed(WebSocket webSocket, int code, String reason) {
* Disconnects the WebSocket connection and releases resources.
*/
public void disconnect() {
+ clientOptions.unregisterWebSocket(this);
if (reconnectingListener != null) {
reconnectingListener.disconnect();
}
diff --git a/src/main/java/com/deepgram/types/DeepgramModel.java b/src/main/java/com/deepgram/types/DeepgramModel.java
index 14a797cc..6444d7f7 100644
--- a/src/main/java/com/deepgram/types/DeepgramModel.java
+++ b/src/main/java/com/deepgram/types/DeepgramModel.java
@@ -3,8 +3,6 @@
*/
package com.deepgram.types;
-// Manual patch - see .fernignore.
-
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
diff --git a/src/main/java/com/deepgram/types/SharedIntents.java b/src/main/java/com/deepgram/types/SharedIntents.java
index c689861c..05799c25 100644
--- a/src/main/java/com/deepgram/types/SharedIntents.java
+++ b/src/main/java/com/deepgram/types/SharedIntents.java
@@ -13,6 +13,7 @@
import com.fasterxml.jackson.annotation.Nulls;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
@@ -20,18 +21,19 @@
@JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonDeserialize(builder = SharedIntents.Builder.class)
public final class SharedIntents {
- private final Optional results;
+ private final Optional> segments;
private final Map additionalProperties;
- private SharedIntents(Optional results, Map additionalProperties) {
- this.results = results;
+ private SharedIntents(
+ Optional> segments, Map additionalProperties) {
+ this.segments = segments;
this.additionalProperties = additionalProperties;
}
- @JsonProperty("results")
- public Optional getResults() {
- return results;
+ @JsonProperty("segments")
+ public Optional> getSegments() {
+ return segments;
}
@java.lang.Override
@@ -46,12 +48,12 @@ public Map getAdditionalProperties() {
}
private boolean equalTo(SharedIntents other) {
- return results.equals(other.results);
+ return segments.equals(other.segments);
}
@java.lang.Override
public int hashCode() {
- return Objects.hash(this.results);
+ return Objects.hash(this.segments);
}
@java.lang.Override
@@ -65,7 +67,7 @@ public static Builder builder() {
@JsonIgnoreProperties(ignoreUnknown = true)
public static final class Builder {
- private Optional results = Optional.empty();
+ private Optional> segments = Optional.empty();
@JsonAnySetter
private Map additionalProperties = new HashMap<>();
@@ -73,23 +75,23 @@ public static final class Builder {
private Builder() {}
public Builder from(SharedIntents other) {
- results(other.getResults());
+ segments(other.getSegments());
return this;
}
- @JsonSetter(value = "results", nulls = Nulls.SKIP)
- public Builder results(Optional results) {
- this.results = results;
+ @JsonSetter(value = "segments", nulls = Nulls.SKIP)
+ public Builder segments(Optional> segments) {
+ this.segments = segments;
return this;
}
- public Builder results(SharedIntentsResults results) {
- this.results = Optional.ofNullable(results);
+ public Builder segments(List segments) {
+ this.segments = Optional.ofNullable(segments);
return this;
}
public SharedIntents build() {
- return new SharedIntents(results, additionalProperties);
+ return new SharedIntents(segments, additionalProperties);
}
public Builder additionalProperty(String key, Object value) {
diff --git a/src/main/java/com/deepgram/types/SharedIntentsResults.java b/src/main/java/com/deepgram/types/SharedIntentsResults.java
deleted file mode 100644
index 44bfe377..00000000
--- a/src/main/java/com/deepgram/types/SharedIntentsResults.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/**
- * This file was auto-generated by Fern from our API Definition.
- */
-package com.deepgram.types;
-
-import com.deepgram.core.ObjectMappers;
-import com.fasterxml.jackson.annotation.JsonAnyGetter;
-import com.fasterxml.jackson.annotation.JsonAnySetter;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonSetter;
-import com.fasterxml.jackson.annotation.Nulls;
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-
-@JsonInclude(JsonInclude.Include.NON_ABSENT)
-@JsonDeserialize(builder = SharedIntentsResults.Builder.class)
-public final class SharedIntentsResults {
- private final Optional intents;
-
- private final Map additionalProperties;
-
- private SharedIntentsResults(
- Optional intents, Map additionalProperties) {
- this.intents = intents;
- this.additionalProperties = additionalProperties;
- }
-
- @JsonProperty("intents")
- public Optional getIntents() {
- return intents;
- }
-
- @java.lang.Override
- public boolean equals(Object other) {
- if (this == other) return true;
- return other instanceof SharedIntentsResults && equalTo((SharedIntentsResults) other);
- }
-
- @JsonAnyGetter
- public Map getAdditionalProperties() {
- return this.additionalProperties;
- }
-
- private boolean equalTo(SharedIntentsResults other) {
- return intents.equals(other.intents);
- }
-
- @java.lang.Override
- public int hashCode() {
- return Objects.hash(this.intents);
- }
-
- @java.lang.Override
- public String toString() {
- return ObjectMappers.stringify(this);
- }
-
- public static Builder builder() {
- return new Builder();
- }
-
- @JsonIgnoreProperties(ignoreUnknown = true)
- public static final class Builder {
- private Optional intents = Optional.empty();
-
- @JsonAnySetter
- private Map additionalProperties = new HashMap<>();
-
- private Builder() {}
-
- public Builder from(SharedIntentsResults other) {
- intents(other.getIntents());
- return this;
- }
-
- @JsonSetter(value = "intents", nulls = Nulls.SKIP)
- public Builder intents(Optional intents) {
- this.intents = intents;
- return this;
- }
-
- public Builder intents(SharedIntentsResultsIntents intents) {
- this.intents = Optional.ofNullable(intents);
- return this;
- }
-
- public SharedIntentsResults build() {
- return new SharedIntentsResults(intents, additionalProperties);
- }
-
- public Builder additionalProperty(String key, Object value) {
- this.additionalProperties.put(key, value);
- return this;
- }
-
- public Builder additionalProperties(Map additionalProperties) {
- this.additionalProperties.putAll(additionalProperties);
- return this;
- }
- }
-}
diff --git a/src/main/java/com/deepgram/types/SharedIntentsResultsIntents.java b/src/main/java/com/deepgram/types/SharedIntentsResultsIntents.java
deleted file mode 100644
index a5fe89b0..00000000
--- a/src/main/java/com/deepgram/types/SharedIntentsResultsIntents.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/**
- * This file was auto-generated by Fern from our API Definition.
- */
-package com.deepgram.types;
-
-import com.deepgram.core.ObjectMappers;
-import com.fasterxml.jackson.annotation.JsonAnyGetter;
-import com.fasterxml.jackson.annotation.JsonAnySetter;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonSetter;
-import com.fasterxml.jackson.annotation.Nulls;
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-
-@JsonInclude(JsonInclude.Include.NON_ABSENT)
-@JsonDeserialize(builder = SharedIntentsResultsIntents.Builder.class)
-public final class SharedIntentsResultsIntents {
- private final Optional> segments;
-
- private final Map additionalProperties;
-
- private SharedIntentsResultsIntents(
- Optional> segments,
- Map additionalProperties) {
- this.segments = segments;
- this.additionalProperties = additionalProperties;
- }
-
- @JsonProperty("segments")
- public Optional> getSegments() {
- return segments;
- }
-
- @java.lang.Override
- public boolean equals(Object other) {
- if (this == other) return true;
- return other instanceof SharedIntentsResultsIntents && equalTo((SharedIntentsResultsIntents) other);
- }
-
- @JsonAnyGetter
- public Map getAdditionalProperties() {
- return this.additionalProperties;
- }
-
- private boolean equalTo(SharedIntentsResultsIntents other) {
- return segments.equals(other.segments);
- }
-
- @java.lang.Override
- public int hashCode() {
- return Objects.hash(this.segments);
- }
-
- @java.lang.Override
- public String toString() {
- return ObjectMappers.stringify(this);
- }
-
- public static Builder builder() {
- return new Builder();
- }
-
- @JsonIgnoreProperties(ignoreUnknown = true)
- public static final class Builder {
- private Optional> segments = Optional.empty();
-
- @JsonAnySetter
- private Map additionalProperties = new HashMap<>();
-
- private Builder() {}
-
- public Builder from(SharedIntentsResultsIntents other) {
- segments(other.getSegments());
- return this;
- }
-
- @JsonSetter(value = "segments", nulls = Nulls.SKIP)
- public Builder segments(Optional> segments) {
- this.segments = segments;
- return this;
- }
-
- public Builder segments(List segments) {
- this.segments = Optional.ofNullable(segments);
- return this;
- }
-
- public SharedIntentsResultsIntents build() {
- return new SharedIntentsResultsIntents(segments, additionalProperties);
- }
-
- public Builder additionalProperty(String key, Object value) {
- this.additionalProperties.put(key, value);
- return this;
- }
-
- public Builder additionalProperties(Map additionalProperties) {
- this.additionalProperties.putAll(additionalProperties);
- return this;
- }
- }
-}
diff --git a/src/main/java/com/deepgram/types/SharedIntentsResultsIntentsSegmentsItem.java b/src/main/java/com/deepgram/types/SharedIntentsSegmentsItem.java
similarity index 78%
rename from src/main/java/com/deepgram/types/SharedIntentsResultsIntentsSegmentsItem.java
rename to src/main/java/com/deepgram/types/SharedIntentsSegmentsItem.java
index 694be4f6..431b68f0 100644
--- a/src/main/java/com/deepgram/types/SharedIntentsResultsIntentsSegmentsItem.java
+++ b/src/main/java/com/deepgram/types/SharedIntentsSegmentsItem.java
@@ -19,23 +19,23 @@
import java.util.Optional;
@JsonInclude(JsonInclude.Include.NON_ABSENT)
-@JsonDeserialize(builder = SharedIntentsResultsIntentsSegmentsItem.Builder.class)
-public final class SharedIntentsResultsIntentsSegmentsItem {
+@JsonDeserialize(builder = SharedIntentsSegmentsItem.Builder.class)
+public final class SharedIntentsSegmentsItem {
private final Optional text;
private final Optional startWord;
private final Optional endWord;
- private final Optional> intents;
+ private final Optional> intents;
private final Map additionalProperties;
- private SharedIntentsResultsIntentsSegmentsItem(
+ private SharedIntentsSegmentsItem(
Optional text,
Optional startWord,
Optional endWord,
- Optional> intents,
+ Optional> intents,
Map additionalProperties) {
this.text = text;
this.startWord = startWord;
@@ -60,15 +60,14 @@ public Optional getEndWord() {
}
@JsonProperty("intents")
- public Optional> getIntents() {
+ public Optional> getIntents() {
return intents;
}
@java.lang.Override
public boolean equals(Object other) {
if (this == other) return true;
- return other instanceof SharedIntentsResultsIntentsSegmentsItem
- && equalTo((SharedIntentsResultsIntentsSegmentsItem) other);
+ return other instanceof SharedIntentsSegmentsItem && equalTo((SharedIntentsSegmentsItem) other);
}
@JsonAnyGetter
@@ -76,7 +75,7 @@ public Map getAdditionalProperties() {
return this.additionalProperties;
}
- private boolean equalTo(SharedIntentsResultsIntentsSegmentsItem other) {
+ private boolean equalTo(SharedIntentsSegmentsItem other) {
return text.equals(other.text)
&& startWord.equals(other.startWord)
&& endWord.equals(other.endWord)
@@ -105,14 +104,14 @@ public static final class Builder {
private Optional endWord = Optional.empty();
- private Optional> intents = Optional.empty();
+ private Optional> intents = Optional.empty();
@JsonAnySetter
private Map additionalProperties = new HashMap<>();
private Builder() {}
- public Builder from(SharedIntentsResultsIntentsSegmentsItem other) {
+ public Builder from(SharedIntentsSegmentsItem other) {
text(other.getText());
startWord(other.getStartWord());
endWord(other.getEndWord());
@@ -154,18 +153,18 @@ public Builder endWord(Double endWord) {
}
@JsonSetter(value = "intents", nulls = Nulls.SKIP)
- public Builder intents(Optional> intents) {
+ public Builder intents(Optional> intents) {
this.intents = intents;
return this;
}
- public Builder intents(List intents) {
+ public Builder intents(List intents) {
this.intents = Optional.ofNullable(intents);
return this;
}
- public SharedIntentsResultsIntentsSegmentsItem build() {
- return new SharedIntentsResultsIntentsSegmentsItem(text, startWord, endWord, intents, additionalProperties);
+ public SharedIntentsSegmentsItem build() {
+ return new SharedIntentsSegmentsItem(text, startWord, endWord, intents, additionalProperties);
}
public Builder additionalProperty(String key, Object value) {
diff --git a/src/main/java/com/deepgram/types/SharedIntentsResultsIntentsSegmentsItemIntentsItem.java b/src/main/java/com/deepgram/types/SharedIntentsSegmentsItemIntentsItem.java
similarity index 81%
rename from src/main/java/com/deepgram/types/SharedIntentsResultsIntentsSegmentsItemIntentsItem.java
rename to src/main/java/com/deepgram/types/SharedIntentsSegmentsItemIntentsItem.java
index d6554e2b..9f97c919 100644
--- a/src/main/java/com/deepgram/types/SharedIntentsResultsIntentsSegmentsItemIntentsItem.java
+++ b/src/main/java/com/deepgram/types/SharedIntentsSegmentsItemIntentsItem.java
@@ -18,15 +18,15 @@
import java.util.Optional;
@JsonInclude(JsonInclude.Include.NON_ABSENT)
-@JsonDeserialize(builder = SharedIntentsResultsIntentsSegmentsItemIntentsItem.Builder.class)
-public final class SharedIntentsResultsIntentsSegmentsItemIntentsItem {
+@JsonDeserialize(builder = SharedIntentsSegmentsItemIntentsItem.Builder.class)
+public final class SharedIntentsSegmentsItemIntentsItem {
private final Optional intent;
private final Optional confidenceScore;
private final Map additionalProperties;
- private SharedIntentsResultsIntentsSegmentsItemIntentsItem(
+ private SharedIntentsSegmentsItemIntentsItem(
Optional intent, Optional confidenceScore, Map additionalProperties) {
this.intent = intent;
this.confidenceScore = confidenceScore;
@@ -46,8 +46,8 @@ public Optional getConfidenceScore() {
@java.lang.Override
public boolean equals(Object other) {
if (this == other) return true;
- return other instanceof SharedIntentsResultsIntentsSegmentsItemIntentsItem
- && equalTo((SharedIntentsResultsIntentsSegmentsItemIntentsItem) other);
+ return other instanceof SharedIntentsSegmentsItemIntentsItem
+ && equalTo((SharedIntentsSegmentsItemIntentsItem) other);
}
@JsonAnyGetter
@@ -55,7 +55,7 @@ public Map getAdditionalProperties() {
return this.additionalProperties;
}
- private boolean equalTo(SharedIntentsResultsIntentsSegmentsItemIntentsItem other) {
+ private boolean equalTo(SharedIntentsSegmentsItemIntentsItem other) {
return intent.equals(other.intent) && confidenceScore.equals(other.confidenceScore);
}
@@ -84,7 +84,7 @@ public static final class Builder {
private Builder() {}
- public Builder from(SharedIntentsResultsIntentsSegmentsItemIntentsItem other) {
+ public Builder from(SharedIntentsSegmentsItemIntentsItem other) {
intent(other.getIntent());
confidenceScore(other.getConfidenceScore());
return this;
@@ -112,9 +112,8 @@ public Builder confidenceScore(Float confidenceScore) {
return this;
}
- public SharedIntentsResultsIntentsSegmentsItemIntentsItem build() {
- return new SharedIntentsResultsIntentsSegmentsItemIntentsItem(
- intent, confidenceScore, additionalProperties);
+ public SharedIntentsSegmentsItemIntentsItem build() {
+ return new SharedIntentsSegmentsItemIntentsItem(intent, confidenceScore, additionalProperties);
}
public Builder additionalProperty(String key, Object value) {
diff --git a/src/main/java/com/deepgram/types/SharedTopics.java b/src/main/java/com/deepgram/types/SharedTopics.java
index 463e84ca..25a75ea4 100644
--- a/src/main/java/com/deepgram/types/SharedTopics.java
+++ b/src/main/java/com/deepgram/types/SharedTopics.java
@@ -13,6 +13,7 @@
import com.fasterxml.jackson.annotation.Nulls;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
@@ -20,18 +21,18 @@
@JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonDeserialize(builder = SharedTopics.Builder.class)
public final class SharedTopics {
- private final Optional results;
+ private final Optional> segments;
private final Map additionalProperties;
- private SharedTopics(Optional results, Map additionalProperties) {
- this.results = results;
+ private SharedTopics(Optional> segments, Map additionalProperties) {
+ this.segments = segments;
this.additionalProperties = additionalProperties;
}
- @JsonProperty("results")
- public Optional getResults() {
- return results;
+ @JsonProperty("segments")
+ public Optional> getSegments() {
+ return segments;
}
@java.lang.Override
@@ -46,12 +47,12 @@ public Map getAdditionalProperties() {
}
private boolean equalTo(SharedTopics other) {
- return results.equals(other.results);
+ return segments.equals(other.segments);
}
@java.lang.Override
public int hashCode() {
- return Objects.hash(this.results);
+ return Objects.hash(this.segments);
}
@java.lang.Override
@@ -65,7 +66,7 @@ public static Builder builder() {
@JsonIgnoreProperties(ignoreUnknown = true)
public static final class Builder {
- private Optional results = Optional.empty();
+ private Optional> segments = Optional.empty();
@JsonAnySetter
private Map additionalProperties = new HashMap<>();
@@ -73,23 +74,23 @@ public static final class Builder {
private Builder() {}
public Builder from(SharedTopics other) {
- results(other.getResults());
+ segments(other.getSegments());
return this;
}
- @JsonSetter(value = "results", nulls = Nulls.SKIP)
- public Builder results(Optional results) {
- this.results = results;
+ @JsonSetter(value = "segments", nulls = Nulls.SKIP)
+ public Builder segments(Optional> segments) {
+ this.segments = segments;
return this;
}
- public Builder results(SharedTopicsResults results) {
- this.results = Optional.ofNullable(results);
+ public Builder segments(List segments) {
+ this.segments = Optional.ofNullable(segments);
return this;
}
public SharedTopics build() {
- return new SharedTopics(results, additionalProperties);
+ return new SharedTopics(segments, additionalProperties);
}
public Builder additionalProperty(String key, Object value) {
diff --git a/src/main/java/com/deepgram/types/SharedTopicsResults.java b/src/main/java/com/deepgram/types/SharedTopicsResults.java
deleted file mode 100644
index d25c8cc9..00000000
--- a/src/main/java/com/deepgram/types/SharedTopicsResults.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/**
- * This file was auto-generated by Fern from our API Definition.
- */
-package com.deepgram.types;
-
-import com.deepgram.core.ObjectMappers;
-import com.fasterxml.jackson.annotation.JsonAnyGetter;
-import com.fasterxml.jackson.annotation.JsonAnySetter;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonSetter;
-import com.fasterxml.jackson.annotation.Nulls;
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-
-@JsonInclude(JsonInclude.Include.NON_ABSENT)
-@JsonDeserialize(builder = SharedTopicsResults.Builder.class)
-public final class SharedTopicsResults {
- private final Optional topics;
-
- private final Map additionalProperties;
-
- private SharedTopicsResults(Optional topics, Map additionalProperties) {
- this.topics = topics;
- this.additionalProperties = additionalProperties;
- }
-
- @JsonProperty("topics")
- public Optional getTopics() {
- return topics;
- }
-
- @java.lang.Override
- public boolean equals(Object other) {
- if (this == other) return true;
- return other instanceof SharedTopicsResults && equalTo((SharedTopicsResults) other);
- }
-
- @JsonAnyGetter
- public Map getAdditionalProperties() {
- return this.additionalProperties;
- }
-
- private boolean equalTo(SharedTopicsResults other) {
- return topics.equals(other.topics);
- }
-
- @java.lang.Override
- public int hashCode() {
- return Objects.hash(this.topics);
- }
-
- @java.lang.Override
- public String toString() {
- return ObjectMappers.stringify(this);
- }
-
- public static Builder builder() {
- return new Builder();
- }
-
- @JsonIgnoreProperties(ignoreUnknown = true)
- public static final class Builder {
- private Optional topics = Optional.empty();
-
- @JsonAnySetter
- private Map additionalProperties = new HashMap<>();
-
- private Builder() {}
-
- public Builder from(SharedTopicsResults other) {
- topics(other.getTopics());
- return this;
- }
-
- @JsonSetter(value = "topics", nulls = Nulls.SKIP)
- public Builder topics(Optional topics) {
- this.topics = topics;
- return this;
- }
-
- public Builder topics(SharedTopicsResultsTopics topics) {
- this.topics = Optional.ofNullable(topics);
- return this;
- }
-
- public SharedTopicsResults build() {
- return new SharedTopicsResults(topics, additionalProperties);
- }
-
- public Builder additionalProperty(String key, Object value) {
- this.additionalProperties.put(key, value);
- return this;
- }
-
- public Builder additionalProperties(Map additionalProperties) {
- this.additionalProperties.putAll(additionalProperties);
- return this;
- }
- }
-}
diff --git a/src/main/java/com/deepgram/types/SharedTopicsResultsTopics.java b/src/main/java/com/deepgram/types/SharedTopicsResultsTopics.java
deleted file mode 100644
index e3a1cbba..00000000
--- a/src/main/java/com/deepgram/types/SharedTopicsResultsTopics.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/**
- * This file was auto-generated by Fern from our API Definition.
- */
-package com.deepgram.types;
-
-import com.deepgram.core.ObjectMappers;
-import com.fasterxml.jackson.annotation.JsonAnyGetter;
-import com.fasterxml.jackson.annotation.JsonAnySetter;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonSetter;
-import com.fasterxml.jackson.annotation.Nulls;
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-
-@JsonInclude(JsonInclude.Include.NON_ABSENT)
-@JsonDeserialize(builder = SharedTopicsResultsTopics.Builder.class)
-public final class SharedTopicsResultsTopics {
- private final Optional> segments;
-
- private final Map additionalProperties;
-
- private SharedTopicsResultsTopics(
- Optional> segments, Map additionalProperties) {
- this.segments = segments;
- this.additionalProperties = additionalProperties;
- }
-
- @JsonProperty("segments")
- public Optional> getSegments() {
- return segments;
- }
-
- @java.lang.Override
- public boolean equals(Object other) {
- if (this == other) return true;
- return other instanceof SharedTopicsResultsTopics && equalTo((SharedTopicsResultsTopics) other);
- }
-
- @JsonAnyGetter
- public Map getAdditionalProperties() {
- return this.additionalProperties;
- }
-
- private boolean equalTo(SharedTopicsResultsTopics other) {
- return segments.equals(other.segments);
- }
-
- @java.lang.Override
- public int hashCode() {
- return Objects.hash(this.segments);
- }
-
- @java.lang.Override
- public String toString() {
- return ObjectMappers.stringify(this);
- }
-
- public static Builder builder() {
- return new Builder();
- }
-
- @JsonIgnoreProperties(ignoreUnknown = true)
- public static final class Builder {
- private Optional> segments = Optional.empty();
-
- @JsonAnySetter
- private Map additionalProperties = new HashMap<>();
-
- private Builder() {}
-
- public Builder from(SharedTopicsResultsTopics other) {
- segments(other.getSegments());
- return this;
- }
-
- @JsonSetter(value = "segments", nulls = Nulls.SKIP)
- public Builder segments(Optional> segments) {
- this.segments = segments;
- return this;
- }
-
- public Builder segments(List segments) {
- this.segments = Optional.ofNullable(segments);
- return this;
- }
-
- public SharedTopicsResultsTopics build() {
- return new SharedTopicsResultsTopics(segments, additionalProperties);
- }
-
- public Builder additionalProperty(String key, Object value) {
- this.additionalProperties.put(key, value);
- return this;
- }
-
- public Builder additionalProperties(Map additionalProperties) {
- this.additionalProperties.putAll(additionalProperties);
- return this;
- }
- }
-}
diff --git a/src/main/java/com/deepgram/types/SharedTopicsResultsTopicsSegmentsItem.java b/src/main/java/com/deepgram/types/SharedTopicsSegmentsItem.java
similarity index 78%
rename from src/main/java/com/deepgram/types/SharedTopicsResultsTopicsSegmentsItem.java
rename to src/main/java/com/deepgram/types/SharedTopicsSegmentsItem.java
index 19cd942e..b479076e 100644
--- a/src/main/java/com/deepgram/types/SharedTopicsResultsTopicsSegmentsItem.java
+++ b/src/main/java/com/deepgram/types/SharedTopicsSegmentsItem.java
@@ -19,23 +19,23 @@
import java.util.Optional;
@JsonInclude(JsonInclude.Include.NON_ABSENT)
-@JsonDeserialize(builder = SharedTopicsResultsTopicsSegmentsItem.Builder.class)
-public final class SharedTopicsResultsTopicsSegmentsItem {
+@JsonDeserialize(builder = SharedTopicsSegmentsItem.Builder.class)
+public final class SharedTopicsSegmentsItem {
private final Optional text;
private final Optional startWord;
private final Optional endWord;
- private final Optional> topics;
+ private final Optional> topics;
private final Map additionalProperties;
- private SharedTopicsResultsTopicsSegmentsItem(
+ private SharedTopicsSegmentsItem(
Optional text,
Optional startWord,
Optional endWord,
- Optional> topics,
+ Optional> topics,
Map additionalProperties) {
this.text = text;
this.startWord = startWord;
@@ -60,15 +60,14 @@ public Optional getEndWord() {
}
@JsonProperty("topics")
- public Optional> getTopics() {
+ public Optional> getTopics() {
return topics;
}
@java.lang.Override
public boolean equals(Object other) {
if (this == other) return true;
- return other instanceof SharedTopicsResultsTopicsSegmentsItem
- && equalTo((SharedTopicsResultsTopicsSegmentsItem) other);
+ return other instanceof SharedTopicsSegmentsItem && equalTo((SharedTopicsSegmentsItem) other);
}
@JsonAnyGetter
@@ -76,7 +75,7 @@ public Map getAdditionalProperties() {
return this.additionalProperties;
}
- private boolean equalTo(SharedTopicsResultsTopicsSegmentsItem other) {
+ private boolean equalTo(SharedTopicsSegmentsItem other) {
return text.equals(other.text)
&& startWord.equals(other.startWord)
&& endWord.equals(other.endWord)
@@ -105,14 +104,14 @@ public static final class Builder {
private Optional endWord = Optional.empty();
- private Optional> topics = Optional.empty();
+ private Optional> topics = Optional.empty();
@JsonAnySetter
private Map additionalProperties = new HashMap<>();
private Builder() {}
- public Builder from(SharedTopicsResultsTopicsSegmentsItem other) {
+ public Builder from(SharedTopicsSegmentsItem other) {
text(other.getText());
startWord(other.getStartWord());
endWord(other.getEndWord());
@@ -154,18 +153,18 @@ public Builder endWord(Double endWord) {
}
@JsonSetter(value = "topics", nulls = Nulls.SKIP)
- public Builder topics(Optional> topics) {
+ public Builder topics(Optional> topics) {
this.topics = topics;
return this;
}
- public Builder topics(List topics) {
+ public Builder topics(List topics) {
this.topics = Optional.ofNullable(topics);
return this;
}
- public SharedTopicsResultsTopicsSegmentsItem build() {
- return new SharedTopicsResultsTopicsSegmentsItem(text, startWord, endWord, topics, additionalProperties);
+ public SharedTopicsSegmentsItem build() {
+ return new SharedTopicsSegmentsItem(text, startWord, endWord, topics, additionalProperties);
}
public Builder additionalProperty(String key, Object value) {
diff --git a/src/main/java/com/deepgram/types/SharedTopicsResultsTopicsSegmentsItemTopicsItem.java b/src/main/java/com/deepgram/types/SharedTopicsSegmentsItemTopicsItem.java
similarity index 82%
rename from src/main/java/com/deepgram/types/SharedTopicsResultsTopicsSegmentsItemTopicsItem.java
rename to src/main/java/com/deepgram/types/SharedTopicsSegmentsItemTopicsItem.java
index 3721cd8b..03464d24 100644
--- a/src/main/java/com/deepgram/types/SharedTopicsResultsTopicsSegmentsItemTopicsItem.java
+++ b/src/main/java/com/deepgram/types/SharedTopicsSegmentsItemTopicsItem.java
@@ -18,15 +18,15 @@
import java.util.Optional;
@JsonInclude(JsonInclude.Include.NON_ABSENT)
-@JsonDeserialize(builder = SharedTopicsResultsTopicsSegmentsItemTopicsItem.Builder.class)
-public final class SharedTopicsResultsTopicsSegmentsItemTopicsItem {
+@JsonDeserialize(builder = SharedTopicsSegmentsItemTopicsItem.Builder.class)
+public final class SharedTopicsSegmentsItemTopicsItem {
private final Optional topic;
private final Optional confidenceScore;
private final Map additionalProperties;
- private SharedTopicsResultsTopicsSegmentsItemTopicsItem(
+ private SharedTopicsSegmentsItemTopicsItem(
Optional topic, Optional confidenceScore, Map additionalProperties) {
this.topic = topic;
this.confidenceScore = confidenceScore;
@@ -46,8 +46,8 @@ public Optional getConfidenceScore() {
@java.lang.Override
public boolean equals(Object other) {
if (this == other) return true;
- return other instanceof SharedTopicsResultsTopicsSegmentsItemTopicsItem
- && equalTo((SharedTopicsResultsTopicsSegmentsItemTopicsItem) other);
+ return other instanceof SharedTopicsSegmentsItemTopicsItem
+ && equalTo((SharedTopicsSegmentsItemTopicsItem) other);
}
@JsonAnyGetter
@@ -55,7 +55,7 @@ public Map getAdditionalProperties() {
return this.additionalProperties;
}
- private boolean equalTo(SharedTopicsResultsTopicsSegmentsItemTopicsItem other) {
+ private boolean equalTo(SharedTopicsSegmentsItemTopicsItem other) {
return topic.equals(other.topic) && confidenceScore.equals(other.confidenceScore);
}
@@ -84,7 +84,7 @@ public static final class Builder {
private Builder() {}
- public Builder from(SharedTopicsResultsTopicsSegmentsItemTopicsItem other) {
+ public Builder from(SharedTopicsSegmentsItemTopicsItem other) {
topic(other.getTopic());
confidenceScore(other.getConfidenceScore());
return this;
@@ -112,8 +112,8 @@ public Builder confidenceScore(Float confidenceScore) {
return this;
}
- public SharedTopicsResultsTopicsSegmentsItemTopicsItem build() {
- return new SharedTopicsResultsTopicsSegmentsItemTopicsItem(topic, confidenceScore, additionalProperties);
+ public SharedTopicsSegmentsItemTopicsItem build() {
+ return new SharedTopicsSegmentsItemTopicsItem(topic, confidenceScore, additionalProperties);
}
public Builder additionalProperty(String key, Object value) {
diff --git a/src/test/java/com/deepgram/ClientBuilderTest.java b/src/test/java/com/deepgram/ClientBuilderTest.java
index 01d0f680..348164c6 100644
--- a/src/test/java/com/deepgram/ClientBuilderTest.java
+++ b/src/test/java/com/deepgram/ClientBuilderTest.java
@@ -3,8 +3,19 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import com.deepgram.core.ClientOptions;
import com.deepgram.core.Environment;
+import com.deepgram.core.WebSocketFactory;
+import com.deepgram.resources.listen.v1.websocket.V1ConnectOptions;
+import com.deepgram.resources.listen.v1.websocket.V1WebSocketClient;
+import com.deepgram.types.ListenV1Model;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.WebSocket;
+import okio.ByteString;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
@@ -193,6 +204,74 @@ void closesWebSocketClientsBeforeConnecting() {
}
}
+ @Test
+ @DisplayName("closing the root client closes a connected WebSocket and blocks reconnects")
+ void closesConnectedWebSocketAndBlocksReconnects() throws Exception {
+ CountDownLatch closed = new CountDownLatch(1);
+ AtomicInteger connectionAttempts = new AtomicInteger();
+ WebSocket connectedSocket = new WebSocket() {
+ @Override
+ public Request request() {
+ return new Request.Builder().url("http://localhost/").build();
+ }
+
+ @Override
+ public long queueSize() {
+ return 0;
+ }
+
+ @Override
+ public boolean send(String text) {
+ return true;
+ }
+
+ @Override
+ public boolean send(ByteString bytes) {
+ return true;
+ }
+
+ @Override
+ public boolean close(int code, String reason) {
+ closed.countDown();
+ return true;
+ }
+
+ @Override
+ public void cancel() {}
+ };
+ WebSocketFactory factory = (request, listener) -> {
+ connectionAttempts.incrementAndGet();
+ listener.onOpen(connectedSocket, null);
+ return connectedSocket;
+ };
+ DeepgramClient client = new DeepgramClient(ClientOptions.builder()
+ .environment(Environment.PRODUCTION)
+ .webSocketFactory(factory)
+ .build());
+ V1WebSocketClient webSocket = client.listen().v1().v1WebSocket();
+ V1ConnectOptions options =
+ V1ConnectOptions.builder().model(ListenV1Model.NOVA3).build();
+
+ try {
+ webSocket.connect(options).get(5, TimeUnit.SECONDS);
+ assertThat(connectionAttempts).hasValue(1);
+
+ client.close();
+
+ assertThat(closed.await(5, TimeUnit.SECONDS))
+ .as("root close disconnects the active WebSocket")
+ .isTrue();
+ assertThatThrownBy(() -> webSocket.connect(options))
+ .isInstanceOf(IllegalStateException.class)
+ .hasMessage("root client has been closed");
+ assertThat(connectionAttempts)
+ .as("closed clients do not open another WebSocket")
+ .hasValue(1);
+ } finally {
+ client.close();
+ }
+ }
+
@Test
@DisplayName("closing a client does not release caller-owned HTTP resources")
void doesNotCloseCustomClientResources() {
diff --git a/src/test/java/com/deepgram/IntegrationTest.java b/src/test/java/com/deepgram/IntegrationTest.java
index a6c2ef1c..251a37cb 100644
--- a/src/test/java/com/deepgram/IntegrationTest.java
+++ b/src/test/java/com/deepgram/IntegrationTest.java
@@ -14,9 +14,13 @@
import com.deepgram.resources.listen.v2.types.ListenV2TurnInfoEvent;
import com.deepgram.resources.read.v1.text.requests.TextAnalyzeRequest;
import com.deepgram.resources.speak.v1.audio.requests.SpeakV1Request;
+import com.deepgram.resources.speak.v2.audio.requests.SpeakV2Request;
+import com.deepgram.resources.speak.v2.audio.types.AudioGenerateRequestEncoding;
import com.deepgram.resources.speak.v2.types.SpeakV2Close;
import com.deepgram.resources.speak.v2.types.SpeakV2Flush;
import com.deepgram.resources.speak.v2.types.SpeakV2Speak;
+import com.deepgram.resources.speak.v2.types.SpeakV2SpeechMetadata;
+import com.deepgram.resources.speak.v2.types.SpeakV2SpeechMetadataControlsApplied;
import com.deepgram.resources.speak.v2.websocket.V2ConnectOptions;
import com.deepgram.resources.speak.v2.websocket.V2WebSocketClient;
import com.deepgram.types.ListProjectsV1Response;
@@ -90,6 +94,14 @@ void setUp() {
client = builder.build();
}
+ private void assumeFluxTtsControlsEnabled() {
+ // Controls are Early Access, so deployments opt in until production availability is universal.
+ String enabled = System.getenv("DEEPGRAM_FLUX_TTS_CONTROLS");
+ org.junit.jupiter.api.Assumptions.assumeTrue(
+ enabled != null && !enabled.isEmpty(),
+ "DEEPGRAM_FLUX_TTS_CONTROLS not set, skipping Flux TTS Controls integration test");
+ }
+
// --- Tier 1: Must pass before release ---
@Nested
@@ -330,6 +342,124 @@ void testIntegration_SpeakV2WebSocket() throws Exception {
}
}
+ @Test
+ @DisplayName("SpeakV2ControlsBatchPause - synthesize batch audio with a pause control")
+ void testIntegration_SpeakV2ControlsBatchPause() throws Exception {
+ assumeFluxTtsControlsEnabled();
+
+ SpeakV2Request request = SpeakV2Request.builder()
+ .model("flux-alexis-en")
+ .text("Before \\{pause:500ms\\} after.")
+ .encoding(AudioGenerateRequestEncoding.MP3)
+ .build();
+
+ try (InputStream audio = client.speak().v2().audio().generate(request)) {
+ assertThat(audio.readAllBytes()).as("expected audio bytes").isNotEmpty();
+ }
+ }
+
+ @Test
+ @DisplayName("SpeakV2ControlsBatchPronunciation - synthesize batch audio with a pronunciation control")
+ void testIntegration_SpeakV2ControlsBatchPronunciation() throws Exception {
+ assumeFluxTtsControlsEnabled();
+
+ SpeakV2Request request = SpeakV2Request.builder()
+ .model("flux-alexis-en")
+ .text("\\{\"word\": \"dupilumab\", \"pronounce\": \"duːˈpɪljuːmæb\"\\}")
+ .encoding(AudioGenerateRequestEncoding.MP3)
+ .build();
+
+ try (InputStream audio = client.speak().v2().audio().generate(request)) {
+ assertThat(audio.readAllBytes()).as("expected audio bytes").isNotEmpty();
+ }
+ }
+
+ @Test
+ @DisplayName("SpeakV2ControlsBatchConflict - reject speed with a pronunciation control")
+ void testIntegration_SpeakV2ControlsBatchConflict() {
+ assumeFluxTtsControlsEnabled();
+
+ SpeakV2Request request = SpeakV2Request.builder()
+ .model("flux-alexis-en")
+ .text("\\{\"word\": \"dupilumab\", \"pronounce\": \"duːˈpɪljuːmæb\"\\}")
+ .encoding(AudioGenerateRequestEncoding.MP3)
+ .speed(1.05)
+ .build();
+
+ assertThatThrownBy(() -> client.speak().v2().audio().generate(request))
+ .isInstanceOf(DeepgramHttpException.class)
+ .satisfies(thrown -> {
+ DeepgramHttpException exception = (DeepgramHttpException) thrown;
+ assertThat(exception.statusCode()).isEqualTo(400);
+ assertThat(String.valueOf(exception.body())).contains("CONTROL_COMBINATION_INVALID");
+ });
+ }
+
+ @Test
+ @DisplayName("SpeakV2ControlsWebSocket - stream audio and metadata with a pronunciation control")
+ void testIntegration_SpeakV2ControlsWebSocket() throws Exception {
+ assumeFluxTtsControlsEnabled();
+
+ V2WebSocketClient wsClient = client.speak().v2().v2WebSocket();
+ CountDownLatch audioLatch = new CountDownLatch(1);
+ CountDownLatch metadataLatch = new CountDownLatch(1);
+ AtomicLong totalAudioBytes = new AtomicLong(0);
+ AtomicReference metadata = new AtomicReference<>();
+ AtomicReference serverError = new AtomicReference<>();
+
+ wsClient.onSpeakV2Audio(audio -> {
+ totalAudioBytes.addAndGet(audio.size());
+ audioLatch.countDown();
+ });
+ wsClient.onSpeechMetadata(value -> {
+ metadata.set(value);
+ metadataLatch.countDown();
+ });
+ wsClient.onErrorMessage(error -> serverError.set(String.valueOf(error)));
+ wsClient.onError(error -> serverError.set(error.getMessage()));
+
+ try {
+ wsClient.connect(V2ConnectOptions.builder()
+ .model("flux-alexis-en")
+ .build())
+ .get(15, TimeUnit.SECONDS);
+ wsClient.sendSpeak(SpeakV2Speak.builder()
+ .text("\\{\"word\": \"dupilumab\", \"pronounce\": \"duːˈpɪljuːmæb\"\\}")
+ .build());
+ wsClient.sendFlush(SpeakV2Flush.builder().build());
+
+ assertThat(audioLatch.await(20, TimeUnit.SECONDS))
+ .as("received audio")
+ .isTrue();
+ assertThat(metadataLatch.await(20, TimeUnit.SECONDS))
+ .as("received SpeechMetadata")
+ .isTrue();
+
+ assertThat(serverError.get())
+ .as("no server/transport error during streaming")
+ .isNull();
+ assertThat(totalAudioBytes.get())
+ .as("expected streamed audio bytes")
+ .isGreaterThan(0);
+
+ SpeakV2SpeechMetadata speechMetadata = metadata.get();
+ assertThat(speechMetadata).as("received SpeechMetadata").isNotNull();
+ SpeakV2SpeechMetadataControlsApplied controlsApplied = speechMetadata.getControlsApplied();
+ assertThat(controlsApplied)
+ .as("received controls_applied metadata")
+ .isNotNull();
+ assertThat(controlsApplied.getPronunciationsApplied())
+ .as("the submitted pronunciation was applied")
+ .isEqualTo(1);
+ assertThat(controlsApplied.getBreaksApplied()).isZero();
+ assertThat(controlsApplied.getPronunciationWarnings()).isZero();
+
+ wsClient.sendClose(SpeakV2Close.builder().build());
+ } finally {
+ wsClient.disconnect();
+ }
+ }
+
@Test
@DisplayName("ListenV2ForceEndTurn - force a turn to end and read back trigger=manual")
void testIntegration_ListenV2ForceEndTurn() throws Exception {
diff --git a/src/test/java/com/deepgram/RegenTypesTest.java b/src/test/java/com/deepgram/RegenTypesTest.java
index fffaed76..f2202c1a 100644
--- a/src/test/java/com/deepgram/RegenTypesTest.java
+++ b/src/test/java/com/deepgram/RegenTypesTest.java
@@ -30,6 +30,8 @@
import com.deepgram.types.ListenV1ResponseMetadata;
import com.deepgram.types.ListenV1ResponseResultsChannelsItemAlternativesItemWordsItem;
import com.deepgram.types.ListenV2Redact;
+import com.deepgram.types.SharedIntents;
+import com.deepgram.types.SharedTopics;
import com.deepgram.types.ThinkSettingsV1FunctionsItem;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Arrays;
@@ -376,4 +378,47 @@ void wordsItemSpeakerConfidenceAbsent() throws Exception {
assertThat(word.getSpeaker()).isEmpty();
}
}
+
+ /**
+ * Coverage for the 2026-09-30 correction that removes the nonexistent nested {@code results}
+ * wrappers from Topics and Intents response objects.
+ */
+ @Nested
+ @DisplayName("2026-09-30 Topics and Intents response shapes")
+ class TopicsAndIntentsShapes {
+
+ @Test
+ @DisplayName("SharedTopics deserializes direct segments from the server payload")
+ void topicsDeserializeDirectSegments() throws Exception {
+ SharedTopics topics = MAPPER.readValue(
+ "{\"segments\":[{\"text\":\"Spacewalk\",\"topics\":[{\"topic\":\"Spacewalk\",\"confidence_score\":0.9}]}]}",
+ SharedTopics.class);
+
+ assertThat(topics.getSegments()).hasValueSatisfying(segments -> {
+ assertThat(segments).singleElement().satisfies(segment -> {
+ assertThat(segment.getText()).contains("Spacewalk");
+ assertThat(segment.getTopics()).hasValueSatisfying(values -> assertThat(values)
+ .singleElement()
+ .satisfies(value -> assertThat(value.getTopic()).contains("Spacewalk")));
+ });
+ });
+ }
+
+ @Test
+ @DisplayName("SharedIntents deserializes direct segments from the server payload")
+ void intentsDeserializeDirectSegments() throws Exception {
+ SharedIntents intents = MAPPER.readValue(
+ "{\"segments\":[{\"text\":\"Book a flight\",\"intents\":[{\"intent\":\"Book travel\",\"confidence_score\":0.9}]}]}",
+ SharedIntents.class);
+
+ assertThat(intents.getSegments()).hasValueSatisfying(segments -> {
+ assertThat(segments).singleElement().satisfies(segment -> {
+ assertThat(segment.getText()).contains("Book a flight");
+ assertThat(segment.getIntents()).hasValueSatisfying(values -> assertThat(values)
+ .singleElement()
+ .satisfies(value -> assertThat(value.getIntent()).contains("Book travel")));
+ });
+ });
+ }
+ }
}
diff --git a/src/test/java/com/deepgram/StreamingAdditionalPropertiesWireTest.java b/src/test/java/com/deepgram/StreamingAdditionalPropertiesWireTest.java
index 7ce1779c..a67a4ae8 100644
--- a/src/test/java/com/deepgram/StreamingAdditionalPropertiesWireTest.java
+++ b/src/test/java/com/deepgram/StreamingAdditionalPropertiesWireTest.java
@@ -6,6 +6,7 @@
import com.deepgram.types.ListenV1Model;
import com.deepgram.types.ListenV2Model;
import com.deepgram.types.SpeakV1Model;
+import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import okhttp3.HttpUrl;
@@ -71,6 +72,8 @@ private void assertEscapeHatchEmitted(HttpUrl url) {
// The unmodeled params reached the wire, with a non-string value serialized correctly...
assertThat(url.queryParameter("no_delay")).isEqualTo("true");
assertThat(url.queryParameter("custom_key")).isEqualTo("custom_value");
+ assertThat(url.queryParameter("numeric_value")).isEqualTo("42");
+ assertThat(url.queryParameterValues("multi_value")).containsExactly("first", "second");
// ...alongside (not instead of) the typed option.
assertThat(url.queryParameterNames()).contains("model");
}
@@ -83,9 +86,11 @@ void listenV1() throws Exception {
.v1()
.v1WebSocket()
.connect(com.deepgram.resources.listen.v1.websocket.V1ConnectOptions.builder()
- .model(ListenV1Model.NOVA3)
- .additionalProperty("no_delay", true)
- .additionalProperty("custom_key", "custom_value")
+ .model(ListenV1Model.NOVA3)
+ .additionalProperty("no_delay", true)
+ .additionalProperty("custom_key", "custom_value")
+ .additionalProperty("numeric_value", 42)
+ .additionalProperty("multi_value", List.of("first", "second"))
.build()),
"/v1/listen");
assertEscapeHatchEmitted(url);
@@ -99,9 +104,11 @@ void listenV2() throws Exception {
.v2()
.v2WebSocket()
.connect(com.deepgram.resources.listen.v2.websocket.V2ConnectOptions.builder()
- .model(ListenV2Model.FLUX_GENERAL_EN)
- .additionalProperty("no_delay", true)
- .additionalProperty("custom_key", "custom_value")
+ .model(ListenV2Model.FLUX_GENERAL_EN)
+ .additionalProperty("no_delay", true)
+ .additionalProperty("custom_key", "custom_value")
+ .additionalProperty("numeric_value", 42)
+ .additionalProperty("multi_value", List.of("first", "second"))
.build()),
"/v2/listen");
assertEscapeHatchEmitted(url);
@@ -115,9 +122,11 @@ void speakV1() throws Exception {
.v1()
.v1WebSocket()
.connect(com.deepgram.resources.speak.v1.websocket.V1ConnectOptions.builder()
- .model(SpeakV1Model.AURA2HERA_EN)
- .additionalProperty("no_delay", true)
- .additionalProperty("custom_key", "custom_value")
+ .model(SpeakV1Model.AURA2HERA_EN)
+ .additionalProperty("no_delay", true)
+ .additionalProperty("custom_key", "custom_value")
+ .additionalProperty("numeric_value", 42)
+ .additionalProperty("multi_value", List.of("first", "second"))
.build()),
"/v1/speak");
assertEscapeHatchEmitted(url);
@@ -131,9 +140,11 @@ void speakV2() throws Exception {
.v2()
.v2WebSocket()
.connect(com.deepgram.resources.speak.v2.websocket.V2ConnectOptions.builder()
- .model("aura-2-thalia-en")
- .additionalProperty("no_delay", true)
- .additionalProperty("custom_key", "custom_value")
+ .model("aura-2-thalia-en")
+ .additionalProperty("no_delay", true)
+ .additionalProperty("custom_key", "custom_value")
+ .additionalProperty("numeric_value", 42)
+ .additionalProperty("multi_value", List.of("first", "second"))
.build()),
"/v2/speak");
assertEscapeHatchEmitted(url);
diff --git a/src/test/java/com/deepgram/core/RetryInterceptorTest.java b/src/test/java/com/deepgram/core/RetryInterceptorTest.java
index 70173211..25fc24ee 100644
--- a/src/test/java/com/deepgram/core/RetryInterceptorTest.java
+++ b/src/test/java/com/deepgram/core/RetryInterceptorTest.java
@@ -3,9 +3,16 @@
import static org.assertj.core.api.Assertions.assertThat;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import okhttp3.MediaType;
import okhttp3.OkHttpClient;
+import okhttp3.Protocol;
import okhttp3.Request;
import okhttp3.Response;
+import okhttp3.ResponseBody;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import org.junit.jupiter.api.AfterEach;
@@ -37,6 +44,13 @@ private OkHttpClient buildClientWithRetries(int maxRetries) {
.build();
}
+ private OkHttpClient buildClientWithRetriesAndCallTimeout(int maxRetries, long callTimeoutMillis) {
+ return new OkHttpClient.Builder()
+ .callTimeout(callTimeoutMillis, TimeUnit.MILLISECONDS)
+ .addInterceptor(new RetryInterceptor(maxRetries, Optional.of(0L), Optional.of(1000L), Optional.of(0.0)))
+ .build();
+ }
+
private Request buildRequest() {
return new Request.Builder().url(server.url("/test")).build();
}
@@ -284,4 +298,60 @@ void testMultipleDifferentErrors() throws Exception {
assertThat(server.getRequestCount()).isEqualTo(4);
}
}
+
+ @Nested
+ @DisplayName("Retry transport failures")
+ class RetryTransportFailures {
+
+ @Test
+ @DisplayName("returns the buffered retryable response when a later retry disconnects")
+ void preservesEarlierResponseAfterRetryTransportFailure() throws Exception {
+ AtomicInteger attempts = new AtomicInteger();
+ client = new OkHttpClient.Builder()
+ .addInterceptor(new RetryInterceptor(1, Optional.of(0L), Optional.of(1000L), Optional.of(0.0)))
+ .addInterceptor(chain -> {
+ if (attempts.incrementAndGet() == 1) {
+ return new Response.Builder()
+ .request(chain.request())
+ .protocol(Protocol.HTTP_1_1)
+ .code(500)
+ .message("original server error")
+ .header("X-Retry-Source", "original")
+ .body(ResponseBody.create(
+ "original server error".getBytes(StandardCharsets.UTF_8),
+ MediaType.get("text/plain")))
+ .build();
+ }
+ throw new IOException("retry transport failure");
+ })
+ .build();
+
+ Response response = client.newCall(buildRequest()).execute();
+
+ assertThat(response.code()).isEqualTo(500);
+ assertThat(response.header("X-Retry-Source")).isEqualTo("original");
+ assertThat(response.body().string()).isEqualTo("original server error");
+ assertThat(attempts).hasValue(2);
+ }
+
+ @Test
+ @DisplayName("does not spend the next attempt timeout budget during Retry-After backoff")
+ void pausesCallTimeoutDuringRetryAfterBackoff() throws Exception {
+ client = buildClientWithRetriesAndCallTimeout(1, 100);
+ server.enqueue(new MockResponse()
+ .setResponseCode(429)
+ .setHeader("Retry-After", "1")
+ .setBody("rate limited"));
+ server.enqueue(new MockResponse().setResponseCode(200).setBody("success"));
+
+ long start = System.nanoTime();
+ Response response = client.newCall(buildRequest()).execute();
+ long elapsedMillis = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
+
+ assertThat(response.code()).isEqualTo(200);
+ assertThat(response.body().string()).isEqualTo("success");
+ assertThat(server.getRequestCount()).isEqualTo(2);
+ assertThat(elapsedMillis).isGreaterThanOrEqualTo(900L);
+ }
+ }
}