Describe the bug
When Gemini returns multiple function calls in the same streamed model response, only the first function-call part may carry a ThoughtSignature. ADK Go's streaming response aggregator preserves a thought signature for the function call currently being assembled, but it does not propagate that signature to sibling function-call parts that are emitted in the same parallel batch without their own signature.
Gemini thinking models require replayed model-role function-call parts to carry thought signatures. If one or more parallel function-call parts are later replayed from session history without a ThoughtSignature, the next model request can fail with 400 INVALID_ARGUMENT complaining that a function call is missing a thought_signature.
There is a related but separate issue for synthetic adk_request_confirmation parts: #656. This issue is about parallel function calls emitted by the model through the streaming aggregator.
To Reproduce
- Use a Gemini model with thinking enabled.
- Trigger a streamed response where the model emits multiple function calls in parallel.
- Observe that the first function-call part includes a
ThoughtSignature, while sibling function-call parts in the same model-role content may not.
- Persist and replay that model-role content in a subsequent request.
- The Gemini API may reject the request because one of the replayed function-call parts is missing
thought_signature.
Expected behavior
When ADK Go aggregates streamed model responses into a final model-role content block, all function-call parts in the same parallel function-call batch should be replay-safe. If one function-call part has a thought signature and sibling function-call parts are missing it, the aggregator should copy the available signature onto the missing sibling parts before returning the final aggregated response.
Observed behavior
internal/llminternal/stream_aggregator.go preserves a thought signature for an individual streamed function call, but does not ensure sibling parallel function-call parts also carry a signature before the aggregated content is persisted/replayed.
Proposed fix
After flushing the final text/function-call buffers in streamingResponseAggregator.Close, scan the aggregated sequence for function-call parts:
- remember the first non-empty
ThoughtSignature
- copy it onto subsequent function-call parts that are missing a signature
This keeps the fix local to streamed response aggregation and avoids changing unrelated tool confirmation behavior.
Testing
Add or update unit coverage for internal/llminternal/stream_aggregator.go with a streamed response containing multiple parallel function calls where only the first carries ThoughtSignature. The test should assert that all emitted function-call parts in the final aggregated response carry a non-empty signature.
Alignment with adk-python
This is specific to ADK Go's streaming aggregation path and the Go genai.Part representation. The cross-language invariant is that model-role function-call history generated from Gemini thinking models must be replayable without losing required thought signatures.
Describe the bug
When Gemini returns multiple function calls in the same streamed model response, only the first function-call part may carry a
ThoughtSignature. ADK Go's streaming response aggregator preserves a thought signature for the function call currently being assembled, but it does not propagate that signature to sibling function-call parts that are emitted in the same parallel batch without their own signature.Gemini thinking models require replayed model-role function-call parts to carry thought signatures. If one or more parallel function-call parts are later replayed from session history without a
ThoughtSignature, the next model request can fail with400 INVALID_ARGUMENTcomplaining that a function call is missing athought_signature.There is a related but separate issue for synthetic
adk_request_confirmationparts: #656. This issue is about parallel function calls emitted by the model through the streaming aggregator.To Reproduce
ThoughtSignature, while sibling function-call parts in the same model-role content may not.thought_signature.Expected behavior
When ADK Go aggregates streamed model responses into a final model-role content block, all function-call parts in the same parallel function-call batch should be replay-safe. If one function-call part has a thought signature and sibling function-call parts are missing it, the aggregator should copy the available signature onto the missing sibling parts before returning the final aggregated response.
Observed behavior
internal/llminternal/stream_aggregator.gopreserves a thought signature for an individual streamed function call, but does not ensure sibling parallel function-call parts also carry a signature before the aggregated content is persisted/replayed.Proposed fix
After flushing the final text/function-call buffers in
streamingResponseAggregator.Close, scan the aggregated sequence for function-call parts:ThoughtSignatureThis keeps the fix local to streamed response aggregation and avoids changing unrelated tool confirmation behavior.
Testing
Add or update unit coverage for
internal/llminternal/stream_aggregator.gowith a streamed response containing multiple parallel function calls where only the first carriesThoughtSignature. The test should assert that all emitted function-call parts in the final aggregated response carry a non-empty signature.Alignment with adk-python
This is specific to ADK Go's streaming aggregation path and the Go
genai.Partrepresentation. The cross-language invariant is that model-role function-call history generated from Gemini thinking models must be replayable without losing required thought signatures.