From b64ed3f9e2ea499f59eeda47ca654b6c30013a63 Mon Sep 17 00:00:00 2001 From: Mark Backman Date: Wed, 22 Apr 2026 11:50:51 -0400 Subject: [PATCH] Narrow settings.model at service boundaries, not via truthiness MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two services were reading `_settings.model` (typed `str | _NotGiven | None` because NOT_GIVEN is the default) and coercing it with `or ""` or similar. `_NotGiven.__bool__` returns False, so the runtime behavior happened to work, but the type was a lie — pyright saw `str | _NotGiven` flowing into APIs that required `str` or `str | None`. - `AIService._sync_model_name_to_metrics`: use `isinstance(model, str)` narrowing with an empty-string fallback. Equivalent runtime behavior, honest type, no truthiness dependency on a sentinel. - `SarvamLLMService.__init__`: validate the model is a real string before handing it to `_validate_model(str)`. A non-string model at this point is a configuration bug; raise `ValueError` so the error is clear and survives `python -O` (unlike an assert). --- pyrightconfig.json | 14 +++----------- src/pipecat/services/ai_service.py | 3 ++- src/pipecat/services/sarvam/llm.py | 5 ++++- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/pyrightconfig.json b/pyrightconfig.json index 0a019fc4f..d087425bf 100644 --- a/pyrightconfig.json +++ b/pyrightconfig.json @@ -2,14 +2,8 @@ "typeCheckingMode": "basic", "pythonVersion": "3.11", "pythonPlatform": "All", - "include": [ - "scripts", - "src/pipecat" - ], - "exclude": [ - "**/*_pb2.py", - "**/__pycache__" - ], + "include": ["scripts", "src/pipecat"], + "exclude": ["**/*_pb2.py", "**/__pycache__"], "ignore": [ "tests", "src/pipecat/adapters/base_llm_adapter.py", @@ -40,7 +34,6 @@ "src/pipecat/processors/frameworks/rtvi/processor.py", "src/pipecat/processors/frameworks/strands_agents.py", "src/pipecat/processors/gstreamer/pipeline_source.py", - "src/pipecat/services/ai_service.py", "src/pipecat/services/anthropic/llm.py", "src/pipecat/services/assemblyai/stt.py", "src/pipecat/services/asyncai/tts.py", @@ -106,7 +99,6 @@ "src/pipecat/services/resembleai/tts.py", "src/pipecat/services/rime/tts.py", "src/pipecat/services/sambanova/llm.py", - "src/pipecat/services/sarvam/llm.py", "src/pipecat/services/sarvam/stt.py", "src/pipecat/services/sarvam/tts.py", "src/pipecat/services/simli/video.py", @@ -138,4 +130,4 @@ "src/pipecat/transports/whatsapp/client.py" ], "reportMissingImports": false -} \ No newline at end of file +} diff --git a/src/pipecat/services/ai_service.py b/src/pipecat/services/ai_service.py index 5d914dd00..6e4064976 100644 --- a/src/pipecat/services/ai_service.py +++ b/src/pipecat/services/ai_service.py @@ -66,8 +66,9 @@ class AIService(FrameProcessor): Args: model: The name of the AI model to use. """ + model = self._settings.model self.set_core_metrics_data( - MetricsData(processor=self.name, model=self._settings.model or "") + MetricsData(processor=self.name, model=model if isinstance(model, str) else "") ) async def start(self, frame: StartFrame): diff --git a/src/pipecat/services/sarvam/llm.py b/src/pipecat/services/sarvam/llm.py index d86ba1874..224b2da43 100644 --- a/src/pipecat/services/sarvam/llm.py +++ b/src/pipecat/services/sarvam/llm.py @@ -83,7 +83,10 @@ class SarvamLLMService(OpenAILLMService): if settings is not None: default_settings.apply_update(settings) - self._validate_model(default_settings.model) + model = default_settings.model + if not isinstance(model, str): + raise ValueError("Sarvam LLM requires a non-empty model string.") + self._validate_model(model) super().__init__( api_key=api_key,