Skip to content

Python: Set the assistant role on streamed Gemini updates - #9491

Open
Aditya Kumar (Aditya-XR) wants to merge 1 commit into
microsoft:mainfrom
Aditya-XR:fix/gemini-stream-role
Open

Aditya Kumar (Aditya-XR) wants to merge 1 commit into
microsoft:mainfrom
Aditya-XR:fix/gemini-stream-role

Conversation

@Aditya-XR

Copy link
Copy Markdown
Contributor

Motivation & Context

With stream=True, GeminiChatClient creates every ChatResponseUpdate without a role. After a tool call, the function-invocation layer adds the tool result as a role="tool" update, and the answer that Gemini streams next is appended to that tool message. The Gemini request builder keeps only function_result content from tool messages, so the answer is dropped from the history and Gemini never sees it on the next turn. Without streaming the same agent gives the expected assistant, tool, assistant messages.

Description & Review Guide

  • What are the major changes?

    _process_chunk now builds each streamed update with role="assistant", like the non-streaming path and the Anthropic, Bedrock, Mistral and Ollama clients:

             return ChatResponseUpdate(
    +            role="assistant",
                 contents=contents,
                 model=chunk.model_version or model,

    The docstring of _process_chunk now says it returns an assistant update. Two new tests in test_gemini_client.py cover the change:

    • test_streaming_updates_have_assistant_role checks that each streamed update has the assistant role. Without the fix the roles are [None, None].
    • test_streaming_answer_after_tool_call_stays_in_history streams a tool call followed by an answer through GeminiChatClient with function invocation. It checks that the final response is assistant, tool (only the function result), assistant (the answer), and that the answer is sent back as a model turn on the next request. Without the fix the answer is inside the tool message and is missing from the next request.
  • What is the impact of these changes?

    Streaming Gemini agents that call tools keep their final answer as an assistant message, so the answer stays in the session history and is sent back to Gemini on later turns. Streams without tool calls are unchanged in practice: the first message of a response already defaulted to the assistant role. Consumers that read update.role now get "assistant" instead of None.

  • What do you want reviewers to focus on?

    The role is set on every chunk, including chunks that carry only usage or a finish reason, and chunks with hosted tool calls and results (code execution). Non-streaming already puts all of these in one assistant message, so streaming now matches it.

Related Issue

Fixes #9490

This is a one-line correction that makes streaming match the non-streaming path and the other providers (the same fix as #4329 for Anthropic), so I opened it together with the issue.

AI Assistance

  • No material AI assistance was used.
  • This is an AI-assisted contribution. I reviewed, understood, and verified all submitted content and accept responsibility for it.

AI assistance details: I used Claude Code as an assistant to help find the bug and to draft the fix, the tests, the linked issue and this description. I did the final review myself: I read and understood every change, checked the repro and test results, and made the final decisions on what to submit.

Contribution Checklist

  • The code builds clean without any errors or warnings
  • All unit tests pass, and I have added new tests where possible
  • The PR follows the Contribution Guidelines
  • This PR links to an agreed issue with no competing open PR, or the Related Issue section documents a trivial-change or repository-automation exception.
  • This is not a breaking change. If it is a breaking change, add the breaking change label (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.

GeminiChatClient built streaming ChatResponseUpdates without a role. After the
function-invocation layer adds a tool-role update, the next role-less text was
appended to the tool message, and the Gemini serializer then dropped it, so the
answer was missing from the next turn. The non-streaming path already uses the
assistant role, and the other providers set it on every streamed update.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@agent-framework-automation agent-framework-automation Bot added the python Usage: [Issues, PRs], Target: Python label Oct 18, 2026

This branch was successfully deployed

1 active deployment
github-app-auth — 0b8f227b Deployed Oct 18, 2026 by Aditya-XR via team_check #7012
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Usage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: [Bug]: Gemini streaming loses the final answer after a tool call

2 participants