test, refactor: follow-ups to LLMService generic refactor
Two follow-ups now that LLMService is generic over its adapter: - Add an explicit backward-compat test verifying that an LLMService subclass with no generic parameter (the third-party-provider pattern) instantiates and returns a usable adapter. The existing MockLLMService (declared without brackets) already exercised this implicitly, but it's worth a named assertion. - Drop the now-redundant `params: SomeLLMInvocationParams = ...` variable annotations on `adapter.get_llm_invocation_params()` results. Since `get_llm_adapter()` now returns the precise adapter type, and `BaseLLMAdapter` is generic in its invocation-params type, the call already infers the right TypedDict.
This commit is contained in:
@@ -329,7 +329,7 @@ class AnthropicLLMService(LLMService[AnthropicLLMAdapter]):
|
|||||||
|
|
||||||
def _get_llm_invocation_params(self, context: LLMContext) -> AnthropicLLMInvocationParams:
|
def _get_llm_invocation_params(self, context: LLMContext) -> AnthropicLLMInvocationParams:
|
||||||
adapter = self.get_llm_adapter()
|
adapter = self.get_llm_adapter()
|
||||||
params: AnthropicLLMInvocationParams = adapter.get_llm_invocation_params(
|
params = adapter.get_llm_invocation_params(
|
||||||
context,
|
context,
|
||||||
enable_prompt_caching=assert_given(self._settings.enable_prompt_caching),
|
enable_prompt_caching=assert_given(self._settings.enable_prompt_caching),
|
||||||
system_instruction=assert_given(self._settings.system_instruction),
|
system_instruction=assert_given(self._settings.system_instruction),
|
||||||
|
|||||||
@@ -283,7 +283,7 @@ class AWSBedrockLLMService(LLMService[AWSBedrockLLMAdapter]):
|
|||||||
self._settings.system_instruction
|
self._settings.system_instruction
|
||||||
)
|
)
|
||||||
adapter = self.get_llm_adapter()
|
adapter = self.get_llm_adapter()
|
||||||
params: AWSBedrockLLMInvocationParams = adapter.get_llm_invocation_params(
|
params = adapter.get_llm_invocation_params(
|
||||||
context, system_instruction=effective_instruction
|
context, system_instruction=effective_instruction
|
||||||
)
|
)
|
||||||
messages = params["messages"]
|
messages = params["messages"]
|
||||||
@@ -372,7 +372,7 @@ class AWSBedrockLLMService(LLMService[AWSBedrockLLMAdapter]):
|
|||||||
|
|
||||||
def _get_llm_invocation_params(self, context: LLMContext) -> AWSBedrockLLMInvocationParams:
|
def _get_llm_invocation_params(self, context: LLMContext) -> AWSBedrockLLMInvocationParams:
|
||||||
adapter = self.get_llm_adapter()
|
adapter = self.get_llm_adapter()
|
||||||
params: AWSBedrockLLMInvocationParams = adapter.get_llm_invocation_params(
|
params = adapter.get_llm_invocation_params(
|
||||||
context, system_instruction=assert_given(self._settings.system_instruction)
|
context, system_instruction=assert_given(self._settings.system_instruction)
|
||||||
)
|
)
|
||||||
return params
|
return params
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ from loguru import logger
|
|||||||
from PIL import Image
|
from PIL import Image
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
from pipecat.adapters.services.gemini_adapter import GeminiLLMAdapter, GeminiLLMInvocationParams
|
from pipecat.adapters.services.gemini_adapter import GeminiLLMAdapter
|
||||||
from pipecat.frames.frames import (
|
from pipecat.frames.frames import (
|
||||||
AssistantImageRawFrame,
|
AssistantImageRawFrame,
|
||||||
Frame,
|
Frame,
|
||||||
@@ -292,7 +292,7 @@ class GoogleLLMService(LLMService[GeminiLLMAdapter]):
|
|||||||
tools = []
|
tools = []
|
||||||
effective_instruction = system_instruction or self._settings.system_instruction
|
effective_instruction = system_instruction or self._settings.system_instruction
|
||||||
adapter = self.get_llm_adapter()
|
adapter = self.get_llm_adapter()
|
||||||
params: GeminiLLMInvocationParams = adapter.get_llm_invocation_params(
|
params = adapter.get_llm_invocation_params(
|
||||||
context, system_instruction=effective_instruction
|
context, system_instruction=effective_instruction
|
||||||
)
|
)
|
||||||
messages = params["messages"]
|
messages = params["messages"]
|
||||||
@@ -387,7 +387,7 @@ class GoogleLLMService(LLMService[GeminiLLMAdapter]):
|
|||||||
|
|
||||||
async def _stream_content(self, context: LLMContext) -> AsyncIterator[GenerateContentResponse]:
|
async def _stream_content(self, context: LLMContext) -> AsyncIterator[GenerateContentResponse]:
|
||||||
adapter = self.get_llm_adapter()
|
adapter = self.get_llm_adapter()
|
||||||
params: GeminiLLMInvocationParams = adapter.get_llm_invocation_params(
|
params = adapter.get_llm_invocation_params(
|
||||||
context, system_instruction=assert_given(self._settings.system_instruction)
|
context, system_instruction=assert_given(self._settings.system_instruction)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -297,7 +297,7 @@ class BaseOpenAILLMService(LLMService[OpenAILLMAdapter]):
|
|||||||
f"{self}: Generating chat from context {adapter.get_messages_for_logging(context)}"
|
f"{self}: Generating chat from context {adapter.get_messages_for_logging(context)}"
|
||||||
)
|
)
|
||||||
|
|
||||||
params_from_context: OpenAILLMInvocationParams = adapter.get_llm_invocation_params(
|
params_from_context = adapter.get_llm_invocation_params(
|
||||||
context,
|
context,
|
||||||
system_instruction=self._settings.system_instruction,
|
system_instruction=self._settings.system_instruction,
|
||||||
convert_developer_to_user=not self.supports_developer_role,
|
convert_developer_to_user=not self.supports_developer_role,
|
||||||
@@ -374,7 +374,7 @@ class BaseOpenAILLMService(LLMService[OpenAILLMAdapter]):
|
|||||||
"""
|
"""
|
||||||
effective_instruction = system_instruction or self._settings.system_instruction
|
effective_instruction = system_instruction or self._settings.system_instruction
|
||||||
adapter = self.get_llm_adapter()
|
adapter = self.get_llm_adapter()
|
||||||
invocation_params: OpenAILLMInvocationParams = adapter.get_llm_invocation_params(
|
invocation_params = adapter.get_llm_invocation_params(
|
||||||
context,
|
context,
|
||||||
system_instruction=effective_instruction,
|
system_instruction=effective_instruction,
|
||||||
convert_developer_to_user=not self.supports_developer_role,
|
convert_developer_to_user=not self.supports_developer_role,
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
import unittest
|
import unittest
|
||||||
from unittest.mock import AsyncMock, patch
|
from unittest.mock import AsyncMock, patch
|
||||||
|
|
||||||
|
from pipecat.adapters.base_llm_adapter import BaseLLMAdapter
|
||||||
|
from pipecat.adapters.services.open_ai_adapter import OpenAILLMAdapter
|
||||||
from pipecat.frames.frames import (
|
from pipecat.frames.frames import (
|
||||||
FunctionCallFromLLM,
|
FunctionCallFromLLM,
|
||||||
FunctionCallInProgressFrame,
|
FunctionCallInProgressFrame,
|
||||||
@@ -39,6 +41,25 @@ class MockLLMService(LLMService):
|
|||||||
super().__init__(settings=settings, **kwargs)
|
super().__init__(settings=settings, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class TestUnparameterizedSubclass(unittest.TestCase):
|
||||||
|
"""Backward-compat coverage: third-party providers subclass LLMService
|
||||||
|
without specifying a generic adapter parameter. That should keep working
|
||||||
|
after LLMService became `Generic[TAdapter]`.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def test_unparameterized_subclass_instantiates(self):
|
||||||
|
# MockLLMService is declared as `class MockLLMService(LLMService):`
|
||||||
|
# — no generic bracket. The TypeVar's `bound=BaseLLMAdapter` should
|
||||||
|
# resolve TAdapter to BaseLLMAdapter for callers that don't opt in.
|
||||||
|
service = MockLLMService()
|
||||||
|
adapter = service.get_llm_adapter()
|
||||||
|
|
||||||
|
# Default adapter_class is OpenAILLMAdapter; the runtime instance
|
||||||
|
# should reflect that, regardless of how generics are erased.
|
||||||
|
self.assertIsInstance(adapter, OpenAILLMAdapter)
|
||||||
|
self.assertIsInstance(adapter, BaseLLMAdapter)
|
||||||
|
|
||||||
|
|
||||||
class TestLLMService(unittest.IsolatedAsyncioTestCase):
|
class TestLLMService(unittest.IsolatedAsyncioTestCase):
|
||||||
async def _run_function_calls_inline(self, service: MockLLMService):
|
async def _run_function_calls_inline(self, service: MockLLMService):
|
||||||
async def run_inline(runner_items):
|
async def run_inline(runner_items):
|
||||||
|
|||||||
Reference in New Issue
Block a user