Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/blaxel/livekit/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,21 @@

logger = getLogger(__name__)

GPT_54_REASONING_MODELS = {"gpt-5.4", "gpt-5.4-mini", "gpt-5.4-nano"}


def _provider_type_value(provider_type):
return getattr(provider_type, "value", provider_type)


def _set_default_reasoning_effort(provider_type, model: str, kwargs: dict):
if (
_provider_type_value(provider_type) == "openai"
and model in GPT_54_REASONING_MODELS
and "reasoning_effort" not in kwargs
):
kwargs["reasoning_effort"] = "none"


class DynamicHeadersHTTPClient(httpx.AsyncClient):
"""Custom HTTP client that dynamically updates headers on each request."""
Expand All @@ -31,6 +46,8 @@ async def send(self, request, *args, **kwargs):


async def get_livekit_model(url: str, type: str, model: str, **kwargs):
_set_default_reasoning_effort(type, model, kwargs)

# Create custom HTTP client with dynamic headers
http_client = AsyncOpenAI(
base_url=f"{url}/v1",
Expand Down
42 changes: 42 additions & 0 deletions tests/integration/livekit/test_model.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
"""LiveKit Model Integration Tests."""

pytest_plugins = []
from unittest.mock import Mock, patch

import pytest # noqa: E402

pytest.importorskip(
Expand All @@ -10,12 +12,52 @@
from livekit.agents.llm import ChatContext # noqa: E402

from blaxel.livekit import bl_model # noqa: E402
from blaxel.livekit.model import get_livekit_model # noqa: E402

TEST_MODELS = [
"sandbox-openai",
]


async def _created_livekit_kwargs(provider_type: str, model: str, **kwargs):
llm = Mock(name="llm")
http_client = Mock(name="http_client")
openai_client = Mock(name="openai_client")

with (
patch("blaxel.livekit.model.DynamicHeadersHTTPClient", return_value=http_client),
patch("blaxel.livekit.model.AsyncOpenAI", return_value=openai_client),
patch("blaxel.livekit.model.openai.LLM", return_value=llm) as llm_factory,
):
result = await get_livekit_model("https://example.com/models/test", provider_type, model, **kwargs)

assert result is llm
return llm_factory.call_args.kwargs


@pytest.mark.asyncio
async def test_gpt54_openai_models_default_reasoning_effort_to_none():
for model_name in ["gpt-5.4", "gpt-5.4-mini", "gpt-5.4-nano"]:
kwargs = await _created_livekit_kwargs("openai", model_name)

assert kwargs["model"] == model_name
assert kwargs["reasoning_effort"] == "none"


@pytest.mark.asyncio
async def test_livekit_reasoning_effort_override_is_preserved():
kwargs = await _created_livekit_kwargs("openai", "gpt-5.4-mini", reasoning_effort="low")

assert kwargs["reasoning_effort"] == "low"


@pytest.mark.asyncio
async def test_livekit_non_openai_provider_does_not_default_reasoning_effort():
kwargs = await _created_livekit_kwargs("xai", "gpt-5.4-mini")

assert "reasoning_effort" not in kwargs


@pytest.mark.asyncio(loop_scope="class")
class TestBlModel:
"""Test bl_model functionality."""
Expand Down
Loading