In GeminiLLMAdapter, when translating from the universal LLMContext format, only pull out the first "system" message as the system instruction, and convert subsequent ones into "user" messages. This is a more correct thing to do than simply drop subsequent "system" messages, especially when potentially sharing a context between multiple LLMs.

This commit is contained in:
Paul Kompfner
2025-08-21 16:56:32 -04:00
parent 04a50df3d5
commit a0a2bb3aa4

View File

@@ -161,7 +161,9 @@ class GeminiLLMAdapter(BaseLLMAdapter[GeminiLLMInvocationParams]):
continue continue
# Convert standard format to Google format # Convert standard format to Google format
converted = self._from_standard_message(message) converted = self._from_standard_message(
message, already_have_system_instruction=bool(system_instruction)
)
if isinstance(converted, Content): if isinstance(converted, Content):
# Regular (non-system) message # Regular (non-system) message
messages.append(converted) messages.append(converted)
@@ -187,7 +189,9 @@ class GeminiLLMAdapter(BaseLLMAdapter[GeminiLLMInvocationParams]):
return self.ConvertedMessages(messages=messages, system_instruction=system_instruction) return self.ConvertedMessages(messages=messages, system_instruction=system_instruction)
def _from_standard_message(self, message: LLMStandardMessage) -> Content | str: def _from_standard_message(
self, message: LLMStandardMessage, already_have_system_instruction: bool
) -> Content | str:
"""Convert universal context message to Google Content object. """Convert universal context message to Google Content object.
Handles conversion of text, images, and function calls to Google's Handles conversion of text, images, and function calls to Google's
@@ -196,6 +200,7 @@ class GeminiLLMAdapter(BaseLLMAdapter[GeminiLLMInvocationParams]):
Args: Args:
message: Message in universal context format. message: Message in universal context format.
already_have_system_instruction: Whether we already have a system instruction
Returns: Returns:
Content object with role and parts, or a plain string for system Content object with role and parts, or a plain string for system
@@ -240,12 +245,15 @@ class GeminiLLMAdapter(BaseLLMAdapter[GeminiLLMInvocationParams]):
role = message["role"] role = message["role"]
content = message.get("content", []) content = message.get("content", [])
if role == "system": if role == "system":
# System instructions are returned as plain text if already_have_system_instruction:
if isinstance(content, str): role = "user" # Convert system message to user role if we already have a system instruction
return content else:
elif isinstance(content, list): # System instructions are returned as plain text
# If content is a list, we assume it's a list of text parts, per the standard if isinstance(content, str):
return " ".join(part["text"] for part in content if part.get("type") == "text") return content
elif isinstance(content, list):
# If content is a list, we assume it's a list of text parts, per the standard
return " ".join(part["text"] for part in content if part.get("type") == "text")
elif role == "assistant": elif role == "assistant":
role = "model" role = "model"