Fix: warn on system_instruction conflict even with single system message

When the only message in context was a system message,
_extract_initial_system_or_developer would convert it to "user" (to
prevent empty history) without warning about the conflict with
system_instruction. Now warns inline before converting, with a message
explaining both the conflict and the user-role conversion.
This commit is contained in:
Paul Kompfner
2026-03-20 15:25:39 -04:00
parent 64ba013b68
commit a0393b9af6
2 changed files with 26 additions and 0 deletions

View File

@@ -188,6 +188,15 @@ class BaseLLMAdapter(ABC, Generic[TLLMInvocationParams]):
# Would extracting empty the list? Convert to "user" instead.
if len(messages) == 1:
if role == "system" and system_instruction:
if not self._warned_system_instruction:
self._warned_system_instruction = True
logger.warning(
"Both system_instruction and a system message in context are set."
" Using system_instruction. The system message in context is being"
" converted to a user message to avoid sending an empty conversation"
" history."
)
messages[0]["role"] = "user"
return None, None

View File

@@ -2002,6 +2002,23 @@ class TestBaseLLMAdapterHelpers(unittest.TestCase):
self.assertEqual(len(messages), 1) # not popped
self.assertEqual(messages[0]["role"], "user")
def test_single_system_message_with_system_instruction_warns(self):
"""Single system message + system_instruction still warns even though content isn't extracted."""
messages = [
{"role": "system", "content": "Be helpful."},
]
adapter = OpenAILLMAdapter()
with patch("pipecat.adapters.base_llm_adapter.logger") as mock_logger:
content, role = adapter._extract_initial_system_or_developer(
messages, system_instruction="Be concise."
)
mock_logger.warning.assert_called_once()
self.assertIsNone(content)
self.assertIsNone(role)
self.assertEqual(messages[0]["role"], "user")
def test_non_system_message_ignored(self):
"""Non-system/developer first message is ignored."""
messages = [