fix: skip empty text finalization chunk after function call#270
fix: skip empty text finalization chunk after function call#270RobinClowers wants to merge 1 commit into
Conversation
|
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. |
6aafbbe to
6a4f9bc
Compare
|
I created a local e2e test that uses your exact function and agent. It seems like it's working fine, I see the functionResponse with STOP and a final event with model output. I pushed a branch called Is there something else that you know would be different from that setup? |
|
@ScottMansfield thanks for creating that test, and sorry for the late response. I pushed a commit to my fork that causes the test to fail https://github.com/RobinClowers/adk-js/tree/weather-tool-test. Two key changes: multiple turns and enabling SSE streaming. I'll also resolve the merge conflicts here. |
Gemini thinking models send an empty text chunk with finishReason STOP after a function call to signal completion. The streaming loop in generateContentAsync was yielding this chunk unconditionally, causing isFinalResponse() to treat it as the agent's final response and preventing the follow-up model call that generates the actual text. Track whether a function call has been seen in the current streaming turn. When we encounter a chunk that has only empty text parts and finishReason STOP after a function call, skip it instead of yielding.
6a4f9bc to
2a6d3c6
Compare
|
@ScottMansfield checking in on this, anything else you need from me? |
Link to Issue or Description of Change
streaming=Truein/run_ssereturns empty text after AgentTool calls (works withstreaming=False) adk-python#3754Problem:
Gemini thinking models send an empty text chunk with finishReason STOP after a function call to signal completion. The streaming loop in generateContentAsync was yielding this chunk unconditionally, causing isFinalResponse() to treat it as the agent's final response and preventing the follow-up model call that generates the actual text.
Solution:
Track whether a function call has been seen in the current streaming turn. When we encounter a chunk that has only empty text parts and finishReason STOP after a function call, skip it instead of yielding.
Testing Plan
Please describe the tests that you ran to verify your changes. This is required
for all PRs that are not small documentation or typo fixes.
Unit Tests:
Please include a summary of passed npm test results.
Manual End-to-End (E2E) Tests:
The bug triggers when a thinking model makes a function call during streaming — Gemini sends the function call chunk, then an empty text chunk with finishReason: STOP. Without the fix, the agent treats that
empty chunk as the final response and never makes the second model call to generate actual text.
Setup: An agent with a tool and a thinking model:
A simple prompt like "What's the weather in Seattle?" is enough — you just need one tool call.
What to look for:
error is thrown — it just produces no answer.
Key conditions:
Checklist