Removes version and adds Gemini thoughtSignature support#30
Removes version and adds Gemini thoughtSignature support#30carmelosantana merged 2 commits intomainfrom
Conversation
Enables proper handling of thoughtSignature metadata for function calls in Gemini responses, ensuring correct round-trip behavior and validation compatibility.
There was a problem hiding this comment.
Pull request overview
Adds Gemini “thoughtSignature” support to tool-call parsing/serialization while removing the explicit package version from composer.json, aligning the library with common Composer distribution practices.
Changes:
- Extend
ToolCallto carry provider-specific metadata (used for GeminithoughtSignature). - Update
GeminiProviderto parsethoughtSignaturefrom responses/streams and emit it on outgoing functionCall parts (with a dummy fallback). - Add unit tests covering
thoughtSignaturecapture and request-payload roundtrips.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| tests/Unit/Provider/GeminiProviderTest.php | Adds tests for parsing and emitting thoughtSignature, including parallel tool call scenarios and dummy fallback behavior. |
| src/Tool/ToolCall.php | Introduces a metadata field to store provider-specific tool-call attributes. |
| src/Provider/GeminiProvider.php | Captures thoughtSignature into ToolCall metadata and serializes it back into Gemini functionCall parts. |
| composer.json | Removes the version field. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Per Gemini docs, only the first functionCall part in a parallel call has the signature | ||
| $provider->chat([ | ||
| new UserMessage('Do two things'), | ||
| new AssistantMessage('', [ | ||
| new ToolCall('g00000000', 'read_file', ['path' => '/a'], ['thoughtSignature' => 'gs:parallel_sig']), | ||
| new ToolCall('g00000001', 'exec', ['cmd' => 'ls']), | ||
| ]), |
There was a problem hiding this comment.
This inline comment says only the first parallel functionCall part “has the signature”, but the assertion expects a dummy thoughtSignature to be sent on subsequent parts. Reword the comment to reflect the implemented behavior (real signature only on the first call; dummy used for the rest).
| // Gemini 3 requires thoughtSignature on functionCall parts. | ||
| // Use real signature if available, otherwise dummy to skip validation. | ||
| if (isset($toolCall->metadata['thoughtSignature'])) { | ||
| $part['thoughtSignature'] = $toolCall->metadata['thoughtSignature']; | ||
| } else { | ||
| $part['thoughtSignature'] = 'skip_thought_signature_validator'; | ||
| } |
There was a problem hiding this comment.
The provider comment states “Gemini 3 requires thoughtSignature on functionCall parts”, but the implementation currently adds a thoughtSignature for every tool call regardless of model. Either gate this behavior by model/version, or adjust the comment to match the always-on behavior to avoid confusing future maintainers.
| // Gemini 3 requires thoughtSignature on functionCall parts. | ||
| // Use real signature if available, otherwise dummy to skip validation. | ||
| if (isset($toolCall->metadata['thoughtSignature'])) { | ||
| $part['thoughtSignature'] = $toolCall->metadata['thoughtSignature']; | ||
| } else { | ||
| $part['thoughtSignature'] = 'skip_thought_signature_validator'; | ||
| } | ||
| $parts[] = $part; |
There was a problem hiding this comment.
The dummy thoughtSignature value is a hard-coded magic string and is duplicated in multiple places (provider + tests). Consider extracting it to a single constant (e.g., on GeminiProvider) and reusing it, so future changes don’t silently desync behavior vs. expectations.
Removes version field from composer.json and adds support for Gemini's thoughtSignature in tool calls: