fix(flows): pair async function responses on (id, name) not id alone - #6764
Open
a-yeyang wants to merge 1 commit into
Open
fix(flows): pair async function responses on (id, name) not id alone#6764a-yeyang wants to merge 1 commit into
a-yeyang wants to merge 1 commit into
Conversation
Model-supplied function-call ids are not guaranteed unique. Vertex Gemini mints `call_<n>` ids from a small space that can repeat within a single session, and ADK preserves model-supplied ids (only `adk-` prefixed ids are generated or stripped by the framework), so a repeated id survives into the history rebuild. `_rearrange_events_for_async_function_responses_in_history` indexed responses by `function_response.id` alone, in forward order, so a repeated id kept only the newest response. The second pass then appended that response after the oldest call carrying the same id, pairing a `function_call` for one tool with the `function_response` of another. The model rejects the resulting contents with a bare `400 INVALID_ARGUMENT`. Key the pairing on `(id, name)` instead. ADK always sets `function_response.name` to the tool name and the matching `function_call` carries the same name, so this is behavior-preserving for every non-colliding history while keeping a collision from resolving across two different tools. Adds a regression test that reproduces the reported shape (two tools reusing `call_807`) and asserts each call is paired with its own tool's response. Fixes google#6761
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Link to Issue or Description of Change
Problem:
_rearrange_events_for_async_function_responses_in_historypairs function responses to calls byfunction_response.idalone. Model-supplied ids are not guaranteed unique — Vertex Gemini mintscall_<n>ids from a space small enough to repeat within a single session, and ADK preserves model-supplied ids (remove_client_function_call_idstrips onlyadk--prefixed ids;populate_client_function_call_idassigns one only when the id is empty). So a repeated id survives into this rebuild.Because the index is built in forward order, a repeated id keeps only the newest response. The second pass then appends that response directly after the oldest call carrying the same id, pairing a
function_callfor one tool with thefunction_responseof another. On the nextgenerateContentthe model rejects the contents with a bare400 INVALID_ARGUMENT. The reporter measured this at ~1 collision in 153 requests in a real session (gemini-3.5-flash, Vertex EU), where a single collision ended the run.Solution:
Key the pairing on
(id, name)instead ofid. ADK always setsfunction_response.nameto the tool name (Part.from_function_response(name=tool.name, ...)), and the matchingfunction_callcarries the same name, so:This is the narrowest change that fixes the reported, reproduced behavior; it touches only the pairing key in this one function.
Testing Plan
Unit Tests:
test_rearrange_async_function_responses_pairs_on_id_and_name) that reproduces the reported shape — two tools (site_security_posture,fleet_security_summary) both reusing idcall_807, interleaved with their responses — and asserts each call is followed by the response for the same tool. It fails on the old id-only keying and passes with this change.tests/unittests/flows/llm_flows/test_contents.pypass locally.Manual End-to-End (E2E) Tests:
The failure is intermittent and content-dependent (it requires the model to reuse an id across two different tools within one session), so it is exercised through the unit test above rather than a manual E2E run. The reproduction in the issue captures the exact rejected-request contents.
Checklist