feat(regen): add diarize_info, Flux force-end-turn, update-listen, word speaker confidence - #89
Conversation
dg-coreylweathers
left a comment
There was a problem hiding this comment.
Approved — clean pre-regen prep. Verified:
- All 17 .bak snapshots are byte-identical to the patched originals on main (hash-compared each pair), so the reconciliation source-of-truth is faithful and complete.
- Unfreeze is complete: no original (non-.bak) path lingers in .fernignore that would silently keep a file frozen.
- Blast radius is exactly .fernignore + 17 .bak files — no original .java modified/deleted; patches (no_delay escape-hatch + arraysAsRepeats multi-value serialization) still intact on the originals.
- Permanent freezes untouched; functionally inert (.bak isn't compiled, no withSourcesJar() so nothing leaks to a published artifact).
One optional nit: the .bak files sit under src/main/java/ with no .gitignore coverage — carry a cleanup item into the reconciliation PR to delete them and restore the 17 .fernignore entries to their .java paths.
The real risk lives in the post-regen reconciliation, not here. When Fern overwrites the now-unfrozen originals it drops every manual patch; the .bak snapshots are the only safety net. The deepgram-sdk-review-regen pass must confirm all four patch families survive — especially the no_delay escape-hatch + multi-value WS serialization, plus the Flux oneOf non-breaking reshape (#1064) that the regen source carries. Leaving merge to Greg.
…enaming fern-java-sdk 4.16.0 unconditionally shortens provider type names, renaming public types that 0.7.x shipped (e.g. DeepgramSpeakProviderModel -> DeepgramModel). Rename them back and freeze the reverted leaf types + referencing payloads so the regen is source-compatible. Stopgap until the generator regression is fixed upstream.
- AgentV1UpdateListenListen: additive shim — getProvider() still returns DeepgramListenProviderV2 (0.7.x compat) while the new V1|V2 union is exposed via getProviderValue()/provider(DeepgramListenProviderV1) for model/language changes (#1066). - ConversationHistoryMessage / FunctionCallHistoryMessage: restored to 0.7.x shapes and re-added the two deleted ContextMessagesItem types (return-type changes can't be shimmed additively in Java). Frozen. Stopgap until the new shapes ship in a major.
Adds AgentV1UpdateListenShimTest — verifies the hand-written shim keeps the 0.7.x typed API (getProvider()/provider(V2)), exposes the union additively (getProviderValue()/provider(V1)), serializes the provider as the bare object once, and round-trips both V1 and V2.
`version` is optional on both DeepgramListenProviderV1 and V2, so a provider
object without it is a valid payload -- and is exactly what 0.7.x emitted and
parsed as a v2. Fern points the unions' @JsonTypeInfo defaultImpl at
_UnknownValue, whose @JsonCreator has an empty body, so such a payload
deserialized to an unknown variant carrying null: the provider getter returned
null and re-serializing emitted {"provider":null}, silently dropping the
caller's provider. _getUnknown() and equals() threw NullPointerException.
Measured against the released 0.7.1 jar, same input:
IN : {"provider":{"type":"deepgram","model":"nova-3"}}
0.7.1 : getProvider() = DeepgramListenProviderV2
before: getProvider() = null, re-serialize {"provider":null}
after : getProvider() = DeepgramListenProviderV2
Point defaultImpl at V2Value on all three agent listen-provider unions, which
matches the server's own default and restores 0.7.x behaviour. Jackson applies
defaultImpl for an absent OR unrecognized discriminator, so an unknown future
version now coerces to v2 rather than losing the provider; these messages are
client-sent, so the caller chooses the version. This leaves _isUnknown() and
_getUnknown() unreachable on these types.
AgentV1UpdateListenListenProvider is new in the 4.16.0 regen, so that one was a
regression. The two Settings unions shipped with the same defect in 0.7.1 and
are patched too, so all three behave consistently.
Fern emits equals() (all instances of a fields-less message are equal) but no hashCode(), violating the Object contract: two equal instances hash differently, so a HashSet built from one does not contain the other. ListenV2ForceEndTurn is new in this regen and was the only one of twelve fields-less types left unpatched -- the other eleven already carry the manual hashCode(), are frozen, and are asserted by RegenTypesTest. Bring it in line and add it to the existing contract assertion.
The regen added initialRetryDelayMillis, maxRetryDelayMillis and
retryJitterFactor to DeepgramApiClientBuilder only. Those return the parent
type, so using one mid-chain downgraded the static type and build() yielded a
DeepgramApiClient:
DeepgramClient client = DeepgramClient.builder()
.apiKey("k")
.initialRetryDelayMillis(500) // returns the parent type from here on
.build(); // error: DeepgramApiClient -> DeepgramClient
The hand-maintained wrappers already override apiKey/timeout/maxRetries and
friends for exactly this reason; the new methods just were not added. Override
all three in both the sync and async wrappers.
Worth a checklist item on future regens: when the generated parent builder gains
public methods, our frozen wrappers go stale silently -- nothing fails until a
consumer tries the fluent chain.
Freeze the three patched agent listen-provider unions and ListenV2ForceEndTurn so the fixes survive the next regen, and record each one in the temporarily-frozen list in AGENTS.md with the reason and the unfreeze condition. The two Settings provider unions were not frozen before, so without this the next regen would have silently reverted them.
… entry ClientOptions no longer carries x-release-please-version markers -- the regen replaced the hardcoded version strings with a manifest lookup (runtime-version: true), so the release-please "generic" updater had nothing left to rewrite in that file and silently no-opped. Remove the entry rather than leave it looking like that file's version is release-managed. The version now resolves via Package.getImplementationVersion(). pom.xml already stamped the manifest for the published artifact (mvn deploy); add the same to the Gradle jar task so both build paths carry a real Implementation-Version and the hardcoded fallback in ClientOptions stays unreachable in practice.
The Retry Configuration section showed only maxRetries while this release adds three backoff knobs and a per-request RequestOptions.maxRetries override. Note which statuses are retried, and show both. All snippets compile against the SDK.
dg-coreylweathers
left a comment
There was a problem hiding this comment.
Approved — full Fern 4.16.0 regeneration review (this supersedes the earlier prep-PR approval that was auto-dismissed when the head moved).
Independently verified (build gate run in Docker, not trusting CI):
- ./gradlew clean unitTest spotlessCheck compileExamples -> BUILD SUCCESSFUL, 104 tests, 0 failures; all new guard tests ran (shim, provider-default, regen-types hashCode, additionalProperties wire, forward-compat).
- Source-compat with 0.7.x: 0 removed/renamed public-type files vs v0.7.1; compileExamples (real usage code) green corroborates the surface.
- All 3 documented shims present and correct: type-rename reversal (short-named orphans not in tree), additive UpdateListen union shim, conversation-history reparent restored.
- Version-less provider drop fixed (defaultImpl=V2Value on all 3 agent listen-provider unions).
- hashCode on all 12 fields-less types incl. ListenV2ForceEndTurn; retry-tuning options reachable from both wrapper builders.
- no_delay escape hatch survived: wire test asserts it lands in the real upgrade URL on all 4 WS clients.
- New freezes complete + documented; .bak prep leftovers cleaned up; ClientOptions headers correct.
Two conditions, both about the RELEASE not the merge (details in Slack):
- Merge preserving the fix: commits (not squash-as-chore, or release-please cuts nothing) + add a 0.7.2 changelog stanza for the new features (diarize_info, speaker_confidence, force-end-turn, redact, gzip) so the release isn't undersold.
- Land docs #1069 (one line) so the now-unfrozen ClientOptions doesn't restamp the wrong Maven coordinate on the next regen. Order vs this PR doesn't matter for today's artifact; #1069 just must land before the next regen-from-main.
Cutting 0.7.2 today is safe: release CI does mvn deploy from committed source (no regen), and the correct headers are already committed here.
SDK regeneration for 2026-07-31 against fern-java-sdk 4.16.0, generated from the deepgram-docs
sdk-gen-2026-07-31branch (coordinate fix deepgram/deepgram-docs#1069 + Flux non-breaking reshape deepgram/deepgram-docs#1064 + cherry-picked spec PRs deepgram/deepgram-docs#1066, deepgram/deepgram-docs#1063, deepgram/deepgram-docs#1036, deepgram/deepgram-docs#1047).Source-compatible with 0.7.x — no breaking changes
Verified by a full breaking-change sweep against 0.7.1 (public API diffed from compiled trees): zero deleted public types, zero renames, zero removed or retyped getters — 1414 public types and 10,999 public members all still present. The generator (4.16.0) introduced several source-breaking changes that are shimmed back below.
Two caveats on "purely additive", for the record:
provider()overloads onAgentV1UpdateListenListenmake a bareprovider(null)ambiguous, so that one call no longer compiles. No working 0.7.x program is affected — it already threwNullPointerExceptionfromObjects.requireNonNull.ProviderStagegained two abstract methods, which technically breaks anyone implementing that generated builder-stage interface directly.New functionality (additive)
diarize_infoin listen v1 response metadata (deepgram-docs#1036)ListenV2ForceEndTurn+sendForceEndTurn(...)on the listen v2 WS client (deepgram-docs#1047)UpdateListencan now change model/language — exposed additively (see shim below) (deepgram-docs#1066)speaker/speaker_confidenceon pre-recorded words (deepgram-docs#1063)ListenV2Redact, retry-backoff tuning, and transparent gzip/deflate (ResponseDecompressionInterceptor)Back-compat handling for generator-introduced breaks (STOPGAP)
fern-java-sdk 4.16.0 renamed/reshaped public types 0.7.x shipped. These are patched back and frozen; drop once fixed upstream (Fern report pending):
DeepgramSpeakProviderModel→DeepgramModel,AnthropicThinkProviderModel→AnthropicModel,GoogleThinkProviderModel→GoogleModel,Cartesia*,Groq*— renamed back. (OpenAi*was unaffected — it's the only think+speak provider, so its names never collided.)AgentV1UpdateListenListen.getProvider()widenedDeepgramListenProviderV2→ aV1|V2union. Additive shim:getProvider()still returnsDeepgramListenProviderV2andprovider(DeepgramListenProviderV2)still builds; the union is exposed viagetProviderValue()andprovider(DeepgramListenProviderV1)for the new model/language capability. Regression-tested byAgentV1UpdateListenShimTest.ConversationHistoryMessage,FunctionCallHistoryMessage) reparented onto history-specific types with the sharedContextMessagesItem*types deleted — restored to 0.7.x shapes, deleted types re-added (return-type changes can't be shimmed additively in Java).Patch reconciliation
ClientOptionsretired from.fernignore— theruntime-versionflag is on docsmain, and the Maven-coordinate fix is deepgram/deepgram-docs#1069, which is still open. This regen was generated from a branch that includes it, so the headers in this PR are correct, but the unfreeze depends on #1069 landing: #1069 must merge before 0.7.2 is cut, or a later regen frommainwould restamp the wrongX-Fern-SDK-Name(com.deepgram:deepgram-sdk) with no freeze left to catch it. Addedmaven-jar-pluginmanifest stamping topom.xmlso the published JAR carriesImplementation-Versionfrom the release-please-managed<version>.ReconnectingWebSocketListener, 11 fields-lesshashCode()types, listen/speak WS query-param +additionalProperties+ forward-compat patches. listen v2 merge preserves the newredact+sendForceEndTurn.Verification
./gradlew unitTest) — pass, including the newAgentV1UpdateListenShimTest(shim API surface, outbound JSON shape, V1/V2 round-trip) alongside the existing patch guards (RegenTypesTesthashCode,QueryStringMapperTest, connect wire tests,ListenV2/SpeakV2ForwardCompatTest,ReconnectingWebSocketListenerTest,RetryInterceptorTest)../gradlew integrationTest, live API) — pass (transcribe URL/file, speak REST, read analyze, manage projects; invalid-key error handling).compileExamples); the safe / changed-area set runs green against the live API.spotlessCheckclean; CI green.Review follow-ups (added after the initial regen)
versionis optional on both provider variants, so{"provider":{"type":"deepgram","model":"nova-3"}}is valid and is what 0.7.x emitted — but Fern'sdefaultImpl = _UnknownValuesent it to an unknown variant whose value was never populated, so the getter returnednulland re-serializing emitted{"provider":null}, silently dropping the provider. NowdefaultImpl = V2Valueon all three agent listen-provider unions.AgentV1UpdateListenListenProvideris new here so that was a regression; the two Settings unions shipped the same defect in 0.7.1 and are fixed too, so all three agree. Guarded byAgentV1UpdateListenShimTestand the newAgentSettingsProviderDefaultTest.ListenV2ForceEndTurnwas missinghashCode()— the only one of twelve fields-less types not carrying the manual patch. Added, frozen, and asserted inRegenTypesTest.DeepgramClient.builder().initialRetryDelayMillis/maxRetryDelayMillis/retryJitterFactorlanded on the parent builder only, so using one mid-chain downgraded the static type andbuild()returned aDeepgramApiClient. Overridden in both hand-maintained wrappers, matching the existingapiKey/timeout/maxRetriespattern.release-please: dropped the now-deadClientOptions.javaentry (the file has nox-release-please-versionmarkers left, so the updater silently no-opped), and added jar-manifest stamping tobuild.gradlesoPackage.getImplementationVersion()resolves on the Gradle path too, not just the published Maven artifact.RequestOptions.maxRetries(...)override. All snippets were compiled against the built SDK — which is how the builder gap above was found.Gate after these changes:
./gradlew clean unitTest spotlessCheck compileExamples— 104 tests, 0 failures. Each new guard was checked by reverting its fix and confirming the test fails.