forked from boos/BoosAPI
Merge pull request #83 from ksmaze/test-gemini
fix: remove gemini unrecognized fields before sending request
This commit is contained in:
@@ -614,6 +614,105 @@ describe('buildUpstreamEndpointRequest', () => {
|
||||
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('strips unsupported openai parameters like frequency_penalty for Gemini models from downstream responses bodies', () => {
|
||||
const request = buildUpstreamEndpointRequest({
|
||||
endpoint: 'responses',
|
||||
modelName: 'gemini-1.5-pro',
|
||||
stream: false,
|
||||
tokenValue: 'sk-test',
|
||||
sitePlatform: 'gemini',
|
||||
openaiBody: {},
|
||||
downstreamFormat: 'responses',
|
||||
responsesOriginalBody: {
|
||||
model: 'gemini-1.5-pro',
|
||||
input: '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,
|
||||
},
|
||||
});
|
||||
|
||||
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);
|
||||
expect(request.body.top_p).toBe(1.0);
|
||||
});
|
||||
|
||||
it('preserves structured responses content blocks instead of flattening them', () => {
|
||||
const request = buildUpstreamEndpointRequest({
|
||||
endpoint: 'responses',
|
||||
|
||||
@@ -437,6 +437,7 @@ export function buildUpstreamEndpointRequest(input: {
|
||||
} {
|
||||
const sitePlatform = normalizePlatformName(input.sitePlatform);
|
||||
const isClaudeUpstream = sitePlatform === 'claude';
|
||||
const isGeminiUpstream = sitePlatform === 'gemini';
|
||||
|
||||
const resolveGeminiEndpointPath = (endpoint: UpstreamEndpoint): string => {
|
||||
const normalizedSiteUrl = asTrimmedString(input.siteUrl).toLowerCase();
|
||||
@@ -452,7 +453,7 @@ export function buildUpstreamEndpointRequest(input: {
|
||||
};
|
||||
|
||||
const resolveEndpointPath = (endpoint: UpstreamEndpoint): string => {
|
||||
if (sitePlatform === 'gemini') {
|
||||
if (isGeminiUpstream) {
|
||||
return resolveGeminiEndpointPath(endpoint);
|
||||
}
|
||||
|
||||
@@ -480,6 +481,25 @@ export function buildUpstreamEndpointRequest(input: {
|
||||
commonHeaders.Authorization = `Bearer ${input.tokenValue}`;
|
||||
}
|
||||
|
||||
const stripGeminiUnsupportedFields = (body: Record<string, unknown>) => {
|
||||
const next = { ...body };
|
||||
if (isGeminiUpstream) {
|
||||
for (const key of [
|
||||
'frequency_penalty',
|
||||
'presence_penalty',
|
||||
'logit_bias',
|
||||
'logprobs',
|
||||
'top_logprobs',
|
||||
'store',
|
||||
]) {
|
||||
delete next[key];
|
||||
}
|
||||
}
|
||||
return next;
|
||||
};
|
||||
|
||||
const openaiBody = stripGeminiUnsupportedFields(input.openaiBody);
|
||||
|
||||
if (input.endpoint === 'messages') {
|
||||
const claudeHeaders = input.downstreamFormat === 'claude'
|
||||
? extractClaudePassthroughHeaders(input.downstreamHeaders)
|
||||
@@ -514,7 +534,7 @@ export function buildUpstreamEndpointRequest(input: {
|
||||
const sanitizedBody = nativeClaudeBody
|
||||
?? normalizedClaudeBody
|
||||
?? sanitizeAnthropicMessagesBody(
|
||||
convertOpenAiBodyToAnthropicMessagesBody(input.openaiBody, input.modelName, input.stream),
|
||||
convertOpenAiBodyToAnthropicMessagesBody(openaiBody, input.modelName, input.stream),
|
||||
);
|
||||
|
||||
const headers = ensureStreamAcceptHeader({
|
||||
@@ -538,11 +558,11 @@ export function buildUpstreamEndpointRequest(input: {
|
||||
const rawBody = (
|
||||
input.downstreamFormat === 'responses' && input.responsesOriginalBody
|
||||
? {
|
||||
...input.responsesOriginalBody,
|
||||
...stripGeminiUnsupportedFields(input.responsesOriginalBody),
|
||||
model: input.modelName,
|
||||
stream: input.stream,
|
||||
}
|
||||
: convertOpenAiBodyToResponsesBodyViaTransformer(input.openaiBody, input.modelName, input.stream)
|
||||
: convertOpenAiBodyToResponsesBodyViaTransformer(openaiBody, input.modelName, input.stream)
|
||||
);
|
||||
const body = sanitizeResponsesBodyForProxyViaTransformer(rawBody, input.modelName, input.stream);
|
||||
|
||||
@@ -563,7 +583,7 @@ export function buildUpstreamEndpointRequest(input: {
|
||||
path: resolveEndpointPath('chat'),
|
||||
headers,
|
||||
body: {
|
||||
...input.openaiBody,
|
||||
...openaiBody,
|
||||
model: input.modelName,
|
||||
stream: input.stream,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user