feat(regen): agent force-end-turn and Flux expressivity controls - #783
Conversation
|
dg-coreylweathers
left a comment
There was a problem hiding this comment.
DevRel review — changes requested, for three items before sign-off; the code, patches, and tests are sound.
What this PR does
Regenerates the Python SDK from the 2026-09-03 spec with fern-python-sdk 5.27.1. Voice Agent developers get agent.send_force_end_turn() to cut a user's turn short (Flux/V2 listen provider only; a V1 provider gets a FORCE_END_TURN_UNSUPPORTED warning), the Deepgram speak provider gains an expressivity setting (whole numbers -2 to 2, Flux voices, beta), the Flux TTS speed docs now say 0.5-1.5 instead of 0.85-1.15, keywords docstrings say Nova-3 does not support it and point at keyterm, and the aura-2-perseo-it voice name leaves the Speak V1 model literals. All hand patches were re-applied and the SpeakV2Speed float patch was retired because Fern now emits float.
What I checked
- Does the build pass? Yes: mypy clean on 904 files; 973 unit/custom tests pass in a
python:3.12container (wire tests need docker-compose and ran green in CI). - Is dropping
aura-2-perseo-ita break? No. I sent it to the live/v1/speakendpoint and got HTTP 400 "No such model/version combination found" (a real Italian voice,aura-2-livia-it, returned audio). The literal union still containsAny, so the string still type-checks and still sends; nothing that worked stops working. Minor bump is honest. - Did every hand patch survive? Yes:
Authorizationis still masked asToken [REDACTED]in error strings, booleans still serialize as lowercase in websocket URLs, thelanguage_hintand legacy alias shims are intact, and.fernignorecovers each of them. - Do unmodeled query params still reach the websocket URL? Yes, verified empirically (
no_delay=true&tag=a&tag=bon both/v2/listenand/v1/agent/converse), but no test asserts it. - Same spec as the JS/Java regens? Yes: the only file that differs between the 09-03 and 09-04 snapshots is
fern/generators.yml. - Is the Flux speed range true on production today? Not consistently — live probes against
/v2/speakshow some requests outside 0.85–1.15 rejected with the old-range error and others returning audio (your "accepted 0.5 and 1.5" matches the new nodes). Waiting on the Flux TTS team for a fleet-wide date; see the Java #100 review.
What to fix
- Version:
pyproject.toml,.fern/metadata.json, and theclient_wrapper.pyfallback say7.8.2, but afeattitle makes release-please produce7.9.0; the fallback would report a version that never ships. Unless there is a reason for stamping it, leave them at7.8.1(as #768 did). - Add a wire assertion for
additional_query_parametersintests/custom/test_listen_v2_connect_wire.py— assert the captured URL containsno_delay=true&tag=a&tag=brather than only that a socket was created. - The Listen V2
send_force_end_turndocstring lost its "requires server-side enablement / UNPARSABLE_CLIENT_MESSAGE closes the connection" warning whilereference.md:5417,examples/16, and the STT skill still state it. Is ForceEndTurn live on every prod deployment? That answer makes the four files agree and fixes the Java/JS docstrings too. - Restore the
See: internal-api-specs/issues/205line in_sanitize_numeric_types; it is now cited nowhere. - Add two lines to the squash-commit body so the changelog names the speed-range change (with the caveat if rollout is not confirmed) and the perseo removal, using the same sentence as Java and JS: "never served by the API (returns 400) and removed from the spec."
Nits: align reference.md wording with the generated "not supported with Nova-3 models"; keep the "0 is the only value validated for production" expressivity caveat at reference.md:6247; example 32 ends in a misleading TimeoutError 15 s after a FORCE_END_TURN_UNSUPPORTED warning.
|
Addressed the review feedback in 43f4704. @dg-coreylweathers, could you please re-review when you have a chance? |
|
@dg-coreylweathers Reposting the Flux speed rollout verification from closed #768: production verification on 2026-09-10 accepted all four boundary values:
No |
dg-coreylweathers
left a comment
There was a problem hiding this comment.
Approving. S7 and S6 are fixed in 8bd34b5 and I re-verified everything at that head.
What I checked
- Build in a clean python:3.12 container: mypy clean on 904 files, 981 tests passing (4 skipped), lockfile resolves,
git diff --checkclean. - S7:
python-dotenvis out ofpyproject.tomlandpoetry.lock, and the lock content-hash is back to the value from before it was added. - S6: I ran
tests/manual/speak/v2/matrix/main.pyagainst production onflux-alexis-enandflux-rufus-en. 0.5 / 0.85 / 1.15 / 1.5 were accepted byConfigure, connect-timespeed=, and batchspeak.v2.audio.generate. 0.45 and 1.55 came backSPEED_OUT_OF_RANGE, 1.03 came backSPEED_INCREMENT_INVALIDonConfigure, and all three got a 400 on connect and batch. 14 for 14. - The new
eot_thresholdsentence, on production withflux-general-en, 5 s of speech then 14 s of silence:0.7ended the turn withtrigger="model",1.0ended it withtrigger="timeout", and1.0witheot_timeout_ms=60000never ended it. The docstring says what the server does. - Listen V2 ForceEndTurn on production: accepted, socket stayed open,
trigger="manual". So the "requires server-side enablement" caveat is about other deployments, not api.deepgram.com. - The 09-07 fixes are still in place:
7.8.1inpyproject.toml,.fern/metadata.json, and theclient_wrapper.pyfallback; the wire test assertsno_delay=true&tag=a&tag=breaches the upgrade URL; theissues/205link is back;reference.mdkeeps "the only value validated for production" on expressivity.
Follow-up PR, not gating this one
- S8: the "
eot_timeout_msstill ends idle turns" sentence only exists in two frozen Python files (src/deepgram/types/listen_v2eot_threshold.py,src/deepgram/requests/deepgram_listen_provider_v2.py). It is true, I confirmed it above, so the spec is what is behind. Please open the deepgram-docs spec PR adding it toListenV2EotThresholdand the agentdeepgram-v2.ymllisten provider, then cite that PR in the.fernignorecomment so the unfreeze condition is a link and not a memory. reference.mdlines 378, 736, 5093 say "Not compatible with Nova-3; usekeyterminstead" while the generated docstring says "keywordsis not supported with Nova-3 models; usekeyterminstead". Use the generated wording.examples/32-voice-agent-force-end-turn.pyline 92: after aFORCE_END_TURN_UNSUPPORTEDwarning the script still waits 15 s and raisesTimeoutError("Timed out waiting for the agent response"), which points at the wrong cause. Set a flag in the Warning/Error branch and raise with the warning code..fernignoreline 46 andAGENTS.mdline 66 say the StrictInt freeze lifts "when Fern emits a strict integer". Fern will not; it lifts when we drop pydantic v1 support. Say that.AGENTS.mdlines 65-67: the two new ledger entries landed between thespeak/v2/socket_client.pyentry and thelisten/v1/socket_client.py — sameentry, so "same" now points at the expressivity entry. Move them below the socket-client block.- Since production has ForceEndTurn enabled, decide whether the enablement caveat in the docstrings,
reference.md, example 16, and the STT skill should name self-hosted explicitly, so a developer on api.deepgram.com does not read it as a warning about them.
At squash time I will add these two lines to the commit body so the changelog names both changes:
docs(speak): Flux TTS speed accepts 0.5-1.5 in 0.05 increments (was documented as 0.85-1.15)
fix(speak): drop aura-2-perseo-it from Speak V1 model literals; the API returns 400 "No such model/version combination found" for it
🤖 I have created a release *beep* *boop* --- ## [7.9.0](v7.8.1...v7.9.0) (2026-09-14) ### Features * **Voice Agent:** Adds `send_force_end_turn()` and typed ForceEndTurn messages for V2 Flux listen providers. ([#783](#783)) ([ff49864](ff49864)) * **Voice Agent:** Adds integer `expressivity` from `-2` through `2` for Deepgram Flux TTS providers. ([#783](#783)) ([ff49864](ff49864)) * **Flux TTS:** `speed` accepts `0.5` through `1.5` in `0.05` increments, replacing the previously documented `0.85` through `1.15` range. ([#783](#783)) ([ff49864](ff49864)) ### Model Catalog * **Speak V1:** Removes `aura-2-perseo-it` from model literals. The API never served the model and returns 400 `No such model/version combination found` for it. ([#783](#783)) ([ff49864](ff49864)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Greg Holmes <greg.holmes@deepgram.com>
Summary
fern-python-sdk5.27.1.send_force_end_turn()helpers.expressivityand the generated Flux speed range.ForceEndTurn availability
Listen V2 ForceEndTurn requires server-side enablement. Deployments without the feature return
UNPARSABLE_CLIENT_MESSAGEand close the connection.Unsupported voice removal
aura-2-perseo-itwas never served by the API (it returns 400) and was removed from the spec. The Python model union remains open throughAny, so callers can still pass the string and the removal is not source-breaking.Generator provenance
originGitCommitIsDirtyis expected: Fern ran after an uncommittedfern/generators.ymlchange that switched only the Python output mode and target branch to this regeneration branch. No API specification or Python code-generation setting was uncommitted, so the generated SDK contract is unchanged by that marker.Validation
poetry run mypy src/ tests/typecheck/compat_aliases.pyruff checkon changed tests and examplesgit diff --check