Skip to content

Commit 8f95ca9

Browse files
authored
fix: filter Gemini thinking parts from user-facing message chain (#7196)
Gemini 3 models return thinking parts (part.thought=True) alongside the actual response text. _process_content_parts was including these thinking parts in the message chain sent to the user, effectively leaking internal reasoning into the output. On platforms that split long messages (e.g. aiocqhttp with realtime segmenting), this caused duplicate or triple replies since the thinking text often mirrors the actual response. The streaming path already handled this correctly via chunk.text which skips thinking parts, but the non-streaming path and the final-chunk processing in streaming both went through _process_content_parts. Also switch the Gemini 3 model name matching from an exhaustive list to prefix matching (gemini-3- / gemini-3.) so new variants like gemini-3.1 get proper thinkingLevel config without code changes. Fixes #7183
1 parent 5e78a24 commit 8f95ca9

File tree

1 file changed

+9
-10
lines changed

1 file changed

+9
-10
lines changed

astrbot/core/provider/sources/gemini_source.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -241,15 +241,10 @@ async def _prepare_query_config(
241241
thinking_config = types.ThinkingConfig(
242242
thinking_budget=thinking_budget,
243243
)
244-
elif model_name in [
245-
"gemini-3-pro",
246-
"gemini-3-pro-preview",
247-
"gemini-3-flash",
248-
"gemini-3-flash-preview",
249-
"gemini-3-flash-lite",
250-
"gemini-3-flash-lite-preview",
251-
]:
252-
# The thinkingLevel parameter, recommended for Gemini 3 models and onwards
244+
elif any(model_name.startswith(p) for p in ("gemini-3-", "gemini-3.")):
245+
# The thinkingLevel parameter, recommended for Gemini 3 models and onwards.
246+
# Use prefix match so new variants (3.1, 3-flash-lite-preview, etc.) are
247+
# covered without needing to keep an exhaustive list up to date.
253248
# Gemini 2.5 series models don't support thinkingLevel; use thinkingBudget instead.
254249
thinking_level = self.provider_config.get("gm_thinking_config", {}).get(
255250
"level", "HIGH"
@@ -517,7 +512,11 @@ def _process_content_parts(
517512
):
518513
chain.append(Comp.Plain("这是图片"))
519514
for part in result_parts:
520-
if part.text:
515+
# Skip thinking parts — their text is already captured via
516+
# _extract_reasoning_content above. Including them here would
517+
# leak the model's internal reasoning into the user-facing message,
518+
# which also causes duplicate/triple replies on some platforms.
519+
if part.text and not part.thought:
521520
chain.append(Comp.Plain(part.text))
522521

523522
if (

0 commit comments

Comments
 (0)