Add missing realtime speech-to-text options (#830)
* Add missing realtime speech-to-text options Ports the TypeScript SDK fix (elevenlabs-js#436) to Python. The hand-written realtime wrapper only exposed a subset of the parameters the websocket endpoint accepts. asyncapi.yml is the contract used throughout. New options, accepted by both connection modes: - secondary_languages, sent as repeated secondary_languages params - include_language_detection - entity_detection, accepting a single category/type or a list - filter_background_audio - enable_logging - token, a single-use token that authenticates the session on its own, so the xi-api-key header is omitted when no key is configured The two option TypedDicts duplicated every shared field, so they now inherit from a shared base instead of restating it, and the connect methods build their query kwargs through one helper rather than unpacking each option twice. New server messages, previously dropped by the dispatcher: - final_transcript and final_transcript_with_timestamps - committed_transcript_entities Also fixes unaccepted_terms: the enum only carried "unaccepted_terms_error", which the server never sends, so RealtimeEvents(message_type) raised and the message was swallowed. The correct literal is added and both event names are emitted so existing subscribers keep firing. Behaviour change: connecting with neither an api_key nor a token now raises ValueError instead of sending an empty xi-api-key header and waiting for the server to reject it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Test behaviour rather than parameter presence The URL tests asserted one substring each, which only proved a value passed in came back out. Replaced with assertions on the exhaustive parameter set, so a renamed, dropped or duplicated parameter fails, plus cases for the behaviour that can actually regress: explicitly false booleans surviving serialization, list parameters repeating rather than joining, and both keyterm limits being inclusive at the boundary. Also drops the "new params" framing, which described the diff rather than the endpoint. Verified by mutation: comma-joining a list, switching enable_logging to a truthiness check, appending audio_format twice, and always sending the api key header each fail at least two tests. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Address review: token precedence, and stop editing generated exports Two fixes from bugbot review. The api key was still sent whenever one was configured, even when the caller passed a token. The server tries the single-use token first and closes the session if it fails rather than falling back, so the key could never authenticate that connection - it was just a long-lived credential on the wire for no reason. A token now suppresses the header outright, which is also what the option's docstring already claimed. RealtimeEntityDetection was hand-added to src/elevenlabs/__init__.py, which Fern generates. The realtime root exports come from additional_init_exports in the API definition's generators.yml, so the next regeneration would have dropped this one while leaving the others, breaking `from elevenlabs import RealtimeEntityDetection`. Reverted that file to generated state; the type is exported from elevenlabs.realtime. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Leave parameter constraints to the API Per review: replicating server-side invariants client-side gives no type safety, and the server reports these anyway. The real cost is drift - if the constraint is relaxed server-side, callers cannot adopt the change until the SDK is updated and shipped, which is a failure mode nobody is watching for. Drops the filter_background_audio/include_timestamps conflict check and the keyterms count and length checks, along with their tests. The constraints stay in the docstrings, mirroring the API reference, since a stale doc misleads far less than a hard failure. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Handle the invalid_request error message Now declared in asyncapi.yml (elevenlabs/xi#44830), so the SDK can pick it up from the spec. The server sends this when it rejects the connection parameters: it accepts the websocket, sends the error, then closes. The dispatcher resolves events through RealtimeEvents(message_type) and ignores unknown types, so the message was dropped and a bad parameter surfaced as a connection close with no error event at all. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Drop tests that only exercised language primitives Two of the tests added on this branch asserted nothing about the SDK. test_committed_transcript_entities_carries_entities checked that a payload the SDK never transforms survived an emitter, and the list-parameter test duplicated the exhaustive serialization assertion, which already fails on a joined list. Strengthens the connect() option test instead: it is the only cover for the _shared_url_kwargs mapping, where a typo drops an option silently, so it now asserts the full parameter set rather than a few substrings. Verified by mutation: comma-joining a list, enable_logging truthiness, a mapping typo, sending the api key alongside a token, and removing either the INVALID_REQUEST or FINAL_TRANSCRIPT enum member each still fail. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Bump version to 2.63.0 Minor: adds realtime speech-to-text options and message types. Matches the JS SDK, which the two are released in lockstep with. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
P
Paul Asjes committed
e1cf8db99cfb5dc06861fc6b0a93453db06f4068
Parent: 80f2f2e
Committed by GitHub <noreply@github.com>
on 8/11/2026, 9:52:20 AM