Curated history keeps half a user turn when the model turn is invalid
Maintainers usually reply within 1 day
@Venkaiahbabuneelam is already working on this.
Since Oct 5, 2026.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 62/100
Research direction
Start at _extract_curated_history in chats.py, specifically the single curated_history.pop() at lines 107-108, reached through chats.create(history=...) at line 136. Read google/genai/tests/chats/test_get_history.py, especially test_history_with_consecutive_valid_user_inputs (line 152) and test_history_with_invalid_turns (line 401), which bracket the intended behavior. Reproduce with the multi-content user turn plus empty model turn shown in the issue. Done means an invalid model turn drops the whole preceding user run, not one content, and the get-history suite passes.
Written by the indexing model from the issue text.
Description
Title: _extract_curated_history drops only the last user content when a model turn is invalid
An invalid model turn makes _extract_curated_history call curated_history.pop() once (chats.py:107-108). A user turn of two or more Content objects went in one at a time, so one pop removes part of it. The rest stays in the curated history with no model answer behind it.
The way in is chats.create(history=...), the only caller of that function (chats.py:136): a caller persisting raw exchanges stores one content per function response, and a blocked model turn as an empty content.
At 618f0aa, through the public constructor:
$ /var/tmp/p9bL16/genai/.venv/bin/python probe_hist2.py
import: /var/tmp/p9bL16/genai/google/genai/__init__.py
curated: [('user', 1)]
comprehensive: [('user', 1), ('user', 1), ('model', 0)]
hist = [
C(role="user", parts=[P(text="what is the weather")]),
C(role="user", parts=[P.from_function_response(name="get_weather", response={"c": 21})]),
C(role="model", parts=[]), # invalid model turn
]
chat = client.chats.create(model="gemini-2.0-flash", history=hist)
The question survives and the tool result behind it disappears, so the next send_message sends a user turn the model already failed on, minus its evidence.
$ python -m pytest google/genai/tests/chats/test_get_history.py -q
17 passed, 1 warning in 0.06s
# not run: the replay suites, which need recorded sessions
Two of those tests bracket the gap. test_history_with_consecutive_valid_user_inputs (test_get_history.py:152) makes back-to-back user contents supported input, and test_history_with_invalid_turns (:401) sets the intent that the whole rejected user turn goes. One pop meets that intent only where the turn is a single content.
There is no CODEOWNERS here and every merge on GitHub is the Copybara import, so @jaycee-li, I am going by your last commit on this file. Should the pop walk back over the whole user run? I can write the diff out here if that helps the internal fix.
- Dominant language
- Python
- Stars
- 4.1k
- Forks
- 1.1k
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 90
Getting set up
- No Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from googleapis/python-genai
-
Interactions retries ignore the documented `initial_delay` and `max_delay` defaultsPossibly taken @Venkaiahbabuneelam claimed this 4 days ago. Openpriority: p2 status:awaiting user response type: bug
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
googleapis/python-genai#3317 · 1 comment · 1 assignee ·
Maintainers usually reply within 1 day
-
Test import module that doesn't existPossibly taken @Venkaiahbabuneelam claimed this 30 days ago. Openpriority: p2 type: bug
Difficulty 2/5 1-3 hours Newbie friendliness 66/100
googleapis/python-genai#3122 · 6 comments · 1 assignee ·
Maintainers usually reply within 1 day
-
[Bug]: Unsubscripted typing.List and typing.Dict crash convert_if_exist_pydantic_model in AFCPossibly taken @Venkaiahbabuneelam claimed this 39 days ago. Openpriority: p2 type: bug
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
googleapis/python-genai#3044 · 1 comment · 1 assignee ·
Maintainers usually reply within 1 day
-
Structured-output continuation merge raises AttributeError: __pydantic_generic_metadata__ when a hop has parsed JSONPossibly taken @Venkaiahbabuneelam claimed this 3 days ago. Openpriority: p2 type: bug
googleapis/python-genai#3350 · 1 comment · 1 assignee ·
Maintainers usually reply within 1 day
-
Automatic function calling rejects `datetime` and `UUID` argumentsPossibly taken @Venkaiahbabuneelam claimed this 3 days ago. Openpriority: p2 type: bug
Difficulty 3/5 1-2 days Newbie friendliness 75/100
googleapis/python-genai#3331 · 1 comment · 1 assignee ·
Maintainers usually reply within 1 day
All issues in googleapis/python-genai
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
dbt-labs/spark-utils#51 ·
-
bug pydanty:is-working
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
pydantic/pydantic-ai#13444 ·
Maintainers usually reply within 1 day
-
good first issue help wanted
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
-
good first issue help wanted
Difficulty 1/5 Under an hour Newbie friendliness 72/100
-
changelog investigate
Difficulty 1/5 Under an hour Newbie friendliness 68/100
ramnes/notion-sdk-py#502 ·