1
0
forked from boos/BoosAPI

fix: remove gemini unrecognized fields before sending request

This commit is contained in:
ksmaze
2026-03-14 21:39:36 -07:00
parent 5da3fbf874
commit e227fc0dd3
2 changed files with 85 additions and 4 deletions
@@ -614,6 +614,71 @@ describe('buildUpstreamEndpointRequest', () => {
expect(request.headers['Content-Type']).toBe('application/json'); expect(request.headers['Content-Type']).toBe('application/json');
}); });
it('strips unsupported openai parameters like frequency_penalty for Gemini models on chat endpoints', () => {
const request = buildUpstreamEndpointRequest({
endpoint: 'chat',
modelName: 'gemini-1.5-pro',
stream: false,
tokenValue: 'sk-test',
sitePlatform: 'gemini',
openaiBody: {
model: 'gemini-1.5-pro',
messages: [{ role: 'user', content: 'hello' }],
frequency_penalty: 0.5,
presence_penalty: 0.2,
logit_bias: { '100': 1 },
logprobs: true,
top_logprobs: 2,
store: true,
temperature: 0.8,
top_p: 1.0,
},
downstreamFormat: 'openai',
});
expect(request.path).toBe('/v1beta/openai/chat/completions');
expect(request.body.frequency_penalty).toBeUndefined();
expect(request.body.presence_penalty).toBeUndefined();
expect(request.body.logit_bias).toBeUndefined();
expect(request.body.logprobs).toBeUndefined();
expect(request.body.top_logprobs).toBeUndefined();
expect(request.body.store).toBeUndefined();
expect(request.body.temperature).toBe(0.8);
expect(request.body.top_p).toBe(1.0);
});
it('strips unsupported openai parameters like frequency_penalty for Gemini models on responses endpoints', () => {
const request = buildUpstreamEndpointRequest({
endpoint: 'responses',
modelName: 'gemini-1.5-pro',
stream: false,
tokenValue: 'sk-test',
sitePlatform: 'gemini',
openaiBody: {
model: 'gemini-1.5-pro',
messages: [{ role: 'user', content: 'hello' }],
frequency_penalty: 0.5,
presence_penalty: 0.2,
logit_bias: { '100': 1 },
logprobs: true,
top_logprobs: 2,
store: true,
temperature: 0.8,
top_p: 1.0,
},
downstreamFormat: 'openai',
});
expect(request.path).toBe('/v1beta/openai/responses');
expect(request.body.frequency_penalty).toBeUndefined();
expect(request.body.presence_penalty).toBeUndefined();
expect(request.body.logit_bias).toBeUndefined();
expect(request.body.logprobs).toBeUndefined();
expect(request.body.top_logprobs).toBeUndefined();
expect(request.body.store).toBeUndefined();
expect(request.body.temperature).toBe(0.8);
});
it('preserves structured responses content blocks instead of flattening them', () => { it('preserves structured responses content blocks instead of flattening them', () => {
const request = buildUpstreamEndpointRequest({ const request = buildUpstreamEndpointRequest({
endpoint: 'responses', endpoint: 'responses',
+20 -4
View File
@@ -437,6 +437,7 @@ export function buildUpstreamEndpointRequest(input: {
} { } {
const sitePlatform = normalizePlatformName(input.sitePlatform); const sitePlatform = normalizePlatformName(input.sitePlatform);
const isClaudeUpstream = sitePlatform === 'claude'; const isClaudeUpstream = sitePlatform === 'claude';
const isGeminiUpstream = sitePlatform === 'gemini';
const resolveGeminiEndpointPath = (endpoint: UpstreamEndpoint): string => { const resolveGeminiEndpointPath = (endpoint: UpstreamEndpoint): string => {
const normalizedSiteUrl = asTrimmedString(input.siteUrl).toLowerCase(); const normalizedSiteUrl = asTrimmedString(input.siteUrl).toLowerCase();
@@ -452,7 +453,7 @@ export function buildUpstreamEndpointRequest(input: {
}; };
const resolveEndpointPath = (endpoint: UpstreamEndpoint): string => { const resolveEndpointPath = (endpoint: UpstreamEndpoint): string => {
if (sitePlatform === 'gemini') { if (isGeminiUpstream) {
return resolveGeminiEndpointPath(endpoint); return resolveGeminiEndpointPath(endpoint);
} }
@@ -480,6 +481,21 @@ export function buildUpstreamEndpointRequest(input: {
commonHeaders.Authorization = `Bearer ${input.tokenValue}`; commonHeaders.Authorization = `Bearer ${input.tokenValue}`;
} }
const openaiBody = { ...input.openaiBody };
if (isGeminiUpstream) {
const blacklist = [
'frequency_penalty',
'presence_penalty',
'logit_bias',
'logprobs',
'top_logprobs',
'store',
];
for (const key of blacklist) {
delete openaiBody[key];
}
}
if (input.endpoint === 'messages') { if (input.endpoint === 'messages') {
const claudeHeaders = input.downstreamFormat === 'claude' const claudeHeaders = input.downstreamFormat === 'claude'
? extractClaudePassthroughHeaders(input.downstreamHeaders) ? extractClaudePassthroughHeaders(input.downstreamHeaders)
@@ -514,7 +530,7 @@ export function buildUpstreamEndpointRequest(input: {
const sanitizedBody = nativeClaudeBody const sanitizedBody = nativeClaudeBody
?? normalizedClaudeBody ?? normalizedClaudeBody
?? sanitizeAnthropicMessagesBody( ?? sanitizeAnthropicMessagesBody(
convertOpenAiBodyToAnthropicMessagesBody(input.openaiBody, input.modelName, input.stream), convertOpenAiBodyToAnthropicMessagesBody(openaiBody, input.modelName, input.stream),
); );
const headers = ensureStreamAcceptHeader({ const headers = ensureStreamAcceptHeader({
@@ -542,7 +558,7 @@ export function buildUpstreamEndpointRequest(input: {
model: input.modelName, model: input.modelName,
stream: input.stream, stream: input.stream,
} }
: convertOpenAiBodyToResponsesBodyViaTransformer(input.openaiBody, input.modelName, input.stream) : convertOpenAiBodyToResponsesBodyViaTransformer(openaiBody, input.modelName, input.stream)
); );
const body = sanitizeResponsesBodyForProxyViaTransformer(rawBody, input.modelName, input.stream); const body = sanitizeResponsesBodyForProxyViaTransformer(rawBody, input.modelName, input.stream);
@@ -563,7 +579,7 @@ export function buildUpstreamEndpointRequest(input: {
path: resolveEndpointPath('chat'), path: resolveEndpointPath('chat'),
headers, headers,
body: { body: {
...input.openaiBody, ...openaiBody,
model: input.modelName, model: input.modelName,
stream: input.stream, stream: input.stream,
}, },