Update LLMs

This commit is contained in:
Mark Backman
2026-03-04 21:12:44 -05:00
parent 14c663d03f
commit 53a47c0ef4
27 changed files with 144 additions and 151 deletions

View File

@@ -75,10 +75,12 @@ class AWSBedrockLLMSettings(LLMSettings):
"""Settings for AWS Bedrock LLM services.
Parameters:
stop_sequences: List of strings that stop generation.
latency: Performance mode - "standard" or "optimized".
additional_model_request_fields: Additional model-specific parameters.
"""
stop_sequences: List[str] | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN)
latency: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN)
additional_model_request_fields: Dict[str, Any] | _NotGiven = field(
default_factory=lambda: NOT_GIVEN
@@ -810,6 +812,10 @@ class AWSBedrockLLMService(LLMService):
deprecated parameters and *settings* are provided, *settings*
values take precedence.
stop_sequences: List of strings that stop generation.
.. deprecated:: 0.0.105
Use ``settings=AWSBedrockLLMSettings(stop_sequences=...)`` instead.
client_config: Custom boto3 client configuration.
retry_timeout_secs: Request timeout in seconds for retry logic.
retry_on_timeout: Whether to retry the request once if it times out.
@@ -828,6 +834,7 @@ class AWSBedrockLLMService(LLMService):
seed=None,
filter_incomplete_user_turns=False,
user_turn_completion_config=None,
stop_sequences=None,
latency=None,
additional_model_request_fields={},
)
@@ -836,6 +843,9 @@ class AWSBedrockLLMService(LLMService):
if model is not None:
_warn_deprecated_param("model", AWSBedrockLLMSettings, "model")
default_settings.model = model
if stop_sequences is not None:
_warn_deprecated_param("stop_sequences", AWSBedrockLLMSettings, "stop_sequences")
default_settings.stop_sequences = stop_sequences
# 3. Apply params overrides — only if settings not provided
if params is not None:
@@ -844,6 +854,8 @@ class AWSBedrockLLMService(LLMService):
default_settings.max_tokens = params.max_tokens
default_settings.temperature = params.temperature
default_settings.top_p = params.top_p
if params.stop_sequences:
default_settings.stop_sequences = params.stop_sequences
default_settings.latency = params.latency
if isinstance(params.additional_model_request_fields, dict):
default_settings.additional_model_request_fields = (
@@ -856,14 +868,6 @@ class AWSBedrockLLMService(LLMService):
super().__init__(settings=default_settings, **kwargs)
# Handle stop_sequences (not a settings field)
if stop_sequences is not None:
self._stop_sequences = stop_sequences
elif params is not None:
self._stop_sequences = params.stop_sequences or []
else:
self._stop_sequences = []
# Initialize the AWS Bedrock client
if not client_config:
client_config = Config(
@@ -915,6 +919,8 @@ class AWSBedrockLLMService(LLMService):
inference_config["temperature"] = self._settings.temperature
if self._settings.top_p is not None:
inference_config["topP"] = self._settings.top_p
if self._settings.stop_sequences:
inference_config["stopSequences"] = self._settings.stop_sequences
return inference_config
async def run_inference(

View File

@@ -191,12 +191,12 @@ class AWSNovaSonicLLMSettings(LLMSettings):
"""Settings for AWS Nova Sonic LLM service.
Parameters:
voice_id: Voice for speech synthesis.
voice: Voice identifier for speech synthesis.
endpointing_sensitivity: Controls how quickly Nova Sonic decides the
user has stopped speaking. Can be "LOW", "MEDIUM", or "HIGH".
"""
voice_id: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN)
voice: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN)
endpointing_sensitivity: str | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN)
@@ -250,7 +250,7 @@ class AWSNovaSonicLLMService(LLMService):
- Nova Sonic (the older model): see https://docs.aws.amazon.com/nova/latest/userguide/available-voices.html.
.. deprecated::
Use ``settings=AWSNovaSonicLLMSettings(voice_id=...)`` instead.
Use ``settings=AWSNovaSonicLLMSettings(voice=...)`` instead.
params: Model parameters for audio configuration and inference.
@@ -273,7 +273,7 @@ class AWSNovaSonicLLMService(LLMService):
# 1. Initialize default_settings with hardcoded defaults
default_settings = AWSNovaSonicLLMSettings(
model="amazon.nova-2-sonic-v1:0",
voice_id="matthew",
voice="matthew",
temperature=0.7,
max_tokens=1024,
top_p=0.9,
@@ -291,8 +291,8 @@ class AWSNovaSonicLLMService(LLMService):
_warn_deprecated_param("model", AWSNovaSonicLLMSettings, "model")
default_settings.model = model
if voice_id != "matthew":
_warn_deprecated_param("voice_id", AWSNovaSonicLLMSettings, "voice_id")
default_settings.voice_id = voice_id
_warn_deprecated_param("voice_id", AWSNovaSonicLLMSettings, "voice")
default_settings.voice = voice_id
# 3. Apply params overrides — only if settings not provided
if params is not None:
@@ -811,7 +811,7 @@ class AWSNovaSonicLLMService(LLMService):
"sampleRateHertz": {self._output_sample_rate},
"sampleSizeBits": {self._output_sample_size},
"channelCount": {self._output_channel_count},
"voiceId": "{self._settings.voice_id}",
"voiceId": "{self._settings.voice}",
"encoding": "base64",
"audioType": "SPEECH"
}}{tools_config}

View File

@@ -35,6 +35,8 @@ class AzureRealtimeLLMService(OpenAIRealtimeLLMService):
real-time audio and text communication capabilities as the base OpenAI service.
"""
_settings: AzureRealtimeLLMSettings
def __init__(
self,
*,

View File

@@ -31,6 +31,8 @@ class CerebrasLLMService(OpenAILLMService):
maintaining full compatibility with OpenAI's interface and functionality.
"""
_settings: CerebrasLLMSettings
def __init__(
self,
*,

View File

@@ -31,6 +31,8 @@ class DeepSeekLLMService(OpenAILLMService):
maintaining full compatibility with OpenAI's interface and functionality.
"""
_settings: DeepSeekLLMSettings
def __init__(
self,
*,

View File

@@ -31,6 +31,8 @@ class FireworksLLMService(OpenAILLMService):
maintaining full compatibility with OpenAI's interface and functionality.
"""
_settings: FireworksLLMSettings
def __init__(
self,
*,

View File

@@ -610,6 +610,7 @@ class GeminiLiveLLMSettings(LLMSettings):
"""Settings for Gemini Live LLM services.
Parameters:
voice: TTS voice identifier (e.g. ``"Charon"``).
modalities: Response modalities.
language: Language for generation.
media_resolution: Media resolution setting.
@@ -620,6 +621,7 @@ class GeminiLiveLLMSettings(LLMSettings):
proactivity: Proactivity configuration.
"""
voice: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN)
modalities: GeminiModalities | _NotGiven = field(default_factory=lambda: NOT_GIVEN)
language: Language | str | _NotGiven = field(default_factory=lambda: NOT_GIVEN)
media_resolution: GeminiMediaResolution | _NotGiven = field(default_factory=lambda: NOT_GIVEN)
@@ -680,6 +682,9 @@ class GeminiLiveLLMService(LLMService):
Use ``settings=GeminiLiveLLMSettings(model=...)`` instead.
voice_id: TTS voice identifier. Defaults to "Charon".
.. deprecated:: 0.0.105
Use ``settings=GeminiLiveLLMSettings(voice=...)`` instead.
start_audio_paused: Whether to start with audio input paused. Defaults to False.
start_video_paused: Whether to start with video input paused. Defaults to False.
system_instruction: System prompt for the model. Defaults to None.
@@ -712,6 +717,7 @@ class GeminiLiveLLMService(LLMService):
# 1. Initialize default_settings with hardcoded defaults
default_settings = GeminiLiveLLMSettings(
model="models/gemini-2.5-flash-native-audio-preview-12-2025",
voice="Charon",
frequency_penalty=None,
max_tokens=4096,
presence_penalty=None,
@@ -736,6 +742,9 @@ class GeminiLiveLLMService(LLMService):
if model is not None:
_warn_deprecated_param("model", GeminiLiveLLMSettings, "model")
default_settings.model = model
if voice_id != "Charon":
_warn_deprecated_param("voice_id", GeminiLiveLLMSettings, "voice")
default_settings.voice = voice_id
# 3. Apply params overrides — only if settings not provided
if params is not None:
@@ -776,7 +785,6 @@ class GeminiLiveLLMService(LLMService):
self._last_sent_time = 0
self._base_url = base_url
self._voice_id = voice_id
self._language_code = params.language if params is not None else Language.EN_US
self._system_instruction_from_init = system_instruction
@@ -1184,7 +1192,7 @@ class GeminiLiveLLMService(LLMService):
response_modalities=[Modality(self._settings.modalities.value)],
speech_config=SpeechConfig(
voice_config=VoiceConfig(
prebuilt_voice_config={"voice_name": self._voice_id}
prebuilt_voice_config={"voice_name": self._settings.voice}
),
language_code=self._settings.language,
),

View File

@@ -57,6 +57,8 @@ class GeminiLiveVertexLLMService(GeminiLiveLLMService):
responses, and tool usage.
"""
_settings: GeminiLiveVertexLLMSettings
def __init__(
self,
*,
@@ -90,6 +92,9 @@ class GeminiLiveVertexLLMService(GeminiLiveLLMService):
Use ``settings=GeminiLiveLLMSettings(model=...)`` instead.
voice_id: TTS voice identifier. Defaults to "Charon".
.. deprecated:: 0.0.105
Use ``settings=GeminiLiveVertexLLMSettings(voice=...)`` instead.
start_audio_paused: Whether to start with audio input paused. Defaults to False.
start_video_paused: Whether to start with video input paused. Defaults to False.
system_instruction: System prompt for the model. Defaults to None.
@@ -132,6 +137,7 @@ class GeminiLiveVertexLLMService(GeminiLiveLLMService):
# 1. Initialize default_settings with hardcoded defaults
default_settings = GeminiLiveVertexLLMSettings(
model="google/gemini-live-2.5-flash-native-audio",
voice="Charon",
frequency_penalty=None,
max_tokens=4096,
presence_penalty=None,
@@ -156,6 +162,9 @@ class GeminiLiveVertexLLMService(GeminiLiveLLMService):
if model is not None:
_warn_deprecated_param("model", GeminiLiveVertexLLMSettings, "model")
default_settings.model = model
if voice_id != "Charon":
_warn_deprecated_param("voice_id", GeminiLiveVertexLLMSettings, "voice")
default_settings.voice = voice_id
# 3. Apply params overrides — only if settings not provided
if params is not None:
@@ -193,7 +202,6 @@ class GeminiLiveVertexLLMService(GeminiLiveLLMService):
# api_key is required by parent class, but actually not used with
# Vertex
api_key="dummy",
voice_id=voice_id,
start_audio_paused=start_audio_paused,
start_video_paused=start_video_paused,
system_instruction=system_instruction,

View File

@@ -58,6 +58,8 @@ class GoogleLLMOpenAIBetaService(OpenAILLMService):
https://ai.google.dev/gemini-api/docs/openai
"""
_settings: GoogleOpenAILLMSettings
def __init__(
self,
*,

View File

@@ -59,6 +59,8 @@ class GoogleVertexLLMService(GoogleLLMService):
https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/inference
"""
_settings: GoogleVertexLLMSettings
class InputParams(GoogleLLMService.InputParams):
"""Input parameters specific to Vertex AI.

View File

@@ -86,6 +86,8 @@ class GrokLLMService(OpenAILLMService):
processing and reports final totals.
"""
_settings: GrokLLMSettings
def __init__(
self,
*,

View File

@@ -13,7 +13,7 @@ https://docs.x.ai/docs/guides/voice/agent
import base64
import json
import time
from dataclasses import dataclass, field
from dataclasses import dataclass
from typing import Any, Optional
from loguru import logger
@@ -56,7 +56,7 @@ from pipecat.processors.aggregators.llm_response_universal import (
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
from pipecat.processors.frame_processor import FrameDirection
from pipecat.services.llm_service import FunctionCallFromLLM, LLMService
from pipecat.services.settings import NOT_GIVEN, LLMSettings, _NotGiven, _warn_deprecated_param
from pipecat.services.settings import LLMSettings
from pipecat.utils.time import time_now_iso8601
from . import events
@@ -88,15 +88,9 @@ class CurrentAudioResponse:
@dataclass
class GrokRealtimeLLMSettings(LLMSettings):
"""Settings for Grok Realtime LLM services.
"""Settings for Grok Realtime LLM services."""
Parameters:
session_properties: Grok Realtime session configuration.
"""
session_properties: events.SessionProperties | _NotGiven = field(
default_factory=lambda: NOT_GIVEN
)
pass
class GrokRealtimeLLMService(LLMService):
@@ -137,19 +131,13 @@ class GrokRealtimeLLMService(LLMService):
base_url: WebSocket base URL for the realtime API.
Defaults to "wss://api.x.ai/v1/realtime".
session_properties: Configuration properties for the realtime session.
.. deprecated::
Use ``settings=GrokRealtimeLLMSettings(session_properties=...)``
instead.
If None, uses default SessionProperties with voice "Ara".
To set a different voice, configure it in session_properties:
session_properties = events.SessionProperties(voice="Rex")
Available voices: Ara, Rex, Sal, Eve, Leo.
settings: Grok Realtime LLM settings. If provided together with deprecated
top-level parameters, the ``settings`` values take precedence.
settings: Runtime-updatable settings for this service.
start_audio_paused: Whether to start with audio input paused. Defaults to False.
**kwargs: Additional arguments passed to parent LLMService.
"""
@@ -165,17 +153,9 @@ class GrokRealtimeLLMService(LLMService):
seed=None,
filter_incomplete_user_turns=False,
user_turn_completion_config=None,
session_properties=events.SessionProperties(),
)
# 2. Apply direct init arg overrides (deprecated)
if session_properties is not None:
_warn_deprecated_param(
"session_properties", GrokRealtimeLLMSettings, "session_properties"
)
default_settings.session_properties = session_properties
# 4. Apply settings delta (canonical API, always wins)
# 2. Apply settings delta (canonical API, always wins)
if settings is not None:
default_settings.apply_update(settings)
@@ -187,6 +167,7 @@ class GrokRealtimeLLMService(LLMService):
self.api_key = api_key
self.base_url = base_url
self._session_properties = session_properties or events.SessionProperties()
self._audio_input_paused = start_audio_paused
self._websocket = None
@@ -235,13 +216,13 @@ class GrokRealtimeLLMService(LLMService):
Configured sample rate or None if not manually configured.
For PCMU/PCMA formats, returns 8000 Hz (G.711 standard).
"""
if not self._settings.session_properties.audio:
if not self._session_properties.audio:
return None
audio_config = (
self._settings.session_properties.audio.input
self._session_properties.audio.input
if direction == "input"
else self._settings.session_properties.audio.output
else self._session_properties.audio.output
)
if audio_config and audio_config.format:
@@ -271,8 +252,8 @@ class GrokRealtimeLLMService(LLMService):
def _is_turn_detection_enabled(self) -> bool:
"""Check if server-side VAD is enabled."""
if self._settings.session_properties.turn_detection:
return self._settings.session_properties.turn_detection.type == "server_vad"
if self._session_properties.turn_detection:
return self._session_properties.turn_detection.type == "server_vad"
return False
async def _handle_interruption(self):
@@ -339,7 +320,7 @@ class GrokRealtimeLLMService(LLMService):
input_sample_rate: Sample rate for audio input (Hz).
output_sample_rate: Sample rate for audio output (Hz).
"""
props = self._settings.session_properties
props = self._session_properties
if not props.audio:
props.audio = events.AudioConfiguration()
if not props.audio.input:
@@ -395,7 +376,12 @@ class GrokRealtimeLLMService(LLMService):
# directly. The frame.delta path falls through to super, which calls
# _update_settings → our override handles the rest.
if isinstance(frame, LLMUpdateSettingsFrame) and frame.delta is None:
self._settings.session_properties = events.SessionProperties(**frame.settings)
# Capture current audio config before replacing session properties.
input_rate = self._get_configured_sample_rate("input")
output_rate = self._get_configured_sample_rate("output")
self._session_properties = events.SessionProperties(**frame.settings)
if input_rate and output_rate:
self._ensure_audio_config(input_rate, output_rate)
await self._send_session_update()
await self.push_frame(frame, direction)
return
@@ -498,29 +484,14 @@ class GrokRealtimeLLMService(LLMService):
await self.push_error(error_msg=f"Error sending client event: {e}", exception=e)
async def _update_settings(self, delta):
"""Apply a settings delta, sending a session update if needed."""
# Capture current sample rates before the update replaces them.
input_rate = self._get_configured_sample_rate("input")
output_rate = self._get_configured_sample_rate("output")
"""Apply a settings delta."""
changed = await super()._update_settings(delta)
if "session_properties" in changed:
if input_rate and output_rate:
self._ensure_audio_config(input_rate, output_rate)
else:
logger.warning(
"Attempting to apply session properties update without configured sample rates. "
"Audio configuration may be incomplete."
)
await self._send_session_update()
self._warn_unhandled_updated_settings(changed.keys() - {"session_properties"})
self._warn_unhandled_updated_settings(changed.keys())
return changed
async def _send_session_update(self):
"""Update session settings on the server."""
settings = self._settings.session_properties
settings = self._session_properties
adapter: GrokRealtimeLLMAdapter = self.get_llm_adapter()
if self._context:

View File

@@ -30,6 +30,8 @@ class GroqLLMService(OpenAILLMService):
maintaining full compatibility with OpenAI's interface and functionality.
"""
_settings: GroqLLMSettings
def __init__(
self,
*,

View File

@@ -33,6 +33,8 @@ class MistralLLMService(OpenAILLMService):
maintaining full compatibility with OpenAI's interface and functionality.
"""
_settings: MistralLLMSettings
def __init__(
self,
*,

View File

@@ -36,6 +36,8 @@ class NvidiaLLMService(OpenAILLMService):
in token usage reporting between NIM (incremental) and OpenAI (final summary).
"""
_settings: NvidiaLLMSettings
def __init__(
self,
*,

View File

@@ -30,6 +30,8 @@ class OLLamaLLMService(OpenAILLMService):
providing a compatible interface for running large language models locally.
"""
_settings: OllamaLLMSettings
def __init__(
self,
*,

View File

@@ -53,11 +53,9 @@ class OpenAILLMSettings(LLMSettings):
Parameters:
max_completion_tokens: Maximum completion tokens to generate.
service_tier: Service tier to use (e.g., "auto", "flex", "priority").
"""
max_completion_tokens: int | _NotGiven = field(default_factory=lambda: _NOT_GIVEN)
service_tier: str | _NotGiven = field(default_factory=lambda: _NOT_GIVEN)
class BaseOpenAILLMService(LLMService):
@@ -118,6 +116,7 @@ class BaseOpenAILLMService(LLMService):
organization=None,
project=None,
default_headers: Optional[Mapping[str, str]] = None,
service_tier: Optional[str] = None,
params: Optional[InputParams] = None,
settings: Optional[OpenAILLMSettings] = None,
retry_timeout_secs: Optional[float] = 5.0,
@@ -138,6 +137,7 @@ class BaseOpenAILLMService(LLMService):
organization: OpenAI organization ID.
project: OpenAI project ID.
default_headers: Additional HTTP headers to include in requests.
service_tier: Service tier to use (e.g., "auto", "flex", "priority").
params: Input parameters for model configuration and behavior.
.. deprecated:: 0.0.105
@@ -161,7 +161,6 @@ class BaseOpenAILLMService(LLMService):
top_k=None,
max_tokens=NOT_GIVEN,
max_completion_tokens=NOT_GIVEN,
service_tier=NOT_GIVEN,
filter_incomplete_user_turns=False,
user_turn_completion_config=None,
extra={},
@@ -180,7 +179,6 @@ class BaseOpenAILLMService(LLMService):
default_settings.top_p = params.top_p
default_settings.max_tokens = params.max_tokens
default_settings.max_completion_tokens = params.max_completion_tokens
default_settings.service_tier = params.service_tier
if isinstance(params.extra, dict):
default_settings.extra = params.extra
@@ -192,6 +190,7 @@ class BaseOpenAILLMService(LLMService):
settings=default_settings,
**kwargs,
)
self._service_tier = service_tier
self._retry_timeout_secs = retry_timeout_secs
self._retry_on_timeout = retry_on_timeout
self._system_instruction = system_instruction
@@ -321,7 +320,7 @@ class BaseOpenAILLMService(LLMService):
"top_p": self._settings.top_p,
"max_tokens": self._settings.max_tokens,
"max_completion_tokens": self._settings.max_completion_tokens,
"service_tier": self._settings.service_tier,
"service_tier": self._service_tier,
}
# Messages, tools, tool_choice

View File

@@ -76,6 +76,7 @@ class OpenAILLMService(BaseOpenAILLMService):
self,
*,
model: Optional[str] = None,
service_tier: Optional[str] = None,
params: Optional[BaseOpenAILLMService.InputParams] = None,
settings: Optional[OpenAILLMSettings] = None,
**kwargs,
@@ -88,6 +89,7 @@ class OpenAILLMService(BaseOpenAILLMService):
.. deprecated:: 0.0.105
Use ``settings=OpenAILLMSettings(model=...)`` instead.
service_tier: Service tier to use (e.g., "auto", "flex", "priority").
params: Input parameters for model configuration.
.. deprecated:: 0.0.105
@@ -108,7 +110,6 @@ class OpenAILLMService(BaseOpenAILLMService):
top_k=None,
max_tokens=NOT_GIVEN,
max_completion_tokens=NOT_GIVEN,
service_tier=NOT_GIVEN,
filter_incomplete_user_turns=False,
user_turn_completion_config=None,
extra={},
@@ -119,6 +120,10 @@ class OpenAILLMService(BaseOpenAILLMService):
_warn_deprecated_param("model", OpenAILLMSettings, "model")
default_settings.model = model
# Handle service_tier from deprecated params
if params is not None and not settings and params.service_tier is not NOT_GIVEN:
service_tier = service_tier or params.service_tier
# 3. Apply params overrides — only if settings not provided
if params is not None:
_warn_deprecated_param("params", OpenAILLMSettings)
@@ -130,7 +135,6 @@ class OpenAILLMService(BaseOpenAILLMService):
default_settings.top_p = params.top_p
default_settings.max_tokens = params.max_tokens
default_settings.max_completion_tokens = params.max_completion_tokens
default_settings.service_tier = params.service_tier
if isinstance(params.extra, dict):
default_settings.extra = params.extra
@@ -138,7 +142,7 @@ class OpenAILLMService(BaseOpenAILLMService):
if settings is not None:
default_settings.apply_update(settings)
super().__init__(settings=default_settings, **kwargs)
super().__init__(service_tier=service_tier, settings=default_settings, **kwargs)
def create_context_aggregator(
self,

View File

@@ -10,7 +10,7 @@ import base64
import io
import json
import time
from dataclasses import dataclass, field
from dataclasses import dataclass
from typing import Any, Optional
from loguru import logger
@@ -59,7 +59,7 @@ from pipecat.processors.aggregators.openai_llm_context import (
)
from pipecat.processors.frame_processor import FrameDirection
from pipecat.services.llm_service import FunctionCallFromLLM, LLMService
from pipecat.services.settings import NOT_GIVEN, LLMSettings, _NotGiven, _warn_deprecated_param
from pipecat.services.settings import LLMSettings, _warn_deprecated_param
from pipecat.transcriptions.language import Language
from pipecat.utils.time import time_now_iso8601
from pipecat.utils.tracing.service_decorators import traced_openai_realtime, traced_stt
@@ -93,15 +93,9 @@ class CurrentAudioResponse:
@dataclass
class OpenAIRealtimeLLMSettings(LLMSettings):
"""Settings for OpenAI Realtime LLM services.
"""Settings for OpenAI Realtime LLM services."""
Parameters:
session_properties: OpenAI Realtime session configuration.
"""
session_properties: events.SessionProperties | _NotGiven = field(
default_factory=lambda: NOT_GIVEN
)
pass
class OpenAIRealtimeLLMService(LLMService):
@@ -145,15 +139,8 @@ class OpenAIRealtimeLLMService(LLMService):
base_url: WebSocket base URL for the realtime API.
Defaults to "wss://api.openai.com/v1/realtime".
session_properties: Configuration properties for the realtime session.
.. deprecated::
Use ``settings=OpenAIRealtimeLLMSettings(session_properties=...)``
instead.
These are session-level settings that can be updated during the session
(except for voice and model). If None, uses default SessionProperties.
settings: Realtime LLM settings. If provided together with deprecated
top-level parameters, the ``settings`` values take precedence.
If None, uses default SessionProperties.
settings: Runtime-updatable settings for this service.
start_audio_paused: Whether to start with audio input paused. Defaults to False.
start_video_paused: Whether to start with video input paused. Defaults to False.
video_frame_detail: Detail level for video processing. Can be "auto", "low", or "high".
@@ -192,20 +179,14 @@ class OpenAIRealtimeLLMService(LLMService):
seed=None,
filter_incomplete_user_turns=False,
user_turn_completion_config=None,
session_properties=events.SessionProperties(),
)
# 2. Apply direct init arg overrides (deprecated)
if model is not None:
_warn_deprecated_param("model", OpenAIRealtimeLLMSettings, "model")
default_settings.model = model
if session_properties is not None:
_warn_deprecated_param(
"session_properties", OpenAIRealtimeLLMSettings, "session_properties"
)
default_settings.session_properties = session_properties
# 4. Apply settings delta (canonical API, always wins)
# 3. Apply settings delta (canonical API, always wins)
if settings is not None:
default_settings.apply_update(settings)
@@ -220,6 +201,7 @@ class OpenAIRealtimeLLMService(LLMService):
self.api_key = api_key
self.base_url = full_url
self._session_properties = session_properties or events.SessionProperties()
self._audio_input_paused = start_audio_paused
self._video_input_paused = start_video_paused
self._video_frame_detail = video_frame_detail
@@ -282,12 +264,12 @@ class OpenAIRealtimeLLMService(LLMService):
def _is_modality_enabled(self, modality: str) -> bool:
"""Check if a specific modality is enabled, "text" or "audio"."""
modalities = self._settings.session_properties.output_modalities or ["audio", "text"]
modalities = self._session_properties.output_modalities or ["audio", "text"]
return modality in modalities
def _get_enabled_modalities(self) -> list[str]:
"""Get the list of enabled modalities."""
modalities = self._settings.session_properties.output_modalities or ["audio", "text"]
modalities = self._session_properties.output_modalities or ["audio", "text"]
# API only supports single modality responses: either ["text"] or ["audio"]
if "audio" in modalities:
return ["audio"]
@@ -360,9 +342,9 @@ class OpenAIRealtimeLLMService(LLMService):
# None and False are different. Check for False. None means we're using OpenAI's
# built-in turn detection defaults.
turn_detection_disabled = (
self._settings.session_properties.audio
and self._settings.session_properties.audio.input
and self._settings.session_properties.audio.input.turn_detection is False
self._session_properties.audio
and self._session_properties.audio.input
and self._session_properties.audio.input.turn_detection is False
)
if turn_detection_disabled:
await self.send_client_event(events.InputAudioBufferClearEvent())
@@ -382,9 +364,9 @@ class OpenAIRealtimeLLMService(LLMService):
# None and False are different. Check for False. None means we're using OpenAI's
# built-in turn detection defaults.
turn_detection_disabled = (
self._settings.session_properties.audio
and self._settings.session_properties.audio.input
and self._settings.session_properties.audio.input.turn_detection is False
self._session_properties.audio
and self._session_properties.audio.input
and self._session_properties.audio.input.turn_detection is False
)
if turn_detection_disabled:
await self.send_client_event(events.InputAudioBufferCommitEvent())
@@ -457,7 +439,7 @@ class OpenAIRealtimeLLMService(LLMService):
# directly. The frame.delta path falls through to super, which calls
# _update_settings → our override handles the rest.
if isinstance(frame, LLMUpdateSettingsFrame) and frame.delta is None:
self._settings.session_properties = events.SessionProperties(**frame.settings)
self._session_properties = events.SessionProperties(**frame.settings)
await self._send_session_update()
await self.push_frame(frame, direction)
return
@@ -576,15 +558,13 @@ class OpenAIRealtimeLLMService(LLMService):
await self.push_error(error_msg=f"Error sending client event: {e}", exception=e)
async def _update_settings(self, delta):
"""Apply a settings delta, sending a session update if needed."""
"""Apply a settings delta."""
changed = await super()._update_settings(delta)
if "session_properties" in changed:
await self._send_session_update()
self._warn_unhandled_updated_settings(changed.keys() - {"session_properties"})
self._warn_unhandled_updated_settings(changed.keys())
return changed
async def _send_session_update(self):
settings = self._settings.session_properties
settings = self._session_properties
adapter: OpenAIRealtimeLLMAdapter = self.get_llm_adapter()
if self._context:

View File

@@ -42,6 +42,8 @@ class AzureRealtimeBetaLLMService(OpenAIRealtimeBetaLLMService):
real-time audio and text communication capabilities as the base OpenAI service.
"""
_settings: AzureRealtimeBetaLLMSettings
def __init__(
self,
*,

View File

@@ -10,7 +10,7 @@ import base64
import json
import time
import warnings
from dataclasses import dataclass, field
from dataclasses import dataclass
from typing import Optional
from loguru import logger
@@ -54,7 +54,7 @@ from pipecat.processors.aggregators.openai_llm_context import (
from pipecat.processors.frame_processor import FrameDirection
from pipecat.services.llm_service import FunctionCallFromLLM, LLMService
from pipecat.services.openai.llm import OpenAIContextAggregatorPair
from pipecat.services.settings import NOT_GIVEN, LLMSettings, _NotGiven, _warn_deprecated_param
from pipecat.services.settings import LLMSettings, _warn_deprecated_param
from pipecat.transcriptions.language import Language
from pipecat.utils.time import time_now_iso8601
from pipecat.utils.tracing.service_decorators import traced_openai_realtime, traced_stt
@@ -94,15 +94,9 @@ class CurrentAudioResponse:
@dataclass
class OpenAIRealtimeBetaLLMSettings(LLMSettings):
"""Settings for OpenAI Realtime Beta LLM services.
"""Settings for OpenAI Realtime Beta LLM services."""
Parameters:
session_properties: OpenAI Realtime session configuration.
"""
session_properties: events.SessionProperties | _NotGiven = field(
default_factory=lambda: NOT_GIVEN
)
pass
class OpenAIRealtimeBetaLLMService(LLMService):
@@ -146,14 +140,8 @@ class OpenAIRealtimeBetaLLMService(LLMService):
base_url: WebSocket base URL for the realtime API.
Defaults to "wss://api.openai.com/v1/realtime".
session_properties: Configuration properties for the realtime session.
.. deprecated::
Use ``settings=OpenAIRealtimeBetaLLMSettings(session_properties=...)``
instead.
If None, uses default SessionProperties.
settings: Realtime Beta LLM settings. If provided together with deprecated
top-level parameters, the ``settings`` values take precedence.
settings: Runtime-updatable settings for this service.
start_audio_paused: Whether to start with audio input paused. Defaults to False.
send_transcription_frames: Whether to emit transcription frames. Defaults to True.
**kwargs: Additional arguments passed to parent LLMService.
@@ -179,20 +167,13 @@ class OpenAIRealtimeBetaLLMService(LLMService):
seed=None,
filter_incomplete_user_turns=False,
user_turn_completion_config=None,
session_properties=events.SessionProperties(),
)
# 2. Apply direct init arg overrides (deprecated)
if model is not None:
_warn_deprecated_param("model", OpenAIRealtimeBetaLLMSettings, "model")
default_settings.model = model
if session_properties is not None:
_warn_deprecated_param(
"session_properties", OpenAIRealtimeBetaLLMSettings, "session_properties"
)
default_settings.session_properties = session_properties
# 4. Apply settings delta (canonical API, always wins)
# 3. Apply settings delta (canonical API, always wins)
if settings is not None:
default_settings.apply_update(settings)
@@ -205,6 +186,7 @@ class OpenAIRealtimeBetaLLMService(LLMService):
self.api_key = api_key
self.base_url = full_url
self._session_properties = session_properties or events.SessionProperties()
self._audio_input_paused = start_audio_paused
self._send_transcription_frames = send_transcription_frames
self._websocket = None
@@ -243,12 +225,12 @@ class OpenAIRealtimeBetaLLMService(LLMService):
def _is_modality_enabled(self, modality: str) -> bool:
"""Check if a specific modality is enabled, "text" or "audio"."""
modalities = self._settings.session_properties.modalities or ["audio", "text"]
modalities = self._session_properties.modalities or ["audio", "text"]
return modality in modalities
def _get_enabled_modalities(self) -> list[str]:
"""Get the list of enabled modalities."""
return self._settings.session_properties.modalities or ["audio", "text"]
return self._session_properties.modalities or ["audio", "text"]
async def retrieve_conversation_item(self, item_id: str):
"""Retrieve a conversation item by ID from the server.
@@ -315,7 +297,7 @@ class OpenAIRealtimeBetaLLMService(LLMService):
async def _handle_interruption(self):
# None and False are different. Check for False. None means we're using OpenAI's
# built-in turn detection defaults.
if self._settings.session_properties.turn_detection is False:
if self._session_properties.turn_detection is False:
await self.send_client_event(events.InputAudioBufferClearEvent())
await self.send_client_event(events.ResponseCancelEvent())
await self._truncate_current_audio_response()
@@ -332,7 +314,7 @@ class OpenAIRealtimeBetaLLMService(LLMService):
async def _handle_user_stopped_speaking(self, frame):
# None and False are different. Check for False. None means we're using OpenAI's
# built-in turn detection defaults.
if self._settings.session_properties.turn_detection is False:
if self._session_properties.turn_detection is False:
await self.send_client_event(events.InputAudioBufferCommitEvent())
await self.send_client_event(events.ResponseCreateEvent())
@@ -403,7 +385,7 @@ class OpenAIRealtimeBetaLLMService(LLMService):
# directly. The frame.delta path falls through to super, which calls
# _update_settings → our override handles the rest.
if isinstance(frame, LLMUpdateSettingsFrame) and frame.delta is None:
self._settings.session_properties = events.SessionProperties(**frame.settings)
self._session_properties = events.SessionProperties(**frame.settings)
await self._send_session_update()
await self.push_frame(frame, direction)
return
@@ -520,14 +502,13 @@ class OpenAIRealtimeBetaLLMService(LLMService):
await self.push_error(error_msg=f"Error sending client event: {e}", exception=e)
async def _update_settings(self, delta):
"""Apply a settings delta, sending a session update if needed."""
"""Apply a settings delta."""
changed = await super()._update_settings(delta)
if "session_properties" in changed:
await self._send_session_update()
self._warn_unhandled_updated_settings(changed.keys())
return changed
async def _send_session_update(self):
settings = self._settings.session_properties
settings = self._session_properties
# tools given in the context override the tools in the session properties
if self._context and self._context.tools:
settings.tools = self._context.tools

View File

@@ -43,6 +43,8 @@ class OpenPipeLLMService(OpenAILLMService):
for model training and evaluation.
"""
_settings: OpenPipeLLMSettings
def __init__(
self,
*,

View File

@@ -34,6 +34,8 @@ class OpenRouterLLMService(OpenAILLMService):
maintaining full compatibility with OpenAI's interface and functionality.
"""
_settings: OpenRouterLLMSettings
def __init__(
self,
*,

View File

@@ -38,6 +38,8 @@ class PerplexityLLMService(OpenAILLMService):
in token usage reporting between Perplexity (incremental) and OpenAI (final summary).
"""
_settings: PerplexityLLMSettings
def __init__(
self,
*,

View File

@@ -30,6 +30,8 @@ class QwenLLMService(OpenAILLMService):
maintaining full compatibility with OpenAI's interface and functionality.
"""
_settings: QwenLLMSettings
def __init__(
self,
*,

View File

@@ -42,6 +42,8 @@ class SambaNovaLLMService(OpenAILLMService): # type: ignore
maintaining full compatibility with OpenAI's interface and functionality.
"""
_settings: SambaNovaLLMSettings
def __init__(
self,
*,

View File

@@ -30,6 +30,8 @@ class TogetherLLMService(OpenAILLMService):
maintaining full compatibility with OpenAI's interface and functionality.
"""
_settings: TogetherLLMSettings
def __init__(
self,
*,