feat(regen): add Speak V2 streaming, agent update-listen, and Flux EOT tuning#742
Open
GregHolmes wants to merge 8 commits into
Open
feat(regen): add Speak V2 streaming, agent update-listen, and Flux EOT tuning#742GregHolmes wants to merge 8 commits into
GregHolmes wants to merge 8 commits into
Conversation
…nce.md Apply the socket-client patch convention to the newly generated speak/v2/socket_client.py so it is consistent with the other four clients: broad `except Exception` (custom-transport error contract) and optional `send_flush()`/`send_close()` for no-payload control messages. Freeze it in .fernignore and add regression coverage. Document the new Speak V2 WebSocket in reference.md and add send_update_listen to the Agent V1 send-methods section.
…fields Cover the functionality introduced by the 2026-07-08 regen that shipped with only indirect coverage: - tests/custom/test_speak_v2_socket.py: Speak V2 send serialization, response-type parsing, and broad-except error-emit behavior. - tests/custom/test_eot_thresholds_feature.py: eot_threshold / eager_eot_threshold / eot_timeout_ms serialize on the three listen providers (mirrors test_language_hints_feature.py). - tests/custom/test_agent_update_listen.py: send_update_listen serialization + AgentV1ListenUpdated response resolution. - tests/manual/speak/v2/connect/: standalone connect scripts (main, async, with_auth_token, with_raw_response), parity with speak/v1. - examples/25-text-to-speech-streaming-v2.py: Speak V2 streaming example. Freeze the three new custom tests in .fernignore.
…g E2E Addresses review feedback on the Speak V2 (Flux TTS) update: - Forward compat: add unknown-message coverage across all four receive paths (sync/async recv() and start_listening loop) in test_speak_v2_socket.py, pinning that an unrecognized message type passes through as a raw dict without raising or dropping the connection. - Wire shape: add test_speak_v2_connect_wire.py asserting connect targets /v2/speak and serializes query params, incl. mip_opt_out=True -> "true" (also guards the frozen query_encoder bool-coercion patch). Frozen in .fernignore since Fern never generates websocket-connect wire tests. - Staging E2E: the manual connect scripts hardcoded production; add an env-driven DEEPGRAM_BASE_URL override so they can target staging.
client_wrapper.py is a `generic` release-please extra-file, but the generic updater only rewrites annotated lines. Without annotations the User-Agent and X-Fern-SDK-Version headers never get bumped, so wire telemetry drifts from the published package version (main shipping 7.4.0 while sending 7.3.2). Add `# x-release-please-version` to both header lines so they bump in lockstep with the release. Freeze client_wrapper.py in .fernignore (it is a live Fern-generated file that would otherwise be regenerated without the annotations) and document the freeze in AGENTS.md.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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)
client.speak.v2.connect(...)): newspeak/v2/package (client, socket client, request/response types) plus top-levelSpeakV2Encoding/MipOptOut/Model/SampleRate/Tag.send_update_listen(...)withAgentV1UpdateListen/AgentV1UpdateListenListen, and theAgentV1ListenUpdatedserver acknowledgement.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:__init__.pyfiles (kept alongside the newSpeakV2*/AgentV1*entries).language_hint→language_hintsmigration shim re-added to the three listen-provider models (kept alongside the neweot_*fields)._sanitize_numeric_types, broadexcept Exception, optionalsend_keep_alive(kept the newsend_update_listen).query_encoderbool coercion,agent_v1settings*back-compat, create-key alias + wire test — all restored.Judgment call — listen/v2
send_configureshim: keptThe generator now emits complete
ListenV2Configure/ListenV2ConfigureSuccessmodels, but adopting them changes the public signature (raw dict → model, typed responses) — a breaking change. Thetyping.Anyshim 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.pywas made consistent with the other four socket clients and frozen: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).send_flush()/send_close()for no-payload control messages (parity withspeak/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 + asyncrecv()and thestart_listeningloop), 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/speakpath and serializes query params, incl.mip_opt_out=True→"true"; doubles as the wire-level guard on the frozenquery_encoderbool coercion. Frozen in.fernignoresince 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_listenserialization +AgentV1ListenUpdatedresolution.tests/manual/speak/v2/connect/— standalone scripts (main / async / with_auth_token / with_raw_response), parity withspeak/v1; now accept aDEEPGRAM_BASE_URLoverride for non-prod (staging) targeting.examples/25-text-to-speech-streaming-v2.py(+examples/README.mdentry).reference.md— new "Speak V2 Connect" section andsend_update_listenadded to the Agent V1 send methods.Verification
mypy src/— clean (844 files)mypy tests/typecheck— cleanpytest— 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/mypyon the review follow-up files — cleanRelease telemetry — version drift fix
client_wrapper.pyis agenericextra-file inrelease-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).# x-release-please-versionto theUser-AgentandX-Fern-SDK-Versionheader lines so they bump in lockstep with the release.client_wrapper.pyin.fernignore— it is a live Fern-generated file, so a regen would strip the annotations otherwise — and documented the freeze + re-apply step inAGENTS.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 aDEEPGRAM_BASE_URLoverride to point at staging:Ran against staging (
wss://api.staging.deepgram.com), both sync and async: Connect → Speak → Flush → Close completes end to end —Connected(modelalexis, v2026-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.