@@ -112,13 +112,46 @@ def __init__(
112112
113113 def _process_messages (self , messages ) -> List [OpenAIMessage ]:
114114 r"""Process the messages for Gemini API to ensure no empty content,
115- which is not accepted by Gemini.
115+ which is not accepted by Gemini. Also preserves thought signatures
116+ required for Gemini 3 Pro function calling and adds fallback signatures
117+ when they are missing.
116118 """
119+ import copy
120+
117121 processed_messages = []
118122 for msg in messages :
119- msg_copy = msg .copy ()
123+ # Use deep copy to preserve all nested structures including
124+ # thought signatures in extra_content
125+ msg_copy = copy .deepcopy (msg )
120126 if 'content' in msg_copy and msg_copy ['content' ] == '' :
121127 msg_copy ['content' ] = 'null'
128+
129+ # Handle missing thought signatures for function calls
130+ # This is required for Gemini 3 Pro compatibility
131+ # TODO: support multi round thought signatures
132+ if (
133+ msg_copy .get ('role' ) == 'assistant'
134+ and 'tool_calls' in msg_copy
135+ and isinstance (msg_copy ['tool_calls' ], list )
136+ ):
137+ for i , tool_call in enumerate (msg_copy ['tool_calls' ]):
138+ # Check if this is the first tool call in a parallel set
139+ # or any tool call that's missing a thought signature
140+ if i == 0 : # First tool call should have a signature
141+ # Check if thought signature is missing
142+ extra_content = tool_call .get ('extra_content' , {})
143+ google_content = extra_content .get ('google' , {})
144+
145+ if 'thought_signature' not in google_content :
146+ # Add fallback signature for missing signatures
147+ if 'extra_content' not in tool_call :
148+ tool_call ['extra_content' ] = {}
149+ if 'google' not in tool_call ['extra_content' ]:
150+ tool_call ['extra_content' ]['google' ] = {}
151+ tool_call ['extra_content' ]['google' ][
152+ 'thought_signature'
153+ ] = "skip_thought_signature_validator"
154+
122155 processed_messages .append (msg_copy )
123156 return processed_messages
124157
0 commit comments