fix(gemini): normalize contents and handle intermediate tool responses in Antigravity

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
decolua
2026-09-09 09:45:18 +07:00
parent eb712ca821
commit e7b5f09d50
3 changed files with 33 additions and 26 deletions

View File

@@ -432,3 +432,21 @@ export function cleanJSONSchemaForAntigravity(schema) {
return cleaned;
}
// Merge adjacent same-role messages, strip empty parts, ensure initial user turn
export function normalizeGeminiContents(contents) {
const out = [];
for (const c of contents || []) {
if (!c?.role || !Array.isArray(c.parts)) continue;
const parts = c.parts.filter(p => p && Object.keys(p).length > 0);
if (parts.length === 0) continue;
const last = out.at(-1);
if (last?.role === c.role) last.parts.push(...parts);
else out.push({ ...c, parts: [...parts] });
}
if (out.length > 0 && out[0].role !== "user") {
out.unshift({ role: "user", parts: [{ text: "..." }] });
}
return out;
}

View File

@@ -15,7 +15,8 @@ import {
generateRequestId,
generateSessionId,
generateProjectId,
cleanJSONSchemaForAntigravity
cleanJSONSchemaForAntigravity,
normalizeGeminiContents
} from "../formats/gemini.js";
import { deriveSessionId, toNumericSessionId } from "../../utils/sessionManager.js";
import { ROLE, GEMINI_ROLE, OPENAI_BLOCK, CLAUDE_BLOCK } from "../schema/index.js";
@@ -35,17 +36,6 @@ function sanitizeGeminiFunctionName(name) {
return sanitized.substring(0, 64);
}
function normalizeGeminiContents(contents) {
const out = [];
for (const c of contents || []) {
if (!c?.role || !Array.isArray(c.parts) || c.parts.length === 0) continue;
const last = out.at(-1);
if (last?.role === c.role) last.parts.push(...c.parts);
else out.push({ ...c, parts: [...c.parts] });
}
return out;
}
// Core: Convert OpenAI request to Gemini format (base for all variants)
function openaiToGeminiBase(model, body, stream, signature = DEFAULT_THINKING_AG_SIGNATURE, sessionId = null) {
const result = {
@@ -163,12 +153,14 @@ function openaiToGeminiBase(model, body, stream, signature = DEFAULT_THINKING_AG
}
// Check if there are actual tool responses in the next messages
const hasActualResponses = toolCallIds.some(fid => toolResponses[fid]);
const isIntermediate = i < body.messages.length - 1;
const hasActualResponses = toolCallIds.some(fid => toolResponses[fid] !== undefined);
if (hasActualResponses) {
if (hasActualResponses || isIntermediate) {
const toolParts = [];
for (const fid of toolCallIds) {
if (!toolResponses[fid]) continue;
let resp = toolResponses[fid];
if (resp === undefined) resp = "";
let name = tcID2Name[fid];
if (!name) {
@@ -180,7 +172,6 @@ function openaiToGeminiBase(model, body, stream, signature = DEFAULT_THINKING_AG
}
}
let resp = toolResponses[fid];
let parsedResp = tryParseJSON(resp);
if (parsedResp === null) {
parsedResp = { result: resp };