83ba938d1e
* Python: preserve Gemini 3 thought_signature across function-call replays Gemini 3 requires the opaque thought_signature attached to each functionCall part to be echoed back on every replay of that call, or the request is rejected with 400 INVALID_ARGUMENT. The signature previously survived only via raw_representation, so any layer that reconstructs a FunctionCallContent (e.g. harness tool approval) dropped it and broke the next step of the tool loop. Capture the signature into additional_properties on parse and replay it when building the Gemini Part, independent of raw_representation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 33233834-bc6e-4ad2-a6f3-6f1d6e57b1d2 * Store Gemini thought_signature as base64 for JSON-safe persistence Content.additional_properties is serialized via json.dumps(message.to_dict()) by history providers (e.g. RedisHistoryProvider), which fails on raw bytes. Store the thought_signature as a base64 string on parse and decode it back to bytes when building the Gemini Part. Also narrow call_id/name in the round-trip test to satisfy the type checkers. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 33233834-bc6e-4ad2-a6f3-6f1d6e57b1d2 * Harden Gemini thought_signature decode against corrupted history Guard the untyped additional_properties value with an isinstance(str) check and decode with validate=True, degrading gracefully (warn + drop the signature) on malformed data instead of raising binascii.Error mid tool loop. Matches the defensive base64 handling already used for data URIs in this file. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 33233834-bc6e-4ad2-a6f3-6f1d6e57b1d2 * Carry Gemini thought_signature on reasoning content via protected_data Represent the signature as a text_reasoning content's protected_data (base64) immediately preceding the function call, instead of a bespoke additional_properties key. This uses the framework's first-class opaque-signature field (as Anthropic does), survives streaming accumulation, and stays intact when the harness reconstructs the function call. Replay correlates the signature by adjacency. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 33233834-bc6e-4ad2-a6f3-6f1d6e57b1d2 --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>