From 90fd2e48d398e6858c76145803d4ac2f4778d8ed Mon Sep 17 00:00:00 2001 From: AnegasakiNene <990126341@qq.com> Date: Wed, 19 Aug 2026 10:11:12 +0800 Subject: [PATCH 1/2] fix: preserve current user turn in Gemini history --- .../core/provider/sources/gemini_source.py | 2 +- tests/test_gemini_source.py | 47 ++++++++++++++++++- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/astrbot/core/provider/sources/gemini_source.py b/astrbot/core/provider/sources/gemini_source.py index abf7bb7cf8..992c4e6b9b 100644 --- a/astrbot/core/provider/sources/gemini_source.py +++ b/astrbot/core/provider/sources/gemini_source.py @@ -428,7 +428,7 @@ def append_or_extend( append_or_extend(gemini_contents, parts, types.UserContent) if gemini_contents and isinstance(gemini_contents[0], types.ModelContent): - gemini_contents.pop() + gemini_contents.pop(0) return gemini_contents diff --git a/tests/test_gemini_source.py b/tests/test_gemini_source.py index 9294ea46b2..e19ac6d940 100644 --- a/tests/test_gemini_source.py +++ b/tests/test_gemini_source.py @@ -2,13 +2,58 @@ import httpx import pytest +from google.genai import types -from astrbot.core.exceptions import EmptyModelOutputError import astrbot.core.provider.sources.request_retry as request_retry +from astrbot.core.exceptions import EmptyModelOutputError from astrbot.core.provider.entities import LLMResponse from astrbot.core.provider.sources.gemini_source import ProviderGoogleGenAI +def _make_gemini_provider() -> ProviderGoogleGenAI: + return ProviderGoogleGenAI.__new__(ProviderGoogleGenAI) + + +def test_gemini_prepare_conversation_removes_leading_model_content(): + provider = _make_gemini_provider() + + contents = provider._prepare_conversation( + { + "messages": [ + {"role": "assistant", "content": "stale assistant turn"}, + {"role": "user", "content": "current user turn"}, + ] + } + ) + + assert len(contents) == 1 + assert isinstance(contents[0], types.UserContent) + assert contents[0].parts is not None + assert contents[0].parts[-1].text == "current user turn" + + +def test_gemini_prepare_conversation_keeps_normal_user_first_history(): + provider = _make_gemini_provider() + + contents = provider._prepare_conversation( + { + "messages": [ + {"role": "user", "content": "first user turn"}, + {"role": "assistant", "content": "assistant turn"}, + {"role": "user", "content": "current user turn"}, + ] + } + ) + + assert [type(content) for content in contents] == [ + types.UserContent, + types.ModelContent, + types.UserContent, + ] + assert contents[-1].parts is not None + assert contents[-1].parts[-1].text == "current user turn" + + def test_gemini_empty_output_raises_empty_model_output_error(): llm_response = LLMResponse(role="assistant") From b2e4b3d2e70233c4aea3ecc7e540643c5a70e418 Mon Sep 17 00:00:00 2001 From: AnegasakiNene <990126341@qq.com> Date: Wed, 19 Aug 2026 10:18:10 +0800 Subject: [PATCH 2/2] test(provider): cover Gemini assistant-ending history --- tests/test_gemini_source.py | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/tests/test_gemini_source.py b/tests/test_gemini_source.py index e19ac6d940..7b47bcb5e1 100644 --- a/tests/test_gemini_source.py +++ b/tests/test_gemini_source.py @@ -10,12 +10,8 @@ from astrbot.core.provider.sources.gemini_source import ProviderGoogleGenAI -def _make_gemini_provider() -> ProviderGoogleGenAI: - return ProviderGoogleGenAI.__new__(ProviderGoogleGenAI) - - def test_gemini_prepare_conversation_removes_leading_model_content(): - provider = _make_gemini_provider() + provider = ProviderGoogleGenAI.__new__(ProviderGoogleGenAI) contents = provider._prepare_conversation( { @@ -33,7 +29,7 @@ def test_gemini_prepare_conversation_removes_leading_model_content(): def test_gemini_prepare_conversation_keeps_normal_user_first_history(): - provider = _make_gemini_provider() + provider = ProviderGoogleGenAI.__new__(ProviderGoogleGenAI) contents = provider._prepare_conversation( { @@ -54,6 +50,26 @@ def test_gemini_prepare_conversation_keeps_normal_user_first_history(): assert contents[-1].parts[-1].text == "current user turn" +def test_gemini_prepare_conversation_preserves_user_model_history(): + provider = ProviderGoogleGenAI.__new__(ProviderGoogleGenAI) + + contents = provider._prepare_conversation( + { + "messages": [ + {"role": "user", "content": "user turn"}, + {"role": "assistant", "content": "assistant turn"}, + ] + } + ) + + assert [type(content) for content in contents] == [ + types.UserContent, + types.ModelContent, + ] + assert contents[-1].parts is not None + assert contents[-1].parts[-1].text == "assistant turn" + + def test_gemini_empty_output_raises_empty_model_output_error(): llm_response = LLMResponse(role="assistant")