Convert developer messages to user for Cerebras (and lay groundwork for other incompatible services)
OpenAI-compatible services that don't support the "developer" message role can now set supports_developer_role = False on the service class. BaseOpenAILLMService passes this as convert_developer_to_user to the adapter, which converts developer messages to user messages before sending them to the API. Applied to Cerebras and Perplexity. Also removes the now-redundant developer→user conversion step from PerplexityLLMAdapter (handled by the parent adapter via the flag).
This commit is contained in:
@@ -52,7 +52,11 @@ class OpenAILLMAdapter(BaseLLMAdapter[OpenAILLMInvocationParams]):
|
|||||||
return "openai"
|
return "openai"
|
||||||
|
|
||||||
def get_llm_invocation_params(
|
def get_llm_invocation_params(
|
||||||
self, context: LLMContext, *, system_instruction: Optional[str] = None
|
self,
|
||||||
|
context: LLMContext,
|
||||||
|
*,
|
||||||
|
system_instruction: Optional[str] = None,
|
||||||
|
convert_developer_to_user: bool,
|
||||||
) -> OpenAILLMInvocationParams:
|
) -> OpenAILLMInvocationParams:
|
||||||
"""Get OpenAI-specific LLM invocation parameters from a universal LLM context.
|
"""Get OpenAI-specific LLM invocation parameters from a universal LLM context.
|
||||||
|
|
||||||
@@ -60,11 +64,16 @@ class OpenAILLMAdapter(BaseLLMAdapter[OpenAILLMInvocationParams]):
|
|||||||
context: The LLM context containing messages, tools, etc.
|
context: The LLM context containing messages, tools, etc.
|
||||||
system_instruction: Optional system instruction from service settings
|
system_instruction: Optional system instruction from service settings
|
||||||
or ``run_inference``. If provided, prepended as a system message.
|
or ``run_inference``. If provided, prepended as a system message.
|
||||||
|
convert_developer_to_user: If True, convert "developer"-role messages
|
||||||
|
to "user"-role messages. Used by OpenAI-compatible services that
|
||||||
|
don't support the "developer" role.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Dictionary of parameters for OpenAI's ChatCompletion API.
|
Dictionary of parameters for OpenAI's ChatCompletion API.
|
||||||
"""
|
"""
|
||||||
messages = self._from_universal_context_messages(self.get_messages(context))
|
messages = self._from_universal_context_messages(
|
||||||
|
self.get_messages(context), convert_developer_to_user=convert_developer_to_user
|
||||||
|
)
|
||||||
|
|
||||||
if system_instruction:
|
if system_instruction:
|
||||||
# Detect initial system message for warning purposes (don't extract)
|
# Detect initial system message for warning purposes (don't extract)
|
||||||
@@ -131,7 +140,10 @@ class OpenAILLMAdapter(BaseLLMAdapter[OpenAILLMInvocationParams]):
|
|||||||
return msgs
|
return msgs
|
||||||
|
|
||||||
def _from_universal_context_messages(
|
def _from_universal_context_messages(
|
||||||
self, messages: List[LLMContextMessage]
|
self,
|
||||||
|
messages: List[LLMContextMessage],
|
||||||
|
*,
|
||||||
|
convert_developer_to_user: bool,
|
||||||
) -> List[ChatCompletionMessageParam]:
|
) -> List[ChatCompletionMessageParam]:
|
||||||
result = []
|
result = []
|
||||||
for message in messages:
|
for message in messages:
|
||||||
@@ -141,6 +153,12 @@ class OpenAILLMAdapter(BaseLLMAdapter[OpenAILLMInvocationParams]):
|
|||||||
else:
|
else:
|
||||||
# Standard message, pass through unchanged
|
# Standard message, pass through unchanged
|
||||||
result.append(message)
|
result.append(message)
|
||||||
|
|
||||||
|
if convert_developer_to_user:
|
||||||
|
for msg in result:
|
||||||
|
if msg.get("role") == "developer":
|
||||||
|
msg["role"] = "user"
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def _from_standard_tool_choice(
|
def _from_standard_tool_choice(
|
||||||
|
|||||||
@@ -50,7 +50,11 @@ class PerplexityLLMAdapter(OpenAILLMAdapter):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def get_llm_invocation_params(
|
def get_llm_invocation_params(
|
||||||
self, context: LLMContext, *, system_instruction: Optional[str] = None
|
self,
|
||||||
|
context: LLMContext,
|
||||||
|
*,
|
||||||
|
system_instruction: Optional[str] = None,
|
||||||
|
convert_developer_to_user: bool,
|
||||||
) -> OpenAILLMInvocationParams:
|
) -> OpenAILLMInvocationParams:
|
||||||
"""Get OpenAI-compatible invocation parameters with Perplexity message fixes applied.
|
"""Get OpenAI-compatible invocation parameters with Perplexity message fixes applied.
|
||||||
|
|
||||||
@@ -58,12 +62,18 @@ class PerplexityLLMAdapter(OpenAILLMAdapter):
|
|||||||
context: The LLM context containing messages, tools, etc.
|
context: The LLM context containing messages, tools, etc.
|
||||||
system_instruction: Optional system instruction from service settings
|
system_instruction: Optional system instruction from service settings
|
||||||
or ``run_inference``. Forwarded to the parent adapter.
|
or ``run_inference``. Forwarded to the parent adapter.
|
||||||
|
convert_developer_to_user: If True, convert "developer"-role messages
|
||||||
|
to "user"-role messages. Forwarded to the parent adapter.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Dictionary of parameters for Perplexity's ChatCompletion API, with
|
Dictionary of parameters for Perplexity's ChatCompletion API, with
|
||||||
messages transformed to satisfy Perplexity's constraints.
|
messages transformed to satisfy Perplexity's constraints.
|
||||||
"""
|
"""
|
||||||
params = super().get_llm_invocation_params(context, system_instruction=system_instruction)
|
params = super().get_llm_invocation_params(
|
||||||
|
context,
|
||||||
|
system_instruction=system_instruction,
|
||||||
|
convert_developer_to_user=convert_developer_to_user,
|
||||||
|
)
|
||||||
params["messages"] = self._transform_messages(list(params["messages"]))
|
params["messages"] = self._transform_messages(list(params["messages"]))
|
||||||
return params
|
return params
|
||||||
|
|
||||||
@@ -109,11 +119,8 @@ class PerplexityLLMAdapter(OpenAILLMAdapter):
|
|||||||
|
|
||||||
messages = copy.deepcopy(messages)
|
messages = copy.deepcopy(messages)
|
||||||
|
|
||||||
# Step 0: Convert "developer" messages to "user".
|
# Note: "developer" → "user" conversion is handled by the parent adapter
|
||||||
# Perplexity doesn't support the "developer" role.
|
# via the convert_developer_to_user parameter.
|
||||||
for msg in messages:
|
|
||||||
if msg.get("role") == "developer":
|
|
||||||
msg["role"] = "user"
|
|
||||||
|
|
||||||
# Step 1: Convert non-initial system messages to "user".
|
# Step 1: Convert non-initial system messages to "user".
|
||||||
# Perplexity allows system messages at the start, but rejects them
|
# Perplexity allows system messages at the start, but rejects them
|
||||||
|
|||||||
@@ -30,6 +30,10 @@ class CerebrasLLMService(OpenAILLMService):
|
|||||||
maintaining full compatibility with OpenAI's interface and functionality.
|
maintaining full compatibility with OpenAI's interface and functionality.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# Cerebras doesn't support the "developer" message role.
|
||||||
|
# This value is used by BaseOpenAILLMService when calling the adapter.
|
||||||
|
supports_developer_role = False
|
||||||
|
|
||||||
Settings = CerebrasLLMSettings
|
Settings = CerebrasLLMSettings
|
||||||
_settings: Settings
|
_settings: Settings
|
||||||
|
|
||||||
|
|||||||
@@ -71,6 +71,15 @@ class BaseOpenAILLMService(LLMService):
|
|||||||
Settings = OpenAILLMSettings
|
Settings = OpenAILLMSettings
|
||||||
_settings: Settings
|
_settings: Settings
|
||||||
|
|
||||||
|
supports_developer_role: bool = True
|
||||||
|
"""Whether this service's API supports the "developer" message role.
|
||||||
|
|
||||||
|
OpenAI's native API supports it, but some OpenAI-compatible services
|
||||||
|
(e.g. Cerebras) do not. Subclasses that don't support it should set
|
||||||
|
this to ``False``, which causes the adapter to convert "developer"
|
||||||
|
messages to "user" messages before sending them to the API.
|
||||||
|
"""
|
||||||
|
|
||||||
class InputParams(BaseModel):
|
class InputParams(BaseModel):
|
||||||
"""Input parameters for OpenAI model configuration.
|
"""Input parameters for OpenAI model configuration.
|
||||||
|
|
||||||
@@ -351,7 +360,9 @@ class BaseOpenAILLMService(LLMService):
|
|||||||
if isinstance(context, LLMContext):
|
if isinstance(context, LLMContext):
|
||||||
adapter = self.get_llm_adapter()
|
adapter = self.get_llm_adapter()
|
||||||
invocation_params: OpenAILLMInvocationParams = adapter.get_llm_invocation_params(
|
invocation_params: OpenAILLMInvocationParams = adapter.get_llm_invocation_params(
|
||||||
context, system_instruction=effective_instruction
|
context,
|
||||||
|
system_instruction=effective_instruction,
|
||||||
|
convert_developer_to_user=not self.supports_developer_role,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
invocation_params = OpenAILLMInvocationParams(
|
invocation_params = OpenAILLMInvocationParams(
|
||||||
@@ -421,7 +432,9 @@ class BaseOpenAILLMService(LLMService):
|
|||||||
)
|
)
|
||||||
|
|
||||||
params: OpenAILLMInvocationParams = adapter.get_llm_invocation_params(
|
params: OpenAILLMInvocationParams = adapter.get_llm_invocation_params(
|
||||||
context, system_instruction=self._settings.system_instruction
|
context,
|
||||||
|
system_instruction=self._settings.system_instruction,
|
||||||
|
convert_developer_to_user=not self.supports_developer_role,
|
||||||
)
|
)
|
||||||
chunks = await self.get_chat_completions(params)
|
chunks = await self.get_chat_completions(params)
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,9 @@ class PerplexityLLMService(OpenAILLMService):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
adapter_class = PerplexityLLMAdapter
|
adapter_class = PerplexityLLMAdapter
|
||||||
|
# Perplexity doesn't support the "developer" message role.
|
||||||
|
# This value is used by BaseOpenAILLMService when calling the adapter.
|
||||||
|
supports_developer_role = False
|
||||||
|
|
||||||
Settings = PerplexityLLMSettings
|
Settings = PerplexityLLMSettings
|
||||||
_settings: Settings
|
_settings: Settings
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ For OpenAI adapter:
|
|||||||
3. Complex message structures (like multi-part content) are preserved
|
3. Complex message structures (like multi-part content) are preserved
|
||||||
4. System instructions are preserved throughout messages at any position
|
4. System instructions are preserved throughout messages at any position
|
||||||
5. system_instruction is prepended as a system message, with conflict warnings
|
5. system_instruction is prepended as a system message, with conflict warnings
|
||||||
6. Developer messages pass through without triggering warnings
|
6. Developer messages pass through when convert_developer_to_user is False
|
||||||
|
7. Developer messages are converted to user when convert_developer_to_user is True
|
||||||
|
|
||||||
For Gemini adapter:
|
For Gemini adapter:
|
||||||
1. LLMStandardMessage objects are converted to Gemini Content format
|
1. LLMStandardMessage objects are converted to Gemini Content format
|
||||||
@@ -85,6 +86,11 @@ from pipecat.processors.aggregators.llm_context import (
|
|||||||
|
|
||||||
|
|
||||||
class TestOpenAIGetLLMInvocationParams(unittest.TestCase):
|
class TestOpenAIGetLLMInvocationParams(unittest.TestCase):
|
||||||
|
# In production, BaseOpenAILLMService always passes convert_developer_to_user
|
||||||
|
# to the adapter (True or False depending on the service's supports_developer_role).
|
||||||
|
# Tests below use False to simulate native OpenAI usage, except for the
|
||||||
|
# developer-conversion-specific tests which use True.
|
||||||
|
|
||||||
def setUp(self) -> None:
|
def setUp(self) -> None:
|
||||||
"""Sets up a common adapter instance for all tests."""
|
"""Sets up a common adapter instance for all tests."""
|
||||||
self.adapter = OpenAILLMAdapter()
|
self.adapter = OpenAILLMAdapter()
|
||||||
@@ -102,7 +108,7 @@ class TestOpenAIGetLLMInvocationParams(unittest.TestCase):
|
|||||||
context = LLMContext(messages=standard_messages)
|
context = LLMContext(messages=standard_messages)
|
||||||
|
|
||||||
# Get invocation params
|
# Get invocation params
|
||||||
params = self.adapter.get_llm_invocation_params(context)
|
params = self.adapter.get_llm_invocation_params(context, convert_developer_to_user=False)
|
||||||
|
|
||||||
# Verify messages are passed through unchanged
|
# Verify messages are passed through unchanged
|
||||||
self.assertEqual(params["messages"], standard_messages)
|
self.assertEqual(params["messages"], standard_messages)
|
||||||
@@ -134,7 +140,7 @@ class TestOpenAIGetLLMInvocationParams(unittest.TestCase):
|
|||||||
context = LLMContext(messages=messages)
|
context = LLMContext(messages=messages)
|
||||||
|
|
||||||
# Get invocation params
|
# Get invocation params
|
||||||
params = self.adapter.get_llm_invocation_params(context)
|
params = self.adapter.get_llm_invocation_params(context, convert_developer_to_user=False)
|
||||||
|
|
||||||
# Should only include standard messages and OpenAI-specific ones
|
# Should only include standard messages and OpenAI-specific ones
|
||||||
# (3 total: system, standard user, openai assistant)
|
# (3 total: system, standard user, openai assistant)
|
||||||
@@ -181,7 +187,7 @@ class TestOpenAIGetLLMInvocationParams(unittest.TestCase):
|
|||||||
context = LLMContext(messages=messages)
|
context = LLMContext(messages=messages)
|
||||||
|
|
||||||
# Get invocation params
|
# Get invocation params
|
||||||
params = self.adapter.get_llm_invocation_params(context)
|
params = self.adapter.get_llm_invocation_params(context, convert_developer_to_user=False)
|
||||||
|
|
||||||
# Verify complex content is preserved
|
# Verify complex content is preserved
|
||||||
self.assertEqual(len(params["messages"]), 3)
|
self.assertEqual(len(params["messages"]), 3)
|
||||||
@@ -222,7 +228,7 @@ class TestOpenAIGetLLMInvocationParams(unittest.TestCase):
|
|||||||
context = LLMContext(messages=messages)
|
context = LLMContext(messages=messages)
|
||||||
|
|
||||||
# Get invocation params
|
# Get invocation params
|
||||||
params = self.adapter.get_llm_invocation_params(context)
|
params = self.adapter.get_llm_invocation_params(context, convert_developer_to_user=False)
|
||||||
|
|
||||||
# OpenAI should preserve all messages unchanged, including multiple system messages
|
# OpenAI should preserve all messages unchanged, including multiple system messages
|
||||||
self.assertEqual(len(params["messages"]), 7)
|
self.assertEqual(len(params["messages"]), 7)
|
||||||
@@ -249,7 +255,9 @@ class TestOpenAIGetLLMInvocationParams(unittest.TestCase):
|
|||||||
{"role": "user", "content": "Hello"},
|
{"role": "user", "content": "Hello"},
|
||||||
]
|
]
|
||||||
context = LLMContext(messages=messages)
|
context = LLMContext(messages=messages)
|
||||||
params = self.adapter.get_llm_invocation_params(context, system_instruction="Be helpful.")
|
params = self.adapter.get_llm_invocation_params(
|
||||||
|
context, system_instruction="Be helpful.", convert_developer_to_user=False
|
||||||
|
)
|
||||||
|
|
||||||
self.assertEqual(params["messages"][0]["role"], "system")
|
self.assertEqual(params["messages"][0]["role"], "system")
|
||||||
self.assertEqual(params["messages"][0]["content"], "Be helpful.")
|
self.assertEqual(params["messages"][0]["content"], "Be helpful.")
|
||||||
@@ -262,7 +270,7 @@ class TestOpenAIGetLLMInvocationParams(unittest.TestCase):
|
|||||||
{"role": "user", "content": "Hello"},
|
{"role": "user", "content": "Hello"},
|
||||||
]
|
]
|
||||||
context = LLMContext(messages=messages)
|
context = LLMContext(messages=messages)
|
||||||
params = self.adapter.get_llm_invocation_params(context)
|
params = self.adapter.get_llm_invocation_params(context, convert_developer_to_user=False)
|
||||||
|
|
||||||
self.assertEqual(len(params["messages"]), 2)
|
self.assertEqual(len(params["messages"]), 2)
|
||||||
self.assertEqual(params["messages"][0]["role"], "system")
|
self.assertEqual(params["messages"][0]["role"], "system")
|
||||||
@@ -278,7 +286,7 @@ class TestOpenAIGetLLMInvocationParams(unittest.TestCase):
|
|||||||
|
|
||||||
with patch("pipecat.adapters.base_llm_adapter.logger") as mock_logger:
|
with patch("pipecat.adapters.base_llm_adapter.logger") as mock_logger:
|
||||||
params = self.adapter.get_llm_invocation_params(
|
params = self.adapter.get_llm_invocation_params(
|
||||||
context, system_instruction="Be concise."
|
context, system_instruction="Be concise.", convert_developer_to_user=False
|
||||||
)
|
)
|
||||||
mock_logger.warning.assert_called_once()
|
mock_logger.warning.assert_called_once()
|
||||||
warning_msg = mock_logger.warning.call_args[0][0]
|
warning_msg = mock_logger.warning.call_args[0][0]
|
||||||
@@ -298,7 +306,7 @@ class TestOpenAIGetLLMInvocationParams(unittest.TestCase):
|
|||||||
|
|
||||||
with patch("pipecat.adapters.base_llm_adapter.logger") as mock_logger:
|
with patch("pipecat.adapters.base_llm_adapter.logger") as mock_logger:
|
||||||
params = self.adapter.get_llm_invocation_params(
|
params = self.adapter.get_llm_invocation_params(
|
||||||
context, system_instruction="Be concise."
|
context, system_instruction="Be concise.", convert_developer_to_user=False
|
||||||
)
|
)
|
||||||
mock_logger.warning.assert_not_called()
|
mock_logger.warning.assert_not_called()
|
||||||
|
|
||||||
@@ -315,10 +323,45 @@ class TestOpenAIGetLLMInvocationParams(unittest.TestCase):
|
|||||||
context = LLMContext(messages=messages)
|
context = LLMContext(messages=messages)
|
||||||
|
|
||||||
with patch("pipecat.adapters.base_llm_adapter.logger") as mock_logger:
|
with patch("pipecat.adapters.base_llm_adapter.logger") as mock_logger:
|
||||||
self.adapter.get_llm_invocation_params(context, system_instruction="Be concise.")
|
self.adapter.get_llm_invocation_params(
|
||||||
self.adapter.get_llm_invocation_params(context, system_instruction="Be concise.")
|
context, system_instruction="Be concise.", convert_developer_to_user=False
|
||||||
|
)
|
||||||
|
self.adapter.get_llm_invocation_params(
|
||||||
|
context, system_instruction="Be concise.", convert_developer_to_user=False
|
||||||
|
)
|
||||||
mock_logger.warning.assert_called_once()
|
mock_logger.warning.assert_called_once()
|
||||||
|
|
||||||
|
def test_developer_messages_converted_to_user(self):
|
||||||
|
"""Developer messages are converted to user role when convert_developer_to_user is True."""
|
||||||
|
messages: list[LLMStandardMessage] = [
|
||||||
|
{"role": "developer", "content": "Extra context."},
|
||||||
|
{"role": "user", "content": "Hello"},
|
||||||
|
]
|
||||||
|
|
||||||
|
context = LLMContext(messages=messages)
|
||||||
|
params = self.adapter.get_llm_invocation_params(context, convert_developer_to_user=True)
|
||||||
|
|
||||||
|
self.assertEqual(params["messages"][0]["role"], "user")
|
||||||
|
self.assertEqual(params["messages"][0]["content"], "Extra context.")
|
||||||
|
|
||||||
|
def test_developer_conversion_does_not_affect_other_roles(self):
|
||||||
|
"""convert_developer_to_user only affects developer messages, not system/user/assistant."""
|
||||||
|
messages: list[LLMStandardMessage] = [
|
||||||
|
{"role": "system", "content": "System prompt."},
|
||||||
|
{"role": "developer", "content": "Dev guidance."},
|
||||||
|
{"role": "user", "content": "Hello"},
|
||||||
|
{"role": "assistant", "content": "Hi"},
|
||||||
|
]
|
||||||
|
|
||||||
|
context = LLMContext(messages=messages)
|
||||||
|
params = self.adapter.get_llm_invocation_params(context, convert_developer_to_user=True)
|
||||||
|
|
||||||
|
self.assertEqual(params["messages"][0]["role"], "system")
|
||||||
|
self.assertEqual(params["messages"][1]["role"], "user")
|
||||||
|
self.assertEqual(params["messages"][1]["content"], "Dev guidance.")
|
||||||
|
self.assertEqual(params["messages"][2]["role"], "user")
|
||||||
|
self.assertEqual(params["messages"][3]["role"], "assistant")
|
||||||
|
|
||||||
|
|
||||||
class TestGeminiGetLLMInvocationParams(unittest.TestCase):
|
class TestGeminiGetLLMInvocationParams(unittest.TestCase):
|
||||||
def setUp(self) -> None:
|
def setUp(self) -> None:
|
||||||
@@ -1377,6 +1420,10 @@ class TestAWSBedrockGetLLMInvocationParams(unittest.TestCase):
|
|||||||
|
|
||||||
|
|
||||||
class TestPerplexityGetLLMInvocationParams(unittest.TestCase):
|
class TestPerplexityGetLLMInvocationParams(unittest.TestCase):
|
||||||
|
# Perplexity doesn't support the "developer" role, so PerplexityLLMService
|
||||||
|
# sets supports_developer_role = False. Tests below pass
|
||||||
|
# convert_developer_to_user=True to match production behavior.
|
||||||
|
|
||||||
def setUp(self) -> None:
|
def setUp(self) -> None:
|
||||||
"""Sets up a common adapter instance for all tests."""
|
"""Sets up a common adapter instance for all tests."""
|
||||||
self.adapter = PerplexityLLMAdapter()
|
self.adapter = PerplexityLLMAdapter()
|
||||||
@@ -1390,7 +1437,7 @@ class TestPerplexityGetLLMInvocationParams(unittest.TestCase):
|
|||||||
]
|
]
|
||||||
|
|
||||||
context = LLMContext(messages=messages)
|
context = LLMContext(messages=messages)
|
||||||
params = self.adapter.get_llm_invocation_params(context)
|
params = self.adapter.get_llm_invocation_params(context, convert_developer_to_user=True)
|
||||||
|
|
||||||
self.assertEqual(len(params["messages"]), 3)
|
self.assertEqual(len(params["messages"]), 3)
|
||||||
self.assertEqual(params["messages"][0]["role"], "user")
|
self.assertEqual(params["messages"][0]["role"], "user")
|
||||||
@@ -1410,7 +1457,7 @@ class TestPerplexityGetLLMInvocationParams(unittest.TestCase):
|
|||||||
]
|
]
|
||||||
|
|
||||||
context = LLMContext(messages=messages)
|
context = LLMContext(messages=messages)
|
||||||
params = self.adapter.get_llm_invocation_params(context)
|
params = self.adapter.get_llm_invocation_params(context, convert_developer_to_user=True)
|
||||||
|
|
||||||
self.assertEqual(len(params["messages"]), 4)
|
self.assertEqual(len(params["messages"]), 4)
|
||||||
self.assertEqual(params["messages"][0]["role"], "system")
|
self.assertEqual(params["messages"][0]["role"], "system")
|
||||||
@@ -1429,7 +1476,7 @@ class TestPerplexityGetLLMInvocationParams(unittest.TestCase):
|
|||||||
]
|
]
|
||||||
|
|
||||||
context = LLMContext(messages=messages)
|
context = LLMContext(messages=messages)
|
||||||
params = self.adapter.get_llm_invocation_params(context)
|
params = self.adapter.get_llm_invocation_params(context, convert_developer_to_user=True)
|
||||||
|
|
||||||
self.assertEqual(len(params["messages"]), 3)
|
self.assertEqual(len(params["messages"]), 3)
|
||||||
|
|
||||||
@@ -1457,7 +1504,7 @@ class TestPerplexityGetLLMInvocationParams(unittest.TestCase):
|
|||||||
]
|
]
|
||||||
|
|
||||||
context = LLMContext(messages=messages)
|
context = LLMContext(messages=messages)
|
||||||
params = self.adapter.get_llm_invocation_params(context)
|
params = self.adapter.get_llm_invocation_params(context, convert_developer_to_user=True)
|
||||||
|
|
||||||
# system(initial), user, assistant, merged(system→user + user)
|
# system(initial), user, assistant, merged(system→user + user)
|
||||||
self.assertEqual(len(params["messages"]), 4)
|
self.assertEqual(len(params["messages"]), 4)
|
||||||
@@ -1482,7 +1529,7 @@ class TestPerplexityGetLLMInvocationParams(unittest.TestCase):
|
|||||||
]
|
]
|
||||||
|
|
||||||
context = LLMContext(messages=messages)
|
context = LLMContext(messages=messages)
|
||||||
params = self.adapter.get_llm_invocation_params(context)
|
params = self.adapter.get_llm_invocation_params(context, convert_developer_to_user=True)
|
||||||
|
|
||||||
self.assertEqual(len(params["messages"]), 3)
|
self.assertEqual(len(params["messages"]), 3)
|
||||||
self.assertEqual(params["messages"][0]["role"], "system")
|
self.assertEqual(params["messages"][0]["role"], "system")
|
||||||
@@ -1500,7 +1547,7 @@ class TestPerplexityGetLLMInvocationParams(unittest.TestCase):
|
|||||||
]
|
]
|
||||||
|
|
||||||
context = LLMContext(messages=messages)
|
context = LLMContext(messages=messages)
|
||||||
params = self.adapter.get_llm_invocation_params(context)
|
params = self.adapter.get_llm_invocation_params(context, convert_developer_to_user=True)
|
||||||
|
|
||||||
self.assertEqual(len(params["messages"]), 1)
|
self.assertEqual(len(params["messages"]), 1)
|
||||||
self.assertEqual(params["messages"][0]["role"], "user")
|
self.assertEqual(params["messages"][0]["role"], "user")
|
||||||
@@ -1519,7 +1566,7 @@ class TestPerplexityGetLLMInvocationParams(unittest.TestCase):
|
|||||||
]
|
]
|
||||||
|
|
||||||
context = LLMContext(messages=messages)
|
context = LLMContext(messages=messages)
|
||||||
params = self.adapter.get_llm_invocation_params(context)
|
params = self.adapter.get_llm_invocation_params(context, convert_developer_to_user=True)
|
||||||
|
|
||||||
self.assertEqual(len(params["messages"]), 1)
|
self.assertEqual(len(params["messages"]), 1)
|
||||||
self.assertEqual(params["messages"][0]["role"], "system")
|
self.assertEqual(params["messages"][0]["role"], "system")
|
||||||
@@ -1538,7 +1585,7 @@ class TestPerplexityGetLLMInvocationParams(unittest.TestCase):
|
|||||||
]
|
]
|
||||||
|
|
||||||
context = LLMContext(messages=messages)
|
context = LLMContext(messages=messages)
|
||||||
params = self.adapter.get_llm_invocation_params(context)
|
params = self.adapter.get_llm_invocation_params(context, convert_developer_to_user=True)
|
||||||
|
|
||||||
# Trailing assistant removed → [system], system stays as-is
|
# Trailing assistant removed → [system], system stays as-is
|
||||||
self.assertEqual(len(params["messages"]), 1)
|
self.assertEqual(len(params["messages"]), 1)
|
||||||
@@ -1554,7 +1601,7 @@ class TestPerplexityGetLLMInvocationParams(unittest.TestCase):
|
|||||||
]
|
]
|
||||||
|
|
||||||
context = LLMContext(messages=messages)
|
context = LLMContext(messages=messages)
|
||||||
params = self.adapter.get_llm_invocation_params(context)
|
params = self.adapter.get_llm_invocation_params(context, convert_developer_to_user=True)
|
||||||
|
|
||||||
# After merging assistants we get [user, assistant(merged)], then trailing
|
# After merging assistants we get [user, assistant(merged)], then trailing
|
||||||
# assistant is removed, leaving just [user]
|
# assistant is removed, leaving just [user]
|
||||||
@@ -1576,7 +1623,7 @@ class TestPerplexityGetLLMInvocationParams(unittest.TestCase):
|
|||||||
]
|
]
|
||||||
|
|
||||||
context = LLMContext(messages=messages)
|
context = LLMContext(messages=messages)
|
||||||
params = self.adapter.get_llm_invocation_params(context)
|
params = self.adapter.get_llm_invocation_params(context, convert_developer_to_user=True)
|
||||||
|
|
||||||
self.assertEqual(len(params["messages"]), 4)
|
self.assertEqual(len(params["messages"]), 4)
|
||||||
self.assertEqual(params["messages"][0]["role"], "user")
|
self.assertEqual(params["messages"][0]["role"], "user")
|
||||||
@@ -1594,7 +1641,7 @@ class TestPerplexityGetLLMInvocationParams(unittest.TestCase):
|
|||||||
]
|
]
|
||||||
|
|
||||||
context = LLMContext(messages=messages)
|
context = LLMContext(messages=messages)
|
||||||
params = self.adapter.get_llm_invocation_params(context)
|
params = self.adapter.get_llm_invocation_params(context, convert_developer_to_user=True)
|
||||||
|
|
||||||
self.assertEqual(params["messages"][0]["role"], "user")
|
self.assertEqual(params["messages"][0]["role"], "user")
|
||||||
self.assertEqual(params["messages"][0]["content"], "Extra context.")
|
self.assertEqual(params["messages"][0]["content"], "Extra context.")
|
||||||
@@ -1609,7 +1656,7 @@ class TestPerplexityGetLLMInvocationParams(unittest.TestCase):
|
|||||||
]
|
]
|
||||||
|
|
||||||
context = LLMContext(messages=messages)
|
context = LLMContext(messages=messages)
|
||||||
params = self.adapter.get_llm_invocation_params(context)
|
params = self.adapter.get_llm_invocation_params(context, convert_developer_to_user=True)
|
||||||
|
|
||||||
# developer→user merged with following user
|
# developer→user merged with following user
|
||||||
self.assertEqual(len(params["messages"]), 3)
|
self.assertEqual(len(params["messages"]), 3)
|
||||||
@@ -1623,7 +1670,7 @@ class TestPerplexityGetLLMInvocationParams(unittest.TestCase):
|
|||||||
def test_empty_messages(self):
|
def test_empty_messages(self):
|
||||||
"""Test that empty messages list returns empty."""
|
"""Test that empty messages list returns empty."""
|
||||||
context = LLMContext(messages=[])
|
context = LLMContext(messages=[])
|
||||||
params = self.adapter.get_llm_invocation_params(context)
|
params = self.adapter.get_llm_invocation_params(context, convert_developer_to_user=True)
|
||||||
|
|
||||||
self.assertEqual(params["messages"], [])
|
self.assertEqual(params["messages"], [])
|
||||||
|
|
||||||
|
|||||||
@@ -60,8 +60,9 @@ async def test_openai_run_inference_with_llm_context():
|
|||||||
# Verify
|
# Verify
|
||||||
assert result == "Hello! How can I help you today?"
|
assert result == "Hello! How can I help you today?"
|
||||||
service.get_llm_adapter.assert_called_once()
|
service.get_llm_adapter.assert_called_once()
|
||||||
|
# convert_developer_to_user=False because OpenAILLMService.supports_developer_role is True
|
||||||
mock_adapter.get_llm_invocation_params.assert_called_once_with(
|
mock_adapter.get_llm_invocation_params.assert_called_once_with(
|
||||||
mock_context, system_instruction=None
|
mock_context, system_instruction=None, convert_developer_to_user=False
|
||||||
)
|
)
|
||||||
service._client.chat.completions.create.assert_called_once_with(
|
service._client.chat.completions.create.assert_called_once_with(
|
||||||
model="gpt-4",
|
model="gpt-4",
|
||||||
@@ -549,9 +550,12 @@ async def test_openai_run_inference_system_instruction_overrides_context():
|
|||||||
)
|
)
|
||||||
|
|
||||||
assert result == "Response"
|
assert result == "Response"
|
||||||
# Verify the adapter was called with the correct system_instruction
|
# Verify the adapter was called with the correct system_instruction.
|
||||||
|
# convert_developer_to_user=False because OpenAILLMService.supports_developer_role is True.
|
||||||
mock_adapter.get_llm_invocation_params.assert_called_once_with(
|
mock_adapter.get_llm_invocation_params.assert_called_once_with(
|
||||||
mock_context, system_instruction="New system instruction"
|
mock_context,
|
||||||
|
system_instruction="New system instruction",
|
||||||
|
convert_developer_to_user=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user