feat(regen): add Speak V2 streaming, agent update-listen, and Flux EOT tuning (#742)
## Summary Fern SDK regeneration (2026-07-08). Pulls in new generator output, re-applies the hand-maintained patches, extends the socket-client convention to the new client, and adds test + example coverage for the new surface. ## New public surface (Fern-generated this regen) - **Speak V2 — Flux TTS WebSocket** (`client.speak.v2.connect(...)`): new `speak/v2/` package (client, socket client, request/response types) plus top-level `SpeakV2Encoding/MipOptOut/Model/SampleRate/Tag`. - **Agent mid-session listen reconfigure**: `send_update_listen(...)` with `AgentV1UpdateListen`/`AgentV1UpdateListenListen`, and the `AgentV1ListenUpdated` server acknowledgement. - **Flux end-of-turn tuning fields** on the listen providers: `eot_threshold`, `eager_eot_threshold`, `eot_timeout_ms`. ## Manual-patch reconciliation The generator caught up on **none** of the existing back-compat concerns, so **all 25 frozen patches were re-applied** (nothing dropped from `.fernignore`), preserving the new generator additions: - Legacy alias re-exports merged back into the package `__init__.py` files (kept alongside the new `SpeakV2*` / `AgentV1*` entries). - `language_hint` → `language_hints` migration shim re-added to the three listen-provider models (kept alongside the new `eot_*` fields). - Agent socket client: `_sanitize_numeric_types`, broad `except Exception`, optional `send_keep_alive` (kept the new `send_update_listen`). - listen/v1, listen/v2, speak/v1 socket clients, `query_encoder` bool coercion, `agent_v1settings*` back-compat, create-key alias + wire test — all restored. ### Judgment call — listen/v2 `send_configure` shim: **kept** The generator now emits complete `ListenV2Configure`/`ListenV2ConfigureSuccess` models, but adopting them changes the public signature (raw dict → model, typed responses) — a breaking change. The `typing.Any` shim is kept for this maintenance regen; typed-model adoption is deferred to a future major/minor. ## New: Speak V2 socket-client patch The newly generated `speak/v2/socket_client.py` was made consistent with the other four socket clients and frozen: - Broad `except Exception` (preserves the custom-transport error contract — a transport can raise arbitrary types; the narrow generated catch would leak them past the message loop). - Optional `send_flush()` / `send_close()` for no-payload control messages (parity with `speak/v1`). ## Test & example coverage - `tests/custom/test_speak_v2_socket.py` — send serialization, response-type parsing, broad-except error emission, and **forward compatibility**: an unknown/future message type passes through untouched on all four receive paths (sync + async `recv()` and the `start_listening` loop), so a newer server never breaks an older client. - `tests/custom/test_speak_v2_connect_wire.py` — **connect request wire shape** (sync + async): targets the `/v2/speak` path and serializes query params, incl. `mip_opt_out=True` → `"true"`; doubles as the wire-level guard on the frozen `query_encoder` bool coercion. Frozen in `.fernignore` since Fern never generates websocket-connect wire tests. - `tests/custom/test_eot_thresholds_feature.py` — `eot_*` fields serialize on all three listen providers. - `tests/custom/test_agent_update_listen.py` — `send_update_listen` serialization + `AgentV1ListenUpdated` resolution. - `tests/manual/speak/v2/connect/` — standalone scripts (main / async / with_auth_token / with_raw_response), parity with `speak/v1`; now accept a `DEEPGRAM_BASE_URL` override for non-prod (staging) targeting. - `examples/25-text-to-speech-streaming-v2.py` (+ `examples/README.md` entry). - `reference.md` — new "Speak V2 Connect" section and `send_update_listen` added to the Agent V1 send methods. ## Verification - `mypy src/` — clean (844 files) - `mypy tests/typecheck` — clean - `pytest` — 318 passed, 1 skipped (pre-review baseline; the review follow-up tests below add 6 more and pass) - `pytest tests/custom` — 205 passed, 1 skipped (includes the new forward-compat + connect-wire tests) - `ruff check` / `mypy` on the review follow-up files — clean ## Release telemetry — version drift fix `client_wrapper.py` is a `generic` extra-file in `release-please-config.json`, but the generic updater only rewrites lines carrying an annotation — and the two version header lines had none, so release-please never bumped the wire telemetry version. It drifts from the published package version (the pre-existing pattern: main shipping 7.4.0 while sending 7.3.2, and this branch would send 7.4.1 against a 7.5.0 release). - Added `# x-release-please-version` to the `User-Agent` and `X-Fern-SDK-Version` header lines so they bump in lockstep with the release. - Froze `client_wrapper.py` in `.fernignore` — it is a *live* Fern-generated file, so a regen would strip the annotations otherwise — and documented the freeze + re-apply step in `AGENTS.md`. ## Live end-to-end ✅ validated against staging Prod `/v2/speak` (Flux) returns HTTP 400 at the handshake until GA, so the manual connect scripts accept a `DEEPGRAM_BASE_URL` override to point at staging: ``` DEEPGRAM_BASE_URL=wss://api.staging.deepgram.com DEEPGRAM_API_KEY=<staging-key> \ poetry run python tests/manual/speak/v2/connect/main.py ``` **Ran against staging (`wss://api.staging.deepgram.com`), both sync and async:** Connect → Speak → Flush → Close completes end to end — `Connected` (model `alexis`, v `2026-07-02.2`) → `SpeechStarted` → 20 binary audio frames (~77 KB) → `Flushed` → `SpeechMetadata` → `SessionMetadata` → clean close. The forward-compat and connect-wire unit tests remain the regression guards; this confirms the real handshake + streaming path. --------- Co-authored-by: fern-api[bot] <115122769+fern-api[bot]@users.noreply.github.com>
G
Greg Holmes committed
69a2445c7c0c5ce1726566331f13030df64062e5
Parent: 0c2bf79
Committed by GitHub <noreply@github.com>
on 7/13/2026, 3:53:31 PM