Skip to content

feat(regen): agent force-end-turn and Flux expressivity controls - #783

Merged
GregHolmes merged 22 commits into
mainfrom
gh/sdk-gen-2026-09-03
Sep 14, 2026
Merged

feat(regen): agent force-end-turn and Flux expressivity controls#783
GregHolmes merged 22 commits into
mainfrom
gh/sdk-gen-2026-09-03

Conversation

@GregHolmes

@GregHolmes GregHolmes commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Regenerate the Python SDK from the latest API definition with fern-python-sdk 5.27.1.
  • Add Agent ForceEndTurn request and response types plus no-payload send_force_end_turn() helpers.
  • Add Agent TTS expressivity and the generated Flux speed range.
  • Reapply compatibility, credential-redaction, WebSocket query-encoding, and regression-test patches.

ForceEndTurn availability

Listen V2 ForceEndTurn requires server-side enablement. Deployments without the feature return UNPARSABLE_CLIENT_MESSAGE and close the connection.

Unsupported voice removal

aura-2-perseo-it was never served by the API (it returns 400) and was removed from the spec. The Python model union remains open through Any, so callers can still pass the string and the removal is not source-breaking.

Generator provenance

originGitCommitIsDirty is expected: Fern ran after an uncommitted fern/generators.yml change 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.py
  • unit and focused wire suites
  • ruff check on changed tests and examples
  • git diff --check

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Code Coverage

Package Line Rate Branch Rate Complexity Health
src.deepgram 97% 94% 0
src.deepgram.agent 100% 100% 0
src.deepgram.agent.v1 98% 100% 0
src.deepgram.agent.v1.settings 100% 100% 0
src.deepgram.agent.v1.settings.think 100% 100% 0
src.deepgram.agent.v1.settings.think.models 97% 100% 0
src.deepgram.auth 100% 100% 0
src.deepgram.auth.v1 100% 100% 0
src.deepgram.auth.v1.tokens 97% 100% 0
src.deepgram.core 88% 81% 0
src.deepgram.errors 100% 100% 0
src.deepgram.helpers 100% 95% 0
src.deepgram.listen 100% 100% 0
src.deepgram.listen.v1 98% 93% 0
src.deepgram.listen.v1.media 97% 100% 0
src.deepgram.listen.v2 98% 93% 0
src.deepgram.manage 100% 100% 0
src.deepgram.manage.v1 100% 100% 0
src.deepgram.manage.v1.models 96% 100% 0
src.deepgram.manage.v1.projects 97% 100% 0
src.deepgram.manage.v1.projects.billing 100% 100% 0
src.deepgram.manage.v1.projects.billing.balances 96% 100% 0
src.deepgram.manage.v1.projects.billing.breakdown 97% 100% 0
src.deepgram.manage.v1.projects.billing.fields 97% 100% 0
src.deepgram.manage.v1.projects.billing.purchases 97% 100% 0
src.deepgram.manage.v1.projects.keys 96% 100% 0
src.deepgram.manage.v1.projects.members 97% 100% 0
src.deepgram.manage.v1.projects.members.invites 96% 100% 0
src.deepgram.manage.v1.projects.members.scopes 96% 100% 0
src.deepgram.manage.v1.projects.models 96% 100% 0
src.deepgram.manage.v1.projects.usage 98% 100% 0
src.deepgram.manage.v1.projects.usage.breakdown 97% 100% 0
src.deepgram.manage.v1.projects.usage.fields 97% 100% 0
src.deepgram.read 100% 100% 0
src.deepgram.read.v1 100% 100% 0
src.deepgram.read.v1.text 98% 100% 0
src.deepgram.self_hosted 100% 100% 0
src.deepgram.self_hosted.v1 100% 100% 0
src.deepgram.self_hosted.v1.distribution_credentials 96% 100% 0
src.deepgram.speak 100% 100% 0
src.deepgram.speak.v1 98% 97% 0
src.deepgram.speak.v1.audio 91% 80% 0
src.deepgram.speak.v2 98% 93% 0
src.deepgram.speak.v2.audio 100% 100% 0
src.deepgram.voice_agent 100% 100% 0
src.deepgram.voice_agent.configurations 95% 100% 0
src.deepgram.voice_agent.variables 95% 100% 0
Summary 95% (6503 / 6818) 91% (1419 / 1552) 0

Scope: hand-maintained SDK logic. Fern-generated data models (types/, requests/), package __init__.py files, version.py, and the unused core/http_sse/ scaffolding are excluded — see .coveragerc. Unscoped whole-package coverage is ~70%.

@GregHolmes GregHolmes changed the title chore: SDK regeneration 2026-09-03 chore: sdk regeneration 2026-09-03 Sep 4, 2026
@GregHolmes GregHolmes changed the title chore: sdk regeneration 2026-09-03 feat(regen): agent force-end-turn and Flux expressivity controls Sep 4, 2026

@dg-coreylweathers dg-coreylweathers left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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.12 container (wire tests need docker-compose and ran green in CI).
  • Is dropping aura-2-perseo-it a break? No. I sent it to the live /v1/speak endpoint and got HTTP 400 "No such model/version combination found" (a real Italian voice, aura-2-livia-it, returned audio). The literal union still contains Any, so the string still type-checks and still sends; nothing that worked stops working. Minor bump is honest.
  • Did every hand patch survive? Yes: Authorization is still masked as Token [REDACTED] in error strings, booleans still serialize as lowercase in websocket URLs, the language_hint and legacy alias shims are intact, and .fernignore covers each of them.
  • Do unmodeled query params still reach the websocket URL? Yes, verified empirically (no_delay=true&tag=a&tag=b on both /v2/listen and /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/speak show 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

  1. Version: pyproject.toml, .fern/metadata.json, and the client_wrapper.py fallback say 7.8.2, but a feat title makes release-please produce 7.9.0; the fallback would report a version that never ships. Unless there is a reason for stamping it, leave them at 7.8.1 (as #768 did).
  2. Add a wire assertion for additional_query_parameters in tests/custom/test_listen_v2_connect_wire.py — assert the captured URL contains no_delay=true&tag=a&tag=b rather than only that a socket was created.
  3. The Listen V2 send_force_end_turn docstring lost its "requires server-side enablement / UNPARSABLE_CLIENT_MESSAGE closes the connection" warning while reference.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.
  4. Restore the See: internal-api-specs/issues/205 line in _sanitize_numeric_types; it is now cited nowhere.
  5. 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.

@GregHolmes

Copy link
Copy Markdown
Contributor Author

Addressed the review feedback in 43f4704. @dg-coreylweathers, could you please re-review when you have a chance?

@GregHolmes

Copy link
Copy Markdown
Contributor Author

@dg-coreylweathers Reposting the Flux speed rollout verification from closed #768: production verification on 2026-09-10 accepted all four boundary values: 0.5, 0.85, 1.15, and 1.5.

  • JS SDK: batch REST synthesis returned non-empty audio for each value; Speak V2 WebSocket Configure returned ConfigureSuccess and echoed the exact requested applied.speed for each.
  • Python SDK: the same REST and WebSocket matrix passed.
  • Java SDK: the four-value Speak V2 WebSocket Configure matrix passed with exact echoed values; its existing live streaming-audio integration also passed at 1.05. I did not run a separate Java REST boundary matrix.

No SPEED_OUT_OF_RANGE responses occurred at either new boundary. This resolves the prior fleet-rollout acceptance concern. A separate repeated batch-audio duration probe showed substantial variation at 0.5, so I would not use these results alone to claim strict rate-fidelity at the slow endpoint.

@dg-coreylweathers dg-coreylweathers left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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 --check clean.
  • S7: python-dotenv is out of pyproject.toml and poetry.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.py against production on flux-alexis-en and flux-rufus-en. 0.5 / 0.85 / 1.15 / 1.5 were accepted by Configure, connect-time speed=, and batch speak.v2.audio.generate. 0.45 and 1.55 came back SPEED_OUT_OF_RANGE, 1.03 came back SPEED_INCREMENT_INVALID on Configure, and all three got a 400 on connect and batch. 14 for 14.
  • The new eot_threshold sentence, on production with flux-general-en, 5 s of speech then 14 s of silence: 0.7 ended the turn with trigger="model", 1.0 ended it with trigger="timeout", and 1.0 with eot_timeout_ms=60000 never 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.1 in pyproject.toml, .fern/metadata.json, and the client_wrapper.py fallback; the wire test asserts no_delay=true&tag=a&tag=b reaches the upgrade URL; the issues/205 link is back; reference.md keeps "the only value validated for production" on expressivity.

Follow-up PR, not gating this one

  • S8: the "eot_timeout_ms still 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 to ListenV2EotThreshold and the agent deepgram-v2.yml listen provider, then cite that PR in the .fernignore comment so the unfreeze condition is a link and not a memory.
  • reference.md lines 378, 736, 5093 say "Not compatible with Nova-3; use keyterm instead" while the generated docstring says "keywords is not supported with Nova-3 models; use keyterm instead". Use the generated wording.
  • examples/32-voice-agent-force-end-turn.py line 92: after a FORCE_END_TURN_UNSUPPORTED warning the script still waits 15 s and raises TimeoutError("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.
  • .fernignore line 46 and AGENTS.md line 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.md lines 65-67: the two new ledger entries landed between the speak/v2/socket_client.py entry and the listen/v1/socket_client.py — same entry, 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

@GregHolmes
GregHolmes merged commit ff49864 into main Sep 14, 2026
10 checks passed
@GregHolmes
GregHolmes deleted the gh/sdk-gen-2026-09-03 branch September 14, 2026 11:23
GregHolmes added a commit that referenced this pull request Sep 14, 2026
🤖 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>
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