It sent gemini-2.5-pro and reported gemini-2.5-flash
A response's model field is not decoration. It is what your logs record, what your cost attribution divides by, what a router uses to pick the next call, and what a UI puts under the message. When it is wrong it is wrong quietly, and every downstream reader inherits it. Here is a case where two cal

A response's model field is not decoration. It is what your logs record, what your cost attribution divides by, what a router uses to pick the next call, and what a UI puts under the message. When it is wrong it is wrong quietly, and every downstream reader inherits it.
Here is a case where two call paths of the same client disagree about that field, for the same request, on the same server reply.
Two calls. Same client, same per-request model override, same reply shape — a reply that carries no model_version. One call streams, the other does not.
The second row is the client's configured model, not the one this request resolved to. The client was built with model="gemini-2.5-flash" and asked for options={"model": "gemini-2.5-pro"}.
I did not invent the streaming test; that one is theirs. I wrote its non-streaming twin — same fixture factory, same options dict, same absent model_version, only the call path differs:
test_streaming_falls_back_to_requested_model PASSED test_non_streaming_falls_back_to_requested_model FAILED E AssertionError: assert 'gemini-2.5-flash' == 'gemini-2.5-pro' Enter fullscreen mode Exit fullscreen mode Run against agent-framework-gemini 1.0.0b261015 from PyPI, and the same two lines are still on main today.
model, contents, config = self. _prepare_request ( messages, validated ) # the model this request resolved to raw = await generate_content ( model = model, contents = contents, config = config ) # sent correctly return self. _process_generate_response ( raw, response_format =...) #...and not handed on Enter fullscreen mode Exit fullscreen mode and inside _process_generate_response:
model = response. model_version or self. model, Enter fullscreen mode Exit fullscreen mode Two different model s, one frame apart. self.model is the client's configured default; the local model is what this request resolved to after the options override. When the reply omits model_version, or falls through to the attribute — so the label reports whatever the client was constructed with, no matter what was actually asked for or sent.
The streaming path does not have this problem, because it takes the resolved model as a parameter, and its docstring says exactly the right thing:
the last version the server reported in this stream, or the model resolved for this request
This is not an oversight, and I want to be careful about that, because the thread tells a better story than "someone missed a path".
The person who fixed the streaming case named the sibling himself, on the pull request, before it merged:
_process_generate_response has the same client-default fallback at:1058. I left it alone to keep this PR on the streaming path — happy to align it here or in a follow-up, whichever you prefer.
microsoft/agent-framework#9139 merged on 2026-10-13. Six days before that he had flagged the sibling; four days before, another comment reported the conflict resolved and the diff as "4 lines in _chat_client.py and the 48 test lines". The follow-up was never asked for, never refused, and never tracked. Today the sibling still reads self.model.
So the defect's history is: found, described precisely, offered as a choice, and then closed by the sweep of an issue going green. Not hidden — unanswered. That is a much more ordinary way for a bug to survive, and a much more useful one to learn from, because the same thing happens in every repository where a fixer is being polite about scope.
The suite has eleven tests with "model" in the name. All eleven pass on this install. What separates them is not count but which boundary they assert:
Both sentences are true about this code. They are just not the same sentence: one asks what did we report, the other asks what did we send. And the single non-streaming test that does look at response.model always hands the mock a model_version, so the or self.model branch is unreachable from the suite.
Tallied: four streaming tests about the reported model, one non-streaming, zero non-streaming tests about the fallback.
Not really about Gemini, or about this package. Four checkable parts:
The fix here is one argument: pass the resolved model into _process_generate_response and use response.model_version or model. Then write the twin — the streaming test already exists, so the twin is a copy with stream=True deleted.
All of this runs on mocks; I did not call the live Gemini API. So the honest scope is narrow and sufficient: given a reply with no model_version, the two call paths report different things. Whether Gemini's API omits model_version in practice is not something I measured — but a fallback branch exists because it can, and there is already a test for exactly that case on the other leg.
What I can add is that the streaming half is correct and tested. This is not a broken fix. It is a fix that did what its author said it would do, on the path it was aiming at.
The reading you want, when a fix lands on one of two siblings, is not "did the fix work" but "what did its author leave for later — and did anyone come back?"