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
+104
View File
@@ -97,6 +97,12 @@ beforeEach(() => {
ANTHROPIC_MODEL: 'sonar-pro',
CCS_DROID_PROVIDER: 'generic-chat-completion-api',
}),
mm: writeSettings('mm', {
ANTHROPIC_BASE_URL: 'https://api.minimax.io/v1',
ANTHROPIC_AUTH_TOKEN: 'minimax_token',
ANTHROPIC_MODEL: 'MiniMax-M2.7',
CCS_DROID_PROVIDER: 'openai',
}),
};
fs.writeFileSync(
@@ -242,4 +248,102 @@ describe('handleProxyMessagesRequest', () => {
expect(closeCalls).toBe(0);
expect(res.statusCode).toBe(502);
});
it('moves system messages into the first user message for MiniMax OpenAI-compatible upstreams', async () => {
const activeProfile = buildProfile('mm');
let capturedBody: unknown;
globalThis.fetch = (async (_input: RequestInfo | URL, init?: RequestInit) => {
capturedBody = JSON.parse(String(init?.body));
return new Response(
JSON.stringify({
id: 'chatcmpl_1',
object: 'chat.completion',
created: 1,
model: 'MiniMax-M2.7',
choices: [{ index: 0, message: { role: 'assistant', content: 'ok' } }],
}),
{ status: 200, headers: { 'content-type': 'application/json' } }
);
}) as typeof globalThis.fetch;
const req = new FakeRequest({
'x-api-key': 'local-token',
});
const res = new FakeResponse();
const pending = handleProxyMessagesRequest(
req as never,
res as never,
activeProfile,
'local-token'
);
req.end(
JSON.stringify({
model: 'MiniMax-M2.7',
stream: false,
messages: [
{ role: 'system', content: 'Use Turkish.' },
{ role: 'user', content: 'bu hangi model' },
],
})
);
await pending;
expect(capturedBody).toMatchObject({
model: 'MiniMax-M2.7',
messages: [{ role: 'user', content: 'Use Turkish.\n\nbu hangi model' }],
});
expect((capturedBody as { messages: Array<{ role: string }> }).messages).not.toContainEqual(
expect.objectContaining({ role: 'system' })
);
});
it('strips blank system messages for MiniMax OpenAI-compatible upstreams', async () => {
const activeProfile = buildProfile('mm');
let capturedBody: unknown;
globalThis.fetch = (async (_input: RequestInfo | URL, init?: RequestInit) => {
capturedBody = JSON.parse(String(init?.body));
return new Response(
JSON.stringify({
id: 'chatcmpl_1',
object: 'chat.completion',
created: 1,
model: 'MiniMax-M2.7',
choices: [{ index: 0, message: { role: 'assistant', content: 'ok' } }],
}),
{ status: 200, headers: { 'content-type': 'application/json' } }
);
}) as typeof globalThis.fetch;
const req = new FakeRequest({
'x-api-key': 'local-token',
});
const res = new FakeResponse();
const pending = handleProxyMessagesRequest(
req as never,
res as never,
activeProfile,
'local-token'
);
req.end(
JSON.stringify({
model: 'MiniMax-M2.7',
stream: false,
messages: [
{ role: 'system', content: [{ type: 'text', text: '' }] },
{ role: 'user', content: 'bu hangi model' },
],
})
);
await pending;
expect(capturedBody).toMatchObject({
model: 'MiniMax-M2.7',
messages: [{ role: 'user', content: 'bu hangi model' }],
});
expect((capturedBody as { messages: Array<{ role: string }> }).messages).not.toContainEqual(
expect.objectContaining({ role: 'system' })
);
});
});
@@ -43,6 +43,23 @@ describe('ProxyRequestTransformer', () => {
});
});
it('accepts Claude Code system messages in the messages array', () => {
const transformer = new ProxyRequestTransformer();
const result = transformer.transform({
messages: [
{ role: 'user', content: 'hello' },
{ role: 'system', content: [{ type: 'text', text: 'answer tersely' }] },
{ role: 'user', content: 'which model is this?' },
],
});
expect(result.messages).toEqual([
{ role: 'user', content: 'hello' },
{ role: 'system', content: 'answer tersely' },
{ role: 'user', content: 'which model is this?' },
]);
});
it('translates base64 image blocks into OpenAI image_url parts', () => {
const transformer = new ProxyRequestTransformer();
const result = transformer.transform({