fix: handle system messages in OpenAI proxy (#1403)

This commit is contained in:
Halil Ertekin
2026-05-28 22:08:07 -04:00
committed by GitHub
parent e22424097e
commit f42aee9a20
4 changed files with 213 additions and 6 deletions
+81 -3
View File
@@ -42,15 +42,93 @@ function isDirectOpenAIReasoningChatModel(
);
}
function isMiniMaxOpenAICompatProfile(profile: OpenAICompatProfileConfig): boolean {
try {
return new URL(profile.baseUrl).hostname.toLowerCase().includes('minimax');
} catch {
return false;
}
}
function prependTextToContent(
content: ProxyOpenAIRequest['messages'][number]['content'],
text: string
): ProxyOpenAIRequest['messages'][number]['content'] {
if (Array.isArray(content)) {
return [{ type: 'text', text }, ...content];
}
if (typeof content === 'string') {
return `${text}\n\n${content}`;
}
return text;
}
function extractTextContent(content: ProxyOpenAIRequest['messages'][number]['content']): string {
if (typeof content === 'string') {
return content;
}
if (!Array.isArray(content)) {
return '';
}
return content
.filter((part): part is { type: 'text'; text: string } => part.type === 'text')
.map((part) => part.text)
.join('\n\n');
}
function shapeMiniMaxChatPayload(payload: ProxyOpenAIRequest): ProxyOpenAIRequest {
const systemMessages: string[] = [];
let removedSystemMessage = false;
const messages = payload.messages.filter((message) => {
if (message.role !== 'system') {
return true;
}
removedSystemMessage = true;
const systemText = extractTextContent(message.content).trim();
if (systemText.length > 0) {
systemMessages.push(systemText);
}
return false;
});
if (!removedSystemMessage) {
return payload;
}
if (systemMessages.length === 0) {
return { ...payload, messages };
}
const systemPrefix = systemMessages.join('\n\n');
const firstUserIndex = messages.findIndex((message) => message.role === 'user');
if (firstUserIndex >= 0) {
messages[firstUserIndex] = {
...messages[firstUserIndex],
content: prependTextToContent(messages[firstUserIndex].content, systemPrefix),
};
} else {
messages.unshift({ role: 'user', content: systemPrefix });
}
return { ...payload, messages };
}
function shapeUpstreamChatPayload(
payload: ProxyOpenAIRequest,
profile: OpenAICompatProfileConfig
): ProxyOpenAIRequest {
if (!isDirectOpenAIReasoningChatModel(profile, payload.model)) {
return payload;
let shaped = payload;
if (isMiniMaxOpenAICompatProfile(profile)) {
shaped = shapeMiniMaxChatPayload(shaped);
}
const shaped = { ...payload };
if (!isDirectOpenAIReasoningChatModel(profile, shaped.model)) {
return shaped;
}
shaped = { ...shaped };
if (shaped.max_tokens !== undefined) {
shaped.max_completion_tokens = shaped.max_tokens;
+11 -3
View File
@@ -40,7 +40,7 @@ type AnthropicContentBlock =
| { type: string; [key: string]: unknown };
interface AnthropicMessage {
role?: 'user' | 'assistant' | string;
role?: 'system' | 'user' | 'assistant' | string;
content?: string | AnthropicContentBlock[];
}
@@ -435,8 +435,8 @@ function transformMessages(messagesValue: unknown): OpenAIMessage[] {
messagesValue.forEach((message, messageIndex) => {
const parsedMessage = assertObject(message, `messages[${messageIndex}]`) as AnthropicMessage;
const role = parsedMessage.role;
if (role !== 'user' && role !== 'assistant') {
throw new Error(`messages[${messageIndex}].role must be "user" or "assistant"`);
if (role !== 'system' && role !== 'user' && role !== 'assistant') {
throw new Error(`messages[${messageIndex}].role must be "system", "user", or "assistant"`);
}
if (pendingToolUseIds && pendingToolUseIds.size > 0 && role !== 'user') {
@@ -446,6 +446,14 @@ function transformMessages(messagesValue: unknown): OpenAIMessage[] {
}
const content = parsedMessage.content;
if (role === 'system') {
translatedMessages.push({
role: 'system',
content: flattenTextContent(content, `messages[${messageIndex}].content`),
});
return;
}
if (typeof content === 'string') {
if (pendingToolUseIds && pendingToolUseIds.size > 0) {
throw new Error(