From edf4ba45a5c0aafac6f93ba66581f071d10c4e96 Mon Sep 17 00:00:00 2001 From: dhruvladia-sarvam Date: Tue, 17 Mar 2026 02:47:47 +0530 Subject: [PATCH] wrapper fixes --- .../55zzq-update-settings-sarvam-llm.py | 31 +++++++----------- src/pipecat/services/sarvam/__init__.py | 1 - src/pipecat/services/sarvam/llm.py | 32 +++++++++++++------ 3 files changed, 33 insertions(+), 31 deletions(-) diff --git a/examples/foundational/55zzq-update-settings-sarvam-llm.py b/examples/foundational/55zzq-update-settings-sarvam-llm.py index 1d3f9d754..227adb3cb 100644 --- a/examples/foundational/55zzq-update-settings-sarvam-llm.py +++ b/examples/foundational/55zzq-update-settings-sarvam-llm.py @@ -23,7 +23,6 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.sarvam.llm import SarvamLLMService from pipecat.services.sarvam.stt import SarvamSTTService from pipecat.services.sarvam.tts import SarvamTTSService @@ -60,34 +59,24 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): logger.info("Starting bot") stt = SarvamSTTService( - model="saaras:v3", + settings=SarvamSTTService.Settings(model="saaras:v3"), api_key=_require_env("SARVAM_API_KEY"), ) tts = SarvamTTSService( - model="bulbul:v3", + settings=SarvamTTSService.Settings(model="bulbul:v3"), api_key=_require_env("SARVAM_API_KEY"), ) llm = SarvamLLMService( api_key=_require_env("SARVAM_API_KEY"), - model="sarvam-30b", + settings=SarvamLLMService.Settings(model="sarvam-30b"), + system_instruction=( + "You are a helpful LLM in a WebRTC call. Your goal is to demonstrate your capabilities in a succinct way. Your output will be spoken aloud, so avoid special characters that can't easily be spoken, such as emojis or bullet points. Respond to what the user said in a creative and helpful way." + ), ) - messages: list[Any] = [ - { - "role": "system", - "content": ( - "You are a helpful LLM in a WebRTC call. Your goal is to " - "demonstrate your capabilities in a succinct way. Your output " - "will be spoken aloud, so avoid special characters that can't " - "easily be spoken, such as emojis or bullet points. Respond to " - "what the user said in a creative and helpful way." - ), - }, - ] - - context = LLMContext(messages) + context = LLMContext() user_aggregator, assistant_aggregator = LLMContextAggregatorPair( context, user_params=LLMUserAggregatorParams(vad_analyzer=SileroVADAnalyzer()), @@ -117,12 +106,14 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): @transport.event_handler("on_client_connected") async def on_client_connected(transport, client): logger.info("Client connected") - messages.append({"role": "system", "content": "Please introduce yourself to the user."}) + context.add_message({"role": "user", "content": "Please introduce yourself to the user."}) await task.queue_frames([LLMRunFrame()]) await asyncio.sleep(10) logger.info("Updating Sarvam LLM settings: temperature=0.1") - await task.queue_frame(LLMUpdateSettingsFrame(delta=OpenAILLMSettings(temperature=0.1))) + await task.queue_frame( + LLMUpdateSettingsFrame(delta=SarvamLLMService.Settings(temperature=0.1)) + ) @transport.event_handler("on_client_disconnected") async def on_client_disconnected(transport, client): diff --git a/src/pipecat/services/sarvam/__init__.py b/src/pipecat/services/sarvam/__init__.py index 1357f737a..30d115d3f 100644 --- a/src/pipecat/services/sarvam/__init__.py +++ b/src/pipecat/services/sarvam/__init__.py @@ -4,5 +4,4 @@ # SPDX-License-Identifier: BSD 2-Clause License # -from .llm import SarvamLLMService from .tts import * diff --git a/src/pipecat/services/sarvam/llm.py b/src/pipecat/services/sarvam/llm.py index c99e3dfb9..3512778f1 100644 --- a/src/pipecat/services/sarvam/llm.py +++ b/src/pipecat/services/sarvam/llm.py @@ -25,7 +25,6 @@ from pipecat.services.sarvam._sdk import sdk_headers from pipecat.services.settings import NOT_GIVEN as _NOT_GIVEN from pipecat.services.settings import _NotGiven, _warn_deprecated_param, is_given -__all__ = ["SarvamLLMService", "SarvamLLMSettings"] _T = TypeVar("_T") @@ -56,10 +55,10 @@ class SarvamLLMService(OpenAILLMService): - raw Sarvam server error passthrough """ - SUPPORTED_MODELS = frozenset({"sarvam-30b", "sarvam-30b-16k", "sarvam-105b", "sarvam-105b-32k"}) - TOOL_CALLING_MODELS = frozenset( + _SUPPORTED_MODELS = frozenset( {"sarvam-30b", "sarvam-30b-16k", "sarvam-105b", "sarvam-105b-32k"} ) + _TOOL_CALLING_MODELS = _SUPPORTED_MODELS Settings = SarvamLLMSettings _settings: SarvamLLMSettings @@ -94,6 +93,8 @@ class SarvamLLMService(OpenAILLMService): # 2. Apply direct init arg overrides (deprecated) if model is not None: + # Keep deprecated init arg for backward compatibility while steering callers + # to settings=SarvamLLMService.Settings(model=...). _warn_deprecated_param("model", SarvamLLMSettings, "model") default_settings.model = model @@ -101,8 +102,9 @@ class SarvamLLMService(OpenAILLMService): if settings is not None: default_settings.apply_update(settings) - # BaseOpenAILLMService stores settings as OpenAILLMSettings, so keep - # Sarvam-specific runtime knobs in ``extra``. + # BaseOpenAILLMService currently stores settings as OpenAILLMSettings. + # Preserve Sarvam-only runtime knobs in ``extra`` so they survive + # initialization and future update frames. default_settings.extra = dict(default_settings.extra) default_settings.extra.update(self._extract_sarvam_extra_from_settings(default_settings)) @@ -158,6 +160,7 @@ class SarvamLLMService(OpenAILLMService): params.pop("max_completion_tokens", None) params.pop("service_tier", None) + # Sarvam-only fields are bridged through settings.extra (see __init__ and _update_settings). extra = self._settings.extra if isinstance(self._settings.extra, dict) else {} if "wiki_grounding" in extra and extra["wiki_grounding"] is not None: params["wiki_grounding"] = extra["wiki_grounding"] @@ -168,6 +171,8 @@ class SarvamLLMService(OpenAILLMService): async def _update_settings(self, delta: OpenAILLMSettings) -> dict[str, Any]: """Apply settings updates, preserving Sarvam-specific runtime knobs.""" + # LLMUpdateSettingsFrame commonly carries OpenAILLMSettings deltas. + # Lift Sarvam-only fields into delta.extra before delegating to base. sarvam_extra = self._extract_sarvam_extra_from_settings(delta) if sarvam_extra: delta.extra = dict(delta.extra) @@ -176,7 +181,13 @@ class SarvamLLMService(OpenAILLMService): return await super()._update_settings(delta) async def _call_with_raw_sarvam_errors(self, awaitable: Awaitable[_T]) -> _T: - """Await an OpenAI call while preserving Sarvam raw error payloads.""" + """Await an OpenAI call while preserving Sarvam raw error payloads. + + BaseOpenAILLMService handles pipeline-frame exceptions via push_error(), + but direct helper methods like ``get_chat_completions`` and + ``run_inference`` are often consumed directly. We normalize those errors + here so applications consistently receive server-provided messages. + """ try: return await awaitable except (APITimeoutError, asyncio.TimeoutError, httpx.TimeoutException): @@ -208,8 +219,8 @@ class SarvamLLMService(OpenAILLMService): ) def _validate_model(self, model: str): - if model not in self.SUPPORTED_MODELS: - allowed = ", ".join(sorted(self.SUPPORTED_MODELS)) + if model not in self._SUPPORTED_MODELS: + allowed = ", ".join(sorted(self._SUPPORTED_MODELS)) raise ValueError(f"Unsupported Sarvam LLM model '{model}'. Allowed values: {allowed}.") def _extract_sarvam_extra_from_settings(self, settings_obj: Any) -> dict[str, Any]: @@ -238,8 +249,9 @@ class SarvamLLMService(OpenAILLMService): if has_tool_choice and not has_tools: raise ValueError("Sarvam requires non-empty `tools` when `tool_choice` is provided.") - if has_tools and self._settings.model not in self.TOOL_CALLING_MODELS: - allowed = ", ".join(sorted(self.TOOL_CALLING_MODELS)) + # Validate early to provide deterministic errors before network calls. + if has_tools and self._settings.model not in self._TOOL_CALLING_MODELS: + allowed = ", ".join(sorted(self._TOOL_CALLING_MODELS)) raise ValueError( f"Model '{self._settings.model}' does not support tools. " f"Supported models: {allowed}."