@@ -369,7 +369,37 @@ function sanitizeRequestPayloadForAntigravity(payload: Record<string, unknown>):
369369
370370 const contentRecord = content as Record < string , unknown > ;
371371 const rawParts = Array . isArray ( contentRecord . parts ) ? contentRecord . parts : [ ] ;
372- const sanitizedParts = rawParts . filter ( isValidRequestPart ) ;
372+ let foundFirstFunctionCall = false ;
373+
374+ const sanitizedParts = rawParts . filter ( isValidRequestPart ) . map ( ( part : any ) => {
375+ if ( part && typeof part === "object" && part . functionCall ) {
376+ let sig = part . thoughtSignature || part . thought_signature ;
377+
378+ // Only the first functionCall part in a block should have the signature.
379+ // If it's the first one and missing a valid signature, inject the sentinel
380+ // to prevent the API from rejecting the request with a 400 error.
381+ if ( ! foundFirstFunctionCall ) {
382+ foundFirstFunctionCall = true ;
383+ if ( ! sig || sig . length < MIN_SIGNATURE_LENGTH ) {
384+ sig = SKIP_THOUGHT_SIGNATURE ;
385+ }
386+ } else {
387+ // Parallel function calls MUST NOT have a signature
388+ sig = undefined ;
389+ }
390+
391+ if ( sig ) {
392+ return { ...part , thought_signature : sig , thoughtSignature : sig } ;
393+ }
394+
395+ // If not the first part, just return the part without adding any signature keys
396+ const newPart = { ...part } ;
397+ delete newPart . thoughtSignature ;
398+ delete newPart . thought_signature ;
399+ return newPart ;
400+ }
401+ return part ;
402+ } ) ;
373403
374404 if ( sanitizedParts . length === 0 ) {
375405 return null ;
@@ -1237,29 +1267,6 @@ export function prepareAntigravityRequest(
12371267 const conversationKey = resolveConversationKey ( requestPayload ) ;
12381268 signatureSessionKey = buildSignatureSessionKey ( PLUGIN_SESSION_ID , effectiveModel , conversationKey , resolveProjectKey ( projectId ) ) ;
12391269
1240- // Ensure thoughtSignature is present on all functionCall parts if at least one part has it
1241- // This is required by Gemini 3.1 Pro which otherwise fails with 400 Bad Request
1242- if ( Array . isArray ( requestPayload . contents ) ) {
1243- requestPayload . contents = requestPayload . contents . map ( ( content : any ) => {
1244- if ( ! content || ! Array . isArray ( content . parts ) ) return content ;
1245-
1246- // Find if any part has a thoughtSignature
1247- const signature = content . parts . find ( ( p : any ) => p && typeof p === "object" && typeof p . thoughtSignature === "string" ) ?. thoughtSignature ;
1248-
1249- if ( signature ) {
1250- const newParts = content . parts . map ( ( p : any ) => {
1251- if ( p && typeof p === "object" && p . functionCall && ! p . thoughtSignature ) {
1252- return { ...p , thoughtSignature : signature } ;
1253- }
1254- return p ;
1255- } ) ;
1256- return { ...content , parts : newParts } ;
1257- }
1258-
1259- return content ;
1260- } ) ;
1261- }
1262-
12631270 // For Claude models, filter out unsigned thinking blocks (required by Claude API)
12641271 // Attempts to restore signatures from cache for multi-turn conversations
12651272 // Handle both Gemini-style contents[] and Anthropic-style messages[] payloads.
0 commit comments