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"
|
||||
|
||||
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:
|
||||
"""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.
|
||||
system_instruction: Optional system instruction from service settings
|
||||
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:
|
||||
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:
|
||||
# Detect initial system message for warning purposes (don't extract)
|
||||
@@ -131,7 +140,10 @@ class OpenAILLMAdapter(BaseLLMAdapter[OpenAILLMInvocationParams]):
|
||||
return msgs
|
||||
|
||||
def _from_universal_context_messages(
|
||||
self, messages: List[LLMContextMessage]
|
||||
self,
|
||||
messages: List[LLMContextMessage],
|
||||
*,
|
||||
convert_developer_to_user: bool,
|
||||
) -> List[ChatCompletionMessageParam]:
|
||||
result = []
|
||||
for message in messages:
|
||||
@@ -141,6 +153,12 @@ class OpenAILLMAdapter(BaseLLMAdapter[OpenAILLMInvocationParams]):
|
||||
else:
|
||||
# Standard message, pass through unchanged
|
||||
result.append(message)
|
||||
|
||||
if convert_developer_to_user:
|
||||
for msg in result:
|
||||
if msg.get("role") == "developer":
|
||||
msg["role"] = "user"
|
||||
|
||||
return result
|
||||
|
||||
def _from_standard_tool_choice(
|
||||
|
||||
@@ -50,7 +50,11 @@ class PerplexityLLMAdapter(OpenAILLMAdapter):
|
||||
"""
|
||||
|
||||
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:
|
||||
"""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.
|
||||
system_instruction: Optional system instruction from service settings
|
||||
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:
|
||||
Dictionary of parameters for Perplexity's ChatCompletion API, with
|
||||
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"]))
|
||||
return params
|
||||
|
||||
@@ -109,11 +119,8 @@ class PerplexityLLMAdapter(OpenAILLMAdapter):
|
||||
|
||||
messages = copy.deepcopy(messages)
|
||||
|
||||
# Step 0: Convert "developer" messages to "user".
|
||||
# Perplexity doesn't support the "developer" role.
|
||||
for msg in messages:
|
||||
if msg.get("role") == "developer":
|
||||
msg["role"] = "user"
|
||||
# Note: "developer" → "user" conversion is handled by the parent adapter
|
||||
# via the convert_developer_to_user parameter.
|
||||
|
||||
# Step 1: Convert non-initial system messages to "user".
|
||||
# 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.
|
||||
"""
|
||||
|
||||
# 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: Settings
|
||||
|
||||
|
||||
@@ -71,6 +71,15 @@ class BaseOpenAILLMService(LLMService):
|
||||
Settings = OpenAILLMSettings
|
||||
_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):
|
||||
"""Input parameters for OpenAI model configuration.
|
||||
|
||||
@@ -351,7 +360,9 @@ class BaseOpenAILLMService(LLMService):
|
||||
if isinstance(context, LLMContext):
|
||||
adapter = self.get_llm_adapter()
|
||||
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:
|
||||
invocation_params = OpenAILLMInvocationParams(
|
||||
@@ -421,7 +432,9 @@ class BaseOpenAILLMService(LLMService):
|
||||
)
|
||||
|
||||
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)
|
||||
|
||||
|
||||
@@ -41,6 +41,9 @@ class PerplexityLLMService(OpenAILLMService):
|
||||
"""
|
||||
|
||||
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: Settings
|
||||
|
||||
Reference in New Issue
Block a user