diff --git a/.fern/metadata.json b/.fern/metadata.json index 1955a2a..3c25483 100644 --- a/.fern/metadata.json +++ b/.fern/metadata.json @@ -12,7 +12,7 @@ "enable-wire-tests": true, "runtime-version": true }, - "originGitCommit": "9dcbd3d5e8d36420319e1b33988613ad2cb2be10", + "originGitCommit": "59a99c27e5f91158072fc98b3567fc88c3315f67", "originGitCommitIsDirty": true, "invokedBy": "manual", "sdkVersion": "0.11.1" diff --git a/.fernignore b/.fernignore index aacb4e3..001477f 100644 --- a/.fernignore +++ b/.fernignore @@ -98,6 +98,10 @@ src/main/java/com/deepgram/resources/agent/v1/types/AgentV1UpdateListenListenPro src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SettingsAgentListenProvider.java src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SettingsAgentContextListenProvider.java +# Preserve binary-compatible Visitor implementations from before this generated enum added +# CONTROL_COMBINATION_INVALID. The default method routes old visitors through visitUnknown. +src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2ConfigureFailureCode.java + # Build and project configuration build.gradle settings.gradle diff --git a/AGENTS.md b/AGENTS.md index ea1c345..ecec18a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -53,8 +53,9 @@ Current temporarily frozen files: - `src/main/java/com/deepgram/resources/speak/v2/websocket/V2WebSocketClient.java` and `src/main/java/com/deepgram/resources/listen/v2/websocket/V2WebSocketClient.java` - forward-compat patch (both clients). Fern's generated `handleIncomingMessage` dispatcher routes any unrecognized message type to `onError` with "Update your SDK version...", which makes a benign new server control frame look fatal to a deployed client. Patched so the unrecognized-type branch is a no-op — the raw frame is already delivered via `onMessage(String)` earlier in the method, so consumers still see it. Mirrors the JS/Python SDKs' forward-compat behavior and is regression-guarded by `src/test/java/com/deepgram/SpeakV2ForwardCompatTest.java` and `src/test/java/com/deepgram/ListenV2ForwardCompatTest.java`. These two clients also carry the streaming query-param patches described in the next entry. Use the standard `.bak` swap/restore workflow during regen review; re-apply the no-op to both after regen, and unfreeze once the generator stops treating unknown frames as errors. - `src/main/java/com/deepgram/resources/listen/v1/websocket/V1WebSocketClient.java` and `src/main/java/com/deepgram/resources/speak/v1/websocket/V1WebSocketClient.java` (and the v2 clients above) - streaming query-param patches on the generated `connect()` builders. Two fixes: (1) multi-value serialization — array-valued params (listen: `keyterm`, `keywords`, `replace`, `search`, `tag`, `extra`, `language_hint`; speak: `tag`) were serialized with `String.valueOf(union.get())`, collapsing a `List` into one param (`keyterm=[a, b]`) instead of repeats (`keyterm=a&keyterm=b`); (2) an `additionalProperties` escape hatch — the builder exposes `additionalProperty(key, value)` for unmodeled params (e.g. `no_delay`) but `connect()` never emitted them to the URL. Both patched to route through `QueryStringMapper(arraysAsRepeats=true)`, matching the REST path. Listen V1 also forwards a parsed server `Error` to `onError` as a `ListenV1ErrorException` (carrying the typed `ListenV1Error`) when no `onErrorMessage` handler is registered, preserving the prior generic error-handler behavior. Use the standard `.bak` swap/restore workflow during regen review; re-apply after regen and unfreeze once the generator emits array params as repeats and serializes `additionalProperties` on the WS `connect()` path (tracked as an upstream Fern request). - Fields-less message types carrying a manual `hashCode()` patch (Fern generates `equals()` but no `hashCode()` for these, violating the Object contract): `src/main/java/com/deepgram/resources/listen/v2/types/ListenV2CloseStream.java`, `src/main/java/com/deepgram/resources/listen/v2/types/ListenV2ForceEndTurn.java`, `src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Close.java`, `src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2Flush.java`, and the `AgentV1*` event types `src/main/java/com/deepgram/resources/agent/v1/types/{AgentV1ListenUpdated,AgentV1SpeakUpdated,AgentV1AgentAudioDone,AgentV1SettingsApplied,AgentV1UserStartedSpeaking,AgentV1KeepAlive,AgentV1ThinkUpdated,AgentV1PromptUpdated,AgentV1ForceEndTurn}.java`. Use the standard `.bak` swap/restore workflow during regen review; drop the patches and unfreeze all of them once the generator emits a matching equals/hashCode pair for fields-less types (tracked as an upstream Fern request). -- `src/main/java/com/deepgram/types/DeepgramModel.java` - restores the `FLUX_RENEE_EN` constant that generator 4.18.0 dropped. The voice is live: `POST /v2/speak?model=flux-renee-en` returns 200 with valid audio, and the name resolves in the server's model registry (an invented `flux-*` name is rejected with `INVALID_QUERY_PARAMETER`), so the removal is a spec regression rather than a retirement, and dropping the constant would break 0.8.0 callers for nothing. Five touchpoints: the constant, the `Value` enum entry, the `visit()` case, the `valueOf()` case, and the `Visitor` method. **This file is unlike the other temporarily frozen ones — it receives frequent additive spec changes (4.18.0 alone added 25 constants), so on the next regen do NOT restore the `.bak` wholesale.** Diff the `.bak` against the newly generated file, carry forward every new voice, and re-apply only the `FLUX_RENEE_EN` touchpoints. Drop the patch and unfreeze once the spec lists the voice again (tracked as an upstream spec request). +- `src/main/java/com/deepgram/types/DeepgramModel.java` - restores the `FLUX_RENEE_EN` constant that generator 4.18.0 dropped. Renee is an unlisted voice: the spec owner removed it from the catalog on purpose (#project-flux-tts, 2026-08-19), but it still synthesizes (`POST /v2/speak?model=flux-renee-en` returns 200 with valid audio), so dropping the constant would be a source break for 0.8.0+ callers over a catalog delisting alone. The constant and its `Visitor` method are marked `@Deprecated` with a note pointing callers to a listed voice. Five touchpoints: the constant, the `Value` enum entry, the `visit()` case, the `valueOf()` case, and the `Visitor` method (the constant and `Visitor` method carry the `@Deprecated` tag and Javadoc). **This file is unlike the other temporarily frozen ones — it receives frequent additive spec changes (4.18.0 alone added 25 constants), so on the next regen do NOT restore the `.bak` wholesale.** Diff the `.bak` against the newly generated file, carry forward every new voice, and re-apply only the `FLUX_RENEE_EN` touchpoints. The spec will not list the voice again, so drop the Renee touchpoints at the next major release; keep the file frozen until then for the reasons above. - Union default-variant fix on the agent listen-provider unions: `src/main/java/com/deepgram/resources/agent/v1/types/AgentV1UpdateListenListenProvider.java`, `src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SettingsAgentListenProvider.java`, `src/main/java/com/deepgram/resources/agent/v1/types/AgentV1SettingsAgentContextListenProvider.java`. `version` is an optional discriminator, so a provider payload without it is valid (and is what 0.7.x emits), but Fern points `@JsonTypeInfo` `defaultImpl` at the empty-bodied `_UnknownValue`, so such a payload deserializes to an unknown variant carrying `null` — `getProvider()` returns `null` and re-serialization emits `{"provider":null}`, silently dropping the provider on the wire. Patched to `defaultImpl = V2Value` on each; guarded by `src/test/java/com/deepgram/AgentSettingsProviderDefaultTest.java`. Use the standard `.bak` swap/restore workflow during regen review; drop the patches and unfreeze once the generator stops defaulting unions to the empty `_UnknownValue` (tracked as an upstream Fern request). +- `src/main/java/com/deepgram/resources/speak/v2/types/SpeakV2ConfigureFailureCode.java` makes `Visitor.visitControlCombinationInvalid()` a default method that delegates to `visitUnknown("CONTROL_COMBINATION_INVALID")`. This restores source compatibility for `Visitor` implementations written against 0.8.0–0.10.x, before the value existed (0.11.0 shipped the method as abstract and listed it as breaking), while retaining the new generated enum value. Guarded by `src/test/java/com/deepgram/RegenTypesTest.java`. Use the standard `.bak` swap/restore workflow during regen review so new failure codes from the spec are carried forward, and re-apply only the default method. Keep frozen until the next major release. ### Prepare repo for regeneration diff --git a/README.md b/README.md index 21204b2..aeade6c 100644 --- a/README.md +++ b/README.md @@ -302,8 +302,8 @@ ws.connect(V1ConnectOptions.builder() .get(10, TimeUnit.SECONDS); // Update Nova-3 keyterms and numerals without reconnecting. Keep the keyterm list under the -// 500-token limit: an over-limit update currently stops transcription without an Error, and -// the server closes the stream. +// 500-token limit: an over-limit update does not close the stream, and the server may reply +// with a ConfigureFailure (CONFIGURE_KEYTERM_LIMIT_EXCEEDED), which this client reports to onError. ws.sendConfigure(ListenV1Configure.builder() .keyterms(List.of("Deepgram")) .features(Map.of("numerals", true)) diff --git a/docs/Migrating-v0.8-to-v0.9.md b/docs/Migrating-v0.8-to-v0.9.md index 68c9c24..916d6cc 100644 --- a/docs/Migrating-v0.8-to-v0.9.md +++ b/docs/Migrating-v0.8-to-v0.9.md @@ -183,6 +183,8 @@ ConversationHistoryMessage msg = ConversationHistoryMessage.builder() This is called out only because the generator dropped `FLUX_RENEE_EN` in this cycle and the SDK deliberately does not ship that removal. The voice is live: `POST /v2/speak?model=flux-renee-en` returns `200` with valid audio, and the name resolves in the server's model registry (an invented `flux-*` name is rejected with `INVALID_QUERY_PARAMETER`). The constant is restored and frozen, so existing references keep compiling. +> **Later update:** `flux-renee-en` is an unlisted voice, so releases after 0.11.1 mark `DeepgramModel.FLUX_RENEE_EN` `@Deprecated`. The voice still synthesizes and the constant still compiles; prefer a listed Flux voice from `GET /v2/models` for new code. + `DeepgramModel` remains a forward-compatible enum, so if you need to send a value the current SDK does not model, `DeepgramModel.valueOf("some-model-name")` still works. ### Speak V2 Connect Speed diff --git a/examples/listen/LiveReconfigure.java b/examples/listen/LiveReconfigure.java index 6da7fcc..af027be 100644 --- a/examples/listen/LiveReconfigure.java +++ b/examples/listen/LiveReconfigure.java @@ -15,8 +15,9 @@ /** * Reconfigures an active Nova-3 Listen V1 stream without reconnecting. * - *
Keep the keyterm list under the 500-token limit: an over-limit update currently stops transcription without an - * {@code Error}, and the server closes the stream. + *
Keep the keyterm list under the 500-token limit: an over-limit update does not close the stream, and the server + * may reply with a {@code ConfigureFailure} ({@code CONFIGURE_KEYTERM_LIMIT_EXCEEDED}), which this client reports to + * {@code onError}. * *
Usage: {@code DEEPGRAM_API_KEY=... java LiveReconfigure}
*/
diff --git a/src/main/java/com/deepgram/core/ClientOptions.java b/src/main/java/com/deepgram/core/ClientOptions.java
index b2c87ee..66dfa86 100644
--- a/src/main/java/com/deepgram/core/ClientOptions.java
+++ b/src/main/java/com/deepgram/core/ClientOptions.java
@@ -146,9 +146,10 @@ public Optional
* In-flight calls are not cancelled or awaited. When this client owns its OkHttpClient, later
* asynchronous HTTP requests can fail when the dispatcher rejects work, while synchronous
- * requests may still run. An OkHttpClient supplied through {@code httpClient(...)} remains
- * caller-owned and running. Options derived via {@code Builder.from(...)} share lifecycle
- * state; calling this method more than once has no further effect.
+ * requests may still run. Options derived from this one via
+ * {@code Builder.from(...)} share the same dispatcher and connection pool, so closing either
+ * releases them for both. A caller-supplied OkHttpClient remains running. Calling this method
+ * more than once has no further effect.
*
* WebSocket clients created from this client that are still connected are disconnected
* first (whether or not the OkHttpClient is owned), so they stop reconnecting before the
diff --git a/src/main/java/com/deepgram/resources/listen/v1/types/ListenV1Configure.java b/src/main/java/com/deepgram/resources/listen/v1/types/ListenV1Configure.java
index 967d27e..4232f3f 100644
--- a/src/main/java/com/deepgram/resources/listen/v1/types/ListenV1Configure.java
+++ b/src/main/java/com/deepgram/resources/listen/v1/types/ListenV1Configure.java
@@ -50,8 +50,9 @@ public String getType() {
* including keyterms set with the Each entry is a plain term or phrase with no weights or intensifiers. The 500-token keyterm limit that
- * applies to the keyterm query parameter. Send an empty array to clear all keyterms. Omit
* the field, or set it to null, to keep the current keyterms.
* keyterm query parameter also applies to each update. An over-limit update returns an
- * Error, and the stream keeps its previous keyterms.keyterm query parameter also applies to each update. An over-limit update currently stops
+ * transcription without an Error; after about 30 seconds, the server closes the stream with 1011
+ * (NET-0000). Keep each list under the limit and check its size before sending.
keyterm query parameter. Send an empty array to clear all keyterms. Omit
* the field, or set it to null, to keep the current keyterms.
* Each entry is a plain term or phrase with no weights or intensifiers. The 500-token keyterm limit that
- * applies to the keyterm query parameter also applies to each update. An over-limit update returns an
- * Error, and the stream keeps its previous keyterms.
keyterm query parameter also applies to each update. An over-limit update currently stops
+ * transcription without an Error; after about 30 seconds, the server closes the stream with 1011
+ * (NET-0000). Keep each list under the limit and check its size before sending.
*/
@JsonSetter(value = "keyterms", nulls = Nulls.SKIP)
public Builder keyterms(Optional