From 2135557689751a98010ceed17b0f4f17e24162c2 Mon Sep 17 00:00:00 2001 From: Paul Kompfner Date: Fri, 20 Mar 2026 15:58:34 -0400 Subject: [PATCH] Simplify: don't promote developer messages to system instruction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Developer messages are now always converted to "user" in non-OpenAI adapters, never promoted to the system instruction. This removes an inconsistency where adding an unrelated message to context would change whether a developer message got promoted. Simplifications: - Rename _extract_initial_system_or_developer → _extract_initial_system - Return Optional[str] instead of Tuple (role is always "system") - Drop initial_context_message_role from _resolve_system_instruction - Drop system_role fields from all ConvertedMessages dataclasses --- src/pipecat/adapters/base_llm_adapter.py | 90 +++++--------- .../adapters/services/anthropic_adapter.py | 14 +-- .../adapters/services/bedrock_adapter.py | 14 +-- .../adapters/services/gemini_adapter.py | 8 +- .../adapters/services/open_ai_adapter.py | 8 +- .../services/open_ai_responses_adapter.py | 1 - tests/test_get_llm_invocation_params.py | 112 ++++++++---------- 7 files changed, 98 insertions(+), 149 deletions(-) diff --git a/src/pipecat/adapters/base_llm_adapter.py b/src/pipecat/adapters/base_llm_adapter.py index 6242d373e..aeef313b0 100644 --- a/src/pipecat/adapters/base_llm_adapter.py +++ b/src/pipecat/adapters/base_llm_adapter.py @@ -11,7 +11,7 @@ adapters that handle tool format conversion and standardization. """ from abc import ABC, abstractmethod -from typing import Any, Dict, Generic, List, Optional, Tuple, TypeVar +from typing import Any, Dict, Generic, List, Optional, TypeVar from loguru import logger @@ -135,60 +135,46 @@ class BaseLLMAdapter(ABC, Generic[TLLMInvocationParams]): # Fallback to return the same tools in case they are not in a standard format return tools - def _extract_initial_system_or_developer( + def _extract_initial_system( self, messages: list, *, - system_instruction: Optional[str], - ) -> Tuple[Optional[str], Optional[str]]: - """Extract an initial system/developer message for use as a system instruction. + system_instruction: Optional[str] = None, + ) -> Optional[str]: + """Extract an initial ``"system"`` message for use as a system instruction. Only useful for services that expect the system instruction as a separate parameter, not inline in conversation history (today, all - non-OpenAI services). + non-OpenAI services). Does not extract ``"developer"`` messages — + those are converted to ``"user"`` by the adapter's subsequent message + loop, like any other non-system role the provider doesn't support. - Checks ``messages[0]``. Behavior: - - - ``"system"`` role: assumed to be intended as the system instruction. - Extract (pop from messages). - - ``"developer"`` role **without** ``system_instruction``: also assumed - to be intended as the system instruction. Extract (pop). - - ``"developer"`` role **with** ``system_instruction``: assumed to be - intended as a conversation-history message (since a system instruction - is already provided). Don't extract; convert to ``"user"`` in-place. - - Any other role: no-op. - - If extracting would leave the messages list empty - (``len(messages) == 1``), the message is converted to ``"user"`` role - instead of being extracted. This prevents sending an empty conversation - history to providers that require at least one non-system message. + Checks ``messages[0]``. If the role is ``"system"``, pops and returns + its content. If extracting would leave the messages list empty + (``len(messages) == 1``), the message is converted to ``"user"`` + role instead of being extracted, to prevent sending an empty + conversation history to providers that require at least one + non-system message. Args: messages: Message list in standard format (mutated in-place). system_instruction: The system instruction from service settings - or ``run_inference``, used to decide whether to extract a - ``"developer"`` message. + or ``run_inference``. Only used to decide whether to warn + about a conflict in the single-message case. Returns: - ``(extracted_content, original_role)`` where *original_role* is - ``"system"`` or ``"developer"``, or ``(None, None)`` if nothing + The extracted system message content, or ``None`` if nothing was extracted. """ if not messages: - return None, None + return None - role = messages[0].get("role") - if role not in ("system", "developer"): - return None, None - - # "developer" + system_instruction present → keep in messages as "user" - if role == "developer" and system_instruction: - messages[0]["role"] = "user" - return None, None + if messages[0].get("role") != "system": + return None # Would extracting empty the list? Convert to "user" instead. if len(messages) == 1: - if role == "system" and system_instruction: + if system_instruction: if not self._warned_system_instruction: self._warned_system_instruction = True logger.warning( @@ -198,7 +184,7 @@ class BaseLLMAdapter(ABC, Generic[TLLMInvocationParams]): " history." ) messages[0]["role"] = "user" - return None, None + return None # Extract content = messages[0].get("content", "") @@ -208,28 +194,21 @@ class BaseLLMAdapter(ABC, Generic[TLLMInvocationParams]): part.get("text", "") for part in content if part.get("type") == "text" ) messages.pop(0) - return content, role + return content def _resolve_system_instruction( self, - initial_context_message: Optional[str], - initial_context_message_role: Optional[str], + system_from_context: Optional[str], system_instruction: Optional[str], *, discard_context_system: bool, ) -> Optional[str]: - """Resolve conflict between ``system_instruction`` and an initial context message. - - Only warns when *initial_context_message_role* is ``"system"`` (not - ``"developer"``), since a developer message coexisting with - ``system_instruction`` is expected and handled elsewhere. + """Resolve conflict between ``system_instruction`` and an extracted context system message. Args: - initial_context_message: Content extracted from ``messages[0]`` - by :meth:`_extract_initial_system_or_developer`, or detected + system_from_context: Content extracted from an initial ``"system"`` + message by :meth:`_extract_initial_system`, or detected inline (OpenAI adapters). - initial_context_message_role: ``"system"`` or ``"developer"`` — - the original role before extraction/detection. system_instruction: From service settings or ``run_inference`` param. discard_context_system: If ``True`` (non-OpenAI adapters), the context system message is discarded when ``system_instruction`` @@ -239,10 +218,7 @@ class BaseLLMAdapter(ABC, Generic[TLLMInvocationParams]): The effective system instruction to use, or ``None`` if the system instruction is already represented in the messages (OpenAI path). """ - both_present = initial_context_message and system_instruction - from_system_role = initial_context_message_role == "system" - - if both_present and from_system_role: + if system_from_context and system_instruction: if not self._warned_system_instruction: self._warned_system_instruction = True if discard_context_system: @@ -257,15 +233,11 @@ class BaseLLMAdapter(ABC, Generic[TLLMInvocationParams]): ) if system_instruction: - if discard_context_system: - return system_instruction - else: - # OpenAI path: caller prepends; return the instruction for prepending - return system_instruction + return system_instruction - if initial_context_message: + if system_from_context: if discard_context_system: - return initial_context_message + return system_from_context else: # Content is already in messages; nothing to prepend return None diff --git a/src/pipecat/adapters/services/anthropic_adapter.py b/src/pipecat/adapters/services/anthropic_adapter.py index dfd68375c..9617dadeb 100644 --- a/src/pipecat/adapters/services/anthropic_adapter.py +++ b/src/pipecat/adapters/services/anthropic_adapter.py @@ -69,7 +69,6 @@ class AnthropicLLMAdapter(BaseLLMAdapter[AnthropicLLMInvocationParams]): ) system = self._resolve_system_instruction( converted.system if converted.system is not NOT_GIVEN else None, - converted.system_role, system_instruction, discard_context_system=True, ) @@ -118,7 +117,6 @@ class AnthropicLLMAdapter(BaseLLMAdapter[AnthropicLLMInvocationParams]): messages: List[MessageParam] system: str | NotGiven - system_role: Optional[str] = None # "system" or "developer" — origin of extracted system def _from_universal_context_messages( self, @@ -127,18 +125,16 @@ class AnthropicLLMAdapter(BaseLLMAdapter[AnthropicLLMInvocationParams]): system_instruction: Optional[str] = None, ) -> ConvertedMessages: system = NOT_GIVEN - system_role = None - # Extract initial system/developer from universal messages BEFORE conversion, + # Extract initial system message from universal messages BEFORE conversion, # so the helper works with standard message format (not provider-specific). remaining = list(universal_context_messages) if remaining and not isinstance(remaining[0], LLMSpecificMessage): - extracted_content, extracted_role = self._extract_initial_system_or_developer( + extracted = self._extract_initial_system( remaining, system_instruction=system_instruction ) - if extracted_content is not None: - system = extracted_content - system_role = extracted_role + if extracted is not None: + system = extracted # Convert remaining messages to Anthropic format messages = [] @@ -180,7 +176,7 @@ class AnthropicLLMAdapter(BaseLLMAdapter[AnthropicLLMInvocationParams]): elif isinstance(message["content"], list) and len(message["content"]) == 0: message["content"] = [{"type": "text", "text": "(empty)"}] - return self.ConvertedMessages(messages=messages, system=system, system_role=system_role) + return self.ConvertedMessages(messages=messages, system=system) def _from_universal_context_message(self, message: LLMContextMessage) -> MessageParam: if isinstance(message, LLMSpecificMessage): diff --git a/src/pipecat/adapters/services/bedrock_adapter.py b/src/pipecat/adapters/services/bedrock_adapter.py index 7df924880..3150e6458 100644 --- a/src/pipecat/adapters/services/bedrock_adapter.py +++ b/src/pipecat/adapters/services/bedrock_adapter.py @@ -65,7 +65,6 @@ class AWSBedrockLLMAdapter(BaseLLMAdapter[AWSBedrockLLMInvocationParams]): ) effective_system = self._resolve_system_instruction( converted.system, - converted.system_role, system_instruction, discard_context_system=True, ) @@ -112,7 +111,6 @@ class AWSBedrockLLMAdapter(BaseLLMAdapter[AWSBedrockLLMInvocationParams]): messages: List[dict[str, Any]] system: Optional[str] - system_role: Optional[str] = None # "system" or "developer" — origin of extracted system def _from_universal_context_messages( self, @@ -121,18 +119,12 @@ class AWSBedrockLLMAdapter(BaseLLMAdapter[AWSBedrockLLMInvocationParams]): system_instruction: Optional[str] = None, ) -> ConvertedMessages: system = None - system_role = None - # Extract initial system/developer from universal messages BEFORE conversion, + # Extract initial system message from universal messages BEFORE conversion, # so the helper works with standard message format (not provider-specific). remaining = list(universal_context_messages) if remaining and not isinstance(remaining[0], LLMSpecificMessage): - extracted_content, extracted_role = self._extract_initial_system_or_developer( - remaining, system_instruction=system_instruction - ) - if extracted_content is not None: - system = extracted_content - system_role = extracted_role + system = self._extract_initial_system(remaining, system_instruction=system_instruction) # Convert remaining messages to Bedrock format messages = [] @@ -174,7 +166,7 @@ class AWSBedrockLLMAdapter(BaseLLMAdapter[AWSBedrockLLMInvocationParams]): elif isinstance(message["content"], list) and len(message["content"]) == 0: message["content"] = [{"type": "text", "text": "(empty)"}] - return self.ConvertedMessages(messages=messages, system=system, system_role=system_role) + return self.ConvertedMessages(messages=messages, system=system) def _from_universal_context_message(self, message: LLMContextMessage) -> dict[str, Any]: if isinstance(message, LLMSpecificMessage): diff --git a/src/pipecat/adapters/services/gemini_adapter.py b/src/pipecat/adapters/services/gemini_adapter.py index d73ac388d..565d0d0b8 100644 --- a/src/pipecat/adapters/services/gemini_adapter.py +++ b/src/pipecat/adapters/services/gemini_adapter.py @@ -71,7 +71,6 @@ class GeminiLLMAdapter(BaseLLMAdapter[GeminiLLMInvocationParams]): ) effective_system = self._resolve_system_instruction( converted.system_instruction, - converted.system_instruction_role, system_instruction, discard_context_system=True, ) @@ -176,7 +175,6 @@ class GeminiLLMAdapter(BaseLLMAdapter[GeminiLLMInvocationParams]): messages: List[Content] system_instruction: Optional[str] = None - system_instruction_role: Optional[str] = None # "system" or "developer" @dataclass class MessageConversionResult: @@ -220,12 +218,11 @@ class GeminiLLMAdapter(BaseLLMAdapter[GeminiLLMInvocationParams]): # We work on a mutable copy so we can pop messages[0] if needed. remaining_messages = list(universal_context_messages) extracted_system = None - extracted_role = None - # Extract initial system/developer from universal messages BEFORE conversion, + # Extract initial system message from universal messages BEFORE conversion, # so the helper works with standard message format. if remaining_messages and not isinstance(remaining_messages[0], LLMSpecificMessage): - extracted_system, extracted_role = self._extract_initial_system_or_developer( + extracted_system = self._extract_initial_system( remaining_messages, system_instruction=system_instruction ) @@ -294,7 +291,6 @@ class GeminiLLMAdapter(BaseLLMAdapter[GeminiLLMInvocationParams]): return self.ConvertedMessages( messages=messages, system_instruction=extracted_system, - system_instruction_role=extracted_role, ) def _from_standard_message( diff --git a/src/pipecat/adapters/services/open_ai_adapter.py b/src/pipecat/adapters/services/open_ai_adapter.py index 9e8b449d0..f544f2c29 100644 --- a/src/pipecat/adapters/services/open_ai_adapter.py +++ b/src/pipecat/adapters/services/open_ai_adapter.py @@ -68,11 +68,13 @@ class OpenAILLMAdapter(BaseLLMAdapter[OpenAILLMInvocationParams]): if system_instruction: # Detect initial system message for warning purposes (don't extract) - initial_role = messages[0].get("role") if messages else None - initial_content = messages[0].get("content", "") if initial_role == "system" else None + initial_content = ( + messages[0].get("content", "") + if messages and messages[0].get("role") == "system" + else None + ) self._resolve_system_instruction( initial_content, - initial_role if initial_role == "system" else None, system_instruction, discard_context_system=False, ) diff --git a/src/pipecat/adapters/services/open_ai_responses_adapter.py b/src/pipecat/adapters/services/open_ai_responses_adapter.py index 89968a721..57398a9f6 100644 --- a/src/pipecat/adapters/services/open_ai_responses_adapter.py +++ b/src/pipecat/adapters/services/open_ai_responses_adapter.py @@ -68,7 +68,6 @@ class OpenAIResponsesLLMAdapter(BaseLLMAdapter[OpenAIResponsesLLMInvocationParam if first_msg and first_msg.get("role") == "system": self._resolve_system_instruction( first_msg.get("content", ""), - "system", system_instruction, discard_context_system=False, ) diff --git a/tests/test_get_llm_invocation_params.py b/tests/test_get_llm_invocation_params.py index b695cde59..524d409c5 100644 --- a/tests/test_get_llm_invocation_params.py +++ b/tests/test_get_llm_invocation_params.py @@ -25,7 +25,7 @@ For Gemini adapter: 5. Single system instruction is converted to user message when no other messages exist 6. Multiple system instructions: first extracted, later ones converted to user messages 7. system_instruction overrides context system message, with conflict warnings -8. Developer messages are promoted to system instruction or converted to user +8. Developer messages are converted to user For Anthropic adapter: 1. LLMStandardMessage objects are converted to Anthropic MessageParam format @@ -35,7 +35,7 @@ For Anthropic adapter: 5. Consecutive messages with same role are merged into multi-content-block messages 6. Empty text content is converted to "(empty)" 7. system_instruction overrides context system message, with conflict warnings -8. Developer messages are promoted to system instruction or converted to user +8. Developer messages are converted to user For AWS Bedrock adapter: 1. LLMStandardMessage objects are converted to AWS Bedrock format @@ -45,7 +45,7 @@ For AWS Bedrock adapter: 5. Consecutive messages with same role are merged into multi-content-block messages 6. Empty text content is converted to "(empty)" 7. system_instruction overrides context system message, with conflict warnings -8. Developer messages are promoted to system instruction or converted to user +8. Developer messages are converted to user For OpenAI Responses adapter: 1. LLMContext messages are converted to Responses API input items @@ -58,7 +58,7 @@ For OpenAI Responses adapter: 8. Developer messages pass through as developer role without triggering warnings For BaseLLMAdapter helpers: -1. _extract_initial_system_or_developer: system/developer extraction and conversion logic +1. _extract_initial_system: system extraction and conversion logic 2. _resolve_system_instruction: conflict resolution between context and settings """ @@ -602,8 +602,8 @@ class TestGeminiGetLLMInvocationParams(unittest.TestCase): self.assertEqual(params["system_instruction"], "You are helpful.") self.assertEqual(len(params["messages"]), 1) - def test_initial_developer_message_promoted(self): - """Initial developer message without system_instruction is promoted.""" + def test_initial_developer_message_becomes_user(self): + """Initial developer message without system_instruction becomes user, not system_instruction.""" messages: list[LLMStandardMessage] = [ {"role": "developer", "content": "Extra context."}, {"role": "user", "content": "Hello"}, @@ -611,7 +611,10 @@ class TestGeminiGetLLMInvocationParams(unittest.TestCase): context = LLMContext(messages=messages) params = self.adapter.get_llm_invocation_params(context) - self.assertEqual(params["system_instruction"], "Extra context.") + self.assertIsNone(params["system_instruction"]) + self.assertEqual(len(params["messages"]), 2) + self.assertEqual(params["messages"][0].role, "user") + self.assertEqual(params["messages"][0].parts[0].text, "Extra context.") def test_both_system_instruction_and_system_message_warns(self): """system_instruction + initial system message warns and uses system_instruction.""" @@ -947,17 +950,22 @@ class TestAnthropicGetLLMInvocationParams(unittest.TestCase): self.assertEqual(len(params["messages"]), 1) self.assertEqual(params["messages"][0]["role"], "user") - def test_initial_developer_message_promoted(self): - """Initial developer message without system_instruction is promoted to system.""" + def test_initial_developer_message_becomes_user(self): + """Initial developer message without system_instruction becomes user, not system.""" + from anthropic import NOT_GIVEN + messages: list[LLMStandardMessage] = [ {"role": "developer", "content": "Extra context."}, + {"role": "assistant", "content": "OK"}, {"role": "user", "content": "Hello"}, ] context = LLMContext(messages=messages) params = self.adapter.get_llm_invocation_params(context, enable_prompt_caching=False) - self.assertEqual(params["system"], "Extra context.") - self.assertEqual(len(params["messages"]), 1) + self.assertEqual(params["system"], NOT_GIVEN) + self.assertEqual(len(params["messages"]), 3) + self.assertEqual(params["messages"][0]["role"], "user") + self.assertEqual(params["messages"][0]["content"], "Extra context.") def test_both_system_instruction_and_system_message_warns(self): """system_instruction + initial system message warns and uses system_instruction.""" @@ -1304,16 +1312,20 @@ class TestAWSBedrockGetLLMInvocationParams(unittest.TestCase): self.assertEqual(params["system"], [{"text": "Be helpful."}]) - def test_initial_developer_message_promoted(self): - """Initial developer message without system_instruction is promoted.""" + def test_initial_developer_message_becomes_user(self): + """Initial developer message without system_instruction becomes user, not system.""" messages: list[LLMStandardMessage] = [ {"role": "developer", "content": "Extra context."}, + {"role": "assistant", "content": "OK"}, {"role": "user", "content": "Hello"}, ] context = LLMContext(messages=messages) params = self.adapter.get_llm_invocation_params(context) - self.assertEqual(params["system"], [{"text": "Extra context."}]) + self.assertIsNone(params["system"]) + self.assertEqual(len(params["messages"]), 3) + self.assertEqual(params["messages"][0]["role"], "user") + self.assertEqual(params["messages"][0]["content"][0]["text"], "Extra context.") def test_both_system_instruction_and_system_message_warns(self): """system_instruction + initial system message warns and uses system_instruction.""" @@ -1951,54 +1963,43 @@ class TestBaseLLMAdapterHelpers(unittest.TestCase): {"role": "system", "content": "Be helpful."}, {"role": "user", "content": "Hello"}, ] - content, role = self.adapter._extract_initial_system_or_developer( - messages, system_instruction=None - ) + content = self.adapter._extract_initial_system(messages, system_instruction=None) self.assertEqual(content, "Be helpful.") - self.assertEqual(role, "system") self.assertEqual(len(messages), 1) # popped - def test_extract_developer_without_system_instruction(self): - """Developer message is extracted when no system_instruction.""" + def test_extract_developer_not_extracted(self): + """Developer message is not extracted by _extract_initial_system.""" messages = [ {"role": "developer", "content": "Context."}, {"role": "user", "content": "Hello"}, ] - content, role = self.adapter._extract_initial_system_or_developer( - messages, system_instruction=None - ) - - self.assertEqual(content, "Context.") - self.assertEqual(role, "developer") - self.assertEqual(len(messages), 1) - - def test_developer_with_system_instruction_converts_to_user(self): - """Developer message with system_instruction is converted to user, not extracted.""" - messages = [ - {"role": "developer", "content": "Context."}, - {"role": "user", "content": "Hello"}, - ] - content, role = self.adapter._extract_initial_system_or_developer( - messages, system_instruction="Be helpful." - ) + content = self.adapter._extract_initial_system(messages, system_instruction=None) self.assertIsNone(content) - self.assertIsNone(role) self.assertEqual(len(messages), 2) # not popped - self.assertEqual(messages[0]["role"], "user") # converted to user + self.assertEqual(messages[0]["role"], "developer") # unchanged + + def test_developer_with_system_instruction_not_extracted(self): + """Developer message with system_instruction is not handled by _extract_initial_system.""" + messages = [ + {"role": "developer", "content": "Context."}, + {"role": "user", "content": "Hello"}, + ] + content = self.adapter._extract_initial_system(messages, system_instruction="Be helpful.") + + self.assertIsNone(content) + self.assertEqual(len(messages), 2) # not popped + self.assertEqual(messages[0]["role"], "developer") # unchanged by helper def test_single_system_message_becomes_user(self): """Single system message is converted to user instead of extracting (empty prevention).""" messages = [ {"role": "system", "content": "Be helpful."}, ] - content, role = self.adapter._extract_initial_system_or_developer( - messages, system_instruction=None - ) + content = self.adapter._extract_initial_system(messages, system_instruction=None) self.assertIsNone(content) - self.assertIsNone(role) self.assertEqual(len(messages), 1) # not popped self.assertEqual(messages[0]["role"], "user") @@ -2010,13 +2011,10 @@ class TestBaseLLMAdapterHelpers(unittest.TestCase): 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." - ) + content = adapter._extract_initial_system(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): @@ -2024,29 +2022,23 @@ class TestBaseLLMAdapterHelpers(unittest.TestCase): messages = [ {"role": "user", "content": "Hello"}, ] - content, role = self.adapter._extract_initial_system_or_developer( - messages, system_instruction=None - ) + content = self.adapter._extract_initial_system(messages, system_instruction=None) self.assertIsNone(content) - self.assertIsNone(role) self.assertEqual(len(messages), 1) def test_empty_messages(self): """Empty messages list returns None.""" messages = [] - content, role = self.adapter._extract_initial_system_or_developer( - messages, system_instruction=None - ) + content = self.adapter._extract_initial_system(messages, system_instruction=None) self.assertIsNone(content) - self.assertIsNone(role) def test_resolve_both_system_discard(self): """Resolve with discard=True: system_instruction wins, warns.""" with patch("pipecat.adapters.base_llm_adapter.logger") as mock_logger: result = self.adapter._resolve_system_instruction( - "from context", "system", "from settings", discard_context_system=True + "from context", "from settings", discard_context_system=True ) mock_logger.warning.assert_called_once() @@ -2056,7 +2048,7 @@ class TestBaseLLMAdapterHelpers(unittest.TestCase): """Resolve with discard=False: warns but returns system_instruction.""" with patch("pipecat.adapters.base_llm_adapter.logger") as mock_logger: result = self.adapter._resolve_system_instruction( - "from context", "system", "from settings", discard_context_system=False + "from context", "from settings", discard_context_system=False ) mock_logger.warning.assert_called_once() @@ -2066,7 +2058,7 @@ class TestBaseLLMAdapterHelpers(unittest.TestCase): """Only system_instruction: returns it, no warning.""" with patch("pipecat.adapters.base_llm_adapter.logger") as mock_logger: result = self.adapter._resolve_system_instruction( - None, None, "from settings", discard_context_system=True + None, "from settings", discard_context_system=True ) mock_logger.warning.assert_not_called() @@ -2075,7 +2067,7 @@ class TestBaseLLMAdapterHelpers(unittest.TestCase): def test_resolve_only_context_system_discard(self): """Only context system (discard=True): returns it.""" result = self.adapter._resolve_system_instruction( - "from context", "system", None, discard_context_system=True + "from context", None, discard_context_system=True ) self.assertEqual(result, "from context") @@ -2083,7 +2075,7 @@ class TestBaseLLMAdapterHelpers(unittest.TestCase): def test_resolve_only_context_system_keep(self): """Only context system (discard=False): returns None (already in messages).""" result = self.adapter._resolve_system_instruction( - "from context", "system", None, discard_context_system=False + "from context", None, discard_context_system=False ) self.assertIsNone(result)