Skip to content

revert: listen v2 force-end-turn/redaction + diarize regen (#750) - #757

Merged
GregHolmes merged 1 commit into
mainfrom
gh/revert-listen-v2-regen-2026-08-11
Aug 11, 2026
Merged

revert: listen v2 force-end-turn/redaction + diarize regen (#750)#757
GregHolmes merged 1 commit into
mainfrom
gh/revert-listen-v2-regen-2026-08-11

Conversation

@GregHolmes

Copy link
Copy Markdown
Contributor

Reverts the listen v2 regen (4678f0e, originally #750: force-end-turn, redaction, listen v1 diarize metadata) off main.

Why

This work isn't ready to ship yet, and other priorities need to release from main without it. Since the regen is already on main, any release cut from main (including the pending release-please 7.7.0, #751) would publish it. Reverting removes it from the release line cleanly, without rewriting history.

Preserved

The regen is not lost — it's parked on gh/sdk-gen-2026-08-11 (branched from main at 4678f0e) and can be re-applied / re-released when it's ready.

Follow-ups

  • The release-please PR chore(main): release 7.7.0 #751 (release 7.7.0) should not be merged; once this lands, release-please will regenerate its release notes without the reverted work.
  • To bring the regen back later, re-apply from gh/sdk-gen-2026-08-11 (a revert-of-this-revert, or a fresh regen).

@dg-coreylweathers dg-coreylweathers left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving. Verified this is a pure inverse of #750git diff 7da415d 63e25d6 is empty, so the tree lands byte-identical to the v7.6.0 tag. No collateral.

Checked independently rather than relying on CI:

  • No customer impact. PyPI latest is 7.6.0; #750 bumped pyproject to 7.6.1 but never published. Rated against the last released SDK this is non-breaking — no semver event.
  • Gate passes on 63e25d6: pytest 331 passed / 1 skipped, mypy clean across 857 source files (run in a python:3.12-slim container, full wire suite via an external WireMock).
  • Release plumbing stays coherent. The revert restores both halves of a matched pair — the generic client_wrapper.py entry in release-please-config.json and the # x-release-please-version annotations on the User-Agent / X-Fern-SDK-Version lines. No wire-telemetry version drift.
  • #758 restores what this drops: reconnection plumbing, importlib.metadata version resolution, redaction, and all the compat-alias shims.

Two non-blocking notes on the description (code is fine, merge away):

1. Scope is wider than the title. #750 was a full generator cycle, not three spec features — it also carried stream-reconnection plumbing (stream_reconnection_enabled / max_stream_reconnection_attempts) and ~446 net lines across src/deepgram/core/ (http_sse/_api.py alone +365). All of that reverts too, and all of it returns in #758. Worth a line in the body so the next reader of main's history knows why core/ moved.

2. The "Preserved" paragraph points somewhere slightly wrong. gh/sdk-gen-2026-08-11 is stacked on top of this revert, and its tip is a fresh regen rather than a replay of #750 — grepping src/deepgram there gives 0 files for force_end_turn and 0 for diarize_info (redaction and the infra do survive). Nothing is orphaned, since 4678f0e stays an ancestor of that branch, but "re-apply from the parked branch" would quietly hand someone a regen missing two of the three features. Suggest naming 4678f0e as the recovery point for those two specifically.

One thing to settle before the next release, not a blocker on this PR: #751 currently announces "Listen v2 turn control & redaction" as shipped in 7.7.0, citing 4678f0e. If it merges after this lands, we publish a changelog describing features that aren't in the tree. Suggest closing #751 now and letting #758 drive the next version, rather than letting release-please re-open it as a no-op 7.6.1 whose artifact is identical to 7.6.0. Your call on the release infra.

@GregHolmes
GregHolmes merged commit 48c88fc into main Aug 11, 2026
10 checks passed
@GregHolmes
GregHolmes deleted the gh/revert-listen-v2-regen-2026-08-11 branch August 11, 2026 11:48
GregHolmes added a commit to deepgram/deepgram-java-sdk that referenced this pull request Aug 11, 2026
#91)

Reverts the listen v2 regen (`5b6323a`, originally #89: Flux
force-end-turn, listen v1 diarize metadata + arch, word speaker
confidence, `AgentV1UpdateListen` provider retype, `ListenV2Redact`) off
`main`.

Mirrors the equivalent revert on deepgram-python-sdk:
deepgram/deepgram-python-sdk#757

## Why
This work isn't ready to ship yet, and other priorities need to release
from `main` without it. Since the regen is already on `main`, any
release cut from `main` (including the pending release-please 0.7.2,
#90) would publish it. Reverting removes it from the release line
cleanly, without rewriting history.

## Redoing the regen
The regen commit `5b6323a` stays reachable in history (and on the #89
branch), and the next regen branch `gh/sdk-gen-2026-08-11` (#92) is
stacked on this revert. **Caveat:** re-landing is a fresh 4.16.0 regen,
not a replay of #89's hand-patches — see "Forfeited by this revert"
below.

## Also reverted (not spec features)
Beyond the five spec features, this 184-file revert also rolls back:
- **Fern toolchain downgrade** (`.fern/metadata.json`): `cliVersion`
5.89.0 → 5.44.6, `generatorVersion` 4.16.0 → 4.10.1, `runtime-version`
dropped. This is what makes most of the rest follow.
- **Restores** the `ClientOptions.java` `.fernignore` freeze block + its
release-please `generic` extra-file entry (both dropped by #89) — this
is what keeps `X-Fern-SDK-Version` release-please-bumpable (no
wire-version drift).
- **Removes** the three 4.16.0-era stopgap freeze blocks (type-rename,
return-type shim, union default-variant) and the `ListenV2ForceEndTurn`
`hashCode()` entry from `.fernignore` and `AGENTS.md`.
- **`README.md`**: removes the 4.16.0 retry-knob docs (retry-behavior
prose that remains accurate has been restored — see the diff).

## Forfeited by this revert (tracked in #93)
The revert also drops patches #89 carried that are **not** preserved on
`gh/sdk-gen-2026-08-11` and **not** among #92's 17 reconciled patches
(verified: all three unions read `defaultImpl = _UnknownValue.class` on
#92, both tests absent):
- **Union default-variant fix** (`defaultImpl = V2Value`) on
`AgentV1UpdateListenListenProvider`,
`AgentV1SettingsAgentListenProvider`,
`AgentV1SettingsAgentContextListenProvider`. The two Settings unions
carry this bug in **released 0.7.1** (pre-existing, not a regression),
so the revert restores released behavior — it forfeits an *unreleased*
fix.
- **`AgentV1UpdateListenListen.getProvider()` additive return-type
shim.**
- **Regression guards** `AgentV1UpdateListenShimTest.java`,
`AgentSettingsProviderDefaultTest.java`.

Whether to re-apply the `defaultImpl` fix on #92 is a deliberate
decision tracked in #93.

## Verification
- `./gradlew compileJava compileExamples unitTest` — build successful,
all unit tests pass.
- The revert is a clean inverse of the single regen commit (184 files):
`git diff 5b6323a^ HEAD` over the pre-README-fix tree is empty
(byte-identical to the 0.7.1 release commit `8b3c605`). Restores
pre-regen `.fern/metadata.json` (sdkVersion 0.7.1, generator 4.10.1),
the `.fernignore` freeze blocks, and the `release-please-config.json`
`ClientOptions.java` generic entry.
- Escape-hatch (`additionalProperties`), forward-compat no-op, and
fields-less `hashCode()` patches from 0.7.1 all survive.
GregHolmes added a commit that referenced this pull request Aug 12, 2026
…n v2 redaction (#758)

Python SDK regeneration from the `jherlihy/flux-tts-ga` docs branch
(fern-python-sdk 5.23.0).

## What this adds

**Speak v2**
- `send_interrupt()` — barge-in, optionally with a `playback_offset`
(`{type: "time_ms", value: N}`)
- `send_configure()` — mid-stream `speed` changes, acknowledged by
`ConfigureSuccess` / `ConfigureFailure`
- `SpeechInterrupted` server message, with metadata incl. a new
`controls_applied.breaks_applied` counter
- `speed` and `expressivity` connect query parameters

**Listen v2**
- `redact` connect parameter (`ListenV2Redact`: `numbers`,
`aggressive_numbers`)
- `send_configure()` is now properly typed (`ListenV2Configure` +
`ListenV2ConfigureSuccess` in the response union), replacing the
previous `typing.Any` shim

**Other**
- `GoogleThinkProviderVersion` (adds `ai-studio-v1beta`,
`gemini-enterprise-agent-v1`)
- `AgentV1UpdateListenListenProvider` discriminated union (`_V1`/`_V2`,
discriminant `version`)
- `deepgram` speak provider `version` widened from `Literal["v1"]` to
`str`
- `client_wrapper` now derives its version from `importlib.metadata`
instead of a hardcoded string

## Manual patch reconciliation

**Re-applied** (generator still misses these): socket-client broad
`except` (required for custom transports, which raise non-`websockets`
errors) and the optional no-payload control params; agent-settings and
`language_hint` back-compat validators; `query_encoder` bool coercion;
the 10 `__init__.py` legacy alias re-exports (merged with the new
generated exports); wire-test legacy create-key alias coverage.

**Dropped** (generator now covers them, entries removed from
`.fernignore`):
- `agent_v1latency_report` — `stt_latency` is emitted natively again
- `core/client_wrapper` — dynamic versioning supersedes the
`x-release-please-version` annotations; its `generic` extra-file entry
is also removed from `release-please-config.json`

**Recovered**: the `agent_v1update_listen_listen.py` provider-coercion
validator was missing from `.fernignore` and was overwritten by the
generator. Restored and now frozen — a regression test caught it.

`listen/v2 send_configure` keeps runtime tolerance for a raw dict (sent
verbatim) for back-compat with pre-typed-model callers.

## Compatibility

No breaking changes against the last release (**v7.6.0**): 0 removed
public exports, 0 deleted modules, all baseline socket-client signatures
intact, and enum changes are widenings only. Compat alias shims still
pass.

The one change that *would* have broken callers is
`AgentV1UpdateListenListen.provider` (bare `DeepgramListenProviderV2` ->
required discriminated union). The restored validator coerces a legacy
provider instance *or* a legacy bare dict into the new shape, verified
at runtime — both produce `version: "v2"` on the wire.

## Review follow-ups (b8b2e78)
- **AGENTS.md freeze ledger synced with `.fernignore`.** Removed the
now-unfrozen `client_wrapper.py` entry, added the newly-frozen
`agent_v1update_listen_listen.py` (with a note that this patch was
silently lost once by a regen), added the three `language_hint` provider
validators and the new frozen test file, and corrected the
`listen/v2/socket_client.py` entry which still described the superseded
`typing.Any` `send_configure` shim. Verified zero drift in both
directions.
- **`speak/v2 send_interrupt` now takes an optional message**, matching
the sibling no-payload controls (`send_flush`/`send_close`) —
`SpeakV2Interrupt` has no required fields, so `send_interrupt()` is
meaningful. `send_configure` deliberately keeps its required argument (a
Configure with no settings is meaningless). Covered by new sync + async
tests.

### Version bump
The branch carries `7.6.1` (a patch) but this is a `feat`. That's
expected: the generator patch-bumps `pyproject.toml` on every regen and
release-please recomputes the correct minor at release time from the
conventional-commit type. Verified across three cycles — e.g. `#750`
left `7.6.1` and release-please's PR proposed `7.7.0`. This only holds
because the squash-merge message is `feat(...)`, which is why the PR
title matters here.

## Review follow-ups (round 2)

**[B1] blocking — fixed.** Passing `provider` as a plain dict to
`AgentV1UpdateListenListen` skipped the `language_hint` →
`language_hints` remap, so the deprecated singular key reached the wire.
The API uses `deny_unknown_fields`, so the whole `UpdateListen` was
rejected with no client-side signal. The dict branch now routes through
`DeepgramListenProviderV1/V2` so their own before-validators run — one
remap implementation instead of two. **[S1]** fixed in the same edit:
the version is inferred from the dict's own keys
(`language`/`smart_format` are v1-only) rather than blanket-stamped
`v2`.

One deviation from the suggested fix: constructing the shim model
*raises* on a malformed dict (e.g. missing the required `model`), which
would have made the compat shim a new source of exceptions. Wrapped with
a pass-through fallback, so behaviour is never worse than pre-regen. The
downstream union rejection of a genuinely-invalid payload was confirmed
pre-existing (the old code produced an identical payload, rejected
identically).

**[S3] restored wire coverage.** The regen dropped all ten optional
query params from the `manage.v1.projects.requests.list` wire test (Fern
derives the test from the spec *example*, which was simplified
upstream), leaving their serialisation — including `datetime` → ISO-8601
`Z` — unverified while the client still forwarded them. Restored and
frozen in `.fernignore` with the same rationale as the `_keys.py` entry.

**[S2] reference.md updated.** Added the five missing entries (`redact`,
`send_configure` for listen v2; `speed`, `expressivity`,
`send_interrupt`, `send_configure` for speak v2). The param entries
spell out accepted values, since the spec's numeric enums are dropped in
codegen.

**[S7] barge-in example added** —
`examples/26-text-to-speech-barge-in-v2.py`, async (the sync client
blocks in `start_listening()`, so mid-stream interrupt can't be shown).
⚠️ **Not yet verifiable**: `speak.v2.connect(model="flux-alexis-en")`
returns HTTP 400 on `api.deepgram.com` today, consistent with the API
not being in production yet.

**[S8] documented** — AGENTS.md now records the residual concerns on the
two newly-unfrozen files, notably that `client_wrapper`'s version
fallback literal is refreshed only by regen.

## Security fix (found while running the new example)

Every websocket `connect()` path raises `ApiError(headers=dict(headers),
...)` with the **full request headers**, and both `ApiError` and
`ParsingError` stringify that dict. A failed connect therefore printed:

```
headers: {'Authorization': 'Token <live key>', ...}, status_code: 400, ...
```

so any application logging the exception — `print(e)`, a traceback, a
log aggregator, an error tracker — wrote the customer's API key in clear
text. This is the same threat `_secure_logging.py` already covers for
the `websockets` DEBUG handshake logs; the exception path is simply the
other route to it, and was uncovered. It also defeats the telemetry
scrubber, which strips `request.headers` but not the exception
*message*.

Both error types now mask credential values **at construction** (so
`repr()` and attribute serialisation are covered too, not just
`__str__`), reusing `_secure_logging`'s existing sensitive-header set
and scheme-preserving mask. Non-sensitive headers are kept —
`dg-request-id` is the main reason to inspect them. Both files are
generated, so they're frozen with the rationale and documented in the
ledger. 14 new tests, mutation-checked.

**Pre-existing, not introduced by this regen**, and it affects all five
socket clients.

## Core / generator upgrade (5.14.18 → 5.23.0)

Nine generator minors also changed core HTTP behaviour that the feature
summary above doesn't cover:

1. **`RequestOptions` gains `timeout`**, and `timeout_in_seconds`
becomes a deprecated alias — a new public option plus a deprecation.
2. **Behaviour change for custom `httpx_client` users.** The SDK
previously adopted your client's `.timeout.read` as the base timeout for
every request; the base timeout is now `None`, resolving to
`httpx.USE_CLIENT_DEFAULT`. This is an improvement — the old path
flattened a granular `httpx.Timeout(connect=5, read=30, …)` down to a
single `30`, silently widening the connect timeout — but if you tuned
around that flattening, expect connect timeouts to tighten to what you
actually configured.
3. **`get_keepalive_socket_options()`** is a new public helper in
`core/http_client.py` that nothing in the SDK calls.
4. **`stream_reconnection_enabled` /
`max_stream_reconnection_attempts`** are added to both client
constructors and to `RequestOptions`, documented as "Defaults to True" —
but they are consumed only by `core/http_sse/_api.py`, and nothing wires
`http_sse` to an endpoint, so **they are inert today and do not apply to
the WebSocket clients**. Worth knowing, since `DeepgramClient` already
has an unrelated hand-written `reconnect` flag. (Not patched in the
docstring: those files are generated and now unfrozen, so a comment
there would be lost next regen.)

## Spec copy fixes — [S4] / [S5] (done, not deferred)

Both are spec `description` fields, so the durable fix is in
`deepgram-docs`: **deepgram-docs#1094**, stacked on the Flux GA PR #1090
(`SpeakV2Speed`/`SpeakV2Expressivity` don't exist on docs `main` yet, so
there was nothing to edit there).

To avoid this release shipping stale copy while waiting on a regen, the
**same text is applied by hand here**:

- **[S4] Flux TTS "Early Access" wording removed** from the Deepgram
agent speak-provider descriptions (`types/deepgram.py` +
`requests/deepgram.py`). Flux is GA; the direct Speak V2 path had
already been updated, so the Agent path was the only surface still
telling developers Flux might change before GA. `src/` now has **zero**
"Early Access" occurrences. No "GA" wording added in its place.
- **[S5] accepted values stated** for `speed` and `expressivity`. Both
*are* enums in the spec — the problem is downstream: Fern drops numeric
enums, so `speed`'s "Only the multipliers listed here are accepted"
pointed at a list that wasn't there and `expressivity` gave no range at
all. Both now spell the values out, and `speed` names the two failure
codes (`SPEED_OUT_OF_RANGE`, `SPEED_INCREMENT_INVALID`).

These four files are **not frozen**. The hand-applied text was verified
to match #1094 byte-for-byte — the spec YAML was parsed, folded scalars
normalised the way Fern renders them, and all five descriptions
(provider, version, model, speed, expressivity) compared equal — so the
next regen emits identical output and a freeze would protect nothing.
Fern keeps ownership; no maintenance debt once #1094 merges.

## Known issues NOT fixed here

- **Numeric spec enums lose their constraints in codegen**
(`SpeakV2Speed` → bare `float`, `SpeakV2Expressivity` → bare `int`;
string enums keep their `Literal` unions), so out-of-range values are
caught only by the server. Documented rather than hand-validated — the
`reference.md` entries and the corrected docstrings now state the
accepted values. Worth raising with Fern, since it affects every
Deepgram SDK.
- **[N2] `.fern/metadata.json` records `originGitCommitIsDirty: true`**
— the spec input isn't reproducible from version control. Pre-existing
practice (`main` carries the same flag) and unchanged here, since fixing
it needs a spec commit plus a regen.
- **[S7] the new barge-in example is unverified against a live API.**
`speak.v2.connect(model="flux-alexis-en")` returns HTTP 400 on
`api.deepgram.com` today, consistent with the merge gate below.

## Note on the `ApiError` fix and the other SDKs

The credential leak above is **Python-specific** and does not need
porting. It required two Python-only things to coincide:
`ApiError.__str__` printing `self.headers`, *and* the websocket
`connect()` paths passing the **request** headers. Checked both
siblings: the JS `DeepgramError.buildMessage({message, statusCode,
body})` takes no headers and none of its construction sites pass request
headers; Java's `DeepgramHttpException` populates its header map from
`rawResponse.headers()` (response headers) and has no `toString` that
dumps them.

## Verification

- `pytest` — **375 passed**, 1 skipped
- `ruff check src/` clean; `mypy src/` (882 files) and `mypy
tests/typecheck/` clean
- **18 new tests** covering the added surface, each mutation-verified
(deliberately broke the source and confirmed the test fails). Note these
models are `extra="allow"`, so asserting a field's *value* does not
detect a dropped field *declaration* — the metadata tests assert the
declared field set as well.
- **16 examples run against the live API**, including
`25-text-to-speech-streaming-v2.py` (Speak v2 streaming) and
`30-voice-agent.py`. Management examples were intentionally skipped; 5
others need a local audio file, a microphone, or the separate
`deepgram-sagemaker` package.

Rebased onto `main` after #757 (the listen-v2 revert) merged, so the
revert is no longer duplicated on this branch.

---------

Co-authored-by: fern-api[bot] <115122769+fern-api[bot]@users.noreply.github.com>
This was referenced Aug 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants