5050 "gemini-3-pro-image-preview" ,
5151}
5252
53+ # https://ai.google.dev/gemini-api/docs/thought-signatures#faqs
54+ DEFAULT_THOUGHT_SIGNATURE : bytes = b"skip_thought_signature_validator"
55+
5356
5457class GoogleLargeLanguageModel (LargeLanguageModel ):
5558 is_thinking = None
@@ -506,25 +509,32 @@ def _format_message_to_gemini_content(
506509 :return: Gemini Content representation of message
507510 """
508511
509- def _build_text_parts (_content : str | TextPromptMessageContent ) -> List [types .Part ]:
512+ def _build_text_parts (
513+ _content : str | TextPromptMessageContent , * , is_assistant_tree : bool = False
514+ ) -> List [types .Part ]:
510515 text_parts = []
511516 if isinstance (_content , TextPromptMessageContent ):
512517 _content = _content .data
513518 if message .role == PromptMessageRole .ASSISTANT :
514519 _content = re .sub (r"^<think>.*?</think>\s*" , "" , _content , count = 1 , flags = re .DOTALL )
515520 if _content :
516- text_parts .append (types .Part .from_text (text = _content ))
521+ _unverified_part = types .Part .from_text (text = _content )
522+ if is_assistant_tree :
523+ _unverified_part .thought_signature = DEFAULT_THOUGHT_SIGNATURE
524+ text_parts .append (_unverified_part )
517525 return text_parts
518526
519527 # Helper function to build parts from content
520- def build_parts (content : str | List [PromptMessageContentUnionTypes ]) -> List [types .Part ]:
528+ def build_parts (
529+ content : str | List [PromptMessageContentUnionTypes ], * , is_assistant_tree : bool = False
530+ ) -> List [types .Part ]:
521531 if isinstance (content , str ):
522- return _build_text_parts (content )
532+ return _build_text_parts (content , is_assistant_tree = is_assistant_tree )
523533
524534 parts_ = []
525535 for obj in content :
526536 if obj .type == PromptMessageContentType .TEXT :
527- parts_ .extend (_build_text_parts (obj ))
537+ parts_ .extend (_build_text_parts (obj , is_assistant_tree = is_assistant_tree ))
528538 else :
529539 # Filter files based on type and supported formats
530540 should_upload = True
@@ -542,7 +552,10 @@ def build_parts(content: str | List[PromptMessageContentUnionTypes]) -> List[typ
542552 uri , mime_type = self ._upload_file_content_to_google (
543553 obj , genai_client , file_server_url_prefix
544554 )
545- parts_ .append (types .Part .from_uri (file_uri = uri , mime_type = mime_type ))
555+ _unverified_part = types .Part .from_uri (file_uri = uri , mime_type = mime_type )
556+ if is_assistant_tree :
557+ _unverified_part .thought_signature = DEFAULT_THOUGHT_SIGNATURE
558+ parts_ .append (_unverified_part )
546559 else :
547560 # Log skipped files for debugging
548561 logging .debug (
@@ -560,17 +573,17 @@ def build_parts(content: str | List[PromptMessageContentUnionTypes]) -> List[typ
560573
561574 # Handle text content (remove thinking tags)
562575 if message .content :
563- parts .extend (build_parts (message .content ))
576+ parts .extend (build_parts (message .content , is_assistant_tree = True ))
564577
565578 # Handle tool calls
566579 # https://ai.google.dev/gemini-api/docs/function-calling?hl=zh-cn&example=chart#how-it-works
567580 if message .tool_calls :
568581 call = message .tool_calls [0 ]
569- parts .append (
570- types .Part .from_function_call (
571- name = call .function .name , args = json .loads (call .function .arguments )
572- )
582+ _unsafe_part = types .Part .from_function_call (
583+ name = call .function .name , args = json .loads (call .function .arguments )
573584 )
585+ _unsafe_part .thought_signature = DEFAULT_THOUGHT_SIGNATURE
586+ parts .append (_unsafe_part )
574587
575588 return types .Content (role = "model" , parts = parts )
576589
0 commit comments