stoXe nsarrazin commited on
Commit
bdb443a
·
unverified ·
1 Parent(s): f6a70cc

Fix system message handling to preserve user-configured system prompts (#1764)

Browse files

Previously, when a preprompt was provided, it would completely replace any user-configured system message instead of being prepended to it.

Co-authored-by: Nathan Sarrazin <sarrazin.nathan@gmail.com>

src/lib/server/endpoints/openai/endpointOai.ts CHANGED
@@ -198,25 +198,42 @@ export async function endpointOai(
198
  toolResults,
199
  conversationId,
200
  }) => {
 
201
  let messagesOpenAI: OpenAI.Chat.Completions.ChatCompletionMessageParam[] =
202
  await prepareMessages(messages, imageProcessor, !model.tools && model.multimodal);
203
 
204
- if (messagesOpenAI?.[0]?.role !== "system") {
205
- messagesOpenAI = [{ role: "system", content: "" }, ...messagesOpenAI];
206
- }
207
 
208
- if (messagesOpenAI?.[0]) {
209
- messagesOpenAI[0].content = preprompt ?? "";
 
 
 
 
 
 
 
 
 
 
210
  }
211
 
212
- // if system role is not supported, convert first message to a user message.
213
- if (!model.systemRoleSupported && messagesOpenAI?.[0]?.role === "system") {
 
 
 
 
 
214
  messagesOpenAI[0] = {
215
  ...messagesOpenAI[0],
216
  role: "user",
217
  };
218
  }
219
 
 
 
220
  if (toolResults && toolResults.length > 0) {
221
  const toolCallRequests: OpenAI.Chat.Completions.ChatCompletionAssistantMessageParam = {
222
  role: "assistant",
@@ -253,12 +270,14 @@ export async function endpointOai(
253
  messagesOpenAI.push(...responses);
254
  }
255
 
 
256
  const parameters = { ...model.parameters, ...generateSettings };
257
  const toolCallChoices = createChatCompletionToolsArray(tools);
258
  const body = {
259
  model: model.id ?? model.name,
260
  messages: messagesOpenAI,
261
  stream: streamingSupported,
 
262
  ...(useCompletionTokens
263
  ? { max_completion_tokens: parameters?.max_new_tokens }
264
  : { max_tokens: parameters?.max_new_tokens }),
@@ -267,9 +286,11 @@ export async function endpointOai(
267
  top_p: parameters?.top_p,
268
  frequency_penalty: parameters?.repetition_penalty,
269
  presence_penalty: parameters?.presence_penalty,
 
270
  ...(toolCallChoices.length > 0 ? { tools: toolCallChoices, tool_choice: "auto" } : {}),
271
  };
272
 
 
273
  if (streamingSupported) {
274
  const openChatAICompletion = await openai.chat.completions.create(
275
  body as ChatCompletionCreateParamsStreaming,
 
198
  toolResults,
199
  conversationId,
200
  }) => {
201
+ // Format messages for the chat API, handling multimodal content if supported
202
  let messagesOpenAI: OpenAI.Chat.Completions.ChatCompletionMessageParam[] =
203
  await prepareMessages(messages, imageProcessor, !model.tools && model.multimodal);
204
 
205
+ // Check if a system message already exists as the first message
206
+ const hasSystemMessage = messagesOpenAI.length > 0 && messagesOpenAI[0]?.role === "system";
 
207
 
208
+ if (hasSystemMessage) {
209
+ // System message exists - preserve user configuration
210
+ if (preprompt !== undefined) {
211
+ // Prepend preprompt to existing system message if preprompt exists
212
+ const userSystemPrompt = messagesOpenAI[0].content || "";
213
+ messagesOpenAI[0].content =
214
+ preprompt + (userSystemPrompt ? "\n\n" + userSystemPrompt : "");
215
+ }
216
+ // If no preprompt, user's system message remains unchanged
217
+ } else {
218
+ // No system message exists - create a new one with preprompt or empty string
219
+ messagesOpenAI = [{ role: "system", content: preprompt ?? "" }, ...messagesOpenAI];
220
  }
221
 
222
+ // Handle models that don't support system role by converting to user message
223
+ // This maintains compatibility with older or non-standard models
224
+ if (
225
+ !model.systemRoleSupported &&
226
+ messagesOpenAI.length > 0 &&
227
+ messagesOpenAI[0]?.role === "system"
228
+ ) {
229
  messagesOpenAI[0] = {
230
  ...messagesOpenAI[0],
231
  role: "user",
232
  };
233
  }
234
 
235
+ // Format tool results for the API to provide context for follow-up tool calls
236
+ // This creates the full conversation flow needed for multi-step tool interactions
237
  if (toolResults && toolResults.length > 0) {
238
  const toolCallRequests: OpenAI.Chat.Completions.ChatCompletionAssistantMessageParam = {
239
  role: "assistant",
 
270
  messagesOpenAI.push(...responses);
271
  }
272
 
273
+ // Combine model defaults with request-specific parameters
274
  const parameters = { ...model.parameters, ...generateSettings };
275
  const toolCallChoices = createChatCompletionToolsArray(tools);
276
  const body = {
277
  model: model.id ?? model.name,
278
  messages: messagesOpenAI,
279
  stream: streamingSupported,
280
+ // Support two different ways of specifying token limits depending on the model
281
  ...(useCompletionTokens
282
  ? { max_completion_tokens: parameters?.max_new_tokens }
283
  : { max_tokens: parameters?.max_new_tokens }),
 
286
  top_p: parameters?.top_p,
287
  frequency_penalty: parameters?.repetition_penalty,
288
  presence_penalty: parameters?.presence_penalty,
289
+ // Only include tool configuration if tools are provided
290
  ...(toolCallChoices.length > 0 ? { tools: toolCallChoices, tool_choice: "auto" } : {}),
291
  };
292
 
293
+ // Handle both streaming and non-streaming responses with appropriate processors
294
  if (streamingSupported) {
295
  const openChatAICompletion = await openai.chat.completions.create(
296
  body as ChatCompletionCreateParamsStreaming,