Skip to content

Broad refactor of service settings and how they’re updated at runtime#3714

Draft
kompfner wants to merge 7 commits intomainfrom
pk/service-settings-refactor
Draft

Broad refactor of service settings and how they’re updated at runtime#3714
kompfner wants to merge 7 commits intomainfrom
pk/service-settings-refactor

Conversation

@kompfner
Copy link
Contributor

@kompfner kompfner commented Feb 11, 2026

Does not (yet) touch InputParams, to avoid scope creep.

Maybe the best way to understand these changes is to check out the COMMUNITY_INTEGRATIONS.md changes.

@codecov
Copy link

codecov bot commented Feb 11, 2026

Codecov Report

❌ Patch coverage is 20.62726% with 658 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/pipecat/services/elevenlabs/tts.py 0.00% 68 Missing ⚠️
src/pipecat/services/rime/tts.py 0.00% 63 Missing ⚠️
src/pipecat/services/sarvam/tts.py 0.00% 55 Missing ⚠️
src/pipecat/services/cartesia/tts.py 0.00% 40 Missing ⚠️
src/pipecat/services/inworld/tts.py 0.00% 37 Missing ⚠️
src/pipecat/services/minimax/tts.py 0.00% 36 Missing ⚠️
src/pipecat/services/google/tts.py 43.54% 35 Missing ⚠️
src/pipecat/services/azure/tts.py 0.00% 33 Missing ⚠️
src/pipecat/services/deepgram/stt.py 0.00% 27 Missing ⚠️
src/pipecat/services/tts_service.py 10.71% 25 Missing ⚠️
... and 27 more
Files with missing lines Coverage Δ
src/pipecat/services/elevenlabs/stt.py 0.00% <ø> (ø)
src/pipecat/services/google/stt.py 24.49% <ø> (+0.09%) ⬆️
src/pipecat/services/settings.py 100.00% <100.00%> (ø)
src/pipecat/frames/frames.py 89.32% <66.66%> (-0.13%) ⬇️
src/pipecat/services/nvidia/tts.py 0.00% <0.00%> (ø)
src/pipecat/services/speechmatics/tts.py 0.00% <0.00%> (ø)
src/pipecat/services/whisper/base_stt.py 49.15% <87.50%> (+6.84%) ⬆️
src/pipecat/services/hume/tts.py 0.00% <0.00%> (ø)
src/pipecat/services/aws/stt.py 29.71% <69.23%> (+4.90%) ⬆️
src/pipecat/services/kokoro/tts.py 0.00% <0.00%> (ø)
... and 30 more

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.


self.set_model_name(model)
self.set_voice(voice_id)
self._voice_id = voice_id
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Previously it wasn't clear whether set_voice/set_model/set_language were meant to be public APIs that users could directly invoke—in which case they should handle applying the change by reconnecting if necessary, etc.—or whether they were meant to only be "bookkeeping" methods, invokable only by subclasses, to update the underlying instance variables (_voice_id, etc).

I've made the decision here to make set_voice/set_model/set_language the "public" methods (even though we probably would suggest that users to use *UpdateSettingsFrames instead) and if we just need to update bookkeeping, access the instance variable directly.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We do use set_voice() directly in one example.

@kompfner kompfner force-pushed the pk/service-settings-refactor branch 13 times, most recently from 25536e8 to b1f4c32 Compare February 12, 2026 19:15
language_codes: List of Google STT language code strings
(e.g. ``["en-US"]``).

.. deprecated:: 0.0.103
Copy link
Contributor Author

Choose a reason for hiding this comment

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

TODO: update this (and all other occurrences of this) if it looks like these changes will land in a different version

@kompfner kompfner force-pushed the pk/service-settings-refactor branch 10 times, most recently from 7a8f453 to 6d7794f Compare February 13, 2026 16:41
model: Any = field(default_factory=lambda: NOT_GIVEN)
"""AI model identifier (e.g. ``"gpt-4o"``, ``"eleven_turbo_v2_5"``)."""

extra: Dict[str, Any] = field(default_factory=dict)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note that this PR doesn't go through every service and add handling for the extra field. It will be up to each service to add it when it's a priority. This can be done piecemeal.

…ce settings discoverable and strongly-typed. Service settings can be updated at runtime with `*UpdateSettingsFrame`s.

Does not (yet) touch `InputParams`, to avoid scope creep and touching something currently part of the public API. But there is a lot of overlap between `*Settings` object fields and `InputParams` fields.

Other than discoverability/typing, these are some other improvements brought by this refactor:
- There is now a single code path (see `_update_settings_from_typed`) where services can respond to settings changes (by, say, reconnecting if needed), improving maintainability and guaranteeing one and only one reconnection no matter which settings changed
- `set_language`/`set_model`/`set_voice`—which we're assuming are usable as public methods, though *not* recommended over `*UpdateSettingsFrame`—all use the same code path as settings updates. They're also now all consistent in that, if a service needs to respond to a change (by, say, reconnecting if needed), any of these methods will kick off that process. Note that this is technically a behavior change.
- Several services now properly react to changed settings by reconnecting:
  - `AWSTranscribeSTTService`
  - `AzureSTTService`
  - `SonioxSTTService`
  - `GladiaSTTService`
  - `SpeechmaticsSTTService`
  - `AssemblyAISTTService`
  - `CartesiaSTTService`
  - `FishAudioTTSService` (would previously only reconnect when `model` changed)
  - `GoogleSTTService`
  - `SpeechmaticsSTTService` (which previously only handled *some* settings updates through a nonstandard public `update_params` method)
  - `GradiumSTTService`
  - `NvidiaSegmentedSTTService` (which previously only handled changes to language)
- Bookkeeping across various services has been reduced, mostly by deduping ivars; the `self._settings` ivar is treated as the source of truth

NOTE: I pretty much guarantee that there are services missed in this PR in terms of bringing to consistency with how updates are handled (like whether changes in certain fields trigger reconnects when they need to). We can squash remaining inconsistencies as we stumble onto them, service by service. The goal here is to get things *mostly* in order, and establish the infrastructure and patterns we'll need going forward.
…d-service-settings path.

`filter_incomplete_user_turns` and `user_turn_completion_config` were only handled in the legacy dict-based `_update_settings` code path. This adds them to `LLMSettings` and introduces `LLMService._update_settings_from_typed` so the typed path handles them too.
…or better editor support.

Standardize all STT, TTS, and LLM service classes to declare `_settings` with the narrowed Settings type as a class-level annotation. This gives editors and type checkers the specific type when hovering or autocompleting on `self._settings` in each service and its subclasses. Inline `self._settings: Type = ...` assignments are replaced with plain `self._settings = ...`.
- NvidiaSTTService.set_model: convert to proper DeprecationWarning (model can't change at runtime for Riva streaming STT)
- NvidiaTTSService.set_model: same treatment for Riva TTS
- NvidiaSegmentedSTTService.set_model: remove — base class now routes through _update_settings_from_typed which re-creates the recognition config
- GeminiTTSService.set_voice: remove — move AVAILABLE_VOICES validation into _update_settings_from_typed so it fires on both legacy and new paths
…ngs_from_typed` to `_update_settings`.

Now that all services use typed `ServiceSettings` objects, this removes the interim scaffolding that supported both dict-based and typed settings paths in parallel. Specifically: removes old dict-based `_update_settings(settings: Mapping)` methods from base classes, removes `isinstance(self._settings, ServiceSettings)` guards, simplifies `process_frame` branching, and renames `_update_settings_from_typed` to `_update_settings` across all ~30 service implementations. Also renames the no-arg `_update_settings()` helper on realtime services to `_send_session_update()` to avoid collision, adds `from_mapping` overrides on `GoogleLLMSettings` and `AnthropicLLMSettings` for ThinkingConfig dict-to-object conversion, and replaces a broken no-arg `_update_settings()` call in Gemini Live with a TODO.
@kompfner kompfner force-pushed the pk/service-settings-refactor branch from 465b700 to b08548a Compare February 13, 2026 20:12
@kompfner kompfner changed the title Broad service settings refactor, with the primary aim of making servi… Broad refactor of service settings and how they’re updated at runtime Feb 13, 2026
model: The Deepgram model name to use.
Top-level ``model`` and ``language`` are the source of truth. When
they are given in *update* their values are propagated into
``live_options``. When only ``live_options`` is given, its ``model``
Copy link
Contributor

Choose a reason for hiding this comment

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

Developers will want to change more than just model and language. Is it possible to make any live_options change apply, as well?

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