Spaces:
Running
Running
Fix system message handling to preserve user-configured system prompts (#1764)
Browse filesPreviously, 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
|
| 205 |
-
|
| 206 |
-
}
|
| 207 |
|
| 208 |
-
if (
|
| 209 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 210 |
}
|
| 211 |
|
| 212 |
-
//
|
| 213 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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,
|