|
|
|
|
|
import config from '../../config/config.js'; |
|
|
import { generateRequestId } from '../idGenerator.js'; |
|
|
import { convertGeminiToolsToAntigravity } from '../toolConverter.js'; |
|
|
import { getSignatureContext, createThoughtPart, modelMapping, isEnableThinking } from './common.js'; |
|
|
import { normalizeGeminiParameters, toGenerationConfig } from '../parameterNormalizer.js'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function generateFunctionCallId() { |
|
|
return `call_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function processFunctionCallIds(contents) { |
|
|
const functionCallIds = []; |
|
|
|
|
|
|
|
|
contents.forEach(content => { |
|
|
if (content.role === 'model' && content.parts && Array.isArray(content.parts)) { |
|
|
content.parts.forEach(part => { |
|
|
if (part.functionCall) { |
|
|
if (!part.functionCall.id) { |
|
|
part.functionCall.id = generateFunctionCallId(); |
|
|
} |
|
|
functionCallIds.push(part.functionCall.id); |
|
|
} |
|
|
}); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
let responseIndex = 0; |
|
|
contents.forEach(content => { |
|
|
if (content.role === 'user' && content.parts && Array.isArray(content.parts)) { |
|
|
content.parts.forEach(part => { |
|
|
if (part.functionResponse) { |
|
|
if (!part.functionResponse.id && responseIndex < functionCallIds.length) { |
|
|
part.functionResponse.id = functionCallIds[responseIndex]; |
|
|
responseIndex++; |
|
|
} |
|
|
} |
|
|
}); |
|
|
} |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function processModelThoughts(content, reasoningSignature, toolSignature) { |
|
|
const parts = content.parts; |
|
|
|
|
|
|
|
|
let thoughtIndex = -1; |
|
|
let signatureIndex = -1; |
|
|
let signatureValue = null; |
|
|
|
|
|
for (let i = 0; i < parts.length; i++) { |
|
|
const part = parts[i]; |
|
|
if (part.thought === true && !part.thoughtSignature) { |
|
|
thoughtIndex = i; |
|
|
} |
|
|
if (part.thoughtSignature && !part.thought) { |
|
|
signatureIndex = i; |
|
|
signatureValue = part.thoughtSignature; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (thoughtIndex !== -1 && signatureIndex !== -1) { |
|
|
parts[thoughtIndex].thoughtSignature = signatureValue; |
|
|
parts.splice(signatureIndex, 1); |
|
|
} else if (thoughtIndex !== -1 && signatureIndex === -1) { |
|
|
parts[thoughtIndex].thoughtSignature = reasoningSignature; |
|
|
} else if (thoughtIndex === -1) { |
|
|
parts.unshift(createThoughtPart(' ', reasoningSignature)); |
|
|
} |
|
|
|
|
|
|
|
|
const standaloneSignatures = []; |
|
|
for (let i = parts.length - 1; i >= 0; i--) { |
|
|
const part = parts[i]; |
|
|
if (part.thoughtSignature && !part.thought && !part.functionCall && !part.text) { |
|
|
standaloneSignatures.unshift({ index: i, signature: part.thoughtSignature }); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
let sigIndex = 0; |
|
|
for (let i = 0; i < parts.length; i++) { |
|
|
const part = parts[i]; |
|
|
if (part.functionCall && !part.thoughtSignature) { |
|
|
if (sigIndex < standaloneSignatures.length) { |
|
|
part.thoughtSignature = standaloneSignatures[sigIndex].signature; |
|
|
sigIndex++; |
|
|
} else { |
|
|
part.thoughtSignature = toolSignature; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
for (let i = standaloneSignatures.length - 1; i >= 0; i--) { |
|
|
if (i < sigIndex) { |
|
|
parts.splice(standaloneSignatures[i].index, 1); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
export function generateGeminiRequestBody(geminiBody, modelName, token) { |
|
|
const enableThinking = isEnableThinking(modelName); |
|
|
const actualModelName = modelMapping(modelName); |
|
|
const request = JSON.parse(JSON.stringify(geminiBody)); |
|
|
|
|
|
if (request.contents && Array.isArray(request.contents)) { |
|
|
processFunctionCallIds(request.contents); |
|
|
|
|
|
if (enableThinking) { |
|
|
const { reasoningSignature, toolSignature } = getSignatureContext(token.sessionId, actualModelName); |
|
|
|
|
|
request.contents.forEach(content => { |
|
|
if (content.role === 'model' && content.parts && Array.isArray(content.parts)) { |
|
|
processModelThoughts(content, reasoningSignature, toolSignature); |
|
|
} |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const normalizedParams = normalizeGeminiParameters(request.generationConfig || {}); |
|
|
|
|
|
|
|
|
request.generationConfig = toGenerationConfig(normalizedParams, enableThinking, actualModelName); |
|
|
request.sessionId = token.sessionId; |
|
|
delete request.safetySettings; |
|
|
|
|
|
|
|
|
if (request.tools && Array.isArray(request.tools)) { |
|
|
request.tools = convertGeminiToolsToAntigravity(request.tools, token.sessionId, actualModelName); |
|
|
} |
|
|
|
|
|
|
|
|
if (request.tools && request.tools.length > 0 && !request.toolConfig) { |
|
|
request.toolConfig = { functionCallingConfig: { mode: 'VALIDATED' } }; |
|
|
} |
|
|
|
|
|
const existingText = request.systemInstruction?.parts?.[0]?.text || ''; |
|
|
const mergedText = existingText ? `${config.systemInstruction}\n\n${existingText}` : config.systemInstruction ?? ""; |
|
|
request.systemInstruction = { |
|
|
role: 'user', |
|
|
parts: [{ text: mergedText }] |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const requestBody = { |
|
|
project: token.projectId, |
|
|
requestId: generateRequestId(), |
|
|
request: request, |
|
|
model: actualModelName, |
|
|
userAgent: 'antigravity' |
|
|
}; |
|
|
|
|
|
return requestBody; |
|
|
} |
|
|
|