From 58bef4418d47c115a41fb8afbfeb5428fe8c40a0 Mon Sep 17 00:00:00 2001 From: Greg Holmes Date: Mon, 20 Jul 2026 10:55:31 +0100 Subject: [PATCH 1/8] chore: initialize SDK regeneration branch From a7fe34d9d79449b0f84c2a4b9aab02f0ff996b38 Mon Sep 17 00:00:00 2001 From: Greg Holmes Date: Mon, 20 Jul 2026 10:57:41 +0100 Subject: [PATCH 2/8] chore: unfreeze files pending regen --- .fernignore | 30 +- .../com/deepgram/core/ClientOptions.java.bak | 241 ++++++++ .../ReconnectingWebSocketListener.java.bak | 545 ++++++++++++++++++ .../v1/types/AgentV1AgentAudioDone.java.bak | 86 +++ .../agent/v1/types/AgentV1KeepAlive.java.bak | 86 +++ .../v1/types/AgentV1ListenUpdated.java.bak | 86 +++ .../v1/types/AgentV1PromptUpdated.java.bak | 86 +++ .../v1/types/AgentV1SettingsApplied.java.bak | 86 +++ .../v1/types/AgentV1SpeakUpdated.java.bak | 86 +++ .../v1/types/AgentV1ThinkUpdated.java.bak | 86 +++ .../types/AgentV1UserStartedSpeaking.java.bak | 86 +++ .../v2/types/ListenV2CloseStream.java.bak | 86 +++ .../v2/websocket/V2WebSocketClient.java.bak | 483 ++++++++++++++++ .../speak/v2/types/SpeakV2Close.java.bak | 86 +++ .../speak/v2/types/SpeakV2Flush.java.bak | 86 +++ .../v2/websocket/V2WebSocketClient.java.bak | 507 ++++++++++++++++ 16 files changed, 2737 insertions(+), 15 deletions(-) create mode 100644 src/main/java/com/deepgram/core/ClientOptions.java.bak create mode 100644 src/main/java/com/deepgram/core/ReconnectingWebSocketListener.java.bak create mode 100644 src/main/java/com/deepgram/resources/agent/v1/types/AgentV1AgentAudioDone.java.bak create mode 100644 src/main/java/com/deepgram/resources/agent/v1/types/AgentV1KeepAlive.java.bak create mode 100644 src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ListenUpdated.java.bak create mode 100644 src/main/java/com/deepgram/resources/agent/v1/types/AgentV1PromptUpdated.java.bak create mode 100644 src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SettingsApplied.java.bak create mode 100644 src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SpeakUpdated.java.bak create mode 100644 src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ThinkUpdated.java.bak create mode 100644 src/main/java/com/deepgram/resources/agent/v1/types/AgentV1UserStartedSpeaking.java.bak create mode 100644 src/main/java/com/deepgram/resources/listen/v2/types/ListenV2CloseStream.java.bak create mode 100644 src/main/java/com/deepgram/resources/listen/v2/websocket/V2WebSocketClient.java.bak create mode 100644 src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Close.java.bak create mode 100644 src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Flush.java.bak create mode 100644 src/main/java/com/deepgram/resources/speak/v2/websocket/V2WebSocketClient.java.bak diff --git a/.fernignore b/.fernignore index b7c4722..d1507b2 100644 --- a/.fernignore +++ b/.fernignore @@ -14,7 +14,7 @@ src/main/java/com/deepgram/AsyncDeepgramClientBuilder.java # Contains User-Agent, X-Fern-SDK-Name, and X-Fern-SDK-Version headers # with // x-release-please-version comments for automated version bumps. # Fern regen overwrites these with incorrect SDK names and strips the markers. -src/main/java/com/deepgram/core/ClientOptions.java +src/main/java/com/deepgram/core/ClientOptions.java.bak # Transport abstraction (pluggable transport for SageMaker, etc.) src/main/java/com/deepgram/core/transport/ @@ -22,31 +22,31 @@ src/main/java/com/deepgram/core/transport/ # Bug fixes for maxRetries(0) semantics ("connect once, don't retry") and a # configurable connectionTimeoutMs on ReconnectOptions (was hardcoded 4000ms). # Pull this back out once the fixes are upstreamed into the Fern generator. -src/main/java/com/deepgram/core/ReconnectingWebSocketListener.java +src/main/java/com/deepgram/core/ReconnectingWebSocketListener.java.bak # Forward-compat patch: Fern's generated dispatcher routes any unrecognized message # type to the error handler ("Update your SDK version..."), which makes benign new # server control frames look fatal to deployed clients. Patched to a no-op (the raw # frame is still delivered via onMessage(String)); mirrors the JS/Python SDKs. Re-apply # after regen. Unfreeze once the generator stops treating unknown frames as errors. -src/main/java/com/deepgram/resources/speak/v2/websocket/V2WebSocketClient.java -src/main/java/com/deepgram/resources/listen/v2/websocket/V2WebSocketClient.java +src/main/java/com/deepgram/resources/speak/v2/websocket/V2WebSocketClient.java.bak +src/main/java/com/deepgram/resources/listen/v2/websocket/V2WebSocketClient.java.bak # Manual equals/hashCode contract fix: Fern generates equals() (all instances equal) but no # hashCode() for fields-less message types, violating the Object contract. We add a consistent # hashCode() to each. Unfreeze and drop these patches once the generator emits a matching # equals/hashCode pair for fields-less types (tracked as an upstream Fern request). -src/main/java/com/deepgram/resources/listen/v2/types/ListenV2CloseStream.java -src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Close.java -src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Flush.java -src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ListenUpdated.java -src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SpeakUpdated.java -src/main/java/com/deepgram/resources/agent/v1/types/AgentV1AgentAudioDone.java -src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SettingsApplied.java -src/main/java/com/deepgram/resources/agent/v1/types/AgentV1UserStartedSpeaking.java -src/main/java/com/deepgram/resources/agent/v1/types/AgentV1KeepAlive.java -src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ThinkUpdated.java -src/main/java/com/deepgram/resources/agent/v1/types/AgentV1PromptUpdated.java +src/main/java/com/deepgram/resources/listen/v2/types/ListenV2CloseStream.java.bak +src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Close.java.bak +src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Flush.java.bak +src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ListenUpdated.java.bak +src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SpeakUpdated.java.bak +src/main/java/com/deepgram/resources/agent/v1/types/AgentV1AgentAudioDone.java.bak +src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SettingsApplied.java.bak +src/main/java/com/deepgram/resources/agent/v1/types/AgentV1UserStartedSpeaking.java.bak +src/main/java/com/deepgram/resources/agent/v1/types/AgentV1KeepAlive.java.bak +src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ThinkUpdated.java.bak +src/main/java/com/deepgram/resources/agent/v1/types/AgentV1PromptUpdated.java.bak # Build and project configuration build.gradle diff --git a/src/main/java/com/deepgram/core/ClientOptions.java.bak b/src/main/java/com/deepgram/core/ClientOptions.java.bak new file mode 100644 index 0000000..0b070bd --- /dev/null +++ b/src/main/java/com/deepgram/core/ClientOptions.java.bak @@ -0,0 +1,241 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.deepgram.core; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; +import okhttp3.OkHttpClient; + +public final class ClientOptions { + private final Environment environment; + + private final Map headers; + + private final Map> headerSuppliers; + + private final OkHttpClient httpClient; + + private final int timeout; + + private final int maxRetries; + + private final Optional webSocketFactory; + + private final Optional logging; + + private ClientOptions( + Environment environment, + Map headers, + Map> headerSuppliers, + OkHttpClient httpClient, + int timeout, + int maxRetries, + Optional webSocketFactory, + Optional logging) { + this.environment = environment; + this.headers = new HashMap<>(); + this.headers.putAll(headers); + this.headers.putAll(new HashMap() { + { + put("User-Agent", "com.deepgram:deepgram-java-sdk/0.6.1"); // x-release-please-version + put("X-Fern-Language", "JAVA"); + put("X-Fern-SDK-Name", "com.deepgram:deepgram-java-sdk"); + put("X-Fern-SDK-Version", "0.6.1"); // x-release-please-version + } + }); + this.headerSuppliers = headerSuppliers; + this.httpClient = httpClient; + this.timeout = timeout; + this.maxRetries = maxRetries; + this.webSocketFactory = webSocketFactory; + this.logging = logging; + } + + public Environment environment() { + return this.environment; + } + + public Map headers(RequestOptions requestOptions) { + Map values = new HashMap<>(this.headers); + headerSuppliers.forEach((key, supplier) -> { + values.put(key, supplier.get()); + }); + if (requestOptions != null) { + values.putAll(requestOptions.getHeaders()); + } + return values; + } + + public int timeout(RequestOptions requestOptions) { + if (requestOptions == null) { + return this.timeout; + } + return requestOptions.getTimeout().orElse(this.timeout); + } + + public OkHttpClient httpClient() { + return this.httpClient; + } + + public OkHttpClient httpClientWithTimeout(RequestOptions requestOptions) { + if (requestOptions == null) { + return this.httpClient; + } + return this.httpClient + .newBuilder() + .callTimeout(requestOptions.getTimeout().get(), requestOptions.getTimeoutTimeUnit()) + .connectTimeout(0, TimeUnit.SECONDS) + .writeTimeout(0, TimeUnit.SECONDS) + .readTimeout(0, TimeUnit.SECONDS) + .build(); + } + + public int maxRetries() { + return this.maxRetries; + } + + public Optional webSocketFactory() { + return this.webSocketFactory; + } + + public Optional logging() { + return this.logging; + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private Environment environment; + + private final Map headers = new HashMap<>(); + + private final Map> headerSuppliers = new HashMap<>(); + + private int maxRetries = 2; + + private Optional timeout = Optional.empty(); + + private OkHttpClient httpClient = null; + + private Optional logging = Optional.empty(); + + private Optional webSocketFactory = Optional.empty(); + + public Builder environment(Environment environment) { + this.environment = environment; + return this; + } + + public Builder addHeader(String key, String value) { + this.headers.put(key, value); + return this; + } + + public Builder addHeader(String key, Supplier value) { + this.headerSuppliers.put(key, value); + return this; + } + + /** + * Override the timeout in seconds. Defaults to 60 seconds. + */ + public Builder timeout(int timeout) { + this.timeout = Optional.of(timeout); + return this; + } + + /** + * Override the timeout in seconds. Defaults to 60 seconds. + */ + public Builder timeout(Optional timeout) { + this.timeout = timeout; + return this; + } + + /** + * Override the maximum number of retries. Defaults to 2 retries. + */ + public Builder maxRetries(int maxRetries) { + this.maxRetries = maxRetries; + return this; + } + + public Builder httpClient(OkHttpClient httpClient) { + this.httpClient = httpClient; + return this; + } + + /** + * Set a custom WebSocketFactory for creating WebSocket connections. + */ + public Builder webSocketFactory(WebSocketFactory webSocketFactory) { + this.webSocketFactory = Optional.of(webSocketFactory); + return this; + } + + /** + * Configure logging for the SDK. Silent by default — no log output unless explicitly configured. + */ + public Builder logging(LogConfig logging) { + this.logging = Optional.of(logging); + return this; + } + + public ClientOptions build() { + OkHttpClient.Builder httpClientBuilder = + this.httpClient != null ? this.httpClient.newBuilder() : new OkHttpClient.Builder(); + + if (this.httpClient != null) { + timeout.ifPresent(timeout -> httpClientBuilder + .callTimeout(timeout, TimeUnit.SECONDS) + .connectTimeout(0, TimeUnit.SECONDS) + .writeTimeout(0, TimeUnit.SECONDS) + .readTimeout(0, TimeUnit.SECONDS)); + } else { + httpClientBuilder + .callTimeout(this.timeout.orElse(60), TimeUnit.SECONDS) + .connectTimeout(0, TimeUnit.SECONDS) + .writeTimeout(0, TimeUnit.SECONDS) + .readTimeout(0, TimeUnit.SECONDS) + .addInterceptor(new RetryInterceptor(this.maxRetries)); + } + + Logger logger = Logger.from(this.logging); + httpClientBuilder.addInterceptor(new LoggingInterceptor(logger)); + + this.httpClient = httpClientBuilder.build(); + this.timeout = Optional.of(httpClient.callTimeoutMillis() / 1000); + + return new ClientOptions( + environment, + headers, + headerSuppliers, + httpClient, + this.timeout.get(), + this.maxRetries, + this.webSocketFactory, + this.logging); + } + + /** + * Create a new Builder initialized with values from an existing ClientOptions + */ + public static Builder from(ClientOptions clientOptions) { + Builder builder = new Builder(); + builder.environment = clientOptions.environment(); + builder.timeout = Optional.of(clientOptions.timeout(null)); + builder.httpClient = clientOptions.httpClient(); + builder.headers.putAll(clientOptions.headers); + builder.headerSuppliers.putAll(clientOptions.headerSuppliers); + builder.maxRetries = clientOptions.maxRetries(); + builder.logging = clientOptions.logging(); + return builder; + } + } +} diff --git a/src/main/java/com/deepgram/core/ReconnectingWebSocketListener.java.bak b/src/main/java/com/deepgram/core/ReconnectingWebSocketListener.java.bak new file mode 100644 index 0000000..a533068 --- /dev/null +++ b/src/main/java/com/deepgram/core/ReconnectingWebSocketListener.java.bak @@ -0,0 +1,545 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.deepgram.core; + +import static java.util.concurrent.TimeUnit.*; + +import java.util.ArrayList; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Supplier; +import okhttp3.Response; +import okhttp3.WebSocket; +import okhttp3.WebSocketListener; +import okio.ByteString; + +/** + * WebSocketListener with automatic reconnection, exponential backoff, and message queuing. + * Provides production-ready resilience for WebSocket connections. + */ +public abstract class ReconnectingWebSocketListener extends WebSocketListener { + // Overridable options are held behind a single volatile reference (not five separate volatile + // fields) so {@link #applyOptionsOverride} swaps them atomically — a reader that snapshots the + // reference once sees a mutually-consistent set (e.g. getNextDelay() cannot observe a new min + // paired with an old max). Rewiring is used by {@code TransportWebSocketFactory} to honour + // {@code DeepgramTransportFactory.reconnectOptions()} without editing the generated WS clients. + private volatile ReconnectOptions activeOptions; + + // maxEnqueuedMessages is fixed at construction (the queue is sized once) and intentionally not + // overridable, so it stays a separate final field rather than being read from activeOptions. + private final int maxEnqueuedMessages; + + private final AtomicInteger retryCount = new AtomicInteger(0); + + private final AtomicBoolean connectLock = new AtomicBoolean(false); + + private final AtomicBoolean shouldReconnect = new AtomicBoolean(true); + + protected volatile WebSocket webSocket; + + private volatile long connectionEstablishedTime = 0L; + + private final ConcurrentLinkedQueue messageQueue = new ConcurrentLinkedQueue<>(); + + private final ConcurrentLinkedQueue binaryMessageQueue = new ConcurrentLinkedQueue<>(); + + private final ScheduledExecutorService reconnectExecutor = Executors.newSingleThreadScheduledExecutor(); + + private final Supplier connectionSupplier; + + /** + * Creates a new reconnecting WebSocket listener. + * + * @param options Reconnection configuration options + * @param connectionSupplier Supplier that creates new WebSocket connections + */ + public ReconnectingWebSocketListener( + ReconnectingWebSocketListener.ReconnectOptions options, Supplier connectionSupplier) { + this.activeOptions = options; + this.maxEnqueuedMessages = options.maxEnqueuedMessages; + this.connectionSupplier = connectionSupplier; + } + + /** + * Replaces the option-derived parameters on this listener at runtime. Used by + * {@code TransportWebSocketFactory} to apply {@code DeepgramTransportFactory.reconnectOptions()} + * without requiring edits to the generated per-resource WebSocket clients. {@code maxEnqueuedMessages} + * is intentionally not overridden — the message queue is sized at construction. + * + *

Thread-safety: the override is a single atomic write to a {@code volatile} reference, so a + * reader that snapshots {@link #activeOptions} once sees a mutually-consistent set of values + * (never a new min paired with an old max). The initial connect() call may have already started + * before the override lands, so for the very first attempt the original options apply; the + * override takes effect from the next attempt onwards. For the SageMaker storm-suppression case + * ({@code maxRetries(0)}) this is fine because the initial attempt's gate + * ({@code retryCount > maxRetries} with {@code retryCount=0}) always passes regardless. + * + * @param options replacement options; {@code null} is a no-op. + */ + public void applyOptionsOverride(ReconnectOptions options) { + if (options == null) { + return; + } + this.activeOptions = options; + } + + /** + * Initiates a WebSocket connection with automatic reconnection enabled. + * + * Connection behavior: + * - Times out after {@code ReconnectOptions.connectionTimeoutMs} (default 4000ms) + * - Thread-safe via atomic lock (returns immediately if connection in progress) + * - {@code maxRetries} counts retries only — the initial attempt always proceeds. + * {@code maxRetries(0)} means "connect once, don't retry" (not "refuse to connect"). + * + * Error handling: + * - TimeoutException: Includes retry attempt context + * - InterruptedException: Preserves thread interruption status + * - ExecutionException: Extracts actual cause and adds context + */ + public void connect() { + if (!connectLock.compareAndSet(false, true)) { + return; + } + // Snapshot the overridable options once so the gate and timeout below use a consistent set. + ReconnectOptions opts = this.activeOptions; + // retryCount is incremented inside scheduleReconnect() before re-entering connect(), + // so on the initial call retryCount == 0 and we always proceed. The cap applies to + // retries only — maxRetries(0) blocks retries but allows the initial attempt. + if (retryCount.get() > opts.maxRetries) { + connectLock.set(false); + return; + } + try { + CompletableFuture connectionFuture = CompletableFuture.supplyAsync(connectionSupplier); + try { + webSocket = connectionFuture.get(opts.connectionTimeoutMs, MILLISECONDS); + } catch (TimeoutException e) { + connectionFuture.cancel(true); + TimeoutException timeoutError = + new TimeoutException("WebSocket connection timeout after " + opts.connectionTimeoutMs + + " milliseconds" + + (retryCount.get() > 0 + ? " (retry attempt #" + retryCount.get() + ")" + : " (initial connection attempt)")); + onWebSocketFailure(null, timeoutError, null); + if (shouldReconnect.get()) { + scheduleReconnect(); + } + } catch (InterruptedException e) { + connectionFuture.cancel(true); + Thread.currentThread().interrupt(); + InterruptedException interruptError = new InterruptedException("WebSocket connection interrupted" + + (retryCount.get() > 0 + ? " during retry attempt #" + retryCount.get() + : " during initial connection")); + interruptError.initCause(e); + onWebSocketFailure(null, interruptError, null); + } catch (ExecutionException e) { + Throwable cause = e.getCause() != null ? e.getCause() : e; + String context = retryCount.get() > 0 + ? "WebSocket connection failed during retry attempt #" + retryCount.get() + : "WebSocket connection failed during initial attempt"; + RuntimeException wrappedException = new RuntimeException( + context + ": " + cause.getClass().getSimpleName() + ": " + cause.getMessage()); + wrappedException.initCause(cause); + onWebSocketFailure(null, wrappedException, null); + if (shouldReconnect.get()) { + scheduleReconnect(); + } + } + } finally { + connectLock.set(false); + } + } + + /** + * Disconnects the WebSocket and disables automatic reconnection. + * + * This method: + * - Disables automatic reconnection + * - Clears queued messages to prevent stale data + * - Closes the WebSocket with standard close code 1000 + * - Properly shuts down the reconnect executor to prevent thread leaks + * - Waits up to 5 seconds for executor termination + */ + public void disconnect() { + shouldReconnect.set(false); + messageQueue.clear(); + binaryMessageQueue.clear(); + if (webSocket != null) { + webSocket.close(1000, "Client disconnecting"); + } + reconnectExecutor.shutdown(); + try { + if (!reconnectExecutor.awaitTermination(5, SECONDS)) { + reconnectExecutor.shutdownNow(); + } + } catch (InterruptedException e) { + reconnectExecutor.shutdownNow(); + Thread.currentThread().interrupt(); + } + } + + /** + * Sends a message or queues it if not connected. + * + * Thread-safe: Synchronized to prevent race conditions with flushMessageQueue(). + * + * Behavior: + * - If connected: Attempts direct send, queues if buffer full + * - If disconnected: Queues message up to maxEnqueuedMessages limit + * - If queue full: Message is dropped + * + * @param message The message to send + * @return true if sent immediately, false if queued or dropped + */ + public synchronized boolean send(String message) { + WebSocket ws = webSocket; + if (ws != null) { + boolean sent = ws.send(message); + if (!sent && messageQueue.size() < maxEnqueuedMessages) { + messageQueue.offer(message); + return false; + } + return sent; + } else { + if (messageQueue.size() < maxEnqueuedMessages) { + messageQueue.offer(message); + return false; + } + return false; + } + } + + /** + * Sends binary data or queues it if not connected. + * + * Thread-safe: Synchronized to prevent race conditions with flushMessageQueue(). + * + * Behavior: + * - If connected: Attempts direct send, queues if buffer full + * - If disconnected: Queues data up to maxEnqueuedMessages limit + * - If queue full: Data is dropped + * + * @param data The binary data to send + * @return true if sent immediately, false if queued or dropped + */ + public synchronized boolean sendBinary(ByteString data) { + WebSocket ws = webSocket; + if (ws != null) { + boolean sent = ws.send(data); + if (!sent && binaryMessageQueue.size() < maxEnqueuedMessages) { + binaryMessageQueue.offer(data); + return false; + } + return sent; + } else { + if (binaryMessageQueue.size() < maxEnqueuedMessages) { + binaryMessageQueue.offer(data); + return false; + } + return false; + } + } + + /** + * Gets the current WebSocket instance. + * Thread-safe method to access the WebSocket connection. + * @return the WebSocket or null if not connected + */ + public WebSocket getWebSocket() { + return webSocket; + } + + /** + * @hidden + */ + @Override + public void onOpen(WebSocket webSocket, Response response) { + this.webSocket = webSocket; + connectionEstablishedTime = System.currentTimeMillis(); + retryCount.set(0); + flushMessageQueue(); + onWebSocketOpen(webSocket, response); + } + + @Override + public void onMessage(WebSocket webSocket, String text) { + onWebSocketMessage(webSocket, text); + } + + @Override + public void onMessage(WebSocket webSocket, ByteString bytes) { + onWebSocketBinaryMessage(webSocket, bytes); + } + + /** + * @hidden + */ + @Override + public void onFailure(WebSocket webSocket, Throwable t, Response response) { + this.webSocket = null; + long uptime = 0L; + if (connectionEstablishedTime > 0) { + uptime = System.currentTimeMillis() - connectionEstablishedTime; + if (uptime >= 5000) { + retryCount.set(0); + } + } + connectionEstablishedTime = 0L; + Throwable enhancedError = t; + if (t != null) { + String errorContext = "WebSocket connection failed"; + if (uptime > 0) { + errorContext += " after " + (uptime / 1000) + " seconds"; + } + if (response != null) { + errorContext += " with HTTP " + response.code() + " " + response.message(); + } + enhancedError = + new RuntimeException(errorContext + ": " + t.getClass().getSimpleName() + ": " + t.getMessage()); + enhancedError.initCause(t); + } + onWebSocketFailure(webSocket, enhancedError, response); + if (shouldReconnect.get()) { + scheduleReconnect(); + } + } + + /** + * @hidden + */ + @Override + public void onClosed(WebSocket webSocket, int code, String reason) { + this.webSocket = null; + if (connectionEstablishedTime > 0) { + long uptime = System.currentTimeMillis() - connectionEstablishedTime; + if (uptime >= 5000) { + retryCount.set(0); + } + } + connectionEstablishedTime = 0L; + onWebSocketClosed(webSocket, code, reason); + if (code != 1000 && shouldReconnect.get()) { + scheduleReconnect(); + } + } + + /** + * Calculates the next reconnection delay using exponential backoff. + * + * Uses 0-based retry count where: + * - 0 = initial connection (not used by this method) + * - 1 = first retry (returns minReconnectionDelayMs) + * - 2+ = exponential backoff up to maxReconnectionDelayMs + */ + private long getNextDelay() { + // Single volatile read → a consistent (min, growFactor, max) snapshot even if + // applyOptionsOverride swaps the options concurrently. + ReconnectOptions opts = this.activeOptions; + if (retryCount.get() == 1) { + return opts.minReconnectionDelayMs; + } + long delay = (long) (opts.minReconnectionDelayMs * Math.pow(opts.reconnectionDelayGrowFactor, retryCount.get() - 1)); + return Math.min(delay, opts.maxReconnectionDelayMs); + } + + /** + * Schedules a reconnection attempt with appropriate delay. + * Increments retry count and uses exponential backoff. + */ + private void scheduleReconnect() { + retryCount.incrementAndGet(); + long delay = getNextDelay(); + reconnectExecutor.schedule(this::connect, delay, MILLISECONDS); + } + + /** + * Sends all queued messages after reconnection. + * + * Thread-safe: Synchronized to prevent race conditions with send() method. + * + * Algorithm: + * 1. Drains queue into temporary list to avoid holding lock during sends + * 2. Attempts to send each message in order + * 3. If any send fails, re-queues that message and all subsequent messages + * 4. Preserves message ordering during re-queueing + * 5. Repeats for binary message queue + */ + private synchronized void flushMessageQueue() { + WebSocket ws = webSocket; + if (ws != null) { + ArrayList tempQueue = new ArrayList<>(); + String message; + while ((message = messageQueue.poll()) != null) { + tempQueue.add(message); + } + for (int i = 0; i < tempQueue.size(); i++) { + if (!ws.send(tempQueue.get(i))) { + for (int j = i; j < tempQueue.size(); j++) { + messageQueue.offer(tempQueue.get(j)); + } + break; + } + } + ArrayList tempBinaryQueue = new ArrayList<>(); + ByteString binaryMsg; + while ((binaryMsg = binaryMessageQueue.poll()) != null) { + tempBinaryQueue.add(binaryMsg); + } + for (int i = 0; i < tempBinaryQueue.size(); i++) { + if (!ws.send(tempBinaryQueue.get(i))) { + for (int j = i; j < tempBinaryQueue.size(); j++) { + binaryMessageQueue.offer(tempBinaryQueue.get(j)); + } + break; + } + } + } + } + + protected abstract void onWebSocketOpen(WebSocket webSocket, Response response); + + protected abstract void onWebSocketMessage(WebSocket webSocket, String text); + + protected abstract void onWebSocketBinaryMessage(WebSocket webSocket, ByteString bytes); + + protected abstract void onWebSocketFailure(WebSocket webSocket, Throwable t, Response response); + + protected abstract void onWebSocketClosed(WebSocket webSocket, int code, String reason); + + /** + * Configuration options for automatic reconnection. + */ + public static final class ReconnectOptions { + public final long minReconnectionDelayMs; + + public final long maxReconnectionDelayMs; + + public final double reconnectionDelayGrowFactor; + + public final int maxRetries; + + public final int maxEnqueuedMessages; + + public final long connectionTimeoutMs; + + private ReconnectOptions(Builder builder) { + this.minReconnectionDelayMs = builder.minReconnectionDelayMs; + this.maxReconnectionDelayMs = builder.maxReconnectionDelayMs; + this.reconnectionDelayGrowFactor = builder.reconnectionDelayGrowFactor; + this.maxRetries = builder.maxRetries; + this.maxEnqueuedMessages = builder.maxEnqueuedMessages; + this.connectionTimeoutMs = builder.connectionTimeoutMs; + } + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + private long minReconnectionDelayMs; + + private long maxReconnectionDelayMs; + + private double reconnectionDelayGrowFactor; + + private int maxRetries; + + private int maxEnqueuedMessages; + + private long connectionTimeoutMs; + + public Builder() { + this.minReconnectionDelayMs = 1000; + this.maxReconnectionDelayMs = 10000; + this.reconnectionDelayGrowFactor = 1.3; + this.maxRetries = 2147483647; + this.maxEnqueuedMessages = 1000; + this.connectionTimeoutMs = 4000; + } + + public Builder minReconnectionDelayMs(long minReconnectionDelayMs) { + this.minReconnectionDelayMs = minReconnectionDelayMs; + return this; + } + + public Builder maxReconnectionDelayMs(long maxReconnectionDelayMs) { + this.maxReconnectionDelayMs = maxReconnectionDelayMs; + return this; + } + + public Builder reconnectionDelayGrowFactor(double reconnectionDelayGrowFactor) { + this.reconnectionDelayGrowFactor = reconnectionDelayGrowFactor; + return this; + } + + public Builder maxRetries(int maxRetries) { + this.maxRetries = maxRetries; + return this; + } + + public Builder maxEnqueuedMessages(int maxEnqueuedMessages) { + this.maxEnqueuedMessages = maxEnqueuedMessages; + return this; + } + + /** + * Sets the per-attempt connection timeout in milliseconds. Defaults to {@code 4000}. + * Each call to {@link ReconnectingWebSocketListener#connect()} will wait at most + * this long for the underlying WebSocket factory to produce a connected socket. + */ + public Builder connectionTimeoutMs(long connectionTimeoutMs) { + this.connectionTimeoutMs = connectionTimeoutMs; + return this; + } + + /** + * Builds the ReconnectOptions with validation. + * + * Validates that: + * - All delay values are positive + * - minReconnectionDelayMs <= maxReconnectionDelayMs + * - reconnectionDelayGrowFactor >= 1.0 + * - maxRetries and maxEnqueuedMessages are non-negative + * - connectionTimeoutMs is positive + * + * @return The validated ReconnectOptions instance + * @throws IllegalArgumentException if configuration is invalid + */ + public ReconnectOptions build() { + if (minReconnectionDelayMs <= 0) { + throw new IllegalArgumentException("minReconnectionDelayMs must be positive"); + } + if (maxReconnectionDelayMs <= 0) { + throw new IllegalArgumentException("maxReconnectionDelayMs must be positive"); + } + if (minReconnectionDelayMs > maxReconnectionDelayMs) { + throw new IllegalArgumentException("minReconnectionDelayMs (" + minReconnectionDelayMs + + ") must not exceed maxReconnectionDelayMs (" + maxReconnectionDelayMs + ")"); + } + if (reconnectionDelayGrowFactor < 1.0) { + throw new IllegalArgumentException("reconnectionDelayGrowFactor must be >= 1.0"); + } + if (maxRetries < 0) { + throw new IllegalArgumentException("maxRetries must be non-negative"); + } + if (maxEnqueuedMessages < 0) { + throw new IllegalArgumentException("maxEnqueuedMessages must be non-negative"); + } + if (connectionTimeoutMs <= 0) { + throw new IllegalArgumentException("connectionTimeoutMs must be positive"); + } + return new ReconnectOptions(this); + } + } + } +} diff --git a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1AgentAudioDone.java.bak b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1AgentAudioDone.java.bak new file mode 100644 index 0000000..41af522 --- /dev/null +++ b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1AgentAudioDone.java.bak @@ -0,0 +1,86 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.deepgram.resources.agent.v1.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.databind.annotation.JsonDeserialize; +import java.util.HashMap; +import java.util.Map; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = AgentV1AgentAudioDone.Builder.class) +public final class AgentV1AgentAudioDone { + private final Map additionalProperties; + + private AgentV1AgentAudioDone(Map additionalProperties) { + this.additionalProperties = additionalProperties; + } + + /** + * @return Message type identifier indicating the agent has finished sending audio + */ + @JsonProperty("type") + public String getType() { + return "AgentAudioDone"; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof AgentV1AgentAudioDone; + } + + @java.lang.Override + public int hashCode() { + // Manual patch: Fern generates equals() (all instances of this fields-less message + // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a + // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. + return getClass().hashCode(); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @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 { + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(AgentV1AgentAudioDone other) { + return this; + } + + public AgentV1AgentAudioDone build() { + return new AgentV1AgentAudioDone(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/resources/agent/v1/types/AgentV1KeepAlive.java.bak b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1KeepAlive.java.bak new file mode 100644 index 0000000..083578b --- /dev/null +++ b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1KeepAlive.java.bak @@ -0,0 +1,86 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.deepgram.resources.agent.v1.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.databind.annotation.JsonDeserialize; +import java.util.HashMap; +import java.util.Map; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = AgentV1KeepAlive.Builder.class) +public final class AgentV1KeepAlive { + private final Map additionalProperties; + + private AgentV1KeepAlive(Map additionalProperties) { + this.additionalProperties = additionalProperties; + } + + /** + * @return Message type identifier + */ + @JsonProperty("type") + public String getType() { + return "KeepAlive"; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof AgentV1KeepAlive; + } + + @java.lang.Override + public int hashCode() { + // Manual patch: Fern generates equals() (all instances of this fields-less message + // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a + // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. + return getClass().hashCode(); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @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 { + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(AgentV1KeepAlive other) { + return this; + } + + public AgentV1KeepAlive build() { + return new AgentV1KeepAlive(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/resources/agent/v1/types/AgentV1ListenUpdated.java.bak b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ListenUpdated.java.bak new file mode 100644 index 0000000..6018473 --- /dev/null +++ b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ListenUpdated.java.bak @@ -0,0 +1,86 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.deepgram.resources.agent.v1.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.databind.annotation.JsonDeserialize; +import java.util.HashMap; +import java.util.Map; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = AgentV1ListenUpdated.Builder.class) +public final class AgentV1ListenUpdated { + private final Map additionalProperties; + + private AgentV1ListenUpdated(Map additionalProperties) { + this.additionalProperties = additionalProperties; + } + + /** + * @return Message type identifier for listen update confirmation + */ + @JsonProperty("type") + public String getType() { + return "ListenUpdated"; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof AgentV1ListenUpdated; + } + + @java.lang.Override + public int hashCode() { + // Manual patch: Fern generates equals() (all instances of this fields-less message + // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a + // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. + return getClass().hashCode(); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @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 { + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(AgentV1ListenUpdated other) { + return this; + } + + public AgentV1ListenUpdated build() { + return new AgentV1ListenUpdated(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/resources/agent/v1/types/AgentV1PromptUpdated.java.bak b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1PromptUpdated.java.bak new file mode 100644 index 0000000..6edec37 --- /dev/null +++ b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1PromptUpdated.java.bak @@ -0,0 +1,86 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.deepgram.resources.agent.v1.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.databind.annotation.JsonDeserialize; +import java.util.HashMap; +import java.util.Map; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = AgentV1PromptUpdated.Builder.class) +public final class AgentV1PromptUpdated { + private final Map additionalProperties; + + private AgentV1PromptUpdated(Map additionalProperties) { + this.additionalProperties = additionalProperties; + } + + /** + * @return Message type identifier for prompt update confirmation + */ + @JsonProperty("type") + public String getType() { + return "PromptUpdated"; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof AgentV1PromptUpdated; + } + + @java.lang.Override + public int hashCode() { + // Manual patch: Fern generates equals() (all instances of this fields-less message + // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a + // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. + return getClass().hashCode(); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @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 { + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(AgentV1PromptUpdated other) { + return this; + } + + public AgentV1PromptUpdated build() { + return new AgentV1PromptUpdated(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/resources/agent/v1/types/AgentV1SettingsApplied.java.bak b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SettingsApplied.java.bak new file mode 100644 index 0000000..fb23c60 --- /dev/null +++ b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SettingsApplied.java.bak @@ -0,0 +1,86 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.deepgram.resources.agent.v1.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.databind.annotation.JsonDeserialize; +import java.util.HashMap; +import java.util.Map; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = AgentV1SettingsApplied.Builder.class) +public final class AgentV1SettingsApplied { + private final Map additionalProperties; + + private AgentV1SettingsApplied(Map additionalProperties) { + this.additionalProperties = additionalProperties; + } + + /** + * @return Message type identifier for settings applied confirmation + */ + @JsonProperty("type") + public String getType() { + return "SettingsApplied"; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof AgentV1SettingsApplied; + } + + @java.lang.Override + public int hashCode() { + // Manual patch: Fern generates equals() (all instances of this fields-less message + // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a + // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. + return getClass().hashCode(); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @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 { + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(AgentV1SettingsApplied other) { + return this; + } + + public AgentV1SettingsApplied build() { + return new AgentV1SettingsApplied(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/resources/agent/v1/types/AgentV1SpeakUpdated.java.bak b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SpeakUpdated.java.bak new file mode 100644 index 0000000..7619157 --- /dev/null +++ b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SpeakUpdated.java.bak @@ -0,0 +1,86 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.deepgram.resources.agent.v1.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.databind.annotation.JsonDeserialize; +import java.util.HashMap; +import java.util.Map; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = AgentV1SpeakUpdated.Builder.class) +public final class AgentV1SpeakUpdated { + private final Map additionalProperties; + + private AgentV1SpeakUpdated(Map additionalProperties) { + this.additionalProperties = additionalProperties; + } + + /** + * @return Message type identifier for speak update confirmation + */ + @JsonProperty("type") + public String getType() { + return "SpeakUpdated"; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof AgentV1SpeakUpdated; + } + + @java.lang.Override + public int hashCode() { + // Manual patch: Fern generates equals() (all instances of this fields-less message + // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a + // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. + return getClass().hashCode(); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @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 { + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(AgentV1SpeakUpdated other) { + return this; + } + + public AgentV1SpeakUpdated build() { + return new AgentV1SpeakUpdated(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/resources/agent/v1/types/AgentV1ThinkUpdated.java.bak b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ThinkUpdated.java.bak new file mode 100644 index 0000000..2f2a981 --- /dev/null +++ b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ThinkUpdated.java.bak @@ -0,0 +1,86 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.deepgram.resources.agent.v1.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.databind.annotation.JsonDeserialize; +import java.util.HashMap; +import java.util.Map; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = AgentV1ThinkUpdated.Builder.class) +public final class AgentV1ThinkUpdated { + private final Map additionalProperties; + + private AgentV1ThinkUpdated(Map additionalProperties) { + this.additionalProperties = additionalProperties; + } + + /** + * @return Message type identifier for think update confirmation + */ + @JsonProperty("type") + public String getType() { + return "ThinkUpdated"; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof AgentV1ThinkUpdated; + } + + @java.lang.Override + public int hashCode() { + // Manual patch: Fern generates equals() (all instances of this fields-less message + // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a + // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. + return getClass().hashCode(); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @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 { + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(AgentV1ThinkUpdated other) { + return this; + } + + public AgentV1ThinkUpdated build() { + return new AgentV1ThinkUpdated(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/resources/agent/v1/types/AgentV1UserStartedSpeaking.java.bak b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1UserStartedSpeaking.java.bak new file mode 100644 index 0000000..7c3fc38 --- /dev/null +++ b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1UserStartedSpeaking.java.bak @@ -0,0 +1,86 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.deepgram.resources.agent.v1.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.databind.annotation.JsonDeserialize; +import java.util.HashMap; +import java.util.Map; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = AgentV1UserStartedSpeaking.Builder.class) +public final class AgentV1UserStartedSpeaking { + private final Map additionalProperties; + + private AgentV1UserStartedSpeaking(Map additionalProperties) { + this.additionalProperties = additionalProperties; + } + + /** + * @return Message type identifier indicating that the user has begun speaking + */ + @JsonProperty("type") + public String getType() { + return "UserStartedSpeaking"; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof AgentV1UserStartedSpeaking; + } + + @java.lang.Override + public int hashCode() { + // Manual patch: Fern generates equals() (all instances of this fields-less message + // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a + // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. + return getClass().hashCode(); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @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 { + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(AgentV1UserStartedSpeaking other) { + return this; + } + + public AgentV1UserStartedSpeaking build() { + return new AgentV1UserStartedSpeaking(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/resources/listen/v2/types/ListenV2CloseStream.java.bak b/src/main/java/com/deepgram/resources/listen/v2/types/ListenV2CloseStream.java.bak new file mode 100644 index 0000000..e508681 --- /dev/null +++ b/src/main/java/com/deepgram/resources/listen/v2/types/ListenV2CloseStream.java.bak @@ -0,0 +1,86 @@ +/** + * 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.databind.annotation.JsonDeserialize; +import java.util.HashMap; +import java.util.Map; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = ListenV2CloseStream.Builder.class) +public final class ListenV2CloseStream { + private final Map additionalProperties; + + private ListenV2CloseStream(Map additionalProperties) { + this.additionalProperties = additionalProperties; + } + + /** + * @return Message type identifier + */ + @JsonProperty("type") + public String getType() { + return "CloseStream"; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof ListenV2CloseStream; + } + + @java.lang.Override + public int hashCode() { + // Manual patch: Fern generates equals() (all instances of this fields-less message + // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a + // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. + return getClass().hashCode(); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @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 { + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(ListenV2CloseStream other) { + return this; + } + + public ListenV2CloseStream build() { + return new ListenV2CloseStream(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/resources/listen/v2/websocket/V2WebSocketClient.java.bak b/src/main/java/com/deepgram/resources/listen/v2/websocket/V2WebSocketClient.java.bak new file mode 100644 index 0000000..1325569 --- /dev/null +++ b/src/main/java/com/deepgram/resources/listen/v2/websocket/V2WebSocketClient.java.bak @@ -0,0 +1,483 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.deepgram.resources.listen.v2.websocket; + +import com.deepgram.core.ClientOptions; +import com.deepgram.core.DisconnectReason; +import com.deepgram.core.ObjectMappers; +import com.deepgram.core.ReconnectingWebSocketListener; +import com.deepgram.core.RequestOptions; +import com.deepgram.core.WebSocketReadyState; +import com.deepgram.resources.listen.v2.types.ListenV2CloseStream; +import com.deepgram.resources.listen.v2.types.ListenV2Configure; +import com.deepgram.resources.listen.v2.types.ListenV2ConfigureFailure; +import com.deepgram.resources.listen.v2.types.ListenV2ConfigureSuccess; +import com.deepgram.resources.listen.v2.types.ListenV2Connected; +import com.deepgram.resources.listen.v2.types.ListenV2FatalError; +import com.deepgram.resources.listen.v2.types.ListenV2TurnInfo; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ScheduledExecutorService; +import java.util.function.Consumer; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.WebSocket; +import okio.ByteString; + +/** + * WebSocket client for the v2 channel. + * Provides real-time bidirectional communication with strongly-typed messages. + */ +public class V2WebSocketClient implements AutoCloseable { + protected final ClientOptions clientOptions; + + private final ObjectMapper objectMapper; + + private final OkHttpClient okHttpClient; + + private ScheduledExecutorService timeoutExecutor; + + private volatile WebSocketReadyState readyState = WebSocketReadyState.CLOSED; + + private volatile Runnable onConnectedHandler; + + private volatile Consumer onDisconnectedHandler; + + private volatile Consumer onErrorHandler; + + private volatile Consumer onMessageHandler; + + private volatile ReconnectingWebSocketListener.ReconnectOptions reconnectOptions; + + private CompletableFuture connectionFuture; + + private ReconnectingWebSocketListener reconnectingListener; + + private volatile Consumer connectedHandler; + + private volatile Consumer turnInfoHandler; + + private volatile Consumer configureSuccessHandler; + + private volatile Consumer configureFailureHandler; + + private volatile Consumer errorHandler; + + /** + * Creates a new async WebSocket client for the v2 channel. + */ + public V2WebSocketClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + this.objectMapper = ObjectMappers.JSON_MAPPER; + this.okHttpClient = clientOptions.httpClient(); + } + + /** + * Establishes the WebSocket connection asynchronously with automatic reconnection. + * @return a CompletableFuture that completes when the connection is established + * @param options connection options including query parameters + */ + public CompletableFuture connect(V2ConnectOptions options) { + connectionFuture = new CompletableFuture<>(); + String baseUrl = clientOptions.environment().getProductionURL(); + String fullPath = "/v2/listen"; + if (baseUrl.endsWith("/") && fullPath.startsWith("/")) { + fullPath = fullPath.substring(1); + } else if (!baseUrl.endsWith("/") && !fullPath.startsWith("/")) { + fullPath = "/" + fullPath; + } + // OkHttp's HttpUrl only supports http/https schemes; convert wss/ws for URL parsing + if (baseUrl.startsWith("wss://")) { + baseUrl = "https://" + baseUrl.substring(6); + } else if (baseUrl.startsWith("ws://")) { + baseUrl = "http://" + baseUrl.substring(5); + } + HttpUrl parsedUrl = HttpUrl.parse(baseUrl + fullPath); + if (parsedUrl == null) { + throw new IllegalArgumentException("Invalid WebSocket URL: " + baseUrl + fullPath); + } + HttpUrl.Builder urlBuilder = parsedUrl.newBuilder(); + urlBuilder.addQueryParameter("model", String.valueOf(options.getModel())); + if (options.getEncoding() != null && options.getEncoding().isPresent()) { + urlBuilder.addQueryParameter( + "encoding", String.valueOf(options.getEncoding().get())); + } + if (options.getSampleRate() != null && options.getSampleRate().isPresent()) { + urlBuilder.addQueryParameter( + "sample_rate", String.valueOf(options.getSampleRate().get())); + } + if (options.getEagerEotThreshold() != null + && options.getEagerEotThreshold().isPresent()) { + urlBuilder.addQueryParameter( + "eager_eot_threshold", + String.valueOf(options.getEagerEotThreshold().get())); + } + if (options.getEotThreshold() != null && options.getEotThreshold().isPresent()) { + urlBuilder.addQueryParameter( + "eot_threshold", String.valueOf(options.getEotThreshold().get())); + } + if (options.getEotTimeoutMs() != null && options.getEotTimeoutMs().isPresent()) { + urlBuilder.addQueryParameter( + "eot_timeout_ms", String.valueOf(options.getEotTimeoutMs().get())); + } + if (options.getKeyterm() != null && options.getKeyterm().isPresent()) { + urlBuilder.addQueryParameter( + "keyterm", String.valueOf(options.getKeyterm().get())); + } + if (options.getLanguageHint() != null && options.getLanguageHint().isPresent()) { + urlBuilder.addQueryParameter( + "language_hint", String.valueOf(options.getLanguageHint().get())); + } + if (options.getProfanityFilter() != null && options.getProfanityFilter().isPresent()) { + urlBuilder.addQueryParameter( + "profanity_filter", + String.valueOf(options.getProfanityFilter().get())); + } + if (options.getMipOptOut() != null && options.getMipOptOut().isPresent()) { + urlBuilder.addQueryParameter( + "mip_opt_out", String.valueOf(options.getMipOptOut().get())); + } + if (options.getTag() != null && options.getTag().isPresent()) { + urlBuilder.addQueryParameter("tag", String.valueOf(options.getTag().get())); + } + Request.Builder requestBuilder = new Request.Builder().url(urlBuilder.build()); + clientOptions.headers((RequestOptions) null).forEach(requestBuilder::addHeader); + final Request request = requestBuilder.build(); + this.readyState = WebSocketReadyState.CONNECTING; + ReconnectingWebSocketListener.ReconnectOptions reconnectOpts = this.reconnectOptions != null + ? 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); + } + }) { + @Override + protected void onWebSocketOpen(WebSocket webSocket, Response response) { + readyState = WebSocketReadyState.OPEN; + if (onConnectedHandler != null) { + onConnectedHandler.run(); + } + connectionFuture.complete(null); + } + + @Override + protected void onWebSocketMessage(WebSocket webSocket, String text) { + handleIncomingMessage(text); + } + + @Override + protected void onWebSocketBinaryMessage(WebSocket webSocket, ByteString bytes) {} + + @Override + protected void onWebSocketFailure(WebSocket webSocket, Throwable t, Response response) { + readyState = WebSocketReadyState.CLOSED; + if (onErrorHandler != null) { + onErrorHandler.accept(new RuntimeException(t)); + } + connectionFuture.completeExceptionally(t); + } + + @Override + protected void onWebSocketClosed(WebSocket webSocket, int code, String reason) { + readyState = WebSocketReadyState.CLOSED; + if (onDisconnectedHandler != null) { + onDisconnectedHandler.accept(new DisconnectReason(code, reason)); + } + } + }; + reconnectingListener.connect(); + return connectionFuture; + } + + /** + * Disconnects the WebSocket connection and releases resources. + */ + public void disconnect() { + reconnectingListener.disconnect(); + if (timeoutExecutor != null) { + timeoutExecutor.shutdownNow(); + timeoutExecutor = null; + } + } + + /** + * Gets the current state of the WebSocket connection. + * + * This provides the actual connection state, similar to the W3C WebSocket API. + * + * @return the current WebSocket ready state + */ + public WebSocketReadyState getReadyState() { + return readyState; + } + + /** + * Sends a ListenV2Media message to the server asynchronously. + * @param message the message to send + * @return a CompletableFuture that completes when the message is sent + */ + public CompletableFuture sendMedia(ByteString message) { + CompletableFuture future = new CompletableFuture<>(); + try { + assertSocketIsOpen(); + // Use reconnecting listener's sendBinary method which handles queuing + reconnectingListener.sendBinary(message); + future.complete(null); + } catch (Exception e) { + future.completeExceptionally(new RuntimeException("Failed to send binary data", e)); + } + return future; + } + + /** + * Sends a ListenV2CloseStream message to the server asynchronously. + * @param message the message to send + * @return a CompletableFuture that completes when the message is sent + */ + public CompletableFuture sendCloseStream(ListenV2CloseStream message) { + return sendMessage(message); + } + + /** + * Sends a ListenV2Configure message to the server asynchronously. + * @param message the message to send + * @return a CompletableFuture that completes when the message is sent + */ + public CompletableFuture sendConfigure(ListenV2Configure message) { + return sendMessage(message); + } + + /** + * Registers a handler for ListenV2Connected messages from the server. + * @param handler the handler to invoke when a message is received + */ + public void onConnected(Consumer handler) { + this.connectedHandler = handler; + } + + /** + * Registers a handler for ListenV2TurnInfo messages from the server. + * @param handler the handler to invoke when a message is received + */ + public void onTurnInfo(Consumer handler) { + this.turnInfoHandler = handler; + } + + /** + * Registers a handler for ListenV2ConfigureSuccess messages from the server. + * @param handler the handler to invoke when a message is received + */ + public void onConfigureSuccess(Consumer handler) { + this.configureSuccessHandler = handler; + } + + /** + * Registers a handler for ListenV2ConfigureFailure messages from the server. + * @param handler the handler to invoke when a message is received + */ + public void onConfigureFailure(Consumer handler) { + this.configureFailureHandler = handler; + } + + /** + * Registers a handler for ListenV2FatalError messages from the server. + * @param handler the handler to invoke when a message is received + */ + public void onErrorMessage(Consumer handler) { + this.errorHandler = handler; + } + + /** + * Registers a handler called when the connection is established. + * @param handler the handler to invoke when connected + */ + public void onConnected(Runnable handler) { + this.onConnectedHandler = handler; + } + + /** + * Registers a handler called when the connection is closed. + * @param handler the handler to invoke when disconnected + */ + public void onDisconnected(Consumer handler) { + this.onDisconnectedHandler = handler; + } + + /** + * Registers a handler called when an error occurs. + * @param handler the handler to invoke on error + */ + public void onError(Consumer handler) { + this.onErrorHandler = handler; + } + + /** + * Registers a handler called for every incoming text message. + * The handler receives the raw JSON string before type-specific dispatch. + * @param handler the handler to invoke with the raw message JSON + */ + public void onMessage(Consumer handler) { + this.onMessageHandler = handler; + } + + /** + * Configures reconnection behavior. Must be called before {@link #connect}. + * + * @param options the reconnection options (backoff, retries, queue size) + */ + public void reconnectOptions(ReconnectingWebSocketListener.ReconnectOptions options) { + this.reconnectOptions = options; + } + + /** + * Closes this WebSocket client, releasing all resources. + * Equivalent to calling {@link #disconnect()}. + */ + @Override + public void close() { + disconnect(); + } + + /** + * Ensures the WebSocket is connected and ready to send messages. + * @throws IllegalStateException if the socket is not connected or not open + */ + private void assertSocketIsOpen() { + if (reconnectingListener.getWebSocket() == null) { + throw new IllegalStateException("WebSocket is not connected. Call connect() first."); + } + if (readyState != WebSocketReadyState.OPEN) { + throw new IllegalStateException("WebSocket is not open. Current state: " + readyState); + } + } + + private CompletableFuture sendMessage(Object body) { + CompletableFuture future = new CompletableFuture<>(); + try { + assertSocketIsOpen(); + String json = objectMapper.writeValueAsString(body); + // Use reconnecting listener's send method which handles queuing + reconnectingListener.send(json); + future.complete(null); + } catch (IllegalStateException e) { + future.completeExceptionally(e); + } catch (Exception e) { + future.completeExceptionally(new RuntimeException("Failed to send message", e)); + } + return future; + } + + private void handleIncomingMessage(String json) { + try { + if (onMessageHandler != null) { + onMessageHandler.accept(json); + } + JsonNode node = objectMapper.readTree(json); + if (node == null || node.isNull()) { + throw new IllegalArgumentException("Received null or invalid JSON message"); + } + if (node.has("request_id") + && node.has("sequence_id") + && node.has("event") + && node.has("turn_index") + && node.has("audio_window_start") + && node.has("audio_window_end") + && node.has("transcript") + && node.has("words") + && node.has("end_of_turn_confidence") + && "TurnInfo".equals(node.path("type").asText())) { + ListenV2TurnInfo turnInfoHandlerEvent = null; + try { + turnInfoHandlerEvent = objectMapper.treeToValue(node, ListenV2TurnInfo.class); + } catch (Exception e) { + } + if (turnInfoHandlerEvent != null) { + if (turnInfoHandler != null) { + turnInfoHandler.accept(turnInfoHandlerEvent); + } + return; + } + } + if (node.has("request_id") + && node.has("thresholds") + && node.has("keyterms") + && node.has("sequence_id") + && "ConfigureSuccess".equals(node.path("type").asText())) { + ListenV2ConfigureSuccess configureSuccessHandlerEvent = null; + try { + configureSuccessHandlerEvent = objectMapper.treeToValue(node, ListenV2ConfigureSuccess.class); + } catch (Exception e) { + } + if (configureSuccessHandlerEvent != null) { + if (configureSuccessHandler != null) { + configureSuccessHandler.accept(configureSuccessHandlerEvent); + } + return; + } + } + if (node.has("sequence_id") + && node.has("code") + && node.has("description") + && "Error".equals(node.path("type").asText())) { + ListenV2FatalError errorHandlerEvent = null; + try { + errorHandlerEvent = objectMapper.treeToValue(node, ListenV2FatalError.class); + } catch (Exception e) { + } + if (errorHandlerEvent != null) { + if (errorHandler != null) { + errorHandler.accept(errorHandlerEvent); + } + return; + } + } + if (node.has("request_id") + && node.has("sequence_id") + && "Connected".equals(node.path("type").asText())) { + ListenV2Connected connectedHandlerEvent = null; + try { + connectedHandlerEvent = objectMapper.treeToValue(node, ListenV2Connected.class); + } catch (Exception e) { + } + if (connectedHandlerEvent != null) { + if (connectedHandler != null) { + connectedHandler.accept(connectedHandlerEvent); + } + return; + } + } + if (node.has("request_id") + && node.has("sequence_id") + && "ConfigureFailure".equals(node.path("type").asText())) { + ListenV2ConfigureFailure configureFailureHandlerEvent = null; + try { + configureFailureHandlerEvent = objectMapper.treeToValue(node, ListenV2ConfigureFailure.class); + } catch (Exception e) { + } + if (configureFailureHandlerEvent != null) { + if (configureFailureHandler != null) { + configureFailureHandler.accept(configureFailureHandlerEvent); + } + return; + } + } + // Unrecognized message type: forward-compatible no-op. The raw frame was + // already delivered to onMessage(String) above, so a newer server adding a + // benign control frame (e.g. a GA addition to this endpoint) must not surface + // as a fatal error to deployed clients. Routing it to onError would make a + // harmless frame look fatal; mirrors the speak v2 client and the JS/Python SDKs. + } catch (Exception e) { + if (onErrorHandler != null) { + onErrorHandler.accept(e); + } + } + } +} diff --git a/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Close.java.bak b/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Close.java.bak new file mode 100644 index 0000000..51fef19 --- /dev/null +++ b/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Close.java.bak @@ -0,0 +1,86 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.deepgram.resources.speak.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.databind.annotation.JsonDeserialize; +import java.util.HashMap; +import java.util.Map; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = SpeakV2Close.Builder.class) +public final class SpeakV2Close { + private final Map additionalProperties; + + private SpeakV2Close(Map additionalProperties) { + this.additionalProperties = additionalProperties; + } + + /** + * @return Message type identifier + */ + @JsonProperty("type") + public String getType() { + return "Close"; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof SpeakV2Close; + } + + @java.lang.Override + public int hashCode() { + // Manual patch: Fern generates equals() (all instances of this fields-less message + // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a + // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. + return getClass().hashCode(); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @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 { + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(SpeakV2Close other) { + return this; + } + + public SpeakV2Close build() { + return new SpeakV2Close(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/resources/speak/v2/types/SpeakV2Flush.java.bak b/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Flush.java.bak new file mode 100644 index 0000000..e122400 --- /dev/null +++ b/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Flush.java.bak @@ -0,0 +1,86 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.deepgram.resources.speak.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.databind.annotation.JsonDeserialize; +import java.util.HashMap; +import java.util.Map; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = SpeakV2Flush.Builder.class) +public final class SpeakV2Flush { + private final Map additionalProperties; + + private SpeakV2Flush(Map additionalProperties) { + this.additionalProperties = additionalProperties; + } + + /** + * @return Message type identifier + */ + @JsonProperty("type") + public String getType() { + return "Flush"; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof SpeakV2Flush; + } + + @java.lang.Override + public int hashCode() { + // Manual patch: Fern generates equals() (all instances of this fields-less message + // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a + // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. + return getClass().hashCode(); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @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 { + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(SpeakV2Flush other) { + return this; + } + + public SpeakV2Flush build() { + return new SpeakV2Flush(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/resources/speak/v2/websocket/V2WebSocketClient.java.bak b/src/main/java/com/deepgram/resources/speak/v2/websocket/V2WebSocketClient.java.bak new file mode 100644 index 0000000..1ce8ea5 --- /dev/null +++ b/src/main/java/com/deepgram/resources/speak/v2/websocket/V2WebSocketClient.java.bak @@ -0,0 +1,507 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.deepgram.resources.speak.v2.websocket; + +import com.deepgram.core.ClientOptions; +import com.deepgram.core.DisconnectReason; +import com.deepgram.core.ObjectMappers; +import com.deepgram.core.ReconnectingWebSocketListener; +import com.deepgram.core.RequestOptions; +import com.deepgram.core.WebSocketReadyState; +import com.deepgram.resources.speak.v2.types.SpeakV2Close; +import com.deepgram.resources.speak.v2.types.SpeakV2Connected; +import com.deepgram.resources.speak.v2.types.SpeakV2Error; +import com.deepgram.resources.speak.v2.types.SpeakV2Flush; +import com.deepgram.resources.speak.v2.types.SpeakV2Flushed; +import com.deepgram.resources.speak.v2.types.SpeakV2SessionMetadata; +import com.deepgram.resources.speak.v2.types.SpeakV2Speak; +import com.deepgram.resources.speak.v2.types.SpeakV2SpeechMetadata; +import com.deepgram.resources.speak.v2.types.SpeakV2SpeechStarted; +import com.deepgram.resources.speak.v2.types.SpeakV2Warning; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ScheduledExecutorService; +import java.util.function.Consumer; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.WebSocket; +import okio.ByteString; + +/** + * WebSocket client for the v2 channel. + * Provides real-time bidirectional communication with strongly-typed messages. + */ +public class V2WebSocketClient implements AutoCloseable { + protected final ClientOptions clientOptions; + + private final ObjectMapper objectMapper; + + private final OkHttpClient okHttpClient; + + private ScheduledExecutorService timeoutExecutor; + + private volatile WebSocketReadyState readyState = WebSocketReadyState.CLOSED; + + private volatile Runnable onConnectedHandler; + + private volatile Consumer onDisconnectedHandler; + + private volatile Consumer onErrorHandler; + + private volatile Consumer onMessageHandler; + + private volatile ReconnectingWebSocketListener.ReconnectOptions reconnectOptions; + + private CompletableFuture connectionFuture; + + private ReconnectingWebSocketListener reconnectingListener; + + private volatile Consumer speakV2AudioHandler; + + private volatile Consumer connectedHandler; + + private volatile Consumer speechStartedHandler; + + private volatile Consumer speechMetadataHandler; + + private volatile Consumer flushedHandler; + + private volatile Consumer sessionMetadataHandler; + + private volatile Consumer warningHandler; + + private volatile Consumer errorHandler; + + /** + * Creates a new async WebSocket client for the v2 channel. + */ + public V2WebSocketClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + this.objectMapper = ObjectMappers.JSON_MAPPER; + this.okHttpClient = clientOptions.httpClient(); + } + + /** + * Establishes the WebSocket connection asynchronously with automatic reconnection. + * @return a CompletableFuture that completes when the connection is established + * @param options connection options including query parameters + */ + public CompletableFuture connect(V2ConnectOptions options) { + connectionFuture = new CompletableFuture<>(); + String baseUrl = clientOptions.environment().getProductionURL(); + String fullPath = "/v2/speak"; + if (baseUrl.endsWith("/") && fullPath.startsWith("/")) { + fullPath = fullPath.substring(1); + } else if (!baseUrl.endsWith("/") && !fullPath.startsWith("/")) { + fullPath = "/" + fullPath; + } + // OkHttp's HttpUrl only supports http/https schemes; convert wss/ws for URL parsing + if (baseUrl.startsWith("wss://")) { + baseUrl = "https://" + baseUrl.substring(6); + } else if (baseUrl.startsWith("ws://")) { + baseUrl = "http://" + baseUrl.substring(5); + } + HttpUrl parsedUrl = HttpUrl.parse(baseUrl + fullPath); + if (parsedUrl == null) { + throw new IllegalArgumentException("Invalid WebSocket URL: " + baseUrl + fullPath); + } + HttpUrl.Builder urlBuilder = parsedUrl.newBuilder(); + urlBuilder.addQueryParameter("model", String.valueOf(options.getModel())); + if (options.getEncoding() != null && options.getEncoding().isPresent()) { + urlBuilder.addQueryParameter( + "encoding", String.valueOf(options.getEncoding().get())); + } + if (options.getSampleRate() != null && options.getSampleRate().isPresent()) { + urlBuilder.addQueryParameter( + "sample_rate", String.valueOf(options.getSampleRate().get())); + } + if (options.getMipOptOut() != null && options.getMipOptOut().isPresent()) { + urlBuilder.addQueryParameter( + "mip_opt_out", String.valueOf(options.getMipOptOut().get())); + } + if (options.getTag() != null && options.getTag().isPresent()) { + urlBuilder.addQueryParameter("tag", String.valueOf(options.getTag().get())); + } + Request.Builder requestBuilder = new Request.Builder().url(urlBuilder.build()); + clientOptions.headers((RequestOptions) null).forEach(requestBuilder::addHeader); + final Request request = requestBuilder.build(); + this.readyState = WebSocketReadyState.CONNECTING; + ReconnectingWebSocketListener.ReconnectOptions reconnectOpts = this.reconnectOptions != null + ? 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); + } + }) { + @Override + protected void onWebSocketOpen(WebSocket webSocket, Response response) { + readyState = WebSocketReadyState.OPEN; + if (onConnectedHandler != null) { + onConnectedHandler.run(); + } + connectionFuture.complete(null); + } + + @Override + protected void onWebSocketMessage(WebSocket webSocket, String text) { + handleIncomingMessage(text); + } + + @Override + protected void onWebSocketBinaryMessage(WebSocket webSocket, ByteString bytes) { + if (speakV2AudioHandler != null) { + speakV2AudioHandler.accept(bytes); + } + } + + @Override + protected void onWebSocketFailure(WebSocket webSocket, Throwable t, Response response) { + readyState = WebSocketReadyState.CLOSED; + if (onErrorHandler != null) { + onErrorHandler.accept(new RuntimeException(t)); + } + connectionFuture.completeExceptionally(t); + } + + @Override + protected void onWebSocketClosed(WebSocket webSocket, int code, String reason) { + readyState = WebSocketReadyState.CLOSED; + if (onDisconnectedHandler != null) { + onDisconnectedHandler.accept(new DisconnectReason(code, reason)); + } + } + }; + reconnectingListener.connect(); + return connectionFuture; + } + + /** + * Disconnects the WebSocket connection and releases resources. + */ + public void disconnect() { + reconnectingListener.disconnect(); + if (timeoutExecutor != null) { + timeoutExecutor.shutdownNow(); + timeoutExecutor = null; + } + } + + /** + * Gets the current state of the WebSocket connection. + * + * This provides the actual connection state, similar to the W3C WebSocket API. + * + * @return the current WebSocket ready state + */ + public WebSocketReadyState getReadyState() { + return readyState; + } + + /** + * Sends a SpeakV2Speak message to the server asynchronously. + * @param message the message to send + * @return a CompletableFuture that completes when the message is sent + */ + public CompletableFuture sendSpeak(SpeakV2Speak message) { + return sendMessage(message); + } + + /** + * Sends a SpeakV2Flush message to the server asynchronously. + * @param message the message to send + * @return a CompletableFuture that completes when the message is sent + */ + public CompletableFuture sendFlush(SpeakV2Flush message) { + return sendMessage(message); + } + + /** + * Sends a SpeakV2Close message to the server asynchronously. + * @param message the message to send + * @return a CompletableFuture that completes when the message is sent + */ + public CompletableFuture sendClose(SpeakV2Close message) { + return sendMessage(message); + } + + /** + * Registers a handler for SpeakV2Audio messages from the server. + * @param handler the handler to invoke when a message is received + */ + public void onSpeakV2Audio(Consumer handler) { + this.speakV2AudioHandler = handler; + } + + /** + * Registers a handler for SpeakV2Connected messages from the server. + * @param handler the handler to invoke when a message is received + */ + public void onConnected(Consumer handler) { + this.connectedHandler = handler; + } + + /** + * Registers a handler for SpeakV2SpeechStarted messages from the server. + * @param handler the handler to invoke when a message is received + */ + public void onSpeechStarted(Consumer handler) { + this.speechStartedHandler = handler; + } + + /** + * Registers a handler for SpeakV2SpeechMetadata messages from the server. + * @param handler the handler to invoke when a message is received + */ + public void onSpeechMetadata(Consumer handler) { + this.speechMetadataHandler = handler; + } + + /** + * Registers a handler for SpeakV2Flushed messages from the server. + * @param handler the handler to invoke when a message is received + */ + public void onFlushed(Consumer handler) { + this.flushedHandler = handler; + } + + /** + * Registers a handler for SpeakV2SessionMetadata messages from the server. + * @param handler the handler to invoke when a message is received + */ + public void onSessionMetadata(Consumer handler) { + this.sessionMetadataHandler = handler; + } + + /** + * Registers a handler for SpeakV2Warning 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 SpeakV2Error messages from the server. + * @param handler the handler to invoke when a message is received + */ + public void onErrorMessage(Consumer handler) { + this.errorHandler = handler; + } + + /** + * Registers a handler called when the connection is established. + * @param handler the handler to invoke when connected + */ + public void onConnected(Runnable handler) { + this.onConnectedHandler = handler; + } + + /** + * Registers a handler called when the connection is closed. + * @param handler the handler to invoke when disconnected + */ + public void onDisconnected(Consumer handler) { + this.onDisconnectedHandler = handler; + } + + /** + * Registers a handler called when an error occurs. + * @param handler the handler to invoke on error + */ + public void onError(Consumer handler) { + this.onErrorHandler = handler; + } + + /** + * Registers a handler called for every incoming text message. + * The handler receives the raw JSON string before type-specific dispatch. + * @param handler the handler to invoke with the raw message JSON + */ + public void onMessage(Consumer handler) { + this.onMessageHandler = handler; + } + + /** + * Configures reconnection behavior. Must be called before {@link #connect}. + * + * @param options the reconnection options (backoff, retries, queue size) + */ + public void reconnectOptions(ReconnectingWebSocketListener.ReconnectOptions options) { + this.reconnectOptions = options; + } + + /** + * Closes this WebSocket client, releasing all resources. + * Equivalent to calling {@link #disconnect()}. + */ + @Override + public void close() { + disconnect(); + } + + /** + * Ensures the WebSocket is connected and ready to send messages. + * @throws IllegalStateException if the socket is not connected or not open + */ + private void assertSocketIsOpen() { + if (reconnectingListener.getWebSocket() == null) { + throw new IllegalStateException("WebSocket is not connected. Call connect() first."); + } + if (readyState != WebSocketReadyState.OPEN) { + throw new IllegalStateException("WebSocket is not open. Current state: " + readyState); + } + } + + private CompletableFuture sendMessage(Object body) { + CompletableFuture future = new CompletableFuture<>(); + try { + assertSocketIsOpen(); + String json = objectMapper.writeValueAsString(body); + // Use reconnecting listener's send method which handles queuing + reconnectingListener.send(json); + future.complete(null); + } catch (IllegalStateException e) { + future.completeExceptionally(e); + } catch (Exception e) { + future.completeExceptionally(new RuntimeException("Failed to send message", e)); + } + return future; + } + + private void handleIncomingMessage(String json) { + try { + if (onMessageHandler != null) { + onMessageHandler.accept(json); + } + JsonNode node = objectMapper.readTree(json); + if (node == null || node.isNull()) { + throw new IllegalArgumentException("Received null or invalid JSON message"); + } + if (node.has("speech_id") + && node.has("audio_duration_ms") + && node.has("input_character_count") + && node.has("billable_character_count") + && node.has("controls_applied") + && "SpeechMetadata".equals(node.path("type").asText())) { + SpeakV2SpeechMetadata speechMetadataHandlerEvent = null; + try { + speechMetadataHandlerEvent = objectMapper.treeToValue(node, SpeakV2SpeechMetadata.class); + } catch (Exception e) { + } + if (speechMetadataHandlerEvent != null) { + if (speechMetadataHandler != null) { + speechMetadataHandler.accept(speechMetadataHandlerEvent); + } + return; + } + } + if (node.has("request_id") + && node.has("model_name") + && node.has("model_version") + && node.has("model_uuids") + && "Connected".equals(node.path("type").asText())) { + SpeakV2Connected connectedHandlerEvent = null; + try { + connectedHandlerEvent = objectMapper.treeToValue(node, SpeakV2Connected.class); + } catch (Exception e) { + } + if (connectedHandlerEvent != null) { + if (connectedHandler != null) { + connectedHandler.accept(connectedHandlerEvent); + } + return; + } + } + if (node.has("total_audio_duration_ms") + && node.has("total_input_character_count") + && node.has("total_billable_character_count") + && "SessionMetadata".equals(node.path("type").asText())) { + SpeakV2SessionMetadata sessionMetadataHandlerEvent = null; + try { + sessionMetadataHandlerEvent = objectMapper.treeToValue(node, SpeakV2SessionMetadata.class); + } catch (Exception e) { + } + if (sessionMetadataHandlerEvent != null) { + if (sessionMetadataHandler != null) { + sessionMetadataHandler.accept(sessionMetadataHandlerEvent); + } + return; + } + } + if (node.has("code") + && node.has("description") + && "Warning".equals(node.path("type").asText())) { + SpeakV2Warning warningHandlerEvent = null; + try { + warningHandlerEvent = objectMapper.treeToValue(node, SpeakV2Warning.class); + } catch (Exception e) { + } + if (warningHandlerEvent != null) { + if (warningHandler != null) { + warningHandler.accept(warningHandlerEvent); + } + return; + } + } + if (node.has("code") + && node.has("description") + && "Error".equals(node.path("type").asText())) { + SpeakV2Error errorHandlerEvent = null; + try { + errorHandlerEvent = objectMapper.treeToValue(node, SpeakV2Error.class); + } catch (Exception e) { + } + if (errorHandlerEvent != null) { + if (errorHandler != null) { + errorHandler.accept(errorHandlerEvent); + } + return; + } + } + if (node.has("speech_id") + && "SpeechStarted".equals(node.path("type").asText())) { + SpeakV2SpeechStarted speechStartedHandlerEvent = null; + try { + speechStartedHandlerEvent = objectMapper.treeToValue(node, SpeakV2SpeechStarted.class); + } catch (Exception e) { + } + if (speechStartedHandlerEvent != null) { + if (speechStartedHandler != null) { + speechStartedHandler.accept(speechStartedHandlerEvent); + } + return; + } + } + if (node.has("speech_id") && "Flushed".equals(node.path("type").asText())) { + SpeakV2Flushed flushedHandlerEvent = null; + try { + flushedHandlerEvent = objectMapper.treeToValue(node, SpeakV2Flushed.class); + } catch (Exception e) { + } + if (flushedHandlerEvent != null) { + if (flushedHandler != null) { + flushedHandler.accept(flushedHandlerEvent); + } + return; + } + } + // Unrecognized message type: forward-compatible no-op. The raw frame was + // already delivered to onMessage(String) above, so a newer server adding a + // benign control frame (e.g. a GA addition to this endpoint) must not surface + // as a fatal error to deployed clients. Routing it to onError would make a + // harmless frame look fatal to a voice agent; mirrors the JS/Python SDKs. + } catch (Exception e) { + if (onErrorHandler != null) { + onErrorHandler.accept(e); + } + } + } +} From cd6295467e98e0577313454275a23f619b1e566b Mon Sep 17 00:00:00 2001 From: "fern-api[bot]" <115122769+fern-api[bot]@users.noreply.github.com> Date: Mon, 20 Jul 2026 10:02:09 +0000 Subject: [PATCH 3/8] SDK regeneration --- .fern/metadata.json | 4 +- .../java/com/deepgram/core/ClientOptions.java | 6 +- .../core/ReconnectingWebSocketListener.java | 93 +- .../agent/v1/types/AgentV1AgentAudioDone.java | 8 - .../agent/v1/types/AgentV1KeepAlive.java | 8 - .../agent/v1/types/AgentV1LatencyReport.java | 34 +- .../agent/v1/types/AgentV1ListenUpdated.java | 8 - .../agent/v1/types/AgentV1PromptUpdated.java | 8 - .../v1/types/AgentV1SettingsApplied.java | 8 - .../agent/v1/types/AgentV1SpeakUpdated.java | 8 - .../agent/v1/types/AgentV1ThinkUpdated.java | 8 - .../v1/types/AgentV1UserStartedSpeaking.java | 8 - .../listen/v2/types/ListenV2CloseStream.java | 8 - .../listen/v2/websocket/V2ConnectOptions.java | 33 + .../v2/websocket/V2WebSocketClient.java | 14 +- .../types/AudioGenerateRequestModel.java | 842 +++++++++++++----- .../v2/audio/requests/SpeakV2Request.java | 8 +- .../speak/v2/types/SpeakV2Close.java | 8 - .../speak/v2/types/SpeakV2Flush.java | 8 - .../speak/v2/websocket/V2WebSocketClient.java | 10 +- .../com/deepgram/types/ListenV2Numerals.java | 83 ++ .../java/com/deepgram/types/SpeakV1Model.java | 754 ++++++++++++---- 22 files changed, 1379 insertions(+), 590 deletions(-) create mode 100644 src/main/java/com/deepgram/types/ListenV2Numerals.java diff --git a/.fern/metadata.json b/.fern/metadata.json index 5e8f480..5a420ca 100644 --- a/.fern/metadata.json +++ b/.fern/metadata.json @@ -11,8 +11,8 @@ }, "enable-wire-tests": true }, - "originGitCommit": "14c0ca94fcd0279d99570389d7b688dc3a18ea41", + "originGitCommit": "ff8fd2b74fdd5c081e9f111d59d3619f7e286dd8", "originGitCommitIsDirty": true, "invokedBy": "manual", - "sdkVersion": "0.6.1" + "sdkVersion": "0.6.2" } \ No newline at end of file diff --git a/src/main/java/com/deepgram/core/ClientOptions.java b/src/main/java/com/deepgram/core/ClientOptions.java index 0b070bd..094347e 100644 --- a/src/main/java/com/deepgram/core/ClientOptions.java +++ b/src/main/java/com/deepgram/core/ClientOptions.java @@ -41,10 +41,10 @@ private ClientOptions( this.headers.putAll(headers); this.headers.putAll(new HashMap() { { - put("User-Agent", "com.deepgram:deepgram-java-sdk/0.6.1"); // x-release-please-version + put("User-Agent", "com.deepgram:deepgram-sdk/0.6.2"); put("X-Fern-Language", "JAVA"); - put("X-Fern-SDK-Name", "com.deepgram:deepgram-java-sdk"); - put("X-Fern-SDK-Version", "0.6.1"); // x-release-please-version + put("X-Fern-SDK-Name", "com.deepgram.fern:api-sdk"); + put("X-Fern-SDK-Version", "0.6.2"); } }); this.headerSuppliers = headerSuppliers; diff --git a/src/main/java/com/deepgram/core/ReconnectingWebSocketListener.java b/src/main/java/com/deepgram/core/ReconnectingWebSocketListener.java index a533068..0ca455a 100644 --- a/src/main/java/com/deepgram/core/ReconnectingWebSocketListener.java +++ b/src/main/java/com/deepgram/core/ReconnectingWebSocketListener.java @@ -25,15 +25,14 @@ * Provides production-ready resilience for WebSocket connections. */ public abstract class ReconnectingWebSocketListener extends WebSocketListener { - // Overridable options are held behind a single volatile reference (not five separate volatile - // fields) so {@link #applyOptionsOverride} swaps them atomically — a reader that snapshots the - // reference once sees a mutually-consistent set (e.g. getNextDelay() cannot observe a new min - // paired with an old max). Rewiring is used by {@code TransportWebSocketFactory} to honour - // {@code DeepgramTransportFactory.reconnectOptions()} without editing the generated WS clients. - private volatile ReconnectOptions activeOptions; - - // maxEnqueuedMessages is fixed at construction (the queue is sized once) and intentionally not - // overridable, so it stays a separate final field rather than being read from activeOptions. + private final long minReconnectionDelayMs; + + private final long maxReconnectionDelayMs; + + private final double reconnectionDelayGrowFactor; + + private final int maxRetries; + private final int maxEnqueuedMessages; private final AtomicInteger retryCount = new AtomicInteger(0); @@ -62,42 +61,21 @@ public abstract class ReconnectingWebSocketListener extends WebSocketListener { */ public ReconnectingWebSocketListener( ReconnectingWebSocketListener.ReconnectOptions options, Supplier connectionSupplier) { - this.activeOptions = options; + this.minReconnectionDelayMs = options.minReconnectionDelayMs; + this.maxReconnectionDelayMs = options.maxReconnectionDelayMs; + this.reconnectionDelayGrowFactor = options.reconnectionDelayGrowFactor; + this.maxRetries = options.maxRetries; this.maxEnqueuedMessages = options.maxEnqueuedMessages; this.connectionSupplier = connectionSupplier; } - /** - * Replaces the option-derived parameters on this listener at runtime. Used by - * {@code TransportWebSocketFactory} to apply {@code DeepgramTransportFactory.reconnectOptions()} - * without requiring edits to the generated per-resource WebSocket clients. {@code maxEnqueuedMessages} - * is intentionally not overridden — the message queue is sized at construction. - * - *

Thread-safety: the override is a single atomic write to a {@code volatile} reference, so a - * reader that snapshots {@link #activeOptions} once sees a mutually-consistent set of values - * (never a new min paired with an old max). The initial connect() call may have already started - * before the override lands, so for the very first attempt the original options apply; the - * override takes effect from the next attempt onwards. For the SageMaker storm-suppression case - * ({@code maxRetries(0)}) this is fine because the initial attempt's gate - * ({@code retryCount > maxRetries} with {@code retryCount=0}) always passes regardless. - * - * @param options replacement options; {@code null} is a no-op. - */ - public void applyOptionsOverride(ReconnectOptions options) { - if (options == null) { - return; - } - this.activeOptions = options; - } - /** * Initiates a WebSocket connection with automatic reconnection enabled. * * Connection behavior: - * - Times out after {@code ReconnectOptions.connectionTimeoutMs} (default 4000ms) + * - Times out after 4000 milliseconds * - Thread-safe via atomic lock (returns immediately if connection in progress) - * - {@code maxRetries} counts retries only — the initial attempt always proceeds. - * {@code maxRetries(0)} means "connect once, don't retry" (not "refuse to connect"). + * - Retry count not incremented for initial connection attempt * * Error handling: * - TimeoutException: Includes retry attempt context @@ -108,26 +86,20 @@ public void connect() { if (!connectLock.compareAndSet(false, true)) { return; } - // Snapshot the overridable options once so the gate and timeout below use a consistent set. - ReconnectOptions opts = this.activeOptions; - // retryCount is incremented inside scheduleReconnect() before re-entering connect(), - // so on the initial call retryCount == 0 and we always proceed. The cap applies to - // retries only — maxRetries(0) blocks retries but allows the initial attempt. - if (retryCount.get() > opts.maxRetries) { + if (retryCount.get() >= maxRetries) { connectLock.set(false); return; } try { CompletableFuture connectionFuture = CompletableFuture.supplyAsync(connectionSupplier); try { - webSocket = connectionFuture.get(opts.connectionTimeoutMs, MILLISECONDS); + webSocket = connectionFuture.get(4000, MILLISECONDS); } catch (TimeoutException e) { connectionFuture.cancel(true); TimeoutException timeoutError = - new TimeoutException("WebSocket connection timeout after " + opts.connectionTimeoutMs - + " milliseconds" + new TimeoutException("WebSocket connection timeout after " + 4000 + " milliseconds" + (retryCount.get() > 0 - ? " (retry attempt #" + retryCount.get() + ")" + ? " (retry attempt #" + retryCount.get() : " (initial connection attempt)")); onWebSocketFailure(null, timeoutError, null); if (shouldReconnect.get()) { @@ -342,14 +314,11 @@ public void onClosed(WebSocket webSocket, int code, String reason) { * - 2+ = exponential backoff up to maxReconnectionDelayMs */ private long getNextDelay() { - // Single volatile read → a consistent (min, growFactor, max) snapshot even if - // applyOptionsOverride swaps the options concurrently. - ReconnectOptions opts = this.activeOptions; if (retryCount.get() == 1) { - return opts.minReconnectionDelayMs; + return minReconnectionDelayMs; } - long delay = (long) (opts.minReconnectionDelayMs * Math.pow(opts.reconnectionDelayGrowFactor, retryCount.get() - 1)); - return Math.min(delay, opts.maxReconnectionDelayMs); + long delay = (long) (minReconnectionDelayMs * Math.pow(reconnectionDelayGrowFactor, retryCount.get() - 1)); + return Math.min(delay, maxReconnectionDelayMs); } /** @@ -430,15 +399,12 @@ public static final class ReconnectOptions { public final int maxEnqueuedMessages; - public final long connectionTimeoutMs; - private ReconnectOptions(Builder builder) { this.minReconnectionDelayMs = builder.minReconnectionDelayMs; this.maxReconnectionDelayMs = builder.maxReconnectionDelayMs; this.reconnectionDelayGrowFactor = builder.reconnectionDelayGrowFactor; this.maxRetries = builder.maxRetries; this.maxEnqueuedMessages = builder.maxEnqueuedMessages; - this.connectionTimeoutMs = builder.connectionTimeoutMs; } public static Builder builder() { @@ -456,15 +422,12 @@ public static final class Builder { private int maxEnqueuedMessages; - private long connectionTimeoutMs; - public Builder() { this.minReconnectionDelayMs = 1000; this.maxReconnectionDelayMs = 10000; this.reconnectionDelayGrowFactor = 1.3; this.maxRetries = 2147483647; this.maxEnqueuedMessages = 1000; - this.connectionTimeoutMs = 4000; } public Builder minReconnectionDelayMs(long minReconnectionDelayMs) { @@ -492,16 +455,6 @@ public Builder maxEnqueuedMessages(int maxEnqueuedMessages) { return this; } - /** - * Sets the per-attempt connection timeout in milliseconds. Defaults to {@code 4000}. - * Each call to {@link ReconnectingWebSocketListener#connect()} will wait at most - * this long for the underlying WebSocket factory to produce a connected socket. - */ - public Builder connectionTimeoutMs(long connectionTimeoutMs) { - this.connectionTimeoutMs = connectionTimeoutMs; - return this; - } - /** * Builds the ReconnectOptions with validation. * @@ -510,7 +463,6 @@ public Builder connectionTimeoutMs(long connectionTimeoutMs) { * - minReconnectionDelayMs <= maxReconnectionDelayMs * - reconnectionDelayGrowFactor >= 1.0 * - maxRetries and maxEnqueuedMessages are non-negative - * - connectionTimeoutMs is positive * * @return The validated ReconnectOptions instance * @throws IllegalArgumentException if configuration is invalid @@ -535,9 +487,6 @@ public ReconnectOptions build() { if (maxEnqueuedMessages < 0) { throw new IllegalArgumentException("maxEnqueuedMessages must be non-negative"); } - if (connectionTimeoutMs <= 0) { - throw new IllegalArgumentException("connectionTimeoutMs must be positive"); - } return new ReconnectOptions(this); } } 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 41af522..71825ed 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 @@ -36,14 +36,6 @@ public boolean equals(Object other) { return other instanceof AgentV1AgentAudioDone; } - @java.lang.Override - public int hashCode() { - // Manual patch: Fern generates equals() (all instances of this fields-less message - // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a - // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. - return getClass().hashCode(); - } - @JsonAnyGetter public Map getAdditionalProperties() { return this.additionalProperties; 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 083578b..7842266 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 @@ -36,14 +36,6 @@ public boolean equals(Object other) { return other instanceof AgentV1KeepAlive; } - @java.lang.Override - public int hashCode() { - // Manual patch: Fern generates equals() (all instances of this fields-less message - // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a - // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. - return getClass().hashCode(); - } - @JsonAnyGetter public Map getAdditionalProperties() { return this.additionalProperties; diff --git a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1LatencyReport.java b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1LatencyReport.java index 39aecfb..f6efcc4 100644 --- a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1LatencyReport.java +++ b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1LatencyReport.java @@ -20,8 +20,6 @@ @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = AgentV1LatencyReport.Builder.class) public final class AgentV1LatencyReport { - private final Optional sttLatency; - private final Optional tttTokenLatency; private final Optional tttTextLatency; @@ -37,7 +35,6 @@ public final class AgentV1LatencyReport { private final Map additionalProperties; private AgentV1LatencyReport( - Optional sttLatency, Optional tttTokenLatency, Optional tttTextLatency, Optional tttToolLatency, @@ -45,7 +42,6 @@ private AgentV1LatencyReport( Optional ttsLatency, Optional totalLatency, Map additionalProperties) { - this.sttLatency = sttLatency; this.tttTokenLatency = tttTokenLatency; this.tttTextLatency = tttTextLatency; this.tttToolLatency = tttToolLatency; @@ -63,14 +59,6 @@ public String getType() { return "LatencyReport"; } - /** - * @return Speech-to-text: time from audio received to transcript produced, in seconds - */ - @JsonProperty("stt_latency") - public Optional getSttLatency() { - return sttLatency; - } - /** * @return Time to first token of any type (text, tool call, or thinking), in seconds */ @@ -131,8 +119,7 @@ public Map getAdditionalProperties() { } private boolean equalTo(AgentV1LatencyReport other) { - return sttLatency.equals(other.sttLatency) - && tttTokenLatency.equals(other.tttTokenLatency) + return tttTokenLatency.equals(other.tttTokenLatency) && tttTextLatency.equals(other.tttTextLatency) && tttToolLatency.equals(other.tttToolLatency) && tttThinkingLatency.equals(other.tttThinkingLatency) @@ -143,7 +130,6 @@ private boolean equalTo(AgentV1LatencyReport other) { @java.lang.Override public int hashCode() { return Objects.hash( - this.sttLatency, this.tttTokenLatency, this.tttTextLatency, this.tttToolLatency, @@ -163,8 +149,6 @@ public static Builder builder() { @JsonIgnoreProperties(ignoreUnknown = true) public static final class Builder { - private Optional sttLatency = Optional.empty(); - private Optional tttTokenLatency = Optional.empty(); private Optional tttTextLatency = Optional.empty(); @@ -183,7 +167,6 @@ public static final class Builder { private Builder() {} public Builder from(AgentV1LatencyReport other) { - sttLatency(other.getSttLatency()); tttTokenLatency(other.getTttTokenLatency()); tttTextLatency(other.getTttTextLatency()); tttToolLatency(other.getTttToolLatency()); @@ -193,20 +176,6 @@ public Builder from(AgentV1LatencyReport other) { return this; } - /** - *

Speech-to-text: time from audio received to transcript produced, in seconds

- */ - @JsonSetter(value = "stt_latency", nulls = Nulls.SKIP) - public Builder sttLatency(Optional sttLatency) { - this.sttLatency = sttLatency; - return this; - } - - public Builder sttLatency(Float sttLatency) { - this.sttLatency = Optional.ofNullable(sttLatency); - return this; - } - /** *

Time to first token of any type (text, tool call, or thinking), in seconds

*/ @@ -293,7 +262,6 @@ public Builder totalLatency(Float totalLatency) { public AgentV1LatencyReport build() { return new AgentV1LatencyReport( - sttLatency, tttTokenLatency, tttTextLatency, tttToolLatency, 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 6018473..65878c9 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 @@ -36,14 +36,6 @@ public boolean equals(Object other) { return other instanceof AgentV1ListenUpdated; } - @java.lang.Override - public int hashCode() { - // Manual patch: Fern generates equals() (all instances of this fields-less message - // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a - // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. - return getClass().hashCode(); - } - @JsonAnyGetter public Map getAdditionalProperties() { return this.additionalProperties; 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 6edec37..68d71cc 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 @@ -36,14 +36,6 @@ public boolean equals(Object other) { return other instanceof AgentV1PromptUpdated; } - @java.lang.Override - public int hashCode() { - // Manual patch: Fern generates equals() (all instances of this fields-less message - // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a - // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. - return getClass().hashCode(); - } - @JsonAnyGetter public Map getAdditionalProperties() { return this.additionalProperties; 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 fb23c60..0d60b72 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 @@ -36,14 +36,6 @@ public boolean equals(Object other) { return other instanceof AgentV1SettingsApplied; } - @java.lang.Override - public int hashCode() { - // Manual patch: Fern generates equals() (all instances of this fields-less message - // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a - // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. - return getClass().hashCode(); - } - @JsonAnyGetter public Map getAdditionalProperties() { return this.additionalProperties; 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 7619157..747aa9d 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 @@ -36,14 +36,6 @@ public boolean equals(Object other) { return other instanceof AgentV1SpeakUpdated; } - @java.lang.Override - public int hashCode() { - // Manual patch: Fern generates equals() (all instances of this fields-less message - // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a - // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. - return getClass().hashCode(); - } - @JsonAnyGetter public Map getAdditionalProperties() { return this.additionalProperties; 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 2f2a981..5668a71 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 @@ -36,14 +36,6 @@ public boolean equals(Object other) { return other instanceof AgentV1ThinkUpdated; } - @java.lang.Override - public int hashCode() { - // Manual patch: Fern generates equals() (all instances of this fields-less message - // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a - // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. - return getClass().hashCode(); - } - @JsonAnyGetter public Map getAdditionalProperties() { return this.additionalProperties; 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 7c3fc38..edb80f8 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 @@ -36,14 +36,6 @@ public boolean equals(Object other) { return other instanceof AgentV1UserStartedSpeaking; } - @java.lang.Override - public int hashCode() { - // Manual patch: Fern generates equals() (all instances of this fields-less message - // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a - // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. - return getClass().hashCode(); - } - @JsonAnyGetter public Map getAdditionalProperties() { return this.additionalProperties; 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 e508681..e6308e2 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 @@ -36,14 +36,6 @@ public boolean equals(Object other) { return other instanceof ListenV2CloseStream; } - @java.lang.Override - public int hashCode() { - // Manual patch: Fern generates equals() (all instances of this fields-less message - // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a - // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. - return getClass().hashCode(); - } - @JsonAnyGetter public Map getAdditionalProperties() { return this.additionalProperties; diff --git a/src/main/java/com/deepgram/resources/listen/v2/websocket/V2ConnectOptions.java b/src/main/java/com/deepgram/resources/listen/v2/websocket/V2ConnectOptions.java index 50cb3bf..d14542a 100644 --- a/src/main/java/com/deepgram/resources/listen/v2/websocket/V2ConnectOptions.java +++ b/src/main/java/com/deepgram/resources/listen/v2/websocket/V2ConnectOptions.java @@ -12,6 +12,7 @@ import com.deepgram.types.ListenV2LanguageHint; import com.deepgram.types.ListenV2MipOptOut; import com.deepgram.types.ListenV2Model; +import com.deepgram.types.ListenV2Numerals; import com.deepgram.types.ListenV2ProfanityFilter; import com.deepgram.types.ListenV2SampleRate; import com.deepgram.types.ListenV2Tag; @@ -50,6 +51,8 @@ public final class V2ConnectOptions { private final Optional profanityFilter; + private final Optional numerals; + private final Optional mipOptOut; private final Optional tag; @@ -66,6 +69,7 @@ private V2ConnectOptions( Optional keyterm, Optional languageHint, Optional profanityFilter, + Optional numerals, Optional mipOptOut, Optional tag, Map additionalProperties) { @@ -78,6 +82,7 @@ private V2ConnectOptions( this.keyterm = keyterm; this.languageHint = languageHint; this.profanityFilter = profanityFilter; + this.numerals = numerals; this.mipOptOut = mipOptOut; this.tag = tag; this.additionalProperties = additionalProperties; @@ -128,6 +133,11 @@ public Optional getProfanityFilter() { return profanityFilter; } + @JsonProperty("numerals") + public Optional getNumerals() { + return numerals; + } + @JsonProperty("mip_opt_out") public Optional getMipOptOut() { return mipOptOut; @@ -159,6 +169,7 @@ private boolean equalTo(V2ConnectOptions other) { && keyterm.equals(other.keyterm) && languageHint.equals(other.languageHint) && profanityFilter.equals(other.profanityFilter) + && numerals.equals(other.numerals) && mipOptOut.equals(other.mipOptOut) && tag.equals(other.tag); } @@ -175,6 +186,7 @@ public int hashCode() { this.keyterm, this.languageHint, this.profanityFilter, + this.numerals, this.mipOptOut, this.tag); } @@ -233,6 +245,10 @@ public interface _FinalStage { _FinalStage profanityFilter(ListenV2ProfanityFilter profanityFilter); + _FinalStage numerals(Optional numerals); + + _FinalStage numerals(ListenV2Numerals numerals); + _FinalStage mipOptOut(Optional mipOptOut); _FinalStage mipOptOut(ListenV2MipOptOut mipOptOut); @@ -250,6 +266,8 @@ public static final class Builder implements ModelStage, _FinalStage { private Optional mipOptOut = Optional.empty(); + private Optional numerals = Optional.empty(); + private Optional profanityFilter = Optional.empty(); private Optional languageHint = Optional.empty(); @@ -282,6 +300,7 @@ public Builder from(V2ConnectOptions other) { keyterm(other.getKeyterm()); languageHint(other.getLanguageHint()); profanityFilter(other.getProfanityFilter()); + numerals(other.getNumerals()); mipOptOut(other.getMipOptOut()); tag(other.getTag()); return this; @@ -320,6 +339,19 @@ public _FinalStage mipOptOut(Optional mipOptOut) { return this; } + @java.lang.Override + public _FinalStage numerals(ListenV2Numerals numerals) { + this.numerals = Optional.ofNullable(numerals); + return this; + } + + @java.lang.Override + @JsonSetter(value = "numerals", nulls = Nulls.SKIP) + public _FinalStage numerals(Optional numerals) { + this.numerals = numerals; + return this; + } + @java.lang.Override public _FinalStage profanityFilter(ListenV2ProfanityFilter profanityFilter) { this.profanityFilter = Optional.ofNullable(profanityFilter); @@ -436,6 +468,7 @@ public V2ConnectOptions build() { keyterm, languageHint, profanityFilter, + numerals, mipOptOut, tag, additionalProperties); 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 1325569..d62cebd 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 @@ -137,6 +137,10 @@ public CompletableFuture connect(V2ConnectOptions options) { "profanity_filter", String.valueOf(options.getProfanityFilter().get())); } + if (options.getNumerals() != null && options.getNumerals().isPresent()) { + urlBuilder.addQueryParameter( + "numerals", String.valueOf(options.getNumerals().get())); + } if (options.getMipOptOut() != null && options.getMipOptOut().isPresent()) { urlBuilder.addQueryParameter( "mip_opt_out", String.valueOf(options.getMipOptOut().get())); @@ -469,11 +473,11 @@ private void handleIncomingMessage(String json) { return; } } - // Unrecognized message type: forward-compatible no-op. The raw frame was - // already delivered to onMessage(String) above, so a newer server adding a - // benign control frame (e.g. a GA addition to this endpoint) must not surface - // as a fatal error to deployed clients. Routing it to onError would make a - // harmless frame look fatal; mirrors the speak v2 client and the JS/Python SDKs. + if (onErrorHandler != null) { + onErrorHandler.accept(new RuntimeException( + "Unrecognized WebSocket message: " + json.substring(0, Math.min(200, json.length())) + + "... Update your SDK version to support new message types.")); + } } catch (Exception e) { if (onErrorHandler != null) { onErrorHandler.accept(e); diff --git a/src/main/java/com/deepgram/resources/speak/v1/audio/types/AudioGenerateRequestModel.java b/src/main/java/com/deepgram/resources/speak/v1/audio/types/AudioGenerateRequestModel.java index 368444d..ae6b9e4 100644 --- a/src/main/java/com/deepgram/resources/speak/v1/audio/types/AudioGenerateRequestModel.java +++ b/src/main/java/com/deepgram/resources/speak/v1/audio/types/AudioGenerateRequestModel.java @@ -13,8 +13,8 @@ public final class AudioGenerateRequestModel { public static final AudioGenerateRequestModel AURA2HERA_EN = new AudioGenerateRequestModel(Value.AURA2HERA_EN, "aura-2-hera-en"); - public static final AudioGenerateRequestModel AURA2ASTERIA_EN = - new AudioGenerateRequestModel(Value.AURA2ASTERIA_EN, "aura-2-asteria-en"); + public static final AudioGenerateRequestModel AURA2KARA_DE = + new AudioGenerateRequestModel(Value.AURA2KARA_DE, "aura-2-kara-de"); public static final AudioGenerateRequestModel AURA2HARMONIA_EN = new AudioGenerateRequestModel(Value.AURA2HARMONIA_EN, "aura-2-harmonia-en"); @@ -28,15 +28,18 @@ public final class AudioGenerateRequestModel { public static final AudioGenerateRequestModel AURA2HERMES_EN = new AudioGenerateRequestModel(Value.AURA2HERMES_EN, "aura-2-hermes-en"); - public static final AudioGenerateRequestModel AURA2SELENA_ES = - new AudioGenerateRequestModel(Value.AURA2SELENA_ES, "aura-2-selena-es"); - public static final AudioGenerateRequestModel AURA2NEPTUNE_EN = new AudioGenerateRequestModel(Value.AURA2NEPTUNE_EN, "aura-2-neptune-en"); public static final AudioGenerateRequestModel AURA2CALLISTA_EN = new AudioGenerateRequestModel(Value.AURA2CALLISTA_EN, "aura-2-callista-en"); + public static final AudioGenerateRequestModel AURA2CORNELIA_NL = + new AudioGenerateRequestModel(Value.AURA2CORNELIA_NL, "aura-2-cornelia-nl"); + + public static final AudioGenerateRequestModel AURA2RHEA_NL = + new AudioGenerateRequestModel(Value.AURA2RHEA_NL, "aura-2-rhea-nl"); + public static final AudioGenerateRequestModel AURA2AURORA_EN = new AudioGenerateRequestModel(Value.AURA2AURORA_EN, "aura-2-aurora-en"); @@ -46,26 +49,23 @@ public final class AudioGenerateRequestModel { public static final AudioGenerateRequestModel AURA2APOLLO_EN = new AudioGenerateRequestModel(Value.AURA2APOLLO_EN, "aura-2-apollo-en"); - public static final AudioGenerateRequestModel AURA_LUNA_EN = - new AudioGenerateRequestModel(Value.AURA_LUNA_EN, "aura-luna-en"); - - public static final AudioGenerateRequestModel AURA_ORPHEUS_EN = - new AudioGenerateRequestModel(Value.AURA_ORPHEUS_EN, "aura-orpheus-en"); - public static final AudioGenerateRequestModel AURA2DELIA_EN = new AudioGenerateRequestModel(Value.AURA2DELIA_EN, "aura-2-delia-en"); public static final AudioGenerateRequestModel AURA2MARS_EN = new AudioGenerateRequestModel(Value.AURA2MARS_EN, "aura-2-mars-en"); - public static final AudioGenerateRequestModel AURA2AMALTHEA_EN = - new AudioGenerateRequestModel(Value.AURA2AMALTHEA_EN, "aura-2-amalthea-en"); + public static final AudioGenerateRequestModel AURA2AURELIA_DE = + new AudioGenerateRequestModel(Value.AURA2AURELIA_DE, "aura-2-aurelia-de"); + + public static final AudioGenerateRequestModel AURA2AGATHE_FR = + new AudioGenerateRequestModel(Value.AURA2AGATHE_FR, "aura-2-agathe-fr"); public static final AudioGenerateRequestModel AURA_HERA_EN = new AudioGenerateRequestModel(Value.AURA_HERA_EN, "aura-hera-en"); - public static final AudioGenerateRequestModel AURA2SELENE_EN = - new AudioGenerateRequestModel(Value.AURA2SELENE_EN, "aura-2-selene-en"); + public static final AudioGenerateRequestModel AURA2CINZIA_IT = + new AudioGenerateRequestModel(Value.AURA2CINZIA_IT, "aura-2-cinzia-it"); public static final AudioGenerateRequestModel AURA2ARIES_EN = new AudioGenerateRequestModel(Value.AURA2ARIES_EN, "aura-2-aries-en"); @@ -73,29 +73,173 @@ public final class AudioGenerateRequestModel { public static final AudioGenerateRequestModel AURA2JUNO_EN = new AudioGenerateRequestModel(Value.AURA2JUNO_EN, "aura-2-juno-en"); - public static final AudioGenerateRequestModel AURA2LUNA_EN = - new AudioGenerateRequestModel(Value.AURA2LUNA_EN, "aura-2-luna-en"); + public static final AudioGenerateRequestModel AURA2MAIA_IT = + new AudioGenerateRequestModel(Value.AURA2MAIA_IT, "aura-2-maia-it"); public static final AudioGenerateRequestModel AURA2JAVIER_ES = new AudioGenerateRequestModel(Value.AURA2JAVIER_ES, "aura-2-javier-es"); + public static final AudioGenerateRequestModel AURA2ANDROMEDA_EN = + new AudioGenerateRequestModel(Value.AURA2ANDROMEDA_EN, "aura-2-andromeda-en"); + + public static final AudioGenerateRequestModel AURA2SATURN_EN = + new AudioGenerateRequestModel(Value.AURA2SATURN_EN, "aura-2-saturn-en"); + + public static final AudioGenerateRequestModel AURA2IRIS_EN = + new AudioGenerateRequestModel(Value.AURA2IRIS_EN, "aura-2-iris-en"); + + public static final AudioGenerateRequestModel AURA2DIONISIO_IT = + new AudioGenerateRequestModel(Value.AURA2DIONISIO_IT, "aura-2-dionisio-it"); + + public static final AudioGenerateRequestModel AURA_ANGUS_EN = + new AudioGenerateRequestModel(Value.AURA_ANGUS_EN, "aura-angus-en"); + + public static final AudioGenerateRequestModel AURA2HESTIA_NL = + new AudioGenerateRequestModel(Value.AURA2HESTIA_NL, "aura-2-hestia-nl"); + + public static final AudioGenerateRequestModel AURA2HECTOR_FR = + new AudioGenerateRequestModel(Value.AURA2HECTOR_FR, "aura-2-hector-fr"); + + public static final AudioGenerateRequestModel AURA2PERSEO_IT = + new AudioGenerateRequestModel(Value.AURA2PERSEO_IT, "aura-2-perseo-it"); + + public static final AudioGenerateRequestModel AURA2ELARA_DE = + new AudioGenerateRequestModel(Value.AURA2ELARA_DE, "aura-2-elara-de"); + + public static final AudioGenerateRequestModel AURA2DAPHNE_NL = + new AudioGenerateRequestModel(Value.AURA2DAPHNE_NL, "aura-2-daphne-nl"); + + public static final AudioGenerateRequestModel AURA2LARA_DE = + new AudioGenerateRequestModel(Value.AURA2LARA_DE, "aura-2-lara-de"); + + public static final AudioGenerateRequestModel AURA2HELENA_EN = + new AudioGenerateRequestModel(Value.AURA2HELENA_EN, "aura-2-helena-en"); + + public static final AudioGenerateRequestModel AURA2JULIUS_DE = + new AudioGenerateRequestModel(Value.AURA2JULIUS_DE, "aura-2-julius-de"); + + public static final AudioGenerateRequestModel AURA_STELLA_EN = + new AudioGenerateRequestModel(Value.AURA_STELLA_EN, "aura-stella-en"); + + public static final AudioGenerateRequestModel AURA2ANTONIA_ES = + new AudioGenerateRequestModel(Value.AURA2ANTONIA_ES, "aura-2-antonia-es"); + + public static final AudioGenerateRequestModel AURA2DRACO_EN = + new AudioGenerateRequestModel(Value.AURA2DRACO_EN, "aura-2-draco-en"); + + public static final AudioGenerateRequestModel AURA_HELIOS_EN = + new AudioGenerateRequestModel(Value.AURA_HELIOS_EN, "aura-helios-en"); + + public static final AudioGenerateRequestModel AURA2FABIAN_DE = + new AudioGenerateRequestModel(Value.AURA2FABIAN_DE, "aura-2-fabian-de"); + + public static final AudioGenerateRequestModel AURA2JANUS_EN = + new AudioGenerateRequestModel(Value.AURA2JANUS_EN, "aura-2-janus-en"); + + public static final AudioGenerateRequestModel AURA2NESTOR_ES = + new AudioGenerateRequestModel(Value.AURA2NESTOR_ES, "aura-2-nestor-es"); + + public static final AudioGenerateRequestModel AURA2VALERIO_ES = + new AudioGenerateRequestModel(Value.AURA2VALERIO_ES, "aura-2-valerio-es"); + + public static final AudioGenerateRequestModel AURA2ORION_EN = + new AudioGenerateRequestModel(Value.AURA2ORION_EN, "aura-2-orion-en"); + + public static final AudioGenerateRequestModel AURA2SILVIA_ES = + new AudioGenerateRequestModel(Value.AURA2SILVIA_ES, "aura-2-silvia-es"); + + public static final AudioGenerateRequestModel AURA2MINERVA_EN = + new AudioGenerateRequestModel(Value.AURA2MINERVA_EN, "aura-2-minerva-en"); + + public static final AudioGenerateRequestModel AURA2ALVARO_ES = + new AudioGenerateRequestModel(Value.AURA2ALVARO_ES, "aura-2-alvaro-es"); + + public static final AudioGenerateRequestModel AURA_PERSEUS_EN = + new AudioGenerateRequestModel(Value.AURA_PERSEUS_EN, "aura-perseus-en"); + + public static final AudioGenerateRequestModel AURA2VESTA_EN = + new AudioGenerateRequestModel(Value.AURA2VESTA_EN, "aura-2-vesta-en"); + + public static final AudioGenerateRequestModel AURA2ZEUS_EN = + new AudioGenerateRequestModel(Value.AURA2ZEUS_EN, "aura-2-zeus-en"); + + public static final AudioGenerateRequestModel AURA2ORPHEUS_EN = + new AudioGenerateRequestModel(Value.AURA2ORPHEUS_EN, "aura-2-orpheus-en"); + + public static final AudioGenerateRequestModel AURA2THALIA_EN = + new AudioGenerateRequestModel(Value.AURA2THALIA_EN, "aura-2-thalia-en"); + + public static final AudioGenerateRequestModel AURA2IZANAMI_JA = + new AudioGenerateRequestModel(Value.AURA2IZANAMI_JA, "aura-2-izanami-ja"); + + public static final AudioGenerateRequestModel AURA2ASTERIA_EN = + new AudioGenerateRequestModel(Value.AURA2ASTERIA_EN, "aura-2-asteria-en"); + + public static final AudioGenerateRequestModel AURA2LUCIANO_ES = + new AudioGenerateRequestModel(Value.AURA2LUCIANO_ES, "aura-2-luciano-es"); + + public static final AudioGenerateRequestModel AURA2UZUME_JA = + new AudioGenerateRequestModel(Value.AURA2UZUME_JA, "aura-2-uzume-ja"); + + public static final AudioGenerateRequestModel AURA2SELENA_ES = + new AudioGenerateRequestModel(Value.AURA2SELENA_ES, "aura-2-selena-es"); + + public static final AudioGenerateRequestModel AURA2GLORIA_ES = + new AudioGenerateRequestModel(Value.AURA2GLORIA_ES, "aura-2-gloria-es"); + + public static final AudioGenerateRequestModel AURA2ELIO_IT = + new AudioGenerateRequestModel(Value.AURA2ELIO_IT, "aura-2-elio-it"); + + public static final AudioGenerateRequestModel AURA2AMA_JA = + new AudioGenerateRequestModel(Value.AURA2AMA_JA, "aura-2-ama-ja"); + + public static final AudioGenerateRequestModel AURA_LUNA_EN = + new AudioGenerateRequestModel(Value.AURA_LUNA_EN, "aura-luna-en"); + + public static final AudioGenerateRequestModel AURA_ORPHEUS_EN = + new AudioGenerateRequestModel(Value.AURA_ORPHEUS_EN, "aura-orpheus-en"); + + public static final AudioGenerateRequestModel AURA2AMALTHEA_EN = + new AudioGenerateRequestModel(Value.AURA2AMALTHEA_EN, "aura-2-amalthea-en"); + + public static final AudioGenerateRequestModel AURA2OLIVIA_ES = + new AudioGenerateRequestModel(Value.AURA2OLIVIA_ES, "aura-2-olivia-es"); + + public static final AudioGenerateRequestModel AURA2DEMETRA_IT = + new AudioGenerateRequestModel(Value.AURA2DEMETRA_IT, "aura-2-demetra-it"); + + public static final AudioGenerateRequestModel AURA2BEATRIX_NL = + new AudioGenerateRequestModel(Value.AURA2BEATRIX_NL, "aura-2-beatrix-nl"); + + public static final AudioGenerateRequestModel AURA2SELENE_EN = + new AudioGenerateRequestModel(Value.AURA2SELENE_EN, "aura-2-selene-en"); + + public static final AudioGenerateRequestModel AURA2EBISU_JA = + new AudioGenerateRequestModel(Value.AURA2EBISU_JA, "aura-2-ebisu-ja"); + + public static final AudioGenerateRequestModel AURA2LUNA_EN = + new AudioGenerateRequestModel(Value.AURA2LUNA_EN, "aura-2-luna-en"); + public static final AudioGenerateRequestModel AURA2PHOEBE_EN = new AudioGenerateRequestModel(Value.AURA2PHOEBE_EN, "aura-2-phoebe-en"); + public static final AudioGenerateRequestModel AURA2FLAVIO_IT = + new AudioGenerateRequestModel(Value.AURA2FLAVIO_IT, "aura-2-flavio-it"); + public static final AudioGenerateRequestModel AURA2DIANA_ES = new AudioGenerateRequestModel(Value.AURA2DIANA_ES, "aura-2-diana-es"); public static final AudioGenerateRequestModel AURA_ORION_EN = new AudioGenerateRequestModel(Value.AURA_ORION_EN, "aura-orion-en"); - public static final AudioGenerateRequestModel AURA2ANDROMEDA_EN = - new AudioGenerateRequestModel(Value.AURA2ANDROMEDA_EN, "aura-2-andromeda-en"); - public static final AudioGenerateRequestModel AURA2ATHENA_EN = new AudioGenerateRequestModel(Value.AURA2ATHENA_EN, "aura-2-athena-en"); - public static final AudioGenerateRequestModel AURA2SATURN_EN = - new AudioGenerateRequestModel(Value.AURA2SATURN_EN, "aura-2-saturn-en"); + public static final AudioGenerateRequestModel AURA2LARS_NL = + new AudioGenerateRequestModel(Value.AURA2LARS_NL, "aura-2-lars-nl"); + + public static final AudioGenerateRequestModel AURA2FUJIN_JA = + new AudioGenerateRequestModel(Value.AURA2FUJIN_JA, "aura-2-fujin-ja"); public static final AudioGenerateRequestModel AURA_ARCAS_EN = new AudioGenerateRequestModel(Value.AURA_ARCAS_EN, "aura-arcas-en"); @@ -103,35 +247,38 @@ public final class AudioGenerateRequestModel { public static final AudioGenerateRequestModel AURA2THEIA_EN = new AudioGenerateRequestModel(Value.AURA2THEIA_EN, "aura-2-theia-en"); - public static final AudioGenerateRequestModel AURA2IRIS_EN = - new AudioGenerateRequestModel(Value.AURA2IRIS_EN, "aura-2-iris-en"); + public static final AudioGenerateRequestModel AURA2LIVIA_IT = + new AudioGenerateRequestModel(Value.AURA2LIVIA_IT, "aura-2-livia-it"); - public static final AudioGenerateRequestModel AURA_ANGUS_EN = - new AudioGenerateRequestModel(Value.AURA_ANGUS_EN, "aura-angus-en"); + public static final AudioGenerateRequestModel AURA2LEDA_NL = + new AudioGenerateRequestModel(Value.AURA2LEDA_NL, "aura-2-leda-nl"); public static final AudioGenerateRequestModel AURA2JUPITER_EN = new AudioGenerateRequestModel(Value.AURA2JUPITER_EN, "aura-2-jupiter-en"); + public static final AudioGenerateRequestModel AURA2MELIA_IT = + new AudioGenerateRequestModel(Value.AURA2MELIA_IT, "aura-2-melia-it"); + public static final AudioGenerateRequestModel AURA2AQUILA_ES = new AudioGenerateRequestModel(Value.AURA2AQUILA_ES, "aura-2-aquila-es"); public static final AudioGenerateRequestModel AURA2CORA_EN = new AudioGenerateRequestModel(Value.AURA2CORA_EN, "aura-2-cora-en"); + public static final AudioGenerateRequestModel AURA2AGUSTINA_ES = + new AudioGenerateRequestModel(Value.AURA2AGUSTINA_ES, "aura-2-agustina-es"); + + public static final AudioGenerateRequestModel AURA2ROMAN_NL = + new AudioGenerateRequestModel(Value.AURA2ROMAN_NL, "aura-2-roman-nl"); + public static final AudioGenerateRequestModel AURA2CORDELIA_EN = new AudioGenerateRequestModel(Value.AURA2CORDELIA_EN, "aura-2-cordelia-en"); public static final AudioGenerateRequestModel AURA2ATLAS_EN = new AudioGenerateRequestModel(Value.AURA2ATLAS_EN, "aura-2-atlas-en"); - public static final AudioGenerateRequestModel AURA2HELENA_EN = - new AudioGenerateRequestModel(Value.AURA2HELENA_EN, "aura-2-helena-en"); - - public static final AudioGenerateRequestModel AURA_STELLA_EN = - new AudioGenerateRequestModel(Value.AURA_STELLA_EN, "aura-stella-en"); - - public static final AudioGenerateRequestModel AURA2DRACO_EN = - new AudioGenerateRequestModel(Value.AURA2DRACO_EN, "aura-2-draco-en"); + public static final AudioGenerateRequestModel AURA2VIKTORIA_DE = + new AudioGenerateRequestModel(Value.AURA2VIKTORIA_DE, "aura-2-viktoria-de"); public static final AudioGenerateRequestModel AURA2HYPERION_EN = new AudioGenerateRequestModel(Value.AURA2HYPERION_EN, "aura-2-hyperion-en"); @@ -139,23 +286,17 @@ public final class AudioGenerateRequestModel { public static final AudioGenerateRequestModel AURA2CELESTE_ES = new AudioGenerateRequestModel(Value.AURA2CELESTE_ES, "aura-2-celeste-es"); - public static final AudioGenerateRequestModel AURA_HELIOS_EN = - new AudioGenerateRequestModel(Value.AURA_HELIOS_EN, "aura-helios-en"); - public static final AudioGenerateRequestModel AURA2PLUTO_EN = new AudioGenerateRequestModel(Value.AURA2PLUTO_EN, "aura-2-pluto-en"); - public static final AudioGenerateRequestModel AURA2JANUS_EN = - new AudioGenerateRequestModel(Value.AURA2JANUS_EN, "aura-2-janus-en"); - - public static final AudioGenerateRequestModel AURA2NESTOR_ES = - new AudioGenerateRequestModel(Value.AURA2NESTOR_ES, "aura-2-nestor-es"); + public static final AudioGenerateRequestModel AURA2SANDER_NL = + new AudioGenerateRequestModel(Value.AURA2SANDER_NL, "aura-2-sander-nl"); public static final AudioGenerateRequestModel AURA2ARCAS_EN = new AudioGenerateRequestModel(Value.AURA2ARCAS_EN, "aura-2-arcas-en"); - public static final AudioGenerateRequestModel AURA2ORION_EN = - new AudioGenerateRequestModel(Value.AURA2ORION_EN, "aura-2-orion-en"); + public static final AudioGenerateRequestModel AURA2CESARE_IT = + new AudioGenerateRequestModel(Value.AURA2CESARE_IT, "aura-2-cesare-it"); public static final AudioGenerateRequestModel AURA_ATHENA_EN = new AudioGenerateRequestModel(Value.AURA_ATHENA_EN, "aura-athena-en"); @@ -166,36 +307,15 @@ public final class AudioGenerateRequestModel { public static final AudioGenerateRequestModel AURA2PANDORA_EN = new AudioGenerateRequestModel(Value.AURA2PANDORA_EN, "aura-2-pandora-en"); - public static final AudioGenerateRequestModel AURA2MINERVA_EN = - new AudioGenerateRequestModel(Value.AURA2MINERVA_EN, "aura-2-minerva-en"); - - public static final AudioGenerateRequestModel AURA2ALVARO_ES = - new AudioGenerateRequestModel(Value.AURA2ALVARO_ES, "aura-2-alvaro-es"); - - public static final AudioGenerateRequestModel AURA_PERSEUS_EN = - new AudioGenerateRequestModel(Value.AURA_PERSEUS_EN, "aura-perseus-en"); - - public static final AudioGenerateRequestModel AURA2VESTA_EN = - new AudioGenerateRequestModel(Value.AURA2VESTA_EN, "aura-2-vesta-en"); - public static final AudioGenerateRequestModel AURA_ASTERIA_EN = new AudioGenerateRequestModel(Value.AURA_ASTERIA_EN, "aura-asteria-en"); - public static final AudioGenerateRequestModel AURA2ZEUS_EN = - new AudioGenerateRequestModel(Value.AURA2ZEUS_EN, "aura-2-zeus-en"); - public static final AudioGenerateRequestModel AURA2ELECTRA_EN = new AudioGenerateRequestModel(Value.AURA2ELECTRA_EN, "aura-2-electra-en"); - public static final AudioGenerateRequestModel AURA2ORPHEUS_EN = - new AudioGenerateRequestModel(Value.AURA2ORPHEUS_EN, "aura-2-orpheus-en"); - public static final AudioGenerateRequestModel AURA2ESTRELLA_ES = new AudioGenerateRequestModel(Value.AURA2ESTRELLA_ES, "aura-2-estrella-es"); - public static final AudioGenerateRequestModel AURA2THALIA_EN = - new AudioGenerateRequestModel(Value.AURA2THALIA_EN, "aura-2-thalia-en"); - private final Value value; private final String string; @@ -233,8 +353,8 @@ public T visit(Visitor visitor) { return visitor.visitAura2SirioEs(); case AURA2HERA_EN: return visitor.visitAura2HeraEn(); - case AURA2ASTERIA_EN: - return visitor.visitAura2AsteriaEn(); + case AURA2KARA_DE: + return visitor.visitAura2KaraDe(); case AURA2HARMONIA_EN: return visitor.visitAura2HarmoniaEn(); case AURA2CARINA_ES: @@ -243,118 +363,198 @@ public T visit(Visitor visitor) { return visitor.visitAuraZeusEn(); case AURA2HERMES_EN: return visitor.visitAura2HermesEn(); - case AURA2SELENA_ES: - return visitor.visitAura2SelenaEs(); case AURA2NEPTUNE_EN: return visitor.visitAura2NeptuneEn(); case AURA2CALLISTA_EN: return visitor.visitAura2CallistaEn(); + case AURA2CORNELIA_NL: + return visitor.visitAura2CorneliaNl(); + case AURA2RHEA_NL: + return visitor.visitAura2RheaNl(); case AURA2AURORA_EN: return visitor.visitAura2AuroraEn(); case AURA2OPHELIA_EN: return visitor.visitAura2OpheliaEn(); case AURA2APOLLO_EN: return visitor.visitAura2ApolloEn(); - case AURA_LUNA_EN: - return visitor.visitAuraLunaEn(); - case AURA_ORPHEUS_EN: - return visitor.visitAuraOrpheusEn(); case AURA2DELIA_EN: return visitor.visitAura2DeliaEn(); case AURA2MARS_EN: return visitor.visitAura2MarsEn(); - case AURA2AMALTHEA_EN: - return visitor.visitAura2AmaltheaEn(); + case AURA2AURELIA_DE: + return visitor.visitAura2AureliaDe(); + case AURA2AGATHE_FR: + return visitor.visitAura2AgatheFr(); case AURA_HERA_EN: return visitor.visitAuraHeraEn(); - case AURA2SELENE_EN: - return visitor.visitAura2SeleneEn(); + case AURA2CINZIA_IT: + return visitor.visitAura2CinziaIt(); case AURA2ARIES_EN: return visitor.visitAura2AriesEn(); case AURA2JUNO_EN: return visitor.visitAura2JunoEn(); - case AURA2LUNA_EN: - return visitor.visitAura2LunaEn(); + case AURA2MAIA_IT: + return visitor.visitAura2MaiaIt(); case AURA2JAVIER_ES: return visitor.visitAura2JavierEs(); + case AURA2ANDROMEDA_EN: + return visitor.visitAura2AndromedaEn(); + case AURA2SATURN_EN: + return visitor.visitAura2SaturnEn(); + case AURA2IRIS_EN: + return visitor.visitAura2IrisEn(); + case AURA2DIONISIO_IT: + return visitor.visitAura2DionisioIt(); + case AURA_ANGUS_EN: + return visitor.visitAuraAngusEn(); + case AURA2HESTIA_NL: + return visitor.visitAura2HestiaNl(); + case AURA2HECTOR_FR: + return visitor.visitAura2HectorFr(); + case AURA2PERSEO_IT: + return visitor.visitAura2PerseoIt(); + case AURA2ELARA_DE: + return visitor.visitAura2ElaraDe(); + case AURA2DAPHNE_NL: + return visitor.visitAura2DaphneNl(); + case AURA2LARA_DE: + return visitor.visitAura2LaraDe(); + case AURA2HELENA_EN: + return visitor.visitAura2HelenaEn(); + case AURA2JULIUS_DE: + return visitor.visitAura2JuliusDe(); + case AURA_STELLA_EN: + return visitor.visitAuraStellaEn(); + case AURA2ANTONIA_ES: + return visitor.visitAura2AntoniaEs(); + case AURA2DRACO_EN: + return visitor.visitAura2DracoEn(); + case AURA_HELIOS_EN: + return visitor.visitAuraHeliosEn(); + case AURA2FABIAN_DE: + return visitor.visitAura2FabianDe(); + case AURA2JANUS_EN: + return visitor.visitAura2JanusEn(); + case AURA2NESTOR_ES: + return visitor.visitAura2NestorEs(); + case AURA2VALERIO_ES: + return visitor.visitAura2ValerioEs(); + case AURA2ORION_EN: + return visitor.visitAura2OrionEn(); + case AURA2SILVIA_ES: + return visitor.visitAura2SilviaEs(); + case AURA2MINERVA_EN: + return visitor.visitAura2MinervaEn(); + case AURA2ALVARO_ES: + return visitor.visitAura2AlvaroEs(); + case AURA_PERSEUS_EN: + return visitor.visitAuraPerseusEn(); + case AURA2VESTA_EN: + return visitor.visitAura2VestaEn(); + case AURA2ZEUS_EN: + return visitor.visitAura2ZeusEn(); + case AURA2ORPHEUS_EN: + return visitor.visitAura2OrpheusEn(); + case AURA2THALIA_EN: + return visitor.visitAura2ThaliaEn(); + case AURA2IZANAMI_JA: + return visitor.visitAura2IzanamiJa(); + case AURA2ASTERIA_EN: + return visitor.visitAura2AsteriaEn(); + case AURA2LUCIANO_ES: + return visitor.visitAura2LucianoEs(); + case AURA2UZUME_JA: + return visitor.visitAura2UzumeJa(); + case AURA2SELENA_ES: + return visitor.visitAura2SelenaEs(); + case AURA2GLORIA_ES: + return visitor.visitAura2GloriaEs(); + case AURA2ELIO_IT: + return visitor.visitAura2ElioIt(); + case AURA2AMA_JA: + return visitor.visitAura2AmaJa(); + case AURA_LUNA_EN: + return visitor.visitAuraLunaEn(); + case AURA_ORPHEUS_EN: + return visitor.visitAuraOrpheusEn(); + case AURA2AMALTHEA_EN: + return visitor.visitAura2AmaltheaEn(); + case AURA2OLIVIA_ES: + return visitor.visitAura2OliviaEs(); + case AURA2DEMETRA_IT: + return visitor.visitAura2DemetraIt(); + case AURA2BEATRIX_NL: + return visitor.visitAura2BeatrixNl(); + case AURA2SELENE_EN: + return visitor.visitAura2SeleneEn(); + case AURA2EBISU_JA: + return visitor.visitAura2EbisuJa(); + case AURA2LUNA_EN: + return visitor.visitAura2LunaEn(); case AURA2PHOEBE_EN: return visitor.visitAura2PhoebeEn(); + case AURA2FLAVIO_IT: + return visitor.visitAura2FlavioIt(); case AURA2DIANA_ES: return visitor.visitAura2DianaEs(); case AURA_ORION_EN: return visitor.visitAuraOrionEn(); - case AURA2ANDROMEDA_EN: - return visitor.visitAura2AndromedaEn(); case AURA2ATHENA_EN: return visitor.visitAura2AthenaEn(); - case AURA2SATURN_EN: - return visitor.visitAura2SaturnEn(); + case AURA2LARS_NL: + return visitor.visitAura2LarsNl(); + case AURA2FUJIN_JA: + return visitor.visitAura2FujinJa(); case AURA_ARCAS_EN: return visitor.visitAuraArcasEn(); case AURA2THEIA_EN: return visitor.visitAura2TheiaEn(); - case AURA2IRIS_EN: - return visitor.visitAura2IrisEn(); - case AURA_ANGUS_EN: - return visitor.visitAuraAngusEn(); + case AURA2LIVIA_IT: + return visitor.visitAura2LiviaIt(); + case AURA2LEDA_NL: + return visitor.visitAura2LedaNl(); case AURA2JUPITER_EN: return visitor.visitAura2JupiterEn(); + case AURA2MELIA_IT: + return visitor.visitAura2MeliaIt(); case AURA2AQUILA_ES: return visitor.visitAura2AquilaEs(); case AURA2CORA_EN: return visitor.visitAura2CoraEn(); + case AURA2AGUSTINA_ES: + return visitor.visitAura2AgustinaEs(); + case AURA2ROMAN_NL: + return visitor.visitAura2RomanNl(); case AURA2CORDELIA_EN: return visitor.visitAura2CordeliaEn(); case AURA2ATLAS_EN: return visitor.visitAura2AtlasEn(); - case AURA2HELENA_EN: - return visitor.visitAura2HelenaEn(); - case AURA_STELLA_EN: - return visitor.visitAuraStellaEn(); - case AURA2DRACO_EN: - return visitor.visitAura2DracoEn(); + case AURA2VIKTORIA_DE: + return visitor.visitAura2ViktoriaDe(); case AURA2HYPERION_EN: return visitor.visitAura2HyperionEn(); case AURA2CELESTE_ES: return visitor.visitAura2CelesteEs(); - case AURA_HELIOS_EN: - return visitor.visitAuraHeliosEn(); case AURA2PLUTO_EN: return visitor.visitAura2PlutoEn(); - case AURA2JANUS_EN: - return visitor.visitAura2JanusEn(); - case AURA2NESTOR_ES: - return visitor.visitAura2NestorEs(); + case AURA2SANDER_NL: + return visitor.visitAura2SanderNl(); case AURA2ARCAS_EN: return visitor.visitAura2ArcasEn(); - case AURA2ORION_EN: - return visitor.visitAura2OrionEn(); + case AURA2CESARE_IT: + return visitor.visitAura2CesareIt(); case AURA_ATHENA_EN: return visitor.visitAuraAthenaEn(); case AURA2ODYSSEUS_EN: return visitor.visitAura2OdysseusEn(); case AURA2PANDORA_EN: return visitor.visitAura2PandoraEn(); - case AURA2MINERVA_EN: - return visitor.visitAura2MinervaEn(); - case AURA2ALVARO_ES: - return visitor.visitAura2AlvaroEs(); - case AURA_PERSEUS_EN: - return visitor.visitAuraPerseusEn(); - case AURA2VESTA_EN: - return visitor.visitAura2VestaEn(); case AURA_ASTERIA_EN: return visitor.visitAuraAsteriaEn(); - case AURA2ZEUS_EN: - return visitor.visitAura2ZeusEn(); case AURA2ELECTRA_EN: return visitor.visitAura2ElectraEn(); - case AURA2ORPHEUS_EN: - return visitor.visitAura2OrpheusEn(); case AURA2ESTRELLA_ES: return visitor.visitAura2EstrellaEs(); - case AURA2THALIA_EN: - return visitor.visitAura2ThaliaEn(); case UNKNOWN: default: return visitor.visitUnknown(string); @@ -368,8 +568,8 @@ public static AudioGenerateRequestModel valueOf(String value) { return AURA2SIRIO_ES; case "aura-2-hera-en": return AURA2HERA_EN; - case "aura-2-asteria-en": - return AURA2ASTERIA_EN; + case "aura-2-kara-de": + return AURA2KARA_DE; case "aura-2-harmonia-en": return AURA2HARMONIA_EN; case "aura-2-carina-es": @@ -378,145 +578,225 @@ public static AudioGenerateRequestModel valueOf(String value) { return AURA_ZEUS_EN; case "aura-2-hermes-en": return AURA2HERMES_EN; - case "aura-2-selena-es": - return AURA2SELENA_ES; case "aura-2-neptune-en": return AURA2NEPTUNE_EN; case "aura-2-callista-en": return AURA2CALLISTA_EN; + case "aura-2-cornelia-nl": + return AURA2CORNELIA_NL; + case "aura-2-rhea-nl": + return AURA2RHEA_NL; case "aura-2-aurora-en": return AURA2AURORA_EN; case "aura-2-ophelia-en": return AURA2OPHELIA_EN; case "aura-2-apollo-en": return AURA2APOLLO_EN; - case "aura-luna-en": - return AURA_LUNA_EN; - case "aura-orpheus-en": - return AURA_ORPHEUS_EN; case "aura-2-delia-en": return AURA2DELIA_EN; case "aura-2-mars-en": return AURA2MARS_EN; - case "aura-2-amalthea-en": - return AURA2AMALTHEA_EN; + case "aura-2-aurelia-de": + return AURA2AURELIA_DE; + case "aura-2-agathe-fr": + return AURA2AGATHE_FR; case "aura-hera-en": return AURA_HERA_EN; - case "aura-2-selene-en": - return AURA2SELENE_EN; + case "aura-2-cinzia-it": + return AURA2CINZIA_IT; case "aura-2-aries-en": return AURA2ARIES_EN; case "aura-2-juno-en": return AURA2JUNO_EN; - case "aura-2-luna-en": - return AURA2LUNA_EN; + case "aura-2-maia-it": + return AURA2MAIA_IT; case "aura-2-javier-es": return AURA2JAVIER_ES; + case "aura-2-andromeda-en": + return AURA2ANDROMEDA_EN; + case "aura-2-saturn-en": + return AURA2SATURN_EN; + case "aura-2-iris-en": + return AURA2IRIS_EN; + case "aura-2-dionisio-it": + return AURA2DIONISIO_IT; + case "aura-angus-en": + return AURA_ANGUS_EN; + case "aura-2-hestia-nl": + return AURA2HESTIA_NL; + case "aura-2-hector-fr": + return AURA2HECTOR_FR; + case "aura-2-perseo-it": + return AURA2PERSEO_IT; + case "aura-2-elara-de": + return AURA2ELARA_DE; + case "aura-2-daphne-nl": + return AURA2DAPHNE_NL; + case "aura-2-lara-de": + return AURA2LARA_DE; + case "aura-2-helena-en": + return AURA2HELENA_EN; + case "aura-2-julius-de": + return AURA2JULIUS_DE; + case "aura-stella-en": + return AURA_STELLA_EN; + case "aura-2-antonia-es": + return AURA2ANTONIA_ES; + case "aura-2-draco-en": + return AURA2DRACO_EN; + case "aura-helios-en": + return AURA_HELIOS_EN; + case "aura-2-fabian-de": + return AURA2FABIAN_DE; + case "aura-2-janus-en": + return AURA2JANUS_EN; + case "aura-2-nestor-es": + return AURA2NESTOR_ES; + case "aura-2-valerio-es": + return AURA2VALERIO_ES; + case "aura-2-orion-en": + return AURA2ORION_EN; + case "aura-2-silvia-es": + return AURA2SILVIA_ES; + case "aura-2-minerva-en": + return AURA2MINERVA_EN; + case "aura-2-alvaro-es": + return AURA2ALVARO_ES; + case "aura-perseus-en": + return AURA_PERSEUS_EN; + case "aura-2-vesta-en": + return AURA2VESTA_EN; + case "aura-2-zeus-en": + return AURA2ZEUS_EN; + case "aura-2-orpheus-en": + return AURA2ORPHEUS_EN; + case "aura-2-thalia-en": + return AURA2THALIA_EN; + case "aura-2-izanami-ja": + return AURA2IZANAMI_JA; + case "aura-2-asteria-en": + return AURA2ASTERIA_EN; + case "aura-2-luciano-es": + return AURA2LUCIANO_ES; + case "aura-2-uzume-ja": + return AURA2UZUME_JA; + case "aura-2-selena-es": + return AURA2SELENA_ES; + case "aura-2-gloria-es": + return AURA2GLORIA_ES; + case "aura-2-elio-it": + return AURA2ELIO_IT; + case "aura-2-ama-ja": + return AURA2AMA_JA; + case "aura-luna-en": + return AURA_LUNA_EN; + case "aura-orpheus-en": + return AURA_ORPHEUS_EN; + case "aura-2-amalthea-en": + return AURA2AMALTHEA_EN; + case "aura-2-olivia-es": + return AURA2OLIVIA_ES; + case "aura-2-demetra-it": + return AURA2DEMETRA_IT; + case "aura-2-beatrix-nl": + return AURA2BEATRIX_NL; + case "aura-2-selene-en": + return AURA2SELENE_EN; + case "aura-2-ebisu-ja": + return AURA2EBISU_JA; + case "aura-2-luna-en": + return AURA2LUNA_EN; case "aura-2-phoebe-en": return AURA2PHOEBE_EN; + case "aura-2-flavio-it": + return AURA2FLAVIO_IT; case "aura-2-diana-es": return AURA2DIANA_ES; case "aura-orion-en": return AURA_ORION_EN; - case "aura-2-andromeda-en": - return AURA2ANDROMEDA_EN; case "aura-2-athena-en": return AURA2ATHENA_EN; - case "aura-2-saturn-en": - return AURA2SATURN_EN; + case "aura-2-lars-nl": + return AURA2LARS_NL; + case "aura-2-fujin-ja": + return AURA2FUJIN_JA; case "aura-arcas-en": return AURA_ARCAS_EN; case "aura-2-theia-en": return AURA2THEIA_EN; - case "aura-2-iris-en": - return AURA2IRIS_EN; - case "aura-angus-en": - return AURA_ANGUS_EN; + case "aura-2-livia-it": + return AURA2LIVIA_IT; + case "aura-2-leda-nl": + return AURA2LEDA_NL; case "aura-2-jupiter-en": return AURA2JUPITER_EN; + case "aura-2-melia-it": + return AURA2MELIA_IT; case "aura-2-aquila-es": return AURA2AQUILA_ES; case "aura-2-cora-en": return AURA2CORA_EN; + case "aura-2-agustina-es": + return AURA2AGUSTINA_ES; + case "aura-2-roman-nl": + return AURA2ROMAN_NL; case "aura-2-cordelia-en": return AURA2CORDELIA_EN; case "aura-2-atlas-en": return AURA2ATLAS_EN; - case "aura-2-helena-en": - return AURA2HELENA_EN; - case "aura-stella-en": - return AURA_STELLA_EN; - case "aura-2-draco-en": - return AURA2DRACO_EN; + case "aura-2-viktoria-de": + return AURA2VIKTORIA_DE; case "aura-2-hyperion-en": return AURA2HYPERION_EN; case "aura-2-celeste-es": return AURA2CELESTE_ES; - case "aura-helios-en": - return AURA_HELIOS_EN; case "aura-2-pluto-en": return AURA2PLUTO_EN; - case "aura-2-janus-en": - return AURA2JANUS_EN; - case "aura-2-nestor-es": - return AURA2NESTOR_ES; + case "aura-2-sander-nl": + return AURA2SANDER_NL; case "aura-2-arcas-en": return AURA2ARCAS_EN; - case "aura-2-orion-en": - return AURA2ORION_EN; + case "aura-2-cesare-it": + return AURA2CESARE_IT; case "aura-athena-en": return AURA_ATHENA_EN; case "aura-2-odysseus-en": return AURA2ODYSSEUS_EN; case "aura-2-pandora-en": return AURA2PANDORA_EN; - case "aura-2-minerva-en": - return AURA2MINERVA_EN; - case "aura-2-alvaro-es": - return AURA2ALVARO_ES; - case "aura-perseus-en": - return AURA_PERSEUS_EN; - case "aura-2-vesta-en": - return AURA2VESTA_EN; case "aura-asteria-en": return AURA_ASTERIA_EN; - case "aura-2-zeus-en": - return AURA2ZEUS_EN; case "aura-2-electra-en": return AURA2ELECTRA_EN; - case "aura-2-orpheus-en": - return AURA2ORPHEUS_EN; case "aura-2-estrella-es": return AURA2ESTRELLA_ES; - case "aura-2-thalia-en": - return AURA2THALIA_EN; default: return new AudioGenerateRequestModel(Value.UNKNOWN, value); } } public enum Value { - AURA_ASTERIA_EN, + AURA_ANGUS_EN, - AURA_LUNA_EN, + AURA_ARCAS_EN, - AURA_STELLA_EN, + AURA_ASTERIA_EN, AURA_ATHENA_EN, + AURA_HELIOS_EN, + AURA_HERA_EN, + AURA_LUNA_EN, + AURA_ORION_EN, - AURA_ARCAS_EN, + AURA_ORPHEUS_EN, AURA_PERSEUS_EN, - AURA_ANGUS_EN, - - AURA_ORPHEUS_EN, - - AURA_HELIOS_EN, + AURA_STELLA_EN, AURA_ZEUS_EN, @@ -540,10 +820,10 @@ public enum Value { AURA2CALLISTA_EN, - AURA2CORDELIA_EN, - AURA2CORA_EN, + AURA2CORDELIA_EN, + AURA2DELIA_EN, AURA2DRACO_EN, @@ -602,51 +882,131 @@ public enum Value { AURA2ZEUS_EN, - AURA2SIRIO_ES, + AURA2AGUSTINA_ES, - AURA2NESTOR_ES, + AURA2ALVARO_ES, + + AURA2ANTONIA_ES, + + AURA2AQUILA_ES, AURA2CARINA_ES, AURA2CELESTE_ES, - AURA2ALVARO_ES, - AURA2DIANA_ES, - AURA2AQUILA_ES, + AURA2ESTRELLA_ES, + + AURA2GLORIA_ES, + + AURA2JAVIER_ES, + + AURA2LUCIANO_ES, + + AURA2NESTOR_ES, + + AURA2OLIVIA_ES, AURA2SELENA_ES, - AURA2ESTRELLA_ES, + AURA2SILVIA_ES, - AURA2JAVIER_ES, + AURA2SIRIO_ES, + + AURA2VALERIO_ES, + + AURA2AURELIA_DE, + + AURA2ELARA_DE, + + AURA2FABIAN_DE, + + AURA2JULIUS_DE, + + AURA2KARA_DE, + + AURA2LARA_DE, + + AURA2VIKTORIA_DE, + + AURA2BEATRIX_NL, + + AURA2CORNELIA_NL, + + AURA2DAPHNE_NL, + + AURA2HESTIA_NL, + + AURA2LARS_NL, + + AURA2LEDA_NL, + + AURA2RHEA_NL, + + AURA2ROMAN_NL, + + AURA2SANDER_NL, + + AURA2AGATHE_FR, + + AURA2HECTOR_FR, + + AURA2CESARE_IT, + + AURA2CINZIA_IT, + + AURA2DEMETRA_IT, + + AURA2DIONISIO_IT, + + AURA2ELIO_IT, + + AURA2FLAVIO_IT, + + AURA2LIVIA_IT, + + AURA2MAIA_IT, + + AURA2MELIA_IT, + + AURA2PERSEO_IT, + + AURA2AMA_JA, + + AURA2EBISU_JA, + + AURA2FUJIN_JA, + + AURA2IZANAMI_JA, + + AURA2UZUME_JA, UNKNOWN } public interface Visitor { - T visitAuraAsteriaEn(); + T visitAuraAngusEn(); - T visitAuraLunaEn(); + T visitAuraArcasEn(); - T visitAuraStellaEn(); + T visitAuraAsteriaEn(); T visitAuraAthenaEn(); + T visitAuraHeliosEn(); + T visitAuraHeraEn(); + T visitAuraLunaEn(); + T visitAuraOrionEn(); - T visitAuraArcasEn(); + T visitAuraOrpheusEn(); T visitAuraPerseusEn(); - T visitAuraAngusEn(); - - T visitAuraOrpheusEn(); - - T visitAuraHeliosEn(); + T visitAuraStellaEn(); T visitAuraZeusEn(); @@ -670,10 +1030,10 @@ public interface Visitor { T visitAura2CallistaEn(); - T visitAura2CordeliaEn(); - T visitAura2CoraEn(); + T visitAura2CordeliaEn(); + T visitAura2DeliaEn(); T visitAura2DracoEn(); @@ -732,25 +1092,105 @@ public interface Visitor { T visitAura2ZeusEn(); - T visitAura2SirioEs(); + T visitAura2AgustinaEs(); - T visitAura2NestorEs(); + T visitAura2AlvaroEs(); + + T visitAura2AntoniaEs(); + + T visitAura2AquilaEs(); T visitAura2CarinaEs(); T visitAura2CelesteEs(); - T visitAura2AlvaroEs(); - T visitAura2DianaEs(); - T visitAura2AquilaEs(); + T visitAura2EstrellaEs(); + + T visitAura2GloriaEs(); + + T visitAura2JavierEs(); + + T visitAura2LucianoEs(); + + T visitAura2NestorEs(); + + T visitAura2OliviaEs(); T visitAura2SelenaEs(); - T visitAura2EstrellaEs(); + T visitAura2SilviaEs(); - T visitAura2JavierEs(); + T visitAura2SirioEs(); + + T visitAura2ValerioEs(); + + T visitAura2AureliaDe(); + + T visitAura2ElaraDe(); + + T visitAura2FabianDe(); + + T visitAura2JuliusDe(); + + T visitAura2KaraDe(); + + T visitAura2LaraDe(); + + T visitAura2ViktoriaDe(); + + T visitAura2BeatrixNl(); + + T visitAura2CorneliaNl(); + + T visitAura2DaphneNl(); + + T visitAura2HestiaNl(); + + T visitAura2LarsNl(); + + T visitAura2LedaNl(); + + T visitAura2RheaNl(); + + T visitAura2RomanNl(); + + T visitAura2SanderNl(); + + T visitAura2AgatheFr(); + + T visitAura2HectorFr(); + + T visitAura2CesareIt(); + + T visitAura2CinziaIt(); + + T visitAura2DemetraIt(); + + T visitAura2DionisioIt(); + + T visitAura2ElioIt(); + + T visitAura2FlavioIt(); + + T visitAura2LiviaIt(); + + T visitAura2MaiaIt(); + + T visitAura2MeliaIt(); + + T visitAura2PerseoIt(); + + T visitAura2AmaJa(); + + T visitAura2EbisuJa(); + + T visitAura2FujinJa(); + + T visitAura2IzanamiJa(); + + T visitAura2UzumeJa(); T visitUnknown(String unknownType); } 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 dcf5b22..bf7a08c 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 @@ -135,7 +135,7 @@ public Optional getEncoding() { } /** - * @return Flux TTS model used to synthesize the submitted text, in the form flux-{voice}-{language} (for example, flux-alexis-en). Required; unlike the v1 (Aura) endpoint there is no default and only flux models are accepted. English-only at launch. The voice catalog is not yet finalized, so this is typed as a free-form string rather than a closed enum; it can be locked to an enum (matching STT Flux ListenV2Model) once the GA catalog is confirmed. + * @return Flux TTS model used to synthesize the submitted text, in the form flux-{voice}-{language} (for example, flux-alexis-en). Required; unlike the v1 (Aura) endpoint there is no default and only flux models are accepted. English-only at launch. */ @JsonIgnore public String getModel() { @@ -218,7 +218,7 @@ public static ModelStage builder() { public interface ModelStage { /** - *

Flux TTS model used to synthesize the submitted text, in the form flux-{voice}-{language} (for example, flux-alexis-en). Required; unlike the v1 (Aura) endpoint there is no default and only flux models are accepted. English-only at launch. The voice catalog is not yet finalized, so this is typed as a free-form string rather than a closed enum; it can be locked to an enum (matching STT Flux ListenV2Model) once the GA catalog is confirmed.

+ *

Flux TTS model used to synthesize the submitted text, in the form flux-{voice}-{language} (for example, flux-alexis-en). Required; unlike the v1 (Aura) endpoint there is no default and only flux models are accepted. English-only at launch.

*/ TextStage model(@NotNull String model); @@ -351,8 +351,8 @@ public Builder from(SpeakV2Request other) { } /** - *

Flux TTS model used to synthesize the submitted text, in the form flux-{voice}-{language} (for example, flux-alexis-en). Required; unlike the v1 (Aura) endpoint there is no default and only flux models are accepted. English-only at launch. The voice catalog is not yet finalized, so this is typed as a free-form string rather than a closed enum; it can be locked to an enum (matching STT Flux ListenV2Model) once the GA catalog is confirmed.

- *

Flux TTS model used to synthesize the submitted text, in the form flux-{voice}-{language} (for example, flux-alexis-en). Required; unlike the v1 (Aura) endpoint there is no default and only flux models are accepted. English-only at launch. The voice catalog is not yet finalized, so this is typed as a free-form string rather than a closed enum; it can be locked to an enum (matching STT Flux ListenV2Model) once the GA catalog is confirmed.

+ *

Flux TTS model used to synthesize the submitted text, in the form flux-{voice}-{language} (for example, flux-alexis-en). Required; unlike the v1 (Aura) endpoint there is no default and only flux models are accepted. English-only at launch.

+ *

Flux TTS model used to synthesize the submitted text, in the form flux-{voice}-{language} (for example, flux-alexis-en). Required; unlike the v1 (Aura) endpoint there is no default and only flux models are accepted. English-only at launch.

* @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/SpeakV2Close.java b/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Close.java index 51fef19..2e96a5c 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 @@ -36,14 +36,6 @@ public boolean equals(Object other) { return other instanceof SpeakV2Close; } - @java.lang.Override - public int hashCode() { - // Manual patch: Fern generates equals() (all instances of this fields-less message - // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a - // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. - return getClass().hashCode(); - } - @JsonAnyGetter public Map getAdditionalProperties() { return this.additionalProperties; 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 e122400..acd717d 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 @@ -36,14 +36,6 @@ public boolean equals(Object other) { return other instanceof SpeakV2Flush; } - @java.lang.Override - public int hashCode() { - // Manual patch: Fern generates equals() (all instances of this fields-less message - // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a - // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. - return getClass().hashCode(); - } - @JsonAnyGetter public Map getAdditionalProperties() { return this.additionalProperties; 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 1ce8ea5..cf23bcf 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 @@ -493,11 +493,11 @@ private void handleIncomingMessage(String json) { return; } } - // Unrecognized message type: forward-compatible no-op. The raw frame was - // already delivered to onMessage(String) above, so a newer server adding a - // benign control frame (e.g. a GA addition to this endpoint) must not surface - // as a fatal error to deployed clients. Routing it to onError would make a - // harmless frame look fatal to a voice agent; mirrors the JS/Python SDKs. + if (onErrorHandler != null) { + onErrorHandler.accept(new RuntimeException( + "Unrecognized WebSocket message: " + json.substring(0, Math.min(200, json.length())) + + "... Update your SDK version to support new message types.")); + } } catch (Exception e) { if (onErrorHandler != null) { onErrorHandler.accept(e); diff --git a/src/main/java/com/deepgram/types/ListenV2Numerals.java b/src/main/java/com/deepgram/types/ListenV2Numerals.java new file mode 100644 index 0000000..c1bbb63 --- /dev/null +++ b/src/main/java/com/deepgram/types/ListenV2Numerals.java @@ -0,0 +1,83 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.deepgram.types; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +public final class ListenV2Numerals { + public static final ListenV2Numerals FALSE = new ListenV2Numerals(Value.FALSE, "false"); + + public static final ListenV2Numerals TRUE = new ListenV2Numerals(Value.TRUE, "true"); + + private final Value value; + + private final String string; + + ListenV2Numerals(Value value, String string) { + this.value = value; + this.string = string; + } + + public Value getEnumValue() { + return value; + } + + @java.lang.Override + @JsonValue + public String toString() { + return this.string; + } + + @java.lang.Override + public boolean equals(Object other) { + return (this == other) + || (other instanceof ListenV2Numerals && this.string.equals(((ListenV2Numerals) other).string)); + } + + @java.lang.Override + public int hashCode() { + return this.string.hashCode(); + } + + public T visit(Visitor visitor) { + switch (value) { + case FALSE: + return visitor.visitFalse(); + case TRUE: + return visitor.visitTrue(); + case UNKNOWN: + default: + return visitor.visitUnknown(string); + } + } + + @JsonCreator(mode = JsonCreator.Mode.DELEGATING) + public static ListenV2Numerals valueOf(String value) { + switch (value) { + case "false": + return FALSE; + case "true": + return TRUE; + default: + return new ListenV2Numerals(Value.UNKNOWN, value); + } + } + + public enum Value { + TRUE, + + FALSE, + + UNKNOWN + } + + public interface Visitor { + T visitTrue(); + + T visitFalse(); + + T visitUnknown(String unknownType); + } +} diff --git a/src/main/java/com/deepgram/types/SpeakV1Model.java b/src/main/java/com/deepgram/types/SpeakV1Model.java index 9bdccc2..161d870 100644 --- a/src/main/java/com/deepgram/types/SpeakV1Model.java +++ b/src/main/java/com/deepgram/types/SpeakV1Model.java @@ -11,7 +11,7 @@ public final class SpeakV1Model { public static final SpeakV1Model AURA2HERA_EN = new SpeakV1Model(Value.AURA2HERA_EN, "aura-2-hera-en"); - public static final SpeakV1Model AURA2ASTERIA_EN = new SpeakV1Model(Value.AURA2ASTERIA_EN, "aura-2-asteria-en"); + public static final SpeakV1Model AURA2KARA_DE = new SpeakV1Model(Value.AURA2KARA_DE, "aura-2-kara-de"); public static final SpeakV1Model AURA2HARMONIA_EN = new SpeakV1Model(Value.AURA2HARMONIA_EN, "aura-2-harmonia-en"); @@ -21,92 +21,186 @@ public final class SpeakV1Model { public static final SpeakV1Model AURA2HERMES_EN = new SpeakV1Model(Value.AURA2HERMES_EN, "aura-2-hermes-en"); - public static final SpeakV1Model AURA2SELENA_ES = new SpeakV1Model(Value.AURA2SELENA_ES, "aura-2-selena-es"); - public static final SpeakV1Model AURA2NEPTUNE_EN = new SpeakV1Model(Value.AURA2NEPTUNE_EN, "aura-2-neptune-en"); public static final SpeakV1Model AURA2CALLISTA_EN = new SpeakV1Model(Value.AURA2CALLISTA_EN, "aura-2-callista-en"); + public static final SpeakV1Model AURA2CORNELIA_NL = new SpeakV1Model(Value.AURA2CORNELIA_NL, "aura-2-cornelia-nl"); + + public static final SpeakV1Model AURA2RHEA_NL = new SpeakV1Model(Value.AURA2RHEA_NL, "aura-2-rhea-nl"); + public static final SpeakV1Model AURA2AURORA_EN = new SpeakV1Model(Value.AURA2AURORA_EN, "aura-2-aurora-en"); public static final SpeakV1Model AURA2OPHELIA_EN = new SpeakV1Model(Value.AURA2OPHELIA_EN, "aura-2-ophelia-en"); public static final SpeakV1Model AURA2APOLLO_EN = new SpeakV1Model(Value.AURA2APOLLO_EN, "aura-2-apollo-en"); - public static final SpeakV1Model AURA_LUNA_EN = new SpeakV1Model(Value.AURA_LUNA_EN, "aura-luna-en"); - - public static final SpeakV1Model AURA_ORPHEUS_EN = new SpeakV1Model(Value.AURA_ORPHEUS_EN, "aura-orpheus-en"); - public static final SpeakV1Model AURA2DELIA_EN = new SpeakV1Model(Value.AURA2DELIA_EN, "aura-2-delia-en"); public static final SpeakV1Model AURA2MARS_EN = new SpeakV1Model(Value.AURA2MARS_EN, "aura-2-mars-en"); - public static final SpeakV1Model AURA2AMALTHEA_EN = new SpeakV1Model(Value.AURA2AMALTHEA_EN, "aura-2-amalthea-en"); + public static final SpeakV1Model AURA2AURELIA_DE = new SpeakV1Model(Value.AURA2AURELIA_DE, "aura-2-aurelia-de"); + + public static final SpeakV1Model AURA2AGATHE_FR = new SpeakV1Model(Value.AURA2AGATHE_FR, "aura-2-agathe-fr"); public static final SpeakV1Model AURA_HERA_EN = new SpeakV1Model(Value.AURA_HERA_EN, "aura-hera-en"); - public static final SpeakV1Model AURA2SELENE_EN = new SpeakV1Model(Value.AURA2SELENE_EN, "aura-2-selene-en"); + public static final SpeakV1Model AURA2CINZIA_IT = new SpeakV1Model(Value.AURA2CINZIA_IT, "aura-2-cinzia-it"); public static final SpeakV1Model AURA2ARIES_EN = new SpeakV1Model(Value.AURA2ARIES_EN, "aura-2-aries-en"); public static final SpeakV1Model AURA2JUNO_EN = new SpeakV1Model(Value.AURA2JUNO_EN, "aura-2-juno-en"); - public static final SpeakV1Model AURA2LUNA_EN = new SpeakV1Model(Value.AURA2LUNA_EN, "aura-2-luna-en"); + public static final SpeakV1Model AURA2MAIA_IT = new SpeakV1Model(Value.AURA2MAIA_IT, "aura-2-maia-it"); public static final SpeakV1Model AURA2JAVIER_ES = new SpeakV1Model(Value.AURA2JAVIER_ES, "aura-2-javier-es"); + public static final SpeakV1Model AURA2ANDROMEDA_EN = + new SpeakV1Model(Value.AURA2ANDROMEDA_EN, "aura-2-andromeda-en"); + + public static final SpeakV1Model AURA2SATURN_EN = new SpeakV1Model(Value.AURA2SATURN_EN, "aura-2-saturn-en"); + + public static final SpeakV1Model AURA2IRIS_EN = new SpeakV1Model(Value.AURA2IRIS_EN, "aura-2-iris-en"); + + public static final SpeakV1Model AURA2DIONISIO_IT = new SpeakV1Model(Value.AURA2DIONISIO_IT, "aura-2-dionisio-it"); + + public static final SpeakV1Model AURA_ANGUS_EN = new SpeakV1Model(Value.AURA_ANGUS_EN, "aura-angus-en"); + + public static final SpeakV1Model AURA2HESTIA_NL = new SpeakV1Model(Value.AURA2HESTIA_NL, "aura-2-hestia-nl"); + + public static final SpeakV1Model AURA2HECTOR_FR = new SpeakV1Model(Value.AURA2HECTOR_FR, "aura-2-hector-fr"); + + public static final SpeakV1Model AURA2PERSEO_IT = new SpeakV1Model(Value.AURA2PERSEO_IT, "aura-2-perseo-it"); + + public static final SpeakV1Model AURA2ELARA_DE = new SpeakV1Model(Value.AURA2ELARA_DE, "aura-2-elara-de"); + + public static final SpeakV1Model AURA2DAPHNE_NL = new SpeakV1Model(Value.AURA2DAPHNE_NL, "aura-2-daphne-nl"); + + public static final SpeakV1Model AURA2LARA_DE = new SpeakV1Model(Value.AURA2LARA_DE, "aura-2-lara-de"); + + public static final SpeakV1Model AURA2HELENA_EN = new SpeakV1Model(Value.AURA2HELENA_EN, "aura-2-helena-en"); + + public static final SpeakV1Model AURA2JULIUS_DE = new SpeakV1Model(Value.AURA2JULIUS_DE, "aura-2-julius-de"); + + public static final SpeakV1Model AURA_STELLA_EN = new SpeakV1Model(Value.AURA_STELLA_EN, "aura-stella-en"); + + public static final SpeakV1Model AURA2ANTONIA_ES = new SpeakV1Model(Value.AURA2ANTONIA_ES, "aura-2-antonia-es"); + + public static final SpeakV1Model AURA2DRACO_EN = new SpeakV1Model(Value.AURA2DRACO_EN, "aura-2-draco-en"); + + public static final SpeakV1Model AURA_HELIOS_EN = new SpeakV1Model(Value.AURA_HELIOS_EN, "aura-helios-en"); + + public static final SpeakV1Model AURA2FABIAN_DE = new SpeakV1Model(Value.AURA2FABIAN_DE, "aura-2-fabian-de"); + + public static final SpeakV1Model AURA2JANUS_EN = new SpeakV1Model(Value.AURA2JANUS_EN, "aura-2-janus-en"); + + public static final SpeakV1Model AURA2NESTOR_ES = new SpeakV1Model(Value.AURA2NESTOR_ES, "aura-2-nestor-es"); + + public static final SpeakV1Model AURA2VALERIO_ES = new SpeakV1Model(Value.AURA2VALERIO_ES, "aura-2-valerio-es"); + + public static final SpeakV1Model AURA2ORION_EN = new SpeakV1Model(Value.AURA2ORION_EN, "aura-2-orion-en"); + + public static final SpeakV1Model AURA2SILVIA_ES = new SpeakV1Model(Value.AURA2SILVIA_ES, "aura-2-silvia-es"); + + public static final SpeakV1Model AURA2MINERVA_EN = new SpeakV1Model(Value.AURA2MINERVA_EN, "aura-2-minerva-en"); + + public static final SpeakV1Model AURA2ALVARO_ES = new SpeakV1Model(Value.AURA2ALVARO_ES, "aura-2-alvaro-es"); + + public static final SpeakV1Model AURA_PERSEUS_EN = new SpeakV1Model(Value.AURA_PERSEUS_EN, "aura-perseus-en"); + + public static final SpeakV1Model AURA2VESTA_EN = new SpeakV1Model(Value.AURA2VESTA_EN, "aura-2-vesta-en"); + + public static final SpeakV1Model AURA2ZEUS_EN = new SpeakV1Model(Value.AURA2ZEUS_EN, "aura-2-zeus-en"); + + public static final SpeakV1Model AURA2ORPHEUS_EN = new SpeakV1Model(Value.AURA2ORPHEUS_EN, "aura-2-orpheus-en"); + + public static final SpeakV1Model AURA2THALIA_EN = new SpeakV1Model(Value.AURA2THALIA_EN, "aura-2-thalia-en"); + + public static final SpeakV1Model AURA2IZANAMI_JA = new SpeakV1Model(Value.AURA2IZANAMI_JA, "aura-2-izanami-ja"); + + public static final SpeakV1Model AURA2ASTERIA_EN = new SpeakV1Model(Value.AURA2ASTERIA_EN, "aura-2-asteria-en"); + + public static final SpeakV1Model AURA2LUCIANO_ES = new SpeakV1Model(Value.AURA2LUCIANO_ES, "aura-2-luciano-es"); + + public static final SpeakV1Model AURA2UZUME_JA = new SpeakV1Model(Value.AURA2UZUME_JA, "aura-2-uzume-ja"); + + public static final SpeakV1Model AURA2SELENA_ES = new SpeakV1Model(Value.AURA2SELENA_ES, "aura-2-selena-es"); + + public static final SpeakV1Model AURA2GLORIA_ES = new SpeakV1Model(Value.AURA2GLORIA_ES, "aura-2-gloria-es"); + + public static final SpeakV1Model AURA2ELIO_IT = new SpeakV1Model(Value.AURA2ELIO_IT, "aura-2-elio-it"); + + public static final SpeakV1Model AURA2AMA_JA = new SpeakV1Model(Value.AURA2AMA_JA, "aura-2-ama-ja"); + + public static final SpeakV1Model AURA_LUNA_EN = new SpeakV1Model(Value.AURA_LUNA_EN, "aura-luna-en"); + + public static final SpeakV1Model AURA_ORPHEUS_EN = new SpeakV1Model(Value.AURA_ORPHEUS_EN, "aura-orpheus-en"); + + public static final SpeakV1Model AURA2AMALTHEA_EN = new SpeakV1Model(Value.AURA2AMALTHEA_EN, "aura-2-amalthea-en"); + + public static final SpeakV1Model AURA2OLIVIA_ES = new SpeakV1Model(Value.AURA2OLIVIA_ES, "aura-2-olivia-es"); + + public static final SpeakV1Model AURA2DEMETRA_IT = new SpeakV1Model(Value.AURA2DEMETRA_IT, "aura-2-demetra-it"); + + public static final SpeakV1Model AURA2BEATRIX_NL = new SpeakV1Model(Value.AURA2BEATRIX_NL, "aura-2-beatrix-nl"); + + public static final SpeakV1Model AURA2SELENE_EN = new SpeakV1Model(Value.AURA2SELENE_EN, "aura-2-selene-en"); + + public static final SpeakV1Model AURA2EBISU_JA = new SpeakV1Model(Value.AURA2EBISU_JA, "aura-2-ebisu-ja"); + + public static final SpeakV1Model AURA2LUNA_EN = new SpeakV1Model(Value.AURA2LUNA_EN, "aura-2-luna-en"); + public static final SpeakV1Model AURA2PHOEBE_EN = new SpeakV1Model(Value.AURA2PHOEBE_EN, "aura-2-phoebe-en"); + public static final SpeakV1Model AURA2FLAVIO_IT = new SpeakV1Model(Value.AURA2FLAVIO_IT, "aura-2-flavio-it"); + public static final SpeakV1Model AURA2DIANA_ES = new SpeakV1Model(Value.AURA2DIANA_ES, "aura-2-diana-es"); public static final SpeakV1Model AURA_ORION_EN = new SpeakV1Model(Value.AURA_ORION_EN, "aura-orion-en"); - public static final SpeakV1Model AURA2ANDROMEDA_EN = - new SpeakV1Model(Value.AURA2ANDROMEDA_EN, "aura-2-andromeda-en"); - public static final SpeakV1Model AURA2ATHENA_EN = new SpeakV1Model(Value.AURA2ATHENA_EN, "aura-2-athena-en"); - public static final SpeakV1Model AURA2SATURN_EN = new SpeakV1Model(Value.AURA2SATURN_EN, "aura-2-saturn-en"); + public static final SpeakV1Model AURA2LARS_NL = new SpeakV1Model(Value.AURA2LARS_NL, "aura-2-lars-nl"); + + public static final SpeakV1Model AURA2FUJIN_JA = new SpeakV1Model(Value.AURA2FUJIN_JA, "aura-2-fujin-ja"); public static final SpeakV1Model AURA_ARCAS_EN = new SpeakV1Model(Value.AURA_ARCAS_EN, "aura-arcas-en"); public static final SpeakV1Model AURA2THEIA_EN = new SpeakV1Model(Value.AURA2THEIA_EN, "aura-2-theia-en"); - public static final SpeakV1Model AURA2IRIS_EN = new SpeakV1Model(Value.AURA2IRIS_EN, "aura-2-iris-en"); + public static final SpeakV1Model AURA2LIVIA_IT = new SpeakV1Model(Value.AURA2LIVIA_IT, "aura-2-livia-it"); - public static final SpeakV1Model AURA_ANGUS_EN = new SpeakV1Model(Value.AURA_ANGUS_EN, "aura-angus-en"); + public static final SpeakV1Model AURA2LEDA_NL = new SpeakV1Model(Value.AURA2LEDA_NL, "aura-2-leda-nl"); public static final SpeakV1Model AURA2JUPITER_EN = new SpeakV1Model(Value.AURA2JUPITER_EN, "aura-2-jupiter-en"); + public static final SpeakV1Model AURA2MELIA_IT = new SpeakV1Model(Value.AURA2MELIA_IT, "aura-2-melia-it"); + public static final SpeakV1Model AURA2AQUILA_ES = new SpeakV1Model(Value.AURA2AQUILA_ES, "aura-2-aquila-es"); public static final SpeakV1Model AURA2CORA_EN = new SpeakV1Model(Value.AURA2CORA_EN, "aura-2-cora-en"); - public static final SpeakV1Model AURA2CORDELIA_EN = new SpeakV1Model(Value.AURA2CORDELIA_EN, "aura-2-cordelia-en"); + public static final SpeakV1Model AURA2AGUSTINA_ES = new SpeakV1Model(Value.AURA2AGUSTINA_ES, "aura-2-agustina-es"); - public static final SpeakV1Model AURA2ATLAS_EN = new SpeakV1Model(Value.AURA2ATLAS_EN, "aura-2-atlas-en"); + public static final SpeakV1Model AURA2ROMAN_NL = new SpeakV1Model(Value.AURA2ROMAN_NL, "aura-2-roman-nl"); - public static final SpeakV1Model AURA2HELENA_EN = new SpeakV1Model(Value.AURA2HELENA_EN, "aura-2-helena-en"); + public static final SpeakV1Model AURA2CORDELIA_EN = new SpeakV1Model(Value.AURA2CORDELIA_EN, "aura-2-cordelia-en"); - public static final SpeakV1Model AURA_STELLA_EN = new SpeakV1Model(Value.AURA_STELLA_EN, "aura-stella-en"); + public static final SpeakV1Model AURA2ATLAS_EN = new SpeakV1Model(Value.AURA2ATLAS_EN, "aura-2-atlas-en"); - public static final SpeakV1Model AURA2DRACO_EN = new SpeakV1Model(Value.AURA2DRACO_EN, "aura-2-draco-en"); + public static final SpeakV1Model AURA2VIKTORIA_DE = new SpeakV1Model(Value.AURA2VIKTORIA_DE, "aura-2-viktoria-de"); public static final SpeakV1Model AURA2HYPERION_EN = new SpeakV1Model(Value.AURA2HYPERION_EN, "aura-2-hyperion-en"); public static final SpeakV1Model AURA2CELESTE_ES = new SpeakV1Model(Value.AURA2CELESTE_ES, "aura-2-celeste-es"); - public static final SpeakV1Model AURA_HELIOS_EN = new SpeakV1Model(Value.AURA_HELIOS_EN, "aura-helios-en"); - public static final SpeakV1Model AURA2PLUTO_EN = new SpeakV1Model(Value.AURA2PLUTO_EN, "aura-2-pluto-en"); - public static final SpeakV1Model AURA2JANUS_EN = new SpeakV1Model(Value.AURA2JANUS_EN, "aura-2-janus-en"); - - public static final SpeakV1Model AURA2NESTOR_ES = new SpeakV1Model(Value.AURA2NESTOR_ES, "aura-2-nestor-es"); + public static final SpeakV1Model AURA2SANDER_NL = new SpeakV1Model(Value.AURA2SANDER_NL, "aura-2-sander-nl"); public static final SpeakV1Model AURA2ARCAS_EN = new SpeakV1Model(Value.AURA2ARCAS_EN, "aura-2-arcas-en"); - public static final SpeakV1Model AURA2ORION_EN = new SpeakV1Model(Value.AURA2ORION_EN, "aura-2-orion-en"); + public static final SpeakV1Model AURA2CESARE_IT = new SpeakV1Model(Value.AURA2CESARE_IT, "aura-2-cesare-it"); public static final SpeakV1Model AURA_ATHENA_EN = new SpeakV1Model(Value.AURA_ATHENA_EN, "aura-athena-en"); @@ -114,26 +208,12 @@ public final class SpeakV1Model { public static final SpeakV1Model AURA2PANDORA_EN = new SpeakV1Model(Value.AURA2PANDORA_EN, "aura-2-pandora-en"); - public static final SpeakV1Model AURA2MINERVA_EN = new SpeakV1Model(Value.AURA2MINERVA_EN, "aura-2-minerva-en"); - - public static final SpeakV1Model AURA2ALVARO_ES = new SpeakV1Model(Value.AURA2ALVARO_ES, "aura-2-alvaro-es"); - - public static final SpeakV1Model AURA_PERSEUS_EN = new SpeakV1Model(Value.AURA_PERSEUS_EN, "aura-perseus-en"); - - public static final SpeakV1Model AURA2VESTA_EN = new SpeakV1Model(Value.AURA2VESTA_EN, "aura-2-vesta-en"); - public static final SpeakV1Model AURA_ASTERIA_EN = new SpeakV1Model(Value.AURA_ASTERIA_EN, "aura-asteria-en"); - public static final SpeakV1Model AURA2ZEUS_EN = new SpeakV1Model(Value.AURA2ZEUS_EN, "aura-2-zeus-en"); - public static final SpeakV1Model AURA2ELECTRA_EN = new SpeakV1Model(Value.AURA2ELECTRA_EN, "aura-2-electra-en"); - public static final SpeakV1Model AURA2ORPHEUS_EN = new SpeakV1Model(Value.AURA2ORPHEUS_EN, "aura-2-orpheus-en"); - public static final SpeakV1Model AURA2ESTRELLA_ES = new SpeakV1Model(Value.AURA2ESTRELLA_ES, "aura-2-estrella-es"); - public static final SpeakV1Model AURA2THALIA_EN = new SpeakV1Model(Value.AURA2THALIA_EN, "aura-2-thalia-en"); - private final Value value; private final String string; @@ -169,8 +249,8 @@ public T visit(Visitor visitor) { return visitor.visitAura2SirioEs(); case AURA2HERA_EN: return visitor.visitAura2HeraEn(); - case AURA2ASTERIA_EN: - return visitor.visitAura2AsteriaEn(); + case AURA2KARA_DE: + return visitor.visitAura2KaraDe(); case AURA2HARMONIA_EN: return visitor.visitAura2HarmoniaEn(); case AURA2CARINA_ES: @@ -179,118 +259,198 @@ public T visit(Visitor visitor) { return visitor.visitAuraZeusEn(); case AURA2HERMES_EN: return visitor.visitAura2HermesEn(); - case AURA2SELENA_ES: - return visitor.visitAura2SelenaEs(); case AURA2NEPTUNE_EN: return visitor.visitAura2NeptuneEn(); case AURA2CALLISTA_EN: return visitor.visitAura2CallistaEn(); + case AURA2CORNELIA_NL: + return visitor.visitAura2CorneliaNl(); + case AURA2RHEA_NL: + return visitor.visitAura2RheaNl(); case AURA2AURORA_EN: return visitor.visitAura2AuroraEn(); case AURA2OPHELIA_EN: return visitor.visitAura2OpheliaEn(); case AURA2APOLLO_EN: return visitor.visitAura2ApolloEn(); - case AURA_LUNA_EN: - return visitor.visitAuraLunaEn(); - case AURA_ORPHEUS_EN: - return visitor.visitAuraOrpheusEn(); case AURA2DELIA_EN: return visitor.visitAura2DeliaEn(); case AURA2MARS_EN: return visitor.visitAura2MarsEn(); - case AURA2AMALTHEA_EN: - return visitor.visitAura2AmaltheaEn(); + case AURA2AURELIA_DE: + return visitor.visitAura2AureliaDe(); + case AURA2AGATHE_FR: + return visitor.visitAura2AgatheFr(); case AURA_HERA_EN: return visitor.visitAuraHeraEn(); - case AURA2SELENE_EN: - return visitor.visitAura2SeleneEn(); + case AURA2CINZIA_IT: + return visitor.visitAura2CinziaIt(); case AURA2ARIES_EN: return visitor.visitAura2AriesEn(); case AURA2JUNO_EN: return visitor.visitAura2JunoEn(); - case AURA2LUNA_EN: - return visitor.visitAura2LunaEn(); + case AURA2MAIA_IT: + return visitor.visitAura2MaiaIt(); case AURA2JAVIER_ES: return visitor.visitAura2JavierEs(); + case AURA2ANDROMEDA_EN: + return visitor.visitAura2AndromedaEn(); + case AURA2SATURN_EN: + return visitor.visitAura2SaturnEn(); + case AURA2IRIS_EN: + return visitor.visitAura2IrisEn(); + case AURA2DIONISIO_IT: + return visitor.visitAura2DionisioIt(); + case AURA_ANGUS_EN: + return visitor.visitAuraAngusEn(); + case AURA2HESTIA_NL: + return visitor.visitAura2HestiaNl(); + case AURA2HECTOR_FR: + return visitor.visitAura2HectorFr(); + case AURA2PERSEO_IT: + return visitor.visitAura2PerseoIt(); + case AURA2ELARA_DE: + return visitor.visitAura2ElaraDe(); + case AURA2DAPHNE_NL: + return visitor.visitAura2DaphneNl(); + case AURA2LARA_DE: + return visitor.visitAura2LaraDe(); + case AURA2HELENA_EN: + return visitor.visitAura2HelenaEn(); + case AURA2JULIUS_DE: + return visitor.visitAura2JuliusDe(); + case AURA_STELLA_EN: + return visitor.visitAuraStellaEn(); + case AURA2ANTONIA_ES: + return visitor.visitAura2AntoniaEs(); + case AURA2DRACO_EN: + return visitor.visitAura2DracoEn(); + case AURA_HELIOS_EN: + return visitor.visitAuraHeliosEn(); + case AURA2FABIAN_DE: + return visitor.visitAura2FabianDe(); + case AURA2JANUS_EN: + return visitor.visitAura2JanusEn(); + case AURA2NESTOR_ES: + return visitor.visitAura2NestorEs(); + case AURA2VALERIO_ES: + return visitor.visitAura2ValerioEs(); + case AURA2ORION_EN: + return visitor.visitAura2OrionEn(); + case AURA2SILVIA_ES: + return visitor.visitAura2SilviaEs(); + case AURA2MINERVA_EN: + return visitor.visitAura2MinervaEn(); + case AURA2ALVARO_ES: + return visitor.visitAura2AlvaroEs(); + case AURA_PERSEUS_EN: + return visitor.visitAuraPerseusEn(); + case AURA2VESTA_EN: + return visitor.visitAura2VestaEn(); + case AURA2ZEUS_EN: + return visitor.visitAura2ZeusEn(); + case AURA2ORPHEUS_EN: + return visitor.visitAura2OrpheusEn(); + case AURA2THALIA_EN: + return visitor.visitAura2ThaliaEn(); + case AURA2IZANAMI_JA: + return visitor.visitAura2IzanamiJa(); + case AURA2ASTERIA_EN: + return visitor.visitAura2AsteriaEn(); + case AURA2LUCIANO_ES: + return visitor.visitAura2LucianoEs(); + case AURA2UZUME_JA: + return visitor.visitAura2UzumeJa(); + case AURA2SELENA_ES: + return visitor.visitAura2SelenaEs(); + case AURA2GLORIA_ES: + return visitor.visitAura2GloriaEs(); + case AURA2ELIO_IT: + return visitor.visitAura2ElioIt(); + case AURA2AMA_JA: + return visitor.visitAura2AmaJa(); + case AURA_LUNA_EN: + return visitor.visitAuraLunaEn(); + case AURA_ORPHEUS_EN: + return visitor.visitAuraOrpheusEn(); + case AURA2AMALTHEA_EN: + return visitor.visitAura2AmaltheaEn(); + case AURA2OLIVIA_ES: + return visitor.visitAura2OliviaEs(); + case AURA2DEMETRA_IT: + return visitor.visitAura2DemetraIt(); + case AURA2BEATRIX_NL: + return visitor.visitAura2BeatrixNl(); + case AURA2SELENE_EN: + return visitor.visitAura2SeleneEn(); + case AURA2EBISU_JA: + return visitor.visitAura2EbisuJa(); + case AURA2LUNA_EN: + return visitor.visitAura2LunaEn(); case AURA2PHOEBE_EN: return visitor.visitAura2PhoebeEn(); + case AURA2FLAVIO_IT: + return visitor.visitAura2FlavioIt(); case AURA2DIANA_ES: return visitor.visitAura2DianaEs(); case AURA_ORION_EN: return visitor.visitAuraOrionEn(); - case AURA2ANDROMEDA_EN: - return visitor.visitAura2AndromedaEn(); case AURA2ATHENA_EN: return visitor.visitAura2AthenaEn(); - case AURA2SATURN_EN: - return visitor.visitAura2SaturnEn(); + case AURA2LARS_NL: + return visitor.visitAura2LarsNl(); + case AURA2FUJIN_JA: + return visitor.visitAura2FujinJa(); case AURA_ARCAS_EN: return visitor.visitAuraArcasEn(); case AURA2THEIA_EN: return visitor.visitAura2TheiaEn(); - case AURA2IRIS_EN: - return visitor.visitAura2IrisEn(); - case AURA_ANGUS_EN: - return visitor.visitAuraAngusEn(); + case AURA2LIVIA_IT: + return visitor.visitAura2LiviaIt(); + case AURA2LEDA_NL: + return visitor.visitAura2LedaNl(); case AURA2JUPITER_EN: return visitor.visitAura2JupiterEn(); + case AURA2MELIA_IT: + return visitor.visitAura2MeliaIt(); case AURA2AQUILA_ES: return visitor.visitAura2AquilaEs(); case AURA2CORA_EN: return visitor.visitAura2CoraEn(); + case AURA2AGUSTINA_ES: + return visitor.visitAura2AgustinaEs(); + case AURA2ROMAN_NL: + return visitor.visitAura2RomanNl(); case AURA2CORDELIA_EN: return visitor.visitAura2CordeliaEn(); case AURA2ATLAS_EN: return visitor.visitAura2AtlasEn(); - case AURA2HELENA_EN: - return visitor.visitAura2HelenaEn(); - case AURA_STELLA_EN: - return visitor.visitAuraStellaEn(); - case AURA2DRACO_EN: - return visitor.visitAura2DracoEn(); + case AURA2VIKTORIA_DE: + return visitor.visitAura2ViktoriaDe(); case AURA2HYPERION_EN: return visitor.visitAura2HyperionEn(); case AURA2CELESTE_ES: return visitor.visitAura2CelesteEs(); - case AURA_HELIOS_EN: - return visitor.visitAuraHeliosEn(); case AURA2PLUTO_EN: return visitor.visitAura2PlutoEn(); - case AURA2JANUS_EN: - return visitor.visitAura2JanusEn(); - case AURA2NESTOR_ES: - return visitor.visitAura2NestorEs(); + case AURA2SANDER_NL: + return visitor.visitAura2SanderNl(); case AURA2ARCAS_EN: return visitor.visitAura2ArcasEn(); - case AURA2ORION_EN: - return visitor.visitAura2OrionEn(); + case AURA2CESARE_IT: + return visitor.visitAura2CesareIt(); case AURA_ATHENA_EN: return visitor.visitAuraAthenaEn(); case AURA2ODYSSEUS_EN: return visitor.visitAura2OdysseusEn(); case AURA2PANDORA_EN: return visitor.visitAura2PandoraEn(); - case AURA2MINERVA_EN: - return visitor.visitAura2MinervaEn(); - case AURA2ALVARO_ES: - return visitor.visitAura2AlvaroEs(); - case AURA_PERSEUS_EN: - return visitor.visitAuraPerseusEn(); - case AURA2VESTA_EN: - return visitor.visitAura2VestaEn(); case AURA_ASTERIA_EN: return visitor.visitAuraAsteriaEn(); - case AURA2ZEUS_EN: - return visitor.visitAura2ZeusEn(); case AURA2ELECTRA_EN: return visitor.visitAura2ElectraEn(); - case AURA2ORPHEUS_EN: - return visitor.visitAura2OrpheusEn(); case AURA2ESTRELLA_ES: return visitor.visitAura2EstrellaEs(); - case AURA2THALIA_EN: - return visitor.visitAura2ThaliaEn(); case UNKNOWN: default: return visitor.visitUnknown(string); @@ -304,8 +464,8 @@ public static SpeakV1Model valueOf(String value) { return AURA2SIRIO_ES; case "aura-2-hera-en": return AURA2HERA_EN; - case "aura-2-asteria-en": - return AURA2ASTERIA_EN; + case "aura-2-kara-de": + return AURA2KARA_DE; case "aura-2-harmonia-en": return AURA2HARMONIA_EN; case "aura-2-carina-es": @@ -314,145 +474,225 @@ public static SpeakV1Model valueOf(String value) { return AURA_ZEUS_EN; case "aura-2-hermes-en": return AURA2HERMES_EN; - case "aura-2-selena-es": - return AURA2SELENA_ES; case "aura-2-neptune-en": return AURA2NEPTUNE_EN; case "aura-2-callista-en": return AURA2CALLISTA_EN; + case "aura-2-cornelia-nl": + return AURA2CORNELIA_NL; + case "aura-2-rhea-nl": + return AURA2RHEA_NL; case "aura-2-aurora-en": return AURA2AURORA_EN; case "aura-2-ophelia-en": return AURA2OPHELIA_EN; case "aura-2-apollo-en": return AURA2APOLLO_EN; - case "aura-luna-en": - return AURA_LUNA_EN; - case "aura-orpheus-en": - return AURA_ORPHEUS_EN; case "aura-2-delia-en": return AURA2DELIA_EN; case "aura-2-mars-en": return AURA2MARS_EN; - case "aura-2-amalthea-en": - return AURA2AMALTHEA_EN; + case "aura-2-aurelia-de": + return AURA2AURELIA_DE; + case "aura-2-agathe-fr": + return AURA2AGATHE_FR; case "aura-hera-en": return AURA_HERA_EN; - case "aura-2-selene-en": - return AURA2SELENE_EN; + case "aura-2-cinzia-it": + return AURA2CINZIA_IT; case "aura-2-aries-en": return AURA2ARIES_EN; case "aura-2-juno-en": return AURA2JUNO_EN; - case "aura-2-luna-en": - return AURA2LUNA_EN; + case "aura-2-maia-it": + return AURA2MAIA_IT; case "aura-2-javier-es": return AURA2JAVIER_ES; + case "aura-2-andromeda-en": + return AURA2ANDROMEDA_EN; + case "aura-2-saturn-en": + return AURA2SATURN_EN; + case "aura-2-iris-en": + return AURA2IRIS_EN; + case "aura-2-dionisio-it": + return AURA2DIONISIO_IT; + case "aura-angus-en": + return AURA_ANGUS_EN; + case "aura-2-hestia-nl": + return AURA2HESTIA_NL; + case "aura-2-hector-fr": + return AURA2HECTOR_FR; + case "aura-2-perseo-it": + return AURA2PERSEO_IT; + case "aura-2-elara-de": + return AURA2ELARA_DE; + case "aura-2-daphne-nl": + return AURA2DAPHNE_NL; + case "aura-2-lara-de": + return AURA2LARA_DE; + case "aura-2-helena-en": + return AURA2HELENA_EN; + case "aura-2-julius-de": + return AURA2JULIUS_DE; + case "aura-stella-en": + return AURA_STELLA_EN; + case "aura-2-antonia-es": + return AURA2ANTONIA_ES; + case "aura-2-draco-en": + return AURA2DRACO_EN; + case "aura-helios-en": + return AURA_HELIOS_EN; + case "aura-2-fabian-de": + return AURA2FABIAN_DE; + case "aura-2-janus-en": + return AURA2JANUS_EN; + case "aura-2-nestor-es": + return AURA2NESTOR_ES; + case "aura-2-valerio-es": + return AURA2VALERIO_ES; + case "aura-2-orion-en": + return AURA2ORION_EN; + case "aura-2-silvia-es": + return AURA2SILVIA_ES; + case "aura-2-minerva-en": + return AURA2MINERVA_EN; + case "aura-2-alvaro-es": + return AURA2ALVARO_ES; + case "aura-perseus-en": + return AURA_PERSEUS_EN; + case "aura-2-vesta-en": + return AURA2VESTA_EN; + case "aura-2-zeus-en": + return AURA2ZEUS_EN; + case "aura-2-orpheus-en": + return AURA2ORPHEUS_EN; + case "aura-2-thalia-en": + return AURA2THALIA_EN; + case "aura-2-izanami-ja": + return AURA2IZANAMI_JA; + case "aura-2-asteria-en": + return AURA2ASTERIA_EN; + case "aura-2-luciano-es": + return AURA2LUCIANO_ES; + case "aura-2-uzume-ja": + return AURA2UZUME_JA; + case "aura-2-selena-es": + return AURA2SELENA_ES; + case "aura-2-gloria-es": + return AURA2GLORIA_ES; + case "aura-2-elio-it": + return AURA2ELIO_IT; + case "aura-2-ama-ja": + return AURA2AMA_JA; + case "aura-luna-en": + return AURA_LUNA_EN; + case "aura-orpheus-en": + return AURA_ORPHEUS_EN; + case "aura-2-amalthea-en": + return AURA2AMALTHEA_EN; + case "aura-2-olivia-es": + return AURA2OLIVIA_ES; + case "aura-2-demetra-it": + return AURA2DEMETRA_IT; + case "aura-2-beatrix-nl": + return AURA2BEATRIX_NL; + case "aura-2-selene-en": + return AURA2SELENE_EN; + case "aura-2-ebisu-ja": + return AURA2EBISU_JA; + case "aura-2-luna-en": + return AURA2LUNA_EN; case "aura-2-phoebe-en": return AURA2PHOEBE_EN; + case "aura-2-flavio-it": + return AURA2FLAVIO_IT; case "aura-2-diana-es": return AURA2DIANA_ES; case "aura-orion-en": return AURA_ORION_EN; - case "aura-2-andromeda-en": - return AURA2ANDROMEDA_EN; case "aura-2-athena-en": return AURA2ATHENA_EN; - case "aura-2-saturn-en": - return AURA2SATURN_EN; + case "aura-2-lars-nl": + return AURA2LARS_NL; + case "aura-2-fujin-ja": + return AURA2FUJIN_JA; case "aura-arcas-en": return AURA_ARCAS_EN; case "aura-2-theia-en": return AURA2THEIA_EN; - case "aura-2-iris-en": - return AURA2IRIS_EN; - case "aura-angus-en": - return AURA_ANGUS_EN; + case "aura-2-livia-it": + return AURA2LIVIA_IT; + case "aura-2-leda-nl": + return AURA2LEDA_NL; case "aura-2-jupiter-en": return AURA2JUPITER_EN; + case "aura-2-melia-it": + return AURA2MELIA_IT; case "aura-2-aquila-es": return AURA2AQUILA_ES; case "aura-2-cora-en": return AURA2CORA_EN; + case "aura-2-agustina-es": + return AURA2AGUSTINA_ES; + case "aura-2-roman-nl": + return AURA2ROMAN_NL; case "aura-2-cordelia-en": return AURA2CORDELIA_EN; case "aura-2-atlas-en": return AURA2ATLAS_EN; - case "aura-2-helena-en": - return AURA2HELENA_EN; - case "aura-stella-en": - return AURA_STELLA_EN; - case "aura-2-draco-en": - return AURA2DRACO_EN; + case "aura-2-viktoria-de": + return AURA2VIKTORIA_DE; case "aura-2-hyperion-en": return AURA2HYPERION_EN; case "aura-2-celeste-es": return AURA2CELESTE_ES; - case "aura-helios-en": - return AURA_HELIOS_EN; case "aura-2-pluto-en": return AURA2PLUTO_EN; - case "aura-2-janus-en": - return AURA2JANUS_EN; - case "aura-2-nestor-es": - return AURA2NESTOR_ES; + case "aura-2-sander-nl": + return AURA2SANDER_NL; case "aura-2-arcas-en": return AURA2ARCAS_EN; - case "aura-2-orion-en": - return AURA2ORION_EN; + case "aura-2-cesare-it": + return AURA2CESARE_IT; case "aura-athena-en": return AURA_ATHENA_EN; case "aura-2-odysseus-en": return AURA2ODYSSEUS_EN; case "aura-2-pandora-en": return AURA2PANDORA_EN; - case "aura-2-minerva-en": - return AURA2MINERVA_EN; - case "aura-2-alvaro-es": - return AURA2ALVARO_ES; - case "aura-perseus-en": - return AURA_PERSEUS_EN; - case "aura-2-vesta-en": - return AURA2VESTA_EN; case "aura-asteria-en": return AURA_ASTERIA_EN; - case "aura-2-zeus-en": - return AURA2ZEUS_EN; case "aura-2-electra-en": return AURA2ELECTRA_EN; - case "aura-2-orpheus-en": - return AURA2ORPHEUS_EN; case "aura-2-estrella-es": return AURA2ESTRELLA_ES; - case "aura-2-thalia-en": - return AURA2THALIA_EN; default: return new SpeakV1Model(Value.UNKNOWN, value); } } public enum Value { - AURA_ASTERIA_EN, + AURA_ANGUS_EN, - AURA_LUNA_EN, + AURA_ARCAS_EN, - AURA_STELLA_EN, + AURA_ASTERIA_EN, AURA_ATHENA_EN, + AURA_HELIOS_EN, + AURA_HERA_EN, + AURA_LUNA_EN, + AURA_ORION_EN, - AURA_ARCAS_EN, + AURA_ORPHEUS_EN, AURA_PERSEUS_EN, - AURA_ANGUS_EN, - - AURA_ORPHEUS_EN, - - AURA_HELIOS_EN, + AURA_STELLA_EN, AURA_ZEUS_EN, @@ -476,10 +716,10 @@ public enum Value { AURA2CALLISTA_EN, - AURA2CORDELIA_EN, - AURA2CORA_EN, + AURA2CORDELIA_EN, + AURA2DELIA_EN, AURA2DRACO_EN, @@ -538,51 +778,131 @@ public enum Value { AURA2ZEUS_EN, - AURA2SIRIO_ES, + AURA2AGUSTINA_ES, - AURA2NESTOR_ES, + AURA2ALVARO_ES, + + AURA2ANTONIA_ES, + + AURA2AQUILA_ES, AURA2CARINA_ES, AURA2CELESTE_ES, - AURA2ALVARO_ES, - AURA2DIANA_ES, - AURA2AQUILA_ES, + AURA2ESTRELLA_ES, + + AURA2GLORIA_ES, + + AURA2JAVIER_ES, + + AURA2LUCIANO_ES, + + AURA2NESTOR_ES, + + AURA2OLIVIA_ES, AURA2SELENA_ES, - AURA2ESTRELLA_ES, + AURA2SILVIA_ES, - AURA2JAVIER_ES, + AURA2SIRIO_ES, + + AURA2VALERIO_ES, + + AURA2AURELIA_DE, + + AURA2ELARA_DE, + + AURA2FABIAN_DE, + + AURA2JULIUS_DE, + + AURA2KARA_DE, + + AURA2LARA_DE, + + AURA2VIKTORIA_DE, + + AURA2BEATRIX_NL, + + AURA2CORNELIA_NL, + + AURA2DAPHNE_NL, + + AURA2HESTIA_NL, + + AURA2LARS_NL, + + AURA2LEDA_NL, + + AURA2RHEA_NL, + + AURA2ROMAN_NL, + + AURA2SANDER_NL, + + AURA2AGATHE_FR, + + AURA2HECTOR_FR, + + AURA2CESARE_IT, + + AURA2CINZIA_IT, + + AURA2DEMETRA_IT, + + AURA2DIONISIO_IT, + + AURA2ELIO_IT, + + AURA2FLAVIO_IT, + + AURA2LIVIA_IT, + + AURA2MAIA_IT, + + AURA2MELIA_IT, + + AURA2PERSEO_IT, + + AURA2AMA_JA, + + AURA2EBISU_JA, + + AURA2FUJIN_JA, + + AURA2IZANAMI_JA, + + AURA2UZUME_JA, UNKNOWN } public interface Visitor { - T visitAuraAsteriaEn(); + T visitAuraAngusEn(); - T visitAuraLunaEn(); + T visitAuraArcasEn(); - T visitAuraStellaEn(); + T visitAuraAsteriaEn(); T visitAuraAthenaEn(); + T visitAuraHeliosEn(); + T visitAuraHeraEn(); + T visitAuraLunaEn(); + T visitAuraOrionEn(); - T visitAuraArcasEn(); + T visitAuraOrpheusEn(); T visitAuraPerseusEn(); - T visitAuraAngusEn(); - - T visitAuraOrpheusEn(); - - T visitAuraHeliosEn(); + T visitAuraStellaEn(); T visitAuraZeusEn(); @@ -606,10 +926,10 @@ public interface Visitor { T visitAura2CallistaEn(); - T visitAura2CordeliaEn(); - T visitAura2CoraEn(); + T visitAura2CordeliaEn(); + T visitAura2DeliaEn(); T visitAura2DracoEn(); @@ -668,25 +988,105 @@ public interface Visitor { T visitAura2ZeusEn(); - T visitAura2SirioEs(); + T visitAura2AgustinaEs(); - T visitAura2NestorEs(); + T visitAura2AlvaroEs(); + + T visitAura2AntoniaEs(); + + T visitAura2AquilaEs(); T visitAura2CarinaEs(); T visitAura2CelesteEs(); - T visitAura2AlvaroEs(); - T visitAura2DianaEs(); - T visitAura2AquilaEs(); + T visitAura2EstrellaEs(); + + T visitAura2GloriaEs(); + + T visitAura2JavierEs(); + + T visitAura2LucianoEs(); + + T visitAura2NestorEs(); + + T visitAura2OliviaEs(); T visitAura2SelenaEs(); - T visitAura2EstrellaEs(); + T visitAura2SilviaEs(); - T visitAura2JavierEs(); + T visitAura2SirioEs(); + + T visitAura2ValerioEs(); + + T visitAura2AureliaDe(); + + T visitAura2ElaraDe(); + + T visitAura2FabianDe(); + + T visitAura2JuliusDe(); + + T visitAura2KaraDe(); + + T visitAura2LaraDe(); + + T visitAura2ViktoriaDe(); + + T visitAura2BeatrixNl(); + + T visitAura2CorneliaNl(); + + T visitAura2DaphneNl(); + + T visitAura2HestiaNl(); + + T visitAura2LarsNl(); + + T visitAura2LedaNl(); + + T visitAura2RheaNl(); + + T visitAura2RomanNl(); + + T visitAura2SanderNl(); + + T visitAura2AgatheFr(); + + T visitAura2HectorFr(); + + T visitAura2CesareIt(); + + T visitAura2CinziaIt(); + + T visitAura2DemetraIt(); + + T visitAura2DionisioIt(); + + T visitAura2ElioIt(); + + T visitAura2FlavioIt(); + + T visitAura2LiviaIt(); + + T visitAura2MaiaIt(); + + T visitAura2MeliaIt(); + + T visitAura2PerseoIt(); + + T visitAura2AmaJa(); + + T visitAura2EbisuJa(); + + T visitAura2FujinJa(); + + T visitAura2IzanamiJa(); + + T visitAura2UzumeJa(); T visitUnknown(String unknownType); } From c42e64cbbfd482dd45f17a881f92c6c62e95733f Mon Sep 17 00:00:00 2001 From: Greg Holmes Date: Mon, 20 Jul 2026 11:10:59 +0100 Subject: [PATCH 4/8] chore: re-apply manual patches after regen --- .fernignore | 30 +- .../java/com/deepgram/core/ClientOptions.java | 6 +- .../com/deepgram/core/ClientOptions.java.bak | 241 -------- .../core/ReconnectingWebSocketListener.java | 93 ++- .../ReconnectingWebSocketListener.java.bak | 545 ------------------ .../agent/v1/types/AgentV1AgentAudioDone.java | 8 + .../v1/types/AgentV1AgentAudioDone.java.bak | 86 --- .../agent/v1/types/AgentV1KeepAlive.java | 8 + .../agent/v1/types/AgentV1KeepAlive.java.bak | 86 --- .../agent/v1/types/AgentV1ListenUpdated.java | 8 + .../v1/types/AgentV1ListenUpdated.java.bak | 86 --- .../agent/v1/types/AgentV1PromptUpdated.java | 8 + .../v1/types/AgentV1PromptUpdated.java.bak | 86 --- .../v1/types/AgentV1SettingsApplied.java | 8 + .../v1/types/AgentV1SettingsApplied.java.bak | 86 --- .../agent/v1/types/AgentV1SpeakUpdated.java | 8 + .../v1/types/AgentV1SpeakUpdated.java.bak | 86 --- .../agent/v1/types/AgentV1ThinkUpdated.java | 8 + .../v1/types/AgentV1ThinkUpdated.java.bak | 86 --- .../v1/types/AgentV1UserStartedSpeaking.java | 8 + .../types/AgentV1UserStartedSpeaking.java.bak | 86 --- .../listen/v2/types/ListenV2CloseStream.java | 8 + .../v2/types/ListenV2CloseStream.java.bak | 86 --- .../v2/websocket/V2WebSocketClient.java | 10 +- .../v2/websocket/V2WebSocketClient.java.bak | 483 ---------------- .../speak/v2/types/SpeakV2Close.java | 8 + .../speak/v2/types/SpeakV2Close.java.bak | 86 --- .../speak/v2/types/SpeakV2Flush.java | 8 + .../speak/v2/types/SpeakV2Flush.java.bak | 86 --- .../speak/v2/websocket/V2WebSocketClient.java | 10 +- .../v2/websocket/V2WebSocketClient.java.bak | 507 ---------------- 31 files changed, 188 insertions(+), 2771 deletions(-) delete mode 100644 src/main/java/com/deepgram/core/ClientOptions.java.bak delete mode 100644 src/main/java/com/deepgram/core/ReconnectingWebSocketListener.java.bak delete mode 100644 src/main/java/com/deepgram/resources/agent/v1/types/AgentV1AgentAudioDone.java.bak delete mode 100644 src/main/java/com/deepgram/resources/agent/v1/types/AgentV1KeepAlive.java.bak delete mode 100644 src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ListenUpdated.java.bak delete mode 100644 src/main/java/com/deepgram/resources/agent/v1/types/AgentV1PromptUpdated.java.bak delete mode 100644 src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SettingsApplied.java.bak delete mode 100644 src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SpeakUpdated.java.bak delete mode 100644 src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ThinkUpdated.java.bak delete mode 100644 src/main/java/com/deepgram/resources/agent/v1/types/AgentV1UserStartedSpeaking.java.bak delete mode 100644 src/main/java/com/deepgram/resources/listen/v2/types/ListenV2CloseStream.java.bak delete mode 100644 src/main/java/com/deepgram/resources/listen/v2/websocket/V2WebSocketClient.java.bak delete mode 100644 src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Close.java.bak delete mode 100644 src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Flush.java.bak delete mode 100644 src/main/java/com/deepgram/resources/speak/v2/websocket/V2WebSocketClient.java.bak diff --git a/.fernignore b/.fernignore index d1507b2..b7c4722 100644 --- a/.fernignore +++ b/.fernignore @@ -14,7 +14,7 @@ src/main/java/com/deepgram/AsyncDeepgramClientBuilder.java # Contains User-Agent, X-Fern-SDK-Name, and X-Fern-SDK-Version headers # with // x-release-please-version comments for automated version bumps. # Fern regen overwrites these with incorrect SDK names and strips the markers. -src/main/java/com/deepgram/core/ClientOptions.java.bak +src/main/java/com/deepgram/core/ClientOptions.java # Transport abstraction (pluggable transport for SageMaker, etc.) src/main/java/com/deepgram/core/transport/ @@ -22,31 +22,31 @@ src/main/java/com/deepgram/core/transport/ # Bug fixes for maxRetries(0) semantics ("connect once, don't retry") and a # configurable connectionTimeoutMs on ReconnectOptions (was hardcoded 4000ms). # Pull this back out once the fixes are upstreamed into the Fern generator. -src/main/java/com/deepgram/core/ReconnectingWebSocketListener.java.bak +src/main/java/com/deepgram/core/ReconnectingWebSocketListener.java # Forward-compat patch: Fern's generated dispatcher routes any unrecognized message # type to the error handler ("Update your SDK version..."), which makes benign new # server control frames look fatal to deployed clients. Patched to a no-op (the raw # frame is still delivered via onMessage(String)); mirrors the JS/Python SDKs. Re-apply # after regen. Unfreeze once the generator stops treating unknown frames as errors. -src/main/java/com/deepgram/resources/speak/v2/websocket/V2WebSocketClient.java.bak -src/main/java/com/deepgram/resources/listen/v2/websocket/V2WebSocketClient.java.bak +src/main/java/com/deepgram/resources/speak/v2/websocket/V2WebSocketClient.java +src/main/java/com/deepgram/resources/listen/v2/websocket/V2WebSocketClient.java # Manual equals/hashCode contract fix: Fern generates equals() (all instances equal) but no # hashCode() for fields-less message types, violating the Object contract. We add a consistent # hashCode() to each. Unfreeze and drop these patches once the generator emits a matching # equals/hashCode pair for fields-less types (tracked as an upstream Fern request). -src/main/java/com/deepgram/resources/listen/v2/types/ListenV2CloseStream.java.bak -src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Close.java.bak -src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Flush.java.bak -src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ListenUpdated.java.bak -src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SpeakUpdated.java.bak -src/main/java/com/deepgram/resources/agent/v1/types/AgentV1AgentAudioDone.java.bak -src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SettingsApplied.java.bak -src/main/java/com/deepgram/resources/agent/v1/types/AgentV1UserStartedSpeaking.java.bak -src/main/java/com/deepgram/resources/agent/v1/types/AgentV1KeepAlive.java.bak -src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ThinkUpdated.java.bak -src/main/java/com/deepgram/resources/agent/v1/types/AgentV1PromptUpdated.java.bak +src/main/java/com/deepgram/resources/listen/v2/types/ListenV2CloseStream.java +src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Close.java +src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Flush.java +src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ListenUpdated.java +src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SpeakUpdated.java +src/main/java/com/deepgram/resources/agent/v1/types/AgentV1AgentAudioDone.java +src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SettingsApplied.java +src/main/java/com/deepgram/resources/agent/v1/types/AgentV1UserStartedSpeaking.java +src/main/java/com/deepgram/resources/agent/v1/types/AgentV1KeepAlive.java +src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ThinkUpdated.java +src/main/java/com/deepgram/resources/agent/v1/types/AgentV1PromptUpdated.java # Build and project configuration build.gradle diff --git a/src/main/java/com/deepgram/core/ClientOptions.java b/src/main/java/com/deepgram/core/ClientOptions.java index 094347e..0b070bd 100644 --- a/src/main/java/com/deepgram/core/ClientOptions.java +++ b/src/main/java/com/deepgram/core/ClientOptions.java @@ -41,10 +41,10 @@ private ClientOptions( this.headers.putAll(headers); this.headers.putAll(new HashMap() { { - put("User-Agent", "com.deepgram:deepgram-sdk/0.6.2"); + put("User-Agent", "com.deepgram:deepgram-java-sdk/0.6.1"); // x-release-please-version put("X-Fern-Language", "JAVA"); - put("X-Fern-SDK-Name", "com.deepgram.fern:api-sdk"); - put("X-Fern-SDK-Version", "0.6.2"); + put("X-Fern-SDK-Name", "com.deepgram:deepgram-java-sdk"); + put("X-Fern-SDK-Version", "0.6.1"); // x-release-please-version } }); this.headerSuppliers = headerSuppliers; diff --git a/src/main/java/com/deepgram/core/ClientOptions.java.bak b/src/main/java/com/deepgram/core/ClientOptions.java.bak deleted file mode 100644 index 0b070bd..0000000 --- a/src/main/java/com/deepgram/core/ClientOptions.java.bak +++ /dev/null @@ -1,241 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.deepgram.core; - -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.TimeUnit; -import java.util.function.Supplier; -import okhttp3.OkHttpClient; - -public final class ClientOptions { - private final Environment environment; - - private final Map headers; - - private final Map> headerSuppliers; - - private final OkHttpClient httpClient; - - private final int timeout; - - private final int maxRetries; - - private final Optional webSocketFactory; - - private final Optional logging; - - private ClientOptions( - Environment environment, - Map headers, - Map> headerSuppliers, - OkHttpClient httpClient, - int timeout, - int maxRetries, - Optional webSocketFactory, - Optional logging) { - this.environment = environment; - this.headers = new HashMap<>(); - this.headers.putAll(headers); - this.headers.putAll(new HashMap() { - { - put("User-Agent", "com.deepgram:deepgram-java-sdk/0.6.1"); // x-release-please-version - put("X-Fern-Language", "JAVA"); - put("X-Fern-SDK-Name", "com.deepgram:deepgram-java-sdk"); - put("X-Fern-SDK-Version", "0.6.1"); // x-release-please-version - } - }); - this.headerSuppliers = headerSuppliers; - this.httpClient = httpClient; - this.timeout = timeout; - this.maxRetries = maxRetries; - this.webSocketFactory = webSocketFactory; - this.logging = logging; - } - - public Environment environment() { - return this.environment; - } - - public Map headers(RequestOptions requestOptions) { - Map values = new HashMap<>(this.headers); - headerSuppliers.forEach((key, supplier) -> { - values.put(key, supplier.get()); - }); - if (requestOptions != null) { - values.putAll(requestOptions.getHeaders()); - } - return values; - } - - public int timeout(RequestOptions requestOptions) { - if (requestOptions == null) { - return this.timeout; - } - return requestOptions.getTimeout().orElse(this.timeout); - } - - public OkHttpClient httpClient() { - return this.httpClient; - } - - public OkHttpClient httpClientWithTimeout(RequestOptions requestOptions) { - if (requestOptions == null) { - return this.httpClient; - } - return this.httpClient - .newBuilder() - .callTimeout(requestOptions.getTimeout().get(), requestOptions.getTimeoutTimeUnit()) - .connectTimeout(0, TimeUnit.SECONDS) - .writeTimeout(0, TimeUnit.SECONDS) - .readTimeout(0, TimeUnit.SECONDS) - .build(); - } - - public int maxRetries() { - return this.maxRetries; - } - - public Optional webSocketFactory() { - return this.webSocketFactory; - } - - public Optional logging() { - return this.logging; - } - - public static Builder builder() { - return new Builder(); - } - - public static class Builder { - private Environment environment; - - private final Map headers = new HashMap<>(); - - private final Map> headerSuppliers = new HashMap<>(); - - private int maxRetries = 2; - - private Optional timeout = Optional.empty(); - - private OkHttpClient httpClient = null; - - private Optional logging = Optional.empty(); - - private Optional webSocketFactory = Optional.empty(); - - public Builder environment(Environment environment) { - this.environment = environment; - return this; - } - - public Builder addHeader(String key, String value) { - this.headers.put(key, value); - return this; - } - - public Builder addHeader(String key, Supplier value) { - this.headerSuppliers.put(key, value); - return this; - } - - /** - * Override the timeout in seconds. Defaults to 60 seconds. - */ - public Builder timeout(int timeout) { - this.timeout = Optional.of(timeout); - return this; - } - - /** - * Override the timeout in seconds. Defaults to 60 seconds. - */ - public Builder timeout(Optional timeout) { - this.timeout = timeout; - return this; - } - - /** - * Override the maximum number of retries. Defaults to 2 retries. - */ - public Builder maxRetries(int maxRetries) { - this.maxRetries = maxRetries; - return this; - } - - public Builder httpClient(OkHttpClient httpClient) { - this.httpClient = httpClient; - return this; - } - - /** - * Set a custom WebSocketFactory for creating WebSocket connections. - */ - public Builder webSocketFactory(WebSocketFactory webSocketFactory) { - this.webSocketFactory = Optional.of(webSocketFactory); - return this; - } - - /** - * Configure logging for the SDK. Silent by default — no log output unless explicitly configured. - */ - public Builder logging(LogConfig logging) { - this.logging = Optional.of(logging); - return this; - } - - public ClientOptions build() { - OkHttpClient.Builder httpClientBuilder = - this.httpClient != null ? this.httpClient.newBuilder() : new OkHttpClient.Builder(); - - if (this.httpClient != null) { - timeout.ifPresent(timeout -> httpClientBuilder - .callTimeout(timeout, TimeUnit.SECONDS) - .connectTimeout(0, TimeUnit.SECONDS) - .writeTimeout(0, TimeUnit.SECONDS) - .readTimeout(0, TimeUnit.SECONDS)); - } else { - httpClientBuilder - .callTimeout(this.timeout.orElse(60), TimeUnit.SECONDS) - .connectTimeout(0, TimeUnit.SECONDS) - .writeTimeout(0, TimeUnit.SECONDS) - .readTimeout(0, TimeUnit.SECONDS) - .addInterceptor(new RetryInterceptor(this.maxRetries)); - } - - Logger logger = Logger.from(this.logging); - httpClientBuilder.addInterceptor(new LoggingInterceptor(logger)); - - this.httpClient = httpClientBuilder.build(); - this.timeout = Optional.of(httpClient.callTimeoutMillis() / 1000); - - return new ClientOptions( - environment, - headers, - headerSuppliers, - httpClient, - this.timeout.get(), - this.maxRetries, - this.webSocketFactory, - this.logging); - } - - /** - * Create a new Builder initialized with values from an existing ClientOptions - */ - public static Builder from(ClientOptions clientOptions) { - Builder builder = new Builder(); - builder.environment = clientOptions.environment(); - builder.timeout = Optional.of(clientOptions.timeout(null)); - builder.httpClient = clientOptions.httpClient(); - builder.headers.putAll(clientOptions.headers); - builder.headerSuppliers.putAll(clientOptions.headerSuppliers); - builder.maxRetries = clientOptions.maxRetries(); - builder.logging = clientOptions.logging(); - return builder; - } - } -} diff --git a/src/main/java/com/deepgram/core/ReconnectingWebSocketListener.java b/src/main/java/com/deepgram/core/ReconnectingWebSocketListener.java index 0ca455a..a533068 100644 --- a/src/main/java/com/deepgram/core/ReconnectingWebSocketListener.java +++ b/src/main/java/com/deepgram/core/ReconnectingWebSocketListener.java @@ -25,14 +25,15 @@ * Provides production-ready resilience for WebSocket connections. */ public abstract class ReconnectingWebSocketListener extends WebSocketListener { - private final long minReconnectionDelayMs; - - private final long maxReconnectionDelayMs; - - private final double reconnectionDelayGrowFactor; - - private final int maxRetries; - + // Overridable options are held behind a single volatile reference (not five separate volatile + // fields) so {@link #applyOptionsOverride} swaps them atomically — a reader that snapshots the + // reference once sees a mutually-consistent set (e.g. getNextDelay() cannot observe a new min + // paired with an old max). Rewiring is used by {@code TransportWebSocketFactory} to honour + // {@code DeepgramTransportFactory.reconnectOptions()} without editing the generated WS clients. + private volatile ReconnectOptions activeOptions; + + // maxEnqueuedMessages is fixed at construction (the queue is sized once) and intentionally not + // overridable, so it stays a separate final field rather than being read from activeOptions. private final int maxEnqueuedMessages; private final AtomicInteger retryCount = new AtomicInteger(0); @@ -61,21 +62,42 @@ public abstract class ReconnectingWebSocketListener extends WebSocketListener { */ public ReconnectingWebSocketListener( ReconnectingWebSocketListener.ReconnectOptions options, Supplier connectionSupplier) { - this.minReconnectionDelayMs = options.minReconnectionDelayMs; - this.maxReconnectionDelayMs = options.maxReconnectionDelayMs; - this.reconnectionDelayGrowFactor = options.reconnectionDelayGrowFactor; - this.maxRetries = options.maxRetries; + this.activeOptions = options; this.maxEnqueuedMessages = options.maxEnqueuedMessages; this.connectionSupplier = connectionSupplier; } + /** + * Replaces the option-derived parameters on this listener at runtime. Used by + * {@code TransportWebSocketFactory} to apply {@code DeepgramTransportFactory.reconnectOptions()} + * without requiring edits to the generated per-resource WebSocket clients. {@code maxEnqueuedMessages} + * is intentionally not overridden — the message queue is sized at construction. + * + *

Thread-safety: the override is a single atomic write to a {@code volatile} reference, so a + * reader that snapshots {@link #activeOptions} once sees a mutually-consistent set of values + * (never a new min paired with an old max). The initial connect() call may have already started + * before the override lands, so for the very first attempt the original options apply; the + * override takes effect from the next attempt onwards. For the SageMaker storm-suppression case + * ({@code maxRetries(0)}) this is fine because the initial attempt's gate + * ({@code retryCount > maxRetries} with {@code retryCount=0}) always passes regardless. + * + * @param options replacement options; {@code null} is a no-op. + */ + public void applyOptionsOverride(ReconnectOptions options) { + if (options == null) { + return; + } + this.activeOptions = options; + } + /** * Initiates a WebSocket connection with automatic reconnection enabled. * * Connection behavior: - * - Times out after 4000 milliseconds + * - Times out after {@code ReconnectOptions.connectionTimeoutMs} (default 4000ms) * - Thread-safe via atomic lock (returns immediately if connection in progress) - * - Retry count not incremented for initial connection attempt + * - {@code maxRetries} counts retries only — the initial attempt always proceeds. + * {@code maxRetries(0)} means "connect once, don't retry" (not "refuse to connect"). * * Error handling: * - TimeoutException: Includes retry attempt context @@ -86,20 +108,26 @@ public void connect() { if (!connectLock.compareAndSet(false, true)) { return; } - if (retryCount.get() >= maxRetries) { + // Snapshot the overridable options once so the gate and timeout below use a consistent set. + ReconnectOptions opts = this.activeOptions; + // retryCount is incremented inside scheduleReconnect() before re-entering connect(), + // so on the initial call retryCount == 0 and we always proceed. The cap applies to + // retries only — maxRetries(0) blocks retries but allows the initial attempt. + if (retryCount.get() > opts.maxRetries) { connectLock.set(false); return; } try { CompletableFuture connectionFuture = CompletableFuture.supplyAsync(connectionSupplier); try { - webSocket = connectionFuture.get(4000, MILLISECONDS); + webSocket = connectionFuture.get(opts.connectionTimeoutMs, MILLISECONDS); } catch (TimeoutException e) { connectionFuture.cancel(true); TimeoutException timeoutError = - new TimeoutException("WebSocket connection timeout after " + 4000 + " milliseconds" + new TimeoutException("WebSocket connection timeout after " + opts.connectionTimeoutMs + + " milliseconds" + (retryCount.get() > 0 - ? " (retry attempt #" + retryCount.get() + ? " (retry attempt #" + retryCount.get() + ")" : " (initial connection attempt)")); onWebSocketFailure(null, timeoutError, null); if (shouldReconnect.get()) { @@ -314,11 +342,14 @@ public void onClosed(WebSocket webSocket, int code, String reason) { * - 2+ = exponential backoff up to maxReconnectionDelayMs */ private long getNextDelay() { + // Single volatile read → a consistent (min, growFactor, max) snapshot even if + // applyOptionsOverride swaps the options concurrently. + ReconnectOptions opts = this.activeOptions; if (retryCount.get() == 1) { - return minReconnectionDelayMs; + return opts.minReconnectionDelayMs; } - long delay = (long) (minReconnectionDelayMs * Math.pow(reconnectionDelayGrowFactor, retryCount.get() - 1)); - return Math.min(delay, maxReconnectionDelayMs); + long delay = (long) (opts.minReconnectionDelayMs * Math.pow(opts.reconnectionDelayGrowFactor, retryCount.get() - 1)); + return Math.min(delay, opts.maxReconnectionDelayMs); } /** @@ -399,12 +430,15 @@ public static final class ReconnectOptions { public final int maxEnqueuedMessages; + public final long connectionTimeoutMs; + private ReconnectOptions(Builder builder) { this.minReconnectionDelayMs = builder.minReconnectionDelayMs; this.maxReconnectionDelayMs = builder.maxReconnectionDelayMs; this.reconnectionDelayGrowFactor = builder.reconnectionDelayGrowFactor; this.maxRetries = builder.maxRetries; this.maxEnqueuedMessages = builder.maxEnqueuedMessages; + this.connectionTimeoutMs = builder.connectionTimeoutMs; } public static Builder builder() { @@ -422,12 +456,15 @@ public static final class Builder { private int maxEnqueuedMessages; + private long connectionTimeoutMs; + public Builder() { this.minReconnectionDelayMs = 1000; this.maxReconnectionDelayMs = 10000; this.reconnectionDelayGrowFactor = 1.3; this.maxRetries = 2147483647; this.maxEnqueuedMessages = 1000; + this.connectionTimeoutMs = 4000; } public Builder minReconnectionDelayMs(long minReconnectionDelayMs) { @@ -455,6 +492,16 @@ public Builder maxEnqueuedMessages(int maxEnqueuedMessages) { return this; } + /** + * Sets the per-attempt connection timeout in milliseconds. Defaults to {@code 4000}. + * Each call to {@link ReconnectingWebSocketListener#connect()} will wait at most + * this long for the underlying WebSocket factory to produce a connected socket. + */ + public Builder connectionTimeoutMs(long connectionTimeoutMs) { + this.connectionTimeoutMs = connectionTimeoutMs; + return this; + } + /** * Builds the ReconnectOptions with validation. * @@ -463,6 +510,7 @@ public Builder maxEnqueuedMessages(int maxEnqueuedMessages) { * - minReconnectionDelayMs <= maxReconnectionDelayMs * - reconnectionDelayGrowFactor >= 1.0 * - maxRetries and maxEnqueuedMessages are non-negative + * - connectionTimeoutMs is positive * * @return The validated ReconnectOptions instance * @throws IllegalArgumentException if configuration is invalid @@ -487,6 +535,9 @@ public ReconnectOptions build() { if (maxEnqueuedMessages < 0) { throw new IllegalArgumentException("maxEnqueuedMessages must be non-negative"); } + if (connectionTimeoutMs <= 0) { + throw new IllegalArgumentException("connectionTimeoutMs must be positive"); + } return new ReconnectOptions(this); } } diff --git a/src/main/java/com/deepgram/core/ReconnectingWebSocketListener.java.bak b/src/main/java/com/deepgram/core/ReconnectingWebSocketListener.java.bak deleted file mode 100644 index a533068..0000000 --- a/src/main/java/com/deepgram/core/ReconnectingWebSocketListener.java.bak +++ /dev/null @@ -1,545 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.deepgram.core; - -import static java.util.concurrent.TimeUnit.*; - -import java.util.ArrayList; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Supplier; -import okhttp3.Response; -import okhttp3.WebSocket; -import okhttp3.WebSocketListener; -import okio.ByteString; - -/** - * WebSocketListener with automatic reconnection, exponential backoff, and message queuing. - * Provides production-ready resilience for WebSocket connections. - */ -public abstract class ReconnectingWebSocketListener extends WebSocketListener { - // Overridable options are held behind a single volatile reference (not five separate volatile - // fields) so {@link #applyOptionsOverride} swaps them atomically — a reader that snapshots the - // reference once sees a mutually-consistent set (e.g. getNextDelay() cannot observe a new min - // paired with an old max). Rewiring is used by {@code TransportWebSocketFactory} to honour - // {@code DeepgramTransportFactory.reconnectOptions()} without editing the generated WS clients. - private volatile ReconnectOptions activeOptions; - - // maxEnqueuedMessages is fixed at construction (the queue is sized once) and intentionally not - // overridable, so it stays a separate final field rather than being read from activeOptions. - private final int maxEnqueuedMessages; - - private final AtomicInteger retryCount = new AtomicInteger(0); - - private final AtomicBoolean connectLock = new AtomicBoolean(false); - - private final AtomicBoolean shouldReconnect = new AtomicBoolean(true); - - protected volatile WebSocket webSocket; - - private volatile long connectionEstablishedTime = 0L; - - private final ConcurrentLinkedQueue messageQueue = new ConcurrentLinkedQueue<>(); - - private final ConcurrentLinkedQueue binaryMessageQueue = new ConcurrentLinkedQueue<>(); - - private final ScheduledExecutorService reconnectExecutor = Executors.newSingleThreadScheduledExecutor(); - - private final Supplier connectionSupplier; - - /** - * Creates a new reconnecting WebSocket listener. - * - * @param options Reconnection configuration options - * @param connectionSupplier Supplier that creates new WebSocket connections - */ - public ReconnectingWebSocketListener( - ReconnectingWebSocketListener.ReconnectOptions options, Supplier connectionSupplier) { - this.activeOptions = options; - this.maxEnqueuedMessages = options.maxEnqueuedMessages; - this.connectionSupplier = connectionSupplier; - } - - /** - * Replaces the option-derived parameters on this listener at runtime. Used by - * {@code TransportWebSocketFactory} to apply {@code DeepgramTransportFactory.reconnectOptions()} - * without requiring edits to the generated per-resource WebSocket clients. {@code maxEnqueuedMessages} - * is intentionally not overridden — the message queue is sized at construction. - * - *

Thread-safety: the override is a single atomic write to a {@code volatile} reference, so a - * reader that snapshots {@link #activeOptions} once sees a mutually-consistent set of values - * (never a new min paired with an old max). The initial connect() call may have already started - * before the override lands, so for the very first attempt the original options apply; the - * override takes effect from the next attempt onwards. For the SageMaker storm-suppression case - * ({@code maxRetries(0)}) this is fine because the initial attempt's gate - * ({@code retryCount > maxRetries} with {@code retryCount=0}) always passes regardless. - * - * @param options replacement options; {@code null} is a no-op. - */ - public void applyOptionsOverride(ReconnectOptions options) { - if (options == null) { - return; - } - this.activeOptions = options; - } - - /** - * Initiates a WebSocket connection with automatic reconnection enabled. - * - * Connection behavior: - * - Times out after {@code ReconnectOptions.connectionTimeoutMs} (default 4000ms) - * - Thread-safe via atomic lock (returns immediately if connection in progress) - * - {@code maxRetries} counts retries only — the initial attempt always proceeds. - * {@code maxRetries(0)} means "connect once, don't retry" (not "refuse to connect"). - * - * Error handling: - * - TimeoutException: Includes retry attempt context - * - InterruptedException: Preserves thread interruption status - * - ExecutionException: Extracts actual cause and adds context - */ - public void connect() { - if (!connectLock.compareAndSet(false, true)) { - return; - } - // Snapshot the overridable options once so the gate and timeout below use a consistent set. - ReconnectOptions opts = this.activeOptions; - // retryCount is incremented inside scheduleReconnect() before re-entering connect(), - // so on the initial call retryCount == 0 and we always proceed. The cap applies to - // retries only — maxRetries(0) blocks retries but allows the initial attempt. - if (retryCount.get() > opts.maxRetries) { - connectLock.set(false); - return; - } - try { - CompletableFuture connectionFuture = CompletableFuture.supplyAsync(connectionSupplier); - try { - webSocket = connectionFuture.get(opts.connectionTimeoutMs, MILLISECONDS); - } catch (TimeoutException e) { - connectionFuture.cancel(true); - TimeoutException timeoutError = - new TimeoutException("WebSocket connection timeout after " + opts.connectionTimeoutMs - + " milliseconds" - + (retryCount.get() > 0 - ? " (retry attempt #" + retryCount.get() + ")" - : " (initial connection attempt)")); - onWebSocketFailure(null, timeoutError, null); - if (shouldReconnect.get()) { - scheduleReconnect(); - } - } catch (InterruptedException e) { - connectionFuture.cancel(true); - Thread.currentThread().interrupt(); - InterruptedException interruptError = new InterruptedException("WebSocket connection interrupted" - + (retryCount.get() > 0 - ? " during retry attempt #" + retryCount.get() - : " during initial connection")); - interruptError.initCause(e); - onWebSocketFailure(null, interruptError, null); - } catch (ExecutionException e) { - Throwable cause = e.getCause() != null ? e.getCause() : e; - String context = retryCount.get() > 0 - ? "WebSocket connection failed during retry attempt #" + retryCount.get() - : "WebSocket connection failed during initial attempt"; - RuntimeException wrappedException = new RuntimeException( - context + ": " + cause.getClass().getSimpleName() + ": " + cause.getMessage()); - wrappedException.initCause(cause); - onWebSocketFailure(null, wrappedException, null); - if (shouldReconnect.get()) { - scheduleReconnect(); - } - } - } finally { - connectLock.set(false); - } - } - - /** - * Disconnects the WebSocket and disables automatic reconnection. - * - * This method: - * - Disables automatic reconnection - * - Clears queued messages to prevent stale data - * - Closes the WebSocket with standard close code 1000 - * - Properly shuts down the reconnect executor to prevent thread leaks - * - Waits up to 5 seconds for executor termination - */ - public void disconnect() { - shouldReconnect.set(false); - messageQueue.clear(); - binaryMessageQueue.clear(); - if (webSocket != null) { - webSocket.close(1000, "Client disconnecting"); - } - reconnectExecutor.shutdown(); - try { - if (!reconnectExecutor.awaitTermination(5, SECONDS)) { - reconnectExecutor.shutdownNow(); - } - } catch (InterruptedException e) { - reconnectExecutor.shutdownNow(); - Thread.currentThread().interrupt(); - } - } - - /** - * Sends a message or queues it if not connected. - * - * Thread-safe: Synchronized to prevent race conditions with flushMessageQueue(). - * - * Behavior: - * - If connected: Attempts direct send, queues if buffer full - * - If disconnected: Queues message up to maxEnqueuedMessages limit - * - If queue full: Message is dropped - * - * @param message The message to send - * @return true if sent immediately, false if queued or dropped - */ - public synchronized boolean send(String message) { - WebSocket ws = webSocket; - if (ws != null) { - boolean sent = ws.send(message); - if (!sent && messageQueue.size() < maxEnqueuedMessages) { - messageQueue.offer(message); - return false; - } - return sent; - } else { - if (messageQueue.size() < maxEnqueuedMessages) { - messageQueue.offer(message); - return false; - } - return false; - } - } - - /** - * Sends binary data or queues it if not connected. - * - * Thread-safe: Synchronized to prevent race conditions with flushMessageQueue(). - * - * Behavior: - * - If connected: Attempts direct send, queues if buffer full - * - If disconnected: Queues data up to maxEnqueuedMessages limit - * - If queue full: Data is dropped - * - * @param data The binary data to send - * @return true if sent immediately, false if queued or dropped - */ - public synchronized boolean sendBinary(ByteString data) { - WebSocket ws = webSocket; - if (ws != null) { - boolean sent = ws.send(data); - if (!sent && binaryMessageQueue.size() < maxEnqueuedMessages) { - binaryMessageQueue.offer(data); - return false; - } - return sent; - } else { - if (binaryMessageQueue.size() < maxEnqueuedMessages) { - binaryMessageQueue.offer(data); - return false; - } - return false; - } - } - - /** - * Gets the current WebSocket instance. - * Thread-safe method to access the WebSocket connection. - * @return the WebSocket or null if not connected - */ - public WebSocket getWebSocket() { - return webSocket; - } - - /** - * @hidden - */ - @Override - public void onOpen(WebSocket webSocket, Response response) { - this.webSocket = webSocket; - connectionEstablishedTime = System.currentTimeMillis(); - retryCount.set(0); - flushMessageQueue(); - onWebSocketOpen(webSocket, response); - } - - @Override - public void onMessage(WebSocket webSocket, String text) { - onWebSocketMessage(webSocket, text); - } - - @Override - public void onMessage(WebSocket webSocket, ByteString bytes) { - onWebSocketBinaryMessage(webSocket, bytes); - } - - /** - * @hidden - */ - @Override - public void onFailure(WebSocket webSocket, Throwable t, Response response) { - this.webSocket = null; - long uptime = 0L; - if (connectionEstablishedTime > 0) { - uptime = System.currentTimeMillis() - connectionEstablishedTime; - if (uptime >= 5000) { - retryCount.set(0); - } - } - connectionEstablishedTime = 0L; - Throwable enhancedError = t; - if (t != null) { - String errorContext = "WebSocket connection failed"; - if (uptime > 0) { - errorContext += " after " + (uptime / 1000) + " seconds"; - } - if (response != null) { - errorContext += " with HTTP " + response.code() + " " + response.message(); - } - enhancedError = - new RuntimeException(errorContext + ": " + t.getClass().getSimpleName() + ": " + t.getMessage()); - enhancedError.initCause(t); - } - onWebSocketFailure(webSocket, enhancedError, response); - if (shouldReconnect.get()) { - scheduleReconnect(); - } - } - - /** - * @hidden - */ - @Override - public void onClosed(WebSocket webSocket, int code, String reason) { - this.webSocket = null; - if (connectionEstablishedTime > 0) { - long uptime = System.currentTimeMillis() - connectionEstablishedTime; - if (uptime >= 5000) { - retryCount.set(0); - } - } - connectionEstablishedTime = 0L; - onWebSocketClosed(webSocket, code, reason); - if (code != 1000 && shouldReconnect.get()) { - scheduleReconnect(); - } - } - - /** - * Calculates the next reconnection delay using exponential backoff. - * - * Uses 0-based retry count where: - * - 0 = initial connection (not used by this method) - * - 1 = first retry (returns minReconnectionDelayMs) - * - 2+ = exponential backoff up to maxReconnectionDelayMs - */ - private long getNextDelay() { - // Single volatile read → a consistent (min, growFactor, max) snapshot even if - // applyOptionsOverride swaps the options concurrently. - ReconnectOptions opts = this.activeOptions; - if (retryCount.get() == 1) { - return opts.minReconnectionDelayMs; - } - long delay = (long) (opts.minReconnectionDelayMs * Math.pow(opts.reconnectionDelayGrowFactor, retryCount.get() - 1)); - return Math.min(delay, opts.maxReconnectionDelayMs); - } - - /** - * Schedules a reconnection attempt with appropriate delay. - * Increments retry count and uses exponential backoff. - */ - private void scheduleReconnect() { - retryCount.incrementAndGet(); - long delay = getNextDelay(); - reconnectExecutor.schedule(this::connect, delay, MILLISECONDS); - } - - /** - * Sends all queued messages after reconnection. - * - * Thread-safe: Synchronized to prevent race conditions with send() method. - * - * Algorithm: - * 1. Drains queue into temporary list to avoid holding lock during sends - * 2. Attempts to send each message in order - * 3. If any send fails, re-queues that message and all subsequent messages - * 4. Preserves message ordering during re-queueing - * 5. Repeats for binary message queue - */ - private synchronized void flushMessageQueue() { - WebSocket ws = webSocket; - if (ws != null) { - ArrayList tempQueue = new ArrayList<>(); - String message; - while ((message = messageQueue.poll()) != null) { - tempQueue.add(message); - } - for (int i = 0; i < tempQueue.size(); i++) { - if (!ws.send(tempQueue.get(i))) { - for (int j = i; j < tempQueue.size(); j++) { - messageQueue.offer(tempQueue.get(j)); - } - break; - } - } - ArrayList tempBinaryQueue = new ArrayList<>(); - ByteString binaryMsg; - while ((binaryMsg = binaryMessageQueue.poll()) != null) { - tempBinaryQueue.add(binaryMsg); - } - for (int i = 0; i < tempBinaryQueue.size(); i++) { - if (!ws.send(tempBinaryQueue.get(i))) { - for (int j = i; j < tempBinaryQueue.size(); j++) { - binaryMessageQueue.offer(tempBinaryQueue.get(j)); - } - break; - } - } - } - } - - protected abstract void onWebSocketOpen(WebSocket webSocket, Response response); - - protected abstract void onWebSocketMessage(WebSocket webSocket, String text); - - protected abstract void onWebSocketBinaryMessage(WebSocket webSocket, ByteString bytes); - - protected abstract void onWebSocketFailure(WebSocket webSocket, Throwable t, Response response); - - protected abstract void onWebSocketClosed(WebSocket webSocket, int code, String reason); - - /** - * Configuration options for automatic reconnection. - */ - public static final class ReconnectOptions { - public final long minReconnectionDelayMs; - - public final long maxReconnectionDelayMs; - - public final double reconnectionDelayGrowFactor; - - public final int maxRetries; - - public final int maxEnqueuedMessages; - - public final long connectionTimeoutMs; - - private ReconnectOptions(Builder builder) { - this.minReconnectionDelayMs = builder.minReconnectionDelayMs; - this.maxReconnectionDelayMs = builder.maxReconnectionDelayMs; - this.reconnectionDelayGrowFactor = builder.reconnectionDelayGrowFactor; - this.maxRetries = builder.maxRetries; - this.maxEnqueuedMessages = builder.maxEnqueuedMessages; - this.connectionTimeoutMs = builder.connectionTimeoutMs; - } - - public static Builder builder() { - return new Builder(); - } - - public static final class Builder { - private long minReconnectionDelayMs; - - private long maxReconnectionDelayMs; - - private double reconnectionDelayGrowFactor; - - private int maxRetries; - - private int maxEnqueuedMessages; - - private long connectionTimeoutMs; - - public Builder() { - this.minReconnectionDelayMs = 1000; - this.maxReconnectionDelayMs = 10000; - this.reconnectionDelayGrowFactor = 1.3; - this.maxRetries = 2147483647; - this.maxEnqueuedMessages = 1000; - this.connectionTimeoutMs = 4000; - } - - public Builder minReconnectionDelayMs(long minReconnectionDelayMs) { - this.minReconnectionDelayMs = minReconnectionDelayMs; - return this; - } - - public Builder maxReconnectionDelayMs(long maxReconnectionDelayMs) { - this.maxReconnectionDelayMs = maxReconnectionDelayMs; - return this; - } - - public Builder reconnectionDelayGrowFactor(double reconnectionDelayGrowFactor) { - this.reconnectionDelayGrowFactor = reconnectionDelayGrowFactor; - return this; - } - - public Builder maxRetries(int maxRetries) { - this.maxRetries = maxRetries; - return this; - } - - public Builder maxEnqueuedMessages(int maxEnqueuedMessages) { - this.maxEnqueuedMessages = maxEnqueuedMessages; - return this; - } - - /** - * Sets the per-attempt connection timeout in milliseconds. Defaults to {@code 4000}. - * Each call to {@link ReconnectingWebSocketListener#connect()} will wait at most - * this long for the underlying WebSocket factory to produce a connected socket. - */ - public Builder connectionTimeoutMs(long connectionTimeoutMs) { - this.connectionTimeoutMs = connectionTimeoutMs; - return this; - } - - /** - * Builds the ReconnectOptions with validation. - * - * Validates that: - * - All delay values are positive - * - minReconnectionDelayMs <= maxReconnectionDelayMs - * - reconnectionDelayGrowFactor >= 1.0 - * - maxRetries and maxEnqueuedMessages are non-negative - * - connectionTimeoutMs is positive - * - * @return The validated ReconnectOptions instance - * @throws IllegalArgumentException if configuration is invalid - */ - public ReconnectOptions build() { - if (minReconnectionDelayMs <= 0) { - throw new IllegalArgumentException("minReconnectionDelayMs must be positive"); - } - if (maxReconnectionDelayMs <= 0) { - throw new IllegalArgumentException("maxReconnectionDelayMs must be positive"); - } - if (minReconnectionDelayMs > maxReconnectionDelayMs) { - throw new IllegalArgumentException("minReconnectionDelayMs (" + minReconnectionDelayMs - + ") must not exceed maxReconnectionDelayMs (" + maxReconnectionDelayMs + ")"); - } - if (reconnectionDelayGrowFactor < 1.0) { - throw new IllegalArgumentException("reconnectionDelayGrowFactor must be >= 1.0"); - } - if (maxRetries < 0) { - throw new IllegalArgumentException("maxRetries must be non-negative"); - } - if (maxEnqueuedMessages < 0) { - throw new IllegalArgumentException("maxEnqueuedMessages must be non-negative"); - } - if (connectionTimeoutMs <= 0) { - throw new IllegalArgumentException("connectionTimeoutMs must be positive"); - } - return new ReconnectOptions(this); - } - } - } -} 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 71825ed..41af522 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 @@ -36,6 +36,14 @@ public boolean equals(Object other) { return other instanceof AgentV1AgentAudioDone; } + @java.lang.Override + public int hashCode() { + // Manual patch: Fern generates equals() (all instances of this fields-less message + // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a + // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. + return getClass().hashCode(); + } + @JsonAnyGetter public Map getAdditionalProperties() { return this.additionalProperties; diff --git a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1AgentAudioDone.java.bak b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1AgentAudioDone.java.bak deleted file mode 100644 index 41af522..0000000 --- a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1AgentAudioDone.java.bak +++ /dev/null @@ -1,86 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.deepgram.resources.agent.v1.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.databind.annotation.JsonDeserialize; -import java.util.HashMap; -import java.util.Map; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = AgentV1AgentAudioDone.Builder.class) -public final class AgentV1AgentAudioDone { - private final Map additionalProperties; - - private AgentV1AgentAudioDone(Map additionalProperties) { - this.additionalProperties = additionalProperties; - } - - /** - * @return Message type identifier indicating the agent has finished sending audio - */ - @JsonProperty("type") - public String getType() { - return "AgentAudioDone"; - } - - @java.lang.Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof AgentV1AgentAudioDone; - } - - @java.lang.Override - public int hashCode() { - // Manual patch: Fern generates equals() (all instances of this fields-less message - // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a - // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. - return getClass().hashCode(); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - @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 { - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(AgentV1AgentAudioDone other) { - return this; - } - - public AgentV1AgentAudioDone build() { - return new AgentV1AgentAudioDone(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/resources/agent/v1/types/AgentV1KeepAlive.java b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1KeepAlive.java index 7842266..083578b 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 @@ -36,6 +36,14 @@ public boolean equals(Object other) { return other instanceof AgentV1KeepAlive; } + @java.lang.Override + public int hashCode() { + // Manual patch: Fern generates equals() (all instances of this fields-less message + // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a + // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. + return getClass().hashCode(); + } + @JsonAnyGetter public Map getAdditionalProperties() { return this.additionalProperties; diff --git a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1KeepAlive.java.bak b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1KeepAlive.java.bak deleted file mode 100644 index 083578b..0000000 --- a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1KeepAlive.java.bak +++ /dev/null @@ -1,86 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.deepgram.resources.agent.v1.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.databind.annotation.JsonDeserialize; -import java.util.HashMap; -import java.util.Map; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = AgentV1KeepAlive.Builder.class) -public final class AgentV1KeepAlive { - private final Map additionalProperties; - - private AgentV1KeepAlive(Map additionalProperties) { - this.additionalProperties = additionalProperties; - } - - /** - * @return Message type identifier - */ - @JsonProperty("type") - public String getType() { - return "KeepAlive"; - } - - @java.lang.Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof AgentV1KeepAlive; - } - - @java.lang.Override - public int hashCode() { - // Manual patch: Fern generates equals() (all instances of this fields-less message - // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a - // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. - return getClass().hashCode(); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - @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 { - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(AgentV1KeepAlive other) { - return this; - } - - public AgentV1KeepAlive build() { - return new AgentV1KeepAlive(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/resources/agent/v1/types/AgentV1ListenUpdated.java b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ListenUpdated.java index 65878c9..6018473 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 @@ -36,6 +36,14 @@ public boolean equals(Object other) { return other instanceof AgentV1ListenUpdated; } + @java.lang.Override + public int hashCode() { + // Manual patch: Fern generates equals() (all instances of this fields-less message + // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a + // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. + return getClass().hashCode(); + } + @JsonAnyGetter public Map getAdditionalProperties() { return this.additionalProperties; diff --git a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ListenUpdated.java.bak b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ListenUpdated.java.bak deleted file mode 100644 index 6018473..0000000 --- a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ListenUpdated.java.bak +++ /dev/null @@ -1,86 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.deepgram.resources.agent.v1.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.databind.annotation.JsonDeserialize; -import java.util.HashMap; -import java.util.Map; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = AgentV1ListenUpdated.Builder.class) -public final class AgentV1ListenUpdated { - private final Map additionalProperties; - - private AgentV1ListenUpdated(Map additionalProperties) { - this.additionalProperties = additionalProperties; - } - - /** - * @return Message type identifier for listen update confirmation - */ - @JsonProperty("type") - public String getType() { - return "ListenUpdated"; - } - - @java.lang.Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof AgentV1ListenUpdated; - } - - @java.lang.Override - public int hashCode() { - // Manual patch: Fern generates equals() (all instances of this fields-less message - // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a - // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. - return getClass().hashCode(); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - @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 { - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(AgentV1ListenUpdated other) { - return this; - } - - public AgentV1ListenUpdated build() { - return new AgentV1ListenUpdated(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/resources/agent/v1/types/AgentV1PromptUpdated.java b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1PromptUpdated.java index 68d71cc..6edec37 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 @@ -36,6 +36,14 @@ public boolean equals(Object other) { return other instanceof AgentV1PromptUpdated; } + @java.lang.Override + public int hashCode() { + // Manual patch: Fern generates equals() (all instances of this fields-less message + // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a + // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. + return getClass().hashCode(); + } + @JsonAnyGetter public Map getAdditionalProperties() { return this.additionalProperties; diff --git a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1PromptUpdated.java.bak b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1PromptUpdated.java.bak deleted file mode 100644 index 6edec37..0000000 --- a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1PromptUpdated.java.bak +++ /dev/null @@ -1,86 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.deepgram.resources.agent.v1.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.databind.annotation.JsonDeserialize; -import java.util.HashMap; -import java.util.Map; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = AgentV1PromptUpdated.Builder.class) -public final class AgentV1PromptUpdated { - private final Map additionalProperties; - - private AgentV1PromptUpdated(Map additionalProperties) { - this.additionalProperties = additionalProperties; - } - - /** - * @return Message type identifier for prompt update confirmation - */ - @JsonProperty("type") - public String getType() { - return "PromptUpdated"; - } - - @java.lang.Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof AgentV1PromptUpdated; - } - - @java.lang.Override - public int hashCode() { - // Manual patch: Fern generates equals() (all instances of this fields-less message - // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a - // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. - return getClass().hashCode(); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - @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 { - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(AgentV1PromptUpdated other) { - return this; - } - - public AgentV1PromptUpdated build() { - return new AgentV1PromptUpdated(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/resources/agent/v1/types/AgentV1SettingsApplied.java b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SettingsApplied.java index 0d60b72..fb23c60 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 @@ -36,6 +36,14 @@ public boolean equals(Object other) { return other instanceof AgentV1SettingsApplied; } + @java.lang.Override + public int hashCode() { + // Manual patch: Fern generates equals() (all instances of this fields-less message + // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a + // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. + return getClass().hashCode(); + } + @JsonAnyGetter public Map getAdditionalProperties() { return this.additionalProperties; diff --git a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SettingsApplied.java.bak b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SettingsApplied.java.bak deleted file mode 100644 index fb23c60..0000000 --- a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SettingsApplied.java.bak +++ /dev/null @@ -1,86 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.deepgram.resources.agent.v1.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.databind.annotation.JsonDeserialize; -import java.util.HashMap; -import java.util.Map; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = AgentV1SettingsApplied.Builder.class) -public final class AgentV1SettingsApplied { - private final Map additionalProperties; - - private AgentV1SettingsApplied(Map additionalProperties) { - this.additionalProperties = additionalProperties; - } - - /** - * @return Message type identifier for settings applied confirmation - */ - @JsonProperty("type") - public String getType() { - return "SettingsApplied"; - } - - @java.lang.Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof AgentV1SettingsApplied; - } - - @java.lang.Override - public int hashCode() { - // Manual patch: Fern generates equals() (all instances of this fields-less message - // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a - // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. - return getClass().hashCode(); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - @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 { - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(AgentV1SettingsApplied other) { - return this; - } - - public AgentV1SettingsApplied build() { - return new AgentV1SettingsApplied(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/resources/agent/v1/types/AgentV1SpeakUpdated.java b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SpeakUpdated.java index 747aa9d..7619157 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 @@ -36,6 +36,14 @@ public boolean equals(Object other) { return other instanceof AgentV1SpeakUpdated; } + @java.lang.Override + public int hashCode() { + // Manual patch: Fern generates equals() (all instances of this fields-less message + // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a + // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. + return getClass().hashCode(); + } + @JsonAnyGetter public Map getAdditionalProperties() { return this.additionalProperties; diff --git a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SpeakUpdated.java.bak b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SpeakUpdated.java.bak deleted file mode 100644 index 7619157..0000000 --- a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SpeakUpdated.java.bak +++ /dev/null @@ -1,86 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.deepgram.resources.agent.v1.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.databind.annotation.JsonDeserialize; -import java.util.HashMap; -import java.util.Map; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = AgentV1SpeakUpdated.Builder.class) -public final class AgentV1SpeakUpdated { - private final Map additionalProperties; - - private AgentV1SpeakUpdated(Map additionalProperties) { - this.additionalProperties = additionalProperties; - } - - /** - * @return Message type identifier for speak update confirmation - */ - @JsonProperty("type") - public String getType() { - return "SpeakUpdated"; - } - - @java.lang.Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof AgentV1SpeakUpdated; - } - - @java.lang.Override - public int hashCode() { - // Manual patch: Fern generates equals() (all instances of this fields-less message - // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a - // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. - return getClass().hashCode(); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - @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 { - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(AgentV1SpeakUpdated other) { - return this; - } - - public AgentV1SpeakUpdated build() { - return new AgentV1SpeakUpdated(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/resources/agent/v1/types/AgentV1ThinkUpdated.java b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ThinkUpdated.java index 5668a71..2f2a981 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 @@ -36,6 +36,14 @@ public boolean equals(Object other) { return other instanceof AgentV1ThinkUpdated; } + @java.lang.Override + public int hashCode() { + // Manual patch: Fern generates equals() (all instances of this fields-less message + // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a + // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. + return getClass().hashCode(); + } + @JsonAnyGetter public Map getAdditionalProperties() { return this.additionalProperties; diff --git a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ThinkUpdated.java.bak b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ThinkUpdated.java.bak deleted file mode 100644 index 2f2a981..0000000 --- a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1ThinkUpdated.java.bak +++ /dev/null @@ -1,86 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.deepgram.resources.agent.v1.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.databind.annotation.JsonDeserialize; -import java.util.HashMap; -import java.util.Map; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = AgentV1ThinkUpdated.Builder.class) -public final class AgentV1ThinkUpdated { - private final Map additionalProperties; - - private AgentV1ThinkUpdated(Map additionalProperties) { - this.additionalProperties = additionalProperties; - } - - /** - * @return Message type identifier for think update confirmation - */ - @JsonProperty("type") - public String getType() { - return "ThinkUpdated"; - } - - @java.lang.Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof AgentV1ThinkUpdated; - } - - @java.lang.Override - public int hashCode() { - // Manual patch: Fern generates equals() (all instances of this fields-less message - // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a - // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. - return getClass().hashCode(); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - @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 { - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(AgentV1ThinkUpdated other) { - return this; - } - - public AgentV1ThinkUpdated build() { - return new AgentV1ThinkUpdated(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/resources/agent/v1/types/AgentV1UserStartedSpeaking.java b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1UserStartedSpeaking.java index edb80f8..7c3fc38 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 @@ -36,6 +36,14 @@ public boolean equals(Object other) { return other instanceof AgentV1UserStartedSpeaking; } + @java.lang.Override + public int hashCode() { + // Manual patch: Fern generates equals() (all instances of this fields-less message + // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a + // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. + return getClass().hashCode(); + } + @JsonAnyGetter public Map getAdditionalProperties() { return this.additionalProperties; diff --git a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1UserStartedSpeaking.java.bak b/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1UserStartedSpeaking.java.bak deleted file mode 100644 index 7c3fc38..0000000 --- a/src/main/java/com/deepgram/resources/agent/v1/types/AgentV1UserStartedSpeaking.java.bak +++ /dev/null @@ -1,86 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.deepgram.resources.agent.v1.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.databind.annotation.JsonDeserialize; -import java.util.HashMap; -import java.util.Map; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = AgentV1UserStartedSpeaking.Builder.class) -public final class AgentV1UserStartedSpeaking { - private final Map additionalProperties; - - private AgentV1UserStartedSpeaking(Map additionalProperties) { - this.additionalProperties = additionalProperties; - } - - /** - * @return Message type identifier indicating that the user has begun speaking - */ - @JsonProperty("type") - public String getType() { - return "UserStartedSpeaking"; - } - - @java.lang.Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof AgentV1UserStartedSpeaking; - } - - @java.lang.Override - public int hashCode() { - // Manual patch: Fern generates equals() (all instances of this fields-less message - // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a - // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. - return getClass().hashCode(); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - @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 { - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(AgentV1UserStartedSpeaking other) { - return this; - } - - public AgentV1UserStartedSpeaking build() { - return new AgentV1UserStartedSpeaking(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/resources/listen/v2/types/ListenV2CloseStream.java b/src/main/java/com/deepgram/resources/listen/v2/types/ListenV2CloseStream.java index e6308e2..e508681 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 @@ -36,6 +36,14 @@ public boolean equals(Object other) { return other instanceof ListenV2CloseStream; } + @java.lang.Override + public int hashCode() { + // Manual patch: Fern generates equals() (all instances of this fields-less message + // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a + // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. + return getClass().hashCode(); + } + @JsonAnyGetter public Map getAdditionalProperties() { return this.additionalProperties; diff --git a/src/main/java/com/deepgram/resources/listen/v2/types/ListenV2CloseStream.java.bak b/src/main/java/com/deepgram/resources/listen/v2/types/ListenV2CloseStream.java.bak deleted file mode 100644 index e508681..0000000 --- a/src/main/java/com/deepgram/resources/listen/v2/types/ListenV2CloseStream.java.bak +++ /dev/null @@ -1,86 +0,0 @@ -/** - * 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.databind.annotation.JsonDeserialize; -import java.util.HashMap; -import java.util.Map; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = ListenV2CloseStream.Builder.class) -public final class ListenV2CloseStream { - private final Map additionalProperties; - - private ListenV2CloseStream(Map additionalProperties) { - this.additionalProperties = additionalProperties; - } - - /** - * @return Message type identifier - */ - @JsonProperty("type") - public String getType() { - return "CloseStream"; - } - - @java.lang.Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof ListenV2CloseStream; - } - - @java.lang.Override - public int hashCode() { - // Manual patch: Fern generates equals() (all instances of this fields-less message - // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a - // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. - return getClass().hashCode(); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - @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 { - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(ListenV2CloseStream other) { - return this; - } - - public ListenV2CloseStream build() { - return new ListenV2CloseStream(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/resources/listen/v2/websocket/V2WebSocketClient.java b/src/main/java/com/deepgram/resources/listen/v2/websocket/V2WebSocketClient.java index d62cebd..abf4077 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 @@ -473,11 +473,11 @@ private void handleIncomingMessage(String json) { return; } } - if (onErrorHandler != null) { - onErrorHandler.accept(new RuntimeException( - "Unrecognized WebSocket message: " + json.substring(0, Math.min(200, json.length())) - + "... Update your SDK version to support new message types.")); - } + // Unrecognized message type: forward-compatible no-op. The raw frame was + // already delivered to onMessage(String) above, so a newer server adding a + // benign control frame (e.g. a GA addition to this endpoint) must not surface + // as a fatal error to deployed clients. Routing it to onError would make a + // harmless frame look fatal; mirrors the speak v2 client and the JS/Python SDKs. } catch (Exception e) { if (onErrorHandler != null) { onErrorHandler.accept(e); diff --git a/src/main/java/com/deepgram/resources/listen/v2/websocket/V2WebSocketClient.java.bak b/src/main/java/com/deepgram/resources/listen/v2/websocket/V2WebSocketClient.java.bak deleted file mode 100644 index 1325569..0000000 --- a/src/main/java/com/deepgram/resources/listen/v2/websocket/V2WebSocketClient.java.bak +++ /dev/null @@ -1,483 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.deepgram.resources.listen.v2.websocket; - -import com.deepgram.core.ClientOptions; -import com.deepgram.core.DisconnectReason; -import com.deepgram.core.ObjectMappers; -import com.deepgram.core.ReconnectingWebSocketListener; -import com.deepgram.core.RequestOptions; -import com.deepgram.core.WebSocketReadyState; -import com.deepgram.resources.listen.v2.types.ListenV2CloseStream; -import com.deepgram.resources.listen.v2.types.ListenV2Configure; -import com.deepgram.resources.listen.v2.types.ListenV2ConfigureFailure; -import com.deepgram.resources.listen.v2.types.ListenV2ConfigureSuccess; -import com.deepgram.resources.listen.v2.types.ListenV2Connected; -import com.deepgram.resources.listen.v2.types.ListenV2FatalError; -import com.deepgram.resources.listen.v2.types.ListenV2TurnInfo; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ScheduledExecutorService; -import java.util.function.Consumer; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import okhttp3.WebSocket; -import okio.ByteString; - -/** - * WebSocket client for the v2 channel. - * Provides real-time bidirectional communication with strongly-typed messages. - */ -public class V2WebSocketClient implements AutoCloseable { - protected final ClientOptions clientOptions; - - private final ObjectMapper objectMapper; - - private final OkHttpClient okHttpClient; - - private ScheduledExecutorService timeoutExecutor; - - private volatile WebSocketReadyState readyState = WebSocketReadyState.CLOSED; - - private volatile Runnable onConnectedHandler; - - private volatile Consumer onDisconnectedHandler; - - private volatile Consumer onErrorHandler; - - private volatile Consumer onMessageHandler; - - private volatile ReconnectingWebSocketListener.ReconnectOptions reconnectOptions; - - private CompletableFuture connectionFuture; - - private ReconnectingWebSocketListener reconnectingListener; - - private volatile Consumer connectedHandler; - - private volatile Consumer turnInfoHandler; - - private volatile Consumer configureSuccessHandler; - - private volatile Consumer configureFailureHandler; - - private volatile Consumer errorHandler; - - /** - * Creates a new async WebSocket client for the v2 channel. - */ - public V2WebSocketClient(ClientOptions clientOptions) { - this.clientOptions = clientOptions; - this.objectMapper = ObjectMappers.JSON_MAPPER; - this.okHttpClient = clientOptions.httpClient(); - } - - /** - * Establishes the WebSocket connection asynchronously with automatic reconnection. - * @return a CompletableFuture that completes when the connection is established - * @param options connection options including query parameters - */ - public CompletableFuture connect(V2ConnectOptions options) { - connectionFuture = new CompletableFuture<>(); - String baseUrl = clientOptions.environment().getProductionURL(); - String fullPath = "/v2/listen"; - if (baseUrl.endsWith("/") && fullPath.startsWith("/")) { - fullPath = fullPath.substring(1); - } else if (!baseUrl.endsWith("/") && !fullPath.startsWith("/")) { - fullPath = "/" + fullPath; - } - // OkHttp's HttpUrl only supports http/https schemes; convert wss/ws for URL parsing - if (baseUrl.startsWith("wss://")) { - baseUrl = "https://" + baseUrl.substring(6); - } else if (baseUrl.startsWith("ws://")) { - baseUrl = "http://" + baseUrl.substring(5); - } - HttpUrl parsedUrl = HttpUrl.parse(baseUrl + fullPath); - if (parsedUrl == null) { - throw new IllegalArgumentException("Invalid WebSocket URL: " + baseUrl + fullPath); - } - HttpUrl.Builder urlBuilder = parsedUrl.newBuilder(); - urlBuilder.addQueryParameter("model", String.valueOf(options.getModel())); - if (options.getEncoding() != null && options.getEncoding().isPresent()) { - urlBuilder.addQueryParameter( - "encoding", String.valueOf(options.getEncoding().get())); - } - if (options.getSampleRate() != null && options.getSampleRate().isPresent()) { - urlBuilder.addQueryParameter( - "sample_rate", String.valueOf(options.getSampleRate().get())); - } - if (options.getEagerEotThreshold() != null - && options.getEagerEotThreshold().isPresent()) { - urlBuilder.addQueryParameter( - "eager_eot_threshold", - String.valueOf(options.getEagerEotThreshold().get())); - } - if (options.getEotThreshold() != null && options.getEotThreshold().isPresent()) { - urlBuilder.addQueryParameter( - "eot_threshold", String.valueOf(options.getEotThreshold().get())); - } - if (options.getEotTimeoutMs() != null && options.getEotTimeoutMs().isPresent()) { - urlBuilder.addQueryParameter( - "eot_timeout_ms", String.valueOf(options.getEotTimeoutMs().get())); - } - if (options.getKeyterm() != null && options.getKeyterm().isPresent()) { - urlBuilder.addQueryParameter( - "keyterm", String.valueOf(options.getKeyterm().get())); - } - if (options.getLanguageHint() != null && options.getLanguageHint().isPresent()) { - urlBuilder.addQueryParameter( - "language_hint", String.valueOf(options.getLanguageHint().get())); - } - if (options.getProfanityFilter() != null && options.getProfanityFilter().isPresent()) { - urlBuilder.addQueryParameter( - "profanity_filter", - String.valueOf(options.getProfanityFilter().get())); - } - if (options.getMipOptOut() != null && options.getMipOptOut().isPresent()) { - urlBuilder.addQueryParameter( - "mip_opt_out", String.valueOf(options.getMipOptOut().get())); - } - if (options.getTag() != null && options.getTag().isPresent()) { - urlBuilder.addQueryParameter("tag", String.valueOf(options.getTag().get())); - } - Request.Builder requestBuilder = new Request.Builder().url(urlBuilder.build()); - clientOptions.headers((RequestOptions) null).forEach(requestBuilder::addHeader); - final Request request = requestBuilder.build(); - this.readyState = WebSocketReadyState.CONNECTING; - ReconnectingWebSocketListener.ReconnectOptions reconnectOpts = this.reconnectOptions != null - ? 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); - } - }) { - @Override - protected void onWebSocketOpen(WebSocket webSocket, Response response) { - readyState = WebSocketReadyState.OPEN; - if (onConnectedHandler != null) { - onConnectedHandler.run(); - } - connectionFuture.complete(null); - } - - @Override - protected void onWebSocketMessage(WebSocket webSocket, String text) { - handleIncomingMessage(text); - } - - @Override - protected void onWebSocketBinaryMessage(WebSocket webSocket, ByteString bytes) {} - - @Override - protected void onWebSocketFailure(WebSocket webSocket, Throwable t, Response response) { - readyState = WebSocketReadyState.CLOSED; - if (onErrorHandler != null) { - onErrorHandler.accept(new RuntimeException(t)); - } - connectionFuture.completeExceptionally(t); - } - - @Override - protected void onWebSocketClosed(WebSocket webSocket, int code, String reason) { - readyState = WebSocketReadyState.CLOSED; - if (onDisconnectedHandler != null) { - onDisconnectedHandler.accept(new DisconnectReason(code, reason)); - } - } - }; - reconnectingListener.connect(); - return connectionFuture; - } - - /** - * Disconnects the WebSocket connection and releases resources. - */ - public void disconnect() { - reconnectingListener.disconnect(); - if (timeoutExecutor != null) { - timeoutExecutor.shutdownNow(); - timeoutExecutor = null; - } - } - - /** - * Gets the current state of the WebSocket connection. - * - * This provides the actual connection state, similar to the W3C WebSocket API. - * - * @return the current WebSocket ready state - */ - public WebSocketReadyState getReadyState() { - return readyState; - } - - /** - * Sends a ListenV2Media message to the server asynchronously. - * @param message the message to send - * @return a CompletableFuture that completes when the message is sent - */ - public CompletableFuture sendMedia(ByteString message) { - CompletableFuture future = new CompletableFuture<>(); - try { - assertSocketIsOpen(); - // Use reconnecting listener's sendBinary method which handles queuing - reconnectingListener.sendBinary(message); - future.complete(null); - } catch (Exception e) { - future.completeExceptionally(new RuntimeException("Failed to send binary data", e)); - } - return future; - } - - /** - * Sends a ListenV2CloseStream message to the server asynchronously. - * @param message the message to send - * @return a CompletableFuture that completes when the message is sent - */ - public CompletableFuture sendCloseStream(ListenV2CloseStream message) { - return sendMessage(message); - } - - /** - * Sends a ListenV2Configure message to the server asynchronously. - * @param message the message to send - * @return a CompletableFuture that completes when the message is sent - */ - public CompletableFuture sendConfigure(ListenV2Configure message) { - return sendMessage(message); - } - - /** - * Registers a handler for ListenV2Connected messages from the server. - * @param handler the handler to invoke when a message is received - */ - public void onConnected(Consumer handler) { - this.connectedHandler = handler; - } - - /** - * Registers a handler for ListenV2TurnInfo messages from the server. - * @param handler the handler to invoke when a message is received - */ - public void onTurnInfo(Consumer handler) { - this.turnInfoHandler = handler; - } - - /** - * Registers a handler for ListenV2ConfigureSuccess messages from the server. - * @param handler the handler to invoke when a message is received - */ - public void onConfigureSuccess(Consumer handler) { - this.configureSuccessHandler = handler; - } - - /** - * Registers a handler for ListenV2ConfigureFailure messages from the server. - * @param handler the handler to invoke when a message is received - */ - public void onConfigureFailure(Consumer handler) { - this.configureFailureHandler = handler; - } - - /** - * Registers a handler for ListenV2FatalError messages from the server. - * @param handler the handler to invoke when a message is received - */ - public void onErrorMessage(Consumer handler) { - this.errorHandler = handler; - } - - /** - * Registers a handler called when the connection is established. - * @param handler the handler to invoke when connected - */ - public void onConnected(Runnable handler) { - this.onConnectedHandler = handler; - } - - /** - * Registers a handler called when the connection is closed. - * @param handler the handler to invoke when disconnected - */ - public void onDisconnected(Consumer handler) { - this.onDisconnectedHandler = handler; - } - - /** - * Registers a handler called when an error occurs. - * @param handler the handler to invoke on error - */ - public void onError(Consumer handler) { - this.onErrorHandler = handler; - } - - /** - * Registers a handler called for every incoming text message. - * The handler receives the raw JSON string before type-specific dispatch. - * @param handler the handler to invoke with the raw message JSON - */ - public void onMessage(Consumer handler) { - this.onMessageHandler = handler; - } - - /** - * Configures reconnection behavior. Must be called before {@link #connect}. - * - * @param options the reconnection options (backoff, retries, queue size) - */ - public void reconnectOptions(ReconnectingWebSocketListener.ReconnectOptions options) { - this.reconnectOptions = options; - } - - /** - * Closes this WebSocket client, releasing all resources. - * Equivalent to calling {@link #disconnect()}. - */ - @Override - public void close() { - disconnect(); - } - - /** - * Ensures the WebSocket is connected and ready to send messages. - * @throws IllegalStateException if the socket is not connected or not open - */ - private void assertSocketIsOpen() { - if (reconnectingListener.getWebSocket() == null) { - throw new IllegalStateException("WebSocket is not connected. Call connect() first."); - } - if (readyState != WebSocketReadyState.OPEN) { - throw new IllegalStateException("WebSocket is not open. Current state: " + readyState); - } - } - - private CompletableFuture sendMessage(Object body) { - CompletableFuture future = new CompletableFuture<>(); - try { - assertSocketIsOpen(); - String json = objectMapper.writeValueAsString(body); - // Use reconnecting listener's send method which handles queuing - reconnectingListener.send(json); - future.complete(null); - } catch (IllegalStateException e) { - future.completeExceptionally(e); - } catch (Exception e) { - future.completeExceptionally(new RuntimeException("Failed to send message", e)); - } - return future; - } - - private void handleIncomingMessage(String json) { - try { - if (onMessageHandler != null) { - onMessageHandler.accept(json); - } - JsonNode node = objectMapper.readTree(json); - if (node == null || node.isNull()) { - throw new IllegalArgumentException("Received null or invalid JSON message"); - } - if (node.has("request_id") - && node.has("sequence_id") - && node.has("event") - && node.has("turn_index") - && node.has("audio_window_start") - && node.has("audio_window_end") - && node.has("transcript") - && node.has("words") - && node.has("end_of_turn_confidence") - && "TurnInfo".equals(node.path("type").asText())) { - ListenV2TurnInfo turnInfoHandlerEvent = null; - try { - turnInfoHandlerEvent = objectMapper.treeToValue(node, ListenV2TurnInfo.class); - } catch (Exception e) { - } - if (turnInfoHandlerEvent != null) { - if (turnInfoHandler != null) { - turnInfoHandler.accept(turnInfoHandlerEvent); - } - return; - } - } - if (node.has("request_id") - && node.has("thresholds") - && node.has("keyterms") - && node.has("sequence_id") - && "ConfigureSuccess".equals(node.path("type").asText())) { - ListenV2ConfigureSuccess configureSuccessHandlerEvent = null; - try { - configureSuccessHandlerEvent = objectMapper.treeToValue(node, ListenV2ConfigureSuccess.class); - } catch (Exception e) { - } - if (configureSuccessHandlerEvent != null) { - if (configureSuccessHandler != null) { - configureSuccessHandler.accept(configureSuccessHandlerEvent); - } - return; - } - } - if (node.has("sequence_id") - && node.has("code") - && node.has("description") - && "Error".equals(node.path("type").asText())) { - ListenV2FatalError errorHandlerEvent = null; - try { - errorHandlerEvent = objectMapper.treeToValue(node, ListenV2FatalError.class); - } catch (Exception e) { - } - if (errorHandlerEvent != null) { - if (errorHandler != null) { - errorHandler.accept(errorHandlerEvent); - } - return; - } - } - if (node.has("request_id") - && node.has("sequence_id") - && "Connected".equals(node.path("type").asText())) { - ListenV2Connected connectedHandlerEvent = null; - try { - connectedHandlerEvent = objectMapper.treeToValue(node, ListenV2Connected.class); - } catch (Exception e) { - } - if (connectedHandlerEvent != null) { - if (connectedHandler != null) { - connectedHandler.accept(connectedHandlerEvent); - } - return; - } - } - if (node.has("request_id") - && node.has("sequence_id") - && "ConfigureFailure".equals(node.path("type").asText())) { - ListenV2ConfigureFailure configureFailureHandlerEvent = null; - try { - configureFailureHandlerEvent = objectMapper.treeToValue(node, ListenV2ConfigureFailure.class); - } catch (Exception e) { - } - if (configureFailureHandlerEvent != null) { - if (configureFailureHandler != null) { - configureFailureHandler.accept(configureFailureHandlerEvent); - } - return; - } - } - // Unrecognized message type: forward-compatible no-op. The raw frame was - // already delivered to onMessage(String) above, so a newer server adding a - // benign control frame (e.g. a GA addition to this endpoint) must not surface - // as a fatal error to deployed clients. Routing it to onError would make a - // harmless frame look fatal; mirrors the speak v2 client and the JS/Python SDKs. - } catch (Exception e) { - if (onErrorHandler != null) { - onErrorHandler.accept(e); - } - } - } -} 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 2e96a5c..51fef19 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 @@ -36,6 +36,14 @@ public boolean equals(Object other) { return other instanceof SpeakV2Close; } + @java.lang.Override + public int hashCode() { + // Manual patch: Fern generates equals() (all instances of this fields-less message + // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a + // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. + return getClass().hashCode(); + } + @JsonAnyGetter public Map getAdditionalProperties() { return this.additionalProperties; diff --git a/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Close.java.bak b/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Close.java.bak deleted file mode 100644 index 51fef19..0000000 --- a/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Close.java.bak +++ /dev/null @@ -1,86 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.deepgram.resources.speak.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.databind.annotation.JsonDeserialize; -import java.util.HashMap; -import java.util.Map; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = SpeakV2Close.Builder.class) -public final class SpeakV2Close { - private final Map additionalProperties; - - private SpeakV2Close(Map additionalProperties) { - this.additionalProperties = additionalProperties; - } - - /** - * @return Message type identifier - */ - @JsonProperty("type") - public String getType() { - return "Close"; - } - - @java.lang.Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof SpeakV2Close; - } - - @java.lang.Override - public int hashCode() { - // Manual patch: Fern generates equals() (all instances of this fields-less message - // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a - // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. - return getClass().hashCode(); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - @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 { - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(SpeakV2Close other) { - return this; - } - - public SpeakV2Close build() { - return new SpeakV2Close(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/resources/speak/v2/types/SpeakV2Flush.java b/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Flush.java index acd717d..e122400 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 @@ -36,6 +36,14 @@ public boolean equals(Object other) { return other instanceof SpeakV2Flush; } + @java.lang.Override + public int hashCode() { + // Manual patch: Fern generates equals() (all instances of this fields-less message + // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a + // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. + return getClass().hashCode(); + } + @JsonAnyGetter public Map getAdditionalProperties() { return this.additionalProperties; diff --git a/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Flush.java.bak b/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Flush.java.bak deleted file mode 100644 index e122400..0000000 --- a/src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Flush.java.bak +++ /dev/null @@ -1,86 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.deepgram.resources.speak.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.databind.annotation.JsonDeserialize; -import java.util.HashMap; -import java.util.Map; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = SpeakV2Flush.Builder.class) -public final class SpeakV2Flush { - private final Map additionalProperties; - - private SpeakV2Flush(Map additionalProperties) { - this.additionalProperties = additionalProperties; - } - - /** - * @return Message type identifier - */ - @JsonProperty("type") - public String getType() { - return "Flush"; - } - - @java.lang.Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof SpeakV2Flush; - } - - @java.lang.Override - public int hashCode() { - // Manual patch: Fern generates equals() (all instances of this fields-less message - // are equal) but no hashCode(), violating the Object contract. Mirror equals() with a - // type-based constant hash. Remove once Fern emits a consistent equals/hashCode pair. - return getClass().hashCode(); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - @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 { - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(SpeakV2Flush other) { - return this; - } - - public SpeakV2Flush build() { - return new SpeakV2Flush(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/resources/speak/v2/websocket/V2WebSocketClient.java b/src/main/java/com/deepgram/resources/speak/v2/websocket/V2WebSocketClient.java index cf23bcf..1ce8ea5 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 @@ -493,11 +493,11 @@ private void handleIncomingMessage(String json) { return; } } - if (onErrorHandler != null) { - onErrorHandler.accept(new RuntimeException( - "Unrecognized WebSocket message: " + json.substring(0, Math.min(200, json.length())) - + "... Update your SDK version to support new message types.")); - } + // Unrecognized message type: forward-compatible no-op. The raw frame was + // already delivered to onMessage(String) above, so a newer server adding a + // benign control frame (e.g. a GA addition to this endpoint) must not surface + // as a fatal error to deployed clients. Routing it to onError would make a + // harmless frame look fatal to a voice agent; mirrors the JS/Python SDKs. } catch (Exception e) { if (onErrorHandler != null) { onErrorHandler.accept(e); diff --git a/src/main/java/com/deepgram/resources/speak/v2/websocket/V2WebSocketClient.java.bak b/src/main/java/com/deepgram/resources/speak/v2/websocket/V2WebSocketClient.java.bak deleted file mode 100644 index 1ce8ea5..0000000 --- a/src/main/java/com/deepgram/resources/speak/v2/websocket/V2WebSocketClient.java.bak +++ /dev/null @@ -1,507 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.deepgram.resources.speak.v2.websocket; - -import com.deepgram.core.ClientOptions; -import com.deepgram.core.DisconnectReason; -import com.deepgram.core.ObjectMappers; -import com.deepgram.core.ReconnectingWebSocketListener; -import com.deepgram.core.RequestOptions; -import com.deepgram.core.WebSocketReadyState; -import com.deepgram.resources.speak.v2.types.SpeakV2Close; -import com.deepgram.resources.speak.v2.types.SpeakV2Connected; -import com.deepgram.resources.speak.v2.types.SpeakV2Error; -import com.deepgram.resources.speak.v2.types.SpeakV2Flush; -import com.deepgram.resources.speak.v2.types.SpeakV2Flushed; -import com.deepgram.resources.speak.v2.types.SpeakV2SessionMetadata; -import com.deepgram.resources.speak.v2.types.SpeakV2Speak; -import com.deepgram.resources.speak.v2.types.SpeakV2SpeechMetadata; -import com.deepgram.resources.speak.v2.types.SpeakV2SpeechStarted; -import com.deepgram.resources.speak.v2.types.SpeakV2Warning; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ScheduledExecutorService; -import java.util.function.Consumer; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import okhttp3.WebSocket; -import okio.ByteString; - -/** - * WebSocket client for the v2 channel. - * Provides real-time bidirectional communication with strongly-typed messages. - */ -public class V2WebSocketClient implements AutoCloseable { - protected final ClientOptions clientOptions; - - private final ObjectMapper objectMapper; - - private final OkHttpClient okHttpClient; - - private ScheduledExecutorService timeoutExecutor; - - private volatile WebSocketReadyState readyState = WebSocketReadyState.CLOSED; - - private volatile Runnable onConnectedHandler; - - private volatile Consumer onDisconnectedHandler; - - private volatile Consumer onErrorHandler; - - private volatile Consumer onMessageHandler; - - private volatile ReconnectingWebSocketListener.ReconnectOptions reconnectOptions; - - private CompletableFuture connectionFuture; - - private ReconnectingWebSocketListener reconnectingListener; - - private volatile Consumer speakV2AudioHandler; - - private volatile Consumer connectedHandler; - - private volatile Consumer speechStartedHandler; - - private volatile Consumer speechMetadataHandler; - - private volatile Consumer flushedHandler; - - private volatile Consumer sessionMetadataHandler; - - private volatile Consumer warningHandler; - - private volatile Consumer errorHandler; - - /** - * Creates a new async WebSocket client for the v2 channel. - */ - public V2WebSocketClient(ClientOptions clientOptions) { - this.clientOptions = clientOptions; - this.objectMapper = ObjectMappers.JSON_MAPPER; - this.okHttpClient = clientOptions.httpClient(); - } - - /** - * Establishes the WebSocket connection asynchronously with automatic reconnection. - * @return a CompletableFuture that completes when the connection is established - * @param options connection options including query parameters - */ - public CompletableFuture connect(V2ConnectOptions options) { - connectionFuture = new CompletableFuture<>(); - String baseUrl = clientOptions.environment().getProductionURL(); - String fullPath = "/v2/speak"; - if (baseUrl.endsWith("/") && fullPath.startsWith("/")) { - fullPath = fullPath.substring(1); - } else if (!baseUrl.endsWith("/") && !fullPath.startsWith("/")) { - fullPath = "/" + fullPath; - } - // OkHttp's HttpUrl only supports http/https schemes; convert wss/ws for URL parsing - if (baseUrl.startsWith("wss://")) { - baseUrl = "https://" + baseUrl.substring(6); - } else if (baseUrl.startsWith("ws://")) { - baseUrl = "http://" + baseUrl.substring(5); - } - HttpUrl parsedUrl = HttpUrl.parse(baseUrl + fullPath); - if (parsedUrl == null) { - throw new IllegalArgumentException("Invalid WebSocket URL: " + baseUrl + fullPath); - } - HttpUrl.Builder urlBuilder = parsedUrl.newBuilder(); - urlBuilder.addQueryParameter("model", String.valueOf(options.getModel())); - if (options.getEncoding() != null && options.getEncoding().isPresent()) { - urlBuilder.addQueryParameter( - "encoding", String.valueOf(options.getEncoding().get())); - } - if (options.getSampleRate() != null && options.getSampleRate().isPresent()) { - urlBuilder.addQueryParameter( - "sample_rate", String.valueOf(options.getSampleRate().get())); - } - if (options.getMipOptOut() != null && options.getMipOptOut().isPresent()) { - urlBuilder.addQueryParameter( - "mip_opt_out", String.valueOf(options.getMipOptOut().get())); - } - if (options.getTag() != null && options.getTag().isPresent()) { - urlBuilder.addQueryParameter("tag", String.valueOf(options.getTag().get())); - } - Request.Builder requestBuilder = new Request.Builder().url(urlBuilder.build()); - clientOptions.headers((RequestOptions) null).forEach(requestBuilder::addHeader); - final Request request = requestBuilder.build(); - this.readyState = WebSocketReadyState.CONNECTING; - ReconnectingWebSocketListener.ReconnectOptions reconnectOpts = this.reconnectOptions != null - ? 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); - } - }) { - @Override - protected void onWebSocketOpen(WebSocket webSocket, Response response) { - readyState = WebSocketReadyState.OPEN; - if (onConnectedHandler != null) { - onConnectedHandler.run(); - } - connectionFuture.complete(null); - } - - @Override - protected void onWebSocketMessage(WebSocket webSocket, String text) { - handleIncomingMessage(text); - } - - @Override - protected void onWebSocketBinaryMessage(WebSocket webSocket, ByteString bytes) { - if (speakV2AudioHandler != null) { - speakV2AudioHandler.accept(bytes); - } - } - - @Override - protected void onWebSocketFailure(WebSocket webSocket, Throwable t, Response response) { - readyState = WebSocketReadyState.CLOSED; - if (onErrorHandler != null) { - onErrorHandler.accept(new RuntimeException(t)); - } - connectionFuture.completeExceptionally(t); - } - - @Override - protected void onWebSocketClosed(WebSocket webSocket, int code, String reason) { - readyState = WebSocketReadyState.CLOSED; - if (onDisconnectedHandler != null) { - onDisconnectedHandler.accept(new DisconnectReason(code, reason)); - } - } - }; - reconnectingListener.connect(); - return connectionFuture; - } - - /** - * Disconnects the WebSocket connection and releases resources. - */ - public void disconnect() { - reconnectingListener.disconnect(); - if (timeoutExecutor != null) { - timeoutExecutor.shutdownNow(); - timeoutExecutor = null; - } - } - - /** - * Gets the current state of the WebSocket connection. - * - * This provides the actual connection state, similar to the W3C WebSocket API. - * - * @return the current WebSocket ready state - */ - public WebSocketReadyState getReadyState() { - return readyState; - } - - /** - * Sends a SpeakV2Speak message to the server asynchronously. - * @param message the message to send - * @return a CompletableFuture that completes when the message is sent - */ - public CompletableFuture sendSpeak(SpeakV2Speak message) { - return sendMessage(message); - } - - /** - * Sends a SpeakV2Flush message to the server asynchronously. - * @param message the message to send - * @return a CompletableFuture that completes when the message is sent - */ - public CompletableFuture sendFlush(SpeakV2Flush message) { - return sendMessage(message); - } - - /** - * Sends a SpeakV2Close message to the server asynchronously. - * @param message the message to send - * @return a CompletableFuture that completes when the message is sent - */ - public CompletableFuture sendClose(SpeakV2Close message) { - return sendMessage(message); - } - - /** - * Registers a handler for SpeakV2Audio messages from the server. - * @param handler the handler to invoke when a message is received - */ - public void onSpeakV2Audio(Consumer handler) { - this.speakV2AudioHandler = handler; - } - - /** - * Registers a handler for SpeakV2Connected messages from the server. - * @param handler the handler to invoke when a message is received - */ - public void onConnected(Consumer handler) { - this.connectedHandler = handler; - } - - /** - * Registers a handler for SpeakV2SpeechStarted messages from the server. - * @param handler the handler to invoke when a message is received - */ - public void onSpeechStarted(Consumer handler) { - this.speechStartedHandler = handler; - } - - /** - * Registers a handler for SpeakV2SpeechMetadata messages from the server. - * @param handler the handler to invoke when a message is received - */ - public void onSpeechMetadata(Consumer handler) { - this.speechMetadataHandler = handler; - } - - /** - * Registers a handler for SpeakV2Flushed messages from the server. - * @param handler the handler to invoke when a message is received - */ - public void onFlushed(Consumer handler) { - this.flushedHandler = handler; - } - - /** - * Registers a handler for SpeakV2SessionMetadata messages from the server. - * @param handler the handler to invoke when a message is received - */ - public void onSessionMetadata(Consumer handler) { - this.sessionMetadataHandler = handler; - } - - /** - * Registers a handler for SpeakV2Warning 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 SpeakV2Error messages from the server. - * @param handler the handler to invoke when a message is received - */ - public void onErrorMessage(Consumer handler) { - this.errorHandler = handler; - } - - /** - * Registers a handler called when the connection is established. - * @param handler the handler to invoke when connected - */ - public void onConnected(Runnable handler) { - this.onConnectedHandler = handler; - } - - /** - * Registers a handler called when the connection is closed. - * @param handler the handler to invoke when disconnected - */ - public void onDisconnected(Consumer handler) { - this.onDisconnectedHandler = handler; - } - - /** - * Registers a handler called when an error occurs. - * @param handler the handler to invoke on error - */ - public void onError(Consumer handler) { - this.onErrorHandler = handler; - } - - /** - * Registers a handler called for every incoming text message. - * The handler receives the raw JSON string before type-specific dispatch. - * @param handler the handler to invoke with the raw message JSON - */ - public void onMessage(Consumer handler) { - this.onMessageHandler = handler; - } - - /** - * Configures reconnection behavior. Must be called before {@link #connect}. - * - * @param options the reconnection options (backoff, retries, queue size) - */ - public void reconnectOptions(ReconnectingWebSocketListener.ReconnectOptions options) { - this.reconnectOptions = options; - } - - /** - * Closes this WebSocket client, releasing all resources. - * Equivalent to calling {@link #disconnect()}. - */ - @Override - public void close() { - disconnect(); - } - - /** - * Ensures the WebSocket is connected and ready to send messages. - * @throws IllegalStateException if the socket is not connected or not open - */ - private void assertSocketIsOpen() { - if (reconnectingListener.getWebSocket() == null) { - throw new IllegalStateException("WebSocket is not connected. Call connect() first."); - } - if (readyState != WebSocketReadyState.OPEN) { - throw new IllegalStateException("WebSocket is not open. Current state: " + readyState); - } - } - - private CompletableFuture sendMessage(Object body) { - CompletableFuture future = new CompletableFuture<>(); - try { - assertSocketIsOpen(); - String json = objectMapper.writeValueAsString(body); - // Use reconnecting listener's send method which handles queuing - reconnectingListener.send(json); - future.complete(null); - } catch (IllegalStateException e) { - future.completeExceptionally(e); - } catch (Exception e) { - future.completeExceptionally(new RuntimeException("Failed to send message", e)); - } - return future; - } - - private void handleIncomingMessage(String json) { - try { - if (onMessageHandler != null) { - onMessageHandler.accept(json); - } - JsonNode node = objectMapper.readTree(json); - if (node == null || node.isNull()) { - throw new IllegalArgumentException("Received null or invalid JSON message"); - } - if (node.has("speech_id") - && node.has("audio_duration_ms") - && node.has("input_character_count") - && node.has("billable_character_count") - && node.has("controls_applied") - && "SpeechMetadata".equals(node.path("type").asText())) { - SpeakV2SpeechMetadata speechMetadataHandlerEvent = null; - try { - speechMetadataHandlerEvent = objectMapper.treeToValue(node, SpeakV2SpeechMetadata.class); - } catch (Exception e) { - } - if (speechMetadataHandlerEvent != null) { - if (speechMetadataHandler != null) { - speechMetadataHandler.accept(speechMetadataHandlerEvent); - } - return; - } - } - if (node.has("request_id") - && node.has("model_name") - && node.has("model_version") - && node.has("model_uuids") - && "Connected".equals(node.path("type").asText())) { - SpeakV2Connected connectedHandlerEvent = null; - try { - connectedHandlerEvent = objectMapper.treeToValue(node, SpeakV2Connected.class); - } catch (Exception e) { - } - if (connectedHandlerEvent != null) { - if (connectedHandler != null) { - connectedHandler.accept(connectedHandlerEvent); - } - return; - } - } - if (node.has("total_audio_duration_ms") - && node.has("total_input_character_count") - && node.has("total_billable_character_count") - && "SessionMetadata".equals(node.path("type").asText())) { - SpeakV2SessionMetadata sessionMetadataHandlerEvent = null; - try { - sessionMetadataHandlerEvent = objectMapper.treeToValue(node, SpeakV2SessionMetadata.class); - } catch (Exception e) { - } - if (sessionMetadataHandlerEvent != null) { - if (sessionMetadataHandler != null) { - sessionMetadataHandler.accept(sessionMetadataHandlerEvent); - } - return; - } - } - if (node.has("code") - && node.has("description") - && "Warning".equals(node.path("type").asText())) { - SpeakV2Warning warningHandlerEvent = null; - try { - warningHandlerEvent = objectMapper.treeToValue(node, SpeakV2Warning.class); - } catch (Exception e) { - } - if (warningHandlerEvent != null) { - if (warningHandler != null) { - warningHandler.accept(warningHandlerEvent); - } - return; - } - } - if (node.has("code") - && node.has("description") - && "Error".equals(node.path("type").asText())) { - SpeakV2Error errorHandlerEvent = null; - try { - errorHandlerEvent = objectMapper.treeToValue(node, SpeakV2Error.class); - } catch (Exception e) { - } - if (errorHandlerEvent != null) { - if (errorHandler != null) { - errorHandler.accept(errorHandlerEvent); - } - return; - } - } - if (node.has("speech_id") - && "SpeechStarted".equals(node.path("type").asText())) { - SpeakV2SpeechStarted speechStartedHandlerEvent = null; - try { - speechStartedHandlerEvent = objectMapper.treeToValue(node, SpeakV2SpeechStarted.class); - } catch (Exception e) { - } - if (speechStartedHandlerEvent != null) { - if (speechStartedHandler != null) { - speechStartedHandler.accept(speechStartedHandlerEvent); - } - return; - } - } - if (node.has("speech_id") && "Flushed".equals(node.path("type").asText())) { - SpeakV2Flushed flushedHandlerEvent = null; - try { - flushedHandlerEvent = objectMapper.treeToValue(node, SpeakV2Flushed.class); - } catch (Exception e) { - } - if (flushedHandlerEvent != null) { - if (flushedHandler != null) { - flushedHandler.accept(flushedHandlerEvent); - } - return; - } - } - // Unrecognized message type: forward-compatible no-op. The raw frame was - // already delivered to onMessage(String) above, so a newer server adding a - // benign control frame (e.g. a GA addition to this endpoint) must not surface - // as a fatal error to deployed clients. Routing it to onError would make a - // harmless frame look fatal to a voice agent; mirrors the JS/Python SDKs. - } catch (Exception e) { - if (onErrorHandler != null) { - onErrorHandler.accept(e); - } - } - } -} From 65c5fb3f78ac7a2fe671990151f429c34ff3aef9 Mon Sep 17 00:00:00 2001 From: Greg Holmes Date: Tue, 21 Jul 2026 10:57:11 +0100 Subject: [PATCH 5/8] test: add Flux numerals connect-wire coverage for listen.v2 --- .../com/deepgram/ListenV2ConnectWireTest.java | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 src/test/java/com/deepgram/ListenV2ConnectWireTest.java diff --git a/src/test/java/com/deepgram/ListenV2ConnectWireTest.java b/src/test/java/com/deepgram/ListenV2ConnectWireTest.java new file mode 100644 index 0000000..75f5d85 --- /dev/null +++ b/src/test/java/com/deepgram/ListenV2ConnectWireTest.java @@ -0,0 +1,91 @@ +package com.deepgram; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.deepgram.core.Environment; +import com.deepgram.resources.listen.v2.websocket.V2ConnectOptions; +import com.deepgram.types.ListenV2Model; +import com.deepgram.types.ListenV2Numerals; +import java.util.concurrent.TimeUnit; +import okhttp3.HttpUrl; +import okhttp3.WebSocket; +import okhttp3.WebSocketListener; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import okhttp3.mockwebserver.RecordedRequest; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +/** + * Hand-written connect-handshake wire coverage for the Flux STT {@code numerals} query param on + * {@code listen().v2().v2WebSocket().connect(...)} (GET /v2/listen upgrade). + * + *

The Fern generator did not emit a wire test for the /v2/listen handshake, so this fills the + * gap for the 2026-07-20 regen's new {@code numerals} option: it pins that {@code numerals=true} + * lands on the connect URL when set, and is omitted entirely when absent. {@code numerals} is a + * {@link ListenV2Numerals} whose {@code @JsonValue toString()} is the raw wire string, so this also + * guards that {@code String.valueOf(...)} serialization stays {@code "true"}/{@code "false"} rather + * than an enum name. Frozen via {@code src/test/} in .fernignore. + */ +class ListenV2ConnectWireTest { + private MockWebServer server; + private DeepgramClient client; + + @BeforeEach + void setUp() throws Exception { + server = new MockWebServer(); + server.start(); + String base = server.url("/").toString().replaceAll("/$", ""); + Environment env = Environment.custom() + .base(base) + .production(base) + .agent(base) + .agentRest(base) + .build(); + client = DeepgramClient.builder().apiKey("test").environment(env).build(); + } + + @AfterEach + void tearDown() throws Exception { + server.shutdown(); + } + + /** Drives a real connect() against MockWebServer and returns the parsed handshake URL. */ + private HttpUrl connectAndCaptureUrl(V2ConnectOptions options) throws Exception { + server.enqueue(new MockResponse().withWebSocketUpgrade(new WebSocketListener() { + @Override + public void onOpen(WebSocket webSocket, okhttp3.Response response) { + webSocket.close(1000, null); + } + })); + client.listen().v2().v2WebSocket().connect(options); + RecordedRequest request = server.takeRequest(5, TimeUnit.SECONDS); + assertThat(request).as("handshake request was sent").isNotNull(); + HttpUrl url = HttpUrl.parse(server.url("/").scheme() + "://" + request.getHeader("Host") + request.getPath()); + assertThat(url).as("parsed handshake URL").isNotNull(); + assertThat(url.encodedPath()).isEqualTo("/v2/listen"); + return url; + } + + @Test + @DisplayName("numerals=true is sent on the connect URL when set") + void numeralsPresentWhenSet() throws Exception { + HttpUrl url = connectAndCaptureUrl(V2ConnectOptions.builder() + .model(ListenV2Model.FLUX_GENERAL_EN) + .numerals(ListenV2Numerals.TRUE) + .build()); + + assertThat(url.queryParameter("numerals")).isEqualTo("true"); + } + + @Test + @DisplayName("numerals is omitted from the connect URL when not set") + void numeralsOmittedWhenAbsent() throws Exception { + HttpUrl url = connectAndCaptureUrl( + V2ConnectOptions.builder().model(ListenV2Model.FLUX_GENERAL_EN).build()); + + assertThat(url.queryParameterNames()).doesNotContain("numerals"); + } +} From cd1c07f662c27bda6706da285a9bba3266d8f8e0 Mon Sep 17 00:00:00 2001 From: Greg Holmes Date: Tue, 21 Jul 2026 11:09:17 +0100 Subject: [PATCH 6/8] docs(examples): show numerals option in listen v2 live streaming --- examples/listen/LiveStreamingV2.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/listen/LiveStreamingV2.java b/examples/listen/LiveStreamingV2.java index cfb0579..1d667d4 100644 --- a/examples/listen/LiveStreamingV2.java +++ b/examples/listen/LiveStreamingV2.java @@ -4,6 +4,7 @@ import com.deepgram.resources.listen.v2.websocket.V2ConnectOptions; import com.deepgram.resources.listen.v2.websocket.V2WebSocketClient; import com.deepgram.types.ListenV2Model; +import com.deepgram.types.ListenV2Numerals; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -65,6 +66,8 @@ public static void main(String[] args) { // Connect to the WebSocket CompletableFuture connectFuture = wsClient.connect(V2ConnectOptions.builder() .model(ListenV2Model.FLUX_GENERAL_EN) + // Render spoken numbers as digits in the transcript (e.g. "twenty three" -> "23"). + .numerals(ListenV2Numerals.TRUE) .build()); connectFuture.get(10, TimeUnit.SECONDS); From 7437e01b02636211946cb02dee7e9ff3140c9b66 Mon Sep 17 00:00:00 2001 From: Greg Holmes Date: Tue, 21 Jul 2026 11:15:56 +0100 Subject: [PATCH 7/8] docs: add v0.6 to v0.7 migration guide --- docs/Migrating-v0.6-to-v0.7.md | 127 +++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 docs/Migrating-v0.6-to-v0.7.md diff --git a/docs/Migrating-v0.6-to-v0.7.md b/docs/Migrating-v0.6-to-v0.7.md new file mode 100644 index 0000000..1e80115 --- /dev/null +++ b/docs/Migrating-v0.6-to-v0.7.md @@ -0,0 +1,127 @@ +# v0.6 to v0.7 Migration Guide + +This guide helps you migrate from Deepgram Java SDK v0.6.x to v0.7.0. The `0.7.0` release is still pre-`1.0`, and it ships one breaking source change from the July 20 SDK regeneration along with two additive features. + +The breaking change is **source/compile-time** only. The on-the-wire payloads are unchanged — your requests and responses still serialize the same way; only one field was removed from the Java API surface because the API removed it from the spec. + +The biggest change is: + +1. `AgentV1LatencyReport.getSttLatency()` was removed — the Voice Agent `LatencyReport` no longer reports `stt_latency` ([deepgram-docs #1006](https://github.com/deepgram/deepgram-docs/pull/1006)). Drop any reads of `getSttLatency()`; the remaining latency getters are unchanged. + +## Table of Contents + +- [Installation](#installation) +- [Configuration Changes](#configuration-changes) +- [Authentication Changes](#authentication-changes) +- [API Method Changes](#api-method-changes) + - [Agent V1 (WebSocket)](#agent-v1-websocket) + - [Listen V2 (WebSocket)](#listen-v2-websocket) +- [Type Changes](#type-changes) + - [Latency Report STT Latency Removal](#latency-report-stt-latency-removal) + - [Other Additive Types](#other-additive-types) +- [Breaking Changes Summary](#breaking-changes-summary) + +## Installation + +Upgrade to `0.7.0` with Gradle or Maven. + +**Gradle** + +```groovy +dependencies { + implementation 'com.deepgram:deepgram-java-sdk:0.7.0' +} +``` + +**Maven** + +```xml + + com.deepgram + deepgram-java-sdk + 0.7.0 + +``` + +## Configuration Changes + +No required client-construction changes. Existing `DeepgramClient.builder()` usage still works. + +## Authentication Changes + +No changes. API key, access token, and session ID configuration all work the same as in `0.6.x`. + +## API Method Changes + +### Agent V1 (WebSocket) + +No breaking client-method changes. The breaking change is on the `AgentV1LatencyReport` server-event **type** you receive in an agent session (see [Type Changes](#type-changes)). + +### Listen V2 (WebSocket) + +No breaking client-method changes. `0.7.0` adds an optional `numerals` query parameter to the V2 WebSocket connection via `V2ConnectOptions`. It is additive. + +## Type Changes + +### Latency Report STT Latency Removal + +The Voice Agent `LatencyReport` server event no longer includes `stt_latency`, so `AgentV1LatencyReport.getSttLatency()` and the `sttLatency(...)` builder methods were removed. `LatencyReport` is a server-emitted (read-only) message, so this has **no request/wire impact** — but any call site that read `getSttLatency()` will no longer compile. + +The remaining latency getters are unchanged: `getTttTokenLatency()`, `getTttTextLatency()`, `getTttToolLatency()`, `getTttThinkingLatency()`, `getTtsLatency()`, and `getTotalLatency()`. + +**v0.6.x** + +```java +report.getSttLatency().ifPresent(stt -> System.out.println("STT latency: " + stt)); +report.getTtsLatency().ifPresent(tts -> System.out.println("TTS latency: " + tts)); +``` + +**v0.7.0** + +```java +// stt_latency is no longer reported by the server; drop the read. +report.getTtsLatency().ifPresent(tts -> System.out.println("TTS latency: " + tts)); +``` + +If you need to tolerate an `stt_latency` value on the wire from an older server, it is still accessible through the type's additional (unknown) properties rather than a typed getter. + +### Other Additive Types + +`0.7.0` also adds new generated types and constants that do not require migration unless you want to use them: + +- **Flux STT `numerals`**: a new `ListenV2Numerals` type (`com.deepgram.types.ListenV2Numerals`, values `TRUE` / `FALSE`) and an optional `numerals` query parameter on the Listen V2 WebSocket connection via `V2ConnectOptions.numerals(...)`. It renders spoken numbers as digits in the transcript (for example, "twenty three" → "23"). Connection-time only. + + ```java + import com.deepgram.resources.listen.v2.websocket.V2ConnectOptions; + import com.deepgram.types.ListenV2Model; + import com.deepgram.types.ListenV2Numerals; + + wsClient.connect(V2ConnectOptions.builder() + .model(ListenV2Model.FLUX_GENERAL_EN) + .numerals(ListenV2Numerals.TRUE) + .build()); + ``` + +- **New Aura-2 multilingual TTS voices**: roughly 40 new voices were added across `SpeakV1Model` (streaming/`speak.v2`) and `AudioGenerateRequestModel` (REST/`speak.v1.audio.generate`), covering Italian, Dutch, Spanish, German, Japanese, and French (for example, `SpeakV1Model.AURA2AURELIA_DE`, wire name `aura-2-aurelia-de`). Purely additive — existing voice constants are unchanged. + +## Breaking Changes Summary + +### Major Changes + +1. **Latency report STT removal**: `AgentV1LatencyReport.getSttLatency()` and the `sttLatency(...)` builder methods removed; the server no longer emits `stt_latency`. + +### Removed or Renamed Features + +- `AgentV1LatencyReport.getSttLatency()` and `AgentV1LatencyReport.Builder.sttLatency(...)` + +### New Features in v0.7.0 + +- **Flux STT numerals**: `ListenV2Numerals` and the `numerals` V2 WebSocket query parameter (`V2ConnectOptions.numerals(...)`) +- **New Aura-2 multilingual TTS voices**: ~40 voices added to `SpeakV1Model` and `AudioGenerateRequestModel` (it/nl/es/de/ja/fr) + +### Migration Checklist + +- [ ] Upgrade to `com.deepgram:deepgram-java-sdk:0.7.0` +- [ ] Remove any reads of `AgentV1LatencyReport.getSttLatency()` and any `sttLatency(...)` builder calls +- [ ] Rebuild your project and fix any remaining references to the removed getter +- [ ] (Optional) Adopt `V2ConnectOptions.numerals(...)` and the new Aura-2 multilingual voices From 92ebb607e838ac41c58abe8a99178093d20240e5 Mon Sep 17 00:00:00 2001 From: Greg Holmes Date: Tue, 21 Jul 2026 11:16:53 +0100 Subject: [PATCH 8/8] docs: link v0.6 to v0.7 migration guide in README --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3ace977..76f9a3c 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,9 @@ You can learn more about the Deepgram API at [developers.deepgram.com](https://d ### Migrating Between Versions -- [v0.3 to v0.4](./docs/Migrating-v0.3-to-v0.4.md) (current) +- [v0.6 to v0.7](./docs/Migrating-v0.6-to-v0.7.md) (current) +- [v0.5 to v0.6](./docs/Migrating-v0.5-to-v0.6.md) +- [v0.3 to v0.4](./docs/Migrating-v0.3-to-v0.4.md) - [v0.2 to v0.3](./docs/Migrating-v0.2-to-v0.3.md) ## Installation